From 60e46f4eb724b9aa0509d07ceca200a25986d38f Mon Sep 17 00:00:00 2001 From: Clawdy Agent Date: Thu, 21 May 2026 16:07:02 +0100 Subject: [PATCH 1/3] feat(ui): add Simple chat appearance Add a chat-scoped Simple appearance preference that keeps the wider app chrome unchanged while simplifying the conversation view. The UI adds a Default/Simple chat style setting with localized labels, applies data-chat-style=simple through the theme layer, and introduces scoped appearance styles for user bubbles, assistant prose, tool-call pills, inline tool summaries, and simplified tool input/output sections. Simple chat styling is isolated under packages/ui/src/styles/appearance so default chat continues to use the existing presentation. Includes the Simple UI planning document. Validation during the branch included UI typecheck and repeated npm run build:ui runs after the final layout changes. --- docs/features/simple-ui/PLAN.md | 121 +++++++++++ .../settings/appearance-settings-section.tsx | 49 ++++- packages/ui/src/index.css | 2 +- .../ui/src/lib/i18n/messages/en/settings.ts | 6 + .../ui/src/lib/i18n/messages/es/settings.ts | 6 + .../ui/src/lib/i18n/messages/fr/settings.ts | 6 + .../ui/src/lib/i18n/messages/he/settings.ts | 6 + .../ui/src/lib/i18n/messages/ja/settings.ts | 6 + .../ui/src/lib/i18n/messages/ru/settings.ts | 6 + .../src/lib/i18n/messages/zh-Hans/settings.ts | 6 + packages/ui/src/lib/theme.tsx | 15 +- packages/ui/src/stores/preferences.tsx | 15 ++ .../styles/appearance/simple-ui-layout.css | 194 ++++++++++++++++++ .../styles/appearance/simple-ui-tokens.css | 47 +++++ .../ui/src/styles/appearance/simple-ui.css | 2 + 15 files changed, 484 insertions(+), 3 deletions(-) create mode 100644 docs/features/simple-ui/PLAN.md create mode 100644 packages/ui/src/styles/appearance/simple-ui-layout.css create mode 100644 packages/ui/src/styles/appearance/simple-ui-tokens.css create mode 100644 packages/ui/src/styles/appearance/simple-ui.css diff --git a/docs/features/simple-ui/PLAN.md b/docs/features/simple-ui/PLAN.md new file mode 100644 index 000000000..59b518527 --- /dev/null +++ b/docs/features/simple-ui/PLAN.md @@ -0,0 +1,121 @@ +# Simple Chat Appearance Plan + +## Goal + +Add a device-scoped Appearance setting that lets users choose between the current Default chat and a new Simple chat style. Simple should be a CSS-only presentation layer over the chat stream and prompt controls, with calmer tool calls and a materially better mobile chat experience. The only non-CSS product change should be the requested prompt action icon update: send becomes an up arrow, stop remains a stop-square control. + +Prototype asset: `docs/features/simple-ui/simple-ui-prototype.png` + +Prototype source: `docs/features/simple-ui/simple-ui-prototype.svg` + +## Current Code Map + +- Appearance settings live in `packages/ui/src/components/settings/appearance-settings-section.tsx`. +- Device UI preferences live in `packages/ui/src/stores/preferences.tsx` under `UiSettings`, with server config persistence already wired through `useConfig()`. +- Theme application lives in `packages/ui/src/lib/theme.tsx`, which already writes `data-theme` to `document.documentElement`. +- Global CSS enters through `packages/ui/src/index.css`, then `tokens.css`, `utilities.css`, `controls.css`, `messaging.css`, `panels.css`, and `markdown.css`. +- Prompt send and stop controls are in `packages/ui/src/components/prompt-input.tsx`; their styles are in `packages/ui/src/styles/messaging/prompt-input.css`. +- The main chat and prompt area are mostly covered by `packages/ui/src/styles/messaging/message-section.css`, `packages/ui/src/styles/messaging/tool-call.css`, `packages/ui/src/styles/messaging/message-base.css`, and `prompt-input.css`. + +## Product Design Direction + +Scene: a user is running CodeNomad from a phone or narrow browser window while moving between tasks, so the chat should reduce chrome, keep the prompt reachable, and make the latest agent work easier to scan in bright ambient light. + +- Keep the Default UI unchanged for existing users. +- Make Simple a restrained chat skin with plain tool calls, compact borders, larger touch targets, and a single calm blue accent used only for primary send. +- Reduce chat visual clutter by removing heavy tool-call backgrounds where spacing and faint dividers are enough. +- Preserve information density on desktop, but make message groups feel like a readable timeline instead of stacked panels. +- Prioritize mobile chat: tool rows compress to a readable inline summary, and the prompt actions sit in a thumb-friendly bottom rail. +- Avoid adding new behavior, new layout state, or alternate component implementations for Simple. The mode should be reversible by switching the setting back to Default. + +## Appearance Setting UX + +- Add a new card in Appearance above Interaction: `Chat style`. +- Choices: `Default` and `Simple`. +- Scope badge: `Device`, consistent with Theme and Interaction. +- Description copy: `Choose how conversations and prompt controls look on this device.` +- Default choice copy: `Current chat layout and styling.` +- Simple choice copy: `Reduced chat chrome, plain tool calls, and mobile-first prompt controls.` +- Persist as `chatStyle: "default" | "simple"` in `UiSettings`. +- Apply as `data-chat-style="simple"` on `document.documentElement`; remove the attribute for Default or set it to `default` consistently. +- Add i18n keys to every locale file in `packages/ui/src/lib/i18n/messages/*/settings.ts`. If translations are not available, use English placeholders matching the repo's current pattern in several locales. + +## Implementation Plan + +1. Add preference plumbing. + +- Add `export type ChatStylePreference = "default" | "simple"` in `preferences.tsx`. +- Add `chatStyle` to `UiSettings`, `defaultUiSettings`, and `normalizeUiSettings`. +- Expose `setChatStyle` from `useConfig()` using the same `updatePreferences` path as other Appearance settings. +- Keep the default as `default` to avoid behavior changes on upgrade. + +2. Apply the selected style globally. + +- Add a small UI appearance provider or extend `ThemeProvider` to react to `preferences().chatStyle`. +- Set `document.documentElement.dataset.chatStyle = "simple"` when selected. +- Remove the dataset value or set `default` when not selected. +- Keep this separate from `data-theme`; Simple chat must work with `light`, `dark`, and `system` theme modes. + +3. Add Appearance controls. + +- In `appearance-settings-section.tsx`, add a `chatStyleOptions` list and render a `settings-choice-grid` card similar to Theme. +- Reuse existing `settings-choice` styles so the new card does not introduce a separate control vocabulary. +- Use icons already in `lucide-solid`, such as `Laptop` for Default and `Sun` for Simple. + +4. Add Simple chat CSS as scoped overrides. + +- Create new focused files under `packages/ui/src/styles/appearance/`, with `simple-ui.css` as the lean entry import. +- Import it once from `packages/ui/src/index.css` after the existing style entry files so it can override safely. +- Prefix all selectors with `:root[data-chat-style="simple"]` to guarantee Default UI remains unchanged. +- Use existing tokens first. Only add Simple-specific tokens in `tokens.css` if repeated values are needed across more than one area. +- Keep aggregate CSS files lean; do not paste Simple chat rules into `messaging.css`, `controls.css`, or `panels.css`. + +5. Update prompt action icons. + +- In `prompt-input.tsx`, replace the send fallback `▶` with an up-arrow icon or inline SVG. +- Keep shell mode as the terminal-style icon unless product decides shell submit should also use the up arrow. +- Keep the stop control as a square stop icon, but refine its Simple chat CSS to be compact, tactile, and visually distinct from send. +- Update button titles only if current i18n labels say Play instead of Send. + +6. Simple chat CSS scope. + +- Tokens: softer surface stack, lighter borders, subtler shadows, consistent `12px` to `16px` radii, minimum touch target around `44px` on coarse pointers. +- Chat header: reduce hard borders without changing global tab or sidebar chrome. +- Messages: reduce per-message chrome, make tool calls plain with no background fill, keep disclosure/dropdown actions inline, keep metrics as small pills only when enabled. +- Prompt: make the textarea feel like a bottom composer, keep attachments/history secondary, place stop and send as large square buttons in the bottom rail. +- Mobile: use `dvh`, safe-area padding, `@media (max-width: 640px)`, and existing container width state on `.session-center-column`. + +## Simple Chat Prototype Notes + +- The prototype shows the intended result, not final layout code. +- Desktop keeps existing app chrome, with simpler message rows in the working area. +- Mobile keeps existing navigation behavior and presents a focused stream with a sticky composer. +- The send button uses an up arrow. The stop button uses a stop square. + +## Testing Plan + +- Run `npm run typecheck` after preference and component changes. +- Run `npm run build:ui` to catch CSS import and bundling issues. +- Manually verify Default chat before and after toggling Simple. +- Manually verify Simple chat at desktop width, tablet width, and mobile width around 390px. +- Verify the setting persists after reload. +- Verify `light`, `dark`, and `system` theme modes still work with both Interface Style choices. +- Verify keyboard focus remains visible on settings choices, prompt buttons, and inline tool-call controls. +- Verify coarse pointer behavior: prompt buttons are at least 44px and textarea does not trigger iOS input zoom. + +## Risks And Constraints + +- CSS-only Simple chat means structural mobile improvements are limited to what the current DOM can support. +- Some current CSS files are large, so Simple chat should live in scoped files rather than expanding existing monoliths. +- Broad selectors could accidentally affect Default UI. Every Simple selector should be scoped under `:root[data-chat-style="simple"]` and target chat/prompt surfaces only. +- Dark theme needs a separate visual pass because Simple chat's light-first direction should not force light mode. +- The send icon update is a markup change, not CSS. It should be isolated to `prompt-input.tsx`. + +## Acceptance Criteria + +- Appearance has a `Default` vs `Simple` chat style setting. +- Default is selected for existing users and remains visually unchanged. +- Simple chat is activated only through the new data attribute and CSS overrides. +- Simple improves mobile chat readability and thumb reach without removing existing features. +- Prompt send displays an up arrow; stop displays a stop square. +- Prototype PNG exists at `docs/features/simple-ui/simple-ui-prototype.png`. diff --git a/packages/ui/src/components/settings/appearance-settings-section.tsx b/packages/ui/src/components/settings/appearance-settings-section.tsx index 281366d67..c0052bcad 100644 --- a/packages/ui/src/components/settings/appearance-settings-section.tsx +++ b/packages/ui/src/components/settings/appearance-settings-section.tsx @@ -3,7 +3,7 @@ import { createEffect, createMemo, createSignal, For, type Component } from "sol import { Check, ChevronDown, Laptop, Moon, Sun } from "lucide-solid" import { useI18n } from "../../lib/i18n" import { useTheme, type ThemeMode } from "../../lib/theme" -import { useConfig } from "../../stores/preferences" +import { useConfig, type ChatStylePreference } from "../../stores/preferences" import { getBehaviorSettings, type BehaviorSetting } from "../../lib/settings/behavior-registry" const themeModeOptions: Array<{ value: ThemeMode; icon: typeof Laptop }> = [ @@ -12,6 +12,11 @@ const themeModeOptions: Array<{ value: ThemeMode; icon: typeof Laptop }> = [ { value: "dark", icon: Moon }, ] +const chatStyleOptions: Array<{ value: ChatStylePreference; icon: typeof Laptop }> = [ + { value: "default", icon: Laptop }, + { value: "simple", icon: Sun }, +] + export const AppearanceSettingsSection: Component = () => { const { t } = useI18n() const { themeMode, setThemeMode } = useTheme() @@ -31,6 +36,7 @@ export const AppearanceSettingsSection: Component = () => { setDiagnosticsExpansion, setThinkingBlocksExpansion, setToolInputsVisibility, + setChatStyle, } = useConfig() const behaviorSettings = createMemo(() => @@ -220,6 +226,11 @@ export const AppearanceSettingsSection: Component = () => { return t("theme.mode.dark") } + const chatStyleLabel = (style: ChatStylePreference) => { + if (style === "simple") return t("settings.appearance.chatStyle.option.simple.label") + return t("settings.appearance.chatStyle.option.default.label") + } + return (
@@ -256,6 +267,42 @@ export const AppearanceSettingsSection: Component = () => {
+
+
+
+

{t("settings.appearance.chatStyle.title")}

+

{t("settings.appearance.chatStyle.subtitle")}

+
+ {t("settings.scope.device")} +
+
+ {chatStyleOptions.map((option) => { + const Icon = option.icon + return ( + + ) + })} +
+
+
diff --git a/packages/ui/src/index.css b/packages/ui/src/index.css index 21a3e8cb7..b06cc9972 100644 --- a/packages/ui/src/index.css +++ b/packages/ui/src/index.css @@ -4,6 +4,7 @@ @import './styles/messaging.css'; @import './styles/panels.css'; @import './styles/markdown.css'; +@import './styles/appearance/simple-ui.css'; @tailwind base; @tailwind components; @tailwind utilities; @@ -59,6 +60,5 @@ body { - diff --git a/packages/ui/src/lib/i18n/messages/en/settings.ts b/packages/ui/src/lib/i18n/messages/en/settings.ts index 5d5e3b027..b1ed44da8 100644 --- a/packages/ui/src/lib/i18n/messages/en/settings.ts +++ b/packages/ui/src/lib/i18n/messages/en/settings.ts @@ -86,6 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", + "settings.appearance.chatStyle.title": "Chat style", + "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", + "settings.appearance.chatStyle.option.default.label": "Default", + "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.option.simple.label": "Simple", + "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/es/settings.ts b/packages/ui/src/lib/i18n/messages/es/settings.ts index 61360a8bb..a441cd986 100644 --- a/packages/ui/src/lib/i18n/messages/es/settings.ts +++ b/packages/ui/src/lib/i18n/messages/es/settings.ts @@ -86,6 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", + "settings.appearance.chatStyle.title": "Chat style", + "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", + "settings.appearance.chatStyle.option.default.label": "Default", + "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.option.simple.label": "Simple", + "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/fr/settings.ts b/packages/ui/src/lib/i18n/messages/fr/settings.ts index 45e1cf855..01c357f26 100644 --- a/packages/ui/src/lib/i18n/messages/fr/settings.ts +++ b/packages/ui/src/lib/i18n/messages/fr/settings.ts @@ -86,6 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", + "settings.appearance.chatStyle.title": "Chat style", + "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", + "settings.appearance.chatStyle.option.default.label": "Default", + "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.option.simple.label": "Simple", + "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/he/settings.ts b/packages/ui/src/lib/i18n/messages/he/settings.ts index 101385e4a..b84c62ec5 100644 --- a/packages/ui/src/lib/i18n/messages/he/settings.ts +++ b/packages/ui/src/lib/i18n/messages/he/settings.ts @@ -85,6 +85,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "התאם להגדרת מערכת ההפעלה", "settings.appearance.theme.option.light": "השתמש במראה בהיר", "settings.appearance.theme.option.dark": "השתמש במראה כהה", + "settings.appearance.chatStyle.title": "Chat style", + "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", + "settings.appearance.chatStyle.option.default.label": "Default", + "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.option.simple.label": "Simple", + "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", "settings.section.notifications.title": "התראות", "settings.section.notifications.subtitle": "שלוט בהתראות ברמת מערכת ההפעלה עבור פעילות סשן.", "settings.notifications.permission.granted": "ניתן", diff --git a/packages/ui/src/lib/i18n/messages/ja/settings.ts b/packages/ui/src/lib/i18n/messages/ja/settings.ts index 9a871c7ff..5a2d25c89 100644 --- a/packages/ui/src/lib/i18n/messages/ja/settings.ts +++ b/packages/ui/src/lib/i18n/messages/ja/settings.ts @@ -86,6 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", + "settings.appearance.chatStyle.title": "Chat style", + "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", + "settings.appearance.chatStyle.option.default.label": "Default", + "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.option.simple.label": "Simple", + "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/ru/settings.ts b/packages/ui/src/lib/i18n/messages/ru/settings.ts index e43d2fff0..ff1dd50d2 100644 --- a/packages/ui/src/lib/i18n/messages/ru/settings.ts +++ b/packages/ui/src/lib/i18n/messages/ru/settings.ts @@ -86,6 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", + "settings.appearance.chatStyle.title": "Chat style", + "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", + "settings.appearance.chatStyle.option.default.label": "Default", + "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.option.simple.label": "Simple", + "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts b/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts index c8264be98..646e19f3e 100644 --- a/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts +++ b/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts @@ -86,6 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", + "settings.appearance.chatStyle.title": "Chat style", + "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", + "settings.appearance.chatStyle.option.default.label": "Default", + "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.option.simple.label": "Simple", + "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/theme.tsx b/packages/ui/src/lib/theme.tsx index 61ad6e4ff..e51bbcf74 100644 --- a/packages/ui/src/lib/theme.tsx +++ b/packages/ui/src/lib/theme.tsx @@ -23,6 +23,15 @@ function applyThemeMode(mode: ThemeMode) { document.documentElement.setAttribute("data-theme", mode) } +function applyChatStyle(style: string) { + if (typeof document === "undefined") return + if (style === "simple") { + document.documentElement.setAttribute("data-chat-style", "simple") + return + } + document.documentElement.removeAttribute("data-chat-style") +} + interface ResolvedPaletteColors { backgroundDefault: string backgroundPaper: string @@ -78,7 +87,7 @@ const resolvePaletteColors = (dark: boolean): ResolvedPaletteColors => { export function ThemeProvider(props: { children: JSX.Element }) { const mediaQuery = typeof window !== "undefined" ? window.matchMedia("(prefers-color-scheme: dark)") : null - const { themePreference, setThemePreference } = useConfig() + const { preferences, themePreference, setThemePreference } = useConfig() const [isDark, setIsDarkSignal] = createSignal(true) const [themeRevision, setThemeRevision] = createSignal(0) @@ -111,6 +120,10 @@ export function ThemeProvider(props: { children: JSX.Element }) { applyResolvedTheme() }) + createEffect(() => { + applyChatStyle(preferences().chatStyle) + }) + onMount(() => { if (!mediaQuery) return const handleSystemThemeChange = () => { diff --git a/packages/ui/src/stores/preferences.tsx b/packages/ui/src/stores/preferences.tsx index a39b07969..f9b126cf1 100644 --- a/packages/ui/src/stores/preferences.tsx +++ b/packages/ui/src/stores/preferences.tsx @@ -28,6 +28,7 @@ export interface ModelPreference { export type DiffViewMode = "split" | "unified" export type ExpansionPreference = "expanded" | "collapsed" export type ToolInputsVisibilityPreference = "hidden" | "collapsed" | "expanded" +export type ChatStylePreference = "default" | "simple" export type ListeningMode = "local" | "all" export type ServerLogLevel = "DEBUG" | "INFO" | "WARN" | "ERROR" export type SpeechProviderPreference = "openai-compatible" @@ -67,6 +68,7 @@ export interface UiSettings { showUsageMetrics: boolean autoCleanupBlankSessions: boolean keepUnseenSubagentIdleStatus: boolean + chatStyle: ChatStylePreference // OS notifications osNotificationsEnabled: boolean @@ -147,6 +149,7 @@ const defaultUiSettings: UiSettings = { showUsageMetrics: true, autoCleanupBlankSessions: true, keepUnseenSubagentIdleStatus: false, + chatStyle: "default", osNotificationsEnabled: false, osNotificationsAllowWhenVisible: false, @@ -188,6 +191,10 @@ function normalizeUiSettings(input?: Partial | null): UiSettings { autoCleanupBlankSessions: sanitized.autoCleanupBlankSessions ?? defaultUiSettings.autoCleanupBlankSessions, keepUnseenSubagentIdleStatus: sanitized.keepUnseenSubagentIdleStatus ?? defaultUiSettings.keepUnseenSubagentIdleStatus, + chatStyle: + sanitized.chatStyle === "simple" || sanitized.chatStyle === "default" + ? sanitized.chatStyle + : defaultUiSettings.chatStyle, osNotificationsEnabled: sanitized.osNotificationsEnabled ?? defaultUiSettings.osNotificationsEnabled, osNotificationsAllowWhenVisible: sanitized.osNotificationsAllowWhenVisible ?? defaultUiSettings.osNotificationsAllowWhenVisible, @@ -647,6 +654,11 @@ function setToolInputsVisibility(mode: ToolInputsVisibilityPreference): void { updateUiSettings({ toolInputsVisibility: mode }) } +function setChatStyle(style: ChatStylePreference): void { + if (preferences().chatStyle === style) return + updateUiSettings({ chatStyle: style }) +} + function setThinkingBlocksExpansion(mode: ExpansionPreference): void { if (preferences().thinkingBlocksExpansion === mode) return updateUiSettings({ thinkingBlocksExpansion: mode }) @@ -761,6 +773,7 @@ interface ConfigContextValue { setDiagnosticsExpansion: typeof setDiagnosticsExpansion setThinkingBlocksExpansion: typeof setThinkingBlocksExpansion setToolInputsVisibility: typeof setToolInputsVisibility + setChatStyle: typeof setChatStyle // instance scoped setAgentModelPreference: typeof setAgentModelPreference @@ -813,6 +826,7 @@ const configContextValue: ConfigContextValue = { setDiagnosticsExpansion, setThinkingBlocksExpansion, setToolInputsVisibility, + setChatStyle, setAgentModelPreference, getAgentModelPreference, } @@ -893,6 +907,7 @@ export { setToolOutputExpansion, setDiagnosticsExpansion, setThinkingBlocksExpansion, + setChatStyle, setAgentModelPreference, getAgentModelPreference, } diff --git a/packages/ui/src/styles/appearance/simple-ui-layout.css b/packages/ui/src/styles/appearance/simple-ui-layout.css new file mode 100644 index 000000000..9dd873347 --- /dev/null +++ b/packages/ui/src/styles/appearance/simple-ui-layout.css @@ -0,0 +1,194 @@ +:root[data-chat-style="simple"] .connection-status, +:root[data-chat-style="simple"] .prompt-input-container { + border-color: var(--simple-chat-faint-border, var(--border-muted)); +} + +:root[data-chat-style="simple"] .message-stream-block { + gap: 0.35rem; + margin-bottom: 0.5rem; +} + +:root[data-chat-style="simple"] .message-item-base[data-message-role="user"] { + align-self: flex-end; + width: fit-content; + max-width: min(78%, calc(100% - 1rem)); + border: 0; + border-radius: 1.25rem; + background: var(--surface-secondary); + margin-inline-end: 0.5rem; + text-align: start; +} + +:root[data-chat-style="simple"] .message-item-base[data-message-role="assistant"] { + width: auto; + border-inline-start-width: 0; + background: transparent; + color: var(--text-primary); + margin-inline: 0.5rem; +} + +:root[data-chat-style="simple"] .message-item-base[data-message-role="assistant"] .message-speaker-label[data-role="assistant"] { + color: var(--text-primary); + font-weight: var(--font-weight-bold); +} + +:root[data-chat-style="simple"] .message-item-base[data-message-role="assistant"] .message-text { + color: var(--text-primary); + line-height: 1.5; + max-width: 75ch; +} + +:root[data-chat-style="simple"] .message-item-base[data-message-role="user"] .message-item-header-row { + justify-content: flex-end; +} + +:root[data-chat-style="simple"] .message-item-base[data-message-role="user"] .message-header-left, +:root[data-chat-style="simple"] .message-item-base[data-message-role="user"] .message-item-actions, +:root[data-chat-style="simple"] .message-item-base[data-message-role="user"] .message-attachments { + justify-content: flex-end; +} + +:root[data-chat-style="simple"] .message-step-start, +:root[data-chat-style="simple"] .message-step-finish, +:root[data-chat-style="simple"] .message-reasoning-card, +:root[data-chat-style="simple"] .tool-call-message { + border-inline-start-width: 0; + border-radius: 0; + margin-inline: 0.5rem; + background: transparent; +} + +:root[data-chat-style="simple"] .tool-call-message { + width: auto; + padding-block: 0.35rem; + margin-inline: 0.5rem 1rem; +} + +:root[data-chat-style="simple"] .tool-call-message .delete-hover-scope { + display: flex; + align-items: center; + border: 1px solid var(--simple-chat-faint-border, var(--border-muted)); + border-radius: 0.75rem; + background: var(--surface-base); + margin-inline-end: 0.75rem; + overflow: hidden; + min-width: 0; +} + +:root[data-chat-style="simple"] .tool-call-header-label { + justify-content: space-between; + flex-wrap: nowrap; + flex: 0 0 auto; + gap: 0.45rem 0.6rem; + padding: 0.35rem 0 0.35rem 0.55rem; +} + +:root[data-chat-style="simple"] .tool-call-header-meta, +:root[data-chat-style="simple"] .tool-call-header-actions { + display: inline-flex; + align-items: center; +} + +:root[data-chat-style="simple"] .tool-call-header-meta { + min-width: 0; +} + +:root[data-chat-style="simple"] .tool-call-header-actions { + flex: 0 0 auto; +} + +:root[data-chat-style="simple"] .tool-call-header-label .tool-name { + background: transparent; +} + +:root[data-chat-style="simple"] .tool-call-header-meta > span:not(.tool-call-icon):not(.tool-name) { + display: none; +} + +:root[data-chat-style="simple"] .tool-call, +:root[data-chat-style="simple"] .message-reasoning-output, +:root[data-chat-style="simple"] .message-text pre { + border-radius: 0.75rem; +} + +:root[data-chat-style="simple"] .tool-call { + border: 0; + background: transparent; + flex: 1 1 auto; + min-width: 0; +} + +:root[data-chat-style="simple"] .tool-call-header-toggle { + padding: 0.4rem 0.55rem; +} + +:root[data-chat-style="simple"] .tool-call-header { + border-bottom: 0; +} + +:root[data-chat-style="simple"] .tool-call-summary { + color: var(--text-muted); +} + +:root[data-chat-style="simple"] .tool-call-preview, +:root[data-chat-style="simple"] .tool-call-details, +:root[data-chat-style="simple"] .tool-call-diagnostics-section, +:root[data-chat-style="simple"] .tool-call-task-section { + border-top: 0; + border-bottom: 0; +} + +:root[data-chat-style="simple"] .tool-call-io-section, +:root[data-chat-style="simple"] .tool-call-markdown, +:root[data-chat-style="simple"] .tool-call-markdown .markdown-code-block, +:root[data-chat-style="simple"] .tool-call-markdown .tool-call-content { + border: 0; +} + +:root[data-chat-style="simple"] .tool-call-io-toggle, +:root[data-chat-style="simple"] .tool-call-io-body, +:root[data-chat-style="simple"] .tool-call-markdown, +:root[data-chat-style="simple"] .tool-call-diff-viewer, +:root[data-chat-style="simple"] .tool-call-diff-fallback { + background: transparent; +} + +:root[data-chat-style="simple"] .tool-call-io-toggle { + border-bottom: 0; + padding-inline: 0; +} + +:root[data-chat-style="simple"] .prompt-input-wrapper { + grid-template-columns: minmax(0, 1fr) 70px 58px; +} + +:root[data-chat-style="simple"] .prompt-input { + border: 0; + background-color: var(--surface-base); +} + +:root[data-chat-style="simple"] .prompt-expand-button, +:root[data-chat-style="simple"] .prompt-history-button, +:root[data-chat-style="simple"] .prompt-attach-button, +:root[data-chat-style="simple"] .prompt-clear-button, +:root[data-chat-style="simple"] .stop-button, +:root[data-chat-style="simple"] .send-button { + border-radius: 0.875rem; +} + +@media (max-width: 640px) { + :root[data-chat-style="simple"] .connection-status { + padding: 0.7rem 0.85rem; + } + + :root[data-chat-style="simple"] .prompt-input-wrapper { + grid-template-columns: minmax(0, 1fr) auto; + padding-bottom: max(0.35rem, env(safe-area-inset-bottom)); + } + + :root[data-chat-style="simple"] .send-button, + :root[data-chat-style="simple"] .stop-button { + width: 2.75rem; + height: 2.75rem; + } +} diff --git a/packages/ui/src/styles/appearance/simple-ui-tokens.css b/packages/ui/src/styles/appearance/simple-ui-tokens.css new file mode 100644 index 000000000..20c8c9c01 --- /dev/null +++ b/packages/ui/src/styles/appearance/simple-ui-tokens.css @@ -0,0 +1,47 @@ +:root[data-chat-style="simple"] .message-stream-container, +:root[data-chat-style="simple"] .prompt-input-container { + --simple-chat-surface: oklch(98.8% 0.006 247); + --simple-chat-muted-surface: oklch(96.5% 0.01 247); + --simple-chat-soft-border: oklch(88% 0.02 247); + --simple-chat-faint-border: oklch(92% 0.012 247); + --simple-chat-code-surface: oklch(95.2% 0.012 247); + --message-tool-bg: transparent; + --message-tool-border: var(--simple-chat-soft-border); + --message-assistant-bg: transparent; + --message-assistant-border: oklch(68% 0.12 76); + --message-user-bg: transparent; + --message-user-border: var(--accent-primary); + --surface-code: var(--simple-chat-code-surface); + --button-danger-bg: oklch(74% 0.14 24); + --button-danger-hover-bg: oklch(69% 0.16 24); +} + +@media (prefers-color-scheme: dark) { + :root[data-chat-style="simple"]:not([data-theme]) .message-stream-container, + :root[data-chat-style="simple"]:not([data-theme]) .prompt-input-container { + --simple-chat-surface: oklch(19% 0.018 252); + --simple-chat-muted-surface: oklch(23% 0.02 252); + --simple-chat-soft-border: oklch(34% 0.025 252); + --simple-chat-faint-border: oklch(29% 0.02 252); + --simple-chat-code-surface: oklch(17% 0.018 252); + --message-tool-bg: transparent; + --message-assistant-bg: transparent; + --message-user-bg: transparent; + --button-danger-bg: oklch(62% 0.16 24); + --button-danger-hover-bg: oklch(67% 0.16 24); + } +} + +:root[data-chat-style="simple"][data-theme="dark"] .message-stream-container, +:root[data-chat-style="simple"][data-theme="dark"] .prompt-input-container { + --simple-chat-surface: oklch(19% 0.018 252); + --simple-chat-muted-surface: oklch(23% 0.02 252); + --simple-chat-soft-border: oklch(34% 0.025 252); + --simple-chat-faint-border: oklch(29% 0.02 252); + --simple-chat-code-surface: oklch(17% 0.018 252); + --message-tool-bg: transparent; + --message-assistant-bg: transparent; + --message-user-bg: transparent; + --button-danger-bg: oklch(62% 0.16 24); + --button-danger-hover-bg: oklch(67% 0.16 24); +} diff --git a/packages/ui/src/styles/appearance/simple-ui.css b/packages/ui/src/styles/appearance/simple-ui.css new file mode 100644 index 000000000..b8df8d4c6 --- /dev/null +++ b/packages/ui/src/styles/appearance/simple-ui.css @@ -0,0 +1,2 @@ +@import "./simple-ui-tokens.css"; +@import "./simple-ui-layout.css"; From 203897b864c25f4804730ab5b00da3a5c9434f72 Mon Sep 17 00:00:00 2001 From: Clawdy Agent Date: Thu, 21 May 2026 19:29:56 +0100 Subject: [PATCH 2/3] fix(i18n): translate Simple chat settings Localize the new Appearance chat style labels and descriptions for Spanish, French, Hebrew, Japanese, Russian, and Simplified Chinese so the Simple chat option does not fall back to English in supported locales. This only updates message catalog entries; English remains the source text and the custom i18n merge/typecheck path verifies the locale files still compile. Validation: npm run typecheck --workspace @codenomad/ui; npm run build:ui --- packages/ui/src/lib/i18n/messages/es/settings.ts | 10 +++++----- packages/ui/src/lib/i18n/messages/fr/settings.ts | 10 +++++----- packages/ui/src/lib/i18n/messages/he/settings.ts | 12 ++++++------ packages/ui/src/lib/i18n/messages/ja/settings.ts | 12 ++++++------ packages/ui/src/lib/i18n/messages/ru/settings.ts | 12 ++++++------ .../ui/src/lib/i18n/messages/zh-Hans/settings.ts | 12 ++++++------ 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/packages/ui/src/lib/i18n/messages/es/settings.ts b/packages/ui/src/lib/i18n/messages/es/settings.ts index a441cd986..cd6bcae7c 100644 --- a/packages/ui/src/lib/i18n/messages/es/settings.ts +++ b/packages/ui/src/lib/i18n/messages/es/settings.ts @@ -86,12 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", - "settings.appearance.chatStyle.title": "Chat style", - "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", - "settings.appearance.chatStyle.option.default.label": "Default", - "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.title": "Estilo del chat", + "settings.appearance.chatStyle.subtitle": "Elige cómo se ven las conversaciones y los controles del prompt en este dispositivo.", + "settings.appearance.chatStyle.option.default.label": "Predeterminado", + "settings.appearance.chatStyle.option.default.description": "Diseño y estilo actuales del chat.", "settings.appearance.chatStyle.option.simple.label": "Simple", - "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", + "settings.appearance.chatStyle.option.simple.description": "Menos elementos visuales en el chat, llamadas a herramientas sencillas y controles del prompt pensados para móvil.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/fr/settings.ts b/packages/ui/src/lib/i18n/messages/fr/settings.ts index 01c357f26..d35c9d29f 100644 --- a/packages/ui/src/lib/i18n/messages/fr/settings.ts +++ b/packages/ui/src/lib/i18n/messages/fr/settings.ts @@ -86,12 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", - "settings.appearance.chatStyle.title": "Chat style", - "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", - "settings.appearance.chatStyle.option.default.label": "Default", - "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", + "settings.appearance.chatStyle.title": "Style du chat", + "settings.appearance.chatStyle.subtitle": "Choisissez l'apparence des conversations et des contrôles du prompt sur cet appareil.", + "settings.appearance.chatStyle.option.default.label": "Par défaut", + "settings.appearance.chatStyle.option.default.description": "Mise en page et style actuels du chat.", "settings.appearance.chatStyle.option.simple.label": "Simple", - "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", + "settings.appearance.chatStyle.option.simple.description": "Interface de chat allégée, appels d'outils simples et contrôles du prompt adaptés au mobile.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/he/settings.ts b/packages/ui/src/lib/i18n/messages/he/settings.ts index b84c62ec5..b84b2b6db 100644 --- a/packages/ui/src/lib/i18n/messages/he/settings.ts +++ b/packages/ui/src/lib/i18n/messages/he/settings.ts @@ -85,12 +85,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "התאם להגדרת מערכת ההפעלה", "settings.appearance.theme.option.light": "השתמש במראה בהיר", "settings.appearance.theme.option.dark": "השתמש במראה כהה", - "settings.appearance.chatStyle.title": "Chat style", - "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", - "settings.appearance.chatStyle.option.default.label": "Default", - "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", - "settings.appearance.chatStyle.option.simple.label": "Simple", - "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", + "settings.appearance.chatStyle.title": "סגנון צ'אט", + "settings.appearance.chatStyle.subtitle": "בחרו איך שיחות ופקדי הפרומפט ייראו במכשיר הזה.", + "settings.appearance.chatStyle.option.default.label": "ברירת מחדל", + "settings.appearance.chatStyle.option.default.description": "פריסת הצ'אט והעיצוב הנוכחיים.", + "settings.appearance.chatStyle.option.simple.label": "פשוט", + "settings.appearance.chatStyle.option.simple.description": "פחות מעטפת חזותית בצ'אט, קריאות כלים פשוטות ופקדי פרומפט שמותאמים קודם כל למובייל.", "settings.section.notifications.title": "התראות", "settings.section.notifications.subtitle": "שלוט בהתראות ברמת מערכת ההפעלה עבור פעילות סשן.", "settings.notifications.permission.granted": "ניתן", diff --git a/packages/ui/src/lib/i18n/messages/ja/settings.ts b/packages/ui/src/lib/i18n/messages/ja/settings.ts index 5a2d25c89..a0109c926 100644 --- a/packages/ui/src/lib/i18n/messages/ja/settings.ts +++ b/packages/ui/src/lib/i18n/messages/ja/settings.ts @@ -86,12 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", - "settings.appearance.chatStyle.title": "Chat style", - "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", - "settings.appearance.chatStyle.option.default.label": "Default", - "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", - "settings.appearance.chatStyle.option.simple.label": "Simple", - "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", + "settings.appearance.chatStyle.title": "チャットスタイル", + "settings.appearance.chatStyle.subtitle": "このデバイスでの会話とプロンプト操作の見た目を選択します。", + "settings.appearance.chatStyle.option.default.label": "デフォルト", + "settings.appearance.chatStyle.option.default.description": "現在のチャットレイアウトとスタイル。", + "settings.appearance.chatStyle.option.simple.label": "シンプル", + "settings.appearance.chatStyle.option.simple.description": "チャットの装飾を減らし、ツール呼び出しを簡素にし、モバイル優先のプロンプト操作にします。", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/ru/settings.ts b/packages/ui/src/lib/i18n/messages/ru/settings.ts index ff1dd50d2..b970d8c64 100644 --- a/packages/ui/src/lib/i18n/messages/ru/settings.ts +++ b/packages/ui/src/lib/i18n/messages/ru/settings.ts @@ -86,12 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", - "settings.appearance.chatStyle.title": "Chat style", - "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", - "settings.appearance.chatStyle.option.default.label": "Default", - "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", - "settings.appearance.chatStyle.option.simple.label": "Simple", - "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", + "settings.appearance.chatStyle.title": "Стиль чата", + "settings.appearance.chatStyle.subtitle": "Выберите, как будут выглядеть беседы и элементы управления промптом на этом устройстве.", + "settings.appearance.chatStyle.option.default.label": "По умолчанию", + "settings.appearance.chatStyle.option.default.description": "Текущая компоновка и оформление чата.", + "settings.appearance.chatStyle.option.simple.label": "Простой", + "settings.appearance.chatStyle.option.simple.description": "Меньше визуальных элементов в чате, простые вызовы инструментов и элементы управления промптом с учетом мобильных устройств.", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", diff --git a/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts b/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts index 646e19f3e..0f226ec41 100644 --- a/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts +++ b/packages/ui/src/lib/i18n/messages/zh-Hans/settings.ts @@ -86,12 +86,12 @@ export const settingsMessages = { "settings.appearance.theme.option.system": "Match your operating system setting", "settings.appearance.theme.option.light": "Use the light appearance", "settings.appearance.theme.option.dark": "Use the dark appearance", - "settings.appearance.chatStyle.title": "Chat style", - "settings.appearance.chatStyle.subtitle": "Choose how conversations and prompt controls look on this device.", - "settings.appearance.chatStyle.option.default.label": "Default", - "settings.appearance.chatStyle.option.default.description": "Current chat layout and styling.", - "settings.appearance.chatStyle.option.simple.label": "Simple", - "settings.appearance.chatStyle.option.simple.description": "Reduced chat chrome, plain tool calls, and mobile-first prompt controls.", + "settings.appearance.chatStyle.title": "聊天样式", + "settings.appearance.chatStyle.subtitle": "选择此设备上对话和提示词控件的显示方式。", + "settings.appearance.chatStyle.option.default.label": "默认", + "settings.appearance.chatStyle.option.default.description": "当前聊天布局和样式。", + "settings.appearance.chatStyle.option.simple.label": "简洁", + "settings.appearance.chatStyle.option.simple.description": "减少聊天界面装饰,简化工具调用,并使用移动优先的提示词控件。", "settings.section.notifications.title": "Notifications", "settings.section.notifications.subtitle": "Control OS-level notifications for session activity.", "settings.notifications.permission.granted": "Granted", From b10b8bbcf13a207540c59ff26490059d68c131cd Mon Sep 17 00:00:00 2001 From: Clawdy Agent Date: Tue, 26 May 2026 21:04:59 +0100 Subject: [PATCH 3/3] docs(ui): align Simple chat plan with implementation Remove stale prototype asset references and the unimplemented prompt send up-arrow requirement from the Simple chat plan so the documented scope matches the CSS-only implementation in the PR. The feature intentionally leaves prompt-input markup unchanged; Simple prompt presentation remains handled through scoped CSS. Validation: documentation-only change; reviewed PLAN.md references for prototype and up-arrow requirements. --- docs/features/simple-ui/PLAN.md | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/docs/features/simple-ui/PLAN.md b/docs/features/simple-ui/PLAN.md index 59b518527..ebaefdb4f 100644 --- a/docs/features/simple-ui/PLAN.md +++ b/docs/features/simple-ui/PLAN.md @@ -2,11 +2,7 @@ ## Goal -Add a device-scoped Appearance setting that lets users choose between the current Default chat and a new Simple chat style. Simple should be a CSS-only presentation layer over the chat stream and prompt controls, with calmer tool calls and a materially better mobile chat experience. The only non-CSS product change should be the requested prompt action icon update: send becomes an up arrow, stop remains a stop-square control. - -Prototype asset: `docs/features/simple-ui/simple-ui-prototype.png` - -Prototype source: `docs/features/simple-ui/simple-ui-prototype.svg` +Add a device-scoped Appearance setting that lets users choose between the current Default chat and a new Simple chat style. Simple should be a CSS-only presentation layer over the chat stream and prompt controls, with calmer tool calls and a materially better mobile chat experience. ## Current Code Map @@ -70,12 +66,11 @@ Scene: a user is running CodeNomad from a phone or narrow browser window while m - Use existing tokens first. Only add Simple-specific tokens in `tokens.css` if repeated values are needed across more than one area. - Keep aggregate CSS files lean; do not paste Simple chat rules into `messaging.css`, `controls.css`, or `panels.css`. -5. Update prompt action icons. +5. Refine prompt action presentation. -- In `prompt-input.tsx`, replace the send fallback `▶` with an up-arrow icon or inline SVG. -- Keep shell mode as the terminal-style icon unless product decides shell submit should also use the up arrow. -- Keep the stop control as a square stop icon, but refine its Simple chat CSS to be compact, tactile, and visually distinct from send. -- Update button titles only if current i18n labels say Play instead of Send. +- Keep existing prompt send and stop behavior unchanged. +- Use Simple chat CSS to make prompt actions compact, tactile, and visually distinct. +- Keep button titles and existing i18n labels unchanged unless product copy changes. 6. Simple chat CSS scope. @@ -85,12 +80,10 @@ Scene: a user is running CodeNomad from a phone or narrow browser window while m - Prompt: make the textarea feel like a bottom composer, keep attachments/history secondary, place stop and send as large square buttons in the bottom rail. - Mobile: use `dvh`, safe-area padding, `@media (max-width: 640px)`, and existing container width state on `.session-center-column`. -## Simple Chat Prototype Notes +## Simple Chat Design Notes -- The prototype shows the intended result, not final layout code. - Desktop keeps existing app chrome, with simpler message rows in the working area. - Mobile keeps existing navigation behavior and presents a focused stream with a sticky composer. -- The send button uses an up arrow. The stop button uses a stop square. ## Testing Plan @@ -109,7 +102,7 @@ Scene: a user is running CodeNomad from a phone or narrow browser window while m - Some current CSS files are large, so Simple chat should live in scoped files rather than expanding existing monoliths. - Broad selectors could accidentally affect Default UI. Every Simple selector should be scoped under `:root[data-chat-style="simple"]` and target chat/prompt surfaces only. - Dark theme needs a separate visual pass because Simple chat's light-first direction should not force light mode. -- The send icon update is a markup change, not CSS. It should be isolated to `prompt-input.tsx`. +- CSS-only Simple chat means prompt icon changes are out of scope unless product explicitly requests a separate markup update. ## Acceptance Criteria @@ -117,5 +110,3 @@ Scene: a user is running CodeNomad from a phone or narrow browser window while m - Default is selected for existing users and remains visually unchanged. - Simple chat is activated only through the new data attribute and CSS overrides. - Simple improves mobile chat readability and thumb reach without removing existing features. -- Prompt send displays an up arrow; stop displays a stop square. -- Prototype PNG exists at `docs/features/simple-ui/simple-ui-prototype.png`.