Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions docs/UI_MODERNIZATION_AUDIT.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Cortex UI modernization audit

**Status:** UI modernization implementation complete for this slice; dedicated image-editor affordances removed; native package rebuilt and startup-verified
**Status:** UI modernization follow-up complete; dedicated image-editor affordances and preset prompt cards removed; native package rebuilt and startup-verified
**Scope:** Every user-facing frontend surface, not a cosmetic theme pass

## What was audited
Expand All @@ -18,7 +18,7 @@ primary problems were structural:
| Area | Finding | Modernization outcome |
| --- | --- | --- |
| Workspace shell | The top bar conveyed almost no context and the sidebar was a loose list of text. | A clear workspace header, local-runtime status, product identity, conversation count, and a deliberate sidebar footer establish hierarchy. |
| Conversation canvas | A new chat opened into a large, empty dark region. | A compact new-thread orientation gives the canvas a clear starting point without turning it into a marketing screen. |
| Conversation canvas | A new chat opened into a large, empty dark region, then introduced generic preset prompts. | A quiet new-thread orientation gives the canvas context while leaving the user in control of the first message. |
| Composer | The input was visually stranded in a full-width bottom strip. | The composer is now a centered, elevated input island with integrated local-model context, state feedback, and responsive sizing. |
| Conversation controls | Saved chats, rename, and delete controls had weak grouping and feedback. | The list uses active/hover/focus states, reveal-on-focus actions, and purposeful confirmation dialogs. |
| Settings and submenus | Settings read as a large collection of unrelated boxes. | Text-led categories, descriptive labels, and a unified detail pane make settings read like a native control surface. |
Expand Down Expand Up @@ -53,7 +53,8 @@ opaque background service.
runtime state, conversation navigation, and better destructive-action dialogs.
- `frontend/src/components/ChatPage.tsx` adds the intentional blank-chat launch
surface and docks the composer as part of the conversation canvas. It does
not advertise image transformation or image generation.
not advertise image transformation, image generation, or preset prompt
suggestions.
- `frontend/src/components/MessageComposer.tsx` integrates local-model context
into the composer island.
- `frontend/src/components/SettingsPanel.tsx` turns settings into a structured
Expand All @@ -77,7 +78,7 @@ This slice passed the release checks: 44 component tests in a single worker,
6 browser-level flows, typecheck, lint, production build, a fresh Windows
package build, and a packaged launch with `GET /api/v1/health/ready` returning
HTTP 200. The production bundle contains no dedicated image-transform UI
labels or selectors.
labels or selectors, and no preset starter-card selectors or labels.

During the audit, the existing packaged executable exposed a separate native
startup defect: Uvicorn's default console formatter dereferenced `sys.stderr`
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/ChatPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,14 @@ function renderChat(api: CortexApi, threadId = "thread-a") {
describe("ChatPage composer integration", () => {
afterEach(() => window.sessionStorage.clear());

it("turns a blank conversation into a useful starting surface", async () => {
const user = userEvent.setup();
it("keeps a blank conversation free of preset prompt suggestions", async () => {
renderChat(chatApi());

await screen.findByRole("heading", { name: "New thread" });
await user.click(screen.getByRole("button", { name: /Think through a decision/i }));

expect(screen.getByLabelText("Message Cortex")).toHaveValue("Help me think through a decision step by step.");
expect(screen.queryByText("Think through a decision")).not.toBeInTheDocument();
expect(screen.queryByText("Check a calculation")).not.toBeInTheDocument();
expect(screen.getByLabelText("Message Cortex")).toHaveValue("");
});

it("retains the exact draft if generation acceptance fails", async () => {
Expand Down
10 changes: 0 additions & 10 deletions frontend/src/components/ChatPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -391,16 +391,6 @@ export function ChatPage({
<p>
Ask a question or check a calculation using the model on this device.
</p>
<div className="chat-starter-list">
<button type="button" onClick={() => updateDraft("Help me think through a decision step by step.")}>
<span className="chat-starter-index" aria-hidden="true">01</span>
<span><strong>Think through a decision</strong><small>Turn a rough idea into a clear plan.</small></span>
</button>
<button type="button" onClick={() => updateDraft("Calculate and explain: ")}>
<span className="chat-starter-index" aria-hidden="true">02</span>
<span><strong>Check a calculation</strong><small>Work through a result with local computation.</small></span>
</button>
</div>
{selectedModel && <span className="chat-welcome-model">{selectedModel}</span>}
</section>
)}
Expand Down
9 changes: 0 additions & 9 deletions frontend/src/styles/tokens.css
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,6 @@ a { color: inherit; text-decoration: none; }
.chat-welcome-mark { display: none; }
.chat-welcome h1 { max-width: 560px; margin: 0; color: var(--text); font-size: clamp(1.35rem, 2vw, 1.65rem); font-weight: 650; letter-spacing: -0.04em; line-height: 1.15; }
.chat-welcome > p:not(.eyebrow) { max-width: 500px; margin: 11px 0 23px; color: var(--text-muted); font-size: 0.86rem; line-height: 1.65; }
.chat-starter-list { display: grid; width: min(100%, 580px); border-top: 1px solid var(--line); text-align: left; }
.chat-starter-list button { display: grid; grid-template-columns: 34px minmax(0, 1fr); align-items: start; min-height: 65px; gap: 9px; border: 0; border-bottom: 1px solid var(--line); padding: 13px 3px; background: transparent; color: var(--text-muted); text-align: left; transition: background 150ms ease, color 150ms ease; }
.chat-starter-list button:hover { background: var(--surface-soft); color: var(--text); }
.chat-starter-list button > span:not(.chat-starter-index) { display: grid; gap: 3px; min-width: 0; }
.chat-starter-index { color: var(--accent); font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; font-size: 0.65rem; line-height: 1.6; }
.chat-starter-list strong { color: var(--text); font-size: 0.78rem; font-weight: 660; }
.chat-starter-list small { color: var(--text-muted); font-size: 0.71rem; line-height: 1.45; }
.chat-welcome-model { margin-top: 14px; color: var(--text-faint); font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace; font-size: 0.67rem; }

.message-card { display: flex; flex-direction: column; width: min(100%, 760px); max-width: 100%; }
Expand Down Expand Up @@ -481,8 +474,6 @@ input[type="range"] { width: 100%; accent-color: var(--accent); }

@media (max-width: 920px) {
.runtime-status { display: none; }
.chat-starter-list { max-width: 100%; }
.chat-starter-list button { min-height: 64px; }
.settings-dialog { width: min(100%, 860px); }
.settings-dialog-body { grid-template-columns: 190px minmax(0, 1fr); }
}
Expand Down
Loading