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

@@ -11,9 +11,7 @@
"bgColor": "#ffffff", "bgColor": "#ffffff",
"fgColor": "#0a0a0a", "fgColor": "#0a0a0a",
"mutedColor": "#f5f5f5", "mutedColor": "#f5f5f5",
"roundedness": "md", "radius": "sm",
"radius": "md",
"shadowLevel": "sm",
"shadow": "sm", "shadow": "sm",
"maxWidth": "xl" "maxWidth": "xl"
} }
@@ -201,9 +199,7 @@
"bgColor": "#ffffff", "bgColor": "#ffffff",
"fgColor": "#0a0a0a", "fgColor": "#0a0a0a",
"mutedColor": "#f5f5f5", "mutedColor": "#f5f5f5",
"roundedness": "md", "radius": "sm",
"radius": "md",
"shadowLevel": "sm",
"shadow": "sm", "shadow": "sm",
"maxWidth": "xl" "maxWidth": "xl"
} }

View File

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

View File

@@ -47,8 +47,8 @@ export function FeaturedProductView({
<Skeleton className="h-4 w-4/6" /> <Skeleton className="h-4 w-4/6" />
</div> </div>
<div className="mt-2 flex flex-wrap gap-3"> <div className="mt-2 flex flex-wrap gap-3">
<Skeleton className="h-11 w-32 rounded-full" /> <Skeleton className="h-11 w-32 rounded-md" />
<Skeleton className="h-11 w-32 rounded-full" /> <Skeleton className="h-11 w-32 rounded-md" />
</div> </div>
</div> </div>
</div> </div>
@@ -111,13 +111,13 @@ export function FeaturedProductView({
await cart.addItem(variant.id, 1); await cart.addItem(variant.id, 1);
cart.openCart(); 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} {ctaLabel}
</button> </button>
<Link <Link
to={`/products/${product.handle}`} 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 View details
</Link> </Link>

View File

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

View File

@@ -63,7 +63,7 @@ export function CTA({
{primaryCta?.label ? ( {primaryCta?.label ? (
<Link <Link
to={primaryCta.href || "#"} 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} {primaryCta.label}
</Link> </Link>
@@ -71,7 +71,7 @@ export function CTA({
{secondaryCta?.label ? ( {secondaryCta?.label ? (
<Link <Link
to={secondaryCta.href || "#"} 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} {secondaryCta.label}
</Link> </Link>

View File

@@ -97,7 +97,7 @@ export function Hero({
<Link <Link
to={primaryCta.href || "#"} to={primaryCta.href || "#"}
className={cn( 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", isDark ? "bg-white text-black" : "bg-foreground text-background",
)} )}
> >
@@ -108,7 +108,7 @@ export function Hero({
<Link <Link
to={secondaryCta.href || "#"} to={secondaryCta.href || "#"}
className={cn( 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", isDark ? "border-white text-white" : "border-foreground text-foreground",
)} )}
> >

View File

@@ -22,8 +22,6 @@ export const navigationEditor: ComponentConfig<NavigationProps> = {
showCart: "yes", showCart: "yes",
sticky: "yes", sticky: "yes",
tone: "default", tone: "default",
bannerText: "",
bannerTone: "accent",
}, },
fields: { fields: {
brand: { label: "Brand", type: "text", contentEditable: true }, brand: { label: "Brand", type: "text", contentEditable: true },
@@ -38,20 +36,6 @@ export const navigationEditor: ComponentConfig<NavigationProps> = {
href: { label: "Link", type: "text" }, 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: { showSearch: {
label: "Search icon", label: "Search icon",
type: "radio", type: "radio",

View File

@@ -13,8 +13,6 @@ export type NavigationProps = {
showCart: "yes" | "no"; showCart: "yes" | "no";
sticky: "yes" | "no"; sticky: "yes" | "no";
tone: "default" | "muted" | "inverse"; tone: "default" | "muted" | "inverse";
bannerText: string;
bannerTone: "default" | "accent" | "inverse";
}; };
export function Navigation({ export function Navigation({
@@ -25,8 +23,6 @@ export function Navigation({
showCart, showCart,
sticky, sticky,
tone, tone,
bannerText,
bannerTone,
}: NavigationProps) { }: NavigationProps) {
const [mobileOpen, setMobileOpen] = useState(false); const [mobileOpen, setMobileOpen] = useState(false);
const cart = useShopifyCart(); const cart = useShopifyCart();
@@ -38,14 +34,6 @@ export function Navigation({
inverse: "bg-foreground text-background", 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 ( return (
<> <>
<div <div
@@ -54,13 +42,6 @@ export function Navigation({
sticky === "yes" && "sticky top-0 z-40", 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 <header
className={cn( className={cn(
"w-full", "w-full",

View File

@@ -31,9 +31,7 @@ export const Root: RootConfig<{
bgColor: "#ffffff", bgColor: "#ffffff",
fgColor: "#0a0a0a", fgColor: "#0a0a0a",
mutedColor: "#f5f5f5", mutedColor: "#f5f5f5",
roundedness: "md",
radius: "md", radius: "md",
shadowLevel: "sm",
shadow: "sm", shadow: "sm",
maxWidth: "xl", maxWidth: "xl",
}, },
@@ -49,11 +47,11 @@ export const Root: RootConfig<{
bgColor: { label: "Background color", type: "color", placeholder: "#ffffff" }, bgColor: { label: "Background color", type: "color", placeholder: "#ffffff" },
fgColor: { label: "Foreground color", type: "color", placeholder: "#0a0a0a" }, fgColor: { label: "Foreground color", type: "color", placeholder: "#0a0a0a" },
mutedColor: { label: "Muted color", type: "color", placeholder: "#f5f5f5" }, mutedColor: { label: "Muted color", type: "color", placeholder: "#f5f5f5" },
roundedness: { radius: {
label: "Roundedness", label: "Radius",
type: "select", type: "select",
options: [ options: [
{ label: "None", value: "none" }, { label: "None (square)", value: "none" },
{ label: "Small", value: "sm" }, { label: "Small", value: "sm" },
{ label: "Medium", value: "md" }, { label: "Medium", value: "md" },
{ label: "Large", value: "lg" }, { label: "Large", value: "lg" },
@@ -61,28 +59,6 @@ export const Root: RootConfig<{
{ label: "Full (pill)", value: "full" }, { label: "Full (pill)", value: "full" },
], ],
}, },
radius: {
label: "Radius",
type: "select",
options: [
{ label: "None", value: "none" },
{ label: "Extra small", value: "xs" },
{ label: "Small", value: "sm" },
{ label: "Medium", value: "md" },
{ label: "Large", value: "lg" },
],
},
shadowLevel: {
label: "Shadow level",
type: "select",
options: [
{ label: "None", 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",
@@ -91,6 +67,7 @@ export const Root: RootConfig<{
{ label: "Small", value: "sm" }, { label: "Small", value: "sm" },
{ label: "Medium", value: "md" }, { label: "Medium", value: "md" },
{ label: "Large", value: "lg" }, { label: "Large", value: "lg" },
{ label: "Extra large", value: "xl" },
], ],
}, },
maxWidth: { maxWidth: {
@@ -116,9 +93,7 @@ export const Root: RootConfig<{
bgColor, bgColor,
fgColor, fgColor,
mutedColor, mutedColor,
roundedness,
radius, radius,
shadowLevel,
shadow, shadow,
}) => { }) => {
return ( return (
@@ -131,9 +106,7 @@ export const Root: RootConfig<{
bgColor={bgColor} bgColor={bgColor}
fgColor={fgColor} fgColor={fgColor}
mutedColor={mutedColor} mutedColor={mutedColor}
roundedness={roundedness}
radius={radius} radius={radius}
shadowLevel={shadowLevel}
shadow={shadow} shadow={shadow}
> >
{children} {children}

View File

@@ -101,11 +101,6 @@ export default function App() {
}} }}
/> />
</ShopifyProvider> </ShopifyProvider>
{isPublishing && (
<div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/30">
<Loader size={32} />
</div>
)}
</div> </div>
); );
} }

View File

@@ -28,10 +28,10 @@
--color-input: var(--input); --color-input: var(--input);
--color-ring: var(--ring); --color-ring: var(--ring);
--radius-sm: calc(var(--radius) - 4px); --radius-sm: calc(var(--radius) * 0.5);
--radius-md: calc(var(--radius) - 2px); --radius-md: calc(var(--radius) * 0.75);
--radius-lg: var(--radius); --radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px); --radius-xl: calc(var(--radius) * 1.5);
--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;
@@ -59,9 +59,9 @@
--color-chart-3: var(--chart-3); --color-chart-3: var(--chart-3);
--color-chart-2: var(--chart-2); --color-chart-2: var(--chart-2);
--color-chart-1: var(--chart-1); --color-chart-1: var(--chart-1);
--radius-2xl: calc(var(--radius) * 1.8); --radius-2xl: calc(var(--radius) * 2);
--radius-3xl: calc(var(--radius) * 2.2); --radius-3xl: calc(var(--radius) * 3);
--radius-4xl: calc(var(--radius) * 2.6) --radius-4xl: calc(var(--radius) * 4)
} }
:root { :root {