@fragments-sdk/cli 0.10.1 → 0.11.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 (149) hide show
  1. package/dist/bin.js +20 -2
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{init-NDQXUWDU.js → init-UFGK5TCN.js} +75 -4
  4. package/dist/init-UFGK5TCN.js.map +1 -0
  5. package/dist/snapshot-SV2JOFZH.js +139 -0
  6. package/dist/snapshot-SV2JOFZH.js.map +1 -0
  7. package/dist/{viewer-DNMNC5VS.js → viewer-DLLJIMCK.js} +68 -46
  8. package/dist/viewer-DLLJIMCK.js.map +1 -0
  9. package/package.json +6 -14
  10. package/src/bin.ts +30 -0
  11. package/src/commands/init.ts +76 -1
  12. package/src/commands/snapshot.ts +197 -0
  13. package/src/viewer/__tests__/viewer-integration.test.ts +85 -74
  14. package/src/viewer/server.ts +37 -22
  15. package/src/viewer/vite-plugin.ts +25 -9
  16. package/dist/init-NDQXUWDU.js.map +0 -1
  17. package/dist/viewer-DNMNC5VS.js.map +0 -1
  18. package/src/viewer/__tests__/a11y-fixes.test.ts +0 -358
  19. package/src/viewer/__tests__/jsx-parser.test.ts +0 -502
  20. package/src/viewer/__tests__/render-utils.test.ts +0 -232
  21. package/src/viewer/__tests__/style-utils.test.ts +0 -404
  22. package/src/viewer/assets/fragments-logo.ts +0 -4
  23. package/src/viewer/assets/fragments_logo.png +0 -0
  24. package/src/viewer/components/AccessibilityPanel.tsx +0 -1457
  25. package/src/viewer/components/ActionCapture.tsx +0 -172
  26. package/src/viewer/components/ActionsPanel.tsx +0 -332
  27. package/src/viewer/components/AllVariantsPreview.tsx +0 -78
  28. package/src/viewer/components/App.tsx +0 -582
  29. package/src/viewer/components/BottomPanel.tsx +0 -288
  30. package/src/viewer/components/CodePanel.naming.test.tsx +0 -59
  31. package/src/viewer/components/CodePanel.tsx +0 -118
  32. package/src/viewer/components/CommandPalette.tsx +0 -392
  33. package/src/viewer/components/ComponentDocView.tsx +0 -164
  34. package/src/viewer/components/ComponentGraph.tsx +0 -380
  35. package/src/viewer/components/ComponentHeader.tsx +0 -88
  36. package/src/viewer/components/ContractPanel.tsx +0 -241
  37. package/src/viewer/components/EmptyVariantMessage.tsx +0 -54
  38. package/src/viewer/components/ErrorBoundary.tsx +0 -97
  39. package/src/viewer/components/FigmaEmbed.tsx +0 -238
  40. package/src/viewer/components/FragmentEditor.tsx +0 -525
  41. package/src/viewer/components/FragmentRenderer.tsx +0 -61
  42. package/src/viewer/components/HeaderSearch.tsx +0 -24
  43. package/src/viewer/components/HealthDashboard.tsx +0 -441
  44. package/src/viewer/components/HmrStatusIndicator.tsx +0 -61
  45. package/src/viewer/components/Icons.tsx +0 -479
  46. package/src/viewer/components/InteractionsPanel.tsx +0 -757
  47. package/src/viewer/components/IsolatedPreviewFrame.tsx +0 -346
  48. package/src/viewer/components/IsolatedRender.tsx +0 -113
  49. package/src/viewer/components/KeyboardShortcutsHelp.tsx +0 -53
  50. package/src/viewer/components/LandingPage.tsx +0 -421
  51. package/src/viewer/components/Layout.tsx +0 -27
  52. package/src/viewer/components/LeftSidebar.tsx +0 -472
  53. package/src/viewer/components/LoadErrorMessage.tsx +0 -102
  54. package/src/viewer/components/MultiViewportPreview.tsx +0 -522
  55. package/src/viewer/components/NoVariantsMessage.tsx +0 -59
  56. package/src/viewer/components/PanelShell.tsx +0 -161
  57. package/src/viewer/components/PerformancePanel.tsx +0 -304
  58. package/src/viewer/components/PreviewArea.tsx +0 -472
  59. package/src/viewer/components/PreviewAside.tsx +0 -168
  60. package/src/viewer/components/PreviewFrameHost.tsx +0 -303
  61. package/src/viewer/components/PreviewPane.tsx +0 -149
  62. package/src/viewer/components/PreviewToolbar.tsx +0 -80
  63. package/src/viewer/components/PropsEditor.tsx +0 -506
  64. package/src/viewer/components/PropsTable.tsx +0 -111
  65. package/src/viewer/components/RelationsSection.tsx +0 -88
  66. package/src/viewer/components/ResizablePanel.tsx +0 -271
  67. package/src/viewer/components/RightSidebar.tsx +0 -102
  68. package/src/viewer/components/RuntimeToolsRegistrar.tsx +0 -17
  69. package/src/viewer/components/ScreenshotButton.tsx +0 -90
  70. package/src/viewer/components/Sidebar.tsx +0 -169
  71. package/src/viewer/components/SkeletonLoader.tsx +0 -161
  72. package/src/viewer/components/ThemeProvider.tsx +0 -42
  73. package/src/viewer/components/Toast.tsx +0 -3
  74. package/src/viewer/components/TokenStylePanel.tsx +0 -699
  75. package/src/viewer/components/TopToolbar.tsx +0 -159
  76. package/src/viewer/components/UsageSection.tsx +0 -95
  77. package/src/viewer/components/VariantMatrix.tsx +0 -388
  78. package/src/viewer/components/VariantRenderer.tsx +0 -131
  79. package/src/viewer/components/VariantTabs.tsx +0 -40
  80. package/src/viewer/components/ViewerHeader.tsx +0 -69
  81. package/src/viewer/components/ViewerStateSync.tsx +0 -52
  82. package/src/viewer/components/ViewportSelector.tsx +0 -172
  83. package/src/viewer/components/WebMCPDevTools.tsx +0 -503
  84. package/src/viewer/components/WebMCPIntegration.tsx +0 -47
  85. package/src/viewer/components/WebMCPStatusIndicator.tsx +0 -60
  86. package/src/viewer/components/_future/CreatePage.tsx +0 -836
  87. package/src/viewer/components/viewer-utils.ts +0 -16
  88. package/src/viewer/composition-renderer.ts +0 -381
  89. package/src/viewer/constants/index.ts +0 -1
  90. package/src/viewer/constants/ui.ts +0 -166
  91. package/src/viewer/entry.tsx +0 -335
  92. package/src/viewer/hooks/index.ts +0 -2
  93. package/src/viewer/hooks/useA11yCache.ts +0 -383
  94. package/src/viewer/hooks/useA11yService.ts +0 -364
  95. package/src/viewer/hooks/useActions.ts +0 -138
  96. package/src/viewer/hooks/useAppState.ts +0 -147
  97. package/src/viewer/hooks/useCompiledFragments.ts +0 -42
  98. package/src/viewer/hooks/useFigmaIntegration.ts +0 -132
  99. package/src/viewer/hooks/useHmrStatus.ts +0 -109
  100. package/src/viewer/hooks/useKeyboardShortcuts.ts +0 -270
  101. package/src/viewer/hooks/usePreviewBridge.ts +0 -347
  102. package/src/viewer/hooks/useScrollSpy.ts +0 -78
  103. package/src/viewer/hooks/useUrlState.ts +0 -318
  104. package/src/viewer/hooks/useViewSettings.ts +0 -111
  105. package/src/viewer/index.html +0 -28
  106. package/src/viewer/intelligence/healthReport.ts +0 -505
  107. package/src/viewer/intelligence/styleDrift.ts +0 -340
  108. package/src/viewer/intelligence/usageScanner.ts +0 -309
  109. package/src/viewer/jsx-parser.ts +0 -486
  110. package/src/viewer/preview-frame-entry.tsx +0 -25
  111. package/src/viewer/preview-frame.html +0 -125
  112. package/src/viewer/public/favicon.ico +0 -0
  113. package/src/viewer/render-template.html +0 -68
  114. package/src/viewer/styles/globals.css +0 -278
  115. package/src/viewer/types/a11y.ts +0 -197
  116. package/src/viewer/utils/a11y-fixes.ts +0 -509
  117. package/src/viewer/utils/actionExport.ts +0 -372
  118. package/src/viewer/utils/colorSchemes.ts +0 -201
  119. package/src/viewer/utils/detectRelationships.ts +0 -256
  120. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss +0 -10
  121. package/src/viewer/vendor/shared/src/ComponentDocContent.module.scss.d.ts +0 -2
  122. package/src/viewer/vendor/shared/src/ComponentDocContent.tsx +0 -274
  123. package/src/viewer/vendor/shared/src/DocsHeaderBar.tsx +0 -129
  124. package/src/viewer/vendor/shared/src/DocsPageAsideHost.tsx +0 -89
  125. package/src/viewer/vendor/shared/src/DocsPageShell.tsx +0 -124
  126. package/src/viewer/vendor/shared/src/DocsSearchCommand.tsx +0 -99
  127. package/src/viewer/vendor/shared/src/DocsSidebarNav.tsx +0 -66
  128. package/src/viewer/vendor/shared/src/PropsTable.module.scss +0 -68
  129. package/src/viewer/vendor/shared/src/PropsTable.module.scss.d.ts +0 -2
  130. package/src/viewer/vendor/shared/src/PropsTable.tsx +0 -76
  131. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss +0 -114
  132. package/src/viewer/vendor/shared/src/VariantPreviewCard.module.scss.d.ts +0 -2
  133. package/src/viewer/vendor/shared/src/VariantPreviewCard.tsx +0 -137
  134. package/src/viewer/vendor/shared/src/docs-data/index.ts +0 -32
  135. package/src/viewer/vendor/shared/src/docs-data/mcp-configs.ts +0 -72
  136. package/src/viewer/vendor/shared/src/docs-data/palettes.ts +0 -75
  137. package/src/viewer/vendor/shared/src/docs-data/setup-examples.ts +0 -55
  138. package/src/viewer/vendor/shared/src/docs-layout.scss +0 -28
  139. package/src/viewer/vendor/shared/src/docs-layout.scss.d.ts +0 -2
  140. package/src/viewer/vendor/shared/src/index.ts +0 -34
  141. package/src/viewer/vendor/shared/src/types.ts +0 -53
  142. package/src/viewer/webmcp/__tests__/analytics.test.ts +0 -108
  143. package/src/viewer/webmcp/analytics.ts +0 -165
  144. package/src/viewer/webmcp/index.ts +0 -3
  145. package/src/viewer/webmcp/posthog-bridge.ts +0 -39
  146. package/src/viewer/webmcp/runtime-tools.ts +0 -152
  147. package/src/viewer/webmcp/scan-utils.ts +0 -135
  148. package/src/viewer/webmcp/use-tool-analytics.ts +0 -69
  149. package/src/viewer/webmcp/viewer-state.ts +0 -45
@@ -1,161 +0,0 @@
1
- /**
2
- * PanelShell — Consistent wrapper for bottom panel tabs.
3
- *
4
- * Provides standardized structure for all 5 bottom panel tabs:
5
- * - Optional toolbar (badges, filters, action buttons)
6
- * - Scrollable body with consistent padding
7
- * - Loading skeleton state
8
- * - Empty state with icon, title, description, action
9
- * - Error state with Alert
10
- *
11
- * The tab label (e.g., "Graph", "Performance") is rendered by
12
- * ResizablePanel — PanelShell does NOT render a title.
13
- */
14
-
15
- import type { ReactNode } from "react";
16
- import { Stack, Box, EmptyState, Alert } from "@fragments-sdk/ui";
17
-
18
- interface PanelShellEmptyConfig {
19
- /** Phosphor icon element */
20
- icon: ReactNode;
21
- /** Empty state title */
22
- title: string;
23
- /** Optional description */
24
- description?: ReactNode;
25
- /** Optional action slot (e.g. Button, CodeBlock) */
26
- action?: ReactNode;
27
- }
28
-
29
- export interface PanelShellProps {
30
- /** Optional toolbar content (badges, filters, action buttons) */
31
- toolbar?: ReactNode;
32
- /** Main body content */
33
- children: ReactNode;
34
- /** Show loading skeleton instead of children */
35
- loading?: boolean;
36
- /** Custom loading content (defaults to generic skeleton) */
37
- loadingContent?: ReactNode;
38
- /** Empty state config — renders when provided (instead of children) */
39
- empty?: PanelShellEmptyConfig;
40
- /** Error message — renders Alert */
41
- error?: string;
42
- /** Body padding (default: "md") */
43
- bodyPadding?: "sm" | "md" | "lg" | "none";
44
- }
45
-
46
- function DefaultSkeleton() {
47
- return (
48
- <Stack gap="md">
49
- {[0, 1, 2].map((i) => (
50
- <div
51
- key={i}
52
- style={{
53
- height: "48px",
54
- borderRadius: "8px",
55
- background: "var(--bg-hover)",
56
- animation: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
57
- animationDelay: `${i * 100}ms`,
58
- }}
59
- />
60
- ))}
61
- </Stack>
62
- );
63
- }
64
-
65
- export function PanelShell({
66
- toolbar,
67
- children,
68
- loading = false,
69
- loadingContent,
70
- empty,
71
- error,
72
- bodyPadding = "md",
73
- }: PanelShellProps) {
74
- const padding = bodyPadding !== "none" ? bodyPadding : undefined;
75
-
76
- const renderBody = (): ReactNode => {
77
- if (loading) {
78
- return (
79
- <Box overflow="auto" padding={padding} style={{ flex: 1 }}>
80
- {loadingContent || <DefaultSkeleton />}
81
- </Box>
82
- );
83
- }
84
-
85
- if (error) {
86
- return (
87
- <Box overflow="auto" padding={padding} style={{ flex: 1 }}>
88
- <Alert variant="danger">{error}</Alert>
89
- </Box>
90
- );
91
- }
92
-
93
- if (empty) {
94
- return (
95
- <Stack
96
- align="center"
97
- justify="center"
98
- style={{ flex: 1, padding: "32px" }}
99
- >
100
- <EmptyState>
101
- <EmptyState.Icon>
102
- <Box
103
- rounded="full"
104
- display="flex"
105
- style={{
106
- width: 48,
107
- height: 48,
108
- alignItems: "center",
109
- justifyContent: "center",
110
- background: "var(--bg-hover)",
111
- }}
112
- >
113
- {empty.icon}
114
- </Box>
115
- </EmptyState.Icon>
116
- <EmptyState.Title>{empty.title}</EmptyState.Title>
117
- {empty.description && (
118
- <EmptyState.Description>
119
- {empty.description}
120
- </EmptyState.Description>
121
- )}
122
- {empty.action && (
123
- <Box
124
- style={{ marginTop: "16px", width: "100%", maxWidth: "400px" }}
125
- >
126
- {empty.action}
127
- </Box>
128
- )}
129
- </EmptyState>
130
- </Stack>
131
- );
132
- }
133
-
134
- return (
135
- <Box overflow="auto" padding={padding} style={{ flex: 1 }}>
136
- {children}
137
- </Box>
138
- );
139
- };
140
-
141
- return (
142
- <Stack style={{ height: "100%" }}>
143
- {toolbar && (
144
- <Box
145
- paddingX="sm"
146
- paddingY="xs"
147
- borderBottom
148
- style={{
149
- flexShrink: 0,
150
- minHeight: "36px",
151
- display: "flex",
152
- alignItems: "center",
153
- }}
154
- >
155
- {toolbar}
156
- </Box>
157
- )}
158
- {renderBody()}
159
- </Stack>
160
- );
161
- }
@@ -1,304 +0,0 @@
1
- /**
2
- * Performance Panel — bundle size visualization in the viewer.
3
- *
4
- * Fetches performance data from /fragments/perf-data (served by the
5
- * Vite dev server from fragments.json) and displays:
6
- * - Gzipped and raw bundle size
7
- * - Complexity tier badge
8
- * - Budget bar with percentage
9
- * - Over-budget alert when applicable
10
- * - Empty state when no data (prompts `fragments perf`)
11
- */
12
-
13
- import { useState, useEffect } from 'react';
14
- import { Card, Badge, Text, Stack, Alert, Collapsible, Box } from '@fragments-sdk/ui';
15
- import { Lightning, Package, FileCode, Star } from '@phosphor-icons/react';
16
- import { BRAND } from '../../core/index.js';
17
- import { PanelShell } from './PanelShell.js';
18
-
19
- interface ImportEntry {
20
- path: string;
21
- bytes: number;
22
- percent: number;
23
- }
24
-
25
- interface PerformanceData {
26
- bundleSize: number;
27
- rawSize: number;
28
- complexity: 'lightweight' | 'moderate' | 'heavy';
29
- budgetPercent: number;
30
- overBudget: boolean;
31
- measuredAt: string;
32
- imports?: ImportEntry[];
33
- }
34
-
35
- interface PerfDataResponse {
36
- summary: {
37
- preset: string;
38
- budget: number;
39
- total: number;
40
- overBudget: number;
41
- tiers: Record<string, number>;
42
- } | null;
43
- components: Record<string, PerformanceData>;
44
- }
45
-
46
- interface PerformancePanelProps {
47
- componentName: string;
48
- }
49
-
50
- function formatBytes(bytes: number): string {
51
- if (bytes < 1024) return `${bytes} B`;
52
- const kb = bytes / 1024;
53
- return kb < 10 ? `${kb.toFixed(1)} KB` : `${Math.round(kb)} KB`;
54
- }
55
-
56
- function tierVariant(tier: string): 'success' | 'warning' | 'danger' {
57
- switch (tier) {
58
- case 'lightweight': return 'success';
59
- case 'moderate': return 'warning';
60
- case 'heavy': return 'danger';
61
- default: return 'warning';
62
- }
63
- }
64
-
65
- function BudgetBar({ percent }: { percent: number }) {
66
- const capped = Math.min(percent, 100);
67
- const isOver = percent > 100;
68
- const color = isOver ? 'var(--fui-color-danger, #e53e3e)'
69
- : percent > 80 ? 'var(--fui-color-warning, #dd6b20)'
70
- : 'var(--fui-color-success, #38a169)';
71
-
72
- return (
73
- <div style={{ width: '100%' }}>
74
- <div style={{
75
- display: 'flex',
76
- justifyContent: 'space-between',
77
- marginBottom: '4px',
78
- }}>
79
- <Text size="sm" color="secondary">Budget usage</Text>
80
- <Text size="sm" weight="semibold" style={{ color }}>
81
- {percent}%
82
- </Text>
83
- </div>
84
- <div style={{
85
- width: '100%',
86
- height: '8px',
87
- borderRadius: '4px',
88
- backgroundColor: 'var(--fui-color-surface-2, #e2e8f0)',
89
- overflow: 'hidden',
90
- }}>
91
- <div style={{
92
- width: `${capped}%`,
93
- height: '100%',
94
- borderRadius: '4px',
95
- backgroundColor: color,
96
- transition: 'width 0.3s ease',
97
- }} />
98
- </div>
99
- </div>
100
- );
101
- }
102
-
103
- /** Labels are already clean from the backend (e.g., "react-markdown", "Markdown (self)") */
104
-
105
- function ImportBreakdown({ imports, rawSize }: { imports: ImportEntry[]; rawSize: number }) {
106
- return (
107
- <Collapsible>
108
- <Collapsible.Trigger style={{ cursor: 'pointer' }}>
109
- <Text size="sm" weight="semibold">
110
- Import breakdown ({imports.length} file{imports.length !== 1 ? 's' : ''})
111
- </Text>
112
- </Collapsible.Trigger>
113
- <Collapsible.Content>
114
- <div style={{ marginTop: '8px' }}>
115
- {imports.map((imp) => {
116
- const barWidth = Math.max(1, Math.round(imp.percent / 2));
117
- return (
118
- <div
119
- key={imp.path}
120
- style={{
121
- display: 'grid',
122
- gridTemplateColumns: '1fr 70px 45px minmax(20px, 100px)',
123
- alignItems: 'center',
124
- gap: '8px',
125
- padding: '4px 0',
126
- borderBottom: '1px solid var(--fui-color-border, #2d3748)',
127
- }}
128
- >
129
- <Text
130
- size="xs"
131
- color="secondary"
132
- style={{
133
- overflow: 'hidden',
134
- textOverflow: 'ellipsis',
135
- whiteSpace: 'nowrap',
136
- fontFamily: 'var(--fui-font-mono, monospace)',
137
- }}
138
- title={imp.path}
139
- >
140
- {imp.path}
141
- </Text>
142
- <Text size="xs" weight="semibold" style={{ textAlign: 'right' }}>
143
- {formatBytes(imp.bytes)}
144
- </Text>
145
- <Text size="xs" color="tertiary" style={{ textAlign: 'right' }}>
146
- {imp.percent}%
147
- </Text>
148
- <div style={{
149
- height: '6px',
150
- borderRadius: '3px',
151
- backgroundColor: 'var(--fui-color-surface-2, #2d3748)',
152
- overflow: 'hidden',
153
- }}>
154
- <div style={{
155
- width: `${Math.min(barWidth * 2, 100)}%`,
156
- height: '100%',
157
- borderRadius: '3px',
158
- backgroundColor: imp.percent > 50
159
- ? 'var(--fui-color-danger, #e53e3e)'
160
- : imp.percent > 20
161
- ? 'var(--fui-color-warning, #dd6b20)'
162
- : 'var(--fui-color-accent, #4299e1)',
163
- }} />
164
- </div>
165
- </div>
166
- );
167
- })}
168
- </div>
169
- </Collapsible.Content>
170
- </Collapsible>
171
- );
172
- }
173
-
174
- export function PerformancePanel({ componentName }: PerformancePanelProps) {
175
- const [perfData, setPerfData] = useState<PerformanceData | null>(null);
176
- const [loading, setLoading] = useState(true);
177
- const [noData, setNoData] = useState(false);
178
-
179
- useEffect(() => {
180
- let cancelled = false;
181
-
182
- async function fetchPerfData() {
183
- setLoading(true);
184
- try {
185
- const res = await fetch('/fragments/perf-data');
186
- if (!res.ok) {
187
- setNoData(true);
188
- return;
189
- }
190
- const data: PerfDataResponse = await res.json();
191
- if (!cancelled) {
192
- const componentPerf = data.components[componentName];
193
- if (componentPerf) {
194
- setPerfData(componentPerf);
195
- setNoData(false);
196
- } else {
197
- setPerfData(null);
198
- setNoData(true);
199
- }
200
- }
201
- } catch {
202
- if (!cancelled) {
203
- setNoData(true);
204
- }
205
- } finally {
206
- if (!cancelled) {
207
- setLoading(false);
208
- }
209
- }
210
- }
211
-
212
- fetchPerfData();
213
- return () => { cancelled = true; };
214
- }, [componentName]);
215
-
216
- const showEmpty = !loading && (noData || !perfData);
217
-
218
- const emptyConfig = showEmpty ? {
219
- icon: <Lightning size={24} weight="regular" style={{ color: 'var(--text-tertiary)' }} />,
220
- title: "No performance data",
221
- description: (
222
- <>
223
- Run <Box as="code" padding="xs" background="secondary" rounded="sm" style={{ fontSize: '12px', display: 'inline', fontFamily: 'var(--fui-font-mono, monospace)' }}>{BRAND.cliCommand} perf</Box> to measure bundle sizes, then reload the viewer.
224
- </>
225
- ),
226
- } : undefined;
227
-
228
- // Safe destructure — only used when PanelShell renders children (not loading/empty)
229
- const { bundleSize = 0, rawSize = 0, complexity = 'lightweight' as const, budgetPercent = 0, overBudget = false, measuredAt = '' } = perfData || {};
230
- const measuredDate = measuredAt ? new Date(measuredAt).toLocaleString() : '';
231
-
232
- return (
233
- <PanelShell loading={loading} empty={emptyConfig}>
234
- <Stack gap="md">
235
- {overBudget && (
236
- <Alert variant="danger">
237
- <strong>{componentName}</strong> exceeds its performance budget ({budgetPercent}% of allowed size).
238
- Consider code splitting, lazy loading heavy dependencies, or tree-shaking unused exports.
239
- </Alert>
240
- )}
241
-
242
- <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '12px' }}>
243
- <Card>
244
- <Card.Body>
245
- <Stack gap="xs">
246
- <Stack direction="row" align="center" gap="xs">
247
- <Package size={14} weight="regular" style={{ color: 'var(--text-tertiary)' }} />
248
- <Text size="xs" color="secondary">Gzipped</Text>
249
- </Stack>
250
- <Text size="xl" weight="bold">{formatBytes(bundleSize)}</Text>
251
- </Stack>
252
- </Card.Body>
253
- </Card>
254
-
255
- <Card>
256
- <Card.Body>
257
- <Stack gap="xs">
258
- <Stack direction="row" align="center" gap="xs">
259
- <FileCode size={14} weight="regular" style={{ color: 'var(--text-tertiary)' }} />
260
- <Text size="xs" color="secondary">Raw (minified)</Text>
261
- </Stack>
262
- <Text size="xl" weight="bold">{formatBytes(rawSize)}</Text>
263
- </Stack>
264
- </Card.Body>
265
- </Card>
266
-
267
- <Card>
268
- <Card.Body>
269
- <Stack gap="xs">
270
- <Stack direction="row" align="center" gap="xs">
271
- <Star size={14} weight="regular" style={{ color: 'var(--text-tertiary)' }} />
272
- <Text size="xs" color="secondary">Complexity</Text>
273
- </Stack>
274
- <div>
275
- <Badge variant={tierVariant(complexity)} size="lg">
276
- {complexity}
277
- </Badge>
278
- </div>
279
- </Stack>
280
- </Card.Body>
281
- </Card>
282
- </div>
283
-
284
- <Card>
285
- <Card.Body>
286
- <BudgetBar percent={budgetPercent} />
287
- </Card.Body>
288
- </Card>
289
-
290
- {perfData?.imports && perfData.imports.length > 0 && (
291
- <Card>
292
- <Card.Body>
293
- <ImportBreakdown imports={perfData.imports} rawSize={rawSize} />
294
- </Card.Body>
295
- </Card>
296
- )}
297
-
298
- <Text size="xs" color="tertiary">
299
- Measured {measuredDate}. CSS excluded (JS-only measurement).
300
- </Text>
301
- </Stack>
302
- </PanelShell>
303
- );
304
- }