Skip to content

Give LocalKit a face: monogram tiles, a Home screen, a live rail, and a light theme - #5

Merged
jhd3197 merged 13 commits into
mainfrom
dev
Jul 22, 2026
Merged

Give LocalKit a face: monogram tiles, a Home screen, a live rail, and a light theme#5
jhd3197 merged 13 commits into
mainfrom
dev

Conversation

@jhd3197

@jhd3197 jhd3197 commented Jul 22, 2026

Copy link
Copy Markdown
Owner

LocalKit spent its whole life as a wall of text pills, and it was starting to look like a database admin panel that wandered into the wrong app. This pass (plans 27 and 28) gives every site a face, adds a proper landing screen you walk up to and glance at, moves navigation into a live rail that answers "is anything running?" without a click, and — because not everyone codes in the dark — ships a light theme.

Highlights

  • Every site now has a deterministic monogram tile — a colored square with its initials that stays the same everywhere (rail, dashboard, list, detail). Running sites glow; stopped ones keep their color but dim down, so identity survives even while the site sleeps.
  • A new Home screen is the landing page: a plain-language status headline ("All 4 sites are running."), the full wall of site tiles, a "needs attention" list for anything half-created or unhealthy, an environment readout (Docker, local domains, ServerKit, blueprints), and quick actions.
  • The sidebar became a live control rail — it lists every site with its tile and a status dot, and the active site expands into its detail tabs. Collapse it to a tile-only strip; the choice sticks between launches.
  • Light theme. A toggle under Settings → Appearance flips the entire palette (dark keeps the navy control-room look; light is for bright rooms). It applies instantly and there's no flash on the next launch.
  • Real brand logos for WordPress, Docker, and PHP replace the old text badges, stamped on the corner of each site's tile and shown inline in the list.
  • Site detail is now tabbed — Overview, Tools, Snapshots, and Logs — and each tab is deep-linkable straight from the rail. Snapshots and logs got their own roomier homes instead of being stacked at the bottom of one long page.
  • Dashboard cards got icon-only action buttons (with tooltips), a subtle lift on hover, and a friendlier empty state that invites your first site instead of just saying "No sites yet."
  • Action buttons throughout gained icons (Start, Stop, Clone, Delete, Open…), and Copy buttons now flash a checkmark when they've copied.
Technical changes

Theme / token layer (plan 28)

  • src/index.css gains a CSS-variable token layer: the zinc ramp is defined as RGB triplets on :root, with a :root[data-theme="light"] override that inverts the values while keeping the semantic roles stable (950 = page, 900 = surface, 800/700 = borders, 600/500 = dim/muted text, 50 = strongest text).
  • tailwind.config.js remaps every zinc-* color to rgb(var(--c-zinc-*) / <alpha-value>), so all existing zinc-* classes become theme-aware with no call-site edits.
  • src/stores/settings.ts adds Theme, getTheme() (non-hook read), applyTheme() (stamps data-theme on <html>), and the useTheme() hook; plus useRailCollapsed() for the sidebar state. Both persist in the settings KV.
  • src/main.tsx calls applyTheme(getTheme()) before first render to avoid a flash.
  • src/pages/Settings.tsx adds an Appearance section (ThemeSection) with a Dark/Light segmented toggle; a couple of literal text-white headings switched to text-zinc-50.
  • New .bg-blueprint utility (faint accent-tinted grid) applied to the main content pane in App.tsx.
  • New --tile-dim-bg-l / --tile-dim-fg-l tokens drive the dimmed-tile lightness so stopped tiles read correctly in both themes; --scrollbar-thumb* and --grid-line are tokenized too.

Site tiles + brand marks (plans 27/28)

  • New src/components/SiteTile.tsx: hueFromSlug() (FNV-1a hash of the slug, folded to a hue — survives renames), initials(), and the tile itself. Running/degraded sites render saturated with a same-hue glow; others dim via the theme tokens. Optional kind prop stamps the brand mark on the corner. creating sites pulse.
  • New src/lib/brandIcons.tsx: offline Iconify wrapper (@iconify/react/offline) that renders curated icon data only — no network name lookups ever reach api.iconify.design. BrandIcon returns null for unknown keys so callers can fall back; kindIcon() maps a site kind to a simple-icons name (WordPress is the default/fallback).
  • New src/lib/brandIconData.ts (auto-generated) + scripts/gen-brand-icons.mjs: extracts a curated subset (wordpress, docker, php, laravel, mariadb) from @iconify-json/simple-icons via @iconify/utils, trims default transform fields, and writes ~1 KB of committed icon data. Run with npm run gen:brand-icons. simple-icons is CC0-1.0.
  • src/components/KindBadge.tsx rewritten around a META map; adds the PHP kind (indigo) and renders the real brand glyph beside the label.
  • src/components/icons.tsx fully replaced: the hand-rolled SVGs are gone, replaced by thin wrap(LucideIcon) wrappers over lucide-react, preserving the old export names and the h-4 w-4 default so no call site changed. Adds the new glyphs the redesign needs (Home, Layers, Camera, Play, Square, Wrench, Trash, Bookmark, chevrons, etc.).

Home screen (plan 28)

  • New src/pages/Home.tsx: status headline derived from running/total counts, tile wall (WallTile), Needs attention section (incomplete / degraded / error sites), Environment card (EnvRow for Docker, local domains, ServerKit, blueprints), and a Quick actions grid. Reads existing stores only; refreshes ServerKit connections and blueprints on mount.
  • src/stores/nav.ts adds the { name: "home" } page and a SiteTab type (overview | tools | snapshots | logs); site pages carry an optional tab. Home is now the default landing page (was sites).
  • src/App.tsx routes the home page and threads tab into SiteDetail.
  • src/lib/commands.tsx adds a go-home command bound to mod+0.

Live rail (plan 28)

  • src/components/Sidebar.tsx largely rewritten: Home/Sites/Terminal nav with icons; a "running" count pill on Sites; a scrollable live list of every site (RailSite) showing tile + name + status dot; the active site expands its detail tabs (subTabs(), capability-gated on db_gui/search_replace/wp_tools/snapshots). Collapsible to a 60px tile-only strip via useRailCollapsed(), with the collapse/expand and settings controls in the footer. When collapsed and Docker is down, an amber dot rides the gear button.

Site detail (plan 28)

  • src/pages/SiteDetail.tsx: the tab is now sourced from the nav store (navTab) instead of local state, so the rail can deep-link into it; setTab navigates. Tabs expanded to Overview / Tools / Snapshots / Logs — Snapshots and Logs are now their own tabs (Logs stays mounted via a hidden wrapper so auto-scroll/polling survive switches; log pane taller at 28rem). Header gains a large monogram tile; section headings use the new SectionTitle; action buttons gained icons and a shared headerGhostBtn class.
  • New src/components/SectionTitle.tsx: iconed h2 whose textContent is unchanged (icon is aria-hidden), so the screenshot script and text-matching tests still work.

Dashboard (plans 27/28)

  • src/pages/Dashboard.tsx: cards and rows render SiteTile; the two views share a single SiteActions component (icon-only buttons — iconBtn/openIconBtn/dangerIconBtn — so grid and list never drift). New illustrated empty state; hover lift + shadow-panel on cards; stackLabel() handles the PHP kind (PHP <version> with no WP); list rows show the inline brand glyph instead of a text pill.
  • src/components/CopyButton.tsx: icon + emerald checkmark on copy.

Docs / tooling

  • scripts/capture-screenshots.mjs: captures in the light theme (plants the localStorage key before load); adds element-crop shots (shotElement), toast clearing, direct-dispatch clicks by aria-label / table row (survive overlays), and new captures for Home, Tools tab, Snapshots panel, and the remote-import dialog.
  • docs/screenshots/*: regenerated all shots in the light theme; added home.png, import-site.png, site-tools.png, snapshots.png. docs/screenshots/CAPTURE.md updated to match.
  • README.md and the docs/README.{es,pt,zh-CN}.md locales: refreshed the screenshots section (new grid, new captions, Tools / Snapshots / Import rows).
  • New plan docs docs/plans/27_visual-identity-pass.md and docs/plans/28_control-room.md; both rows marked shipped in docs/plans/ROADMAP.md.
  • package.json: adds lucide-react and @iconify/react (deps), @iconify-json/simple-icons and @iconify/utils (devDeps, generator-only), and the gen:brand-icons script.

jhd3197 and others added 12 commits July 21, 2026 21:09
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
icons.tsx becomes thin lucide-react wrappers (same names, same h-4 w-4
default). Real WordPress/Docker/PHP logos via a curated simple-icons
subset baked offline by scripts/gen-brand-icons.mjs (Faro plan-14
pattern) — zero icon network calls. KindBadge shows the brand mark and
gains a PHP variant (php sites previously mislabeled "WP"). CopyButton
gets copy/check glyphs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SiteTile hashes a stable hue from the slug — saturated + glow when up,
dimmed same-hue when stopped, pulse while creating. Grid cards lead
with the tile, hero violet Open, iconed actions (Clone/Delete icon-only
so the row never wraps), hover lift behind motion-reduce. List rows get
small tiles; sidebar gets a Layers icon + live running-count pill; the
empty state becomes a tile illustration + invitation. stackLabel now
renders the php kind as "PHP x.y" instead of an empty "WP · PHP".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Large SiteTile beside the h1, icons on every header action, and a
shared SectionTitle (aria-hidden leading icon, so text-matching tests
and the screenshot script are unaffected) across the detail sections
and the Snapshots / Sync / Tools panels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Untracked captures (import-site, site-tools, snapshots) and the README
refresh remain uncommitted — they belong to the in-progress docs work.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Capture script gains toast dismissal before every shot, element-crop
captures (shotElement), and three new pages: import-site, site-tools,
snapshots. All PNGs regenerated against the plan-27 UI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The zinc ramp resolves to CSS variables (dark keeps the exact navy
palette; light inverts the values, not the semantics) — the token layer
the ROADMAP said a light theme needed. Titles move text-white ->
text-zinc-50 so they flip; solid accent buttons keep literal white.
Settings -> General gains an Appearance toggle; main.tsx stamps
data-theme pre-render. Blueprint-grid utility (ServerKit squares) and
theme-aware scrollbars + dimmed-tile lightness included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SiteTile gains the Faro corner stamp — the real WordPress/Docker/PHP
mark on a chip riding the tile. Kind pills leave the cards (the stamp
carries it; list rows show the bare brand glyph). Card and row actions
go icon-only with tooltips + aria-labels; "Resume setup" keeps its
label. New rail icons: House, ChevronsLeft/Right.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Home is the new landing page: status headline, glowing tile wall,
needs-attention list, environment card, quick actions — all from
existing stores. The sidebar becomes a collapsible rail (persisted via
railCollapsed) listing every site with tile + status dot; the active
site expands sub-links into the detail tabs. SiteDetail splits into
Overview | Tools | Snapshots | Logs with the tab in the nav store so
the rail deep-links. Blueprint-grid background on the content pane;
mod+0 "Go to Home" palette command.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Captures now run in the light theme and start with home.png; the
snapshots capture clicks its new tab. Dark spot-checked separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Expand the screenshot grid from 4 to 6 panels, adding Tools, Snapshots, Import, and ServerKit screenshots. Updates captions to reflect multi-stack support (WordPress, PHP, Docker). Applied consistently across EN, ES, PT, and ZH-CN READMEs.
Copilot AI review requested due to automatic review settings July 22, 2026 01:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR delivers the “plans 27/28” frontend redesign for LocalKit: a more visual, glanceable UI with deterministic site identity tiles, a new Home landing screen, a live/collapsible sidebar rail, and a theme-token layer enabling an instant light theme across the app.

Changes:

  • Introduces a CSS-variable token layer for the zinc ramp and wires up a persisted Light/Dark theme toggle (applied pre-render to prevent flashing).
  • Adds new navigational structure: Home as the default landing page, tabbed Site Detail deep-linking, and a live collapsible site rail in the sidebar.
  • Replaces/extends UI presentation with monogram SiteTiles, lucide-based icon wrappers, offline brand glyphs (Iconify), refreshed dashboard actions, and updated docs/screenshot tooling.

Reviewed changes

Copilot reviewed 43 out of 56 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tailwind.config.js Remaps zinc-* colors to CSS-variable tokens so existing Tailwind classes become theme-aware.
src/stores/settings.ts Adds persisted theme + rail-collapse settings helpers and applyTheme()/useTheme() APIs.
src/stores/nav.ts Adds home page and optional tab deep-linking for site detail.
src/pages/Terminal.tsx Adjusts active tab text color to use theme-aware zinc token.
src/pages/SiteDetail.tsx Converts detail view to nav-driven tabs (overview/tools/snapshots/logs) and updates header/actions styling with icons and SiteTile.
src/pages/Settings.tsx Adds an Appearance section with Dark/Light segmented toggle; updates headings to zinc tokens.
src/pages/Home.tsx New Home landing page: headline, site tile wall, attention list, environment card, and quick actions.
src/pages/Dashboard.tsx Updates dashboard card/list rendering to use SiteTile + icon-only actions and refreshed empty state.
src/main.tsx Applies theme to <html> before first render to avoid theme flash.
src/lib/commands.tsx Adds a “Go to Home” command bound to mod+0.
src/lib/brandIcons.tsx Adds offline brand icon rendering (Iconify offline) + kind-to-icon mapping helpers.
src/lib/brandIconData.ts Adds committed curated icon data payload for offline brand marks (generated).
src/index.css Adds theme token layer + light theme overrides + blueprint-grid utility + tokenized scrollbar colors.
src/components/SnapshotsPanel.tsx Switches panel heading to shared SectionTitle with an icon.
src/components/SiteTile.tsx New deterministic monogram tile component (slug-hashed hue, initials, status styling, optional brand stamp).
src/components/Sidebar.tsx Replaces sidebar with collapsible live rail: Home/Sites/Terminal + per-site tile list with status dots and tab deep-links.
src/components/ServerKitSettings.tsx Updates connection label styling to theme-aware zinc tokens.
src/components/SectionTitle.tsx New shared iconed h2 header component used across panels.
src/components/SearchReplacePanel.tsx Switches section heading to SectionTitle and keeps “view snapshots” hook wiring.
src/components/SaveBlueprintDialog.tsx Updates dialog heading text color to zinc token.
src/components/PushPanel.tsx Switches panel heading to SectionTitle with a sync icon.
src/components/NewSiteDialog.tsx Updates dialog heading text color to zinc token.
src/components/KindBadge.tsx Reworks kind badge to use offline brand glyphs and adds PHP-specific styling/labeling.
src/components/KeyboardShortcutsDialog.tsx Updates heading color to theme-aware zinc token.
src/components/ImportSiteDialog.tsx Updates dialog heading color to theme-aware zinc token.
src/components/icons.tsx Replaces hand-rolled SVGs with lucide-react wrappers while preserving prior export names/default sizing.
src/components/DeleteSiteDialog.tsx Updates dialog heading color to theme-aware zinc token.
src/components/DebugPanel.tsx Switches panel heading to SectionTitle with an icon.
src/components/DatabasePanel.tsx Switches panel heading to SectionTitle with an icon.
src/components/CopyButton.tsx Adds icon + copied state visuals (checkmark) and transitions.
src/components/ConfigEditorPanel.tsx Switches panel heading to SectionTitle with an icon.
src/components/CloneSiteDialog.tsx Updates dialog heading color to theme-aware zinc token.
src/App.tsx Routes the new Home page and adds the blueprint-grid background to the non-terminal content pane.
scripts/gen-brand-icons.mjs Adds generator for curated offline brand icon data file.
scripts/capture-screenshots.mjs Updates screenshot automation: light theme, toast clearing, element crops, and new capture paths.
README.md Refreshes screenshot grid/captions to match new UI and adds new shot slots (Tools/Snapshots/Import).
package.json Adds icon dependencies and the gen:brand-icons script.
package-lock.json Locks new dependencies introduced by icon tooling.
docs/screenshots/CAPTURE.md Updates screenshot inventory and descriptions to match new capture script outputs.
docs/README.zh-CN.md Updates localized screenshots section to reflect new screenshot set and captions.
docs/README.pt.md Updates localized screenshots section to reflect new screenshot set and captions.
docs/README.es.md Updates localized screenshots section to reflect new screenshot set and captions.
docs/plans/ROADMAP.md Marks plans 27 and 28 shipped and adds summary rows.
docs/plans/28_control-room.md Adds shipped plan doc describing the control-room redesign and verification steps.
docs/plans/27_visual-identity-pass.md Adds shipped plan doc describing the visual identity pass and verification steps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +231 to +239
<button
onClick={() => onOpen()}
title={site.name}
className={`flex justify-center rounded-lg p-1.5 transition-colors ${
active ? "bg-zinc-800" : "hover:bg-zinc-900"
}`}
>
<SiteTile name={site.name} slug={site.slug} status={site.live_status} size="sm" />
</button>
Comment thread src/lib/brandIcons.tsx
Comment on lines +48 to +58
return (
<Icon
icon={data}
width={size}
height={size}
className={className}
role={title ? "img" : undefined}
aria-label={title}
aria-hidden={title ? undefined : true}
/>
);
Comment thread src/pages/Home.tsx
<h2 className="text-sm font-semibold uppercase tracking-wide text-zinc-500">
Environment
</h2>
<dl className="mt-3 space-y-2.5 text-sm">
Comment thread src/pages/Home.tsx
: "save a site as a blueprint to reuse its stack"
}
/>
</dl>
The test was racy: it dropped ephemeral listeners and immediately probed the ports, but a concurrent test could grab those ports before the probe finished. Now retries up to 5 times with fresh ports, treating a transient false-positive as a fluke rather than a failure.
@jhd3197
jhd3197 merged commit 4901bb0 into main Jul 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants