astro-component-kit 0.3.0 → 0.4.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.
Files changed (115) hide show
  1. package/README.md +159 -176
  2. package/package.json +2 -2
  3. package/src/components/index.ts +16 -202
  4. package/src/components/lib/buttons/NeonBorderButton.astro +162 -0
  5. package/src/components/lib/buttons/RippleButton.astro +199 -0
  6. package/src/components/lib/buttons/SlideRevealButton.astro +159 -0
  7. package/src/components/lib/buttons/index.ts +4 -0
  8. package/src/components/lib/cards/GithubRepoCard.astro +176 -0
  9. package/src/components/lib/cards/PricingCompareMiniCard.astro +196 -0
  10. package/src/components/lib/cards/StatsTrendCard.astro +149 -0
  11. package/src/components/lib/cards/index.ts +3 -0
  12. package/src/components/lib/charts/ActivityRings.astro +105 -0
  13. package/src/components/lib/charts/BoxPlotChart.astro +109 -0
  14. package/src/components/lib/charts/BubbleChart.astro +101 -0
  15. package/src/components/lib/charts/BulletChart.astro +160 -0
  16. package/src/components/lib/charts/BumpChart.astro +92 -0
  17. package/src/components/lib/charts/CandlestickChart.astro +105 -0
  18. package/src/components/lib/charts/ChartFrame.astro +373 -0
  19. package/src/components/lib/charts/DivergingBarChart.astro +98 -0
  20. package/src/components/lib/charts/DumbbellChart.astro +92 -0
  21. package/src/components/lib/charts/ForecastLineChart.astro +125 -0
  22. package/src/components/lib/charts/FunnelChart.astro +122 -0
  23. package/src/components/lib/charts/GaugeChart.astro +111 -0
  24. package/src/components/lib/charts/GoalProgressChart.astro +97 -0
  25. package/src/components/lib/charts/GroupedBarChart.astro +125 -0
  26. package/src/components/lib/charts/HeatmapChart.astro +131 -0
  27. package/src/components/lib/charts/HistogramChart.astro +111 -0
  28. package/src/components/lib/charts/HorizontalBarChart.astro +155 -0
  29. package/src/components/lib/charts/KpiStatTile.astro +116 -0
  30. package/src/components/lib/charts/KpiTrendGrid.astro +60 -0
  31. package/src/components/lib/charts/LineChart.astro +160 -0
  32. package/src/components/lib/charts/LinearProgressGauge.astro +136 -0
  33. package/src/components/lib/charts/LollipopChart.astro +100 -0
  34. package/src/components/lib/charts/MeterGauge.astro +122 -0
  35. package/src/components/lib/charts/MetricDeltaTable.astro +125 -0
  36. package/src/components/lib/charts/PieChart.astro +135 -0
  37. package/src/components/lib/charts/PolarAreaChart.astro +85 -0
  38. package/src/components/lib/charts/PopulationPyramid.astro +122 -0
  39. package/src/components/lib/charts/PunchCardChart.astro +89 -0
  40. package/src/components/lib/charts/RadarChart.astro +94 -0
  41. package/src/components/lib/charts/RadarMetricChart.astro +168 -0
  42. package/src/components/lib/charts/RadialBarChart.astro +124 -0
  43. package/src/components/lib/charts/RangeAreaChart.astro +113 -0
  44. package/src/components/lib/charts/RetentionCohortTable.astro +126 -0
  45. package/src/components/lib/charts/SankeyChart.astro +128 -0
  46. package/src/components/lib/charts/ScatterPlot.astro +139 -0
  47. package/src/components/lib/charts/SegmentedBarChart.astro +119 -0
  48. package/src/components/lib/charts/SlopeChart.astro +105 -0
  49. package/src/components/lib/charts/SparklineChart.astro +87 -0
  50. package/src/components/lib/charts/StackedAreaChart.astro +130 -0
  51. package/src/components/lib/charts/StackedBarChart.astro +136 -0
  52. package/src/components/lib/charts/SunburstChart.astro +103 -0
  53. package/src/components/lib/charts/TreemapChart.astro +94 -0
  54. package/src/components/lib/charts/WaffleChart.astro +121 -0
  55. package/src/components/lib/charts/WaterfallChart.astro +118 -0
  56. package/src/components/lib/charts/chart-tooltip.ts +75 -0
  57. package/src/components/lib/charts/chart-utils.ts +271 -0
  58. package/src/components/lib/charts/index.ts +46 -0
  59. package/src/components/lib/data/ActivityHeatmapGrid.astro +157 -0
  60. package/src/components/lib/data/MetricComparisonRow.astro +109 -0
  61. package/src/components/lib/data/StatusTimelineFeed.astro +168 -0
  62. package/src/components/lib/data/index.ts +3 -0
  63. package/src/components/lib/feedback/ProgressRingCounter.astro +118 -0
  64. package/src/components/lib/feedback/ToastNotificationGroup.astro +173 -0
  65. package/src/components/lib/feedback/index.ts +2 -0
  66. package/src/components/lib/forms/GlassInlineToggleGroup.astro +161 -0
  67. package/src/components/lib/forms/PasswordStrengthInput.astro +242 -0
  68. package/src/components/lib/forms/PhoneCountryInput.astro +145 -0
  69. package/src/components/lib/forms/TagsAutocompleteInput.astro +249 -0
  70. package/src/components/lib/forms/index.ts +5 -0
  71. package/src/components/lib/layout/DiagonalSectionDivider.astro +69 -0
  72. package/src/components/lib/layout/HolyGrailGrid.astro +125 -0
  73. package/src/components/lib/layout/index.ts +3 -1
  74. package/src/components/lib/navigation/QuickJumpDock.astro +125 -0
  75. package/src/components/lib/navigation/StepBreadcrumbBar.astro +151 -0
  76. package/src/components/lib/navigation/SubNavbarPills.astro +102 -0
  77. package/src/components/lib/navigation/index.ts +3 -0
  78. package/src/components/lib/overlays/CookiePreferencesDrawer.astro +226 -0
  79. package/src/components/lib/overlays/FloatingFeedbackWidget.astro +203 -0
  80. package/src/components/lib/overlays/ImageCompareSlider.astro +172 -0
  81. package/src/components/lib/overlays/index.ts +3 -0
  82. package/src/components/lib/sections/BlogGridSection.astro +131 -0
  83. package/src/components/lib/sections/CareersOpenings.astro +139 -0
  84. package/src/components/lib/sections/ChangelogSection.astro +144 -0
  85. package/src/components/lib/sections/ContactSplitMap.astro +139 -0
  86. package/src/components/lib/sections/CtaNewsletterSection.astro +163 -0
  87. package/src/components/lib/sections/CtaSplitImage.astro +147 -0
  88. package/src/components/lib/sections/FaqTwoColumn.astro +119 -0
  89. package/src/components/lib/sections/FeatureAlternatingRows.astro +190 -0
  90. package/src/components/lib/sections/FeatureIconGrid.astro +155 -0
  91. package/src/components/lib/sections/FeatureTabsShowcase.astro +180 -0
  92. package/src/components/lib/sections/FooterMegaSection.astro +155 -0
  93. package/src/components/lib/sections/HeroDashboardPreview.astro +180 -0
  94. package/src/components/lib/sections/HeroMinimalCentered.astro +175 -0
  95. package/src/components/lib/sections/HeroShowcaseSplit.astro +304 -0
  96. package/src/components/lib/sections/HeroTerminal.astro +251 -0
  97. package/src/components/lib/sections/HeroWaitlist.astro +229 -0
  98. package/src/components/lib/sections/HowItWorksSteps.astro +178 -0
  99. package/src/components/lib/sections/IntegrationsGrid.astro +167 -0
  100. package/src/components/lib/sections/LogoCloudSection.astro +96 -0
  101. package/src/components/lib/sections/LogoWallGrid.astro +91 -0
  102. package/src/components/lib/sections/PricingSinglePlan.astro +157 -0
  103. package/src/components/lib/sections/PricingToggleCards.astro +171 -0
  104. package/src/components/lib/sections/StatsCounterBand.astro +122 -0
  105. package/src/components/lib/sections/StatsDashboardSection.astro +83 -0
  106. package/src/components/lib/sections/TestimonialCarousel.astro +165 -0
  107. package/src/components/lib/sections/TestimonialFeatured.astro +120 -0
  108. package/src/components/lib/sections/TestimonialGridSection.astro +188 -0
  109. package/src/components/lib/sections/index.ts +29 -0
  110. package/src/components/lib/typography/AnimatedCounterText.astro +102 -0
  111. package/src/components/lib/typography/CurvedPathHeading.astro +86 -0
  112. package/src/components/lib/typography/GradientTextMarquee.astro +105 -0
  113. package/src/components/lib/typography/HackerDecodeText.astro +85 -0
  114. package/src/components/lib/typography/index.ts +4 -0
  115. package/src/styles/global.css +18 -1
@@ -0,0 +1,155 @@
1
+ ---
2
+ /**
3
+ * FooterMegaSection — Full site footer: brand blurb, newsletter field, four link
4
+ * columns, social icons, system-status pill and legal row.
5
+ *
6
+ * @param {string} brand - Brand name.
7
+ * @param {string} tagline - Short brand description.
8
+ * @param {Array<{title: string, links: Array<{label: string, href: string}>}>} columns - Link columns.
9
+ * @param {Array<{label: string, href: string, icon: 'github'|'x'|'discord'|'youtube'}>} socials - Social links.
10
+ * @param {string} status - System status text (empty to hide).
11
+ * @param {string} copyright - Copyright line.
12
+ * @param {string} variant - Footer style (default|bordered|minimal).
13
+ * @param {string} size - Vertical rhythm (sm|md|lg).
14
+ * @param {string} className - Extra CSS class.
15
+ */
16
+ interface Column { title: string; links: Array<{ label: string; href: string }> }
17
+ interface Social { label: string; href: string; icon: 'github' | 'x' | 'discord' | 'youtube' }
18
+ interface Props {
19
+ brand?: string;
20
+ tagline?: string;
21
+ columns?: Column[];
22
+ socials?: Social[];
23
+ status?: string;
24
+ copyright?: string;
25
+ variant?: 'default' | 'bordered' | 'minimal';
26
+ size?: 'sm' | 'md' | 'lg';
27
+ className?: string;
28
+ }
29
+
30
+ const {
31
+ brand = 'Astro Kit',
32
+ tagline = 'Accessible, zero-dependency components for building beautiful Astro sites.',
33
+ columns = [
34
+ { title: 'Product', links: [{ label: 'Components', href: '#' }, { label: 'Sections', href: '#' }, { label: 'Charts', href: '#' }, { label: 'Changelog', href: '#' }] },
35
+ { title: 'Resources', links: [{ label: 'Documentation', href: '#' }, { label: 'Installation', href: '#' }, { label: 'Notes', href: '#' }, { label: 'Showcase', href: '#' }] },
36
+ { title: 'Company', links: [{ label: 'About', href: '#' }, { label: 'Careers', href: '#' }, { label: 'Contact', href: '#' }] },
37
+ { title: 'Legal', links: [{ label: 'Privacy', href: '#' }, { label: 'Terms', href: '#' }, { label: 'License (MIT)', href: '#' }] },
38
+ ],
39
+ socials = [
40
+ { label: 'GitHub', href: '#', icon: 'github' },
41
+ { label: 'X (Twitter)', href: '#', icon: 'x' },
42
+ { label: 'Discord', href: '#', icon: 'discord' },
43
+ { label: 'YouTube', href: '#', icon: 'youtube' },
44
+ ],
45
+ status = 'All systems operational',
46
+ copyright = `© ${new Date().getFullYear()} Astro Kit. All rights reserved.`,
47
+ variant = 'default',
48
+ size = 'md',
49
+ className = '',
50
+ } = Astro.props;
51
+
52
+ const icons = {
53
+ github: '<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.9a3.4 3.4 0 0 0-.9-2.6c3.1-.4 6.4-1.5 6.4-7A5.4 5.4 0 0 0 20 4.8 5 5 0 0 0 19.9 1S18.7.6 16 2.5a13.4 13.4 0 0 0-7 0C6.3.6 5.1 1 5.1 1A5 5 0 0 0 5 4.8a5.4 5.4 0 0 0-1.5 3.7c0 5.4 3.3 6.6 6.4 7a3.4 3.4 0 0 0-.9 2.6V22"/>',
54
+ x: '<path d="M4 4l16 16M20 4 4 20"/>',
55
+ discord: '<path d="M8 12h.01M16 12h.01"/><path d="M7.5 7.5c3-1 6-1 9 0M7 16.5c3 1 7 1 10 0"/><path d="M15.5 17l1 3c3-1 5-3 5.5-4.5.5-4-1-8-3-11-1.5-.8-3-1.2-4.5-1.5L14 4.5M8.5 17l-1 3c-3-1-5-3-5.5-4.5-.5-4 1-8 3-11 1.5-.8 3-1.2 4.5-1.5L10 4.5"/>',
56
+ youtube: '<path d="M2.5 17a24 24 0 0 1 0-10 2 2 0 0 1 1.4-1.4 49.6 49.6 0 0 1 16.2 0A2 2 0 0 1 21.5 7a24 24 0 0 1 0 10 2 2 0 0 1-1.4 1.4 49.6 49.6 0 0 1-16.2 0A2 2 0 0 1 2.5 17"/><path d="m10 15 5-3-5-3z"/>',
57
+ };
58
+ const id = `fms-${Math.random().toString(36).slice(2, 8)}`;
59
+ ---
60
+
61
+ <footer class={`fms fms--${variant} fms--${size} ${className}`} aria-labelledby={id}>
62
+ <h2 id={id} class="fms__sr">Site footer</h2>
63
+ <div class="fms__inner">
64
+ <div class="fms__top">
65
+ <div class="fms__brand">
66
+ <a class="fms__logo" href="/">
67
+ <svg width="28" height="28" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 2 3 20h4l5-10 5 10h4z" fill="var(--c-primary-light, #d4a017)" /></svg>
68
+ {brand}
69
+ </a>
70
+ <p class="fms__tagline">{tagline}</p>
71
+ <form class="fms__news" action="#" method="post">
72
+ <label for={`${id}-email`} class="fms__news-label">Get product updates</label>
73
+ <div class="fms__news-field">
74
+ <input id={`${id}-email`} type="email" name="email" placeholder="you@company.com" autocomplete="email" required />
75
+ <button type="submit" aria-label="Subscribe to product updates">
76
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
77
+ </button>
78
+ </div>
79
+ </form>
80
+ </div>
81
+ <nav class="fms__cols" aria-label="Footer">
82
+ {columns.map((c) => (
83
+ <div class="fms__col">
84
+ <h3 class="fms__col-title">{c.title}</h3>
85
+ <ul>
86
+ {c.links.map((l) => <li><a href={l.href}>{l.label}</a></li>)}
87
+ </ul>
88
+ </div>
89
+ ))}
90
+ </nav>
91
+ </div>
92
+ <div class="fms__bottom">
93
+ <p class="fms__copy">{copyright}</p>
94
+ {status && (
95
+ <a class="fms__status" href="#">
96
+ <span class="fms__dot" aria-hidden="true"></span>{status}
97
+ </a>
98
+ )}
99
+ <ul class="fms__socials">
100
+ {socials.map((s) => (
101
+ <li>
102
+ <a href={s.href} aria-label={s.label}>
103
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" set:html={icons[s.icon]}></svg>
104
+ </a>
105
+ </li>
106
+ ))}
107
+ </ul>
108
+ </div>
109
+ </div>
110
+ </footer>
111
+
112
+ <style>
113
+ .fms {
114
+ --fms-py: 4.5rem;
115
+ padding: var(--fms-py) var(--sp-6, 1.5rem) 2rem;
116
+ background: var(--c-bg-1, #0a0a0a);
117
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
118
+ }
119
+ .fms--sm { --fms-py: 3rem; }
120
+ .fms--lg { --fms-py: 6rem; }
121
+ .fms--bordered .fms__inner { padding: clamp(1.5rem, 4vw, 3rem); border-radius: var(--r-xl, 28px); border: 1px solid var(--c-border, rgba(255, 255, 255, 0.08)); background: rgba(255, 255, 255, 0.015); }
122
+ .fms--minimal { background: transparent; border-top: 0; }
123
+ .fms--minimal .fms__news { display: none; }
124
+ .fms__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
125
+ .fms__inner { max-width: 1180px; margin: 0 auto; }
126
+ .fms__top { display: grid; grid-template-columns: 1.2fr 2fr; gap: clamp(2rem, 6vw, 5rem); padding-bottom: 3rem; border-bottom: 1px solid rgba(255, 255, 255, 0.07); }
127
+ .fms__logo { display: inline-flex; align-items: center; gap: 0.6rem; min-height: 44px; font-size: 1.25rem; font-weight: 800; letter-spacing: -0.02em; color: var(--c-text-1, #fff); text-decoration: none; }
128
+ .fms__tagline { margin: 0.75rem 0 1.75rem; max-width: 320px; font-size: 0.9375rem; line-height: 1.6; color: var(--c-text-2, #a3a3a3); }
129
+ .fms__news-label { display: block; margin-bottom: 0.5rem; font-size: 0.8125rem; font-weight: 600; color: var(--c-text-1, #fff); }
130
+ .fms__news-field { display: flex; max-width: 340px; border-radius: var(--r-md, 12px); border: 1px solid rgba(255, 255, 255, 0.12); background: rgba(0, 0, 0, 0.3); overflow: hidden; transition: border-color 0.2s ease; }
131
+ .fms__news-field:focus-within { border-color: var(--c-primary-light, #d4a017); }
132
+ .fms__news-field input { flex: 1; min-width: 0; min-height: 46px; padding: 0 0.9rem; border: 0; background: transparent; color: var(--c-text-1, #fff); font: inherit; font-size: 0.9375rem; }
133
+ .fms__news-field input:focus { outline: none; }
134
+ .fms__news-field input::placeholder { color: var(--c-text-3, #737373); }
135
+ .fms__news-field button { width: 46px; border: 0; background: rgba(255, 255, 255, 0.06); color: var(--c-text-1, #fff); cursor: pointer; transition: background 0.2s ease; }
136
+ .fms__news-field button:hover { background: var(--c-primary-light, #d4a017); color: #0a0a0a; }
137
+ .fms__news-field button:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: -2px; }
138
+ .fms__cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 2rem; }
139
+ .fms__col-title { margin: 0 0 1rem; font-size: 0.8125rem; font-weight: 650; letter-spacing: 0.06em; text-transform: uppercase; color: var(--c-text-1, #fff); }
140
+ .fms__col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.25rem; }
141
+ .fms__col a, .fms__copy, .fms__status { font-size: 0.9rem; color: var(--c-text-2, #a3a3a3); text-decoration: none; }
142
+ .fms__col a { display: inline-flex; align-items: center; min-height: 36px; transition: color 0.2s ease; }
143
+ .fms__col a:hover { color: var(--c-text-1, #fff); }
144
+ .fms a:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 2px; border-radius: 4px; }
145
+ .fms__bottom { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem; padding-top: 1.75rem; }
146
+ .fms__copy { margin: 0; font-size: 0.8125rem; }
147
+ .fms__status { display: inline-flex; align-items: center; gap: 0.5rem; min-height: 36px; padding: 0 0.85rem; border-radius: 999px; border: 1px solid rgba(255, 255, 255, 0.08); font-size: 0.8125rem; }
148
+ .fms__status:hover { color: var(--c-text-1, #fff); }
149
+ .fms__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--chart-pos, #34c38f); box-shadow: 0 0 8px var(--chart-pos, #34c38f); }
150
+ .fms__socials { list-style: none; margin: 0; padding: 0; display: flex; gap: 0.25rem; }
151
+ .fms__socials a { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 10px; color: var(--c-text-2, #a3a3a3); transition: color 0.2s ease, background 0.2s ease; }
152
+ .fms__socials a:hover { color: var(--c-text-1, #fff); background: rgba(255, 255, 255, 0.06); }
153
+ @media (max-width: 860px) { .fms__top { grid-template-columns: 1fr; } }
154
+ @media (max-width: 560px) { .fms__bottom { flex-direction: column; align-items: flex-start; } }
155
+ </style>
@@ -0,0 +1,180 @@
1
+ ---
2
+ /**
3
+ * HeroDashboardPreview — SaaS hero with headline, CTAs and a live-rendered
4
+ * product dashboard mockup built from the kit's own SVG charts.
5
+ *
6
+ * @param {string} badge - Eyebrow badge.
7
+ * @param {string} title - Headline.
8
+ * @param {string} subtitle - Supporting paragraph.
9
+ * @param {{label: string, href: string}} primary - Primary CTA.
10
+ * @param {{label: string, href: string}} secondary - Secondary CTA.
11
+ * @param {string} variant - Mockup frame (browser|floating|flat).
12
+ * @param {string} size - Vertical rhythm (sm|md|lg).
13
+ * @param {string} className - Extra CSS class.
14
+ */
15
+ import LineChart from '../charts/LineChart.astro';
16
+ import KpiStatTile from '../charts/KpiStatTile.astro';
17
+
18
+ interface Props {
19
+ badge?: string;
20
+ title?: string;
21
+ subtitle?: string;
22
+ primary?: { label: string; href: string };
23
+ secondary?: { label: string; href: string };
24
+ variant?: 'browser' | 'floating' | 'flat';
25
+ size?: 'sm' | 'md' | 'lg';
26
+ className?: string;
27
+ }
28
+
29
+ const {
30
+ badge = 'Analytics, reimagined',
31
+ title = 'See every metric that matters, in real time',
32
+ subtitle = 'Unified revenue, product and infrastructure dashboards. Set up in minutes, no SQL required.',
33
+ primary = { label: 'Start free trial', href: '#' },
34
+ secondary = { label: 'Book a demo', href: '#' },
35
+ variant = 'browser',
36
+ size = 'md',
37
+ className = '',
38
+ } = Astro.props;
39
+
40
+ const id = `hdp-${Math.random().toString(36).slice(2, 8)}`;
41
+ ---
42
+
43
+ <section class={`hdp hdp--${variant} hdp--${size} ${className}`} aria-labelledby={id}>
44
+ <div class="hdp__glow" aria-hidden="true"></div>
45
+ <div class="hdp__copy">
46
+ <span class="hdp__badge">{badge}</span>
47
+ <h1 id={id} class="hdp__title">{title}</h1>
48
+ <p class="hdp__subtitle">{subtitle}</p>
49
+ <div class="hdp__actions">
50
+ <a class="hdp__btn hdp__btn--primary" href={primary.href}>{primary.label}</a>
51
+ <a class="hdp__btn hdp__btn--ghost" href={secondary.href}>
52
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10" /><path d="m10 8 6 4-6 4V8z" fill="currentColor" /></svg>
53
+ {secondary.label}
54
+ </a>
55
+ </div>
56
+ </div>
57
+
58
+ <div class="hdp__mock" role="group" aria-label="Product dashboard preview">
59
+ {variant === 'browser' && (
60
+ <div class="hdp__chrome" aria-hidden="true">
61
+ <span></span><span></span><span></span>
62
+ <p>app.example.com/overview</p>
63
+ </div>
64
+ )}
65
+ <div class="hdp__screen">
66
+ <div class="hdp__kpis">
67
+ <KpiStatTile label="Revenue" value="$128.4k" change={9.2} period="vs last month" size="sm" variant="solid" trend={[80, 84, 90, 88, 96, 102, 110, 118, 128]} />
68
+ <KpiStatTile label="Active users" value="24,812" change={4.1} period="vs last month" size="sm" variant="solid" trend={[20, 21, 21.5, 22, 22.8, 23.1, 23.9, 24.2, 24.8]} />
69
+ <KpiStatTile label="Churn" value="2.3%" change={-0.6} invert period="vs last month" size="sm" variant="solid" trend={[3.1, 3, 2.9, 2.8, 2.7, 2.6, 2.5, 2.4, 2.3]} />
70
+ </div>
71
+ <LineChart title="Revenue by channel" subtitle="Last 12 weeks" variant="solid" size="sm" height={220} />
72
+ </div>
73
+ </div>
74
+ </section>
75
+
76
+ <style>
77
+ .hdp {
78
+ --hdp-py: 5.5rem;
79
+ position: relative;
80
+ overflow: hidden;
81
+ padding: var(--hdp-py) var(--sp-6, 1.5rem) 0;
82
+ background: var(--c-bg, #050505);
83
+ }
84
+ .hdp--sm { --hdp-py: 3.5rem; }
85
+ .hdp--lg { --hdp-py: 7.5rem; }
86
+ .hdp__glow {
87
+ position: absolute;
88
+ top: 30%;
89
+ left: 50%;
90
+ width: 900px;
91
+ height: 600px;
92
+ transform: translateX(-50%);
93
+ background: radial-gradient(ellipse, rgba(57, 135, 229, 0.16), transparent 65%);
94
+ filter: blur(40px);
95
+ pointer-events: none;
96
+ }
97
+ .hdp__copy { position: relative; max-width: 760px; margin: 0 auto 3.5rem; text-align: center; }
98
+ .hdp__badge {
99
+ display: inline-block;
100
+ padding: 0.35rem 0.85rem;
101
+ border-radius: var(--r-full, 999px);
102
+ background: rgba(57, 135, 229, 0.12);
103
+ border: 1px solid rgba(57, 135, 229, 0.3);
104
+ color: #a9cdf7;
105
+ font-size: 0.8125rem;
106
+ font-weight: 600;
107
+ }
108
+ .hdp__title {
109
+ margin: 1.4rem 0 1rem;
110
+ font-size: clamp(2.25rem, 5.5vw, 3.75rem);
111
+ font-weight: 800;
112
+ letter-spacing: -0.035em;
113
+ line-height: 1.06;
114
+ color: var(--c-text-1, #fff);
115
+ text-wrap: balance;
116
+ }
117
+ .hdp__subtitle { margin: 0 auto 2rem; max-width: 560px; font-size: 1.0625rem; line-height: 1.6; color: var(--c-text-2, #a3a3a3); }
118
+ .hdp__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; }
119
+ .hdp__btn {
120
+ display: inline-flex;
121
+ align-items: center;
122
+ gap: 0.5rem;
123
+ min-height: 48px;
124
+ padding: 0 1.5rem;
125
+ border-radius: var(--r-md, 12px);
126
+ font-weight: 650;
127
+ text-decoration: none;
128
+ transition: transform 0.2s ease, background 0.2s ease;
129
+ }
130
+ .hdp__btn:hover { transform: translateY(-1px); }
131
+ .hdp__btn:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 3px; }
132
+ .hdp__btn--primary { background: var(--chart-1, #3987e5); color: #fff; }
133
+ .hdp__btn--primary:hover { background: #5598e7; color: #fff; }
134
+ .hdp__btn--ghost { color: var(--c-text-1, #fff); border: 1px solid rgba(255, 255, 255, 0.14); }
135
+ .hdp__btn--ghost:hover { border-color: rgba(255, 255, 255, 0.3); color: var(--c-text-1, #fff); }
136
+
137
+ .hdp__mock {
138
+ position: relative;
139
+ max-width: 1080px;
140
+ margin: 0 auto;
141
+ border-radius: var(--r-xl, 24px) var(--r-xl, 24px) 0 0;
142
+ border: 1px solid rgba(255, 255, 255, 0.1);
143
+ border-bottom: 0;
144
+ background: #0a0a0c;
145
+ overflow: hidden;
146
+ mask-image: linear-gradient(to bottom, #000 70%, transparent);
147
+ }
148
+ .hdp--floating .hdp__mock {
149
+ border-radius: var(--r-xl, 24px);
150
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
151
+ margin-bottom: var(--hdp-py);
152
+ mask-image: none;
153
+ transform: perspective(1600px) rotateX(8deg);
154
+ box-shadow: 0 60px 120px -40px rgba(57, 135, 229, 0.35);
155
+ }
156
+ .hdp--flat .hdp__mock { background: transparent; border-color: transparent; }
157
+ .hdp__chrome {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 0.45rem;
161
+ padding: 0.8rem 1rem;
162
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
163
+ }
164
+ .hdp__chrome span { width: 10px; height: 10px; border-radius: 50%; background: rgba(255, 255, 255, 0.12); }
165
+ .hdp__chrome p {
166
+ margin: 0 auto;
167
+ padding: 0.25rem 1rem;
168
+ border-radius: 6px;
169
+ background: rgba(255, 255, 255, 0.04);
170
+ font-size: 0.75rem;
171
+ color: var(--c-text-3, #737373);
172
+ }
173
+ .hdp__screen { display: grid; gap: 1rem; padding: 1.25rem; }
174
+ .hdp__kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
175
+ @media (max-width: 760px) {
176
+ .hdp__kpis { grid-template-columns: 1fr; }
177
+ .hdp__kpis > :global(*:nth-child(n + 2)) { display: none; }
178
+ .hdp--floating .hdp__mock { transform: none; }
179
+ }
180
+ </style>
@@ -0,0 +1,175 @@
1
+ ---
2
+ /**
3
+ * HeroMinimalCentered — Typography-first centered hero with an announcement pill,
4
+ * two CTAs and a row of trust signals. No imagery, loads instantly.
5
+ *
6
+ * @param {string} announcement - Text in the top pill (empty to hide).
7
+ * @param {string} announcementHref - Link for the pill.
8
+ * @param {string} title - Main headline. Wrap a word in *asterisks* to highlight it.
9
+ * @param {string} subtitle - Supporting paragraph.
10
+ * @param {{label: string, href: string}} primary - Primary CTA.
11
+ * @param {{label: string, href: string}} secondary - Secondary CTA.
12
+ * @param {string[]} trust - Short trust signals under the CTAs.
13
+ * @param {string} variant - Background treatment (default|glow|grid).
14
+ * @param {string} size - Vertical rhythm (sm|md|lg).
15
+ * @param {string} className - Extra CSS class.
16
+ */
17
+ interface Props {
18
+ announcement?: string;
19
+ announcementHref?: string;
20
+ title?: string;
21
+ subtitle?: string;
22
+ primary?: { label: string; href: string };
23
+ secondary?: { label: string; href: string };
24
+ trust?: string[];
25
+ variant?: 'default' | 'glow' | 'grid';
26
+ size?: 'sm' | 'md' | 'lg';
27
+ className?: string;
28
+ }
29
+
30
+ const {
31
+ announcement = 'New: 50 sections & 45 SVG charts',
32
+ announcementHref = '#',
33
+ title = 'Build landing pages that *feel* expensive',
34
+ subtitle = 'Accessible, zero-dependency Astro components with a dark, refined aesthetic. Copy, paste, ship.',
35
+ primary = { label: 'Browse components', href: '#' },
36
+ secondary = { label: 'Read the docs', href: '#' },
37
+ trust = ['MIT licensed', 'WCAG AA', 'No runtime JS required'],
38
+ variant = 'glow',
39
+ size = 'lg',
40
+ className = '',
41
+ } = Astro.props;
42
+
43
+ const id = `hmc-${Math.random().toString(36).slice(2, 8)}`;
44
+ const parts = title.split(/\*(.+?)\*/);
45
+ ---
46
+
47
+ <section class={`hmc hmc--${variant} hmc--${size} ${className}`} aria-labelledby={id}>
48
+ <div class="hmc__bg" aria-hidden="true"></div>
49
+ <div class="hmc__inner">
50
+ {announcement && (
51
+ <a class="hmc__pill" href={announcementHref}>
52
+ <span class="hmc__dot" aria-hidden="true"></span>
53
+ {announcement}
54
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M5 12h14M13 6l6 6-6 6" /></svg>
55
+ </a>
56
+ )}
57
+ <h1 id={id} class="hmc__title">
58
+ {parts.map((p, i) => (i % 2 ? <em>{p}</em> : p))}
59
+ </h1>
60
+ <p class="hmc__subtitle">{subtitle}</p>
61
+ <div class="hmc__actions">
62
+ <a class="hmc__btn hmc__btn--primary" href={primary.href}>{primary.label}</a>
63
+ <a class="hmc__btn hmc__btn--ghost" href={secondary.href}>{secondary.label}</a>
64
+ </div>
65
+ {trust.length > 0 && (
66
+ <ul class="hmc__trust">
67
+ {trust.map((t) => (
68
+ <li>
69
+ <svg 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"><path d="M20 6 9 17l-5-5" /></svg>
70
+ {t}
71
+ </li>
72
+ ))}
73
+ </ul>
74
+ )}
75
+ </div>
76
+ </section>
77
+
78
+ <style>
79
+ .hmc {
80
+ --hmc-py: 6rem;
81
+ position: relative;
82
+ overflow: hidden;
83
+ padding: var(--hmc-py) var(--sp-6, 1.5rem);
84
+ background: var(--c-bg, #050505);
85
+ text-align: center;
86
+ }
87
+ .hmc--sm { --hmc-py: 4rem; }
88
+ .hmc--lg { --hmc-py: 8rem; }
89
+ .hmc__bg { position: absolute; inset: 0; pointer-events: none; }
90
+ .hmc--glow .hmc__bg {
91
+ background:
92
+ radial-gradient(ellipse 60% 50% at 50% 0%, var(--c-primary-glow, rgba(184, 134, 11, 0.14)), transparent 70%),
93
+ radial-gradient(ellipse 40% 30% at 50% 100%, rgba(57, 135, 229, 0.08), transparent 70%);
94
+ }
95
+ .hmc--grid .hmc__bg {
96
+ background-image:
97
+ linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px),
98
+ linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
99
+ background-size: 48px 48px;
100
+ mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, #000, transparent);
101
+ }
102
+ .hmc__inner { position: relative; max-width: 820px; margin: 0 auto; }
103
+ .hmc__pill {
104
+ display: inline-flex;
105
+ align-items: center;
106
+ gap: 0.5rem;
107
+ min-height: 36px;
108
+ padding: 0.35rem 0.9rem;
109
+ border-radius: var(--r-full, 999px);
110
+ border: 1px solid var(--c-border, rgba(255, 255, 255, 0.08));
111
+ background: rgba(255, 255, 255, 0.03);
112
+ color: var(--c-text-2, #a3a3a3);
113
+ font-size: 0.8125rem;
114
+ text-decoration: none;
115
+ transition: border-color 0.2s ease, color 0.2s ease;
116
+ }
117
+ .hmc__pill:hover { border-color: rgba(255, 255, 255, 0.2); color: var(--c-text-1, #fff); }
118
+ .hmc__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--c-primary-light, #d4a017); box-shadow: 0 0 10px var(--c-primary-light, #d4a017); }
119
+ .hmc__title {
120
+ margin: 1.75rem 0 1.25rem;
121
+ font-size: clamp(2.5rem, 6vw, 4.5rem);
122
+ font-weight: 800;
123
+ line-height: 1.04;
124
+ letter-spacing: -0.035em;
125
+ color: var(--c-text-1, #fff);
126
+ text-wrap: balance;
127
+ }
128
+ .hmc__title em {
129
+ font-style: normal;
130
+ background: linear-gradient(120deg, var(--c-accent, #fef3c7), var(--c-primary-light, #d4a017));
131
+ -webkit-background-clip: text;
132
+ background-clip: text;
133
+ color: transparent;
134
+ }
135
+ .hmc__subtitle {
136
+ max-width: 600px;
137
+ margin: 0 auto 2.25rem;
138
+ font-size: clamp(1rem, 2vw, 1.1875rem);
139
+ line-height: 1.6;
140
+ color: var(--c-text-2, #a3a3a3);
141
+ }
142
+ .hmc__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; justify-content: center; }
143
+ .hmc__btn {
144
+ display: inline-flex;
145
+ align-items: center;
146
+ justify-content: center;
147
+ min-height: 48px;
148
+ padding: 0 1.5rem;
149
+ border-radius: var(--r-md, 12px);
150
+ font-weight: 650;
151
+ font-size: 0.9375rem;
152
+ text-decoration: none;
153
+ transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
154
+ }
155
+ .hmc__btn:hover { transform: translateY(-1px); }
156
+ .hmc__btn:focus-visible, .hmc__pill:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 3px; }
157
+ .hmc__btn--primary { background: var(--c-primary-light, #d4a017); color: #0a0a0a; }
158
+ .hmc__btn--primary:hover { background: var(--c-accent, #fef3c7); color: #0a0a0a; }
159
+ .hmc__btn--ghost { border: 1px solid rgba(255, 255, 255, 0.14); color: var(--c-text-1, #fff); }
160
+ .hmc__btn--ghost:hover { border-color: rgba(255, 255, 255, 0.32); color: var(--c-text-1, #fff); }
161
+ .hmc__trust {
162
+ display: flex;
163
+ flex-wrap: wrap;
164
+ justify-content: center;
165
+ gap: 0.75rem 1.75rem;
166
+ margin: 2.5rem 0 0;
167
+ padding: 0;
168
+ list-style: none;
169
+ font-size: 0.875rem;
170
+ color: var(--c-text-2, #a3a3a3);
171
+ }
172
+ .hmc__trust li { display: inline-flex; align-items: center; gap: 0.45rem; }
173
+ .hmc__trust svg { color: var(--chart-pos, #34c38f); }
174
+ @media (prefers-reduced-motion: reduce) { .hmc__btn { transition: none; } }
175
+ </style>