From ac98cf0f5bcfe1699506c92905731292853bc8fc Mon Sep 17 00:00:00 2001
From: Giovanni Lupo
Date: Wed, 1 Jul 2026 18:23:19 +0000
Subject: [PATCH 1/2] STS-3.0.1: collapse variant groups to a single item in
listings and counts
Adds lib/variants.ts with dedupeVariantGroups() and countDistinctProducts()
helpers. Variant sets (e.g. sizes/colors) now render as one product card and
count as one item on the homepage, collections overview, collection detail,
and shop-all pages, instead of once per size/color folder.
---
VERSIONING.md | 1 +
app/collections/CollectionCard.tsx | 5 +++--
app/collections/[collectionId]/page.tsx | 8 +++-----
app/page.tsx | 7 ++++---
app/shop-all/page.tsx | 3 ++-
lib/variants.ts | 25 +++++++++++++++++++++++++
lib/version.ts | 2 +-
package.json | 2 +-
8 files changed, 40 insertions(+), 13 deletions(-)
create mode 100644 lib/variants.ts
diff --git a/VERSIONING.md b/VERSIONING.md
index 6f536e1..006023a 100644
--- a/VERSIONING.md
+++ b/VERSIONING.md
@@ -214,3 +214,4 @@ Potential future additions to version system:
## Questions?
For questions about the versioning system, see the About page or contact via the FAQ section.
+| STS-3.0.1 | 2026-07-01 | Variant groups count & list as one item across all pages (shared lib/variants.ts helper) |
diff --git a/app/collections/CollectionCard.tsx b/app/collections/CollectionCard.tsx
index cecf381..777b8ef 100644
--- a/app/collections/CollectionCard.tsx
+++ b/app/collections/CollectionCard.tsx
@@ -3,6 +3,7 @@
import Link from 'next/link';
import { useEffect, useState, useMemo } from 'react';
import FadeImage from '@/components/FadeImage';
+import { countDistinctProducts } from '@/lib/variants';
interface CollectionCardProps {
collection: {
@@ -92,8 +93,8 @@ export default function CollectionCard({ collection, design, tick }: CollectionC
fontFamily: design.fonts.bodyFont,
}}
>
- {collection.products.length}{' '}
- {collection.products.length === 1 ? 'product' : 'products'}
+ {countDistinctProducts(collection.products)}{' '}
+ {countDistinctProducts(collection.products) === 1 ? 'product' : 'products'}
{
- if (!product.variants || product.variants.length === 0) return true;
- return product.variants[0].id === product.id;
- });
+ // One card per variant group (shared helper — see lib/variants.ts)
+ const displayProducts = dedupeVariantGroups(sortedProducts);
return (
diff --git a/app/page.tsx b/app/page.tsx
index 97de2d8..84c296a 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -3,6 +3,7 @@
import Link from 'next/link';
import { useEffect, useState } from 'react';
import FadeImage from '@/components/FadeImage';
+import { countDistinctProducts, dedupeVariantGroups } from '@/lib/variants';
export default function Home() {
const [design, setDesign] = useState
(null);
@@ -33,7 +34,7 @@ export default function Home() {
products.push(product);
});
});
- setAllProducts(products);
+ setAllProducts(dedupeVariantGroups(products));
try {
const inventoryResponse = await fetch('/api/inventory');
@@ -299,8 +300,8 @@ export default function Home() {
fontFamily: design.fonts.bodyFont,
}}
>
- {collection.products.length}{' '}
- {collection.products.length === 1 ? 'product' : 'products'}
+ {countDistinctProducts(collection.products)}{' '}
+ {countDistinctProducts(collection.products) === 1 ? 'product' : 'products'}
(products: T[]): T[] {
+ return products.filter(
+ (p) => !p.variants || p.variants.length === 0 || p.variants[0].id === p.id
+ );
+}
+
+// Count of distinct products, treating each variant group as a single item.
+export function countDistinctProducts(products: VariantLike[]): number {
+ return dedupeVariantGroups(products).length;
+}
diff --git a/lib/version.ts b/lib/version.ts
index 5e70c77..3cfb870 100644
--- a/lib/version.ts
+++ b/lib/version.ts
@@ -36,7 +36,7 @@
* 4. Commit with version number in commit message
*/
-export const VERSION = 'STS-2.6.3';
+export const VERSION = 'STS-3.0.1';
export const VERSION_INFO = {
name: 'Shop Template System',
diff --git a/package.json b/package.json
index c370421..e160e27 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "shop-template-system",
- "version": "3.0.0",
+ "version": "3.0.1",
"private": true,
"scripts": {
"dev": "next dev",
From d2640003a246d2de119f63fda0277e21911d17c7 Mon Sep 17 00:00:00 2001
From: Giovanni Lupo
Date: Wed, 1 Jul 2026 18:33:20 +0000
Subject: [PATCH 2/2] STS-3.0.1: variant cards show base name + value chips on
listings
Listing cards (shop-all, homepage single-collection) now display the variant
group base name (e.g. "Branded Sneakers") instead of a single variant folder
name ("Branded Sneakers (10)"), and render the available values as chips
below via a shared components/VariantChips.tsx, matching the collection detail
page. Adds variantDisplayName() to lib/variants.ts.
---
app/page.tsx | 8 +++--
app/shop-all/page.tsx | 8 +++--
components/VariantChips.tsx | 59 +++++++++++++++++++++++++++++++++++++
lib/variants.ts | 6 ++++
4 files changed, 75 insertions(+), 6 deletions(-)
create mode 100644 components/VariantChips.tsx
diff --git a/app/page.tsx b/app/page.tsx
index 84c296a..71226ca 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -3,7 +3,8 @@
import Link from 'next/link';
import { useEffect, useState } from 'react';
import FadeImage from '@/components/FadeImage';
-import { countDistinctProducts, dedupeVariantGroups } from '@/lib/variants';
+import VariantChips from '@/components/VariantChips';
+import { countDistinctProducts, dedupeVariantGroups, variantDisplayName } from '@/lib/variants';
export default function Home() {
const [design, setDesign] = useState(null);
@@ -216,7 +217,7 @@ export default function Home() {
@@ -232,8 +233,9 @@ export default function Home() {
className="font-bold text-lg mb-1"
style={{ color: design.colors.primary, fontFamily: design.fonts.titleFont }}
>
- {product.name}
+ {variantDisplayName(product)}
+
SKU: {product.sku}
diff --git a/app/shop-all/page.tsx b/app/shop-all/page.tsx
index 2bf332f..93634c5 100644
--- a/app/shop-all/page.tsx
+++ b/app/shop-all/page.tsx
@@ -3,7 +3,8 @@
import Link from 'next/link';
import { useEffect, useState } from 'react';
import FadeImage from '@/components/FadeImage';
-import { dedupeVariantGroups } from '@/lib/variants';
+import VariantChips from '@/components/VariantChips';
+import { dedupeVariantGroups, variantDisplayName } from '@/lib/variants';
type SortOption = 'name-asc' | 'name-desc' | 'price-asc' | 'price-desc' | 'units-asc' | 'units-desc' | 'total-asc' | 'total-desc';
@@ -152,7 +153,7 @@ export default function ShopAllPage() {
@@ -182,8 +183,9 @@ export default function ShopAllPage() {
fontFamily: design.fonts.titleFont,
}}
>
- {product.name}
+ {variantDisplayName(product)}
+
;
+}): ReactElement | null {
+ if (!product.variants || product.variants.length === 0) return null;
+ const seen = new Set();
+ const uniqueValues = product.variants
+ .map((v) => v.values[0])
+ .filter((val) => val && !seen.has(val) && !!seen.add(val));
+
+ return (
+
+
+ {product.variantDimensions?.[0] ?? 'Options'}:
+
+
+ {uniqueValues.map((value) => {
+ const withValue = product.variants!.filter((v) => v.values[0] === value);
+ const allOOS = withValue.length > 0 && withValue.every(
+ (v) => stockMap[v.id] !== undefined && stockMap[v.id] <= 0
+ );
+ const isActive = product.variantValues?.[0] === value;
+ return (
+
+ {value}
+
+ );
+ })}
+
+
+ );
+}
diff --git a/lib/variants.ts b/lib/variants.ts
index a2b2a3e..28cd5d3 100644
--- a/lib/variants.ts
+++ b/lib/variants.ts
@@ -23,3 +23,9 @@ export function dedupeVariantGroups(products: T[]): T[] {
export function countDistinctProducts(products: VariantLike[]): number {
return dedupeVariantGroups(products).length;
}
+
+// Display name for a card: the variant group base name (e.g. "Branded Sneakers")
+// rather than the folder name of one variant ("Branded Sneakers (10)").
+export function variantDisplayName(product: { name: string; variantGroup?: string }): string {
+ return product.variantGroup || product.name;
+}