cloudcommerce 0.22.1 → 0.22.3

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.
Files changed (167) hide show
  1. package/.editorconfig +13 -0
  2. package/.gitmodules +3 -0
  3. package/.vscode/settings.json +2 -1
  4. package/CHANGELOG.md +25 -0
  5. package/ecomplus-stores/barra-doce/.devcontainer/devcontainer.json +30 -0
  6. package/ecomplus-stores/barra-doce/.editorconfig +13 -0
  7. package/ecomplus-stores/barra-doce/.eslintrc.cjs +3 -0
  8. package/ecomplus-stores/barra-doce/.firebaserc +5 -0
  9. package/ecomplus-stores/barra-doce/.github/build-and-deploy +1 -0
  10. package/ecomplus-stores/barra-doce/.github/renovate.json +5 -0
  11. package/ecomplus-stores/barra-doce/.github/workflows/build-and-deploy.yml +36 -0
  12. package/ecomplus-stores/barra-doce/.github/workflows/calibreapp-image-actions.yml +23 -0
  13. package/ecomplus-stores/barra-doce/.gitpod.yml +12 -0
  14. package/ecomplus-stores/barra-doce/.nvmrc +1 -0
  15. package/ecomplus-stores/barra-doce/.vscode/extensions.json +8 -0
  16. package/ecomplus-stores/barra-doce/.vscode/launch.json +11 -0
  17. package/ecomplus-stores/barra-doce/.vscode/settings.json +10 -0
  18. package/ecomplus-stores/barra-doce/LICENSE.md +230 -0
  19. package/ecomplus-stores/barra-doce/README.md +31 -0
  20. package/ecomplus-stores/barra-doce/SETUP.md +117 -0
  21. package/ecomplus-stores/{iluminim/README.pt-BR.md → barra-doce/SETUP.pt-BR.md} +5 -1
  22. package/ecomplus-stores/barra-doce/functions/config.json +3 -0
  23. package/ecomplus-stores/barra-doce/functions/example.env +10 -0
  24. package/ecomplus-stores/barra-doce/functions/many/index.js +14 -0
  25. package/ecomplus-stores/barra-doce/functions/many/package.json +22 -0
  26. package/ecomplus-stores/barra-doce/functions/ssr/.eslintrc.cjs +6 -0
  27. package/ecomplus-stores/barra-doce/functions/ssr/astro.config.mjs +4 -0
  28. package/ecomplus-stores/barra-doce/functions/ssr/content/blog/.gitkeep +0 -0
  29. package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/.gitkeep +0 -0
  30. package/ecomplus-stores/barra-doce/functions/ssr/content/layout.json +37 -0
  31. package/ecomplus-stores/barra-doce/functions/ssr/content/pages/home.json +33 -0
  32. package/ecomplus-stores/barra-doce/functions/ssr/content/settings.json +48 -0
  33. package/ecomplus-stores/barra-doce/functions/ssr/index.js +18 -0
  34. package/ecomplus-stores/barra-doce/functions/ssr/package.json +31 -0
  35. package/ecomplus-stores/barra-doce/functions/ssr/public/admin/.gitkeep +2 -0
  36. package/ecomplus-stores/barra-doce/functions/ssr/public/assets/.gitkeep +2 -0
  37. package/ecomplus-stores/barra-doce/functions/ssr/public/img/icon.png +0 -0
  38. package/ecomplus-stores/barra-doce/functions/ssr/public/img/large-icon.png +0 -0
  39. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/banner-forma-decora.jpg +0 -0
  40. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/banner2.webp +0 -0
  41. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/ecom-icon.png +0 -0
  42. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/headphone.webp +0 -0
  43. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/logo-barradoce.webp +0 -0
  44. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/logo.png +0 -0
  45. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/og-image.png +0 -0
  46. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/passion.webp +0 -0
  47. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/rect8589.png +0 -0
  48. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/rect859.png +0 -0
  49. package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/rect89.webp +0 -0
  50. package/ecomplus-stores/barra-doce/functions/ssr/public/robots.txt +8 -0
  51. package/ecomplus-stores/barra-doce/functions/ssr/scripts/build.sh +14 -0
  52. package/ecomplus-stores/barra-doce/functions/ssr/src/assets/style.css +65 -0
  53. package/ecomplus-stores/barra-doce/functions/ssr/src/components/AccountMenu.vue +104 -0
  54. package/ecomplus-stores/barra-doce/functions/ssr/src/components/Banner.vue +64 -0
  55. package/ecomplus-stores/barra-doce/functions/ssr/src/components/BannersGrid.astro +25 -0
  56. package/ecomplus-stores/barra-doce/functions/ssr/src/components/CartSidebar.vue +35 -0
  57. package/ecomplus-stores/barra-doce/functions/ssr/src/components/HeroSlider.vue +51 -0
  58. package/ecomplus-stores/barra-doce/functions/ssr/src/components/PitchBar.vue +53 -0
  59. package/ecomplus-stores/barra-doce/functions/ssr/src/components/Prices.vue +96 -0
  60. package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductCard.vue +117 -0
  61. package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductShelf.vue +60 -0
  62. package/ecomplus-stores/barra-doce/functions/ssr/src/components/SearchModal.vue +6 -0
  63. package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeader.vue +180 -0
  64. package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeaderMenu.vue +66 -0
  65. package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeaderSubmenu.vue +90 -0
  66. package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopSidenav.vue +61 -0
  67. package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopSidenavCategory.vue +80 -0
  68. package/ecomplus-stores/barra-doce/functions/ssr/src/env.d.ts +13 -0
  69. package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/Base.astro +15 -0
  70. package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/Checkout.astro +0 -0
  71. package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/PageHeader.astro +42 -0
  72. package/ecomplus-stores/barra-doce/functions/ssr/src/main/Fallback.astro +10 -0
  73. package/ecomplus-stores/barra-doce/functions/ssr/src/main/Home.astro +30 -0
  74. package/ecomplus-stores/barra-doce/functions/ssr/src/main/Sections.astro +29 -0
  75. package/ecomplus-stores/barra-doce/functions/ssr/src/main/Wildcard.astro +18 -0
  76. package/ecomplus-stores/barra-doce/functions/ssr/src/pages/[...slug].astro +40 -0
  77. package/ecomplus-stores/barra-doce/functions/ssr/src/pages/_vue.ts +3 -0
  78. package/ecomplus-stores/barra-doce/functions/ssr/src/pages/app/account.astro +0 -0
  79. package/ecomplus-stores/barra-doce/functions/ssr/src/pages/app/index.astro +0 -0
  80. package/ecomplus-stores/barra-doce/functions/ssr/src/pages/fallback.astro +25 -0
  81. package/ecomplus-stores/barra-doce/functions/ssr/src/pages/index.astro +35 -0
  82. package/ecomplus-stores/barra-doce/functions/ssr/src/scripts/InlineScripts.astro +10 -0
  83. package/ecomplus-stores/barra-doce/functions/ssr/tailwind.config.cjs +19 -0
  84. package/ecomplus-stores/barra-doce/functions/ssr/tsconfig.json +12 -0
  85. package/ecomplus-stores/barra-doce/functions/ssr/uno.config.cjs +5 -0
  86. package/ecomplus-stores/barra-doce/functions/with-apps/index.js +12 -0
  87. package/ecomplus-stores/barra-doce/functions/with-apps/package.json +22 -0
  88. package/ecomplus-stores/barra-doce/package.json +28 -0
  89. package/ecomplus-stores/barra-doce/scripts/install.sh +14 -0
  90. package/ecomplus-stores/iluminim/.ecomplus.cd.json +5 -0
  91. package/ecomplus-stores/iluminim/.editorconfig +13 -0
  92. package/ecomplus-stores/iluminim/README.md +11 -93
  93. package/ecomplus-stores/iluminim/SETUP.md +117 -0
  94. package/ecomplus-stores/iluminim/SETUP.pt-BR.md +117 -0
  95. package/ecomplus-stores/iluminim/functions/many/package.json +3 -3
  96. package/ecomplus-stores/iluminim/functions/ssr/package.json +6 -6
  97. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopHeaderSubmenu.vue +1 -1
  98. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopSidenav.vue +2 -2
  99. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopSidenavCategory.vue +4 -2
  100. package/ecomplus-stores/iluminim/functions/ssr/src/layouts/PageHeader.astro +10 -1
  101. package/ecomplus-stores/iluminim/functions/with-apps/package.json +3 -3
  102. package/ecomplus-stores/iluminim/package.json +1 -1
  103. package/package.json +1 -1
  104. package/packages/api/package.json +1 -1
  105. package/packages/apps/affilate-program/package.json +1 -1
  106. package/packages/apps/correios/package.json +1 -1
  107. package/packages/apps/custom-payment/package.json +1 -1
  108. package/packages/apps/custom-shipping/package.json +1 -1
  109. package/packages/apps/datafrete/package.json +1 -1
  110. package/packages/apps/discounts/package.json +1 -1
  111. package/packages/apps/emails/package.json +1 -1
  112. package/packages/apps/fb-conversions/package.json +1 -1
  113. package/packages/apps/flash-courier/package.json +1 -1
  114. package/packages/apps/frenet/package.json +1 -1
  115. package/packages/apps/galaxpay/package.json +1 -1
  116. package/packages/apps/google-analytics/package.json +1 -1
  117. package/packages/apps/jadlog/package.json +1 -1
  118. package/packages/apps/loyalty-points/package.json +1 -1
  119. package/packages/apps/melhor-envio/package.json +1 -1
  120. package/packages/apps/mercadopago/package.json +1 -1
  121. package/packages/apps/pagarme/package.json +1 -1
  122. package/packages/apps/paghiper/package.json +1 -1
  123. package/packages/apps/pix/package.json +1 -1
  124. package/packages/apps/tiny-erp/package.json +1 -1
  125. package/packages/apps/webhooks/package.json +1 -1
  126. package/packages/cli/package.json +1 -1
  127. package/packages/config/package.json +1 -1
  128. package/packages/emails/package.json +1 -1
  129. package/packages/events/package.json +1 -1
  130. package/packages/feeds/package.json +1 -1
  131. package/packages/firebase/package.json +1 -1
  132. package/packages/i18n/package.json +1 -1
  133. package/packages/modules/package.json +1 -1
  134. package/packages/passport/package.json +1 -1
  135. package/packages/ssr/package.json +1 -1
  136. package/packages/storefront/dist/client/_astro/HeroSlider.cea1f361.js +1 -0
  137. package/packages/storefront/dist/client/_astro/{ProductShelf.9e290480.js → ProductShelf.35614736.js} +1 -1
  138. package/packages/storefront/dist/client/_astro/ShopHeader.1c27e68e.js +4 -0
  139. package/packages/storefront/dist/client/_astro/{_...slug_.2f4f6929.css → _...slug_.c13e0486.css} +1 -1
  140. package/packages/storefront/dist/client/sw.js +1 -1
  141. package/packages/storefront/dist/server/chunks/{_...d496b072.mjs → _...75363048.mjs} +2 -2
  142. package/packages/storefront/dist/server/chunks/{account@_@astro.1b311a3d.mjs → account@_@astro.12fbe243.mjs} +1 -1
  143. package/packages/storefront/dist/server/chunks/{endpoint@_@js.631ff6c5.mjs → endpoint@_@js.67b66d0a.mjs} +2 -2
  144. package/packages/storefront/dist/server/chunks/{fallback@_@astro.12cf85ba.mjs → fallback@_@astro.0a6656b6.mjs} +2 -2
  145. package/packages/storefront/dist/server/chunks/{index@_@astro.69eb5e8a.mjs → index@_@astro.a4c9c84e.mjs} +2 -2
  146. package/packages/storefront/dist/server/chunks/{index@_@astro.a20d91aa.mjs → index@_@astro.df499bf2.mjs} +2 -2
  147. package/packages/storefront/dist/server/chunks/pages/{_...slug_.astro.c93fc36d.mjs → _...slug_.astro.a71c9334.mjs} +77 -38
  148. package/packages/storefront/dist/server/chunks/pages/{endpoint.js.630b1212.mjs → endpoint.js.085dadb5.mjs} +1 -1
  149. package/packages/storefront/dist/server/chunks/pages/{fallback.astro.58c7e581.mjs → fallback.astro.055cb7df.mjs} +1 -1
  150. package/packages/storefront/dist/server/chunks/pages/{index.astro.6efe85be.mjs → index.astro.abc34f72.mjs} +5 -5
  151. package/packages/storefront/dist/server/entry.mjs +8 -8
  152. package/packages/storefront/dist/server/renderers.mjs +1 -1
  153. package/packages/storefront/package.json +1 -1
  154. package/packages/storefront/src/lib/$storefront.d.ts +1 -0
  155. package/packages/storefront/src/lib/components/SharedData.astro +12 -0
  156. package/packages/storefront/src/lib/composables/use-prices.ts +1 -1
  157. package/packages/storefront/src/lib/composables/use-shared-data.ts +18 -0
  158. package/packages/storefront/src/lib/composables/use-shop-header-submenu.ts +10 -1
  159. package/packages/storefront/src/lib/composables/use-shop-header.ts +20 -19
  160. package/packages/storefront/src/lib/composables/use-sticky-header.ts +1 -1
  161. package/packages/storefront/src/lib/layouts/BaseHead.astro +1 -1
  162. package/packages/storefront/src/lib/layouts/use-page-header.ts +14 -2
  163. package/packages/storefront/src/lib/ssr-context.ts +1 -0
  164. package/packages/types/package.json +1 -1
  165. package/pnpm-workspace.yaml +2 -0
  166. package/packages/storefront/dist/client/_astro/HeroSlider.0890631f.js +0 -1
  167. package/packages/storefront/dist/client/_astro/ShopHeader.82ae97a5.js +0 -4
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <div class="bg-base-100 relative z-20">
3
+ <div class="container lg:w-2/3 mx-auto px-3 py-1">
4
+ <Carousel :autoplay="countValidSlides > 1 ? 7000 : undefined">
5
+ <li
6
+ v-for="(slide, i) in slides"
7
+ :key="i"
8
+ class="shrink-0 basis-full h-full text-center"
9
+ >
10
+ <component
11
+ :is="slide.href ? 'ALink' : 'span'"
12
+ :href="slide.href"
13
+ :target="slide.target"
14
+ class="inline-block px-8"
15
+ :class="slide.href ? 'hover:underline' : null"
16
+ >
17
+ <span
18
+ v-if="parsedContents[i]"
19
+ v-html="parsedContents[i]"
20
+ class="prose text-sm text-base-800"
21
+ ></span>
22
+ </component>
23
+ </li>
24
+ <template #controls>
25
+ <div
26
+ v-show="countValidSlides > 1"
27
+ class="text-xl leading-none text-base-400"
28
+ >
29
+ <CarouselControl class="pr-2 bg-base-100 hover:text-base-700" is-prev />
30
+ <CarouselControl class="pl-2 bg-base-100 hover:text-base-700" />
31
+ </div>
32
+ </template>
33
+ </Carousel>
34
+ </div>
35
+ </div>
36
+ </template>
37
+
38
+ <script setup lang="ts">
39
+ import {
40
+ type Props as UsePitchBarProps,
41
+ usePitchBar,
42
+ } from '@@sf/composables/use-pitch-bar';
43
+ import Carousel from '@@sf/components/Carousel.vue';
44
+ import CarouselControl from '@@sf/components/CarouselControl.vue';
45
+
46
+ export interface Props extends UsePitchBarProps {}
47
+
48
+ const props = defineProps<Props>();
49
+ const {
50
+ parsedContents,
51
+ countValidSlides,
52
+ } = usePitchBar(props);
53
+ </script>
@@ -0,0 +1,96 @@
1
+ <template>
2
+ <div
3
+ class="text-base-600
4
+ [&>div]:[font-size:90%] [&_small]:lowercase [&_small]:[font-size:92%]"
5
+ :class="isBig ? 'text-lg' : null"
6
+ data-prices
7
+ >
8
+ <span v-if="comparePrice" class="text-base-500 mr-1 [font-size:87%]">
9
+ <small v-if="isLiteral">
10
+ {{ `${$t.i19from} ` }}
11
+ </small>
12
+ <s>{{ $money(comparePrice) }}</s>
13
+ <small v-if="isLiteral">
14
+ {{ ` ${$t.i19to}` }}
15
+ </small>
16
+ </span>
17
+ <strong
18
+ class="inline-block text-base-800"
19
+ :class="isBig ? 'text-5xl block' : null"
20
+ >
21
+ <small v-if="hasVariedPrices">
22
+ {{ `${$t.i19asOf} ` }}
23
+ </small>
24
+ {{ $money(salePrice) }}
25
+ </strong>
26
+ <Fade slide="down">
27
+ <div v-if="cashbackValue && hasCashback" class="relative z-10">
28
+ <span :data-tooltip="$t.i19get$1back
29
+ .replace('$1', $percentage(cashbackPercentage))">
30
+ <i class="i-back-fill mr-1"></i>
31
+ <span class="font-medium">
32
+ {{ $money(cashbackValue) }}
33
+ </span>
34
+ <small> cashback</small>
35
+ </span>
36
+ </div>
37
+ </Fade>
38
+ <Fade slide="down">
39
+ <div v-if="installmentValue && hasPriceOptions">
40
+ <small v-if="isLiteral">
41
+ {{ `${$t.i19upTo} ` }}
42
+ </small>
43
+ {{ installmentsNumber }}x
44
+ <small v-if="isLiteral">
45
+ {{ ` ${$t.i19of} ` }}
46
+ </small>
47
+ <span>{{ $money(installmentValue) }}</span>
48
+ <small v-if="!monthlyInterest && isLiteral">
49
+ {{ $t.i19interestFree }}
50
+ </small>
51
+ </div>
52
+ </Fade>
53
+ <Fade slide="down">
54
+ <div v-if="priceWithDiscount < salePrice && hasPriceOptions">
55
+ <small v-if="!discountLabel">
56
+ {{ `${$t.i19asOf} ` }}
57
+ </small>
58
+ <span>{{ $money(priceWithDiscount) }}</span>
59
+ <small v-if="discountLabel">
60
+ {{ ` ${discountLabel}` }}
61
+ </small>
62
+ </div>
63
+ </Fade>
64
+ </div>
65
+ </template>
66
+
67
+ <script setup lang="ts">
68
+ import {
69
+ type Props as UsePricesProps,
70
+ usePrices,
71
+ } from '@@sf/composables/use-prices';
72
+
73
+ export interface Props extends UsePricesProps {
74
+ isBig?: boolean;
75
+ isLiteral?: boolean;
76
+ hasCashback?: boolean;
77
+ hasPriceOptions?: boolean;
78
+ }
79
+
80
+ const props = withDefaults(defineProps<Props>(), {
81
+ hasCashback: true,
82
+ hasPriceOptions: true,
83
+ });
84
+ const {
85
+ hasVariedPrices,
86
+ salePrice,
87
+ comparePrice,
88
+ cashbackPercentage,
89
+ cashbackValue,
90
+ installmentsNumber,
91
+ monthlyInterest,
92
+ installmentValue,
93
+ priceWithDiscount,
94
+ discountLabel,
95
+ } = usePrices(props);
96
+ </script>
@@ -0,0 +1,117 @@
1
+ <template>
2
+ <article
3
+ ref="card"
4
+ :data-sku="product.sku"
5
+ class="relative h-full max-w-[350px] mx-auto py-3 group"
6
+ >
7
+ <component
8
+ :is="link ? 'ALink' : 'span'"
9
+ :href="link"
10
+ class="flex flex-col h-full rounded overflow-hidden
11
+ group-hover:shadow group-hover:ring-1 ring-black/5"
12
+ >
13
+ <div class="aspect-square p-2
14
+ motion-safe:group-hover:scale-110 transition-transform">
15
+ <div class="relative w-full h-full bg-white rounded overflow-hidden
16
+ group-hover:rounded-none">
17
+ <template v-if="images?.length">
18
+ <AImg
19
+ :picture="images[0]"
20
+ :alt="title"
21
+ class="absolute top-0 left-0 block w-full h-full object-cover"
22
+ />
23
+ <AImg
24
+ v-if="images[1] && wasHoveredOnce"
25
+ :picture="images[1]"
26
+ :alt="title"
27
+ class="absolute top-0 left-0 block w-full h-full object-cover
28
+ opacity-0 group-hover:opacity-100 transition-opacity
29
+ motion-safe:duration-300 text-transparent z-10"
30
+ />
31
+ </template>
32
+ <div
33
+ v-else
34
+ class="w-full h-full bg-gradient-to-br from-base-50/20 to-base-100"
35
+ />
36
+ </div>
37
+ </div>
38
+ <span
39
+ v-if="discountPercentage"
40
+ class=":uno: absolute top-9 right-2
41
+ group-hover:scale-110 group-hover:translate-x-2 transition-transform
42
+ bg-secondary/70 text-on-secondary text-xs
43
+ py-0.5 pr-1.5 pl-3 [clip-path:polygon(20%_0,100%_0,100%_100%,0_100%)]"
44
+ >
45
+ -<strong>{{ discountPercentage }}</strong>%
46
+ </span>
47
+ <div class="relative flex flex-col grow justify-start p-4
48
+ group-hover:backdrop-blur-md bg-white/40 z-10">
49
+ <div class="pb-2">
50
+ <div v-if="isActive">
51
+ <Prices :product="product" />
52
+ </div>
53
+ <span v-else class="ui-badge bg-warning-100 text-warning-700">
54
+ {{ !isInStock ? $t.i19outOfStock : $t.i19inactive }}
55
+ </span>
56
+ </div>
57
+ <component
58
+ :is="headingTag"
59
+ class="ui-link no-underline line-clamp-2 text-sm"
60
+ :class="[
61
+ isActive ? 'text-base-700' : 'text-base-500',
62
+ link ? 'group-hover:underline group-hover:text-primary' : null,
63
+ ]"
64
+ >
65
+ {{ title }}
66
+ </component>
67
+ <button
68
+ v-if="isActive && !hasVariations"
69
+ class="absolute -top-12 left-1/2 -ml-7 w-14 h-14 lg:left-4 lg:ml-0
70
+ primary opacity-75 hover:opacity-100
71
+ rounded-full text-3xl leading-none p-2 z-10"
72
+ @click.prevent="addProductToCart(product)"
73
+ >
74
+ <i class="i-shopping-bag-3-line"></i>
75
+ </button>
76
+ </div>
77
+ </component>
78
+ </article>
79
+ </template>
80
+
81
+ <script setup lang="ts">
82
+ import { ref } from 'vue';
83
+ import { watchOnce, useElementHover } from '@vueuse/core';
84
+ import { addProductToCart } from '@@sf/state/shopping-cart';
85
+ import {
86
+ type Props as UseProductCardProps,
87
+ useProductCard,
88
+ } from '@@sf/composables/use-product-card';
89
+ import Prices from '~/components/Prices.vue';
90
+
91
+ export type Props = UseProductCardProps & {
92
+ headingTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
93
+ };
94
+
95
+ const props = withDefaults(defineProps<Props>(), {
96
+ headingTag: 'h3',
97
+ });
98
+ const {
99
+ product,
100
+ title,
101
+ link,
102
+ images,
103
+ isInStock,
104
+ isActive,
105
+ discountPercentage,
106
+ hasVariations,
107
+ } = useProductCard({
108
+ product: props.product,
109
+ productId: props.productId,
110
+ } as UseProductCardProps);
111
+ const card = ref<HTMLElement | null>(null);
112
+ const isHovered = useElementHover(card);
113
+ const wasHoveredOnce = ref(false);
114
+ watchOnce(isHovered, () => {
115
+ wasHoveredOnce.value = true;
116
+ });
117
+ </script>
@@ -0,0 +1,60 @@
1
+ <template>
2
+ <section class="ui-section">
3
+ <div v-if="title" class="max-w-prose mx-auto text-center mb-2">
4
+ <h2 class="ui-text-brand text-3xl">
5
+ <ALink v-if="titleLink" :href="titleLink" class="ui-link">
6
+ {{ title }}
7
+ </ALink>
8
+ <span v-else class="text-base-700">
9
+ {{ title }}
10
+ </span>
11
+ </h2>
12
+ </div>
13
+ <Carousel class="group/shelf">
14
+ <li
15
+ v-for="product in products"
16
+ :key="product._id"
17
+ class="basis-1/2 md:basis-1/3 lg:basis-1/4 shrink-0"
18
+ >
19
+ <ProductCard :product="product" />
20
+ </li>
21
+ <template #controls>
22
+ <div
23
+ v-show="products.length > 2"
24
+ class="text-3xl lg:text-2xl leading-none text-primary
25
+ lg:opacity-0 group-hover/shelf:opacity-90 transition-opacity"
26
+ >
27
+ <CarouselControl class="!top-1/2 !lg:top-1/3 !-left-4 w-12 h-12
28
+ bg-transparent lg:bg-white/80 lg:hover:bg-primary-300/60 rounded
29
+ lg:shadow-sm lg:ring-1 ring-black/5" is-prev />
30
+ <CarouselControl class="!top-1/2 !lg:top-1/3 !-right-4 w-12 h-12
31
+ bg-transparent lg:bg-white/80 lg:hover:bg-primary-300/60 rounded
32
+ lg:shadow-sm lg:ring-1 ring-black/5" />
33
+ </div>
34
+ </template>
35
+ </Carousel>
36
+ </section>
37
+ </template>
38
+
39
+ <script setup lang="ts">
40
+ import {
41
+ type Props as UseProductShelfProps,
42
+ useProductShelf,
43
+ } from '@@sf/composables/use-product-shelf';
44
+ import Carousel from '@@sf/components/Carousel.vue';
45
+ import CarouselControl from '@@sf/components/CarouselControl.vue';
46
+ import ProductCard from '~/components/ProductCard.vue';
47
+
48
+ export interface Props extends UseProductShelfProps {}
49
+
50
+ const props = defineProps<Props>();
51
+ const {
52
+ title,
53
+ titleLink,
54
+ fetching,
55
+ products,
56
+ } = useProductShelf(props);
57
+ if (import.meta.env.SSR) {
58
+ await fetching;
59
+ }
60
+ </script>
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <div class="w-full h-40 bg-base-300"></div>
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ </script>
@@ -0,0 +1,180 @@
1
+ <template>
2
+ <header
3
+ ref="header"
4
+ class="relative top-0 z-50 transition-colors"
5
+ :class="[
6
+ isSticky && !isSidenavOpen ? 'bg-white/80' : 'bg-white',
7
+ isSticky ? 'backdrop-blur-md shadow py-2 md:py-3' : 'py-3 sm:py-4 md:py-5',
8
+ ]"
9
+ >
10
+ <div class="container 2xl:max-w-7xl
11
+ mx-auto px-1 lg:pr-3 lg:pl-5 xl:pr-7 xl:pl-9 2xl:pr-0 2xl:pl-2">
12
+ <div class="flex justify-between items-center">
13
+ <div
14
+ class="basis-1/4 lg:basis-auto lg:me-5"
15
+ :class="!isSticky ? 'lg:hidden' : null"
16
+ >
17
+ <button
18
+ class="px-2 my-1"
19
+ :aria-label="$t.i19toggleMenu"
20
+ @click="isSidenavOpen = !isSidenavOpen"
21
+ >
22
+ <i
23
+ class="text-base-600 text-3xl"
24
+ :class="isSidenavOpen ? 'i-close' : 'i-menu-line'"
25
+ ></i>
26
+ </button>
27
+ </div>
28
+ <div class="lg:grow" :class="isSticky ? '[&_img]:max-w-[170px]' : null">
29
+ <slot name="logo" />
30
+ </div>
31
+ <div class="basis-1/4 px-2 flex justify-end items-center gap-3 lg:gap-4">
32
+ <form
33
+ action="/search"
34
+ method="get"
35
+ class="hidden lg:block w-[400px] relative mb-1"
36
+ @submit.prevent="searchTerm
37
+ ? (isSearchOpen = !isSearchOpen)
38
+ : searchInput?.focus()"
39
+ >
40
+ <label for="HeaderSearch" class="sr-only">
41
+ {{ $t.i19searchProducts }}
42
+ </label>
43
+ <input
44
+ ref="searchInput"
45
+ type="search"
46
+ id="HeaderSearch"
47
+ name="term"
48
+ v-model="searchTerm"
49
+ :placeholder="$t.i19searchProducts"
50
+ class="w-full rounded-md py-2.5 pe-10 sm:text-sm
51
+ bg-gradient-to-br from-primary-50/10 to-primary-50/80
52
+ border-primary-200 shadow-sm"
53
+ />
54
+ <span class="absolute inset-y-0 end-0 px-1 grid place-content-center">
55
+ <button
56
+ type="submit"
57
+ class="p-1 text-2xl text-primary-600 hover:text-primary"
58
+ >
59
+ <span class="sr-only">{{ $t.i19search }}</span>
60
+ <i class="i-search-3-line"></i>
61
+ </button>
62
+ </span>
63
+ </form>
64
+ <button
65
+ :aria-label="$t.i19searchProducts"
66
+ @click="isSearchOpen = !isSearchOpen"
67
+ class="lg:hidden"
68
+ >
69
+ <i class="i-search-3-line w-7 h-7
70
+ text-base-700 hover:text-primary hover:scale-110 active:scale-125"></i>
71
+ </button>
72
+ <AccountMenu
73
+ class="hidden sm:block"
74
+ :aria-label="$t.i19myAccount"
75
+ :service-links="serviceLinks"
76
+ >
77
+ <template #button="{ open }">
78
+ <i
79
+ class="i-user-2-line w-7 h-7
80
+ text-base-600 hover:text-primary hover:scale-110 active:scale-125"
81
+ :class="open ? 'text-base-800 scale-110' : null"
82
+ ></i>
83
+ </template>
84
+ </AccountMenu>
85
+ <button
86
+ :aria-label="$t.i19openCart"
87
+ @click="isCartOpen = !isCartOpen"
88
+ class="relative group text-primary-500"
89
+ >
90
+ <i class="i-shopping-bag-3-fill w-7 h-7 group-hover:text-primary
91
+ group-hover:scale-110 group-active:scale-125"></i>
92
+ <span
93
+ v-if="delayedTotalItems"
94
+ class="ui-badge-pill-sm absolute -top-1 -right-1.5"
95
+ >
96
+ {{ delayedTotalItems }}
97
+ </span>
98
+ </button>
99
+ </div>
100
+ </div>
101
+ <ShopHeaderMenu
102
+ v-show="!isSticky"
103
+ v-bind="{ inlineMenuTrees }"
104
+ class="hidden lg:block px-3 2xl:px-8 mt-3"
105
+ />
106
+ </div>
107
+ <Drawer
108
+ v-model="isSidenavOpen"
109
+ :has-close-button="false"
110
+ position="absolute"
111
+ :class="isSticky ? 'mt-2 md:mt-3' : 'mt-3 sm:mt-4 md:mt-5'"
112
+ :style="{ height: `calc(100vh - ${positionY}px + .5rem)` }"
113
+ >
114
+ <ShopSidenav class="bg-white pt-6" v-bind="{ categoryTrees }" />
115
+ </Drawer>
116
+ <Drawer
117
+ v-model="isSearchOpen"
118
+ :has-close-button="false"
119
+ placement="top"
120
+ >
121
+ <SearchModal />
122
+ </Drawer>
123
+ <Teleport v-if="isMounted" to="#teleported-overlap">
124
+ <Drawer
125
+ v-model="isCartOpen"
126
+ placement="end"
127
+ backdrop-target="#teleported-overlap"
128
+ >
129
+ <CartSidebar />
130
+ </Drawer>
131
+ </Teleport>
132
+ </header>
133
+ </template>
134
+
135
+ <script setup lang="ts">
136
+ import { ref, watch, onMounted } from 'vue';
137
+ import { totalItems } from '@@sf/state/shopping-cart';
138
+ import {
139
+ type Props as UseShopHeaderProps,
140
+ useShopHeader,
141
+ } from '@@sf/composables/use-shop-header';
142
+ import Drawer from '@@sf/components/Drawer.vue';
143
+ import ShopSidenav from '~/components/ShopSidenav.vue';
144
+ import ShopHeaderMenu from '~/components/ShopHeaderMenu.vue';
145
+ import SearchModal from '~/components/SearchModal.vue';
146
+ import AccountMenu from '~/components/AccountMenu.vue';
147
+ import CartSidebar from '~/components/CartSidebar.vue';
148
+
149
+ export interface Props extends Omit<UseShopHeaderProps, 'header'> {
150
+ serviceLinks?: Array<{
151
+ title: string;
152
+ href: string;
153
+ }>;
154
+ }
155
+
156
+ const props = defineProps<Props>();
157
+ const header = ref<HTMLElement | null>(null);
158
+ const {
159
+ isSticky,
160
+ positionY,
161
+ categoryTrees,
162
+ inlineMenuTrees,
163
+ } = useShopHeader({ ...props, header });
164
+ const isSidenavOpen = ref(false);
165
+ const isSearchOpen = ref(false);
166
+ const isCartOpen = ref(false);
167
+ const isMounted = ref(false);
168
+ const delayedTotalItems = ref(0);
169
+ const searchTerm = ref('');
170
+ const searchInput = ref<HTMLElement | null>(null);
171
+ onMounted(() => {
172
+ isMounted.value = true;
173
+ watch(totalItems, (newTotalItems, prevTotalItems) => {
174
+ if (prevTotalItems && prevTotalItems < newTotalItems) {
175
+ isCartOpen.value = true;
176
+ }
177
+ delayedTotalItems.value = newTotalItems;
178
+ }, { immediate: true });
179
+ });
180
+ </script>
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <nav>
3
+ <ul
4
+ class="flex justify-between gap-1.5 text-base-700"
5
+ :class="inlineMenuTrees.length < 7 ? 'text-base' : 'text-sm'"
6
+ >
7
+ <li v-for="(categoryTree, i) in inlineMenuTrees" :key="i">
8
+ <ShopHeaderSubmenu
9
+ v-if="categoryTree.subcategories.length"
10
+ :category-tree="categoryTree"
11
+ :class="[
12
+ i < 4 ? '[&_.Popover]:translate-x-0 [&_.Popover]:-left-2' : null,
13
+ i > 3 ? '[&_.Popover]:text-right [&_.Popover]:-right-2' : null,
14
+ ]"
15
+ >
16
+ <template #button="{ open }">
17
+ <span class="hover:text-primary group">
18
+ <span class="hidden lg:inline text-secondary-400">
19
+ <i v-if="categoryTree.slug.includes('confeitar')"
20
+ class="i-cupcake-line me-1"></i>
21
+ <i v-else-if="categoryTree.slug.includes('cortadores')"
22
+ class="i-scissors-2-line me-1"></i>
23
+ <i v-else-if="categoryTree.slug.includes('panificacao')"
24
+ class="i-bread-line me-1"></i>
25
+ <i v-else-if="categoryTree.slug.includes('embalagens')"
26
+ class="i-package-2-line me-1"></i>
27
+ <i v-else-if="categoryTree.slug.includes('chocolate')"
28
+ class="i-cookie-man-line me-1"></i>
29
+ <i v-else-if="categoryTree.slug.includes('ingredientes')"
30
+ class="i-drop-line me-1"></i>
31
+ </span>
32
+ <h3
33
+ class="group-hover:underline inline tracking-tight"
34
+ :class="[
35
+ inlineMenuTrees.length < 7 ? 'decoration-2' : null,
36
+ open ? 'underline' : null,
37
+ ]"
38
+ >
39
+ {{ categoryTree.name }}
40
+ </h3>
41
+ </span>
42
+ </template>
43
+ </ShopHeaderSubmenu>
44
+ <a
45
+ v-else
46
+ :href="`/${categoryTree.slug}`"
47
+ class="hover:text-primary hover:underline"
48
+ :class="inlineMenuTrees.length < 7 ? 'decoration-2' : null"
49
+ >
50
+ <h3 class="inline">{{ categoryTree.name }}</h3>
51
+ </a>
52
+ </li>
53
+ </ul>
54
+ </nav>
55
+ </template>
56
+
57
+ <script setup lang="ts">
58
+ import type { CategoryTree } from '@@sf/composables/use-shop-header';
59
+ import ShopHeaderSubmenu from '~/components/ShopHeaderSubmenu.vue';
60
+
61
+ export interface Props {
62
+ inlineMenuTrees: CategoryTree[];
63
+ }
64
+
65
+ defineProps<Props>();
66
+ </script>
@@ -0,0 +1,90 @@
1
+ <template>
2
+ <Popover v-slot="{ open }">
3
+ <PopoverButton class="outline-none">
4
+ <slot name="button" v-bind="{ open }" />
5
+ </PopoverButton>
6
+ <div class="relative">
7
+ <Fade>
8
+ <PopoverPanel
9
+ class="Popover absolute z-20 top-3 !transform
10
+ px-7 py-5 rounded backdrop-blur-md shadow bg-white/80
11
+ text-base text-base-700"
12
+ :class="countMenuCols === 1 ? 'w-auto'
13
+ : countMenuCols === 2 ? `w-screen ${(categoryPicture ? 'max-w-lg' : 'max-w-sm')}`
14
+ : countMenuCols === 3 ? `w-screen ${(categoryPicture ? 'max-w-xl' : 'max-w-md')}`
15
+ : countMenuCols < 6 ? 'w-screen max-w-3xl' : 'w-screen max-w-5xl'"
16
+ >
17
+ <div class="flex gap-6 w-full">
18
+ <ul v-if="subcategoryLinks.length" class="flex-1">
19
+ <li
20
+ v-for="(subcategory, i) in subcategoryLinks"
21
+ :key="`link-${i}`"
22
+ class="text-sm mb-2"
23
+ >
24
+ <a :href="`/${subcategory.slug}`" class="hover:text-primary">
25
+ <h3 :class="countMenuCols === 1 ? 'whitespace-nowrap' : null">
26
+ {{ subcategory.name }}
27
+ </h3>
28
+ </a>
29
+ </li>
30
+ </ul>
31
+ <div
32
+ v-for="(subcategory, i) in subcategoryCols"
33
+ :key="i"
34
+ class="flex-1"
35
+ >
36
+ <a :href="`/${subcategory.slug}`" class="hover:text-primary">
37
+ <h3>{{ subcategory.name }}</h3>
38
+ </a>
39
+ <ul class="text-sm text-base-600 mt-1 mb-1.5">
40
+ <li
41
+ v-for="(nestedSubcategory, ii) in subcategory.subcategories"
42
+ :key="`${i}-${ii}`"
43
+ class="mb-0.5"
44
+ >
45
+ <a
46
+ :href="`/${nestedSubcategory.slug}`"
47
+ class="hover:text-primary hover:underline"
48
+ >
49
+ <h3>{{ nestedSubcategory.name }}</h3>
50
+ </a>
51
+ </li>
52
+ </ul>
53
+ </div>
54
+ <div
55
+ v-if="categoryPicture"
56
+ :class="countMenuCols === 2 ? 'basis-1/2'
57
+ : countMenuCols < 5 ? 'basis-2/5' : 'basis-1/3'"
58
+ >
59
+ <AImg :picture="categoryPicture" class="ml-auto rounded" />
60
+ </div>
61
+ </div>
62
+ <a
63
+ :href="`/${categoryTree.slug}`"
64
+ class="block mt-1 text-xs text-base-600 leading-snug underline"
65
+ >
66
+ {{ $t.i19seeAll$1Category.replace('$1', categoryTree.name) }}
67
+ </a>
68
+ </PopoverPanel>
69
+ </Fade>
70
+ </div>
71
+ </Popover>
72
+ </template>
73
+
74
+ <script setup lang="ts">
75
+ import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue';
76
+ import {
77
+ type Props as UseShopHeaderSubmenuProps,
78
+ useShopHeaderSubmenu,
79
+ } from '@@sf/composables/use-shop-header-submenu';
80
+
81
+ export interface Props extends UseShopHeaderSubmenuProps {}
82
+
83
+ const props = defineProps<Props>();
84
+ const {
85
+ categoryPicture,
86
+ subcategoryLinks,
87
+ subcategoryCols,
88
+ countMenuCols,
89
+ } = useShopHeaderSubmenu(props);
90
+ </script>