Consolidate theme radius/shadow props and make rounded utilities responsive

- Remove duplicate roundedness/shadowLevel props (keep radius/shadow)
- Switch globals.css radius scale to proportional (square→pill works)
- Replace rounded-full with rounded-md on theme-driven elements
- Remove banner props from Navigation, drop publishing overlay

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Rami Bitar
2026-05-08 10:01:55 -04:00
parent f0323c2c57
commit 564c98c805
11 changed files with 34 additions and 128 deletions

View File

@@ -13,14 +13,12 @@ export type ThemeProps = {
mutedColor?: string;
mutedForegroundColor?: string;
borderColor?: string;
roundedness?: "none" | "sm" | "md" | "lg" | "xl" | "full";
radius?: "none" | "xs" | "sm" | "md" | "lg";
shadowLevel?: "none" | "sm" | "md" | "lg" | "xl";
shadow?: "none" | "sm" | "md" | "lg";
radius?: "none" | "sm" | "md" | "lg" | "xl" | "full";
shadow?: "none" | "sm" | "md" | "lg" | "xl";
maxWidth?: "sm" | "md" | "lg" | "xl" | "2xl" | "full";
};
const radiusMap: Record<NonNullable<ThemeProps["roundedness"]>, string> = {
const radiusMap: Record<NonNullable<ThemeProps["radius"]>, string> = {
none: "0px",
sm: "0.25rem",
md: "0.5rem",
@@ -29,15 +27,7 @@ const radiusMap: Record<NonNullable<ThemeProps["roundedness"]>, string> = {
full: "9999px",
};
const radiusEnumMap: Record<NonNullable<ThemeProps["radius"]>, string> = {
none: "0px",
xs: "0.125rem",
sm: "0.25rem",
md: "0.5rem",
lg: "0.75rem",
};
const shadowMap: Record<NonNullable<ThemeProps["shadowLevel"]>, string> = {
const shadowMap: Record<NonNullable<ThemeProps["shadow"]>, string> = {
none: "0 0 #0000",
sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
md: "0 4px 6px -1px rgb(0 0 0 / 0.10), 0 2px 4px -2px rgb(0 0 0 / 0.10)",
@@ -45,13 +35,6 @@ const shadowMap: Record<NonNullable<ThemeProps["shadowLevel"]>, string> = {
xl: "0 20px 25px -5px rgb(0 0 0 / 0.10), 0 8px 10px -6px rgb(0 0 0 / 0.10)",
};
const shadowEnumMap: Record<NonNullable<ThemeProps["shadow"]>, string> = {
none: "0 0 #0000",
sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
md: "0 4px 6px -1px rgb(0 0 0 / 0.10), 0 2px 4px -2px rgb(0 0 0 / 0.10)",
lg: "0 10px 15px -3px rgb(0 0 0 / 0.10), 0 4px 6px -4px rgb(0 0 0 / 0.10)",
};
function googleFontsHref(headerFont?: string, bodyFont?: string): string | null {
const fonts = [headerFont, bodyFont].filter(
(f): f is string => !!f && f !== "system-ui"
@@ -75,9 +58,7 @@ export function ThemeProvider({
mutedColor,
mutedForegroundColor,
borderColor,
roundedness,
radius,
shadowLevel,
shadow,
children,
}: ThemeProps & { children?: React.ReactNode }) {
@@ -93,10 +74,8 @@ export function ThemeProvider({
if (mutedColor) vars["--muted"] = mutedColor;
if (mutedForegroundColor) vars["--muted-foreground"] = mutedForegroundColor;
if (borderColor) vars["--border"] = borderColor;
if (radius) vars["--radius"] = radiusEnumMap[radius];
else if (roundedness) vars["--radius"] = radiusMap[roundedness];
if (shadow) vars["--shadow"] = shadowEnumMap[shadow];
else if (shadowLevel) vars["--shadow"] = shadowMap[shadowLevel];
if (radius) vars["--radius"] = radiusMap[radius];
if (shadow) vars["--shadow"] = shadowMap[shadow];
if (headerFont) vars["--font-header"] = `"${headerFont}", system-ui, sans-serif`;
if (bodyFont) vars["--font-body"] = `"${bodyFont}", system-ui, sans-serif`;
return vars;
@@ -112,9 +91,7 @@ export function ThemeProvider({
mutedColor,
mutedForegroundColor,
borderColor,
roundedness,
radius,
shadowLevel,
shadow,
]);

View File

@@ -47,8 +47,8 @@ export function FeaturedProductView({
<Skeleton className="h-4 w-4/6" />
</div>
<div className="mt-2 flex flex-wrap gap-3">
<Skeleton className="h-11 w-32 rounded-full" />
<Skeleton className="h-11 w-32 rounded-full" />
<Skeleton className="h-11 w-32 rounded-md" />
<Skeleton className="h-11 w-32 rounded-md" />
</div>
</div>
</div>
@@ -111,13 +111,13 @@ export function FeaturedProductView({
await cart.addItem(variant.id, 1);
cart.openCart();
}}
className="inline-flex items-center justify-center rounded-full bg-foreground px-6 py-3 text-sm font-medium tracking-wide text-background hover:opacity-90"
className="inline-flex items-center justify-center rounded-md bg-foreground px-6 py-3 text-sm font-medium tracking-wide text-background hover:opacity-90"
>
{ctaLabel}
</button>
<Link
to={`/products/${product.handle}`}
className="inline-flex items-center justify-center rounded-full border border-foreground px-6 py-3 text-sm font-medium tracking-wide hover:opacity-80"
className="inline-flex items-center justify-center rounded-md border border-foreground px-6 py-3 text-sm font-medium tracking-wide hover:opacity-80"
>
View details
</Link>

View File

@@ -46,14 +46,14 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
<div className="flex flex-col gap-3">
<Skeleton className="h-3 w-16" />
<div className="flex gap-2">
<Skeleton className="h-10 w-16 rounded-full" />
<Skeleton className="h-10 w-16 rounded-full" />
<Skeleton className="h-10 w-16 rounded-full" />
<Skeleton className="h-10 w-16 rounded-md" />
<Skeleton className="h-10 w-16 rounded-md" />
<Skeleton className="h-10 w-16 rounded-md" />
</div>
</div>
<div className="flex items-center gap-4 pt-2">
<Skeleton className="h-11 w-32 rounded-full" />
<Skeleton className="h-11 flex-1 rounded-full" />
<Skeleton className="h-11 w-32 rounded-md" />
<Skeleton className="h-11 flex-1 rounded-md" />
</div>
<div className="space-y-2 border-t border-border pt-6">
<Skeleton className="h-3 w-20" />
@@ -157,7 +157,7 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
key={val}
onClick={() => matching && setVariant(matching.node)}
className={cn(
"min-w-12 rounded-full border px-4 py-2 text-sm transition-colors",
"min-w-12 rounded-md border px-4 py-2 text-sm transition-colors",
selected
? "border-foreground bg-foreground text-background"
: "border-border hover:border-foreground",
@@ -172,7 +172,7 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
))}
<div className="flex items-center gap-4 pt-2">
<div className="flex items-center gap-3 rounded-full border border-border px-4 py-2">
<div className="flex items-center gap-3 rounded-md border border-border px-4 py-2">
<button
onClick={() => setQuantity((q) => Math.max(1, q - 1))}
className="text-base hover:opacity-60"
@@ -190,7 +190,7 @@ export function ProductDetailsView({ product: selected }: ProductDetailsProps) {
<button
onClick={onAdd}
disabled={!variant || adding}
className="flex-1 rounded-full bg-foreground px-6 py-3 text-sm font-medium tracking-wide text-background transition-opacity hover:opacity-90 disabled:opacity-50"
className="flex-1 rounded-md bg-foreground px-6 py-3 text-sm font-medium tracking-wide text-background transition-opacity hover:opacity-90 disabled:opacity-50"
>
{adding ? (
<span className="flex items-center justify-center gap-2">

View File

@@ -63,7 +63,7 @@ export function CTA({
{primaryCta?.label ? (
<Link
to={primaryCta.href || "#"}
className="inline-flex items-center justify-center rounded-full bg-white px-6 py-3 text-sm font-medium tracking-wide text-black hover:opacity-90"
className="inline-flex items-center justify-center rounded-md bg-white px-6 py-3 text-sm font-medium tracking-wide text-black hover:opacity-90"
>
{primaryCta.label}
</Link>
@@ -71,7 +71,7 @@ export function CTA({
{secondaryCta?.label ? (
<Link
to={secondaryCta.href || "#"}
className="inline-flex items-center justify-center rounded-full border border-white px-6 py-3 text-sm font-medium tracking-wide text-white hover:bg-white/10"
className="inline-flex items-center justify-center rounded-md border border-white px-6 py-3 text-sm font-medium tracking-wide text-white hover:bg-white/10"
>
{secondaryCta.label}
</Link>

View File

@@ -97,7 +97,7 @@ export function Hero({
<Link
to={primaryCta.href || "#"}
className={cn(
"inline-flex items-center justify-center rounded-full px-6 py-3 text-sm font-medium tracking-wide transition-opacity hover:opacity-90",
"inline-flex items-center justify-center rounded-md px-6 py-3 text-sm font-medium tracking-wide transition-opacity hover:opacity-90",
isDark ? "bg-white text-black" : "bg-foreground text-background",
)}
>
@@ -108,7 +108,7 @@ export function Hero({
<Link
to={secondaryCta.href || "#"}
className={cn(
"inline-flex items-center justify-center rounded-full border px-6 py-3 text-sm font-medium tracking-wide transition-opacity hover:opacity-80",
"inline-flex items-center justify-center rounded-md border px-6 py-3 text-sm font-medium tracking-wide transition-opacity hover:opacity-80",
isDark ? "border-white text-white" : "border-foreground text-foreground",
)}
>

View File

@@ -22,8 +22,6 @@ export const navigationEditor: ComponentConfig<NavigationProps> = {
showCart: "yes",
sticky: "yes",
tone: "default",
bannerText: "",
bannerTone: "accent",
},
fields: {
brand: { label: "Brand", type: "text", contentEditable: true },
@@ -38,20 +36,6 @@ export const navigationEditor: ComponentConfig<NavigationProps> = {
href: { label: "Link", type: "text" },
},
},
bannerText: {
label: "Banner text",
type: "text",
contentEditable: true,
},
bannerTone: {
label: "Banner tone",
type: "select",
options: [
{ label: "Default", value: "default" },
{ label: "Accent", value: "accent" },
{ label: "Inverse (dark)", value: "inverse" },
],
},
showSearch: {
label: "Search icon",
type: "radio",

View File

@@ -13,8 +13,6 @@ export type NavigationProps = {
showCart: "yes" | "no";
sticky: "yes" | "no";
tone: "default" | "muted" | "inverse";
bannerText: string;
bannerTone: "default" | "accent" | "inverse";
};
export function Navigation({
@@ -25,8 +23,6 @@ export function Navigation({
showCart,
sticky,
tone,
bannerText,
bannerTone,
}: NavigationProps) {
const [mobileOpen, setMobileOpen] = useState(false);
const cart = useShopifyCart();
@@ -38,14 +34,6 @@ export function Navigation({
inverse: "bg-foreground text-background",
};
const bannerToneClass: Record<NavigationProps["bannerTone"], string> = {
default: "bg-muted text-foreground",
accent: "bg-primary text-primary-foreground",
inverse: "bg-foreground text-background",
};
const hasBanner = typeof bannerText === "string" && bannerText.trim().length > 0;
return (
<>
<div
@@ -54,13 +42,6 @@ export function Navigation({
sticky === "yes" && "sticky top-0 z-40",
)}
>
{hasBanner && (
<div className={cn("w-full", bannerToneClass[bannerTone])}>
<div className="container mx-auto max-w-7xl px-6 py-2 text-center text-xs tracking-wide md:text-sm">
{bannerText}
</div>
</div>
)}
<header
className={cn(
"w-full",