@cimplify/cli 0.2.8 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-7PTWJV4F.mjs → add-OUMIT4YX.mjs} +10 -10
- package/dist/assets-DMK2QOPD.mjs +208 -0
- package/dist/chunk-42PFJBC6.mjs +5707 -0
- package/dist/{chunk-4SBJVRGM.mjs → chunk-C4M3DXKC.mjs} +3 -1
- package/dist/{chunk-NC3GKHDD.mjs → chunk-D7WMSGKK.mjs} +1 -1
- package/dist/{chunk-NZ4RG62Z.mjs → chunk-I3XQSSOT.mjs} +4 -1
- package/dist/chunk-I6P3I2YJ.mjs +259 -0
- package/dist/{chunk-UPEHLREA.mjs → chunk-IQJ45AK3.mjs} +3 -3
- package/dist/{chunk-JJYWETGA.mjs → chunk-LS2VTSMQ.mjs} +8 -2
- package/dist/{chunk-JOUXICGV.mjs → chunk-MOZQODQS.mjs} +1 -1
- package/dist/{chunk-KPGRCXQY.mjs → chunk-QGBXGDA5.mjs} +5 -5
- package/dist/chunk-RRY3NEZZ.mjs +79 -0
- package/dist/{chunk-L6474RPL.mjs → chunk-RZQTHTXX.mjs} +1 -1
- package/dist/{chunk-4YSOZ6LY.mjs → chunk-YI7UMMM7.mjs} +1 -1
- package/dist/{deploy-6KVOROT3.mjs → deploy-UKOOPJAE.mjs} +8 -82
- package/dist/{dev-AQP6TMYK.mjs → dev-FD4PM3UD.mjs} +5 -5
- package/dist/dispatcher.mjs +34 -22
- package/dist/doctor-AY7VDIJZ.mjs +314 -0
- package/dist/{domains-2ZQ7AG27.mjs → domains-JQMV6GAP.mjs} +5 -5
- package/dist/{env-FDBPGU3W.mjs → env-EVMYQUIK.mjs} +6 -6
- package/dist/explain-QZVAK5I3.mjs +223 -0
- package/dist/introspect-MNTC26UY.mjs +8 -0
- package/dist/{link-P4K2HRXY.mjs → link-X3E4UZBF.mjs} +4 -4
- package/dist/{list-44MLIFI2.mjs → list-TEQ73IR7.mjs} +3 -3
- package/dist/{login-RSKGT6GU.mjs → login-7O7ZXKU3.mjs} +9 -15
- package/dist/{logout-ZFZLSJ32.mjs → logout-DJDINVDF.mjs} +2 -2
- package/dist/{logs-E2AGTDCF.mjs → logs-KUKGEXR2.mjs} +4 -4
- package/dist/{projects-5CJOZ3MT.mjs → projects-364HGWHO.mjs} +13 -11
- package/dist/repo-26N2CHF6.mjs +8 -0
- package/dist/{rollback-36O4NOEL.mjs → rollback-5YALPQXL.mjs} +5 -5
- package/dist/{status-6AT4HF63.mjs → status-W4HW3CX3.mjs} +4 -4
- package/dist/{unlink-5ABCT7B6.mjs → unlink-HIIW57OO.mjs} +2 -2
- package/dist/{update-6KEG7EWK.mjs → update-2DCENLHM.mjs} +7 -7
- package/dist/{whoami-DIJZYZIN.mjs → whoami-LACWBSNL.mjs} +3 -3
- package/package.json +3 -3
- package/templates/storefront-auto/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-auto/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-auto/.env.example +22 -0
- package/templates/storefront-auto/AGENTS.md +95 -0
- package/templates/storefront-auto/CLAUDE.md +22 -0
- package/templates/storefront-auto/README.md +48 -0
- package/templates/storefront-auto/__tests__/brand.test.ts +4 -0
- package/templates/storefront-auto/__tests__/cart-flow.test.ts +4 -0
- package/templates/storefront-auto/__tests__/contract.test.ts +4 -0
- package/templates/storefront-auto/app/.well-known/ucp/route.ts +65 -0
- package/templates/storefront-auto/app/about/page.tsx +41 -0
- package/templates/storefront-auto/app/accessibility/page.tsx +11 -0
- package/templates/storefront-auto/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-auto/app/account/orders/page.tsx +21 -0
- package/templates/storefront-auto/app/account/page.tsx +22 -0
- package/templates/storefront-auto/app/account/settings/page.tsx +21 -0
- package/templates/storefront-auto/app/cart/page.tsx +9 -0
- package/templates/storefront-auto/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-auto/app/categories/[slug]/page.tsx +130 -0
- package/templates/storefront-auto/app/checkout/page.tsx +17 -0
- package/templates/storefront-auto/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-auto/app/collections/[slug]/page.tsx +130 -0
- package/templates/storefront-auto/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-auto/app/contact/page.tsx +54 -0
- package/templates/storefront-auto/app/error.tsx +61 -0
- package/templates/storefront-auto/app/faq/page.tsx +46 -0
- package/templates/storefront-auto/app/globals.css +47 -0
- package/templates/storefront-auto/app/layout.tsx +77 -0
- package/templates/storefront-auto/app/llms.txt/route.ts +94 -0
- package/templates/storefront-auto/app/login/page.tsx +17 -0
- package/templates/storefront-auto/app/not-found.tsx +39 -0
- package/templates/storefront-auto/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-auto/app/orders/[id]/page.tsx +24 -0
- package/templates/storefront-auto/app/page.tsx +94 -0
- package/templates/storefront-auto/app/privacy/page.tsx +44 -0
- package/templates/storefront-auto/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-auto/app/products/[slug]/product-detail.tsx +70 -0
- package/templates/storefront-auto/app/returns/page.tsx +11 -0
- package/templates/storefront-auto/app/robots.ts +18 -0
- package/templates/storefront-auto/app/search/page.tsx +38 -0
- package/templates/storefront-auto/app/search/search-client.tsx +7 -0
- package/templates/storefront-auto/app/shipping/page.tsx +16 -0
- package/templates/storefront-auto/app/shop/page.tsx +63 -0
- package/templates/storefront-auto/app/shop/shop-client.tsx +32 -0
- package/templates/storefront-auto/app/signup/page.tsx +17 -0
- package/templates/storefront-auto/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-auto/app/sitemap.ts +59 -0
- package/templates/storefront-auto/app/terms/page.tsx +44 -0
- package/templates/storefront-auto/app/track-order/page.tsx +24 -0
- package/templates/storefront-auto/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-auto/components/account-iframe.tsx +13 -0
- package/templates/storefront-auto/components/auto-hero.tsx +85 -0
- package/templates/storefront-auto/components/brand-marquee.tsx +27 -0
- package/templates/storefront-auto/components/cart-drawer.tsx +14 -0
- package/templates/storefront-auto/components/cart-pill.tsx +36 -0
- package/templates/storefront-auto/components/category-grid.tsx +28 -0
- package/templates/storefront-auto/components/category-tiles.tsx +104 -0
- package/templates/storefront-auto/components/collection-strip.tsx +45 -0
- package/templates/storefront-auto/components/feature-hero.tsx +84 -0
- package/templates/storefront-auto/components/fitment-finder.tsx +184 -0
- package/templates/storefront-auto/components/footer.tsx +153 -0
- package/templates/storefront-auto/components/header.tsx +45 -0
- package/templates/storefront-auto/components/hero.tsx +28 -0
- package/templates/storefront-auto/components/nav-link.tsx +20 -0
- package/templates/storefront-auto/components/newsletter.tsx +50 -0
- package/templates/storefront-auto/components/policy-page.tsx +49 -0
- package/templates/storefront-auto/components/promo-banner.tsx +41 -0
- package/templates/storefront-auto/components/providers.tsx +35 -0
- package/templates/storefront-auto/components/section-heading.tsx +37 -0
- package/templates/storefront-auto/components/service-brief.tsx +65 -0
- package/templates/storefront-auto/components/store-product-card.tsx +88 -0
- package/templates/storefront-auto/components/trade-in-cta.tsx +54 -0
- package/templates/storefront-auto/components/trust-bar.tsx +66 -0
- package/templates/storefront-auto/lib/brand.ts +744 -0
- package/templates/storefront-auto/lib/cart.ts +12 -0
- package/templates/storefront-auto/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-auto/next.config.ts +45 -0
- package/templates/storefront-auto/package.json +35 -0
- package/templates/storefront-auto/postcss.config.mjs +7 -0
- package/templates/storefront-auto/tsconfig.json +23 -0
- package/templates/storefront-auto/vitest.config.ts +9 -0
- package/templates/storefront-bakery/.env.example +2 -2
- package/templates/storefront-bakery/README.md +1 -1
- package/templates/storefront-bakery/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-bakery/next.config.ts +3 -0
- package/templates/storefront-bakery/package.json +1 -1
- package/templates/storefront-fashion/.env.example +2 -2
- package/templates/storefront-fashion/README.md +1 -1
- package/templates/storefront-fashion/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-fashion/next.config.ts +3 -0
- package/templates/storefront-fashion/package.json +1 -1
- package/templates/storefront-grocery/.env.example +2 -2
- package/templates/storefront-grocery/README.md +1 -1
- package/templates/storefront-grocery/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-grocery/next.config.ts +3 -0
- package/templates/storefront-grocery/package.json +1 -1
- package/templates/storefront-pharmacy/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-pharmacy/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-pharmacy/.env.example +22 -0
- package/templates/storefront-pharmacy/AGENTS.md +118 -0
- package/templates/storefront-pharmacy/CLAUDE.md +22 -0
- package/templates/storefront-pharmacy/README.md +87 -0
- package/templates/storefront-pharmacy/__tests__/brand.test.ts +4 -0
- package/templates/storefront-pharmacy/__tests__/cart-flow.test.ts +4 -0
- package/templates/storefront-pharmacy/__tests__/contract.test.ts +4 -0
- package/templates/storefront-pharmacy/app/.well-known/ucp/route.ts +65 -0
- package/templates/storefront-pharmacy/app/about/page.tsx +41 -0
- package/templates/storefront-pharmacy/app/accessibility/page.tsx +11 -0
- package/templates/storefront-pharmacy/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-pharmacy/app/account/orders/page.tsx +21 -0
- package/templates/storefront-pharmacy/app/account/page.tsx +22 -0
- package/templates/storefront-pharmacy/app/account/settings/page.tsx +21 -0
- package/templates/storefront-pharmacy/app/cart/page.tsx +9 -0
- package/templates/storefront-pharmacy/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-pharmacy/app/categories/[slug]/page.tsx +130 -0
- package/templates/storefront-pharmacy/app/checkout/page.tsx +17 -0
- package/templates/storefront-pharmacy/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-pharmacy/app/collections/[slug]/page.tsx +130 -0
- package/templates/storefront-pharmacy/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-pharmacy/app/contact/page.tsx +54 -0
- package/templates/storefront-pharmacy/app/error.tsx +61 -0
- package/templates/storefront-pharmacy/app/faq/page.tsx +46 -0
- package/templates/storefront-pharmacy/app/globals.css +47 -0
- package/templates/storefront-pharmacy/app/layout.tsx +77 -0
- package/templates/storefront-pharmacy/app/llms.txt/route.ts +94 -0
- package/templates/storefront-pharmacy/app/login/page.tsx +17 -0
- package/templates/storefront-pharmacy/app/not-found.tsx +39 -0
- package/templates/storefront-pharmacy/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-pharmacy/app/orders/[id]/page.tsx +24 -0
- package/templates/storefront-pharmacy/app/page.tsx +78 -0
- package/templates/storefront-pharmacy/app/privacy/page.tsx +44 -0
- package/templates/storefront-pharmacy/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-pharmacy/app/products/[slug]/product-detail.tsx +70 -0
- package/templates/storefront-pharmacy/app/returns/page.tsx +11 -0
- package/templates/storefront-pharmacy/app/robots.ts +18 -0
- package/templates/storefront-pharmacy/app/search/page.tsx +38 -0
- package/templates/storefront-pharmacy/app/search/search-client.tsx +7 -0
- package/templates/storefront-pharmacy/app/shipping/page.tsx +16 -0
- package/templates/storefront-pharmacy/app/shop/page.tsx +63 -0
- package/templates/storefront-pharmacy/app/shop/shop-client.tsx +32 -0
- package/templates/storefront-pharmacy/app/signup/page.tsx +17 -0
- package/templates/storefront-pharmacy/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-pharmacy/app/sitemap.ts +59 -0
- package/templates/storefront-pharmacy/app/terms/page.tsx +44 -0
- package/templates/storefront-pharmacy/app/track-order/page.tsx +24 -0
- package/templates/storefront-pharmacy/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-pharmacy/components/account-iframe.tsx +13 -0
- package/templates/storefront-pharmacy/components/brand-marquee.tsx +27 -0
- package/templates/storefront-pharmacy/components/cart-drawer.tsx +14 -0
- package/templates/storefront-pharmacy/components/cart-pill.tsx +36 -0
- package/templates/storefront-pharmacy/components/category-grid.tsx +28 -0
- package/templates/storefront-pharmacy/components/category-tiles.tsx +104 -0
- package/templates/storefront-pharmacy/components/collection-strip.tsx +45 -0
- package/templates/storefront-pharmacy/components/feature-hero.tsx +84 -0
- package/templates/storefront-pharmacy/components/footer.tsx +153 -0
- package/templates/storefront-pharmacy/components/header.tsx +45 -0
- package/templates/storefront-pharmacy/components/health-brief.tsx +65 -0
- package/templates/storefront-pharmacy/components/hero.tsx +28 -0
- package/templates/storefront-pharmacy/components/nav-link.tsx +20 -0
- package/templates/storefront-pharmacy/components/newsletter.tsx +50 -0
- package/templates/storefront-pharmacy/components/pharmacy-hero.tsx +95 -0
- package/templates/storefront-pharmacy/components/policy-page.tsx +49 -0
- package/templates/storefront-pharmacy/components/promo-banner.tsx +41 -0
- package/templates/storefront-pharmacy/components/providers.tsx +35 -0
- package/templates/storefront-pharmacy/components/section-heading.tsx +37 -0
- package/templates/storefront-pharmacy/components/store-product-card.tsx +88 -0
- package/templates/storefront-pharmacy/components/symptom-finder.tsx +108 -0
- package/templates/storefront-pharmacy/components/trade-in-cta.tsx +54 -0
- package/templates/storefront-pharmacy/components/trust-bar.tsx +66 -0
- package/templates/storefront-pharmacy/components/urgent-ctas.tsx +117 -0
- package/templates/storefront-pharmacy/lib/brand.ts +790 -0
- package/templates/storefront-pharmacy/lib/cart.ts +12 -0
- package/templates/storefront-pharmacy/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-pharmacy/next.config.ts +45 -0
- package/templates/storefront-pharmacy/package.json +35 -0
- package/templates/storefront-pharmacy/postcss.config.mjs +7 -0
- package/templates/storefront-pharmacy/tsconfig.json +23 -0
- package/templates/storefront-pharmacy/vitest.config.ts +9 -0
- package/templates/storefront-restaurant/.env.example +2 -2
- package/templates/storefront-restaurant/README.md +1 -1
- package/templates/storefront-restaurant/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-restaurant/next.config.ts +3 -0
- package/templates/storefront-restaurant/package.json +1 -1
- package/templates/storefront-retail/.env.example +2 -2
- package/templates/storefront-retail/README.md +1 -1
- package/templates/storefront-retail/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-retail/next.config.ts +3 -0
- package/templates/storefront-retail/package.json +1 -1
- package/templates/storefront-services/.env.example +2 -2
- package/templates/storefront-services/README.md +1 -1
- package/templates/storefront-services/lib/cimplify-loader.ts +19 -0
- package/templates/storefront-services/next.config.ts +3 -0
- package/templates/storefront-services/package.json +1 -1
- package/dist/chunk-H2HJQGFY.mjs +0 -3911
- package/dist/repo-E6SBKVDG.mjs +0 -8
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { brand } from "@/lib/brand";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Brand authority strip. Wordmark-only (avoids licensing issues with real
|
|
5
|
+
* logos), monospaced for the brand-as-typography aesthetic.
|
|
6
|
+
*/
|
|
7
|
+
export function BrandMarquee() {
|
|
8
|
+
const strip = brand.brandStrip;
|
|
9
|
+
if (!strip || strip.brands.length === 0) return null;
|
|
10
|
+
return (
|
|
11
|
+
<section className="border-y border-border bg-background py-8 sm:py-10 overflow-hidden">
|
|
12
|
+
<p className="text-center text-[11px] font-mono uppercase tracking-[0.2em] text-muted-foreground mb-6">
|
|
13
|
+
{strip.headline}
|
|
14
|
+
</p>
|
|
15
|
+
<div className="flex items-center justify-around gap-10 sm:gap-14 flex-wrap px-6">
|
|
16
|
+
{strip.brands.map((b) => (
|
|
17
|
+
<span
|
|
18
|
+
key={b}
|
|
19
|
+
className="text-[clamp(1.25rem,2vw,1.75rem)] font-semibold text-muted-foreground hover:text-foreground transition-colors -tracking-[0.025em] opacity-70 hover:opacity-100"
|
|
20
|
+
>
|
|
21
|
+
{b}
|
|
22
|
+
</span>
|
|
23
|
+
))}
|
|
24
|
+
</div>
|
|
25
|
+
</section>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRouter } from "next/navigation";
|
|
4
|
+
import { CartDrawer as SdkCartDrawer } from "@cimplify/sdk/react";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Side-drawer cart. Auto-opens when an item is added (via
|
|
8
|
+
* `<CartDrawerProvider>` in `providers.tsx`). The header's cart pill
|
|
9
|
+
* also calls `useCartDrawer().open()` to reveal it on click.
|
|
10
|
+
*/
|
|
11
|
+
export function CartDrawer() {
|
|
12
|
+
const router = useRouter();
|
|
13
|
+
return <SdkCartDrawer onCheckout={() => router.push("/checkout")} />;
|
|
14
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCartDrawer } from "@cimplify/sdk/react";
|
|
4
|
+
import { useCartCount } from "@/lib/cart";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Cart pill — dynamic island. Reads the live cart count via the SDK and
|
|
8
|
+
* opens the side cart drawer on click (instead of navigating to /cart).
|
|
9
|
+
* Wrap in `<Suspense fallback={<CartPillSkeleton/>}>` so the cached
|
|
10
|
+
* header chrome streams without blocking on the cart fetch.
|
|
11
|
+
*/
|
|
12
|
+
export function CartPill() {
|
|
13
|
+
const { count } = useCartCount();
|
|
14
|
+
const { open } = useCartDrawer();
|
|
15
|
+
return (
|
|
16
|
+
<button
|
|
17
|
+
type="button"
|
|
18
|
+
onClick={open}
|
|
19
|
+
aria-label={`Open cart, ${count} ${count === 1 ? "item" : "items"}`}
|
|
20
|
+
className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full bg-foreground text-background text-xs font-semibold tracking-wide transition-transform hover:scale-105 cursor-pointer"
|
|
21
|
+
>
|
|
22
|
+
Cart · {count}
|
|
23
|
+
</button>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function CartPillSkeleton() {
|
|
28
|
+
return (
|
|
29
|
+
<span
|
|
30
|
+
aria-hidden
|
|
31
|
+
className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full bg-foreground/80 text-background text-xs font-semibold tracking-wide"
|
|
32
|
+
>
|
|
33
|
+
Cart · …
|
|
34
|
+
</span>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRouter } from "next/navigation";
|
|
4
|
+
import { CategoryGrid as SdkCategoryGrid } from "@cimplify/sdk/react";
|
|
5
|
+
import type { Category } from "@cimplify/sdk";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Homepage category tiles — defers to the SDK's <CategoryGrid/> for layout
|
|
9
|
+
* and accessibility, and routes selections to /categories/:slug.
|
|
10
|
+
*/
|
|
11
|
+
export function CategoryGrid({ categories }: { categories?: Category[] }) {
|
|
12
|
+
const router = useRouter();
|
|
13
|
+
return (
|
|
14
|
+
<section className="max-w-7xl mx-auto px-8 pt-14">
|
|
15
|
+
<h2 className="font-serif text-[28px] font-semibold m-0 mb-5">Browse the menu</h2>
|
|
16
|
+
<SdkCategoryGrid
|
|
17
|
+
categories={categories}
|
|
18
|
+
onSelect={(c) => router.push(`/categories/${c.slug}`)}
|
|
19
|
+
classNames={{
|
|
20
|
+
item: "flex flex-col gap-1 p-6 bg-card border border-border rounded-2xl cursor-pointer text-left transition-all hover:border-primary hover:-translate-y-0.5",
|
|
21
|
+
name: "font-serif text-lg font-semibold text-foreground",
|
|
22
|
+
description: "text-xs text-muted-foreground",
|
|
23
|
+
count: "text-xs text-muted-foreground mt-1",
|
|
24
|
+
}}
|
|
25
|
+
/>
|
|
26
|
+
</section>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import Image from "next/image";
|
|
3
|
+
import type { Category } from "@cimplify/sdk";
|
|
4
|
+
|
|
5
|
+
interface CategoryTilesProps {
|
|
6
|
+
categories: Category[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const ICONS: Record<string, React.ReactNode> = {
|
|
10
|
+
phones: (
|
|
11
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-7 h-7" aria-hidden>
|
|
12
|
+
<rect x="6" y="2" width="12" height="20" rx="2.5" />
|
|
13
|
+
<line x1="12" y1="18" x2="12" y2="18" strokeWidth="2.5" strokeLinecap="round" />
|
|
14
|
+
</svg>
|
|
15
|
+
),
|
|
16
|
+
laptops: (
|
|
17
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-7 h-7" aria-hidden>
|
|
18
|
+
<rect x="3" y="4" width="18" height="12" rx="1.5" />
|
|
19
|
+
<line x1="2" y1="20" x2="22" y2="20" strokeLinecap="round" />
|
|
20
|
+
</svg>
|
|
21
|
+
),
|
|
22
|
+
audio: (
|
|
23
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-7 h-7" aria-hidden>
|
|
24
|
+
<path d="M3 14v-2a9 9 0 0 1 18 0v2" />
|
|
25
|
+
<rect x="2" y="14" width="5" height="6" rx="1.5" />
|
|
26
|
+
<rect x="17" y="14" width="5" height="6" rx="1.5" />
|
|
27
|
+
</svg>
|
|
28
|
+
),
|
|
29
|
+
accessories: (
|
|
30
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-7 h-7" aria-hidden>
|
|
31
|
+
<rect x="2" y="6" width="14" height="10" rx="2" />
|
|
32
|
+
<path d="M16 12h4l2 2v0l-2 2h-4" />
|
|
33
|
+
</svg>
|
|
34
|
+
),
|
|
35
|
+
gaming: (
|
|
36
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-7 h-7" aria-hidden>
|
|
37
|
+
<path d="M5 7h14a3 3 0 0 1 3 3v4a3 3 0 0 1-3 3h-1l-2-3H8l-2 3H5a3 3 0 0 1-3-3v-4a3 3 0 0 1 3-3z" />
|
|
38
|
+
<line x1="9" y1="11" x2="9" y2="13" strokeLinecap="round" />
|
|
39
|
+
<line x1="8" y1="12" x2="10" y2="12" strokeLinecap="round" />
|
|
40
|
+
<circle cx="15" cy="11" r="0.75" fill="currentColor" />
|
|
41
|
+
<circle cx="17" cy="13" r="0.75" fill="currentColor" />
|
|
42
|
+
</svg>
|
|
43
|
+
),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function CategoryTiles({ categories }: CategoryTilesProps) {
|
|
47
|
+
if (categories.length === 0) return null;
|
|
48
|
+
return (
|
|
49
|
+
<section className="max-w-7xl mx-auto px-6 sm:px-8 py-14 sm:py-20">
|
|
50
|
+
<div className="flex items-end justify-between gap-6 mb-8">
|
|
51
|
+
<div>
|
|
52
|
+
<p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-2">
|
|
53
|
+
Shop the catalogue
|
|
54
|
+
</p>
|
|
55
|
+
<h2 className="text-[clamp(1.75rem,3vw,2.25rem)] font-bold -tracking-[0.025em]">
|
|
56
|
+
Pick your category.
|
|
57
|
+
</h2>
|
|
58
|
+
</div>
|
|
59
|
+
<Link
|
|
60
|
+
href="/shop"
|
|
61
|
+
className="text-sm font-semibold text-primary hover:underline whitespace-nowrap hidden sm:inline-flex items-center gap-1"
|
|
62
|
+
>
|
|
63
|
+
See everything
|
|
64
|
+
<svg viewBox="0 0 12 12" className="w-3 h-3" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden>
|
|
65
|
+
<path d="M3 6h7m0 0L7 3m3 3L7 9" strokeLinecap="round" strokeLinejoin="round" />
|
|
66
|
+
</svg>
|
|
67
|
+
</Link>
|
|
68
|
+
</div>
|
|
69
|
+
<div className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 sm:gap-4">
|
|
70
|
+
{categories.map((c, i) => (
|
|
71
|
+
<Link
|
|
72
|
+
key={c.id}
|
|
73
|
+
href={`/categories/${c.slug}`}
|
|
74
|
+
className="group relative overflow-hidden rounded-2xl bg-card border border-border p-5 hover:border-primary hover:-translate-y-0.5 transition-all"
|
|
75
|
+
>
|
|
76
|
+
<div className="flex items-start justify-between mb-12">
|
|
77
|
+
<div className="grid place-items-center w-10 h-10 rounded-lg bg-primary/10 text-primary">
|
|
78
|
+
{ICONS[c.slug] ?? (
|
|
79
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" className="w-7 h-7" aria-hidden>
|
|
80
|
+
<rect x="3" y="3" width="18" height="18" rx="2" />
|
|
81
|
+
</svg>
|
|
82
|
+
)}
|
|
83
|
+
</div>
|
|
84
|
+
<span className="text-[10px] font-mono text-muted-foreground tabular-nums">
|
|
85
|
+
{String(i + 1).padStart(2, "0")}
|
|
86
|
+
</span>
|
|
87
|
+
</div>
|
|
88
|
+
<p className="text-base font-semibold mb-1 -tracking-[0.015em]">{c.name}</p>
|
|
89
|
+
{c.product_count != null && (
|
|
90
|
+
<p className="text-xs text-muted-foreground">
|
|
91
|
+
{c.product_count} {c.product_count === 1 ? "product" : "products"}
|
|
92
|
+
</p>
|
|
93
|
+
)}
|
|
94
|
+
<span className="absolute right-4 bottom-4 grid place-items-center w-7 h-7 rounded-full bg-foreground text-background opacity-0 group-hover:opacity-100 transition-opacity">
|
|
95
|
+
<svg viewBox="0 0 12 12" className="w-3 h-3" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden>
|
|
96
|
+
<path d="M3 6h7m0 0L7 3m3 3L7 9" strokeLinecap="round" strokeLinejoin="round" />
|
|
97
|
+
</svg>
|
|
98
|
+
</span>
|
|
99
|
+
</Link>
|
|
100
|
+
))}
|
|
101
|
+
</div>
|
|
102
|
+
</section>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import type { Collection, Product } from "@cimplify/sdk";
|
|
3
|
+
import { StoreProductCard } from "./store-product-card";
|
|
4
|
+
|
|
5
|
+
interface CollectionStripProps {
|
|
6
|
+
collection: Collection;
|
|
7
|
+
products: Product[];
|
|
8
|
+
collectionHref?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Horizontal strip of products under a collection title. Cards come from the
|
|
13
|
+
* SDK so every variant (Food, Bundle, Composite, Service, …) renders
|
|
14
|
+
* correctly; clicks open the shared URL-driven product modal.
|
|
15
|
+
*/
|
|
16
|
+
export function CollectionStrip({ collection, products, collectionHref }: CollectionStripProps) {
|
|
17
|
+
if (products.length === 0) return null;
|
|
18
|
+
return (
|
|
19
|
+
<section className="max-w-7xl mx-auto px-8 pt-12">
|
|
20
|
+
<header className="grid grid-cols-[1fr_auto] items-end gap-4 mb-5">
|
|
21
|
+
<h2 className="font-serif text-[28px] font-semibold m-0">{collection.name}</h2>
|
|
22
|
+
{collectionHref && (
|
|
23
|
+
<Link
|
|
24
|
+
href={collectionHref}
|
|
25
|
+
className="text-[13px] font-semibold text-primary hover:underline"
|
|
26
|
+
>
|
|
27
|
+
See all →
|
|
28
|
+
</Link>
|
|
29
|
+
)}
|
|
30
|
+
{collection.description && (
|
|
31
|
+
<p className="col-span-full m-0 mt-1 text-sm text-muted-foreground">
|
|
32
|
+
{collection.description}
|
|
33
|
+
</p>
|
|
34
|
+
)}
|
|
35
|
+
</header>
|
|
36
|
+
<div className="grid grid-flow-col auto-cols-[minmax(220px,1fr)] gap-4 overflow-x-auto snap-x snap-mandatory pb-2">
|
|
37
|
+
{products.slice(0, 8).map((p) => (
|
|
38
|
+
<div key={p.id} className="snap-start">
|
|
39
|
+
<StoreProductCard product={p} />
|
|
40
|
+
</div>
|
|
41
|
+
))}
|
|
42
|
+
</div>
|
|
43
|
+
</section>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import Image from "next/image";
|
|
3
|
+
|
|
4
|
+
interface FeatureHeroProps {
|
|
5
|
+
eyebrow: string;
|
|
6
|
+
title: React.ReactNode;
|
|
7
|
+
description: string;
|
|
8
|
+
primaryCta: { label: string; href: string };
|
|
9
|
+
secondaryCta?: { label: string; href: string };
|
|
10
|
+
imageUrl: string;
|
|
11
|
+
imageAlt: string;
|
|
12
|
+
badge?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Apple-style split hero. Left: copy + CTAs. Right: large product image.
|
|
17
|
+
* Stacks to image-on-top on mobile. Strings come from `brand.hero` at the
|
|
18
|
+
* call site — this component is otherwise design-only.
|
|
19
|
+
*/
|
|
20
|
+
export function FeatureHero({
|
|
21
|
+
eyebrow,
|
|
22
|
+
title,
|
|
23
|
+
description,
|
|
24
|
+
primaryCta,
|
|
25
|
+
secondaryCta,
|
|
26
|
+
imageUrl,
|
|
27
|
+
imageAlt,
|
|
28
|
+
badge,
|
|
29
|
+
}: FeatureHeroProps) {
|
|
30
|
+
return (
|
|
31
|
+
<section className="relative overflow-hidden bg-foreground text-background">
|
|
32
|
+
<div className="absolute inset-0 opacity-[0.04] pointer-events-none [background-image:radial-gradient(circle_at_2px_2px,white_1px,transparent_0)] [background-size:40px_40px]" />
|
|
33
|
+
<div className="relative max-w-7xl mx-auto px-6 sm:px-8 py-16 sm:py-20 lg:py-24 grid grid-cols-1 lg:grid-cols-[1.1fr_1fr] gap-10 lg:gap-16 items-center">
|
|
34
|
+
<div>
|
|
35
|
+
{badge && (
|
|
36
|
+
<span className="inline-flex items-center gap-2 mb-5 px-3 py-1.5 rounded-full bg-primary/15 border border-primary/40 text-primary-foreground/95 text-[11px] font-mono uppercase tracking-[0.16em]">
|
|
37
|
+
<span className="grid place-items-center w-1.5 h-1.5 rounded-full bg-primary animate-pulse" />
|
|
38
|
+
{badge}
|
|
39
|
+
</span>
|
|
40
|
+
)}
|
|
41
|
+
<p className="text-[12px] font-mono uppercase tracking-[0.2em] text-background/60 mb-3">
|
|
42
|
+
{eyebrow}
|
|
43
|
+
</p>
|
|
44
|
+
<h1 className="text-[clamp(2.5rem,6vw,4.75rem)] font-bold m-0 mb-5 -tracking-[0.035em] leading-[1.02]">
|
|
45
|
+
{title}
|
|
46
|
+
</h1>
|
|
47
|
+
<p className="text-base sm:text-lg text-background/75 leading-relaxed max-w-xl">
|
|
48
|
+
{description}
|
|
49
|
+
</p>
|
|
50
|
+
<div className="flex flex-wrap items-center gap-3 mt-7">
|
|
51
|
+
<Link
|
|
52
|
+
href={primaryCta.href}
|
|
53
|
+
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md bg-primary text-primary-foreground font-semibold text-sm hover:bg-primary/90 transition-colors"
|
|
54
|
+
>
|
|
55
|
+
{primaryCta.label}
|
|
56
|
+
<svg viewBox="0 0 12 12" className="w-3 h-3" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden>
|
|
57
|
+
<path d="M3 6h7m0 0L7 3m3 3L7 9" strokeLinecap="round" strokeLinejoin="round" />
|
|
58
|
+
</svg>
|
|
59
|
+
</Link>
|
|
60
|
+
{secondaryCta && (
|
|
61
|
+
<Link
|
|
62
|
+
href={secondaryCta.href}
|
|
63
|
+
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md border border-background/25 text-background hover:bg-background/10 transition-colors text-sm font-medium"
|
|
64
|
+
>
|
|
65
|
+
{secondaryCta.label}
|
|
66
|
+
</Link>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
<div className="relative aspect-[4/3] lg:aspect-square w-full rounded-2xl overflow-hidden bg-background/5 ring-1 ring-background/10">
|
|
71
|
+
<Image
|
|
72
|
+
src={imageUrl}
|
|
73
|
+
alt={imageAlt}
|
|
74
|
+
fill
|
|
75
|
+
sizes="(min-width: 1024px) 50vw, 100vw"
|
|
76
|
+
className="object-cover"
|
|
77
|
+
priority
|
|
78
|
+
/>
|
|
79
|
+
<div className="absolute inset-0 bg-gradient-to-tr from-foreground/40 via-transparent to-transparent pointer-events-none" />
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</section>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRouter, useSearchParams } from "next/navigation";
|
|
4
|
+
import { useMemo, useState } from "react";
|
|
5
|
+
import { brand } from "@/lib/brand";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Vehicle / fitment finder — the signature auto-parts widget.
|
|
9
|
+
*
|
|
10
|
+
* UX: customer picks Make → Model → Year (each subsequent select is
|
|
11
|
+
* filtered by the previous choice). Submit pushes ?fits=<tag>&y=<year>
|
|
12
|
+
* onto the shop URL; the shop page reads the tag and filters the
|
|
13
|
+
* catalogue. Universal-fit products always appear regardless.
|
|
14
|
+
*
|
|
15
|
+
* Data lives entirely in `brand.fitments` (lib/brand.ts) so a merchant
|
|
16
|
+
* can rebrand the catalogue without touching this component. Each
|
|
17
|
+
* fitment entry carries the tag that maps onto product `tags` like
|
|
18
|
+
* `fits:toyota:corolla`.
|
|
19
|
+
*/
|
|
20
|
+
export function FitmentFinder() {
|
|
21
|
+
const router = useRouter();
|
|
22
|
+
const searchParams = useSearchParams();
|
|
23
|
+
const { eyebrow, title, description, ctaLabel, anyMakeLabel, anyModelLabel, anyYearLabel, makes } =
|
|
24
|
+
brand.fitments;
|
|
25
|
+
|
|
26
|
+
const [make, setMake] = useState<string>(searchParams?.get("make") ?? "");
|
|
27
|
+
const [model, setModel] = useState<string>(searchParams?.get("model") ?? "");
|
|
28
|
+
const [year, setYear] = useState<string>(searchParams?.get("y") ?? "");
|
|
29
|
+
|
|
30
|
+
const selectedMake = useMemo(() => makes.find((m) => m.slug === make), [make, makes]);
|
|
31
|
+
const models = selectedMake?.models ?? [];
|
|
32
|
+
const selectedModel = useMemo(() => models.find((m) => m.slug === model), [model, models]);
|
|
33
|
+
const years = selectedModel?.years ?? [];
|
|
34
|
+
|
|
35
|
+
function onSubmit(e: React.FormEvent) {
|
|
36
|
+
e.preventDefault();
|
|
37
|
+
if (!make) return;
|
|
38
|
+
const params = new URLSearchParams();
|
|
39
|
+
if (model) {
|
|
40
|
+
params.set("fits", `fits:${make}:${model}`);
|
|
41
|
+
params.set("make", make);
|
|
42
|
+
params.set("model", model);
|
|
43
|
+
} else {
|
|
44
|
+
params.set("fits", `fits:${make}`);
|
|
45
|
+
params.set("make", make);
|
|
46
|
+
}
|
|
47
|
+
if (year) params.set("y", year);
|
|
48
|
+
router.push(`/shop?${params.toString()}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<section id="fitment" className="max-w-7xl mx-auto px-6 sm:px-8 -mt-10 sm:-mt-14 relative z-10 scroll-mt-20">
|
|
53
|
+
<div className="bg-card border border-border rounded-2xl p-6 sm:p-8 shadow-[0_8px_30px_rgb(0_0_0/0.06)]">
|
|
54
|
+
<div className="flex flex-col lg:flex-row lg:items-end lg:justify-between gap-6 mb-6">
|
|
55
|
+
<div className="max-w-xl">
|
|
56
|
+
<p className="text-[12px] font-mono uppercase tracking-[0.2em] text-muted-foreground mb-2">
|
|
57
|
+
{eyebrow}
|
|
58
|
+
</p>
|
|
59
|
+
<h2 className="text-[clamp(1.5rem,3vw,2rem)] font-semibold m-0 -tracking-[0.025em] leading-tight">
|
|
60
|
+
{title}
|
|
61
|
+
</h2>
|
|
62
|
+
<p className="text-sm text-muted-foreground mt-2 leading-relaxed">{description}</p>
|
|
63
|
+
</div>
|
|
64
|
+
<FitmentBadge />
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<form onSubmit={onSubmit} className="grid grid-cols-1 md:grid-cols-[1.2fr_1.2fr_1fr_auto] gap-3">
|
|
68
|
+
<Select
|
|
69
|
+
label="Make"
|
|
70
|
+
value={make}
|
|
71
|
+
placeholder={anyMakeLabel}
|
|
72
|
+
onChange={(v) => {
|
|
73
|
+
setMake(v);
|
|
74
|
+
setModel("");
|
|
75
|
+
setYear("");
|
|
76
|
+
}}
|
|
77
|
+
options={makes.map((m) => ({ value: m.slug, label: m.name }))}
|
|
78
|
+
/>
|
|
79
|
+
<Select
|
|
80
|
+
label="Model"
|
|
81
|
+
value={model}
|
|
82
|
+
placeholder={anyModelLabel}
|
|
83
|
+
disabled={!make}
|
|
84
|
+
onChange={(v) => {
|
|
85
|
+
setModel(v);
|
|
86
|
+
setYear("");
|
|
87
|
+
}}
|
|
88
|
+
options={models.map((m) => ({ value: m.slug, label: m.name }))}
|
|
89
|
+
/>
|
|
90
|
+
<Select
|
|
91
|
+
label="Year"
|
|
92
|
+
value={year}
|
|
93
|
+
placeholder={anyYearLabel}
|
|
94
|
+
disabled={!model}
|
|
95
|
+
onChange={setYear}
|
|
96
|
+
options={years.map((y) => ({ value: String(y), label: String(y) }))}
|
|
97
|
+
/>
|
|
98
|
+
<button
|
|
99
|
+
type="submit"
|
|
100
|
+
disabled={!make}
|
|
101
|
+
className="self-end inline-flex items-center justify-center gap-2 px-6 h-11 rounded-xl bg-primary text-primary-foreground text-sm font-semibold hover:bg-primary/90 disabled:bg-muted disabled:text-muted-foreground disabled:cursor-not-allowed transition-colors"
|
|
102
|
+
>
|
|
103
|
+
{ctaLabel}
|
|
104
|
+
<ArrowIcon />
|
|
105
|
+
</button>
|
|
106
|
+
</form>
|
|
107
|
+
</div>
|
|
108
|
+
</section>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
interface SelectProps {
|
|
113
|
+
label: string;
|
|
114
|
+
value: string;
|
|
115
|
+
placeholder: string;
|
|
116
|
+
options: { value: string; label: string }[];
|
|
117
|
+
onChange: (v: string) => void;
|
|
118
|
+
disabled?: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function Select({ label, value, placeholder, options, onChange, disabled }: SelectProps) {
|
|
122
|
+
return (
|
|
123
|
+
<label className="block">
|
|
124
|
+
<span className="block text-[11px] font-mono uppercase tracking-[0.16em] text-muted-foreground mb-1.5">
|
|
125
|
+
{label}
|
|
126
|
+
</span>
|
|
127
|
+
<div className="relative">
|
|
128
|
+
<select
|
|
129
|
+
value={value}
|
|
130
|
+
disabled={disabled}
|
|
131
|
+
onChange={(e) => onChange(e.target.value)}
|
|
132
|
+
className="block w-full h-11 pl-3.5 pr-10 rounded-xl border border-border bg-background text-sm font-medium appearance-none disabled:opacity-60 disabled:cursor-not-allowed focus:outline-none focus:ring-2 focus:ring-primary/40 focus:border-primary"
|
|
133
|
+
>
|
|
134
|
+
<option value="">{placeholder}</option>
|
|
135
|
+
{options.map((o) => (
|
|
136
|
+
<option key={o.value} value={o.value}>
|
|
137
|
+
{o.label}
|
|
138
|
+
</option>
|
|
139
|
+
))}
|
|
140
|
+
</select>
|
|
141
|
+
<ChevronIcon />
|
|
142
|
+
</div>
|
|
143
|
+
</label>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function FitmentBadge() {
|
|
148
|
+
return (
|
|
149
|
+
<div className="hidden lg:flex items-center gap-3 px-4 py-3 rounded-xl bg-accent text-accent-foreground">
|
|
150
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" className="w-5 h-5" aria-hidden>
|
|
151
|
+
<path d="M5 13l2-5h10l2 5" strokeLinejoin="round" />
|
|
152
|
+
<path d="M3 13h18v5a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1v-1H7v1a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-5z" strokeLinejoin="round" />
|
|
153
|
+
<circle cx="7" cy="16" r="1" />
|
|
154
|
+
<circle cx="17" cy="16" r="1" />
|
|
155
|
+
</svg>
|
|
156
|
+
<span className="text-[12px] font-mono uppercase tracking-[0.14em]">
|
|
157
|
+
Universal parts always shown
|
|
158
|
+
</span>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function ChevronIcon() {
|
|
164
|
+
return (
|
|
165
|
+
<svg
|
|
166
|
+
viewBox="0 0 24 24"
|
|
167
|
+
fill="none"
|
|
168
|
+
stroke="currentColor"
|
|
169
|
+
strokeWidth="2"
|
|
170
|
+
className="absolute right-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground pointer-events-none"
|
|
171
|
+
aria-hidden
|
|
172
|
+
>
|
|
173
|
+
<path d="M6 9l6 6 6-6" strokeLinecap="round" strokeLinejoin="round" />
|
|
174
|
+
</svg>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function ArrowIcon() {
|
|
179
|
+
return (
|
|
180
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="w-3.5 h-3.5" aria-hidden>
|
|
181
|
+
<path d="M5 12h14M13 6l6 6-6 6" strokeLinecap="round" strokeLinejoin="round" />
|
|
182
|
+
</svg>
|
|
183
|
+
);
|
|
184
|
+
}
|