Shell: server, dashboard grid with drag/resize/remove, localStorage layouts

Milestone 1 of SPEC.md. Zero-dependency Node server serving public/;
12-column tile grid with add (placeholder tile), drag to move, drag to
resize, remove; collision-free placement; layout autosaves to this
browser's localStorage and survives reload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RNYUv9EyrGSFmCnmH7WYKH
This commit is contained in:
Claude
2026-08-30 14:50:37 +00:00
parent 7ec3637a73
commit 9d9b92e6d9
5 changed files with 1225 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ProdDash</title>
<meta name="theme-color" content="#0b0e12">
<link rel="stylesheet" href="/style.css">
</head>
<body>
<header id="topbar">
<span id="brand">Prod<span class="accent">Dash</span></span>
<span class="spacer"></span>
<div class="dropdown" id="add-dd">
<button class="tb-btn" id="add-btn" title="Add a module tile">+ Add tile ▾</button>
<div class="menu" id="add-menu" hidden></div>
</div>
<div class="dropdown" id="layout-dd">
<button class="tb-btn" id="layout-btn" title="Save, load or reset layouts">Layout ▾</button>
<div class="menu" id="layout-menu" hidden></div>
</div>
<a class="tb-btn" href="/admin/" title="Configure modules (server-wide)">
<svg width="13" height="13" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M12 15.5a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7Zm8.4-2.1.1-1.4-.1-1.4 1.7-1.3-1.6-2.8-2 .7a7.9 7.9 0 0 0-2.4-1.4l-.3-2.1H11l-.3 2.1a7.9 7.9 0 0 0-2.4 1.4l-2-.7L4.7 9.3 6.4 10.6l-.1 1.4.1 1.4-1.7 1.3 1.6 2.8 2-.7a7.9 7.9 0 0 0 2.4 1.4l.3 2.1h2.8l.3-2.1a7.9 7.9 0 0 0 2.4-1.4l2 .7 1.6-2.8-1.7-1.3Z"/>
</svg>
Admin
</a>
</header>
<main id="gridwrap">
<div id="grid">
<div id="empty-state">No tiles yet — use “+ Add tile” to build this dashboard.<br>
Every browser keeps its own layout.</div>
</div>
</main>
<div id="modal-backdrop" hidden>
<div id="modal" role="dialog" aria-modal="true"></div>
</div>
<div id="toast" hidden></div>
<script type="module" src="/shell.js"></script>
</body>
</html>