@fragments-sdk/cli 0.7.10 → 0.7.11

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.
@@ -1,247 +0,0 @@
1
- /**
2
- * PreviewMenu — Storybook-style hamburger menu for the viewer.
3
- * Provides navigation, view mode toggles, panel controls, and settings submenus.
4
- * Placed left of the header beside the logo.
5
- */
6
-
7
- import { useEffect, useCallback } from 'react';
8
- import { Button, Menu, Text, Stack } from '@fragments-sdk/ui';
9
- import { List, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, GridFour, DeviceMobile, Rows, Eye } from '@phosphor-icons/react';
10
- import {
11
- ZOOM_LEVELS,
12
- VIEWPORT_PRESETS,
13
- type ZoomLevel,
14
- type BackgroundOption,
15
- type ViewportPreset,
16
- } from '../constants/ui.js';
17
-
18
- // Background options with display labels
19
- const BACKGROUND_OPTIONS_UI: { value: BackgroundOption; label: string }[] = [
20
- { value: 'checkerboard', label: 'Checkerboard' },
21
- { value: 'black', label: 'Dark' },
22
- { value: 'white', label: 'Light' },
23
- { value: 'transparent', label: 'Transparent' },
24
- ];
25
-
26
- // Viewport presets for submenu display
27
- const VIEWPORT_OPTIONS = Object.entries(VIEWPORT_PRESETS).map(([value, config]) => ({
28
- value: value as Exclude<ViewportPreset, 'custom'>,
29
- label: config.label,
30
- }));
31
-
32
- /** Shortcut label helper — renders a right-aligned keyboard hint */
33
- function Shortcut({ keys }: { keys: string }) {
34
- return (
35
- <Text as="span" size="2xs" color="tertiary" style={{ marginLeft: 'auto', paddingLeft: '16px', fontFamily: 'inherit' }}>
36
- {keys}
37
- </Text>
38
- );
39
- }
40
-
41
- interface PreviewMenuProps {
42
- zoom: ZoomLevel;
43
- background: BackgroundOption;
44
- viewport: ViewportPreset;
45
- showMatrixView: boolean;
46
- showMultiViewport: boolean;
47
- panelOpen: boolean;
48
- onZoomChange: (zoom: ZoomLevel) => void;
49
- onBackgroundChange: (bg: BackgroundOption) => void;
50
- onViewportChange: (viewport: ViewportPreset) => void;
51
- onToggleMatrix: () => void;
52
- onToggleMultiViewport: () => void;
53
- onTogglePanel: () => void;
54
- onPrevComponent: () => void;
55
- onNextComponent: () => void;
56
- onPrevVariant: () => void;
57
- onNextVariant: () => void;
58
- }
59
-
60
- export function PreviewMenu({
61
- zoom,
62
- background,
63
- viewport,
64
- showMatrixView,
65
- showMultiViewport,
66
- panelOpen,
67
- onZoomChange,
68
- onBackgroundChange,
69
- onViewportChange,
70
- onToggleMatrix,
71
- onToggleMultiViewport,
72
- onTogglePanel,
73
- onPrevComponent,
74
- onNextComponent,
75
- onPrevVariant,
76
- onNextVariant,
77
- }: PreviewMenuProps) {
78
- // Keyboard shortcuts for zoom
79
- const handleKeyDown = useCallback((e: KeyboardEvent) => {
80
- const target = e.target as HTMLElement;
81
- if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
82
- return;
83
- }
84
-
85
- if (e.key === '=' || e.key === '+') {
86
- e.preventDefault();
87
- const currentIndex = ZOOM_LEVELS.indexOf(zoom);
88
- if (currentIndex < ZOOM_LEVELS.length - 1) {
89
- onZoomChange(ZOOM_LEVELS[currentIndex + 1]);
90
- }
91
- } else if (e.key === '-') {
92
- e.preventDefault();
93
- const currentIndex = ZOOM_LEVELS.indexOf(zoom);
94
- if (currentIndex > 0) {
95
- onZoomChange(ZOOM_LEVELS[currentIndex - 1]);
96
- }
97
- } else if (e.key === '0') {
98
- e.preventDefault();
99
- onZoomChange(100);
100
- }
101
- }, [zoom, onZoomChange]);
102
-
103
- useEffect(() => {
104
- document.addEventListener('keydown', handleKeyDown);
105
- return () => document.removeEventListener('keydown', handleKeyDown);
106
- }, [handleKeyDown]);
107
-
108
- const iconSize = 16;
109
- const iconWeight = 'regular' as const;
110
-
111
- return (
112
- <Menu modal={false}>
113
- <Menu.Trigger asChild>
114
- <Button variant="ghost" size="sm" aria-label="Options menu">
115
- <Stack direction="row" gap="xs" align="center">
116
- <List size={18} weight="bold" />
117
- <Text size="sm" weight="medium">Options</Text>
118
- </Stack>
119
- </Button>
120
- </Menu.Trigger>
121
- <Menu.Content side="bottom" align="start" style={{ minWidth: '14rem' }}>
122
- {/* View modes */}
123
- <Menu.Item
124
- checked={showMatrixView}
125
- icon={<GridFour size={iconSize} weight={iconWeight} />}
126
- onSelect={onToggleMatrix}
127
- >
128
- <Stack direction="row" align="center" style={{ flex: 1 }}>
129
- Matrix view
130
- <Shortcut keys="M" />
131
- </Stack>
132
- </Menu.Item>
133
- <Menu.Item
134
- checked={showMultiViewport}
135
- icon={<DeviceMobile size={iconSize} weight={iconWeight} />}
136
- onSelect={onToggleMultiViewport}
137
- >
138
- <Stack direction="row" align="center" style={{ flex: 1 }}>
139
- Responsive view
140
- <Shortcut keys="V" />
141
- </Stack>
142
- </Menu.Item>
143
- <Menu.Item
144
- checked={panelOpen}
145
- icon={<Rows size={iconSize} weight={iconWeight} />}
146
- onSelect={onTogglePanel}
147
- >
148
- <Stack direction="row" align="center" style={{ flex: 1 }}>
149
- Show addons
150
- <Shortcut keys="P" />
151
- </Stack>
152
- </Menu.Item>
153
-
154
- <Menu.Separator />
155
-
156
- {/* Navigation */}
157
- <Menu.Group>
158
- <Menu.GroupLabel>Navigate</Menu.GroupLabel>
159
- <Menu.Item
160
- icon={<ArrowUp size={iconSize} weight={iconWeight} />}
161
- onSelect={onPrevComponent}
162
- >
163
- <Stack direction="row" align="center" style={{ flex: 1 }}>
164
- Previous component
165
- <Shortcut keys="⌘↑" />
166
- </Stack>
167
- </Menu.Item>
168
- <Menu.Item
169
- icon={<ArrowDown size={iconSize} weight={iconWeight} />}
170
- onSelect={onNextComponent}
171
- >
172
- <Stack direction="row" align="center" style={{ flex: 1 }}>
173
- Next component
174
- <Shortcut keys="⌘↓" />
175
- </Stack>
176
- </Menu.Item>
177
- <Menu.Item
178
- icon={<ArrowLeft size={iconSize} weight={iconWeight} />}
179
- onSelect={onPrevVariant}
180
- >
181
- <Stack direction="row" align="center" style={{ flex: 1 }}>
182
- Previous variant
183
- <Shortcut keys="⌘←" />
184
- </Stack>
185
- </Menu.Item>
186
- <Menu.Item
187
- icon={<ArrowRight size={iconSize} weight={iconWeight} />}
188
- onSelect={onNextVariant}
189
- >
190
- <Stack direction="row" align="center" style={{ flex: 1 }}>
191
- Next variant
192
- <Shortcut keys="⌘→" />
193
- </Stack>
194
- </Menu.Item>
195
- </Menu.Group>
196
-
197
- <Menu.Separator />
198
-
199
- {/* Settings submenus */}
200
- <Menu.Submenu>
201
- <Menu.SubmenuTrigger icon={<Eye size={iconSize} weight={iconWeight} />}>Viewport</Menu.SubmenuTrigger>
202
- <Menu.Content side="right" align="start">
203
- {VIEWPORT_OPTIONS.map((option) => (
204
- <Menu.Item
205
- key={option.value}
206
- checked={viewport === option.value}
207
- onSelect={() => onViewportChange(option.value)}
208
- >
209
- {option.label}
210
- </Menu.Item>
211
- ))}
212
- </Menu.Content>
213
- </Menu.Submenu>
214
-
215
- <Menu.Submenu>
216
- <Menu.SubmenuTrigger>Background</Menu.SubmenuTrigger>
217
- <Menu.Content side="right" align="start">
218
- {BACKGROUND_OPTIONS_UI.map((option) => (
219
- <Menu.Item
220
- key={option.value}
221
- checked={background === option.value}
222
- onSelect={() => onBackgroundChange(option.value)}
223
- >
224
- {option.label}
225
- </Menu.Item>
226
- ))}
227
- </Menu.Content>
228
- </Menu.Submenu>
229
-
230
- <Menu.Submenu>
231
- <Menu.SubmenuTrigger>Zoom ({zoom}%)</Menu.SubmenuTrigger>
232
- <Menu.Content side="right" align="start">
233
- {ZOOM_LEVELS.map((level) => (
234
- <Menu.Item
235
- key={level}
236
- checked={zoom === level}
237
- onSelect={() => onZoomChange(level)}
238
- >
239
- {level}%
240
- </Menu.Item>
241
- ))}
242
- </Menu.Content>
243
- </Menu.Submenu>
244
- </Menu.Content>
245
- </Menu>
246
- );
247
- }