astro-component-kit 0.4.0 → 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.
Files changed (208) hide show
  1. package/README.md +139 -27
  2. package/bin/cli.js +67 -0
  3. package/bin/installer.js +179 -0
  4. package/package.json +35 -5
  5. package/src/components/index.ts +2 -0
  6. package/src/components/lib/Galaxy3D.astro +249 -137
  7. package/src/components/lib/app/AppSidebar.astro +249 -0
  8. package/src/components/lib/app/AppTopbar.astro +284 -0
  9. package/src/components/lib/app/ArrivalsBoard.astro +176 -0
  10. package/src/components/lib/app/AuthCard.astro +213 -0
  11. package/src/components/lib/app/DataTable.astro +346 -0
  12. package/src/components/lib/app/GuestProfileCard.astro +133 -0
  13. package/src/components/lib/app/HousekeepingBoard.astro +189 -0
  14. package/src/components/lib/app/PageHeader.astro +157 -0
  15. package/src/components/lib/app/PlanUsageCard.astro +112 -0
  16. package/src/components/lib/app/RoomRack.astro +207 -0
  17. package/src/components/lib/app/SettingsSection.astro +96 -0
  18. package/src/components/lib/app/SwitchRow.astro +71 -0
  19. package/src/components/lib/app/TeamMembers.astro +190 -0
  20. package/src/components/lib/app/app-icons.ts +52 -0
  21. package/src/components/lib/app/index.ts +19 -0
  22. package/src/components/lib/charts/AreaChart.astro +4 -4
  23. package/src/components/lib/charts/BarChart.astro +3 -3
  24. package/src/components/lib/charts/ChartFrame.astro +10 -10
  25. package/src/components/lib/charts/DonutChart.astro +2 -2
  26. package/src/components/lib/charts/DumbbellChart.astro +1 -1
  27. package/src/components/lib/charts/ForecastLineChart.astro +1 -1
  28. package/src/components/lib/charts/GaugeChart.astro +1 -1
  29. package/src/components/lib/charts/HeatmapChart.astro +1 -1
  30. package/src/components/lib/charts/HorizontalBarChart.astro +2 -2
  31. package/src/components/lib/charts/KpiStatTile.astro +4 -4
  32. package/src/components/lib/charts/LinearProgressGauge.astro +4 -4
  33. package/src/components/lib/charts/MetricDeltaTable.astro +3 -3
  34. package/src/components/lib/charts/RadarMetricChart.astro +4 -4
  35. package/src/components/lib/charts/RadialBarChart.astro +1 -1
  36. package/src/components/lib/charts/RetentionCohortTable.astro +2 -2
  37. package/src/components/lib/charts/TreemapChart.astro +1 -1
  38. package/src/components/lib/ecommerce/CartDrawer.astro +483 -0
  39. package/src/components/lib/ecommerce/CartPageList.astro +290 -0
  40. package/src/components/lib/ecommerce/CartToast.astro +276 -0
  41. package/src/components/lib/ecommerce/CategoryTiles.astro +143 -0
  42. package/src/components/lib/ecommerce/CheckoutForm.astro +423 -0
  43. package/src/components/lib/ecommerce/CountdownBanner.astro +230 -0
  44. package/src/components/lib/ecommerce/FilterBar.astro +278 -0
  45. package/src/components/lib/ecommerce/FilterSidebar.astro +405 -0
  46. package/src/components/lib/ecommerce/LiveActivityToast.astro +213 -0
  47. package/src/components/lib/ecommerce/OrderSummary.astro +295 -0
  48. package/src/components/lib/ecommerce/ProductBuyBox.astro +247 -0
  49. package/src/components/lib/ecommerce/ProductCardMinimal.astro +229 -0
  50. package/src/components/lib/ecommerce/ProductGallery.astro +145 -0
  51. package/src/components/lib/ecommerce/ProductGrid.astro +118 -0
  52. package/src/components/lib/ecommerce/ProductMedia.astro +113 -0
  53. package/src/components/lib/ecommerce/ProductRating.astro +78 -0
  54. package/src/components/lib/ecommerce/ProductToolbar.astro +93 -0
  55. package/src/components/lib/ecommerce/PromoBar.astro +145 -0
  56. package/src/components/lib/ecommerce/StockIndicator.astro +127 -0
  57. package/src/components/lib/ecommerce/StoreHeader.astro +446 -0
  58. package/src/components/lib/ecommerce/StoreHero.astro +260 -0
  59. package/src/components/lib/ecommerce/StoreProductCard.astro +307 -0
  60. package/src/components/lib/ecommerce/TrustBadges.astro +101 -0
  61. package/src/components/lib/ecommerce/VariantPicker.astro +145 -0
  62. package/src/components/lib/ecommerce/cart-store.ts +151 -0
  63. package/src/components/lib/ecommerce/catalog-filter.ts +62 -0
  64. package/src/components/lib/ecommerce/index.ts +34 -0
  65. package/src/components/lib/ecommerce/product-icons.ts +28 -0
  66. package/src/components/lib/ecommerce/types.ts +70 -0
  67. package/src/components/lib/forms/AnimatedInput.astro +4 -2
  68. package/src/components/lib/forms/CustomRadioGroup.astro +3 -1
  69. package/src/components/lib/index.ts +2 -0
  70. package/src/components/lib/layout/BentoGrid3.astro +6 -4
  71. package/src/components/lib/layout/CenterFixedBox.astro +2 -2
  72. package/src/components/lib/layout/CenteredContainer.astro +4 -2
  73. package/src/components/lib/layout/ClusterHorizontal.astro +2 -2
  74. package/src/components/lib/layout/FeatureHero.astro +4 -2
  75. package/src/components/lib/layout/FooterCenteredMinimal.astro +4 -2
  76. package/src/components/lib/layout/FullBleedSection.astro +2 -2
  77. package/src/components/lib/layout/GalleryGrid4.astro +2 -2
  78. package/src/components/lib/layout/HolyGrailGrid.astro +11 -9
  79. package/src/components/lib/layout/LandingSectionSplit.astro +5 -3
  80. package/src/components/lib/layout/MasonryGrid.astro +2 -2
  81. package/src/components/lib/layout/MinimalFooterGrid.astro +1 -1
  82. package/src/components/lib/layout/ScrollSnapSection.astro +1 -1
  83. package/src/components/lib/layout/SidebarLayoutWrapper.astro +4 -2
  84. package/src/components/lib/layout/SplitScreenLayout.astro +3 -3
  85. package/src/components/lib/layout/StepLayoutVertical.astro +1 -1
  86. package/src/components/lib/layout/StickySidebarWrapper.astro +4 -2
  87. package/src/components/lib/sections/AgencyContactBrief.astro +194 -0
  88. package/src/components/lib/sections/AgencyFooterCta.astro +94 -0
  89. package/src/components/lib/sections/AgencyHeader.astro +161 -0
  90. package/src/components/lib/sections/AgencyHeroKinetic.astro +172 -0
  91. package/src/components/lib/sections/AgencyServicesList.astro +113 -0
  92. package/src/components/lib/sections/AgencyTeamGrid.astro +111 -0
  93. package/src/components/lib/sections/AgencyWorkGrid.astro +147 -0
  94. package/src/components/lib/sections/BlogGridSection.astro +9 -7
  95. package/src/components/lib/sections/ButtonsShowcase.astro +20 -18
  96. package/src/components/lib/sections/CardsShowcase.astro +28 -26
  97. package/src/components/lib/sections/CareersOpenings.astro +10 -8
  98. package/src/components/lib/sections/ChangelogSection.astro +20 -7
  99. package/src/components/lib/sections/ContactGlassForm.astro +10 -8
  100. package/src/components/lib/sections/ContactSplitMap.astro +11 -9
  101. package/src/components/lib/sections/CtaAppDownload.astro +13 -11
  102. package/src/components/lib/sections/CtaGlowBanner.astro +12 -10
  103. package/src/components/lib/sections/CtaNewsletterSection.astro +13 -11
  104. package/src/components/lib/sections/CtaSplitImage.astro +13 -11
  105. package/src/components/lib/sections/DataShowcase.astro +23 -21
  106. package/src/components/lib/sections/FaqAccordionSection.astro +8 -8
  107. package/src/components/lib/sections/FaqTwoColumn.astro +9 -7
  108. package/src/components/lib/sections/FeatureAlternatingRows.astro +10 -8
  109. package/src/components/lib/sections/FeatureBentoGrid.astro +13 -11
  110. package/src/components/lib/sections/FeatureIconGrid.astro +6 -6
  111. package/src/components/lib/sections/FeatureTabsShowcase.astro +13 -11
  112. package/src/components/lib/sections/FeatureTimelineFlow.astro +8 -6
  113. package/src/components/lib/sections/FeedbackShowcase.astro +15 -13
  114. package/src/components/lib/sections/FooterMegaSection.astro +13 -11
  115. package/src/components/lib/sections/FormsShowcase.astro +22 -20
  116. package/src/components/lib/sections/HeroDashboardPreview.astro +11 -9
  117. package/src/components/lib/sections/HeroGlass.astro +22 -20
  118. package/src/components/lib/sections/HeroGradient.astro +15 -13
  119. package/src/components/lib/sections/HeroMinimalCentered.astro +10 -10
  120. package/src/components/lib/sections/HeroShowcaseSplit.astro +18 -16
  121. package/src/components/lib/sections/HeroSplit.astro +13 -11
  122. package/src/components/lib/sections/HeroTerminal.astro +14 -12
  123. package/src/components/lib/sections/HeroWaitlist.astro +10 -8
  124. package/src/components/lib/sections/HowItWorksSteps.astro +12 -10
  125. package/src/components/lib/sections/IntegrationsGrid.astro +7 -7
  126. package/src/components/lib/sections/LayoutShowcase.astro +21 -19
  127. package/src/components/lib/sections/LogoCloudSection.astro +4 -4
  128. package/src/components/lib/sections/LogoWallGrid.astro +6 -4
  129. package/src/components/lib/sections/NavigationShowcase.astro +15 -13
  130. package/src/components/lib/sections/OverlaysShowcase.astro +21 -19
  131. package/src/components/lib/sections/PricingComparisonMatrix.astro +15 -13
  132. package/src/components/lib/sections/PricingSinglePlan.astro +13 -11
  133. package/src/components/lib/sections/PricingTierCards.astro +11 -9
  134. package/src/components/lib/sections/PricingToggleCards.astro +13 -13
  135. package/src/components/lib/sections/ShopCategoryHero.astro +103 -0
  136. package/src/components/lib/sections/ShopCollectionMosaic.astro +131 -0
  137. package/src/components/lib/sections/ShopFooterWordmark.astro +100 -0
  138. package/src/components/lib/sections/ShopHeaderEditorial.astro +396 -0
  139. package/src/components/lib/sections/ShopHeroEditorial.astro +151 -0
  140. package/src/components/lib/sections/ShopLookbook.astro +250 -0
  141. package/src/components/lib/sections/ShopNewsletterEditorial.astro +128 -0
  142. package/src/components/lib/sections/ShopProductRail.astro +150 -0
  143. package/src/components/lib/sections/ShopReviewsEditorial.astro +133 -0
  144. package/src/components/lib/sections/ShopValuesMarquee.astro +91 -0
  145. package/src/components/lib/sections/StatsCounterBand.astro +9 -7
  146. package/src/components/lib/sections/StatsDashboardSection.astro +4 -2
  147. package/src/components/lib/sections/StatsMetricShowcase.astro +9 -7
  148. package/src/components/lib/sections/TeamGridSection.astro +12 -10
  149. package/src/components/lib/sections/TestimonialCarousel.astro +10 -8
  150. package/src/components/lib/sections/TestimonialFeatured.astro +7 -5
  151. package/src/components/lib/sections/TestimonialGridSection.astro +7 -7
  152. package/src/components/lib/sections/TestimonialWallGlass.astro +11 -9
  153. package/src/components/lib/sections/TypographyShowcase.astro +10 -8
  154. package/src/components/lib/sections/index.ts +10 -0
  155. package/src/components/lib/templates/ecommerce/StoreCategoryPage.astro +160 -0
  156. package/src/components/lib/templates/ecommerce/StoreCheckoutPage.astro +98 -0
  157. package/src/components/lib/templates/ecommerce/StoreHomePage.astro +191 -0
  158. package/src/components/lib/templates/ecommerce/StoreLayout.astro +169 -0
  159. package/src/components/lib/templates/ecommerce/StoreProductPage.astro +165 -0
  160. package/src/components/lib/templates/ecommerce/data.ts +187 -0
  161. package/src/components/lib/templates/ecommerce/index.ts +14 -0
  162. package/src/components/lib/templates/ecommerce-editorial/EditorialBagPage.astro +52 -0
  163. package/src/components/lib/templates/ecommerce-editorial/EditorialCheckoutPage.astro +123 -0
  164. package/src/components/lib/templates/ecommerce-editorial/EditorialHomePage.astro +102 -0
  165. package/src/components/lib/templates/ecommerce-editorial/EditorialLayout.astro +216 -0
  166. package/src/components/lib/templates/ecommerce-editorial/EditorialProductPage.astro +205 -0
  167. package/src/components/lib/templates/ecommerce-editorial/EditorialShopPage.astro +112 -0
  168. package/src/components/lib/templates/ecommerce-editorial/data.ts +125 -0
  169. package/src/components/lib/templates/ecommerce-editorial/index.ts +16 -0
  170. package/src/components/lib/templates/saas-hotel/AppLayout.astro +83 -0
  171. package/src/components/lib/templates/saas-hotel/DashboardPage.astro +66 -0
  172. package/src/components/lib/templates/saas-hotel/GuestsPage.astro +65 -0
  173. package/src/components/lib/templates/saas-hotel/LandingPage.astro +213 -0
  174. package/src/components/lib/templates/saas-hotel/ReportsPage.astro +63 -0
  175. package/src/components/lib/templates/saas-hotel/ReservationsPage.astro +49 -0
  176. package/src/components/lib/templates/saas-hotel/RoomsPage.astro +48 -0
  177. package/src/components/lib/templates/saas-hotel/SettingsPage.astro +115 -0
  178. package/src/components/lib/templates/saas-hotel/SignInPage.astro +50 -0
  179. package/src/components/lib/templates/saas-hotel/data.ts +229 -0
  180. package/src/components/lib/templates/saas-hotel/index.ts +19 -0
  181. package/src/components/lib/templates/saas-hotel/lobby-theme.css +90 -0
  182. package/src/data/registry/app.ts +93 -0
  183. package/src/data/registry/buttons.ts +3279 -0
  184. package/src/data/registry/cards.ts +1753 -0
  185. package/src/data/registry/charts-svg.ts +557 -0
  186. package/src/data/registry/charts.ts +500 -0
  187. package/src/data/registry/data.ts +986 -0
  188. package/src/data/registry/ecommerce.ts +269 -0
  189. package/src/data/registry/feedback.ts +1824 -0
  190. package/src/data/registry/forms.ts +2513 -0
  191. package/src/data/registry/index.ts +64 -0
  192. package/src/data/registry/layout.ts +206 -0
  193. package/src/data/registry/navigation.ts +936 -0
  194. package/src/data/registry/overlays.ts +1133 -0
  195. package/src/data/registry/sections-extra.ts +397 -0
  196. package/src/data/registry/sections.ts +361 -0
  197. package/src/data/registry/sources.ts +41 -0
  198. package/src/data/registry/templates.ts +414 -0
  199. package/src/data/registry/types.ts +30 -0
  200. package/src/data/registry/typography.ts +777 -0
  201. package/src/mcp/http-server.ts +324 -0
  202. package/src/mcp/index.ts +67 -0
  203. package/src/mcp/installer.ts +178 -0
  204. package/src/mcp/registry-adapter.ts +278 -0
  205. package/src/mcp/stdio-server.ts +11 -0
  206. package/src/mcp/tools.ts +247 -0
  207. package/src/mcp/types.ts +53 -0
  208. package/src/styles/global.css +95 -0
@@ -0,0 +1,1133 @@
1
+ // src/data/registry/overlays.ts
2
+ import type { ComponentDoc } from './types';
3
+
4
+ export const overlays: ComponentDoc[] = [
5
+ {
6
+ slug: 'overlay-modal',
7
+ name: 'Glass Modal',
8
+ description: 'A focused overlay window with a premium glassmorphism blur and smooth entrance animation.',
9
+ category: 'overlays',
10
+ tags: ['modal', 'overlay', 'glass'],
11
+ featured: true,
12
+ code: `---
13
+ ---
14
+ <div class="modal-overlay">
15
+ <div class="modal-card anim-scale-up">
16
+ <div class="modal-close">×</div>
17
+ <h3>Confirm Action</h3>
18
+ <p>Are you sure you want to proceed with this sensitive operation?</p>
19
+ <div class="modal-actions">
20
+ <button class="cancel">Cancel</button>
21
+ <button class="confirm">Continue</button>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ <style>
26
+ .modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); backdrop-filter: blur(8px); display: grid; place-items: center; z-index: 1000; }
27
+ .modal-card { background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.1); border-radius: 24px; padding: 2rem; width: 90%; max-width: 400px; box-shadow: 0 40px 100px rgba(0,0,0,0.5); position: relative; }
28
+ .modal-close { position: absolute; top: 1rem; right: 1rem; cursor: pointer; color: #94a3b8; font-size: 1.5rem; }
29
+ h3 { margin: 0 0 1rem; color: #fff; }
30
+ p { color: #94a3b8; font-size: 0.9rem; line-height: 1.6; }
31
+ .modal-actions { display: flex; justify-content: flex-end; gap: 1rem; margin-top: 2rem; }
32
+ button { padding: 0.6rem 1.25rem; border-radius: 10px; border: none; font-weight: 700; cursor: pointer; }
33
+ .cancel { background: transparent; color: #fff; border: 1px solid rgba(255,255,255,0.1); }
34
+ .confirm { background: #6366f1; color: #fff; }
35
+ </style>
36
+ `,
37
+ usage: `---
38
+ import { OverlayModal, GlassButton } from 'astro-component-kit';
39
+ ---
40
+
41
+ <OverlayModal>
42
+ <div class="modal-content">
43
+ <h3>Project Created</h3>
44
+ <p>Your new workspace is ready to use.</p>
45
+ <div class="flex-end mt-6">
46
+ <GlassButton size="sm">Go to Dashboard</GlassButton>
47
+ </div>
48
+ </div>
49
+ </OverlayModal>`,
50
+ },
51
+ {
52
+ slug: 'side-drawer-right',
53
+ name: 'Slide-over (Right)',
54
+ description: 'A panel that slides in from the right side of the screen, common for filters or settings.',
55
+ category: 'overlays',
56
+ tags: ['drawer', 'panel', 'overlay'],
57
+ code: `---
58
+ ---
59
+ <div class="drawer-wrap">
60
+ <div class="drawer-overlay"></div>
61
+ <div class="drawer-panel right">
62
+ <div class="drawer-header"><h3>Filters</h3><span>×</span></div>
63
+ <div class="drawer-body"><slot /></div>
64
+ </div>
65
+ </div>
66
+ <style>
67
+ .drawer-wrap { position: fixed; inset: 0; z-index: 2000; }
68
+ .drawer-overlay { position: absolute; inset: 0; background: rgba(0,0,0,0.4); backdrop-filter: blur(4px); }
69
+ .drawer-panel { position: absolute; top: 0; bottom: 0; width: 350px; background: #080b14; border-left: 1px solid rgba(255, 255, 255, 0.1); padding: 2rem; transform: translateX(100%); transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1); }
70
+ .drawer-panel.right { right: 0; transform: translateX(0); }
71
+ .drawer-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem; color: #fff; }
72
+ </style>
73
+ `,
74
+ usage: `---
75
+ import { SideDrawerRight } from 'astro-component-kit';
76
+ ---
77
+
78
+ <SideDrawerRight>
79
+ <div class="p-6">
80
+ <h4 class="mb-4">Quick Settings</h4>
81
+ <div class="stack-v gap-2">
82
+ <label>Notifications</label>
83
+ <label>Privacy</label>
84
+ <label>Security</label>
85
+ </div>
86
+ </div>
87
+ </SideDrawerRight>`,
88
+ },
89
+ {
90
+ slug: 'bottom-sheet-mobile',
91
+ name: 'Bottom Sheet',
92
+ description: 'A mobile-optimized overlay that slides up from the bottom of the screen.',
93
+ category: 'overlays',
94
+ tags: ['mobile', 'sheet', 'overlay'],
95
+ code: `---
96
+ ---
97
+ <div class="sheet-overlay">
98
+ <div class="sheet-content">
99
+ <div class="drag-handle"></div>
100
+ <h3>Select Option</h3>
101
+ <div class="options"><div>Archive</div><div>Delete</div><div>Share</div></div>
102
+ </div>
103
+ </div>
104
+ <style>
105
+ .sheet-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); display: flex; align-items: flex-end; z-index: 2000; }
106
+ .sheet-content { width: 100%; background: #0f172a; border-radius: 20px 20px 0 0; padding: 1.5rem; transform: translateY(0); }
107
+ .drag-handle { width: 40px; height: 4px; background: #334155; border-radius: 2px; margin: 0 auto 1.5rem; }
108
+ h3 { color: #fff; text-align: center; margin-bottom: 1.5rem; }
109
+ .options div { padding: 1rem; color: #e2e8f0; border-bottom: 1px solid #1e293b; text-align: center; cursor: pointer; }
110
+ </style>
111
+ `,
112
+ usage: `<BottomSheetMobile>Content</BottomSheetMobile>`,
113
+ },
114
+ {
115
+ slug: 'popover-menu-glass',
116
+ name: 'Glass Popover',
117
+ description: 'A small floating menu that appears near a trigger element.',
118
+ category: 'overlays',
119
+ tags: ['popover', 'menu', 'glass'],
120
+ code: `---
121
+ ---
122
+ <div class="popover">
123
+ <div class="pop-inner">
124
+ <div class="pop-item">Edit Account</div>
125
+ <div class="pop-item">Billing</div>
126
+ <hr />
127
+ <div class="pop-item logout">Logout</div>
128
+ </div>
129
+ </div>
130
+ <style>
131
+ .popover { width: 180px; background: rgba(10, 10, 20, 0.8); backdrop-filter: blur(20px); border: 1px solid rgba(255,255,255,0.1); border-radius: 12px; padding: 6px; box-shadow: 0 20px 50px rgba(0,0,0,0.5); }
132
+ .pop-item { padding: 8px 12px; border-radius: 8px; color: #94a3b8; font-size: 0.85rem; cursor: pointer; }
133
+ .pop-item:hover { background: rgba(255,255,255,0.06); color: #fff; }
134
+ .logout { color: #f87171 !important; }
135
+ hr { border: none; border-top: 1px solid rgba(255,255,255,0.06); margin: 6px 0; }
136
+ </style>
137
+ `,
138
+ usage: `<PopoverMenuGlass>Content</PopoverMenuGlass>`,
139
+ },
140
+ {
141
+ slug: 'command-dialog',
142
+ name: 'Command Palette Overlay',
143
+ description: 'Search-first command center overlay for advanced site navigation.',
144
+ category: 'overlays',
145
+ tags: ['command', 'overlay', 'search'],
146
+ code: `---
147
+ ---
148
+ <div class="cmd-overlay">
149
+ <div class="cmd-box">
150
+ <div class="cmd-input"><input type="text" placeholder="Search commands..." /></div>
151
+ <div class="cmd-results">
152
+ <div class="res"><span>Recent: Dashboard</span><kbd>↵</kbd></div>
153
+ <div class="res"><span>Docs: Navigation</span><kbd>↵</kbd></div>
154
+ </div>
155
+ </div>
156
+ </div>
157
+ <style>
158
+ .cmd-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.6); backdrop-filter: blur(4px); display: flex; justify-content: center; padding-top: 15vh; z-index: 3000; }
159
+ .cmd-box { width: 100%; max-width: 600px; background: #080b14; border: 1px solid #334155; border-radius: 12px; overflow: hidden; box-shadow: 0 30px 100px rgba(0,0,0,0.8); }
160
+ .cmd-input input { width: 100%; padding: 1.25rem; background: transparent; border: none; border-bottom: 1px solid #1e293b; color: #fff; outline: none; font-size: 1.1rem; }
161
+ .res { display: flex; justify-content: space-between; padding: 0.75rem 1.25rem; color: #94a3b8; font-size: 0.9rem; cursor: pointer; }
162
+ .res:hover { background: #1e293b; color: #fff; }
163
+ kbd { background: #111; padding: 2px 4px; border-radius: 4px; font-size: 0.7rem; }
164
+ </style>
165
+ `,
166
+ usage: `<CommandDialog>Content</CommandDialog>`,
167
+ },
168
+ {
169
+ slug: 'lightbox-overlay',
170
+ name: 'Image Lightbox',
171
+ description: 'Overlay for viewing high-resolution images in isolation.',
172
+ category: 'overlays',
173
+ tags: ['lightbox', 'image', 'overlay'],
174
+ code: `---
175
+ ---
176
+ <div class="lightbox">
177
+ <div class="close">×</div>
178
+ <div class="img-preview"></div>
179
+ <div class="caption">Nature Landscape / 2024</div>
180
+ </div>
181
+ <style>
182
+ .lightbox { position: fixed; inset: 0; background: #000; z-index: 5000; display: flex; flex-direction: column; align-items: center; justify-content: center; }
183
+ .close { position: absolute; top: 2rem; right: 2rem; color: #fff; font-size: 2.2rem; cursor: pointer; }
184
+ .img-preview { width: 80%; height: 70%; background: #1e293b; border-radius: 12px; }
185
+ .caption { margin-top: 2rem; color: #94a3b8; font-family: monospace; }
186
+ </style>
187
+ `,
188
+ usage: `<LightboxOverlay>Content</LightboxOverlay>`,
189
+ },
190
+ {
191
+ slug: 'cookie-banner-glass',
192
+ name: 'Cookie Consent',
193
+ description: 'Minimalist glass banner for privacy and cookie compliance.',
194
+ category: 'overlays',
195
+ tags: ['cookie', 'legal', 'overlay'],
196
+ code: `---
197
+ ---
198
+ <div class="cookie-bar">
199
+ <div class="text">We use cookies to improve your experience. <a href="#">Learn more</a></div>
200
+ <div class="acts"><button class="opt">Options</button><button class="acc">Accept All</button></div>
201
+ </div>
202
+ <style>
203
+ .cookie-bar { position: fixed; bottom: 2rem; left: 2rem; right: 2rem; max-width: 600px; margin: 0 auto; background: rgba(15,23,42,0.8); backdrop-filter: blur(20px); border: 1px solid rgba(255,255,255,0.1); border-radius: 16px; padding: 1.25rem; display: flex; justify-content: space-between; align-items: center; z-index: 1000; }
204
+ .text { color: #e2e8f0; font-size: 0.85rem; }
205
+ .acts { display: flex; gap: 0.75rem; }
206
+ button { padding: 0.5rem 1rem; border-radius: 8px; border: none; font-size: 0.8rem; font-weight: 700; cursor: pointer; }
207
+ .opt { background: transparent; color: #fff; border: 1px solid #334155; }
208
+ .acc { background: #6366f1; color: #fff; }
209
+ </style>
210
+ `,
211
+ usage: `<CookieBannerGlass>Content</CookieBannerGlass>`,
212
+ },
213
+ {
214
+ slug: 'loading-overlay-full',
215
+ name: 'Page Loader Overlay',
216
+ description: 'Blocking overlay used during initial page loads or heavy transitions.',
217
+ category: 'overlays',
218
+ tags: ['loading', 'overlay', 'fullscreen'],
219
+ code: `---
220
+ ---
221
+ <div class="load-overlay">
222
+ <div class="spinner"></div>
223
+ </div>
224
+ <style>
225
+ .load-overlay { position: fixed; inset: 0; background: #080b14; z-index: 9999; display: grid; place-items: center; }
226
+ .spinner { width: 50px; height: 50px; border: 4px solid rgba(99,102,241,0.1); border-top-color: #6366f1; border-radius: 50%; animation: spin 0.8s infinite linear; }
227
+ @keyframes spin { to { transform: rotate(360deg); } }
228
+ </style>
229
+ `,
230
+ usage: `<LoadingOverlayFull>Content</LoadingOverlayFull>`,
231
+ },
232
+ {
233
+ slug: 'backdrop-blur-mask',
234
+ name: 'Backdrop Mask',
235
+ description: 'Simple reusable overlay for dimming/blurring the page behind menus.',
236
+ category: 'overlays',
237
+ tags: ['mask', 'overlay', 'utility'],
238
+ code: `---
239
+ ---
240
+ <div class="mask"></div>
241
+ <style>
242
+ .mask { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(4px); z-index: 500; pointer-events: none; }
243
+ </style>
244
+ `,
245
+ usage: `<BackdropBlurMask>Content</BackdropBlurMask>`,
246
+ },
247
+ {
248
+ slug: 'help-bubble-overlay',
249
+ name: 'Support Chat Bubble',
250
+ description: 'Floating action triggered icon for chat or support requests.',
251
+ category: 'overlays',
252
+ tags: ['support', 'chat', 'floating'],
253
+ code: `---
254
+ ---
255
+ <div class="help-bubble">
256
+ <div class="tip">We are online!</div>
257
+ <div class="icon">💬</div>
258
+ </div>
259
+ <style>
260
+ .help-bubble { position: fixed; bottom: 2rem; right: 2rem; cursor: pointer; display: flex; align-items: center; gap: 1rem; z-index: 1000; }
261
+ .icon { width: 55px; height: 55px; background: #6366f1; border-radius: 50%; display: grid; place-items: center; font-size: 1.5rem; color: #fff; box-shadow: 0 10px 30px rgba(99,102,241,0.4); }
262
+ .tip { background: #fff; color: #000; padding: 6px 12px; border-radius: 10px; font-size: 0.75rem; font-weight: 800; box-shadow: 0 5px 15px rgba(0,0,0,0.2); }
263
+ </style>
264
+ `,
265
+ usage: `<HelpBubbleOverlay>Content</HelpBubbleOverlay>`,
266
+ },
267
+ {
268
+ slug: 'search-overlay-fullscreen',
269
+ name: 'Fullscreen Search',
270
+ description: 'Immersive search interface that covers the entire viewport.',
271
+ category: 'overlays',
272
+ tags: ['search', 'fullscreen', 'overlay'],
273
+ code: `---
274
+ ---
275
+ <div class="search-hero">
276
+ <div class="close">Esc</div>
277
+ <input type="text" placeholder="Start searching..." autofocus />
278
+ <div class="hints">Search for <span>components</span>, <span>guides</span>, or <span>authors</span></div>
279
+ </div>
280
+ <style>
281
+ .search-hero { position: fixed; inset: 0; background: #080b14; z-index: 5000; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 2rem; }
282
+ .close { position: absolute; top: 3rem; right: 3rem; color: #64748b; font-weight: 700; cursor: pointer; border: 1px solid rgba(255, 255, 255, 0.1); padding: 2px 8px; border-radius: 4px; font-size: 0.8rem; }
283
+ input { width: 100%; max-width: 800px; background: transparent; border: none; color: #fff; font-size: 3rem; font-weight: 800; text-align: center; outline: none; }
284
+ .hints { margin-top: 2rem; color: #64748b; font-size: 1rem; }
285
+ span { color: #818cf8; text-decoration: underline; cursor: pointer; }
286
+ @media (max-width: 768px) { input { font-size: 1.5rem; } }
287
+ </style>
288
+ `,
289
+ usage: `<SearchOverlayFullscreen>Content</SearchOverlayFullscreen>`,
290
+ },
291
+ {
292
+ slug: 'age-verification-overlay',
293
+ name: 'Age Gate Modal',
294
+ description: 'Splash overlay for age-restricted content verification.',
295
+ category: 'overlays',
296
+ tags: ['legal', 'verification', 'overlay'],
297
+ code: `---
298
+ ---
299
+ <div class="age-gate">
300
+ <div class="age-card">
301
+ <h2>Age Verification</h2>
302
+ <p>Please confirm you are 18 or older to view this site.</p>
303
+ <div class="acts-row"><button class="no">Exit</button><button class="yes">I am 18+</button></div>
304
+ </div>
305
+ </div>
306
+ <style>
307
+ .age-gate { position: fixed; inset: 0; background: #000; z-index: 9999; display: grid; place-items: center; }
308
+ .age-card { text-align: center; color: #fff; max-width: 350px; padding: 2rem; }
309
+ h2 { font-size: 2rem; font-weight: 900; margin-bottom: 1rem; }
310
+ p { color: #94a3b8; line-height: 1.6; margin-bottom: 2.5rem; }
311
+ .acts-row { display: flex; gap: 1rem; }
312
+ button { flex: 1; padding: 1rem; border: none; border-radius: 12px; font-weight: 800; cursor: pointer; transition: 0.2s; }
313
+ .no { background: #1e293b; color: #fff; }
314
+ .yes { background: #6366f1; color: #fff; }
315
+ button:hover { transform: translateY(-2px); }
316
+ </style>
317
+ `,
318
+ usage: `<AgeVerificationOverlay>Content</AgeVerificationOverlay>`,
319
+ },
320
+ {
321
+ slug: 'context-menu-overlay',
322
+ name: 'Custom Context Menu',
323
+ description: 'Right-click menu replacement with custom actions and styling.',
324
+ category: 'overlays',
325
+ tags: ['menu', 'context', 'overlay'],
326
+ code: `---
327
+ ---
328
+ <div class="ctx-menu">
329
+ <div class="ctx-group">
330
+ <div class="ctx-item">Copy Link</div>
331
+ <div class="ctx-item">Duplicate</div>
332
+ </div>
333
+ <hr />
334
+ <div class="ctx-item danger">Delete Item</div>
335
+ </div>
336
+ <style>
337
+ .ctx-menu { width: 200px; background: #111; border: 1px solid #333; border-radius: 10px; padding: 4px; box-shadow: 0 15px 40px rgba(0,0,0,0.6); position: fixed; top: 100px; left: 100px; z-index: 5000; }
338
+ .ctx-item { padding: 8px 12px; font-size: 0.85rem; color: #e2e8f0; border-radius: 6px; cursor: pointer; transition: 0.2s; }
339
+ .ctx-item:hover { background: #6366f1; color: #fff; }
340
+ .danger:hover { background: #ef4444 !important; }
341
+ hr { border: none; border-top: 1px solid #222; margin: 4px 0; }
342
+ </style>
343
+ `,
344
+ usage: `<ContextMenuOverlay>Content</ContextMenuOverlay>`,
345
+ },
346
+ {
347
+ slug: 'mobile-nav-overlay',
348
+ name: 'Mobile Menu Overlay',
349
+ description: 'Full-screen mobile drawer triggered by burger menu.',
350
+ category: 'overlays',
351
+ tags: ['mobile', 'navigation', 'overlay'],
352
+ code: `---
353
+ ---
354
+ <div class="mob-nav">
355
+ <div class="mob-close">×</div>
356
+ <nav class="mob-links">
357
+ <a href="#">Home</a>
358
+ <a href="#">Features</a>
359
+ <a href="#">Pricing</a>
360
+ <a href="#">Team</a>
361
+ </nav>
362
+ </div>
363
+ <style>
364
+ .mob-nav { position: fixed; inset: 0; background: #080b14; z-index: 4000; padding: 4rem 2rem; display: flex; flex-direction: column; }
365
+ .mob-close { font-size: 3rem; color: #fff; align-self: flex-end; cursor: pointer; margin-bottom: 2rem; }
366
+ .mob-links { display: flex; flex-direction: column; gap: 1.5rem; }
367
+ .mob-links a { font-size: 2.2rem; font-weight: 800; color: #fff; text-decoration: none; transition: 0.2s; }
368
+ .mob-links a:hover { color: #6366f1; padding-left: 10px; }
369
+ </style>
370
+ `,
371
+ usage: `<MobileNavOverlay>Content</MobileNavOverlay>`,
372
+ },
373
+ {
374
+ slug: 'floating-tray-actions',
375
+ name: 'Bottom Action Tray',
376
+ description: 'Compact set of floating actions locked to the bottom viewport.',
377
+ category: 'overlays',
378
+ tags: ['actions', 'overlay', 'mobile'],
379
+ code: `---
380
+ ---
381
+ <div class="tray">
382
+ <button class="tray-btn">✏️ Edit</button>
383
+ <div class="sep"></div>
384
+ <button class="tray-btn">↗️ Share</button>
385
+ </div>
386
+ <style>
387
+ .tray { position: fixed; bottom: 2rem; left: 50%; transform: translateX(-50%); background: #fff; border-radius: 100px; display: flex; align-items: center; padding: 4px; box-shadow: 0 10px 40px rgba(0,0,0,0.2); z-index: 1000; border: 1px solid rgba(0,0,0,0.1); }
388
+ .tray-btn { background: none; border: none; padding: 0.6rem 1.25rem; font-weight: 700; color: #000; cursor: pointer; font-size: 0.85rem; transition: 0.2s; }
389
+ .tray-btn:hover { opacity: 0.6; }
390
+ .sep { width: 1px; height: 20px; background: #eee; }
391
+ </style>
392
+ `,
393
+ usage: `<FloatingTrayActions>Content</FloatingTrayActions>`,
394
+ },
395
+ {
396
+ slug: 'toast-stack-overlay',
397
+ name: 'Stacked Toast Center',
398
+ description: 'Container for multiple toasts appearing simultaneously.',
399
+ category: 'overlays',
400
+ tags: ['toast', 'feedback', 'stack'],
401
+ code: `---
402
+ ---
403
+ <div class="toast-stack">
404
+ <div class="toast-mini success">Profile updated!</div>
405
+ <div class="toast-mini error">Failed to sync changes.</div>
406
+ </div>
407
+ <style>
408
+ .toast-stack { position: fixed; top: 2rem; right: 2rem; z-index: 5000; display: flex; flex-direction: column; gap: 0.75rem; }
409
+ .toast-mini { background: #111; color: #fff; padding: 0.75rem 1.5rem; border-radius: 10px; border-left: 4px solid #333; font-size: 0.85rem; box-shadow: 0 10px 30px rgba(0,0,0,0.4); border: 1px solid rgba(255,255,255,0.05); }
410
+ .success { border-left-color: #10b981; }
411
+ .error { border-left-color: #ef4444; }
412
+ </style>
413
+ `,
414
+ usage: `<ToastStackOverlay>Content</ToastStackOverlay>`,
415
+ },
416
+ {
417
+ slug: 'exit-intent-overlay',
418
+ name: 'Exit Intent Popup',
419
+ description: 'Modal triggered when the user moves to close the tab.',
420
+ category: 'overlays',
421
+ tags: ['conversion', 'modal', 'overlay'],
422
+ code: `---
423
+ ---
424
+ <div class="exit-modal">
425
+ <div class="exit-card">
426
+ <h2>Wait! Before you go...</h2>
427
+ <p>Get 20% off your first order when you join our mailing list.</p>
428
+ <input type="email" placeholder="Your email" />
429
+ <button>Get My Code</button>
430
+ </div>
431
+ </div>
432
+ <style>
433
+ .exit-modal { position: fixed; inset: 0; background: rgba(99,102,241,0.1); backdrop-filter: blur(15px); z-index: 6000; display: grid; place-items: center; }
434
+ .exit-card { background: #fff; color: #000; padding: 3rem; border-radius: 30px; text-align: center; max-width: 450px; box-shadow: 0 20px 60px rgba(0,0,0,0.1); }
435
+ h2 { font-weight: 900; font-size: 1.8rem; margin-bottom: 1rem; }
436
+ p { color: #64748b; margin-bottom: 2rem; line-height: 1.5; }
437
+ input { width: 100%; padding: 1rem; border: 1px solid #eee; border-radius: 12px; margin-bottom: 1rem; outline: none; font-size: 1rem; }
438
+ button { width: 100%; padding: 1rem; background: #6366f1; color: #fff; border: none; border-radius: 12px; font-weight: 800; cursor: pointer; transition: 0.2s; }
439
+ button:hover { background: #4f46e5; }
440
+ </style>
441
+ `,
442
+ usage: `<ExitIntentOverlay>Content</ExitIntentOverlay>`,
443
+ },
444
+ {
445
+ slug: 'tooltip-action-tray',
446
+ name: 'Action Tooltip',
447
+ description: 'Tooltip that contains interactive buttons instead of just text.',
448
+ category: 'overlays',
449
+ tags: ['tooltip', 'actions', 'ux'],
450
+ code: `---
451
+ ---
452
+ <div class="act-tip">
453
+ <div class="tip-body">Action required</div>
454
+ <div class="tip-btns"><button class="fix">Fix</button><button class="ign">Ignore</button></div>
455
+ </div>
456
+ <style>
457
+ .act-tip { position: relative; background: #1e293b; border: 1px solid #334155; border-radius: 10px; padding: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); width: fit-content; }
458
+ .tip-body { color: #fff; font-weight: 700; font-size: 0.8rem; margin-bottom: 8px; }
459
+ .tip-btns { display: flex; gap: 8px; }
460
+ button { padding: 4px 10px; font-size: 0.75rem; border-radius: 4px; border: none; cursor: pointer; font-weight: 600; }
461
+ .fix { background: #6366f1; color: #fff; }
462
+ .ign { background: #334155; color: #94a3b8; }
463
+ </style>
464
+ `,
465
+ usage: `<TooltipActionTray>Content</TooltipActionTray>`,
466
+ },
467
+ {
468
+ slug: 'splash-intro-overlay',
469
+ name: 'Entrance Splash',
470
+ description: 'Temporary full-screen intro animation for brand reveal.',
471
+ category: 'overlays',
472
+ tags: ['branding', 'animation', 'overlay'],
473
+ code: `---
474
+ ---
475
+ <div class="splash">
476
+ <div class="logo-anim">Astro Components</div>
477
+ </div>
478
+ <style>
479
+ .splash { position: fixed; inset: 0; background: #080b14; z-index: 9999; display: grid; place-items: center; animation: fade-out 1s forwards 2s; }
480
+ .logo-anim { font-size: 3rem; font-weight: 900; color: #fff; animation: scale-pulse 1.5s infinite linear; background: linear-gradient(135deg, #6366f1, #c084fc); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
481
+ @keyframes fade-out { to { opacity: 0; pointer-events: none; } }
482
+ @keyframes scale-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.1); } }
483
+ </style>
484
+ `,
485
+ usage: `<SplashIntroOverlay>Content</SplashIntroOverlay>`,
486
+ },
487
+ {
488
+ slug: 'spotlight-indicator',
489
+ name: 'Step Spotlight',
490
+ description: 'Circular mask that highlights a specific element for onboarding.',
491
+ category: 'overlays',
492
+ tags: ['onboarding', 'highlight', 'overlay'],
493
+ code: `---
494
+ ---
495
+ <div class="spot-mask"></div>
496
+ <style>
497
+ .spot-mask { position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 500; clip-path: circle(60px at 50% 50%); pointer-events: none; }
498
+ </style>
499
+ `,
500
+ usage: `<SpotlightIndicator>Content</SpotlightIndicator>`,
501
+ },
502
+ {
503
+ slug: 'cookie-preferences-drawer',
504
+ name: 'Cookie Preferences Drawer',
505
+ description: 'Full GDPR-compliant cookie consent bottom drawer with category toggles for essential, analytics, and marketing cookies.',
506
+ category: 'overlays',
507
+ tags: ["overlays","cookie","gdpr","privacy","drawer"],
508
+ featured: true,
509
+ code: `---
510
+ /**
511
+ * CookiePreferencesDrawer — GDPR/CCPA consent drawer with frosted glass styling and category toggles.
512
+ *
513
+ * @param {string} title - Header text. Default is 'Privacy Preferences'.
514
+ * @param {string} description - Explanation text for user privacy consent.
515
+ */
516
+ interface Props {
517
+ title?: string;
518
+ description?: string;
519
+ }
520
+
521
+ const {
522
+ title = 'Privacy & Cookie Settings',
523
+ description = 'We use cookies and telemetry to improve performance, analyze usage, and customize your experience.',
524
+ } = Astro.props;
525
+
526
+ const categories = [
527
+ { id: 'necessary', name: 'Strictly Necessary', desc: 'Required for core authentication and security.', locked: true },
528
+ { id: 'analytics', name: 'Performance & Analytics', desc: 'Anonymous traffic data to improve component reliability.', locked: false },
529
+ { id: 'marketing', name: 'Targeted Experience', desc: 'Personalized recommendations based on library interactions.', locked: false },
530
+ ];
531
+ ---
532
+
533
+ <aside class="cookie-drawer" role="dialog" aria-modal="true" aria-label={title} data-cookie-drawer>
534
+ <div class="cookie-drawer__header">
535
+ <div class="cookie-drawer__icon">🍪</div>
536
+ <div class="cookie-drawer__titles">
537
+ <h4 class="cookie-drawer__title">{title}</h4>
538
+ <p class="cookie-drawer__desc">{description}</p>
539
+ </div>
540
+ </div>
541
+
542
+ <div class="cookie-drawer__categories">
543
+ {categories.map((cat) => (
544
+ <div class="cookie-cat">
545
+ <div class="cookie-cat__info">
546
+ <span class="cookie-cat__name">{cat.name}</span>
547
+ <span class="cookie-cat__desc">{cat.desc}</span>
548
+ </div>
549
+ <label class="switch">
550
+ <input
551
+ type="checkbox"
552
+ checked={cat.locked}
553
+ disabled={cat.locked}
554
+ name={cat.id}
555
+ />
556
+ <span class="slider"></span>
557
+ </label>
558
+ </div>
559
+ ))}
560
+ </div>
561
+
562
+ <div class="cookie-drawer__actions">
563
+ <button type="button" class="btn btn--secondary" data-cookie-reject>Reject All</button>
564
+ <button type="button" class="btn btn--primary" data-cookie-accept>Accept Selected</button>
565
+ </div>
566
+ </aside>
567
+
568
+ <style>
569
+ .cookie-drawer {
570
+ position: fixed;
571
+ bottom: 1.5rem;
572
+ left: 1.5rem;
573
+ right: 1.5rem;
574
+ max-width: 520px;
575
+ z-index: 100;
576
+ margin: 0 auto;
577
+ padding: 1.4rem;
578
+ background: rgba(12, 12, 16, 0.94);
579
+ backdrop-filter: blur(24px);
580
+ border: 1px solid rgba(255, 255, 255, 0.12);
581
+ border-radius: var(--r-xl, 24px);
582
+ box-shadow: 0 24px 64px rgba(0, 0, 0, 0.7);
583
+ font-family: var(--font-sans, system-ui, sans-serif);
584
+ transition: transform 0.3s ease, opacity 0.3s ease;
585
+ }
586
+
587
+ .cookie-drawer__header {
588
+ display: flex;
589
+ gap: 12px;
590
+ margin-bottom: 16px;
591
+ }
592
+
593
+ .cookie-drawer__icon {
594
+ font-size: 1.8rem;
595
+ line-height: 1;
596
+ }
597
+
598
+ .cookie-drawer__title {
599
+ font-size: 1rem;
600
+ font-weight: 800;
601
+ color: var(--c-text-1, #ffffff);
602
+ margin: 0 0 4px 0;
603
+ }
604
+
605
+ .cookie-drawer__desc {
606
+ font-size: 0.8rem;
607
+ color: var(--c-text-2, #a3a3a3);
608
+ margin: 0;
609
+ line-height: 1.45;
610
+ }
611
+
612
+ .cookie-drawer__categories {
613
+ display: flex;
614
+ flex-direction: column;
615
+ gap: 10px;
616
+ margin-bottom: 18px;
617
+ padding: 10px 0;
618
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
619
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
620
+ }
621
+
622
+ .cookie-cat {
623
+ display: flex;
624
+ justify-content: space-between;
625
+ align-items: center;
626
+ gap: 12px;
627
+ }
628
+
629
+ .cookie-cat__name {
630
+ display: block;
631
+ font-size: 0.82rem;
632
+ font-weight: 700;
633
+ color: var(--c-text-1, #ffffff);
634
+ }
635
+
636
+ .cookie-cat__desc {
637
+ display: block;
638
+ font-size: 0.72rem;
639
+ color: var(--c-text-3, #737373);
640
+ }
641
+
642
+ /* Switch toggle */
643
+ .switch {
644
+ position: relative;
645
+ display: inline-block;
646
+ width: 38px;
647
+ height: 22px;
648
+ flex-shrink: 0;
649
+ }
650
+ .switch input { opacity: 0; width: 0; height: 0; }
651
+ .slider {
652
+ position: absolute;
653
+ cursor: pointer;
654
+ inset: 0;
655
+ background-color: rgba(255, 255, 255, 0.15);
656
+ border-radius: 34px;
657
+ transition: 0.25s;
658
+ }
659
+ .slider:before {
660
+ position: absolute;
661
+ content: "";
662
+ height: 16px;
663
+ width: 16px;
664
+ left: 3px;
665
+ bottom: 3px;
666
+ background-color: white;
667
+ border-radius: 50%;
668
+ transition: 0.25s;
669
+ }
670
+ input:checked + .slider {
671
+ background-color: var(--c-primary-light, #d4a017);
672
+ }
673
+ input:checked + .slider:before {
674
+ transform: translateX(16px);
675
+ }
676
+ input:disabled + .slider {
677
+ opacity: 0.6;
678
+ cursor: not-allowed;
679
+ }
680
+
681
+ .cookie-drawer__actions {
682
+ display: flex;
683
+ justify-content: flex-end;
684
+ gap: 10px;
685
+ }
686
+
687
+ .btn {
688
+ padding: 0.55rem 1.2rem;
689
+ font-size: 0.82rem;
690
+ font-weight: 700;
691
+ border-radius: var(--r-md, 10px);
692
+ cursor: pointer;
693
+ transition: all 0.2s ease;
694
+ }
695
+
696
+ .btn--secondary {
697
+ background: rgba(255, 255, 255, 0.05);
698
+ border: 1px solid rgba(255, 255, 255, 0.1);
699
+ color: var(--c-text-2, #a3a3a3);
700
+ }
701
+ .btn--secondary:hover {
702
+ color: var(--c-text-1, #ffffff);
703
+ background: rgba(255, 255, 255, 0.1);
704
+ }
705
+
706
+ .btn--primary {
707
+ background: linear-gradient(135deg, #d4a017, #b8860b);
708
+ border: none;
709
+ color: #050505;
710
+ box-shadow: 0 4px 14px rgba(184, 134, 11, 0.35);
711
+ }
712
+ .btn--primary:hover {
713
+ transform: translateY(-1px);
714
+ box-shadow: 0 6px 20px rgba(184, 134, 11, 0.45);
715
+ }
716
+ </style>
717
+
718
+ <script>
719
+ function setupCookieDrawers() {
720
+ document.querySelectorAll('[data-cookie-drawer]').forEach((drawer) => {
721
+ const dismiss = () => {
722
+ (drawer as HTMLElement).style.transform = 'translateY(120%)';
723
+ (drawer as HTMLElement).style.opacity = '0';
724
+ setTimeout(() => drawer.remove(), 350);
725
+ };
726
+
727
+ drawer.querySelector('[data-cookie-reject]')?.addEventListener('click', dismiss);
728
+ drawer.querySelector('[data-cookie-accept]')?.addEventListener('click', dismiss);
729
+ });
730
+ }
731
+
732
+ setupCookieDrawers();
733
+ document.addEventListener('astro:page-load', setupCookieDrawers);
734
+ </script>
735
+ `,
736
+ usage: `<CookiePreferencesDrawer title="Cookie Preferences" description="Manage your privacy and data sharing settings." />`,
737
+ },
738
+ {
739
+ slug: 'image-compare-slider',
740
+ name: 'Image Compare Slider',
741
+ description: 'Interactive before-and-after visual comparison slider with draggable separator handle and touch support.',
742
+ category: 'overlays',
743
+ tags: ["overlays","image","compare","slider","before-after"],
744
+ featured: true,
745
+ code: `---
746
+ /**
747
+ * ImageCompareSlider — Interactive dual-image split compare slider with draggable separator bar.
748
+ *
749
+ * @param {string} beforeImage - URL of original / before image.
750
+ * @param {string} afterImage - URL of modified / after image.
751
+ * @param {string} beforeLabel - Label tag. Default is 'Before'.
752
+ * @param {string} afterLabel - Label tag. Default is 'After'.
753
+ * @param {number} initialPosition - Starting separator position (0 to 100). Default is 50.
754
+ */
755
+ interface Props {
756
+ beforeImage?: string;
757
+ afterImage?: string;
758
+ beforeLabel?: string;
759
+ afterLabel?: string;
760
+ initialPosition?: number;
761
+ }
762
+
763
+ const {
764
+ beforeImage = 'https://images.unsplash.com/photo-1518770660439-4636190af475?w=800&auto=format&fit=crop&q=80',
765
+ afterImage = 'https://images.unsplash.com/photo-1550751827-4bd374c3f58b?w=800&auto=format&fit=crop&q=80',
766
+ beforeLabel = 'Before (Wireframe)',
767
+ afterLabel = 'After (Production)',
768
+ initialPosition = 50,
769
+ } = Astro.props;
770
+ ---
771
+
772
+ <div class="img-compare" data-img-compare style={\`--pos: \${initialPosition}%;\`}>
773
+ <div class="img-compare__layer img-compare__layer--after">
774
+ <img src={afterImage} alt={afterLabel} loading="lazy" />
775
+ <span class="img-compare__tag img-compare__tag--after">{afterLabel}</span>
776
+ </div>
777
+
778
+ <div class="img-compare__layer img-compare__layer--before" data-compare-before>
779
+ <img src={beforeImage} alt={beforeLabel} loading="lazy" />
780
+ <span class="img-compare__tag img-compare__tag--before">{beforeLabel}</span>
781
+ </div>
782
+
783
+ <div class="img-compare__handle" data-compare-handle aria-hidden="true">
784
+ <div class="handle-line"></div>
785
+ <div class="handle-button">
786
+ <span>‹</span>
787
+ <span>›</span>
788
+ </div>
789
+ </div>
790
+
791
+ <input
792
+ type="range"
793
+ min="0"
794
+ max="100"
795
+ value={initialPosition}
796
+ class="img-compare__range"
797
+ aria-label="Drag to compare images"
798
+ data-compare-range
799
+ />
800
+ </div>
801
+
802
+ <style>
803
+ .img-compare {
804
+ position: relative;
805
+ width: 100%;
806
+ max-width: 600px;
807
+ aspect-ratio: 16 / 10;
808
+ overflow: hidden;
809
+ border-radius: var(--r-xl, 20px);
810
+ border: 1px solid rgba(255, 255, 255, 0.1);
811
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
812
+ user-select: none;
813
+ font-family: var(--font-sans, system-ui, sans-serif);
814
+ }
815
+
816
+ .img-compare__layer {
817
+ position: absolute;
818
+ inset: 0;
819
+ width: 100%;
820
+ height: 100%;
821
+ }
822
+
823
+ .img-compare__layer img {
824
+ width: 100%;
825
+ height: 100%;
826
+ object-fit: cover;
827
+ display: block;
828
+ pointer-events: none;
829
+ }
830
+
831
+ .img-compare__layer--before {
832
+ clip-path: polygon(0 0, var(--pos) 0, var(--pos) 100%, 0 100%);
833
+ }
834
+
835
+ .img-compare__tag {
836
+ position: absolute;
837
+ top: 14px;
838
+ padding: 4px 10px;
839
+ background: rgba(0, 0, 0, 0.65);
840
+ backdrop-filter: blur(8px);
841
+ color: #ffffff;
842
+ font-size: 0.72rem;
843
+ font-weight: 700;
844
+ border-radius: var(--r-full, 9999px);
845
+ border: 1px solid rgba(255, 255, 255, 0.15);
846
+ pointer-events: none;
847
+ }
848
+
849
+ .img-compare__tag--before { left: 14px; }
850
+ .img-compare__tag--after { right: 14px; }
851
+
852
+ .img-compare__handle {
853
+ position: absolute;
854
+ top: 0;
855
+ bottom: 0;
856
+ left: var(--pos);
857
+ transform: translateX(-50%);
858
+ pointer-events: none;
859
+ z-index: 5;
860
+ display: flex;
861
+ flex-direction: column;
862
+ align-items: center;
863
+ justify-content: center;
864
+ }
865
+
866
+ .handle-line {
867
+ width: 2px;
868
+ height: 100%;
869
+ background: #ffffff;
870
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.8);
871
+ }
872
+
873
+ .handle-button {
874
+ position: absolute;
875
+ top: 50%;
876
+ transform: translateY(-50%);
877
+ width: 36px;
878
+ height: 36px;
879
+ border-radius: 50%;
880
+ background: #ffffff;
881
+ color: #050505;
882
+ display: flex;
883
+ align-items: center;
884
+ justify-content: center;
885
+ gap: 4px;
886
+ font-size: 0.95rem;
887
+ font-weight: 900;
888
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6);
889
+ }
890
+
891
+ .img-compare__range {
892
+ position: absolute;
893
+ inset: 0;
894
+ width: 100%;
895
+ height: 100%;
896
+ opacity: 0;
897
+ cursor: ew-resize;
898
+ z-index: 10;
899
+ }
900
+ </style>
901
+
902
+ <script>
903
+ function setupImageCompare() {
904
+ document.querySelectorAll('[data-img-compare]').forEach((comp) => {
905
+ const range = comp.querySelector('[data-compare-range]') as HTMLInputElement;
906
+ if (!range) return;
907
+
908
+ range.addEventListener('input', () => {
909
+ (comp as HTMLElement).style.setProperty('--pos', \`\${range.value}%\`);
910
+ });
911
+ });
912
+ }
913
+
914
+ setupImageCompare();
915
+ document.addEventListener('astro:page-load', setupImageCompare);
916
+ </script>
917
+ `,
918
+ usage: `<ImageCompareSlider beforeImage="/assets/before.webp" afterImage="/assets/after.webp" beforeLabel="Before" afterLabel="After" />`,
919
+ },
920
+ {
921
+ slug: 'floating-feedback-widget',
922
+ name: 'Floating Feedback Widget',
923
+ description: 'Fixed bottom-right collapsible feedback trigger with emoji satisfaction ratings and text submission textarea.',
924
+ category: 'overlays',
925
+ tags: ["overlays","feedback","floating","widget","survey"],
926
+ featured: false,
927
+ code: `---
928
+ /**
929
+ * FloatingFeedbackWidget — Fixed corner floating pill that expands into an interactive feedback survey card.
930
+ *
931
+ * @param {string} title - Widget title. Default is 'Was this helpful?'.
932
+ * @param {string} position - Screen anchor ('bottom-right' | 'bottom-left'). Default is 'bottom-right'.
933
+ */
934
+ interface Props {
935
+ title?: string;
936
+ position?: 'bottom-right' | 'bottom-left';
937
+ }
938
+
939
+ const {
940
+ title = 'Send Feedback',
941
+ position = 'bottom-right',
942
+ } = Astro.props;
943
+ ---
944
+
945
+ <div class:list={['fb-widget', \`fb-widget--\${position}\`]} data-feedback-widget>
946
+ <button type="button" class="fb-widget__trigger" aria-label="Open feedback modal" data-fb-trigger>
947
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
948
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
949
+ </svg>
950
+ <span>Feedback</span>
951
+ </button>
952
+
953
+ <div class="fb-widget__card" data-fb-card hidden>
954
+ <div class="fb-widget__head">
955
+ <h5 class="fb-widget__title">{title}</h5>
956
+ <button type="button" class="fb-widget__close" aria-label="Close" data-fb-close>×</button>
957
+ </div>
958
+
959
+ <div class="fb-widget__emojis">
960
+ <button type="button" class="emoji-btn" aria-label="Sad">🙁</button>
961
+ <button type="button" class="emoji-btn" aria-label="Neutral">😐</button>
962
+ <button type="button" class="emoji-btn emoji-btn--selected" aria-label="Happy">😊</button>
963
+ <button type="button" class="emoji-btn" aria-label="Love it">🤩</button>
964
+ </div>
965
+
966
+ <textarea
967
+ placeholder="Any details to share? (optional)"
968
+ class="fb-widget__textarea"
969
+ rows="2"
970
+ ></textarea>
971
+
972
+ <button type="button" class="fb-widget__send" data-fb-send>
973
+ Send Feedback
974
+ </button>
975
+ </div>
976
+ </div>
977
+
978
+ <style>
979
+ .fb-widget {
980
+ position: fixed;
981
+ z-index: 90;
982
+ font-family: var(--font-sans, system-ui, sans-serif);
983
+ }
984
+
985
+ .fb-widget--bottom-right { bottom: 1.5rem; right: 1.5rem; }
986
+ .fb-widget--bottom-left { bottom: 1.5rem; left: 1.5rem; }
987
+
988
+ .fb-widget__trigger {
989
+ display: inline-flex;
990
+ align-items: center;
991
+ gap: 8px;
992
+ padding: 0.6rem 1.1rem;
993
+ background: rgba(14, 14, 18, 0.9);
994
+ backdrop-filter: blur(16px);
995
+ border: 1px solid rgba(255, 255, 255, 0.12);
996
+ border-radius: var(--r-full, 9999px);
997
+ color: var(--c-text-1, #ffffff);
998
+ font-size: 0.82rem;
999
+ font-weight: 700;
1000
+ cursor: pointer;
1001
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
1002
+ transition: transform 0.2s ease, border-color 0.2s ease;
1003
+ }
1004
+
1005
+ .fb-widget__trigger:hover {
1006
+ transform: translateY(-2px);
1007
+ border-color: rgba(184, 134, 11, 0.4);
1008
+ color: var(--c-primary-light, #d4a017);
1009
+ }
1010
+
1011
+ .fb-widget__card {
1012
+ position: absolute;
1013
+ bottom: calc(100% + 12px);
1014
+ right: 0;
1015
+ width: 280px;
1016
+ padding: 1.2rem;
1017
+ background: rgba(12, 12, 16, 0.95);
1018
+ backdrop-filter: blur(24px);
1019
+ border: 1px solid rgba(255, 255, 255, 0.12);
1020
+ border-radius: var(--r-xl, 20px);
1021
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.6);
1022
+ display: flex;
1023
+ flex-direction: column;
1024
+ gap: 12px;
1025
+ }
1026
+
1027
+ .fb-widget__head {
1028
+ display: flex;
1029
+ justify-content: space-between;
1030
+ align-items: center;
1031
+ }
1032
+
1033
+ .fb-widget__title {
1034
+ font-size: 0.88rem;
1035
+ font-weight: 800;
1036
+ color: var(--c-text-1, #ffffff);
1037
+ margin: 0;
1038
+ }
1039
+
1040
+ .fb-widget__close {
1041
+ background: transparent;
1042
+ border: none;
1043
+ color: var(--c-text-3, #737373);
1044
+ font-size: 1.2rem;
1045
+ line-height: 1;
1046
+ cursor: pointer;
1047
+ }
1048
+
1049
+ .fb-widget__emojis {
1050
+ display: flex;
1051
+ justify-content: space-between;
1052
+ gap: 6px;
1053
+ }
1054
+
1055
+ .emoji-btn {
1056
+ flex: 1;
1057
+ font-size: 1.4rem;
1058
+ background: rgba(255, 255, 255, 0.03);
1059
+ border: 1px solid rgba(255, 255, 255, 0.08);
1060
+ border-radius: var(--r-md, 10px);
1061
+ padding: 6px 0;
1062
+ cursor: pointer;
1063
+ transition: transform 0.2s ease, background 0.2s ease;
1064
+ }
1065
+
1066
+ .emoji-btn:hover,
1067
+ .emoji-btn--selected {
1068
+ transform: scale(1.15);
1069
+ background: rgba(184, 134, 11, 0.2);
1070
+ border-color: rgba(184, 134, 11, 0.4);
1071
+ }
1072
+
1073
+ .fb-widget__textarea {
1074
+ width: 100%;
1075
+ background: rgba(255, 255, 255, 0.03);
1076
+ border: 1px solid rgba(255, 255, 255, 0.08);
1077
+ border-radius: var(--r-sm, 8px);
1078
+ color: var(--c-text-1, #ffffff);
1079
+ font-size: 0.8rem;
1080
+ padding: 8px;
1081
+ resize: none;
1082
+ outline: none;
1083
+ font-family: inherit;
1084
+ }
1085
+
1086
+ .fb-widget__send {
1087
+ padding: 0.6rem;
1088
+ background: linear-gradient(135deg, #d4a017, #b8860b);
1089
+ border: none;
1090
+ border-radius: var(--r-sm, 8px);
1091
+ color: #050505;
1092
+ font-size: 0.8rem;
1093
+ font-weight: 800;
1094
+ cursor: pointer;
1095
+ transition: opacity 0.2s;
1096
+ }
1097
+
1098
+ .fb-widget__send:hover {
1099
+ opacity: 0.9;
1100
+ }
1101
+ </style>
1102
+
1103
+ <script>
1104
+ function setupFeedbackWidgets() {
1105
+ document.querySelectorAll('[data-feedback-widget]').forEach((widget) => {
1106
+ const trigger = widget.querySelector('[data-fb-trigger]');
1107
+ const card = widget.querySelector('[data-fb-card]') as HTMLElement;
1108
+ const close = widget.querySelector('[data-fb-close]');
1109
+ const send = widget.querySelector('[data-fb-send]');
1110
+ if (!trigger || !card) return;
1111
+
1112
+ trigger.addEventListener('click', () => {
1113
+ card.hidden = !card.hidden;
1114
+ });
1115
+
1116
+ close?.addEventListener('click', () => {
1117
+ card.hidden = true;
1118
+ });
1119
+
1120
+ send?.addEventListener('click', () => {
1121
+ card.innerHTML = \`<p style="text-align:center;font-size:0.85rem;color:#10b981;font-weight:700;margin:1rem 0;">✓ Thank you for your feedback!</p>\`;
1122
+ setTimeout(() => { card.hidden = true; }, 2000);
1123
+ });
1124
+ });
1125
+ }
1126
+
1127
+ setupFeedbackWidgets();
1128
+ document.addEventListener('astro:page-load', setupFeedbackWidgets);
1129
+ </script>
1130
+ `,
1131
+ usage: `<FloatingFeedbackWidget placeholder="How can we improve this experience?" />`,
1132
+ },
1133
+ ];