Live-review iteration on the browser SPA, driven by crit feedback. Sidebar / session tree - Compact single-line leaf rows; status shown as a faint "alive" row wash instead of per-row dots (exited rows dim + keep the "exited" badge). - Host is now the first level of nesting (host → label path → session); the inline @daemon is dropped from rows. - Flush, borderless search input spanning the sidebar; drag-to-resize grip on the sidebar edge (width persisted to localStorage); narrower default. - Per-row clone action (opens the spawn modal prefilled); right-pointing chevron when collapsed. Chrome / layout - Buttons swapped to a bracket terminal style ([ + Spawn ]); ghost/icon drop the brackets. Old filled styles removed. - Squared corners globally (radius tokens) and tighter, denser spacing. - Session tally + daemon chips moved into the centered app header. - Shorter control height; shared --bar-h aligns the search and attach bars. Attach / terminal - Useful attach title (name · command @ host) over a bare UUID. - Robust fit: compute columns from the viewport's scrollbar-excluded clientWidth (fixes mobile under-fit and desktop overflow); ResizeObserver + font-load refit; full-bleed terminal on mobile. Spawn / empty states - Spawn modal accepts a prefill (clone); real "+ Spawn" buttons in welcome and no-sessions empty states. Dev - New ?kit design-kit page (kit.ts/kit.css, DEV-only) showcasing components. - Richer ?mock fixture with deeper label nesting. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+38
-1
@@ -2,7 +2,20 @@ import { createSession } from "./api.js";
|
||||
import { attachDirAutocomplete } from "./dirAutocomplete.js";
|
||||
import type { CreateSessionRequest, DaemonInfo } from "./types.js";
|
||||
|
||||
export function openSpawnModal(daemons: Map<string, DaemonInfo>): void {
|
||||
/** Seed values for the spawn form — used by "clone" to reopen the dialog with
|
||||
* the same daemon, cwd, command, name, and label as an existing session. */
|
||||
export interface SpawnPrefill {
|
||||
daemon_id?: string;
|
||||
cwd?: string;
|
||||
command?: string;
|
||||
name?: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export function openSpawnModal(
|
||||
daemons: Map<string, DaemonInfo>,
|
||||
prefill?: SpawnPrefill,
|
||||
): void {
|
||||
const existing = document.getElementById("modal-host");
|
||||
if (existing) existing.remove();
|
||||
|
||||
@@ -98,6 +111,30 @@ export function openSpawnModal(daemons: Map<string, DaemonInfo>): void {
|
||||
select.addEventListener("change", applyHomeDir);
|
||||
applyHomeDir();
|
||||
|
||||
// Clone: seed the form from an existing session. cwd is marked edited so the
|
||||
// home-dir sync won't clobber it on daemon change.
|
||||
if (prefill) {
|
||||
(host.querySelector("#spawn-title") as HTMLElement).textContent =
|
||||
"Clone session";
|
||||
const set = (name: string, value: string | undefined) => {
|
||||
if (value == null) return;
|
||||
const field = host.querySelector(
|
||||
`[name=${name}]`,
|
||||
) as HTMLInputElement | HTMLSelectElement | null;
|
||||
if (field) field.value = value;
|
||||
};
|
||||
if (prefill.daemon_id && daemons.has(prefill.daemon_id)) {
|
||||
select.value = prefill.daemon_id;
|
||||
}
|
||||
set("command", prefill.command);
|
||||
set("name", prefill.name);
|
||||
set("label", prefill.label);
|
||||
if (prefill.cwd) {
|
||||
cwdInput.value = prefill.cwd;
|
||||
cwdEdited = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Live directory autocomplete (NAP-329) on the path fields, scoped to the
|
||||
// currently-selected daemon — re-reading `select.value` per query means it
|
||||
// tracks host changes for free.
|
||||
|
||||
Reference in New Issue
Block a user