create-brainerce-store 1.50.1 → 1.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +171 -66
- package/messages/en.json +4 -1
- package/messages/he.json +4 -1
- package/package.json +1 -1
- package/templates/nextjs/base/.claude/commands/design.md +51 -0
- package/templates/nextjs/base/.env.local.ejs +5 -0
- package/templates/nextjs/base/.eslintrc.json +57 -3
- package/templates/nextjs/base/AGENTS.md +41 -0
- package/templates/nextjs/base/AI-GUIDE.md +94 -0
- package/templates/nextjs/base/CLAUDE.md +42 -0
- package/templates/nextjs/base/TRANSLATIONS.md +1 -1
- package/templates/nextjs/base/next.config.ts +18 -10
- package/templates/nextjs/base/package.json.ejs +5 -1
- package/templates/nextjs/base/src/app/account/page.tsx +5 -5
- package/templates/nextjs/base/src/app/api/auth/logout/route.ts +1 -1
- package/templates/nextjs/base/src/app/api/auth/reset-password/route.ts +2 -2
- package/templates/nextjs/base/src/app/api/store/[...path]/route.ts +1 -1
- package/templates/nextjs/base/src/app/auth/callback/page.tsx +4 -4
- package/templates/nextjs/base/src/app/blog/[slug]/page.tsx.ejs +4 -4
- package/templates/nextjs/base/src/app/blog/page.tsx.ejs +2 -2
- package/templates/nextjs/base/src/app/cart/page.tsx +2 -173
- package/templates/nextjs/base/src/app/checkout/page.tsx +12 -11
- package/templates/nextjs/base/src/app/contact/page.tsx +3 -3
- package/templates/nextjs/base/src/app/faq/page.tsx.ejs +2 -2
- package/templates/nextjs/base/src/app/forgot-password/page.tsx +4 -4
- package/templates/nextjs/base/src/app/layout.tsx.ejs +16 -14
- package/templates/nextjs/base/src/app/login/page.tsx +4 -4
- package/templates/nextjs/base/src/app/order-confirmation/page.tsx +19 -12
- package/templates/nextjs/base/src/app/page.tsx +4 -4
- package/templates/nextjs/base/src/app/pages/[slug]/page.tsx.ejs +3 -3
- package/templates/nextjs/base/src/app/payment-complete/page.tsx +1 -1
- package/templates/nextjs/base/src/app/products/[slug]/page.tsx +6 -6
- package/templates/nextjs/base/src/app/products/page.tsx +4 -623
- package/templates/nextjs/base/src/app/register/page.tsx +4 -4
- package/templates/nextjs/base/src/app/reset-password/page.tsx +5 -5
- package/templates/nextjs/base/src/app/sitemap.ts +1 -1
- package/templates/nextjs/base/src/app/verify-email/page.tsx +5 -5
- package/templates/nextjs/base/src/components/account/address-book.tsx +3 -3
- package/templates/nextjs/base/src/components/account/order-customizations.tsx +3 -3
- package/templates/nextjs/base/src/components/account/order-history.tsx +13 -5
- package/templates/nextjs/base/src/components/account/order-payment-block.tsx +2 -2
- package/templates/nextjs/base/src/components/account/order-shipping-block.tsx +2 -2
- package/templates/nextjs/base/src/components/account/order-status-timeline.tsx +2 -2
- package/templates/nextjs/base/src/components/account/profile-section.tsx +3 -3
- package/templates/nextjs/base/src/components/auth/login-form.tsx +4 -4
- package/templates/nextjs/base/src/components/auth/oauth-buttons.tsx +4 -4
- package/templates/nextjs/base/src/components/auth/register-form.tsx +4 -4
- package/templates/nextjs/base/src/components/brainerce-bot.tsx +2 -2
- package/templates/nextjs/base/src/components/checkout/checkout-form.tsx +24 -3
- package/templates/nextjs/base/src/components/checkout/custom-fields-step.tsx +2 -2
- package/templates/nextjs/base/src/components/checkout/delivery-method-step.tsx +2 -2
- package/templates/nextjs/base/src/components/checkout/order-bump-card.tsx +4 -4
- package/templates/nextjs/base/src/components/checkout/payment-step.tsx +6 -6
- package/templates/nextjs/base/src/components/checkout/pickup-step.tsx +3 -3
- package/templates/nextjs/base/src/components/checkout/shipping-step.tsx +3 -3
- package/templates/nextjs/base/src/components/checkout/tax-display.tsx +3 -3
- package/templates/nextjs/base/src/components/seo/organization-json-ld.tsx +2 -2
- package/templates/nextjs/base/src/components/seo/product-json-ld.tsx +3 -3
- package/templates/nextjs/base/src/core/hooks/use-cart-page.ts +58 -0
- package/templates/nextjs/base/src/core/hooks/use-home-data.ts +51 -0
- package/templates/nextjs/base/src/core/hooks/use-product-listing.ts +295 -0
- package/templates/nextjs/base/src/core/hooks/use-product-page.ts +278 -0
- package/templates/nextjs/base/src/{hooks → core/hooks}/use-search.ts +1 -1
- package/templates/nextjs/base/src/{lib → core/lib}/brainerce.ts.ejs +1 -1
- package/templates/nextjs/base/src/core/lib/image-hosts.ts +7 -0
- package/templates/nextjs/base/src/core/lib/product-options.ts +121 -0
- package/templates/nextjs/base/src/{lib → core/lib}/resolve-currency.ts +1 -1
- package/templates/nextjs/base/src/{lib → core/lib}/safe-redirect.ts +1 -1
- package/templates/nextjs/base/src/{lib → core/lib}/sanitize-html.ts +12 -0
- package/templates/nextjs/base/src/{lib → core/lib}/sanitize.ts.ejs +1 -1
- package/templates/nextjs/base/src/{lib → core/lib}/use-currency.ts +1 -1
- package/templates/nextjs/base/src/{providers → core/providers}/store-provider.tsx.ejs +4 -4
- package/templates/nextjs/base/src/middleware.ts.ejs +2 -2
- package/templates/nextjs/base/src/{components → ui}/cart/cart-bundle-offer.tsx +5 -5
- package/templates/nextjs/base/src/{components → ui}/cart/cart-item.tsx +6 -6
- package/templates/nextjs/base/src/{components → ui}/cart/cart-nudges.tsx +1 -1
- package/templates/nextjs/base/src/{components → ui}/cart/cart-summary.tsx +4 -4
- package/templates/nextjs/base/src/{components → ui}/cart/cart-upgrade-banner.tsx +5 -5
- package/templates/nextjs/base/src/ui/cart/cart-view.tsx +149 -0
- package/templates/nextjs/base/src/{components → ui}/cart/coupon-input.tsx +4 -4
- package/templates/nextjs/base/src/{components → ui}/cart/free-shipping-bar.tsx +4 -4
- package/templates/nextjs/base/src/{components → ui}/cart/reservation-countdown.tsx +2 -2
- package/templates/nextjs/base/src/ui/home/discount-banner-strip.tsx +20 -0
- package/templates/nextjs/base/src/ui/home/featured-products-section.tsx +24 -0
- package/templates/nextjs/base/src/ui/home/hero-section.tsx +29 -0
- package/templates/nextjs/base/src/ui/home/home-client.tsx +29 -0
- package/templates/nextjs/base/src/{components/content → ui/layout}/faq-section.tsx.ejs +2 -2
- package/templates/nextjs/base/src/{components/content → ui/layout}/header-account.tsx +3 -3
- package/templates/nextjs/base/src/{components/content → ui/layout}/rich-text-block.tsx.ejs +1 -1
- package/templates/nextjs/base/src/{components/content → ui/layout}/site-header.tsx.ejs +1 -1
- package/templates/nextjs/base/src/{components/products → ui/product}/customization-fields.tsx +18 -51
- package/templates/nextjs/base/src/{components/products → ui/product}/discount-badge.tsx +1 -1
- package/templates/nextjs/base/src/{components/products → ui/product}/frequently-bought-together.tsx +6 -6
- package/templates/nextjs/base/src/{components/products → ui/product}/modifier-group-selector.tsx +10 -77
- package/templates/nextjs/base/src/{components/shared → ui/product}/price-display.tsx +2 -2
- package/templates/nextjs/base/src/{components/products → ui/product}/product-card.tsx +10 -10
- package/templates/nextjs/base/src/{app/products/[slug] → ui/product}/product-client-section.tsx +45 -206
- package/templates/nextjs/base/src/{components/products → ui/product}/product-grid.tsx +3 -3
- package/templates/nextjs/base/src/ui/product/product-listing.tsx +429 -0
- package/templates/nextjs/base/src/{components/products → ui/product}/recommendation-section.tsx +4 -4
- package/templates/nextjs/base/src/{components/reviews → ui/product}/review-form.tsx +2 -2
- package/templates/nextjs/base/src/{components/reviews → ui/product}/reviews-section.tsx +1 -1
- package/templates/nextjs/base/src/{components/products → ui/product}/stock-badge.tsx +2 -2
- package/templates/nextjs/base/src/{components/products → ui/product}/variant-selector.tsx +3 -3
- package/templates/nextjs/base/src/ui/shared/cdn-image.tsx +26 -0
- package/templates/nextjs/base/src/{components → ui}/shared/loading-spinner.tsx +2 -2
- package/templates/nextjs/base/tailwind.config.ts +12 -0
- package/templates/nextjs/designs/passepartout/app-overlay/layout.tsx.ejs +253 -0
- package/templates/nextjs/designs/passepartout/globals.css +412 -0
- package/templates/nextjs/designs/passepartout/messages-patch/en.json +87 -0
- package/templates/nextjs/designs/passepartout/messages-patch/he.json +87 -0
- package/templates/nextjs/designs/passepartout/ui/cart/cart-bundle-offer.tsx +111 -0
- package/templates/nextjs/designs/passepartout/ui/cart/cart-nudges.tsx +39 -0
- package/templates/nextjs/designs/passepartout/ui/cart/cart-upgrade-banner.tsx +141 -0
- package/templates/nextjs/designs/passepartout/ui/cart/cart-view.tsx +149 -0
- package/templates/nextjs/designs/passepartout/ui/cart/free-shipping-bar.tsx +62 -0
- package/templates/nextjs/designs/passepartout/ui/cart/reservation-countdown.tsx +103 -0
- package/templates/nextjs/designs/passepartout/ui/home/home-client.tsx +401 -0
- package/templates/nextjs/designs/passepartout/ui/layout/announcement-bar.tsx +139 -0
- package/templates/nextjs/designs/passepartout/ui/layout/cart-link.tsx +45 -0
- package/templates/nextjs/designs/passepartout/ui/layout/faq-section.tsx +103 -0
- package/templates/nextjs/designs/passepartout/ui/layout/site-footer.tsx +159 -0
- package/templates/nextjs/designs/passepartout/ui/layout/site-header.tsx.ejs +155 -0
- package/templates/nextjs/designs/passepartout/ui/layout/trust-icons.tsx +60 -0
- package/templates/nextjs/designs/passepartout/ui/layout/whatsapp-button.tsx +34 -0
- package/templates/nextjs/designs/passepartout/ui/product/discount-badge.tsx +22 -0
- package/templates/nextjs/designs/passepartout/ui/product/frequently-bought-together.tsx +205 -0
- package/templates/nextjs/designs/passepartout/ui/product/price-display.tsx +111 -0
- package/templates/nextjs/designs/passepartout/ui/product/product-card.tsx +265 -0
- package/templates/nextjs/designs/passepartout/ui/product/product-client-section.tsx +667 -0
- package/templates/nextjs/designs/passepartout/ui/product/product-grid.tsx +35 -0
- package/templates/nextjs/designs/passepartout/ui/product/product-listing.tsx +427 -0
- package/templates/nextjs/designs/passepartout/ui/product/recommendation-section.tsx +113 -0
- package/templates/nextjs/designs/passepartout/ui/product/review-form.tsx +294 -0
- package/templates/nextjs/designs/passepartout/ui/product/reviews-section.tsx.ejs +96 -0
- package/templates/nextjs/designs/passepartout/ui/product/stock-badge.tsx +52 -0
- package/templates/nextjs/designs/passepartout/ui/product/variant-selector.tsx +307 -0
- package/templates/nextjs/designs/passepartout/ui/shared/fly-to-cart.ts +85 -0
- package/templates/nextjs/designs/passepartout/ui/shared/loading-spinner.tsx +33 -0
- package/templates/nextjs/ui-canvas/cart/cart-bundle-offer.tsx +87 -0
- package/templates/nextjs/ui-canvas/cart/cart-item.tsx +121 -0
- package/templates/nextjs/ui-canvas/cart/cart-nudges.tsx +25 -0
- package/templates/nextjs/ui-canvas/cart/cart-summary.tsx +97 -0
- package/templates/nextjs/ui-canvas/cart/cart-upgrade-banner.tsx +103 -0
- package/templates/nextjs/ui-canvas/cart/cart-view.tsx +106 -0
- package/templates/nextjs/ui-canvas/cart/coupon-input.tsx +117 -0
- package/templates/nextjs/ui-canvas/cart/free-shipping-bar.tsx +52 -0
- package/templates/nextjs/ui-canvas/cart/reservation-countdown.tsx +79 -0
- package/templates/nextjs/ui-canvas/home/discount-banner-strip.tsx +19 -0
- package/templates/nextjs/ui-canvas/home/featured-products-section.tsx +23 -0
- package/templates/nextjs/ui-canvas/home/hero-section.tsx +21 -0
- package/templates/nextjs/ui-canvas/home/home-client.tsx +26 -0
- package/templates/nextjs/ui-canvas/layout/announcement-bar.tsx.ejs +101 -0
- package/templates/nextjs/ui-canvas/layout/faq-section.tsx.ejs +71 -0
- package/templates/nextjs/ui-canvas/layout/header-account.tsx +31 -0
- package/templates/nextjs/ui-canvas/layout/language-switcher.tsx.ejs +74 -0
- package/templates/nextjs/ui-canvas/layout/rich-text-block.tsx.ejs +34 -0
- package/templates/nextjs/ui-canvas/layout/site-footer.tsx.ejs +82 -0
- package/templates/nextjs/ui-canvas/layout/site-header.tsx.ejs +119 -0
- package/templates/nextjs/ui-canvas/product/customization-fields.tsx +443 -0
- package/templates/nextjs/ui-canvas/product/discount-badge.tsx +17 -0
- package/templates/nextjs/ui-canvas/product/frequently-bought-together.tsx +166 -0
- package/templates/nextjs/ui-canvas/product/modifier-group-selector.tsx +163 -0
- package/templates/nextjs/ui-canvas/product/price-display.tsx +50 -0
- package/templates/nextjs/ui-canvas/product/product-card.tsx +197 -0
- package/templates/nextjs/ui-canvas/product/product-client-section.tsx +352 -0
- package/templates/nextjs/ui-canvas/product/product-grid.tsx +27 -0
- package/templates/nextjs/ui-canvas/product/product-listing.tsx +224 -0
- package/templates/nextjs/ui-canvas/product/recommendation-section.tsx +95 -0
- package/templates/nextjs/ui-canvas/product/review-form.tsx +269 -0
- package/templates/nextjs/ui-canvas/product/reviews-section.tsx +78 -0
- package/templates/nextjs/ui-canvas/product/stock-badge.tsx +43 -0
- package/templates/nextjs/ui-canvas/product/variant-selector.tsx +210 -0
- package/templates/nextjs/ui-canvas/shared/cdn-image.tsx +29 -0
- package/templates/nextjs/ui-canvas/shared/loading-spinner.tsx +25 -0
- package/templates/nextjs/base/src/app/home-client.tsx +0 -98
- package/templates/nextjs/base/src/components/products/allergen-chips.tsx +0 -78
- /package/templates/nextjs/base/src/{lib → core/lib}/auth.ts +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/csrf.ts +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/navigation.tsx.ejs +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/nonce.ts +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/seo.ts +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/store-info.ts +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/translations.ts.ejs +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/utils.ts +0 -0
- /package/templates/nextjs/base/src/{lib → core/lib}/validation.ts +0 -0
- /package/templates/nextjs/base/src/{components/content → ui/layout}/announcement-bar.tsx.ejs +0 -0
- /package/templates/nextjs/base/src/{components → ui}/layout/language-switcher.tsx.ejs +0 -0
- /package/templates/nextjs/base/src/{components/content → ui/layout}/site-footer.tsx.ejs +0 -0
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
import { Link } from '@/lib/navigation';
|
|
5
|
-
import type { Product, DiscountBanner } from 'brainerce';
|
|
6
|
-
import { getClient } from '@/lib/brainerce';
|
|
7
|
-
import { useStoreInfo } from '@/providers/store-provider';
|
|
8
|
-
import { ProductGrid } from '@/components/products/product-grid';
|
|
9
|
-
import { LoadingSpinner } from '@/components/shared/loading-spinner';
|
|
10
|
-
import { useTranslations } from '@/lib/translations';
|
|
11
|
-
|
|
12
|
-
export function HomeClient() {
|
|
13
|
-
const { storeInfo, loading: storeLoading } = useStoreInfo();
|
|
14
|
-
const [products, setProducts] = useState<Product[]>([]);
|
|
15
|
-
const [banners, setBanners] = useState<DiscountBanner[]>([]);
|
|
16
|
-
const [loading, setLoading] = useState(true);
|
|
17
|
-
const t = useTranslations('home');
|
|
18
|
-
const tc = useTranslations('common');
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
async function load() {
|
|
22
|
-
try {
|
|
23
|
-
const client = getClient();
|
|
24
|
-
const [productsRes, bannersRes] = await Promise.allSettled([
|
|
25
|
-
client.getProducts({ limit: 8, sortBy: 'createdAt', sortOrder: 'desc' }),
|
|
26
|
-
client.getDiscountBanners(),
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
if (productsRes.status === 'fulfilled') {
|
|
30
|
-
setProducts(productsRes.value.data);
|
|
31
|
-
}
|
|
32
|
-
if (bannersRes.status === 'fulfilled') {
|
|
33
|
-
setBanners(bannersRes.value);
|
|
34
|
-
}
|
|
35
|
-
} catch (err) {
|
|
36
|
-
console.error('Failed to load home page data:', err);
|
|
37
|
-
} finally {
|
|
38
|
-
setLoading(false);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
load();
|
|
43
|
-
}, []);
|
|
44
|
-
|
|
45
|
-
if (storeLoading || loading) {
|
|
46
|
-
return (
|
|
47
|
-
<div className="flex min-h-[60vh] items-center justify-center">
|
|
48
|
-
<LoadingSpinner size="lg" />
|
|
49
|
-
</div>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<div>
|
|
55
|
-
{/* Discount Banners */}
|
|
56
|
-
{banners.length > 0 && (
|
|
57
|
-
<div className="bg-primary text-primary-foreground">
|
|
58
|
-
<div className="mx-auto max-w-7xl px-4 py-2 sm:px-6 lg:px-8">
|
|
59
|
-
<div className="flex items-center justify-center gap-4 overflow-x-auto text-sm font-medium">
|
|
60
|
-
{banners.map((banner) => (
|
|
61
|
-
<span key={banner.ruleId}>{banner.text}</span>
|
|
62
|
-
))}
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
)}
|
|
67
|
-
|
|
68
|
-
{/* Hero Section */}
|
|
69
|
-
<section className="bg-muted">
|
|
70
|
-
<div className="mx-auto max-w-7xl px-4 py-20 text-center sm:px-6 lg:px-8">
|
|
71
|
-
<h1 className="text-foreground text-4xl font-bold tracking-tight sm:text-5xl">
|
|
72
|
-
{t('welcomeTo')} {storeInfo?.name || tc('store')}
|
|
73
|
-
</h1>
|
|
74
|
-
<p className="text-muted-foreground mx-auto mt-4 max-w-2xl text-lg">
|
|
75
|
-
{t('heroSubtitle')}
|
|
76
|
-
</p>
|
|
77
|
-
<Link
|
|
78
|
-
href="/products"
|
|
79
|
-
className="bg-primary text-primary-foreground mt-8 inline-flex items-center rounded px-6 py-3 font-medium transition-opacity hover:opacity-90"
|
|
80
|
-
>
|
|
81
|
-
{tc('shopNow')}
|
|
82
|
-
</Link>
|
|
83
|
-
</div>
|
|
84
|
-
</section>
|
|
85
|
-
|
|
86
|
-
{/* Featured Products */}
|
|
87
|
-
<section className="mx-auto max-w-7xl px-4 py-16 sm:px-6 lg:px-8">
|
|
88
|
-
<div className="mb-8 flex items-center justify-between">
|
|
89
|
-
<h2 className="text-foreground text-2xl font-bold">{t('featuredProducts')}</h2>
|
|
90
|
-
<Link href="/products" className="text-primary text-sm font-medium hover:underline">
|
|
91
|
-
{tc('viewAll')}
|
|
92
|
-
</Link>
|
|
93
|
-
</div>
|
|
94
|
-
<ProductGrid products={products} />
|
|
95
|
-
</section>
|
|
96
|
-
</div>
|
|
97
|
-
);
|
|
98
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* <AllergenChips> — informational allergen markers for storefront PDPs.
|
|
5
|
-
* Pure presentation; no interactivity. Pairs with `<ModifierGroupSelector>`
|
|
6
|
-
* but works standalone next to a product as well.
|
|
7
|
-
*
|
|
8
|
-
* Allergens are descriptive only: the system surfaces them but does not
|
|
9
|
-
* auto-block purchase. Customer-side allergen filtering is a deferred SDK
|
|
10
|
-
* feature (PRD §16).
|
|
11
|
-
*
|
|
12
|
-
* Icon resolution (PRD §15 Q4): when `allergen.iconUrl` is set, use it.
|
|
13
|
-
* Otherwise fall back to a built-in emoji keyed by `allergen.code` for the
|
|
14
|
-
* 8 common allergens listed in PRD §5.7. Stores that want branded icons
|
|
15
|
-
* upload via `iconUrl` per allergen; the rest get a sensible default
|
|
16
|
-
* without any setup.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import type { Allergen } from 'brainerce';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Default emoji per canonical allergen code. The schema's @@unique on
|
|
23
|
-
* `(accountId, storeId, code)` means a store may have at most one of each;
|
|
24
|
-
* any code not in this map renders without an icon (the chip still shows
|
|
25
|
-
* the localized name, so the customer is informed regardless).
|
|
26
|
-
*/
|
|
27
|
-
const DEFAULT_EMOJI_BY_CODE: Record<string, string> = {
|
|
28
|
-
gluten: '🌾',
|
|
29
|
-
dairy: '🥛',
|
|
30
|
-
nuts: '🥜',
|
|
31
|
-
eggs: '🥚',
|
|
32
|
-
soy: '🫘',
|
|
33
|
-
fish: '🐟',
|
|
34
|
-
shellfish: '🦐',
|
|
35
|
-
sesame: '🌱',
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
interface AllergenChipsProps {
|
|
39
|
-
allergens: Allergen[];
|
|
40
|
-
/**
|
|
41
|
-
* When the storefront has more allergen icons than fit nicely, condense
|
|
42
|
-
* to "Contains: X, Y, +N more" instead of rendering every chip.
|
|
43
|
-
*/
|
|
44
|
-
maxVisible?: number;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export function AllergenChips({ allergens, maxVisible = 6 }: AllergenChipsProps) {
|
|
48
|
-
if (!allergens || allergens.length === 0) return null;
|
|
49
|
-
|
|
50
|
-
const visible = allergens.slice(0, maxVisible);
|
|
51
|
-
const overflow = Math.max(0, allergens.length - visible.length);
|
|
52
|
-
|
|
53
|
-
return (
|
|
54
|
-
<span className="allergen-chips" role="list" aria-label="Contains">
|
|
55
|
-
{visible.map((allergen) => {
|
|
56
|
-
const fallbackEmoji = DEFAULT_EMOJI_BY_CODE[allergen.code];
|
|
57
|
-
return (
|
|
58
|
-
<span key={allergen.id} className="allergen-chip" role="listitem" title={allergen.name}>
|
|
59
|
-
{allergen.iconUrl ? (
|
|
60
|
-
<img
|
|
61
|
-
src={allergen.iconUrl}
|
|
62
|
-
alt=""
|
|
63
|
-
aria-hidden="true"
|
|
64
|
-
className="allergen-chip__icon"
|
|
65
|
-
/>
|
|
66
|
-
) : fallbackEmoji ? (
|
|
67
|
-
<span aria-hidden="true" className="allergen-chip__emoji">
|
|
68
|
-
{fallbackEmoji}
|
|
69
|
-
</span>
|
|
70
|
-
) : null}
|
|
71
|
-
<span className="allergen-chip__name">{allergen.name}</span>
|
|
72
|
-
</span>
|
|
73
|
-
);
|
|
74
|
-
})}
|
|
75
|
-
{overflow > 0 && <span className="allergen-chip allergen-chip--more">+{overflow} more</span>}
|
|
76
|
-
</span>
|
|
77
|
-
);
|
|
78
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/nextjs/base/src/{components/content → ui/layout}/announcement-bar.tsx.ejs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|