tuiuiu.js 1.0.4 → 1.0.6-next.4ff3fbc
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/dist/app/render-loop.d.ts +2 -0
- package/dist/app/render-loop.d.ts.map +1 -1
- package/dist/app/render-loop.js +14 -3
- package/dist/app/render-loop.js.map +1 -1
- package/dist/atoms/button.d.ts +1 -1
- package/dist/atoms/button.d.ts.map +1 -1
- package/dist/atoms/button.js +13 -11
- package/dist/atoms/button.js.map +1 -1
- package/dist/atoms/progress-bar.d.ts.map +1 -1
- package/dist/atoms/progress-bar.js +15 -12
- package/dist/atoms/progress-bar.js.map +1 -1
- package/dist/atoms/scrollbar.d.ts +30 -0
- package/dist/atoms/scrollbar.d.ts.map +1 -0
- package/dist/atoms/scrollbar.js +46 -0
- package/dist/atoms/scrollbar.js.map +1 -0
- package/dist/atoms/slider.js +6 -6
- package/dist/atoms/slider.js.map +1 -1
- package/dist/atoms/spinner.d.ts.map +1 -1
- package/dist/atoms/spinner.js +3 -2
- package/dist/atoms/spinner.js.map +1 -1
- package/dist/atoms/switch.d.ts.map +1 -1
- package/dist/atoms/switch.js +3 -2
- package/dist/atoms/switch.js.map +1 -1
- package/dist/atoms/text-input.d.ts.map +1 -1
- package/dist/atoms/text-input.js +6 -5
- package/dist/atoms/text-input.js.map +1 -1
- package/dist/atoms/timer.d.ts +1 -1
- package/dist/atoms/timer.js +4 -4
- package/dist/atoms/timer.js.map +1 -1
- package/dist/atoms/tooltip.d.ts +4 -4
- package/dist/atoms/tooltip.js +19 -19
- package/dist/atoms/tooltip.js.map +1 -1
- package/dist/core/delta-render.d.ts.map +1 -1
- package/dist/core/delta-render.js +17 -12
- package/dist/core/delta-render.js.map +1 -1
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +15 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/renderer.d.ts +4 -2
- package/dist/core/renderer.d.ts.map +1 -1
- package/dist/core/renderer.js +70 -43
- package/dist/core/renderer.js.map +1 -1
- package/dist/core/theme-loader.d.ts +89 -0
- package/dist/core/theme-loader.d.ts.map +1 -0
- package/dist/core/theme-loader.js +228 -0
- package/dist/core/theme-loader.js.map +1 -0
- package/dist/core/theme-types.d.ts +577 -0
- package/dist/core/theme-types.d.ts.map +1 -0
- package/dist/core/theme-types.js +13 -0
- package/dist/core/theme-types.js.map +1 -0
- package/dist/core/theme.d.ts +155 -236
- package/dist/core/theme.d.ts.map +1 -1
- package/dist/core/theme.js +418 -709
- package/dist/core/theme.js.map +1 -1
- package/dist/design-system/core/renderer.d.ts +14 -3
- package/dist/design-system/core/renderer.d.ts.map +1 -1
- package/dist/design-system/core/renderer.js +77 -38
- package/dist/design-system/core/renderer.js.map +1 -1
- package/dist/design-system/feedback/badge.d.ts +2 -8
- package/dist/design-system/feedback/badge.d.ts.map +1 -1
- package/dist/design-system/feedback/badge.js +32 -8
- package/dist/design-system/feedback/badge.js.map +1 -1
- package/dist/design-system/feedback/progress-bar.d.ts.map +1 -1
- package/dist/design-system/feedback/progress-bar.js +15 -12
- package/dist/design-system/feedback/progress-bar.js.map +1 -1
- package/dist/design-system/feedback/spinner.d.ts.map +1 -1
- package/dist/design-system/feedback/spinner.js +4 -3
- package/dist/design-system/feedback/spinner.js.map +1 -1
- package/dist/design-system/feedback/timer.js +3 -3
- package/dist/design-system/feedback/timer.js.map +1 -1
- package/dist/design-system/layout/app.js +6 -6
- package/dist/design-system/layout/app.js.map +1 -1
- package/dist/design-system/navigation/file-manager.js +15 -15
- package/dist/design-system/navigation/file-manager.js.map +1 -1
- package/dist/design-system/visual/big-text.js +6 -6
- package/dist/design-system/visual/big-text.js.map +1 -1
- package/dist/design-system/visual/digits.js +7 -7
- package/dist/design-system/visual/digits.js.map +1 -1
- package/dist/design-system/visual/splash-screen.d.ts.map +1 -1
- package/dist/design-system/visual/splash-screen.js +23 -17
- package/dist/design-system/visual/splash-screen.js.map +1 -1
- package/dist/design-system/visual/tooltip.js +16 -16
- package/dist/design-system/visual/tooltip.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/types.d.ts +2 -0
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/hooks/use-app.d.ts +5 -0
- package/dist/hooks/use-app.d.ts.map +1 -1
- package/dist/hooks/use-app.js +10 -0
- package/dist/hooks/use-app.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/docs-data.d.ts.map +1 -1
- package/dist/mcp/docs-data.js +625 -28
- package/dist/mcp/docs-data.js.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/molecules/autocomplete.js +10 -10
- package/dist/molecules/autocomplete.js.map +1 -1
- package/dist/molecules/calendar.d.ts.map +1 -1
- package/dist/molecules/calendar.js +13 -12
- package/dist/molecules/calendar.js.map +1 -1
- package/dist/molecules/code-block.js +21 -21
- package/dist/molecules/code-block.js.map +1 -1
- package/dist/molecules/collapsible.d.ts +9 -5
- package/dist/molecules/collapsible.d.ts.map +1 -1
- package/dist/molecules/collapsible.js +39 -7
- package/dist/molecules/collapsible.js.map +1 -1
- package/dist/molecules/data-viz/bar-chart.js +8 -8
- package/dist/molecules/data-viz/bar-chart.js.map +1 -1
- package/dist/molecules/data-viz/gauge.d.ts.map +1 -1
- package/dist/molecules/data-viz/gauge.js +17 -17
- package/dist/molecules/data-viz/gauge.js.map +1 -1
- package/dist/molecules/data-viz/heatmap.js +11 -11
- package/dist/molecules/data-viz/heatmap.js.map +1 -1
- package/dist/molecules/data-viz/legend.js +3 -3
- package/dist/molecules/data-viz/legend.js.map +1 -1
- package/dist/molecules/data-viz/line-chart.js +4 -4
- package/dist/molecules/data-viz/line-chart.js.map +1 -1
- package/dist/molecules/data-viz/sparkline.js +1 -1
- package/dist/molecules/data-viz/sparkline.js.map +1 -1
- package/dist/molecules/markdown.js +23 -23
- package/dist/molecules/markdown.js.map +1 -1
- package/dist/molecules/multi-select.js +9 -9
- package/dist/molecules/multi-select.js.map +1 -1
- package/dist/molecules/radio-group.js +8 -8
- package/dist/molecules/radio-group.js.map +1 -1
- package/dist/molecules/select.d.ts.map +1 -1
- package/dist/molecules/select.js +15 -13
- package/dist/molecules/select.js.map +1 -1
- package/dist/molecules/table.js +3 -3
- package/dist/molecules/table.js.map +1 -1
- package/dist/molecules/tabs.d.ts +6 -2
- package/dist/molecules/tabs.d.ts.map +1 -1
- package/dist/molecules/tabs.js +25 -13
- package/dist/molecules/tabs.js.map +1 -1
- package/dist/molecules/tree.js +5 -5
- package/dist/molecules/tree.js.map +1 -1
- package/dist/organisms/command-palette.d.ts.map +1 -1
- package/dist/organisms/command-palette.js +19 -17
- package/dist/organisms/command-palette.js.map +1 -1
- package/dist/organisms/data-table.js +5 -5
- package/dist/organisms/data-table.js.map +1 -1
- package/dist/organisms/file-browser.js +15 -15
- package/dist/organisms/file-browser.js.map +1 -1
- package/dist/organisms/index.d.ts +2 -1
- package/dist/organisms/index.d.ts.map +1 -1
- package/dist/organisms/index.js +13 -1
- package/dist/organisms/index.js.map +1 -1
- package/dist/organisms/modal.d.ts +46 -0
- package/dist/organisms/modal.d.ts.map +1 -1
- package/dist/organisms/modal.js +110 -29
- package/dist/organisms/modal.js.map +1 -1
- package/dist/organisms/scroll-area.js +6 -6
- package/dist/organisms/scroll-area.js.map +1 -1
- package/dist/organisms/scroll-list.d.ts +168 -0
- package/dist/organisms/scroll-list.d.ts.map +1 -0
- package/dist/organisms/scroll-list.js +338 -0
- package/dist/organisms/scroll-list.js.map +1 -0
- package/dist/organisms/split-panel.d.ts.map +1 -1
- package/dist/organisms/split-panel.js +7 -4
- package/dist/organisms/split-panel.js.map +1 -1
- package/dist/primitives/divider.d.ts.map +1 -1
- package/dist/primitives/divider.js +4 -3
- package/dist/primitives/divider.js.map +1 -1
- package/dist/primitives/index.d.ts +1 -0
- package/dist/primitives/index.d.ts.map +1 -1
- package/dist/primitives/index.js +1 -0
- package/dist/primitives/index.js.map +1 -1
- package/dist/primitives/nodes.d.ts.map +1 -1
- package/dist/primitives/nodes.js +5 -3
- package/dist/primitives/nodes.js.map +1 -1
- package/dist/primitives/scroll.d.ts +127 -0
- package/dist/primitives/scroll.d.ts.map +1 -0
- package/dist/primitives/scroll.js +202 -0
- package/dist/primitives/scroll.js.map +1 -0
- package/dist/storybook/app.d.ts.map +1 -1
- package/dist/storybook/app.js +218 -84
- package/dist/storybook/app.js.map +1 -1
- package/dist/storybook/components/compare-view.d.ts.map +1 -1
- package/dist/storybook/components/compare-view.js +25 -19
- package/dist/storybook/components/compare-view.js.map +1 -1
- package/dist/storybook/components/hotkeys-panel.d.ts +12 -0
- package/dist/storybook/components/hotkeys-panel.d.ts.map +1 -0
- package/dist/storybook/components/hotkeys-panel.js +44 -0
- package/dist/storybook/components/hotkeys-panel.js.map +1 -0
- package/dist/storybook/components/index.d.ts +6 -0
- package/dist/storybook/components/index.d.ts.map +1 -1
- package/dist/storybook/components/index.js +9 -0
- package/dist/storybook/components/index.js.map +1 -1
- package/dist/storybook/components/log-viewer.d.ts +9 -4
- package/dist/storybook/components/log-viewer.d.ts.map +1 -1
- package/dist/storybook/components/log-viewer.js +97 -35
- package/dist/storybook/components/log-viewer.js.map +1 -1
- package/dist/storybook/components/navbar.d.ts +17 -0
- package/dist/storybook/components/navbar.d.ts.map +1 -0
- package/dist/storybook/components/navbar.js +52 -0
- package/dist/storybook/components/navbar.js.map +1 -0
- package/dist/storybook/components/pressed-keys.d.ts +29 -0
- package/dist/storybook/components/pressed-keys.d.ts.map +1 -0
- package/dist/storybook/components/pressed-keys.js +148 -0
- package/dist/storybook/components/pressed-keys.js.map +1 -0
- package/dist/storybook/components/preview.d.ts.map +1 -1
- package/dist/storybook/components/preview.js +44 -34
- package/dist/storybook/components/preview.js.map +1 -1
- package/dist/storybook/components/search-bar.d.ts +29 -0
- package/dist/storybook/components/search-bar.d.ts.map +1 -0
- package/dist/storybook/components/search-bar.js +101 -0
- package/dist/storybook/components/search-bar.js.map +1 -0
- package/dist/storybook/components/sidebar.d.ts.map +1 -1
- package/dist/storybook/components/sidebar.js +27 -21
- package/dist/storybook/components/sidebar.js.map +1 -1
- package/dist/storybook/components/status-bar.d.ts +22 -0
- package/dist/storybook/components/status-bar.d.ts.map +1 -0
- package/dist/storybook/components/status-bar.js +64 -0
- package/dist/storybook/components/status-bar.js.map +1 -0
- package/dist/storybook/store.d.ts +13 -1
- package/dist/storybook/store.d.ts.map +1 -1
- package/dist/storybook/store.js +21 -1
- package/dist/storybook/store.js.map +1 -1
- package/dist/storybook/stories/apps/index.d.ts.map +1 -1
- package/dist/storybook/stories/apps/index.js +82 -147
- package/dist/storybook/stories/apps/index.js.map +1 -1
- package/dist/storybook/stories/atoms/index.d.ts.map +1 -1
- package/dist/storybook/stories/atoms/index.js +57 -52
- package/dist/storybook/stories/atoms/index.js.map +1 -1
- package/dist/storybook/stories/molecules/index.d.ts +16 -0
- package/dist/storybook/stories/molecules/index.d.ts.map +1 -1
- package/dist/storybook/stories/molecules/index.js +299 -91
- package/dist/storybook/stories/molecules/index.js.map +1 -1
- package/dist/storybook/stories/organisms/index.d.ts.map +1 -1
- package/dist/storybook/stories/organisms/index.js +207 -120
- package/dist/storybook/stories/organisms/index.js.map +1 -1
- package/dist/templates/app.d.ts +28 -23
- package/dist/templates/app.d.ts.map +1 -1
- package/dist/templates/app.js +104 -17
- package/dist/templates/app.js.map +1 -1
- package/dist/themes/catppuccin.theme.d.ts +8 -0
- package/dist/themes/catppuccin.theme.d.ts.map +1 -0
- package/dist/themes/catppuccin.theme.js +538 -0
- package/dist/themes/catppuccin.theme.js.map +1 -0
- package/dist/themes/dark.theme.d.ts +8 -0
- package/dist/themes/dark.theme.d.ts.map +1 -0
- package/dist/themes/dark.theme.js +502 -0
- package/dist/themes/dark.theme.js.map +1 -0
- package/dist/themes/dracula.theme.d.ts +8 -0
- package/dist/themes/dracula.theme.d.ts.map +1 -0
- package/dist/themes/dracula.theme.js +518 -0
- package/dist/themes/dracula.theme.js.map +1 -0
- package/dist/themes/gruvbox.theme.d.ts +8 -0
- package/dist/themes/gruvbox.theme.d.ts.map +1 -0
- package/dist/themes/gruvbox.theme.js +529 -0
- package/dist/themes/gruvbox.theme.js.map +1 -0
- package/dist/themes/high-contrast-dark.theme.d.ts +8 -0
- package/dist/themes/high-contrast-dark.theme.d.ts.map +1 -0
- package/dist/themes/high-contrast-dark.theme.js +503 -0
- package/dist/themes/high-contrast-dark.theme.js.map +1 -0
- package/dist/themes/index.d.ts +58 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +75 -0
- package/dist/themes/index.js.map +1 -0
- package/dist/themes/light.theme.d.ts +8 -0
- package/dist/themes/light.theme.d.ts.map +1 -0
- package/dist/themes/light.theme.js +502 -0
- package/dist/themes/light.theme.js.map +1 -0
- package/dist/themes/monochrome.theme.d.ts +8 -0
- package/dist/themes/monochrome.theme.d.ts.map +1 -0
- package/dist/themes/monochrome.theme.js +503 -0
- package/dist/themes/monochrome.theme.js.map +1 -0
- package/dist/themes/monokai.theme.d.ts +8 -0
- package/dist/themes/monokai.theme.d.ts.map +1 -0
- package/dist/themes/monokai.theme.js +518 -0
- package/dist/themes/monokai.theme.js.map +1 -0
- package/dist/themes/nord.theme.d.ts +8 -0
- package/dist/themes/nord.theme.d.ts.map +1 -0
- package/dist/themes/nord.theme.js +527 -0
- package/dist/themes/nord.theme.js.map +1 -0
- package/dist/themes/solarized-dark.theme.d.ts +8 -0
- package/dist/themes/solarized-dark.theme.d.ts.map +1 -0
- package/dist/themes/solarized-dark.theme.js +525 -0
- package/dist/themes/solarized-dark.theme.js.map +1 -0
- package/dist/themes/tokyo-night.theme.d.ts +8 -0
- package/dist/themes/tokyo-night.theme.d.ts.map +1 -0
- package/dist/themes/tokyo-night.theme.js +529 -0
- package/dist/themes/tokyo-night.theme.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/storybook/app.js
CHANGED
|
@@ -9,13 +9,16 @@ import { render } from '../app/render-loop.js';
|
|
|
9
9
|
import { useState, useInput, useApp, useEffect } from '../hooks/index.js';
|
|
10
10
|
import { createRef } from '../core/index.js';
|
|
11
11
|
import { startTick, stopTick, getTick, isTickRunning, setTickRate } from '../core/tick.js';
|
|
12
|
-
import { setTheme, useTheme, getNextTheme,
|
|
12
|
+
import { setTheme, useTheme, getNextTheme, getTheme } from '../core/theme.js';
|
|
13
13
|
import { allStories } from './stories/index.js';
|
|
14
14
|
import { COLORS, TUIUIU_BIRD_COLORED } from './data/ascii-art.js';
|
|
15
15
|
import { SplashScreen, createSplashScreen } from '../design-system/visual/splash-screen.js';
|
|
16
|
+
// Version
|
|
17
|
+
import { getVersion, getVersionSync } from '../version.js';
|
|
16
18
|
// Storybook Global State & Logger
|
|
17
19
|
import { storybookStore, interceptConsole } from './store.js';
|
|
18
|
-
|
|
20
|
+
// Storybook UI Components
|
|
21
|
+
import { Navbar, MetricsStatusBar, SearchBar, searchStories, ConsoleAccordion, HotkeysPanel, PressedKeysIndicator, recordKeyPress, clearOldKeyPresses, } from './components/index.js';
|
|
19
22
|
// =============================================================================
|
|
20
23
|
// Initialization
|
|
21
24
|
// =============================================================================
|
|
@@ -41,19 +44,21 @@ function getStoriesByCategory(category) {
|
|
|
41
44
|
* Render story content safely
|
|
42
45
|
*/
|
|
43
46
|
function StoryContent(props) {
|
|
47
|
+
const theme = getTheme();
|
|
44
48
|
const { story, values, frame = 0 } = props;
|
|
45
49
|
try {
|
|
46
50
|
return story.render(values, frame);
|
|
47
51
|
}
|
|
48
52
|
catch (error) {
|
|
49
53
|
console.error('Render error:', error); // Captured by our interceptor!
|
|
50
|
-
return Box({ flexDirection: 'column', padding: 1, borderStyle: 'single', borderColor:
|
|
54
|
+
return Box({ flexDirection: 'column', padding: 1, borderStyle: 'single', borderColor: theme.accents.critical }, Text({ color: theme.accents.critical, bold: true }, 'Render Error'), Text({ color: theme.accents.critical }, error.message || String(error)));
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
/**
|
|
54
58
|
* Sidebar component - category and story list with virtual scroll
|
|
55
59
|
*/
|
|
56
60
|
function Sidebar(props) {
|
|
61
|
+
const theme = getTheme();
|
|
57
62
|
const { categories, currentCategory, stories, selectedIndex, focusArea, onCategoryClick, onFocus } = props;
|
|
58
63
|
const isFocused = focusArea === 'sidebar';
|
|
59
64
|
// Virtual scroll: show window around selected item
|
|
@@ -81,12 +86,12 @@ function Sidebar(props) {
|
|
|
81
86
|
flexDirection: 'column',
|
|
82
87
|
width: 50,
|
|
83
88
|
borderStyle: 'single',
|
|
84
|
-
borderColor: isFocused ?
|
|
89
|
+
borderColor: isFocused ? theme.palette.primary[500] : theme.borders.default,
|
|
85
90
|
},
|
|
86
91
|
// Header
|
|
87
|
-
Box({ borderStyle: 'single', borderColor: isFocused ?
|
|
92
|
+
Box({ borderStyle: 'single', borderColor: isFocused ? theme.palette.primary[500] : theme.borders.default, paddingX: 1 }, Text({ color: theme.palette.primary[500], bold: true }, 'Stories')),
|
|
88
93
|
// Categories (horizontal tabs) - clickable
|
|
89
|
-
Box({ flexDirection: 'row', paddingX: 1, marginY: 1 }, Text({ color:
|
|
94
|
+
Box({ flexDirection: 'row', paddingX: 1, marginY: 1 }, Text({ color: theme.foreground.muted }, '◀ ▶ '), ...categories.map((cat, catIdx) => {
|
|
90
95
|
const isActive = cat === currentCategory;
|
|
91
96
|
const count = getStoriesByCategory(cat).length;
|
|
92
97
|
const shortName = cat.slice(0, 4);
|
|
@@ -96,13 +101,13 @@ function Sidebar(props) {
|
|
|
96
101
|
onCategoryClick?.(catIdx);
|
|
97
102
|
},
|
|
98
103
|
}, Text({
|
|
99
|
-
color: isActive ?
|
|
104
|
+
color: isActive ? theme.palette.primary[500] : theme.foreground.muted,
|
|
100
105
|
bold: isActive,
|
|
101
106
|
inverse: isActive,
|
|
102
107
|
}, isActive ? `[${shortName}:${count}]` : ` ${shortName}:${count} `));
|
|
103
|
-
})), Divider({ color:
|
|
108
|
+
})), Divider({ color: theme.borders.default }),
|
|
104
109
|
// Scroll up indicator (always present, may be empty)
|
|
105
|
-
Box({ paddingX: 1, height: 1 }, Text({ color:
|
|
110
|
+
Box({ paddingX: 1, height: 1 }, Text({ color: theme.palette.primary[500], dim: true }, scrollUpText)),
|
|
106
111
|
// Stories list (fixed height container) - clickable items
|
|
107
112
|
Box({ flexDirection: 'column', paddingX: 1, flexGrow: 1 }, ...visibleStories.map((story, idx) => {
|
|
108
113
|
const actualIdx = startIdx + idx;
|
|
@@ -113,32 +118,33 @@ function Sidebar(props) {
|
|
|
113
118
|
props.onStorySelect(actualIdx);
|
|
114
119
|
},
|
|
115
120
|
}, Text({
|
|
116
|
-
color: isSelected ?
|
|
121
|
+
color: isSelected ? theme.foreground.primary : theme.foreground.muted,
|
|
117
122
|
bold: isSelected,
|
|
118
123
|
inverse: isSelected && isFocused,
|
|
119
124
|
}, isSelected ? ` ${story.name} ` : ` ${story.name}`));
|
|
120
125
|
})),
|
|
121
126
|
// Scroll down indicator (always present, may be empty)
|
|
122
|
-
Box({ paddingX: 1, height: 1 }, Text({ color:
|
|
127
|
+
Box({ paddingX: 1, height: 1 }, Text({ color: theme.palette.primary[500], dim: true }, scrollDownText)),
|
|
123
128
|
// Footer
|
|
124
|
-
Box({ borderStyle: 'single', borderColor:
|
|
129
|
+
Box({ borderStyle: 'single', borderColor: theme.borders.default, paddingX: 1 }, Text({ color: theme.foreground.muted, dim: true }, `${selectedIndex + 1}/${stories.length}`)));
|
|
125
130
|
}
|
|
126
131
|
/**
|
|
127
132
|
* Control Panel component - edit story props
|
|
128
133
|
*/
|
|
129
134
|
function ControlPanel(props) {
|
|
135
|
+
const theme = getTheme();
|
|
130
136
|
const { story, values, focusedControlIndex, focusArea, isEditingText, editingTextValue, onTextChange, onFocus, onSelectControl, onStartTextEdit } = props;
|
|
131
137
|
const isFocused = focusArea === 'controls';
|
|
132
138
|
const controls = Object.entries(story.controls || {});
|
|
133
139
|
if (controls.length === 0) {
|
|
134
|
-
return Box({ padding: 1, borderStyle: 'single', borderColor:
|
|
140
|
+
return Box({ padding: 1, borderStyle: 'single', borderColor: theme.borders.default }, Text({ color: theme.foreground.muted, dim: true }, 'No controls defined'));
|
|
135
141
|
}
|
|
136
142
|
return Box({
|
|
137
143
|
flexDirection: 'column',
|
|
138
144
|
borderStyle: 'single',
|
|
139
|
-
borderColor: isFocused ?
|
|
145
|
+
borderColor: isFocused ? theme.palette.primary[500] : theme.borders.default,
|
|
140
146
|
width: 30,
|
|
141
|
-
}, Box({ borderStyle: 'single', borderColor: isFocused ?
|
|
147
|
+
}, Box({ borderStyle: 'single', borderColor: isFocused ? theme.palette.primary[500] : theme.borders.default, paddingX: 1 }, Text({ color: theme.accents.warning, bold: true }, 'Controls')), Box({ flexDirection: 'column', padding: 1 }, ...controls.map(([key, control], idx) => {
|
|
142
148
|
const value = values[key] ?? control.defaultValue;
|
|
143
149
|
const isActive = idx === focusedControlIndex && isFocused;
|
|
144
150
|
const isThisEditingText = isActive && isEditingText && control.type === 'text';
|
|
@@ -158,7 +164,7 @@ function ControlPanel(props) {
|
|
|
158
164
|
flexDirection: 'column',
|
|
159
165
|
marginBottom: 1,
|
|
160
166
|
onClick: handleClick,
|
|
161
|
-
}, Box({}, Text({ color: isActive ?
|
|
167
|
+
}, Box({}, Text({ color: isActive ? theme.palette.primary[500] : theme.foreground.muted }, `${control.label}: `), isThisEditingText
|
|
162
168
|
? renderTextInputInline(editingTextValue, isActive, onTextChange)
|
|
163
169
|
: renderControlValue(value, control.type, isActive)));
|
|
164
170
|
})));
|
|
@@ -167,18 +173,20 @@ function ControlPanel(props) {
|
|
|
167
173
|
* Render inline text input for editing
|
|
168
174
|
*/
|
|
169
175
|
function renderTextInputInline(value, isActive, onChange) {
|
|
176
|
+
const theme = getTheme();
|
|
170
177
|
// Create inline text input with visible cursor
|
|
171
178
|
const cursorChar = '▎';
|
|
172
|
-
return Box({ flexDirection: 'row' }, Text({ color:
|
|
179
|
+
return Box({ flexDirection: 'row' }, Text({ color: theme.foreground.primary }, '"'), Text({ color: theme.palette.primary[500] }, value), isActive ? Text({ color: theme.palette.primary[500], bold: true }, cursorChar) : null, Text({ color: theme.foreground.primary }, '"'));
|
|
173
180
|
}
|
|
174
181
|
/**
|
|
175
182
|
* Render control value display
|
|
176
183
|
*/
|
|
177
184
|
function renderControlValue(value, type, isActive) {
|
|
178
|
-
const
|
|
185
|
+
const theme = getTheme();
|
|
186
|
+
const color = isActive ? theme.foreground.primary : theme.foreground.muted;
|
|
179
187
|
switch (type) {
|
|
180
188
|
case 'boolean':
|
|
181
|
-
return Text({ color: value ?
|
|
189
|
+
return Text({ color: value ? theme.accents.positive : theme.accents.critical }, value ? 'true' : 'false');
|
|
182
190
|
case 'number':
|
|
183
191
|
case 'range':
|
|
184
192
|
return Text({ color }, String(value));
|
|
@@ -196,50 +204,53 @@ function renderControlValue(value, type, isActive) {
|
|
|
196
204
|
* Docs view - show story documentation
|
|
197
205
|
*/
|
|
198
206
|
function DocsView(props) {
|
|
207
|
+
const theme = getTheme();
|
|
199
208
|
const { story } = props;
|
|
200
209
|
const controls = Object.entries(story.controls || {});
|
|
201
210
|
const children = [
|
|
202
211
|
// Title
|
|
203
|
-
Box({ marginBottom: 1 }, Text({ color:
|
|
212
|
+
Box({ marginBottom: 1 }, Text({ color: theme.palette.primary[500], bold: true }, `📖 ${story.name}`)),
|
|
204
213
|
];
|
|
205
214
|
// Description (optional)
|
|
206
215
|
if (story.description) {
|
|
207
|
-
children.push(Box({ marginBottom: 1 }, Text({ color:
|
|
216
|
+
children.push(Box({ marginBottom: 1 }, Text({ color: theme.foreground.primary }, story.description)));
|
|
208
217
|
}
|
|
209
218
|
// Controls documentation (if any)
|
|
210
219
|
if (controls.length > 0) {
|
|
211
|
-
children.push(Box({ flexDirection: 'column', marginTop: 1 }, Text({ color:
|
|
220
|
+
children.push(Box({ flexDirection: 'column', marginTop: 1 }, Text({ color: theme.accents.warning, bold: true }, 'Props:'), ...controls.map(([key, control]) => Box({ marginLeft: 1 }, Text({ color: theme.palette.primary[500] }, `• ${key}`), Text({ color: theme.foreground.muted }, ` (${control.type})`), Text({ color: theme.foreground.muted, dim: true }, ` - ${control.label}`)))));
|
|
212
221
|
}
|
|
213
222
|
// Category
|
|
214
|
-
children.push(Box({ marginTop: 1 }, Text({ color:
|
|
223
|
+
children.push(Box({ marginTop: 1 }, Text({ color: theme.foreground.muted }, 'Category: '), Text({ color: theme.accents.highlight }, story.category)));
|
|
215
224
|
return Box({ flexDirection: 'column', padding: 1 }, ...children);
|
|
216
225
|
}
|
|
217
226
|
/**
|
|
218
227
|
* Compare view - show story variants side by side
|
|
219
228
|
*/
|
|
220
229
|
function CompareView(props) {
|
|
230
|
+
const theme = getTheme();
|
|
221
231
|
const { story, values } = props;
|
|
222
232
|
const controls = Object.entries(story.controls || {});
|
|
223
233
|
// Find a control to compare (prefer select or boolean)
|
|
224
234
|
const compareControl = controls.find(([, c]) => c.type === 'select' || c.type === 'boolean');
|
|
225
235
|
if (!compareControl) {
|
|
226
|
-
return Box({ padding: 1 }, Text({ color:
|
|
236
|
+
return Box({ padding: 1 }, Text({ color: theme.foreground.muted }, 'No comparable props found for this story'));
|
|
227
237
|
}
|
|
228
238
|
const [key, control] = compareControl;
|
|
229
239
|
const variants = control.type === 'select' ? (control.options || []) :
|
|
230
240
|
control.type === 'boolean' ? [true, false] : [];
|
|
231
|
-
return Box({ flexDirection: 'column', padding: 1 }, Text({ color:
|
|
241
|
+
return Box({ flexDirection: 'column', padding: 1 }, Text({ color: theme.accents.positive, bold: true }, `🔀 Comparing: ${control.label}`), Divider({ color: theme.borders.default }), Box({ flexDirection: 'row', flexWrap: 'wrap', gap: 1 }, ...variants.slice(0, 4).map((variant) => Box({
|
|
232
242
|
flexDirection: 'column',
|
|
233
243
|
borderStyle: 'single',
|
|
234
|
-
borderColor: values[key] === variant ?
|
|
244
|
+
borderColor: values[key] === variant ? theme.palette.primary[500] : theme.borders.default,
|
|
235
245
|
padding: 1,
|
|
236
246
|
minWidth: 20,
|
|
237
|
-
}, Text({ color:
|
|
247
|
+
}, Text({ color: theme.palette.primary[500], dim: true }, String(variant)), Box({ marginTop: 1 }, StoryContent({ story, values: { ...values, [key]: variant }, frame: 0 }))))));
|
|
238
248
|
}
|
|
239
249
|
/**
|
|
240
250
|
* Preview Panel component - render story with mode-specific content
|
|
241
251
|
*/
|
|
242
252
|
function PreviewPanel(props) {
|
|
253
|
+
const theme = getTheme();
|
|
243
254
|
const { story, values, viewMode, focusArea, frame, isPaused } = props;
|
|
244
255
|
const isFocused = focusArea === 'preview';
|
|
245
256
|
const isAnimated = story.animation?.enabled;
|
|
@@ -260,51 +271,49 @@ function PreviewPanel(props) {
|
|
|
260
271
|
const previewChildren = [];
|
|
261
272
|
// Header with optional animation indicator
|
|
262
273
|
const headerChildren = [
|
|
263
|
-
Text({ color:
|
|
264
|
-
Text({ color:
|
|
274
|
+
Text({ color: theme.foreground.muted }, `${story.category} / `),
|
|
275
|
+
Text({ color: theme.palette.primary[500], bold: true }, story.name),
|
|
265
276
|
];
|
|
266
277
|
if (isAnimated) {
|
|
267
|
-
headerChildren.push(Text({ color: isPaused ?
|
|
278
|
+
headerChildren.push(Text({ color: isPaused ? theme.accents.warning : theme.accents.positive }, isPaused ? ' ⏸' : ' ▶'));
|
|
268
279
|
}
|
|
269
|
-
previewChildren.push(Box({ borderStyle: 'single', borderColor: isFocused ?
|
|
280
|
+
previewChildren.push(Box({ borderStyle: 'single', borderColor: isFocused ? theme.palette.primary[500] : theme.borders.default, paddingX: 1 }, ...headerChildren));
|
|
270
281
|
// View mode tabs
|
|
271
282
|
const modeText = isAnimated
|
|
272
283
|
? `[P][G][C][D] ${viewMode.toUpperCase()} Frame:${frame}`
|
|
273
284
|
: `[P][G][C][D] ${viewMode.toUpperCase()}`;
|
|
274
285
|
previewChildren.push(Box({ paddingX: 1 }, Text({ color: getModeColor(viewMode) }, modeText)));
|
|
275
286
|
if ((viewMode === 'preview' || viewMode === 'playground') && story.description) {
|
|
276
|
-
previewChildren.push(Box({ paddingX: 1 }, Text({ color:
|
|
287
|
+
previewChildren.push(Box({ paddingX: 1 }, Text({ color: theme.foreground.muted, dim: true }, story.description)));
|
|
277
288
|
}
|
|
278
|
-
previewChildren.push(Divider({ color:
|
|
289
|
+
previewChildren.push(Divider({ color: theme.borders.default }));
|
|
279
290
|
previewChildren.push(renderContent());
|
|
280
291
|
return Box({
|
|
281
292
|
flexDirection: 'column',
|
|
282
293
|
flexGrow: 1,
|
|
283
294
|
borderStyle: 'single',
|
|
284
|
-
borderColor: isFocused ?
|
|
295
|
+
borderColor: isFocused ? theme.palette.primary[500] : theme.borders.default,
|
|
285
296
|
}, ...previewChildren);
|
|
286
297
|
}
|
|
287
298
|
/**
|
|
288
299
|
* Get color for view mode
|
|
289
300
|
*/
|
|
290
301
|
function getModeColor(mode) {
|
|
302
|
+
const theme = getTheme();
|
|
291
303
|
switch (mode) {
|
|
292
|
-
case 'preview': return
|
|
293
|
-
case 'playground': return
|
|
294
|
-
case 'comparatives': return
|
|
295
|
-
case 'docs': return
|
|
296
|
-
default: return
|
|
304
|
+
case 'preview': return theme.palette.primary[500];
|
|
305
|
+
case 'playground': return theme.accents.warning;
|
|
306
|
+
case 'comparatives': return theme.accents.positive;
|
|
307
|
+
case 'docs': return theme.accents.highlight;
|
|
308
|
+
default: return theme.foreground.primary;
|
|
297
309
|
}
|
|
298
310
|
}
|
|
299
311
|
/**
|
|
300
|
-
*
|
|
312
|
+
* Text editing mode indicator
|
|
301
313
|
*/
|
|
302
|
-
function
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
return Box({ borderStyle: 'single', borderColor: themeColor('warning'), paddingX: 1 }, Text({ color: themeColor('warning'), bold: true }, '✏️ EDITING TEXT '), Text({ color: themeColor('mutedForeground') }, '[Enter] Save '), Text({ color: themeColor('mutedForeground') }, '[Esc] Cancel '), Text({ color: themeColor('mutedForeground') }, '[Backspace] Delete'));
|
|
306
|
-
}
|
|
307
|
-
return Box({ borderStyle: 'single', borderColor: themeColor('border'), paddingX: 1 }, Text({ color: themeColor('mutedForeground') }, '[Esc] Back/Quit '), Text({ color: themeColor('mutedForeground') }, '[Enter] Select '), Text({ color: themeColor('mutedForeground') }, '[Tab] Focus '), Text({ color: themeColor('mutedForeground') }, '[F1] Theme '), Text({ color: themeColor('mutedForeground') }, '[F12] Logs '), Text({ color: themeColor('primary'), dim: true }, '🖱️ Mouse enabled'));
|
|
314
|
+
function TextEditingIndicator() {
|
|
315
|
+
const theme = getTheme();
|
|
316
|
+
return Box({ borderStyle: 'single', borderColor: theme.accents.warning, paddingX: 1 }, Text({ color: theme.accents.warning, bold: true }, '✏️ EDITING TEXT '), Text({ color: theme.foreground.muted }, '[Enter] Save '), Text({ color: theme.foreground.muted }, '[Esc] Cancel '), Text({ color: theme.foreground.muted }, '[Backspace] Delete'));
|
|
308
317
|
}
|
|
309
318
|
/**
|
|
310
319
|
* Format elapsed time
|
|
@@ -314,55 +323,52 @@ function formatTime(seconds) {
|
|
|
314
323
|
const secs = seconds % 60;
|
|
315
324
|
return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
|
316
325
|
}
|
|
317
|
-
/**
|
|
318
|
-
* Navbar component with metrics
|
|
319
|
-
*/
|
|
320
|
-
function Navbar(props) {
|
|
321
|
-
const { componentCount, clicks, keystrokes, fps, elapsedSeconds, themeName } = props;
|
|
322
|
-
const fpsColor = fps >= 30 ? themeColor('success') : fps >= 15 ? themeColor('warning') : themeColor('error');
|
|
323
|
-
return Box({
|
|
324
|
-
flexDirection: 'row',
|
|
325
|
-
justifyContent: 'space-between',
|
|
326
|
-
borderStyle: 'single',
|
|
327
|
-
borderColor: themeColor('accent'),
|
|
328
|
-
}, Box({ flexDirection: 'row' }, Text({ color: themeColor('accent'), bold: true }, ' Tuiuiu.js '), Text({ color: themeColor('warning'), dim: true }, `[${themeName}] `)), Box({ flexDirection: 'row' }, Text({ color: themeColor('foreground'), bold: true }, formatTime(elapsedSeconds)), Text({ color: themeColor('mutedForeground'), dim: true }, ' '), Text({ color: themeColor('primary') }, String(componentCount)), Text({ color: themeColor('mutedForeground'), dim: true }, 's '), Text({ color: themeColor('warning') }, String(clicks)), Text({ color: themeColor('mutedForeground'), dim: true }, 'c '), Text({ color: themeColor('success') }, String(keystrokes)), Text({ color: themeColor('mutedForeground'), dim: true }, 'k '), Text({ color: fpsColor, bold: true }, `${fps}fps `)));
|
|
329
|
-
}
|
|
330
326
|
// =============================================================================
|
|
331
327
|
// Splash Screen
|
|
332
328
|
// =============================================================================
|
|
333
329
|
// Module-level splash state (created once when storybook starts)
|
|
334
330
|
let splashState = null;
|
|
331
|
+
// Module-level flag for splash completion
|
|
332
|
+
let splashCompleted = false;
|
|
333
|
+
let splashCompletionCallbacks = [];
|
|
335
334
|
function getSplashState() {
|
|
336
335
|
if (!splashState) {
|
|
337
336
|
splashState = createSplashScreen({
|
|
338
337
|
duration: 1500,
|
|
339
338
|
fadeInDuration: 300,
|
|
339
|
+
onComplete: () => {
|
|
340
|
+
splashCompleted = true;
|
|
341
|
+
// Notify all callbacks
|
|
342
|
+
for (const cb of splashCompletionCallbacks) {
|
|
343
|
+
cb();
|
|
344
|
+
}
|
|
345
|
+
splashCompletionCallbacks = [];
|
|
346
|
+
},
|
|
340
347
|
});
|
|
341
348
|
}
|
|
342
349
|
return splashState;
|
|
343
350
|
}
|
|
351
|
+
function onSplashComplete(callback) {
|
|
352
|
+
if (splashCompleted) {
|
|
353
|
+
callback();
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
splashCompletionCallbacks.push(callback);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
344
359
|
/**
|
|
345
360
|
* Main Storybook App
|
|
346
361
|
*/
|
|
347
362
|
function StorybookApp() {
|
|
363
|
+
const theme = getTheme();
|
|
348
364
|
const app = useApp();
|
|
349
365
|
// Get or create splash state
|
|
350
366
|
const splash = getSplashState();
|
|
351
|
-
//
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
version: '1.0.0',
|
|
357
|
-
loadingType: 'spinner',
|
|
358
|
-
spinnerStyle: 'dots',
|
|
359
|
-
loadingMessage: 'Loading stories...',
|
|
360
|
-
state: splash,
|
|
361
|
-
});
|
|
362
|
-
// Return splash or empty box (SplashScreen can return null when not visible)
|
|
363
|
-
return splashNode ?? Box({});
|
|
364
|
-
}
|
|
365
|
-
// State
|
|
367
|
+
// =========================================================================
|
|
368
|
+
// ALL HOOKS MUST BE CALLED BEFORE ANY CONDITIONAL RETURNS
|
|
369
|
+
// This ensures consistent hook ordering across renders
|
|
370
|
+
// =========================================================================
|
|
371
|
+
// State - always call these regardless of splash visibility
|
|
366
372
|
const categories = getCategories();
|
|
367
373
|
const [currentCategoryIndex, setCurrentCategoryIndex] = useState(0);
|
|
368
374
|
const [selectedStoryIndex, setSelectedStoryIndex] = useState(0);
|
|
@@ -375,6 +381,8 @@ function StorybookApp() {
|
|
|
375
381
|
const [editingTextValue, setEditingTextValue] = useState('');
|
|
376
382
|
// Animation state - now uses global tick
|
|
377
383
|
const [isPaused, setIsPaused] = useState(false);
|
|
384
|
+
// Track if we've already cleared screen after splash
|
|
385
|
+
const [splashDone, setSplashDone] = useState(false);
|
|
378
386
|
// Get animation frame from global tick
|
|
379
387
|
const animationFrame = () => getTick();
|
|
380
388
|
// Metrics state
|
|
@@ -450,11 +458,27 @@ function StorybookApp() {
|
|
|
450
458
|
}));
|
|
451
459
|
};
|
|
452
460
|
const controlKeys = currentStory ? Object.keys(currentStory.controls || {}) : [];
|
|
461
|
+
// Search state from store
|
|
462
|
+
const [searchSelectedIndex, setSearchSelectedIndex] = useState(0);
|
|
463
|
+
// Get search results
|
|
464
|
+
const storeState = storybookStore.state();
|
|
465
|
+
const searchResults = storeState.searchVisible
|
|
466
|
+
? searchStories(allStories, storeState.searchQuery)
|
|
467
|
+
: [];
|
|
453
468
|
// Input handling
|
|
454
469
|
useInput((input, key) => {
|
|
455
470
|
setKeystrokeCount((c) => c + 1);
|
|
456
|
-
//
|
|
471
|
+
// Record key press for indicator
|
|
472
|
+
recordKeyPress(input, key);
|
|
473
|
+
clearOldKeyPresses();
|
|
474
|
+
// Toggle Search with F1
|
|
457
475
|
if (key.f1) {
|
|
476
|
+
storybookStore.dispatch({ type: 'TOGGLE_SEARCH' });
|
|
477
|
+
setSearchSelectedIndex(0);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
// Toggle Theme with F2
|
|
481
|
+
if (key.f2) {
|
|
458
482
|
const currentTheme = useTheme();
|
|
459
483
|
const nextTheme = getNextTheme(currentTheme);
|
|
460
484
|
setTheme(nextTheme);
|
|
@@ -470,6 +494,56 @@ function StorybookApp() {
|
|
|
470
494
|
storybookStore.dispatch({ type: 'CLEAR_LOGS' });
|
|
471
495
|
}
|
|
472
496
|
// =========================================================================
|
|
497
|
+
// SEARCH MODE
|
|
498
|
+
// =========================================================================
|
|
499
|
+
if (storeState.searchVisible) {
|
|
500
|
+
// Escape - close search
|
|
501
|
+
if (key.escape) {
|
|
502
|
+
storybookStore.dispatch({ type: 'CLOSE_SEARCH' });
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
// Navigate results
|
|
506
|
+
if (key.upArrow) {
|
|
507
|
+
setSearchSelectedIndex((i) => Math.max(0, i - 1));
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (key.downArrow) {
|
|
511
|
+
setSearchSelectedIndex((i) => Math.min(searchResults.length - 1, i + 1));
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
// Select result and navigate
|
|
515
|
+
if (key.return && searchResults.length > 0) {
|
|
516
|
+
const selected = searchResults[searchSelectedIndex()];
|
|
517
|
+
if (selected) {
|
|
518
|
+
// Find category and story indices
|
|
519
|
+
const catIndex = categories.indexOf(selected.story.category);
|
|
520
|
+
const catStories = getStoriesByCategory(selected.story.category);
|
|
521
|
+
const storyIndex = catStories.findIndex((s) => s.name === selected.story.name);
|
|
522
|
+
if (catIndex >= 0)
|
|
523
|
+
setCurrentCategoryIndex(catIndex);
|
|
524
|
+
if (storyIndex >= 0)
|
|
525
|
+
setSelectedStoryIndex(storyIndex);
|
|
526
|
+
storybookStore.dispatch({ type: 'CLOSE_SEARCH' });
|
|
527
|
+
}
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
// Backspace - delete character from query
|
|
531
|
+
if (key.backspace) {
|
|
532
|
+
const current = storeState.searchQuery;
|
|
533
|
+
storybookStore.dispatch({ type: 'SET_SEARCH_QUERY', payload: current.slice(0, -1) });
|
|
534
|
+
setSearchSelectedIndex(0);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
// Regular character input - append to search query
|
|
538
|
+
if (input && input.length > 0 && !key.ctrl && !key.meta) {
|
|
539
|
+
storybookStore.dispatch({ type: 'SET_SEARCH_QUERY', payload: storeState.searchQuery + input });
|
|
540
|
+
setSearchSelectedIndex(0);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
// Consume all other keys while searching
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
// =========================================================================
|
|
473
547
|
// TEXT EDITING MODE
|
|
474
548
|
// =========================================================================
|
|
475
549
|
if (isEditingText()) {
|
|
@@ -641,17 +715,66 @@ function StorybookApp() {
|
|
|
641
715
|
}
|
|
642
716
|
}
|
|
643
717
|
});
|
|
718
|
+
// =========================================================================
|
|
719
|
+
// SPLASH→MAIN TRANSITION
|
|
720
|
+
// Use callback-based approach to ensure state update triggers re-render
|
|
721
|
+
// =========================================================================
|
|
722
|
+
// Register callback to update state when splash completes
|
|
723
|
+
useEffect(() => {
|
|
724
|
+
if (!splashDone()) {
|
|
725
|
+
onSplashComplete(() => {
|
|
726
|
+
app.clearScreen?.();
|
|
727
|
+
setSplashDone(true);
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
// Render splash while not done (use module-level flag + state for reactivity)
|
|
732
|
+
if (!splashDone() && !splashCompleted) {
|
|
733
|
+
const splashNode = SplashScreen({
|
|
734
|
+
coloredArt: TUIUIU_BIRD_COLORED,
|
|
735
|
+
subtitle: 'Component Explorer',
|
|
736
|
+
version: getVersionSync(),
|
|
737
|
+
loadingType: 'spinner',
|
|
738
|
+
spinnerStyle: 'dots',
|
|
739
|
+
loadingMessage: 'Loading stories...',
|
|
740
|
+
state: splash,
|
|
741
|
+
});
|
|
742
|
+
return splashNode ?? Box({});
|
|
743
|
+
}
|
|
744
|
+
// Wait for state to update
|
|
745
|
+
if (!splashDone()) {
|
|
746
|
+
return Box({});
|
|
747
|
+
}
|
|
644
748
|
if (!currentStory) {
|
|
645
|
-
return Box({ flexDirection: 'column', padding: 2 }, Text({ color:
|
|
749
|
+
return Box({ flexDirection: 'column', padding: 2 }, Text({ color: theme.accents.warning }, 'No stories found'), Text({ color: theme.foreground.muted }, 'Add stories to src/storybook/stories/'));
|
|
646
750
|
}
|
|
647
|
-
return Box({ flexDirection: 'column', height: '100%' },
|
|
648
|
-
|
|
751
|
+
return Box({ flexDirection: 'column', height: '100%' },
|
|
752
|
+
// =========================================================================
|
|
753
|
+
// HEADER SECTION
|
|
754
|
+
// =========================================================================
|
|
755
|
+
// Enhanced Navbar with branding
|
|
756
|
+
Navbar({ componentCount: allStories.length }),
|
|
757
|
+
// StatusBar with metrics
|
|
758
|
+
MetricsStatusBar({
|
|
759
|
+
themeName: useTheme().name,
|
|
649
760
|
clicks: clickCount(),
|
|
650
761
|
keystrokes: keystrokeCount(),
|
|
651
762
|
fps: fps(),
|
|
652
763
|
elapsedSeconds: elapsedSeconds(),
|
|
653
|
-
|
|
654
|
-
|
|
764
|
+
}),
|
|
765
|
+
// Search bar (conditional)
|
|
766
|
+
SearchBar({
|
|
767
|
+
query: storeState.searchQuery,
|
|
768
|
+
results: searchResults,
|
|
769
|
+
selectedIndex: searchSelectedIndex(),
|
|
770
|
+
isVisible: storeState.searchVisible,
|
|
771
|
+
}),
|
|
772
|
+
// Text editing indicator (when editing)
|
|
773
|
+
isEditingText() ? TextEditingIndicator() : null,
|
|
774
|
+
// =========================================================================
|
|
775
|
+
// MAIN CONTENT
|
|
776
|
+
// =========================================================================
|
|
777
|
+
Box({ flexDirection: 'row', flexGrow: 1 }, Sidebar({
|
|
655
778
|
categories,
|
|
656
779
|
currentCategory,
|
|
657
780
|
stories,
|
|
@@ -687,17 +810,28 @@ function StorybookApp() {
|
|
|
687
810
|
setEditingTextValue(value);
|
|
688
811
|
setIsEditingText(true);
|
|
689
812
|
},
|
|
690
|
-
})),
|
|
691
|
-
//
|
|
692
|
-
|
|
813
|
+
})),
|
|
814
|
+
// =========================================================================
|
|
815
|
+
// FOOTER SECTION (Console > Hotkeys > Pressed Keys)
|
|
816
|
+
// =========================================================================
|
|
817
|
+
// Console accordion
|
|
818
|
+
ConsoleAccordion(),
|
|
819
|
+
// Hotkeys panel
|
|
820
|
+
HotkeysPanel(),
|
|
821
|
+
// Pressed keys indicator
|
|
822
|
+
PressedKeysIndicator());
|
|
693
823
|
}
|
|
694
824
|
/**
|
|
695
825
|
* Run the storybook
|
|
696
826
|
*/
|
|
697
827
|
export async function runStorybook() {
|
|
828
|
+
// Pre-cache version (async load, then sync access everywhere)
|
|
829
|
+
await getVersion();
|
|
698
830
|
// Start global tick for animations
|
|
699
831
|
startTick(100);
|
|
700
|
-
const { waitUntilExit } = render(() => StorybookApp()
|
|
832
|
+
const { waitUntilExit } = render(() => StorybookApp(), {
|
|
833
|
+
fullHeight: true, // Fill entire terminal to cover splash screen content
|
|
834
|
+
});
|
|
701
835
|
await waitUntilExit();
|
|
702
836
|
// Cleanup tick on exit
|
|
703
837
|
stopTick();
|