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",
"fgColor": "#0a0a0a",
"mutedColor": "#f5f5f5",
"roundedness": "md",
"radius": "md",
"shadowLevel": "sm",
"radius": "sm",
"shadow": "sm",
"maxWidth": "xl"
}
@@ -201,9 +199,7 @@
"bgColor": "#ffffff",
"fgColor": "#0a0a0a",
"mutedColor": "#f5f5f5",
"roundedness": "md",
"radius": "md",
"shadowLevel": "sm",
"radius": "sm",
"shadow": "sm",
"maxWidth": "xl"
}

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",

View File

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

View File

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

View File

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