negodesign 0.0.35 → 0.0.36
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/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 +61 -0
- package/dist/components/core/carousel/grid/product/ui/CarouselGridProduct.svelte.d.ts +4 -0
- 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 +50 -0
- package/dist/components/core/carousel/grid/promotion/ui/CarouselGridPromotion.svelte.d.ts +4 -0
- 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 +47 -0
- package/dist/components/core/carousel/product/ui/CarouselProduct.svelte.d.ts +4 -0
- package/dist/components/pages/company-profile/CompanyProfile.svelte +140 -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 +68 -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 +194 -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/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 +117 -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/globals.css +244 -5
- package/dist/i18n/langs/en.d.ts +10 -0
- package/dist/i18n/langs/en.js +10 -0
- package/dist/i18n/langs/pt.d.ts +10 -0
- package/dist/i18n/langs/pt.js +10 -0
- package/dist/i18n/translations.d.ts +20 -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,22 @@
|
|
|
1
|
+
import type { CardProductProps } from "../../../card/types";
|
|
2
|
+
import type { CarouselSlotProps } from "../../../panel/type";
|
|
3
|
+
import type { CarouselHeaderProps } from "../../types";
|
|
4
|
+
/**
|
|
5
|
+
* Props do CarouselGridProduct — layout em grid de cards de product
|
|
6
|
+
*/
|
|
7
|
+
export interface CarouselGridProductProps {
|
|
8
|
+
/** Props do cabeçalho do carousel (título, descrição, etc.) */
|
|
9
|
+
headerProps?: CarouselHeaderProps;
|
|
10
|
+
/** Props do slot/container do carousel (botões navegação, plugins) */
|
|
11
|
+
slotProps?: CarouselSlotProps;
|
|
12
|
+
/** Classe CSS adicional para o container do grid */
|
|
13
|
+
gridClass?: string;
|
|
14
|
+
/** Variante visual do card: 1 ou 2 */
|
|
15
|
+
variant?: 1 | 2;
|
|
16
|
+
/** Lista de perfis para exibir nos cards */
|
|
17
|
+
items: CardProductProps[];
|
|
18
|
+
/** Estado de carregamento (skeleton) */
|
|
19
|
+
isLoading?: boolean;
|
|
20
|
+
isDescriptionIcon?: boolean;
|
|
21
|
+
isDescriptionLabel?: boolean;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CarouselGridSlot from "../../shared/ui/CarouselGridSlot.svelte";
|
|
3
|
+
import * as Carousel from "../../../../../ui/carousel/index.js";
|
|
4
|
+
import CarouselHeader from "../../../shared/ui/CarouselHeader.svelte";
|
|
5
|
+
import { useDevice } from "../../../../../../hooks/responsive.svelte";
|
|
6
|
+
import CardProduct from "../../../../card/product/CardProduct.svelte";
|
|
7
|
+
import type { CarouselGridProductProps } from "../types";
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
headerProps,
|
|
11
|
+
slotProps,
|
|
12
|
+
gridClass = "lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6",
|
|
13
|
+
items,
|
|
14
|
+
variant,
|
|
15
|
+
isLoading = false,
|
|
16
|
+
isDescriptionIcon = false,
|
|
17
|
+
isDescriptionLabel = false,
|
|
18
|
+
}: CarouselGridProductProps = $props();
|
|
19
|
+
|
|
20
|
+
const responsive = useDevice();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<CarouselHeader {...headerProps}>
|
|
24
|
+
<CarouselGridSlot {slotProps} {gridClass} totalItems={items.length}>
|
|
25
|
+
{#if isLoading}
|
|
26
|
+
{#each Array.from( { length: responsive.isMobile ? 3 : 6 }, ) as _, i (`loading-${i}`)}
|
|
27
|
+
{#if responsive.isMobile}
|
|
28
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
29
|
+
<CardProduct id={i} {variant} isLoading />
|
|
30
|
+
</Carousel.Item>
|
|
31
|
+
{:else}
|
|
32
|
+
<div>
|
|
33
|
+
<CardProduct id={i} {variant} isLoading />
|
|
34
|
+
</div>
|
|
35
|
+
{/if}
|
|
36
|
+
{/each}
|
|
37
|
+
{:else}
|
|
38
|
+
{#each items as item, i (`profile-${item.id ?? i}`)}
|
|
39
|
+
{#if responsive.isMobile}
|
|
40
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
41
|
+
<CardProduct
|
|
42
|
+
{...item}
|
|
43
|
+
{variant}
|
|
44
|
+
{isDescriptionIcon}
|
|
45
|
+
{isDescriptionLabel}
|
|
46
|
+
/>
|
|
47
|
+
</Carousel.Item>
|
|
48
|
+
{:else}
|
|
49
|
+
<div>
|
|
50
|
+
<CardProduct
|
|
51
|
+
{...item}
|
|
52
|
+
{variant}
|
|
53
|
+
{isDescriptionIcon}
|
|
54
|
+
{isDescriptionLabel}
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
{/if}
|
|
58
|
+
{/each}
|
|
59
|
+
{/if}
|
|
60
|
+
</CarouselGridSlot>
|
|
61
|
+
</CarouselHeader>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CardPromotionProps } from "../../../card/types";
|
|
2
|
+
import type { CarouselSlotProps } from "../../../panel/type";
|
|
3
|
+
import type { CarouselHeaderProps } from "../../types";
|
|
4
|
+
/**
|
|
5
|
+
* Props do CarouselGridProfile — layout em grid de cards de perfil
|
|
6
|
+
* (guias, intérpretes, organizações). Em mobile vira carousel com swipe.
|
|
7
|
+
*/
|
|
8
|
+
export interface CarouselGridPromotionProps {
|
|
9
|
+
/** Props do cabeçalho do carousel (título, descrição, etc.) */
|
|
10
|
+
headerProps?: CarouselHeaderProps;
|
|
11
|
+
/** Props do slot/container do carousel (botões navegação, plugins) */
|
|
12
|
+
slotProps?: CarouselSlotProps;
|
|
13
|
+
/** Classe CSS adicional para o container do grid */
|
|
14
|
+
gridClass?: string;
|
|
15
|
+
/** Variante visual do card: 1 ou 2 */
|
|
16
|
+
variant?: 1 | 2;
|
|
17
|
+
/** Lista de perfis para exibir nos cards */
|
|
18
|
+
items: CardPromotionProps[];
|
|
19
|
+
/** Estado de carregamento (skeleton) */
|
|
20
|
+
isLoading?: boolean;
|
|
21
|
+
isDescriptionIcon?: boolean;
|
|
22
|
+
isDescriptionLabel?: boolean;
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CarouselGridSlot from "../../shared/ui/CarouselGridSlot.svelte";
|
|
3
|
+
import * as Carousel from "../../../../../ui/carousel/index.js";
|
|
4
|
+
import CarouselHeader from "../../../shared/ui/CarouselHeader.svelte";
|
|
5
|
+
import { useDevice } from "../../../../../../hooks/responsive.svelte";
|
|
6
|
+
import CardPromotion from "../../../../card/promotion/CardPromotion.svelte";
|
|
7
|
+
import type { CarouselGridPromotionProps } from "../types";
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
headerProps,
|
|
11
|
+
slotProps,
|
|
12
|
+
gridClass = "lg:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5",
|
|
13
|
+
items,
|
|
14
|
+
isLoading = false,
|
|
15
|
+
isDescriptionIcon = false,
|
|
16
|
+
isDescriptionLabel = false,
|
|
17
|
+
}: CarouselGridPromotionProps = $props();
|
|
18
|
+
|
|
19
|
+
const responsive = useDevice();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<CarouselHeader {...headerProps}>
|
|
23
|
+
<CarouselGridSlot {slotProps} {gridClass} totalItems={items.length}>
|
|
24
|
+
{#if isLoading}
|
|
25
|
+
{#each Array.from( { length: responsive.isMobile ? 3 : 6 }, ) as _, i (`loading-${i}`)}
|
|
26
|
+
{#if responsive.isMobile}
|
|
27
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
28
|
+
<CardPromotion id={i} isLoading />
|
|
29
|
+
</Carousel.Item>
|
|
30
|
+
{:else}
|
|
31
|
+
<div>
|
|
32
|
+
<CardPromotion id={i} isLoading />
|
|
33
|
+
</div>
|
|
34
|
+
{/if}
|
|
35
|
+
{/each}
|
|
36
|
+
{:else}
|
|
37
|
+
{#each items as item, i (`promotion-${item.id ?? i}`)}
|
|
38
|
+
{#if responsive.isMobile}
|
|
39
|
+
<Carousel.Item class="pl-2 basis-auto">
|
|
40
|
+
<CardPromotion {...item} {isDescriptionIcon} {isDescriptionLabel} />
|
|
41
|
+
</Carousel.Item>
|
|
42
|
+
{:else}
|
|
43
|
+
<div>
|
|
44
|
+
<CardPromotion {...item} {isDescriptionIcon} {isDescriptionLabel} />
|
|
45
|
+
</div>
|
|
46
|
+
{/if}
|
|
47
|
+
{/each}
|
|
48
|
+
{/if}
|
|
49
|
+
</CarouselGridSlot>
|
|
50
|
+
</CarouselHeader>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CarouselGridPromotionProps } from "../types";
|
|
2
|
+
declare const CarouselGridPromotion: import("svelte").Component<CarouselGridPromotionProps, {}, "">;
|
|
3
|
+
type CarouselGridPromotion = ReturnType<typeof CarouselGridPromotion>;
|
|
4
|
+
export default CarouselGridPromotion;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CardProductProps } from "../../card/types";
|
|
2
|
+
import type { CarouselSlotProps } from "../../panel/type";
|
|
3
|
+
import type { CarouselHeaderProps } from "../types";
|
|
4
|
+
/**
|
|
5
|
+
* Props do CarouselProduct — carousel de cards de produto
|
|
6
|
+
* com preços antigo/novo e botões de compra.
|
|
7
|
+
*/
|
|
8
|
+
export interface CarouselProductProps {
|
|
9
|
+
/** Props do cabeçalho do carousel (título, descrição, etc.) */
|
|
10
|
+
headerProps?: CarouselHeaderProps;
|
|
11
|
+
/** Props do slot/container do carousel (botões navegação, plugins) */
|
|
12
|
+
slotProps?: CarouselSlotProps;
|
|
13
|
+
/** Lista de promoções para exibir */
|
|
14
|
+
items: CardProductProps[];
|
|
15
|
+
/** Exibe ícone antes da descrição do card */
|
|
16
|
+
isDescriptionIcon?: boolean;
|
|
17
|
+
/** Exibe etiqueta (label) na descrição do card */
|
|
18
|
+
isDescriptionLabel?: boolean;
|
|
19
|
+
/** Estado de carregamento (skeleton) */
|
|
20
|
+
isLoading?: boolean;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CarouselSlot from "../../../panel/CarouselSlot.svelte";
|
|
3
|
+
import * as Carousel from "../../../../ui/carousel/index.js";
|
|
4
|
+
import type { CarouselProductProps } from "../types";
|
|
5
|
+
import CarouselHeader from "../../shared/ui/CarouselHeader.svelte";
|
|
6
|
+
import { useDevice } from "../../../../../hooks/responsive.svelte";
|
|
7
|
+
import Autoplay from "embla-carousel-autoplay";
|
|
8
|
+
import CardProduct from "../../../card/product/CardProduct.svelte";
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
headerProps,
|
|
12
|
+
slotProps,
|
|
13
|
+
items,
|
|
14
|
+
isLoading = false,
|
|
15
|
+
isDescriptionIcon,
|
|
16
|
+
isDescriptionLabel,
|
|
17
|
+
}: CarouselProductProps = $props();
|
|
18
|
+
|
|
19
|
+
const responsive = useDevice();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<CarouselHeader {...headerProps}>
|
|
23
|
+
<CarouselSlot
|
|
24
|
+
{...slotProps}
|
|
25
|
+
containerClass="w-full"
|
|
26
|
+
plugins={[Autoplay({ delay: 4000, stopOnInteraction: true })]}
|
|
27
|
+
>
|
|
28
|
+
{#if isLoading}
|
|
29
|
+
{#each Array.from( { length: responsive.isMobile ? 5 : 10 }, ) as _, i (`loading-${i}`)}
|
|
30
|
+
<Carousel.Item class="pl-5 w-75 basis-auto">
|
|
31
|
+
<CardProduct
|
|
32
|
+
id={i}
|
|
33
|
+
{isLoading}
|
|
34
|
+
{isDescriptionIcon}
|
|
35
|
+
{isDescriptionLabel}
|
|
36
|
+
/>
|
|
37
|
+
</Carousel.Item>
|
|
38
|
+
{/each}
|
|
39
|
+
{:else}
|
|
40
|
+
{#each items as item, i (`product-${item.id ?? i}`)}
|
|
41
|
+
<Carousel.Item class="pl-2 w-75 basis-auto">
|
|
42
|
+
<CardProduct {...item} {isDescriptionIcon} {isDescriptionLabel} />
|
|
43
|
+
</Carousel.Item>
|
|
44
|
+
{/each}
|
|
45
|
+
{/if}
|
|
46
|
+
</CarouselSlot>
|
|
47
|
+
</CarouselHeader>
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/**
|
|
3
|
+
* Página de perfil da empresa/fábrica.
|
|
4
|
+
* Combina o banner de apresentação, navegação entre secções
|
|
5
|
+
* (Sidebar em desktop, badges em mobile) e as secções
|
|
6
|
+
* "Sobre a Empresa" e "Galeria".
|
|
7
|
+
*
|
|
8
|
+
* @component
|
|
9
|
+
* @example
|
|
10
|
+
* ```svelte
|
|
11
|
+
* <CompanyProfile data={companyData} />
|
|
12
|
+
*
|
|
13
|
+
* <CompanyProfile
|
|
14
|
+
* data={companyData}
|
|
15
|
+
* onContact={(id) => openWhatsapp(id)}
|
|
16
|
+
* onShare={(id) => navigator.share?.({ url: shareUrl(id) })}
|
|
17
|
+
* />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import { onMount } from "svelte";
|
|
24
|
+
import { useDevice } from "../../../hooks/responsive.svelte";
|
|
25
|
+
import ProfileBanner from "./shared/ProfileBanner.svelte";
|
|
26
|
+
import ProfileSidebar from "./shared/ProfileSidebar.svelte";
|
|
27
|
+
import ProfileMenuBadge from "./shared/ProfileMenuBadge.svelte";
|
|
28
|
+
import ProfileAboutCompany from "./shared/ProfileAboutCompany.svelte";
|
|
29
|
+
import ProfileGallery from "./shared/ProfileGallery.svelte";
|
|
30
|
+
import { defaultCompanyProfileData } from "./data";
|
|
31
|
+
import type { CompanyProfileProps, ProfileNavItem } from "./types";
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
data = defaultCompanyProfileData,
|
|
35
|
+
isLoading = false,
|
|
36
|
+
yearFounded,
|
|
37
|
+
category,
|
|
38
|
+
address,
|
|
39
|
+
website,
|
|
40
|
+
onEmail,
|
|
41
|
+
onWhatsapp,
|
|
42
|
+
onCopyLink,
|
|
43
|
+
onShare,
|
|
44
|
+
}: CompanyProfileProps = $props();
|
|
45
|
+
|
|
46
|
+
const responsive = useDevice();
|
|
47
|
+
|
|
48
|
+
const sections: ProfileNavItem[] = [
|
|
49
|
+
{ id: "banner", label: "Apresentação" },
|
|
50
|
+
{ id: "sobre-empresa", label: "Sobre a empresa" },
|
|
51
|
+
{ id: "galeria-empresa", label: "Galeria da empresa" },
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
let activeSection = $state(sections[0]?.id);
|
|
55
|
+
let sectionEls: Record<string, HTMLElement> = {};
|
|
56
|
+
|
|
57
|
+
function scrollToSection(id: string) {
|
|
58
|
+
activeSection = id;
|
|
59
|
+
sectionEls[id]?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onMount(() => {
|
|
63
|
+
const observer = new IntersectionObserver(
|
|
64
|
+
(entries) => {
|
|
65
|
+
const visible = entries
|
|
66
|
+
.filter((entry) => entry.isIntersecting)
|
|
67
|
+
.sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
|
|
68
|
+
if (
|
|
69
|
+
visible[0]?.target instanceof HTMLElement &&
|
|
70
|
+
visible[0].target.dataset.sectionId
|
|
71
|
+
) {
|
|
72
|
+
activeSection = visible[0].target.dataset.sectionId;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{ rootMargin: "-45% 0px -45% 0px", threshold: 0 },
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
Object.values(sectionEls).forEach((el) => el && observer.observe(el));
|
|
79
|
+
|
|
80
|
+
return () => observer.disconnect();
|
|
81
|
+
});
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<div class="">
|
|
85
|
+
{#if responsive.isMobile}
|
|
86
|
+
<ProfileMenuBadge
|
|
87
|
+
items={sections}
|
|
88
|
+
active={activeSection}
|
|
89
|
+
onSelect={scrollToSection}
|
|
90
|
+
className="mt-6"
|
|
91
|
+
/>
|
|
92
|
+
{/if}
|
|
93
|
+
|
|
94
|
+
<div class="flex gap-6">
|
|
95
|
+
{#if !responsive.isMobile}
|
|
96
|
+
<ProfileSidebar
|
|
97
|
+
items={sections}
|
|
98
|
+
active={activeSection}
|
|
99
|
+
onSelect={scrollToSection}
|
|
100
|
+
/>
|
|
101
|
+
{/if}
|
|
102
|
+
|
|
103
|
+
<div class="flex min-w-0 flex-1 flex-col gap-6 md:px-5 md:pl-10 lg:pl-12">
|
|
104
|
+
<div
|
|
105
|
+
id="banner"
|
|
106
|
+
bind:this={sectionEls["banner"]}
|
|
107
|
+
data-section-id="banner"
|
|
108
|
+
class="p-3"
|
|
109
|
+
>
|
|
110
|
+
<ProfileBanner
|
|
111
|
+
id={data.id}
|
|
112
|
+
data={data.banner}
|
|
113
|
+
{isLoading}
|
|
114
|
+
{onEmail}
|
|
115
|
+
{onWhatsapp}
|
|
116
|
+
{onCopyLink}
|
|
117
|
+
{onShare}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div
|
|
122
|
+
id="sobre-empresa"
|
|
123
|
+
bind:this={sectionEls["sobre-empresa"]}
|
|
124
|
+
data-section-id="sobre-empresa"
|
|
125
|
+
>
|
|
126
|
+
<ProfileAboutCompany data={data.about} {isLoading} />
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<hr />
|
|
130
|
+
|
|
131
|
+
<div
|
|
132
|
+
id="galeria-empresa"
|
|
133
|
+
bind:this={sectionEls["galeria-empresa"]}
|
|
134
|
+
data-section-id="galeria-empresa"
|
|
135
|
+
>
|
|
136
|
+
<ProfileGallery data={data.gallery} {isLoading} />
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import ImgPlaceholder from "../../../assets/placeholder-image.png";
|
|
2
|
+
import VideoPlaceholder from "../../../assets/lonely-404.mp4";
|
|
3
|
+
export const defaultCompanyProfileData = {
|
|
4
|
+
id: "cartaplast",
|
|
5
|
+
banner: {
|
|
6
|
+
coverImages: [
|
|
7
|
+
{
|
|
8
|
+
src: "https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?q=80&w=1200&auto=format&fit=crop",
|
|
9
|
+
alt: "Armazém de bobinas e logística Cartaplast",
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
src: "https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?q=80&w=1200&auto=format&fit=crop",
|
|
13
|
+
alt: "Linha de produção industrial de embalagens",
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
logo: "https://images.unsplash.com/photo-1560179707-f14e90ef3623?q=80&w=300&auto=format&fit=crop",
|
|
17
|
+
name: "Hotel empanados S.A",
|
|
18
|
+
countryLabel: "Angola",
|
|
19
|
+
countryFlag: "🇦🇴",
|
|
20
|
+
contactLabel: "Contactar fábrica",
|
|
21
|
+
stats: [
|
|
22
|
+
{ label: "Setor de atuação", value: "Papel e Embalagens" },
|
|
23
|
+
{ label: "Anos de Atuação", value: "8+ Anos" },
|
|
24
|
+
{ label: "Número de Funcionários", value: "51 - 100 Funcionários" },
|
|
25
|
+
{ label: "Localização", value: "Polo Industrial da Catumbela, Benguela" },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
about: {
|
|
29
|
+
image: "https://images.unsplash.com/photo-1504917599217-d4dc5ebe6122?q=80&w=1200&auto=format&fit=crop",
|
|
30
|
+
imageAlt: "Instalações industriais da fábrica Cartaplast",
|
|
31
|
+
title: "Sobre a CARTAPLAST",
|
|
32
|
+
paragraphs: [
|
|
33
|
+
"A Cartaplast é uma empresa de referência em Angola, especializada na fabricação de cartão canelado, caixas de papelão e soluções sustentáveis de embalagens industriais, localizada estrategicamente no Polo de Desenvolvimento Industrial da Catumbela (PDIC), na província de Benguela.",
|
|
34
|
+
"A nossa capacidade instalada e tecnologia de ponta proporcionam total flexibilidade na produção de múltiplos modelos e dimensões de caixas com impressão personalizada de alta precisão, agregando valor e identidade à marca de cada parceiro.",
|
|
35
|
+
"Com rigorosos padrões de controlo de qualidade e foco na sustentabilidade, atendemos com excelência os setores da Indústria Pesqueira, Agroalimentar, Avicultura, Bebidas, Farmacêutica, Distribuição e Comércio Geral em todo o país.",
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
gallery: {
|
|
39
|
+
title: "Galeria",
|
|
40
|
+
images: [
|
|
41
|
+
{
|
|
42
|
+
src: "https://images.unsplash.com/photo-1581091226825-a6a2a5aee158?q=80&w=1200&auto=format&fit=crop",
|
|
43
|
+
alt: "Linha de produção automatizada de caixas",
|
|
44
|
+
type: "image",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
src: VideoPlaceholder,
|
|
48
|
+
alt: "Vídeo institucional e processo de fabrico",
|
|
49
|
+
type: "video",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
src: "https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?q=80&w=1200&auto=format&fit=crop",
|
|
53
|
+
alt: "Armazém de matéria-prima e bobinas de papel",
|
|
54
|
+
type: "image",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
src: "https://images.unsplash.com/photo-1504917599217-d4dc5ebe6122?q=80&w=1200&auto=format&fit=crop",
|
|
58
|
+
alt: "Maquinaria de corte e vincagem",
|
|
59
|
+
type: "image",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
src: "https://images.unsplash.com/photo-1587293852726-70cdb56c2866?q=80&w=1200&auto=format&fit=crop",
|
|
63
|
+
alt: "Área de expedição e embalamento final",
|
|
64
|
+
type: "image",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
/**
|
|
3
|
+
* Secção "Sobre a Empresa": imagem ilustrativa e parágrafos descritivos.
|
|
4
|
+
* Quando `isLoading` é true, exibe Skeletons.
|
|
5
|
+
* @component
|
|
6
|
+
* @example
|
|
7
|
+
* ```svelte
|
|
8
|
+
* <ProfileAboutCompany data={data.about} />
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import Skeleton from "../../../ui/skeleton/skeleton.svelte";
|
|
15
|
+
import ImgPlaceholder from "../../../../assets/placeholder-image.png";
|
|
16
|
+
import type { ProfileAboutData } from "../types";
|
|
17
|
+
|
|
18
|
+
let {
|
|
19
|
+
data,
|
|
20
|
+
isLoading = false,
|
|
21
|
+
className,
|
|
22
|
+
}: {
|
|
23
|
+
data: ProfileAboutData;
|
|
24
|
+
isLoading?: boolean;
|
|
25
|
+
className?: string;
|
|
26
|
+
} = $props();
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<div class="bg-gray-50 dark:bg-background p-4 md:p-6 rounded-lg {className}">
|
|
30
|
+
<h2 class="mb-4 flex items-center gap-2 text-lg font-bold">
|
|
31
|
+
<svg
|
|
32
|
+
viewBox="0 0 24 24"
|
|
33
|
+
class="size-5 text-muted-foreground"
|
|
34
|
+
fill="none"
|
|
35
|
+
stroke="currentColor"
|
|
36
|
+
stroke-width="2"
|
|
37
|
+
stroke-linecap="round"
|
|
38
|
+
stroke-linejoin="round"
|
|
39
|
+
aria-hidden="true"
|
|
40
|
+
>
|
|
41
|
+
<path d="M3 21h18" />
|
|
42
|
+
<path d="M6 21V7l6-4 6 4v14" />
|
|
43
|
+
<path d="M10 21v-6h4v6" />
|
|
44
|
+
<path d="M10 11h.01M14 11h.01M10 15h.01M14 15h.01" />
|
|
45
|
+
</svg>
|
|
46
|
+
Sobre a Empresa
|
|
47
|
+
</h2>
|
|
48
|
+
|
|
49
|
+
{#if isLoading}
|
|
50
|
+
<div class="grid gap-6 md:grid-cols-2">
|
|
51
|
+
<Skeleton class="aspect-4/3 w-full rounded-lg" />
|
|
52
|
+
<div class="flex flex-col gap-3">
|
|
53
|
+
{#each Array.from({ length: 5 }) as _, i (i)}
|
|
54
|
+
<Skeleton class="h-4 w-full rounded-md" />
|
|
55
|
+
{/each}
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
{:else}
|
|
59
|
+
<div class="grid gap-6 md:grid-cols-2 md:items-start">
|
|
60
|
+
{#if data.image}
|
|
61
|
+
<div class="overflow-hidden rounded-lg border">
|
|
62
|
+
<img
|
|
63
|
+
src={data.image || ImgPlaceholder}
|
|
64
|
+
alt={data.imageAlt ?? data.title ?? "Sobre a empresa"}
|
|
65
|
+
class="aspect-4/3 w-full object-cover"
|
|
66
|
+
onerror={(e) =>
|
|
67
|
+
((e.target as HTMLImageElement).src = ImgPlaceholder)}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
{/if}
|
|
71
|
+
|
|
72
|
+
<div class="flex flex-col gap-4">
|
|
73
|
+
{#each data.paragraphs as paragraph, i (i)}
|
|
74
|
+
<p class="leading-7 text-foreground/80">{paragraph}</p>
|
|
75
|
+
{/each}
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
{/if}
|
|
79
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProfileAboutData } from "../types";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
data: ProfileAboutData;
|
|
4
|
+
isLoading?: boolean;
|
|
5
|
+
className?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const ProfileAboutCompany: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type ProfileAboutCompany = ReturnType<typeof ProfileAboutCompany>;
|
|
9
|
+
export default ProfileAboutCompany;
|