@fayz-ai/storefront 0.7.0 → 0.8.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/README.md CHANGED
@@ -5,9 +5,11 @@
5
5
  [![npm](https://img.shields.io/npm/v/@fayz-ai/storefront.svg)](https://www.npmjs.com/package/@fayz-ai/storefront)
6
6
  [![license](https://img.shields.io/npm/l/@fayz-ai/storefront.svg)](https://github.com/FayaLabs/fayz-sdk/blob/main/LICENSE)
7
7
 
8
+ **Status:** beta — published to npm and used across Fayz dogfood apps. Pre-1.0: minor APIs may change before 1.0.
9
+
8
10
  `@fayz-ai/storefront` is the customer-facing surface of the Fayz SDK: a storefront scaffold that renders a page as a tree of **blocks** (hero, products, manifesto, cart, …) defined in the app manifest. Two completely different brands come out of the same template with zero custom components — the storefront is *data*, not a fork.
9
11
 
10
- It reads commerce from `@fayz-ai/shop`, so the same engine powering an admin also powers the public store. Customize from labels to a fully bespoke section via the [customization ladder](../../docs/customization-ladder.md) — never by editing this package.
12
+ It reads commerce from `@fayz-ai/shop`, so the same engine powering an admin also powers the public store. Customize from labels to a fully bespoke section via the [customization ladder](../../docs/CUSTOMIZATION.md) — never by editing this package.
11
13
 
12
14
  ## What's inside
13
15
  - **Scaffold** — `defineStorefront(config)` + `StorefrontScaffold` rendered by `renderApp`
@@ -1 +1 @@
1
- {"version":3,"file":"StorefrontHeader.d.ts","sourceRoot":"","sources":["../../src/components/StorefrontHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAkRvC,wBAAgB,gBAAgB,sBAwE/B"}
1
+ {"version":3,"file":"StorefrontHeader.d.ts","sourceRoot":"","sources":["../../src/components/StorefrontHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AA0SvC,wBAAgB,gBAAgB,sBA2E/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"createStorefrontApp.d.ts","sourceRoot":"","sources":["../src/createStorefrontApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,OAAO,KAAK,EAAE,gBAAgB,EAA4B,MAAM,UAAU,CAAA;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AA0GnD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAmBpE;AAED;gFACgF;AAChF,wBAAgB,eAAe,sBAkC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAajF;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,gBAAgB,CAAA;IACxB,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IACnC,KAAK,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAClC,QAAQ,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;CACxC;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,KAAK,CAAC,aAAa,CAgBtF"}
1
+ {"version":3,"file":"createStorefrontApp.d.ts","sourceRoot":"","sources":["../src/createStorefrontApp.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAG1D,OAAO,KAAK,EAAE,gBAAgB,EAA4B,MAAM,UAAU,CAAA;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AA2GnD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAmCpE;AAED;gFACgF;AAChF,wBAAgB,eAAe,sBAkC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAajF;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,gBAAgB,CAAA;IACxB,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IACnC,KAAK,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAClC,QAAQ,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAA;CACxC;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,KAAK,CAAC,aAAa,CAgBtF"}
package/dist/index.cjs CHANGED
@@ -229,92 +229,6 @@ function matchPath(pattern, path) {
229
229
  function Link({ to, children, ...rest }) {
230
230
  return React6__default.default.createElement("a", { href: `#${to}`, ...rest }, children);
231
231
  }
232
- var RADIUS_MAP = {
233
- none: { button: "0px", card: "0px", input: "0px" },
234
- soft: { button: "6px", card: "10px", input: "6px" },
235
- round: { button: "10px", card: "16px", input: "10px" },
236
- pill: { button: "999px", card: "20px", input: "999px" }
237
- };
238
- var COLOR_VAR_MAP = {
239
- background: "--background",
240
- foreground: "--foreground",
241
- primary: "--primary",
242
- primaryForeground: "--primary-foreground",
243
- card: "--card",
244
- cardForeground: "--card-foreground",
245
- muted: "--muted",
246
- mutedForeground: "--muted-foreground",
247
- border: "--border",
248
- headerBackground: "--sf-header-bg",
249
- headerForeground: "--sf-header-fg",
250
- announcementBackground: "--sf-announcement-bg",
251
- announcementForeground: "--sf-announcement-fg"
252
- };
253
- function themeToCss(theme) {
254
- const lines = [];
255
- for (const [key, cssVar] of Object.entries(COLOR_VAR_MAP)) {
256
- const value = theme.colors?.[key];
257
- if (value) lines.push(`${cssVar}: ${value};`);
258
- }
259
- if (!theme.colors?.headerBackground && theme.colors?.background) {
260
- lines.push(`--sf-header-bg: ${theme.colors.background};`);
261
- }
262
- if (!theme.colors?.headerForeground && theme.colors?.foreground) {
263
- lines.push(`--sf-header-fg: ${theme.colors.foreground};`);
264
- }
265
- if (theme.font) {
266
- const fallback = theme.font.fallback ?? "sans-serif";
267
- lines.push(`--font-family: '${theme.font.body}', ${fallback};`);
268
- lines.push(`--sf-font-heading: '${theme.font.heading}', ${fallback};`);
269
- }
270
- const radius = RADIUS_MAP[theme.radius ?? "soft"];
271
- lines.push(`--button-radius: ${radius.button};`);
272
- lines.push(`--card-radius: ${radius.card};`);
273
- lines.push(`--input-radius: ${radius.input};`);
274
- lines.push(`--sf-radius-button: ${radius.button};`);
275
- lines.push(`--sf-radius-card: ${radius.card};`);
276
- lines.push(`--sf-radius-input: ${radius.input};`);
277
- let css = `:root {
278
- ${lines.join("\n ")}
279
- }
280
- `;
281
- css += `body { font-family: var(--font-family); }
282
- `;
283
- css += `h1, h2, h3, h4, .sf-heading { font-family: var(--sf-font-heading, var(--font-family)); }
284
- `;
285
- if (theme.uppercaseButtons) {
286
- css += `.sf-cta { text-transform: uppercase; letter-spacing: 0.08em; }
287
- `;
288
- }
289
- if (theme.header?.uppercaseNav) {
290
- css += `.sf-nav-link { text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.8rem; }
291
- `;
292
- }
293
- return css;
294
- }
295
- function googleFontsHref(theme) {
296
- if (!theme.font) return null;
297
- const families = theme.font.googleFonts ?? [theme.font.heading, theme.font.body];
298
- const unique = [...new Set(families)];
299
- const params = unique.map((f) => `family=${encodeURIComponent(f).replace(/%20/g, "+")}:wght@300;400;500;600;700`).join("&");
300
- return `https://fonts.googleapis.com/css2?${params}&display=swap`;
301
- }
302
- function StorefrontThemeStyle({ theme }) {
303
- const fontsHref = googleFontsHref(theme);
304
- React6.useEffect(() => {
305
- if (!fontsHref) return;
306
- const id = "sf-theme-fonts";
307
- let link = document.getElementById(id);
308
- if (!link) {
309
- link = document.createElement("link");
310
- link.id = id;
311
- link.rel = "stylesheet";
312
- document.head.appendChild(link);
313
- }
314
- link.href = fontsHref;
315
- }, [fontsHref]);
316
- return React6__default.default.createElement("style", { "data-sf-theme": theme.name }, themeToCss(theme));
317
- }
318
232
 
319
233
  // src/format.ts
320
234
  function formatMoney(value, currency = "BRL", locale = "pt-BR") {
@@ -367,7 +281,7 @@ function productOptionSelectionKey(selection) {
367
281
  // src/stores/cart.store.ts
368
282
  var useCartStore = zustand.create()(
369
283
  middleware.persist(
370
- (set) => ({
284
+ (set, get) => ({
371
285
  lines: [],
372
286
  discountCode: null,
373
287
  discountPercent: 0,
@@ -419,7 +333,16 @@ var useCartStore = zustand.create()(
419
333
  clearDiscount: () => set({ discountCode: null, discountPercent: 0 }),
420
334
  clear: () => set({ lines: [], discountCode: null, discountPercent: 0 }),
421
335
  openDrawer: () => set({ isOpen: true }),
422
- closeDrawer: () => set({ isOpen: false, justAddedLineId: null })
336
+ closeDrawer: () => set({ isOpen: false, justAddedLineId: null }),
337
+ reconcile: async (resolve) => {
338
+ const lines = get().lines;
339
+ if (lines.length === 0) return;
340
+ const keep = await Promise.all(
341
+ lines.map((line) => resolve(line).catch(() => true))
342
+ );
343
+ const kept = lines.filter((_, i) => keep[i]);
344
+ if (kept.length !== lines.length) set({ lines: kept });
345
+ }
423
346
  }),
424
347
  {
425
348
  name: "fayz.storefront.cart.v1",
@@ -441,6 +364,102 @@ var selectShipping = (s, cfg) => {
441
364
  return cfg.shipping.flatRate;
442
365
  };
443
366
  var selectTotal = (s, cfg) => roundCents(selectSubtotal(s) - selectDiscountTotal(s) + selectShipping(s, cfg));
367
+ var RADIUS_MAP = {
368
+ none: { button: "0px", card: "0px", input: "0px" },
369
+ soft: { button: "6px", card: "10px", input: "6px" },
370
+ round: { button: "10px", card: "16px", input: "10px" },
371
+ pill: { button: "999px", card: "20px", input: "999px" }
372
+ };
373
+ var COLOR_VAR_MAP = {
374
+ background: "--background",
375
+ foreground: "--foreground",
376
+ primary: "--primary",
377
+ primaryForeground: "--primary-foreground",
378
+ card: "--card",
379
+ cardForeground: "--card-foreground",
380
+ muted: "--muted",
381
+ mutedForeground: "--muted-foreground",
382
+ border: "--border",
383
+ headerBackground: "--sf-header-bg",
384
+ headerForeground: "--sf-header-fg",
385
+ announcementBackground: "--sf-announcement-bg",
386
+ announcementForeground: "--sf-announcement-fg",
387
+ accent: "--sf-accent",
388
+ accentForeground: "--sf-accent-foreground"
389
+ };
390
+ function themeToCss(theme) {
391
+ const lines = [];
392
+ for (const [key, cssVar] of Object.entries(COLOR_VAR_MAP)) {
393
+ const value = theme.colors?.[key];
394
+ if (value) lines.push(`${cssVar}: ${value};`);
395
+ }
396
+ if (!theme.colors?.headerBackground && theme.colors?.background) {
397
+ lines.push(`--sf-header-bg: ${theme.colors.background};`);
398
+ }
399
+ if (!theme.colors?.headerForeground && theme.colors?.foreground) {
400
+ lines.push(`--sf-header-fg: ${theme.colors.foreground};`);
401
+ }
402
+ if (theme.font) {
403
+ const fallback = theme.font.fallback ?? "sans-serif";
404
+ lines.push(`--font-family: '${theme.font.body}', ${fallback};`);
405
+ lines.push(`--sf-font-heading: '${theme.font.heading}', ${fallback};`);
406
+ if (theme.font.display) lines.push(`--sf-font-display: '${theme.font.display}', ${fallback};`);
407
+ if (theme.font.serif) lines.push(`--sf-font-serif: '${theme.font.serif}', serif;`);
408
+ }
409
+ for (const [key, value] of Object.entries(theme.tokens ?? {})) {
410
+ const name = key.startsWith("--") ? key : `--${key}`;
411
+ lines.push(`${name}: ${value};`);
412
+ }
413
+ const radius = RADIUS_MAP[theme.radius ?? "soft"];
414
+ lines.push(`--button-radius: ${radius.button};`);
415
+ lines.push(`--card-radius: ${radius.card};`);
416
+ lines.push(`--input-radius: ${radius.input};`);
417
+ lines.push(`--sf-radius-button: ${radius.button};`);
418
+ lines.push(`--sf-radius-card: ${radius.card};`);
419
+ lines.push(`--sf-radius-input: ${radius.input};`);
420
+ let css = `:root {
421
+ ${lines.join("\n ")}
422
+ }
423
+ `;
424
+ css += `body { font-family: var(--font-family); }
425
+ `;
426
+ css += `h1, h2, h3, h4, .sf-heading { font-family: var(--sf-font-heading, var(--font-family)); }
427
+ `;
428
+ if (theme.uppercaseButtons) {
429
+ css += `.sf-cta { text-transform: uppercase; letter-spacing: 0.08em; }
430
+ `;
431
+ }
432
+ if (theme.header?.uppercaseNav) {
433
+ css += `.sf-nav-link { text-transform: uppercase; letter-spacing: 0.06em; font-size: 0.8rem; }
434
+ `;
435
+ }
436
+ return css;
437
+ }
438
+ function googleFontsHref(theme) {
439
+ if (!theme.font) return null;
440
+ const families = theme.font.googleFonts ?? [theme.font.heading, theme.font.body, theme.font.display, theme.font.serif].filter(
441
+ (f) => Boolean(f)
442
+ );
443
+ const unique = [...new Set(families)];
444
+ const params = unique.map((f) => `family=${encodeURIComponent(f).replace(/%20/g, "+")}:wght@300;400;500;600;700`).join("&");
445
+ return `https://fonts.googleapis.com/css2?${params}&display=swap`;
446
+ }
447
+ function StorefrontThemeStyle({ theme }) {
448
+ const fontsHref = googleFontsHref(theme);
449
+ React6.useEffect(() => {
450
+ if (!fontsHref) return;
451
+ const id = "sf-theme-fonts";
452
+ let link = document.getElementById(id);
453
+ if (!link) {
454
+ link = document.createElement("link");
455
+ link.id = id;
456
+ link.rel = "stylesheet";
457
+ document.head.appendChild(link);
458
+ }
459
+ link.href = fontsHref;
460
+ }, [fontsHref]);
461
+ return React6__default.default.createElement("style", { "data-sf-theme": theme.name }, themeToCss(theme));
462
+ }
444
463
  var initial = {
445
464
  search: "",
446
465
  categoryId: null,
@@ -549,6 +568,7 @@ function usePopOnChange(value) {
549
568
  var TID = {
550
569
  // header
551
570
  headerSearch: "header-search",
571
+ headerSearchToggle: "header-search-toggle",
552
572
  cartButton: "cart-button",
553
573
  cartCount: "cart-count",
554
574
  accountLink: "account-link",
@@ -737,12 +757,26 @@ function UtilityBar() {
737
757
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto flex items-center gap-4", children: social?.map((s) => /* @__PURE__ */ jsxRuntime.jsx("a", { href: s.href, target: "_blank", rel: "noreferrer", className: "hover:underline", children: s.label }, s.href)) })
738
758
  ] }) });
739
759
  }
740
- function SearchInput({ className }) {
760
+ function SearchInput({ className, iconOnly = false }) {
741
761
  const config = useStorefrontConfig();
742
762
  const search = useCatalogStore((s) => s.search);
743
763
  const setSearch = useCatalogStore((s) => s.setSearch);
744
764
  const path = useHashPath();
745
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative ${className ?? ""}`, children: [
765
+ const [open, setOpen] = React6.useState(false);
766
+ if (iconOnly && !open) {
767
+ return /* @__PURE__ */ jsxRuntime.jsx(
768
+ "button",
769
+ {
770
+ type: "button",
771
+ "aria-label": "Buscar produtos",
772
+ "data-testid": TID.headerSearchToggle,
773
+ onClick: () => setOpen(true),
774
+ className: "rounded-full p-2.5 transition-opacity hover:opacity-70",
775
+ children: /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Search, { className: "h-5 w-5" })
776
+ }
777
+ );
778
+ }
779
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `relative ${iconOnly ? "w-full max-w-xs" : className ?? ""}`, children: [
746
780
  /* @__PURE__ */ jsxRuntime.jsx(LucideIcons.Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 opacity-60" }),
747
781
  /* @__PURE__ */ jsxRuntime.jsx(
748
782
  "input",
@@ -751,10 +785,17 @@ function SearchInput({ className }) {
751
785
  type: "search",
752
786
  placeholder: "Buscar produtos...",
753
787
  value: search,
788
+ autoFocus: iconOnly,
754
789
  onChange: (e) => {
755
790
  setSearch(e.target.value);
756
791
  if (path !== config.catalogPath) navigateTo(config.catalogPath);
757
792
  },
793
+ onKeyDown: (e) => {
794
+ if (e.key === "Escape" && iconOnly) setOpen(false);
795
+ },
796
+ onBlur: () => {
797
+ if (iconOnly && !search) setOpen(false);
798
+ },
758
799
  className: "w-full border bg-white/10 py-2 pl-9 pr-4 text-sm outline-none transition-colors placeholder:opacity-60 focus:border-primary focus:bg-white focus:text-gray-900",
759
800
  style: {
760
801
  borderRadius: "var(--sf-radius-input)",
@@ -907,6 +948,7 @@ function StorefrontHeader() {
907
948
  const variant = config.theme?.header?.variant ?? "classic";
908
949
  const scrolled = useScrolled();
909
950
  const showSearch = config.theme?.header?.showSearch !== false;
951
+ const iconSearch = config.theme?.header?.searchStyle === "icon";
910
952
  const logo = /* @__PURE__ */ jsxRuntime.jsx(Link, { to: "/", className: "sf-heading shrink-0 text-xl font-bold tracking-tight", children: config.logo ?? config.name });
911
953
  return /* @__PURE__ */ jsxRuntime.jsxs(
912
954
  "header",
@@ -920,7 +962,7 @@ function StorefrontHeader() {
920
962
  // Rio/Flex pattern: centered logo row, nav row below
921
963
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
922
964
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto grid h-16 max-w-7xl grid-cols-[1fr_auto_1fr] items-center px-4 sm:px-6", children: [
923
- showSearch ? /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { className: "hidden w-full max-w-xs sm:block" }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
965
+ showSearch ? /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { iconOnly: iconSearch, className: "hidden w-full max-w-xs sm:block" }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
924
966
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: logo }),
925
967
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "justify-self-end", children: /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, {}) })
926
968
  ] }),
@@ -930,7 +972,7 @@ function StorefrontHeader() {
930
972
  // Brasília pattern: prominent search left, logo center, actions right; nav row below
931
973
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
932
974
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto grid h-16 max-w-7xl grid-cols-[1fr_auto_1fr] items-center gap-6 px-4 sm:px-6", children: [
933
- showSearch ? /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { className: "hidden w-full max-w-sm sm:block" }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
975
+ showSearch ? /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { iconOnly: iconSearch, className: "hidden w-full max-w-sm sm:block" }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
934
976
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: logo }),
935
977
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "justify-self-end", children: /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, {}) })
936
978
  ] }),
@@ -942,17 +984,19 @@ function StorefrontHeader() {
942
984
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-5", children: /* @__PURE__ */ jsxRuntime.jsx(NavLinks, { className: "hidden sm:flex" }) }),
943
985
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center", children: logo }),
944
986
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-3", children: [
945
- showSearch && /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { className: "hidden w-44 lg:block" }),
987
+ showSearch && /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { iconOnly: iconSearch, className: "hidden w-44 lg:block" }),
946
988
  /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, {})
947
989
  ] })
948
990
  ] })
949
991
  ) : (
950
- // classic: logo left, search center-right, actions right (original layout)
992
+ // classic: logo left, nav, then a right-aligned search + actions cluster
951
993
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto flex h-16 max-w-7xl items-center gap-6 px-4 sm:px-6", children: [
952
994
  logo,
953
995
  /* @__PURE__ */ jsxRuntime.jsx(NavLinks, { className: "hidden md:flex" }),
954
- showSearch && /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { className: "ml-auto hidden w-full max-w-sm sm:block" }),
955
- /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, {})
996
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "ml-auto flex items-center gap-2 sm:gap-3", children: [
997
+ showSearch && /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { iconOnly: iconSearch, className: iconSearch ? "" : "hidden w-full max-w-sm sm:block" }),
998
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, {})
999
+ ] })
956
1000
  ] })
957
1001
  )
958
1002
  ]
@@ -2960,7 +3004,8 @@ async function placeStorefrontOrder({
2960
3004
  }))
2961
3005
  });
2962
3006
  if (markPaid) {
2963
- await provider.updateOrder(order.id, { financialStatus: "paid" });
3007
+ if (provider.confirmPayment) await provider.confirmPayment(order.id);
3008
+ else await provider.updateOrder(order.id, { financialStatus: "paid" });
2964
3009
  }
2965
3010
  return { order, customerId: customerId ?? order.customerId ?? "" };
2966
3011
  }
@@ -4440,6 +4485,15 @@ function initStorefrontRuntime(config) {
4440
4485
  } else {
4441
4486
  runtime.setShopProvider(mock.createMockShopProvider(buildMockSeed(config)));
4442
4487
  }
4488
+ const reconcileCart = () => {
4489
+ const provider = runtime.getShopProvider();
4490
+ void useCartStore.getState().reconcile(async (line) => {
4491
+ const product = await provider.getProduct(line.productId);
4492
+ return product != null;
4493
+ });
4494
+ };
4495
+ if (useCartStore.persist.hasHydrated()) reconcileCart();
4496
+ else useCartStore.persist.onFinishHydration(reconcileCart);
4443
4497
  if (config.supabaseUrl || config.supabaseAnonKey) {
4444
4498
  console.warn(
4445
4499
  "@fayz-ai/shop: supabaseUrl/supabaseAnonKey are legacy fields. Pass an explicit provider/adapter or use the Fayz SDK broker path."
@@ -4799,11 +4853,73 @@ var atelierTemplate = {
4799
4853
  ]
4800
4854
  })
4801
4855
  };
4856
+ var foodTemplate = {
4857
+ id: "food",
4858
+ inspiration: "Delivery / restaurant storefront",
4859
+ announcement: "ENTREGA GR\xC1TIS ACIMA DE R$ 150 \xB7 PE\xC7A J\xC1",
4860
+ theme: {
4861
+ name: "food",
4862
+ colors: {
4863
+ background: "30 33% 97%",
4864
+ foreground: "20 14% 15%",
4865
+ primary: "14 84% 50%",
4866
+ primaryForeground: "0 0% 100%",
4867
+ card: "30 33% 99%",
4868
+ cardForeground: "20 14% 15%",
4869
+ muted: "28 20% 92%",
4870
+ mutedForeground: "22 10% 42%",
4871
+ border: "28 18% 85%",
4872
+ headerBackground: "20 14% 11%",
4873
+ headerForeground: "30 24% 96%",
4874
+ announcementBackground: "14 84% 50%",
4875
+ announcementForeground: "0 0% 100%"
4876
+ },
4877
+ font: { heading: "Poppins", body: "Inter" },
4878
+ radius: "round",
4879
+ header: { variant: "classic" },
4880
+ productCard: { style: "card", imageAspect: "square" }
4881
+ },
4882
+ home: (storeName, images) => ({
4883
+ sections: [
4884
+ {
4885
+ type: "hero",
4886
+ variant: "banner",
4887
+ height: "tall",
4888
+ slides: [
4889
+ { title: "Sabor de verdade, na sua porta", subtitle: `${storeName} \u2014 feito na hora, do jeito que voc\xEA ama.`, cta: "Ver card\xE1pio", href: "/catalog", hue: 20, image: images?.hero?.[0] }
4890
+ ]
4891
+ },
4892
+ {
4893
+ type: "benefits",
4894
+ items: [
4895
+ { icon: "Flame", title: "Feito na hora", text: "Preparado com capricho" },
4896
+ { icon: "Truck", title: "Entrega r\xE1pida", text: "Frete gr\xE1tis acima de R$ 150" },
4897
+ { icon: "CreditCard", title: "Pagamento f\xE1cil", text: "Pix, cart\xE3o e mais" }
4898
+ ]
4899
+ },
4900
+ { type: "categories", style: "tiles", title: "Nosso card\xE1pio" },
4901
+ { type: "products", title: "Mais pedidos", eyebrow: "favoritos da casa", filter: "all", limit: 8 },
4902
+ { type: "banner", title: "Combo do dia", eyebrow: "oferta", subtitle: "Sele\xE7\xE3o especial com desconto", cta: "Aproveitar", hue: 14, image: images?.banners?.[0] },
4903
+ { type: "products", title: "Novidades no card\xE1pio", filter: "new", limit: 4 },
4904
+ {
4905
+ type: "testimonials",
4906
+ title: "O que dizem por a\xED",
4907
+ items: [
4908
+ { quote: "Chegou quentinho e absurdo de bom. Virei cliente!", author: "Rafael M." },
4909
+ { quote: "Sabor de restaurante em casa, sem complica\xE7\xE3o.", author: "Beatriz L." },
4910
+ { quote: "Entrega r\xE1pida e por\xE7\xE3o generosa. Recomendo demais.", author: "Diego S." }
4911
+ ]
4912
+ },
4913
+ { type: "newsletter", title: "Receba nossas ofertas", subtitle: "Promo\xE7\xF5es e novidades do card\xE1pio, direto no seu e-mail." }
4914
+ ]
4915
+ })
4916
+ };
4802
4917
  var storefrontTemplates = {
4803
4918
  mare: mareTemplate,
4804
4919
  sertao: sertaoTemplate,
4805
4920
  volt: voltTemplate,
4806
- atelier: atelierTemplate
4921
+ atelier: atelierTemplate,
4922
+ food: foodTemplate
4807
4923
  };
4808
4924
 
4809
4925
  Object.defineProperty(exports, "getSupabaseClientOptional", {
@@ -4860,6 +4976,7 @@ exports.defineStorefrontConfig = defineStorefrontConfig;
4860
4976
  exports.defineStorefrontRoutes = defineStorefrontRoutes;
4861
4977
  exports.defineStorefrontSections = defineStorefrontSections;
4862
4978
  exports.establishCustomerSession = establishCustomerSession;
4979
+ exports.foodTemplate = foodTemplate;
4863
4980
  exports.formatMoney = formatMoney;
4864
4981
  exports.formatProductOptionSelection = formatProductOptionSelection;
4865
4982
  exports.getCustomerAuthAdapter = getCustomerAuthAdapter;