Skip to content

Commit 83ead61

Browse files
committed
fix(ui): calibrate compact indicators and launcher geometry
Use a full 24px badge surface, 14px keyboard hints, 18px status pills with opt-in short-label emphasis, and 72px launcher geometry with 11px monospace text. Align light switch, scrollbar, hint, badge and launcher surfaces while retaining other theme modes and legacy Appearance overrides. Add a real inline-controls Lab composition. The product's deliberate compact Hi-to-Hello interaction remains intact. Validation: design-system:check; 19 focused Appearance regressions including old-payload round trips; check:web with all theme audits and type checking. Native visual checks pending desktop auto-rebuild. Four remote scenarios not interactively exercised.
1 parent 57ceb3e commit 83ead61

33 files changed

Lines changed: 210 additions & 61 deletions

‎design-system/apps/design-lab/src/pages/ComponentDetailPage.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ export function ComponentDetailPage({
618618
return `import { Icon, SegmentedControl } from "@openbitfun/ui";\n\n<SegmentedControl\n size="md"\n aria-label="${t("components.preview.segmentedLabel")}"\n defaultValue="${defaultMode}"\n onValueChange={setMode}\n options={[\n { icon: <Icon name="session" />, label: "${t("components.preview.segmentedChat")}", value: "chat" },\n { label: "${t("components.preview.segmentedAgent")}", value: "agent" },\n ]}\n/>`;
619619
}
620620
if (component.name === "StatusPill") {
621-
return `import { Icon, StatusPill } from "@openbitfun/ui";\n\n<StatusPill leading={<Icon name="unselected" />} tone="${previewState}">\n Ask\n</StatusPill>`;
621+
return `import { Icon, StatusPill } from "@openbitfun/ui";\n\n<StatusPill emphasis leading={<Icon name="unselected" />} tone="${previewState}">\n Ask\n</StatusPill>`;
622622
}
623623
if (component.name === "Disclosure") {
624624
const stateProps = previewState === "open" ? " defaultOpen" : previewState === "disabled" ? " disabled" : "";
@@ -1149,6 +1149,7 @@ export function ComponentDetailPage({
11491149
if (component.name === "StatusPill") {
11501150
return (
11511151
<StatusPill
1152+
emphasis
11521153
leading={<Icon name="unselected" />}
11531154
tone={state as StatusPillTone}
11541155
>

‎design-system/apps/design-lab/src/pages/PatternsPage.tsx‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {
3535
type TokenOverrides,
3636
} from "@openbitfun/ui";
3737
import { useI18n, type MessageKey } from "../i18n";
38-
import { FormTypographyPattern, NestedMenuPattern, ProviderConfigurationPattern, SceneToolbarPattern, WorkspaceConfigurationPattern } from "./ReferencePatterns";
38+
import { IndicatorsPattern, FormTypographyPattern, NestedMenuPattern, ProviderConfigurationPattern, SceneToolbarPattern, WorkspaceConfigurationPattern } from "./ReferencePatterns";
3939

4040
interface PatternsPageProps {
4141
colorScheme: ColorScheme;
@@ -80,6 +80,8 @@ export function PatternsPage({ colorScheme, contrast, density, tokenOverrides }:
8080
<p>{t("patterns.description")}</p>
8181
</header>
8282

83+
<IndicatorsPattern />
84+
8385
<PatternSection description={t("patterns.settings.description")} index="01" title={t("patterns.settings.title")}>
8486
<Card appearance="raised" className="pattern-settings" data-openbitfun-pattern="settings-form" padding="md" radius="md">
8587
<PageHeader description={t("components.preview.appearanceDescription")} level={3} size="md" title={t("components.preview.appearance")} />

‎design-system/apps/design-lab/src/pages/ReferencePatterns.tsx‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import {
1616
MenuPopover,
1717
MultiSelect,
1818
NumberInput,
19+
NumberBadge,
20+
LauncherButton,
1921
PageHeader,
2022
SearchField,
2123
Select,
@@ -36,6 +38,17 @@ import {
3638
} from "@openbitfun/ui";
3739
import { useI18n } from "../i18n";
3840

41+
export function IndicatorsPattern() {
42+
const { t } = useI18n();
43+
const [enabled, setEnabled] = useState(false);
44+
return <Toolbar bordered={false} leadingOverflow="scroll" data-openbitfun-pattern="inline-indicators" leading={<>
45+
<ToolbarGroup><NumberBadge value={0} /><NumberBadge value={18} /><NumberBadge value="1234" /></ToolbarGroup>
46+
<ToolbarGroup><KeyHint icon="Ctrl">K</KeyHint><KeyHint icon={<Icon name="command-mac" />}>K</KeyHint></ToolbarGroup>
47+
<ToolbarGroup><StatusPill emphasis leading={<Icon name="unselected" />}>Ask</StatusPill><StatusPill tone="success">{t("patterns.device.online")}</StatusPill></ToolbarGroup>
48+
<ToolbarGroup><Switch aria-label={t("patterns.settings.pointer")} checked={enabled} onCheckedChange={setEnabled} /><LauncherButton leadingIcon={<Icon name="session" />}>Hello</LauncherButton></ToolbarGroup>
49+
</>} />;
50+
}
51+
3952
export function FormTypographyPattern() {
4053
const { t } = useI18n();
4154
return <Card appearance="subtle" padding="md" data-openbitfun-pattern="form-typography">

‎design-system/packages/design-tokens/src/system.tokens.json‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,10 @@
180180
"lineHeight": { "$value": "{lineHeight.tight}" },
181181
"letterSpacing": { "$value": "{letterSpacing.normal}" }
182182
},
183+
"statusPill": {
184+
"$description": "Short status leading: 14px at 11px, scaling with typography.",
185+
"lineHeight": { "$type": "number", "$value": 1.2727272727272727 }
186+
},
183187
"fieldHelper": {
184188
"$description": "Field helper leading: 16px at the default 11px type size, scaling with user typography.",
185189
"lineHeight": { "$type": "number", "$value": 1.4545454545454546 }
@@ -291,6 +295,13 @@
291295
}
292296
},
293297
"code": {
298+
"meta": {
299+
"fontFamily": { "$value": "{font.family.mono}" },
300+
"fontSize": { "$value": "{font.size.meta}" },
301+
"fontWeight": { "$value": "{font.weight.regular}" },
302+
"lineHeight": { "$value": "{lineHeight.tight}" },
303+
"letterSpacing": { "$value": "{letterSpacing.normal}" }
304+
},
294305
"sm": {
295306
"fontFamily": { "$value": "{font.family.mono}" },
296307
"fontSize": { "$value": "{font.size.xs}" },
@@ -618,11 +629,11 @@
618629
"launcherButton": {
619630
"$description": "Geometry for a shell-edge launcher with an icon and short label.",
620631
"$type": "dimension",
621-
"minInlineSize": { "$value": "104px" },
632+
"minInlineSize": { "$value": "72px" },
622633
"blockSize": { "$value": "{control.height.md}" },
623-
"paddingInline": { "$value": "14px" },
624-
"gap": { "$value": "{space.2}" },
625-
"iconSize": { "$value": "16px" },
634+
"paddingInline": { "$value": "10px" },
635+
"gap": { "$value": "{space.1}" },
636+
"iconSize": { "$value": "12px" },
626637
"radius": { "$value": "{radius.lg}" }
627638
},
628639
"changeCount": {
@@ -635,7 +646,7 @@
635646
"statusPill": {
636647
"$type": "dimension",
637648
"gap": { "$value": "2px" },
638-
"paddingBlock": { "$value": "3px" },
649+
"paddingBlock": { "$value": "2px" },
639650
"paddingInline": { "$value": "6px" },
640651
"radius": { "$value": "{radius.pill}" },
641652
"iconSize": { "$value": "14px" }

‎design-system/packages/design-tokens/tests/contract.test.mjs‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ test("StatusPill geometry preserves compact semantic status anatomy", async () =
114114
const systemDocument = await readSource("system.tokens.json");
115115

116116
assert.equal(tokens["control.statusPill.gap"], "2px");
117-
assert.equal(tokens["control.statusPill.paddingBlock"], "3px");
117+
assert.equal(tokens["control.statusPill.paddingBlock"], "2px");
118118
assert.equal(tokens["control.statusPill.paddingInline"], "6px");
119119
assert.equal(tokens["control.statusPill.iconSize"], "14px");
120120
assert.equal(systemDocument.control.statusPill.radius.$value, "{radius.pill}");
@@ -145,11 +145,11 @@ test("ActionCard geometry preserves compact and descriptive entry compositions",
145145
test("LauncherButton geometry preserves the shell-edge action contract", async () => {
146146
const systemDocument = await readSource("system.tokens.json");
147147

148-
assert.equal(tokens["control.launcherButton.minInlineSize"], "104px");
148+
assert.equal(tokens["control.launcherButton.minInlineSize"], "72px");
149149
assert.equal(tokens["control.launcherButton.blockSize"], "40px");
150-
assert.equal(tokens["control.launcherButton.paddingInline"], "14px");
151-
assert.equal(tokens["control.launcherButton.gap"], "8px");
152-
assert.equal(tokens["control.launcherButton.iconSize"], "16px");
150+
assert.equal(tokens["control.launcherButton.paddingInline"], "10px");
151+
assert.equal(tokens["control.launcherButton.gap"], "4px");
152+
assert.equal(tokens["control.launcherButton.iconSize"], "12px");
153153
assert.equal(
154154
systemDocument.control.launcherButton.radius.$value,
155155
"{radius.lg}",

‎design-system/packages/theme-openbitfun/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ in both root and chrome; generic palette projection previously reduced product
7979
menu labels to secondary text (60%). Explicit imported action colors still win.
8080

8181
Action cards own `color.actionCard.background`: the light entry surface is black at 3% opacity. `surface.subtle` is a transient navy tint and `field.groupBackground` belongs to form groups, so neither represents this persistent action surface. Other modes retain their neutral action surface. Product Appearance preserves explicit legacy neutral-surface overrides in root and chrome.
82+
83+
Compact indicators own `color.numberBadge.background` and `color.keyHint.content` so reference light values (8% fill and 60% text) can coexist with existing dark/contrast values and explicit legacy Appearance overrides. The light Switch off track and resting scrollbar thumb use 10% black; KeyHint and Launcher resting fills use 8%. Long status labels keep content colors; StatusPill emphasis is opt-in.

‎design-system/packages/theme-openbitfun/src/dark.tokens.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
}
2020
},
2121
"color": {
22+
"numberBadge": {
23+
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
24+
},
2225
"actionCard": {
2326
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
2427
},
@@ -60,6 +63,7 @@
6063
}
6164
},
6265
"keyHint": {
66+
"content": { "$type": "color", "$value": "{color.content.muted}" },
6367
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
6468
},
6569
"scrollbar": {

‎design-system/packages/theme-openbitfun/src/high-contrast-dark.tokens.json‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
}
2020
},
2121
"color": {
22+
"keyHint": {
23+
"content": { "$type": "color", "$value": "{color.content.muted}" }
24+
},
25+
"numberBadge": {
26+
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
27+
},
2228
"actionCard": {
2329
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
2430
},

‎design-system/packages/theme-openbitfun/src/high-contrast-light.tokens.json‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
}
2020
},
2121
"color": {
22+
"keyHint": {
23+
"content": { "$type": "color", "$value": "{color.content.muted}" }
24+
},
25+
"numberBadge": {
26+
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
27+
},
2228
"actionCard": {
2329
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
2430
},

‎design-system/packages/theme-openbitfun/src/light.tokens.json‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
}
2020
},
2121
"color": {
22+
"numberBadge": {
23+
"background": { "$type": "color", "$value": "{color.action.neutral.surfaceHover}" }
24+
},
2225
"actionCard": {
2326
"background": { "$type": "color", "$value": "rgba(0, 0, 0, 0.03)" }
2427
},
@@ -60,10 +63,11 @@
6063
}
6164
},
6265
"keyHint": {
63-
"background": { "$type": "color", "$value": "{color.action.neutral.surface}" }
66+
"content": { "$type": "color", "$value": "{color.content.secondary}" },
67+
"background": { "$type": "color", "$value": "{color.action.neutral.surfaceHover}" }
6468
},
6569
"scrollbar": {
66-
"thumb": { "$type": "color", "$value": "{color.action.neutral.surfaceHover}" },
70+
"thumb": { "$type": "color", "$value": "{color.action.neutral.surfacePressed}" },
6771
"thumbHover": { "$type": "color", "$value": "{color.action.neutral.surfacePressed}" }
6872
},
6973
"content": {
@@ -196,7 +200,7 @@
196200
},
197201
"launcher": {
198202
"$description": "Shell-edge launcher states: neutral at rest, then cyan-tinted with cyan content on hover and press.",
199-
"background": { "$type": "color", "$value": "{color.action.neutral.surfacePressed}" },
203+
"background": { "$type": "color", "$value": "{color.action.neutral.surfaceHover}" },
200204
"backgroundHover": { "$type": "color", "$value": "color-mix(in srgb, {color.control.highlight.background} 20%, transparent)" },
201205
"backgroundPressed": { "$type": "color", "$value": "color-mix(in srgb, {color.control.highlight.background} 30%, transparent)" },
202206
"content": { "$type": "color", "$value": "{color.action.neutral.content}" },
@@ -205,7 +209,7 @@
205209
"contentDisabled": { "$type": "color", "$value": "{color.action.neutral.contentDisabled}" }
206210
},
207211
"switch": {
208-
"track": { "$type": "color", "$value": "{ref.color.neutral.250}" },
212+
"track": { "$type": "color", "$value": "{color.action.neutral.surfacePressed}" },
209213
"trackChecked": { "$type": "color", "$value": "{color.control.highlight.background}" },
210214
"thumb": { "$type": "color", "$value": "{ref.color.neutral.0}" }
211215
}

0 commit comments

Comments
 (0)