rojects/workspace/history/2026/07-July/02-Thursday/index.html

234 lines
9.4 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Session Summary — 2 July 2026</title>
<link rel="stylesheet" href="../../../../_assets_/styles.css">
<link rel="stylesheet" href="../../../../_assets_/nav.css">
</head>
<body>
<div class="page">
<header>
<p class="date">Thursday, 2 July 2026</p>
<h1>Roject — Editor Build</h1>
<p class="subtitle">Session summary: TypeScript conversion, UUID IDs, CLAUDE.md, and a full project editor with WYSIWYG HTML editing.</p>
</header>
<section>
<h2>What we built</h2>
<div class="card">
<h3>TypeScript Conversion</h3>
<p>
All server and frontend JavaScript converted to TypeScript. Server runs via
<code>ts-node</code> using <code>tsconfig.json</code>. Frontend components
compile from <code>src/components/</code> to <code>public/components/</code>
via <code>tsconfig.client.json</code> with <code>module: none</code> — no bundler,
each component is a self-contained global script. Interfaces added for all
data shapes.
</p>
<div class="tags">
<span class="tag">typescript</span>
<span class="tag">ts-node</span>
<span class="tag">tsconfig.client.json</span>
<span class="tag">module: none</span>
</div>
</div>
<div class="card">
<h3>UUID IDs</h3>
<p>
All entity IDs (users, groups, projects, members) switched from integers to
UUIDs via <code>crypto.randomUUID()</code>. This allows multiple server instances
to generate IDs independently without collision, enabling data merging and
parallel deployments without a central ID authority.
</p>
<div class="tags">
<span class="tag">crypto.randomUUID()</span>
<span class="tag">id: string</span>
<span class="tag">no extra dependency</span>
</div>
</div>
<div class="card">
<h3>Project File Storage</h3>
<p>
Creating a project now creates a real directory structure on the server under
<code>storage/&lt;project-id&gt;/root/</code>. A default <code>index.html</code>
with a Hello World <code>&lt;page-content&gt;</code> element is generated automatically.
A new <code>/api/files</code> route handles tree listing and file read/write
with path traversal protection.
</p>
<div class="tags">
<span class="tag">storage/</span>
<span class="tag">GET /api/files/:id/tree</span>
<span class="tag">GET /api/files/:id/*</span>
<span class="tag">PUT /api/files/:id/*</span>
</div>
</div>
<div class="card">
<h3>Editor Page</h3>
<p>
A full editor page (<code>/editor.html</code>) with a 3-panel layout: Left
(file tree), Center (HTML editor), Right (empty, accepts dropped tabs). Panels
are resizable via drag handles. Sections within a panel are arranged
side by side and can be split using the ⊟ button on each tab container.
Portrait mode shows one panel at a time, switched via a top bar.
</p>
<div class="tags">
<span class="tag">&lt;editor-shell&gt;</span>
<span class="tag">3-panel layout</span>
<span class="tag">resize handles</span>
<span class="tag">portrait mode</span>
</div>
</div>
<div class="card">
<h3>Tab Container</h3>
<p>
A custom <code>&lt;tab-container&gt;</code> element manages tabs within each
panel section. Tabs are draggable between containers using the HTML5 Drag and
Drop API. A dirty dot (●) appears on tabs with unsaved changes. The ⊟ split
button creates a new side-by-side section in the same panel.
</p>
<div class="tags">
<span class="tag">&lt;tab-container&gt;</span>
<span class="tag">drag and drop</span>
<span class="tag">dirty indicator</span>
<span class="tag">section split</span>
</div>
</div>
<div class="card">
<h3>HTML Editor Panel</h3>
<p>
A WYSIWYG editor that loads HTML documents in an iframe and makes the
<code>&lt;page-content&gt;</code> element contenteditable. Changes are tracked
via MutationObserver. Includes an undo/redo stack (up to 200 steps),
Ctrl+S save, and a save button that highlights when the document is dirty.
</p>
<div class="tags">
<span class="tag">&lt;html-editor-panel&gt;</span>
<span class="tag">iframe WYSIWYG</span>
<span class="tag">MutationObserver</span>
<span class="tag">undo/redo</span>
<span class="tag">Ctrl+S</span>
</div>
</div>
<div class="card">
<h3>File Tree Panel</h3>
<p>
A <code>&lt;file-tree-panel&gt;</code> component fetches and renders the
project's <code>root/</code> directory structure. HTML files are clickable
and open in the HTML editor. Directories are collapsible. Non-HTML files
are shown but not openable in this version.
</p>
<div class="tags">
<span class="tag">&lt;file-tree-panel&gt;</span>
<span class="tag">collapsible dirs</span>
<span class="tag">HTML-only editing</span>
</div>
</div>
</section>
<section>
<h2>Key Decisions</h2>
<div class="decision">
<strong>LayoutPanel sections are arranged horizontally</strong>
<p>
Sections within a panel sit side by side (not stacked), so the Right panel
can hold an object graph next to an inspector. Each section can contain
multiple TabContainers stacked vertically. Portrait mode shows one section
at a time via a secondary tab row below the main panel switcher.
</p>
</div>
<div class="decision">
<strong>Fixed 3-column structure, flexible rows</strong>
<p>
The editor has three named panels (Left, Center, Right). The column count
is fixed because portrait mode maps each column to one top-bar button — a
clean 1-to-1 relationship. Within each column, sections and tab containers
can be freely split and resized.
</p>
</div>
<div class="decision">
<strong>Tab drag uses HTML5 DnD, not pointer events</strong>
<p>
HTML5 Drag and Drop handles cross-container tab moves via
<code>application/editor-tab</code> in dataTransfer. The source container
exposes an <code>extractTab()</code> method and the target calls
<code>receiveTab()</code>, preserving the panel's DOM element and state
across moves.
</p>
</div>
<div class="decision">
<strong>EditorState on window, not imported</strong>
<p>
Since <code>module: none</code> forbids imports between frontend files,
shared state lives on <code>window.editorState</code>, initialised
synchronously in <code>editor-shell</code> before any child component
connects. Other components wait via <code>customElements.whenDefined()</code>
before accessing it.
</p>
</div>
<div class="decision">
<strong>Real-time collaboration deferred</strong>
<p>
The spec described multi-user selections but building WebSocket sync would
have consumed the full session. The document/state model is designed for it —
EditorState can emit events that a future sync layer hooks into.
</p>
</div>
</section>
<section>
<h2>Project Structure</h2>
<div class="card">
<p>
<code>server/storage.ts</code> — project file storage helpers<br>
<code>server/routes/files.ts</code> — file tree + read/write API<br>
<code>storage/</code> — project file directories (auto-created)<br>
<code>src/components/editor-shell/</code> — main editor layout + EditorState<br>
<code>src/components/tab-container/</code> — tabbed panel with drag-drop<br>
<code>src/components/file-tree-panel/</code> — project file browser<br>
<code>src/components/html-editor-panel/</code> — WYSIWYG iframe editor<br>
<code>public/editor.html</code> — editor page entry point<br>
<code>CLAUDE.md</code> — project conventions (UUID IDs, raw CSS, custom elements)
</p>
</div>
</section>
<section>
<h2>What is missing</h2>
<div class="card">
<p>
Real-time multi-user collaboration and shared selections are not implemented.
The file tree is read-only — creating, renaming, and deleting files from the
editor is not yet supported. The Right panel is empty by default and requires
manual tab dragging to populate. Portrait secondary section switching (when a
panel has multiple side-by-side sections) is defined but not yet wired up as
a secondary tab row.
</p>
</div>
</section>
<footer>
Roject &mdash; session log &mdash; 2 July 2026
</footer>
</div>
<script>var NAV_ROOT = '../../../../';</script>
<script src="../../../../_assets_/nav-data.js"></script>
<script src="../../../../_assets_/nav.js"></script>
</body>
</html>