astro-component-kit 0.4.1 → 0.5.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.
@@ -0,0 +1,1753 @@
1
+ // src/data/registry/cards.ts
2
+ import type { ComponentDoc } from './types';
3
+
4
+ export const cards: ComponentDoc[] = [
5
+ {
6
+ slug: 'blog-horizontal-card',
7
+ name: 'Horizontal Blog Card',
8
+ description: 'Landscape card layout for blog feeds or news items.',
9
+ category: 'cards',
10
+ tags: ["card","blog"],
11
+ featured: true,
12
+ code: `---
13
+ /**
14
+ * BlogHorizontalCard — Landscape card layout for blog feeds or news items.
15
+ *
16
+ * @param {string} title - The blog post title.
17
+ * @param {string} description - Brief summary or excerpt.
18
+ * @param {string} tag - Featured label or category (e.g. "Tutorial").
19
+ * @param {string} thumbUrl - Optional thumbnail image URL.
20
+ */
21
+ interface Props {
22
+ title: string;
23
+ description: string;
24
+ tag: string;
25
+ thumbUrl?: string;
26
+ }
27
+
28
+ const { title, description, tag, thumbUrl } = Astro.props;
29
+ ---
30
+
31
+ <article class="blog-h-card">
32
+ <div class="blog-h-card__thumb" style={thumbUrl ? \`background-image: url('\${thumbUrl}'); background-size: cover;\` : ''}></div>
33
+ <div class="blog-h-card__content">
34
+ <span class="blog-h-card__tag">{tag}</span>
35
+ <h4 class="blog-h-card__title">{title}</h4>
36
+ <p class="blog-h-card__desc">{description}</p>
37
+ </div>
38
+ </article>
39
+
40
+ <style>
41
+ .blog-h-card {
42
+ display: flex; gap: var(--sp-6, 1.5rem);
43
+ background: var(--c-bg-elev, rgba(255,255,255,0.02));
44
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
45
+ border-radius: var(--r-lg, 16px);
46
+ overflow: hidden;
47
+ }
48
+ .blog-h-card__thumb {
49
+ width: 150px;
50
+ background-color: var(--c-bg, #1e293b);
51
+ flex-shrink: 0;
52
+ }
53
+ .blog-h-card__content { padding: var(--sp-5, 1.2rem); }
54
+ .blog-h-card__title { color: var(--c-text-1, #fff); margin: 0.5rem 0; font-size: 1.1rem; }
55
+ .blog-h-card__desc { font-size: 0.85rem; color: var(--c-text-2, #94a3b8); margin: 0; }
56
+ .blog-h-card__tag { font-size: 0.7rem; color: var(--c-primary, #818cf8); font-weight: 700; text-transform: uppercase; }
57
+
58
+ @media (max-width: 600px) {
59
+ .blog-h-card { flex-direction: column; }
60
+ .blog-h-card__thumb { width: 100%; height: 180px; }
61
+ }
62
+ </style>
63
+ `,
64
+ usage: `<BlogHorizontalCard title="Building Astro Components" description="Learn to scale." tag="Tutorial" />`,
65
+ },
66
+ {
67
+ slug: 'cyber-feature-card',
68
+ name: 'Cyber Feature Card',
69
+ description: 'A feature card with sharp angles and neon stroke animations.',
70
+ category: 'cards',
71
+ tags: ["card","cyberpunk"],
72
+ featured: true,
73
+ code: `---
74
+ /**
75
+ * CyberFeatureCard — A feature card with sharp angles and neon stroke animations.
76
+ *
77
+ * @param {string} title - The main headline of the feature card.
78
+ * @param {string} subtitle - Optional description context.
79
+ */
80
+ interface Props {
81
+ title: string;
82
+ subtitle?: string;
83
+ }
84
+
85
+ const { title, subtitle } = Astro.props;
86
+ ---
87
+
88
+ <div class="cyber-card">
89
+ <div class="cyber-card__glitch-line"></div>
90
+ <h3 class="cyber-card__title">{title}</h3>
91
+ {subtitle && <p class="cyber-card__subtitle">{subtitle}</p>}
92
+ <slot />
93
+ </div>
94
+
95
+ <style>
96
+ .cyber-card {
97
+ background: var(--c-bg-elev, #000);
98
+ color: var(--c-text-1, #00e0ff);
99
+ border: 1px solid var(--c-primary, #ff003c);
100
+ padding: var(--sp-6, 1.5rem);
101
+ clip-path: polygon(0 0, 100% 0, 100% 85%, 85% 100%, 0 100%);
102
+ position: relative;
103
+ }
104
+ .cyber-card__glitch-line {
105
+ position: absolute;
106
+ height: 1px;
107
+ width: 100%;
108
+ background: var(--c-primary, #ff003c);
109
+ top: 10%; left: 0;
110
+ opacity: 0.5;
111
+ animation: glitch-anim 4s infinite;
112
+ }
113
+ .cyber-card__title {
114
+ margin: 0 0 0.5rem;
115
+ font-size: 1.25rem;
116
+ color: var(--c-text-1);
117
+ }
118
+ .cyber-card__subtitle {
119
+ margin: 0;
120
+ font-size: 0.9rem;
121
+ color: var(--c-text-2, #ccc);
122
+ }
123
+
124
+ @keyframes glitch-anim {
125
+ 0%, 100% { top: 10%; }
126
+ 50% { top: 90%; }
127
+ }
128
+ </style>
129
+ `,
130
+ usage: `<CyberFeatureCard title="System Core" subtitle="Neural engine">Activate protocol.</CyberFeatureCard>`,
131
+ },
132
+ {
133
+ slug: 'ecommerce-product-card',
134
+ name: 'Product Card',
135
+ description: 'Commercial card with price, rating and action buttons.',
136
+ category: 'cards',
137
+ tags: ["card","ecommerce"],
138
+ featured: true,
139
+ code: `---
140
+ /**
141
+ * EcommerceProductCard — Commercial card with price, rating and action buttons.
142
+ *
143
+ * @param {string} title - The product name.
144
+ * @param {string} price - The parsed price string (e.g. "$299").
145
+ * @param {string} imageUrl - The URL mapping to the product's thumbnail.
146
+ * @param {string} tag - Optional. The highlight bubble tag (e.g. "New").
147
+ * @param {string} rating - Optional. Formatted rating string.
148
+ * @param {string} ctaText - Optional. Label for the call to action button. Default is "Add".
149
+ */
150
+ interface Props {
151
+ title: string;
152
+ price: string;
153
+ imageUrl?: string;
154
+ tag?: string;
155
+ rating?: string;
156
+ ctaText?: string;
157
+ }
158
+
159
+ const {
160
+ title,
161
+ price,
162
+ imageUrl,
163
+ tag,
164
+ rating,
165
+ ctaText = 'Add'
166
+ } = Astro.props;
167
+ ---
168
+
169
+ <div class="prod-card">
170
+ <div class="prod-card__image" style={imageUrl ? \`background-image: url('\${imageUrl}'); background-size: cover;\` : ''}></div>
171
+ <div class="prod-card__info">
172
+ <div class="prod-card__meta">
173
+ {tag ? <span>{tag}</span> : <span></span>},
174
+ {rating ? <span>{rating}</span> : null}
175
+ </div>
176
+ <h4 class="prod-card__title">{title}</h4>
177
+ <div class="prod-card__bot">
178
+ <span class="prod-card__price">{price}</span>
179
+ <button class="prod-card__cta" type="button">{ctaText}</button>
180
+ </div>
181
+ </div>
182
+ </div>
183
+
184
+ <style>
185
+ .prod-card {
186
+ background: var(--c-bg-elev, #0f172a);
187
+ border-radius: var(--r-lg, 16px);
188
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
189
+ overflow: hidden;
190
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.3s ease;
191
+ }
192
+ .prod-card:hover {
193
+ border-color: var(--c-primary, #6366f1);
194
+ transform: translateY(-3px);
195
+ }
196
+ .prod-card__image {
197
+ height: 180px;
198
+ background-color: var(--c-bg, #1e293b);
199
+ }
200
+ .prod-card__info { padding: var(--sp-5, 1.25rem); }
201
+ .prod-card__meta {
202
+ display: flex; justify-content: space-between;
203
+ font-size: 0.75rem; color: var(--c-primary-light, #818cf8);
204
+ font-weight: 700; margin-bottom: 0.5rem;
205
+ }
206
+ .prod-card__title { color: var(--c-text-1, #fff); margin: 0; font-size: 1.1rem; }
207
+ .prod-card__bot { display: flex; justify-content: space-between; align-items: center; margin-top: 1.25rem; }
208
+ .prod-card__price { font-weight: 800; color: var(--c-text-1, #fff); font-size: 1.25rem; }
209
+ .prod-card__cta {
210
+ background: var(--c-primary, #6366f1); border: none; color: #fff;
211
+ padding: 0.5rem 1.2rem; border-radius: var(--r-md, 8px);
212
+ font-weight: 600; cursor: pointer; transition: 0.2s;
213
+ }
214
+ .prod-card__cta:hover { filter: brightness(1.1); }
215
+ </style>
216
+ `,
217
+ usage: `<EcommerceProductCard title="Premium Headphones" price="$299" tag="New" rating="5.0 ★" />`,
218
+ },
219
+ {
220
+ slug: 'glass-card',
221
+ name: 'Glass Card',
222
+ description: 'A versatile glassmorphism card with hover lift effect.',
223
+ category: 'cards',
224
+ tags: ["card","glass"],
225
+ featured: true,
226
+ code: `---
227
+ /**
228
+ * GlassCard — A versatile glassmorphism card with hover lift effect and gradient border.
229
+ *
230
+ * @param {string} title - Optional title for the glass card header.
231
+ * @param {string} subtitle - Optional description below the title.
232
+ * @param {boolean} hoverable - Whether the card lifts on hover. Default is true.
233
+ * @param {'sm'|'md'|'lg'} padding - Internal padding control. Default is 'md'.
234
+ */
235
+ interface Props { title?: string; subtitle?: string; hoverable?: boolean; padding?: 'sm' | 'md' | 'lg'; }
236
+ const { title, subtitle, hoverable = true, padding = 'md' } = Astro.props;
237
+ ---
238
+ <div class:list={['glass-card', \`glass-card--p\${padding}\`, { 'glass-card--hoverable': hoverable }]}>
239
+ {title && (<div class="glass-card__header"><h3 class="glass-card__title">{title}</h3>{subtitle && <p class="glass-card__subtitle">{subtitle}</p>}</div>)}
240
+ <div class="glass-card__body"><slot /></div>
241
+ </div>
242
+ <style>
243
+ .glass-card { background: rgba(255, 255, 255, 0.04); backdrop-filter: blur(16px); border: 1px solid rgba(255, 255, 255, 0.09); border-radius: 20px; position: relative; overflow: hidden; transition: 0.3s; }
244
+ .glass-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); }
245
+ .glass-card--hoverable:hover { transform: translateY(-4px); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4); border-color: rgba(99, 102, 241, 0.25); }
246
+ .glass-card__header { border-bottom: 1px solid rgba(255, 255, 255, 0.07); margin-bottom: 1rem; padding-bottom: 0.75rem; }
247
+ .glass-card__title { margin: 0 0 0.25rem; font-size: 1.05rem; font-weight: 600; color: #f1f5f9; }
248
+ .glass-card__subtitle { margin: 0; font-size: 0.82rem; color: #64748b; }
249
+ .glass-card--psm { padding: 1rem; } .glass-card--pmd { padding: 1.5rem; } .glass-card--plg { padding: 2rem; }
250
+ </style>
251
+ `,
252
+ usage: `---
253
+ import { GlassCard } from 'astro-component-kit';
254
+ ---
255
+
256
+ <GlassCard
257
+ title="Analytics Dashboard"
258
+ subtitle="Last 30 days performance"
259
+ padding="lg"
260
+ >
261
+ <div class="stat-group">
262
+ <span class="stat-label">Active Users</span>
263
+ <span class="stat-value">2,841</span>
264
+ </div>
265
+ <p>Your workspace is performing 15% better than last month.</p>
266
+ </GlassCard>`,
267
+ },
268
+ {
269
+ slug: 'glass-event-card',
270
+ name: 'Glass Event Card',
271
+ description: 'Vibrant card for events with date badge and glass effect.',
272
+ category: 'cards',
273
+ tags: ["card","event"],
274
+ featured: true,
275
+ code: `---
276
+ /**
277
+ * GlassEventCard — Vibrant card for events with date badge and glass effect.
278
+ *
279
+ * @param {string|number} day - The event date numeric segment.
280
+ * @param {string} month - The event month string indicator.
281
+ * @param {string} title - The name of the event.
282
+ * @param {string} details - Additional string metadata (e.g location and time).
283
+ */
284
+ interface Props {
285
+ day: string | number;
286
+ month: string;
287
+ title: string;
288
+ details: string;
289
+ }
290
+
291
+ const { day, month, title, details } = Astro.props;
292
+ ---
293
+
294
+ <div class="event-card">
295
+ <div class="event-card__badge">
296
+ <span class="event-card__day">{day}</span>
297
+ {month}
298
+ </div>
299
+ <div class="event-card__info">
300
+ <h3 class="event-card__title">{title}</h3>
301
+ <p class="event-card__details">{details}</p>
302
+ </div>
303
+ <button class="event-card__join" type="button" aria-label="Join event">+</button>
304
+ </div>
305
+
306
+ <style>
307
+ .event-card {
308
+ display: flex; align-items: center; gap: var(--sp-4, 1rem);
309
+ padding: var(--sp-5, 1.25rem);
310
+ background: var(--c-bg-elev, rgba(255,255,255,0.04));
311
+ backdrop-filter: blur(10px);
312
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
313
+ border-radius: var(--r-xl, 20px);
314
+ }
315
+ .event-card__badge {
316
+ background: var(--c-primary, #6366f1); color: #fff;
317
+ width: 50px; height: 60px;
318
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
319
+ font-size: 0.7rem; font-weight: 800; border-radius: var(--r-md, 12px);
320
+ text-transform: uppercase;
321
+ }
322
+ .event-card__day { font-size: 1.2rem; line-height: 1; margin-bottom: 2px; }
323
+ .event-card__info { flex: 1; }
324
+ .event-card__title { font-size: 1rem; color: var(--c-text-1, #fff); margin: 0; }
325
+ .event-card__details { font-size: 0.8rem; color: var(--c-text-2, #94a3b8); margin: 2px 0 0; }
326
+ .event-card__join {
327
+ margin-left: auto; width: 40px; height: 40px;
328
+ border-radius: var(--r-full, 50%);
329
+ border: 1px solid var(--c-border, rgba(255,255,255,0.2));
330
+ background: none; color: var(--c-text-1, #fff);
331
+ font-size: 1.2rem; cursor: pointer; transition: 0.2s;
332
+ }
333
+ .event-card__join:hover { background: var(--c-text-1, #fff); color: var(--c-bg, #000); }
334
+ </style>
335
+ `,
336
+ usage: `<GlassEventCard day={24} month="OCT" title="Dev Meetup" details="SF, CA" />`,
337
+ },
338
+ {
339
+ slug: 'glow-portfolio-card',
340
+ name: 'Glow Portfolio Card',
341
+ description: 'Card with a hovering background glow that follows the card edges.',
342
+ category: 'cards',
343
+ tags: ["card","glow"],
344
+ featured: true,
345
+ code: `---
346
+ /**
347
+ * GlowPortfolioCard — Card with a hovering background glow that follows the card edges.
348
+ *
349
+ * @param {string} title - Project title heading.
350
+ * @param {string} subtitle - Project metadata (e.g. "Web design / 2024").
351
+ * @param {string} glowColor - Optional. Hex color for the animated border glow. Default is '#6366f1'.
352
+ */
353
+ interface Props {
354
+ title: string;
355
+ subtitle: string;
356
+ glowColor?: string;
357
+ }
358
+
359
+ const { title, subtitle, glowColor = 'var(--c-primary, #6366f1)' } = Astro.props;
360
+ ---
361
+
362
+ <div class="glow-wrap" style={\`--glow-color: \${glowColor};\`}>
363
+ <div class="glow-content">
364
+ <h3 class="glow-content__title">{title}</h3>
365
+ <p class="glow-content__subtitle">{subtitle}</p>
366
+ <slot />
367
+ </div>
368
+ </div>
369
+
370
+ <style>
371
+ .glow-wrap {
372
+ position: relative;
373
+ padding: 2px;
374
+ border-radius: var(--r-xl, 20px);
375
+ background: var(--c-border, rgba(255,255,255,0.1));
376
+ overflow: hidden;
377
+ }
378
+ .glow-wrap::before {
379
+ content: '';
380
+ position: absolute;
381
+ inset: -50%;
382
+ background: conic-gradient(from 0deg, transparent, var(--glow-color), transparent);
383
+ animation: rotate-glow 4s linear infinite;
384
+ }
385
+ .glow-content {
386
+ position: relative;
387
+ background: var(--c-bg, #080b14);
388
+ padding: var(--sp-8, 2rem);
389
+ border-radius: calc(var(--r-xl, 20px) - 2px);
390
+ z-index: 1;
391
+ text-align: center;
392
+ }
393
+ .glow-content__title { margin: 0; color: var(--c-text-1, #fff); font-size: 1.25rem; }
394
+ .glow-content__subtitle { color: var(--c-text-2, #94a3b8); font-size: 0.9rem; margin-top: 0.5rem; }
395
+
396
+ @keyframes rotate-glow { 100% { transform: rotate(360deg); } }
397
+ </style>
398
+ `,
399
+ usage: `<GlowPortfolioCard title="Redesign" subtitle="Web / 2024"><button>View</button></GlowPortfolioCard>`,
400
+ },
401
+ {
402
+ slug: 'interactive-tilt-card',
403
+ name: 'Interactive Tilt Card',
404
+ description: 'Card that tilts in 3D space based on mouse position.',
405
+ category: 'cards',
406
+ tags: ["card","tilt","3d"],
407
+ featured: true,
408
+ code: `---
409
+ /**
410
+ * InteractiveTiltCard — Card that tilts in 3D space based on mouse position.
411
+ *
412
+ * @param {string} title - The card's heading text.
413
+ * @param {string} description - The descriptive paragraph attached to the card.
414
+ */
415
+ interface Props {
416
+ title: string;
417
+ description: string;
418
+ }
419
+
420
+ const { title, description } = Astro.props;
421
+ ---
422
+
423
+ <div class="tilt-card-wrap">
424
+ <div class="tilt-card-inner">
425
+ <h3 class="tilt-card__title">{title}</h3>
426
+ <p class="tilt-card__desc">{description}</p>
427
+ </div>
428
+ </div>
429
+
430
+ <style>
431
+ .tilt-card-wrap {
432
+ perspective: 1000px;
433
+ width: 100%;
434
+ max-width: 300px;
435
+ }
436
+ .tilt-card-inner {
437
+ background: var(--c-bg-elev, #1e293b);
438
+ padding: var(--sp-12, 3rem);
439
+ border-radius: var(--r-xl, 24px);
440
+ color: var(--c-text-1, #fff);
441
+ text-align: center;
442
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
443
+ transform-style: preserve-3d;
444
+ transition: transform 0.1s;
445
+ }
446
+ .tilt-card__title {
447
+ transform: translateZ(50px);
448
+ font-size: 1.5rem;
449
+ color: var(--c-primary, #818cf8);
450
+ margin: 0;
451
+ }
452
+ .tilt-card__desc {
453
+ transform: translateZ(30px);
454
+ color: var(--c-text-2, #94a3b8);
455
+ font-size: 0.9rem;
456
+ margin-top: 1rem;
457
+ }
458
+ </style>
459
+
460
+ <script>
461
+ document.querySelectorAll('.tilt-card-inner').forEach(card => {
462
+ card.addEventListener('mousemove', e => {
463
+ const rect = card.getBoundingClientRect();
464
+ const x = ((e as MouseEvent).clientX - rect.left - rect.width/2) / 10;
465
+ const y = ((e as MouseEvent).clientY - rect.top - rect.height/2) / -10;
466
+ (card as HTMLElement).style.transform = \`rotateY(\${x}deg) rotateX(\${y}deg)\`;
467
+ });
468
+ card.addEventListener('mouseleave', () => {
469
+ (card as HTMLElement).style.transform = 'rotateY(0deg) rotateX(0deg)';
470
+ });
471
+ });
472
+ </script>
473
+ `,
474
+ usage: `<InteractiveTiltCard title="3D Hover" description="Move your mouse over me." />`,
475
+ },
476
+ {
477
+ slug: 'kanban-item-card',
478
+ name: 'Project Task Card',
479
+ description: 'Small card optimized for list-based project management.',
480
+ category: 'cards',
481
+ tags: ["card","project"],
482
+ featured: true,
483
+ code: `---
484
+ /**
485
+ * KanbanItemCard — Small card optimized for list-based project management.
486
+ *
487
+ * @param {string} title - The description of the ticket/task.
488
+ * @param {string} priority - Priority level label (e.g. "Prio").
489
+ * @param {string} tag - Contextual label tag (e.g. "SEO", "Bug").
490
+ */
491
+ interface Props {
492
+ title: string;
493
+ priority?: string;
494
+ tag?: string;
495
+ }
496
+
497
+ const { title, priority, tag } = Astro.props;
498
+ ---
499
+
500
+ <div class="k-item">
501
+ <p class="k-item__title">{title}</p>
502
+ <div class="k-item__badges">
503
+ {priority && <span class="k-item__badge k-item__badge--prio">{priority}</span>},
504
+ {tag && <span class="k-item__badge k-item__badge--opt">{tag}</span>}
505
+ </div>
506
+ </div>
507
+
508
+ <style>
509
+ .k-item {
510
+ background: var(--c-bg-elev, #111);
511
+ border: 1px solid var(--c-border, #333);
512
+ padding: var(--sp-4, 1rem);
513
+ border-radius: var(--r-md, 8px);
514
+ cursor: pointer;
515
+ transition: 0.2s;
516
+ }
517
+ .k-item:hover {
518
+ border-color: var(--c-primary, #6366f1);
519
+ transform: scale(1.02);
520
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
521
+ }
522
+ .k-item__title { margin: 0 0 0.75rem; font-size: 0.85rem; color: var(--c-text-1, #fff); font-weight: 500; line-height: 1.4; }
523
+ .k-item__badges { display: flex; gap: 4px; flex-wrap: wrap; }
524
+ .k-item__badge { font-size: 0.65rem; font-weight: 700; padding: 2px 6px; border-radius: 4px; text-transform: uppercase; }
525
+
526
+ .k-item__badge--prio { background: rgba(245,158,11,0.1); color: #fbbf24; }
527
+ .k-item__badge--opt { background: rgba(52,211,153,0.1); color: #34d399; }
528
+ </style>
529
+ `,
530
+ usage: `<KanbanItemCard title="Update SEO" priority="Prio" tag="SEO" />`,
531
+ },
532
+ {
533
+ slug: 'minimal-link-card',
534
+ name: 'Minimal Link Card',
535
+ description: 'Elegant arrow-link card for site navigation sections.',
536
+ category: 'cards',
537
+ tags: ["card","link","minimal"],
538
+ featured: true,
539
+ code: `---
540
+ /**
541
+ * MinimalLinkCard — Elegant arrow-link card for site navigation sections.
542
+ *
543
+ * @param {string} title - The text label of the link.
544
+ * @param {string} href - The destination URL.
545
+ */
546
+ interface Props {
547
+ title: string;
548
+ href: string;
549
+ }
550
+
551
+ const { title, href } = Astro.props;
552
+ ---
553
+
554
+ <a href={href} class="link-card">
555
+ <span class="link-card__title">{title}</span>
556
+ <svg class="link-card__icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
557
+ <path d="M5 12h14M12 5l7 7-7 7"/>
558
+ </svg>
559
+ </a>
560
+
561
+ <style>
562
+ .link-card {
563
+ display: flex; justify-content: space-between; align-items: center;
564
+ padding: var(--sp-6, 1.5rem);
565
+ background: var(--c-bg-elev, rgba(255,255,255,0.03));
566
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
567
+ border-radius: var(--r-md, 12px);
568
+ text-decoration: none;
569
+ color: var(--c-text-1, #fff);
570
+ font-weight: 600;
571
+ transition: 0.2s;
572
+ }
573
+ .link-card:hover {
574
+ background: rgba(255,255,255,0.06);
575
+ border-color: var(--c-primary, #6366f1);
576
+ color: var(--c-primary-light, #818cf8);
577
+ }
578
+ .link-card__icon { transition: transform 0.2s; }
579
+ .link-card:hover .link-card__icon { transform: translateX(5px); }
580
+ </style>
581
+ `,
582
+ usage: `<MinimalLinkCard title="Documentation" href="/docs" />`,
583
+ },
584
+ {
585
+ slug: 'music-player-mini',
586
+ name: 'Mini Music Player',
587
+ description: 'Compact player widget with controls and progress bar.',
588
+ category: 'cards',
589
+ tags: ["card","music"],
590
+ featured: true,
591
+ code: `---
592
+ /**
593
+ * MusicPlayerMini — Compact player widget with controls and progress bar.
594
+ *
595
+ * @param {string} title - The song track title.
596
+ * @param {string} artist - The artist or band name.
597
+ * @param {string} coverUrl - Optional string matching the album cover image URL.
598
+ * @param {number} progress - The song progress representation (0 to 100). Default is 40.
599
+ */
600
+ interface Props {
601
+ title: string;
602
+ artist: string;
603
+ coverUrl?: string;
604
+ progress?: number;
605
+ }
606
+
607
+ const { title, artist, coverUrl, progress = 40 } = Astro.props;
608
+ ---
609
+
610
+ <div class="music-mini">
611
+ <div class="music-mini__art" style={coverUrl ? \`background-image: url('\${coverUrl}'); background-size: cover;\` : ''}></div>
612
+ <div class="music-mini__track">
613
+ <h4 class="music-mini__title">{title}</h4>
614
+ <p class="music-mini__artist">{artist}</p>
615
+ <div class="music-mini__progress" role="progressbar" aria-valuenow={progress} aria-valuemin="0" aria-valuemax="100">
616
+ <div class="music-mini__bar" style={\`width: \${progress}%;\`}></div>
617
+ </div>
618
+ </div>
619
+ <button class="music-mini__play" type="button" aria-label="Play track">▶</button>
620
+ </div>
621
+
622
+ <style>
623
+ .music-mini {
624
+ display: flex; align-items: center; gap: var(--sp-4, 1rem);
625
+ background: var(--c-bg-elev, #111);
626
+ padding: var(--sp-3, 0.75rem);
627
+ border-radius: var(--r-md, 14px); border: 1px solid var(--c-border, #333);
628
+ width: 100%; max-width: 320px;
629
+ }
630
+ .music-mini__art {
631
+ width: 50px; height: 50px;
632
+ background-color: var(--c-primary-light, #818cf8);
633
+ border-radius: var(--r-sm, 8px); flex-shrink: 0;
634
+ }
635
+ .music-mini__track { flex: 1; }
636
+ .music-mini__title { font-size: 0.85rem; color: var(--c-text-1, #fff); margin: 0; }
637
+ .music-mini__artist { font-size: 0.7rem; color: var(--c-text-2, #64748b); margin: 0; }
638
+ .music-mini__progress {
639
+ height: 3px; background: rgba(255,255,255,0.1);
640
+ border-radius: 2px; margin-top: 8px; position: relative; overflow: hidden;
641
+ }
642
+ .music-mini__bar {
643
+ position: absolute; left: 0; top: 0; height: 100%;
644
+ background: var(--c-primary, #6366f1); border-radius: 2px;
645
+ }
646
+ .music-mini__play {
647
+ font-size: 1.2rem; cursor: pointer; color: var(--c-text-1, #fff);
648
+ background: none; border: none; padding: 0.25rem; display: grid; place-items: center;
649
+ }
650
+ .music-mini__play:hover { color: var(--c-primary-light, #818cf8); }
651
+ </style>
652
+ `,
653
+ usage: `<MusicPlayerMini title="Moonlight" artist="Astro Orchestra" progress={60} />`,
654
+ },
655
+ {
656
+ slug: 'neumorphic-card',
657
+ name: 'Neumorphic Card',
658
+ description: 'A soft UI card with deep shadows for a realistic elevated look.',
659
+ category: 'cards',
660
+ tags: ["card","neumorphism"],
661
+ featured: true,
662
+ code: `---
663
+ /**
664
+ * NeumorphicCard — A soft UI card with deep shadows for a realistic elevated look.
665
+ *
666
+ * @param {'sm'|'md'|'lg'} padding - Optional. Inner padding layout size. Default is 'md'.
667
+ */
668
+ interface Props {
669
+ padding?: 'sm' | 'md' | 'lg';
670
+ }
671
+
672
+ const { padding = 'md' } = Astro.props;
673
+ ---
674
+
675
+ <div class={\`neu-card neu-card--p\${padding}\`}>
676
+ <slot />
677
+ </div>
678
+
679
+ <style>
680
+ .neu-card {
681
+ background: var(--c-bg-elev, #e0e0e0);
682
+ border-radius: var(--r-xl, 30px);
683
+ box-shadow: 15px 15px 30px rgba(0,0,0,0.1), -15px -15px 30px rgba(255,255,255,0.7);
684
+ color: var(--c-text-1, #444);
685
+ transition: all 0.3s ease;
686
+ }
687
+
688
+ .neu-card--psm { padding: var(--sp-4, 1rem); }
689
+ .neu-card--pmd { padding: var(--sp-8, 2rem); }
690
+ .neu-card--plg { padding: var(--sp-12, 3rem); }
691
+
692
+ @media (prefers-color-scheme: dark) {
693
+ .neu-card {
694
+ box-shadow: 15px 15px 30px rgba(0,0,0,0.4), -15px -15px 30px rgba(255,255,255,0.05);
695
+ }
696
+ }
697
+ </style>
698
+ `,
699
+ usage: `<NeumorphicCard padding="lg"><p>Elevated focus container</p></NeumorphicCard>`,
700
+ },
701
+ {
702
+ slug: 'notification-card',
703
+ name: 'Notification Card',
704
+ description: 'Toast-like card for app notifications and alerts.',
705
+ category: 'cards',
706
+ tags: ["card","notification"],
707
+ featured: true,
708
+ code: `---
709
+ /**
710
+ * NotificationCard — Toast-like card for app notifications and alerts.
711
+ *
712
+ * @param {string} title - The notification headline.
713
+ * @param {string} message - The notification detail text.
714
+ * @param {'info'|'warning'|'success'|'error'} type - Optional. Changes the notification dot indicator color. Default is 'info'.
715
+ */
716
+ interface Props {
717
+ title: string;
718
+ message: string;
719
+ type?: 'info' | 'warning' | 'success' | 'error';
720
+ }
721
+
722
+ const { title, message, type = 'info' } = Astro.props;
723
+ ---
724
+
725
+ <div class={\`notify-card notify-card--\${type}\`}>
726
+ <div class="notify-card__dot" aria-hidden="true"></div>
727
+ <div class="notify-card__content">
728
+ <strong class="notify-card__title">{title}</strong>
729
+ <p class="notify-card__message">{message}</p>
730
+ </div>
731
+ </div>
732
+
733
+ <style>
734
+ .notify-card {
735
+ display: flex; gap: var(--sp-4, 1rem);
736
+ padding: var(--sp-4, 1rem);
737
+ background: var(--c-bg-elev, #0f172a);
738
+ border-radius: var(--r-md, 12px);
739
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
740
+ box-shadow: 0 10px 40px rgba(0,0,0,0.4);
741
+ max-width: 300px;
742
+ }
743
+ .notify-card__dot {
744
+ width: 8px; height: 8px;
745
+ border-radius: var(--r-full, 50%);
746
+ margin-top: 5px;
747
+ flex-shrink: 0;
748
+ }
749
+ .notify-card__content { flex: 1; }
750
+ .notify-card__title { font-size: 0.9rem; color: var(--c-text-1, #fff); }
751
+ .notify-card__message { margin: 2px 0 0; font-size: 0.82rem; color: var(--c-text-2, #94a3b8); line-height: 1.4; }
752
+
753
+ .notify-card--info .notify-card__dot { background: var(--c-primary, #6366f1); }
754
+ .notify-card--success .notify-card__dot { background: #10b981; }
755
+ .notify-card--warning .notify-card__dot { background: #f59e0b; }
756
+ .notify-card--error .notify-card__dot { background: #ef4444; }
757
+ </style>
758
+ `,
759
+ usage: `<NotificationCard title="Updates Available" message="Version 2.0 is ready." type="info" />`,
760
+ },
761
+ {
762
+ slug: 'pricing-card',
763
+ name: 'Pricing Tier Card',
764
+ description: 'Optimized card for showing product plans and features.',
765
+ category: 'cards',
766
+ tags: ["card","pricing"],
767
+ featured: true,
768
+ code: `---
769
+ /**
770
+ * PricingCard — Optimized card for showing product plans and features.
771
+ *
772
+ * @param {string} plan - The plan name (e.g. "Pro").
773
+ * @param {string} price - The integer/decimal price value.
774
+ * @param {boolean} featured - Applies a highlighted styling variant if true.
775
+ */
776
+ interface Props { plan: string; price: string; featured?: boolean; }
777
+ const { plan, price, featured = false } = Astro.props;
778
+ ---
779
+ <div class:list={["price-card", { "featured": featured }]}>
780
+ <span class="price-card__plan">{plan}</span>
781
+ <div class="price-card__price"><span>$</span>{price}</div>
782
+ <ul class="price-card__features">
783
+ <slot />
784
+ </ul>
785
+ <button class="price-card__btn" type="button">Choose Plan</button>
786
+ </div>
787
+
788
+ <style>
789
+ .price-card {
790
+ background: var(--c-bg-elev, rgba(255,255,255,0.03));
791
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
792
+ border-radius: var(--r-xl, 24px);
793
+ padding: var(--sp-10, 2.5rem);
794
+ display: flex; flex-direction: column; gap: var(--sp-6, 1.5rem);
795
+ }
796
+ .featured {
797
+ border-color: var(--c-primary, #6366f1);
798
+ background: rgba(99,102,241,0.05);
799
+ transform: scale(1.05);
800
+ }
801
+ .price-card__plan { font-size: 1.1rem; font-weight: 600; color: var(--c-text-1, #fff); }
802
+ .price-card__price { font-size: 2.5rem; font-weight: 800; color: var(--c-text-1, #fff); }
803
+ .price-card__price span { font-size: 1.2rem; opacity: 0.7; margin-right: 2px; }
804
+
805
+ .price-card__features {
806
+ list-style: none; padding: 0; margin: 0;
807
+ font-size: 0.9rem; color: var(--c-text-2, #94a3b8);
808
+ display: flex; flex-direction: column; gap: 0.5rem;
809
+ }
810
+
811
+ /* Global sub-selector rule to style slotted list items cleanly */
812
+ .price-card__features :global(li) { position: relative; padding-left: 1.5rem; }
813
+ .price-card__features :global(li::before) {
814
+ content: "✓"; position: absolute; left: 0; color: var(--c-primary, #6366f1);
815
+ }
816
+
817
+ .price-card__btn {
818
+ background: var(--c-primary, #6366f1); color: #fff;
819
+ border: none; padding: 0.8rem; border-radius: var(--r-md, 12px);
820
+ font-weight: 700; cursor: pointer; transition: 0.2s;
821
+ }
822
+ </style>
823
+ `,
824
+ usage: `---
825
+ import { PricingCard } from 'astro-component-kit';
826
+ ---
827
+
828
+ <div class="grid-layout">
829
+ <PricingCard plan="Starter" price="0">
830
+ <li>10 Projects</li>
831
+ <li>Email Support</li>
832
+ <li>1GB Storage</li>
833
+ </PricingCard>
834
+
835
+ <PricingCard plan="Pro" price="29" featured>
836
+ <li>Unlimited Projects</li>
837
+ <li>24/7 Support</li>
838
+ <li>50GB Storage</li>
839
+ </PricingCard>
840
+ </div>`,
841
+ },
842
+ {
843
+ slug: 'profile-card',
844
+ name: 'Profile Card',
845
+ description: 'Image-centric profile card with social links and blur effect.',
846
+ category: 'cards',
847
+ tags: ["card","profile"],
848
+ featured: true,
849
+ code: `---
850
+ /**
851
+ * ProfileCard — Image-centric profile card with social links and blur effect.
852
+ *
853
+ * @param {string} name - The person's full name.
854
+ * @param {string} role - Their job title or role.
855
+ * @param {string} avatarUrl - Optional URL string pointing to their avatar image.
856
+ */
857
+ interface Props {
858
+ name: string;
859
+ role: string;
860
+ avatarUrl?: string;
861
+ }
862
+
863
+ const { name, role, avatarUrl } = Astro.props;
864
+ ---
865
+
866
+ <div class="profile-card">
867
+ <div class="profile-card__banner"></div>
868
+ <div class="profile-card__avatar" style={avatarUrl ? \`background-image: url('\${avatarUrl}'); background-size: cover;\` : ''}></div>
869
+ <h3 class="profile-card__name">{name}</h3>
870
+ <p class="profile-card__role">{role}</p>
871
+ <div class="profile-card__socials">
872
+ <slot name="socials">
873
+ <!-- Fallback generic icons if no socials slot passed -->
874
+ <span aria-hidden="true">🐦</span>
875
+ <span aria-hidden="true">💼</span>
876
+ <span aria-hidden="true">🌐</span>
877
+ </slot>
878
+ </div>
879
+ </div>
880
+
881
+ <style>
882
+ .profile-card {
883
+ background: rgba(255,255,255,0.03);
884
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
885
+ border-radius: var(--r-xl, 20px);
886
+ text-align: center;
887
+ overflow: hidden;
888
+ padding-bottom: var(--sp-6, 1.5rem);
889
+ }
890
+ .profile-card__banner {
891
+ height: 80px;
892
+ background: linear-gradient(135deg, var(--c-primary, #6366f1), var(--c-primary-light, #c084fc));
893
+ }
894
+ .profile-card__avatar {
895
+ width: 80px; height: 80px;
896
+ background-color: var(--c-bg-elev, #334155);
897
+ border: 4px solid var(--c-bg, #080b14);
898
+ border-radius: var(--r-full, 50%);
899
+ margin: -40px auto 1rem;
900
+ }
901
+ .profile-card__name { color: var(--c-text-1, #fff); margin: 0; }
902
+ .profile-card__role { font-size: 0.85rem; color: var(--c-text-2, #94a3b8); margin: 4px 0 0; }
903
+ .profile-card__socials { display: flex; justify-content: center; gap: 1rem; margin-top: 1rem; cursor: pointer; }
904
+ </style>
905
+ `,
906
+ usage: `<ProfileCard name="Sarah Jenkins" role="Lead Developer" />`,
907
+ },
908
+ {
909
+ slug: 'retro-game-card',
910
+ name: 'Retro Arcade Game Card',
911
+ description: 'Bold gaming card with scanlines and pixel fonts.',
912
+ category: 'cards',
913
+ tags: ["card","retro"],
914
+ featured: true,
915
+ code: `---
916
+ /**
917
+ * RetroGameCard — Bold gaming card with scanlines and pixel fonts.
918
+ *
919
+ * @param {string} title - The retro game title.
920
+ * @param {string} level - Current stage or level string.
921
+ * @param {number|string} score - The player's score.
922
+ */
923
+ interface Props {
924
+ title: string;
925
+ level: string;
926
+ score: number | string;
927
+ }
928
+
929
+ const { title, level, score } = Astro.props;
930
+ ---
931
+
932
+ <div class="retro-game">
933
+ <div class="retro-game__scanlines"></div>
934
+ <div class="retro-game__screen">{level}</div>
935
+ <h3 class="retro-game__title">{title}</h3>
936
+ <div class="retro-game__score">SCORE: {score}</div>
937
+ </div>
938
+
939
+ <style>
940
+ .retro-game {
941
+ background: #22c55e; border: 4px solid #000;
942
+ padding: var(--sp-4, 1rem); position: relative;
943
+ box-shadow: 8px 8px 0 #000;
944
+ font-family: 'Courier New', Courier, monospace;
945
+ }
946
+ .retro-game__screen {
947
+ background: #000; color: #22c55e;
948
+ padding: var(--sp-4, 1rem); text-align: center;
949
+ font-weight: 900; margin-bottom: 0.5rem; text-transform: uppercase;
950
+ }
951
+ .retro-game__scanlines {
952
+ position: absolute; inset: 0; pointer-events: none;
953
+ background: linear-gradient(rgba(0,0,0,0.1) 50%, transparent 50%); background-size: 100% 4px;
954
+ }
955
+ .retro-game__title { margin: 0; font-size: 1.1rem; color: #000; font-weight: 900; text-transform: uppercase; }
956
+ .retro-game__score { font-size: 0.8rem; color: #000; margin-top: 0.5rem; font-weight: bold; }
957
+ </style>
958
+ `,
959
+ usage: `<RetroGameCard title="SUPER ASTRO" level="LVL 01" score="4820" />`,
960
+ },
961
+ {
962
+ slug: 'stat-card',
963
+ name: 'Data Stat Card',
964
+ description: 'Compact card for displaying key metrics with an icon.',
965
+ category: 'cards',
966
+ tags: ["card","stats"],
967
+ featured: true,
968
+ code: `---
969
+ /**
970
+ * StatCard — Compact card for displaying key metrics with an icon.
971
+ *
972
+ * @param {string} label - The metric name (e.g., "Total Revenue").
973
+ * @param {string} value - The primary statistic value (e.g., "$124,590").
974
+ * @param {string} icon - The emoji or text character representing the stat.
975
+ */
976
+ interface Props {
977
+ label: string;
978
+ value: string;
979
+ icon: string;
980
+ }
981
+
982
+ const { label, value, icon } = Astro.props;
983
+ ---
984
+
985
+ <div class="stat-card">
986
+ <div class="stat-card__icon" aria-hidden="true">{icon}</div>
987
+ <div class="stat-card__info">
988
+ <span class="stat-card__label">{label}</span>
989
+ <span class="stat-card__value">{value}</span>
990
+ </div>
991
+ </div>
992
+
993
+ <style>
994
+ .stat-card {
995
+ display: flex; align-items: center; gap: var(--sp-5, 1.25rem);
996
+ padding: var(--sp-6, 1.5rem);
997
+ background: var(--c-bg-elev, rgba(99,102,241,0.06));
998
+ border: 1px solid var(--c-border, rgba(99,102,241,0.2));
999
+ border-radius: var(--r-lg, 16px);
1000
+ }
1001
+ .stat-card__icon {
1002
+ font-size: 1.5rem;
1003
+ background: rgba(99,102,241,0.1);
1004
+ width: 50px; height: 50px;
1005
+ display: grid; place-items: center;
1006
+ border-radius: var(--r-md, 12px);
1007
+ }
1008
+ .stat-card__label {
1009
+ display: block; font-size: 0.8rem;
1010
+ color: var(--c-text-2, #94a3b8);
1011
+ font-weight: 600; text-transform: uppercase;
1012
+ }
1013
+ .stat-card__value {
1014
+ display: block; font-size: 1.4rem;
1015
+ font-weight: 800; color: var(--c-text-1, #fff);
1016
+ }
1017
+ </style>
1018
+ `,
1019
+ usage: `<StatCard label="Total Revenue" value="$124,590" icon="📈" />`,
1020
+ },
1021
+ {
1022
+ slug: 'task-kanban-card',
1023
+ name: 'Kanban Task Card',
1024
+ description: 'Agile task card with priority labels and due dates.',
1025
+ category: 'cards',
1026
+ tags: ["card","kanban","task"],
1027
+ featured: true,
1028
+ code: `---
1029
+ /**
1030
+ * TaskKanbanCard — Agile task card with priority labels and due dates.
1031
+ *
1032
+ * @param {string} task - The description of the task being managed.
1033
+ * @param {string} date - Visual date string indicator (e.g. "📅 Oct 24").
1034
+ * @param {string} assigneeInitials - Short initials for the user avatar (e.g "MJ").
1035
+ * @param {'low'|'med'|'high'} priority - Controls the appearance of the priority tag label. Default is 'low'.
1036
+ */
1037
+ interface Props {
1038
+ task: string;
1039
+ date: string;
1040
+ assigneeInitials: string;
1041
+ priority?: 'low' | 'med' | 'high';
1042
+ }
1043
+
1044
+ const { task, date, assigneeInitials, priority = 'low' } = Astro.props;
1045
+
1046
+ const priorityLabels = { low: 'Low', med: 'Medium', high: 'High' };
1047
+ ---
1048
+
1049
+ <div class="task-card">
1050
+ <div class="task-card__tags">
1051
+ <span class={\`task-card__tag task-card__tag--\${priority}\`}>{priorityLabels[priority]}</span>
1052
+ </div>
1053
+ <p class="task-card__desc">{task}</p>
1054
+ <div class="task-card__footer">
1055
+ <span class="task-card__date">{date}</span>
1056
+ <div class="task-card__assignee">{assigneeInitials}</div>
1057
+ </div>
1058
+ </div>
1059
+
1060
+ <style>
1061
+ .task-card {
1062
+ background: var(--c-bg-elev, #1e293b);
1063
+ padding: var(--sp-4, 1rem);
1064
+ border-radius: var(--r-md, 10px);
1065
+ border: 1px solid var(--c-border, #334155);
1066
+ }
1067
+ .task-card__tag {
1068
+ font-size: 0.7rem; font-weight: 700;
1069
+ padding: 2px 8px; border-radius: 4px;
1070
+ }
1071
+ .task-card__tag--high { background: rgba(239,68,68,0.1); color: #f87171; }
1072
+ .task-card__tag--med { background: rgba(245,158,11,0.1); color: #fbbf24; }
1073
+ .task-card__tag--low { background: rgba(52,211,153,0.1); color: #34d399; }
1074
+
1075
+ .task-card__desc { font-size: 0.85rem; color: var(--c-text-1, #e2e8f0); margin: 0.75rem 0; font-weight: 500; }
1076
+ .task-card__footer { display: flex; justify-content: space-between; align-items: center; }
1077
+ .task-card__date { font-size: 0.75rem; color: var(--c-text-2, #64748b); }
1078
+ .task-card__assignee {
1079
+ width: 24px; height: 24px;
1080
+ background: var(--c-primary, #6366f1); color: #fff;
1081
+ font-size: 0.65rem; border-radius: 50%;
1082
+ display: grid; place-items: center; font-weight: 700;
1083
+ }
1084
+ </style>
1085
+ `,
1086
+ usage: `<TaskKanbanCard task="Update SEO metadata" date="Oct 24" assigneeInitials="MJ" priority="high" />`,
1087
+ },
1088
+ {
1089
+ slug: 'testimonial-card-clean',
1090
+ name: 'Clean Testimonial Card',
1091
+ description: 'Minimalist card for user quotes and reviews.',
1092
+ category: 'cards',
1093
+ tags: ["card","testimonial"],
1094
+ featured: true,
1095
+ code: `---
1096
+ /**
1097
+ * TestimonialCardClean — Minimalist card for user quotes and reviews.
1098
+ *
1099
+ * @param {string} quote - The body of the testimonial review.
1100
+ * @param {string} name - The reviewer's full name.
1101
+ * @param {string} role - The reviewer's job title or company role.
1102
+ * @param {string} avatarUrl - Optional string tracking the avatar headshot URL.
1103
+ */
1104
+ interface Props {
1105
+ quote: string;
1106
+ name: string;
1107
+ role: string;
1108
+ avatarUrl?: string;
1109
+ }
1110
+
1111
+ const { quote, name, role, avatarUrl } = Astro.props;
1112
+ ---
1113
+
1114
+ <div class="testi-card">
1115
+ <blockquote class="testi-card__quote">"{quote}"</blockquote>
1116
+ <div class="testi-card__author">
1117
+ <div class="testi-card__pic" style={avatarUrl ? \`background-image: url('\${avatarUrl}'); background-size: cover;\` : ''}></div>
1118
+ <div class="testi-card__info">
1119
+ <h5 class="testi-card__name">{name}</h5>
1120
+ <span class="testi-card__role">{role}</span>
1121
+ </div>
1122
+ </div>
1123
+ </div>
1124
+
1125
+ <style>
1126
+ .testi-card {
1127
+ background: var(--c-bg-elev, rgba(255,255,255,0.03));
1128
+ padding: var(--sp-8, 2rem);
1129
+ border-radius: var(--r-xl, 20px);
1130
+ border: 1px solid var(--c-border, rgba(255,255,255,0.1));
1131
+ }
1132
+ .testi-card__quote {
1133
+ font-size: 1rem; color: var(--c-text-1, #e2e8f0);
1134
+ font-style: italic; line-height: 1.6;
1135
+ margin: 0 0 2rem 0;
1136
+ }
1137
+ .testi-card__author { display: flex; align-items: center; gap: var(--sp-4, 1rem); }
1138
+ .testi-card__pic {
1139
+ width: 40px; height: 40px;
1140
+ background: var(--c-bg, #334155);
1141
+ border-radius: var(--r-full, 50%);
1142
+ }
1143
+ .testi-card__name { margin: 0; color: var(--c-text-1, #fff); font-size: 0.95rem; }
1144
+ .testi-card__role { font-size: 0.75rem; color: var(--c-text-2, #64748b); }
1145
+ </style>
1146
+ `,
1147
+ usage: `<TestimonialCardClean quote="Best library ever." name="Alex Rivera" role="CTO at TechFlow" />`,
1148
+ },
1149
+ {
1150
+ slug: 'weather-widget-card',
1151
+ name: 'Weather Widget',
1152
+ description: 'Glassmorphism card showing weather conditions.',
1153
+ category: 'cards',
1154
+ tags: ["card","weather"],
1155
+ featured: true,
1156
+ code: `---
1157
+ /**
1158
+ * WeatherWidgetCard — Glassmorphism card showing weather conditions.
1159
+ *
1160
+ * @param {string} temp - The formatted temperature (e.g. "24°").
1161
+ * @param {string} city - The location name.
1162
+ * @param {string} condition - Short weather condition string (e.g. "Partly Cloudy").
1163
+ * @param {string} icon - Emoji or symbol representing the weather.
1164
+ */
1165
+ interface Props {
1166
+ temp: string;
1167
+ city: string;
1168
+ condition: string;
1169
+ icon: string;
1170
+ }
1171
+
1172
+ const { temp, city, condition, icon } = Astro.props;
1173
+ ---
1174
+
1175
+ <div class="weather-card">
1176
+ <div class="weather-card__temp">{temp}</div>
1177
+ <div class="weather-card__city">
1178
+ <h4 class="weather-card__name">{city}</h4>
1179
+ <p class="weather-card__cond">{condition}</p>
1180
+ </div>
1181
+ <div class="weather-card__icon" aria-hidden="true">{icon}</div>
1182
+ </div>
1183
+
1184
+ <style>
1185
+ .weather-card {
1186
+ display: flex; align-items: center; gap: var(--sp-6, 1.5rem);
1187
+ padding: var(--sp-6, 1.5rem);
1188
+ background: linear-gradient(135deg, rgba(99,102,241,0.2), rgba(192,132,252,0.2));
1189
+ backdrop-filter: blur(20px);
1190
+ border: 1px solid var(--c-border, rgba(255,255,255,0.15));
1191
+ border-radius: var(--r-xl, 24px);
1192
+ color: var(--c-text-1, #fff);
1193
+ }
1194
+ .weather-card__temp { font-size: 2.2rem; font-weight: 800; }
1195
+ .weather-card__name { margin: 0; font-size: 1rem; }
1196
+ .weather-card__cond { margin: 0; font-size: 0.8rem; opacity: 0.7; }
1197
+ .weather-card__icon { font-size: 2.5rem; margin-left: auto; }
1198
+ </style>
1199
+ `,
1200
+ usage: `<WeatherWidgetCard temp="24°" city="Sunnyvale" condition="Clear" icon="☀️" />`,
1201
+ },
1202
+ {
1203
+ slug: 'pricing-compare-mini-card',
1204
+ name: 'Pricing Compare Mini Card',
1205
+ description: 'A compact pricing tier card with gradient spotlight highlight, feature checkmarks, and CTA.',
1206
+ category: 'cards',
1207
+ tags: ["cards","pricing","tier","plan","commerce"],
1208
+ featured: true,
1209
+ code: `---
1210
+ /**
1211
+ * PricingCompareMiniCard — High-conversion mini pricing card with plan perks, price tier, and action button.
1212
+ *
1213
+ * @param {string} planName - Plan name (e.g. 'Pro Developer').
1214
+ * @param {string} price - Price figure (e.g. '$29').
1215
+ * @param {string} period - Frequency string (e.g. '/month').
1216
+ * @param {string} description - Plan highlight subtitle.
1217
+ * @param {string[]} features - List of plan feature bullet points.
1218
+ * @param {boolean} featured - Whether the card is visually emphasized.
1219
+ * @param {string} ctaText - Label for the call to action button. Default is 'Get Started'.
1220
+ * @param {string} ctaHref - Link URL for the button.
1221
+ */
1222
+ interface Props {
1223
+ planName: string;
1224
+ price: string;
1225
+ period?: string;
1226
+ description?: string;
1227
+ features?: string[];
1228
+ featured?: boolean;
1229
+ ctaText?: string;
1230
+ ctaHref?: string;
1231
+ }
1232
+
1233
+ const {
1234
+ planName,
1235
+ price,
1236
+ period = '/month',
1237
+ description = 'For growing teams and fast production workflows.',
1238
+ features = [
1239
+ 'Unlimited UI components',
1240
+ 'Full source code access',
1241
+ 'Commercial license',
1242
+ 'Community Discord support',
1243
+ ],
1244
+ featured = false,
1245
+ ctaText = 'Get Started',
1246
+ ctaHref = '#',
1247
+ } = Astro.props;
1248
+ ---
1249
+
1250
+ <div class:list={['mini-price-card', { 'mini-price-card--featured': featured }]}>
1251
+ {featured && <span class="mini-price-card__badge">Most Popular</span>}
1252
+
1253
+ <div class="mini-price-card__header">
1254
+ <h3 class="mini-price-card__plan">{planName}</h3>
1255
+ <p class="mini-price-card__desc">{description}</p>
1256
+ <div class="mini-price-card__amount">
1257
+ <span class="val">{price}</span>
1258
+ <span class="period">{period}</span>
1259
+ </div>
1260
+ </div>
1261
+
1262
+ <ul class="mini-price-card__features">
1263
+ {features.map((feat) => (
1264
+ <li class="mini-price-card__feature">
1265
+ <svg class="check-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
1266
+ <polyline points="20 6 9 17 4 12" />
1267
+ </svg>
1268
+ <span>{feat}</span>
1269
+ </li>
1270
+ ))}
1271
+ </ul>
1272
+
1273
+ <a href={ctaHref} class="mini-price-card__btn">
1274
+ {ctaText}
1275
+ <span aria-hidden="true">→</span>
1276
+ </a>
1277
+ </div>
1278
+
1279
+ <style>
1280
+ .mini-price-card {
1281
+ position: relative;
1282
+ display: flex;
1283
+ flex-direction: column;
1284
+ padding: var(--sp-6, 1.5rem);
1285
+ background: rgba(255, 255, 255, 0.02);
1286
+ backdrop-filter: blur(20px);
1287
+ border: 1px solid rgba(255, 255, 255, 0.08);
1288
+ border-radius: var(--r-xl, 24px);
1289
+ width: 100%;
1290
+ max-width: 320px;
1291
+ font-family: var(--font-sans, system-ui, sans-serif);
1292
+ transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.3s ease, box-shadow 0.3s ease;
1293
+ }
1294
+
1295
+ .mini-price-card:hover {
1296
+ transform: translateY(-4px);
1297
+ border-color: rgba(184, 134, 11, 0.3);
1298
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
1299
+ }
1300
+
1301
+ .mini-price-card--featured {
1302
+ border-color: rgba(184, 134, 11, 0.5);
1303
+ background: radial-gradient(circle at top, rgba(184, 134, 11, 0.12), rgba(255, 255, 255, 0.02) 60%);
1304
+ box-shadow: 0 12px 36px rgba(184, 134, 11, 0.15);
1305
+ }
1306
+
1307
+ .mini-price-card__badge {
1308
+ position: absolute;
1309
+ top: -12px;
1310
+ right: 20px;
1311
+ background: linear-gradient(135deg, #d4a017, #b8860b);
1312
+ color: #050505;
1313
+ font-size: 0.72rem;
1314
+ font-weight: 800;
1315
+ text-transform: uppercase;
1316
+ letter-spacing: 0.06em;
1317
+ padding: 0.25rem 0.75rem;
1318
+ border-radius: var(--r-full, 9999px);
1319
+ box-shadow: 0 4px 12px rgba(184, 134, 11, 0.4);
1320
+ }
1321
+
1322
+ .mini-price-card__plan {
1323
+ font-size: 1.15rem;
1324
+ font-weight: 800;
1325
+ color: var(--c-text-1, #ffffff);
1326
+ margin: 0;
1327
+ }
1328
+
1329
+ .mini-price-card__desc {
1330
+ font-size: 0.8rem;
1331
+ color: var(--c-text-2, #a3a3a3);
1332
+ margin: 4px 0 16px 0;
1333
+ line-height: 1.45;
1334
+ }
1335
+
1336
+ .mini-price-card__amount {
1337
+ display: flex;
1338
+ align-items: baseline;
1339
+ gap: 4px;
1340
+ margin-bottom: var(--sp-4, 1rem);
1341
+ padding-bottom: var(--sp-4, 1rem);
1342
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
1343
+ }
1344
+
1345
+ .mini-price-card__amount .val {
1346
+ font-size: 2.2rem;
1347
+ font-weight: 900;
1348
+ color: var(--c-text-1, #ffffff);
1349
+ letter-spacing: -0.03em;
1350
+ }
1351
+
1352
+ .mini-price-card__amount .period {
1353
+ font-size: 0.82rem;
1354
+ color: var(--c-text-3, #737373);
1355
+ }
1356
+
1357
+ .mini-price-card__features {
1358
+ list-style: none;
1359
+ display: flex;
1360
+ flex-direction: column;
1361
+ gap: 10px;
1362
+ margin: 0 0 24px 0;
1363
+ padding: 0;
1364
+ flex: 1;
1365
+ }
1366
+
1367
+ .mini-price-card__feature {
1368
+ display: flex;
1369
+ align-items: center;
1370
+ gap: 10px;
1371
+ font-size: 0.82rem;
1372
+ color: var(--c-text-2, #a3a3a3);
1373
+ }
1374
+
1375
+ .check-icon {
1376
+ color: var(--c-primary-light, #d4a017);
1377
+ flex-shrink: 0;
1378
+ }
1379
+
1380
+ .mini-price-card__btn {
1381
+ display: inline-flex;
1382
+ align-items: center;
1383
+ justify-content: center;
1384
+ gap: 8px;
1385
+ width: 100%;
1386
+ padding: 0.75rem;
1387
+ background: rgba(255, 255, 255, 0.06);
1388
+ color: var(--c-text-1, #ffffff);
1389
+ font-size: 0.88rem;
1390
+ font-weight: 700;
1391
+ text-decoration: none;
1392
+ border-radius: var(--r-md, 12px);
1393
+ border: 1px solid rgba(255, 255, 255, 0.1);
1394
+ transition: all 0.25s ease;
1395
+ }
1396
+
1397
+ .mini-price-card--featured .mini-price-card__btn,
1398
+ .mini-price-card__btn:hover {
1399
+ background: linear-gradient(135deg, #d4a017, #b8860b);
1400
+ color: #050505;
1401
+ border-color: transparent;
1402
+ box-shadow: 0 6px 20px rgba(184, 134, 11, 0.35);
1403
+ }
1404
+ </style>
1405
+ `,
1406
+ usage: `<PricingCompareMiniCard title="Pro Plan" price="$29" period="/month" description="For scaling teams" features={['Unlimited components', 'Priority support', 'Commercial license']} isPopular={true} ctaText="Upgrade to Pro" />`,
1407
+ },
1408
+ {
1409
+ slug: 'github-repo-card',
1410
+ name: 'Github Repo Card',
1411
+ description: 'Clean developer portfolio card displaying GitHub repository name, description, language dot, star count, and fork stats.',
1412
+ category: 'cards',
1413
+ tags: ["cards","github","repo","developer","portfolio"],
1414
+ featured: true,
1415
+ code: `---
1416
+ /**
1417
+ * GithubRepoCard — Dark glass card highlighting repository statistics, language dot, license, and stars.
1418
+ *
1419
+ * @param {string} repoName - Repository name (e.g. 'astro-components').
1420
+ * @param {string} owner - Repo owner or organization (e.g. 'konstantinWDK').
1421
+ * @param {string} description - Brief summary of the repo.
1422
+ * @param {string} language - Primary programming language. Default is 'TypeScript'.
1423
+ * @param {string} languageColor - Hex color for the language dot. Default is '#3178c6'.
1424
+ * @param {number} stars - Star count figure. Default is 248.
1425
+ * @param {number} forks - Fork count figure. Default is 32.
1426
+ * @param {string} href - Link to the GitHub repository.
1427
+ */
1428
+ interface Props {
1429
+ repoName: string;
1430
+ owner?: string;
1431
+ description?: string;
1432
+ language?: string;
1433
+ languageColor?: string;
1434
+ stars?: number;
1435
+ forks?: number;
1436
+ href?: string;
1437
+ }
1438
+
1439
+ const {
1440
+ repoName,
1441
+ owner = 'konstantinWDK',
1442
+ description = 'Premium open-source UI component library for Astro with glassmorphism and accessibility.',
1443
+ language = 'TypeScript',
1444
+ languageColor = '#3178c6',
1445
+ stars = 248,
1446
+ forks = 32,
1447
+ href = '#',
1448
+ } = Astro.props;
1449
+ ---
1450
+
1451
+ <a href={href} target="_blank" rel="noopener noreferrer" class="gh-repo-card">
1452
+ <div class="gh-repo-card__head">
1453
+ <svg class="gh-repo-card__icon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1454
+ <path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1-2.5-2.5Z"/>
1455
+ <path d="M6 6h10"/>
1456
+ <path d="M6 10h10"/>
1457
+ </svg>
1458
+ <div class="gh-repo-card__title-wrap">
1459
+ <span class="owner">{owner}/</span>
1460
+ <h4 class="name">{repoName}</h4>
1461
+ </div>
1462
+ <span class="gh-repo-card__badge">Public</span>
1463
+ </div>
1464
+
1465
+ <p class="gh-repo-card__desc">{description}</p>
1466
+
1467
+ <div class="gh-repo-card__meta">
1468
+ <div class="gh-repo-card__lang">
1469
+ <span class="lang-dot" style={\`background-color: \${languageColor};\`}></span>
1470
+ <span>{language}</span>
1471
+ </div>
1472
+
1473
+ <div class="gh-repo-card__stat">
1474
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
1475
+ <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
1476
+ </svg>
1477
+ <span>{stars.toLocaleString()}</span>
1478
+ </div>
1479
+
1480
+ <div class="gh-repo-card__stat">
1481
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1482
+ <line x1="6" y1="3" x2="6" y2="15"/>
1483
+ <circle cx="18" cy="6" r="3"/>
1484
+ <circle cx="6" cy="18" r="3"/>
1485
+ <path d="M18 9a9 9 0 0 1-9 9"/>
1486
+ </svg>
1487
+ <span>{forks.toLocaleString()}</span>
1488
+ </div>
1489
+ </div>
1490
+ </a>
1491
+
1492
+ <style>
1493
+ .gh-repo-card {
1494
+ display: flex;
1495
+ flex-direction: column;
1496
+ padding: var(--sp-6, 1.5rem);
1497
+ background: rgba(255, 255, 255, 0.02);
1498
+ backdrop-filter: blur(16px);
1499
+ border: 1px solid rgba(255, 255, 255, 0.08);
1500
+ border-radius: var(--r-xl, 20px);
1501
+ text-decoration: none;
1502
+ width: 100%;
1503
+ max-width: 360px;
1504
+ font-family: var(--font-sans, system-ui, sans-serif);
1505
+ transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
1506
+ }
1507
+
1508
+ .gh-repo-card:hover {
1509
+ transform: translateY(-3px);
1510
+ border-color: rgba(184, 134, 11, 0.4);
1511
+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
1512
+ }
1513
+
1514
+ .gh-repo-card__head {
1515
+ display: flex;
1516
+ align-items: center;
1517
+ gap: 8px;
1518
+ margin-bottom: 8px;
1519
+ }
1520
+
1521
+ .gh-repo-card__icon {
1522
+ color: var(--c-primary-light, #d4a017);
1523
+ flex-shrink: 0;
1524
+ }
1525
+
1526
+ .gh-repo-card__title-wrap {
1527
+ display: flex;
1528
+ align-items: baseline;
1529
+ gap: 2px;
1530
+ overflow: hidden;
1531
+ }
1532
+
1533
+ .gh-repo-card__title-wrap .owner {
1534
+ font-size: 0.82rem;
1535
+ color: var(--c-text-3, #737373);
1536
+ }
1537
+
1538
+ .gh-repo-card__title-wrap .name {
1539
+ font-size: 0.95rem;
1540
+ font-weight: 700;
1541
+ color: var(--c-primary-light, #d4a017);
1542
+ margin: 0;
1543
+ }
1544
+
1545
+ .gh-repo-card__badge {
1546
+ margin-left: auto;
1547
+ font-size: 0.65rem;
1548
+ font-weight: 700;
1549
+ color: var(--c-text-2, #a3a3a3);
1550
+ background: rgba(255, 255, 255, 0.06);
1551
+ border: 1px solid rgba(255, 255, 255, 0.1);
1552
+ padding: 2px 8px;
1553
+ border-radius: var(--r-full, 9999px);
1554
+ }
1555
+
1556
+ .gh-repo-card__desc {
1557
+ font-size: 0.82rem;
1558
+ color: var(--c-text-2, #a3a3a3);
1559
+ margin: 0 0 16px 0;
1560
+ line-height: 1.5;
1561
+ flex: 1;
1562
+ }
1563
+
1564
+ .gh-repo-card__meta {
1565
+ display: flex;
1566
+ align-items: center;
1567
+ gap: 16px;
1568
+ font-size: 0.78rem;
1569
+ color: var(--c-text-3, #737373);
1570
+ }
1571
+
1572
+ .gh-repo-card__lang {
1573
+ display: flex;
1574
+ align-items: center;
1575
+ gap: 6px;
1576
+ }
1577
+
1578
+ .lang-dot {
1579
+ width: 10px;
1580
+ height: 10px;
1581
+ border-radius: 50%;
1582
+ }
1583
+
1584
+ .gh-repo-card__stat {
1585
+ display: flex;
1586
+ align-items: center;
1587
+ gap: 5px;
1588
+ color: var(--c-text-2, #a3a3a3);
1589
+ }
1590
+ </style>
1591
+ `,
1592
+ usage: `<GithubRepoCard repoName="astro-components" repoOwner="konstantinwdk" description="Accessible glassmorphic Astro UI component library" language="TypeScript" languageColor="#3178c6" stars={482} forks={64} />`,
1593
+ },
1594
+ {
1595
+ slug: 'stats-trend-card',
1596
+ name: 'Stats Trend Card',
1597
+ description: 'Modern analytics KPI metric card displaying values, positive/negative delta trend badge, and mini sparkline bar visual.',
1598
+ category: 'cards',
1599
+ tags: ["cards","stats","analytics","kpi","dashboard"],
1600
+ featured: false,
1601
+ code: `---
1602
+ /**
1603
+ * StatsTrendCard — Compact KPI metric card featuring delta percentages, trend directions, and mini activity bars.
1604
+ *
1605
+ * @param {string} label - Metric name (e.g. 'Active Users').
1606
+ * @param {string} value - Formatted value figure (e.g. '42,850').
1607
+ * @param {string} change - Delta percentage string (e.g. '+18.4%').
1608
+ * @param {'up' | 'down' | 'neutral'} trend - Direction of the trend. Default is 'up'.
1609
+ * @param {string} timeframe - Timeframe subtitle (e.g. 'vs last month').
1610
+ */
1611
+ interface Props {
1612
+ label: string;
1613
+ value: string;
1614
+ change: string;
1615
+ trend?: 'up' | 'down' | 'neutral';
1616
+ timeframe?: string;
1617
+ }
1618
+
1619
+ const {
1620
+ label,
1621
+ value,
1622
+ change,
1623
+ trend = 'up',
1624
+ timeframe = 'vs last 30 days',
1625
+ } = Astro.props;
1626
+
1627
+ const bars = [35, 55, 40, 75, 60, 90, 80, 100];
1628
+ ---
1629
+
1630
+ <div class="trend-card">
1631
+ <div class="trend-card__top">
1632
+ <span class="trend-card__label">{label}</span>
1633
+ <span class:list={['trend-card__badge', \`trend-card__badge--\${trend}\`]}>
1634
+ {trend === 'up' && '↑'}
1635
+ {trend === 'down' && '↓'}
1636
+ {change}
1637
+ </span>
1638
+ </div>
1639
+
1640
+ <div class="trend-card__value">{value}</div>
1641
+
1642
+ <div class="trend-card__bottom">
1643
+ <span class="trend-card__timeframe">{timeframe}</span>
1644
+ <div class="trend-card__chart" aria-hidden="true">
1645
+ {bars.map((h) => (
1646
+ <span class="bar" style={\`height: \${h}%;\`}></span>
1647
+ ))}
1648
+ </div>
1649
+ </div>
1650
+ </div>
1651
+
1652
+ <style>
1653
+ .trend-card {
1654
+ display: flex;
1655
+ flex-direction: column;
1656
+ padding: var(--sp-6, 1.5rem);
1657
+ background: rgba(255, 255, 255, 0.02);
1658
+ backdrop-filter: blur(16px);
1659
+ border: 1px solid rgba(255, 255, 255, 0.08);
1660
+ border-radius: var(--r-xl, 20px);
1661
+ width: 100%;
1662
+ max-width: 280px;
1663
+ font-family: var(--font-sans, system-ui, sans-serif);
1664
+ transition: transform 0.25s ease, border-color 0.25s ease;
1665
+ }
1666
+
1667
+ .trend-card:hover {
1668
+ transform: translateY(-2px);
1669
+ border-color: rgba(184, 134, 11, 0.3);
1670
+ }
1671
+
1672
+ .trend-card__top {
1673
+ display: flex;
1674
+ justify-content: space-between;
1675
+ align-items: center;
1676
+ margin-bottom: 8px;
1677
+ }
1678
+
1679
+ .trend-card__label {
1680
+ font-size: 0.8rem;
1681
+ font-weight: 600;
1682
+ color: var(--c-text-2, #a3a3a3);
1683
+ }
1684
+
1685
+ .trend-card__badge {
1686
+ font-size: 0.72rem;
1687
+ font-weight: 700;
1688
+ padding: 2px 8px;
1689
+ border-radius: var(--r-full, 9999px);
1690
+ display: inline-flex;
1691
+ align-items: center;
1692
+ gap: 2px;
1693
+ }
1694
+
1695
+ .trend-card__badge--up {
1696
+ background: rgba(16, 185, 129, 0.15);
1697
+ color: #34d399;
1698
+ border: 1px solid rgba(16, 185, 129, 0.3);
1699
+ }
1700
+
1701
+ .trend-card__badge--down {
1702
+ background: rgba(239, 68, 68, 0.15);
1703
+ color: #f87171;
1704
+ border: 1px solid rgba(239, 68, 68, 0.3);
1705
+ }
1706
+
1707
+ .trend-card__badge--neutral {
1708
+ background: rgba(255, 255, 255, 0.08);
1709
+ color: var(--c-text-2, #a3a3a3);
1710
+ }
1711
+
1712
+ .trend-card__value {
1713
+ font-size: 1.85rem;
1714
+ font-weight: 900;
1715
+ color: var(--c-text-1, #ffffff);
1716
+ letter-spacing: -0.02em;
1717
+ margin-bottom: 12px;
1718
+ }
1719
+
1720
+ .trend-card__bottom {
1721
+ display: flex;
1722
+ justify-content: space-between;
1723
+ align-items: flex-end;
1724
+ }
1725
+
1726
+ .trend-card__timeframe {
1727
+ font-size: 0.74rem;
1728
+ color: var(--c-text-3, #737373);
1729
+ }
1730
+
1731
+ .trend-card__chart {
1732
+ display: flex;
1733
+ align-items: flex-end;
1734
+ gap: 3px;
1735
+ height: 24px;
1736
+ width: 60px;
1737
+ }
1738
+
1739
+ .bar {
1740
+ flex: 1;
1741
+ background: rgba(184, 134, 11, 0.35);
1742
+ border-radius: 2px;
1743
+ transition: background 0.2s;
1744
+ }
1745
+
1746
+ .trend-card:hover .bar {
1747
+ background: var(--c-primary-light, #d4a017);
1748
+ }
1749
+ </style>
1750
+ `,
1751
+ usage: `<StatsTrendCard title="Active Subscriptions" value="14,290" change="+12.8%" isPositive={true} subtitle="Compared to previous 30 days" />`,
1752
+ },
1753
+ ];