@dfosco/storyboard 0.8.1 → 0.9.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.
Files changed (114) hide show
  1. package/dist/storyboard-ui.css +1 -1
  2. package/dist/storyboard-ui.js +6420 -6336
  3. package/dist/storyboard-ui.js.map +1 -1
  4. package/dist/tailwind.css +1 -1
  5. package/dist/tiny-canvas.css +1 -1
  6. package/package.json +1 -1
  7. package/scaffold/src/library/_app.jsx +2 -14
  8. package/scaffold/src/library/_app.module.css +2 -8
  9. package/scaffold/src/library/mount.jsx +0 -1
  10. package/src/canvas/style.css +16 -16
  11. package/src/core/artifact/operations.js +35 -2
  12. package/src/core/artifact/schemas/canvas.schema.json +7 -1
  13. package/src/core/canvas/hot-pool.js +11 -22
  14. package/src/core/canvas/selectedWidgets.js +1 -1
  15. package/src/core/canvas/server.js +52 -31
  16. package/src/core/canvas/server.test.js +107 -0
  17. package/src/core/cli/artifact.js +2 -0
  18. package/src/core/cli/create.js +35 -5
  19. package/src/core/cli/schemas.js +6 -1
  20. package/src/core/comments/ui/comment-layout.css +14 -14
  21. package/src/core/index.js +18 -0
  22. package/src/core/inspector/highlighter.js +1 -1
  23. package/src/core/inspector/mouseMode.js +2 -2
  24. package/src/core/lib/components/ui/dialog/dialog.module.css +8 -8
  25. package/src/core/modes/modes.css +4 -4
  26. package/src/core/mountStoryboardCore.js +53 -9
  27. package/src/core/mountStoryboardCore.test.js +25 -1
  28. package/src/core/rename-watcher/config.json +1 -1
  29. package/src/core/rename-watcher/watcher.js +1 -1
  30. package/src/core/stores/canvasInteractionStore.js +120 -0
  31. package/src/core/stores/canvasInteractionStore.test.js +126 -0
  32. package/src/core/stores/configSchema.js +23 -6
  33. package/src/core/stores/configSchema.test.js +3 -0
  34. package/src/core/stores/customerModeConfig.js +24 -3
  35. package/src/core/stores/customerModeConfig.test.js +46 -0
  36. package/src/core/stores/presentationStore.js +118 -0
  37. package/src/core/stores/presentationStore.test.js +114 -0
  38. package/src/core/stores/uiConfig.js +10 -2
  39. package/src/core/styles/tailwind.css +138 -90
  40. package/src/core/styles/workspace-chrome.css +4 -21
  41. package/src/core/ui/AutosyncMenuButton.css +7 -7
  42. package/src/core/ui/BranchSelect.module.css +5 -5
  43. package/src/core/ui/ChromeSlot.jsx +92 -0
  44. package/src/core/ui/ChromeSlot.test.jsx +140 -0
  45. package/src/core/ui/CoreUIBar.css +5 -5
  46. package/src/core/ui/CoreUIBar.jsx +161 -136
  47. package/src/core/ui/InspectorPanel.css +5 -5
  48. package/src/core/ui/InspectorPanel.jsx +9 -9
  49. package/src/core/ui/PwaInstallBanner.css +5 -5
  50. package/src/core/ui/PwaInstallBanner.jsx +5 -5
  51. package/src/core/ui/core-ui-colors.css +28 -66
  52. package/src/core/ui/sidepanel.css +12 -12
  53. package/src/core/workshop/features/createCanvas/CreateCanvasForm.jsx +102 -13
  54. package/src/internals/ArtifactForm/ArtifactForm.module.css +7 -7
  55. package/src/internals/AuthModal/AuthModal.module.css +34 -34
  56. package/src/internals/BaseUiForm/BaseUiForm.module.css +85 -85
  57. package/src/internals/BranchBar/BranchBar.module.css +4 -4
  58. package/src/internals/BranchesDropdown/BranchesDropdown.module.css +9 -9
  59. package/src/internals/CommandPalette/CommandPalette.jsx +16 -10
  60. package/src/internals/CommandPalette/WidgetArtifactDialog.css +16 -16
  61. package/src/internals/CommandPalette/command-palette.css +14 -14
  62. package/src/internals/CreatePage/CreatePage.module.css +1 -1
  63. package/src/internals/FlowError.module.css +5 -5
  64. package/src/internals/PrototypeErrorBoundary.module.css +15 -15
  65. package/src/internals/SimpleWorkspace/SimpleWorkspace.jsx +5 -4
  66. package/src/internals/SimpleWorkspace/SimpleWorkspace.module.css +38 -38
  67. package/src/internals/Viewfinder.jsx +33 -16
  68. package/src/internals/Viewfinder.module.css +189 -189
  69. package/src/internals/canvas/CanvasControls.module.css +11 -11
  70. package/src/internals/canvas/CanvasPage.bridge.test.jsx +11 -37
  71. package/src/internals/canvas/CanvasPage.jsx +91 -93
  72. package/src/internals/canvas/CanvasPage.module.css +20 -19
  73. package/src/internals/canvas/CanvasToolbar.module.css +11 -11
  74. package/src/internals/canvas/ConnectorLayer.jsx +39 -2
  75. package/src/internals/canvas/ConnectorLayer.module.css +10 -10
  76. package/src/internals/canvas/PageSelector.module.css +28 -28
  77. package/src/internals/canvas/canvasTheme.js +22 -111
  78. package/src/internals/canvas/isolation/prototypeRoutes.jsx +12 -3
  79. package/src/internals/canvas/isolation/storyRoutes.jsx +1 -1
  80. package/src/internals/canvas/widgets/CodePenEmbed.jsx +16 -36
  81. package/src/internals/canvas/widgets/CodePenEmbed.module.css +12 -12
  82. package/src/internals/canvas/widgets/CropOverlay.module.css +23 -23
  83. package/src/internals/canvas/widgets/ExpandedPane.module.css +8 -8
  84. package/src/internals/canvas/widgets/FigmaEmbed.jsx +15 -36
  85. package/src/internals/canvas/widgets/FigmaEmbed.module.css +15 -15
  86. package/src/internals/canvas/widgets/FrozenTerminalOverlay.module.css +5 -5
  87. package/src/internals/canvas/widgets/ImageWidget.module.css +3 -3
  88. package/src/internals/canvas/widgets/LinkPreview.module.css +77 -78
  89. package/src/internals/canvas/widgets/MarkdownBlock.module.css +31 -31
  90. package/src/internals/canvas/widgets/PromptWidget.jsx +2 -16
  91. package/src/internals/canvas/widgets/PromptWidget.module.css +33 -33
  92. package/src/internals/canvas/widgets/PrototypeEmbed.jsx +23 -7
  93. package/src/internals/canvas/widgets/PrototypeEmbed.module.css +58 -56
  94. package/src/internals/canvas/widgets/PrototypeEmbed.test.jsx +4 -4
  95. package/src/internals/canvas/widgets/ResizeHandle.module.css +4 -4
  96. package/src/internals/canvas/widgets/StorySetWidget.jsx +45 -21
  97. package/src/internals/canvas/widgets/StoryWidget.jsx +53 -21
  98. package/src/internals/canvas/widgets/StoryWidget.module.css +22 -20
  99. package/src/internals/canvas/widgets/TerminalReadWidget.module.css +4 -4
  100. package/src/internals/canvas/widgets/TerminalWidget.jsx +56 -45
  101. package/src/internals/canvas/widgets/TerminalWidget.module.css +10 -10
  102. package/src/internals/canvas/widgets/TilesWidget.module.css +17 -17
  103. package/src/internals/canvas/widgets/WidgetChrome.module.css +61 -61
  104. package/src/internals/canvas/widgets/WidgetWrapper.module.css +2 -2
  105. package/src/internals/canvas/widgets/embedOverlay.module.css +14 -4
  106. package/src/internals/canvas/widgets/embedTheme.js +10 -102
  107. package/src/internals/canvas/widgets/widgetConfig.js +5 -5
  108. package/src/internals/story/ComponentSetPage.module.css +14 -14
  109. package/src/internals/story/StoryPage.module.css +2 -2
  110. package/src/internals/vite/data-plugin.js +5 -2
  111. package/src/internals/canvas/WebGLContextPool.jsx +0 -291
  112. package/src/internals/canvas/WebGLContextPool.test.jsx +0 -165
  113. package/src/internals/canvas/widgets/ComponentSetWidget.module.css +0 -89
  114. package/src/internals/canvas/widgets/StorySetWidget.module.css +0 -89
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Presentation Store — consumer-supplied overrides for storyboard chrome elements.
3
+ *
4
+ * A chrome element is any rendered piece of storyboard UI that is wrapped in
5
+ * `<ChromeSlot id="...">` (toolbar buttons, canvas title, page selector, etc.).
6
+ *
7
+ * Consumers seed this registry through `mountStoryboardCore({ presentation })`
8
+ * and the store applies per-element overrides at render time:
9
+ *
10
+ * {
11
+ * "tool:command-palette": {
12
+ * style: { transform: 'translateY(20px)', opacity: 0 },
13
+ * className: 'landing-floating-button',
14
+ * props: { onPointerEnter: handleHover },
15
+ * decorator: (Element, ctx) => <ScrollAnimator>{Element}</ScrollAnimator>,
16
+ * },
17
+ * "canvas:title": { hidden: true },
18
+ * }
19
+ *
20
+ * This is an **advanced, undocumented** extension surface — intended for
21
+ * landing-page / hero canvas use cases where the consumer needs heavy
22
+ * customization of storyboard chrome. Not part of the public API.
23
+ *
24
+ * Framework-agnostic (zero npm dependencies).
25
+ */
26
+
27
+ /**
28
+ * @typedef {object} PresentationOverride
29
+ * @property {React.CSSProperties} [style] - Spread onto the chrome element root style
30
+ * @property {string} [className] - Appended to the chrome element root className
31
+ * @property {object} [props] - Spread as additional props on the chrome element
32
+ * @property {Function} [decorator] - (Element, ctx) => ReactNode wrapper
33
+ * @property {boolean} [hidden] - If true, render null (shorthand for full hide)
34
+ */
35
+
36
+ /** @type {Map<string, PresentationOverride>} */
37
+ let _overrides = new Map()
38
+
39
+ /** @type {Set<Function>} */
40
+ const _listeners = new Set()
41
+
42
+ let _snapshotVersion = 0
43
+
44
+ /**
45
+ * Seed the presentation registry from a consumer-supplied map.
46
+ * Replaces any previous overrides. Called once at app startup.
47
+ *
48
+ * @param {Record<string, PresentationOverride>} [map]
49
+ */
50
+ export function initPresentation(map) {
51
+ _overrides = new Map()
52
+ if (map && typeof map === 'object') {
53
+ for (const [id, override] of Object.entries(map)) {
54
+ if (override && typeof override === 'object') {
55
+ _overrides.set(id, override)
56
+ }
57
+ }
58
+ }
59
+ _notify()
60
+ }
61
+
62
+ /**
63
+ * Set or replace a single chrome element's presentation override.
64
+ * @param {string} id
65
+ * @param {PresentationOverride|null|undefined} override Pass null/undefined to clear.
66
+ */
67
+ export function setPresentation(id, override) {
68
+ if (override == null) {
69
+ _overrides.delete(id)
70
+ } else if (typeof override === 'object') {
71
+ _overrides.set(id, override)
72
+ }
73
+ _notify()
74
+ }
75
+
76
+ /**
77
+ * Get the presentation override for a chrome element ID, or null if none.
78
+ * @param {string} id
79
+ * @returns {PresentationOverride|null}
80
+ */
81
+ export function getPresentation(id) {
82
+ return _overrides.get(id) || null
83
+ }
84
+
85
+ /**
86
+ * Subscribe to presentation registry changes. Returns an unsubscribe fn.
87
+ * Compatible with `useSyncExternalStore` shape.
88
+ * @param {Function} callback
89
+ * @returns {Function}
90
+ */
91
+ export function subscribeToPresentation(callback) {
92
+ _listeners.add(callback)
93
+ return () => _listeners.delete(callback)
94
+ }
95
+
96
+ /**
97
+ * Snapshot version for change detection. Compatible with `useSyncExternalStore`.
98
+ * @returns {string}
99
+ */
100
+ export function getPresentationSnapshot() {
101
+ return String(_snapshotVersion)
102
+ }
103
+
104
+ function _notify() {
105
+ _snapshotVersion++
106
+ for (const cb of _listeners) {
107
+ try { cb() } catch (err) {
108
+ console.error('[storyboard] Error in presentation subscriber:', err)
109
+ }
110
+ }
111
+ }
112
+
113
+ /** Reset all state. Only for tests. */
114
+ export function _resetPresentation() {
115
+ _overrides = new Map()
116
+ _listeners.clear()
117
+ _snapshotVersion = 0
118
+ }
@@ -0,0 +1,114 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest'
2
+
3
+ import {
4
+ initPresentation,
5
+ setPresentation,
6
+ getPresentation,
7
+ subscribeToPresentation,
8
+ getPresentationSnapshot,
9
+ _resetPresentation,
10
+ } from './presentationStore.js'
11
+
12
+ describe('presentationStore', () => {
13
+ beforeEach(() => {
14
+ _resetPresentation()
15
+ })
16
+
17
+ it('returns null when no override is registered', () => {
18
+ expect(getPresentation('tool:command-palette')).toBeNull()
19
+ })
20
+
21
+ it('seeds overrides from initPresentation', () => {
22
+ initPresentation({
23
+ 'tool:command-palette': { hidden: true },
24
+ 'canvas:title': { className: 'landing-title' },
25
+ })
26
+ expect(getPresentation('tool:command-palette')).toEqual({ hidden: true })
27
+ expect(getPresentation('canvas:title')).toEqual({ className: 'landing-title' })
28
+ expect(getPresentation('nope:nothing')).toBeNull()
29
+ })
30
+
31
+ it('ignores non-object values in initPresentation', () => {
32
+ initPresentation({
33
+ 'tool:a': null,
34
+ 'tool:b': 'invalid',
35
+ 'tool:c': 42,
36
+ 'tool:d': { hidden: true },
37
+ })
38
+ expect(getPresentation('tool:a')).toBeNull()
39
+ expect(getPresentation('tool:b')).toBeNull()
40
+ expect(getPresentation('tool:c')).toBeNull()
41
+ expect(getPresentation('tool:d')).toEqual({ hidden: true })
42
+ })
43
+
44
+ it('replaces previous overrides on subsequent initPresentation calls', () => {
45
+ initPresentation({ 'tool:a': { hidden: true } })
46
+ initPresentation({ 'tool:b': { hidden: true } })
47
+ expect(getPresentation('tool:a')).toBeNull()
48
+ expect(getPresentation('tool:b')).toEqual({ hidden: true })
49
+ })
50
+
51
+ it('initPresentation() with no arg clears all overrides', () => {
52
+ initPresentation({ 'tool:a': { hidden: true } })
53
+ initPresentation()
54
+ expect(getPresentation('tool:a')).toBeNull()
55
+ })
56
+
57
+ it('setPresentation adds and updates individual overrides', () => {
58
+ setPresentation('tool:a', { className: 'foo' })
59
+ expect(getPresentation('tool:a')).toEqual({ className: 'foo' })
60
+
61
+ setPresentation('tool:a', { className: 'bar' })
62
+ expect(getPresentation('tool:a')).toEqual({ className: 'bar' })
63
+ })
64
+
65
+ it('setPresentation with null/undefined deletes the override', () => {
66
+ setPresentation('tool:a', { hidden: true })
67
+ setPresentation('tool:a', null)
68
+ expect(getPresentation('tool:a')).toBeNull()
69
+
70
+ setPresentation('tool:b', { hidden: true })
71
+ setPresentation('tool:b', undefined)
72
+ expect(getPresentation('tool:b')).toBeNull()
73
+ })
74
+
75
+ it('subscribers are notified on init, set, and clear', () => {
76
+ const cb = vi.fn()
77
+ const unsub = subscribeToPresentation(cb)
78
+
79
+ initPresentation({ 'tool:a': { hidden: true } })
80
+ setPresentation('tool:b', { className: 'x' })
81
+ setPresentation('tool:a', null)
82
+
83
+ expect(cb).toHaveBeenCalledTimes(3)
84
+ unsub()
85
+
86
+ setPresentation('tool:c', { hidden: true })
87
+ expect(cb).toHaveBeenCalledTimes(3) // not called after unsubscribe
88
+ })
89
+
90
+ it('snapshot version changes on every mutation', () => {
91
+ const v0 = getPresentationSnapshot()
92
+ setPresentation('tool:a', { hidden: true })
93
+ const v1 = getPresentationSnapshot()
94
+ expect(v1).not.toBe(v0)
95
+
96
+ setPresentation('tool:b', { hidden: true })
97
+ const v2 = getPresentationSnapshot()
98
+ expect(v2).not.toBe(v1)
99
+ })
100
+
101
+ it('subscriber errors are isolated', () => {
102
+ const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
103
+ const goodCb = vi.fn()
104
+
105
+ subscribeToPresentation(() => { throw new Error('boom') })
106
+ subscribeToPresentation(goodCb)
107
+
108
+ setPresentation('tool:a', { hidden: true })
109
+
110
+ expect(goodCb).toHaveBeenCalled()
111
+ expect(consoleSpy).toHaveBeenCalled()
112
+ consoleSpy.mockRestore()
113
+ })
114
+ })
@@ -2,14 +2,22 @@
2
2
  * UI Config — project-level overrides for storyboard chrome visibility.
3
3
  *
4
4
  * Client repos use the "ui" key in storyboard.config.json to hide
5
- * specific menus or UI elements from the CoreUIBar.
5
+ * specific menus, toolbar items, or workspace nav entries.
6
6
  *
7
7
  * {
8
8
  * "ui": {
9
- * "hide": ["docs", "comments"]
9
+ * "hide": [
10
+ * "docs", // CoreUIBar menu key
11
+ * "comments", // CoreUIBar menu key
12
+ * "workspace:components" // workspace sidebar nav id
13
+ * ]
10
14
  * }
11
15
  * }
12
16
  *
17
+ * Convention: namespaced keys (`<surface>:<id>`) are recommended for new
18
+ * surfaces to avoid collisions. Existing CoreUIBar menus use bare keys
19
+ * for back-compat.
20
+ *
13
21
  * Framework-agnostic (zero npm dependencies).
14
22
  */
15
23
 
@@ -23,103 +23,151 @@
23
23
  font-display: swap;
24
24
  }
25
25
 
26
+ /*
27
+ * Storyboard color token Single Source of Truth.
28
+ *
29
+ * All semantic color variables live here. Two naming families coexist:
30
+ *
31
+ * 1. shadcn-style (`--color-*`) — used by Tailwind utilities
32
+ * (`bg-background`, `text-foreground`) and shadcn primitives.
33
+ * 2. Storyboard chrome (`--color-background-*`, `--color-foreground-*`,
34
+ * `--color-border-*`, `--color-overlay-*`, `--shadow-*`)
35
+ * — used by every workspace / canvas / widget CSS module.
36
+ *
37
+ * Light values live on `:root` (via `@theme`). Dark overrides live on
38
+ * `[data-sb-theme^="dark"]` and every per-surface dark attribute
39
+ * (`data-sb-canvas-theme`, `data-sb-prototype-theme`, etc.). The same
40
+ * selector list drives the `dark:` Tailwind variant (`themes.generated.css`).
41
+ *
42
+ * Concrete hex values are GitHub Primer palette values, kept verbatim
43
+ * so the visual identity is unchanged after dropping `@primer/primitives`.
44
+ */
26
45
  @theme {
27
- --color-background: hsl(0 0% 100%);
28
- --color-foreground: hsl(222.2 84% 4.9%);
29
- --color-card: hsl(0 0% 100%);
30
- --color-card-foreground: hsl(222.2 84% 4.9%);
31
- --color-popover: hsl(0 0% 100%);
32
- --color-popover-foreground: hsl(222.2 84% 4.9%);
33
- --color-primary: hsl(222.2 47.4% 11.2%);
34
- --color-primary-foreground: hsl(210 40% 98%);
35
- --color-secondary: hsl(210 40% 96.1%);
36
- --color-secondary-foreground: hsl(222.2 47.4% 11.2%);
37
- --color-muted: hsl(210 40% 96.1%);
38
- --color-muted-foreground: hsl(215.4 16.3% 46.9%);
39
- --color-accent: hsl(210 40% 96.1%);
40
- --color-accent-foreground: hsl(222.2 47.4% 11.2%);
41
- --color-destructive: hsl(0 84.2% 60.2%);
42
- --color-destructive-foreground: hsl(210 40% 98%);
43
- --color-border: hsl(214.3 31.8% 91.4%);
44
- --color-input: hsl(214.3 31.8% 91.4%);
45
- --color-ring: hsl(222.2 84% 4.9%);
46
- --color-success: hsl(142 71% 36%);
47
- --color-success-foreground: hsl(0 0% 100%);
46
+ --color-background: #ffffff;
47
+ --color-background-muted: #f6f8fa;
48
+ --color-background-inset: #f6f8fa;
49
+ --color-background-emphasis: #25292e;
50
+ --color-background-inverse: #25292e;
51
+ --color-background-neutral-muted: #818b981f;
52
+ --color-background-neutral-emphasis: #59636e;
53
+ --color-background-accent-muted: #ddf4ff;
54
+ --color-background-accent-emphasis: #0969da;
55
+ --color-background-accent-emphasis-hover: #0860c7;
56
+ --color-background-danger-muted: #ffebe9;
57
+ --color-background-danger-emphasis: #cf222e;
58
+ --color-background-success-muted: #dafbe1;
59
+ --color-background-success-emphasis: #1f883d;
60
+ --color-background-success-hover: #1a7f37;
61
+ --color-background-attention-muted: #fff8c5;
62
+ --color-background-done-muted: #fbefff;
63
+ --color-background-done-emphasis: #8250df;
64
+ --color-background-open-emphasis: #1f883d;
65
+ --color-background-closed-emphasis: #cf222e;
66
+
67
+ --color-foreground: #1f2328;
68
+ --color-foreground-muted: #59636e;
69
+ --color-foreground-accent: #0969da;
70
+ --color-foreground-danger: #d1242f;
71
+ --color-foreground-success: #1a7f37;
72
+ --color-foreground-attention: #9a6700;
73
+ --color-foreground-on-emphasis: #ffffff;
74
+ --color-foreground-on-inverse: #ffffff;
75
+
76
+ --color-border: #d1d9e0;
77
+ --color-border-muted: #d1d9e0b3;
78
+ --color-border-emphasis: #818b98;
79
+ --color-border-accent-emphasis: #0969da;
80
+ --color-border-accent-muted: #54aeff66;
81
+ --color-border-danger-emphasis: #cf222e;
82
+ --color-border-danger-muted: #ff818266;
83
+ --color-border-success-muted: #4ac26b66;
84
+ --color-border-attention-muted: #d4a72c66;
85
+
86
+ --color-overlay-backdrop: #c8d1da66;
87
+
88
+ --shadow-resting: 0px 1px 1px 0px #1f23280f, 0px 1px 3px 0px #1f23280f;
89
+ --shadow-floating: 0px 0px 0px 1px #d1d9e080, 0px 6px 12px -3px #25292e0a, 0px 6px 18px 0px #25292e1f;
90
+
91
+ /* shadcn primitives (Tailwind utility-friendly aliases) */
92
+ --color-card: var(--color-background);
93
+ --color-card-foreground: var(--color-foreground);
94
+ --color-popover: var(--color-background);
95
+ --color-popover-foreground: var(--color-foreground);
96
+ --color-primary: #1f2328;
97
+ --color-primary-foreground: #ffffff;
98
+ --color-secondary: var(--color-background-muted);
99
+ --color-secondary-foreground: var(--color-foreground);
100
+ --color-muted: var(--color-background-muted);
101
+ --color-muted-foreground: var(--color-foreground-muted);
102
+ --color-accent: var(--color-background-accent-muted);
103
+ --color-accent-foreground: var(--color-foreground-accent);
104
+ --color-destructive: var(--color-background-danger-emphasis);
105
+ --color-destructive-foreground: #ffffff;
106
+ --color-input: var(--color-border);
107
+ --color-ring: var(--color-background-accent-emphasis);
108
+ --color-success: var(--color-background-success-emphasis);
109
+ --color-success-foreground: #ffffff;
110
+
48
111
  --radius: 0.5rem;
49
112
  --font-sans: "Hubot Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
50
113
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
51
-
52
- --sb--color-background: hsl(0 0% 100%);
53
- --sb--color-foreground: hsl(222.2 84% 4.9%);
54
- --sb--color-card: hsl(0 0% 100%);
55
- --sb--color-card-foreground: hsl(222.2 84% 4.9%);
56
- --sb--color-popover: hsl(0 0% 100%);
57
- --sb--color-popover-foreground: hsl(222.2 84% 4.9%);
58
- --sb--color-primary: hsl(222.2 47.4% 11.2%);
59
- --sb--color-primary-foreground: hsl(210 40% 98%);
60
- --sb--color-secondary: hsl(210 40% 96.1%);
61
- --sb--color-secondary-foreground: hsl(222.2 47.4% 11.2%);
62
- --sb--color-muted: hsl(210 40% 96.1%);
63
- --sb--color-muted-foreground: hsl(215.4 16.3% 46.9%);
64
- --sb--color-accent: hsl(210 40% 96.1%);
65
- --sb--color-accent-foreground: hsl(222.2 47.4% 11.2%);
66
- --sb--color-destructive: hsl(0 84.2% 60.2%);
67
- --sb--color-destructive-foreground: hsl(210 40% 98%);
68
- --sb--color-border: hsl(214.3 31.8% 91.4%);
69
- --sb--color-input: hsl(214.3 31.8% 91.4%);
70
- --sb--color-ring: hsl(222.2 84% 4.9%);
71
- --sb--color-success: hsl(142 71% 36%);
72
- --sb--color-success-foreground: hsl(0 0% 100%);
73
- --sb--radius: var(--radius);
74
- --sb--font-sans: var(--font-sans);
75
- --sb--font-mono: var(--font-mono);
76
114
  }
77
115
 
78
116
  @layer base {
79
- [data-sb-theme^="dark"] {
80
- --color-background: hsl(222.2 84% 4.9%);
81
- --color-foreground: hsl(210 40% 98%);
82
- --color-card: hsl(222.2 84% 4.9%);
83
- --color-card-foreground: hsl(210 40% 98%);
84
- --color-popover: hsl(222.2 84% 4.9%);
85
- --color-popover-foreground: hsl(210 40% 98%);
86
- --color-primary: hsl(210 40% 98%);
87
- --color-primary-foreground: hsl(222.2 47.4% 11.2%);
88
- --color-secondary: hsl(217.2 32.6% 17.5%);
89
- --color-secondary-foreground: hsl(210 40% 98%);
90
- --color-muted: hsl(217.2 32.6% 17.5%);
91
- --color-muted-foreground: hsl(215 20.2% 65.1%);
92
- --color-accent: hsl(217.2 32.6% 17.5%);
93
- --color-accent-foreground: hsl(210 40% 98%);
94
- --color-destructive: hsl(0 62.8% 30.6%);
95
- --color-destructive-foreground: hsl(210 40% 98%);
96
- --color-border: hsl(217.2 32.6% 17.5%);
97
- --color-input: hsl(217.2 32.6% 17.5%);
98
- --color-ring: hsl(212.7 26.8% 83.9%);
99
- --color-success: hsl(142 71% 45%);
100
- --color-success-foreground: hsl(0 0% 100%);
101
-
102
- --sb--color-background: hsl(222.2 84% 4.9%);
103
- --sb--color-foreground: hsl(210 40% 98%);
104
- --sb--color-card: hsl(222.2 84% 4.9%);
105
- --sb--color-card-foreground: hsl(210 40% 98%);
106
- --sb--color-popover: hsl(222.2 84% 4.9%);
107
- --sb--color-popover-foreground: hsl(210 40% 98%);
108
- --sb--color-primary: hsl(210 40% 98%);
109
- --sb--color-primary-foreground: hsl(222.2 47.4% 11.2%);
110
- --sb--color-secondary: hsl(217.2 32.6% 17.5%);
111
- --sb--color-secondary-foreground: hsl(210 40% 98%);
112
- --sb--color-muted: hsl(217.2 32.6% 17.5%);
113
- --sb--color-muted-foreground: hsl(215 20.2% 65.1%);
114
- --sb--color-accent: hsl(217.2 32.6% 17.5%);
115
- --sb--color-accent-foreground: hsl(210 40% 98%);
116
- --sb--color-destructive: hsl(0 62.8% 30.6%);
117
- --sb--color-destructive-foreground: hsl(210 40% 98%);
118
- --sb--color-border: hsl(217.2 32.6% 17.5%);
119
- --sb--color-input: hsl(217.2 32.6% 17.5%);
120
- --sb--color-ring: hsl(212.7 26.8% 83.9%);
121
- --sb--color-success: hsl(142 71% 45%);
122
- --sb--color-success-foreground: hsl(0 0% 100%);
117
+ [data-sb-theme^="dark"],
118
+ [data-sb-canvas-theme^="dark"],
119
+ [data-sb-prototype-theme^="dark"],
120
+ [data-sb-toolbar-theme^="dark"],
121
+ [data-sb-codeboxes-theme^="dark"],
122
+ [data-sb-code-theme^="dark"] {
123
+ --color-background: #0d1117;
124
+ --color-background-muted: #151b23;
125
+ --color-background-inset: #010409;
126
+ --color-background-emphasis: #3d444d;
127
+ --color-background-inverse: #ffffff;
128
+ --color-background-neutral-muted: #656c7633;
129
+ --color-background-neutral-emphasis: #656c76;
130
+ --color-background-accent-muted: #388bfd1a;
131
+ --color-background-accent-emphasis: #1f6feb;
132
+ --color-background-accent-emphasis-hover: #388bfd;
133
+ --color-background-danger-muted: #f851491a;
134
+ --color-background-danger-emphasis: #da3633;
135
+ --color-background-success-muted: #2ea04326;
136
+ --color-background-success-emphasis: #238636;
137
+ --color-background-success-hover: #2ea043;
138
+ --color-background-attention-muted: #bb800926;
139
+ --color-background-done-muted: #ab7df81a;
140
+ --color-background-done-emphasis: #8957e5;
141
+ --color-background-open-emphasis: #238636;
142
+ --color-background-closed-emphasis: #da3633;
143
+
144
+ --color-foreground: #f0f6fc;
145
+ --color-foreground-muted: #9198a1;
146
+ --color-foreground-accent: #4493f8;
147
+ --color-foreground-danger: #f85149;
148
+ --color-foreground-success: #3fb950;
149
+ --color-foreground-attention: #d29922;
150
+ --color-foreground-on-emphasis: #ffffff;
151
+ --color-foreground-on-inverse: #010409;
152
+
153
+ --color-border: #3d444d;
154
+ --color-border-muted: #3d444db3;
155
+ --color-border-emphasis: #656c76;
156
+ --color-border-accent-emphasis: #1f6feb;
157
+ --color-border-accent-muted: #388bfd66;
158
+ --color-border-danger-emphasis: #da3633;
159
+ --color-border-danger-muted: #f8514966;
160
+ --color-border-success-muted: #2ea04366;
161
+ --color-border-attention-muted: #bb800966;
162
+
163
+ --color-overlay-backdrop: #21283066;
164
+
165
+ --shadow-resting: 0px 1px 1px 0px #01040999, 0px 1px 3px 0px #01040999;
166
+ --shadow-floating: 0px 0px 0px 1px #3d444d, 0px 6px 12px -3px #01040966, 0px 6px 18px 0px #01040966;
167
+
168
+ --color-primary: #f0f6fc;
169
+ --color-primary-foreground: #0d1117;
170
+ --color-ring: var(--color-background-accent-emphasis);
123
171
  }
124
172
  }
125
173
  @custom-variant data-open {
@@ -6,25 +6,8 @@
6
6
  * Prototypes and stories do NOT load this stylesheet — their CSS chain
7
7
  * is owned by the consumer's `src/_prototype.jsx` / `src/_story.jsx`.
8
8
  *
9
- * Sources:
10
- * - @primer/primitives supplies the --fgColor-*, --bgColor-*,
11
- * --borderColor-*, and theme attr selectors that the ~200 CSS module
12
- * references across the workspace surfaces depend on.
9
+ * All color/spacing/typography tokens previously sourced from
10
+ * `@primer/primitives` now live in `core/styles/tailwind.css` (the
11
+ * single source of truth). This file is intentionally empty but kept
12
+ * for backward compatibility with consumers that import it directly.
13
13
  */
14
- @import '@primer/primitives/dist/css/base/size/size.css';
15
- @import '@primer/primitives/dist/css/base/typography/typography.css';
16
- @import '@primer/primitives/dist/css/base/motion/motion.css';
17
- @import '@primer/primitives/dist/css/functional/size/border.css';
18
- @import '@primer/primitives/dist/css/functional/size/breakpoints.css';
19
- @import '@primer/primitives/dist/css/functional/size/size-coarse.css';
20
- @import '@primer/primitives/dist/css/functional/size/size-fine.css';
21
- @import '@primer/primitives/dist/css/functional/size/size.css';
22
- @import '@primer/primitives/dist/css/functional/size/viewport.css';
23
- @import '@primer/primitives/dist/css/functional/typography/typography.css';
24
-
25
- @import '@primer/primitives/dist/css/functional/themes/light.css';
26
- @import '@primer/primitives/dist/css/functional/themes/light-colorblind.css';
27
- @import '@primer/primitives/dist/css/functional/themes/dark.css';
28
- @import '@primer/primitives/dist/css/functional/themes/dark-colorblind.css';
29
- @import '@primer/primitives/dist/css/functional/themes/dark-high-contrast.css';
30
- @import '@primer/primitives/dist/css/functional/themes/dark-dimmed.css';
@@ -1,14 +1,14 @@
1
1
  .menuTitle {
2
2
  font-size: 13px;
3
3
  font-weight: 500;
4
- color: var(--fgColor-default, #e6edf3);
4
+ color: var(--color-foreground, #e6edf3);
5
5
  padding: 6px 6px 0;
6
6
  margin: 0;
7
7
  }
8
8
 
9
9
  .description {
10
10
  font-size: 12px;
11
- color: var(--fgColor-muted, #848d97);
11
+ color: var(--color-foreground-muted, #848d97);
12
12
  padding: 0 6px 4px;
13
13
  margin: 0;
14
14
  line-height: 1.4;
@@ -24,7 +24,7 @@
24
24
  .branchLabel {
25
25
  font-size: 13px;
26
26
  font-weight: 500;
27
- color: var(--fgColor-default, #e6edf3);
27
+ color: var(--color-foreground, #e6edf3);
28
28
  }
29
29
 
30
30
  .statusRow {
@@ -33,19 +33,19 @@
33
33
 
34
34
  .scopeHint {
35
35
  font-size: 11px;
36
- color: var(--fgColor-muted, #848d97);
36
+ color: var(--color-foreground-muted, #848d97);
37
37
  padding: 4px 0;
38
38
  margin: 0;
39
39
  }
40
40
 
41
41
  .statusError {
42
42
  font-size: 11px;
43
- color: var(--fgColor-danger, #f85149);
43
+ color: var(--color-foreground-danger, #f85149);
44
44
  }
45
45
 
46
46
  .statusOk {
47
47
  font-size: 11px;
48
- color: var(--fgColor-muted, #848d97);
48
+ color: var(--color-foreground-muted, #848d97);
49
49
  }
50
50
 
51
51
  .footer {
@@ -53,7 +53,7 @@
53
53
  align-items: center;
54
54
  gap: 6px;
55
55
  font-size: 12px;
56
- color: var(--fgColor-muted, #848d97);
56
+ color: var(--color-foreground-muted, #848d97);
57
57
  padding: 2px 6px 0;
58
58
  margin: 0;
59
59
  }
@@ -1,9 +1,9 @@
1
1
  .select {
2
2
  width: 100%;
3
3
  appearance: none;
4
- background-color: var(--bgColor-default, #0d1117);
5
- color: var(--fgColor-default, #e6edf3);
6
- border: 1px solid var(--borderColor-default, #30363d);
4
+ background-color: var(--color-background, #0d1117);
5
+ color: var(--color-foreground, #e6edf3);
6
+ border: 1px solid var(--color-border, #30363d);
7
7
  border-radius: 8px;
8
8
  padding: 8px 32px 8px 12px;
9
9
  font-size: 13px;
@@ -16,11 +16,11 @@
16
16
  }
17
17
 
18
18
  .select:hover:not(:disabled) {
19
- border-color: var(--fgColor-muted, #848d97);
19
+ border-color: var(--color-foreground-muted, #848d97);
20
20
  }
21
21
 
22
22
  .select:focus-visible {
23
- outline: 2px solid var(--borderColor-accent-emphasis, #1f6feb);
23
+ outline: 2px solid var(--color-border-accent-emphasis, #1f6feb);
24
24
  outline-offset: -1px;
25
25
  }
26
26