+
@@ -175,13 +166,7 @@ function CheckoutLayoutContent({ children }: CheckoutLayoutProps) {
{/* Desktop summary sidebar — Shopify: light gray bg with left border */}
-
+
diff --git a/src/app/[country]/[locale]/(storefront)/page.tsx b/src/app/[country]/[locale]/(storefront)/page.tsx
index cd434d1b..02052253 100644
--- a/src/app/[country]/[locale]/(storefront)/page.tsx
+++ b/src/app/[country]/[locale]/(storefront)/page.tsx
@@ -105,9 +105,7 @@ export default async function HomePage({
);
diff --git a/src/app/[country]/[locale]/(storefront)/pages/[...slug]/page.tsx b/src/app/[country]/[locale]/(storefront)/pages/[...slug]/page.tsx
index 50722937..19e8f662 100644
--- a/src/app/[country]/[locale]/(storefront)/pages/[...slug]/page.tsx
+++ b/src/app/[country]/[locale]/(storefront)/pages/[...slug]/page.tsx
@@ -58,12 +58,6 @@ export default async function DynamicStorePage({
}
return (
-
+
);
}
diff --git a/src/app/[country]/[locale]/(storefront)/products/[slug]/page.tsx b/src/app/[country]/[locale]/(storefront)/products/[slug]/page.tsx
index 7224c88f..1d5d717a 100644
--- a/src/app/[country]/[locale]/(storefront)/products/[slug]/page.tsx
+++ b/src/app/[country]/[locale]/(storefront)/products/[slug]/page.tsx
@@ -107,8 +107,6 @@ export default async function ProductPage({
@@ -118,8 +116,6 @@ export default async function ProductPage({
diff --git a/src/app/favicon.ico b/src/app/favicon.ico
deleted file mode 100644
index 718d6fea..00000000
Binary files a/src/app/favicon.ico and /dev/null differ
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 69277513..68c1d825 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -35,6 +35,7 @@ export const metadata: Metadata = {
default: rootStoreName,
},
description: getStoreDescription(),
+ icons: { icon: "/olitt-logo.svg" },
};
export default async function RootLayout({
diff --git a/src/components/home/FeaturedProductsSection.tsx b/src/components/home/FeaturedProductsSection.tsx
index 95408d71..ba52e97f 100644
--- a/src/components/home/FeaturedProductsSection.tsx
+++ b/src/components/home/FeaturedProductsSection.tsx
@@ -1,10 +1,10 @@
import Link from "next/link";
-import type { CSSProperties } from "react";
import { Suspense } from "react";
import { FeaturedProducts } from "@/components/products/FeaturedProducts";
import { ProductCardSkeleton } from "@/components/products/ProductCardSkeleton";
import { Button } from "@/components/ui/button";
import type { HomepageFeaturedProductsSectionConfig } from "@/lib/homepage";
+import { buildSectionThemeVars } from "@/lib/homepage/section-theme";
function CarouselSkeleton() {
return (
@@ -18,24 +18,17 @@ function CarouselSkeleton() {
interface FeaturedProductsSectionProps {
basePath: string;
- locale: string;
- country: string;
currency?: string;
section: HomepageFeaturedProductsSectionConfig;
}
export async function FeaturedProductsSection({
basePath,
- locale,
- country,
currency,
section,
}: FeaturedProductsSectionProps) {
const theme = section.theme ?? {};
- const sectionStyle: CSSProperties = {
- backgroundColor: theme.background,
- color: theme.foreground,
- };
+ const sectionStyle = buildSectionThemeVars(theme);
const mutedTextColor = theme.mutedForeground ?? "#64748b";
const borderColor = theme.borderColor ?? "#cbd5e1";
@@ -79,12 +72,7 @@ export async function FeaturedProductsSection({
}>
-
+
diff --git a/src/components/home/FeaturesSection.tsx b/src/components/home/FeaturesSection.tsx
index 08b51efb..2ccbfeae 100644
--- a/src/components/home/FeaturesSection.tsx
+++ b/src/components/home/FeaturesSection.tsx
@@ -1,6 +1,6 @@
import { ShieldCheck, ShoppingBag, Sparkles, Truck } from "lucide-react";
-import type { CSSProperties } from "react";
import type { HomepageFeaturesSectionConfig } from "@/lib/homepage";
+import { buildSectionThemeVars } from "@/lib/homepage/section-theme";
interface FeaturesSectionProps {
section: HomepageFeaturesSectionConfig;
@@ -21,10 +21,7 @@ function getFeatureIcon(iconName?: string) {
export async function FeaturesSection({ section }: FeaturesSectionProps) {
const theme = section.theme ?? {};
- const sectionStyle: CSSProperties = {
- backgroundColor: theme.background,
- color: theme.foreground,
- };
+ const sectionStyle = buildSectionThemeVars(theme);
const mutedTextColor = theme.mutedForeground ?? "#6b7280";
const cardBackground = theme.cardBackground ?? "#ffffff";
const borderColor = theme.borderColor ?? "#e5e7eb";
diff --git a/src/components/home/HeroSection.tsx b/src/components/home/HeroSection.tsx
index 1dba2f59..6e37fce2 100644
--- a/src/components/home/HeroSection.tsx
+++ b/src/components/home/HeroSection.tsx
@@ -1,12 +1,12 @@
import { ArrowRight, Play } from "lucide-react";
import Image from "next/image";
import Link from "next/link";
-import type { CSSProperties } from "react";
import { Button } from "@/components/ui/button";
import type {
HomepageActionIcon,
HomepageHeroSectionConfig,
} from "@/lib/homepage";
+import { buildSectionThemeVars } from "@/lib/homepage/section-theme";
interface HeroSectionProps {
basePath: string;
@@ -36,10 +36,7 @@ function getActionIcon(icon?: HomepageActionIcon) {
export async function HeroSection({ basePath, section }: HeroSectionProps) {
const theme = section.theme ?? {};
- const sectionStyle: CSSProperties = {
- backgroundColor: theme.background,
- color: theme.foreground,
- };
+ const sectionStyle = buildSectionThemeVars(theme);
const mutedTextColor = theme.mutedForeground ?? "#6b7280";
const cardBackground = theme.cardBackground ?? "#ffffff";
const borderColor = theme.borderColor ?? "#e5e7eb";
diff --git a/src/components/page-builder/DynamicPageRenderer.tsx b/src/components/page-builder/DynamicPageRenderer.tsx
index acc61120..12b26fa5 100644
--- a/src/components/page-builder/DynamicPageRenderer.tsx
+++ b/src/components/page-builder/DynamicPageRenderer.tsx
@@ -4,24 +4,18 @@ import type { DynamicPageConfig } from "@/lib/page-builder";
interface DynamicPageRendererProps {
page: DynamicPageConfig;
basePath: string;
- locale: string;
- country: string;
currency?: string;
}
export function DynamicPageRenderer({
page,
basePath,
- locale,
- country,
currency,
}: DynamicPageRendererProps) {
return (
diff --git a/src/components/page-builder/PageSectionsRenderer.tsx b/src/components/page-builder/PageSectionsRenderer.tsx
index bb316d1e..0a37a29a 100644
--- a/src/components/page-builder/PageSectionsRenderer.tsx
+++ b/src/components/page-builder/PageSectionsRenderer.tsx
@@ -8,8 +8,6 @@ import type { DynamicPageSectionConfig } from "@/lib/page-builder";
interface PageSectionsRendererProps {
sections: DynamicPageSectionConfig[];
basePath: string;
- locale: string;
- country: string;
currency?: string;
keyPrefix?: string;
}
@@ -17,8 +15,6 @@ interface PageSectionsRendererProps {
export function PageSectionsRenderer({
sections,
basePath,
- locale,
- country,
currency,
keyPrefix = "section",
}: PageSectionsRendererProps) {
@@ -39,9 +35,7 @@ export function PageSectionsRenderer({
);
diff --git a/src/components/products/FeaturedProducts.tsx b/src/components/products/FeaturedProducts.tsx
index ac989146..ab16c713 100644
--- a/src/components/products/FeaturedProducts.tsx
+++ b/src/components/products/FeaturedProducts.tsx
@@ -1,8 +1,7 @@
import dynamic from "next/dynamic";
import { ProductCardSkeleton } from "@/components/products/ProductCardSkeleton";
import { PRODUCT_CARD_FIELDS } from "@/lib/data/cached";
-import { cachedListProducts } from "@/lib/data/products";
-import { getAccessToken } from "@/lib/spree";
+import { getProducts } from "@/lib/data/products";
const LazyProductCarousel = dynamic(
() =>
@@ -22,23 +21,17 @@ const LazyProductCarousel = dynamic(
interface FeaturedProductsProps {
basePath: string;
- locale: string;
- country: string;
currency?: string;
}
export async function FeaturedProducts({
basePath,
- locale,
- country,
currency,
}: FeaturedProductsProps) {
- const userToken = await getAccessToken();
- const productsResponse = await cachedListProducts(
- { limit: 8, fields: PRODUCT_CARD_FIELDS },
- { locale, country },
- userToken,
- );
+ const productsResponse = await getProducts({
+ limit: 10,
+ fields: PRODUCT_CARD_FIELDS,
+ });
return (
{/* Image */}
-
+
-
+
{product.name}
{displayPrice && (
-
+
{displayPrice}
)}
{onSale && strikethroughPrice && (
-
+
{strikethroughPrice}
)}
{!product.purchasable && (
- {t("outOfStock")}
+
+ {t("outOfStock")}
+
)}
diff --git a/src/components/products/ProductCarousel.tsx b/src/components/products/ProductCarousel.tsx
index 0b050657..d887d7e7 100644
--- a/src/components/products/ProductCarousel.tsx
+++ b/src/components/products/ProductCarousel.tsx
@@ -20,7 +20,7 @@ interface ProductCarouselProps {
}
const NAV_BUTTON_BASE =
- "absolute top-1/2 -translate-y-1/2 z-10 w-10 h-10 flex items-center justify-center cursor-pointer rounded-lg bg-white border border-gray-300 text-gray-600 hover:bg-gray-100 hover:text-gray-900 transition-colors";
+ "absolute top-1/2 -translate-y-1/2 z-10 w-10 h-10 flex items-center justify-center cursor-pointer rounded-lg bg-background border border-border text-muted-foreground hover:bg-muted hover:text-foreground transition-colors";
export function ProductCarousel({
products,
@@ -49,7 +49,7 @@ export function ProductCarousel({
if (products.length === 0) {
return (
-
{t("noProductsFound")}
+
{t("noProductsFound")}
);
}
diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx
index 3464538f..8119db1e 100644
--- a/src/components/ui/button.tsx
+++ b/src/components/ui/button.tsx
@@ -11,7 +11,7 @@ const buttonVariants = cva(
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/80",
outline:
- "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
+ "border-border bg-background text-foreground hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
ghost:
diff --git a/src/lib/homepage/section-theme.ts b/src/lib/homepage/section-theme.ts
new file mode 100644
index 00000000..c0d463aa
--- /dev/null
+++ b/src/lib/homepage/section-theme.ts
@@ -0,0 +1,44 @@
+import type { CSSProperties } from "react";
+import type { HomepageThemeConfig } from "./types";
+
+type ThemeVars = CSSProperties & Record<`--${string}`, string | undefined>;
+
+/**
+ * Build the inline style for a themed homepage section.
+ *
+ * Paints the section and scopes the design-system color variables to it, so
+ * descendants styled with utility classes such as `bg-background` or
+ * `text-foreground` resolve against the section's theme instead of the page
+ * defaults. The variables are set on the section element, so pages and
+ * components outside the section are unaffected.
+ *
+ * The accent pair is applied only when the theme carries both `accent` and
+ * `accentForeground`: an accent without its generator-validated label color
+ * would leave button labels on the default ink, which can fail contrast.
+ */
+export function buildSectionThemeVars(theme: HomepageThemeConfig): ThemeVars {
+ const hasReadableAccent = Boolean(theme.accent && theme.accentForeground);
+ const vars: ThemeVars = {
+ backgroundColor: theme.background,
+ color: theme.foreground,
+ "--background": theme.background,
+ "--foreground": theme.foreground,
+ "--card": theme.cardBackground,
+ "--card-foreground": theme.foreground,
+ "--muted": theme.cardBackground,
+ "--muted-foreground": theme.mutedForeground,
+ "--border": theme.borderColor,
+ "--input": theme.borderColor,
+ "--primary": hasReadableAccent ? theme.accent : undefined,
+ "--primary-foreground": hasReadableAccent
+ ? theme.accentForeground
+ : undefined,
+ "--ring": theme.accent,
+ };
+
+ for (const key of Object.keys(vars) as (keyof ThemeVars)[]) {
+ if (vars[key] === undefined) delete vars[key];
+ }
+
+ return vars;
+}
diff --git a/src/lib/homepage/types.ts b/src/lib/homepage/types.ts
index e6d2d1dc..d9dcbbd7 100644
--- a/src/lib/homepage/types.ts
+++ b/src/lib/homepage/types.ts
@@ -17,6 +17,7 @@ export interface HomepageThemeConfig {
background?: string;
foreground?: string;
accent?: string;
+ accentForeground?: string;
mutedForeground?: string;
cardBackground?: string;
borderColor?: string;