@getmicdrop/svelte-components 5.0.0 → 5.1.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.
- package/dist/primitives/Button/Button.stories.svelte +46 -79
- package/dist/primitives/Button/Button.stories.svelte.d.ts.map +1 -1
- package/dist/primitives/Button/Button.svelte +11 -5
- package/dist/primitives/Button/Button.svelte.d.ts +2 -0
- package/dist/primitives/Button/Button.svelte.d.ts.map +1 -1
- package/dist/primitives/Button/ButtonVariantShowcase.svelte +137 -0
- package/dist/primitives/Button/ButtonVariantShowcase.svelte.d.ts +27 -0
- package/dist/primitives/Button/ButtonVariantShowcase.svelte.d.ts.map +1 -0
- package/dist/recipes/SuperLogin/SuperLogin.svelte +5 -5
- package/dist/stories/ButtonAuditDashboard.stories.svelte +14 -0
- package/dist/stories/ButtonAuditDashboard.stories.svelte.d.ts +28 -0
- package/dist/stories/ButtonAuditDashboard.stories.svelte.d.ts.map +1 -0
- package/dist/stories/ButtonAuditDashboard.svelte +444 -0
- package/dist/stories/ButtonAuditDashboard.svelte.d.ts +7 -0
- package/dist/stories/ButtonAuditDashboard.svelte.d.ts.map +1 -0
- package/dist/stories/ButtonAuditReview.stories.svelte +14 -0
- package/dist/stories/ButtonAuditReview.stories.svelte.d.ts +28 -0
- package/dist/stories/ButtonAuditReview.stories.svelte.d.ts.map +1 -0
- package/dist/stories/ButtonAuditReview.svelte +463 -0
- package/dist/stories/ButtonAuditReview.svelte.d.ts +7 -0
- package/dist/stories/ButtonAuditReview.svelte.d.ts.map +1 -0
- package/dist/stories/ButtonGridView.stories.svelte +14 -0
- package/dist/stories/ButtonGridView.stories.svelte.d.ts +28 -0
- package/dist/stories/ButtonGridView.stories.svelte.d.ts.map +1 -0
- package/dist/stories/ButtonGridView.svelte +146 -0
- package/dist/stories/ButtonGridView.svelte.d.ts +7 -0
- package/dist/stories/ButtonGridView.svelte.d.ts.map +1 -0
- package/dist/stories/ButtonShowcase.stories.svelte +14 -0
- package/dist/stories/ButtonShowcase.stories.svelte.d.ts +28 -0
- package/dist/stories/ButtonShowcase.stories.svelte.d.ts.map +1 -0
- package/dist/stories/ButtonShowcase.svelte +529 -0
- package/dist/stories/ButtonShowcase.svelte.d.ts +7 -0
- package/dist/stories/ButtonShowcase.svelte.d.ts.map +1 -0
- package/dist/stories/DesignSystemAudit.stories.svelte +4 -12
- package/dist/stories/DesignSystemAudit.stories.svelte.d.ts.map +1 -1
- package/dist/stories/button-audit-manifest.json +11187 -0
- package/package.json +5 -2
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Button from '../primitives/Button/Button.svelte';
|
|
3
|
+
|
|
4
|
+
// Issue severity levels
|
|
5
|
+
const SEVERITY = {
|
|
6
|
+
HIGH: 'high',
|
|
7
|
+
MEDIUM: 'medium',
|
|
8
|
+
LOW: 'low'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// All identified issues
|
|
12
|
+
const issues = [
|
|
13
|
+
// HIGH SEVERITY - Invalid variants that won't render correctly
|
|
14
|
+
{
|
|
15
|
+
id: 1,
|
|
16
|
+
severity: SEVERITY.HIGH,
|
|
17
|
+
category: 'Invalid Variant',
|
|
18
|
+
problem: 'Variant "secondary" is not recognized',
|
|
19
|
+
location: 'CustomDropzone.svelte, widgets/+page.svelte',
|
|
20
|
+
count: 4,
|
|
21
|
+
current: { variant: 'secondary', text: 'Browse files' },
|
|
22
|
+
proposed: { variant: 'alternative', text: 'Browse files' },
|
|
23
|
+
explanation: '"secondary" should map to "alternative" (gray outline style)'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
id: 2,
|
|
27
|
+
severity: SEVERITY.HIGH,
|
|
28
|
+
category: 'Invalid Variant',
|
|
29
|
+
problem: 'Variant "danger" is not recognized',
|
|
30
|
+
location: 'widgets/+page.svelte:309',
|
|
31
|
+
count: 1,
|
|
32
|
+
current: { variant: 'danger', text: 'Delete' },
|
|
33
|
+
proposed: { variant: 'red', text: 'Delete' },
|
|
34
|
+
explanation: '"danger" should be "red" for destructive actions'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 3,
|
|
38
|
+
severity: SEVERITY.HIGH,
|
|
39
|
+
category: 'Invalid Variant',
|
|
40
|
+
problem: 'Variant "text" is not recognized',
|
|
41
|
+
location: 'PromocodeInput.svelte:169',
|
|
42
|
+
count: 1,
|
|
43
|
+
current: { variant: 'text', text: 'Apply' },
|
|
44
|
+
proposed: { variant: 'ghost', text: 'Apply' },
|
|
45
|
+
explanation: '"text" should be "ghost" for text-only buttons'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 4,
|
|
49
|
+
severity: SEVERITY.HIGH,
|
|
50
|
+
category: 'Invalid Variant',
|
|
51
|
+
problem: 'Variant "blue-text" is not recognized',
|
|
52
|
+
location: 'csv-import/results, team/edit-user',
|
|
53
|
+
count: 5,
|
|
54
|
+
current: { variant: 'blue-text', text: 'Add more events' },
|
|
55
|
+
proposed: { variant: 'link', text: 'Add more events' },
|
|
56
|
+
explanation: '"blue-text" should be "link" for link-styled buttons'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 5,
|
|
60
|
+
severity: SEVERITY.HIGH,
|
|
61
|
+
category: 'Invalid Variant',
|
|
62
|
+
problem: 'Variant "gray-solid" is not recognized',
|
|
63
|
+
location: 'payments/+page.svelte',
|
|
64
|
+
count: 2,
|
|
65
|
+
current: { variant: 'gray-solid', text: 'Set Default' },
|
|
66
|
+
proposed: { variant: 'alternative', text: 'Set Default' },
|
|
67
|
+
explanation: '"gray-solid" doesn\'t exist - use "alternative" for gray buttons'
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 6,
|
|
71
|
+
severity: SEVERITY.HIGH,
|
|
72
|
+
category: 'Invalid Variant',
|
|
73
|
+
problem: 'Variant "gray" is not recognized',
|
|
74
|
+
location: 'invite/accept/+page.svelte:64',
|
|
75
|
+
count: 1,
|
|
76
|
+
current: { variant: 'gray', text: 'Try Again' },
|
|
77
|
+
proposed: { variant: 'alternative', text: 'Try Again' },
|
|
78
|
+
explanation: '"gray" should be "alternative"'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 7,
|
|
82
|
+
severity: SEVERITY.HIGH,
|
|
83
|
+
category: 'Invalid Variant',
|
|
84
|
+
problem: 'Variant "custom" is not recognized',
|
|
85
|
+
location: 'ProfilePictureSection.svelte:109',
|
|
86
|
+
count: 1,
|
|
87
|
+
current: { variant: 'custom', text: '(icon only)' },
|
|
88
|
+
proposed: { variant: 'icon', text: '' },
|
|
89
|
+
explanation: '"custom" for icon buttons should be "icon" variant'
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 8,
|
|
93
|
+
severity: SEVERITY.HIGH,
|
|
94
|
+
category: 'Invalid Variant',
|
|
95
|
+
problem: 'Variant "green-solid" is not recognized',
|
|
96
|
+
location: 'Unknown location',
|
|
97
|
+
count: 1,
|
|
98
|
+
current: { variant: 'green-solid', text: 'Success' },
|
|
99
|
+
proposed: { variant: 'default', text: 'Success', success: true },
|
|
100
|
+
explanation: 'Green success buttons should use success prop, not variant'
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
// MEDIUM SEVERITY - Invalid sizes
|
|
104
|
+
// NOTE: full-md-auto and half are now VALID standard sizes
|
|
105
|
+
// {
|
|
106
|
+
// id: 9,
|
|
107
|
+
// severity: SEVERITY.MEDIUM,
|
|
108
|
+
// category: 'RESOLVED',
|
|
109
|
+
// problem: 'Size "full-md-auto" - NOW A STANDARD SIZE',
|
|
110
|
+
// explanation: 'Added to Button component: full width mobile, auto width md+'
|
|
111
|
+
// },
|
|
112
|
+
// {
|
|
113
|
+
// id: 10,
|
|
114
|
+
// severity: SEVERITY.MEDIUM,
|
|
115
|
+
// category: 'RESOLVED',
|
|
116
|
+
// problem: 'Size "half" - NOW A STANDARD SIZE',
|
|
117
|
+
// explanation: 'Added to Button component: 50% width with medium text'
|
|
118
|
+
// },
|
|
119
|
+
{
|
|
120
|
+
id: 11,
|
|
121
|
+
severity: SEVERITY.MEDIUM,
|
|
122
|
+
category: 'Invalid Size',
|
|
123
|
+
problem: 'Size "small" should be "sm"',
|
|
124
|
+
location: 'Various files',
|
|
125
|
+
count: 3,
|
|
126
|
+
current: { variant: 'blue-solid', size: 'small', text: 'Submit' },
|
|
127
|
+
proposed: { variant: 'default', size: 'sm', text: 'Submit' },
|
|
128
|
+
explanation: 'Standard size name is "sm", not "small"'
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
// LOW SEVERITY - Style consistency
|
|
132
|
+
{
|
|
133
|
+
id: 12,
|
|
134
|
+
severity: SEVERITY.LOW,
|
|
135
|
+
category: 'Legacy Naming',
|
|
136
|
+
problem: '801 buttons use legacy variant names',
|
|
137
|
+
location: 'Throughout codebase',
|
|
138
|
+
count: 801,
|
|
139
|
+
current: { variant: 'blue-solid', text: 'Save' },
|
|
140
|
+
proposed: { variant: 'default', text: 'Save' },
|
|
141
|
+
explanation: 'Consider migrating to Flowbite naming: blue-solid → default'
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: 13,
|
|
145
|
+
severity: SEVERITY.LOW,
|
|
146
|
+
category: 'Legacy Naming',
|
|
147
|
+
problem: 'gray-outline should be alternative',
|
|
148
|
+
location: 'Throughout codebase',
|
|
149
|
+
count: 128,
|
|
150
|
+
current: { variant: 'gray-outline', text: 'Cancel' },
|
|
151
|
+
proposed: { variant: 'alternative', text: 'Cancel' },
|
|
152
|
+
explanation: 'Flowbite naming: gray-outline → alternative'
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
id: 14,
|
|
156
|
+
severity: SEVERITY.LOW,
|
|
157
|
+
category: 'Empty Text',
|
|
158
|
+
problem: 'Non-icon buttons with no visible text',
|
|
159
|
+
location: 'Various components',
|
|
160
|
+
count: 191,
|
|
161
|
+
current: { variant: 'blue-solid', text: '' },
|
|
162
|
+
proposed: { variant: 'icon', text: '' },
|
|
163
|
+
explanation: 'Buttons with only icons should use variant="icon"'
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// Group by severity
|
|
168
|
+
const highSeverity = issues.filter(i => i.severity === SEVERITY.HIGH);
|
|
169
|
+
const mediumSeverity = issues.filter(i => i.severity === SEVERITY.MEDIUM);
|
|
170
|
+
const lowSeverity = issues.filter(i => i.severity === SEVERITY.LOW);
|
|
171
|
+
|
|
172
|
+
// Approval state
|
|
173
|
+
let approvals = $state({});
|
|
174
|
+
|
|
175
|
+
function approve(id) {
|
|
176
|
+
approvals[id] = 'approved';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function reject(id) {
|
|
180
|
+
approvals[id] = 'rejected';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function getStatusClass(id) {
|
|
184
|
+
if (approvals[id] === 'approved') return 'bg-green-100 border-green-500';
|
|
185
|
+
if (approvals[id] === 'rejected') return 'bg-red-100 border-red-500';
|
|
186
|
+
return 'bg-white border-gray-200';
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function getSeverityColor(severity) {
|
|
190
|
+
if (severity === SEVERITY.HIGH) return 'bg-red-100 text-red-800';
|
|
191
|
+
if (severity === SEVERITY.MEDIUM) return 'bg-yellow-100 text-yellow-800';
|
|
192
|
+
return 'bg-blue-100 text-blue-800';
|
|
193
|
+
}
|
|
194
|
+
</script>
|
|
195
|
+
|
|
196
|
+
<div class="p-6 max-w-7xl mx-auto space-y-8">
|
|
197
|
+
<div class="text-center mb-8">
|
|
198
|
+
<h1 class="text-3xl font-bold text-gray-900 mb-2">Button Audit Review</h1>
|
|
199
|
+
<p class="text-gray-600">Review identified issues and approve/reject proposed fixes</p>
|
|
200
|
+
<div class="flex justify-center gap-4 mt-4 text-sm">
|
|
201
|
+
<span class="px-3 py-1 rounded-full bg-red-100 text-red-800">High: {highSeverity.length} issues</span>
|
|
202
|
+
<span class="px-3 py-1 rounded-full bg-yellow-100 text-yellow-800">Medium: {mediumSeverity.length} issues</span>
|
|
203
|
+
<span class="px-3 py-1 rounded-full bg-blue-100 text-blue-800">Low: {lowSeverity.length} issues</span>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<!-- HIGH SEVERITY -->
|
|
208
|
+
<section>
|
|
209
|
+
<h2 class="text-xl font-bold text-red-700 mb-4 flex items-center gap-2">
|
|
210
|
+
<span class="w-3 h-3 rounded-full bg-red-500"></span>
|
|
211
|
+
High Severity - Invalid Variants ({highSeverity.length})
|
|
212
|
+
</h2>
|
|
213
|
+
<p class="text-gray-600 mb-4">These buttons use variant names that don't exist and may not render correctly.</p>
|
|
214
|
+
|
|
215
|
+
<div class="space-y-4">
|
|
216
|
+
{#each highSeverity as issue}
|
|
217
|
+
<div class="border-2 rounded-lg p-4 {getStatusClass(issue.id)}">
|
|
218
|
+
<div class="flex justify-between items-start mb-4">
|
|
219
|
+
<div>
|
|
220
|
+
<span class="text-xs font-medium px-2 py-1 rounded {getSeverityColor(issue.severity)}">
|
|
221
|
+
{issue.category}
|
|
222
|
+
</span>
|
|
223
|
+
<span class="text-xs text-gray-500 ml-2">{issue.count} occurrence{issue.count > 1 ? 's' : ''}</span>
|
|
224
|
+
</div>
|
|
225
|
+
<div class="flex gap-2">
|
|
226
|
+
<button
|
|
227
|
+
onclick={() => approve(issue.id)}
|
|
228
|
+
class="px-3 py-1 text-sm rounded bg-green-600 text-white hover:bg-green-700"
|
|
229
|
+
>
|
|
230
|
+
Approve
|
|
231
|
+
</button>
|
|
232
|
+
<button
|
|
233
|
+
onclick={() => reject(issue.id)}
|
|
234
|
+
class="px-3 py-1 text-sm rounded bg-red-600 text-white hover:bg-red-700"
|
|
235
|
+
>
|
|
236
|
+
Reject
|
|
237
|
+
</button>
|
|
238
|
+
</div>
|
|
239
|
+
</div>
|
|
240
|
+
|
|
241
|
+
<h3 class="font-semibold text-gray-900 mb-2">{issue.problem}</h3>
|
|
242
|
+
<p class="text-sm text-gray-500 mb-4">Location: {issue.location}</p>
|
|
243
|
+
|
|
244
|
+
<div class="grid grid-cols-2 gap-6">
|
|
245
|
+
<!-- Current State -->
|
|
246
|
+
<div class="space-y-2">
|
|
247
|
+
<div class="text-sm font-medium text-red-600">Current (Problem)</div>
|
|
248
|
+
<div class="p-4 bg-gray-50 rounded-lg flex items-center justify-center min-h-[60px]">
|
|
249
|
+
<Button
|
|
250
|
+
variant={issue.current.variant}
|
|
251
|
+
size={issue.current.size || 'md'}
|
|
252
|
+
>
|
|
253
|
+
{issue.current.text || '(no text)'}
|
|
254
|
+
</Button>
|
|
255
|
+
</div>
|
|
256
|
+
<code class="text-xs bg-gray-100 px-2 py-1 rounded block">
|
|
257
|
+
variant="{issue.current.variant}"
|
|
258
|
+
</code>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<!-- Proposed Fix -->
|
|
262
|
+
<div class="space-y-2">
|
|
263
|
+
<div class="text-sm font-medium text-green-600">Proposed Fix</div>
|
|
264
|
+
<div class="p-4 bg-green-50 rounded-lg flex items-center justify-center min-h-[60px]">
|
|
265
|
+
<Button
|
|
266
|
+
variant={issue.proposed.variant}
|
|
267
|
+
size={issue.proposed.size || 'md'}
|
|
268
|
+
success={issue.proposed.success || false}
|
|
269
|
+
>
|
|
270
|
+
{issue.proposed.text || '(no text)'}
|
|
271
|
+
</Button>
|
|
272
|
+
</div>
|
|
273
|
+
<code class="text-xs bg-gray-100 px-2 py-1 rounded block">
|
|
274
|
+
variant="{issue.proposed.variant}"
|
|
275
|
+
</code>
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
<p class="mt-4 text-sm text-gray-700 bg-blue-50 p-3 rounded">
|
|
280
|
+
<strong>Explanation:</strong> {issue.explanation}
|
|
281
|
+
</p>
|
|
282
|
+
</div>
|
|
283
|
+
{/each}
|
|
284
|
+
</div>
|
|
285
|
+
</section>
|
|
286
|
+
|
|
287
|
+
<!-- MEDIUM SEVERITY -->
|
|
288
|
+
<section>
|
|
289
|
+
<h2 class="text-xl font-bold text-yellow-700 mb-4 flex items-center gap-2">
|
|
290
|
+
<span class="w-3 h-3 rounded-full bg-yellow-500"></span>
|
|
291
|
+
Medium Severity - Invalid Sizes ({mediumSeverity.length})
|
|
292
|
+
</h2>
|
|
293
|
+
<p class="text-gray-600 mb-4">These buttons use non-standard size values.</p>
|
|
294
|
+
|
|
295
|
+
<div class="space-y-4">
|
|
296
|
+
{#each mediumSeverity as issue}
|
|
297
|
+
<div class="border-2 rounded-lg p-4 {getStatusClass(issue.id)}">
|
|
298
|
+
<div class="flex justify-between items-start mb-4">
|
|
299
|
+
<div>
|
|
300
|
+
<span class="text-xs font-medium px-2 py-1 rounded {getSeverityColor(issue.severity)}">
|
|
301
|
+
{issue.category}
|
|
302
|
+
</span>
|
|
303
|
+
<span class="text-xs text-gray-500 ml-2">{issue.count} occurrence{issue.count > 1 ? 's' : ''}</span>
|
|
304
|
+
</div>
|
|
305
|
+
<div class="flex gap-2">
|
|
306
|
+
<button
|
|
307
|
+
onclick={() => approve(issue.id)}
|
|
308
|
+
class="px-3 py-1 text-sm rounded bg-green-600 text-white hover:bg-green-700"
|
|
309
|
+
>
|
|
310
|
+
Approve
|
|
311
|
+
</button>
|
|
312
|
+
<button
|
|
313
|
+
onclick={() => reject(issue.id)}
|
|
314
|
+
class="px-3 py-1 text-sm rounded bg-red-600 text-white hover:bg-red-700"
|
|
315
|
+
>
|
|
316
|
+
Reject
|
|
317
|
+
</button>
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
|
|
321
|
+
<h3 class="font-semibold text-gray-900 mb-2">{issue.problem}</h3>
|
|
322
|
+
<p class="text-sm text-gray-500 mb-4">Location: {issue.location}</p>
|
|
323
|
+
|
|
324
|
+
<div class="grid grid-cols-2 gap-6">
|
|
325
|
+
<div class="space-y-2">
|
|
326
|
+
<div class="text-sm font-medium text-red-600">Current (Problem)</div>
|
|
327
|
+
<div class="p-4 bg-gray-50 rounded-lg flex items-center justify-center min-h-[60px]">
|
|
328
|
+
<Button
|
|
329
|
+
variant={issue.current.variant}
|
|
330
|
+
size={issue.current.size || 'md'}
|
|
331
|
+
>
|
|
332
|
+
{issue.current.text}
|
|
333
|
+
</Button>
|
|
334
|
+
</div>
|
|
335
|
+
<code class="text-xs bg-gray-100 px-2 py-1 rounded block">
|
|
336
|
+
size="{issue.current.size}"
|
|
337
|
+
</code>
|
|
338
|
+
</div>
|
|
339
|
+
|
|
340
|
+
<div class="space-y-2">
|
|
341
|
+
<div class="text-sm font-medium text-green-600">Proposed Fix</div>
|
|
342
|
+
<div class="p-4 bg-green-50 rounded-lg flex items-center justify-center min-h-[60px]">
|
|
343
|
+
<Button
|
|
344
|
+
variant={issue.proposed.variant}
|
|
345
|
+
size={issue.proposed.size || 'md'}
|
|
346
|
+
class={issue.proposed.className || ''}
|
|
347
|
+
>
|
|
348
|
+
{issue.proposed.text}
|
|
349
|
+
</Button>
|
|
350
|
+
</div>
|
|
351
|
+
<code class="text-xs bg-gray-100 px-2 py-1 rounded block">
|
|
352
|
+
size="{issue.proposed.size}"{issue.proposed.className ? ` class="${issue.proposed.className}"` : ''}
|
|
353
|
+
</code>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
|
|
357
|
+
<p class="mt-4 text-sm text-gray-700 bg-blue-50 p-3 rounded">
|
|
358
|
+
<strong>Explanation:</strong> {issue.explanation}
|
|
359
|
+
</p>
|
|
360
|
+
</div>
|
|
361
|
+
{/each}
|
|
362
|
+
</div>
|
|
363
|
+
</section>
|
|
364
|
+
|
|
365
|
+
<!-- LOW SEVERITY -->
|
|
366
|
+
<section>
|
|
367
|
+
<h2 class="text-xl font-bold text-blue-700 mb-4 flex items-center gap-2">
|
|
368
|
+
<span class="w-3 h-3 rounded-full bg-blue-500"></span>
|
|
369
|
+
Low Severity - Style Consistency ({lowSeverity.length})
|
|
370
|
+
</h2>
|
|
371
|
+
<p class="text-gray-600 mb-4">These are style improvements for consistency, not functional issues.</p>
|
|
372
|
+
|
|
373
|
+
<div class="space-y-4">
|
|
374
|
+
{#each lowSeverity as issue}
|
|
375
|
+
<div class="border-2 rounded-lg p-4 {getStatusClass(issue.id)}">
|
|
376
|
+
<div class="flex justify-between items-start mb-4">
|
|
377
|
+
<div>
|
|
378
|
+
<span class="text-xs font-medium px-2 py-1 rounded {getSeverityColor(issue.severity)}">
|
|
379
|
+
{issue.category}
|
|
380
|
+
</span>
|
|
381
|
+
<span class="text-xs text-gray-500 ml-2">{issue.count} occurrence{issue.count > 1 ? 's' : ''}</span>
|
|
382
|
+
</div>
|
|
383
|
+
<div class="flex gap-2">
|
|
384
|
+
<button
|
|
385
|
+
onclick={() => approve(issue.id)}
|
|
386
|
+
class="px-3 py-1 text-sm rounded bg-green-600 text-white hover:bg-green-700"
|
|
387
|
+
>
|
|
388
|
+
Approve
|
|
389
|
+
</button>
|
|
390
|
+
<button
|
|
391
|
+
onclick={() => reject(issue.id)}
|
|
392
|
+
class="px-3 py-1 text-sm rounded bg-red-600 text-white hover:bg-red-700"
|
|
393
|
+
>
|
|
394
|
+
Reject
|
|
395
|
+
</button>
|
|
396
|
+
</div>
|
|
397
|
+
</div>
|
|
398
|
+
|
|
399
|
+
<h3 class="font-semibold text-gray-900 mb-2">{issue.problem}</h3>
|
|
400
|
+
<p class="text-sm text-gray-500 mb-4">Location: {issue.location}</p>
|
|
401
|
+
|
|
402
|
+
<div class="grid grid-cols-2 gap-6">
|
|
403
|
+
<div class="space-y-2">
|
|
404
|
+
<div class="text-sm font-medium text-gray-600">Current</div>
|
|
405
|
+
<div class="p-4 bg-gray-50 rounded-lg flex items-center justify-center min-h-[60px]">
|
|
406
|
+
<Button
|
|
407
|
+
variant={issue.current.variant}
|
|
408
|
+
size={issue.current.size || 'md'}
|
|
409
|
+
>
|
|
410
|
+
{issue.current.text || '(icon)'}
|
|
411
|
+
</Button>
|
|
412
|
+
</div>
|
|
413
|
+
<code class="text-xs bg-gray-100 px-2 py-1 rounded block">
|
|
414
|
+
variant="{issue.current.variant}"
|
|
415
|
+
</code>
|
|
416
|
+
</div>
|
|
417
|
+
|
|
418
|
+
<div class="space-y-2">
|
|
419
|
+
<div class="text-sm font-medium text-green-600">Flowbite Standard</div>
|
|
420
|
+
<div class="p-4 bg-green-50 rounded-lg flex items-center justify-center min-h-[60px]">
|
|
421
|
+
<Button
|
|
422
|
+
variant={issue.proposed.variant}
|
|
423
|
+
size={issue.proposed.size || 'md'}
|
|
424
|
+
>
|
|
425
|
+
{issue.proposed.text || '(icon)'}
|
|
426
|
+
</Button>
|
|
427
|
+
</div>
|
|
428
|
+
<code class="text-xs bg-gray-100 px-2 py-1 rounded block">
|
|
429
|
+
variant="{issue.proposed.variant}"
|
|
430
|
+
</code>
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
433
|
+
|
|
434
|
+
<p class="mt-4 text-sm text-gray-700 bg-blue-50 p-3 rounded">
|
|
435
|
+
<strong>Explanation:</strong> {issue.explanation}
|
|
436
|
+
</p>
|
|
437
|
+
</div>
|
|
438
|
+
{/each}
|
|
439
|
+
</div>
|
|
440
|
+
</section>
|
|
441
|
+
|
|
442
|
+
<!-- Summary -->
|
|
443
|
+
<section class="mt-8 p-6 bg-gray-100 rounded-lg">
|
|
444
|
+
<h2 class="text-xl font-bold mb-4">Summary</h2>
|
|
445
|
+
<div class="grid grid-cols-3 gap-4 text-center">
|
|
446
|
+
<div class="p-4 bg-white rounded-lg">
|
|
447
|
+
<div class="text-3xl font-bold text-red-600">{highSeverity.reduce((sum, i) => sum + i.count, 0)}</div>
|
|
448
|
+
<div class="text-sm text-gray-600">High Severity Buttons</div>
|
|
449
|
+
</div>
|
|
450
|
+
<div class="p-4 bg-white rounded-lg">
|
|
451
|
+
<div class="text-3xl font-bold text-yellow-600">{mediumSeverity.reduce((sum, i) => sum + i.count, 0)}</div>
|
|
452
|
+
<div class="text-sm text-gray-600">Medium Severity Buttons</div>
|
|
453
|
+
</div>
|
|
454
|
+
<div class="p-4 bg-white rounded-lg">
|
|
455
|
+
<div class="text-3xl font-bold text-blue-600">{lowSeverity.reduce((sum, i) => sum + i.count, 0)}</div>
|
|
456
|
+
<div class="text-sm text-gray-600">Low Severity Buttons</div>
|
|
457
|
+
</div>
|
|
458
|
+
</div>
|
|
459
|
+
<p class="mt-4 text-sm text-gray-600">
|
|
460
|
+
Total buttons audited: 916 | Issues found: {issues.length} categories affecting {issues.reduce((sum, i) => sum + i.count, 0)} buttons
|
|
461
|
+
</p>
|
|
462
|
+
</section>
|
|
463
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export default ButtonAuditReview;
|
|
2
|
+
type ButtonAuditReview = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<Record<string, never>>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const ButtonAuditReview: import("svelte").Component<Record<string, never>, {}, "">;
|
|
7
|
+
//# sourceMappingURL=ButtonAuditReview.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonAuditReview.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/stories/ButtonAuditReview.svelte.js"],"names":[],"mappings":";;;;;AAibA,2FAAgE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from "@storybook/addon-svelte-csf";
|
|
3
|
+
import ButtonGridView from "./ButtonGridView.svelte";
|
|
4
|
+
|
|
5
|
+
const { Story } = defineMeta({
|
|
6
|
+
title: "Design System/Button Grid View",
|
|
7
|
+
component: ButtonGridView,
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: 'fullscreen',
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Story name="All Buttons" />
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export default ButtonGridView;
|
|
2
|
+
type ButtonGridView = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const ButtonGridView: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
14
|
+
import ButtonGridView from "./ButtonGridView.svelte";
|
|
15
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
16
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
17
|
+
$$bindings?: Bindings;
|
|
18
|
+
} & Exports;
|
|
19
|
+
(internal: unknown, props: {
|
|
20
|
+
$$events?: Events;
|
|
21
|
+
$$slots?: Slots;
|
|
22
|
+
}): Exports & {
|
|
23
|
+
$set?: any;
|
|
24
|
+
$on?: any;
|
|
25
|
+
};
|
|
26
|
+
z_$$bindings?: Bindings;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=ButtonGridView.stories.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonGridView.stories.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/stories/ButtonGridView.stories.svelte.js"],"names":[],"mappings":";;;;;;;;AA4BA;;;;mBAA0H;2BAxB7F,yBAAyB;6CAeT,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,OAAO,OAAO,QAAQ;IAC3L,cAAc,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,WAAW,OAAO,SAAS;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Button from '../primitives/Button/Button.svelte';
|
|
3
|
+
import manifest from './button-audit-manifest.json';
|
|
4
|
+
|
|
5
|
+
// Flatten all buttons into a single array with source info
|
|
6
|
+
const allButtons = Object.entries(manifest.categories).flatMap(([category, routes]) =>
|
|
7
|
+
routes.flatMap(route =>
|
|
8
|
+
route.buttons.map(button => ({
|
|
9
|
+
...button,
|
|
10
|
+
category,
|
|
11
|
+
file: route.file,
|
|
12
|
+
fullPath: route.fullPath
|
|
13
|
+
}))
|
|
14
|
+
)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
// Dark mode
|
|
18
|
+
let isDark = $state(false);
|
|
19
|
+
function toggleDark() {
|
|
20
|
+
isDark = !isDark;
|
|
21
|
+
document.documentElement.classList.toggle('dark', isDark);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Filters
|
|
25
|
+
let variantFilter = $state('all');
|
|
26
|
+
let sizeFilter = $state('all');
|
|
27
|
+
let searchQuery = $state('');
|
|
28
|
+
|
|
29
|
+
const allVariants = [...new Set(allButtons.map(b => b.variant))].sort();
|
|
30
|
+
const allSizes = [...new Set(allButtons.map(b => b.size))].sort();
|
|
31
|
+
|
|
32
|
+
// Filtered buttons
|
|
33
|
+
let filtered = $derived.by(() => {
|
|
34
|
+
return allButtons.filter(b => {
|
|
35
|
+
if (variantFilter !== 'all' && b.variant !== variantFilter) return false;
|
|
36
|
+
if (sizeFilter !== 'all' && b.size !== sizeFilter) return false;
|
|
37
|
+
if (searchQuery) {
|
|
38
|
+
const q = searchQuery.toLowerCase();
|
|
39
|
+
return b.text.toLowerCase().includes(q) ||
|
|
40
|
+
b.file.toLowerCase().includes(q) ||
|
|
41
|
+
b.variant.toLowerCase().includes(q);
|
|
42
|
+
}
|
|
43
|
+
return true;
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Get short file name
|
|
48
|
+
function shortFile(file) {
|
|
49
|
+
const parts = file.split('/');
|
|
50
|
+
return parts.slice(-2).join('/');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// VS Code link
|
|
54
|
+
function vscodeLink(fullPath, line) {
|
|
55
|
+
return `vscode://file${fullPath}:${line}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Variant colors
|
|
59
|
+
function variantColor(variant) {
|
|
60
|
+
const colors = {
|
|
61
|
+
'blue-solid': 'bg-blue-100 text-blue-700',
|
|
62
|
+
'gray-outline': 'bg-gray-100 text-gray-700',
|
|
63
|
+
'blue-outline': 'bg-blue-50 text-blue-600',
|
|
64
|
+
'gray-text': 'bg-gray-50 text-gray-500',
|
|
65
|
+
'red-solid': 'bg-red-100 text-red-700',
|
|
66
|
+
'red-outline': 'bg-red-50 text-red-600',
|
|
67
|
+
'green-solid': 'bg-green-100 text-green-700',
|
|
68
|
+
'icon': 'bg-purple-100 text-purple-700',
|
|
69
|
+
'ghost': 'bg-yellow-100 text-yellow-700'
|
|
70
|
+
};
|
|
71
|
+
return colors[variant] || 'bg-gray-100 text-gray-700';
|
|
72
|
+
}
|
|
73
|
+
</script>
|
|
74
|
+
|
|
75
|
+
<div class="min-h-screen bg-gray-100 dark:bg-gray-900 p-4">
|
|
76
|
+
<!-- Header -->
|
|
77
|
+
<div class="sticky top-0 z-50 bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4 mb-4">
|
|
78
|
+
<div class="flex flex-wrap items-center justify-between gap-4">
|
|
79
|
+
<div>
|
|
80
|
+
<h1 class="text-xl font-bold text-gray-900 dark:text-white">Button Grid View</h1>
|
|
81
|
+
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
82
|
+
Showing {filtered.length} of {allButtons.length} buttons
|
|
83
|
+
</p>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
87
|
+
<input
|
|
88
|
+
type="text"
|
|
89
|
+
bind:value={searchQuery}
|
|
90
|
+
placeholder="Search..."
|
|
91
|
+
class="px-3 py-1.5 text-sm rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white w-40"
|
|
92
|
+
/>
|
|
93
|
+
|
|
94
|
+
<select bind:value={variantFilter} class="px-2 py-1.5 text-sm rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
95
|
+
<option value="all">All Variants</option>
|
|
96
|
+
{#each allVariants as v}<option value={v}>{v}</option>{/each}
|
|
97
|
+
</select>
|
|
98
|
+
|
|
99
|
+
<select bind:value={sizeFilter} class="px-2 py-1.5 text-sm rounded border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white">
|
|
100
|
+
<option value="all">All Sizes</option>
|
|
101
|
+
{#each allSizes as s}<option value={s}>{s}</option>{/each}
|
|
102
|
+
</select>
|
|
103
|
+
|
|
104
|
+
<button onclick={toggleDark} class="px-3 py-1.5 text-sm rounded {isDark ? 'bg-gray-800 text-white' : 'bg-yellow-500 text-black'}">
|
|
105
|
+
{isDark ? '🌙' : '☀️'}
|
|
106
|
+
</button>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<!-- Grid -->
|
|
112
|
+
<div class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-8 gap-3">
|
|
113
|
+
{#each filtered as button, i}
|
|
114
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg p-3 border border-gray-200 dark:border-gray-700 flex flex-col">
|
|
115
|
+
<!-- Button Preview -->
|
|
116
|
+
<div class="flex items-center justify-center p-3 bg-gray-50 dark:bg-gray-700 rounded mb-2 min-h-[50px]">
|
|
117
|
+
<Button
|
|
118
|
+
variant={button.variant}
|
|
119
|
+
size={button.size}
|
|
120
|
+
loading={button.loading}
|
|
121
|
+
disabled={button.disabled}
|
|
122
|
+
danger={button.danger}
|
|
123
|
+
deemphasized={button.deemphasized}
|
|
124
|
+
>
|
|
125
|
+
{button.text === '(no text)' ? '' : button.text.slice(0, 20)}{button.text.length > 20 ? '…' : ''}
|
|
126
|
+
</Button>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<!-- Metadata -->
|
|
130
|
+
<div class="text-xs space-y-1">
|
|
131
|
+
<div class="flex gap-1 flex-wrap">
|
|
132
|
+
<span class="px-1.5 py-0.5 rounded {variantColor(button.variant)}">{button.variant}</span>
|
|
133
|
+
<span class="px-1.5 py-0.5 rounded bg-gray-100 dark:bg-gray-700 text-gray-600 dark:text-gray-300">{button.size}</span>
|
|
134
|
+
</div>
|
|
135
|
+
<a
|
|
136
|
+
href={vscodeLink(button.fullPath, button.line)}
|
|
137
|
+
class="block text-blue-500 hover:underline truncate"
|
|
138
|
+
title={button.file}
|
|
139
|
+
>
|
|
140
|
+
{shortFile(button.file)}:{button.line}
|
|
141
|
+
</a>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
{/each}
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export default ButtonGridView;
|
|
2
|
+
type ButtonGridView = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<Record<string, never>>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const ButtonGridView: import("svelte").Component<Record<string, never>, {}, "">;
|
|
7
|
+
//# sourceMappingURL=ButtonGridView.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonGridView.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/stories/ButtonGridView.svelte.js"],"names":[],"mappings":";;;;;AA2IA,wFAA6D"}
|