@streamsai/ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +57 -2
- package/dist/components/ui/agent-avatar.d.ts +50 -0
- package/dist/components/ui/agent-avatar.js +38 -0
- package/dist/components/ui/alert-dialog.d.ts +12 -0
- package/dist/components/ui/alert-dialog.js +37 -0
- package/dist/components/ui/alert.d.ts +10 -0
- package/dist/components/ui/alert.js +28 -0
- package/dist/components/ui/assets/loader.json.js +1 -0
- package/dist/components/ui/avatar-frame.d.ts +11 -0
- package/dist/components/ui/avatar-frame.js +20 -0
- package/dist/components/ui/avatar.d.ts +23 -0
- package/dist/components/ui/avatar.js +54 -0
- package/dist/components/ui/badge.d.ts +7 -0
- package/dist/components/ui/badge.js +36 -0
- package/dist/components/ui/bar-list.d.ts +40 -0
- package/dist/components/ui/bar-list.js +37 -0
- package/dist/components/ui/breadcrumb.d.ts +8 -0
- package/dist/components/ui/breadcrumb.js +21 -0
- package/dist/components/ui/button-group.d.ts +10 -0
- package/dist/components/ui/button-group.js +41 -0
- package/dist/components/ui/button.d.ts +9 -0
- package/dist/components/ui/button.js +39 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.js +25 -0
- package/dist/components/ui/checkbox.d.ts +3 -0
- package/dist/components/ui/checkbox.js +16 -0
- package/dist/components/ui/chip.d.ts +13 -0
- package/dist/components/ui/chip.js +22 -0
- package/dist/components/ui/clickable.d.ts +27 -0
- package/dist/components/ui/clickable.js +54 -0
- package/dist/components/ui/code-block.d.ts +68 -0
- package/dist/components/ui/code-block.js +112 -0
- package/dist/components/ui/code-view.d.ts +21 -0
- package/dist/components/ui/code-view.js +20 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/collapsible.js +18 -0
- package/dist/components/ui/combobox.d.ts +14 -0
- package/dist/components/ui/combobox.js +37 -0
- package/dist/components/ui/command.d.ts +15 -0
- package/dist/components/ui/command.js +34 -0
- package/dist/components/ui/context-menu.d.ts +21 -0
- package/dist/components/ui/context-menu.js +60 -0
- package/dist/components/ui/counter.d.ts +11 -0
- package/dist/components/ui/counter.js +20 -0
- package/dist/components/ui/dialog.d.ts +17 -0
- package/dist/components/ui/dialog.js +41 -0
- package/dist/components/ui/disabled-reason.d.ts +22 -0
- package/dist/components/ui/disabled-reason.js +16 -0
- package/dist/components/ui/dropdown-menu.d.ts +33 -0
- package/dist/components/ui/dropdown-menu.js +58 -0
- package/dist/components/ui/editable-text.d.ts +95 -0
- package/dist/components/ui/editable-text.js +191 -0
- package/dist/components/ui/heading.d.ts +24 -0
- package/dist/components/ui/heading.js +92 -0
- package/dist/components/ui/hover-card.d.ts +9 -0
- package/dist/components/ui/hover-card.js +16 -0
- package/dist/components/ui/icon-button.d.ts +23 -0
- package/dist/components/ui/icon-button.js +32 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/input.js +8 -0
- package/dist/components/ui/kbd.d.ts +12 -0
- package/dist/components/ui/kbd.js +12 -0
- package/dist/components/ui/label.d.ts +3 -0
- package/dist/components/ui/label.js +7 -0
- package/dist/components/ui/loader.d.ts +19 -0
- package/dist/components/ui/loader.js +157 -0
- package/dist/components/ui/message-toolbar.d.ts +20 -0
- package/dist/components/ui/message-toolbar.js +17 -0
- package/dist/components/ui/modal.d.ts +30 -0
- package/dist/components/ui/modal.js +41 -0
- package/dist/components/ui/nav-item.d.ts +25 -0
- package/dist/components/ui/nav-item.js +66 -0
- package/dist/components/ui/panel-section.d.ts +22 -0
- package/dist/components/ui/panel-section.js +26 -0
- package/dist/components/ui/popover.d.ts +14 -0
- package/dist/components/ui/popover.js +30 -0
- package/dist/components/ui/progress.d.ts +5 -0
- package/dist/components/ui/progress.js +16 -0
- package/dist/components/ui/provider-badge.d.ts +22 -0
- package/dist/components/ui/provider-badge.js +38 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/radio-group.js +21 -0
- package/dist/components/ui/reply-summary.d.ts +16 -0
- package/dist/components/ui/reply-summary.js +8 -0
- package/dist/components/ui/resizable.d.ts +8 -0
- package/dist/components/ui/resizable.js +15 -0
- package/dist/components/ui/rich-text-editor.d.ts +447 -0
- package/dist/components/ui/rich-text-editor.js +2419 -0
- package/dist/components/ui/running-indicator.d.ts +17 -0
- package/dist/components/ui/running-indicator.js +34 -0
- package/dist/components/ui/sandboxed-frame.d.ts +29 -0
- package/dist/components/ui/sandboxed-frame.js +77 -0
- package/dist/components/ui/scroll-area.d.ts +14 -0
- package/dist/components/ui/scroll-area.js +17 -0
- package/dist/components/ui/section-header.d.ts +12 -0
- package/dist/components/ui/section-header.js +12 -0
- package/dist/components/ui/select.d.ts +15 -0
- package/dist/components/ui/select.js +40 -0
- package/dist/components/ui/separator.d.ts +3 -0
- package/dist/components/ui/separator.js +13 -0
- package/dist/components/ui/sheet.d.ts +23 -0
- package/dist/components/ui/sheet.js +48 -0
- package/dist/components/ui/shimmer-text.d.ts +26 -0
- package/dist/components/ui/shimmer-text.js +32 -0
- package/dist/components/ui/sidebar.d.ts +63 -0
- package/dist/components/ui/sidebar.js +283 -0
- package/dist/components/ui/skeleton.d.ts +14 -0
- package/dist/components/ui/skeleton.js +12 -0
- package/dist/components/ui/sonner.d.ts +4 -0
- package/dist/components/ui/sonner.js +14 -0
- package/dist/components/ui/spark-bars.d.ts +29 -0
- package/dist/components/ui/spark-bars.js +24 -0
- package/dist/components/ui/spinner.d.ts +16 -0
- package/dist/components/ui/spinner.js +26 -0
- package/dist/components/ui/stacked-bar.d.ts +37 -0
- package/dist/components/ui/stacked-bar.js +56 -0
- package/dist/components/ui/status-dot.d.ts +16 -0
- package/dist/components/ui/status-dot.js +32 -0
- package/dist/components/ui/switch.d.ts +5 -0
- package/dist/components/ui/switch.js +13 -0
- package/dist/components/ui/tabs.d.ts +14 -0
- package/dist/components/ui/tabs.js +55 -0
- package/dist/components/ui/text.d.ts +27 -0
- package/dist/components/ui/text.js +100 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/textarea.js +7 -0
- package/dist/components/ui/theme-toggle.d.ts +21 -0
- package/dist/components/ui/theme-toggle.js +17 -0
- package/dist/components/ui/toggle-group.d.ts +6 -0
- package/dist/components/ui/toggle-group.js +12 -0
- package/dist/components/ui/tooltip.d.ts +11 -0
- package/dist/components/ui/tooltip.js +21 -0
- package/dist/components/ui/trace.d.ts +24 -0
- package/dist/components/ui/trace.js +57 -0
- package/dist/components/ui/trend-line.d.ts +93 -0
- package/dist/components/ui/trend-line.js +215 -0
- package/dist/components/ui/truncate.d.ts +30 -0
- package/dist/components/ui/truncate.js +54 -0
- package/dist/components/ui/viewer-shell.d.ts +55 -0
- package/dist/components/ui/viewer-shell.js +15 -0
- package/dist/components/ui/virtual-list.d.ts +91 -0
- package/dist/components/ui/virtual-list.js +406 -0
- package/dist/components/ui/visually-hidden.d.ts +15 -0
- package/dist/components/ui/visually-hidden.js +19 -0
- package/dist/direction/index.d.ts +19 -0
- package/dist/direction/index.js +32 -0
- package/dist/hooks/use-code-highlighting.d.ts +22 -0
- package/dist/hooks/use-code-highlighting.js +47 -0
- package/dist/hooks/use-is-truncated.d.ts +7 -0
- package/dist/hooks/use-is-truncated.js +23 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.js +15 -0
- package/dist/icons/custom.d.ts +29 -0
- package/dist/icons/custom.js +48 -0
- package/dist/icons/index.d.ts +49 -0
- package/dist/icons/index.js +50 -0
- package/dist/icons/provider-logos.d.ts +17 -0
- package/dist/icons/provider-logos.js +28 -0
- package/dist/icons/providers.d.ts +9 -0
- package/dist/icons/providers.js +51 -0
- package/dist/index.d.ts +102 -0
- package/dist/index.js +124 -0
- package/dist/lib/code-highlighter.d.ts +9 -0
- package/dist/lib/code-highlighter.js +65 -0
- package/dist/lib/code-language.d.ts +13 -0
- package/dist/lib/code-language.js +103 -0
- package/dist/lib/code-tokens.d.ts +9 -0
- package/dist/lib/code-tokens.js +27 -0
- package/dist/lib/copy-text.d.ts +6 -0
- package/dist/lib/copy-text.js +46 -0
- package/dist/lib/home-tile.d.ts +12 -0
- package/dist/lib/home-tile.js +45 -0
- package/dist/lib/reveal-mask.d.ts +9 -0
- package/dist/lib/reveal-mask.js +16 -0
- package/dist/lib/text-direction.d.ts +28 -0
- package/dist/lib/text-direction.js +119 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.js +30 -0
- package/dist/motion/components.d.ts +184 -0
- package/dist/motion/components.js +211 -0
- package/dist/motion/config.d.ts +849 -0
- package/dist/motion/config.js +429 -0
- package/dist/motion/index.d.ts +8 -0
- package/dist/motion/index.js +8 -0
- package/dist/motion/modal-presence.d.ts +5 -0
- package/dist/motion/modal-presence.js +27 -0
- package/dist/motion/popup.d.ts +77 -0
- package/dist/motion/popup.js +103 -0
- package/dist/platform/index.d.ts +29 -0
- package/dist/platform/index.js +63 -0
- package/dist/styles/base.css +319 -0
- package/dist/styles/fonts/Figtree-Variable.woff2 +0 -0
- package/dist/styles/fonts/OFL.txt +93 -0
- package/dist/styles/fonts/Poppins-Medium.woff2 +0 -0
- package/dist/styles/fonts/Poppins-Regular.woff2 +0 -0
- package/dist/styles/fonts/Poppins-SemiBold.woff2 +0 -0
- package/dist/styles/fonts.css +28 -0
- package/dist/styles/globals.css +8 -0
- package/dist/styles/mcp-host.css +76 -0
- package/dist/styles/tokens.css +387 -0
- package/dist/styles/tokens.d.mts +57 -0
- package/dist/styles/tokens.mjs +59 -0
- package/dist/theme/index.d.ts +28 -0
- package/dist/theme/index.js +65 -0
- package/package.json +136 -3
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Design tokens — the single source of truth for streams theming.
|
|
3
|
+
*
|
|
4
|
+
* 1. primitive the Vibe palette the Workstreams Figma uses, prefixed --vibe-*.
|
|
5
|
+
* Components never reference these. Light on :root, dark on :root.dark.
|
|
6
|
+
* 2. semantic shadcn naming plus our additions. Each points at a primitive via var().
|
|
7
|
+
* 3. bridge `@theme inline` in globals.css → Tailwind utilities.
|
|
8
|
+
*
|
|
9
|
+
* Dark mode is ONE class, `.dark`, on <html>. ThemeProvider (src/theme) owns it. There is
|
|
10
|
+
* deliberately no `prefers-color-scheme` media query here: the provider resolves "system"
|
|
11
|
+
* and writes the class, so a user choice and the OS choice go through the same path.
|
|
12
|
+
* Keep primitive values in sync with tokens.mjs (tokens.test.ts enforces it).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/* --- 1. primitive, light ------------------------------------------------- */
|
|
16
|
+
:root {
|
|
17
|
+
--vibe-primary-color: #0073ea;
|
|
18
|
+
--vibe-primary-hover-color: #0060b9;
|
|
19
|
+
--vibe-primary-text-color: #323338;
|
|
20
|
+
--vibe-secondary-text-color: #676879;
|
|
21
|
+
--vibe-icon-color: #676879;
|
|
22
|
+
--vibe-primary-background-color: #ffffff;
|
|
23
|
+
--vibe-grey-background-color: #f6f7fb;
|
|
24
|
+
--vibe-primary-surface-color: #edf1fc;
|
|
25
|
+
--vibe-primary-selected-color: #cce4ff;
|
|
26
|
+
--vibe-primary-highlighted-color: #f0f7ff;
|
|
27
|
+
--vibe-primary-background-hover-color: #6768791a;
|
|
28
|
+
--vibe-layout-border-color: #d0d4e4;
|
|
29
|
+
--vibe-ui-border-color: #c3c6d4;
|
|
30
|
+
--vibe-ui-background-color: #e7e9ef;
|
|
31
|
+
--vibe-disabled-background-color: #ecedf5;
|
|
32
|
+
--vibe-disabled-text-color: #32333861;
|
|
33
|
+
--vibe-disabled-text-color-solid: #9595a1;
|
|
34
|
+
--vibe-placeholder-color: #676879;
|
|
35
|
+
--vibe-inverted-color-background: #323338;
|
|
36
|
+
--vibe-text-color-on-inverted: #ffffff;
|
|
37
|
+
--vibe-text-color-on-primary: #ffffff;
|
|
38
|
+
--vibe-color-stuck-red: #df2f4a;
|
|
39
|
+
--vibe-color-purple: #9d50dd;
|
|
40
|
+
--vibe-color-done-green: #00c875;
|
|
41
|
+
--vibe-color-done-green-strong: #00854d; /* iOS swipe/action fills */
|
|
42
|
+
--vibe-color-chili-blue: #66ccff;
|
|
43
|
+
--vibe-color-aquamarine: #00858a;
|
|
44
|
+
--vibe-color-done-green-selected-with-opacity: #80e3ba99;
|
|
45
|
+
--vibe-color-done-green-selected: #80e3ba;
|
|
46
|
+
--vibe-color-egg-yolk-selected: #ffe580;
|
|
47
|
+
--vibe-color-egg-yolk-text: #7a5a00; /* amber text on a yellow tint */
|
|
48
|
+
--vibe-color-egg-yolk-on-selected: #5c4300; /* text on the solid yellow */
|
|
49
|
+
--vibe-color-winter: #9aadbd;
|
|
50
|
+
--vibe-color-running-yellow: #f7c55e;
|
|
51
|
+
--vibe-color-running-halo: #fdeecf;
|
|
52
|
+
--vibe-color-running-green: #b7cf9f;
|
|
53
|
+
--vibe-color-running-green-halo: #e9f1e2;
|
|
54
|
+
--vibe-home-offline-banner: #eceff8;
|
|
55
|
+
--vibe-home-tile-1: #d4e2c5;
|
|
56
|
+
--vibe-home-tile-2: #d9e8fb;
|
|
57
|
+
--vibe-home-tile-3: #fbd4ba;
|
|
58
|
+
--vibe-home-tile-4: #fadd9e;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* --- 1b. primitive, dark -------------------------------------------------- */
|
|
62
|
+
:root:where(.dark) {
|
|
63
|
+
--vibe-primary-color: #0073ea;
|
|
64
|
+
--vibe-primary-hover-color: #1f76d2;
|
|
65
|
+
--vibe-primary-text-color: #eeeeee;
|
|
66
|
+
--vibe-secondary-text-color: #aaaaaa;
|
|
67
|
+
--vibe-icon-color: #aaaaaa;
|
|
68
|
+
--vibe-primary-background-color: #1e2026;
|
|
69
|
+
--vibe-grey-background-color: #111111;
|
|
70
|
+
--vibe-primary-surface-color: #22283a;
|
|
71
|
+
--vibe-primary-selected-color: #133774;
|
|
72
|
+
--vibe-primary-highlighted-color: #1b2436;
|
|
73
|
+
--vibe-primary-background-hover-color: #63636359;
|
|
74
|
+
--vibe-layout-border-color: #636363;
|
|
75
|
+
--vibe-ui-border-color: #636363;
|
|
76
|
+
--vibe-ui-background-color: #2f3138;
|
|
77
|
+
--vibe-disabled-background-color: #2a2b31;
|
|
78
|
+
--vibe-disabled-text-color: #eeeeee61;
|
|
79
|
+
--vibe-disabled-text-color-solid: #7a7a7a;
|
|
80
|
+
--vibe-placeholder-color: #aaaaaa;
|
|
81
|
+
--vibe-inverted-color-background: #eeeeee;
|
|
82
|
+
--vibe-text-color-on-inverted: #323338;
|
|
83
|
+
--vibe-text-color-on-primary: #ffffff;
|
|
84
|
+
--vibe-color-stuck-red: #e8697d;
|
|
85
|
+
--vibe-color-purple: #b072e6;
|
|
86
|
+
--vibe-color-done-green: #33d391;
|
|
87
|
+
--vibe-color-done-green-strong: #00a35c; /* iOS swipe/action fills */
|
|
88
|
+
--vibe-color-chili-blue: #66ccff;
|
|
89
|
+
--vibe-color-aquamarine: #4eccc6;
|
|
90
|
+
--vibe-color-done-green-selected-with-opacity: #80e3ba99;
|
|
91
|
+
--vibe-color-done-green-selected: #80e3ba;
|
|
92
|
+
--vibe-color-egg-yolk-selected: #ffe580;
|
|
93
|
+
--vibe-color-egg-yolk-text: #ffcb00;
|
|
94
|
+
--vibe-color-egg-yolk-on-selected: #5c4300;
|
|
95
|
+
--vibe-color-winter: #9aadbd;
|
|
96
|
+
--vibe-color-running-yellow: #f7c55e;
|
|
97
|
+
--vibe-color-running-halo: #5f5237;
|
|
98
|
+
--vibe-color-running-green: #b7cf9f;
|
|
99
|
+
--vibe-color-running-green-halo: #4c554a;
|
|
100
|
+
--vibe-home-offline-banner: #22283a;
|
|
101
|
+
--vibe-home-tile-1: #4a5545;
|
|
102
|
+
--vibe-home-tile-2: #3a4a60;
|
|
103
|
+
--vibe-home-tile-3: #62483a;
|
|
104
|
+
--vibe-home-tile-4: #625433;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* --- 2. semantic (light and dark share this block: every value is a var()) -- */
|
|
108
|
+
:root {
|
|
109
|
+
color-scheme: light;
|
|
110
|
+
|
|
111
|
+
--background: var(--vibe-primary-background-color);
|
|
112
|
+
--foreground: var(--vibe-primary-text-color);
|
|
113
|
+
--card: var(--vibe-primary-background-color);
|
|
114
|
+
--card-foreground: var(--vibe-primary-text-color);
|
|
115
|
+
--popover: var(--vibe-primary-background-color);
|
|
116
|
+
--popover-foreground: var(--vibe-primary-text-color);
|
|
117
|
+
|
|
118
|
+
--primary: var(--vibe-primary-color);
|
|
119
|
+
--primary-hover: var(--vibe-primary-hover-color);
|
|
120
|
+
--primary-foreground: var(--vibe-text-color-on-primary);
|
|
121
|
+
--secondary: var(--vibe-ui-background-color);
|
|
122
|
+
--secondary-foreground: var(--vibe-primary-text-color);
|
|
123
|
+
--muted: var(--vibe-grey-background-color);
|
|
124
|
+
--muted-foreground: var(--vibe-secondary-text-color);
|
|
125
|
+
--accent: var(--vibe-primary-background-hover-color);
|
|
126
|
+
--accent-foreground: var(--vibe-primary-text-color);
|
|
127
|
+
--destructive: var(--vibe-color-stuck-red);
|
|
128
|
+
--destructive-foreground: var(--vibe-text-color-on-primary);
|
|
129
|
+
|
|
130
|
+
--border: var(--vibe-layout-border-color);
|
|
131
|
+
--input: var(--vibe-ui-border-color);
|
|
132
|
+
--ring: var(--vibe-primary-color);
|
|
133
|
+
|
|
134
|
+
/* Ours — the Figma needs these and shadcn has no name for them. */
|
|
135
|
+
--selected: var(--vibe-primary-selected-color);
|
|
136
|
+
--selected-foreground: var(--vibe-primary-text-color);
|
|
137
|
+
--highlight: var(--vibe-primary-highlighted-color);
|
|
138
|
+
--icon: var(--vibe-icon-color);
|
|
139
|
+
--disabled: var(--vibe-disabled-background-color);
|
|
140
|
+
--disabled-foreground: var(--vibe-disabled-text-color);
|
|
141
|
+
--placeholder: var(--vibe-placeholder-color);
|
|
142
|
+
--inverted: var(--vibe-inverted-color-background);
|
|
143
|
+
--inverted-foreground: var(--vibe-text-color-on-inverted);
|
|
144
|
+
--surface-1: var(
|
|
145
|
+
--vibe-grey-background-color
|
|
146
|
+
); /* one step off the page: sidebar, pills, thread root */
|
|
147
|
+
--surface-primary: var(
|
|
148
|
+
--vibe-primary-surface-color
|
|
149
|
+
); /* tinted surface: mentions, chips, AI accents */
|
|
150
|
+
--status-idle: var(--vibe-icon-color);
|
|
151
|
+
--status-working: var(--vibe-color-purple);
|
|
152
|
+
--status-done: var(--vibe-color-done-green);
|
|
153
|
+
--status-stuck: var(--vibe-color-stuck-red);
|
|
154
|
+
/* The one yellow / green for progress: a cycle run's in-progress and completed accents, in the
|
|
155
|
+
run bar, the message bar and the segments. Use these, not a new shade. */
|
|
156
|
+
--warning: var(--vibe-color-egg-yolk-selected);
|
|
157
|
+
/* Text on solid `--warning` (the number in the current phase's circle). Dark in both themes: the yellow is the same in both. */
|
|
158
|
+
--warning-foreground: var(--vibe-color-egg-yolk-on-selected);
|
|
159
|
+
--positive: var(--vibe-color-done-green-selected);
|
|
160
|
+
/* Text and icons on a white surface that say "done": the answered check in a submitted form. */
|
|
161
|
+
--positive-foreground: var(--vibe-color-done-green-strong);
|
|
162
|
+
/* Quieter than muted-foreground: character counters, "No answer". Not for anything that must be read. */
|
|
163
|
+
--subtle-foreground: var(--vibe-disabled-text-color-solid);
|
|
164
|
+
/* A stopped run's remaining phases. */
|
|
165
|
+
--run-stopped: var(--vibe-color-winter);
|
|
166
|
+
/* Advance chip text on a phase card: dark teal on `--positive` ("Auto advance") and amber on
|
|
167
|
+
`--warning` ("Human advance"), so the chips match the progress segments. */
|
|
168
|
+
--accent-teal: var(--vibe-color-aquamarine);
|
|
169
|
+
--accent-yellow: var(--vibe-color-egg-yolk-text);
|
|
170
|
+
/* Vibe's aquamarine, following its dark value: the "Auto advance" chip text, on a 10% tint of itself. */
|
|
171
|
+
--aquamarine: var(--vibe-color-aquamarine);
|
|
172
|
+
/* Vibe's purple, following its dark value: a condition's badge and icon tile in the cycle builder, on a 12% tint of itself. */
|
|
173
|
+
--accent-purple: var(--vibe-color-purple);
|
|
174
|
+
/* Vibe's negative color (stuck red), following its dark value: the "Fill in required fields" chip text, on a 10% tint of itself. */
|
|
175
|
+
--negative: var(--vibe-color-stuck-red);
|
|
176
|
+
/* Avatar fallbacks: chili blue for people, purple for agents. */
|
|
177
|
+
--avatar-person: var(--vibe-color-chili-blue);
|
|
178
|
+
--avatar-agent: var(--vibe-color-purple);
|
|
179
|
+
|
|
180
|
+
/* Mobile Home (iOS Streams tab, mweb /home). Scoped names so the desktop sidebar and the shared
|
|
181
|
+
`--status-working` purple stay as they are. */
|
|
182
|
+
--home-canvas: var(--vibe-grey-background-color);
|
|
183
|
+
--home-card: var(--vibe-primary-background-color);
|
|
184
|
+
--home-chip: var(--vibe-primary-background-color);
|
|
185
|
+
--home-chip-selected: var(--vibe-inverted-color-background);
|
|
186
|
+
--home-chip-selected-foreground: var(--vibe-text-color-on-inverted);
|
|
187
|
+
--home-skeleton: var(--vibe-ui-background-color);
|
|
188
|
+
--home-offline-banner: var(--vibe-home-offline-banner);
|
|
189
|
+
--home-running: var(--vibe-color-running-green);
|
|
190
|
+
--home-running-halo: var(--vibe-color-running-green-halo);
|
|
191
|
+
--home-tile-1: var(--vibe-home-tile-1);
|
|
192
|
+
--home-tile-2: var(--vibe-home-tile-2);
|
|
193
|
+
--home-tile-3: var(--vibe-home-tile-3);
|
|
194
|
+
--home-tile-4: var(--vibe-home-tile-4);
|
|
195
|
+
|
|
196
|
+
--sidebar: var(--vibe-grey-background-color);
|
|
197
|
+
--sidebar-foreground: var(--vibe-primary-text-color);
|
|
198
|
+
--sidebar-primary: var(--vibe-primary-color);
|
|
199
|
+
--sidebar-primary-foreground: var(--vibe-text-color-on-primary);
|
|
200
|
+
--sidebar-accent: var(--vibe-primary-background-hover-color);
|
|
201
|
+
--sidebar-accent-foreground: var(--vibe-primary-text-color);
|
|
202
|
+
--sidebar-border: var(--vibe-layout-border-color);
|
|
203
|
+
--sidebar-ring: var(--vibe-primary-color);
|
|
204
|
+
|
|
205
|
+
--chart-1: var(--primary);
|
|
206
|
+
--chart-2: color-mix(in oklab, var(--primary) 76%, var(--background));
|
|
207
|
+
--chart-3: color-mix(in oklab, var(--primary) 56%, var(--background));
|
|
208
|
+
--chart-4: color-mix(in oklab, var(--primary) 38%, var(--background));
|
|
209
|
+
--chart-5: color-mix(in oklab, var(--primary) 24%, var(--background));
|
|
210
|
+
|
|
211
|
+
/* Chart card (mcp-apps Chart). Data colours are fixed per palette, the same in light and dark, so
|
|
212
|
+
a series keeps its colour when the theme flips: the design's four palettes, six slots each. */
|
|
213
|
+
--chart-vibe-1: #0073ea;
|
|
214
|
+
--chart-vibe-2: #9d50dd;
|
|
215
|
+
--chart-vibe-3: #00c875;
|
|
216
|
+
--chart-vibe-4: #ffcb00;
|
|
217
|
+
--chart-vibe-5: #df2f4a;
|
|
218
|
+
--chart-vibe-6: #66ccff;
|
|
219
|
+
--chart-ocean-1: #0073ea;
|
|
220
|
+
--chart-ocean-2: #66ccff;
|
|
221
|
+
--chart-ocean-3: #00858a;
|
|
222
|
+
--chart-ocean-4: #9aadbd;
|
|
223
|
+
--chart-ocean-5: #133774;
|
|
224
|
+
--chart-ocean-6: #80e3ba;
|
|
225
|
+
--chart-berry-1: #9d50dd;
|
|
226
|
+
--chart-berry-2: #df2f4a;
|
|
227
|
+
--chart-berry-3: #ffcb00;
|
|
228
|
+
--chart-berry-4: #0073ea;
|
|
229
|
+
--chart-berry-5: #ff642e;
|
|
230
|
+
--chart-berry-6: #66ccff;
|
|
231
|
+
--chart-mono-1: #0073ea;
|
|
232
|
+
--chart-mono-2: #3d8fee;
|
|
233
|
+
--chart-mono-3: #7aaef3;
|
|
234
|
+
--chart-mono-4: #a9c7f7;
|
|
235
|
+
--chart-mono-5: #d4e3fb;
|
|
236
|
+
--chart-mono-6: #133774;
|
|
237
|
+
/* Chart furniture follows the theme. */
|
|
238
|
+
--chart-axis: var(--muted-foreground);
|
|
239
|
+
--chart-label: var(--foreground);
|
|
240
|
+
--chart-grid: var(--secondary);
|
|
241
|
+
--chart-baseline: var(--input);
|
|
242
|
+
--chart-guide: var(--input);
|
|
243
|
+
--chart-point-fill: var(--card);
|
|
244
|
+
--chart-gantt-done: var(--positive);
|
|
245
|
+
--chart-gantt-done-text: var(--positive-foreground);
|
|
246
|
+
--chart-gantt-progress: var(--warning);
|
|
247
|
+
--chart-gantt-progress-text: var(--accent-yellow);
|
|
248
|
+
--chart-gantt-upcoming: var(--secondary);
|
|
249
|
+
--chart-gantt-upcoming-text: var(--muted-foreground);
|
|
250
|
+
--chart-today: var(--primary);
|
|
251
|
+
--chart-on-fill: #ffffff;
|
|
252
|
+
--chart-on-fill-soft: rgba(255, 255, 255, 0.85);
|
|
253
|
+
/* A PNG export is always drawn on white, so it reads the light values of the furniture whatever
|
|
254
|
+
the theme is. */
|
|
255
|
+
--chart-export-background: #ffffff;
|
|
256
|
+
--chart-export-axis: #676879;
|
|
257
|
+
--chart-export-label: #323338;
|
|
258
|
+
--chart-export-grid: #e7e9ef;
|
|
259
|
+
--chart-export-baseline: #c3c6d4;
|
|
260
|
+
--chart-export-guide: #c3c6d4;
|
|
261
|
+
--chart-export-point-fill: #ffffff;
|
|
262
|
+
--chart-export-gantt-done: #80e3ba;
|
|
263
|
+
--chart-export-gantt-done-text: #00854d;
|
|
264
|
+
--chart-export-gantt-progress: #ffe580;
|
|
265
|
+
--chart-export-gantt-progress-text: #7a5a00;
|
|
266
|
+
--chart-export-gantt-upcoming: #e7e9ef;
|
|
267
|
+
--chart-export-gantt-upcoming-text: #676879;
|
|
268
|
+
--chart-export-today: #0073ea;
|
|
269
|
+
|
|
270
|
+
--radius: 0.5rem; /* Vibe medium 8px; the bridge derives sm 4px from it */
|
|
271
|
+
|
|
272
|
+
/* Type. Figtree for UI text, Poppins for titles. Named --font-ui/--font-heading/--font-code
|
|
273
|
+
* because a `@theme inline` entry reading `--font-sans: var(--font-sans)` would be circular. */
|
|
274
|
+
--font-ui: 'Figtree', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
275
|
+
--font-heading: 'Poppins', var(--font-ui);
|
|
276
|
+
--font-code: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Consolas, monospace;
|
|
277
|
+
/* Color-emoji glyphs only (reaction pills). Named -stack so @theme `--font-emoji` is not circular. */
|
|
278
|
+
--font-emoji-stack: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
|
|
279
|
+
/* Vibe text scale: Text1 16/22, Text2 14/20 (default), Text3 12/16, H3 18/24. */
|
|
280
|
+
--type-body-1: 1rem;
|
|
281
|
+
--type-body-1-lh: 1.375rem;
|
|
282
|
+
--type-body-2: 0.875rem;
|
|
283
|
+
--type-body-2-lh: 1.25rem;
|
|
284
|
+
--type-body-3: 0.75rem;
|
|
285
|
+
--type-body-3-lh: 1rem;
|
|
286
|
+
--type-h3: 1.125rem;
|
|
287
|
+
--type-h3-lh: 1.5rem;
|
|
288
|
+
--type-h3-tracking: -0.03125rem; /* -0.5px */
|
|
289
|
+
|
|
290
|
+
/* Elevation. Figma: XS, Small, Medium. `lg` reuses Medium so shadow-lg keeps working. */
|
|
291
|
+
--shadow-color: #000000;
|
|
292
|
+
--elevation-xs: 0 4px 6px -4px color-mix(in srgb, var(--shadow-color) 10%, transparent);
|
|
293
|
+
--elevation-sm: 0 4px 8px 0 color-mix(in srgb, var(--shadow-color) 20%, transparent);
|
|
294
|
+
--elevation-md: 0 6px 20px 0 color-mix(in srgb, var(--shadow-color) 20%, transparent);
|
|
295
|
+
--elevation-lg: var(--elevation-md);
|
|
296
|
+
/* Small's spread at a lighter tint, for cards resting on a page surface. */
|
|
297
|
+
--elevation-card: 0 4px 8px 0 color-mix(in srgb, var(--shadow-color) 12%, transparent);
|
|
298
|
+
/* Tight and a little darker than Small, for a pill that shares its colour with the page (mobile dark). */
|
|
299
|
+
--elevation-pill: 0 2px 4px 0 color-mix(in srgb, var(--shadow-color) 35%, transparent);
|
|
300
|
+
|
|
301
|
+
/* Layout — unchanged, plus the nav width the sidebar reads instead of a JS constant. */
|
|
302
|
+
--nav-w: 17.5rem; /* 280px, LEFT_SIDEBAR_DEFAULT_WIDTH */
|
|
303
|
+
--nav-w-icon: 3rem;
|
|
304
|
+
--content-max: 62rem; /* 992px, the shared reading column (chat, analytics, agents) */
|
|
305
|
+
--bar-h: 3.5rem; /* 56px, the Figma pane header */
|
|
306
|
+
--panel-w: 22.5rem; /* 360px, the Figma right pane */
|
|
307
|
+
--panel-w-lg: 26rem;
|
|
308
|
+
--chat-min: 20rem;
|
|
309
|
+
--message-size: 1rem;
|
|
310
|
+
|
|
311
|
+
--z-base: 0;
|
|
312
|
+
--z-sticky: 100;
|
|
313
|
+
--z-overlay: 300;
|
|
314
|
+
--z-modal: 400;
|
|
315
|
+
--z-dropdown: 450;
|
|
316
|
+
--z-toast: 500;
|
|
317
|
+
|
|
318
|
+
/* Mirrors `duration` and `ease` in src/motion/config.ts (the one place motion is tuned;
|
|
319
|
+
* config.test.ts fails when these drift). Only the CSS exceptions read them: the default
|
|
320
|
+
* hover transition timing in globals.css and the mobile View Transitions. */
|
|
321
|
+
--motion-short: 100ms;
|
|
322
|
+
--motion-fast: 120ms;
|
|
323
|
+
--motion-base: 200ms;
|
|
324
|
+
--motion-slow: 320ms;
|
|
325
|
+
--motion-reveal: 480ms;
|
|
326
|
+
--motion-ease: cubic-bezier(0.4, 0, 0.2, 1);
|
|
327
|
+
--motion-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
328
|
+
--motion-ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
329
|
+
--motion-ease-enter: cubic-bezier(0, 0, 0.2, 1);
|
|
330
|
+
--motion-ease-exit: cubic-bezier(0.6, 0, 1, 1);
|
|
331
|
+
|
|
332
|
+
--tap-target: 1.5rem;
|
|
333
|
+
--safe-area-bottom: 0px;
|
|
334
|
+
|
|
335
|
+
--brand-from: #04f6fb;
|
|
336
|
+
--brand-via: #286afd;
|
|
337
|
+
--brand-to: #9351fd;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* --- 2a. syntax highlighting (CodeView) ------------------------------------
|
|
341
|
+
* The variables Shiki's CSS-variables theme reads (`variablePrefix: '--code-'`). Every value is a
|
|
342
|
+
* var() of a primitive, so the `.dark` class re-tints them and no dark block is needed. Picked for
|
|
343
|
+
* contrast on both page backgrounds: done-green-strong rather than done-green for strings. */
|
|
344
|
+
:root {
|
|
345
|
+
--code-foreground: var(--foreground);
|
|
346
|
+
--code-background: transparent;
|
|
347
|
+
--code-token-constant: var(--vibe-color-aquamarine);
|
|
348
|
+
--code-token-string: var(--vibe-color-done-green-strong);
|
|
349
|
+
--code-token-comment: var(--vibe-secondary-text-color);
|
|
350
|
+
--code-token-keyword: var(--vibe-color-purple);
|
|
351
|
+
--code-token-parameter: var(--vibe-color-egg-yolk-text);
|
|
352
|
+
--code-token-function: var(--vibe-primary-color);
|
|
353
|
+
--code-token-string-expression: var(--vibe-color-done-green-strong);
|
|
354
|
+
--code-token-punctuation: var(--vibe-secondary-text-color);
|
|
355
|
+
--code-token-link: var(--vibe-primary-color);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* --- 2b. dark: only what is not a plain var() re-read ---------------------- */
|
|
359
|
+
:root:where(.dark) {
|
|
360
|
+
color-scheme: dark;
|
|
361
|
+
--card: var(--vibe-ui-background-color);
|
|
362
|
+
--popover: var(--vibe-ui-background-color);
|
|
363
|
+
/* `--positive` / `--warning` stay pastel in dark, so the chip text keeps its light-theme shade. */
|
|
364
|
+
--accent-teal: #00858a;
|
|
365
|
+
--accent-yellow: #7a5a00;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/*
|
|
369
|
+
* --- 2c. semantic: mobile ------------------------------------------------
|
|
370
|
+
* A deliberate subset, not a second theme. Everything not listed inherits.
|
|
371
|
+
*/
|
|
372
|
+
|
|
373
|
+
:root:where([data-platform='mobile']) {
|
|
374
|
+
--radius: 0.875rem;
|
|
375
|
+
--tap-target: 2.75rem; /* 44px — the platform minimum */
|
|
376
|
+
--safe-area-bottom: env(safe-area-inset-bottom, 0px);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
:root:where(.dark[data-platform='mobile']) {
|
|
380
|
+
/* Mobile dark sits one step lighter than web dark; OLED pure black smears on scroll. */
|
|
381
|
+
--background: var(--vibe-ui-background-color);
|
|
382
|
+
--card: var(--vibe-ui-background-color);
|
|
383
|
+
--popover: var(--vibe-ui-background-color);
|
|
384
|
+
/* `--positive` / `--warning` stay pastel in dark, so the chip text keeps its light-theme shade. */
|
|
385
|
+
--accent-teal: #00858a;
|
|
386
|
+
--accent-yellow: #7a5a00;
|
|
387
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
type ColorPair = { light: string; dark: string }
|
|
2
|
+
|
|
3
|
+
export declare const colors: {
|
|
4
|
+
'primary-color': ColorPair
|
|
5
|
+
'primary-hover-color': ColorPair
|
|
6
|
+
'primary-text-color': ColorPair
|
|
7
|
+
'secondary-text-color': ColorPair
|
|
8
|
+
'icon-color': ColorPair
|
|
9
|
+
'primary-background-color': ColorPair
|
|
10
|
+
'grey-background-color': ColorPair
|
|
11
|
+
'primary-surface-color': ColorPair
|
|
12
|
+
'primary-selected-color': ColorPair
|
|
13
|
+
'primary-highlighted-color': ColorPair
|
|
14
|
+
'layout-border-color': ColorPair
|
|
15
|
+
'ui-border-color': ColorPair
|
|
16
|
+
'ui-background-color': ColorPair
|
|
17
|
+
'disabled-background-color': ColorPair
|
|
18
|
+
'disabled-text-color-solid': ColorPair
|
|
19
|
+
'placeholder-color': ColorPair
|
|
20
|
+
'inverted-color-background': ColorPair
|
|
21
|
+
'text-color-on-inverted': ColorPair
|
|
22
|
+
'text-color-on-primary': ColorPair
|
|
23
|
+
'color-stuck-red': ColorPair
|
|
24
|
+
'color-purple': ColorPair
|
|
25
|
+
'color-done-green': ColorPair
|
|
26
|
+
'color-done-green-strong': ColorPair
|
|
27
|
+
'color-done-green-selected': ColorPair
|
|
28
|
+
'color-egg-yolk-selected': ColorPair
|
|
29
|
+
'color-winter': ColorPair
|
|
30
|
+
'color-chili-blue': ColorPair
|
|
31
|
+
'color-running-yellow': ColorPair
|
|
32
|
+
'color-running-green': ColorPair
|
|
33
|
+
'color-running-green-halo': ColorPair
|
|
34
|
+
'color-running-halo': ColorPair
|
|
35
|
+
'home-offline-banner': ColorPair
|
|
36
|
+
'home-tile-1': ColorPair
|
|
37
|
+
'home-tile-2': ColorPair
|
|
38
|
+
'home-tile-3': ColorPair
|
|
39
|
+
'home-tile-4': ColorPair
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare const alphaColors: {
|
|
43
|
+
'primary-background-hover-color': ColorPair
|
|
44
|
+
'disabled-text-color': ColorPair
|
|
45
|
+
'color-done-green-selected-with-opacity': ColorPair
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export declare const spacing: {
|
|
49
|
+
xs: number
|
|
50
|
+
sm: number
|
|
51
|
+
md: number
|
|
52
|
+
lg: number
|
|
53
|
+
xl: number
|
|
54
|
+
xxl: number
|
|
55
|
+
xxxl: number
|
|
56
|
+
}
|
|
57
|
+
export declare const radius: { small: number; medium: number; large: number; full: number }
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Primitive palette shared by tokens.css (web) and apps/iOS/tools/gen-tokens.mjs.
|
|
2
|
+
// Values are the Vibe tokens used by the Workstreams Figma (page "Ready For Dev").
|
|
3
|
+
// Dark values marked `derived` are not in the Figma; see docs/design/vibe-shadcn-parity.md.
|
|
4
|
+
export const colors = {
|
|
5
|
+
'primary-color': { light: '#0073ea', dark: '#0073ea' },
|
|
6
|
+
'primary-hover-color': { light: '#0060b9', dark: '#1f76d2' }, // derived dark
|
|
7
|
+
'primary-text-color': { light: '#323338', dark: '#eeeeee' },
|
|
8
|
+
'secondary-text-color': { light: '#676879', dark: '#aaaaaa' },
|
|
9
|
+
'icon-color': { light: '#676879', dark: '#aaaaaa' },
|
|
10
|
+
'primary-background-color': { light: '#ffffff', dark: '#1e2026' },
|
|
11
|
+
'grey-background-color': { light: '#f6f7fb', dark: '#111111' },
|
|
12
|
+
'primary-surface-color': { light: '#edf1fc', dark: '#22283a' }, // derived dark
|
|
13
|
+
'primary-selected-color': { light: '#cce4ff', dark: '#133774' },
|
|
14
|
+
'primary-highlighted-color': { light: '#f0f7ff', dark: '#1b2436' }, // derived dark
|
|
15
|
+
'layout-border-color': { light: '#d0d4e4', dark: '#636363' },
|
|
16
|
+
'ui-border-color': { light: '#c3c6d4', dark: '#636363' },
|
|
17
|
+
'ui-background-color': { light: '#e7e9ef', dark: '#2f3138' }, // derived dark
|
|
18
|
+
'disabled-background-color': { light: '#ecedf5', dark: '#2a2b31' }, // derived dark
|
|
19
|
+
'disabled-text-color-solid': { light: '#9595a1', dark: '#7a7a7a' }, // derived dark
|
|
20
|
+
'placeholder-color': { light: '#676879', dark: '#aaaaaa' },
|
|
21
|
+
'inverted-color-background': { light: '#323338', dark: '#eeeeee' },
|
|
22
|
+
'text-color-on-inverted': { light: '#ffffff', dark: '#323338' },
|
|
23
|
+
// Always white: primary stays #0073ea in both schemes (unlike inverted, which flips).
|
|
24
|
+
'text-color-on-primary': { light: '#ffffff', dark: '#ffffff' },
|
|
25
|
+
'color-stuck-red': { light: '#df2f4a', dark: '#e8697d' },
|
|
26
|
+
'color-purple': { light: '#9d50dd', dark: '#b072e6' }, // derived dark
|
|
27
|
+
'color-done-green': { light: '#00c875', dark: '#33d391' }, // solid form of #80e3ba99
|
|
28
|
+
'color-done-green-strong': { light: '#00854d', dark: '#00a35c' }, // iOS swipe/action fills
|
|
29
|
+
// The one yellow / green for run and phase progress (--warning / --positive), and a stopped run's grey-blue.
|
|
30
|
+
'color-done-green-selected': { light: '#80e3ba', dark: '#80e3ba' },
|
|
31
|
+
'color-egg-yolk-selected': { light: '#ffe580', dark: '#ffe580' },
|
|
32
|
+
'color-winter': { light: '#9aadbd', dark: '#9aadbd' },
|
|
33
|
+
'color-chili-blue': { light: '#66ccff', dark: '#66ccff' }, // a person's square avatar fallback
|
|
34
|
+
// Mobile Home (iOS Streams tab and mweb /home). Light values are sampled from the design PNG;
|
|
35
|
+
// dark values are derived from the dark theme until Design supplies them.
|
|
36
|
+
'color-running-yellow': { light: '#f7c55e', dark: '#f7c55e' }, // a Running session's dot
|
|
37
|
+
'color-running-green': { light: '#b7cf9f', dark: '#b7cf9f' }, // mweb Running dot: the pastel green from Figma
|
|
38
|
+
'color-running-green-halo': { light: '#e9f1e2', dark: '#4c554a' }, // that dot at 30% over the card, composited
|
|
39
|
+
'color-running-halo': { light: '#fdeecf', dark: '#5f5237' }, // that dot at 30% over the card, composited
|
|
40
|
+
'home-offline-banner': { light: '#eceff8', dark: '#22283a' },
|
|
41
|
+
// Stream tile backgrounds, the four pastels from the Home design. `homeTileIndex` picks from them
|
|
42
|
+
// by rendezvous hashing: append a new colour (and bump HOME_TILE_COUNT here and in iOS
|
|
43
|
+
// HomeTileColor) and only ~1/(N+1) of streams change. Never reorder or insert.
|
|
44
|
+
'home-tile-1': { light: '#d4e2c5', dark: '#4a5545' }, // green
|
|
45
|
+
'home-tile-2': { light: '#d9e8fb', dark: '#3a4a60' }, // blue
|
|
46
|
+
'home-tile-3': { light: '#fbd4ba', dark: '#62483a' }, // peach
|
|
47
|
+
'home-tile-4': { light: '#fadd9e', dark: '#625433' }, // yellow
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Alpha tokens stay as CSS-only values (hex with alpha); listed so the parity doc and
|
|
51
|
+
// tokens.css agree. Not exported to iOS (SwiftUI colours are opaque there).
|
|
52
|
+
export const alphaColors = {
|
|
53
|
+
'primary-background-hover-color': { light: '#6768791a', dark: '#63636359' },
|
|
54
|
+
'disabled-text-color': { light: '#32333861', dark: '#eeeeee61' },
|
|
55
|
+
'color-done-green-selected-with-opacity': { light: '#80e3ba99', dark: '#80e3ba99' },
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const spacing = { xs: 2, sm: 4, md: 8, lg: 12, xl: 16, xxl: 24, xxxl: 64 }
|
|
59
|
+
export const radius = { small: 4, medium: 8, large: 12, full: 999 }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @no-story Context provider — renders no UI; toggles the `dark` class on <html>.
|
|
3
|
+
*/
|
|
4
|
+
import { type ReactNode } from 'react';
|
|
5
|
+
type Theme = 'system' | 'light' | 'dark';
|
|
6
|
+
type ResolvedTheme = 'light' | 'dark';
|
|
7
|
+
declare const THEME_STORAGE_KEY = "streams.theme";
|
|
8
|
+
/**
|
|
9
|
+
* Inline this in <head> before any stylesheet paints so a stored dark choice never flashes
|
|
10
|
+
* light. Precedence: native host `colorScheme` (chat webview) → stored theme → OS preference, light
|
|
11
|
+
* where the browser cannot report one.
|
|
12
|
+
* Must stay in sync with THEME_STORAGE_KEY and MobileShell's host-follow path.
|
|
13
|
+
*/
|
|
14
|
+
declare const THEME_INIT_SCRIPT = "(function(){try{var n=window.__STREAMS_NATIVE__&&window.__STREAMS_NATIVE__.colorScheme;var t=localStorage.getItem('streams.theme');var d=n==='dark'||(n!=='light'&&n!=='dark'&&(t==='dark'||(t!=='light'&&!!window.matchMedia&&matchMedia('(prefers-color-scheme: dark)').matches)));document.documentElement.classList.toggle('dark',!!d)}catch(e){}})()";
|
|
15
|
+
interface ThemeContextValue {
|
|
16
|
+
theme: Theme;
|
|
17
|
+
resolvedTheme: ResolvedTheme;
|
|
18
|
+
setTheme: (theme: Theme) => void;
|
|
19
|
+
}
|
|
20
|
+
interface ThemeProviderProps {
|
|
21
|
+
/** Used when nothing is stored. Defaults to `'system'`, which `THEME_INIT_SCRIPT` assumes. */
|
|
22
|
+
defaultTheme?: Theme;
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
}
|
|
25
|
+
declare function ThemeProvider({ defaultTheme, children }: ThemeProviderProps): import("react").JSX.Element;
|
|
26
|
+
declare function useTheme(): ThemeContextValue;
|
|
27
|
+
export type { Theme, ResolvedTheme, ThemeProviderProps };
|
|
28
|
+
export { ThemeProvider, useTheme, THEME_STORAGE_KEY, THEME_INIT_SCRIPT };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* @no-story Context provider — renders no UI; toggles the `dark` class on <html>.
|
|
4
|
+
*/
|
|
5
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react';
|
|
6
|
+
const THEME_STORAGE_KEY = 'streams.theme';
|
|
7
|
+
const DARK_QUERY = '(prefers-color-scheme: dark)';
|
|
8
|
+
/**
|
|
9
|
+
* Inline this in <head> before any stylesheet paints so a stored dark choice never flashes
|
|
10
|
+
* light. Precedence: native host `colorScheme` (chat webview) → stored theme → OS preference, light
|
|
11
|
+
* where the browser cannot report one.
|
|
12
|
+
* Must stay in sync with THEME_STORAGE_KEY and MobileShell's host-follow path.
|
|
13
|
+
*/
|
|
14
|
+
const THEME_INIT_SCRIPT = `(function(){try{var n=window.__STREAMS_NATIVE__&&window.__STREAMS_NATIVE__.colorScheme;var t=localStorage.getItem('${THEME_STORAGE_KEY}');var d=n==='dark'||(n!=='light'&&n!=='dark'&&(t==='dark'||(t!=='light'&&!!window.matchMedia&&matchMedia('${DARK_QUERY}').matches)));document.documentElement.classList.toggle('dark',!!d)}catch(e){}})()`;
|
|
15
|
+
const ThemeContext = createContext(null);
|
|
16
|
+
const isTheme = (v) => v === 'system' || v === 'light' || v === 'dark';
|
|
17
|
+
function readStored() {
|
|
18
|
+
if (typeof localStorage === 'undefined')
|
|
19
|
+
return null;
|
|
20
|
+
const v = localStorage.getItem(THEME_STORAGE_KEY);
|
|
21
|
+
return isTheme(v) ? v : null;
|
|
22
|
+
}
|
|
23
|
+
function systemPrefersDark() {
|
|
24
|
+
if (typeof matchMedia === 'undefined')
|
|
25
|
+
return false;
|
|
26
|
+
return matchMedia(DARK_QUERY).matches;
|
|
27
|
+
}
|
|
28
|
+
function resolve(theme, systemDark) {
|
|
29
|
+
if (theme === 'system')
|
|
30
|
+
return systemDark ? 'dark' : 'light';
|
|
31
|
+
return theme;
|
|
32
|
+
}
|
|
33
|
+
function applyTheme(resolved) {
|
|
34
|
+
if (typeof document === 'undefined')
|
|
35
|
+
return;
|
|
36
|
+
document.documentElement.classList.toggle('dark', resolved === 'dark');
|
|
37
|
+
}
|
|
38
|
+
function ThemeProvider({ defaultTheme = 'system', children }) {
|
|
39
|
+
const [theme, setThemeState] = useState(() => readStored() ?? defaultTheme);
|
|
40
|
+
const [systemDark, setSystemDark] = useState(systemPrefersDark);
|
|
41
|
+
const resolvedTheme = resolve(theme, systemDark);
|
|
42
|
+
// Synchronous during render on the client so portals mounted in the same commit see the class.
|
|
43
|
+
applyTheme(resolvedTheme);
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (typeof matchMedia === 'undefined')
|
|
46
|
+
return;
|
|
47
|
+
const mq = matchMedia(DARK_QUERY);
|
|
48
|
+
const onChange = (e) => setSystemDark(e.matches);
|
|
49
|
+
mq.addEventListener('change', onChange);
|
|
50
|
+
return () => mq.removeEventListener('change', onChange);
|
|
51
|
+
}, []);
|
|
52
|
+
const setTheme = useCallback((next) => {
|
|
53
|
+
setThemeState(next);
|
|
54
|
+
localStorage.setItem(THEME_STORAGE_KEY, next);
|
|
55
|
+
}, []);
|
|
56
|
+
const value = useMemo(() => ({ theme, resolvedTheme, setTheme }), [theme, resolvedTheme, setTheme]);
|
|
57
|
+
return _jsx(ThemeContext.Provider, { value: value, children: children });
|
|
58
|
+
}
|
|
59
|
+
function useTheme() {
|
|
60
|
+
const ctx = useContext(ThemeContext);
|
|
61
|
+
if (ctx === null)
|
|
62
|
+
throw new Error('useTheme() must be called inside a <ThemeProvider>.');
|
|
63
|
+
return ctx;
|
|
64
|
+
}
|
|
65
|
+
export { ThemeProvider, useTheme, THEME_STORAGE_KEY, THEME_INIT_SCRIPT };
|