Add Web Push, guided start screen, SVG icons, chunked uploads, rename

- Web Push (VAPID + RFC 8291, pure Rust): permission/question/finished
  notifications while no app window is visible; settings with test button
- Guided new-session flow: task, craft target (website/app/game/old
  software/fresh), clean room or deep, description, model, folder
  (new, existing or cloned git repository); originals upload to original/
- Craft phase bar (craft_phase tool) for study/specify/build/check/ready
- Chunked uploads (8 MB) up to server.max_upload_mb (default 500 MB)
- All UI glyphs and emojis replaced by themeable SVG icons
- Rename dialog with manual name or model-generated suggestion

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-08 21:03:26 +01:00
1 parent 013695722a
commit a0d0e707f2
48 files changed
+2724 -228

No files matched your search

+6 -5
View File
@@ -1,3 +1,4 @@
import { Icon } from "./Icon";
import { useEffect } from "react";
import { useFetch, useModels } from "../hooks";
import { fmtCompact, fmtCost, fmtDate, fmtNumber, fmtPercent, useT } from "../i18n";
@@ -64,7 +65,7 @@ export function UsageOverlay({ session, onClose }: { session: Session; onClose:
<h3 style={{ margin: 0 }}>{t("usage.title")}</h3>
<span className="spacer" />
<button className="small ghost" onClick={onClose} aria-label={t("common.close")}>
✕
<Icon name="close" />
</button>
</div>
{!data ? (
@@ -85,7 +86,7 @@ export function UsageOverlay({ session, onClose }: { session: Session; onClose:
<div className="kpi">
<div className="k-label">{t("stats.tokens")}</div>
<div className="k-value">
{fmtCompact(data.total.input_tokens + data.total.cache_read_tokens + data.total.cache_write_tokens)}↑ {fmtCompact(data.total.output_tokens)}↓
{fmtCompact(data.total.input_tokens + data.total.cache_read_tokens + data.total.cache_write_tokens)}<Icon name="arrow-up" className="tiny" /> {fmtCompact(data.total.output_tokens)}<Icon name="arrow-down" className="tiny" />
</div>
<div className="k-sub">
{t("stats.cacheHit")}: {fmtPercent(data.total.cache_hit_rate)}
@@ -96,7 +97,7 @@ export function UsageOverlay({ session, onClose }: { session: Session; onClose:
<div className="k-value" style={{ fontSize: 15 }}>
{data.first ? fmtDate(data.first) : "–"}
</div>
<div className="k-sub">{data.last ? `→ ${fmtDate(data.last)}` : ""}</div>
<div className="k-sub">{data.last ? <><Icon name="chevron-right" className="tiny" /> {fmtDate(data.last)}</> : ""}</div>
</div>
</div>
@@ -118,8 +119,8 @@ export function UsageOverlay({ session, onClose }: { session: Session; onClose:
<Row label="ID" value={<code>{m.model}</code>} />
<Row label={t("settings.context")} value={mi?.context ? `${fmtCompact(mi.context)} tok` : "–"} />
<Row label={t("settings.maxOutput")} value={mi?.max_output ? `${fmtCompact(mi.max_output)} tok` : "–"} />
<Row label={t("settings.reasoning")} value={mi?.reasoning ? `✓${mi.effort ? ` (${mi.effort})` : ""}` : "–"} />
<Row label={t("settings.vision")} value={mi?.vision ? "✓" : "–"} />
<Row label={t("settings.reasoning")} value={mi?.reasoning ? <><Icon name="check" />{mi.effort ? ` (${mi.effort})` : ""}</> : "–"} />
<Row label={t("settings.vision")} value={mi?.vision ? <Icon name="check" /> : "–"} />
{isCurrent && mi?.context ? (
<Row label={t("usage.contextNow")} value={`${fmtCompact(ctxTokens)} / ${fmtCompact(mi.context)} (${fmtPercent(ctxTokens / mi.context)})`} />
) : null}