Fix stale PWA service worker after updates; collapsible task list; short screens
Installed apps checked their service worker at /sw-<old build>.js. That file no longer exists after an update and the static fallback answered with index.html, so the update check failed and the old worker kept serving the previous app shell. The old frontend crashed on the new image references (base64Size of a missing `data`), leaving a blank page on phones. Old service worker URLs now get the clean-up worker (/sw.js), which unregisters and reloads; missing scripts and styles answer 404 instead of HTML. - Task list above the composer folds to one line (progress, current task), remembered per device. - max-height: 560px layout (square phones such as the Clicks Communicator, landscape): tighter top bar, composer and new-chat wizard. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b1fa54a7b6
commit
d7f89ee257
6 files changed
+232
-8
No files matched your search
@@ -7,9 +7,9 @@ import { useModels } from "../hooks";
|
||||
import { fmtCompact, fmtCost, fmtNumber, fmtPercent, useT, type Key } from "../i18n";
|
||||
import { navigate } from "../router";
|
||||
import { dismissError, loadSession, loadSessions, useStore } from "../store";
|
||||
import type { Aggregate, ImageData, Message, Part, Session } from "../types";
|
||||
import type { Aggregate, ImageData, Message, Part, Session, Todo } from "../types";
|
||||
import { ActivityLine, Dots, Spinner, ThinkIcon, WorkBar } from "./Activity";
|
||||
import { useReasoningMode } from "../prefs";
|
||||
import { useReasoningMode, useTodosCollapsed } from "../prefs";
|
||||
import { Composer } from "./Composer";
|
||||
import { ShareDialog } from "./ShareDialog";
|
||||
import { RenameDialog } from "./RenameDialog";
|
||||
@@ -503,10 +503,7 @@ export function ChatView({ sessionId, onMenu, onClosePane }: { sessionId: string
|
||||
<ActivityLine sessionId={sessionId} draft={draft} pendingTool={pendingTool} waiting={waiting} permissionPending={permissions.length > 0 || questions.length > 0} />
|
||||
)}
|
||||
{openTodos.length > 0 && (busy || permissions.length > 0 || questions.length > 0) && (
|
||||
<div className="todos">
|
||||
<div style={{ color: "var(--muted)", fontSize: 12 }}>{t("tool.todos")}</div>
|
||||
<TodoList todos={todos} />
|
||||
</div>
|
||||
<TodoPanel todos={todos} />
|
||||
)}
|
||||
{permissions.map((p) => (
|
||||
<PermissionCard key={p.id} req={p} currentId={sessionId} />
|
||||
@@ -633,3 +630,24 @@ function PhaseBar({ phase, deep }: { phase?: string; deep: boolean }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** Tasks of the model above the composer; folds to one line (current task, progress). */
|
||||
function TodoPanel({ todos }: { todos: Todo[] }) {
|
||||
const t = useT();
|
||||
const [collapsed, setCollapsed] = useTodosCollapsed();
|
||||
const done = todos.filter((x) => x.status === "completed").length;
|
||||
const current = todos.find((x) => x.status === "in_progress");
|
||||
return (
|
||||
<div className={`todos ${collapsed ? "collapsed" : ""}`}>
|
||||
<button className="todos-head" onClick={() => setCollapsed(!collapsed)} aria-expanded={!collapsed}>
|
||||
<Icon name={collapsed ? "chevron-right" : "chevron-down"} />
|
||||
<span>{t("tool.todos")}</span>
|
||||
<span className="todos-count">
|
||||
{done}/{todos.length}
|
||||
</span>
|
||||
{collapsed && current && <span className="todos-current">{current.content}</span>}
|
||||
</button>
|
||||
{!collapsed && <TodoList todos={todos} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user