@fragments-sdk/cli 0.5.2 → 0.7.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.
- package/dist/bin.js +996 -79
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-ICAIQ57V.js → chunk-6JBGU74P.js} +5 -3
- package/dist/chunk-6JBGU74P.js.map +1 -0
- package/dist/chunk-7OPWMLOE.js +1625 -0
- package/dist/chunk-7OPWMLOE.js.map +1 -0
- package/dist/{chunk-2H2JAA3U.js → chunk-CVXKXVOY.js} +3 -3
- package/dist/{chunk-2H2JAA3U.js.map → chunk-CVXKXVOY.js.map} +1 -1
- package/dist/{chunk-IOJE35DZ.js → chunk-NWQ4CJOQ.js} +3 -3
- package/dist/{chunk-2DJH4F4P.js → chunk-RVRTRESS.js} +3 -3
- package/dist/{chunk-V7YLRR4C.js → chunk-TJ34N7C7.js} +41 -4
- package/dist/{chunk-V7YLRR4C.js.map → chunk-TJ34N7C7.js.map} +1 -1
- package/dist/{chunk-XNWDI6UT.js → chunk-XHUDJNN3.js} +5 -5
- package/dist/{core-DKHB7FYV.js → core-W2HYIQW6.js} +4 -4
- package/dist/{generate-KL24VZVD.js → generate-LMTISDIJ.js} +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-NION5S3M.js → init-7CHRKQ7P.js} +5 -5
- package/dist/mcp-bin.js +8 -220
- package/dist/mcp-bin.js.map +1 -1
- package/dist/scan-WY23TJCP.js +12 -0
- package/dist/{service-RWUMZ3EW.js → service-T2L7VLTE.js} +5 -5
- package/dist/static-viewer-GBR7YNF3.js +12 -0
- package/dist/{test-ECPEXFDN.js → test-OJRXNDO2.js} +4 -4
- package/dist/{tokens-ITADYVPF.js → tokens-3BWDESVM.js} +6 -6
- package/dist/viewer-SUFOISZM.js +1822 -0
- package/dist/viewer-SUFOISZM.js.map +1 -0
- package/package.json +6 -5
- package/src/bin.ts +31 -0
- package/src/build.ts +147 -13
- package/src/cli-commands.ts +18 -0
- package/src/commands/__tests__/a11y-scoring.test.ts +278 -0
- package/src/commands/a11y-report.ts +625 -0
- package/src/commands/a11y.ts +168 -14
- package/src/commands/build.ts +16 -0
- package/src/commands/graph.ts +274 -0
- package/src/core/auto-props.ts +464 -0
- package/src/core/composition.ts +64 -1
- package/src/core/graph-extractor.test.ts +542 -0
- package/src/core/graph-extractor.ts +601 -0
- package/src/core/importAnalyzer.ts +5 -0
- package/src/core/schema.ts +2 -0
- package/src/core/types.ts +3 -1
- package/src/index.ts +4 -0
- package/src/mcp/server.ts +13 -220
- package/src/theme/__tests__/component-contrast.test.ts +338 -0
- package/src/theme/__tests__/contrast-validation.test.ts +326 -0
- package/src/theme/contrast.test.ts +331 -0
- package/src/theme/contrast.ts +246 -0
- package/src/theme/generator.ts +213 -1
- package/src/theme/index.ts +16 -0
- package/src/theme/types.ts +51 -0
- package/src/viewer/__tests__/a11y-fixes.test.ts +358 -0
- package/src/viewer/__tests__/viewer-integration.test.ts +2 -7
- package/src/viewer/components/AccessibilityPanel.tsx +493 -433
- package/src/viewer/components/ActionCapture.tsx +1 -1
- package/src/viewer/components/ActionsPanel.tsx +142 -183
- package/src/viewer/components/App.tsx +276 -183
- package/src/viewer/components/BottomPanel.tsx +40 -80
- package/src/viewer/components/CodePanel.tsx +9 -87
- package/src/viewer/components/CommandPalette.tsx +117 -74
- package/src/viewer/components/ComponentGraph.tsx +143 -126
- package/src/viewer/components/ComponentHeader.tsx +46 -43
- package/src/viewer/components/ContractPanel.tsx +124 -117
- package/src/viewer/components/ErrorBoundary.tsx +47 -35
- package/src/viewer/components/FigmaEmbed.tsx +18 -13
- package/src/viewer/components/FragmentEditor.tsx +126 -63
- package/src/viewer/components/HealthDashboard.tsx +146 -171
- package/src/viewer/components/HmrStatusIndicator.tsx +31 -41
- package/src/viewer/components/Icons.tsx +151 -98
- package/src/viewer/components/InteractionsPanel.tsx +317 -264
- package/src/viewer/components/IsolatedPreviewFrame.tsx +52 -27
- package/src/viewer/components/IsolatedRender.tsx +12 -6
- package/src/viewer/components/KeyboardShortcutsHelp.tsx +34 -70
- package/src/viewer/components/LandingPage.tsx +285 -305
- package/src/viewer/components/Layout.tsx +12 -10
- package/src/viewer/components/LeftSidebar.tsx +103 -155
- package/src/viewer/components/MultiViewportPreview.tsx +254 -63
- package/src/viewer/components/PreviewArea.tsx +113 -44
- package/src/viewer/components/PreviewFrameHost.tsx +36 -6
- package/src/viewer/components/PreviewPane.tsx +2 -3
- package/src/viewer/components/PreviewToolbar.tsx +109 -105
- package/src/viewer/components/PropsEditor.tsx +154 -74
- package/src/viewer/components/PropsTable.tsx +95 -82
- package/src/viewer/components/RelationsSection.tsx +71 -40
- package/src/viewer/components/ResizablePanel.tsx +158 -55
- package/src/viewer/components/RightSidebar.tsx +46 -56
- package/src/viewer/components/ScreenshotButton.tsx +12 -12
- package/src/viewer/components/SkeletonLoader.tsx +99 -83
- package/src/viewer/components/StoryRenderer.tsx +4 -11
- package/src/viewer/components/Toast.tsx +3 -67
- package/src/viewer/components/TokenStylePanel.tsx +136 -118
- package/src/viewer/components/UsageSection.tsx +26 -26
- package/src/viewer/components/VariantMatrix.tsx +140 -47
- package/src/viewer/components/VariantTabs.tsx +24 -68
- package/src/viewer/components/ViewportSelector.tsx +121 -114
- package/src/viewer/constants/ui.ts +23 -22
- package/src/viewer/entry.tsx +8 -3
- package/src/viewer/index.ts +3 -6
- package/src/viewer/preview-frame.html +43 -18
- package/src/viewer/server.ts +7 -16
- package/src/viewer/styles/globals.css +46 -85
- package/src/viewer/utils/a11y-fixes.ts +53 -30
- package/dist/chunk-ICAIQ57V.js.map +0 -1
- package/dist/chunk-U4GQ2JTD.js +0 -832
- package/dist/chunk-U4GQ2JTD.js.map +0 -1
- package/dist/scan-ESEXV7LF.js +0 -12
- package/dist/static-viewer-O37MJ5B6.js +0 -12
- package/dist/viewer-YDGFDTK5.js +0 -11104
- package/dist/viewer-YDGFDTK5.js.map +0 -1
- package/src/viewer/postcss.config.js +0 -6
- package/src/viewer/tailwind.config.js +0 -37
- /package/dist/{chunk-IOJE35DZ.js.map → chunk-NWQ4CJOQ.js.map} +0 -0
- /package/dist/{chunk-2DJH4F4P.js.map → chunk-RVRTRESS.js.map} +0 -0
- /package/dist/{chunk-XNWDI6UT.js.map → chunk-XHUDJNN3.js.map} +0 -0
- /package/dist/{core-DKHB7FYV.js.map → core-W2HYIQW6.js.map} +0 -0
- /package/dist/{generate-KL24VZVD.js.map → generate-LMTISDIJ.js.map} +0 -0
- /package/dist/{init-NION5S3M.js.map → init-7CHRKQ7P.js.map} +0 -0
- /package/dist/{scan-ESEXV7LF.js.map → scan-WY23TJCP.js.map} +0 -0
- /package/dist/{service-RWUMZ3EW.js.map → service-T2L7VLTE.js.map} +0 -0
- /package/dist/{static-viewer-O37MJ5B6.js.map → static-viewer-GBR7YNF3.js.map} +0 -0
- /package/dist/{test-ECPEXFDN.js.map → test-OJRXNDO2.js.map} +0 -0
- /package/dist/{tokens-ITADYVPF.js.map → tokens-3BWDESVM.js.map} +0 -0
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { useState, useEffect, useCallback } from "react";
|
|
12
|
-
import
|
|
12
|
+
import { Badge } from "@fragments/ui";
|
|
13
13
|
import type { DesignToken, EnhancedStyleDiffItem, TokenUsageSummary } from "../../core/index.js";
|
|
14
14
|
import { CheckIcon, XIcon, LoadingIcon, FigmaIcon, WandIcon } from "./Icons.js";
|
|
15
15
|
|
|
@@ -244,9 +244,9 @@ export function TokenStylePanel({
|
|
|
244
244
|
// Show loading state
|
|
245
245
|
if (figmaLoading) {
|
|
246
246
|
return (
|
|
247
|
-
<div
|
|
248
|
-
<SyncingIcon
|
|
249
|
-
<span
|
|
247
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--text-tertiary)', padding: '16px' }}>
|
|
248
|
+
<SyncingIcon style={{ width: 16, height: 16, animation: 'spin 1s linear infinite' }} />
|
|
249
|
+
<span style={{ fontSize: '12px' }}>Loading Figma styles...</span>
|
|
250
250
|
</div>
|
|
251
251
|
);
|
|
252
252
|
}
|
|
@@ -254,12 +254,12 @@ export function TokenStylePanel({
|
|
|
254
254
|
// Show error state
|
|
255
255
|
if (figmaError) {
|
|
256
256
|
return (
|
|
257
|
-
<div
|
|
258
|
-
<XIcon
|
|
259
|
-
<span
|
|
257
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--text-tertiary)', padding: '16px' }}>
|
|
258
|
+
<XIcon style={{ width: 16, height: 16, color: '#ef4444' }} />
|
|
259
|
+
<span style={{ fontSize: '12px' }}>{figmaError}</span>
|
|
260
260
|
<button
|
|
261
261
|
onClick={onFetchFigma}
|
|
262
|
-
|
|
262
|
+
style={{ fontSize: '12px', color: 'var(--color-accent)', background: 'none', border: 'none', cursor: 'pointer', marginLeft: '8px', textDecoration: 'underline' }}
|
|
263
263
|
>
|
|
264
264
|
Retry
|
|
265
265
|
</button>
|
|
@@ -270,12 +270,12 @@ export function TokenStylePanel({
|
|
|
270
270
|
// Show idle state
|
|
271
271
|
if (!figmaStyles) {
|
|
272
272
|
return (
|
|
273
|
-
<div
|
|
274
|
-
<FigmaIcon
|
|
275
|
-
<span
|
|
273
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--text-tertiary)', padding: '16px' }}>
|
|
274
|
+
<FigmaIcon style={{ width: 16, height: 16 }} />
|
|
275
|
+
<span style={{ fontSize: '12px' }}>Click to load style comparison</span>
|
|
276
276
|
<button
|
|
277
277
|
onClick={onFetchFigma}
|
|
278
|
-
|
|
278
|
+
style={{ fontSize: '12px', color: 'var(--color-accent)', background: 'none', border: 'none', cursor: 'pointer', marginLeft: '8px', textDecoration: 'underline' }}
|
|
279
279
|
>
|
|
280
280
|
Load
|
|
281
281
|
</button>
|
|
@@ -330,157 +330,149 @@ export function TokenStylePanel({
|
|
|
330
330
|
: 100;
|
|
331
331
|
|
|
332
332
|
return (
|
|
333
|
-
<div
|
|
333
|
+
<div style={{ overflowX: 'auto', padding: '16px' }}>
|
|
334
334
|
{/* Summary Header */}
|
|
335
|
-
<div
|
|
336
|
-
<div
|
|
337
|
-
<span
|
|
335
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '12px' }}>
|
|
336
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
|
337
|
+
<span style={{ fontSize: '12px', fontWeight: 500, color: 'var(--text-primary)' }}>Style Comparison</span>
|
|
338
338
|
|
|
339
339
|
{/* Token info badge */}
|
|
340
340
|
{tokenData && (
|
|
341
|
-
<span
|
|
341
|
+
<span style={{ fontSize: '12px', color: 'var(--text-tertiary)' }}>
|
|
342
342
|
{tokenData.meta?.totalTokens || tokenData.tokens.length} tokens loaded
|
|
343
343
|
</span>
|
|
344
344
|
)}
|
|
345
345
|
{tokenLoading && (
|
|
346
|
-
<span
|
|
347
|
-
<SyncingIcon
|
|
346
|
+
<span style={{ fontSize: '12px', color: 'var(--text-tertiary)', display: 'flex', alignItems: 'center', gap: '4px' }}>
|
|
347
|
+
<SyncingIcon style={{ width: 12, height: 12, animation: 'spin 1s linear infinite' }} />
|
|
348
348
|
Loading tokens...
|
|
349
349
|
</span>
|
|
350
350
|
)}
|
|
351
351
|
{tokenError && !tokenLoading && (
|
|
352
|
-
<span
|
|
352
|
+
<span style={{ fontSize: '12px', color: '#d97706' }} title={tokenError}>
|
|
353
353
|
Tokens not configured
|
|
354
354
|
</span>
|
|
355
355
|
)}
|
|
356
356
|
</div>
|
|
357
357
|
|
|
358
|
-
<div
|
|
358
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
|
359
359
|
{/* Compliance badge */}
|
|
360
360
|
{tokenData && (
|
|
361
|
-
<
|
|
362
|
-
|
|
363
|
-
"text-xs font-medium px-2 py-0.5 rounded",
|
|
364
|
-
compliancePercent >= 80
|
|
365
|
-
? "bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300"
|
|
366
|
-
: compliancePercent >= 50
|
|
367
|
-
? "bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300"
|
|
368
|
-
: "bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300"
|
|
369
|
-
)}
|
|
361
|
+
<Badge
|
|
362
|
+
variant={compliancePercent >= 80 ? 'success' : compliancePercent >= 50 ? 'warning' : 'danger'}
|
|
370
363
|
>
|
|
371
364
|
{compliancePercent}% token compliance
|
|
372
|
-
</
|
|
365
|
+
</Badge>
|
|
373
366
|
)}
|
|
374
367
|
|
|
375
368
|
{/* Match summary */}
|
|
376
|
-
<
|
|
377
|
-
className={clsx(
|
|
378
|
-
"text-xs font-medium",
|
|
379
|
-
differences === 0 ? "text-green-600" : "text-amber-600"
|
|
380
|
-
)}
|
|
381
|
-
>
|
|
369
|
+
<Badge variant={differences === 0 ? 'success' : 'warning'}>
|
|
382
370
|
{differences === 0 ? "All styles match" : `${differences} difference${differences !== 1 ? "s" : ""}`}
|
|
383
|
-
</
|
|
371
|
+
</Badge>
|
|
384
372
|
|
|
385
373
|
{/* Hardcoded warning */}
|
|
386
374
|
{hardcodedCount > 0 && (
|
|
387
|
-
<
|
|
375
|
+
<Badge variant="danger">
|
|
388
376
|
{hardcodedCount} hardcoded
|
|
389
|
-
</
|
|
377
|
+
</Badge>
|
|
390
378
|
)}
|
|
391
379
|
</div>
|
|
392
380
|
</div>
|
|
393
381
|
|
|
394
382
|
{/* Comparison Table */}
|
|
395
|
-
<table
|
|
383
|
+
<table style={{ width: '100%', fontSize: '12px' }}>
|
|
396
384
|
<thead>
|
|
397
|
-
<tr
|
|
398
|
-
<th
|
|
399
|
-
<th
|
|
385
|
+
<tr style={{ borderBottom: '1px solid var(--border)' }}>
|
|
386
|
+
<th style={{ padding: '8px 12px', textAlign: 'left', color: 'var(--text-tertiary)', fontWeight: 500 }}>Property</th>
|
|
387
|
+
<th style={{ padding: '8px 12px', textAlign: 'left', color: 'var(--text-tertiary)', fontWeight: 500 }}>Figma</th>
|
|
400
388
|
{tokenData && (
|
|
401
|
-
<th
|
|
389
|
+
<th style={{ padding: '8px 12px', textAlign: 'left', color: 'var(--text-tertiary)', fontWeight: 500 }}>Token</th>
|
|
402
390
|
)}
|
|
403
|
-
<th
|
|
404
|
-
<th
|
|
391
|
+
<th style={{ padding: '8px 12px', textAlign: 'left', color: 'var(--text-tertiary)', fontWeight: 500 }}>Rendered</th>
|
|
392
|
+
<th style={{ padding: '8px 12px', textAlign: 'center', color: 'var(--text-tertiary)', fontWeight: 500, width: '48px' }}>Match</th>
|
|
405
393
|
{tokenData && fixableCount > 0 && (
|
|
406
|
-
<th
|
|
394
|
+
<th style={{ padding: '8px 12px', textAlign: 'center', color: 'var(--text-tertiary)', fontWeight: 500, width: '64px' }}>Fix</th>
|
|
407
395
|
)}
|
|
408
396
|
</tr>
|
|
409
397
|
</thead>
|
|
410
398
|
<tbody>
|
|
411
|
-
{properties.map((prop) => (
|
|
399
|
+
{properties.map((prop, index) => (
|
|
412
400
|
<tr
|
|
413
401
|
key={prop.property}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
402
|
+
style={{
|
|
403
|
+
borderBottom: index < properties.length - 1 ? '1px solid var(--border)' : undefined,
|
|
404
|
+
background: prop.isHardcoded
|
|
405
|
+
? 'color-mix(in srgb, #ef4444 5%, transparent)'
|
|
406
|
+
: !prop.match
|
|
407
|
+
? 'color-mix(in srgb, #f59e0b 5%, transparent)'
|
|
408
|
+
: undefined,
|
|
409
|
+
}}
|
|
419
410
|
>
|
|
420
|
-
<td
|
|
421
|
-
<td
|
|
422
|
-
<div
|
|
411
|
+
<td style={{ padding: '8px 12px', fontFamily: 'monospace', color: 'var(--text-primary)' }}>{prop.property}</td>
|
|
412
|
+
<td style={{ padding: '8px 12px' }}>
|
|
413
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
423
414
|
{/* Color swatch */}
|
|
424
415
|
{isColorProperty(prop.property) && prop.figma !== "(not set)" && (
|
|
425
416
|
<ColorSwatch color={prop.figma} />
|
|
426
417
|
)}
|
|
427
|
-
<span
|
|
418
|
+
<span style={{ fontFamily: 'monospace', color: 'var(--text-secondary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '120px' }} title={prop.figma}>
|
|
428
419
|
{prop.figma}
|
|
429
420
|
</span>
|
|
430
421
|
</div>
|
|
431
422
|
</td>
|
|
432
423
|
{tokenData && (
|
|
433
|
-
<td
|
|
424
|
+
<td style={{ padding: '8px 12px' }}>
|
|
434
425
|
{prop.figmaToken ? (
|
|
435
426
|
<TokenBadge token={prop.figmaToken} confidence={prop.figmaConfidence} />
|
|
436
427
|
) : prop.renderedToken ? (
|
|
437
428
|
<TokenBadge token={prop.renderedToken} confidence={prop.renderedConfidence} />
|
|
438
429
|
) : (
|
|
439
|
-
<span
|
|
430
|
+
<span style={{ color: 'var(--text-tertiary)' }}>-</span>
|
|
440
431
|
)}
|
|
441
432
|
</td>
|
|
442
433
|
)}
|
|
443
|
-
<td
|
|
444
|
-
<div
|
|
434
|
+
<td style={{ padding: '8px 12px' }}>
|
|
435
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
445
436
|
{/* Color swatch */}
|
|
446
437
|
{isColorProperty(prop.property) && prop.rendered !== "(not set)" && (
|
|
447
438
|
<ColorSwatch color={prop.rendered} />
|
|
448
439
|
)}
|
|
449
|
-
<span
|
|
440
|
+
<span style={{ fontFamily: 'monospace', color: 'var(--text-secondary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '120px' }} title={prop.rendered}>
|
|
450
441
|
{prop.rendered}
|
|
451
442
|
</span>
|
|
452
443
|
{/* Hardcoded badge */}
|
|
453
444
|
{prop.isHardcoded && (
|
|
454
|
-
<
|
|
455
|
-
HC
|
|
456
|
-
</span>
|
|
445
|
+
<Badge variant="danger">HC</Badge>
|
|
457
446
|
)}
|
|
458
447
|
</div>
|
|
459
448
|
</td>
|
|
460
|
-
<td
|
|
449
|
+
<td style={{ padding: '8px 12px', textAlign: 'center' }}>
|
|
461
450
|
{prop.match ? (
|
|
462
|
-
<CheckIcon
|
|
451
|
+
<CheckIcon style={{ width: 16, height: 16, color: '#16a34a', margin: '0 auto' }} />
|
|
463
452
|
) : (
|
|
464
|
-
<XIcon
|
|
453
|
+
<XIcon style={{ width: 16, height: 16, color: '#d97706', margin: '0 auto' }} />
|
|
465
454
|
)}
|
|
466
455
|
</td>
|
|
467
456
|
{tokenData && fixableCount > 0 && (
|
|
468
|
-
<td
|
|
457
|
+
<td style={{ padding: '8px 12px', textAlign: 'center' }}>
|
|
469
458
|
{prop.isHardcoded && prop.figmaToken && (
|
|
470
459
|
<button
|
|
471
460
|
onClick={() => copyFix(prop.property, prop.figmaToken!.name)}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
461
|
+
style={{
|
|
462
|
+
padding: '4px',
|
|
463
|
+
borderRadius: '4px',
|
|
464
|
+
transition: 'color 0.15s, background 0.15s',
|
|
465
|
+
background: copiedFix === prop.property ? 'color-mix(in srgb, #22c55e 15%, transparent)' : 'transparent',
|
|
466
|
+
color: copiedFix === prop.property ? '#16a34a' : 'var(--text-tertiary)',
|
|
467
|
+
border: 'none',
|
|
468
|
+
cursor: 'pointer',
|
|
469
|
+
}}
|
|
478
470
|
title={`Copy: ${prop.property.replace(/([A-Z])/g, "-$1").toLowerCase()}: var(${prop.figmaToken.name});`}
|
|
479
471
|
>
|
|
480
472
|
{copiedFix === prop.property ? (
|
|
481
|
-
<CheckIcon
|
|
473
|
+
<CheckIcon style={{ width: 12, height: 12 }} />
|
|
482
474
|
) : (
|
|
483
|
-
<WandIcon
|
|
475
|
+
<WandIcon style={{ width: 12, height: 12 }} />
|
|
484
476
|
)}
|
|
485
477
|
</button>
|
|
486
478
|
)}
|
|
@@ -493,14 +485,14 @@ export function TokenStylePanel({
|
|
|
493
485
|
|
|
494
486
|
{/* Hardcoded fixes summary */}
|
|
495
487
|
{hardcodedCount > 0 && tokenData && (
|
|
496
|
-
<div
|
|
497
|
-
<div
|
|
498
|
-
<WandIcon
|
|
488
|
+
<div style={{ marginTop: '16px', padding: '12px', background: 'color-mix(in srgb, #f59e0b 8%, transparent)', borderRadius: '8px', border: '1px solid color-mix(in srgb, #f59e0b 20%, transparent)' }}>
|
|
489
|
+
<div style={{ display: 'flex', alignItems: 'flex-start', gap: '8px' }}>
|
|
490
|
+
<WandIcon style={{ width: 16, height: 16, color: '#d97706', marginTop: '2px' }} />
|
|
499
491
|
<div>
|
|
500
|
-
<p
|
|
492
|
+
<p style={{ fontSize: '12px', fontWeight: 500, color: '#92400e' }}>
|
|
501
493
|
{hardcodedCount} hardcoded value{hardcodedCount !== 1 ? "s" : ""} detected
|
|
502
494
|
</p>
|
|
503
|
-
<p
|
|
495
|
+
<p style={{ fontSize: '12px', color: '#a16207', marginTop: '4px' }}>
|
|
504
496
|
These values should use design tokens for consistency and theming support.
|
|
505
497
|
Click the fix button to copy the token-based CSS.
|
|
506
498
|
</p>
|
|
@@ -526,15 +518,22 @@ function TokenBadge({
|
|
|
526
518
|
}) {
|
|
527
519
|
const [showTooltip, setShowTooltip] = useState(false);
|
|
528
520
|
|
|
521
|
+
const isValueOnly = confidence === "value-only";
|
|
522
|
+
|
|
529
523
|
return (
|
|
530
|
-
<div
|
|
524
|
+
<div style={{ position: 'relative', display: 'inline-block' }}>
|
|
531
525
|
<span
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
526
|
+
style={{
|
|
527
|
+
fontFamily: 'monospace',
|
|
528
|
+
fontSize: '12px',
|
|
529
|
+
cursor: 'help',
|
|
530
|
+
padding: '2px 6px',
|
|
531
|
+
borderRadius: '4px',
|
|
532
|
+
color: isValueOnly ? '#d97706' : 'var(--color-accent)',
|
|
533
|
+
background: isValueOnly
|
|
534
|
+
? 'color-mix(in srgb, #f59e0b 8%, transparent)'
|
|
535
|
+
: 'color-mix(in srgb, var(--color-accent) 8%, transparent)',
|
|
536
|
+
}}
|
|
538
537
|
onMouseEnter={() => setShowTooltip(true)}
|
|
539
538
|
onMouseLeave={() => setShowTooltip(false)}
|
|
540
539
|
>
|
|
@@ -544,20 +543,32 @@ function TokenBadge({
|
|
|
544
543
|
{/* Enhanced tooltip */}
|
|
545
544
|
{showTooltip && (
|
|
546
545
|
<div
|
|
547
|
-
|
|
548
|
-
|
|
546
|
+
style={{
|
|
547
|
+
position: 'absolute',
|
|
548
|
+
zIndex: 50,
|
|
549
|
+
left: 0,
|
|
550
|
+
top: '100%',
|
|
551
|
+
marginTop: '4px',
|
|
552
|
+
padding: '12px',
|
|
553
|
+
background: 'var(--bg-primary)',
|
|
554
|
+
border: '1px solid var(--border)',
|
|
555
|
+
borderRadius: '8px',
|
|
556
|
+
boxShadow: '0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)',
|
|
557
|
+
minWidth: '280px',
|
|
558
|
+
maxWidth: '320px',
|
|
559
|
+
}}
|
|
549
560
|
>
|
|
550
|
-
<div
|
|
561
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px', fontSize: '12px' }}>
|
|
551
562
|
{/* Token name */}
|
|
552
563
|
<div>
|
|
553
|
-
<span
|
|
554
|
-
<span
|
|
564
|
+
<span style={{ color: 'var(--text-tertiary)' }}>Token:</span>
|
|
565
|
+
<span style={{ marginLeft: '8px', fontFamily: 'monospace', color: 'var(--text-primary)', fontWeight: 500 }}>{token.name}</span>
|
|
555
566
|
</div>
|
|
556
567
|
|
|
557
568
|
{/* Resolved value */}
|
|
558
|
-
<div
|
|
559
|
-
<span
|
|
560
|
-
<span
|
|
569
|
+
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
570
|
+
<span style={{ color: 'var(--text-tertiary)' }}>Value:</span>
|
|
571
|
+
<span style={{ marginLeft: '8px', fontFamily: 'monospace', color: 'var(--text-secondary)' }}>{token.resolvedValue}</span>
|
|
561
572
|
{token.category === "color" && (
|
|
562
573
|
<ColorSwatch color={token.resolvedValue} />
|
|
563
574
|
)}
|
|
@@ -566,20 +577,20 @@ function TokenBadge({
|
|
|
566
577
|
{/* Raw value (if different from resolved) */}
|
|
567
578
|
{token.rawValue !== token.resolvedValue && (
|
|
568
579
|
<div>
|
|
569
|
-
<span
|
|
570
|
-
<span
|
|
580
|
+
<span style={{ color: 'var(--text-tertiary)' }}>Raw:</span>
|
|
581
|
+
<span style={{ marginLeft: '8px', fontFamily: 'monospace', color: 'var(--text-secondary)' }}>{token.rawValue}</span>
|
|
571
582
|
</div>
|
|
572
583
|
)}
|
|
573
584
|
|
|
574
585
|
{/* Category & Level */}
|
|
575
|
-
<div
|
|
586
|
+
<div style={{ display: 'flex', gap: '16px' }}>
|
|
576
587
|
<div>
|
|
577
|
-
<span
|
|
578
|
-
<span
|
|
588
|
+
<span style={{ color: 'var(--text-tertiary)' }}>Category:</span>
|
|
589
|
+
<span style={{ marginLeft: '8px', color: 'var(--text-secondary)', textTransform: 'capitalize' }}>{token.category}</span>
|
|
579
590
|
</div>
|
|
580
591
|
<div>
|
|
581
|
-
<span
|
|
582
|
-
<span
|
|
592
|
+
<span style={{ color: 'var(--text-tertiary)' }}>Level:</span>
|
|
593
|
+
<span style={{ marginLeft: '8px', color: 'var(--text-secondary)' }}>
|
|
583
594
|
{token.level === 1 ? "Base" : token.level === 2 ? "Semantic" : "Component"}
|
|
584
595
|
</span>
|
|
585
596
|
</div>
|
|
@@ -587,18 +598,18 @@ function TokenBadge({
|
|
|
587
598
|
|
|
588
599
|
{/* Theme */}
|
|
589
600
|
<div>
|
|
590
|
-
<span
|
|
591
|
-
<span
|
|
601
|
+
<span style={{ color: 'var(--text-tertiary)' }}>Theme:</span>
|
|
602
|
+
<span style={{ marginLeft: '8px', color: 'var(--text-secondary)' }}>{token.theme}</span>
|
|
592
603
|
</div>
|
|
593
604
|
|
|
594
605
|
{/* Reference chain (if has references) */}
|
|
595
606
|
{token.referenceChain.length > 1 && (
|
|
596
607
|
<div>
|
|
597
|
-
<span
|
|
598
|
-
<div
|
|
608
|
+
<span style={{ color: 'var(--text-tertiary)' }}>References:</span>
|
|
609
|
+
<div style={{ marginTop: '4px', fontFamily: 'monospace', color: 'var(--text-secondary)', fontSize: '10px', display: 'flex', flexDirection: 'column', gap: '2px' }}>
|
|
599
610
|
{token.referenceChain.map((ref, i) => (
|
|
600
|
-
<div key={ref}
|
|
601
|
-
{i > 0 && <span
|
|
611
|
+
<div key={ref} style={{ display: 'flex', alignItems: 'center' }}>
|
|
612
|
+
{i > 0 && <span style={{ marginRight: '4px', color: 'var(--text-tertiary)' }}>→</span>}
|
|
602
613
|
<span>{ref}</span>
|
|
603
614
|
</div>
|
|
604
615
|
))}
|
|
@@ -607,9 +618,9 @@ function TokenBadge({
|
|
|
607
618
|
)}
|
|
608
619
|
|
|
609
620
|
{/* Source file */}
|
|
610
|
-
<div
|
|
611
|
-
<span
|
|
612
|
-
<span
|
|
621
|
+
<div style={{ paddingTop: '4px', borderTop: '1px solid var(--border)' }}>
|
|
622
|
+
<span style={{ color: 'var(--text-tertiary)' }}>Source:</span>
|
|
623
|
+
<span style={{ marginLeft: '8px', fontFamily: 'monospace', fontSize: '10px', color: 'var(--text-tertiary)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
|
613
624
|
{token.sourceFile.split("/").slice(-2).join("/")}
|
|
614
625
|
{token.lineNumber && `:${token.lineNumber}`}
|
|
615
626
|
</span>
|
|
@@ -617,8 +628,8 @@ function TokenBadge({
|
|
|
617
628
|
|
|
618
629
|
{/* Confidence indicator */}
|
|
619
630
|
{confidence === "value-only" && (
|
|
620
|
-
<div
|
|
621
|
-
|
|
631
|
+
<div style={{ paddingTop: '4px', color: '#d97706' }}>
|
|
632
|
+
Warning: Value match only - verify this is the correct token
|
|
622
633
|
</div>
|
|
623
634
|
)}
|
|
624
635
|
</div>
|
|
@@ -631,8 +642,15 @@ function TokenBadge({
|
|
|
631
642
|
function ColorSwatch({ color }: { color: string }) {
|
|
632
643
|
return (
|
|
633
644
|
<div
|
|
634
|
-
|
|
635
|
-
|
|
645
|
+
style={{
|
|
646
|
+
width: '16px',
|
|
647
|
+
height: '16px',
|
|
648
|
+
borderRadius: '4px',
|
|
649
|
+
border: '1px solid var(--border)',
|
|
650
|
+
flexShrink: 0,
|
|
651
|
+
marginLeft: '4px',
|
|
652
|
+
backgroundColor: color,
|
|
653
|
+
}}
|
|
636
654
|
title={color}
|
|
637
655
|
/>
|
|
638
656
|
);
|
|
@@ -16,22 +16,22 @@ export function UsageSection({ usage }: UsageSectionProps) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<section id="usage"
|
|
20
|
-
<h2
|
|
19
|
+
<section id="usage" style={{ scrollMarginTop: '96px' }}>
|
|
20
|
+
<h2 style={{ fontSize: '16px', fontWeight: 600, color: 'var(--text-primary)', marginBottom: '20px' }}>Usage</h2>
|
|
21
21
|
|
|
22
22
|
{/* When to use / When not to use */}
|
|
23
23
|
{(hasWhen || hasWhenNot) && (
|
|
24
|
-
<div
|
|
24
|
+
<div style={{ display: 'grid', gridTemplateColumns: hasWhen && hasWhenNot ? '1fr 1fr' : '1fr', gap: '32px', marginBottom: '32px' }}>
|
|
25
25
|
{hasWhen && (
|
|
26
|
-
<div
|
|
27
|
-
<h3
|
|
28
|
-
<CheckIcon
|
|
26
|
+
<div style={{ padding: '16px', borderRadius: '12px', background: 'var(--color-success-bg)', border: '1px solid rgba(16, 163, 127, 0.2)' }}>
|
|
27
|
+
<h3 style={{ fontSize: '13px', fontWeight: 500, color: 'var(--color-success)', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
28
|
+
<CheckIcon style={{ width: '16px', height: '16px' }} />
|
|
29
29
|
When to use
|
|
30
30
|
</h3>
|
|
31
|
-
<ul
|
|
31
|
+
<ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
32
32
|
{usage.when!.map((item, index) => (
|
|
33
|
-
<li key={index}
|
|
34
|
-
<span
|
|
33
|
+
<li key={index} style={{ fontSize: '13px', color: 'var(--text-primary)', lineHeight: 1.6, display: 'flex', alignItems: 'flex-start', gap: '8px' }}>
|
|
34
|
+
<span style={{ color: 'var(--color-success)', marginTop: '6px', fontSize: '12px' }}>•</span>
|
|
35
35
|
<span>{item}</span>
|
|
36
36
|
</li>
|
|
37
37
|
))}
|
|
@@ -40,15 +40,15 @@ export function UsageSection({ usage }: UsageSectionProps) {
|
|
|
40
40
|
)}
|
|
41
41
|
|
|
42
42
|
{hasWhenNot && (
|
|
43
|
-
<div
|
|
44
|
-
<h3
|
|
45
|
-
<XIcon
|
|
43
|
+
<div style={{ padding: '16px', borderRadius: '12px', background: 'var(--color-danger-bg)', border: '1px solid rgba(239, 68, 68, 0.2)' }}>
|
|
44
|
+
<h3 style={{ fontSize: '13px', fontWeight: 500, color: 'var(--color-danger)', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
45
|
+
<XIcon style={{ width: '16px', height: '16px' }} />
|
|
46
46
|
When not to use
|
|
47
47
|
</h3>
|
|
48
|
-
<ul
|
|
48
|
+
<ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
49
49
|
{usage.whenNot!.map((item, index) => (
|
|
50
|
-
<li key={index}
|
|
51
|
-
<span
|
|
50
|
+
<li key={index} style={{ fontSize: '13px', color: 'var(--text-primary)', lineHeight: 1.6, display: 'flex', alignItems: 'flex-start', gap: '8px' }}>
|
|
51
|
+
<span style={{ color: 'var(--color-danger)', marginTop: '6px', fontSize: '12px' }}>•</span>
|
|
52
52
|
<span>{item}</span>
|
|
53
53
|
</li>
|
|
54
54
|
))}
|
|
@@ -60,12 +60,12 @@ export function UsageSection({ usage }: UsageSectionProps) {
|
|
|
60
60
|
|
|
61
61
|
{/* Guidelines */}
|
|
62
62
|
{hasGuidelines && (
|
|
63
|
-
<div
|
|
64
|
-
<h3
|
|
65
|
-
<ul
|
|
63
|
+
<div style={{ marginBottom: '24px' }}>
|
|
64
|
+
<h3 style={{ fontSize: '13px', fontWeight: 500, color: 'var(--text-primary)', marginBottom: '12px' }}>Guidelines</h3>
|
|
65
|
+
<ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
66
66
|
{usage.guidelines!.map((item, index) => (
|
|
67
|
-
<li key={index}
|
|
68
|
-
<span
|
|
67
|
+
<li key={index} style={{ fontSize: '13px', color: 'var(--text-secondary)', lineHeight: 1.6, display: 'flex', alignItems: 'flex-start', gap: '8px' }}>
|
|
68
|
+
<span style={{ color: 'var(--color-accent)', marginTop: '6px', fontSize: '12px' }}>•</span>
|
|
69
69
|
<span>{item}</span>
|
|
70
70
|
</li>
|
|
71
71
|
))}
|
|
@@ -75,15 +75,15 @@ export function UsageSection({ usage }: UsageSectionProps) {
|
|
|
75
75
|
|
|
76
76
|
{/* Accessibility */}
|
|
77
77
|
{hasAccessibility && (
|
|
78
|
-
<div
|
|
79
|
-
<h3
|
|
80
|
-
<AccessibilityIcon
|
|
78
|
+
<div style={{ padding: '16px', borderRadius: '12px', border: '1px solid var(--border)', background: 'var(--bg-secondary)' }}>
|
|
79
|
+
<h3 style={{ fontSize: '13px', fontWeight: 500, color: 'var(--text-primary)', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
80
|
+
<AccessibilityIcon style={{ width: '16px', height: '16px', color: 'var(--text-secondary)' }} />
|
|
81
81
|
Accessibility
|
|
82
82
|
</h3>
|
|
83
|
-
<ul
|
|
83
|
+
<ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'flex', flexDirection: 'column', gap: '8px' }}>
|
|
84
84
|
{usage.accessibility!.map((item, index) => (
|
|
85
|
-
<li key={index}
|
|
86
|
-
<span
|
|
85
|
+
<li key={index} style={{ fontSize: '13px', color: 'var(--text-secondary)', lineHeight: 1.6, display: 'flex', alignItems: 'flex-start', gap: '8px' }}>
|
|
86
|
+
<span style={{ color: 'var(--text-tertiary)', marginTop: '6px', fontSize: '12px' }}>•</span>
|
|
87
87
|
<span>{item}</span>
|
|
88
88
|
</li>
|
|
89
89
|
))}
|