cloudcommerce 0.20.2 → 0.22.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.
Files changed (198) hide show
  1. package/.gitmodules +3 -0
  2. package/.nvmrc +1 -0
  3. package/.vscode/settings.json +2 -1
  4. package/CHANGELOG.md +44 -0
  5. package/action.yml +37 -13
  6. package/ecomplus-stores/iluminim/.devcontainer/devcontainer.json +30 -0
  7. package/ecomplus-stores/iluminim/.eslintrc.cjs +3 -0
  8. package/ecomplus-stores/iluminim/.firebaserc +5 -0
  9. package/ecomplus-stores/iluminim/.github/renovate.json +5 -0
  10. package/ecomplus-stores/iluminim/.github/workflows/build-and-deploy.yml +36 -0
  11. package/ecomplus-stores/iluminim/.github/workflows/calibreapp-image-actions.yml +23 -0
  12. package/ecomplus-stores/iluminim/.gitpod.yml +12 -0
  13. package/ecomplus-stores/iluminim/.nvmrc +1 -0
  14. package/ecomplus-stores/iluminim/.vscode/extensions.json +8 -0
  15. package/ecomplus-stores/iluminim/.vscode/launch.json +11 -0
  16. package/ecomplus-stores/iluminim/.vscode/settings.json +10 -0
  17. package/ecomplus-stores/iluminim/README.md +113 -0
  18. package/ecomplus-stores/iluminim/README.pt-BR.md +113 -0
  19. package/ecomplus-stores/iluminim/functions/config.json +3 -0
  20. package/ecomplus-stores/iluminim/functions/example.env +10 -0
  21. package/ecomplus-stores/iluminim/functions/many/index.js +14 -0
  22. package/ecomplus-stores/iluminim/functions/many/package.json +22 -0
  23. package/ecomplus-stores/iluminim/functions/ssr/.eslintrc.cjs +6 -0
  24. package/ecomplus-stores/iluminim/functions/ssr/astro.config.mjs +4 -0
  25. package/ecomplus-stores/iluminim/functions/ssr/content/blog/.gitkeep +0 -0
  26. package/ecomplus-stores/iluminim/functions/ssr/content/extra-pages/.gitkeep +0 -0
  27. package/ecomplus-stores/iluminim/functions/ssr/content/layout.json +33 -0
  28. package/ecomplus-stores/iluminim/functions/ssr/content/pages/home.json +70 -0
  29. package/ecomplus-stores/iluminim/functions/ssr/content/settings.json +49 -0
  30. package/ecomplus-stores/iluminim/functions/ssr/index.js +18 -0
  31. package/ecomplus-stores/iluminim/functions/ssr/package.json +31 -0
  32. package/ecomplus-stores/iluminim/functions/ssr/public/admin/.gitkeep +2 -0
  33. package/ecomplus-stores/iluminim/functions/ssr/public/assets/cms-preview.css +274 -0
  34. package/ecomplus-stores/iluminim/functions/ssr/public/assets/cms.css +114 -0
  35. package/ecomplus-stores/iluminim/functions/ssr/public/assets/cvv.png +0 -0
  36. package/ecomplus-stores/iluminim/functions/ssr/public/assets/img-placeholder.png +0 -0
  37. package/ecomplus-stores/iluminim/functions/ssr/public/assets/payments.png +0 -0
  38. package/ecomplus-stores/iluminim/functions/ssr/public/assets/ssl-safe.png +0 -0
  39. package/ecomplus-stores/iluminim/functions/ssr/public/img/icon.png +0 -0
  40. package/ecomplus-stores/iluminim/functions/ssr/public/img/large-icon.png +0 -0
  41. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/banner-chamada-desktop-9x81zmd91q.webp +0 -0
  42. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/banner2.webp +0 -0
  43. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/chamada-mobile-q1c6om6jx4.webp +0 -0
  44. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/ecom-icon.png +0 -0
  45. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/headphone.webp +0 -0
  46. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/logo.webp +0 -0
  47. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/og-image.png +0 -0
  48. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/passion.webp +0 -0
  49. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/rect8589.png +0 -0
  50. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/rect859.png +0 -0
  51. package/ecomplus-stores/iluminim/functions/ssr/public/img/uploads/rect89.webp +0 -0
  52. package/ecomplus-stores/iluminim/functions/ssr/public/robots.txt +8 -0
  53. package/ecomplus-stores/iluminim/functions/ssr/scripts/build.sh +14 -0
  54. package/ecomplus-stores/iluminim/functions/ssr/src/assets/style.css +65 -0
  55. package/ecomplus-stores/iluminim/functions/ssr/src/components/AccountMenu.vue +104 -0
  56. package/ecomplus-stores/iluminim/functions/ssr/src/components/Banner.vue +59 -0
  57. package/ecomplus-stores/iluminim/functions/ssr/src/components/BannersGrid.astro +25 -0
  58. package/ecomplus-stores/iluminim/functions/ssr/src/components/CartSidebar.vue +35 -0
  59. package/ecomplus-stores/iluminim/functions/ssr/src/components/Countdown.vue +79 -0
  60. package/ecomplus-stores/iluminim/functions/ssr/src/components/HeroSlider.vue +52 -0
  61. package/ecomplus-stores/iluminim/functions/ssr/src/components/PitchBar.vue +57 -0
  62. package/ecomplus-stores/iluminim/functions/ssr/src/components/Prices.vue +96 -0
  63. package/ecomplus-stores/iluminim/functions/ssr/src/components/ProductCard.vue +118 -0
  64. package/ecomplus-stores/iluminim/functions/ssr/src/components/ProductShelf.vue +60 -0
  65. package/ecomplus-stores/iluminim/functions/ssr/src/components/ProductsCountdown.vue +20 -0
  66. package/ecomplus-stores/iluminim/functions/ssr/src/components/SearchModal.vue +6 -0
  67. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopHeader.vue +137 -0
  68. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopHeaderMenu.vue +58 -0
  69. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopHeaderSubmenu.vue +88 -0
  70. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopSidenav.vue +61 -0
  71. package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopSidenavCategory.vue +78 -0
  72. package/ecomplus-stores/iluminim/functions/ssr/src/env.d.ts +13 -0
  73. package/ecomplus-stores/iluminim/functions/ssr/src/layouts/Base.astro +16 -0
  74. package/ecomplus-stores/iluminim/functions/ssr/src/layouts/Checkout.astro +0 -0
  75. package/ecomplus-stores/iluminim/functions/ssr/src/layouts/PageHeader.astro +33 -0
  76. package/ecomplus-stores/iluminim/functions/ssr/src/main/Fallback.astro +10 -0
  77. package/ecomplus-stores/iluminim/functions/ssr/src/main/Home.astro +49 -0
  78. package/ecomplus-stores/iluminim/functions/ssr/src/main/Sections.astro +42 -0
  79. package/ecomplus-stores/iluminim/functions/ssr/src/main/Wildcard.astro +18 -0
  80. package/ecomplus-stores/iluminim/functions/ssr/src/pages/[...slug].astro +40 -0
  81. package/ecomplus-stores/iluminim/functions/ssr/src/pages/_vue.ts +3 -0
  82. package/ecomplus-stores/iluminim/functions/ssr/src/pages/app/account.astro +0 -0
  83. package/ecomplus-stores/iluminim/functions/ssr/src/pages/app/index.astro +0 -0
  84. package/ecomplus-stores/iluminim/functions/ssr/src/pages/fallback.astro +25 -0
  85. package/ecomplus-stores/iluminim/functions/ssr/src/pages/index.astro +35 -0
  86. package/ecomplus-stores/iluminim/functions/ssr/src/scripts/InlineScripts.astro +10 -0
  87. package/ecomplus-stores/iluminim/functions/ssr/tailwind.config.cjs +13 -0
  88. package/ecomplus-stores/iluminim/functions/ssr/tsconfig.json +12 -0
  89. package/ecomplus-stores/iluminim/functions/ssr/uno.config.cjs +5 -0
  90. package/ecomplus-stores/iluminim/functions/with-apps/index.js +12 -0
  91. package/ecomplus-stores/iluminim/functions/with-apps/package.json +22 -0
  92. package/ecomplus-stores/iluminim/package.json +28 -0
  93. package/ecomplus-stores/iluminim/scripts/install.sh +14 -0
  94. package/ecomplus-stores/monocard/.eslintrc.cjs +3 -0
  95. package/ecomplus-stores/monocard/.nvmrc +1 -0
  96. package/ecomplus-stores/tia-sonia/.eslintrc.cjs +3 -0
  97. package/ecomplus-stores/tia-sonia/.nvmrc +1 -0
  98. package/package.json +4 -4
  99. package/packages/api/package.json +1 -1
  100. package/packages/api/types.d.ts +1 -1
  101. package/packages/apps/affilate-program/package.json +1 -1
  102. package/packages/apps/correios/package.json +1 -1
  103. package/packages/apps/custom-payment/package.json +1 -1
  104. package/packages/apps/custom-shipping/package.json +1 -1
  105. package/packages/apps/datafrete/package.json +1 -1
  106. package/packages/apps/discounts/package.json +1 -1
  107. package/packages/apps/emails/package.json +1 -1
  108. package/packages/apps/fb-conversions/package.json +1 -1
  109. package/packages/apps/flash-courier/package.json +1 -1
  110. package/packages/apps/frenet/package.json +1 -1
  111. package/packages/apps/galaxpay/package.json +1 -1
  112. package/packages/apps/google-analytics/package.json +1 -1
  113. package/packages/apps/jadlog/package.json +1 -1
  114. package/packages/apps/loyalty-points/package.json +1 -1
  115. package/packages/apps/melhor-envio/package.json +1 -1
  116. package/packages/apps/mercadopago/package.json +1 -1
  117. package/packages/apps/pagarme/package.json +1 -1
  118. package/packages/apps/paghiper/package.json +1 -1
  119. package/packages/apps/pix/package.json +1 -1
  120. package/packages/apps/tiny-erp/package.json +1 -1
  121. package/packages/apps/webhooks/package.json +1 -1
  122. package/packages/cli/config/firebase.json +10 -0
  123. package/packages/cli/package.json +1 -1
  124. package/packages/config/package.json +1 -1
  125. package/packages/emails/package.json +2 -2
  126. package/packages/events/package.json +1 -1
  127. package/packages/feeds/package.json +1 -1
  128. package/packages/firebase/package.json +1 -1
  129. package/packages/i18n/lib/en_us/i19hour.txt +1 -0
  130. package/packages/i18n/lib/en_us/i19hours.txt +1 -0
  131. package/packages/i18n/lib/en_us/i19milliseconds.txt +1 -0
  132. package/packages/i18n/lib/en_us/i19minute.txt +1 -0
  133. package/packages/i18n/lib/en_us/i19minutes.txt +1 -0
  134. package/packages/i18n/lib/en_us/i19second.txt +1 -0
  135. package/packages/i18n/lib/en_us/i19seconds.txt +1 -0
  136. package/packages/i18n/lib/en_us.d.ts +7 -0
  137. package/packages/i18n/lib/en_us.js +7 -0
  138. package/packages/i18n/lib/en_us.js.map +1 -1
  139. package/packages/i18n/lib/pt_br/i19home.txt +1 -1
  140. package/packages/i18n/lib/pt_br/i19hour.txt +1 -0
  141. package/packages/i18n/lib/pt_br/i19hours.txt +1 -0
  142. package/packages/i18n/lib/pt_br/i19milliseconds.txt +1 -0
  143. package/packages/i18n/lib/pt_br/i19minute.txt +1 -0
  144. package/packages/i18n/lib/pt_br/i19minutes.txt +1 -0
  145. package/packages/i18n/lib/pt_br/i19second.txt +1 -0
  146. package/packages/i18n/lib/pt_br/i19seconds.txt +1 -0
  147. package/packages/i18n/lib/pt_br.d.ts +8 -1
  148. package/packages/i18n/lib/pt_br.js +8 -1
  149. package/packages/i18n/lib/pt_br.js.map +1 -1
  150. package/packages/i18n/package.json +1 -1
  151. package/packages/i18n/src/en_us.ts +7 -0
  152. package/packages/i18n/src/pt_br.ts +8 -1
  153. package/packages/modules/package.json +1 -1
  154. package/packages/passport/package.json +1 -1
  155. package/packages/ssr/lib/firebase/serve-storefront.js +24 -18
  156. package/packages/ssr/lib/firebase/serve-storefront.js.map +1 -1
  157. package/packages/ssr/package.json +2 -2
  158. package/packages/ssr/src/firebase/serve-storefront.ts +25 -18
  159. package/packages/storefront/.eslintrc.cjs +8 -1
  160. package/packages/storefront/client.d.ts +1 -19
  161. package/packages/storefront/dist/client/_astro/HeroSlider.0890631f.js +1 -0
  162. package/packages/storefront/dist/client/_astro/{ShopHeader.0c884bbe.js → ShopHeader.82ae97a5.js} +1 -1
  163. package/packages/storefront/dist/client/_astro/_...slug_.c85b8978.css +1 -0
  164. package/packages/storefront/dist/client/_astro/{client.8035a95a.js → client.0fb6b44e.js} +1 -1
  165. package/packages/storefront/dist/client/_astro/{hoisted.9d9d7ac4.js → hoisted.572313d6.js} +1 -1
  166. package/packages/storefront/dist/client/sw.js +1 -1
  167. package/packages/storefront/dist/server/chunks/_...7e1df40a.mjs +34 -0
  168. package/packages/storefront/dist/server/chunks/{account@_@astro.89e4cf60.mjs → account@_@astro.5f1dba7a.mjs} +7 -8
  169. package/packages/storefront/dist/server/chunks/{astro.45d3047f.mjs → astro.2d3ebf0f.mjs} +560 -511
  170. package/packages/storefront/dist/server/chunks/{endpoint@_@js.f880a152.mjs → endpoint@_@js.80de0568.mjs} +7 -8
  171. package/packages/storefront/dist/server/chunks/{fallback@_@astro.89538855.mjs → fallback@_@astro.02a45b47.mjs} +7 -8
  172. package/packages/storefront/dist/server/chunks/{index@_@astro.56fdd6da.mjs → index@_@astro.23b50301.mjs} +7 -8
  173. package/packages/storefront/dist/server/chunks/{index@_@astro.548cf7ad.mjs → index@_@astro.7cb07e52.mjs} +7 -8
  174. package/packages/storefront/dist/server/chunks/pages/{_...slug_.astro.bde9380b.mjs → _...slug_.astro.4358f614.mjs} +92 -104
  175. package/packages/storefront/dist/server/chunks/pages/{account.astro.f07cf19e.mjs → account.astro.afae5a12.mjs} +6 -6
  176. package/packages/storefront/dist/server/chunks/pages/{endpoint.js.d4e37801.mjs → endpoint.js.60fd21aa.mjs} +1 -1
  177. package/packages/storefront/dist/server/chunks/pages/{fallback.astro.e2e8a0e4.mjs → fallback.astro.e5566925.mjs} +10 -10
  178. package/packages/storefront/dist/server/chunks/pages/{index.astro.3760ebe3.mjs → index.astro.5bc6b9d8.mjs} +34 -32
  179. package/packages/storefront/dist/server/entry.mjs +13 -12
  180. package/packages/storefront/dist/server/renderers.mjs +7 -8
  181. package/packages/storefront/package.json +2 -2
  182. package/packages/storefront/server.d.ts +3 -27
  183. package/packages/storefront/src/lib/$storefront.d.ts +28 -0
  184. package/packages/storefront/src/lib/assets/base.css +2 -0
  185. package/packages/storefront/src/lib/layouts/Base.astro +1 -9
  186. package/packages/storefront/src/lib/layouts/BaseHead.astro +73 -2
  187. package/packages/storefront/src/lib/layouts/use-page-main.ts +18 -5
  188. package/packages/storefront/src/lib/pages/_vue.ts +1 -1
  189. package/packages/storefront/src/lib/server-data.ts +1 -1
  190. package/packages/storefront/src/lib/ssr-context.ts +46 -36
  191. package/packages/storefront/src/vue-globals.d.ts +3 -3
  192. package/packages/types/package.json +1 -1
  193. package/pnpm-workspace.yaml +2 -2
  194. package/packages/storefront/dist/client/_astro/HeroSlider.eb156f18.js +0 -1
  195. package/packages/storefront/dist/client/_astro/_...slug_.c2da43fb.css +0 -1
  196. package/packages/storefront/dist/server/chunks/_...9e22b578.mjs +0 -35
  197. package/packages/storefront/src/lib/composables/use-hero-slider.ts +0 -26
  198. package/packages/storefront/src/lib/layouts/BaseStateJson.astro +0 -68
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <Menu
3
+ as="div"
4
+ class="relative text-center text-sm text-base-800"
5
+ v-slot="{ open }"
6
+ >
7
+ <div v-if="open">
8
+ <span v-once>{{ initializeFirebaseAuth() }}</span>
9
+ </div>
10
+ <MenuButton class="outline-none">
11
+ <slot name="button" v-bind="{ open }" />
12
+ </MenuButton>
13
+ <Fade>
14
+ <MenuItems class="absolute -right-8 mt-2 w-56
15
+ rounded shadow ring-1 ring-black/5 bg-white
16
+ divide-y divide-base-100 focus:outline-none">
17
+ <div class="p-3 text-base-600">
18
+ {{ `${$t.i19hello} ${customerName || $t.i19visitor}` }}
19
+ <AccountLink role="button" class="ui-btn-sm ui-btn-primary block my-1">
20
+ {{ $t.i19accessMyAccount }}
21
+ </AccountLink>
22
+ <AccountLink v-if="!isLogged" is-sign-up class="ui-link block">
23
+ {{ $t.i19createAnAccount }}
24
+ </AccountLink>
25
+ </div>
26
+ <ul class="list-none">
27
+ <MenuItem as="li" v-slot="{ active }">
28
+ <AccountLink
29
+ to="orders"
30
+ class="block p-2"
31
+ :class="active ? 'bg-base-100 text-primary' : null"
32
+ >
33
+ {{ $t.i19myOrders }}
34
+ </AccountLink>
35
+ </MenuItem>
36
+ <MenuItem as="li" v-slot="{ active }">
37
+ <AccountLink
38
+ to="favorites"
39
+ class="block p-2"
40
+ :class="active ? 'bg-base-100 text-primary' : null"
41
+ >
42
+ <i class="i-heart mr-1"></i>
43
+ {{ $t.i19myFavorites }}
44
+ </AccountLink>
45
+ </MenuItem>
46
+ <MenuItem
47
+ as="li"
48
+ v-slot="{ active }"
49
+ v-for="({ title, href }, i) in serviceLinks"
50
+ :key="`s-${i}`"
51
+ >
52
+ <ALink
53
+ :href="href"
54
+ class="block p-2"
55
+ :class="active ? 'bg-base-100 text-primary' : null"
56
+ >
57
+ {{ title }}
58
+ </ALink>
59
+ </MenuItem>
60
+ <MenuItem as="li">
61
+ <div class="flex justify-center gap-2 p-2 text-base-500 text-base">
62
+ <span v-for="(href, network) in socialNetworks" :key="network">
63
+ <SocialNetworkLink :network="network" class="p-1 hover:text-primary" />
64
+ </span>
65
+ </div>
66
+ </MenuItem>
67
+ <MenuItem v-if="isLogged" as="li">
68
+ <button @click="logout" class="p-2 text-right text-base-800">
69
+ <span class="text-base-600">{{ $t.i19logout }}</span>
70
+ <i class="i-arrow-right-on-rectangle text-lg ml-1"></i>
71
+ </button>
72
+ </MenuItem>
73
+ </ul>
74
+ </MenuItems>
75
+ </Fade>
76
+ </Menu>
77
+ </template>
78
+
79
+ <script setup lang="ts">
80
+ import {
81
+ Menu,
82
+ MenuButton,
83
+ MenuItems,
84
+ MenuItem,
85
+ } from '@headlessui/vue';
86
+ import { socialNetworks } from '@@sf/server-data';
87
+ import {
88
+ customerName,
89
+ initializeFirebaseAuth,
90
+ isLogged,
91
+ logout,
92
+ } from '@@sf/state/customer-session';
93
+ import AccountLink from '@@sf/components/AccountLink.vue';
94
+ import SocialNetworkLink from '@@sf/components/SocialNetworkLink.vue';
95
+
96
+ export interface Props {
97
+ serviceLinks?: Array<{
98
+ title: string;
99
+ href: string;
100
+ }>;
101
+ }
102
+
103
+ defineProps<Props>();
104
+ </script>
@@ -0,0 +1,59 @@
1
+ <template>
2
+ <div
3
+ class="mx-auto overflow-x-hidden"
4
+ :class="hasHeader ? 'grid grid-cols-1 md:grid-cols-2 items-center' : null"
5
+ >
6
+ <component
7
+ :is="href ? 'a-link' : 'span'"
8
+ :href="href"
9
+ class="[&_img]:rounded-lg"
10
+ :class="hasHeader ? 'basis-1/2 grow-0 md:order-last' : '[&_img]:w-full'"
11
+ >
12
+ <slot name="picture" />
13
+ </component>
14
+ <div
15
+ v-if="hasHeader"
16
+ class="basis-1/2 grow-0 p-12 xl:ps-32 mb-3 md:mb-0"
17
+ >
18
+ <Component
19
+ v-if="parsedTitle"
20
+ :is="headingTag"
21
+ class="ui-title mt-1"
22
+ >
23
+ {{ parsedTitle }}
24
+ </Component>
25
+ <p v-if="parsedSubtitle" class="text-lg mt-4 md:mt-6">
26
+ {{ parsedSubtitle }}
27
+ </p>
28
+ <component
29
+ v-if="parsedButtonText"
30
+ :is="buttonLink ? 'a-link' : 'span'"
31
+ :href="buttonLink"
32
+ class="ui-btn-lg ui-btn-contrast min-w-[150px] mt-7 md:mt-10"
33
+ >
34
+ {{ parsedButtonText }}
35
+ </component>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script setup lang="ts">
41
+ import {
42
+ type Props as UseBannerProps,
43
+ useBanner,
44
+ } from '@@sf/composables/use-banner';
45
+
46
+ export type Props = UseBannerProps & {
47
+ headingTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
48
+ }
49
+
50
+ const props = withDefaults(defineProps<Props>(), {
51
+ headingTag: 'h3',
52
+ });
53
+ const {
54
+ hasHeader,
55
+ parsedTitle,
56
+ parsedSubtitle,
57
+ parsedButtonText,
58
+ } = useBanner(props);
59
+ </script>
@@ -0,0 +1,25 @@
1
+ ---
2
+ import type { Props as UseBannerProps } from '@@sf/composables/use-banner';
3
+ import BannerPictures from '@@sf/components/BannerPictures.astro';
4
+ import Banner from '~/components/Banner.vue';
5
+
6
+ export type Props = {
7
+ title?: string;
8
+ titleLink?: string;
9
+ banners: UseBannerProps[];
10
+ }
11
+
12
+ const { banners } = Astro.props;
13
+ ---
14
+
15
+ <section class="ui-section">
16
+ <ul class="flex flex-wrap lg:flex-nowrap gap-4">
17
+ {banners.map((banner) => (
18
+ <li class="lg:flex-1 [&_img]:w-full [&_img]:object-cover">
19
+ <Banner {...banner}>
20
+ <BannerPictures {...banner} slot="picture" />
21
+ </Banner>
22
+ </li>
23
+ ))}
24
+ </ul>
25
+ </section>
@@ -0,0 +1,35 @@
1
+ <template>
2
+ <aside class="flex flex-col h-full">
3
+ <header class="px-6 py-4 flex justify-end items-center gap-3">
4
+ <span class="text-right text-base text-base-600 font-medium">
5
+ {{ $t.i19myShoppingCart }}
6
+ </span>
7
+ <span class="ui-badge-pill-lg">
8
+ {{ totalItems }}
9
+ </span>
10
+ </header>
11
+ <article class="grow bg-base-50 border-t-2 border-b-2 border-base-100">
12
+ <div v-if="freeShippingFromValue" class="text-sm text-center">
13
+ <div
14
+ v-if="freeShippingFromValue > shoppingCart.subtotal"
15
+ class="p-3 secondary-subtle"
16
+ >
17
+ {{ $t.i19add$1ToEarn.replace('$1',
18
+ $money(freeShippingFromValue - shoppingCart.subtotal)) }}
19
+ <strong class="lowercase">{{ $t.i19freeShipping }}</strong>
20
+ </div>
21
+ <div v-else class="p-3 bg-success-50 text-success-800">
22
+ <i class="text-success-900 i-check mr-1"></i>
23
+ {{ $t.i19freeShippingFrom }} {{ $money(freeShippingFromValue) }}
24
+ </div>
25
+ </div>
26
+ </article>
27
+ <footer class="p-5 shadow">
28
+ </footer>
29
+ </aside>
30
+ </template>
31
+
32
+ <script setup lang="ts">
33
+ import { freeShippingFromValue } from '@@sf/state/modules-info';
34
+ import { shoppingCart, totalItems } from '@@sf/state/shopping-cart';
35
+ </script>
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <div class="flex w-[300px] justify-between">
3
+ <div>
4
+ <strong class="text-lg">{{ hours }}</strong>
5
+ <span>{{ $t.i19about }}</span>
6
+ </div>
7
+ <span>:</span>
8
+ <div>
9
+ {{ minutes }}
10
+ </div>
11
+ <span>:</span>
12
+ <div>
13
+ {{ seconds }}
14
+ </div>
15
+ <span>:</span>
16
+ <div>
17
+ {{ ms }}
18
+ </div>
19
+ </div>
20
+ </template>
21
+
22
+ <script setup lang="ts">
23
+ import {
24
+ ref,
25
+ computed,
26
+ watch,
27
+ watchEffect,
28
+ } from 'vue';
29
+ import { useIntervalFn } from '@vueuse/core';
30
+
31
+ export interface Props {
32
+ endsAt?: string;
33
+ maxHours?: number;
34
+ }
35
+
36
+ const props = withDefaults(defineProps<Props>(), {
37
+ maxHours: 8,
38
+ });
39
+ const endTimestamp = computed(() => {
40
+ if (props.endsAt) {
41
+ return new Date(props.endsAt).getTime();
42
+ }
43
+ return null;
44
+ });
45
+ const hours = ref<number | null>(null);
46
+ const minutes = ref<number>(59);
47
+ const seconds = ref<number>(59);
48
+ const ms = ref<number>(999);
49
+ watchEffect(() => {
50
+ if (endTimestamp.value) {
51
+ const timeDiff = endTimestamp.value - Date.now();
52
+ if (timeDiff > 0) {
53
+ const diffHours = Math.floor(timeDiff / (1000 * 60 * 60));
54
+ hours.value = Math.min(diffHours, props.maxHours);
55
+ }
56
+ return;
57
+ }
58
+ hours.value = props.maxHours;
59
+ });
60
+ useIntervalFn(() => {
61
+ ms.value -= 1;
62
+ if (ms.value < 0) {
63
+ ms.value = 999;
64
+ }
65
+ }, 1);
66
+ watch([ms], () => {
67
+ if (ms.value === 0) {
68
+ seconds.value -= 1;
69
+ if (seconds.value < 0) {
70
+ seconds.value = 59;
71
+ minutes.value -= 1;
72
+ if (minutes.value < 0) {
73
+ minutes.value = 59;
74
+ hours.value = Math.min((hours.value as number) - 1, 0);
75
+ }
76
+ }
77
+ }
78
+ });
79
+ </script>
@@ -0,0 +1,52 @@
1
+ <template>
2
+ <section class="bg-base-100 py-3">
3
+ <div class="relative container mx-auto">
4
+ <Carousel :autoplay="autoplay" class="[&>*]:items-center">
5
+ <li
6
+ v-for="(slide, i) in slides"
7
+ :key="i"
8
+ class="shrink-0 basis-full"
9
+ >
10
+ <Banner
11
+ v-bind="{ ...slide, headingTag: i === 0 ? 'h2' : 'h3' }"
12
+ class="w-full"
13
+ >
14
+ <template #picture>
15
+ <slot :name="`picture-${i}`" />
16
+ </template>
17
+ </Banner>
18
+ </li>
19
+ <template #controls>
20
+ <div
21
+ v-show="slides.length > 1"
22
+ class="absolute z-10 bottom-5 right-5 flex justify-end items-center"
23
+ >
24
+ <div class="relative w-20 h-10 rounded-full
25
+ bg-primary/80 text-on-primary shadow-sm ring-1 ring-black/5">
26
+ <CarouselControl class="w-10 h-10 rounded-full hover:bg-primary" is-prev>
27
+ <i class="i-arrow-left"></i>
28
+ </CarouselControl>
29
+ <CarouselControl class="w-10 h-10 rounded-full hover:bg-primary">
30
+ <i class="i-arrow-right"></i>
31
+ </CarouselControl>
32
+ </div>
33
+ </div>
34
+ </template>
35
+ </Carousel>
36
+ </div>
37
+ </section>
38
+ </template>
39
+
40
+ <script setup lang="ts">
41
+ import type { Props as UseBannerProps } from '@@sf/composables/use-banner';
42
+ import Carousel from '@@sf/components/Carousel.vue';
43
+ import CarouselControl from '@@sf/components/CarouselControl.vue';
44
+ import Banner from '~/components/Banner.vue';
45
+
46
+ export type Props = {
47
+ autoplay?: number;
48
+ slides: UseBannerProps[];
49
+ }
50
+
51
+ defineProps<Props>();
52
+ </script>
@@ -0,0 +1,57 @@
1
+ <template>
2
+ <div class="bg-black relative z-20">
3
+ <div class="container md:w-2/3 mx-auto px-3 py-1 md:py-1.5">
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 md:text-base lg:tracking-wide
21
+ text-base-200 uppercase font-semibold
22
+ [&_b]:text-base-100 [&_strong]:font-black
23
+ [&_strong]:text-transparent [&_strong]:bg-clip-text [&_strong]:bg-gradient-to-r
24
+ [&_strong]:from-yellow-200 [&_strong]:to-yellow-400"
25
+ ></span>
26
+ </component>
27
+ </li>
28
+ <template #controls>
29
+ <div
30
+ v-show="countValidSlides > 1"
31
+ class="text-xl leading-none text-base-300"
32
+ >
33
+ <CarouselControl class="pr-2 bg-black hover:text-white" is-prev />
34
+ <CarouselControl class="pl-2 bg-black hover:text-white" />
35
+ </div>
36
+ </template>
37
+ </Carousel>
38
+ </div>
39
+ </div>
40
+ </template>
41
+
42
+ <script setup lang="ts">
43
+ import {
44
+ type Props as UsePitchBarProps,
45
+ usePitchBar,
46
+ } from '@@sf/composables/use-pitch-bar';
47
+ import Carousel from '@@sf/components/Carousel.vue';
48
+ import CarouselControl from '@@sf/components/CarouselControl.vue';
49
+
50
+ export interface Props extends UsePitchBarProps {}
51
+
52
+ const props = defineProps<Props>();
53
+ const {
54
+ parsedContents,
55
+ countValidSlides,
56
+ } = usePitchBar(props);
57
+ </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-arrow-uturn-left 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,118 @@
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-between p-4
48
+ group-hover:backdrop-blur-md bg-white/40 z-10">
49
+ <component
50
+ :is="headingTag"
51
+ class="ui-link uppercase font-bold text-sm no-underline line-clamp-2"
52
+ :class="[
53
+ isActive ? 'text-base-700' : 'text-base-500',
54
+ link ? 'group-hover:underline group-hover:text-primary' : null,
55
+ ]"
56
+ >
57
+ {{ title }}
58
+ </component>
59
+ <div class="pt-2">
60
+ <div v-if="isActive">
61
+ <Prices :product="product" />
62
+ </div>
63
+ <span v-else class="ui-badge bg-warning-100 text-warning-700">
64
+ {{ !isInStock ? $t.i19outOfStock : $t.i19inactive }}
65
+ </span>
66
+ </div>
67
+ <button
68
+ v-if="isActive && !hasVariations"
69
+ class=":uno: hidden md:block ui-btn-sm ui-btn-primary
70
+ absolute -top-6 left-0 w-full rounded-none
71
+ opacity-0 group-hover:opacity-100 transition -z-10 group-hover:z-10"
72
+ @click.prevent="addProductToCart(product)"
73
+ >
74
+ <i class="i-plus-20-solid mr-0.5"></i>
75
+ {{ $t.i19addToCart }}
76
+ </button>
77
+ </div>
78
+ </component>
79
+ </article>
80
+ </template>
81
+
82
+ <script setup lang="ts">
83
+ import { ref } from 'vue';
84
+ import { watchOnce, useElementHover } from '@vueuse/core';
85
+ import { addProductToCart } from '@@sf/state/shopping-cart';
86
+ import {
87
+ type Props as UseProductCardProps,
88
+ useProductCard,
89
+ } from '@@sf/composables/use-product-card';
90
+ import Prices from '~/components/Prices.vue';
91
+
92
+ export type Props = UseProductCardProps & {
93
+ headingTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
94
+ };
95
+
96
+ const props = withDefaults(defineProps<Props>(), {
97
+ headingTag: 'h3',
98
+ });
99
+ const {
100
+ product,
101
+ title,
102
+ link,
103
+ images,
104
+ isInStock,
105
+ isActive,
106
+ discountPercentage,
107
+ hasVariations,
108
+ } = useProductCard({
109
+ product: props.product,
110
+ productId: props.productId,
111
+ } as UseProductCardProps);
112
+ const card = ref<HTMLElement | null>(null);
113
+ const isHovered = useElementHover(card);
114
+ const wasHoveredOnce = ref(false);
115
+ watchOnce(isHovered, () => {
116
+ wasHoveredOnce.value = true;
117
+ });
118
+ </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 !-left-4 w-12 h-12
28
+ bg-transparent lg:bg-white/80 lg:hover:bg-primary-300/60 rounded-full
29
+ lg:shadow-sm lg:ring-1 ring-black/5" is-prev />
30
+ <CarouselControl class="!top-1/2 !-right-4 w-12 h-12
31
+ bg-transparent lg:bg-white/80 lg:hover:bg-primary-300/60 rounded-full
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>