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.
- package/.editorconfig +13 -0
- package/.gitmodules +3 -0
- package/.vscode/settings.json +2 -1
- package/CHANGELOG.md +25 -0
- package/ecomplus-stores/barra-doce/.devcontainer/devcontainer.json +30 -0
- package/ecomplus-stores/barra-doce/.editorconfig +13 -0
- package/ecomplus-stores/barra-doce/.eslintrc.cjs +3 -0
- package/ecomplus-stores/barra-doce/.firebaserc +5 -0
- package/ecomplus-stores/barra-doce/.github/build-and-deploy +1 -0
- package/ecomplus-stores/barra-doce/.github/renovate.json +5 -0
- package/ecomplus-stores/barra-doce/.github/workflows/build-and-deploy.yml +36 -0
- package/ecomplus-stores/barra-doce/.github/workflows/calibreapp-image-actions.yml +23 -0
- package/ecomplus-stores/barra-doce/.gitpod.yml +12 -0
- package/ecomplus-stores/barra-doce/.nvmrc +1 -0
- package/ecomplus-stores/barra-doce/.vscode/extensions.json +8 -0
- package/ecomplus-stores/barra-doce/.vscode/launch.json +11 -0
- package/ecomplus-stores/barra-doce/.vscode/settings.json +10 -0
- package/ecomplus-stores/barra-doce/LICENSE.md +230 -0
- package/ecomplus-stores/barra-doce/README.md +31 -0
- package/ecomplus-stores/barra-doce/SETUP.md +117 -0
- package/ecomplus-stores/{iluminim/README.pt-BR.md → barra-doce/SETUP.pt-BR.md} +5 -1
- package/ecomplus-stores/barra-doce/functions/config.json +3 -0
- package/ecomplus-stores/barra-doce/functions/example.env +10 -0
- package/ecomplus-stores/barra-doce/functions/many/index.js +14 -0
- package/ecomplus-stores/barra-doce/functions/many/package.json +22 -0
- package/ecomplus-stores/barra-doce/functions/ssr/.eslintrc.cjs +6 -0
- package/ecomplus-stores/barra-doce/functions/ssr/astro.config.mjs +4 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/blog/.gitkeep +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/.gitkeep +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/layout.json +37 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/pages/home.json +33 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/settings.json +48 -0
- package/ecomplus-stores/barra-doce/functions/ssr/index.js +18 -0
- package/ecomplus-stores/barra-doce/functions/ssr/package.json +31 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/admin/.gitkeep +2 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/assets/.gitkeep +2 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/icon.png +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/large-icon.png +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/banner-forma-decora.jpg +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/banner2.webp +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/ecom-icon.png +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/headphone.webp +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/logo-barradoce.webp +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/logo.png +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/og-image.png +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/passion.webp +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/rect8589.png +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/rect859.png +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/img/uploads/rect89.webp +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/public/robots.txt +8 -0
- package/ecomplus-stores/barra-doce/functions/ssr/scripts/build.sh +14 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/assets/style.css +65 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/AccountMenu.vue +104 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/Banner.vue +64 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/BannersGrid.astro +25 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/CartSidebar.vue +35 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/HeroSlider.vue +51 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/PitchBar.vue +53 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/Prices.vue +96 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductCard.vue +117 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductShelf.vue +60 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/SearchModal.vue +6 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeader.vue +180 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeaderMenu.vue +66 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeaderSubmenu.vue +90 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopSidenav.vue +61 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopSidenavCategory.vue +80 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/env.d.ts +13 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/Base.astro +15 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/Checkout.astro +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/PageHeader.astro +42 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Fallback.astro +10 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Home.astro +30 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Sections.astro +29 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Wildcard.astro +18 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/[...slug].astro +40 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/_vue.ts +3 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/app/account.astro +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/app/index.astro +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/fallback.astro +25 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/index.astro +35 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/scripts/InlineScripts.astro +10 -0
- package/ecomplus-stores/barra-doce/functions/ssr/tailwind.config.cjs +19 -0
- package/ecomplus-stores/barra-doce/functions/ssr/tsconfig.json +12 -0
- package/ecomplus-stores/barra-doce/functions/ssr/uno.config.cjs +5 -0
- package/ecomplus-stores/barra-doce/functions/with-apps/index.js +12 -0
- package/ecomplus-stores/barra-doce/functions/with-apps/package.json +22 -0
- package/ecomplus-stores/barra-doce/package.json +28 -0
- package/ecomplus-stores/barra-doce/scripts/install.sh +14 -0
- package/ecomplus-stores/iluminim/.ecomplus.cd.json +5 -0
- package/ecomplus-stores/iluminim/.editorconfig +13 -0
- package/ecomplus-stores/iluminim/README.md +11 -93
- package/ecomplus-stores/iluminim/SETUP.md +117 -0
- package/ecomplus-stores/iluminim/SETUP.pt-BR.md +117 -0
- package/ecomplus-stores/iluminim/functions/many/package.json +3 -3
- package/ecomplus-stores/iluminim/functions/ssr/package.json +6 -6
- package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopHeaderSubmenu.vue +1 -1
- package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopSidenav.vue +2 -2
- package/ecomplus-stores/iluminim/functions/ssr/src/components/ShopSidenavCategory.vue +4 -2
- package/ecomplus-stores/iluminim/functions/ssr/src/layouts/PageHeader.astro +10 -1
- package/ecomplus-stores/iluminim/functions/with-apps/package.json +3 -3
- package/ecomplus-stores/iluminim/package.json +1 -1
- package/package.json +1 -1
- package/packages/api/package.json +1 -1
- package/packages/apps/affilate-program/package.json +1 -1
- package/packages/apps/correios/package.json +1 -1
- package/packages/apps/custom-payment/package.json +1 -1
- package/packages/apps/custom-shipping/package.json +1 -1
- package/packages/apps/datafrete/package.json +1 -1
- package/packages/apps/discounts/package.json +1 -1
- package/packages/apps/emails/package.json +1 -1
- package/packages/apps/fb-conversions/package.json +1 -1
- package/packages/apps/flash-courier/package.json +1 -1
- package/packages/apps/frenet/package.json +1 -1
- package/packages/apps/galaxpay/package.json +1 -1
- package/packages/apps/google-analytics/package.json +1 -1
- package/packages/apps/jadlog/package.json +1 -1
- package/packages/apps/loyalty-points/package.json +1 -1
- package/packages/apps/melhor-envio/package.json +1 -1
- package/packages/apps/mercadopago/package.json +1 -1
- package/packages/apps/pagarme/package.json +1 -1
- package/packages/apps/paghiper/package.json +1 -1
- package/packages/apps/pix/package.json +1 -1
- package/packages/apps/tiny-erp/package.json +1 -1
- package/packages/apps/webhooks/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/config/package.json +1 -1
- package/packages/emails/package.json +1 -1
- package/packages/events/package.json +1 -1
- package/packages/feeds/package.json +1 -1
- package/packages/firebase/package.json +1 -1
- package/packages/i18n/package.json +1 -1
- package/packages/modules/package.json +1 -1
- package/packages/passport/package.json +1 -1
- package/packages/ssr/package.json +1 -1
- package/packages/storefront/dist/client/_astro/HeroSlider.cea1f361.js +1 -0
- package/packages/storefront/dist/client/_astro/{ProductShelf.9e290480.js → ProductShelf.35614736.js} +1 -1
- package/packages/storefront/dist/client/_astro/ShopHeader.1c27e68e.js +4 -0
- package/packages/storefront/dist/client/_astro/{_...slug_.2f4f6929.css → _...slug_.c13e0486.css} +1 -1
- package/packages/storefront/dist/client/sw.js +1 -1
- package/packages/storefront/dist/server/chunks/{_...d496b072.mjs → _...75363048.mjs} +2 -2
- package/packages/storefront/dist/server/chunks/{account@_@astro.1b311a3d.mjs → account@_@astro.12fbe243.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/{endpoint@_@js.631ff6c5.mjs → endpoint@_@js.67b66d0a.mjs} +2 -2
- package/packages/storefront/dist/server/chunks/{fallback@_@astro.12cf85ba.mjs → fallback@_@astro.0a6656b6.mjs} +2 -2
- package/packages/storefront/dist/server/chunks/{index@_@astro.69eb5e8a.mjs → index@_@astro.a4c9c84e.mjs} +2 -2
- package/packages/storefront/dist/server/chunks/{index@_@astro.a20d91aa.mjs → index@_@astro.df499bf2.mjs} +2 -2
- package/packages/storefront/dist/server/chunks/pages/{_...slug_.astro.c93fc36d.mjs → _...slug_.astro.a71c9334.mjs} +77 -38
- package/packages/storefront/dist/server/chunks/pages/{endpoint.js.630b1212.mjs → endpoint.js.085dadb5.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/pages/{fallback.astro.58c7e581.mjs → fallback.astro.055cb7df.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/pages/{index.astro.6efe85be.mjs → index.astro.abc34f72.mjs} +5 -5
- package/packages/storefront/dist/server/entry.mjs +8 -8
- package/packages/storefront/dist/server/renderers.mjs +1 -1
- package/packages/storefront/package.json +1 -1
- package/packages/storefront/src/lib/$storefront.d.ts +1 -0
- package/packages/storefront/src/lib/components/SharedData.astro +12 -0
- package/packages/storefront/src/lib/composables/use-prices.ts +1 -1
- package/packages/storefront/src/lib/composables/use-shared-data.ts +18 -0
- package/packages/storefront/src/lib/composables/use-shop-header-submenu.ts +10 -1
- package/packages/storefront/src/lib/composables/use-shop-header.ts +20 -19
- package/packages/storefront/src/lib/composables/use-sticky-header.ts +1 -1
- package/packages/storefront/src/lib/layouts/BaseHead.astro +1 -1
- package/packages/storefront/src/lib/layouts/use-page-header.ts +14 -2
- package/packages/storefront/src/lib/ssr-context.ts +1 -0
- package/packages/types/package.json +1 -1
- package/pnpm-workspace.yaml +2 -0
- package/packages/storefront/dist/client/_astro/HeroSlider.0890631f.js +0 -1
- 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,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>
|