astro-component-kit 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -27
- package/package.json +16 -3
- package/src/components/index.ts +2 -0
- package/src/components/lib/Galaxy3D.astro +249 -137
- package/src/components/lib/app/AppSidebar.astro +249 -0
- package/src/components/lib/app/AppTopbar.astro +284 -0
- package/src/components/lib/app/ArrivalsBoard.astro +176 -0
- package/src/components/lib/app/AuthCard.astro +213 -0
- package/src/components/lib/app/DataTable.astro +346 -0
- package/src/components/lib/app/GuestProfileCard.astro +133 -0
- package/src/components/lib/app/HousekeepingBoard.astro +189 -0
- package/src/components/lib/app/PageHeader.astro +157 -0
- package/src/components/lib/app/PlanUsageCard.astro +112 -0
- package/src/components/lib/app/RoomRack.astro +207 -0
- package/src/components/lib/app/SettingsSection.astro +96 -0
- package/src/components/lib/app/SwitchRow.astro +71 -0
- package/src/components/lib/app/TeamMembers.astro +190 -0
- package/src/components/lib/app/app-icons.ts +52 -0
- package/src/components/lib/app/index.ts +19 -0
- package/src/components/lib/charts/AreaChart.astro +4 -4
- package/src/components/lib/charts/BarChart.astro +3 -3
- package/src/components/lib/charts/ChartFrame.astro +10 -10
- package/src/components/lib/charts/DonutChart.astro +2 -2
- package/src/components/lib/charts/DumbbellChart.astro +1 -1
- package/src/components/lib/charts/ForecastLineChart.astro +1 -1
- package/src/components/lib/charts/GaugeChart.astro +1 -1
- package/src/components/lib/charts/HeatmapChart.astro +1 -1
- package/src/components/lib/charts/HorizontalBarChart.astro +2 -2
- package/src/components/lib/charts/KpiStatTile.astro +4 -4
- package/src/components/lib/charts/LinearProgressGauge.astro +4 -4
- package/src/components/lib/charts/MetricDeltaTable.astro +3 -3
- package/src/components/lib/charts/RadarMetricChart.astro +4 -4
- package/src/components/lib/charts/RadialBarChart.astro +1 -1
- package/src/components/lib/charts/RetentionCohortTable.astro +2 -2
- package/src/components/lib/charts/TreemapChart.astro +1 -1
- package/src/components/lib/ecommerce/CartDrawer.astro +483 -0
- package/src/components/lib/ecommerce/CartPageList.astro +290 -0
- package/src/components/lib/ecommerce/CartToast.astro +276 -0
- package/src/components/lib/ecommerce/CategoryTiles.astro +143 -0
- package/src/components/lib/ecommerce/CheckoutForm.astro +423 -0
- package/src/components/lib/ecommerce/CountdownBanner.astro +230 -0
- package/src/components/lib/ecommerce/FilterBar.astro +278 -0
- package/src/components/lib/ecommerce/FilterSidebar.astro +405 -0
- package/src/components/lib/ecommerce/LiveActivityToast.astro +213 -0
- package/src/components/lib/ecommerce/OrderSummary.astro +295 -0
- package/src/components/lib/ecommerce/ProductBuyBox.astro +247 -0
- package/src/components/lib/ecommerce/ProductCardMinimal.astro +229 -0
- package/src/components/lib/ecommerce/ProductGallery.astro +145 -0
- package/src/components/lib/ecommerce/ProductGrid.astro +118 -0
- package/src/components/lib/ecommerce/ProductMedia.astro +113 -0
- package/src/components/lib/ecommerce/ProductRating.astro +78 -0
- package/src/components/lib/ecommerce/ProductToolbar.astro +93 -0
- package/src/components/lib/ecommerce/PromoBar.astro +145 -0
- package/src/components/lib/ecommerce/StockIndicator.astro +127 -0
- package/src/components/lib/ecommerce/StoreHeader.astro +446 -0
- package/src/components/lib/ecommerce/StoreHero.astro +260 -0
- package/src/components/lib/ecommerce/StoreProductCard.astro +307 -0
- package/src/components/lib/ecommerce/TrustBadges.astro +101 -0
- package/src/components/lib/ecommerce/VariantPicker.astro +145 -0
- package/src/components/lib/ecommerce/cart-store.ts +151 -0
- package/src/components/lib/ecommerce/catalog-filter.ts +62 -0
- package/src/components/lib/ecommerce/index.ts +34 -0
- package/src/components/lib/ecommerce/product-icons.ts +28 -0
- package/src/components/lib/ecommerce/types.ts +70 -0
- package/src/components/lib/forms/AnimatedInput.astro +4 -2
- package/src/components/lib/forms/CustomRadioGroup.astro +3 -1
- package/src/components/lib/index.ts +2 -0
- package/src/components/lib/layout/BentoGrid3.astro +6 -4
- package/src/components/lib/layout/CenterFixedBox.astro +2 -2
- package/src/components/lib/layout/CenteredContainer.astro +4 -2
- package/src/components/lib/layout/ClusterHorizontal.astro +2 -2
- package/src/components/lib/layout/FeatureHero.astro +4 -2
- package/src/components/lib/layout/FooterCenteredMinimal.astro +4 -2
- package/src/components/lib/layout/FullBleedSection.astro +2 -2
- package/src/components/lib/layout/GalleryGrid4.astro +2 -2
- package/src/components/lib/layout/HolyGrailGrid.astro +11 -9
- package/src/components/lib/layout/LandingSectionSplit.astro +5 -3
- package/src/components/lib/layout/MasonryGrid.astro +2 -2
- package/src/components/lib/layout/MinimalFooterGrid.astro +1 -1
- package/src/components/lib/layout/ScrollSnapSection.astro +1 -1
- package/src/components/lib/layout/SidebarLayoutWrapper.astro +4 -2
- package/src/components/lib/layout/SplitScreenLayout.astro +3 -3
- package/src/components/lib/layout/StepLayoutVertical.astro +1 -1
- package/src/components/lib/layout/StickySidebarWrapper.astro +4 -2
- package/src/components/lib/sections/AgencyContactBrief.astro +194 -0
- package/src/components/lib/sections/AgencyFooterCta.astro +94 -0
- package/src/components/lib/sections/AgencyHeader.astro +161 -0
- package/src/components/lib/sections/AgencyHeroKinetic.astro +172 -0
- package/src/components/lib/sections/AgencyServicesList.astro +113 -0
- package/src/components/lib/sections/AgencyTeamGrid.astro +111 -0
- package/src/components/lib/sections/AgencyWorkGrid.astro +147 -0
- package/src/components/lib/sections/BlogGridSection.astro +9 -7
- package/src/components/lib/sections/ButtonsShowcase.astro +20 -18
- package/src/components/lib/sections/CardsShowcase.astro +28 -26
- package/src/components/lib/sections/CareersOpenings.astro +10 -8
- package/src/components/lib/sections/ChangelogSection.astro +14 -7
- package/src/components/lib/sections/ContactGlassForm.astro +10 -8
- package/src/components/lib/sections/ContactSplitMap.astro +11 -9
- package/src/components/lib/sections/CtaAppDownload.astro +13 -11
- package/src/components/lib/sections/CtaGlowBanner.astro +12 -10
- package/src/components/lib/sections/CtaNewsletterSection.astro +13 -11
- package/src/components/lib/sections/CtaSplitImage.astro +13 -11
- package/src/components/lib/sections/DataShowcase.astro +23 -21
- package/src/components/lib/sections/FaqAccordionSection.astro +8 -8
- package/src/components/lib/sections/FaqTwoColumn.astro +9 -7
- package/src/components/lib/sections/FeatureAlternatingRows.astro +10 -8
- package/src/components/lib/sections/FeatureBentoGrid.astro +13 -11
- package/src/components/lib/sections/FeatureIconGrid.astro +6 -6
- package/src/components/lib/sections/FeatureTabsShowcase.astro +13 -11
- package/src/components/lib/sections/FeatureTimelineFlow.astro +8 -6
- package/src/components/lib/sections/FeedbackShowcase.astro +15 -13
- package/src/components/lib/sections/FooterMegaSection.astro +13 -11
- package/src/components/lib/sections/FormsShowcase.astro +22 -20
- package/src/components/lib/sections/HeroDashboardPreview.astro +11 -9
- package/src/components/lib/sections/HeroGlass.astro +22 -20
- package/src/components/lib/sections/HeroGradient.astro +15 -13
- package/src/components/lib/sections/HeroMinimalCentered.astro +10 -10
- package/src/components/lib/sections/HeroShowcaseSplit.astro +18 -16
- package/src/components/lib/sections/HeroSplit.astro +13 -11
- package/src/components/lib/sections/HeroTerminal.astro +14 -12
- package/src/components/lib/sections/HeroWaitlist.astro +10 -8
- package/src/components/lib/sections/HowItWorksSteps.astro +12 -10
- package/src/components/lib/sections/IntegrationsGrid.astro +7 -7
- package/src/components/lib/sections/LayoutShowcase.astro +21 -19
- package/src/components/lib/sections/LogoCloudSection.astro +4 -4
- package/src/components/lib/sections/LogoWallGrid.astro +6 -4
- package/src/components/lib/sections/NavigationShowcase.astro +15 -13
- package/src/components/lib/sections/OverlaysShowcase.astro +21 -19
- package/src/components/lib/sections/PricingComparisonMatrix.astro +15 -13
- package/src/components/lib/sections/PricingSinglePlan.astro +13 -11
- package/src/components/lib/sections/PricingTierCards.astro +11 -9
- package/src/components/lib/sections/PricingToggleCards.astro +13 -13
- package/src/components/lib/sections/ShopCategoryHero.astro +103 -0
- package/src/components/lib/sections/ShopCollectionMosaic.astro +131 -0
- package/src/components/lib/sections/ShopFooterWordmark.astro +100 -0
- package/src/components/lib/sections/ShopHeaderEditorial.astro +396 -0
- package/src/components/lib/sections/ShopHeroEditorial.astro +151 -0
- package/src/components/lib/sections/ShopLookbook.astro +250 -0
- package/src/components/lib/sections/ShopNewsletterEditorial.astro +128 -0
- package/src/components/lib/sections/ShopProductRail.astro +150 -0
- package/src/components/lib/sections/ShopReviewsEditorial.astro +133 -0
- package/src/components/lib/sections/ShopValuesMarquee.astro +91 -0
- package/src/components/lib/sections/StatsCounterBand.astro +9 -7
- package/src/components/lib/sections/StatsDashboardSection.astro +4 -2
- package/src/components/lib/sections/StatsMetricShowcase.astro +9 -7
- package/src/components/lib/sections/TeamGridSection.astro +12 -10
- package/src/components/lib/sections/TestimonialCarousel.astro +10 -8
- package/src/components/lib/sections/TestimonialFeatured.astro +7 -5
- package/src/components/lib/sections/TestimonialGridSection.astro +7 -7
- package/src/components/lib/sections/TestimonialWallGlass.astro +11 -9
- package/src/components/lib/sections/TypographyShowcase.astro +10 -8
- package/src/components/lib/sections/index.ts +10 -0
- package/src/components/lib/templates/ecommerce/StoreCategoryPage.astro +160 -0
- package/src/components/lib/templates/ecommerce/StoreCheckoutPage.astro +98 -0
- package/src/components/lib/templates/ecommerce/StoreHomePage.astro +191 -0
- package/src/components/lib/templates/ecommerce/StoreLayout.astro +169 -0
- package/src/components/lib/templates/ecommerce/StoreProductPage.astro +165 -0
- package/src/components/lib/templates/ecommerce/data.ts +187 -0
- package/src/components/lib/templates/ecommerce/index.ts +14 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialBagPage.astro +52 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialCheckoutPage.astro +123 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialHomePage.astro +102 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialLayout.astro +216 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialProductPage.astro +205 -0
- package/src/components/lib/templates/ecommerce-editorial/EditorialShopPage.astro +112 -0
- package/src/components/lib/templates/ecommerce-editorial/data.ts +125 -0
- package/src/components/lib/templates/ecommerce-editorial/index.ts +16 -0
- package/src/components/lib/templates/saas-hotel/AppLayout.astro +83 -0
- package/src/components/lib/templates/saas-hotel/DashboardPage.astro +66 -0
- package/src/components/lib/templates/saas-hotel/GuestsPage.astro +65 -0
- package/src/components/lib/templates/saas-hotel/LandingPage.astro +213 -0
- package/src/components/lib/templates/saas-hotel/ReportsPage.astro +63 -0
- package/src/components/lib/templates/saas-hotel/ReservationsPage.astro +49 -0
- package/src/components/lib/templates/saas-hotel/RoomsPage.astro +48 -0
- package/src/components/lib/templates/saas-hotel/SettingsPage.astro +115 -0
- package/src/components/lib/templates/saas-hotel/SignInPage.astro +50 -0
- package/src/components/lib/templates/saas-hotel/data.ts +229 -0
- package/src/components/lib/templates/saas-hotel/index.ts +19 -0
- package/src/components/lib/templates/saas-hotel/lobby-theme.css +90 -0
- package/src/styles/global.css +95 -0
|
@@ -37,6 +37,7 @@ const initials = (n: string) => n.split(' ').map((p) => p[0]).slice(0, 2).join('
|
|
|
37
37
|
const hues = ['var(--chart-1, #3987e5)', 'var(--chart-2, #d95926)', 'var(--chart-3, #199e70)', 'var(--chart-5, #d55181)', 'var(--chart-7, #9085e9)'];
|
|
38
38
|
---
|
|
39
39
|
|
|
40
|
+
<div class="cq-testimonial-carousel-cq">
|
|
40
41
|
<section class={`tc tc--${variant} tc--${size} ${className}`} aria-labelledby={id} aria-roledescription="carousel" data-tc>
|
|
41
42
|
<div class="tc__inner">
|
|
42
43
|
<header class="tc__head">
|
|
@@ -73,7 +74,7 @@ const hues = ['var(--chart-1, #3987e5)', 'var(--chart-2, #d95926)', 'var(--chart
|
|
|
73
74
|
</ul>
|
|
74
75
|
</div>
|
|
75
76
|
</section>
|
|
76
|
-
|
|
77
|
+
</div>
|
|
77
78
|
<script>
|
|
78
79
|
document.querySelectorAll<HTMLElement>('[data-tc]').forEach((root) => {
|
|
79
80
|
const track = root.querySelector<HTMLElement>('.tc__track');
|
|
@@ -96,6 +97,7 @@ const hues = ['var(--chart-1, #3987e5)', 'var(--chart-2, #d95926)', 'var(--chart
|
|
|
96
97
|
</script>
|
|
97
98
|
|
|
98
99
|
<style>
|
|
100
|
+
.cq-testimonial-carousel-cq { container-type: inline-size; }
|
|
99
101
|
.tc {
|
|
100
102
|
--tc-py: 5.5rem;
|
|
101
103
|
padding: var(--tc-py) var(--sp-6, 1.5rem);
|
|
@@ -114,13 +116,13 @@ const hues = ['var(--chart-1, #3987e5)', 'var(--chart-2, #d95926)', 'var(--chart
|
|
|
114
116
|
width: 48px;
|
|
115
117
|
height: 48px;
|
|
116
118
|
border-radius: 50%;
|
|
117
|
-
border: 1px solid
|
|
118
|
-
background:
|
|
119
|
+
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.14);
|
|
120
|
+
background: rgb(var(--ink-rgb, 255 255 255) / 0.03);
|
|
119
121
|
color: var(--c-text-1, #fff);
|
|
120
122
|
cursor: pointer;
|
|
121
123
|
transition: background 0.2s ease, border-color 0.2s ease, opacity 0.2s ease;
|
|
122
124
|
}
|
|
123
|
-
.tc__btn:hover:not(:disabled) { background:
|
|
125
|
+
.tc__btn:hover:not(:disabled) { background: rgb(var(--ink-rgb, 255 255 255) / 0.08); border-color: rgb(var(--ink-rgb, 255 255 255) / 0.3); }
|
|
124
126
|
.tc__btn:disabled { opacity: 0.35; cursor: not-allowed; }
|
|
125
127
|
.tc__btn:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 2px; }
|
|
126
128
|
.tc__track {
|
|
@@ -148,10 +150,10 @@ const hues = ['var(--chart-1, #3987e5)', 'var(--chart-2, #d95926)', 'var(--chart
|
|
|
148
150
|
border-radius: var(--r-lg, 20px);
|
|
149
151
|
box-sizing: border-box;
|
|
150
152
|
}
|
|
151
|
-
.tc--glass .tc__card { background: linear-gradient(160deg,
|
|
152
|
-
.tc--solid .tc__card { background: var(--c-bg-2, #111); border: 1px solid
|
|
153
|
+
.tc--glass .tc__card { background: linear-gradient(160deg, rgb(var(--ink-rgb, 255 255 255) / 0.05), rgb(var(--ink-rgb, 255 255 255) / 0.015)); border: 1px solid var(--c-border, rgb(var(--ink-rgb, 255 255 255) / 0.07)); }
|
|
154
|
+
.tc--solid .tc__card { background: var(--c-bg-2, #111); border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.05); }
|
|
153
155
|
.tc--quote .tc__card { border-left: 2px solid var(--c-primary-light, #d4a017); border-radius: 0; padding-left: 1.5rem; }
|
|
154
|
-
.tc__stars { display: flex; gap: 2px; color:
|
|
156
|
+
.tc__stars { display: flex; gap: 2px; color: rgb(var(--ink-rgb, 255 255 255) / 0.15); }
|
|
155
157
|
.tc__stars .is-on { color: var(--c-primary-light, #d4a017); }
|
|
156
158
|
.tc__quote { margin: 0; flex: 1; }
|
|
157
159
|
.tc__quote p { margin: 0; font-size: 1.0625rem; line-height: 1.6; color: var(--c-text-1, #fff); }
|
|
@@ -159,7 +161,7 @@ const hues = ['var(--chart-1, #3987e5)', 'var(--chart-2, #d95926)', 'var(--chart
|
|
|
159
161
|
.tc__author strong { display: block; color: var(--c-text-1, #fff); font-weight: 650; }
|
|
160
162
|
.tc__role { display: block; color: var(--c-text-2, #a3a3a3); font-size: 0.8125rem; }
|
|
161
163
|
.tc__avatar { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; color: #fff; font-weight: 700; font-size: 0.8125rem; flex-shrink: 0; }
|
|
162
|
-
@
|
|
164
|
+
@container (max-width: 560px) {
|
|
163
165
|
.tc__head { flex-direction: column; align-items: flex-start; }
|
|
164
166
|
}
|
|
165
167
|
</style>
|
|
@@ -44,6 +44,7 @@ const {
|
|
|
44
44
|
const initials = name.split(' ').map((p) => p[0]).slice(0, 2).join('');
|
|
45
45
|
---
|
|
46
46
|
|
|
47
|
+
<div class="cq-testimonial-featured-cq">
|
|
47
48
|
<section class={`tf tf--${variant} tf--${size} ${className}`} aria-label={`Customer story: ${company}`}>
|
|
48
49
|
<div class="tf__inner">
|
|
49
50
|
<figure class="tf__figure">
|
|
@@ -77,8 +78,9 @@ const initials = name.split(' ').map((p) => p[0]).slice(0, 2).join('');
|
|
|
77
78
|
</div>
|
|
78
79
|
</div>
|
|
79
80
|
</section>
|
|
80
|
-
|
|
81
|
+
</div>
|
|
81
82
|
<style>
|
|
83
|
+
.cq-testimonial-featured-cq { container-type: inline-size; }
|
|
82
84
|
.tf {
|
|
83
85
|
--tf-py: 5.5rem;
|
|
84
86
|
padding: var(--tf-py) var(--sp-6, 1.5rem);
|
|
@@ -90,8 +92,8 @@ const initials = name.split(' ').map((p) => p[0]).slice(0, 2).join('');
|
|
|
90
92
|
.tf--card .tf__inner {
|
|
91
93
|
padding: clamp(2rem, 5vw, 3.5rem);
|
|
92
94
|
border-radius: var(--r-xl, 28px);
|
|
93
|
-
background: radial-gradient(circle at 0% 0%, var(--c-primary-glow,
|
|
94
|
-
border: 1px solid var(--c-border,
|
|
95
|
+
background: radial-gradient(circle at 0% 0%, var(--c-primary-glow, color-mix(in srgb, var(--c-primary, #b8860b) 14%, transparent)), transparent 55%), rgb(var(--ink-rgb, 255 255 255) / 0.025);
|
|
96
|
+
border: 1px solid var(--c-border, rgb(var(--ink-rgb, 255 255 255) / 0.08));
|
|
95
97
|
}
|
|
96
98
|
.tf--centered .tf__inner { grid-template-columns: 1fr; text-align: center; max-width: 860px; }
|
|
97
99
|
.tf--centered .tf__author, .tf--centered .tf__company { justify-content: center; }
|
|
@@ -106,7 +108,7 @@ const initials = name.split(' ').map((p) => p[0]).slice(0, 2).join('');
|
|
|
106
108
|
.tf__role { display: block; font-size: 0.875rem; color: var(--c-text-2, #a3a3a3); }
|
|
107
109
|
.tf__avatar { display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%; background: linear-gradient(135deg, var(--chart-7, #9085e9), var(--chart-1, #3987e5)); color: #fff; font-weight: 700; }
|
|
108
110
|
.tf__side { display: grid; gap: 1.5rem; }
|
|
109
|
-
.tf__metrics { margin: 0; display: grid; gap: 1px; border-radius: var(--r-lg, 20px); overflow: hidden; background:
|
|
111
|
+
.tf__metrics { margin: 0; display: grid; gap: 1px; border-radius: var(--r-lg, 20px); overflow: hidden; background: rgb(var(--ink-rgb, 255 255 255) / 0.07); }
|
|
110
112
|
.tf--centered .tf__metrics { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
|
|
111
113
|
.tf__metric { display: flex; flex-direction: column-reverse; gap: 0.25rem; padding: 1.25rem 1.5rem; background: var(--c-bg-1, #0a0a0a); }
|
|
112
114
|
.tf__metric dt { font-size: 0.875rem; color: var(--c-text-2, #a3a3a3); }
|
|
@@ -116,5 +118,5 @@ const initials = name.split(' ').map((p) => p[0]).slice(0, 2).join('');
|
|
|
116
118
|
.tf__link svg { transition: transform 0.2s ease; }
|
|
117
119
|
.tf__link:hover svg { transform: translateX(3px); }
|
|
118
120
|
.tf__link:focus-visible { outline: 2px solid var(--c-primary-light, #d4a017); outline-offset: 2px; border-radius: 4px; }
|
|
119
|
-
@
|
|
121
|
+
@container (max-width: 820px) { .tf__inner { grid-template-columns: 1fr; } }
|
|
120
122
|
</style>
|
|
@@ -95,7 +95,7 @@ const testimonials = [
|
|
|
95
95
|
letter-spacing: 0.12em;
|
|
96
96
|
color: var(--c-primary-light, #d4a017);
|
|
97
97
|
padding: 0.35rem 0.8rem;
|
|
98
|
-
border: 1px solid
|
|
98
|
+
border: 1px solid color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent);
|
|
99
99
|
border-radius: var(--r-sm, 8px);
|
|
100
100
|
margin-bottom: 1rem;
|
|
101
101
|
text-transform: uppercase;
|
|
@@ -126,21 +126,21 @@ const testimonials = [
|
|
|
126
126
|
display: flex;
|
|
127
127
|
flex-direction: column;
|
|
128
128
|
padding: var(--sp-8, 2rem);
|
|
129
|
-
background:
|
|
129
|
+
background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
|
|
130
130
|
backdrop-filter: blur(16px);
|
|
131
|
-
border: 1px solid
|
|
131
|
+
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
|
|
132
132
|
border-radius: var(--r-xl, 24px);
|
|
133
133
|
transition: transform 0.3s ease, border-color 0.3s ease;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
.testi-card:hover {
|
|
137
137
|
transform: translateY(-4px);
|
|
138
|
-
border-color:
|
|
138
|
+
border-color: color-mix(in srgb, var(--c-primary, #b8860b) 30%, transparent);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
.testi-card--highlight {
|
|
142
|
-
background: radial-gradient(circle at top left,
|
|
143
|
-
border-color:
|
|
142
|
+
background: radial-gradient(circle at top left, color-mix(in srgb, var(--c-primary, #b8860b) 10%, transparent), rgb(var(--ink-rgb, 255 255 255) / 0.02) 70%);
|
|
143
|
+
border-color: color-mix(in srgb, var(--c-primary, #b8860b) 40%, transparent);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
.testi-card__stars {
|
|
@@ -171,7 +171,7 @@ const testimonials = [
|
|
|
171
171
|
height: 44px;
|
|
172
172
|
border-radius: 50%;
|
|
173
173
|
object-fit: cover;
|
|
174
|
-
border: 2px solid
|
|
174
|
+
border: 2px solid color-mix(in srgb, var(--c-primary, #b8860b) 40%, transparent);
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
.testi-card__name {
|
|
@@ -21,6 +21,7 @@ const {
|
|
|
21
21
|
} = Astro.props;
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
+
<div class="cq-testimonial-wall-glass-cq">
|
|
24
25
|
<section class={`testimonials-section ${className}`} aria-labelledby="testimonials-title">
|
|
25
26
|
<div class="testimonials-bg" aria-hidden="true">
|
|
26
27
|
<div class="test-glow test-glow--1"></div>
|
|
@@ -151,8 +152,9 @@ const {
|
|
|
151
152
|
</div>
|
|
152
153
|
</div>
|
|
153
154
|
</section>
|
|
154
|
-
|
|
155
|
+
</div>
|
|
155
156
|
<style>
|
|
157
|
+
.cq-testimonial-wall-glass-cq { container-type: inline-size; }
|
|
156
158
|
.testimonials-section {
|
|
157
159
|
position: relative;
|
|
158
160
|
padding: var(--sp-20, 5rem) var(--sp-6, 1.5rem);
|
|
@@ -211,7 +213,7 @@ const {
|
|
|
211
213
|
font-weight: 700;
|
|
212
214
|
letter-spacing: 0.06em;
|
|
213
215
|
text-transform: uppercase;
|
|
214
|
-
background:
|
|
216
|
+
background: color-mix(in srgb, var(--c-primary, #b8860b) 12%, transparent);
|
|
215
217
|
color: #eab308;
|
|
216
218
|
border: 1px solid rgba(234, 179, 8, 0.25);
|
|
217
219
|
margin-bottom: var(--sp-4, 1rem);
|
|
@@ -241,7 +243,7 @@ const {
|
|
|
241
243
|
gap: 2rem;
|
|
242
244
|
padding: 1.25rem 2rem;
|
|
243
245
|
background: rgba(15, 23, 42, 0.7);
|
|
244
|
-
border: 1px solid
|
|
246
|
+
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
|
|
245
247
|
border-radius: 16px;
|
|
246
248
|
backdrop-filter: blur(12px);
|
|
247
249
|
max-width: 750px;
|
|
@@ -284,7 +286,7 @@ const {
|
|
|
284
286
|
.trust-sep {
|
|
285
287
|
width: 1px;
|
|
286
288
|
height: 40px;
|
|
287
|
-
background:
|
|
289
|
+
background: rgb(var(--ink-rgb, 255 255 255) / 0.1);
|
|
288
290
|
}
|
|
289
291
|
|
|
290
292
|
/* Wall Grid */
|
|
@@ -299,7 +301,7 @@ const {
|
|
|
299
301
|
background: rgba(15, 23, 42, 0.55);
|
|
300
302
|
backdrop-filter: blur(20px);
|
|
301
303
|
-webkit-backdrop-filter: blur(20px);
|
|
302
|
-
border: 1px solid
|
|
304
|
+
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
|
|
303
305
|
border-radius: var(--r-xl, 18px);
|
|
304
306
|
padding: 1.75rem;
|
|
305
307
|
display: flex;
|
|
@@ -310,7 +312,7 @@ const {
|
|
|
310
312
|
|
|
311
313
|
.test-card:hover {
|
|
312
314
|
transform: translateY(-4px);
|
|
313
|
-
border-color:
|
|
315
|
+
border-color: rgb(var(--ink-rgb, 255 255 255) / 0.2);
|
|
314
316
|
}
|
|
315
317
|
|
|
316
318
|
.test-card--featured {
|
|
@@ -352,7 +354,7 @@ const {
|
|
|
352
354
|
align-items: center;
|
|
353
355
|
gap: 0.85rem;
|
|
354
356
|
padding-top: 1rem;
|
|
355
|
-
border-top: 1px solid
|
|
357
|
+
border-top: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06);
|
|
356
358
|
}
|
|
357
359
|
|
|
358
360
|
.author-avatar {
|
|
@@ -364,7 +366,7 @@ const {
|
|
|
364
366
|
font-weight: 800;
|
|
365
367
|
font-size: 0.85rem;
|
|
366
368
|
color: #fff;
|
|
367
|
-
border: 2px solid
|
|
369
|
+
border: 2px solid rgb(var(--ink-rgb, 255 255 255) / 0.15);
|
|
368
370
|
}
|
|
369
371
|
|
|
370
372
|
.author-avatar--1 { background: linear-gradient(135deg, #6366f1, #a855f7); }
|
|
@@ -390,7 +392,7 @@ const {
|
|
|
390
392
|
color: #64748b;
|
|
391
393
|
}
|
|
392
394
|
|
|
393
|
-
@
|
|
395
|
+
@container (max-width: 960px) {
|
|
394
396
|
.trust-bar {
|
|
395
397
|
flex-direction: column;
|
|
396
398
|
gap: 1rem;
|
|
@@ -8,6 +8,7 @@ interface Props {
|
|
|
8
8
|
const { title = "Typography", subtitle = "Headings and text patterns." } = Astro.props;
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
<div class="cq-typography-showcase-cq">
|
|
11
12
|
<section class="typography-showcase">
|
|
12
13
|
<div class="container">
|
|
13
14
|
<div class="showcase-header">
|
|
@@ -54,8 +55,9 @@ const { title = "Typography", subtitle = "Headings and text patterns." } = Astro
|
|
|
54
55
|
</div>
|
|
55
56
|
</div>
|
|
56
57
|
</section>
|
|
57
|
-
|
|
58
|
+
</div>
|
|
58
59
|
<style>
|
|
60
|
+
.cq-typography-showcase-cq { container-type: inline-size; }
|
|
59
61
|
.typography-showcase {
|
|
60
62
|
padding: var(--sp-16) 0;
|
|
61
63
|
position: relative;
|
|
@@ -72,8 +74,8 @@ const { title = "Typography", subtitle = "Headings and text patterns." } = Astro
|
|
|
72
74
|
text-transform: uppercase;
|
|
73
75
|
letter-spacing: 0.1em;
|
|
74
76
|
color: var(--c-primary-light);
|
|
75
|
-
background:
|
|
76
|
-
border: 1px solid
|
|
77
|
+
background: color-mix(in srgb, var(--c-primary, #b8860b) 10%, transparent);
|
|
78
|
+
border: 1px solid color-mix(in srgb, var(--c-primary, #b8860b) 25%, transparent);
|
|
77
79
|
border-radius: var(--r-full);
|
|
78
80
|
margin-bottom: var(--sp-4);
|
|
79
81
|
}
|
|
@@ -95,7 +97,7 @@ const { title = "Typography", subtitle = "Headings and text patterns." } = Astro
|
|
|
95
97
|
padding: var(--sp-12);
|
|
96
98
|
background: rgba(10, 10, 10, 0.6);
|
|
97
99
|
backdrop-filter: blur(20px);
|
|
98
|
-
border: 1px solid
|
|
100
|
+
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
|
|
99
101
|
border-radius: var(--r-xl);
|
|
100
102
|
margin-bottom: var(--sp-6);
|
|
101
103
|
box-shadow: 0 20px 60px rgba(0,0,0,0.4);
|
|
@@ -117,9 +119,9 @@ const { title = "Typography", subtitle = "Headings and text patterns." } = Astro
|
|
|
117
119
|
/* Typography Mockups */
|
|
118
120
|
.typo-mockup {
|
|
119
121
|
padding: var(--sp-6);
|
|
120
|
-
background:
|
|
122
|
+
background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
|
|
121
123
|
border-radius: var(--r-md);
|
|
122
|
-
border: 1px solid
|
|
124
|
+
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.05);
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
/* Gradient Heading */
|
|
@@ -221,7 +223,7 @@ const { title = "Typography", subtitle = "Headings and text patterns." } = Astro
|
|
|
221
223
|
.usage-code {
|
|
222
224
|
text-align: center;
|
|
223
225
|
padding: var(--sp-4);
|
|
224
|
-
background:
|
|
226
|
+
background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
|
|
225
227
|
border-radius: var(--r-md);
|
|
226
228
|
}
|
|
227
229
|
.usage-code code {
|
|
@@ -230,7 +232,7 @@ const { title = "Typography", subtitle = "Headings and text patterns." } = Astro
|
|
|
230
232
|
color: var(--c-primary-light);
|
|
231
233
|
}
|
|
232
234
|
|
|
233
|
-
@
|
|
235
|
+
@container (max-width: 640px) {
|
|
234
236
|
.typo-stack { gap: var(--sp-5); }
|
|
235
237
|
.typo-mockup { padding: var(--sp-4); }
|
|
236
238
|
.preview-stage { padding: var(--sp-8) var(--sp-4); }
|
|
@@ -55,3 +55,13 @@ export { default as LogoWallGrid } from './LogoWallGrid.astro';
|
|
|
55
55
|
export { default as BlogGridSection } from './BlogGridSection.astro';
|
|
56
56
|
export { default as ChangelogSection } from './ChangelogSection.astro';
|
|
57
57
|
export { default as FooterMegaSection } from './FooterMegaSection.astro';
|
|
58
|
+
export { default as ShopHeaderEditorial } from './ShopHeaderEditorial.astro';
|
|
59
|
+
export { default as ShopHeroEditorial } from './ShopHeroEditorial.astro';
|
|
60
|
+
export { default as ShopCollectionMosaic } from './ShopCollectionMosaic.astro';
|
|
61
|
+
export { default as ShopProductRail } from './ShopProductRail.astro';
|
|
62
|
+
export { default as ShopLookbook } from './ShopLookbook.astro';
|
|
63
|
+
export { default as ShopValuesMarquee } from './ShopValuesMarquee.astro';
|
|
64
|
+
export { default as ShopReviewsEditorial } from './ShopReviewsEditorial.astro';
|
|
65
|
+
export { default as ShopNewsletterEditorial } from './ShopNewsletterEditorial.astro';
|
|
66
|
+
export { default as ShopFooterWordmark } from './ShopFooterWordmark.astro';
|
|
67
|
+
export { default as ShopCategoryHero } from './ShopCategoryHero.astro';
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* StoreCategoryPage — E-commerce template catalogue: breadcrumb, category chips, toolbar
|
|
4
|
+
* with live count + sort, FilterSidebar and ProductGrid (instant client-side filtering).
|
|
5
|
+
*
|
|
6
|
+
* Usage (src/pages/shop.astro):
|
|
7
|
+
* import { StoreCategoryPage } from 'astro-component-kit/templates/ecommerce';
|
|
8
|
+
* <StoreCategoryPage />
|
|
9
|
+
* Category links use `?category=<id>`; pass `category` to build one static page per category.
|
|
10
|
+
*
|
|
11
|
+
* @param {StoreConfig} store - Catalogue and settings. Default: demo store.
|
|
12
|
+
* @param {StoreRoutes} routes - Page URLs.
|
|
13
|
+
* @param {string} category - Pre-selected category id (optional).
|
|
14
|
+
* @param {boolean} seedCart - Pre-fill the cart with demo items. Default false.
|
|
15
|
+
* @param {string} theme - Initial theme (dark|light|auto). Default 'dark'.
|
|
16
|
+
* @param {boolean} noindex - Add robots noindex. Default false.
|
|
17
|
+
*/
|
|
18
|
+
import StoreLayout from './StoreLayout.astro';
|
|
19
|
+
import ProductToolbar from '../../ecommerce/ProductToolbar.astro';
|
|
20
|
+
import FilterSidebar from '../../ecommerce/FilterSidebar.astro';
|
|
21
|
+
import ProductGrid from '../../ecommerce/ProductGrid.astro';
|
|
22
|
+
import TrustBadges from '../../ecommerce/TrustBadges.astro';
|
|
23
|
+
import { demoStore, defaultRoutes, categoryHref, categoryNames, type StoreConfig, type StoreRoutes } from './data';
|
|
24
|
+
|
|
25
|
+
interface Props {
|
|
26
|
+
store?: StoreConfig;
|
|
27
|
+
routes?: StoreRoutes;
|
|
28
|
+
category?: string;
|
|
29
|
+
seedCart?: boolean;
|
|
30
|
+
noindex?: boolean;
|
|
31
|
+
theme?: 'dark' | 'light' | 'auto';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { store = demoStore, routes = defaultRoutes, category, seedCart = false, noindex = false, theme = 'dark' } = Astro.props;
|
|
35
|
+
|
|
36
|
+
const active = store.categories.find((c) => c.id === category);
|
|
37
|
+
const names = categoryNames(store);
|
|
38
|
+
const maxPrice = Math.ceil(Math.max(...store.products.map((p) => p.price)) / 50) * 50;
|
|
39
|
+
const colors = Array.from(new Map(store.products.flatMap((p) => p.colors ?? []).map((c) => [c.name, c])).values());
|
|
40
|
+
const filterCats = store.categories.map((c) => ({ id: c.id, name: c.name, count: store.products.filter((p) => p.category === c.id).length }));
|
|
41
|
+
const title = active ? active.name : 'All products';
|
|
42
|
+
const description = active?.description ?? 'Everything we make, in one place. Filter by category, price, colour and rating.';
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
<StoreLayout theme={theme} title={title} description={description} store={store} routes={routes} currentHref={routes.shop} seedCart={seedCart} noindex={noindex}>
|
|
46
|
+
<div class="store-container shop">
|
|
47
|
+
<nav class="crumbs" aria-label="Breadcrumb">
|
|
48
|
+
<ol>
|
|
49
|
+
<li><a href={routes.home}>Home</a></li>
|
|
50
|
+
<li><a href={routes.shop} aria-current={active ? undefined : 'page'}>Shop</a></li>
|
|
51
|
+
{active && <li><span aria-current="page">{active.name}</span></li>}
|
|
52
|
+
</ol>
|
|
53
|
+
</nav>
|
|
54
|
+
|
|
55
|
+
<ProductToolbar title={title} description={description} total={store.products.length} target="shop-grid" filtersId="shop-filters" />
|
|
56
|
+
|
|
57
|
+
<ul class="chips" aria-label="Categories">
|
|
58
|
+
<li><a class="chip" href={routes.shop} aria-current={!active ? 'page' : undefined}>All</a></li>
|
|
59
|
+
{store.categories.map((c) => (
|
|
60
|
+
<li><a class="chip" href={categoryHref(routes, c.id)} aria-current={active?.id === c.id ? 'page' : undefined} data-chip={c.id}>{c.name}</a></li>
|
|
61
|
+
))}
|
|
62
|
+
</ul>
|
|
63
|
+
|
|
64
|
+
<div class="shop__layout">
|
|
65
|
+
<div class="shop__filters">
|
|
66
|
+
<FilterSidebar
|
|
67
|
+
target="shop-grid"
|
|
68
|
+
id="shop-filters"
|
|
69
|
+
categories={filterCats}
|
|
70
|
+
selected={active ? [active.id] : []}
|
|
71
|
+
maxPrice={maxPrice}
|
|
72
|
+
colors={colors}
|
|
73
|
+
currency={store.currency}
|
|
74
|
+
locale={store.locale}
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
<ProductGrid
|
|
78
|
+
id="shop-grid"
|
|
79
|
+
products={store.products}
|
|
80
|
+
productBase={routes.product}
|
|
81
|
+
categoryNames={names}
|
|
82
|
+
columns={3}
|
|
83
|
+
currency={store.currency}
|
|
84
|
+
locale={store.locale}
|
|
85
|
+
cartKey={store.cartKey}
|
|
86
|
+
openCart={false}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<div class="shop__trust">
|
|
91
|
+
<TrustBadges variant="divided" size="sm" />
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</StoreLayout>
|
|
95
|
+
|
|
96
|
+
<script>
|
|
97
|
+
// Category chips filter in place (no reload) and keep FilterSidebar in sync.
|
|
98
|
+
document.querySelectorAll<HTMLAnchorElement>('.chips a').forEach((chip) => {
|
|
99
|
+
chip.addEventListener('click', (e) => {
|
|
100
|
+
const form = document.getElementById('shop-filters') as HTMLFormElement | null;
|
|
101
|
+
if (!form) return;
|
|
102
|
+
e.preventDefault();
|
|
103
|
+
const id = chip.dataset.chip;
|
|
104
|
+
form.querySelectorAll<HTMLInputElement>('input[name="category"]').forEach((i) => { i.checked = id ? i.value === id : false; });
|
|
105
|
+
form.dispatchEvent(new Event('change', { bubbles: true }));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
const syncChips = () => {
|
|
109
|
+
const form = document.getElementById('shop-filters') as HTMLFormElement | null;
|
|
110
|
+
if (!form) return;
|
|
111
|
+
const checked = Array.from(form.querySelectorAll<HTMLInputElement>('input[name="category"]:checked')).map((i) => i.value);
|
|
112
|
+
document.querySelectorAll<HTMLAnchorElement>('.chips a').forEach((chip) => {
|
|
113
|
+
const id = chip.dataset.chip;
|
|
114
|
+
const on = id ? checked.length === 1 && checked[0] === id : checked.length === 0;
|
|
115
|
+
if (on) chip.setAttribute('aria-current', 'page');
|
|
116
|
+
else chip.removeAttribute('aria-current');
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
document.getElementById('shop-filters')?.addEventListener('change', syncChips);
|
|
120
|
+
document.getElementById('shop-filters')?.addEventListener('reset', () => window.setTimeout(syncChips, 0));
|
|
121
|
+
syncChips();
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
<style>
|
|
125
|
+
.shop { padding-block: var(--sp-6) clamp(3rem, 7vw, 5rem); }
|
|
126
|
+
|
|
127
|
+
.crumbs ol { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin: 0 0 var(--sp-6); padding: 0; list-style: none; font-size: 0.85rem; }
|
|
128
|
+
.crumbs li { display: flex; align-items: center; gap: var(--sp-2); color: var(--c-text-2); }
|
|
129
|
+
.crumbs li + li::before { content: '/'; opacity: 0.5; }
|
|
130
|
+
.crumbs a { color: var(--c-text-2); }
|
|
131
|
+
.crumbs a:hover { color: var(--c-text-1); }
|
|
132
|
+
.crumbs [aria-current='page'] { color: var(--c-text-1); font-weight: 600; }
|
|
133
|
+
|
|
134
|
+
.chips { display: flex; gap: var(--sp-2); margin: 0 0 var(--sp-6); padding: 0 0 4px; list-style: none; overflow-x: auto; scrollbar-width: none; }
|
|
135
|
+
.chip {
|
|
136
|
+
display: inline-flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
min-height: 40px;
|
|
139
|
+
padding: 0 var(--sp-4);
|
|
140
|
+
border-radius: var(--r-full);
|
|
141
|
+
border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.1);
|
|
142
|
+
color: var(--c-text-2);
|
|
143
|
+
font-size: 0.88rem;
|
|
144
|
+
font-weight: 600;
|
|
145
|
+
white-space: nowrap;
|
|
146
|
+
transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
|
|
147
|
+
}
|
|
148
|
+
.chip:hover { color: var(--c-text-1); border-color: rgb(var(--ink-rgb, 255 255 255) / 0.25); }
|
|
149
|
+
.chip[aria-current='page'] { background: var(--c-text-1); color: var(--c-bg); border-color: var(--c-text-1); }
|
|
150
|
+
.chip:focus-visible { outline: 2px solid var(--c-primary-light); outline-offset: 2px; }
|
|
151
|
+
|
|
152
|
+
.shop__layout { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: var(--sp-8); align-items: start; }
|
|
153
|
+
.shop__filters { position: sticky; top: 88px; }
|
|
154
|
+
.shop__trust { margin-top: clamp(3rem, 6vw, 4.5rem); }
|
|
155
|
+
|
|
156
|
+
@media (max-width: 900px) {
|
|
157
|
+
.shop__layout { grid-template-columns: 1fr; gap: var(--sp-4); }
|
|
158
|
+
.shop__filters { position: static; }
|
|
159
|
+
}
|
|
160
|
+
</style>
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* StoreCheckoutPage — E-commerce template checkout in focus mode: StepBreadcrumbBar,
|
|
4
|
+
* CheckoutForm (contact, delivery, shipping, payment) and a live OrderSummary.
|
|
5
|
+
*
|
|
6
|
+
* Usage (src/pages/checkout.astro):
|
|
7
|
+
* import { StoreCheckoutPage } from 'astro-component-kit/templates/ecommerce';
|
|
8
|
+
* <StoreCheckoutPage />
|
|
9
|
+
*
|
|
10
|
+
* @param {StoreConfig} store - Catalogue and settings. Default: demo store.
|
|
11
|
+
* @param {StoreRoutes} routes - Page URLs.
|
|
12
|
+
* @param {boolean} seedCart - Pre-fill the cart with demo items. Default false.
|
|
13
|
+
* @param {string} theme - Initial theme (dark|light|auto). Default 'dark'.
|
|
14
|
+
* @param {boolean} noindex - Add robots noindex. Default true (checkout pages should not be indexed).
|
|
15
|
+
*/
|
|
16
|
+
import StoreLayout from './StoreLayout.astro';
|
|
17
|
+
import StepBreadcrumbBar from '../../navigation/StepBreadcrumbBar.astro';
|
|
18
|
+
import CheckoutForm from '../../ecommerce/CheckoutForm.astro';
|
|
19
|
+
import OrderSummary from '../../ecommerce/OrderSummary.astro';
|
|
20
|
+
import { demoStore, defaultRoutes, type StoreConfig, type StoreRoutes } from './data';
|
|
21
|
+
|
|
22
|
+
interface Props {
|
|
23
|
+
store?: StoreConfig;
|
|
24
|
+
routes?: StoreRoutes;
|
|
25
|
+
seedCart?: boolean;
|
|
26
|
+
noindex?: boolean;
|
|
27
|
+
theme?: 'dark' | 'light' | 'auto';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const { store = demoStore, routes = defaultRoutes, seedCart = false, noindex = true, theme = 'dark' } = Astro.props;
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
<StoreLayout theme={theme} title="Checkout" description={`Secure checkout — ${store.name}`} store={store} routes={routes} seedCart={seedCart} noindex={noindex} minimal>
|
|
34
|
+
<div class="store-container co">
|
|
35
|
+
<div class="co__steps" data-co-steps>
|
|
36
|
+
<StepBreadcrumbBar
|
|
37
|
+
steps={[
|
|
38
|
+
{ step: 1, label: 'Cart', status: 'complete', href: routes.shop },
|
|
39
|
+
{ step: 2, label: 'Details & payment', status: 'active', href: '#checkout' },
|
|
40
|
+
{ step: 3, label: 'Confirmation', status: 'upcoming', href: '#checkout' },
|
|
41
|
+
]}
|
|
42
|
+
/>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="co__head">
|
|
46
|
+
<h1>Checkout</h1>
|
|
47
|
+
<a href={routes.shop}><span aria-hidden="true">←</span> Continue shopping</a>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="co__layout">
|
|
51
|
+
<CheckoutForm
|
|
52
|
+
id="checkout"
|
|
53
|
+
shippingRates={store.shippingRates}
|
|
54
|
+
freeShippingThreshold={store.freeShippingThreshold}
|
|
55
|
+
cartKey={store.cartKey}
|
|
56
|
+
currency={store.currency}
|
|
57
|
+
locale={store.locale}
|
|
58
|
+
continueHref={routes.home}
|
|
59
|
+
/>
|
|
60
|
+
<OrderSummary
|
|
61
|
+
cartKey={store.cartKey}
|
|
62
|
+
shippingRates={store.shippingRates}
|
|
63
|
+
freeShippingThreshold={store.freeShippingThreshold}
|
|
64
|
+
taxRate={store.taxRate}
|
|
65
|
+
promoCodes={store.promoCodes}
|
|
66
|
+
currency={store.currency}
|
|
67
|
+
locale={store.locale}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</StoreLayout>
|
|
72
|
+
|
|
73
|
+
<script>
|
|
74
|
+
// Move the step bar to "Confirmation" once the order is placed.
|
|
75
|
+
document.addEventListener('ack:order-placed', () => {
|
|
76
|
+
const items = Array.from(document.querySelectorAll<HTMLElement>('[data-co-steps] .step-nav__item'));
|
|
77
|
+
items.forEach((item, i) => {
|
|
78
|
+
item.classList.remove('step-nav__item--active', 'step-nav__item--upcoming');
|
|
79
|
+
item.classList.add(i === items.length - 1 ? 'step-nav__item--active' : 'step-nav__item--complete');
|
|
80
|
+
const link = item.querySelector('a');
|
|
81
|
+
if (i === items.length - 1) link?.setAttribute('aria-current', 'step');
|
|
82
|
+
else link?.removeAttribute('aria-current');
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<style>
|
|
88
|
+
.co { padding-block: var(--sp-8) clamp(3rem, 7vw, 5rem); }
|
|
89
|
+
.co__steps { max-width: 720px; margin: 0 auto var(--sp-8); }
|
|
90
|
+
.co__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-6); }
|
|
91
|
+
.co__head h1 { margin: 0; font-size: clamp(1.8rem, 4vw, 2.6rem); font-weight: 900; letter-spacing: -0.035em; color: var(--c-text-1); }
|
|
92
|
+
.co__head a { display: inline-flex; align-items: center; gap: 0.35rem; min-height: 44px; font-weight: 600; font-size: 0.9rem; }
|
|
93
|
+
.co__layout { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(320px, 1fr); gap: clamp(1.5rem, 4vw, 3rem); align-items: start; }
|
|
94
|
+
@media (max-width: 960px) {
|
|
95
|
+
.co__layout { grid-template-columns: 1fr; }
|
|
96
|
+
.co__layout > :global(.o-summary) { order: -1; }
|
|
97
|
+
}
|
|
98
|
+
</style>
|