diff --git a/app/components/product/badges.tsx b/app/components/product/badges.tsx index e759c8fb..2cfe92b0 100644 --- a/app/components/product/badges.tsx +++ b/app/components/product/badges.tsx @@ -9,17 +9,26 @@ import type { } from "storefront-api.generated"; import { cn } from "~/utils/cn"; +export interface BadgeStyleSettings { + colorText: string; + colorTextInverse: string; + badgeBorderRadius: number; + badgeTextTransform: string; +} + function Badge({ text, backgroundColor, + badgeStyle, className, }: { text: string; backgroundColor: string; + badgeStyle: BadgeStyleSettings; className?: string; }) { - const { colorText, colorTextInverse, badgeBorderRadius, badgeTextTransform } = - useThemeSettings(); + let { colorText, colorTextInverse, badgeBorderRadius, badgeTextTransform } = + badgeStyle; return ( ); @@ -55,34 +72,64 @@ export function NewBadge({ return null; } -export function BestSellerBadge({ className }: { className?: string }) { - const { bestSellerBadgeText, bestSellerBadgeColor } = useThemeSettings(); +export function BestSellerBadge({ + badgeStyle, + bestSellerBadgeText, + bestSellerBadgeColor, + className, +}: { + badgeStyle: BadgeStyleSettings; + bestSellerBadgeText: string; + bestSellerBadgeColor: string; + className?: string; +}) { return ( ); } -export function SoldOutBadge({ className }: { className?: string }) { - const { soldOutBadgeText, soldOutBadgeColor } = useThemeSettings(); +export function SoldOutBadge({ + badgeStyle, + soldOutBadgeText, + soldOutBadgeColor, + className, +}: { + badgeStyle: BadgeStyleSettings; + soldOutBadgeText: string; + soldOutBadgeColor: string; + className?: string; +}) { return ( ); } -export function BundleBadge({ className }: { className?: string }) { - const { bundleBadgeText, bundleBadgeColor } = useThemeSettings(); +export function BundleBadge({ + badgeStyle, + bundleBadgeText, + bundleBadgeColor, + className, +}: { + badgeStyle: BadgeStyleSettings; + bundleBadgeText: string; + bundleBadgeColor: string; + className?: string; +}) { return ( ); @@ -91,16 +138,21 @@ export function BundleBadge({ className }: { className?: string }) { export function SaleBadge({ price, compareAtPrice, + badgeStyle, + saleBadgeText = "Sale", + saleBadgeColor, className, }: { price: MoneyV2; compareAtPrice: MoneyV2; + badgeStyle: BadgeStyleSettings; + saleBadgeText?: string; + saleBadgeColor: string; className?: string; }) { - const { saleBadgeText = "Sale", saleBadgeColor } = useThemeSettings(); - const { amount, percentage } = calculateDiscount(price, compareAtPrice); - const discountAmount = useMoney({ amount, currencyCode: price.currencyCode }); - const text = saleBadgeText + let { amount, percentage } = calculateDiscount(price, compareAtPrice); + let discountAmount = useMoney({ amount, currencyCode: price.currencyCode }); + let text = saleBadgeText .replace("[amount]", discountAmount.withoutTrailingZeros) .replace("[percentage]", percentage); @@ -109,6 +161,7 @@ export function SaleBadge({ ); @@ -118,8 +171,8 @@ export function SaleBadge({ function calculateDiscount(price: MoneyV2, compareAtPrice: MoneyV2) { if (price?.amount && compareAtPrice?.amount) { - const priceNumber = Number(price.amount); - const compareAtPriceNumber = Number(compareAtPrice.amount); + let priceNumber = Number(price.amount); + let compareAtPriceNumber = Number(compareAtPrice.amount); if (compareAtPriceNumber > priceNumber) { return { amount: String(compareAtPriceNumber - priceNumber), @@ -150,18 +203,43 @@ export function ProductBadges({ className?: string; as?: React.ElementType; }) { + let { + colorText, + colorTextInverse, + badgeBorderRadius, + badgeTextTransform, + newBadgeText, + newBadgeColor, + newBadgeDaysOld, + bestSellerBadgeText, + bestSellerBadgeColor, + soldOutBadgeText, + soldOutBadgeColor, + bundleBadgeText, + bundleBadgeColor, + saleBadgeText, + saleBadgeColor, + } = useThemeSettings(); + + let badgeStyle: BadgeStyleSettings = { + colorText, + colorTextInverse, + badgeBorderRadius, + badgeTextTransform, + }; + if (!(product && selectedVariant)) { return null; } - const isBundle = Boolean(product?.isBundle?.requiresComponents); - const { publishedAt, badges } = product; - const isBestSellerProduct = badges + let isBundle = Boolean(product?.isBundle?.requiresComponents); + let { publishedAt, badges } = product; + let isBestSellerProduct = badges .filter(Boolean) .some(({ key, value }) => key === "best_seller" && value === "true"); - const isFragment = Component.toString() === "Symbol(react.fragment)"; - const componentProps = isFragment + let isFragment = Component.toString() === "Symbol(react.fragment)"; + let componentProps = isFragment ? {} : { className: cn( @@ -174,16 +252,41 @@ export function ProductBadges({ {selectedVariant.availableForSale ? ( <> - {isBundle && } + {isBundle && ( + + )} + - - {isBestSellerProduct && } + {isBestSellerProduct && ( + + )} ) : ( - + )} ); diff --git a/app/components/product/product-card.tsx b/app/components/product/product-card.tsx index df47b059..3ee474d8 100644 --- a/app/components/product/product-card.tsx +++ b/app/components/product/product-card.tsx @@ -17,6 +17,7 @@ import JudgemeStarsRating from "~/sections/main-product/judgeme-stars-rating"; import { isCombinedListing } from "~/utils/combined-listings"; import { calculateAspectRatio } from "~/utils/image"; import { + type BadgeStyleSettings, BestSellerBadge, BundleBadge, NewBadge, @@ -34,7 +35,7 @@ export function ProductCard({ product: ProductCardFragment; className?: string; }) { - const { + let { pcardBorderRadius, pcardBackgroundColor, pcardShowImageOnHover, @@ -55,8 +56,30 @@ export function ProductCard({ pcardShowBestSellerBadge, pcardShowNewBadge, pcardShowOutOfStockBadge, + colorText, + colorTextInverse, + badgeBorderRadius, + badgeTextTransform, + newBadgeText, + newBadgeColor, + newBadgeDaysOld, + bestSellerBadgeText, + bestSellerBadgeColor, + soldOutBadgeText, + soldOutBadgeColor, + bundleBadgeText, + bundleBadgeColor, + saleBadgeText, + saleBadgeColor, } = useThemeSettings(); + let badgeStyle: BadgeStyleSettings = { + colorText, + colorTextInverse, + badgeBorderRadius, + badgeTextTransform, + }; + const [selectedVariant, setSelectedVariant] = useState(null); const [isImageLoading, setIsImageLoading] = useState(false); @@ -145,18 +168,45 @@ export function ProductCard({ )}
- {isBundle && pcardShowBundleBadge && } + {isBundle && pcardShowBundleBadge && ( + + )} {pcardShowSaleBadge && ( )} {pcardShowBestSellerBadge && isBestSellerProduct && ( - + + )} + {pcardShowNewBadge && ( + + )} + {pcardShowOutOfStockBadge && ( + )} - {pcardShowNewBadge && } - {pcardShowOutOfStockBadge && }
{pcardEnableQuickShop && (
- + + Sold out +

EXAMPLE PRODUCT TITLE

diff --git a/package-lock.json b/package-lock.json index 08c99be5..3ee8b9da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "@shopify/hydrogen": "^2026.1.0", "@shopify/hydrogen-react": "^2026.1.1", "@tailwindcss/vite": "^4.1.17", - "@weaverse/hydrogen": "^5.9.1", + "@weaverse/hydrogen": "^5.9.3", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "colord": "2.9.3", @@ -5462,23 +5462,23 @@ "license": "MIT" }, "node_modules/@weaverse/core": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/@weaverse/core/-/core-5.9.2.tgz", - "integrity": "sha512-QmEw1mZc3bN+clYPUMAY5LymvP3BhT9u1lb40jG3qpKkwQVHySn1ihXV9WbcO0OFwzw/qwUuemjeDHXfRRTSIg==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@weaverse/core/-/core-5.9.3.tgz", + "integrity": "sha512-YPXt0pH257TyNABcpgv67kek3ob3NPgClXoSqtxiayaGXeOTjv2gK/wG6gsS+eStYZpOGu3zsEDykU7e/y3dCw==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@weaverse/hydrogen": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/@weaverse/hydrogen/-/hydrogen-5.9.2.tgz", - "integrity": "sha512-+oMM9Z9yi/tdloWZalCrlFePSqljK8kpqCMJQCmN/yKuGAV6etgbisja9Pt9J/gR+4wvysMjztTG657UxF8bGg==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@weaverse/hydrogen/-/hydrogen-5.9.3.tgz", + "integrity": "sha512-Fpp48Lh9O1WqBYnwgINcXP1Pu9STNXyo6AVQ4fCRIbQo9W2ruf/CyDgbRfY9fDTZqqc64mLgm2+ZEQ7eeekA5w==", "license": "MIT", "dependencies": { "@shopify/hydrogen": ">=2025.5", "@shopify/remix-oxygen": "3", - "@weaverse/react": "5.9.2", + "@weaverse/react": "5.9.3", "@weaverse/schema": "0.8.2", "react": ">=19", "react-dom": ">=19", @@ -5490,12 +5490,12 @@ } }, "node_modules/@weaverse/react": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/@weaverse/react/-/react-5.9.2.tgz", - "integrity": "sha512-I5rgj6YwR/URQRNFBXBEiLzmRMcSfJPIDAxKid3F9C7re678NLdkV0l90ZQDWG/HhkTN0c3OzRBTwFOVkEP8fg==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/@weaverse/react/-/react-5.9.3.tgz", + "integrity": "sha512-OBS4ZiVolodFtTZ3GGuexL0ZixUtFz8VuKSvbxiM45rm4GoWi6aXPG0OdezxLiDNAYCNsliV22n49vmt5Sv9BQ==", "license": "MIT", "dependencies": { - "@weaverse/core": "5.9.2", + "@weaverse/core": "5.9.3", "clsx": "^2.1.1", "react": ">=19", "react-dom": ">=19" diff --git a/package.json b/package.json index be89a05e..3408997e 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@shopify/hydrogen": "^2026.1.0", "@shopify/hydrogen-react": "^2026.1.1", "@tailwindcss/vite": "^4.1.17", - "@weaverse/hydrogen": "^5.9.1", + "@weaverse/hydrogen": "^5.9.3", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "colord": "2.9.3", @@ -112,4 +112,4 @@ "engines": { "node": ">=20" } -} +} \ No newline at end of file