@donotdev/ui 0.0.2 → 0.0.4

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 (119) hide show
  1. package/dist/components/auth/AuthMenu.d.ts.map +1 -1
  2. package/dist/components/auth/AuthMenu.js +19 -32
  3. package/dist/components/common/FeatureCard.d.ts +7 -19
  4. package/dist/components/common/FeatureCard.d.ts.map +1 -1
  5. package/dist/components/common/FeatureCard.js +5 -29
  6. package/dist/components/common/TechBento.d.ts +15 -3
  7. package/dist/components/common/TechBento.d.ts.map +1 -1
  8. package/dist/components/common/TechBento.js +20 -2
  9. package/dist/components/cookie-consent/CookieConsent.d.ts.map +1 -1
  10. package/dist/components/cookie-consent/CookieConsent.js +2 -41
  11. package/dist/components/cookie-consent/index.d.ts +0 -1
  12. package/dist/components/cookie-consent/index.d.ts.map +1 -1
  13. package/dist/components/cookie-consent/index.js +1 -1
  14. package/dist/components/layout/components/DropdownNavigation.d.ts.map +1 -1
  15. package/dist/components/layout/components/header/ThemeToggle.d.ts +1 -1
  16. package/dist/components/layout/components/header/ThemeToggle.d.ts.map +1 -1
  17. package/dist/components/layout/components/header/ThemeToggle.js +5 -4
  18. package/dist/dndev.css +373 -249
  19. package/dist/index.js +4 -4
  20. package/dist/internal/devtools/DebugTools.d.ts.map +1 -1
  21. package/dist/internal/devtools/DebugTools.js +8 -4
  22. package/dist/internal/devtools/components/ConfigTab.d.ts.map +1 -1
  23. package/dist/internal/devtools/components/ConfigTab.js +33 -133
  24. package/dist/internal/devtools/components/DebugDialog.d.ts.map +1 -1
  25. package/dist/internal/devtools/components/DebugDialog.js +11 -520
  26. package/dist/internal/devtools/components/DesignTab.d.ts +2 -0
  27. package/dist/internal/devtools/components/DesignTab.d.ts.map +1 -0
  28. package/dist/internal/devtools/components/DesignTab.js +431 -0
  29. package/dist/internal/devtools/components/StoresTab.d.ts.map +1 -1
  30. package/dist/internal/devtools/components/StoresTab.js +54 -102
  31. package/dist/internal/devtools/components/index.d.ts +1 -6
  32. package/dist/internal/devtools/components/index.d.ts.map +1 -1
  33. package/dist/internal/devtools/components/index.js +1 -6
  34. package/dist/internal/devtools/utils/index.d.ts +0 -1
  35. package/dist/internal/devtools/utils/index.d.ts.map +1 -1
  36. package/dist/internal/devtools/utils/index.js +0 -1
  37. package/dist/internal/initializers/BaseStoresInitializer.d.ts.map +1 -1
  38. package/dist/internal/initializers/BaseStoresInitializer.js +36 -59
  39. package/dist/internal/layout/DnDevLayout.js +3 -3
  40. package/dist/internal/layout/components/AutoMetaTags.d.ts.map +1 -1
  41. package/dist/internal/layout/components/AutoMetaTags.js +6 -1
  42. package/dist/internal/layout/components/footer/FooterBranding.d.ts.map +1 -1
  43. package/dist/internal/layout/components/footer/FooterBranding.js +3 -1
  44. package/dist/internal/layout/zones/DnDevFooter.js +2 -2
  45. package/dist/routing/AuthGuard.d.ts +14 -10
  46. package/dist/routing/AuthGuard.d.ts.map +1 -1
  47. package/dist/routing/AuthGuard.js +25 -22
  48. package/dist/routing/Link.d.ts +2 -2
  49. package/dist/routing/Link.js +2 -2
  50. package/dist/routing/hooks/hooks.next.js +1 -1
  51. package/dist/routing/hooks/hooks.vite.js +1 -1
  52. package/dist/routing/hooks/useRedirectGuard.next.d.ts +2 -36
  53. package/dist/routing/hooks/useRedirectGuard.next.d.ts.map +1 -1
  54. package/dist/routing/hooks/useRedirectGuard.next.js +14 -55
  55. package/dist/routing/hooks/useRedirectGuard.vite.d.ts +2 -36
  56. package/dist/routing/hooks/useRedirectGuard.vite.d.ts.map +1 -1
  57. package/dist/routing/hooks/useRedirectGuard.vite.js +14 -55
  58. package/dist/routing/index.d.ts +0 -1
  59. package/dist/routing/index.d.ts.map +1 -1
  60. package/dist/routing/index.js +1 -1
  61. package/dist/styles/index.css +373 -249
  62. package/dist/utils/assetResolver.d.ts +5 -5
  63. package/dist/utils/assetResolver.d.ts.map +1 -1
  64. package/dist/utils/assetResolver.js +26 -15
  65. package/dist/utils/index.d.ts +1 -0
  66. package/dist/utils/index.d.ts.map +1 -1
  67. package/dist/utils/index.js +1 -0
  68. package/dist/utils/tList.d.ts +30 -0
  69. package/dist/utils/tList.d.ts.map +1 -0
  70. package/dist/utils/tList.js +51 -0
  71. package/dist/utils/useAuthSafe.d.ts +25 -12
  72. package/dist/utils/useAuthSafe.d.ts.map +1 -1
  73. package/dist/utils/useAuthSafe.js +3 -1
  74. package/dist/utils/useAuthVisibility.d.ts +3 -3
  75. package/dist/utils/useAuthVisibility.d.ts.map +1 -1
  76. package/dist/utils/useAuthVisibility.js +25 -21
  77. package/dist/utils/useBillingVisibility.d.ts +2 -2
  78. package/dist/utils/useBillingVisibility.d.ts.map +1 -1
  79. package/dist/utils/useBillingVisibility.js +12 -13
  80. package/dist/utils/useCrudSafe.d.ts +1 -1
  81. package/dist/utils/useCrudSafe.d.ts.map +1 -1
  82. package/dist/utils/useCrudSafe.js +26 -13
  83. package/dist/utils/useOAuthSafe.d.ts +25 -12
  84. package/dist/utils/useOAuthSafe.d.ts.map +1 -1
  85. package/dist/utils/useStripeBillingSafe.d.ts +30 -18
  86. package/dist/utils/useStripeBillingSafe.d.ts.map +1 -1
  87. package/dist/utils/useStripeBillingSafe.js +5 -6
  88. package/dist/vite-routing/AppRoutes.d.ts.map +1 -1
  89. package/dist/vite-routing/AppRoutes.js +5 -5
  90. package/dist/vite-routing/RootLayout.d.ts.map +1 -1
  91. package/dist/vite-routing/RootLayout.js +34 -7
  92. package/package.json +9 -9
  93. package/dist/internal/devtools/components/AuthTab.d.ts +0 -2
  94. package/dist/internal/devtools/components/AuthTab.d.ts.map +0 -1
  95. package/dist/internal/devtools/components/AuthTab.js +0 -98
  96. package/dist/internal/devtools/components/ColorRatioTab.d.ts +0 -2
  97. package/dist/internal/devtools/components/ColorRatioTab.d.ts.map +0 -1
  98. package/dist/internal/devtools/components/ColorRatioTab.js +0 -322
  99. package/dist/internal/devtools/components/DebugToggle.d.ts +0 -2
  100. package/dist/internal/devtools/components/DebugToggle.d.ts.map +0 -1
  101. package/dist/internal/devtools/components/DebugToggle.js +0 -57
  102. package/dist/internal/devtools/components/EnvironmentTab.d.ts +0 -2
  103. package/dist/internal/devtools/components/EnvironmentTab.d.ts.map +0 -1
  104. package/dist/internal/devtools/components/EnvironmentTab.js +0 -26
  105. package/dist/internal/devtools/components/I18nTab.d.ts +0 -2
  106. package/dist/internal/devtools/components/I18nTab.d.ts.map +0 -1
  107. package/dist/internal/devtools/components/I18nTab.js +0 -76
  108. package/dist/internal/devtools/components/OAuthGuideButton.d.ts +0 -10
  109. package/dist/internal/devtools/components/OAuthGuideButton.d.ts.map +0 -1
  110. package/dist/internal/devtools/components/OAuthGuideButton.js +0 -71
  111. package/dist/internal/devtools/components/StripeDebugTab.d.ts +0 -2
  112. package/dist/internal/devtools/components/StripeDebugTab.d.ts.map +0 -1
  113. package/dist/internal/devtools/components/StripeDebugTab.js +0 -175
  114. package/dist/internal/devtools/components/ThemesTab.d.ts +0 -2
  115. package/dist/internal/devtools/components/ThemesTab.d.ts.map +0 -1
  116. package/dist/internal/devtools/components/ThemesTab.js +0 -77
  117. package/dist/internal/devtools/utils/spacingAnalyzer.d.ts +0 -15
  118. package/dist/internal/devtools/utils/spacingAnalyzer.d.ts.map +0 -1
  119. package/dist/internal/devtools/utils/spacingAnalyzer.js +0 -88
@@ -0,0 +1,431 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ // packages/ui/src/internal/devtools/components/DesignTab.tsx
4
+ /**
5
+ * @fileoverview Design Tab Component
6
+ * @description Unified design debugging: themes, color ratio, typography
7
+ *
8
+ * @version 0.0.1
9
+ * @since 0.0.1
10
+ * @author AMBROISE PARK Consulting
11
+ */
12
+ import { Palette, Type } from 'lucide-react';
13
+ import { useState, useEffect } from 'react';
14
+ import { Card, Button, BUTTON_VARIANT, Stack, Label, Badge, BADGE_VARIANT, Alert, ALERT_VARIANT, DescriptionList, Text, ScrollArea, Accordion, CopyToClipboard, toast, } from '@donotdev/components';
15
+ import { useTheme, useThemeReady } from '@donotdev/core';
16
+ export const DesignTab = () => {
17
+ const currentTheme = useTheme('currentTheme');
18
+ const availableThemes = useTheme('availableThemes');
19
+ const isDarkMode = useTheme('isDarkMode');
20
+ const isReady = useThemeReady();
21
+ // Load cached analysis from localStorage
22
+ const loadCachedAnalysis = () => {
23
+ try {
24
+ const cached = localStorage.getItem('dndev-design-analysis');
25
+ if (cached) {
26
+ const parsed = JSON.parse(cached);
27
+ if (parsed.colorRatio)
28
+ setColorRatio(parsed.colorRatio);
29
+ if (parsed.typography)
30
+ setTypography(parsed.typography);
31
+ if (parsed.fontSizeColors)
32
+ setFontSizeColors(parsed.fontSizeColors);
33
+ }
34
+ }
35
+ catch (e) {
36
+ // Ignore cache errors
37
+ }
38
+ };
39
+ // Save analysis to localStorage
40
+ const saveAnalysis = (colorRatioData, typographyData, fontSizeColorsData) => {
41
+ try {
42
+ localStorage.setItem('dndev-design-analysis', JSON.stringify({
43
+ colorRatio: colorRatioData,
44
+ typography: typographyData,
45
+ fontSizeColors: fontSizeColorsData,
46
+ timestamp: new Date().toISOString(),
47
+ }));
48
+ }
49
+ catch (e) {
50
+ // Ignore save errors
51
+ }
52
+ };
53
+ useEffect(() => {
54
+ loadCachedAnalysis();
55
+ }, []);
56
+ const [colorRatio, setColorRatio] = useState(null);
57
+ const [typography, setTypography] = useState(null);
58
+ const [isAnalyzing, setIsAnalyzing] = useState(false);
59
+ const [highlightedSize, setHighlightedSize] = useState(null);
60
+ const [fontSizeColors, setFontSizeColors] = useState({});
61
+ // Normalize font size for comparison (round to 2 decimals)
62
+ const normalizeFontSize = (size) => {
63
+ return parseFloat(size).toFixed(2) + 'px';
64
+ };
65
+ // Highlight/unhighlight elements by font size
66
+ const toggleHighlight = (size) => {
67
+ // Clear previous highlights
68
+ document.querySelectorAll('[data-dndev-highlight]').forEach((el) => {
69
+ el.style.outline = '';
70
+ el.removeAttribute('data-dndev-highlight');
71
+ });
72
+ if (highlightedSize === size) {
73
+ setHighlightedSize(null);
74
+ return;
75
+ }
76
+ // Highlight elements with matching font size - ONLY leaf nodes
77
+ const elements = document.querySelectorAll('*');
78
+ let count = 0;
79
+ const normalizedSize = normalizeFontSize(size);
80
+ elements.forEach((el) => {
81
+ if (isOverlayElement(el))
82
+ return;
83
+ // Only highlight leaf nodes (same logic as analysis)
84
+ const hasText = el.textContent && el.textContent.trim().length > 0;
85
+ const hasChildElements = el.children.length > 0;
86
+ if (!hasText || hasChildElements)
87
+ return;
88
+ const style = getComputedStyle(el);
89
+ if (normalizeFontSize(style.fontSize) === normalizedSize) {
90
+ el.style.outline = '2px solid var(--primary)';
91
+ el.setAttribute('data-dndev-highlight', 'true');
92
+ count++;
93
+ }
94
+ });
95
+ setHighlightedSize(size);
96
+ toast('info', `Highlighting ${count} elements with ${size}`);
97
+ };
98
+ // Apply color to elements with matching font size
99
+ const applyFontSizeColor = (size, color) => {
100
+ // Clear previous color for this size
101
+ document
102
+ .querySelectorAll(`[data-dndev-font-size-color="${size}"]`)
103
+ .forEach((el) => {
104
+ el.style.color = '';
105
+ el.removeAttribute('data-dndev-font-size-color');
106
+ });
107
+ if (!color) {
108
+ setFontSizeColors((prev) => {
109
+ const next = { ...prev };
110
+ delete next[size];
111
+ return next;
112
+ });
113
+ return;
114
+ }
115
+ // Apply color to all elements with this font size - ONLY leaf nodes
116
+ const elements = document.querySelectorAll('*');
117
+ let count = 0;
118
+ const normalizedSize = normalizeFontSize(size);
119
+ elements.forEach((el) => {
120
+ if (isOverlayElement(el))
121
+ return;
122
+ // Only color leaf nodes (same logic as analysis)
123
+ const hasText = el.textContent && el.textContent.trim().length > 0;
124
+ const hasChildElements = el.children.length > 0;
125
+ if (!hasText || hasChildElements)
126
+ return;
127
+ const style = getComputedStyle(el);
128
+ if (normalizeFontSize(style.fontSize) === normalizedSize) {
129
+ el.style.color = color;
130
+ el.setAttribute('data-dndev-font-size-color', size);
131
+ count++;
132
+ }
133
+ });
134
+ const newColors = { ...fontSizeColors, [size]: color };
135
+ setFontSizeColors(newColors);
136
+ saveAnalysis(colorRatio, typography, newColors);
137
+ };
138
+ // Clear highlights on unmount or when dialog closes
139
+ const clearHighlights = () => {
140
+ document.querySelectorAll('[data-dndev-highlight]').forEach((el) => {
141
+ el.style.outline = '';
142
+ el.removeAttribute('data-dndev-highlight');
143
+ });
144
+ document.querySelectorAll('[data-dndev-font-size-color]').forEach((el) => {
145
+ el.style.color = '';
146
+ el.removeAttribute('data-dndev-font-size-color');
147
+ });
148
+ setHighlightedSize(null);
149
+ setFontSizeColors({});
150
+ saveAnalysis(colorRatio, typography, {});
151
+ };
152
+ // Get CSS variables from :root
153
+ const getCSSVariables = () => {
154
+ const root = document.documentElement;
155
+ const style = getComputedStyle(root);
156
+ const vars = {};
157
+ const relevantVars = [
158
+ '--background',
159
+ '--foreground',
160
+ '--card',
161
+ '--card-foreground',
162
+ '--popover',
163
+ '--popover-foreground',
164
+ '--primary',
165
+ '--primary-foreground',
166
+ '--secondary',
167
+ '--secondary-foreground',
168
+ '--muted',
169
+ '--muted-foreground',
170
+ '--accent',
171
+ '--accent-foreground',
172
+ '--destructive',
173
+ '--destructive-foreground',
174
+ '--border',
175
+ '--input',
176
+ '--ring',
177
+ '--radius',
178
+ ];
179
+ relevantVars.forEach((varName) => {
180
+ const value = style.getPropertyValue(varName).trim();
181
+ if (value)
182
+ vars[varName] = value;
183
+ });
184
+ return vars;
185
+ };
186
+ // Check if element is inside devtools, dialogs, or overlays
187
+ const isOverlayElement = (el) => {
188
+ return !!(el.closest('[data-dndev-devtools]') ||
189
+ el.closest('[data-radix-portal]') ||
190
+ el.closest('[role="dialog"]') ||
191
+ el.closest('[data-state="open"]') ||
192
+ el.closest('.dndev-sheet-content'));
193
+ };
194
+ const analyzeTypography = () => {
195
+ const elements = document.querySelectorAll('*');
196
+ const fontSizeMap = new Map();
197
+ let analyzedCount = 0;
198
+ elements.forEach((el) => {
199
+ if (isOverlayElement(el))
200
+ return;
201
+ if (el.tagName === 'SCRIPT' ||
202
+ el.tagName === 'STYLE' ||
203
+ el.tagName === 'NOSCRIPT')
204
+ return;
205
+ const style = getComputedStyle(el);
206
+ const rect = el.getBoundingClientRect();
207
+ if (rect.width === 0 || rect.height === 0)
208
+ return;
209
+ if (style.display === 'none' || style.visibility === 'hidden')
210
+ return;
211
+ // ONLY leaf nodes with text, no children
212
+ const hasText = el.textContent && el.textContent.trim().length > 0;
213
+ if (!hasText || el.children.length > 0)
214
+ return;
215
+ analyzedCount++;
216
+ const fontSize = style.fontSize;
217
+ const fontSizeRounded = parseFloat(fontSize).toFixed(2) + 'px';
218
+ fontSizeMap.set(fontSizeRounded, (fontSizeMap.get(fontSizeRounded) || 0) + 1);
219
+ });
220
+ const fontSizes = Array.from(fontSizeMap.entries())
221
+ .map(([size, count]) => ({ size, count }))
222
+ .sort((a, b) => b.count - a.count);
223
+ return {
224
+ fontSizes,
225
+ totalElements: analyzedCount,
226
+ };
227
+ };
228
+ const analyzeColorRatio = () => {
229
+ const elements = document.querySelectorAll('*');
230
+ const colorMap = new Map();
231
+ elements.forEach((el) => {
232
+ // Skip overlay/devtools elements
233
+ if (isOverlayElement(el))
234
+ return;
235
+ const style = getComputedStyle(el);
236
+ const bg = style.backgroundColor;
237
+ const rect = el.getBoundingClientRect();
238
+ const area = rect.width * rect.height;
239
+ if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent' && area > 0) {
240
+ const existing = colorMap.get(bg) || { count: 0, area: 0 };
241
+ colorMap.set(bg, {
242
+ count: existing.count + 1,
243
+ area: existing.area + area,
244
+ });
245
+ }
246
+ });
247
+ const totalArea = Array.from(colorMap.values()).reduce((sum, v) => sum + v.area, 0);
248
+ if (totalArea === 0)
249
+ return { dominant: 0, secondary: 0, accent: 0, details: [] };
250
+ const colors = Array.from(colorMap.entries())
251
+ .map(([color, data]) => ({
252
+ color,
253
+ percentage: (data.area / totalArea) * 100,
254
+ }))
255
+ .sort((a, b) => b.percentage - a.percentage);
256
+ // Simplified categorization based on percentage
257
+ const dominant = colors
258
+ .slice(0, 2)
259
+ .reduce((sum, c) => sum + c.percentage, 0);
260
+ const secondary = colors
261
+ .slice(2, 5)
262
+ .reduce((sum, c) => sum + c.percentage, 0);
263
+ const accent = colors.slice(5).reduce((sum, c) => sum + c.percentage, 0);
264
+ return {
265
+ dominant,
266
+ secondary,
267
+ accent,
268
+ details: colors.slice(0, 15).map((c) => ({
269
+ ...c,
270
+ category: c.percentage > 30
271
+ ? 'dominant'
272
+ : c.percentage > 10
273
+ ? 'secondary'
274
+ : 'accent',
275
+ })),
276
+ };
277
+ };
278
+ const runAnalysis = () => {
279
+ setIsAnalyzing(true);
280
+ try {
281
+ const colorRatioData = analyzeColorRatio();
282
+ const typographyData = analyzeTypography();
283
+ setColorRatio(colorRatioData);
284
+ setTypography(typographyData);
285
+ saveAnalysis(colorRatioData, typographyData, fontSizeColors);
286
+ toast('success', 'Analysis complete');
287
+ }
288
+ catch (error) {
289
+ console.error('Analysis failed:', error);
290
+ toast('error', 'Analysis failed');
291
+ }
292
+ finally {
293
+ setIsAnalyzing(false);
294
+ }
295
+ };
296
+ // Format analysis results for clipboard
297
+ const getAnalysisJson = () => {
298
+ return JSON.stringify({
299
+ theme: {
300
+ current: currentTheme,
301
+ isDarkMode,
302
+ isReady,
303
+ availableCount: availableThemes.length,
304
+ },
305
+ cssVariables: getCSSVariables(),
306
+ colorRatio: colorRatio || null,
307
+ typography: typography || null,
308
+ timestamp: new Date().toISOString(),
309
+ }, null, 2);
310
+ };
311
+ const copyAnalysis = () => {
312
+ navigator.clipboard
313
+ .writeText(getAnalysisJson())
314
+ .then(() => {
315
+ toast('success', 'Analysis copied to clipboard');
316
+ })
317
+ .catch(() => {
318
+ toast('error', 'Failed to copy');
319
+ });
320
+ };
321
+ const cssVars = getCSSVariables();
322
+ const themeItems = [
323
+ {
324
+ label: 'Current',
325
+ value: _jsx(Text, { className: "dndev-font-mono", children: currentTheme }),
326
+ },
327
+ {
328
+ label: 'Dark Mode',
329
+ value: (_jsx(Badge, { variant: isDarkMode ? BADGE_VARIANT.DEFAULT : BADGE_VARIANT.SECONDARY, children: isDarkMode ? 'Yes' : 'No' })),
330
+ },
331
+ {
332
+ label: 'Ready',
333
+ value: (_jsx(Badge, { variant: isReady ? BADGE_VARIANT.DEFAULT : BADGE_VARIANT.DESTRUCTIVE, children: isReady ? 'Yes' : 'No' })),
334
+ },
335
+ {
336
+ label: 'Available',
337
+ value: (_jsxs(Text, { className: "dndev-font-mono", children: [availableThemes.length, " themes"] })),
338
+ },
339
+ ];
340
+ const isColorCompliant = colorRatio &&
341
+ colorRatio.dominant >= 50 &&
342
+ colorRatio.dominant <= 70 &&
343
+ colorRatio.secondary >= 20 &&
344
+ colorRatio.secondary <= 40 &&
345
+ colorRatio.accent >= 5 &&
346
+ colorRatio.accent <= 20;
347
+ return (_jsxs(Stack, { gap: "medium", style: { padding: 'var(--gap-md)' }, children: [_jsx(Accordion, { type: "single", collapsible: true, items: [
348
+ {
349
+ value: 'theme',
350
+ trigger: _jsx("span", { children: "Theme Info" }),
351
+ content: (_jsxs(Stack, { gap: "medium", children: [_jsx(Card, { title: "Theme", subtitle: currentTheme, children: _jsx(DescriptionList, { items: themeItems }) }), _jsx(Card, { title: "CSS Variables", subtitle: `${Object.keys(cssVars).length} variables`, children: _jsx(ScrollArea, { className: "dndev-max-h-48", children: _jsx(Stack, { gap: "tight", children: Object.entries(cssVars).map(([name, value]) => (_jsxs(Stack, { direction: "row", align: "center", justify: "between", gap: "tight", children: [_jsx(Text, { className: "dndev-font-mono dndev-text-xs", children: name }), _jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx("div", { style: {
352
+ width: '1rem',
353
+ height: '1rem',
354
+ backgroundColor: `var(${name})`,
355
+ border: '1px solid var(--border)',
356
+ borderRadius: 'var(--radius-sm)',
357
+ } }), _jsx(Text, { className: "dndev-font-mono dndev-text-xs dndev-text-muted-foreground", children: value })] })] }, name))) }) }) })] })),
358
+ },
359
+ ] }), _jsxs(Stack, { direction: "row", gap: "tight", children: [_jsx(Button, { onClick: runAnalysis, variant: BUTTON_VARIANT.DEFAULT, icon: Palette, disabled: isAnalyzing, style: { flex: 1 }, children: isAnalyzing ? 'Analyzing...' : 'Analyze Page' }), _jsx(Button, { onClick: copyAnalysis, variant: BUTTON_VARIANT.OUTLINE, disabled: !colorRatio && !typography, children: "Copy JSON" })] }), colorRatio && (_jsx(Card, { content: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "60/30/10 Color Ratio" }), _jsx(Badge, { variant: isColorCompliant
360
+ ? BADGE_VARIANT.DEFAULT
361
+ : BADGE_VARIANT.SECONDARY, children: isColorCompliant ? '✓ Balanced' : '⚠ Review' })] }), children: _jsxs(Stack, { gap: "tight", children: [_jsxs(Stack, { direction: "row", justify: "between", children: [_jsx("span", { children: "Dominant (60%)" }), _jsxs("span", { className: colorRatio.dominant >= 50 && colorRatio.dominant <= 70
362
+ ? 'dndev-text-primary'
363
+ : 'dndev-text-destructive', children: [colorRatio.dominant.toFixed(1), "%"] })] }), _jsxs(Stack, { direction: "row", justify: "between", children: [_jsx("span", { children: "Secondary (30%)" }), _jsxs("span", { className: colorRatio.secondary >= 20 && colorRatio.secondary <= 40
364
+ ? 'dndev-text-primary'
365
+ : 'dndev-text-destructive', children: [colorRatio.secondary.toFixed(1), "%"] })] }), _jsxs(Stack, { direction: "row", justify: "between", children: [_jsx("span", { children: "Accent (10%)" }), _jsxs("span", { className: colorRatio.accent >= 5 && colorRatio.accent <= 20
366
+ ? 'dndev-text-primary'
367
+ : 'dndev-text-destructive', children: [colorRatio.accent.toFixed(1), "%"] })] }), colorRatio.details.length > 0 && (_jsx(Accordion, { type: "single", collapsible: true, items: [
368
+ {
369
+ value: 'colors',
370
+ trigger: (_jsxs("span", { className: "dndev-text-sm", children: ["Top Colors (", colorRatio.details.length, ")"] })),
371
+ content: (_jsx(Stack, { gap: "tight", children: colorRatio.details.map((c, i) => (_jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx("div", { style: {
372
+ width: '1rem',
373
+ height: '1rem',
374
+ backgroundColor: c.color,
375
+ border: '1px solid var(--border)',
376
+ flexShrink: 0,
377
+ } }), _jsxs(Text, { className: "dndev-text-xs dndev-font-mono", style: { flex: 1 }, children: [c.percentage.toFixed(1), "%"] }), _jsx(Badge, { variant: BADGE_VARIANT.SECONDARY, children: c.category })] }, i))) })),
378
+ },
379
+ ] }))] }) })), typography && (_jsxs(Card, { content: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Font Sizes" }), _jsxs(Badge, { variant: BADGE_VARIANT.SECONDARY, children: [typography.totalElements, " elements"] })] }), children: [_jsxs(Stack, { direction: "row", align: "center", justify: "between", children: [_jsxs(Label, { className: "dndev-text-sm dndev-font-semibold", children: [typography.fontSizes.length, " sizes"] }), (highlightedSize || Object.keys(fontSizeColors).length > 0) && (_jsx(Button, { variant: BUTTON_VARIANT.GHOST, onClick: clearHighlights, style: { padding: '0 var(--gap-xs)', height: 'auto' }, children: _jsx(Text, { className: "dndev-text-xs", children: "Clear All" }) }))] }), _jsx(Stack, { gap: "tight", className: "dndev-mt-xs", children: typography.fontSizes.map((f, i) => {
380
+ const isOrphan = f.count < 5;
381
+ const isHighlighted = highlightedSize === f.size;
382
+ const currentColor = fontSizeColors[f.size] || '';
383
+ const findOrphanElements = () => {
384
+ const normalizedSize = normalizeFontSize(f.size);
385
+ const found = Array.from(document.querySelectorAll('*')).filter((el) => {
386
+ if (el.closest('[data-dndev-devtools]') ||
387
+ el.closest('[data-radix-portal]') ||
388
+ el.closest('[role="dialog"]'))
389
+ return false;
390
+ const style = getComputedStyle(el);
391
+ const hasText = el.textContent && el.textContent.trim().length > 0;
392
+ if (!hasText || el.children.length > 0)
393
+ return false;
394
+ return normalizeFontSize(style.fontSize) === normalizedSize;
395
+ });
396
+ found.forEach((el) => {
397
+ console.log(el, el.textContent?.trim().substring(0, 50));
398
+ el.style.outline = '2px solid red';
399
+ });
400
+ console.log(`Found ${found.length} elements with ${f.size}`);
401
+ };
402
+ return (_jsxs(Stack, { direction: "row", justify: "between", align: "center", gap: "tight", style: {
403
+ padding: 'var(--gap-xs)',
404
+ borderRadius: 'var(--radius-sm)',
405
+ backgroundColor: isHighlighted
406
+ ? 'var(--primary)'
407
+ : 'transparent',
408
+ color: isHighlighted
409
+ ? 'var(--primary-foreground)'
410
+ : 'inherit',
411
+ }, children: [_jsxs(Stack, { direction: "row", align: "center", gap: "tight", onClick: () => toggleHighlight(f.size), style: { cursor: 'pointer', flex: 1 }, children: [_jsx(Text, { className: "dndev-font-mono dndev-text-xs", children: f.size }), isOrphan && (_jsx(Badge, { variant: BADGE_VARIANT.DESTRUCTIVE, children: "orphan" }))] }), isOrphan ? (_jsx(Button, { variant: BUTTON_VARIANT.GHOST, onClick: (e) => {
412
+ e.stopPropagation();
413
+ findOrphanElements();
414
+ }, style: {
415
+ padding: '0 var(--gap-xs)',
416
+ height: '1.5rem',
417
+ minWidth: '2rem',
418
+ }, title: `Find ${f.size} elements in console`, children: _jsx(Text, { className: "dndev-text-xs", children: "\uD83D\uDD0D" }) })) : (_jsx("input", { type: "color", value: currentColor || '#000000', onChange: (e) => applyFontSizeColor(f.size, e.target.value), onClick: (e) => e.stopPropagation(), style: {
419
+ width: '2rem',
420
+ height: '1.5rem',
421
+ border: '1px solid var(--border)',
422
+ borderRadius: 'var(--radius-sm)',
423
+ cursor: 'pointer',
424
+ padding: 0,
425
+ }, title: `Color elements with ${f.size}` })), _jsxs(Text, { className: "dndev-text-xs", style: {
426
+ opacity: isHighlighted ? 1 : 0.6,
427
+ minWidth: '2rem',
428
+ textAlign: 'end',
429
+ }, children: [f.count, "\u00D7"] })] }, i));
430
+ }) })] })), !colorRatio && !typography && (_jsx(Alert, { variant: ALERT_VARIANT.INFO, children: "Click \"Analyze Page\" to check color ratio and typography" }))] }));
431
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"StoresTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/StoresTab.tsx"],"names":[],"mappings":"AAiCA,eAAO,MAAM,SAAS,+CA8NrB,CAAC"}
1
+ {"version":3,"file":"StoresTab.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/StoresTab.tsx"],"names":[],"mappings":"AAwCA,eAAO,MAAM,SAAS,+CAoHrB,CAAC"}
@@ -2,120 +2,72 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  // packages/ui/src/internal/devtools/components/StoresTab.tsx
4
4
  /**
5
-
6
5
  * @fileoverview Stores Tab Component
7
-
8
- * @description Displays all registered Zustand stores from globalThis._DNDEV_STORES_
9
-
6
+ * @description Displays registered Zustand stores from globalThis._DNDEV_STORES_
10
7
  *
11
-
12
- * @version 0.0.1
13
-
8
+ * @version 0.0.2
14
9
  * @since 0.0.1
15
-
16
10
  * @author AMBROISE PARK Consulting
17
-
18
11
  */
19
- import { useState, useEffect } from 'react';
20
- import { Stack, Card, Accordion, ScrollArea, JsonViewer, CopyToClipboard, Text, Alert, ALERT_VARIANT, } from '@donotdev/components';
12
+ import { useState, useEffect, useCallback } from 'react';
13
+ import { Stack, Card, Accordion, ScrollArea, JsonViewer, Text, Badge, BADGE_VARIANT, Button, BUTTON_VARIANT, } from '@donotdev/components';
14
+ import { RefreshCw } from 'lucide-react';
15
+ const STORE_NAMES = {
16
+ 'theme-store': 'Theme',
17
+ 'consent-store': 'Consent',
18
+ 'navigation-store': 'Navigation',
19
+ 'loading-store': 'Loading',
20
+ 'overlay-store': 'Overlay',
21
+ 'network-store': 'Network',
22
+ 'abort-store': 'Abort',
23
+ 'i18n-store': 'i18n',
24
+ 'error-store': 'Error',
25
+ };
21
26
  export const StoresTab = () => {
22
- const [stores, setStores] = useState(() => {
23
- if (typeof globalThis !== 'undefined' &&
24
- globalThis._DNDEV_STORES_) {
25
- const currentStores = globalThis._DNDEV_STORES_;
26
- return Object.keys(currentStores).reduce((acc, key) => {
27
- acc[key] = currentStores[key];
28
- return acc;
29
- }, {});
27
+ const [storeStates, setStoreStates] = useState({});
28
+ const [storeNames, setStoreNames] = useState([]);
29
+ const refreshStores = useCallback(() => {
30
+ const registry = globalThis._DNDEV_STORES_;
31
+ if (!registry) {
32
+ setStoreNames([]);
33
+ setStoreStates({});
34
+ return;
30
35
  }
31
- return {};
32
- });
33
- useEffect(() => {
34
- const updateStores = () => {
35
- if (typeof globalThis !== 'undefined' &&
36
- globalThis._DNDEV_STORES_) {
37
- const currentStores = globalThis._DNDEV_STORES_;
38
- const storeKeys = Object.keys(currentStores);
39
- setStores((prev) => {
40
- const prevKeys = Object.keys(prev);
41
- if (prevKeys.length !== storeKeys.length) {
42
- const newStores = {};
43
- storeKeys.forEach((key) => {
44
- newStores[key] = currentStores[key];
45
- });
46
- return newStores;
47
- }
48
- const hasChanged = storeKeys.some((key) => !prev[key] || prev[key] !== currentStores[key]);
49
- if (hasChanged) {
50
- const newStores = {};
51
- storeKeys.forEach((key) => {
52
- newStores[key] = currentStores[key];
53
- });
54
- return newStores;
55
- }
56
- return prev;
57
- });
36
+ const names = Object.keys(registry);
37
+ setStoreNames(names);
38
+ const states = {};
39
+ names.forEach((name) => {
40
+ try {
41
+ const store = registry[name];
42
+ if (store?.getState) {
43
+ states[name] = store.getState();
44
+ }
45
+ else {
46
+ states[name] = { _error: 'No getState method' };
47
+ }
58
48
  }
59
- else {
60
- setStores({});
49
+ catch (e) {
50
+ states[name] = { _error: String(e) };
61
51
  }
62
- };
63
- updateStores();
64
- const interval = setInterval(updateStores, 500);
65
- return () => clearInterval(interval);
52
+ });
53
+ setStoreStates(states);
66
54
  }, []);
67
- const getStoreDisplayName = (storeName) => {
68
- const nameMap = {
69
- 'theme-store': 'Theme Store',
70
- 'consent-store': 'Consent Store',
71
- 'navigation-store': 'Navigation Store',
72
- loading: 'Loading Store',
73
- overlay: 'Overlay Store',
74
- network: 'Network Store',
75
- abort: 'Abort Controller Store',
76
- 'i18n-store': 'i18n Store',
77
- 'error-store': 'Error Store',
78
- 'dndev-theme-store': 'Theme Store (Legacy)',
79
- };
80
- return (nameMap[storeName] ||
81
- storeName
82
- .replace(/-store$/, ' Store')
83
- .replace(/-/g, ' ')
84
- .replace(/\b\w/g, (l) => l.toUpperCase()));
85
- };
86
- const getStoreState = (store) => {
87
- try {
88
- if (store && typeof store.getState === 'function') {
89
- return store.getState();
90
- }
91
- return null;
92
- }
93
- catch (error) {
94
- return {
95
- error: error instanceof Error ? error.message : 'Unknown error',
96
- };
97
- }
98
- };
99
- const formatJSON = (data) => {
100
- try {
101
- return JSON.stringify(data, null, 2);
102
- }
103
- catch (error) {
104
- return 'Error formatting data';
105
- }
106
- };
107
- const storeEntries = Object.entries(stores);
108
- if (storeEntries.length === 0) {
109
- return (_jsx(Stack, { gap: "medium", children: _jsx(Alert, { variant: ALERT_VARIANT.WARNING, children: _jsx(Text, { as: "span", children: "No stores registered in globalThis._DNDEV_STORES_" }) }) }));
55
+ useEffect(() => {
56
+ refreshStores();
57
+ const interval = setInterval(refreshStores, 1000);
58
+ return () => clearInterval(interval);
59
+ }, [refreshStores]);
60
+ const getDisplayName = (name) => STORE_NAMES[name] || name.replace(/-store$/, '').replace(/-/g, ' ');
61
+ if (storeNames.length === 0) {
62
+ return (_jsx(Stack, { gap: "medium", style: { padding: 'var(--gap-md)' }, children: _jsx(Card, { title: "Stores", subtitle: "No stores registered", children: _jsx(Text, { className: "dndev-text-muted-foreground", children: "globalThis._DNDEV_STORES_ is empty or not initialized." }) }) }));
110
63
  }
111
- return (_jsx(Stack, { gap: "medium", children: _jsx(Card, { title: "Stores", subtitle: `${storeEntries.length} store${storeEntries.length !== 1 ? 's' : ''} registered`, children: _jsx(Accordion, { items: storeEntries.map(([storeName, store]) => {
112
- const state = getStoreState(store);
113
- const hasError = state && 'error' in state;
114
- const displayName = getStoreDisplayName(storeName);
64
+ return (_jsx(Stack, { gap: "medium", style: { padding: 'var(--gap-md)' }, children: _jsx(Card, { title: _jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx("span", { children: "Stores" }), _jsxs(Stack, { direction: "row", align: "center", gap: "tight", children: [_jsx(Badge, { variant: BADGE_VARIANT.SECONDARY, children: storeNames.length }), _jsx(Button, { variant: BUTTON_VARIANT.GHOST, icon: RefreshCw, onClick: refreshStores, title: "Refresh stores" })] })] }), children: _jsx(Accordion, { type: "single", collapsible: true, items: storeNames.map((name) => {
65
+ const state = storeStates[name];
66
+ const hasError = state?._error;
115
67
  return {
116
- value: storeName,
117
- trigger: (_jsxs(Stack, { direction: "row", gap: "tight", align: "center", justify: "between", children: [_jsx(Text, { as: "span", children: displayName }), _jsxs(Text, { as: "span", className: "dndev-text-xs dndev-text-muted-foreground dndev-font-mono", children: ["(", storeName, ")"] })] })),
118
- content: (_jsx(Stack, { gap: "medium", children: hasError ? (_jsx(Alert, { variant: ALERT_VARIANT.ERROR, children: _jsxs(Text, { as: "span", children: ["Failed to get state: ", state.error] }) })) : state === null ? (_jsx(Alert, { variant: ALERT_VARIANT.WARNING, children: _jsx(Text, { as: "span", children: "Store does not have getState() method or is not initialized" }) })) : (_jsx(Card, { title: "Store State", subtitle: "Current state from getState()", footer: _jsx(Stack, { direction: "row", gap: "tight", justify: "end", children: _jsx(CopyToClipboard, { text: formatJSON(state), tooltipText: "Copy store state", copiedTooltipText: "Copied!" }) }), children: _jsx(ScrollArea, { className: "dndev-max-h-96", children: _jsx(JsonViewer, { data: state, defaultDepth: 2, showCopyButton: true }) }) })) })),
68
+ value: name,
69
+ trigger: (_jsxs(Stack, { direction: "row", align: "center", justify: "between", className: "dndev-w-full", children: [_jsx(Text, { className: "dndev-font-medium", children: getDisplayName(name) }), _jsx(Text, { className: "dndev-font-mono dndev-text-xs dndev-text-muted-foreground", children: name })] })),
70
+ content: hasError ? (_jsx(Text, { className: "dndev-text-destructive dndev-text-sm", children: state._error })) : (_jsx(ScrollArea, { className: "dndev-max-h-64", children: _jsx(JsonViewer, { data: state, defaultDepth: 2, showCopyButton: true }) })),
119
71
  };
120
72
  }) }) }) }));
121
73
  };
@@ -6,16 +6,11 @@
6
6
  * @since 0.0.1
7
7
  * @author AMBROISE PARK Consulting
8
8
  */
9
- export * from './AuthTab';
10
9
  export * from './ConfigTab';
11
10
  export * from './CookieTab';
12
11
  export * from './DebugDialog';
13
- export * from './DebugToggle';
14
- export * from './EnvironmentTab';
15
- export * from './I18nTab';
16
12
  export * from './LayoutReset';
17
13
  export * from './MaskedValue';
18
14
  export * from './StoresTab';
19
- export * from './StripeDebugTab';
20
- export * from './ThemesTab';
15
+ export * from './DesignTab';
21
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/internal/devtools/components/index.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
@@ -7,15 +7,10 @@
7
7
  * @since 0.0.1
8
8
  * @author AMBROISE PARK Consulting
9
9
  */
10
- export * from './AuthTab';
11
10
  export * from './ConfigTab';
12
11
  export * from './CookieTab';
13
12
  export * from './DebugDialog';
14
- export * from './DebugToggle';
15
- export * from './EnvironmentTab';
16
- export * from './I18nTab';
17
13
  export * from './LayoutReset';
18
14
  export * from './MaskedValue';
19
15
  export * from './StoresTab';
20
- export * from './StripeDebugTab';
21
- export * from './ThemesTab';
16
+ export * from './DesignTab';