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
33 changes: 21 additions & 12 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,16 +136,22 @@ Preserve established icon and data colors during surface or theme refactors. Use

### Fonts and hierarchy

The global body size is currently 14px, and `src/assets/index.css` does not define a custom brand font. Keep system sans-serif fonts with platform Chinese fallbacks. Do not introduce decorative fonts or remote font dependencies for the client. Keep Monaco's monospace editor font; SQL, types, object identifiers, and code snippets may use the existing `font-mono` utility.
The global body size is `var(--font-size-form)` (14px), and `src/assets/index.css` does not define a custom brand font. Keep system sans-serif fonts with platform Chinese fallbacks. Do not introduce decorative fonts or remote font dependencies for the client. Keep Monaco's monospace editor font; SQL, types, object identifiers, and code snippets may use the existing `font-mono` utility.

The type scale is token-driven. `index.css` defines `--font-size-caption / dense / body / form / title / page-title` (11 / 12 / 13 / 14 / 16 / 20px); `uno.config.ts` maps the two sizes missing from the default scale (`text-caption` = 11px, `text-body` = 13px), and the rest reuse default utilities (`text-xs` = 12, `text-sm` = 14, `text-base` = 16, `text-xl` = 20). Business components must use these utilities or the CSS variables — never a bare px/rem font size. Monaco's editor font size remains a user setting.

Custom font-size utilities must also be registered in the shared `cn()` helper so component overrides merge sizes independently of semantic text colors.

The following hierarchy constrains new UI; it does not require rewriting all existing page titles.

| Role | Size / weight | Usage |
| Role | Token / utility | Usage |
| --- | --- | --- |
| Page title | 20–24px / 600 | Standalone pages such as Connections and Settings; do not add large headings to editor workspaces |
| Dialog / section title | 14–18px / 500–600 | Dialog titles and major groups |
| Body / form | 14px / 400 | Descriptions, inputs, buttons; matches the current `text-sm` |
| Dense data / supporting labels | 12px / 400–500 | Result grids, object trees, toolbars, status bars |
| Page title | `text-xl` (20px / 600) | Standalone pages such as Connections and Settings; do not add large headings to editor workspaces |
| Dialog / panel / card title | `text-base` (16px / 600) | Dialog titles, side-panel headers, card and section titles |
| Body / form | `text-sm` (14px / 400) | Descriptions, inputs, buttons |
| Sidebar lists, trees, and menus | `text-body` (13px / 400–500) | Connection selector rows, object trees, saved-query names, query tabs, dropdown items |
| Dense data / supporting labels | `text-xs` (12px / 400–500) | Result grids, toolbars, status bars, empty-state hints |
| Captions and badges | `text-caption` (11px / 500) | Attribute badges, timestamps, task counters; the readable lower bound — 9–10px text is forbidden |

- Use roughly 1.4–1.6 line height for ordinary text. Code follows editor settings; fixed-height table rows must not clip text.
- Do not use 9–10px text for states, prices, field meanings, or instructions users must read. Adjust the layout first when space is tight.
Expand All @@ -163,11 +169,12 @@ Retain the existing app shell: top window bar → left feature navigation → cu
| --- | --- | --- |
| Initial window | 1600 × 1000 | `src-tauri/tauri.conf.json`; not a minimum window size |
| Window bar | 40px | `h-10` in `AppHeader.vue` |
| Feature navigation | 64px wide, 40 × 40px entries | `AppSidebar.vue` |
| Feature navigation | 56px wide, 36 × 36px entries, 20px icons | `AppSidebar.vue` |
| Query sidebar | Initially 250px, resize range 200–400px | `QueriesPage.vue` |
| Query tabs | 35px high, maximum 200px per tab | `QueryTabs.vue` |
| Result toolbar | 36px high | `QueryResultPanel.vue` |
| Standard buttons / inputs | 32px high | `ui/button`, `ui/input` |
| Object tree rows | 28px row height (20px line + 8px padding), 13px text, 14px icons | `SchemaTree.vue` |
| Query tabs | 35px high, 13px labels, maximum 200px per tab | `QueryTabs.vue` |
| Result toolbar | 36px high (result panel and grid toolbars share this) | `QueryResultPanel.vue`, `DataGrid.vue` |
| Standard buttons / inputs | 32px high; 24 / 28 / 36px via `xs` / `sm` / `lg` | `ui/button`, `ui/input` |
| Virtual result rows | 32px estimated height | `grid/DataGrid.vue`; not a shared height for every table |

### Spacing and containers
Expand Down Expand Up @@ -204,7 +211,9 @@ Keep `--radius: 0.5rem`: `lg` is 8px, `md` is 6px, and `sm` is 4px. Use `rounded

- Use corner radius to convey component hierarchy rather than inventing per-page values. Keep continuous straight edges for data grids, split panes, and editors.
- Limit `rounded-full` to suitable elements such as avatars, small status dots, and existing badges. Do not make every button pill-shaped.
- Toolbar icons are usually 14–16px and main navigation icons 20px; the visible icon is smaller than its hit target. Keep standard action targets at 32px. Compact grid actions should generally be at least 24px with sufficient spacing and keyboard access.
- Icon scale: 12px for inline glyphs (chevrons, close buttons, badge icons), 14px for tree, tab, and compact toolbar icons, 16px for standard buttons, menu items, and input adornments, 20px for main navigation. Dropdown-menu icons inherit the shared `size-4` from `DropdownMenuItem`; do not override per menu. The visible icon is smaller than its hit target; keep standard action targets at 32px and compact grid actions at least 24px with sufficient spacing and keyboard access.
- Database vendor logos use three sizes: 14px inside lists and tabs, 16px in dropdown selected states and forms, 20px on cards and landing states (`DbTypeIcon` defaults to 16).
- Status dots use 8px (`h-2 w-2`) inline within rows and 10px (`h-2.5 w-2.5`) as a standalone indicator beside a control.
- Reuse the component's existing Carbon / Lucide style. Do not add icon libraries for color or decoration, or mix emoji into an action group.

## Components
Expand All @@ -217,7 +226,7 @@ Interactive components must cover default, hover, focus-visible, active / select

### Buttons and toolbars

- `default`: the single primary action, retaining `bg-primary text-primary-foreground`. Current default height is 32px; large is 36px.
- `default`: the single primary action, retaining `bg-primary text-primary-foreground`. Heights: `xs` 24px, `sm` 28px, default 32px, `lg` 36px; icon buttons mirror this via `icon-xs` / `icon-sm` / `icon`. Use `sm` for sidebar and toolbar rows instead of overriding heights per component.
- `outline / secondary`: secondary actions; `ghost`: toolbar and infrequent actions; `link`: explicit text links.
- `destructive`: genuinely destructive actions such as deletion. Ordinary disconnect and stop-query actions do not automatically become solid red buttons because they stop something.
- Loading states prevent duplicate submission and keep readable labels. Provide cancellation for cancellable long tasks rather than disabling the entire panel.
Expand Down
16 changes: 15 additions & 1 deletion src/assets/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,20 @@
--syntax-comment: 112.50 7.55% 58.43%;
}

:root {
/* Type scale (see DESIGN.md Typography). text-caption / text-body map to
--font-size-caption / --font-size-body via uno.config.ts; the other sizes
reuse the default utilities text-xs (12) / text-sm (14) / text-base (16) /
text-xl (20). Business components must use these variables or utilities
instead of bare px/rem font sizes. */
--font-size-caption: 11px;
--font-size-dense: 12px;
--font-size-body: 13px;
--font-size-form: 14px;
--font-size-title: 16px;
--font-size-page-title: 20px;
}

* {
border-color: hsl(var(--border));
}
Expand All @@ -107,7 +121,7 @@ body,
body {
background-color: hsl(var(--background));
color: hsl(var(--foreground));
font-size: 14px;
font-size: var(--font-size-form);
}

[data-tauri-drag-region] {
Expand Down
10 changes: 5 additions & 5 deletions src/components/DeviceReplaceDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ function handleOpenChange(open: boolean) {
}

.slot-usage {
font-size: 13px;
font-size: var(--font-size-body);
color: hsl(var(--muted-foreground));
margin-bottom: 12px;
}
Expand Down Expand Up @@ -204,26 +204,26 @@ function handleOpenChange(open: boolean) {

.device-name {
font-weight: 500;
font-size: 14px;
font-size: var(--font-size-form);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.current-tag {
font-size: 12px;
font-size: var(--font-size-dense);
color: hsl(var(--muted-foreground));
font-weight: 400;
}

.device-info {
font-size: 12px;
font-size: var(--font-size-dense);
color: hsl(var(--muted-foreground));
margin-top: 2px;
}

.replace-error {
font-size: 13px;
font-size: var(--font-size-body);
color: hsl(var(--destructive-text));
margin-top: 8px;
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/SQLEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -313,11 +313,11 @@ defineExpose({ getValue, setValue, handleFormat })
gap: 16px;
padding: 6px 12px;
cursor: pointer;
font-size: 13px;
font-size: var(--font-size-body);
}

.sql-context-menu li .shortcut {
font-size: 11px;
font-size: var(--font-size-dense);
opacity: 0.5;
white-space: nowrap;
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/UpdateNotification.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const buttonsDisabled = computed(() =>
</div>

<div class="flex-1 min-w-0">
<div class="text-[16px] text-foreground font-bold mb-0.5">
<div class="text-base text-foreground font-bold mb-0.5">
{{ t('updater.updateAvailable') }}
</div>
<div class="text-sm text-muted-foreground">
Expand Down
46 changes: 23 additions & 23 deletions src/components/agent-message-bubble.vue
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
max-width: 85%;
padding: 10px 14px;
border-radius: 12px;
font-size: 14px;
font-size: var(--font-size-form);
line-height: 1.5;
}

Expand Down Expand Up @@ -595,7 +595,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
}

.iteration-label {
font-size: 10px;
font-size: var(--font-size-caption);
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
Expand Down Expand Up @@ -631,7 +631,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
}

.activity-label {
font-size: 13px;
font-size: var(--font-size-body);
color: hsl(var(--muted-foreground));
white-space: nowrap;
overflow: hidden;
Expand All @@ -656,7 +656,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
}

.duration-badge {
font-size: 10.5px;
font-size: var(--font-size-caption);
font-weight: 500;
color: hsl(var(--muted-foreground));
background: hsl(var(--muted));
Expand All @@ -673,7 +673,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
}

.tool-name-badge {
font-size: 11.5px;
font-size: var(--font-size-dense);
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Monaco, monospace;
color: hsl(var(--foreground) / 0.75);
background: hsl(var(--muted));
Expand All @@ -688,7 +688,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
}

.tool-verb-label {
font-size: 12px;
font-size: var(--font-size-dense);
color: hsl(var(--muted-foreground));
}

Expand Down Expand Up @@ -719,7 +719,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
}

.result-preview {
font-size: 11.5px;
font-size: var(--font-size-dense);
color: hsl(var(--muted-foreground));
white-space: nowrap;
overflow: hidden;
Expand Down Expand Up @@ -748,7 +748,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
.tool-result-pre {
margin: 0;
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Monaco, monospace;
font-size: 11px;
font-size: var(--font-size-dense);
line-height: 1.5;
white-space: pre-wrap;
word-break: break-all;
Expand Down Expand Up @@ -777,7 +777,7 @@ function toolVerb(toolName: string, tc: AgentToolCall): string {
border-radius: 6px;
background: hsl(var(--destructive-muted));
color: hsl(var(--destructive-text));
font-size: 13px;
font-size: var(--font-size-body);
overflow-wrap: anywhere;
}

Expand All @@ -802,7 +802,7 @@ details[open] .activity-chevron {
.activity-body {
margin: 0 0 4px 42px;
padding: 6px 10px;
font-size: 11.5px;
font-size: var(--font-size-dense);
line-height: 1.6;
color: hsl(var(--muted-foreground));
background: hsl(var(--muted) / 0.5);
Expand Down Expand Up @@ -859,7 +859,7 @@ details[open] .activity-chevron {

.activity-inline-content {
padding: 4px 0 4px 20px;
font-size: 13.5px;
font-size: var(--font-size-body);
line-height: 1.55;
color: hsl(var(--foreground));
}
Expand All @@ -881,7 +881,7 @@ details[open] .activity-chevron {
}

.markdown-body :deep(pre code) {
font-size: 12px;
font-size: var(--font-size-dense);
background: none;
padding: 0;
border: none;
Expand All @@ -892,7 +892,7 @@ details[open] .activity-chevron {
border-collapse: collapse;
width: 100%;
margin: 8px 0;
font-size: 12px;
font-size: var(--font-size-dense);
}

.markdown-body :deep(th),
Expand Down Expand Up @@ -926,38 +926,38 @@ details[open] .activity-chevron {
}

.markdown-body :deep(h1) {
font-size: 22px;
font-size: var(--font-size-page-title);
margin-top: 24px;
margin-bottom: 12px;
border-bottom: 1px solid hsl(var(--border));
padding-bottom: 6px;
}

.markdown-body :deep(h2) {
font-size: 18px;
font-size: var(--font-size-title);
margin-top: 20px;
margin-bottom: 10px;
border-bottom: 1px solid hsl(var(--border));
padding-bottom: 4px;
}

.markdown-body :deep(h3) {
font-size: 16px;
font-size: var(--font-size-form);
margin-top: 18px;
}

.markdown-body :deep(h4) {
font-size: 15px;
font-size: var(--font-size-body);
margin-top: 16px;
}

.markdown-body :deep(h5) {
font-size: 14px;
font-size: var(--font-size-dense);
margin-top: 14px;
}

.markdown-body :deep(h6) {
font-size: 13px;
font-size: var(--font-size-caption);
margin-top: 14px;
color: hsl(var(--muted-foreground));
}
Expand Down Expand Up @@ -1054,7 +1054,7 @@ details[open] .activity-chevron {
border: 1px solid hsl(var(--border) / 0.5);
border-radius: 8px;
max-width: fit-content;
font-size: 11.5px;
font-size: var(--font-size-dense);
color: hsl(var(--muted-foreground));
}

Expand All @@ -1075,7 +1075,7 @@ details[open] .activity-chevron {
align-items: center;
gap: 4px;
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Monaco, monospace;
font-size: 11px;
font-size: var(--font-size-dense);
color: hsl(var(--foreground) / 0.75);
padding: 1px 8px;
background: hsl(var(--background));
Expand Down Expand Up @@ -1104,7 +1104,7 @@ details[open] .activity-chevron {
background: none;
border: none;
cursor: pointer;
font-size: 11px;
font-size: var(--font-size-dense);
color: hsl(var(--muted-foreground));
padding: 0;
margin-left: 4px;
Expand All @@ -1125,7 +1125,7 @@ details[open] .activity-chevron {
padding: 8px 12px;
background: hsl(var(--muted) / 0.4);
border-radius: 8px;
font-size: 12px;
font-size: var(--font-size-dense);
line-height: 1.55;
color: hsl(var(--foreground) / 0.85);
max-height: 240px;
Expand Down
10 changes: 5 additions & 5 deletions src/components/chat-panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ onBeforeUnmount(() => {
<span class="i-carbon-pause-filled shrink-0 h-4 w-4" style="color: hsl(38 92% 50%);" />
<div class="flex flex-col gap-0.5">
<span class="text-xs font-medium">{{ stopMessage }}</span>
<span class="text-[11px] text-muted-foreground">{{ t('dataStudio.agent.continueHint') }}</span>
<span class="text-caption text-muted-foreground">{{ t('dataStudio.agent.continueHint') }}</span>
</div>
</div>
<div class="flex shrink-0 gap-1.5">
Expand Down Expand Up @@ -455,7 +455,7 @@ onBeforeUnmount(() => {
outline: none;
background: transparent;
color: hsl(var(--foreground));
font-size: 13px;
font-size: var(--font-size-body);
resize: none;
line-height: 1.5;
}
Expand Down Expand Up @@ -550,13 +550,13 @@ onBeforeUnmount(() => {
}

.loop-stopped-banner__message {
font-size: 13px;
font-size: var(--font-size-body);
font-weight: 500;
line-height: 1.4;
}

.loop-stopped-banner__hint {
font-size: 12px;
font-size: var(--font-size-dense);
color: hsl(var(--muted-foreground));
line-height: 1.4;
}
Expand All @@ -570,7 +570,7 @@ onBeforeUnmount(() => {

.loop-stopped-banner__action {
padding: 4px 10px;
font-size: 12px;
font-size: var(--font-size-dense);
font-weight: 600;
border-radius: 6px;
cursor: pointer;
Expand Down
Loading
Loading