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:
@@ -45,7 +45,7 @@ function Code({ text, lang, emph }: { text: string; lang: string; emph?: [number
|
||||
return (
|
||||
<>
|
||||
<Code text={text.slice(0, from)} lang={lang} />
|
||||
<span className="rounded-sm bg-white/15">
|
||||
<span className="rounded-sm bg-fg-primary/15">
|
||||
<Code text={text.slice(from, to)} lang={lang} />
|
||||
</span>
|
||||
<Code text={text.slice(to)} lang={lang} />
|
||||
@@ -120,12 +120,21 @@ function Row({ tint, children }: { tint: string; children: React.ReactNode }) {
|
||||
return <div className={`flex w-max min-w-full ${tint}`}>{children}</div>;
|
||||
}
|
||||
|
||||
/** A /20 fill plus a 3px status bar at the row's left edge, so +/- rows still
|
||||
* separate from context at a glance on every theme (the /10 fill alone did not). */
|
||||
function rowTint(type: LaneDiffLine["type"] | null) {
|
||||
if (type === "add") return "bg-status-success/10";
|
||||
if (type === "del") return "bg-status-danger/10";
|
||||
if (type === "add")
|
||||
return "bg-status-success/20 shadow-[inset_3px_0_0_rgb(var(--status-success))]";
|
||||
if (type === "del") return "bg-status-danger/20 shadow-[inset_3px_0_0_rgb(var(--status-danger))]";
|
||||
return "";
|
||||
}
|
||||
|
||||
function markerClass(type: LaneDiffLine["type"]) {
|
||||
if (type === "add") return "font-bold text-status-success";
|
||||
if (type === "del") return "font-bold text-status-danger";
|
||||
return "text-fg-muted";
|
||||
}
|
||||
|
||||
function HunkHeader({ hunk }: { hunk: LaneDiffHunk }) {
|
||||
const at = hunk.header.split("@@")[1];
|
||||
return (
|
||||
@@ -153,7 +162,7 @@ function UnifiedHunk({ hunk, lang }: { hunk: LaneDiffHunk; lang: string }) {
|
||||
<Gutter n={line.oldLine} />
|
||||
<Gutter n={line.newLine} />
|
||||
<span className="whitespace-pre px-2">
|
||||
<span className="select-none text-fg-muted">
|
||||
<span className={`select-none ${markerClass(line.type)}`}>
|
||||
{line.type === "add" ? "+" : line.type === "del" ? "-" : " "}
|
||||
</span>
|
||||
<Code text={line.text} lang={lang} emph={emph.get(i)} />
|
||||
|
||||
Reference in New Issue
Block a user