From d5f1e4759381ba8b3942ced8a8d9f194393e05a5 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 24 Sep 2026 21:05:39 +0400 Subject: [PATCH 1/5] pre app check --- frontend/DESIGN.md | 502 +++++ frontend/eslint.config.js | 203 +- frontend/package-lock.json | 421 +++- frontend/package.json | 2 + frontend/scripts/design-lint-report.mjs | 75 + frontend/src/App.tsx | 45 +- frontend/src/Hero.tsx | 14 +- frontend/src/Navigation.tsx | 197 +- frontend/src/PageNotFound.tsx | 4 +- frontend/src/admin/Activity.tsx | 30 +- frontend/src/admin/AdminUI.test.ts | 26 +- frontend/src/admin/AdminUI.tsx | 57 +- frontend/src/admin/Admins.tsx | 7 +- frontend/src/admin/Overview.tsx | 8 +- frontend/src/admin/QuotaEditor.tsx | 26 +- frontend/src/admin/Quotas.tsx | 18 +- frontend/src/admin/Usage.tsx | 10 +- frontend/src/admin/UserUsageModal.tsx | 4 +- frontend/src/admin/Users.tsx | 63 +- frontend/src/agents/AgentCard.tsx | 13 +- frontend/src/agents/AgentPageHeader.test.tsx | 56 + frontend/src/agents/AgentPageHeader.tsx | 39 +- frontend/src/agents/AgentsList.tsx | 25 +- frontend/src/agents/FolderCard.tsx | 2 +- frontend/src/agents/NewAgent.test.tsx | 301 +++ frontend/src/agents/NewAgent.tsx | 263 +-- frontend/src/agents/SharedAgent.tsx | 4 +- frontend/src/agents/SharedAgentCard.tsx | 8 +- .../agents/components/AgentTypeModal.test.tsx | 72 + .../src/agents/components/AgentTypeModal.tsx | 46 +- .../components/GuardrailEvents.test.tsx | 92 + .../src/agents/components/GuardrailEvents.tsx | 60 +- .../components/GuardrailsSection.test.tsx | 275 +++ .../agents/components/GuardrailsSection.tsx | 238 +- .../src/agents/schedules/RunDetailDrawer.tsx | 8 +- frontend/src/agents/schedules/RunLog.tsx | 4 +- .../agents/schedules/ScheduleFormModal.tsx | 27 +- .../schedules/SchedulerToolCallCard.tsx | 6 +- .../src/agents/schedules/SchedulesView.tsx | 20 +- .../src/agents/schedules/StatusBadge.test.tsx | 39 +- frontend/src/agents/schedules/StatusBadge.tsx | 48 +- .../src/agents/schedules/TimezoneCombobox.tsx | 10 +- .../src/agents/workflow/WorkflowBuilder.tsx | 322 ++- .../agents/workflow/WorkflowMiniMap.test.tsx | 131 ++ .../src/agents/workflow/WorkflowPreview.tsx | 210 +- .../agents/workflow/WorkflowRunArtifacts.tsx | 17 +- .../components/NodeDocumentsControl.tsx | 18 +- .../workflow/components/PromptTextArea.tsx | 47 +- .../src/agents/workflow/nodes/BaseNode.tsx | 32 +- .../src/agents/workflow/nodes/CodeNode.tsx | 8 +- .../agents/workflow/nodes/ConditionNode.tsx | 22 +- .../agents/workflow/nodes/SetStateNode.tsx | 6 +- frontend/src/agents/workflow/nodes/index.tsx | 29 +- frontend/src/components/ActionButtons.tsx | 9 +- frontend/src/components/ArtifactSidebar.tsx | 107 +- frontend/src/components/Chunks.tsx | 117 +- frontend/src/components/ConfigFields.tsx | 14 +- .../src/components/ConnectorAuth.test.tsx | 84 + frontend/src/components/ConnectorAuth.tsx | 69 +- frontend/src/components/ConnectorTree.tsx | 4 +- frontend/src/components/CopyButton.test.tsx | 88 + frontend/src/components/CopyButton.tsx | 64 +- .../src/components/DocumentArtifactView.tsx | 24 +- .../components/DocumentPagination.test.tsx | 76 + .../src/components/DocumentPagination.tsx | 76 +- frontend/src/components/FilePicker.test.tsx | 109 + frontend/src/components/FilePicker.tsx | 126 +- frontend/src/components/FileUpload.test.tsx | 111 + frontend/src/components/FileUpload.tsx | 199 +- frontend/src/components/GoogleDrivePicker.tsx | 28 +- frontend/src/components/GraphView.tsx | 5 +- frontend/src/components/Help.tsx | 4 +- frontend/src/components/MarkdownPreview.tsx | 8 +- .../src/components/MermaidRenderer.test.tsx | 37 +- frontend/src/components/MermaidRenderer.tsx | 121 +- frontend/src/components/MessageInput.tsx | 27 +- .../components/MultiSelectPopover.test.tsx | 81 + .../src/components/MultiSelectPopover.tsx | 54 +- frontend/src/components/Notification.tsx | 176 +- frontend/src/components/ProfileButton.tsx | 24 +- .../src/components/SourcesPopoverFooter.tsx | 5 +- frontend/src/components/Spinner.tsx | 32 +- .../src/components/TextToSpeechButton.tsx | 11 +- frontend/src/components/ToolIcon.tsx | 8 +- frontend/src/components/UploadToast.test.tsx | 121 ++ frontend/src/components/UploadToast.tsx | 284 ++- frontend/src/components/WikiViewer.tsx | 7 +- .../message-input/AttachFileButton.tsx | 48 +- .../message-input/AttachmentChipList.tsx | 13 +- .../components/message-input/MicButton.tsx | 32 +- .../message-input/SourcesTrigger.tsx | 7 +- .../components/message-input/ToolsTrigger.tsx | 7 +- frontend/src/components/tree/TreeBrowser.tsx | 19 +- frontend/src/components/ui/accordion.test.tsx | 49 + frontend/src/components/ui/accordion.tsx | 4 +- frontend/src/components/ui/alert.test.tsx | 55 + frontend/src/components/ui/alert.tsx | 10 +- frontend/src/components/ui/avatar.test.tsx | 34 + frontend/src/components/ui/avatar.tsx | 46 +- frontend/src/components/ui/badge.test.tsx | 39 + frontend/src/components/ui/badge.tsx | 51 + .../src/components/ui/breadcrumb.test.tsx | 24 + frontend/src/components/ui/breadcrumb.tsx | 7 +- frontend/src/components/ui/button.test.tsx | 166 ++ frontend/src/components/ui/button.tsx | 69 +- frontend/src/components/ui/calendar.tsx | 10 +- frontend/src/components/ui/card.test.tsx | 43 + frontend/src/components/ui/card.tsx | 141 ++ frontend/src/components/ui/command.test.tsx | 123 ++ frontend/src/components/ui/command.tsx | 41 +- frontend/src/components/ui/dropzone.test.tsx | 42 + frontend/src/components/ui/dropzone.tsx | 117 + frontend/src/components/ui/feedback.test.tsx | 88 + frontend/src/components/ui/input.test.tsx | 129 ++ frontend/src/components/ui/input.tsx | 115 +- frontend/src/components/ui/modal.tsx | 9 +- frontend/src/components/ui/multi-select.tsx | 12 +- .../src/components/ui/option-card.test.tsx | 54 + frontend/src/components/ui/option-card.tsx | 69 + frontend/src/components/ui/progress.tsx | 73 + frontend/src/components/ui/select.test.tsx | 41 + frontend/src/components/ui/select.tsx | 12 +- frontend/src/components/ui/skeleton.tsx | 17 + frontend/src/components/ui/spinner.tsx | 41 + frontend/src/components/ui/switch.tsx | 2 +- frontend/src/components/ui/table.tsx | 24 +- frontend/src/components/ui/tabs.tsx | 2 +- frontend/src/components/ui/textarea.test.tsx | 33 + frontend/src/components/ui/textarea.tsx | 59 + frontend/src/components/ui/toast.test.tsx | 128 ++ frontend/src/components/ui/toast.tsx | 280 +++ frontend/src/components/ui/tooltip.tsx | 60 + frontend/src/conversation/AnswerFlow.tsx | 20 +- frontend/src/conversation/Conversation.tsx | 2 +- .../conversation/ConversationBubble.test.tsx | 189 ++ .../src/conversation/ConversationBubble.tsx | 104 +- .../ConversationMessages.test.tsx | 80 + .../src/conversation/ConversationMessages.tsx | 45 +- .../src/conversation/ConversationTile.tsx | 21 +- frontend/src/conversation/MarkdownAnswer.tsx | 25 +- .../src/conversation/ResearchProgress.tsx | 37 +- .../src/conversation/SharedConversation.tsx | 6 +- frontend/src/design/DesignSystem.tsx | 1932 +++++++++++++++++ frontend/src/index.css | 132 +- frontend/src/locale/de.json | 8 +- frontend/src/locale/en.json | 8 +- frontend/src/locale/es.json | 8 +- frontend/src/locale/jp.json | 8 +- frontend/src/locale/ru.json | 8 +- frontend/src/locale/zh-TW.json | 8 +- frontend/src/locale/zh.json | 8 +- .../src/modals/AccessTokenCreatedModal.tsx | 20 +- frontend/src/modals/AddActionModal.tsx | 11 +- frontend/src/modals/AgentDetailsModal.tsx | 353 +-- frontend/src/modals/ConfigToolModal.tsx | 9 +- frontend/src/modals/ConfirmationModal.tsx | 4 +- .../src/modals/CreateAccessTokenModal.tsx | 67 +- frontend/src/modals/CustomModelModal.test.tsx | 56 + frontend/src/modals/CustomModelModal.tsx | 71 +- frontend/src/modals/FolderManagementModal.tsx | 4 +- frontend/src/modals/ImportAgentModal.test.tsx | 135 ++ frontend/src/modals/ImportAgentModal.tsx | 43 +- frontend/src/modals/ImportSpecModal.tsx | 38 +- frontend/src/modals/JWTModal.tsx | 4 +- frontend/src/modals/MCPServerModal.tsx | 132 +- .../src/modals/MoveToFolderModal.test.tsx | 252 +++ frontend/src/modals/MoveToFolderModal.tsx | 292 +-- .../src/modals/RegenerateAccessTokenModal.tsx | 47 +- .../modals/SearchConversationsModal.test.tsx | 196 ++ .../src/modals/SearchConversationsModal.tsx | 276 +-- .../src/modals/ShareConversationModal.tsx | 8 +- frontend/src/navigation/DetailBreadcrumb.tsx | 5 +- frontend/src/navigation/SectionPills.tsx | 4 +- frontend/src/navigation/SectionRail.tsx | 3 +- frontend/src/navigation/SidebarLevel.tsx | 4 + .../src/navigation/SidebarNavRow.test.tsx | 55 + .../src/notifications/ActionToast.test.tsx | 94 + frontend/src/notifications/ActionToast.tsx | 59 + .../TeamNotificationToast.test.tsx | 109 + .../notifications/TeamNotificationToast.tsx | 63 +- .../notifications/ToolApprovalToast.test.tsx | 144 ++ .../src/notifications/ToolApprovalToast.tsx | 118 +- .../notifications/actionToastSlice.test.ts | 54 + .../src/notifications/actionToastSlice.ts | 43 + .../src/preferences/PromptsModal.test.tsx | 87 + frontend/src/preferences/PromptsModal.tsx | 94 +- frontend/src/settings/Analytics.tsx | 149 +- frontend/src/settings/ConvertToWikiModal.tsx | 48 +- frontend/src/settings/CustomModels.tsx | 9 +- frontend/src/settings/EnableGraphRAGModal.tsx | 62 +- frontend/src/settings/General.tsx | 7 +- frontend/src/settings/Logs.tsx | 49 +- frontend/src/settings/PairDeviceModal.tsx | 19 +- .../src/settings/PersonalAccessTokens.tsx | 27 +- frontend/src/settings/Prompts.test.tsx | 118 + frontend/src/settings/Prompts.tsx | 62 +- .../src/settings/RemoteDeviceConfig.test.tsx | 104 + frontend/src/settings/RemoteDeviceConfig.tsx | 152 +- frontend/src/settings/SourceConfigModal.tsx | 52 +- frontend/src/settings/Sources.tsx | 45 +- frontend/src/settings/Teams.tsx | 142 +- .../TestRetrievalModal.notices.test.tsx | 117 + frontend/src/settings/TestRetrievalModal.tsx | 34 +- frontend/src/settings/ToolConfig.test.tsx | 265 +++ frontend/src/settings/ToolConfig.tsx | 263 +-- frontend/src/settings/Tools.tsx | 36 +- .../settings/components/RetrievalOptions.tsx | 32 +- .../src/settings/components/UsageQuota.tsx | 22 +- frontend/src/settings/foldSeries.test.ts | 64 + frontend/src/settings/foldSeries.ts | 51 + frontend/src/store.ts | 2 + frontend/src/teams/ShareToTeamModal.tsx | 29 +- frontend/src/teams/TeamSwitcher.tsx | 30 +- frontend/src/upload/Upload.test.tsx | 101 + frontend/src/upload/Upload.tsx | 61 +- frontend/src/utils/httpMethodColors.test.ts | 24 + frontend/src/utils/httpMethodColors.ts | 33 +- 217 files changed, 13133 insertions(+), 3644 deletions(-) create mode 100644 frontend/DESIGN.md create mode 100644 frontend/scripts/design-lint-report.mjs create mode 100644 frontend/src/agents/AgentPageHeader.test.tsx create mode 100644 frontend/src/agents/NewAgent.test.tsx create mode 100644 frontend/src/agents/components/AgentTypeModal.test.tsx create mode 100644 frontend/src/agents/components/GuardrailEvents.test.tsx create mode 100644 frontend/src/agents/components/GuardrailsSection.test.tsx create mode 100644 frontend/src/agents/workflow/WorkflowMiniMap.test.tsx create mode 100644 frontend/src/components/ConnectorAuth.test.tsx create mode 100644 frontend/src/components/CopyButton.test.tsx create mode 100644 frontend/src/components/DocumentPagination.test.tsx create mode 100644 frontend/src/components/FilePicker.test.tsx create mode 100644 frontend/src/components/FileUpload.test.tsx create mode 100644 frontend/src/components/MultiSelectPopover.test.tsx create mode 100644 frontend/src/components/UploadToast.test.tsx create mode 100644 frontend/src/components/ui/accordion.test.tsx create mode 100644 frontend/src/components/ui/alert.test.tsx create mode 100644 frontend/src/components/ui/avatar.test.tsx create mode 100644 frontend/src/components/ui/badge.test.tsx create mode 100644 frontend/src/components/ui/badge.tsx create mode 100644 frontend/src/components/ui/breadcrumb.test.tsx create mode 100644 frontend/src/components/ui/button.test.tsx create mode 100644 frontend/src/components/ui/card.test.tsx create mode 100644 frontend/src/components/ui/card.tsx create mode 100644 frontend/src/components/ui/command.test.tsx create mode 100644 frontend/src/components/ui/dropzone.test.tsx create mode 100644 frontend/src/components/ui/dropzone.tsx create mode 100644 frontend/src/components/ui/feedback.test.tsx create mode 100644 frontend/src/components/ui/input.test.tsx create mode 100644 frontend/src/components/ui/option-card.test.tsx create mode 100644 frontend/src/components/ui/option-card.tsx create mode 100644 frontend/src/components/ui/progress.tsx create mode 100644 frontend/src/components/ui/select.test.tsx create mode 100644 frontend/src/components/ui/skeleton.tsx create mode 100644 frontend/src/components/ui/spinner.tsx create mode 100644 frontend/src/components/ui/textarea.test.tsx create mode 100644 frontend/src/components/ui/textarea.tsx create mode 100644 frontend/src/components/ui/toast.test.tsx create mode 100644 frontend/src/components/ui/toast.tsx create mode 100644 frontend/src/components/ui/tooltip.tsx create mode 100644 frontend/src/conversation/ConversationBubble.test.tsx create mode 100644 frontend/src/conversation/ConversationMessages.test.tsx create mode 100644 frontend/src/design/DesignSystem.tsx create mode 100644 frontend/src/modals/CustomModelModal.test.tsx create mode 100644 frontend/src/modals/ImportAgentModal.test.tsx create mode 100644 frontend/src/modals/MoveToFolderModal.test.tsx create mode 100644 frontend/src/modals/SearchConversationsModal.test.tsx create mode 100644 frontend/src/navigation/SidebarNavRow.test.tsx create mode 100644 frontend/src/notifications/ActionToast.test.tsx create mode 100644 frontend/src/notifications/ActionToast.tsx create mode 100644 frontend/src/notifications/TeamNotificationToast.test.tsx create mode 100644 frontend/src/notifications/ToolApprovalToast.test.tsx create mode 100644 frontend/src/notifications/actionToastSlice.test.ts create mode 100644 frontend/src/notifications/actionToastSlice.ts create mode 100644 frontend/src/preferences/PromptsModal.test.tsx create mode 100644 frontend/src/settings/Prompts.test.tsx create mode 100644 frontend/src/settings/RemoteDeviceConfig.test.tsx create mode 100644 frontend/src/settings/TestRetrievalModal.notices.test.tsx create mode 100644 frontend/src/settings/ToolConfig.test.tsx create mode 100644 frontend/src/settings/foldSeries.test.ts create mode 100644 frontend/src/settings/foldSeries.ts create mode 100644 frontend/src/upload/Upload.test.tsx create mode 100644 frontend/src/utils/httpMethodColors.test.ts diff --git a/frontend/DESIGN.md b/frontend/DESIGN.md new file mode 100644 index 00000000..81a41e0c --- /dev/null +++ b/frontend/DESIGN.md @@ -0,0 +1,502 @@ +# DocsGPT frontend design system + +The UI is Tailwind v4 plus the shadcn-style components in +`src/components/ui/`. `@shadcn/lint` enforces the rules below through +`npm run lint`; its messages point here. Everything in this file is either a +token in `src/index.css` or a variant in a `ui/` component, so an agent or a +contributor can always find the concrete thing to use. + +## Rules in one paragraph + +Pages compose `ui/` components and choose their look through props +(`variant`, `size`, `shape`). `className` on a component is for placement +only: margin, width, flex and grid, positioning. Colours come from the theme +tokens, never from the raw Tailwind palette. Spacing, type and radii come +from the Tailwind scale, never from arbitrary `[...]` values. Runtime values +go in CSS custom properties or, when unavoidable, an inline style with a +disable comment. + +## Colour tokens + +Defined in `src/index.css` (`:root` for light, `.dark` for dark) and exposed +through `@theme inline`, so `bg-`, `text-`, `border-`, `ring-`, `fill-` and +`stroke-` all accept them, including opacity modifiers such as +`bg-success/10`. One token class replaces a light + dark pair. + +| Token | Use for | Replaces | +| --------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------- | +| `background`, `foreground` | page surface and primary text | `bg-white`, `text-gray-700/800/900`, `dark:text-gray-200/300` | +| `card`, `card-foreground` | raised surfaces (cards, dialogs, dropdowns) | `bg-white dark:bg-[#2b2c31]` | +| `popover`, `popover-foreground` | floating menus and popovers | same as card | +| `muted`, `muted-foreground` | quiet fills and secondary text, icons, placeholders, timestamps | `bg-gray-100/200`, `text-gray-400/500/600`, `dark:text-gray-400` | +| `accent`, `accent-foreground` | hover and selected fills | `hover:bg-gray-100`, `dark:hover:bg-gray-700` | +| `border`, `input`, `ring` | dividers, field borders, focus rings | `border-gray-200/300`, `dark:border-gray-600/700` | +| `primary`, `primary-foreground` | brand purple: primary actions, links, selected states | `bg-purple-*`, `text-purple-*`, `#7D54D1`, `#A076F6` | +| `secondary`, `secondary-foreground` | pressed and active toggles (a brand tint), secondary buttons, the question bubble | `bg-accent` on an active icon button | +| `destructive`, `destructive-foreground` | errors, failed states, dangerous actions | `text-red-*`, `bg-red-50/100`, `#B42318`, `#E60000` | +| `success`, `success-foreground` | completed, active, healthy | `text-green-*`, `text-emerald-*`, `bg-green-50/100` | +| `warning`, `warning-foreground` | paused, pending review, degraded | `text-amber-*`, `text-yellow-*`, `text-orange-*`, `bg-amber-50/100` | +| `info`, `info-foreground` | running, informational | `text-blue-*`, `bg-blue-50/100` | +| `sidebar-*` | the navigation rail | | +| `chart-1` to `chart-5` | data series only, never UI chrome (see below) | | +| `answer-bubble` | assistant message background | | + +Status colours are tuned to stay vivid rather than turning brown or olive, +so their contrast is low. Against white in light mode, `destructive` and +`success` are about 3.8:1, `warning` is 2.9:1 and `info` is 5.2:1. On the +dark card, `destructive` is 2.9:1 and the others are 5.5:1 or more. Do not +use them for long body text; they are for badges, icons, short labels and +fills. + +Chart colours are not a separate palette. `chart-1` to `chart-5` alias +`primary`, `info`, `success`, `warning` and `destructive`, in that order, +so the charts use the same colours as the rest of the app in both themes. +A single series uses `chart-1`, the brand colour. When a series has a +meaning, use the token for that meaning, not the next one in order: +failed tool calls use `destructive`, succeeded ones `success`, pending +ones `warning`. Series with no meaning (models, agents, sources) take +`chart-1` to `chart-5` in order. When there are more than five, the four +largest keep `chart-1` to `chart-4` and the rest are summed into one +"Other" series in `chart-5`, so no colour repeats (`settings/foldSeries.ts`). +`secondary` is never a chart colour. + +Patterns: + +- Status pill: ``. Status box: ``. + Reach for `bg-success/10 text-success` directly only on dots and borders. +- Solid status fill: `bg-warning text-warning-foreground`. +- Guardrail outcomes: block `destructive`, flag `warning`, redact `info`, + not evaluated `neutral`. +- Status border: `border-destructive/50`. +- De-emphasised text: `text-muted-foreground`; go lighter with an opacity + modifier (`text-muted-foreground/70`) rather than a lighter grey. +- Text on the brand colour is `text-primary-foreground`, not `text-white`. +- `secondary` is a brand tint, not a grey: primary at 10% (light) or 15% + (dark) over whatever sits behind it, with `primary` text in light and a + lighter purple (#b89cf8) in dark. So a pressed toggle (CopyButton's copied + state, text-to-speech while speaking) shows on card, background and muted + alike, and never reads as the neutral ghost hover. Use it as + `variant={active ? 'secondary' : 'ghost-muted'}`. +- The user's question bubble is `bg-secondary text-foreground`: the brand + tint as the fill, with body text in `foreground` (15.7:1 light, 12.4:1 + dark) rather than `secondary-foreground`, which is only 4.5:1 in light. + Controls on it (the collapse chevron) are plain `ghost` with a lucide icon + in `currentColor`. +- `white`, `black`, `transparent`, `current` and `inherit` are allowed; use + them only for overlays and imagery, not for text or surfaces. + +## Components and their variants + +### Button (`ui/button.tsx`) + +| Prop | Values | +| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `variant` | `default`, `secondary`, `outline`, `outline-primary`, `ghost`, `ghost-muted`, `ghost-destructive`, `link`, `destructive`, `destructive-outline`, `combobox`, `sidebar-item`, `tab`, `section-toggle` | +| `size` | `xs`, `sm`, `default`, `lg`, `field`, `icon-xs`, `icon-sm`, `icon`, `icon-lg`, `inline` | +| `shape` | `default` (rounded-md), `pill` (rounded-full, wider padding) | + +- Round brand buttons (`rounded-3xl px-5`, `rounded-full px-6`): `shape="pill"`, + plus `size="lg"` if they were `px-6`. +- Muted icon buttons (`text-muted-foreground hover:text-foreground`): + `variant="ghost-muted"`. +- Icon actions that remove something (a trash can on a member or shared + resource row) are `variant="ghost-destructive"`: muted at rest, red on + hover, so the warning shows even where the click deletes without asking. +- Bordered purple buttons (`border-primary text-primary hover:bg-primary`): + `variant="outline-primary"`. +- Tiny inline actions (`h-auto px-2 py-1 text-xs`): `size="xs"`. +- A link inside running text (an artifact link in an answer) is + `variant="link" size="inline"`: no height or padding, so it wraps with the + sentence. Standalone links (toggles, crumbs) keep a normal size. +- The composer controls under the chat field (Attach, Voice, Tools, + Sources) are `size="sm" shape="pill"`. Their icons are `size-3.5 sm:size-4` + with no margin; the size's `gap-1.5` spaces them, and the label span keeps + `text-xs sm:text-sm` so the row still fits on a phone. +- Popover comboboxes (`role="combobox"` + `Command`) use `variant="combobox"`, + which matches `SelectTrigger`: card fill, normal weight, and muted text + while `data-placeholder` is set (`data-placeholder={value ? undefined : ''}`). + Pass only layout (`w-full justify-between`) and keep the chevron as the + last child. +- A button or picker that sits in a row of fields is `size="field"`: 42px, + the height of `Input` (default) and `SelectTrigger size="lg"`, so a form + column has one height. With `shape="pill"` its text starts 21px in, like + the Input and Select pills beside it. The agent form's pickers are + `combobox field pill`, its Add button `outline-primary field pill`. +- Rows in the navigation sidebar (`hover:bg-sidebar-accent … pl-3 gap-2.5 +rounded-3xl`) are `variant="sidebar-item"`: left-aligned, full-radius, normal + weight, `bg-sidebar-accent` on hover and while `aria-current="page"`. Use it + with `asChild` around a `` for navigation rows. +- Inline disclosure toggles ("Advanced settings", "Show advanced options") + are `variant="link" size="sm"` with only `-ml-3 w-fit justify-start`; + a chevron, when the toggle has one, is a lucide `ChevronRight` (so it + takes the link colour) as the first child. +- Underline tabs (FilePicker's My Files / Shared with Me, the agent page + sub-nav) are `variant="tab"`: muted text on a transparent 2px bottom border, + square corners, no hover fill. Mark the current tab with `data-active`, which + gives it `foreground` text and a `primary` underline. Padding-free tabs (a + sub-nav with `gap-6`) add `size="inline"`, which keeps 4px above the line; + the row draws the 1px baseline, and `-mb-px` lays the underline over it. + Tabs that switch a panel in place use `ui/tabs` instead. +- A section panel's disclosure header (NewAgent's Advanced and Guardrails + panels) is `variant="section-toggle" size="sm"` with `-ml-3 w-fit + justify-start` and `aria-expanded`: a lucide `ChevronRight` first + (`rotate-90` while open) in primary, then the foreground title, with a + primary underline on hover. The button draws no focus ring; the panel does, + so keyboard focus outlines the whole white block: + `has-[[data-variant=section-toggle]:focus-visible]:ring-3 …:ring-ring/50 + …:ring-inset` on the panel `
` (inset, because a scrolling column clips + an outset ring). Status badges go beside the button, not inside it, or the + hover underline runs under them. +- Drop `text-white` on default and destructive buttons; the foreground token + already provides it. Drop `disabled:cursor-not-allowed`; the base disables + pointer events. + +### Card (`ui/card.tsx`) + +| Prop | Values | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `variant` | `outline` (border + card surface, the default), `filled` (muted fill, no border, for tiles on a card-coloured page), `subtle` (border on the page background) | +| `padding` | `none`, `sm` (p-3, stat tiles and panels), `default` (p-4), `lg` (p-6) | +| `interactive` | whole card is the target: hover, focus ring and `selected` highlight; pair with `asChild` around a `