negodesign 0.0.35 → 0.0.37
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/dist/components/core/card/product/01/CardProduct01.svelte +130 -0
- package/dist/components/core/card/product/01/CardProduct01.svelte.d.ts +4 -0
- package/dist/components/core/card/product/02/CardProduct02.svelte +118 -0
- package/dist/components/core/card/product/02/CardProduct02.svelte.d.ts +4 -0
- package/dist/components/core/card/product/CardProduct.svelte +22 -0
- package/dist/components/core/card/product/CardProduct.svelte.d.ts +11 -0
- package/dist/components/core/card/product/data.d.ts +3 -0
- package/dist/components/core/card/product/data.js +89 -0
- package/dist/components/core/card/profile/01/CardProfile01.svelte +0 -1
- package/dist/components/core/card/promotion/CardPromotion.svelte +1 -1
- package/dist/components/core/card/promotion/CardPromotionPrice.svelte.d.ts +8 -0
- package/dist/components/core/card/shared/CardPhoneOrWhatsapp.svelte +12 -5
- package/dist/components/core/card/shared/CardTags.svelte +49 -24
- package/dist/components/core/card/shared/CardTitlePrice.svelte +24 -0
- package/dist/components/core/card/shared/CardTitlePrice.svelte.d.ts +15 -0
- package/dist/components/core/card/shared/TruncatableText.svelte +1 -1
- package/dist/components/core/card/types.d.ts +48 -0
- package/dist/components/core/carousel/grid/media/ui/CarouselGridMedia.svelte +38 -28
- package/dist/components/core/carousel/grid/product/types.d.ts +22 -0
- package/dist/components/core/carousel/grid/product/types.js +1 -0
- package/dist/components/core/carousel/grid/product/ui/CarouselGridProduct.svelte +71 -0
- package/dist/components/core/carousel/grid/product/ui/CarouselGridProduct.svelte.d.ts +4 -0
- package/dist/components/core/carousel/grid/profile/ui/CarouselGridProfile.svelte +56 -46
- package/dist/components/core/carousel/grid/promotion/types.d.ts +23 -0
- package/dist/components/core/carousel/grid/promotion/types.js +1 -0
- package/dist/components/core/carousel/grid/promotion/ui/CarouselGridPromotion.svelte +68 -0
- package/dist/components/core/carousel/grid/promotion/ui/CarouselGridPromotion.svelte.d.ts +4 -0
- package/dist/components/core/carousel/highlights/ui/CarouselHighlights.svelte +57 -47
- package/dist/components/core/carousel/product/types.d.ts +21 -0
- package/dist/components/core/carousel/product/types.js +1 -0
- package/dist/components/core/carousel/product/ui/CarouselProduct.svelte +57 -0
- package/dist/components/core/carousel/product/ui/CarouselProduct.svelte.d.ts +4 -0
- package/dist/components/core/carousel/promotion/ui/CarouselPromotion.svelte +57 -47
- package/dist/components/core/panel/NotFoundEmpty.svelte +76 -0
- package/dist/components/core/panel/NotFoundEmpty.svelte.d.ts +16 -0
- package/dist/components/pages/company-profile/CompanyProfile.svelte +144 -0
- package/dist/components/pages/company-profile/CompanyProfile.svelte.d.ts +4 -0
- package/dist/components/pages/company-profile/data.d.ts +2 -0
- package/dist/components/pages/company-profile/data.js +115 -0
- package/dist/components/pages/company-profile/shared/ProfileAboutCompany.svelte +79 -0
- package/dist/components/pages/company-profile/shared/ProfileAboutCompany.svelte.d.ts +9 -0
- package/dist/components/pages/company-profile/shared/ProfileBanner.svelte +270 -0
- package/dist/components/pages/company-profile/shared/ProfileBanner.svelte.d.ts +14 -0
- package/dist/components/pages/company-profile/shared/ProfileGallery.svelte +198 -0
- package/dist/components/pages/company-profile/shared/ProfileGallery.svelte.d.ts +9 -0
- package/dist/components/pages/company-profile/shared/ProfileMenuBadge.svelte +56 -0
- package/dist/components/pages/company-profile/shared/ProfileMenuBadge.svelte.d.ts +11 -0
- package/dist/components/pages/company-profile/shared/ProfileProducts.svelte +62 -0
- package/dist/components/pages/company-profile/shared/ProfileProducts.svelte.d.ts +9 -0
- package/dist/components/pages/company-profile/shared/ProfileSidebar.svelte +57 -0
- package/dist/components/pages/company-profile/shared/ProfileSidebar.svelte.d.ts +11 -0
- package/dist/components/pages/company-profile/types.d.ts +137 -0
- package/dist/components/pages/company-profile/types.js +1 -0
- package/dist/components/pages/privacy-policy-or-terms-of-use/data.d.ts +3 -0
- package/dist/components/pages/privacy-policy-or-terms-of-use/data.js +179 -0
- package/dist/components/pages/privacy-policy-or-terms-of-use/shared/DocSectionView.svelte +2 -1
- package/dist/components/pages/privacy-policy-or-terms-of-use/shared/DocSectionView.svelte.d.ts +1 -0
- package/dist/components/pages/product-details/01/ProductDetails01.svelte +19 -7
- package/dist/components/pages/product-details/02/ProductDetails02.svelte +42 -37
- package/dist/components/pages/product-details/03/ProductDetails03.svelte +33 -29
- package/dist/components/pages/product-details/ProductDetails.svelte +11 -7
- package/dist/components/pages/product-details/shared/ProductDetailFeatures.svelte +11 -5
- package/dist/components/pages/product-details/shared/ProductDetailFeatures.svelte.d.ts +2 -1
- package/dist/components/pages/product-details/shared/ProductDetailFilesVertical.svelte +52 -20
- package/dist/components/pages/product-details/shared/ProductDetailFilesVertical.svelte.d.ts +1 -1
- package/dist/components/pages/product-details/shared/ProductDetailImage.svelte +51 -20
- package/dist/components/pages/product-details/shared/ProductDetailImage.svelte.d.ts +1 -1
- package/dist/components/pages/product-details/shared/ProductDetailPrice.svelte +1 -1
- package/dist/components/pages/product-details/types.d.ts +9 -2
- package/dist/components/pages/profile-user/types.d.ts +7 -0
- package/dist/components/ui/empty/empty-content.svelte +23 -0
- package/dist/components/ui/empty/empty-content.svelte.d.ts +5 -0
- package/dist/components/ui/empty/empty-description.svelte +23 -0
- package/dist/components/ui/empty/empty-description.svelte.d.ts +5 -0
- package/dist/components/ui/empty/empty-header.svelte +20 -0
- package/dist/components/ui/empty/empty-header.svelte.d.ts +5 -0
- package/dist/components/ui/empty/empty-media.svelte +41 -0
- package/dist/components/ui/empty/empty-media.svelte.d.ts +26 -0
- package/dist/components/ui/empty/empty-title.svelte +20 -0
- package/dist/components/ui/empty/empty-title.svelte.d.ts +5 -0
- package/dist/components/ui/empty/empty.svelte +23 -0
- package/dist/components/ui/empty/empty.svelte.d.ts +5 -0
- package/dist/components/ui/empty/index.d.ts +7 -0
- package/dist/components/ui/empty/index.js +9 -0
- package/dist/globals.css +301 -5
- package/dist/i18n/langs/en.d.ts +25 -0
- package/dist/i18n/langs/en.js +25 -0
- package/dist/i18n/langs/pt.d.ts +25 -0
- package/dist/i18n/langs/pt.js +25 -0
- package/dist/i18n/translations.d.ts +50 -0
- package/package.json +1 -1
- package/dist/components/core/card/shared/CardStartPrice.svelte.d.ts +0 -8
- package/dist/components/pages/product-details/04/ProductDetails04.svelte +0 -65
- package/dist/components/pages/product-details/04/ProductDetails04.svelte.d.ts +0 -11
- /package/dist/components/core/card/{shared/CardStartPrice.svelte → promotion/CardPromotionPrice.svelte} +0 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Button from "../../../../ui/button/button.svelte";
|
|
3
|
+
import Skeleton from "../../../../ui/skeleton/skeleton.svelte";
|
|
4
|
+
import { t } from "../../../../../i18n";
|
|
5
|
+
import ImgPlaceHolderGallery from "../../../../../assets/placeholder-image.png";
|
|
6
|
+
import ImgPlaceholderCompany from "../../../../../assets/placeholder-company.png";
|
|
7
|
+
import type { CardProductProps } from "../../types";
|
|
8
|
+
import CardFavorite from "../../shared/CardFavorite.svelte";
|
|
9
|
+
import CardCart from "../../shared/CardCart.svelte";
|
|
10
|
+
import CardDescription from "../../shared/CardDescription.svelte";
|
|
11
|
+
import CardTags from "../../shared/CardTags.svelte";
|
|
12
|
+
import CardTitlePrice from "../../shared/CardTitlePrice.svelte";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Card component with a title and content.
|
|
16
|
+
* @component
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
id,
|
|
21
|
+
tags,
|
|
22
|
+
logo,
|
|
23
|
+
title,
|
|
24
|
+
imageUrl,
|
|
25
|
+
rating = 0,
|
|
26
|
+
isFavorite = false,
|
|
27
|
+
isCart = false,
|
|
28
|
+
isLoading = false,
|
|
29
|
+
content,
|
|
30
|
+
price,
|
|
31
|
+
buttonBuyText,
|
|
32
|
+
buttonBuyClass,
|
|
33
|
+
isDescriptionIcon,
|
|
34
|
+
isDescriptionLabel,
|
|
35
|
+
onClickBuy,
|
|
36
|
+
onClickShop,
|
|
37
|
+
onClickFavorite,
|
|
38
|
+
}: CardProductProps = $props();
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<article class="relative rounded-lg border">
|
|
42
|
+
<aside class="relative w-full p-2">
|
|
43
|
+
<div class="absolute top-2 left-2 z-2 gap-1 p-2">
|
|
44
|
+
{#if isLoading}
|
|
45
|
+
<Skeleton class="h-5 w-20 rounded-full bg-black/20" />
|
|
46
|
+
{:else if logo}
|
|
47
|
+
<img
|
|
48
|
+
src={logo}
|
|
49
|
+
width={30}
|
|
50
|
+
height={30}
|
|
51
|
+
alt={title}
|
|
52
|
+
onerror={(e) =>
|
|
53
|
+
((e.target as HTMLImageElement).src = ImgPlaceholderCompany)}
|
|
54
|
+
class="rounded-lg"
|
|
55
|
+
/>
|
|
56
|
+
{:else}
|
|
57
|
+
<img
|
|
58
|
+
src={ImgPlaceholderCompany}
|
|
59
|
+
width={30}
|
|
60
|
+
height={30}
|
|
61
|
+
alt={title}
|
|
62
|
+
class="rounded-lg"
|
|
63
|
+
/>
|
|
64
|
+
{/if}
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="absolute top-2 right-2 z-2 flex items-center gap-1 p-2">
|
|
68
|
+
<CardFavorite
|
|
69
|
+
{id}
|
|
70
|
+
{isFavorite}
|
|
71
|
+
{isLoading}
|
|
72
|
+
onFavoriteClick={onClickFavorite}
|
|
73
|
+
/>
|
|
74
|
+
<CardCart {id} {isCart} {isLoading} onCartClick={onClickShop} />
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
{#if isLoading}
|
|
78
|
+
<Skeleton
|
|
79
|
+
class="rounded-lg h-30 w-full object-cover object-center bg-black/15"
|
|
80
|
+
/>
|
|
81
|
+
{:else if imageUrl}
|
|
82
|
+
<img
|
|
83
|
+
src={imageUrl}
|
|
84
|
+
alt={imageUrl}
|
|
85
|
+
class="rounded-lg h-36 md:h-44 w-full object-cover object-center"
|
|
86
|
+
onerror={(e) =>
|
|
87
|
+
((e.target as HTMLImageElement).src = ImgPlaceHolderGallery)}
|
|
88
|
+
/>
|
|
89
|
+
{/if}
|
|
90
|
+
<div class="absolute inset-0 bg-black/5 rounded-sm h-full w-full"></div>
|
|
91
|
+
</aside>
|
|
92
|
+
|
|
93
|
+
<aside
|
|
94
|
+
class="bottom-1 inset-x-0 flex flex-col items-center justify-center gap-0.5 m-auto max-w-11/12 p-1 rounded-md"
|
|
95
|
+
>
|
|
96
|
+
<div class="flex justify-between w-full items-center mb-1">
|
|
97
|
+
{#if title}
|
|
98
|
+
{#if isLoading}
|
|
99
|
+
<Skeleton class="h-4 w-30 rounded-lg" />
|
|
100
|
+
{:else}
|
|
101
|
+
<div class="font-semibold line-clamp-1 flex-nowrap">
|
|
102
|
+
{title}
|
|
103
|
+
</div>
|
|
104
|
+
{/if}
|
|
105
|
+
{/if}
|
|
106
|
+
<CardTitlePrice {title} {isLoading} {price} />
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
{#if tags && tags.length > 0}
|
|
110
|
+
<div class="w-full my-1">
|
|
111
|
+
<CardTags {tags} />
|
|
112
|
+
</div>
|
|
113
|
+
{/if}
|
|
114
|
+
|
|
115
|
+
<div>
|
|
116
|
+
<CardDescription {content} {isDescriptionIcon} {isDescriptionLabel} />
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
{#if isLoading}
|
|
120
|
+
<Skeleton class="h-9 w-full rounded-md" />
|
|
121
|
+
{:else}
|
|
122
|
+
<Button
|
|
123
|
+
onclick={() => onClickBuy!(id)}
|
|
124
|
+
class="w-full mb-2 bg-gradient text-white rounded-full {buttonBuyClass}"
|
|
125
|
+
>
|
|
126
|
+
{buttonBuyText || $t("label.buy")}
|
|
127
|
+
</Button>
|
|
128
|
+
{/if}
|
|
129
|
+
</aside>
|
|
130
|
+
</article>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Button from "../../../../ui/button/button.svelte";
|
|
3
|
+
import Skeleton from "../../../../ui/skeleton/skeleton.svelte";
|
|
4
|
+
import { t } from "../../../../../i18n";
|
|
5
|
+
import ImgPlaceHolderGallery from "../../../../../assets/placeholder-image.png";
|
|
6
|
+
import ImgPlaceholderCompany from "../../../../../assets/placeholder-company.png";
|
|
7
|
+
import type { CardProductProps } from "../../types";
|
|
8
|
+
import CardFavorite from "../../shared/CardFavorite.svelte";
|
|
9
|
+
import CardCart from "../../shared/CardCart.svelte";
|
|
10
|
+
import CardDescription from "../../shared/CardDescription.svelte";
|
|
11
|
+
import CardTags from "../../shared/CardTags.svelte";
|
|
12
|
+
import CardTitlePrice from "../../shared/CardTitlePrice.svelte";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Card component with a title and content.
|
|
16
|
+
* @component
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
id,
|
|
21
|
+
tags,
|
|
22
|
+
logo,
|
|
23
|
+
title,
|
|
24
|
+
imageUrl,
|
|
25
|
+
isFavorite = false,
|
|
26
|
+
isCart = false,
|
|
27
|
+
isLoading = false,
|
|
28
|
+
content,
|
|
29
|
+
price,
|
|
30
|
+
buttonBuyText,
|
|
31
|
+
buttonBuyClass,
|
|
32
|
+
isDescriptionIcon,
|
|
33
|
+
isDescriptionLabel,
|
|
34
|
+
onClickBuy,
|
|
35
|
+
onClickShop,
|
|
36
|
+
onClickFavorite,
|
|
37
|
+
}: CardProductProps = $props();
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<article class="relative rounded-lg border">
|
|
41
|
+
<aside class="relative w-full">
|
|
42
|
+
<div class="absolute top-1 left-1 z-2 gap-1 p-2">
|
|
43
|
+
{#if isLoading}
|
|
44
|
+
<Skeleton class="h-5 w-20 rounded-full bg-black/20" />
|
|
45
|
+
{:else if logo}
|
|
46
|
+
<img
|
|
47
|
+
src={logo}
|
|
48
|
+
width={30}
|
|
49
|
+
height={30}
|
|
50
|
+
alt={title}
|
|
51
|
+
onerror={(e) =>
|
|
52
|
+
((e.target as HTMLImageElement).src = ImgPlaceholderCompany)}
|
|
53
|
+
class="rounded-lg"
|
|
54
|
+
/>
|
|
55
|
+
{:else}
|
|
56
|
+
<img
|
|
57
|
+
src={ImgPlaceholderCompany}
|
|
58
|
+
width={30}
|
|
59
|
+
height={30}
|
|
60
|
+
alt={title}
|
|
61
|
+
class="rounded-lg"
|
|
62
|
+
/>
|
|
63
|
+
{/if}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div class="absolute top-1 right-1 z-2 flex items-center gap-1 p-2">
|
|
67
|
+
<CardFavorite
|
|
68
|
+
{id}
|
|
69
|
+
{isFavorite}
|
|
70
|
+
{isLoading}
|
|
71
|
+
onFavoriteClick={onClickFavorite}
|
|
72
|
+
/>
|
|
73
|
+
<CardCart {id} {isCart} {isLoading} onCartClick={onClickShop} />
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
{#if isLoading}
|
|
77
|
+
<Skeleton
|
|
78
|
+
class="rounded-lg h-30 w-full object-cover object-center bg-black/15"
|
|
79
|
+
/>
|
|
80
|
+
{:else if imageUrl}
|
|
81
|
+
<img
|
|
82
|
+
src={imageUrl}
|
|
83
|
+
alt={imageUrl}
|
|
84
|
+
class="rounded-tr-lg rounded-tl-lg h-36 md:h-44 w-full object-cover object-center"
|
|
85
|
+
onerror={(e) =>
|
|
86
|
+
((e.target as HTMLImageElement).src = ImgPlaceHolderGallery)}
|
|
87
|
+
/>
|
|
88
|
+
{/if}
|
|
89
|
+
<div class="absolute inset-0 bg-black/5 rounded-sm h-full w-full"></div>
|
|
90
|
+
</aside>
|
|
91
|
+
|
|
92
|
+
<aside
|
|
93
|
+
class="bottom-1 inset-x-0 flex flex-col items-center justify-center gap-0.5 m-auto max-w-11/12 p-1 rounded-md"
|
|
94
|
+
>
|
|
95
|
+
<CardTitlePrice {title} {isLoading} {price} />
|
|
96
|
+
|
|
97
|
+
<div>
|
|
98
|
+
<CardDescription {content} {isDescriptionIcon} {isDescriptionLabel} />
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
{#if tags && tags.length > 0}
|
|
102
|
+
<div class="w-full mb-2">
|
|
103
|
+
<CardTags {tags} />
|
|
104
|
+
</div>
|
|
105
|
+
{/if}
|
|
106
|
+
|
|
107
|
+
{#if isLoading}
|
|
108
|
+
<Skeleton class="h-9 w-full rounded-md" />
|
|
109
|
+
{:else}
|
|
110
|
+
<Button
|
|
111
|
+
onclick={() => onClickBuy!(id)}
|
|
112
|
+
class="w-full bottom-0 bg-gradient {buttonBuyClass}"
|
|
113
|
+
>
|
|
114
|
+
{buttonBuyText || $t("label.buy")}
|
|
115
|
+
</Button>
|
|
116
|
+
{/if}
|
|
117
|
+
</aside>
|
|
118
|
+
</article>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* Card component with a title and content.
|
|
4
|
+
* @component
|
|
5
|
+
*/
|
|
6
|
+
import type { CardProductProps } from "../types";
|
|
7
|
+
import CardProduct01 from "./01/CardProduct01.svelte";
|
|
8
|
+
import CardProduct02 from "./02/CardProduct02.svelte";
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
variant,
|
|
12
|
+
...restProps
|
|
13
|
+
}: CardProductProps & {
|
|
14
|
+
variant?: 1 | 2;
|
|
15
|
+
} = $props();
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
{#if variant === 2}
|
|
19
|
+
<CardProduct02 {...restProps} />
|
|
20
|
+
{:else}
|
|
21
|
+
<CardProduct01 {...restProps} />
|
|
22
|
+
{/if}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Card component with a title and content.
|
|
3
|
+
* @component
|
|
4
|
+
*/
|
|
5
|
+
import type { CardProductProps } from "../types";
|
|
6
|
+
type $$ComponentProps = CardProductProps & {
|
|
7
|
+
variant?: 1 | 2;
|
|
8
|
+
};
|
|
9
|
+
declare const CardProduct: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type CardProduct = ReturnType<typeof CardProduct>;
|
|
11
|
+
export default CardProduct;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { GlobalIcon, MapPin, NecklaceIcon } from "@hugeicons/core-free-icons";
|
|
2
|
+
const items = [
|
|
3
|
+
{
|
|
4
|
+
id: 1,
|
|
5
|
+
imageUrl: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?q=80&w=1170&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
|
|
6
|
+
title: "Hotel Baía Azul",
|
|
7
|
+
content: "Acomodação premium de frente para o mar com quartos luxuosos, restaurante internacional, piscina aquecida e serviço de transfer exclusivo para hóspedes.",
|
|
8
|
+
isFavorite: true,
|
|
9
|
+
price: "45.000 Kz",
|
|
10
|
+
buttonBuyText: "Comprar",
|
|
11
|
+
onClickBuy: (id) => alert(`Comprar produto ${id}`),
|
|
12
|
+
onClickShop: (id) => alert(`Adicionar ao carrinho ${id}`),
|
|
13
|
+
isCart: true,
|
|
14
|
+
tags: [
|
|
15
|
+
{ icon: GlobalIcon, text: "Luanda" },
|
|
16
|
+
{ icon: MapPin, text: "Ilha do Cabo" },
|
|
17
|
+
{ icon: NecklaceIcon, text: "Frente ao Mar" },
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 2,
|
|
22
|
+
imageUrl: "https://images.unsplash.com/photo-1566073771259-6a8506099945?q=80&w=1170&auto=format&fit=crop",
|
|
23
|
+
title: "Miramar Suites",
|
|
24
|
+
content: "Suítes executivas com vista panorâmica da baía, internet de alta velocidade, pequeno-almoço buffet incluído e centro de conferências moderno.",
|
|
25
|
+
isFavorite: false,
|
|
26
|
+
price: "38.500 Kz",
|
|
27
|
+
buttonBuyText: "Comprar",
|
|
28
|
+
onClickBuy: (id) => alert(`Comprar produto ${id}`),
|
|
29
|
+
onClickShop: (id) => alert(`Adicionar ao carrinho ${id}`),
|
|
30
|
+
isCart: true,
|
|
31
|
+
tags: [
|
|
32
|
+
{ icon: GlobalIcon, text: "Luanda" },
|
|
33
|
+
{ icon: MapPin, text: "Miramar" },
|
|
34
|
+
{ icon: NecklaceIcon, text: "Executivo" },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 3,
|
|
39
|
+
imageUrl: "https://images.unsplash.com/photo-1582719478250-c89cae4dc85b?q=80&w=1170&auto=format&fit=crop",
|
|
40
|
+
title: "Palm Resort & Spa",
|
|
41
|
+
content: "Resort paradisíaco rodeado por palmeiras com spa completo, campos de ténis, atividades infantis e acesso privativo à praia.",
|
|
42
|
+
isFavorite: true,
|
|
43
|
+
price: "52.000 Kz",
|
|
44
|
+
buttonBuyText: "Comprar",
|
|
45
|
+
onClickBuy: (id) => alert(`Comprar produto ${id}`),
|
|
46
|
+
onClickShop: (id) => alert(`Adicionar ao carrinho ${id}`),
|
|
47
|
+
isCart: true,
|
|
48
|
+
tags: [
|
|
49
|
+
{ icon: GlobalIcon, text: "Benguela" },
|
|
50
|
+
{ icon: MapPin, text: "Baía Farta" },
|
|
51
|
+
{ icon: NecklaceIcon, text: "Spa & Lazer" },
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 4,
|
|
56
|
+
imageUrl: "https://images.unsplash.com/photo-1542314831-068cd1dbfeeb?q=80&w=1170&auto=format&fit=crop",
|
|
57
|
+
title: "Hotel Central Park",
|
|
58
|
+
content: "Localização privilegiada no coração financeiro da cidade, perfeito para viagens de negócios e turismo cultural.",
|
|
59
|
+
isFavorite: false,
|
|
60
|
+
price: "29.900 Kz",
|
|
61
|
+
buttonBuyText: "Comprar",
|
|
62
|
+
onClickBuy: (id) => alert(`Comprar produto ${id}`),
|
|
63
|
+
onClickShop: (id) => alert(`Adicionar ao carrinho ${id}`),
|
|
64
|
+
isCart: true,
|
|
65
|
+
tags: [
|
|
66
|
+
{ icon: GlobalIcon, text: "Huambo" },
|
|
67
|
+
{ icon: MapPin, text: "Centro" },
|
|
68
|
+
{ icon: NecklaceIcon, text: "Urbano" },
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 5,
|
|
73
|
+
imageUrl: "https://images.unsplash.com/photo-1571896349842-33c89424de2d?q=80&w=1170&auto=format&fit=crop",
|
|
74
|
+
title: "Villa Serena Boutique",
|
|
75
|
+
content: "Charme e tranquilidade num ambiente intimista com arquitetura rústica, piscina infinita e gastronomia regional selecionada.",
|
|
76
|
+
isFavorite: true,
|
|
77
|
+
price: "60.000 Kz",
|
|
78
|
+
buttonBuyText: "Comprar",
|
|
79
|
+
onClickBuy: (id) => alert(`Comprar produto ${id}`),
|
|
80
|
+
onClickShop: (id) => alert(`Adicionar ao carrinho ${id}`),
|
|
81
|
+
isCart: true,
|
|
82
|
+
tags: [
|
|
83
|
+
{ icon: GlobalIcon, text: "Namibe" },
|
|
84
|
+
{ icon: MapPin, text: "Praia Amélia" },
|
|
85
|
+
{ icon: NecklaceIcon, text: "Boutique" },
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
export default items;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import CardCart from "../shared/CardCart.svelte";
|
|
6
6
|
import CardDescription from "../shared/CardDescription.svelte";
|
|
7
7
|
import CardFavorite from "../shared/CardFavorite.svelte";
|
|
8
|
-
import CardStartPrice from "
|
|
8
|
+
import CardStartPrice from "./CardPromotionPrice.svelte";
|
|
9
9
|
import CardTags from "../shared/CardTags.svelte";
|
|
10
10
|
import ImgPlaceHolderGallery from "../../../../assets/placeholder-image.png";
|
|
11
11
|
import ImgPlaceholderCompany from "../../../../assets/placeholder-company.png";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
newPrice?: string | number;
|
|
3
|
+
oldPrice?: string | number;
|
|
4
|
+
type?: "start" | "normal";
|
|
5
|
+
};
|
|
6
|
+
declare const CardPromotionPrice: import("svelte").Component<Props, {}, "">;
|
|
7
|
+
type CardPromotionPrice = ReturnType<typeof CardPromotionPrice>;
|
|
8
|
+
export default CardPromotionPrice;
|
|
@@ -3,18 +3,25 @@
|
|
|
3
3
|
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
4
4
|
import type { CardPhoneOrWhatsappProps } from "../types";
|
|
5
5
|
|
|
6
|
-
let {
|
|
7
|
-
|
|
6
|
+
let {
|
|
7
|
+
id,
|
|
8
|
+
className,
|
|
9
|
+
buttonClass,
|
|
10
|
+
btnWhatsappClass,
|
|
11
|
+
btnEmailClass,
|
|
12
|
+
onEmailClick,
|
|
13
|
+
onWhatsappClick,
|
|
14
|
+
}: CardPhoneOrWhatsappProps = $props();
|
|
8
15
|
|
|
9
16
|
let isFlex = $derived(onEmailClick && onWhatsappClick);
|
|
10
17
|
</script>
|
|
11
18
|
|
|
12
|
-
<div class="flex border-t border-gray-300 dark:border-gray-700">
|
|
19
|
+
<div class="flex border-t border-gray-300 dark:border-gray-700 {className}">
|
|
13
20
|
{#if onEmailClick}
|
|
14
21
|
<button
|
|
15
22
|
class="flex-1 flex justify-center items-center gap-2 p-3 hover:bg-red-800 hover:text-white cursor-pointer rounded-bl-lg {!isFlex
|
|
16
23
|
? 'rounded-br-lg'
|
|
17
|
-
: ''}"
|
|
24
|
+
: ''} {buttonClass} {btnEmailClass}"
|
|
18
25
|
onclick={() => onEmailClick?.(id)}
|
|
19
26
|
>
|
|
20
27
|
<HugeiconsIcon icon={Mail01Icon} size={20} />
|
|
@@ -28,7 +35,7 @@
|
|
|
28
35
|
<button
|
|
29
36
|
class="flex-1 flex justify-center items-center gap-2 p-3 hover:bg-green-600 hover:text-white cursor-pointer rounded-br-lg {!isFlex
|
|
30
37
|
? 'rounded-bl-lg'
|
|
31
|
-
: ''}"
|
|
38
|
+
: ''} {buttonClass} {btnWhatsappClass}"
|
|
32
39
|
onclick={() => onWhatsappClick?.(id)}
|
|
33
40
|
>
|
|
34
41
|
<HugeiconsIcon icon={WhatsappIcon} size={20} />
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { HugeiconsIcon } from "@hugeicons/svelte";
|
|
3
3
|
import type { CardTagsProps } from "../types";
|
|
4
4
|
import Skeleton from "../../../ui/skeleton/skeleton.svelte";
|
|
5
|
+
import * as Popover from "../../../ui/popover"; // adjust path to your setup
|
|
5
6
|
|
|
6
7
|
type Props = {
|
|
7
8
|
className?: string;
|
|
@@ -20,13 +21,14 @@
|
|
|
20
21
|
}: Props = $props();
|
|
21
22
|
|
|
22
23
|
let isJustify = $derived(tags?.length == 2 || tags?.length == 3);
|
|
24
|
+
let open = $state(false);
|
|
23
25
|
</script>
|
|
24
26
|
|
|
25
|
-
{#snippet createBadge(tag: CardTagsProps)}
|
|
27
|
+
{#snippet createBadge(tag: CardTagsProps, clasName?: string)}
|
|
26
28
|
<div
|
|
27
29
|
class="flex items-center h-5 shrink-0 {isTagBorderBottom
|
|
28
30
|
? 'border border-gray-200 rounded-full px-2 py-1'
|
|
29
|
-
: ''}"
|
|
31
|
+
: ''} {clasName}"
|
|
30
32
|
>
|
|
31
33
|
{#if tag.icon}
|
|
32
34
|
<HugeiconsIcon icon={tag.icon} class="mr-0.5 h-3.75 w-3.75 shrink-0" />
|
|
@@ -43,28 +45,51 @@
|
|
|
43
45
|
</div>
|
|
44
46
|
{/snippet}
|
|
45
47
|
|
|
46
|
-
{#
|
|
47
|
-
|
|
48
|
-
{
|
|
49
|
-
{
|
|
50
|
-
|
|
51
|
-
{
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
48
|
+
{#snippet tagsRow()}
|
|
49
|
+
{#if isWrap}
|
|
50
|
+
<div class="flex flex-wrap gap-2 md:gap-5 {className}">
|
|
51
|
+
{#if isLoading}
|
|
52
|
+
{@render skeletonTag()}
|
|
53
|
+
{:else if tags && tags.length > 0}
|
|
54
|
+
{#each tags as tag, i (i)}
|
|
55
|
+
{@render createBadge(tag)}
|
|
56
|
+
{/each}
|
|
57
|
+
{/if}
|
|
58
|
+
</div>
|
|
59
|
+
{:else}
|
|
60
|
+
<div
|
|
61
|
+
class="flex overflow-x-auto no-scrollbar w-full min-w-0
|
|
62
|
+
{isJustify ? 'justify-between gap-3' : 'gap-4 md:gap-5 lg:gap-10'}
|
|
63
|
+
{className}"
|
|
64
|
+
>
|
|
65
|
+
{#if isLoading}
|
|
66
|
+
{@render skeletonTag()}
|
|
67
|
+
{:else if tags && tags.length > 0}
|
|
68
|
+
{#each tags as tag, i (i)}
|
|
69
|
+
{@render createBadge(tag)}
|
|
70
|
+
{/each}
|
|
71
|
+
{/if}
|
|
72
|
+
</div>
|
|
73
|
+
{/if}
|
|
74
|
+
{/snippet}
|
|
75
|
+
|
|
76
|
+
<Popover.Root bind:open>
|
|
77
|
+
<Popover.Trigger
|
|
78
|
+
onmouseenter={() => (open = true)}
|
|
79
|
+
onmouseleave={() => (open = false)}
|
|
80
|
+
class="block w-full text-left"
|
|
81
|
+
>
|
|
82
|
+
{@render tagsRow()}
|
|
83
|
+
</Popover.Trigger>
|
|
84
|
+
<Popover.Content
|
|
85
|
+
class="w-auto max-w-xs p-3"
|
|
86
|
+
onmouseenter={() => (open = true)}
|
|
87
|
+
onmouseleave={() => (open = false)}
|
|
61
88
|
>
|
|
62
|
-
|
|
63
|
-
{@render skeletonTag()}
|
|
64
|
-
{:else if tags && tags.length > 0}
|
|
89
|
+
<div class="flex flex-col gap-2">
|
|
65
90
|
{#each tags as tag, i (i)}
|
|
66
|
-
{@render createBadge(tag)}
|
|
91
|
+
{@render createBadge(tag, "gap-2")}
|
|
67
92
|
{/each}
|
|
68
|
-
|
|
69
|
-
</
|
|
70
|
-
|
|
93
|
+
</div>
|
|
94
|
+
</Popover.Content>
|
|
95
|
+
</Popover.Root>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import Skeleton from "../../../ui/skeleton/skeleton.svelte";
|
|
3
|
+
|
|
4
|
+
let { title, isLoading, price } = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<div class="flex justify-between w-full items-center">
|
|
8
|
+
{#if title}
|
|
9
|
+
{#if isLoading}
|
|
10
|
+
<Skeleton class="h-4 w-30 rounded-lg" />
|
|
11
|
+
{:else}
|
|
12
|
+
<div class="font-semibold line-clamp-1 flex-nowrap">
|
|
13
|
+
{title}
|
|
14
|
+
</div>
|
|
15
|
+
{/if}
|
|
16
|
+
{/if}
|
|
17
|
+
<div class="flex justify-start gap-2">
|
|
18
|
+
{#if isLoading}
|
|
19
|
+
<Skeleton class="h-5 bg-black/10 w-25 my-2 mr-2" />
|
|
20
|
+
{:else if price}
|
|
21
|
+
<div class="text-lg font-semibold text-primary">{price}</div>
|
|
22
|
+
{/if}
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default CardTitlePrice;
|
|
2
|
+
type CardTitlePrice = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const CardTitlePrice: import("svelte").Component<{
|
|
7
|
+
title: any;
|
|
8
|
+
isLoading: any;
|
|
9
|
+
price: any;
|
|
10
|
+
}, {}, "">;
|
|
11
|
+
type $$ComponentProps = {
|
|
12
|
+
title: any;
|
|
13
|
+
isLoading: any;
|
|
14
|
+
price: any;
|
|
15
|
+
};
|
|
@@ -189,6 +189,54 @@ export interface CardHighlightProps {
|
|
|
189
189
|
}
|
|
190
190
|
export interface CardPhoneOrWhatsappProps {
|
|
191
191
|
id: string | number;
|
|
192
|
+
className?: string;
|
|
193
|
+
buttonClass?: string;
|
|
194
|
+
btnWhatsappClass?: string;
|
|
195
|
+
btnEmailClass?: string;
|
|
192
196
|
onEmailClick?: (id: string | number) => void;
|
|
193
197
|
onWhatsappClick?: (id: string | number) => void;
|
|
194
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* Props do CardProduct — card de produto com preço antigo/novo,
|
|
201
|
+
* botão de comprar, favoritar e adicionar ao carrinho.
|
|
202
|
+
*/
|
|
203
|
+
export interface CardProductProps {
|
|
204
|
+
/** Identificador único da produto */
|
|
205
|
+
id: string | number;
|
|
206
|
+
/** Rating da produto */
|
|
207
|
+
rating?: number;
|
|
208
|
+
/** URL do logotipo */
|
|
209
|
+
logo?: string;
|
|
210
|
+
/** URL da imagem do produto em produto */
|
|
211
|
+
imageUrl?: string;
|
|
212
|
+
/** Nome/título da produto */
|
|
213
|
+
title?: string;
|
|
214
|
+
/** Descrição da produto */
|
|
215
|
+
content?: string;
|
|
216
|
+
/** Classe CSS adicional */
|
|
217
|
+
className?: string;
|
|
218
|
+
/** Indica se o botão de carrinho está ativo */
|
|
219
|
+
isCart?: boolean;
|
|
220
|
+
/** Estado de carregamento (skeleton) */
|
|
221
|
+
isLoading?: boolean;
|
|
222
|
+
/** Indica se está marcado como favorito */
|
|
223
|
+
isFavorite?: boolean;
|
|
224
|
+
/** Lista de tags */
|
|
225
|
+
tags?: CardTagsProps[];
|
|
226
|
+
/** Preço do produto */
|
|
227
|
+
price?: string | number;
|
|
228
|
+
/** Texto do botão de compra (padrão: "Comprar") */
|
|
229
|
+
buttonBuyText?: string;
|
|
230
|
+
/** Classe CSS personalizada para o botão comprar */
|
|
231
|
+
buttonBuyClass?: string;
|
|
232
|
+
/** Exibe ícone antes da descrição */
|
|
233
|
+
isDescriptionIcon?: boolean;
|
|
234
|
+
/** Exibe etiqueta (label) na descrição */
|
|
235
|
+
isDescriptionLabel?: boolean;
|
|
236
|
+
/** Callback ao clicar no botão comprar */
|
|
237
|
+
onClickBuy?: (id: string | number) => void;
|
|
238
|
+
/** Callback ao clicar no botão carrinho */
|
|
239
|
+
onClickShop?: (id: string | number) => void;
|
|
240
|
+
/** Callback ao clicar no botão favorito */
|
|
241
|
+
onClickFavorite?: (id: string | number) => void;
|
|
242
|
+
}
|