diff --git a/clients/web/.storybook/preview.tsx b/clients/web/.storybook/preview.tsx index 7c856228..29527c4b 100644 --- a/clients/web/.storybook/preview.tsx +++ b/clients/web/.storybook/preview.tsx @@ -1,5 +1,5 @@ import type { Preview } from '@storybook/react-vite' -import { MantineProvider, useMantineColorScheme } from '@mantine/core' +import { MantineProvider, useMantineColorScheme, type CSSVariablesResolver } from '@mantine/core' import { Notifications } from '@mantine/notifications' import '@mantine/core/styles.css' import '@mantine/notifications/styles.css' @@ -24,6 +24,14 @@ function ColorSchemeWrapper({ return <>{children} } +const resolver: CSSVariablesResolver = () => ({ + variables: {}, + light: {}, + dark: { + '--mantine-color-body': 'var(--mantine-color-dark-9)', + }, +}) + const preview: Preview = { globalTypes: { colorScheme: { @@ -46,7 +54,7 @@ const preview: Preview = { (Story, context) => { const isFullscreen = context.parameters?.layout === 'fullscreen' return ( - + {isFullscreen ? ( diff --git a/clients/web/src/App.css b/clients/web/src/App.css index 48acfc34..5a0a75f2 100644 --- a/clients/web/src/App.css +++ b/clients/web/src/App.css @@ -26,6 +26,9 @@ --inspector-surface-card: var(--mantine-color-gray-0); --inspector-surface-code: var(--mantine-color-white); + /* ── Inputs ────────────────────────────────────────────── */ + --inspector-input-background: var(--mantine-color-white); + /* ── Borders ───────────────────────────────────────────── */ --inspector-border-default: var(--mantine-color-default-border); --inspector-border-subtle: var(--mantine-color-gray-3); @@ -71,7 +74,8 @@ [data-mantine-color-scheme="dark"] { --inspector-surface-card: var(--mantine-color-gray-9); --inspector-surface-code: var(--mantine-color-dark-9); - --inspector-border-subtle: var(--mantine-color-dark-4); + --inspector-border-subtle: var(--mantine-color-gray-4); + --inspector-input-background: var(--mantine-color-dark-9); } /* ── Animations ──────────────────────────────────────────── */ @@ -112,7 +116,33 @@ } [data-mantine-color-scheme="dark"] .list-item:hover { - background-color: var(--mantine-color-dark-5); + background-color: var(--mantine-primary-color-light); +} + +/* ── Select dropdown / option (dark mode) ──────────────────────── */ + +[data-mantine-color-scheme="dark"] .mantine-Select-dropdown { + background-color: var(--mantine-color-gray-8); +} + +[data-mantine-color-scheme="dark"] .mantine-Select-option:hover { + background-color: var(--mantine-primary-color-light); +} + +[data-mantine-color-scheme="dark"] .mantine-Select-option:hover { + background-color: var(--mantine-primary-color-light); +} + +/* ── Segmented control label (dark mode) ──────────────────────── */ + +[data-mantine-color-scheme="dark"] .mantine-SegmentedControl-indicator { + background-color: var(--mantine-primary-color-light); +} + +/* ── Accordion button hover ─────────────────────────────── */ + +[data-mantine-color-scheme="dark"] .mantine-Accordion-control:hover { + background-color: var(--mantine-primary-color-filled-hover); } /* ── Grid alignment ─────────────────────────────────────── */ diff --git a/clients/web/src/components/elements/CopyButton/CopyButton.tsx b/clients/web/src/components/elements/CopyButton/CopyButton.tsx index 487cab9f..98f27549 100644 --- a/clients/web/src/components/elements/CopyButton/CopyButton.tsx +++ b/clients/web/src/components/elements/CopyButton/CopyButton.tsx @@ -15,8 +15,9 @@ export function CopyButton({ value }: CopyButtonProps) { {copied ? "\u2713" : "\u2398"} diff --git a/clients/web/src/components/elements/ListChangedIndicator/ListChangedIndicator.tsx b/clients/web/src/components/elements/ListChangedIndicator/ListChangedIndicator.tsx index a9704b11..1f3365b4 100644 --- a/clients/web/src/components/elements/ListChangedIndicator/ListChangedIndicator.tsx +++ b/clients/web/src/components/elements/ListChangedIndicator/ListChangedIndicator.tsx @@ -19,7 +19,7 @@ const UpdateLabel = Text.withProps({ const RefreshButton = Button.withProps({ size: "sm", - variant: "light", + variant: "subtle", }); export function ListChangedIndicator({ diff --git a/clients/web/src/components/elements/ListToggle/ListToggle.tsx b/clients/web/src/components/elements/ListToggle/ListToggle.tsx index 27964ddd..7d4ec106 100644 --- a/clients/web/src/components/elements/ListToggle/ListToggle.tsx +++ b/clients/web/src/components/elements/ListToggle/ListToggle.tsx @@ -23,7 +23,7 @@ export function ListToggle({ } return ( - ); diff --git a/clients/web/src/components/groups/HistoryListPanel/HistoryListPanel.tsx b/clients/web/src/components/groups/HistoryListPanel/HistoryListPanel.tsx index e0094a9a..0940a35d 100644 --- a/clients/web/src/components/groups/HistoryListPanel/HistoryListPanel.tsx +++ b/clients/web/src/components/groups/HistoryListPanel/HistoryListPanel.tsx @@ -22,7 +22,7 @@ export interface HistoryRequestsPanelProps { } const ToolbarButton = Button.withProps({ - variant: "light", + variant: "subtle", size: "sm", }); @@ -96,7 +96,6 @@ export function HistoryListPanel({ Requests Export JSON - Clear All {hasResults && ( 0 && ( <> - - {formatHistoryTitle(filteredEntries.length)} - + + + {formatHistoryTitle(filteredEntries.length)} + + Clear + {filteredEntries.map((entry) => ( {LOG_LEVELS.map((level) => { const style = LEVEL_COLORS[level]; - const active = !!visibleLevels[level]; + const active = visibleLevels[level]; return ( - setOpenSections(allExpanded ? [] : [...allSections])} - /> setSearchText(e.currentTarget.value)} /> + setOpenSections(allExpanded ? [] : [...allSections])} + /> diff --git a/clients/web/src/components/groups/TaskControls/TaskControls.stories.tsx b/clients/web/src/components/groups/TaskControls/TaskControls.stories.tsx index bb14e11b..83aae64b 100644 --- a/clients/web/src/components/groups/TaskControls/TaskControls.stories.tsx +++ b/clients/web/src/components/groups/TaskControls/TaskControls.stories.tsx @@ -10,7 +10,6 @@ const meta: Meta = { onSearchChange: fn(), onStatusFilterChange: fn(), onRefresh: fn(), - onClearHistory: fn(), }, }; diff --git a/clients/web/src/components/groups/TaskControls/TaskControls.tsx b/clients/web/src/components/groups/TaskControls/TaskControls.tsx index c6939fa2..9bff8aa4 100644 --- a/clients/web/src/components/groups/TaskControls/TaskControls.tsx +++ b/clients/web/src/components/groups/TaskControls/TaskControls.tsx @@ -10,7 +10,7 @@ const STATUS_OPTIONS: TaskStatus[] = [ ]; const ToolbarButton = Button.withProps({ - variant: "light", + variant: "subtle", size: "sm", }); @@ -20,7 +20,6 @@ export interface TaskControlsProps { onSearchChange: (text: string) => void; onStatusFilterChange: (status: string) => void; onRefresh: () => void; - onClearHistory: () => void; } export function TaskControls({ @@ -29,12 +28,13 @@ export function TaskControls({ onSearchChange, onStatusFilterChange, onRefresh, - onClearHistory, }: TaskControlsProps) { return ( - Tasks - + + Tasks + Refresh + Search onStatusFilterChange(value ?? "")} clearable /> - - - Refresh - Clear History - ); } diff --git a/clients/web/src/components/groups/TaskListPanel/TaskListPanel.stories.tsx b/clients/web/src/components/groups/TaskListPanel/TaskListPanel.stories.tsx index 6ed15198..b516b9d2 100644 --- a/clients/web/src/components/groups/TaskListPanel/TaskListPanel.stories.tsx +++ b/clients/web/src/components/groups/TaskListPanel/TaskListPanel.stories.tsx @@ -61,6 +61,7 @@ const meta: Meta = { args: { tasks: sampleTasks, searchText: "", + onClearCompleted: fn(), }, }; diff --git a/clients/web/src/components/groups/TaskListPanel/TaskListPanel.tsx b/clients/web/src/components/groups/TaskListPanel/TaskListPanel.tsx index 15e6d290..57dcad0b 100644 --- a/clients/web/src/components/groups/TaskListPanel/TaskListPanel.tsx +++ b/clients/web/src/components/groups/TaskListPanel/TaskListPanel.tsx @@ -1,5 +1,13 @@ import { useMemo, useState } from "react"; -import { Group, Paper, ScrollArea, Stack, Text, Title } from "@mantine/core"; +import { + Button, + Group, + Paper, + ScrollArea, + Stack, + Text, + Title, +} from "@mantine/core"; import { TaskCard } from "../TaskCard/TaskCard"; import { ListToggle } from "../../elements/ListToggle/ListToggle"; import type { TaskCardProps } from "../TaskCard/TaskCard"; @@ -8,6 +16,7 @@ export interface TaskListPanelProps { tasks: TaskCardProps[]; searchText: string; statusFilter?: string; + onClearCompleted: () => void; } const PanelContainer = Paper.withProps({ @@ -17,6 +26,11 @@ const PanelContainer = Paper.withProps({ variant: "panel", }); +const ClearHistoryButton = Button.withProps({ + variant: "subtle", + size: "sm", +}); + const EmptyState = Text.withProps({ c: "dimmed", ta: "center", @@ -58,6 +72,7 @@ export function TaskListPanel({ tasks, searchText, statusFilter, + onClearCompleted, }: TaskListPanelProps) { const [compact, setCompact] = useState(false); @@ -110,9 +125,14 @@ export function TaskListPanel({ {completedTasks.length > 0 && ( <> - - {formatCompletedTitle(completedTasks.length)} - + + + {formatCompletedTitle(completedTasks.length)} + + + Clear + + {completedTasks.map((task) => ( - + {selectedPrompt ? ( <> @@ -108,7 +109,7 @@ export function PromptsScreen({ Select a prompt to view details )} - + ); diff --git a/clients/web/src/components/screens/TasksScreen/TasksScreen.stories.tsx b/clients/web/src/components/screens/TasksScreen/TasksScreen.stories.tsx index 189f9667..40085855 100644 --- a/clients/web/src/components/screens/TasksScreen/TasksScreen.stories.tsx +++ b/clients/web/src/components/screens/TasksScreen/TasksScreen.stories.tsx @@ -9,7 +9,7 @@ const meta: Meta = { parameters: { layout: "fullscreen" }, args: { onRefresh: fn(), - onClearHistory: fn(), + onClearCompleted: fn(), }, }; diff --git a/clients/web/src/components/screens/TasksScreen/TasksScreen.tsx b/clients/web/src/components/screens/TasksScreen/TasksScreen.tsx index 700365b5..fd7b4417 100644 --- a/clients/web/src/components/screens/TasksScreen/TasksScreen.tsx +++ b/clients/web/src/components/screens/TasksScreen/TasksScreen.tsx @@ -7,7 +7,7 @@ import type { TaskCardProps } from "../../groups/TaskCard/TaskCard"; export interface TasksScreenProps { tasks: TaskCardProps[]; onRefresh: () => void; - onClearHistory: () => void; + onClearCompleted: () => void; } const ScreenLayout = Flex.withProps({ @@ -30,7 +30,7 @@ const SidebarCard = Card.withProps({ export function TasksScreen({ tasks, onRefresh, - onClearHistory, + onClearCompleted, }: TasksScreenProps) { const [searchText, setSearchText] = useState(""); const [statusFilter, setStatusFilter] = useState(); @@ -47,7 +47,6 @@ export function TasksScreen({ setStatusFilter(value || undefined) } onRefresh={onRefresh} - onClearHistory={onClearHistory} /> @@ -55,6 +54,7 @@ export function TasksScreen({ tasks={tasks} searchText={searchText} statusFilter={statusFilter} + onClearCompleted={onClearCompleted} /> ); diff --git a/clients/web/src/components/views/ConnectedView/ConnectedView.stories.tsx b/clients/web/src/components/views/ConnectedView/ConnectedView.stories.tsx index c18dcb76..d5f6dcde 100644 --- a/clients/web/src/components/views/ConnectedView/ConnectedView.stories.tsx +++ b/clients/web/src/components/views/ConnectedView/ConnectedView.stories.tsx @@ -762,7 +762,7 @@ export const TasksActive: Story = { }, ]} onRefresh={fn()} - onClearHistory={fn()} + onClearCompleted={fn()} /> ), }, diff --git a/clients/web/src/main.tsx b/clients/web/src/main.tsx index 29a1d867..63c99077 100644 --- a/clients/web/src/main.tsx +++ b/clients/web/src/main.tsx @@ -1,6 +1,6 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; -import { MantineProvider } from "@mantine/core"; +import { MantineProvider, type CSSVariablesResolver } from "@mantine/core"; import { Notifications } from "@mantine/notifications"; import "@mantine/core/styles.css"; import "@mantine/notifications/styles.css"; @@ -8,9 +8,21 @@ import "./App.css"; import { theme } from "./theme/theme"; import App from "./App"; +const resolver: CSSVariablesResolver = () => ({ + variables: {}, + light: {}, + dark: { + "--mantine-color-body": "var(--mantine-color-blue-9)", + }, +}); + createRoot(document.getElementById("root")!).render( - + diff --git a/clients/web/src/theme/Input.ts b/clients/web/src/theme/Input.ts new file mode 100644 index 00000000..9b8e5f04 --- /dev/null +++ b/clients/web/src/theme/Input.ts @@ -0,0 +1,9 @@ +import { Input } from "@mantine/core"; + +export const ThemeInput = Input.extend({ + styles: () => ({ + input: { + backgroundColor: "var(--inspector-input-background)", + }, + }), +}); diff --git a/clients/web/src/theme/index.ts b/clients/web/src/theme/index.ts index 91835be9..42b0cd1e 100644 --- a/clients/web/src/theme/index.ts +++ b/clients/web/src/theme/index.ts @@ -6,6 +6,7 @@ export { ThemeButton } from "./Button"; export { ThemeCard } from "./Card"; export { ThemeCode } from "./Code"; export { ThemeFlex } from "./Flex"; +export { ThemeInput } from "./Input"; export { ThemePaper } from "./Paper"; export { ThemeSelect } from "./Select"; export { ThemeSwitch } from "./Switch"; diff --git a/clients/web/src/theme/theme.ts b/clients/web/src/theme/theme.ts index d79a8856..bacebf3c 100644 --- a/clients/web/src/theme/theme.ts +++ b/clients/web/src/theme/theme.ts @@ -1,4 +1,4 @@ -import { createTheme } from "@mantine/core"; +import { createTheme, type MantineColorsTuple } from "@mantine/core"; import { ThemeActionIcon, ThemeAlert, @@ -8,6 +8,7 @@ import { ThemeCard, ThemeCode, ThemeFlex, + ThemeInput, ThemePaper, ThemeSelect, ThemeSwitch, @@ -15,10 +16,26 @@ import { ThemeUnstyledButton, } from "./index"; +const inspector: MantineColorsTuple = [ + "#f0f3fa", + "#dee3ee", + "#b9c5de", + "#91a5cf", + "#7089c3", + "#5b78bb", + "#4f70b9", + "#405fa3", + "#375493", + "#121e36", +]; + export const theme = createTheme({ + colors: { + inspector, + }, /* ── Color ──────────────────────────────────────────────── */ - primaryColor: "dark", - primaryShade: { light: 7, dark: 4 }, + primaryColor: "inspector", + primaryShade: { light: 7, dark: 8 }, autoContrast: true, /* ── Shape ──────────────────────────────────────────────── */ @@ -43,6 +60,7 @@ export const theme = createTheme({ Card: ThemeCard, Code: ThemeCode, Flex: ThemeFlex, + Input: ThemeInput, Paper: ThemePaper, Select: ThemeSelect, Switch: ThemeSwitch,