@cimplify/sdk 0.40.0 → 0.41.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.
- package/dist/dispatcher.mjs +3 -2
- package/dist/mock/cli.mjs +30 -6
- package/dist/mock/library.js +30 -6
- package/dist/mock/library.mjs +30 -6
- package/dist/mock/msw.js +30 -6
- package/dist/mock/msw.mjs +30 -6
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/templates/storefront-bakery/.env.example +5 -0
- package/templates/storefront-bakery/AGENTS.md +57 -0
- package/templates/storefront-bakery/app/about/page.tsx +21 -44
- package/templates/storefront-bakery/app/categories/[slug]/page.tsx +2 -1
- package/templates/storefront-bakery/app/collections/[slug]/page.tsx +2 -1
- package/templates/storefront-bakery/app/error.tsx +60 -0
- package/templates/storefront-bakery/app/faq/page.tsx +13 -89
- package/templates/storefront-bakery/app/layout.tsx +37 -2
- package/templates/storefront-bakery/app/llms.txt/route.ts +94 -0
- package/templates/storefront-bakery/app/not-found.tsx +39 -0
- package/templates/storefront-bakery/app/page.tsx +6 -6
- package/templates/storefront-bakery/app/privacy/page.tsx +24 -68
- package/templates/storefront-bakery/app/robots.ts +18 -0
- package/templates/storefront-bakery/app/shop/page.tsx +3 -2
- package/templates/storefront-bakery/app/sitemap.ts +62 -0
- package/templates/storefront-bakery/app/terms/page.tsx +24 -82
- package/templates/storefront-bakery/components/footer.tsx +88 -130
- package/templates/storefront-bakery/components/header.tsx +8 -16
- package/templates/storefront-bakery/lib/brand.ts +453 -0
- package/templates/storefront-fashion/.env.example +16 -0
- package/templates/storefront-fashion/AGENTS.md +52 -0
- package/templates/storefront-fashion/README.md +77 -0
- package/templates/storefront-fashion/app/about/page.tsx +41 -0
- package/templates/storefront-fashion/app/cart/page.tsx +9 -0
- package/templates/storefront-fashion/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-fashion/app/categories/[slug]/page.tsx +130 -0
- package/templates/storefront-fashion/app/checkout/page.tsx +17 -0
- package/templates/storefront-fashion/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-fashion/app/collections/[slug]/page.tsx +130 -0
- package/templates/storefront-fashion/app/error.tsx +61 -0
- package/templates/storefront-fashion/app/faq/page.tsx +46 -0
- package/templates/storefront-fashion/app/globals.css +46 -0
- package/templates/storefront-fashion/app/layout.tsx +76 -0
- package/templates/storefront-fashion/app/llms.txt/route.ts +94 -0
- package/templates/storefront-fashion/app/not-found.tsx +39 -0
- package/templates/storefront-fashion/app/orders/[id]/page.tsx +24 -0
- package/templates/storefront-fashion/app/page.tsx +183 -0
- package/templates/storefront-fashion/app/privacy/page.tsx +44 -0
- package/templates/storefront-fashion/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-fashion/app/products/[slug]/product-detail.tsx +71 -0
- package/templates/storefront-fashion/app/robots.ts +18 -0
- package/templates/storefront-fashion/app/shop/page.tsx +63 -0
- package/templates/storefront-fashion/app/shop/shop-client.tsx +32 -0
- package/templates/storefront-fashion/app/sitemap.ts +59 -0
- package/templates/storefront-fashion/app/terms/page.tsx +44 -0
- package/templates/storefront-fashion/components/brand-marquee.tsx +27 -0
- package/templates/storefront-fashion/components/cart-pill.tsx +32 -0
- package/templates/storefront-fashion/components/category-grid.tsx +28 -0
- package/templates/storefront-fashion/components/category-tiles.tsx +104 -0
- package/templates/storefront-fashion/components/collection-strip.tsx +45 -0
- package/templates/storefront-fashion/components/feature-hero.tsx +82 -0
- package/templates/storefront-fashion/components/footer.tsx +153 -0
- package/templates/storefront-fashion/components/header.tsx +43 -0
- package/templates/storefront-fashion/components/hero.tsx +28 -0
- package/templates/storefront-fashion/components/nav-link.tsx +20 -0
- package/templates/storefront-fashion/components/newsletter.tsx +50 -0
- package/templates/storefront-fashion/components/promo-banner.tsx +41 -0
- package/templates/storefront-fashion/components/providers.tsx +31 -0
- package/templates/storefront-fashion/components/section-heading.tsx +37 -0
- package/templates/storefront-fashion/components/store-product-card.tsx +83 -0
- package/templates/storefront-fashion/components/trade-in-cta.tsx +54 -0
- package/templates/storefront-fashion/components/trust-bar.tsx +66 -0
- package/templates/storefront-fashion/lib/brand.ts +421 -0
- package/templates/storefront-fashion/lib/cart.ts +27 -0
- package/templates/storefront-fashion/next.config.ts +40 -0
- package/templates/storefront-fashion/package.json +28 -0
- package/templates/storefront-fashion/postcss.config.mjs +7 -0
- package/templates/storefront-fashion/tsconfig.json +23 -0
- package/templates/storefront-grocery/.env.example +16 -0
- package/templates/storefront-grocery/AGENTS.md +39 -0
- package/templates/storefront-grocery/README.md +73 -0
- package/templates/storefront-grocery/app/about/page.tsx +38 -0
- package/templates/storefront-grocery/app/cart/page.tsx +9 -0
- package/templates/storefront-grocery/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-grocery/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-grocery/app/checkout/page.tsx +17 -0
- package/templates/storefront-grocery/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-grocery/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-grocery/app/error.tsx +60 -0
- package/templates/storefront-grocery/app/faq/page.tsx +46 -0
- package/templates/storefront-grocery/app/globals.css +45 -0
- package/templates/storefront-grocery/app/layout.tsx +75 -0
- package/templates/storefront-grocery/app/llms.txt/route.ts +94 -0
- package/templates/storefront-grocery/app/not-found.tsx +39 -0
- package/templates/storefront-grocery/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-grocery/app/page.tsx +97 -0
- package/templates/storefront-grocery/app/privacy/page.tsx +44 -0
- package/templates/storefront-grocery/app/robots.ts +18 -0
- package/templates/storefront-grocery/app/shop/page.tsx +31 -0
- package/templates/storefront-grocery/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-grocery/app/sitemap.ts +62 -0
- package/templates/storefront-grocery/app/terms/page.tsx +44 -0
- package/templates/storefront-grocery/components/cart-pill.tsx +32 -0
- package/templates/storefront-grocery/components/category-grid.tsx +28 -0
- package/templates/storefront-grocery/components/collection-strip.tsx +45 -0
- package/templates/storefront-grocery/components/footer.tsx +148 -0
- package/templates/storefront-grocery/components/header.tsx +43 -0
- package/templates/storefront-grocery/components/hero.tsx +25 -0
- package/templates/storefront-grocery/components/nav-link.tsx +20 -0
- package/templates/storefront-grocery/components/providers.tsx +31 -0
- package/templates/storefront-grocery/components/store-product-card.tsx +83 -0
- package/templates/storefront-grocery/lib/brand.ts +284 -0
- package/templates/storefront-grocery/lib/cart.ts +27 -0
- package/templates/storefront-grocery/next.config.ts +40 -0
- package/templates/storefront-grocery/package.json +28 -0
- package/templates/storefront-grocery/postcss.config.mjs +7 -0
- package/templates/storefront-grocery/tsconfig.json +23 -0
- package/templates/storefront-restaurant/.env.example +16 -0
- package/templates/storefront-restaurant/AGENTS.md +39 -0
- package/templates/storefront-restaurant/README.md +73 -0
- package/templates/storefront-restaurant/app/about/page.tsx +38 -0
- package/templates/storefront-restaurant/app/cart/page.tsx +9 -0
- package/templates/storefront-restaurant/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-restaurant/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-restaurant/app/checkout/page.tsx +17 -0
- package/templates/storefront-restaurant/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-restaurant/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-restaurant/app/error.tsx +60 -0
- package/templates/storefront-restaurant/app/faq/page.tsx +46 -0
- package/templates/storefront-restaurant/app/globals.css +44 -0
- package/templates/storefront-restaurant/app/layout.tsx +80 -0
- package/templates/storefront-restaurant/app/llms.txt/route.ts +94 -0
- package/templates/storefront-restaurant/app/not-found.tsx +39 -0
- package/templates/storefront-restaurant/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-restaurant/app/page.tsx +97 -0
- package/templates/storefront-restaurant/app/privacy/page.tsx +44 -0
- package/templates/storefront-restaurant/app/robots.ts +18 -0
- package/templates/storefront-restaurant/app/shop/page.tsx +31 -0
- package/templates/storefront-restaurant/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-restaurant/app/sitemap.ts +62 -0
- package/templates/storefront-restaurant/app/terms/page.tsx +44 -0
- package/templates/storefront-restaurant/components/cart-pill.tsx +32 -0
- package/templates/storefront-restaurant/components/category-grid.tsx +28 -0
- package/templates/storefront-restaurant/components/collection-strip.tsx +45 -0
- package/templates/storefront-restaurant/components/footer.tsx +148 -0
- package/templates/storefront-restaurant/components/header.tsx +43 -0
- package/templates/storefront-restaurant/components/hero.tsx +25 -0
- package/templates/storefront-restaurant/components/nav-link.tsx +20 -0
- package/templates/storefront-restaurant/components/product-modal.tsx +105 -0
- package/templates/storefront-restaurant/components/providers.tsx +31 -0
- package/templates/storefront-restaurant/components/store-product-card.tsx +83 -0
- package/templates/storefront-restaurant/lib/brand.ts +287 -0
- package/templates/storefront-restaurant/lib/cart.ts +27 -0
- package/templates/storefront-restaurant/next.config.ts +40 -0
- package/templates/storefront-restaurant/package.json +28 -0
- package/templates/storefront-restaurant/postcss.config.mjs +7 -0
- package/templates/storefront-restaurant/tsconfig.json +23 -0
- package/templates/storefront-retail/.env.example +5 -0
- package/templates/storefront-retail/AGENTS.md +64 -0
- package/templates/storefront-retail/app/about/page.tsx +24 -54
- package/templates/storefront-retail/app/categories/[slug]/page.tsx +50 -37
- package/templates/storefront-retail/app/collections/[slug]/page.tsx +50 -37
- package/templates/storefront-retail/app/error.tsx +61 -0
- package/templates/storefront-retail/app/faq/page.tsx +11 -92
- package/templates/storefront-retail/app/layout.tsx +37 -8
- package/templates/storefront-retail/app/llms.txt/route.ts +94 -0
- package/templates/storefront-retail/app/not-found.tsx +39 -0
- package/templates/storefront-retail/app/page.tsx +111 -26
- package/templates/storefront-retail/app/privacy/page.tsx +24 -81
- package/templates/storefront-retail/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-retail/app/products/[slug]/product-detail.tsx +71 -0
- package/templates/storefront-retail/app/robots.ts +18 -0
- package/templates/storefront-retail/app/shop/page.tsx +36 -3
- package/templates/storefront-retail/app/shop/shop-client.tsx +6 -1
- package/templates/storefront-retail/app/sitemap.ts +59 -0
- package/templates/storefront-retail/app/terms/page.tsx +24 -97
- package/templates/storefront-retail/components/brand-marquee.tsx +27 -0
- package/templates/storefront-retail/components/category-tiles.tsx +104 -0
- package/templates/storefront-retail/components/feature-hero.tsx +84 -0
- package/templates/storefront-retail/components/footer.tsx +85 -120
- package/templates/storefront-retail/components/header.tsx +10 -12
- package/templates/storefront-retail/components/newsletter.tsx +50 -0
- package/templates/storefront-retail/components/promo-banner.tsx +41 -0
- package/templates/storefront-retail/components/section-heading.tsx +37 -0
- package/templates/storefront-retail/components/store-product-card.tsx +7 -7
- package/templates/storefront-retail/components/trade-in-cta.tsx +54 -0
- package/templates/storefront-retail/components/trust-bar.tsx +66 -0
- package/templates/storefront-retail/lib/brand.ts +567 -0
- package/templates/storefront-services/.env.example +16 -0
- package/templates/storefront-services/AGENTS.md +41 -0
- package/templates/storefront-services/README.md +73 -0
- package/templates/storefront-services/app/about/page.tsx +38 -0
- package/templates/storefront-services/app/cart/page.tsx +9 -0
- package/templates/storefront-services/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-services/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-services/app/checkout/page.tsx +17 -0
- package/templates/storefront-services/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-services/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-services/app/error.tsx +60 -0
- package/templates/storefront-services/app/faq/page.tsx +46 -0
- package/templates/storefront-services/app/globals.css +45 -0
- package/templates/storefront-services/app/layout.tsx +80 -0
- package/templates/storefront-services/app/llms.txt/route.ts +94 -0
- package/templates/storefront-services/app/not-found.tsx +39 -0
- package/templates/storefront-services/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-services/app/page.tsx +97 -0
- package/templates/storefront-services/app/privacy/page.tsx +44 -0
- package/templates/storefront-services/app/robots.ts +18 -0
- package/templates/storefront-services/app/shop/page.tsx +31 -0
- package/templates/storefront-services/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-services/app/sitemap.ts +62 -0
- package/templates/storefront-services/app/terms/page.tsx +44 -0
- package/templates/storefront-services/components/cart-pill.tsx +32 -0
- package/templates/storefront-services/components/category-grid.tsx +28 -0
- package/templates/storefront-services/components/collection-strip.tsx +45 -0
- package/templates/storefront-services/components/footer.tsx +148 -0
- package/templates/storefront-services/components/header.tsx +43 -0
- package/templates/storefront-services/components/hero.tsx +25 -0
- package/templates/storefront-services/components/nav-link.tsx +20 -0
- package/templates/storefront-services/components/product-modal.tsx +105 -0
- package/templates/storefront-services/components/providers.tsx +31 -0
- package/templates/storefront-services/components/store-product-card.tsx +83 -0
- package/templates/storefront-services/lib/brand.ts +303 -0
- package/templates/storefront-services/lib/cart.ts +27 -0
- package/templates/storefront-services/next.config.ts +40 -0
- package/templates/storefront-services/package.json +28 -0
- package/templates/storefront-services/postcss.config.mjs +7 -0
- package/templates/storefront-services/tsconfig.json +23 -0
- /package/templates/{storefront-retail → storefront-grocery}/components/product-modal.tsx +0 -0
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type Product,
|
|
11
11
|
} from "@cimplify/sdk/server";
|
|
12
12
|
import { ListingClient } from "./listing-client";
|
|
13
|
+
import { brand } from "@/lib/brand";
|
|
13
14
|
|
|
14
15
|
interface CategoryData {
|
|
15
16
|
category: Category;
|
|
@@ -42,7 +43,7 @@ export async function generateMetadata({
|
|
|
42
43
|
const data = await getCategory(slug);
|
|
43
44
|
if (!data) return {};
|
|
44
45
|
return {
|
|
45
|
-
title: `${data.category.name} —
|
|
46
|
+
title: `${data.category.name} — ${brand.name}`,
|
|
46
47
|
description: data.category.description ?? undefined,
|
|
47
48
|
};
|
|
48
49
|
}
|
|
@@ -70,48 +71,60 @@ async function CategoryContent({
|
|
|
70
71
|
|
|
71
72
|
const { category, products } = data;
|
|
72
73
|
return (
|
|
73
|
-
|
|
74
|
-
<
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
<>
|
|
75
|
+
<section className="bg-foreground text-background relative overflow-hidden">
|
|
76
|
+
<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:32px_32px]" />
|
|
77
|
+
<div className="relative max-w-7xl mx-auto px-6 sm:px-8 py-12 sm:py-14">
|
|
78
|
+
<nav className="text-[12px] font-mono text-background/60 mb-3 flex items-center gap-2">
|
|
79
|
+
<Link href="/" className="hover:text-background transition-colors">Home</Link>
|
|
80
|
+
<span>/</span>
|
|
81
|
+
<Link href="/shop" className="hover:text-background transition-colors">Shop</Link>
|
|
82
|
+
<span>/</span>
|
|
83
|
+
<span className="text-background/90">{category.name}</span>
|
|
84
|
+
</nav>
|
|
85
|
+
<h1 className="text-[clamp(2rem,4vw,3rem)] font-bold m-0 -tracking-[0.025em]">
|
|
86
|
+
{category.name}
|
|
87
|
+
</h1>
|
|
88
|
+
{category.description && (
|
|
89
|
+
<p className="mt-3 max-w-2xl text-base text-background/75">
|
|
90
|
+
{category.description}
|
|
91
|
+
</p>
|
|
92
|
+
)}
|
|
93
|
+
<p className="mt-4 text-[11px] font-mono uppercase tracking-[0.16em] text-background/60 tabular-nums">
|
|
94
|
+
{products.length} {products.length === 1 ? "product" : "products"}
|
|
95
|
+
</p>
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
<section className="max-w-7xl mx-auto px-6 sm:px-8 py-10 sm:py-12">
|
|
99
|
+
<ListingClient products={products} />
|
|
100
|
+
{products.length === 0 && (
|
|
101
|
+
<p className="text-center mt-8">
|
|
102
|
+
<Link href="/shop" className="text-primary font-semibold hover:underline">
|
|
103
|
+
← Browse all products
|
|
104
|
+
</Link>
|
|
84
105
|
</p>
|
|
85
106
|
)}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</p>
|
|
89
|
-
</header>
|
|
90
|
-
<ListingClient products={products} />
|
|
91
|
-
{products.length === 0 && (
|
|
92
|
-
<p className="text-center mt-8">
|
|
93
|
-
<Link href="/" className="text-primary font-semibold">
|
|
94
|
-
← Back home
|
|
95
|
-
</Link>
|
|
96
|
-
</p>
|
|
97
|
-
)}
|
|
98
|
-
</section>
|
|
107
|
+
</section>
|
|
108
|
+
</>
|
|
99
109
|
);
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
function CategorySkeleton() {
|
|
103
113
|
return (
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
<div className="
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
<>
|
|
115
|
+
<section className="bg-foreground py-12 sm:py-14">
|
|
116
|
+
<div className="max-w-7xl mx-auto px-6 sm:px-8">
|
|
117
|
+
<div className="h-3 w-32 bg-background/20 rounded mb-3 animate-pulse" />
|
|
118
|
+
<div className="h-12 w-72 bg-background/20 rounded animate-pulse" />
|
|
119
|
+
</div>
|
|
120
|
+
</section>
|
|
121
|
+
<section className="max-w-7xl mx-auto px-6 sm:px-8 py-10 sm:py-12">
|
|
122
|
+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3 sm:gap-4">
|
|
123
|
+
{Array.from({ length: 8 }).map((_, i) => (
|
|
124
|
+
<div key={i} className="aspect-[4/3] bg-muted rounded-2xl animate-pulse" />
|
|
125
|
+
))}
|
|
126
|
+
</div>
|
|
127
|
+
</section>
|
|
128
|
+
</>
|
|
116
129
|
);
|
|
117
130
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type Product,
|
|
11
11
|
} from "@cimplify/sdk/server";
|
|
12
12
|
import { ListingClient } from "./listing-client";
|
|
13
|
+
import { brand } from "@/lib/brand";
|
|
13
14
|
|
|
14
15
|
interface CollectionData {
|
|
15
16
|
collection: Collection;
|
|
@@ -42,7 +43,7 @@ export async function generateMetadata({
|
|
|
42
43
|
const data = await getCollection(slug);
|
|
43
44
|
if (!data) return {};
|
|
44
45
|
return {
|
|
45
|
-
title: `${data.collection.name} —
|
|
46
|
+
title: `${data.collection.name} — ${brand.name}`,
|
|
46
47
|
description: data.collection.description ?? undefined,
|
|
47
48
|
};
|
|
48
49
|
}
|
|
@@ -70,48 +71,60 @@ async function CollectionContent({
|
|
|
70
71
|
|
|
71
72
|
const { collection, products } = data;
|
|
72
73
|
return (
|
|
73
|
-
|
|
74
|
-
<
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
74
|
+
<>
|
|
75
|
+
<section className="bg-foreground text-background relative overflow-hidden">
|
|
76
|
+
<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:32px_32px]" />
|
|
77
|
+
<div className="relative max-w-7xl mx-auto px-6 sm:px-8 py-12 sm:py-14">
|
|
78
|
+
<nav className="text-[12px] font-mono text-background/60 mb-3 flex items-center gap-2">
|
|
79
|
+
<Link href="/" className="hover:text-background transition-colors">Home</Link>
|
|
80
|
+
<span>/</span>
|
|
81
|
+
<span className="text-background/90">Collections</span>
|
|
82
|
+
<span>/</span>
|
|
83
|
+
<span className="text-background/90">{collection.name}</span>
|
|
84
|
+
</nav>
|
|
85
|
+
<h1 className="text-[clamp(2rem,4vw,3rem)] font-bold m-0 -tracking-[0.025em]">
|
|
86
|
+
{collection.name}
|
|
87
|
+
</h1>
|
|
88
|
+
{collection.description && (
|
|
89
|
+
<p className="mt-3 max-w-2xl text-base text-background/75">
|
|
90
|
+
{collection.description}
|
|
91
|
+
</p>
|
|
92
|
+
)}
|
|
93
|
+
<p className="mt-4 text-[11px] font-mono uppercase tracking-[0.16em] text-background/60 tabular-nums">
|
|
94
|
+
{products.length} {products.length === 1 ? "product" : "products"}
|
|
95
|
+
</p>
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
<section className="max-w-7xl mx-auto px-6 sm:px-8 py-10 sm:py-12">
|
|
99
|
+
<ListingClient products={products} />
|
|
100
|
+
{products.length === 0 && (
|
|
101
|
+
<p className="text-center mt-8">
|
|
102
|
+
<Link href="/shop" className="text-primary font-semibold hover:underline">
|
|
103
|
+
← Browse all products
|
|
104
|
+
</Link>
|
|
84
105
|
</p>
|
|
85
106
|
)}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</p>
|
|
89
|
-
</header>
|
|
90
|
-
<ListingClient products={products} />
|
|
91
|
-
{products.length === 0 && (
|
|
92
|
-
<p className="text-center mt-8">
|
|
93
|
-
<Link href="/" className="text-primary font-semibold">
|
|
94
|
-
← Back home
|
|
95
|
-
</Link>
|
|
96
|
-
</p>
|
|
97
|
-
)}
|
|
98
|
-
</section>
|
|
107
|
+
</section>
|
|
108
|
+
</>
|
|
99
109
|
);
|
|
100
110
|
}
|
|
101
111
|
|
|
102
112
|
function CollectionSkeleton() {
|
|
103
113
|
return (
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
<div className="
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
<>
|
|
115
|
+
<section className="bg-foreground py-12 sm:py-14">
|
|
116
|
+
<div className="max-w-7xl mx-auto px-6 sm:px-8">
|
|
117
|
+
<div className="h-3 w-32 bg-background/20 rounded mb-3 animate-pulse" />
|
|
118
|
+
<div className="h-12 w-72 bg-background/20 rounded animate-pulse" />
|
|
119
|
+
</div>
|
|
120
|
+
</section>
|
|
121
|
+
<section className="max-w-7xl mx-auto px-6 sm:px-8 py-10 sm:py-12">
|
|
122
|
+
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-3 sm:gap-4">
|
|
123
|
+
{Array.from({ length: 8 }).map((_, i) => (
|
|
124
|
+
<div key={i} className="aspect-[4/3] bg-muted rounded-2xl animate-pulse" />
|
|
125
|
+
))}
|
|
126
|
+
</div>
|
|
127
|
+
</section>
|
|
128
|
+
</>
|
|
116
129
|
);
|
|
117
130
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Root error boundary. Next.js calls this whenever a thrown error escapes
|
|
8
|
+
* a Server Component without being caught by a closer `error.tsx`.
|
|
9
|
+
*
|
|
10
|
+
* Wire `reportError` (Sentry, Datadog, etc.) here so production failures
|
|
11
|
+
* surface — silently recovering hides real bugs.
|
|
12
|
+
*/
|
|
13
|
+
export default function GlobalError({
|
|
14
|
+
error,
|
|
15
|
+
reset,
|
|
16
|
+
}: {
|
|
17
|
+
error: Error & { digest?: string };
|
|
18
|
+
reset: () => void;
|
|
19
|
+
}) {
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
// TODO: replace with your error reporter
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.error("Storefront error:", error);
|
|
24
|
+
}, [error]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<section className="max-w-2xl mx-auto px-6 sm:px-8 py-20 text-center">
|
|
28
|
+
<p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-3">
|
|
29
|
+
Something broke
|
|
30
|
+
</p>
|
|
31
|
+
<h1 className="text-[clamp(2rem,4vw,3rem)] font-bold mb-4 -tracking-[0.025em]">
|
|
32
|
+
That wasn't supposed to happen.
|
|
33
|
+
</h1>
|
|
34
|
+
<p className="text-muted-foreground leading-relaxed mb-8">
|
|
35
|
+
We've been notified. Refresh the page, or head back home — most
|
|
36
|
+
of the time the second try just works.
|
|
37
|
+
</p>
|
|
38
|
+
{error.digest && (
|
|
39
|
+
<p className="text-xs font-mono text-muted-foreground mb-6">
|
|
40
|
+
Reference:{" "}
|
|
41
|
+
<code className="text-foreground">{error.digest}</code>
|
|
42
|
+
</p>
|
|
43
|
+
)}
|
|
44
|
+
<div className="flex flex-wrap items-center justify-center gap-3">
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
onClick={reset}
|
|
48
|
+
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"
|
|
49
|
+
>
|
|
50
|
+
Try again
|
|
51
|
+
</button>
|
|
52
|
+
<Link
|
|
53
|
+
href="/"
|
|
54
|
+
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md border border-border hover:bg-muted transition-colors text-sm font-medium"
|
|
55
|
+
>
|
|
56
|
+
Back home
|
|
57
|
+
</Link>
|
|
58
|
+
</div>
|
|
59
|
+
</section>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -1,106 +1,25 @@
|
|
|
1
1
|
import type { Metadata } from "next";
|
|
2
|
+
import { brand } from "@/lib/brand";
|
|
2
3
|
|
|
3
4
|
export const metadata: Metadata = {
|
|
4
|
-
title:
|
|
5
|
-
description:
|
|
6
|
-
"Shipping, warranty, repairs, returns, payment — answers to the questions we hear most often.",
|
|
5
|
+
title: `Support — ${brand.name}`,
|
|
6
|
+
description: "Shipping, warranty, repairs, returns, payment — answers to the questions we hear most often.",
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
interface QA {
|
|
10
|
-
q: string;
|
|
11
|
-
a: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const SECTIONS: { title: string; items: QA[] }[] = [
|
|
15
|
-
{
|
|
16
|
-
title: "Ordering & delivery",
|
|
17
|
-
items: [
|
|
18
|
-
{
|
|
19
|
-
q: "How fast is shipping?",
|
|
20
|
-
a: "Free same-day delivery within Greater Accra for orders placed before 4pm. Outside Accra, we use a partner courier — usually 1–3 business days, with tracking sent by SMS.",
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
q: "Can I pick up in store?",
|
|
24
|
-
a: "Yes. Choose 'Pickup' at checkout and we'll have your order boxed at our Atomic Junction store within 30 minutes. Bring a photo ID matching the order name.",
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
q: "Do you ship internationally?",
|
|
28
|
-
a: "We ship across West Africa via DHL — rates and ETAs are calculated at checkout once you enter your destination.",
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
q: "How do I track my order?",
|
|
32
|
-
a: "You'll get an SMS and email with a tracking link within 30 minutes of dispatch. Same-day Accra orders include the rider's phone number.",
|
|
33
|
-
},
|
|
34
|
-
],
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
title: "Warranty & repairs",
|
|
38
|
-
items: [
|
|
39
|
-
{
|
|
40
|
-
q: "What does the two-year warranty cover?",
|
|
41
|
-
a: "Manufacturing defects, electrical failures, and battery degradation below 80% within the first 24 months. Accidental damage, water damage, and software issues caused by user installs are excluded.",
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
q: "Where do I send a faulty device?",
|
|
45
|
-
a: "Drop it at our Atomic Junction store, or request a free pickup from your address by emailing support@currentselectronics.test. Loaner devices are available for warranty claims while we diagnose.",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
q: "Can you fix devices bought elsewhere?",
|
|
49
|
-
a: "We offer paid repairs on Apple and Samsung devices regardless of where they were purchased. Expect a quote within 48 hours of inspection.",
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
title: "Trade-in & financing",
|
|
55
|
-
items: [
|
|
56
|
-
{
|
|
57
|
-
q: "How does trade-in work?",
|
|
58
|
-
a: "Tell us the model and condition of your device, get an instant estimate, and ship it free or drop it at our store. Once we verify, we credit your account or pay out via Mobile Money — your choice.",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
q: "Do you offer instalment payments?",
|
|
62
|
-
a: "Yes. Pay in 3 (interest-free) or 6/12 monthly instalments via our partner Fidelity Bank. Available at checkout for orders over GH₵2,000.",
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
q: "Are there bulk discounts for businesses?",
|
|
66
|
-
a: "Yes. Email business@currentselectronics.test with your shopping list and team size — most orders over 5 units qualify for a discount, plus free on-site setup.",
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
{
|
|
71
|
-
title: "Payment & returns",
|
|
72
|
-
items: [
|
|
73
|
-
{
|
|
74
|
-
q: "What payment methods do you accept?",
|
|
75
|
-
a: "Mobile Money (MTN, Telecel, AirtelTigo), Visa/Mastercard, instalments via Fidelity Bank, and cash on delivery for Accra orders.",
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
q: "What's your return policy?",
|
|
79
|
-
a: "14 days, no questions asked, on any sealed product. For opened items, returns are accepted within 7 days subject to a 10% restocking fee. We can't accept returns on activated SIM-bundled phones once the SIM is registered.",
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
q: "Are products genuine?",
|
|
83
|
-
a: "Yes. We're an authorised dealer for every brand we stock. Every product ships with the manufacturer's serial number registered to your name — verify it on the brand's official portal anytime.",
|
|
84
|
-
},
|
|
85
|
-
],
|
|
86
|
-
},
|
|
87
|
-
];
|
|
88
|
-
|
|
89
9
|
export default function FaqPage() {
|
|
10
|
+
const f = brand.faq;
|
|
90
11
|
return (
|
|
91
12
|
<article className="max-w-3xl mx-auto px-8 py-16">
|
|
92
13
|
<p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-2">
|
|
93
|
-
|
|
14
|
+
{f.eyebrow}
|
|
94
15
|
</p>
|
|
95
16
|
<h1 className="text-[clamp(2.25rem,5vw,3.5rem)] font-bold mb-10 -tracking-[0.025em]">
|
|
96
|
-
|
|
17
|
+
{f.title}
|
|
97
18
|
</h1>
|
|
98
19
|
<div className="space-y-12">
|
|
99
|
-
{
|
|
20
|
+
{f.sections.map((section) => (
|
|
100
21
|
<section key={section.title}>
|
|
101
|
-
<h2 className="text-2xl font-semibold mb-5 -tracking-[0.02em]">
|
|
102
|
-
{section.title}
|
|
103
|
-
</h2>
|
|
22
|
+
<h2 className="text-2xl font-semibold mb-5 -tracking-[0.02em]">{section.title}</h2>
|
|
104
23
|
<dl className="space-y-6">
|
|
105
24
|
{section.items.map((item) => (
|
|
106
25
|
<div key={item.q}>
|
|
@@ -113,12 +32,12 @@ export default function FaqPage() {
|
|
|
113
32
|
))}
|
|
114
33
|
</div>
|
|
115
34
|
<p className="mt-12 pt-8 border-t border-border text-sm text-muted-foreground">
|
|
116
|
-
|
|
35
|
+
{f.contactPrompt}{" "}
|
|
117
36
|
<a
|
|
118
|
-
href=
|
|
37
|
+
href={`mailto:${f.contactEmail}`}
|
|
119
38
|
className="text-primary font-semibold hover:underline"
|
|
120
39
|
>
|
|
121
|
-
|
|
40
|
+
{f.contactEmail}
|
|
122
41
|
</a>{" "}
|
|
123
42
|
and a real human will reply within 24 hours.
|
|
124
43
|
</p>
|
|
@@ -4,8 +4,7 @@ import "./globals.css";
|
|
|
4
4
|
import { Providers } from "@/components/providers";
|
|
5
5
|
import { Header } from "@/components/header";
|
|
6
6
|
import { Footer } from "@/components/footer";
|
|
7
|
-
import {
|
|
8
|
-
import { Suspense } from "react";
|
|
7
|
+
import { brand } from "@/lib/brand";
|
|
9
8
|
|
|
10
9
|
const inter = Inter({
|
|
11
10
|
subsets: ["latin"],
|
|
@@ -19,10 +18,39 @@ const mono = JetBrains_Mono({
|
|
|
19
18
|
display: "swap",
|
|
20
19
|
});
|
|
21
20
|
|
|
21
|
+
const SITE_URL =
|
|
22
|
+
process.env.NEXT_PUBLIC_SITE_URL?.trim() || "https://example.com";
|
|
23
|
+
|
|
22
24
|
export const metadata: Metadata = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
metadataBase: new URL(SITE_URL),
|
|
26
|
+
title: {
|
|
27
|
+
default: brand.name,
|
|
28
|
+
template: `%s — ${brand.name}`,
|
|
29
|
+
},
|
|
30
|
+
description: brand.description,
|
|
31
|
+
openGraph: {
|
|
32
|
+
type: "website",
|
|
33
|
+
siteName: brand.name,
|
|
34
|
+
locale: brand.locale,
|
|
35
|
+
},
|
|
36
|
+
twitter: { card: "summary_large_image" },
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const ORGANIZATION_LD = {
|
|
40
|
+
"@context": "https://schema.org",
|
|
41
|
+
"@type": brand.schemaType,
|
|
42
|
+
name: brand.name,
|
|
43
|
+
url: SITE_URL,
|
|
44
|
+
description: brand.description,
|
|
45
|
+
email: brand.contact.email,
|
|
46
|
+
telephone: brand.contact.phoneTel,
|
|
47
|
+
address: {
|
|
48
|
+
"@type": "PostalAddress",
|
|
49
|
+
streetAddress: brand.contact.streetAddress,
|
|
50
|
+
addressLocality: brand.contact.city,
|
|
51
|
+
addressCountry: brand.contact.countryCode,
|
|
52
|
+
},
|
|
53
|
+
sameAs: brand.socials.map((s) => s.href),
|
|
26
54
|
};
|
|
27
55
|
|
|
28
56
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
@@ -32,13 +60,14 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
32
60
|
suppressHydrationWarning
|
|
33
61
|
className="min-h-screen flex flex-col bg-background text-foreground font-sans"
|
|
34
62
|
>
|
|
63
|
+
<script
|
|
64
|
+
type="application/ld+json"
|
|
65
|
+
dangerouslySetInnerHTML={{ __html: JSON.stringify(ORGANIZATION_LD) }}
|
|
66
|
+
/>
|
|
35
67
|
<Providers>
|
|
36
68
|
<Header />
|
|
37
69
|
<main className="flex-1 pb-12 w-full">{children}</main>
|
|
38
70
|
<Footer />
|
|
39
|
-
<Suspense fallback={null}>
|
|
40
|
-
<ProductModal />
|
|
41
|
-
</Suspense>
|
|
42
71
|
</Providers>
|
|
43
72
|
</body>
|
|
44
73
|
</html>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { cacheTag, cacheLife } from "next/cache";
|
|
2
|
+
import { getServerClient, tags, type Product } from "@cimplify/sdk/server";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
const SITE_URL =
|
|
6
|
+
process.env.NEXT_PUBLIC_SITE_URL?.trim() || "https://example.com";
|
|
7
|
+
|
|
8
|
+
async function buildLlmsTxt(): Promise<string> {
|
|
9
|
+
"use cache";
|
|
10
|
+
cacheTag(tags.products(), tags.categories(), tags.collections());
|
|
11
|
+
cacheLife("hours");
|
|
12
|
+
|
|
13
|
+
const client = getServerClient();
|
|
14
|
+
const [productsRes, categoriesRes, collectionsRes] = await Promise.all([
|
|
15
|
+
client.catalogue.getProducts({ limit: 500 }),
|
|
16
|
+
client.catalogue.getCategories(),
|
|
17
|
+
client.catalogue.getCollections(),
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const products: Product[] = productsRes.ok ? productsRes.value.items : [];
|
|
21
|
+
const categories = categoriesRes.ok ? categoriesRes.value : [];
|
|
22
|
+
const collections = collectionsRes.ok ? collectionsRes.value : [];
|
|
23
|
+
|
|
24
|
+
const lines: string[] = [];
|
|
25
|
+
lines.push(`# ${brand.name}`);
|
|
26
|
+
lines.push("");
|
|
27
|
+
lines.push(`> ${brand.llms.summary}`);
|
|
28
|
+
lines.push("");
|
|
29
|
+
lines.push("## Browse");
|
|
30
|
+
lines.push(`- [Home](${SITE_URL}/)`);
|
|
31
|
+
lines.push(`- [Shop](${SITE_URL}/shop): Full catalogue with filter and sort.`);
|
|
32
|
+
|
|
33
|
+
if (categories.length > 0) {
|
|
34
|
+
lines.push("");
|
|
35
|
+
lines.push("## Categories");
|
|
36
|
+
for (const c of categories) {
|
|
37
|
+
lines.push(
|
|
38
|
+
`- [${c.name}](${SITE_URL}/categories/${c.slug})${c.description ? `: ${c.description}` : ""}`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (collections.length > 0) {
|
|
44
|
+
lines.push("");
|
|
45
|
+
lines.push("## Collections");
|
|
46
|
+
for (const c of collections) {
|
|
47
|
+
lines.push(
|
|
48
|
+
`- [${c.name}](${SITE_URL}/collections/${c.slug})${c.description ? `: ${c.description}` : ""}`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (products.length > 0) {
|
|
54
|
+
lines.push("");
|
|
55
|
+
lines.push("## Products");
|
|
56
|
+
for (const p of products) {
|
|
57
|
+
const slug = p.slug ?? p.id;
|
|
58
|
+
const price = `${p.currency ?? brand.currency} ${p.default_price}`;
|
|
59
|
+
const desc = p.description ? ` — ${p.description.replace(/\s+/g, " ").slice(0, 200)}` : "";
|
|
60
|
+
lines.push(`- [${p.name}](${SITE_URL}/products/${slug}) (${price})${desc}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
lines.push("");
|
|
65
|
+
lines.push("## Information");
|
|
66
|
+
lines.push(`- [About](${SITE_URL}/about)`);
|
|
67
|
+
lines.push(`- [Support / FAQ](${SITE_URL}/faq)`);
|
|
68
|
+
lines.push(`- [Terms of Service](${SITE_URL}/terms)`);
|
|
69
|
+
lines.push(`- [Privacy Policy](${SITE_URL}/privacy)`);
|
|
70
|
+
lines.push(`- [Sitemap (XML)](${SITE_URL}/sitemap.xml)`);
|
|
71
|
+
lines.push("");
|
|
72
|
+
lines.push("## Contact");
|
|
73
|
+
lines.push(`- Email: ${brand.contact.email}`);
|
|
74
|
+
lines.push(`- Phone: ${brand.contact.phone}`);
|
|
75
|
+
lines.push(`- Address: ${brand.contact.address}`);
|
|
76
|
+
|
|
77
|
+
return lines.join("\n") + "\n";
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* `/llms.txt` — machine-readable site index for LLMs (per llmstxt.org).
|
|
82
|
+
* Lets coding agents and chat assistants find products, categories, and
|
|
83
|
+
* support pages without scraping HTML. Plain Markdown so it streams cheaply
|
|
84
|
+
* into context windows.
|
|
85
|
+
*/
|
|
86
|
+
export async function GET(): Promise<Response> {
|
|
87
|
+
const body = await buildLlmsTxt();
|
|
88
|
+
return new Response(body, {
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
91
|
+
"Cache-Control": "public, max-age=0, s-maxage=3600, stale-while-revalidate=86400",
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import Link from "next/link";
|
|
3
|
+
import { brand } from "@/lib/brand";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: `Page not found — ${brand.name}`,
|
|
7
|
+
description: "We couldn't find that page.",
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export default function NotFound() {
|
|
11
|
+
return (
|
|
12
|
+
<section className="max-w-2xl mx-auto px-6 sm:px-8 py-20 text-center">
|
|
13
|
+
<p className="text-[11px] font-mono uppercase tracking-[0.16em] text-primary mb-3">
|
|
14
|
+
404
|
|
15
|
+
</p>
|
|
16
|
+
<h1 className="text-[clamp(2.5rem,5vw,4rem)] font-bold mb-4 -tracking-[0.03em]">
|
|
17
|
+
Page not found.
|
|
18
|
+
</h1>
|
|
19
|
+
<p className="text-muted-foreground leading-relaxed mb-8">
|
|
20
|
+
The URL you followed might be old, a typo, or pointing at a product
|
|
21
|
+
that's no longer in stock. Try the menu or head back home.
|
|
22
|
+
</p>
|
|
23
|
+
<div className="flex flex-wrap items-center justify-center gap-3">
|
|
24
|
+
<Link
|
|
25
|
+
href="/shop"
|
|
26
|
+
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"
|
|
27
|
+
>
|
|
28
|
+
Browse the shop
|
|
29
|
+
</Link>
|
|
30
|
+
<Link
|
|
31
|
+
href="/"
|
|
32
|
+
className="inline-flex items-center gap-2 px-5 py-2.5 rounded-md border border-border hover:bg-muted transition-colors text-sm font-medium"
|
|
33
|
+
>
|
|
34
|
+
Back home
|
|
35
|
+
</Link>
|
|
36
|
+
</div>
|
|
37
|
+
</section>
|
|
38
|
+
);
|
|
39
|
+
}
|