@streamsai/ui 0.0.0-stage → 0.1.1

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.
Files changed (206) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -2
  3. package/dist/components/ui/agent-avatar.d.ts +50 -0
  4. package/dist/components/ui/agent-avatar.js +38 -0
  5. package/dist/components/ui/alert-dialog.d.ts +12 -0
  6. package/dist/components/ui/alert-dialog.js +37 -0
  7. package/dist/components/ui/alert.d.ts +10 -0
  8. package/dist/components/ui/alert.js +28 -0
  9. package/dist/components/ui/assets/loader.json.js +1 -0
  10. package/dist/components/ui/avatar-frame.d.ts +11 -0
  11. package/dist/components/ui/avatar-frame.js +20 -0
  12. package/dist/components/ui/avatar.d.ts +23 -0
  13. package/dist/components/ui/avatar.js +54 -0
  14. package/dist/components/ui/badge.d.ts +7 -0
  15. package/dist/components/ui/badge.js +36 -0
  16. package/dist/components/ui/bar-list.d.ts +40 -0
  17. package/dist/components/ui/bar-list.js +37 -0
  18. package/dist/components/ui/breadcrumb.d.ts +8 -0
  19. package/dist/components/ui/breadcrumb.js +21 -0
  20. package/dist/components/ui/button-group.d.ts +10 -0
  21. package/dist/components/ui/button-group.js +41 -0
  22. package/dist/components/ui/button.d.ts +9 -0
  23. package/dist/components/ui/button.js +39 -0
  24. package/dist/components/ui/card.d.ts +9 -0
  25. package/dist/components/ui/card.js +25 -0
  26. package/dist/components/ui/checkbox.d.ts +3 -0
  27. package/dist/components/ui/checkbox.js +16 -0
  28. package/dist/components/ui/chip.d.ts +13 -0
  29. package/dist/components/ui/chip.js +22 -0
  30. package/dist/components/ui/clickable.d.ts +27 -0
  31. package/dist/components/ui/clickable.js +54 -0
  32. package/dist/components/ui/code-block.d.ts +68 -0
  33. package/dist/components/ui/code-block.js +112 -0
  34. package/dist/components/ui/code-view.d.ts +21 -0
  35. package/dist/components/ui/code-view.js +20 -0
  36. package/dist/components/ui/collapsible.d.ts +6 -0
  37. package/dist/components/ui/collapsible.js +18 -0
  38. package/dist/components/ui/combobox.d.ts +14 -0
  39. package/dist/components/ui/combobox.js +37 -0
  40. package/dist/components/ui/command.d.ts +15 -0
  41. package/dist/components/ui/command.js +34 -0
  42. package/dist/components/ui/context-menu.d.ts +21 -0
  43. package/dist/components/ui/context-menu.js +60 -0
  44. package/dist/components/ui/counter.d.ts +11 -0
  45. package/dist/components/ui/counter.js +20 -0
  46. package/dist/components/ui/dialog.d.ts +17 -0
  47. package/dist/components/ui/dialog.js +41 -0
  48. package/dist/components/ui/disabled-reason.d.ts +22 -0
  49. package/dist/components/ui/disabled-reason.js +16 -0
  50. package/dist/components/ui/dropdown-menu.d.ts +33 -0
  51. package/dist/components/ui/dropdown-menu.js +58 -0
  52. package/dist/components/ui/editable-text.d.ts +95 -0
  53. package/dist/components/ui/editable-text.js +191 -0
  54. package/dist/components/ui/heading.d.ts +24 -0
  55. package/dist/components/ui/heading.js +92 -0
  56. package/dist/components/ui/hover-card.d.ts +9 -0
  57. package/dist/components/ui/hover-card.js +16 -0
  58. package/dist/components/ui/icon-button.d.ts +23 -0
  59. package/dist/components/ui/icon-button.js +32 -0
  60. package/dist/components/ui/input.d.ts +3 -0
  61. package/dist/components/ui/input.js +8 -0
  62. package/dist/components/ui/kbd.d.ts +12 -0
  63. package/dist/components/ui/kbd.js +12 -0
  64. package/dist/components/ui/label.d.ts +3 -0
  65. package/dist/components/ui/label.js +7 -0
  66. package/dist/components/ui/loader.d.ts +19 -0
  67. package/dist/components/ui/loader.js +157 -0
  68. package/dist/components/ui/message-toolbar.d.ts +20 -0
  69. package/dist/components/ui/message-toolbar.js +17 -0
  70. package/dist/components/ui/modal.d.ts +30 -0
  71. package/dist/components/ui/modal.js +41 -0
  72. package/dist/components/ui/nav-item.d.ts +25 -0
  73. package/dist/components/ui/nav-item.js +66 -0
  74. package/dist/components/ui/panel-section.d.ts +22 -0
  75. package/dist/components/ui/panel-section.js +26 -0
  76. package/dist/components/ui/popover.d.ts +14 -0
  77. package/dist/components/ui/popover.js +30 -0
  78. package/dist/components/ui/progress.d.ts +5 -0
  79. package/dist/components/ui/progress.js +16 -0
  80. package/dist/components/ui/provider-badge.d.ts +22 -0
  81. package/dist/components/ui/provider-badge.js +38 -0
  82. package/dist/components/ui/radio-group.d.ts +5 -0
  83. package/dist/components/ui/radio-group.js +21 -0
  84. package/dist/components/ui/reply-summary.d.ts +16 -0
  85. package/dist/components/ui/reply-summary.js +8 -0
  86. package/dist/components/ui/resizable.d.ts +8 -0
  87. package/dist/components/ui/resizable.js +15 -0
  88. package/dist/components/ui/rich-text-editor.d.ts +447 -0
  89. package/dist/components/ui/rich-text-editor.js +2419 -0
  90. package/dist/components/ui/running-indicator.d.ts +17 -0
  91. package/dist/components/ui/running-indicator.js +34 -0
  92. package/dist/components/ui/sandboxed-frame.d.ts +29 -0
  93. package/dist/components/ui/sandboxed-frame.js +77 -0
  94. package/dist/components/ui/scroll-area.d.ts +14 -0
  95. package/dist/components/ui/scroll-area.js +17 -0
  96. package/dist/components/ui/section-header.d.ts +12 -0
  97. package/dist/components/ui/section-header.js +12 -0
  98. package/dist/components/ui/select.d.ts +15 -0
  99. package/dist/components/ui/select.js +40 -0
  100. package/dist/components/ui/separator.d.ts +3 -0
  101. package/dist/components/ui/separator.js +13 -0
  102. package/dist/components/ui/sheet.d.ts +23 -0
  103. package/dist/components/ui/sheet.js +48 -0
  104. package/dist/components/ui/shimmer-text.d.ts +26 -0
  105. package/dist/components/ui/shimmer-text.js +32 -0
  106. package/dist/components/ui/sidebar.d.ts +63 -0
  107. package/dist/components/ui/sidebar.js +283 -0
  108. package/dist/components/ui/skeleton.d.ts +14 -0
  109. package/dist/components/ui/skeleton.js +12 -0
  110. package/dist/components/ui/sonner.d.ts +4 -0
  111. package/dist/components/ui/sonner.js +14 -0
  112. package/dist/components/ui/spark-bars.d.ts +29 -0
  113. package/dist/components/ui/spark-bars.js +24 -0
  114. package/dist/components/ui/spinner.d.ts +16 -0
  115. package/dist/components/ui/spinner.js +26 -0
  116. package/dist/components/ui/stacked-bar.d.ts +37 -0
  117. package/dist/components/ui/stacked-bar.js +56 -0
  118. package/dist/components/ui/status-dot.d.ts +16 -0
  119. package/dist/components/ui/status-dot.js +32 -0
  120. package/dist/components/ui/switch.d.ts +5 -0
  121. package/dist/components/ui/switch.js +13 -0
  122. package/dist/components/ui/tabs.d.ts +14 -0
  123. package/dist/components/ui/tabs.js +55 -0
  124. package/dist/components/ui/text.d.ts +27 -0
  125. package/dist/components/ui/text.js +100 -0
  126. package/dist/components/ui/textarea.d.ts +3 -0
  127. package/dist/components/ui/textarea.js +7 -0
  128. package/dist/components/ui/theme-toggle.d.ts +21 -0
  129. package/dist/components/ui/theme-toggle.js +17 -0
  130. package/dist/components/ui/toggle-group.d.ts +6 -0
  131. package/dist/components/ui/toggle-group.js +12 -0
  132. package/dist/components/ui/tooltip.d.ts +11 -0
  133. package/dist/components/ui/tooltip.js +21 -0
  134. package/dist/components/ui/trace.d.ts +24 -0
  135. package/dist/components/ui/trace.js +57 -0
  136. package/dist/components/ui/trend-line.d.ts +93 -0
  137. package/dist/components/ui/trend-line.js +215 -0
  138. package/dist/components/ui/truncate.d.ts +30 -0
  139. package/dist/components/ui/truncate.js +54 -0
  140. package/dist/components/ui/viewer-shell.d.ts +55 -0
  141. package/dist/components/ui/viewer-shell.js +15 -0
  142. package/dist/components/ui/virtual-list.d.ts +91 -0
  143. package/dist/components/ui/virtual-list.js +406 -0
  144. package/dist/components/ui/visually-hidden.d.ts +15 -0
  145. package/dist/components/ui/visually-hidden.js +19 -0
  146. package/dist/direction/index.d.ts +19 -0
  147. package/dist/direction/index.js +32 -0
  148. package/dist/hooks/use-code-highlighting.d.ts +22 -0
  149. package/dist/hooks/use-code-highlighting.js +47 -0
  150. package/dist/hooks/use-is-truncated.d.ts +7 -0
  151. package/dist/hooks/use-is-truncated.js +23 -0
  152. package/dist/hooks/use-mobile.d.ts +2 -0
  153. package/dist/hooks/use-mobile.js +15 -0
  154. package/dist/icons/custom.d.ts +29 -0
  155. package/dist/icons/custom.js +48 -0
  156. package/dist/icons/index.d.ts +49 -0
  157. package/dist/icons/index.js +50 -0
  158. package/dist/icons/provider-logos.d.ts +17 -0
  159. package/dist/icons/provider-logos.js +28 -0
  160. package/dist/icons/providers.d.ts +9 -0
  161. package/dist/icons/providers.js +51 -0
  162. package/dist/index.d.ts +102 -0
  163. package/dist/index.js +124 -0
  164. package/dist/lib/code-highlighter.d.ts +9 -0
  165. package/dist/lib/code-highlighter.js +65 -0
  166. package/dist/lib/code-language.d.ts +13 -0
  167. package/dist/lib/code-language.js +103 -0
  168. package/dist/lib/code-tokens.d.ts +9 -0
  169. package/dist/lib/code-tokens.js +27 -0
  170. package/dist/lib/copy-text.d.ts +6 -0
  171. package/dist/lib/copy-text.js +46 -0
  172. package/dist/lib/home-tile.d.ts +12 -0
  173. package/dist/lib/home-tile.js +45 -0
  174. package/dist/lib/reveal-mask.d.ts +9 -0
  175. package/dist/lib/reveal-mask.js +16 -0
  176. package/dist/lib/text-direction.d.ts +28 -0
  177. package/dist/lib/text-direction.js +119 -0
  178. package/dist/lib/utils.d.ts +11 -0
  179. package/dist/lib/utils.js +30 -0
  180. package/dist/motion/components.d.ts +184 -0
  181. package/dist/motion/components.js +211 -0
  182. package/dist/motion/config.d.ts +849 -0
  183. package/dist/motion/config.js +429 -0
  184. package/dist/motion/index.d.ts +8 -0
  185. package/dist/motion/index.js +8 -0
  186. package/dist/motion/modal-presence.d.ts +5 -0
  187. package/dist/motion/modal-presence.js +27 -0
  188. package/dist/motion/popup.d.ts +77 -0
  189. package/dist/motion/popup.js +103 -0
  190. package/dist/platform/index.d.ts +29 -0
  191. package/dist/platform/index.js +63 -0
  192. package/dist/styles/base.css +319 -0
  193. package/dist/styles/fonts/Figtree-Variable.woff2 +0 -0
  194. package/dist/styles/fonts/OFL.txt +93 -0
  195. package/dist/styles/fonts/Poppins-Medium.woff2 +0 -0
  196. package/dist/styles/fonts/Poppins-Regular.woff2 +0 -0
  197. package/dist/styles/fonts/Poppins-SemiBold.woff2 +0 -0
  198. package/dist/styles/fonts.css +28 -0
  199. package/dist/styles/globals.css +8 -0
  200. package/dist/styles/mcp-host.css +76 -0
  201. package/dist/styles/tokens.css +387 -0
  202. package/dist/styles/tokens.d.mts +57 -0
  203. package/dist/styles/tokens.mjs +59 -0
  204. package/dist/theme/index.d.ts +28 -0
  205. package/dist/theme/index.js +65 -0
  206. 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 };