cloudcommerce 2.0.0 → 2.0.1
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/CHANGELOG.md +8 -0
- package/ecomplus-stores/barra-doce/conf/firebase.json +7 -0
- package/ecomplus-stores/barra-doce/functions/many/package.json +3 -3
- package/ecomplus-stores/barra-doce/functions/ssr/astro.config.mjs +18 -3
- package/ecomplus-stores/barra-doce/functions/ssr/content/blog/3.md +24 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/blog/4.md +24 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/blog/5.md +24 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/blog/dos.md +24 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/blog/uno.md +24 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/contato.md +9 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/terms.md +20 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/trocas.md +9 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/pages/brands.json +16 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/pages/categories.json +16 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/pages/collections.json +16 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/pages/search.json +7 -0
- package/ecomplus-stores/barra-doce/functions/ssr/package.json +10 -9
- package/ecomplus-stores/barra-doce/functions/ssr/src/assets/style.css +23 -9
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/BannersGrid.astro +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/BlogPosts.vue +88 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/Breadcrumbs.vue +49 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/CartSidebar.vue +2 -2
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/CheckoutPage.vue +14 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/Collapse.vue +4 -4
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ContentEntry.vue +23 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/DocBanners.vue +26 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/FooterStamps.vue +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/HeroSlider.vue +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ImagesGallery.vue +5 -4
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/LoginForm.vue +2 -2
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/PageTitle.vue +43 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/Pagination.vue +67 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/Prices.vue +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductCard.vue +3 -4
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductDetails.vue +4 -3
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductShelf.vue +34 -18
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ProductSpecifications.vue +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/SearchFilters.vue +122 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/SearchModal.vue +97 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/SearchShowcase.vue +169 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopFooter.vue +10 -6
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeader.vue +61 -63
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopHeaderSubmenu.vue +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/ShopSidenav.vue +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/SkuSelector.vue +7 -7
- package/ecomplus-stores/barra-doce/functions/ssr/src/env.d.ts +4 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/PageFooter.astro +4 -1
- package/ecomplus-stores/barra-doce/functions/ssr/src/layouts/PageHeader.astro +2 -2
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Fallback.astro +28 -5
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Main.astro +26 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/content/Hero.astro +33 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/{Sections.astro → content/Sections.astro} +27 -4
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/[...slug].astro +35 -8
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/app/account.astro +6 -2
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/app/index.astro +24 -4
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/blog/[page].astro +71 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/blog/_blog-pages.ts +9 -0
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/~fallback.astro +9 -2
- package/ecomplus-stores/barra-doce/functions/with-apps/package.json +3 -3
- package/ecomplus-stores/barra-doce/package.json +2 -2
- package/package.json +2 -2
- package/packages/api/package.json +1 -1
- package/packages/apps/affiliate-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/mandae/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/pagarme-v5/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/eslint/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/config/astro/context-directive.mjs +16 -2
- package/packages/storefront/config/astro/index.d.ts +3 -1
- package/packages/storefront/package.json +1 -1
- package/packages/storefront/src/lib/components/SharedData.astro +1 -1
- package/packages/storefront/src/lib/composables/use-shared-data.ts +2 -1
- package/packages/test-base/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/ecomplus-stores/barra-doce/functions/ssr/content/blog/.gitkeep +0 -0
- package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/contato.json +0 -11
- package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/terms.json +0 -11
- package/ecomplus-stores/barra-doce/functions/ssr/content/extra-pages/trocas.json +0 -11
- package/ecomplus-stores/barra-doce/functions/ssr/src/components/Breadcrumbs.astro +0 -44
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Home.astro +0 -37
- package/ecomplus-stores/barra-doce/functions/ssr/src/main/Wildcard.astro +0 -18
- package/ecomplus-stores/barra-doce/functions/ssr/src/pages/index.astro +0 -32
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<li
|
|
9
9
|
v-for="i in Math.ceil(pictures.length / 2)"
|
|
10
10
|
:key="i"
|
|
11
|
-
class="grid
|
|
11
|
+
class="grid w-full grid-cols-2 gap-3 px-1 pb-3"
|
|
12
12
|
:class="i === 1 && 'pt-1'"
|
|
13
13
|
>
|
|
14
14
|
<template
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
>
|
|
18
18
|
<button
|
|
19
19
|
v-if="index < pictures.length"
|
|
20
|
-
class="bg-secondary-100 h-
|
|
20
|
+
class="bg-secondary-100 block rounded md:h-[175px]"
|
|
21
21
|
@click="activeIndex = index"
|
|
22
22
|
>
|
|
23
23
|
<AImg
|
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
class="hover:bg-primary-300/60 text-primary
|
|
40
40
|
!bottom-3 !left-1/2 -ml-5 h-10 w-10
|
|
41
41
|
rounded-full bg-white/60 text-xl
|
|
42
|
-
opacity-0 shadow-sm ring-1 ring-black/5
|
|
43
|
-
group-hover:opacity-90"
|
|
42
|
+
opacity-0 shadow-sm ring-1 ring-black/5 group-hover:opacity-90"
|
|
44
43
|
/>
|
|
44
|
+
<span class="absolute bottom-0 block h-2 w-full
|
|
45
|
+
bg-gradient-to-b from-transparent to-white"></span>
|
|
45
46
|
</span>
|
|
46
47
|
</template>
|
|
47
48
|
</Carousel>
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
type="email"
|
|
18
18
|
placeholder="email@mail.com"
|
|
19
19
|
v-model="email"
|
|
20
|
-
class="mb-0.5 mt-2 w-full
|
|
20
|
+
class="mb-0.5 mt-2 w-full"
|
|
21
21
|
required
|
|
22
22
|
/>
|
|
23
23
|
<input
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
type="password"
|
|
26
26
|
:placeholder="$t.i19password"
|
|
27
27
|
v-model="password"
|
|
28
|
-
class="mb-0.5 mt-2 w-full
|
|
28
|
+
class="mb-0.5 mt-2 w-full lowercase"
|
|
29
29
|
required
|
|
30
30
|
/>
|
|
31
31
|
<div class="relative">
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<section v-if="title" class="ui-section">
|
|
3
|
+
<div class="flex items-center gap-4">
|
|
4
|
+
<AImg
|
|
5
|
+
v-if="logo"
|
|
6
|
+
:picture="logo"
|
|
7
|
+
:alt="logo.alt || title"
|
|
8
|
+
class="h-auto max-w-[150px] xl:max-w-[200px]"
|
|
9
|
+
/>
|
|
10
|
+
<h1 class="ui-title">
|
|
11
|
+
{{ title }}
|
|
12
|
+
</h1>
|
|
13
|
+
</div>
|
|
14
|
+
<div class="prose">
|
|
15
|
+
<p v-if="description">
|
|
16
|
+
{{ description }}
|
|
17
|
+
</p>
|
|
18
|
+
</div>
|
|
19
|
+
</section>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import type { Categories, Brands, Collections } from '@cloudcommerce/api/types';
|
|
24
|
+
|
|
25
|
+
export interface Props {
|
|
26
|
+
apiDoc?: Partial<Categories | Brands | Collections>;
|
|
27
|
+
title?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
32
|
+
apiDoc: () => globalThis.$storefront.apiContext?.doc as Categories,
|
|
33
|
+
});
|
|
34
|
+
const title = computed(() => {
|
|
35
|
+
return props.title || props.apiDoc?.name;
|
|
36
|
+
});
|
|
37
|
+
const logo = computed(() => {
|
|
38
|
+
return (props.apiDoc as Brands)?.logo;
|
|
39
|
+
});
|
|
40
|
+
const description = computed(() => {
|
|
41
|
+
return props.description || props.apiDoc?.short_description;
|
|
42
|
+
});
|
|
43
|
+
</script>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ol class="text-base-900 flex justify-center gap-1.5
|
|
3
|
+
text-center text-sm font-medium leading-9">
|
|
4
|
+
<li>
|
|
5
|
+
<ALink
|
|
6
|
+
:href="prevPageLink"
|
|
7
|
+
@click.prevent="prevPageLink && emit('update:page', page - 1)"
|
|
8
|
+
class="mr-1 block min-w-9 rounded border px-3"
|
|
9
|
+
:class="prevPageLink
|
|
10
|
+
? 'border-base-100 hover:bg-base-100'
|
|
11
|
+
: 'border-transparent text-base-500'"
|
|
12
|
+
>
|
|
13
|
+
<i class="i-arrow-right rotate-180"></i>
|
|
14
|
+
<span class="ml-1.5 hidden md:inline">{{ $t.i19previous }}</span>
|
|
15
|
+
</ALink>
|
|
16
|
+
</li>
|
|
17
|
+
<li v-for="(pageN, i) in pages" :key="pageN">
|
|
18
|
+
<ALink
|
|
19
|
+
:href="pageN !== page ? pageLinks[i] : null"
|
|
20
|
+
@click.prevent="emit('update:page', pageN)"
|
|
21
|
+
class="block w-9 rounded border ring-black/10"
|
|
22
|
+
:class="pageN === page
|
|
23
|
+
? 'bg-base-50 border-base-100 ring text-base-700'
|
|
24
|
+
: 'border-transparent hover:bg-base-100'"
|
|
25
|
+
>
|
|
26
|
+
{{ pageN }}
|
|
27
|
+
</ALink>
|
|
28
|
+
</li>
|
|
29
|
+
<li>
|
|
30
|
+
<ALink
|
|
31
|
+
:href="nextPageLink"
|
|
32
|
+
@click.prevent="nextPageLink && emit('update:page', page + 1)"
|
|
33
|
+
class="ml-1 block min-w-9 rounded border px-3"
|
|
34
|
+
:class="nextPageLink
|
|
35
|
+
? 'border-base-100 hover:bg-base-100'
|
|
36
|
+
: 'border-transparent text-base-500'"
|
|
37
|
+
>
|
|
38
|
+
<span class="mr-1.5 hidden md:inline">{{ $t.i19next }}</span>
|
|
39
|
+
<i class="i-arrow-right"></i>
|
|
40
|
+
</ALink>
|
|
41
|
+
</li>
|
|
42
|
+
</ol>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
import {
|
|
47
|
+
type Props as UsePaginationProps,
|
|
48
|
+
usePagination,
|
|
49
|
+
} from '@@sf/composables/use-pagination';
|
|
50
|
+
|
|
51
|
+
export interface Props extends UsePaginationProps {}
|
|
52
|
+
|
|
53
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
54
|
+
page: 1,
|
|
55
|
+
maxPages: 7,
|
|
56
|
+
isUrlPath: false,
|
|
57
|
+
});
|
|
58
|
+
const emit = defineEmits<{
|
|
59
|
+
'update:page': [value: number]
|
|
60
|
+
}>();
|
|
61
|
+
const {
|
|
62
|
+
pages,
|
|
63
|
+
pageLinks,
|
|
64
|
+
prevPageLink,
|
|
65
|
+
nextPageLink,
|
|
66
|
+
} = usePagination(props);
|
|
67
|
+
</script>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[&>div]:[font-size:90%] [&_small]:lowercase [&_small]:[font-size:92%]"
|
|
5
5
|
:class="isBig ? 'text-lg' : null"
|
|
6
6
|
>
|
|
7
|
-
<span v-if="comparePrice" class="text-base-500 mr-1 [
|
|
7
|
+
<span v-if="comparePrice" class="text-base-500 mr-1 text-[87%]">
|
|
8
8
|
<small v-if="isLiteral">
|
|
9
9
|
{{ `${$t.i19from} ` }}
|
|
10
10
|
</small>
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
<article
|
|
3
3
|
ref="card"
|
|
4
4
|
:data-sku="product.sku"
|
|
5
|
-
class="group relative mx-auto h-full max-w-[350px] py-3"
|
|
5
|
+
class="group relative mx-auto h-full max-w-[350px] px-0.5 py-3 hover:z-[1]"
|
|
6
6
|
>
|
|
7
7
|
<ALink
|
|
8
8
|
:href="link"
|
|
9
|
-
class="flex h-full flex-col overflow-hidden rounded
|
|
9
|
+
class="flex h-full flex-col overflow-hidden rounded bg-white
|
|
10
10
|
ring-black/5 group-hover:shadow group-hover:ring-1"
|
|
11
11
|
>
|
|
12
12
|
<div class="aspect-square p-2
|
|
@@ -44,8 +44,7 @@
|
|
|
44
44
|
>
|
|
45
45
|
-<strong>{{ discountPercentage }}</strong>%
|
|
46
46
|
</span>
|
|
47
|
-
<div class="relative z-10 flex grow flex-col justify-
|
|
48
|
-
bg-white/40 p-4 group-hover:backdrop-blur-md">
|
|
47
|
+
<div class="relative z-10 flex grow flex-col justify-between p-4">
|
|
49
48
|
<div class="pb-2">
|
|
50
49
|
<div v-if="isActive">
|
|
51
50
|
<Prices :product="product" />
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
<ImagesGallery :pictures="product.pictures" />
|
|
7
7
|
</template>
|
|
8
8
|
</div>
|
|
9
|
-
<div class="top-0 py-4
|
|
10
|
-
|
|
9
|
+
<div class="lg:sticky-header:translate-y-14 top-0 py-4
|
|
10
|
+
transition-transform lg:sticky">
|
|
11
|
+
<h1 class="ui-text-brand text-secondary-900 text-lg">
|
|
11
12
|
{{ title }}
|
|
12
13
|
</h1>
|
|
13
14
|
<div v-if="isActive" class="mt-5">
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
</div>
|
|
26
27
|
</Fade>
|
|
27
28
|
<div class="mt-5 flex flex-wrap items-center gap-x-4 gap-y-2
|
|
28
|
-
|
|
29
|
+
md:flex-nowrap lg:mt-4 lg:flex-wrap">
|
|
29
30
|
<QuantitySelector
|
|
30
31
|
v-model="quantity"
|
|
31
32
|
:min="product.min_quantity"
|
|
@@ -1,48 +1,63 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<section class="ui-section">
|
|
3
|
-
<div v-if="title" class="mx-auto mb-
|
|
3
|
+
<div v-if="title" class="mx-auto mb-4 max-w-prose text-center">
|
|
4
4
|
<h2 class="ui-text-brand text-3xl">
|
|
5
5
|
<ALink :href="titleLink" :class="titleLink ? 'ui-link' : 'text-base-700'">
|
|
6
6
|
{{ title }}
|
|
7
7
|
</ALink>
|
|
8
8
|
</h2>
|
|
9
9
|
</div>
|
|
10
|
-
<
|
|
10
|
+
<Component
|
|
11
|
+
:is="isGrid ? 'ul' : 'Carousel'"
|
|
12
|
+
class="group/shelf"
|
|
13
|
+
:class="isGrid && 'grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4'"
|
|
14
|
+
>
|
|
11
15
|
<li
|
|
12
16
|
v-for="product in products"
|
|
13
17
|
:key="product._id"
|
|
14
18
|
class="shrink-0 basis-1/2 md:basis-1/3 lg:basis-1/4"
|
|
15
19
|
>
|
|
16
|
-
<ProductCard :product="product" />
|
|
20
|
+
<ProductCard :product="product" :list-name="listName" />
|
|
17
21
|
</li>
|
|
18
|
-
<template #controls>
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
lg:bg-white/80 lg:shadow-sm lg:ring-1"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</
|
|
22
|
+
<template v-if="!isGrid" #controls>
|
|
23
|
+
<DefineCarouselControl v-slot="{ isPrev }">
|
|
24
|
+
<CarouselControl
|
|
25
|
+
v-show="products.length > 2"
|
|
26
|
+
class=":uno: text-primary lg:hover:bg-primary-200 !top-1/2 h-12
|
|
27
|
+
w-12 rounded-full bg-transparent text-3xl leading-none
|
|
28
|
+
ring-black/5 backdrop-blur-md
|
|
29
|
+
transition-opacity group-hover/shelf:opacity-90
|
|
30
|
+
lg:bg-white/80 lg:text-2xl lg:opacity-0 lg:shadow-sm lg:ring-1"
|
|
31
|
+
:class="isPrev ? '!-left-4' : '!-right-4'"
|
|
32
|
+
:is-prev="isPrev"
|
|
33
|
+
/>
|
|
34
|
+
</DefineCarouselControl>
|
|
35
|
+
<ReuseCarouselControl :is-prev="true" />
|
|
36
|
+
<ReuseCarouselControl />
|
|
31
37
|
</template>
|
|
32
|
-
</
|
|
38
|
+
</Component>
|
|
39
|
+
<slot name="append" />
|
|
33
40
|
</section>
|
|
34
41
|
</template>
|
|
35
42
|
|
|
36
43
|
<script setup lang="ts">
|
|
44
|
+
import { createReusableTemplate } from '@vueuse/core';
|
|
37
45
|
import {
|
|
38
46
|
type Props as UseProductShelfProps,
|
|
39
47
|
useProductShelf,
|
|
40
48
|
} from '@@sf/composables/use-product-shelf';
|
|
49
|
+
import { useId } from '@@sf/sf-lib';
|
|
41
50
|
import ProductCard from '~/components/ProductCard.vue';
|
|
42
51
|
|
|
43
|
-
export interface Props extends UseProductShelfProps {
|
|
52
|
+
export interface Props extends UseProductShelfProps {
|
|
53
|
+
isGrid?: boolean;
|
|
54
|
+
}
|
|
44
55
|
|
|
45
56
|
const props = defineProps<Props>();
|
|
57
|
+
const [
|
|
58
|
+
DefineCarouselControl,
|
|
59
|
+
ReuseCarouselControl,
|
|
60
|
+
] = createReusableTemplate<{ isPrev?: boolean }>();
|
|
46
61
|
const {
|
|
47
62
|
title,
|
|
48
63
|
titleLink,
|
|
@@ -52,4 +67,5 @@ const {
|
|
|
52
67
|
if (import.meta.env.SSR) {
|
|
53
68
|
await fetching;
|
|
54
69
|
}
|
|
70
|
+
const listName = title.value || `Shelf ${useId()}`;
|
|
55
71
|
</script>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
border-dashed py-2 sm:grid-cols-3 [&:not(:last-child)]:border-b"
|
|
10
10
|
>
|
|
11
11
|
<span class="text-base-700">
|
|
12
|
-
{{ getGridTitle(`${gridId}`, grids) }}
|
|
12
|
+
{{ getGridTitle(`${gridId}`, grids || []) }}
|
|
13
13
|
</span>
|
|
14
14
|
<strong class="font-semibold sm:col-span-2">
|
|
15
15
|
{{ getSpecTextValue(product, `${gridId}`, grids) }}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<aside class="bg-base-50/40 h-screen overflow-y-auto">
|
|
3
|
+
<header class="px-6 pb-3 pt-5 text-center">
|
|
4
|
+
<button
|
|
5
|
+
v-if="filtersCount"
|
|
6
|
+
class="ui-btn-sm ui-btn-danger py-1"
|
|
7
|
+
@click="clearFilters"
|
|
8
|
+
>
|
|
9
|
+
{{ $t.i19clearFilters }}
|
|
10
|
+
<i class="i-trash ml-0.5"></i>
|
|
11
|
+
</button>
|
|
12
|
+
<p v-else class="text-base-500 border border-transparent
|
|
13
|
+
pb-1 text-base font-semibold">
|
|
14
|
+
{{ $t.i19filterResults }}
|
|
15
|
+
</p>
|
|
16
|
+
</header>
|
|
17
|
+
<article v-if="resultBuckets" class="px-6 pb-3">
|
|
18
|
+
<Collapse
|
|
19
|
+
v-if="priceRanges"
|
|
20
|
+
:title="$t.i19price"
|
|
21
|
+
class="[&>summary]:text-xl"
|
|
22
|
+
open
|
|
23
|
+
>
|
|
24
|
+
<div class="space-y-1.5">
|
|
25
|
+
<div
|
|
26
|
+
v-for="({ range, key }) in priceRanges"
|
|
27
|
+
:key="`prices-${key}`"
|
|
28
|
+
class="flex items-center"
|
|
29
|
+
>
|
|
30
|
+
<input
|
|
31
|
+
type="radio"
|
|
32
|
+
:id="`priceRange-${key}`"
|
|
33
|
+
name="priceRange"
|
|
34
|
+
:value="key"
|
|
35
|
+
v-model="priceRangeKey"
|
|
36
|
+
/>
|
|
37
|
+
<label
|
|
38
|
+
:for="`priceRange-${key}`"
|
|
39
|
+
class="cursor-pointer px-3 text-sm"
|
|
40
|
+
>
|
|
41
|
+
{{ getPriceRangeLabel(range) }}
|
|
42
|
+
<small class="text-base-500 font-medium">
|
|
43
|
+
({{ range.count }})
|
|
44
|
+
</small>
|
|
45
|
+
</label>
|
|
46
|
+
</div>
|
|
47
|
+
<div
|
|
48
|
+
v-if="activeFilters['price<'] || activeFilters['price>']"
|
|
49
|
+
class="flex items-center"
|
|
50
|
+
>
|
|
51
|
+
<input
|
|
52
|
+
type="radio"
|
|
53
|
+
id="priceRange-null"
|
|
54
|
+
name="priceRange"
|
|
55
|
+
:value="null"
|
|
56
|
+
v-model="priceRangeKey"
|
|
57
|
+
/>
|
|
58
|
+
<label for="priceRange-null" class="cursor-pointer px-3 text-sm">
|
|
59
|
+
{{ $t.i19anyPrice }}
|
|
60
|
+
</label>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</Collapse>
|
|
64
|
+
<Collapse
|
|
65
|
+
v-for="({ title, options, field }) in filterOptions"
|
|
66
|
+
:key="field"
|
|
67
|
+
:title="title"
|
|
68
|
+
class="[&>summary]:text-xl"
|
|
69
|
+
:open="!!activeFilters[field]"
|
|
70
|
+
>
|
|
71
|
+
<div class="space-y-1.5">
|
|
72
|
+
<div
|
|
73
|
+
v-for="(count, value, i) in options"
|
|
74
|
+
:key="`${field}-${i}`"
|
|
75
|
+
class="flex items-center"
|
|
76
|
+
>
|
|
77
|
+
<input
|
|
78
|
+
type="checkbox"
|
|
79
|
+
:id="`${field}-${value}`"
|
|
80
|
+
:value="value"
|
|
81
|
+
:checked="checkFilterOption(field, value)"
|
|
82
|
+
@change="toggleFilterOption(field, value)"
|
|
83
|
+
/>
|
|
84
|
+
<label
|
|
85
|
+
:for="`${field}-${value}`"
|
|
86
|
+
class="cursor-pointer px-3 text-sm"
|
|
87
|
+
>
|
|
88
|
+
{{ value }}
|
|
89
|
+
<small class="text-base-500 font-medium">
|
|
90
|
+
({{ count }})
|
|
91
|
+
</small>
|
|
92
|
+
</label>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</Collapse>
|
|
96
|
+
</article>
|
|
97
|
+
</aside>
|
|
98
|
+
</template>
|
|
99
|
+
|
|
100
|
+
<script setup lang="ts">
|
|
101
|
+
import {
|
|
102
|
+
type Props as UseSearchFiltersProps,
|
|
103
|
+
useSearchFilters,
|
|
104
|
+
} from '@@sf/composables/use-search-filters';
|
|
105
|
+
import Collapse from '~/components/Collapse.vue';
|
|
106
|
+
|
|
107
|
+
export interface Props extends UseSearchFiltersProps {}
|
|
108
|
+
|
|
109
|
+
const props = defineProps<Props>();
|
|
110
|
+
const {
|
|
111
|
+
resultBuckets,
|
|
112
|
+
activeFilters,
|
|
113
|
+
filtersCount,
|
|
114
|
+
clearFilters,
|
|
115
|
+
priceRanges,
|
|
116
|
+
priceRangeKey,
|
|
117
|
+
getPriceRangeLabel,
|
|
118
|
+
filterOptions,
|
|
119
|
+
checkFilterOption,
|
|
120
|
+
toggleFilterOption,
|
|
121
|
+
} = useSearchFilters(props);
|
|
122
|
+
</script>
|
|
@@ -1,6 +1,102 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<article class="relative">
|
|
3
|
+
<Fade slide="down">
|
|
4
|
+
<section
|
|
5
|
+
v-if="linkHits.length"
|
|
6
|
+
class="bg-white p-4"
|
|
7
|
+
:class="!isFetching && products.length ? 'lg:rounded-t' : 'lg:rounded'"
|
|
8
|
+
>
|
|
9
|
+
<nav>
|
|
10
|
+
<Carousel :wrapper-key="term" class="px-6 [&>ul]:gap-3">
|
|
11
|
+
<li
|
|
12
|
+
v-for="({ title, href }, i) in linkHits"
|
|
13
|
+
:key="i"
|
|
14
|
+
class="shrink-0"
|
|
15
|
+
>
|
|
16
|
+
<ALink :href="href" class="ui-link">
|
|
17
|
+
{{ title }}
|
|
18
|
+
</ALink>
|
|
19
|
+
</li>
|
|
20
|
+
</Carousel>
|
|
21
|
+
</nav>
|
|
22
|
+
</section>
|
|
23
|
+
</Fade>
|
|
24
|
+
<Skeleton v-if="isFetching" class="absolute top-0 w-full px-5 pt-20" />
|
|
25
|
+
<Fade :is-leave-to="false">
|
|
26
|
+
<ProductShelf
|
|
27
|
+
v-if="!isFetching && products.length"
|
|
28
|
+
:products="products"
|
|
29
|
+
class="m-0 max-w-none bg-white px-4
|
|
30
|
+
lg:[&_[data-carousel-control=next]]:!-right-10
|
|
31
|
+
lg:[&_[data-carousel-control=previous]]:!-left-10"
|
|
32
|
+
:class="linkHits.length ? 'lg:rounded-b' : 'lg:rounded'"
|
|
33
|
+
/>
|
|
34
|
+
</Fade>
|
|
35
|
+
<Fade :is-leave-to="false">
|
|
36
|
+
<section
|
|
37
|
+
v-if="!isFetching
|
|
38
|
+
&& (searchHistory.length || productCount > products.length)"
|
|
39
|
+
class="bg-base-100/80 grid grid-cols-1 items-center
|
|
40
|
+
gap-4 p-4 backdrop-blur-md
|
|
41
|
+
md:grid-cols-2 md:rounded-b lg:mt-5 lg:grid-cols-3 lg:rounded"
|
|
42
|
+
>
|
|
43
|
+
<div class="flex items-center justify-end gap-4 md:order-2">
|
|
44
|
+
<p
|
|
45
|
+
v-if="productCount > 1"
|
|
46
|
+
class="text-base-900 text-right text-sm lowercase"
|
|
47
|
+
>
|
|
48
|
+
<strong>{{ productCount }}</strong> {{ $t.i19itemsFound }}
|
|
49
|
+
</p>
|
|
50
|
+
<a
|
|
51
|
+
v-if="productCount > products.length"
|
|
52
|
+
:href="getSearchUrl(term)"
|
|
53
|
+
class="ui-btn ui-btn-primary w-auto whitespace-nowrap text-center"
|
|
54
|
+
>
|
|
55
|
+
{{ $t.i19seeAll }}
|
|
56
|
+
</a>
|
|
57
|
+
</div>
|
|
58
|
+
<div class="lg:col-span-2">
|
|
59
|
+
<nav>
|
|
60
|
+
<Carousel :wrapper-key="term" class="px-6 [&>ul]:gap-2.5">
|
|
61
|
+
<li
|
|
62
|
+
v-for="(term, i) in searchHistory"
|
|
63
|
+
:key="i"
|
|
64
|
+
class="shrink-0"
|
|
65
|
+
>
|
|
66
|
+
<a
|
|
67
|
+
:href="getSearchUrl(term)"
|
|
68
|
+
class="ui-link text-base-700 text-sm font-normal"
|
|
69
|
+
>
|
|
70
|
+
{{ term }}
|
|
71
|
+
</a>
|
|
72
|
+
</li>
|
|
73
|
+
<template #previous>
|
|
74
|
+
<i class="i-clock m-0" :aria-label="$t.i19searchAgain"></i>
|
|
75
|
+
</template>
|
|
76
|
+
</Carousel>
|
|
77
|
+
</nav>
|
|
78
|
+
</div>
|
|
79
|
+
</section>
|
|
80
|
+
</Fade>
|
|
81
|
+
</article>
|
|
3
82
|
</template>
|
|
4
83
|
|
|
5
84
|
<script setup lang="ts">
|
|
85
|
+
import {
|
|
86
|
+
type Props as UseSearchModalProps,
|
|
87
|
+
useSearchModal,
|
|
88
|
+
} from '@@sf/composables/use-search-modal';
|
|
89
|
+
import { getSearchUrl } from '@@sf/sf-lib';
|
|
90
|
+
import ProductShelf from '~/components/ProductShelf.vue';
|
|
91
|
+
|
|
92
|
+
export interface Props extends UseSearchModalProps {}
|
|
93
|
+
|
|
94
|
+
const props = defineProps<Props>();
|
|
95
|
+
const {
|
|
96
|
+
searchHistory,
|
|
97
|
+
isFetching,
|
|
98
|
+
products,
|
|
99
|
+
productCount,
|
|
100
|
+
linkHits,
|
|
101
|
+
} = useSearchModal(props);
|
|
6
102
|
</script>
|