Add Container component and fix radius/maxWidth theming

- Drop buttonRadius prop; button now uses --radius via rounded-md
- Inject @theme radius mappings into ThemeProvider so rounded-* utilities
  pick up --radius inside the Tailwind CDN iframe
- Add shared Container that consumes --container-max-width set from the
  global maxWidth prop, replacing ad-hoc "container mx-auto max-w-7xl px-6"
  wrappers across commerce, landing, footer, navigation, and others
- Simplify maxWidth options to Small/Medium/Large/X-Large/Full bleed and
  shift the scale up so Large (1280px) matches the previous default

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Rami Bitar
2026-05-10 12:25:13 -04:00
parent 3a3d0a6ac8
commit 383a593c42
19 changed files with 92 additions and 65 deletions

View File

@@ -14,9 +14,8 @@ export type ThemeProps = {
mutedForegroundColor?: string; mutedForegroundColor?: string;
borderColor?: string; borderColor?: string;
radius?: "none" | "sm" | "md" | "lg" | "xl"; radius?: "none" | "sm" | "md" | "lg" | "xl";
buttonRadius?: "none" | "sm" | "md" | "lg" | "xl";
shadow?: "none" | "sm" | "md" | "lg" | "xl"; shadow?: "none" | "sm" | "md" | "lg" | "xl";
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full"; maxWidth?: "sm" | "md" | "lg" | "xl" | "full";
}; };
const radiusMap: Record<NonNullable<ThemeProps["radius"]>, string> = { const radiusMap: Record<NonNullable<ThemeProps["radius"]>, string> = {
@@ -27,12 +26,12 @@ const radiusMap: Record<NonNullable<ThemeProps["radius"]>, string> = {
xl: "1rem", xl: "1rem",
}; };
const buttonRadiusMap: Record<NonNullable<ThemeProps["buttonRadius"]>, string> = { const maxWidthMap: Record<NonNullable<ThemeProps["maxWidth"]>, string> = {
none: "0px", sm: "64rem",
sm: "0.25rem", md: "72rem",
md: "0.5rem", lg: "80rem",
lg: "0.75rem", xl: "96rem",
xl: "1rem", full: "100%",
}; };
const shadowMap: Record<NonNullable<ThemeProps["shadow"]>, string> = { const shadowMap: Record<NonNullable<ThemeProps["shadow"]>, string> = {
@@ -67,8 +66,8 @@ export function ThemeProvider({
mutedForegroundColor, mutedForegroundColor,
borderColor, borderColor,
radius, radius,
buttonRadius,
shadow, shadow,
maxWidth,
children, children,
}: ThemeProps & { children?: React.ReactNode }) { }: ThemeProps & { children?: React.ReactNode }) {
// Recompute CSS-variable map only when a relevant prop changes. // Recompute CSS-variable map only when a relevant prop changes.
@@ -84,8 +83,8 @@ export function ThemeProvider({
if (mutedForegroundColor) vars["--muted-foreground"] = mutedForegroundColor; if (mutedForegroundColor) vars["--muted-foreground"] = mutedForegroundColor;
if (borderColor) vars["--border"] = borderColor; if (borderColor) vars["--border"] = borderColor;
if (radius) vars["--radius"] = radiusMap[radius]; if (radius) vars["--radius"] = radiusMap[radius];
if (buttonRadius) vars["--button-radius"] = buttonRadiusMap[buttonRadius];
if (shadow) vars["--shadow"] = shadowMap[shadow]; if (shadow) vars["--shadow"] = shadowMap[shadow];
if (maxWidth) vars["--container-max-width"] = maxWidthMap[maxWidth];
if (headerFont) vars["--font-header"] = `"${headerFont}", system-ui, sans-serif`; if (headerFont) vars["--font-header"] = `"${headerFont}", system-ui, sans-serif`;
if (bodyFont) vars["--font-body"] = `"${bodyFont}", system-ui, sans-serif`; if (bodyFont) vars["--font-body"] = `"${bodyFont}", system-ui, sans-serif`;
return vars; return vars;
@@ -102,8 +101,8 @@ export function ThemeProvider({
mutedForegroundColor, mutedForegroundColor,
borderColor, borderColor,
radius, radius,
buttonRadius,
shadow, shadow,
maxWidth,
]); ]);
// Imperatively push every CSS var onto :root inside the host document // Imperatively push every CSS var onto :root inside the host document
@@ -157,6 +156,12 @@ export function ThemeProvider({
@theme { @theme {
--font-family-heading: var(--font-header), system-ui, -apple-system, sans-serif; --font-family-heading: var(--font-header), system-ui, -apple-system, sans-serif;
--font-family-body: var(--font-body), system-ui, -apple-system, sans-serif; --font-family-body: var(--font-body), system-ui, -apple-system, sans-serif;
--radius-sm: calc(var(--radius) * 0.5);
--radius-md: calc(var(--radius) * 0.75);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.5);
--radius-2xl: calc(var(--radius) * 2);
--radius-3xl: calc(var(--radius) * 3);
} }
`; `;

View File

@@ -3,6 +3,7 @@ import { Link } from "react-router";
import { shopifyFetch } from "@/services/shopify/client"; import { shopifyFetch } from "@/services/shopify/client";
import { GET_COLLECTIONS_QUERY } from "@/graphql/collections"; import { GET_COLLECTIONS_QUERY } from "@/graphql/collections";
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Container } from "@/components/layout/Container";
export type CollectionGridProps = { export type CollectionGridProps = {
tagline: string; tagline: string;
@@ -45,7 +46,7 @@ export function CollectionGrid({
return ( return (
<section className="bg-background py-20 md:py-28"> <section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-7xl px-6"> <Container>
<div className="mx-auto mb-12 max-w-2xl text-center"> <div className="mx-auto mb-12 max-w-2xl text-center">
{tagline ? ( {tagline ? (
<p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground"> <p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground">
@@ -110,7 +111,7 @@ export function CollectionGrid({
</Link> </Link>
))} ))}
</div> </div>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -13,6 +13,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select'; import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, SheetFooter } from '@/components/ui/sheet'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, SheetFooter } from '@/components/ui/sheet';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Container } from '@/components/layout/Container';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
type FilterOption = { label: string }; type FilterOption = { label: string };
@@ -425,7 +426,7 @@ export function CollectionView(props: CollectionProps) {
if (!selected && !paramHandle) { if (!selected && !paramHandle) {
return ( return (
<section className="bg-background pb-24 pt-12 md:pt-20"> <section className="bg-background pb-24 pt-12 md:pt-20">
<div className="container mx-auto max-w-7xl px-6"> <Container>
<header className="mx-auto mb-14 flex max-w-2xl flex-col items-center gap-3 text-center"> <header className="mx-auto mb-14 flex max-w-2xl flex-col items-center gap-3 text-center">
<Skeleton className="h-3 w-24" /> <Skeleton className="h-3 w-24" />
<Skeleton className="h-10 w-3/4" /> <Skeleton className="h-10 w-3/4" />
@@ -435,14 +436,14 @@ export function CollectionView(props: CollectionProps) {
<Skeleton key={i} className="aspect-[4/5] w-full" /> <Skeleton key={i} className="aspect-[4/5] w-full" />
))} ))}
</div> </div>
</div> </Container>
</section> </section>
); );
} }
return ( return (
<section className="bg-background pb-24 pt-12 md:pt-20"> <section className="bg-background pb-24 pt-12 md:pt-20">
<div className="container mx-auto max-w-7xl px-6"> <Container>
{/* Cover image */} {/* Cover image */}
{showCoverImage === 'yes' && collectionImage && ( {showCoverImage === 'yes' && collectionImage && (
<div className="mb-10 overflow-hidden rounded-lg"> <div className="mb-10 overflow-hidden rounded-lg">
@@ -545,7 +546,7 @@ export function CollectionView(props: CollectionProps) {
</button> </button>
</div> </div>
)} )}
</div> </Container>
</section> </section>
); );
} }

View File

@@ -4,6 +4,7 @@ import { useProduct } from "@/hooks/use-shopify-products";
import { useShopifyCart } from "@/hooks/use-shopify-cart"; import { useShopifyCart } from "@/hooks/use-shopify-cart";
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { Container } from "@/components/layout/Container";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
export type FeaturedProductProps = { export type FeaturedProductProps = {
@@ -33,7 +34,7 @@ export function FeaturedProductView({
tone === "muted" ? "bg-muted/40" : "bg-background", tone === "muted" ? "bg-muted/40" : "bg-background",
)} )}
> >
<div className="container mx-auto grid max-w-7xl grid-cols-1 items-center gap-10 px-6 md:grid-cols-2 md:gap-16"> <Container className="grid grid-cols-1 items-center gap-10 md:grid-cols-2 md:gap-16">
<div className={cn(align === "right" && "md:order-2")}> <div className={cn(align === "right" && "md:order-2")}>
<Skeleton className="aspect-[4/5] w-full" /> <Skeleton className="aspect-[4/5] w-full" />
</div> </div>
@@ -51,7 +52,7 @@ export function FeaturedProductView({
<Skeleton className="h-11 w-32 rounded-md" /> <Skeleton className="h-11 w-32 rounded-md" />
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
); );
} }
@@ -75,7 +76,7 @@ export function FeaturedProductView({
: "bg-background py-20 md:py-28" : "bg-background py-20 md:py-28"
} }
> >
<div className="container mx-auto grid max-w-7xl grid-cols-1 items-center gap-10 px-6 md:grid-cols-2 md:gap-16"> <Container className="grid grid-cols-1 items-center gap-10 md:grid-cols-2 md:gap-16">
<div className={align === "right" ? "md:order-2" : ""}> <div className={align === "right" ? "md:order-2" : ""}>
{image ? ( {image ? (
<img <img
@@ -123,7 +124,7 @@ export function FeaturedProductView({
</Link> </Link>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -7,6 +7,7 @@ import { Typography } from "@/components/Typography";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { Loader } from "@/components/ui/loader"; import { Loader } from "@/components/ui/loader";
import { Container } from "@/components/layout/Container";
export type ProductDetailsProps = { export type ProductDetailsProps = {
product: ShopifyProduct | null; product: ShopifyProduct | null;
@@ -31,7 +32,7 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
if (!handle || loading || !product) { if (!handle || loading || !product) {
return ( return (
<section className="bg-background py-12 md:py-20"> <section className="bg-background py-12 md:py-20">
<div className="container mx-auto grid max-w-7xl grid-cols-1 gap-10 px-6 md:grid-cols-2 md:gap-16"> <Container className="grid grid-cols-1 gap-10 md:grid-cols-2 md:gap-16">
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<Skeleton className="aspect-[4/5] w-full" /> <Skeleton className="aspect-[4/5] w-full" />
<div className="flex gap-3"> <div className="flex gap-3">
@@ -62,7 +63,7 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
<Skeleton className="h-4 w-4/6" /> <Skeleton className="h-4 w-4/6" />
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
); );
} }
@@ -90,7 +91,7 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
return ( return (
<section className="bg-background py-12 md:py-20"> <section className="bg-background py-12 md:py-20">
<div className="container mx-auto grid max-w-7xl grid-cols-1 gap-10 px-6 md:grid-cols-2 md:gap-16"> <Container className="grid grid-cols-1 gap-10 md:grid-cols-2 md:gap-16">
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">
<div className="aspect-[4/5] w-full overflow-hidden rounded-md bg-muted"> <div className="aspect-[4/5] w-full overflow-hidden rounded-md bg-muted">
{main ? ( {main ? (
@@ -214,7 +215,7 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
</div> </div>
) : null} ) : null}
</div> </div>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -12,6 +12,7 @@ import {
CarouselNext, CarouselNext,
CarouselPrevious, CarouselPrevious,
} from "@/components/ui/carousel"; } from "@/components/ui/carousel";
import { Container } from "@/components/layout/Container";
export type ProductsCarouselProps = { export type ProductsCarouselProps = {
collection: ShopifyCollection | null; collection: ShopifyCollection | null;
@@ -71,7 +72,7 @@ export function ProductsCarousel({
return ( return (
<section className="bg-background py-20 md:py-28"> <section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-7xl px-6"> <Container>
<div className="mb-10 flex flex-col gap-6 md:flex-row md:items-end md:justify-between"> <div className="mb-10 flex flex-col gap-6 md:flex-row md:items-end md:justify-between">
<div className="max-w-xl"> <div className="max-w-xl">
{tagline ? ( {tagline ? (
@@ -120,7 +121,7 @@ export function ProductsCarousel({
<CarouselPrevious className="hidden md:inline-flex" /> <CarouselPrevious className="hidden md:inline-flex" />
<CarouselNext className="hidden md:inline-flex" /> <CarouselNext className="hidden md:inline-flex" />
</Carousel> </Carousel>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -5,6 +5,7 @@ import { getProducts } from "@/hooks/use-shopify-products";
import { getCollectionProducts } from "@/hooks/use-shopify-collections"; import { getCollectionProducts } from "@/hooks/use-shopify-collections";
import { ProductCard } from "./product-card"; import { ProductCard } from "./product-card";
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Container } from "@/components/layout/Container";
export type ProductsGridProps = { export type ProductsGridProps = {
collection: ShopifyCollection | null; collection: ShopifyCollection | null;
@@ -59,7 +60,7 @@ export function ProductsGrid({
return ( return (
<section className="bg-background py-20 md:py-28"> <section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-7xl px-6"> <Container>
<div className="mb-12 flex flex-col items-end justify-between gap-6 md:flex-row md:items-end"> <div className="mb-12 flex flex-col items-end justify-between gap-6 md:flex-row md:items-end">
<div className="max-w-xl"> <div className="max-w-xl">
{tagline ? ( {tagline ? (
@@ -94,7 +95,7 @@ export function ProductsGrid({
)) ))
: products.map((p) => <ProductCard key={p.id} product={p} />)} : products.map((p) => <ProductCard key={p.id} product={p} />)}
</div> </div>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -6,6 +6,7 @@ import {
import { ProductCard } from "./product-card"; import { ProductCard } from "./product-card";
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { Container } from "@/components/layout/Container";
export type RecommendedProductsProps = { export type RecommendedProductsProps = {
product: ShopifyProduct | null; product: ShopifyProduct | null;
@@ -27,7 +28,7 @@ export function RecommendedProductsView({
if (!selected) { if (!selected) {
return ( return (
<section className="bg-background py-20 md:py-28"> <section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-7xl px-6"> <Container>
<div className="mb-12 flex max-w-xl flex-col gap-3"> <div className="mb-12 flex max-w-xl flex-col gap-3">
{tagline ? <Skeleton className="h-3 w-24" /> : null} {tagline ? <Skeleton className="h-3 w-24" /> : null}
<Skeleton className="h-8 w-2/3" /> <Skeleton className="h-8 w-2/3" />
@@ -37,14 +38,14 @@ export function RecommendedProductsView({
<Skeleton key={i} className="aspect-[4/5] w-full" /> <Skeleton key={i} className="aspect-[4/5] w-full" />
))} ))}
</div> </div>
</div> </Container>
</section> </section>
); );
} }
return ( return (
<section className="bg-background py-20 md:py-28"> <section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-7xl px-6"> <Container>
<div className="mb-12 max-w-xl"> <div className="mb-12 max-w-xl">
{tagline ? ( {tagline ? (
<p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground"> <p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground">
@@ -61,7 +62,7 @@ export function RecommendedProductsView({
)) ))
: items.map((p: any) => <ProductCard key={p.id} product={p} />)} : items.map((p: any) => <ProductCard key={p.id} product={p} />)}
</div> </div>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -8,6 +8,7 @@ import { Skeleton } from '@/components/ui/skeleton';
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select'; import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, SheetFooter } from '@/components/ui/sheet'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger, SheetFooter } from '@/components/ui/sheet';
import { Container } from '@/components/layout/Container';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
type FilterOption = { label: string }; type FilterOption = { label: string };
@@ -397,7 +398,7 @@ export function SearchProductsView(props: SearchProductsProps) {
return ( return (
<section className="bg-background py-12 md:py-16"> <section className="bg-background py-12 md:py-16">
<div className="container mx-auto max-w-7xl px-6"> <Container>
{/* Page header */} {/* Page header */}
<div className="mb-10"> <div className="mb-10">
@@ -523,7 +524,7 @@ export function SearchProductsView(props: SearchProductsProps) {
</button> </button>
</div> </div>
)} )}
</div> </Container>
</section> </section>
); );
} }

View File

@@ -1,4 +1,5 @@
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Container } from "@/components/layout/Container";
export type FeaturesProps = { export type FeaturesProps = {
tagline: string; tagline: string;
@@ -17,7 +18,7 @@ const colClass: Record<FeaturesProps["columns"], string> = {
export function Features({ tagline, heading, subheading, columns, items }: FeaturesProps) { export function Features({ tagline, heading, subheading, columns, items }: FeaturesProps) {
return ( return (
<section className="bg-background py-20 md:py-28"> <section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-7xl px-6"> <Container>
<div className="mx-auto mb-16 max-w-2xl text-center"> <div className="mx-auto mb-16 max-w-2xl text-center">
{tagline ? ( {tagline ? (
<p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground"> <p className="mb-3 text-xs uppercase tracking-[0.2em] text-muted-foreground">
@@ -45,7 +46,7 @@ export function Features({ tagline, heading, subheading, columns, items }: Featu
</div> </div>
))} ))}
</div> </div>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -1,6 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { Link } from "react-router"; import { Link } from "react-router";
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Container } from "@/components/layout/Container";
export type FooterProps = { export type FooterProps = {
brand: string; brand: string;
@@ -45,7 +46,7 @@ export function Footer({
return ( return (
<footer className="border-t border-border bg-background"> <footer className="border-t border-border bg-background">
<div className="container mx-auto max-w-7xl px-6 py-20 md:py-24"> <Container className="py-20 md:py-24">
<div className="grid grid-cols-1 gap-12 md:grid-cols-12"> <div className="grid grid-cols-1 gap-12 md:grid-cols-12">
<div className="md:col-span-4"> <div className="md:col-span-4">
<Typography variant="h5" as="p"> <Typography variant="h5" as="p">
@@ -123,7 +124,7 @@ export function Footer({
))} ))}
</div> </div>
</div> </div>
</div> </Container>
</footer> </footer>
); );
} }

View File

@@ -1,5 +1,6 @@
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Container } from "@/components/layout/Container";
export type ImageGalleryProps = { export type ImageGalleryProps = {
tagline: string; tagline: string;
@@ -12,7 +13,7 @@ export type ImageGalleryProps = {
export function ImageGallery({ tagline, heading, subheading, layout, items }: ImageGalleryProps) { export function ImageGallery({ tagline, heading, subheading, layout, items }: ImageGalleryProps) {
return ( return (
<section className="bg-background py-20 md:py-28"> <section className="bg-background py-20 md:py-28">
<div className="container mx-auto max-w-7xl px-6"> <Container>
{(tagline || heading || subheading) && ( {(tagline || heading || subheading) && (
<div className="mx-auto mb-12 max-w-2xl text-center"> <div className="mx-auto mb-12 max-w-2xl text-center">
{tagline ? ( {tagline ? (
@@ -86,7 +87,7 @@ export function ImageGallery({ tagline, heading, subheading, layout, items }: Im
))} ))}
</div> </div>
)} )}
</div> </Container>
</section> </section>
); );
} }

View File

@@ -1,6 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Typography } from "@/components/Typography"; import { Typography } from "@/components/Typography";
import { Container } from "@/components/layout/Container";
export type EmailProvider = "none" | "mailchimp" | "klaviyo"; export type EmailProvider = "none" | "mailchimp" | "klaviyo";
@@ -131,7 +132,7 @@ export function NewsletterCta({
if (layout === "split") { if (layout === "split") {
return ( return (
<section className="bg-background"> <section className="bg-background">
<div className="container mx-auto max-w-7xl px-6 py-16 md:py-24"> <Container className="py-16 md:py-24">
<div className="grid grid-cols-1 items-center gap-12 md:grid-cols-2"> <div className="grid grid-cols-1 items-center gap-12 md:grid-cols-2">
<div> <div>
{imageUrl ? ( {imageUrl ? (
@@ -165,7 +166,7 @@ export function NewsletterCta({
</div> </div>
</div> </div>
</div> </div>
</div> </Container>
</section> </section>
); );
} }

View File

@@ -0,0 +1,21 @@
import * as React from "react";
import { cn } from "@/lib/utils";
export type ContainerProps = React.HTMLAttributes<HTMLElement> & {
as?: React.ElementType;
};
export function Container({
as: Comp = "div",
className,
style,
...props
}: ContainerProps) {
return (
<Comp
className={cn("mx-auto w-full px-6", className)}
style={{ maxWidth: "var(--container-max-width, 80rem)", ...style }}
{...props}
/>
);
}

View File

@@ -1,3 +1,5 @@
import { Container } from "@/components/layout/Container";
export type LogosProps = { export type LogosProps = {
tagline: string; tagline: string;
items: Array<{ src: string; alt: string }>; items: Array<{ src: string; alt: string }>;
@@ -7,7 +9,7 @@ export type LogosProps = {
export function Logos({ tagline, items, layout }: LogosProps) { export function Logos({ tagline, items, layout }: LogosProps) {
return ( return (
<section className="border-y border-border bg-muted/40 py-12"> <section className="border-y border-border bg-muted/40 py-12">
<div className="container mx-auto max-w-7xl px-6"> <Container>
{tagline ? ( {tagline ? (
<p className="mb-8 text-center text-xs uppercase tracking-[0.2em] text-muted-foreground"> <p className="mb-8 text-center text-xs uppercase tracking-[0.2em] text-muted-foreground">
{tagline} {tagline}
@@ -38,7 +40,7 @@ export function Logos({ tagline, items, layout }: LogosProps) {
))} ))}
</div> </div>
)} )}
</div> </Container>
</section> </section>
); );
} }

View File

@@ -3,6 +3,7 @@ import { useState } from "react";
import { Link } from "react-router"; import { Link } from "react-router";
import { useShopifyCart } from "@/hooks/use-shopify-cart"; import { useShopifyCart } from "@/hooks/use-shopify-cart";
import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet"; import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet";
import { Container } from "@/components/layout/Container";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
export type NavigationProps = { export type NavigationProps = {
@@ -49,7 +50,7 @@ export function Navigation({
toneClass[tone], toneClass[tone],
)} )}
> >
<div className="container mx-auto flex h-16 max-w-7xl items-center justify-between px-6 md:h-20"> <Container className="flex h-16 items-center justify-between md:h-20">
<Link <Link
to="/" to="/"
className="inline-flex items-center font-semibold tracking-tight" className="inline-flex items-center font-semibold tracking-tight"
@@ -110,7 +111,7 @@ export function Navigation({
<MenuIcon size={20} strokeWidth={1.5} /> <MenuIcon size={20} strokeWidth={1.5} />
</button> </button>
</div> </div>
</div> </Container>
</header> </header>
</div> </div>

View File

@@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--radius-button)] text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring", "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:ring-2 focus-visible:ring-ring",
{ {
variants: { variants: {
variant: { variant: {

View File

@@ -32,9 +32,8 @@ export const Root: RootConfig<{
fgColor: "#0a0a0a", fgColor: "#0a0a0a",
mutedColor: "#f5f5f5", mutedColor: "#f5f5f5",
radius: "md", radius: "md",
buttonRadius: "md",
shadow: "sm", shadow: "sm",
maxWidth: "xl", maxWidth: "lg",
}, },
fields: { fields: {
title: { label: "Page title", type: "text" }, title: { label: "Page title", type: "text" },
@@ -59,17 +58,6 @@ export const Root: RootConfig<{
{ label: "Extra large", value: "xl" }, { label: "Extra large", value: "xl" },
], ],
}, },
buttonRadius: {
label: "Button radius",
type: "select",
options: [
{ label: "None (square)", value: "none" },
{ label: "Small", value: "sm" },
{ label: "Medium", value: "md" },
{ label: "Large", value: "lg" },
{ label: "Extra large", value: "xl" },
],
},
shadow: { shadow: {
label: "Shadow", label: "Shadow",
type: "select", type: "select",
@@ -89,7 +77,6 @@ export const Root: RootConfig<{
{ label: "Medium", value: "md" }, { label: "Medium", value: "md" },
{ label: "Large", value: "lg" }, { label: "Large", value: "lg" },
{ label: "Extra large", value: "xl" }, { label: "Extra large", value: "xl" },
{ label: "2X large", value: "2xl" },
{ label: "Full bleed", value: "full" }, { label: "Full bleed", value: "full" },
], ],
}, },
@@ -105,8 +92,8 @@ export const Root: RootConfig<{
fgColor, fgColor,
mutedColor, mutedColor,
radius, radius,
buttonRadius,
shadow, shadow,
maxWidth,
}) => { }) => {
return ( return (
<ThemeProvider <ThemeProvider
@@ -119,8 +106,8 @@ export const Root: RootConfig<{
fgColor={fgColor} fgColor={fgColor}
mutedColor={mutedColor} mutedColor={mutedColor}
radius={radius} radius={radius}
buttonRadius={buttonRadius}
shadow={shadow} shadow={shadow}
maxWidth={maxWidth}
> >
{children} {children}
</ThemeProvider> </ThemeProvider>

View File

@@ -32,7 +32,6 @@
--radius-md: calc(var(--radius) * 0.75); --radius-md: calc(var(--radius) * 0.75);
--radius-lg: var(--radius); --radius-lg: var(--radius);
--radius-xl: calc(var(--radius) * 1.5); --radius-xl: calc(var(--radius) * 1.5);
--radius-button: var(--button-radius, var(--radius));
--animate-marquee: marquee var(--duration) infinite linear; --animate-marquee: marquee var(--duration) infinite linear;
--animate-marquee-vertical: marquee-vertical var(--duration) linear infinite; --animate-marquee-vertical: marquee-vertical var(--duration) linear infinite;