feat(ui): Appearance settings — dark/light/system mode and named themes; fix Add lane silently doing nothing (#42)

- Settings → Appearance: mode Dark / Light / System (follows the OS live) and
  a named theme remembered per mode — dark: Default, Darcula, Apple Dark;
  light: Default, Apple Light, IntelliJ Light, Canvas. Each theme is a
  CSS-variable override block keyed by `data-theme` on <html>; the sidebar
  quick toggle gains System and swaps between the two remembered themes.
- An inline boot script in index.html applies the stored mode and theme
  before first paint, so a reload no longer flashes the default colours.
- Diff +/- rows are easier to tell apart on every theme: a /20 status tint,
  a 3px status bar and a bold coloured marker; the changed-span emphasis no
  longer vanishes on light themes.
- #42: the Add-lane modal (Repo mode / "Current branch") asks
  POST /api/lanes/ensure with `exact: true`. Without it a folder nested inside
  an existing lane resolved to that parent lane with created:false, so the
  modal closed and no new card appeared. When the folder really already has a
  lane, the modal now says which one instead of closing.

Closes #42
This commit is contained in:
2026-09-24 09:44:42 +07:00
parent 2ea2184372
commit 6cf8a82889
33 changed files with 1756 additions and 59 deletions
+5
View File
@@ -59,6 +59,7 @@ import { useEffect, useState, useCallback, useRef, useSyncExternalStore, Fragmen
import { useTranslation } from "react-i18next";
import {
DollarSign,
Palette,
Plus,
Pencil,
Trash2,
@@ -118,6 +119,7 @@ import { ImportHistory } from "../components/ImportHistory";
import { RemoteSources } from "../components/RemoteSources";
import { Skeleton } from "../components/Skeleton";
import { AlertsNotifications } from "../components/AlertsNotifications";
import { AppearanceSettings } from "../components/settings/AppearanceSettings";
import type { ModelPricing, WSMessage } from "../lib/types";
// In-page navigation for the (dense) Settings screen. Each entry maps to a
@@ -128,6 +130,7 @@ const SETTINGS_SECTIONS: {
fallback?: string;
Icon: typeof DollarSign;
}[] = [
{ id: "appearance", labelKey: "appearance.title", Icon: Palette },
{ id: "pricing", labelKey: "pricing.title", Icon: DollarSign },
{ id: "hooks", labelKey: "hooks.title", Icon: Plug },
{ id: "lanes", labelKey: "lanesSection.title", Icon: GitBranch },
@@ -1080,6 +1083,8 @@ export function Settings() {
</div>
</div>
<AppearanceSettings />
{/* ─── MODEL PRICING ─── */}
<section id="pricing" className="scroll-mt-24">
<div className="flex flex-wrap items-center justify-between gap-3 mb-4">