cloudcommerce 0.0.83 → 0.0.85
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/.vscode/extensions.json +1 -1
- package/.vscode/settings.json +2 -3
- package/CHANGELOG.md +27 -0
- package/package.json +6 -6
- package/packages/api/lib/api.d.ts +8 -0
- package/packages/api/lib/api.js +24 -3
- package/packages/api/lib/api.js.map +1 -1
- package/packages/api/lib/types.d.ts +2 -0
- package/packages/api/package.json +6 -1
- package/packages/api/src/api.ts +31 -3
- package/packages/api/src/types.ts +2 -0
- package/packages/api/types.ts +2 -0
- package/packages/apps/correios/package.json +1 -1
- package/packages/apps/custom-shipping/package.json +1 -1
- package/packages/apps/discounts/package.json +1 -1
- package/packages/apps/frenet/package.json +1 -1
- package/packages/apps/tiny-erp/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/config/package.json +1 -1
- package/packages/events/package.json +1 -1
- package/packages/firebase/lib/init.d.ts +1 -1
- package/packages/firebase/lib/init.js +1 -1
- package/packages/firebase/lib/init.js.map +1 -1
- package/packages/firebase/package.json +1 -1
- package/packages/firebase/src/init.ts +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/content/header.json +3 -1
- package/packages/storefront/dist/client/assets/_...2fc8f657.css +1 -0
- package/packages/storefront/dist/client/assets/{_...11681504.css → _...7af61807.css} +1 -1
- package/packages/storefront/dist/client/sw.js +1 -1
- package/packages/storefront/dist/client/{workbox-8b24c3ff.js → workbox-361aba39.js} +1 -1
- package/packages/storefront/dist/server/entry.mjs +605 -94
- package/packages/storefront/package.json +8 -7
- package/packages/storefront/src/env.d.ts +1 -1
- package/packages/storefront/src/lib/components/TheHeader.vue +15 -0
- package/packages/storefront/src/lib/components/TopBar.vue +141 -0
- package/packages/storefront/src/lib/helpers/image.ts +36 -0
- package/packages/storefront/src/lib/layouts/Base.astro +24 -16
- package/packages/storefront/src/lib/layouts/{meta/Head.astro → BaseHead.astro} +4 -3
- package/packages/storefront/src/lib/layouts/{meta/Json.astro → BaseStateJson.astro} +1 -1
- package/packages/storefront/src/lib/layouts/Pages.astro +2 -7
- package/packages/storefront/src/lib/layouts/PagesHeader.astro +92 -0
- package/packages/storefront/src/lib/ssr-context.ts +6 -4
- package/packages/storefront/src/pages/[...slug].astro +4 -0
- package/packages/storefront/src/types/cms-code.d.ts +5 -0
- package/packages/storefront/src/types/cms-contacts.d.ts +5 -0
- package/packages/storefront/src/types/cms-header.d.ts +5 -0
- package/packages/storefront/src/types/cms-settings.d.ts +5 -0
- package/packages/storefront/src/types/cms-social.d.ts +5 -0
- package/packages/storefront/tailwind.config.cjs +78 -0
- package/packages/storefront/uno.config.ts +55 -30
- package/packages/types/index.ts +1 -1
- package/packages/types/package.json +1 -1
- package/tsconfig.json +2 -1
- package/packages/storefront/dist/client/assets/_...65ca64e2.css +0 -1
- package/packages/storefront/src/html.d.ts +0 -23
- package/packages/storefront/tailwind.config.ts +0 -30
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudcommerce/storefront",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.85",
|
|
5
5
|
"description": "E-Com Plus Cloud Commerce storefront with Astro",
|
|
6
6
|
"main": "src/index.js",
|
|
7
7
|
"repository": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"prerelease": "sh scripts/prerelease.sh"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@astrojs/image": "^0.7.
|
|
28
|
+
"@astrojs/image": "^0.7.1",
|
|
29
29
|
"@astrojs/node": "^1.0.1",
|
|
30
30
|
"@astrojs/partytown": "^1.0.0",
|
|
31
31
|
"@astrojs/prefetch": "^0.0.7",
|
|
@@ -34,19 +34,20 @@
|
|
|
34
34
|
"@cloudcommerce/api": "workspace:*",
|
|
35
35
|
"@cloudcommerce/config": "workspace:*",
|
|
36
36
|
"@ecomplus/utils": "^1.4.1",
|
|
37
|
+
"@iconify-json/bxl": "^1.1.4",
|
|
37
38
|
"@iconify-json/heroicons": "^1.1.4",
|
|
38
39
|
"@iconify-json/logos": "^1.1.16",
|
|
39
40
|
"@nanostores/vue": "^0.6.0",
|
|
40
41
|
"@picocss/pico": "^1.5.5",
|
|
41
|
-
"@unocss/preset-
|
|
42
|
-
"
|
|
43
|
-
"astro": "^1.2.6",
|
|
42
|
+
"@unocss/preset-icons": "^0.45.22",
|
|
43
|
+
"astro": "^1.3.0",
|
|
44
44
|
"color": "^4.2.3",
|
|
45
45
|
"dotenv": "^16.0.2",
|
|
46
46
|
"firebase": "^9.10.0",
|
|
47
|
+
"image-size": "^1.0.2",
|
|
47
48
|
"nanostores": "^0.7.0",
|
|
48
|
-
"rollup": "^2.79.
|
|
49
|
-
"unocss": "^0.45.
|
|
49
|
+
"rollup": "^2.79.1",
|
|
50
|
+
"unocss": "^0.45.22",
|
|
50
51
|
"vite": "^3.1.3",
|
|
51
52
|
"vite-plugin-pwa": "^0.12.8",
|
|
52
53
|
"vue": "^3.2.39"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
export interface Props {
|
|
3
|
+
}
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<header class="header bg-surface bg-opacity-70 sticky py-1 sm:py-2">
|
|
8
|
+
<div class="container">
|
|
9
|
+
<div class="grid items-center">
|
|
10
|
+
<div class="i-bars-3-bottom-left md:hidden"></div>
|
|
11
|
+
<slot name="logo"></slot>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</header>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type CmsHeader from '../../types/cms-header';
|
|
3
|
+
import type CmsContacts from '../../types/cms-contacts';
|
|
4
|
+
|
|
5
|
+
export interface Props {
|
|
6
|
+
marketingStripe: CmsHeader['marketing_stripe'];
|
|
7
|
+
hasNavbar?: boolean;
|
|
8
|
+
pageLinks: CmsHeader['contacts_stripe']['pages'];
|
|
9
|
+
contacts: CmsContacts;
|
|
10
|
+
hasPhoneLinks?: boolean;
|
|
11
|
+
hasNetworkLinks?: boolean;
|
|
12
|
+
socialNetworks?: string[];
|
|
13
|
+
countdownClass?: string;
|
|
14
|
+
pageLinksClass?: string;
|
|
15
|
+
contactLinksClass?: string;
|
|
16
|
+
socialNetworksClass?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
withDefaults(defineProps<Props>(), {
|
|
20
|
+
hasNavbar: true,
|
|
21
|
+
hasPhoneLinks: true,
|
|
22
|
+
hasNetworksLinks: true,
|
|
23
|
+
socialNetworks() {
|
|
24
|
+
return ['facebook', 'twitter', 'youtube', 'pinterest', 'instagram', 'tiktok'];
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<template>
|
|
30
|
+
<div class="top-bar w-full bg-surface">
|
|
31
|
+
<slot
|
|
32
|
+
name="countdown"
|
|
33
|
+
v-bind="{ marketingStripe, countdownClass }"
|
|
34
|
+
>
|
|
35
|
+
<template v-if="marketingStripe && marketingStripe.text">
|
|
36
|
+
<component
|
|
37
|
+
:is="marketingStripe.link ? 'a' : 'div'"
|
|
38
|
+
class="top-bar__countdown block text-sm text-center p-1
|
|
39
|
+
whitespace-nowrap overflow-x-auto"
|
|
40
|
+
:class="[countdownClass, marketingStripe.link ? 'primary' : 'secondary']"
|
|
41
|
+
:href="marketingStripe.link"
|
|
42
|
+
>
|
|
43
|
+
{{ marketingStripe.text }}
|
|
44
|
+
</component>
|
|
45
|
+
</template>
|
|
46
|
+
</slot>
|
|
47
|
+
|
|
48
|
+
<div
|
|
49
|
+
v-if="hasNavbar"
|
|
50
|
+
class="top-bar__nav hidden md:block py-2"
|
|
51
|
+
>
|
|
52
|
+
<div class="container">
|
|
53
|
+
<div class="flex items-center lg:px-2 xl:px-4">
|
|
54
|
+
<div class="grow text-xs">
|
|
55
|
+
<slot
|
|
56
|
+
name="contacts-container"
|
|
57
|
+
v-bind="{ pageLinks, pageLinksClass }"
|
|
58
|
+
>
|
|
59
|
+
<nav
|
|
60
|
+
v-if="pageLinks"
|
|
61
|
+
class="top-bar__page-links inline-block mr-4 font-semibold"
|
|
62
|
+
:class="pageLinksClass"
|
|
63
|
+
>
|
|
64
|
+
<a
|
|
65
|
+
v-for="({ link, title }, i) in pageLinks"
|
|
66
|
+
class="mr-2 lg:mr-3"
|
|
67
|
+
:key="i"
|
|
68
|
+
:href="link"
|
|
69
|
+
>
|
|
70
|
+
{{ title }}
|
|
71
|
+
</a>
|
|
72
|
+
</nav>
|
|
73
|
+
</slot>
|
|
74
|
+
|
|
75
|
+
<slot
|
|
76
|
+
name="contact-links"
|
|
77
|
+
v-bind="{ contacts, hasPhoneLinks, contactLinksClass }"
|
|
78
|
+
>
|
|
79
|
+
<div
|
|
80
|
+
v-if="hasPhoneLinks"
|
|
81
|
+
class="top-bar__contact-links inline-block"
|
|
82
|
+
:class="contactLinksClass"
|
|
83
|
+
>
|
|
84
|
+
<a
|
|
85
|
+
v-if="contacts.whatsapp"
|
|
86
|
+
href="javascript:;"
|
|
87
|
+
target="_blank"
|
|
88
|
+
rel="noopener"
|
|
89
|
+
:data-whatsapp-tel="contacts.whatsapp.replace(/\D/g, '')"
|
|
90
|
+
class="mr-2"
|
|
91
|
+
>
|
|
92
|
+
<i class="i-whatsapp"></i>
|
|
93
|
+
{{ contacts.whatsapp }}
|
|
94
|
+
</a>
|
|
95
|
+
<a
|
|
96
|
+
v-if="contacts.phone"
|
|
97
|
+
:href="`tel:+${contacts.phone.replace(/\D/g, '')}`"
|
|
98
|
+
target="_blank"
|
|
99
|
+
rel="noopener"
|
|
100
|
+
class="mr-2"
|
|
101
|
+
>
|
|
102
|
+
<i class="i-phone"></i>
|
|
103
|
+
{{ contacts.phone }}
|
|
104
|
+
</a>
|
|
105
|
+
</div>
|
|
106
|
+
</slot>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<slot
|
|
110
|
+
name="social-networks"
|
|
111
|
+
v-bind="{ contacts, hasNetworkLinks, socialNetworksClass }"
|
|
112
|
+
>
|
|
113
|
+
<div
|
|
114
|
+
v-if="hasNetworkLinks"
|
|
115
|
+
class="top-bar__social-networks leading-none"
|
|
116
|
+
>
|
|
117
|
+
<template v-for="network in socialNetworks">
|
|
118
|
+
<template v-if="contacts[network]">
|
|
119
|
+
<a
|
|
120
|
+
:key="network"
|
|
121
|
+
:href="contacts[network]"
|
|
122
|
+
target="_blank"
|
|
123
|
+
rel="noopener"
|
|
124
|
+
class="ml-1"
|
|
125
|
+
>
|
|
126
|
+
<i v-if="network === 'facebook'" class="i-facebook"></i>
|
|
127
|
+
<i v-else-if="network === 'youtube'" class="i-youtube"></i>
|
|
128
|
+
<i v-else-if="network === 'twitter'" class="i-twitter"></i>
|
|
129
|
+
<i v-else-if="network === 'pinterest'" class="i-pinterest"></i>
|
|
130
|
+
<i v-else-if="network === 'instagram'" class="i-instagram"></i>
|
|
131
|
+
<i v-else-if="network === 'tiktok'" class="i-tiktok"></i>
|
|
132
|
+
</a>
|
|
133
|
+
</template>
|
|
134
|
+
</template>
|
|
135
|
+
</div>
|
|
136
|
+
</slot>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import imageSize from 'image-size';
|
|
2
|
+
// eslint-disable-next-line import/no-unresolved
|
|
3
|
+
import { getImage as _getImage } from '@astrojs/image';
|
|
4
|
+
|
|
5
|
+
const tryImageSize = (src: string) => {
|
|
6
|
+
let dimensions: { width?: number, height?: number } = {};
|
|
7
|
+
if (typeof src === 'string' && src.startsWith('/')) {
|
|
8
|
+
try {
|
|
9
|
+
dimensions = imageSize(`public${src}`);
|
|
10
|
+
} catch (e) {
|
|
11
|
+
dimensions = {};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return dimensions;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const getImage = (options: Parameters<typeof _getImage>[0]) => {
|
|
18
|
+
const { src } = options;
|
|
19
|
+
if (
|
|
20
|
+
typeof src === 'string'
|
|
21
|
+
&& !options.aspectRatio
|
|
22
|
+
&& (!options.width || !options.height)
|
|
23
|
+
) {
|
|
24
|
+
const { width, height } = tryImageSize(src);
|
|
25
|
+
return _getImage({
|
|
26
|
+
width,
|
|
27
|
+
...options,
|
|
28
|
+
aspectRatio: width && height ? width / height : 1,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return _getImage(options);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default getImage;
|
|
35
|
+
|
|
36
|
+
export { tryImageSize, getImage };
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
+
import type CmsCode from '../../types/cms-code';
|
|
2
3
|
import type { PageContext } from '../ssr-context';
|
|
3
4
|
import Color from 'color';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
5
|
+
import BaseHead from './BaseHead.astro';
|
|
6
|
+
import BaseStateJson from './BaseStateJson.astro';
|
|
6
7
|
import '@picocss/pico/css/pico.min.css';
|
|
7
8
|
|
|
8
9
|
export interface Props {
|
|
@@ -17,7 +18,7 @@ const {
|
|
|
17
18
|
secondaryColor,
|
|
18
19
|
cms,
|
|
19
20
|
} = pageContext;
|
|
20
|
-
const cmsCustomCode = cms('code') as
|
|
21
|
+
const cmsCustomCode = cms('code') as CmsCode;
|
|
21
22
|
|
|
22
23
|
const brandColors = {
|
|
23
24
|
primary: primaryColor,
|
|
@@ -44,7 +45,7 @@ Object.keys(brandColors).forEach((colorName) => {
|
|
|
44
45
|
const colorShift = colorVariants[colorVariant];
|
|
45
46
|
const colorLabel = `${colorName}-${colorVariant}`;
|
|
46
47
|
colorCSSVars[colorLabel] = color.darken(colorShift).hex();
|
|
47
|
-
if (Number(
|
|
48
|
+
if (Number(colorVariant) > 100 && Number(colorVariant) < 900) {
|
|
48
49
|
colorCSSVars[`${colorLabel}-yiq`] = color.isLight()
|
|
49
50
|
? 'var(--yiq-text-dark)' : 'var(--yiq-text-light)';
|
|
50
51
|
colorCSSVars[`${colorLabel}-rgb`] = `${color.red()}, ${color.green()}, ${color.blue()}`;
|
|
@@ -56,8 +57,8 @@ Object.keys(brandColors).forEach((colorName) => {
|
|
|
56
57
|
<!DOCTYPE html>
|
|
57
58
|
<html lang={lang.replace('_', '-')}>
|
|
58
59
|
<head>
|
|
59
|
-
<
|
|
60
|
-
<
|
|
60
|
+
<BaseHead pageContext={pageContext} title={title} />
|
|
61
|
+
<BaseStateJson pageContext={pageContext} />
|
|
61
62
|
<slot name="before-head-end">
|
|
62
63
|
{cmsCustomCode.css && <style>{cmsCustomCode.css}</style>}
|
|
63
64
|
{cmsCustomCode.html_head && <Fragment set:html={cmsCustomCode.html_head} />}
|
|
@@ -89,25 +90,35 @@ Object.keys(brandColors).forEach((colorName) => {
|
|
|
89
90
|
|
|
90
91
|
<style is:global define:vars={colorCSSVars}>
|
|
91
92
|
:root {
|
|
93
|
+
--content-max-width: 80rem;
|
|
92
94
|
--white: #fff;
|
|
93
|
-
--gray:
|
|
94
|
-
--gray-
|
|
95
|
+
--gray-50: theme('colors.gray.50');
|
|
96
|
+
--gray-200: theme('colors.gray.200');
|
|
97
|
+
--gray-700: theme('colors.gray.700');
|
|
98
|
+
--gray-800: theme('colors.gray.800');
|
|
99
|
+
--gray-900: theme('colors.gray.900');
|
|
100
|
+
--surface-color: var(--gray-50);
|
|
101
|
+
--surface-border-color: var(--gray-200);
|
|
95
102
|
--yiq-text-light: var(--white);
|
|
96
|
-
--yiq-text-dark: var(--gray-
|
|
103
|
+
--yiq-text-dark: var(--gray-900);
|
|
97
104
|
}
|
|
98
105
|
body,
|
|
99
106
|
body [data-theme=light],
|
|
100
107
|
body [data-theme=dark] {
|
|
101
108
|
--primary: var(--primary-500);
|
|
102
109
|
--primary-hover: var(--primary-700);
|
|
103
|
-
--primary-focus: var(--primary-
|
|
110
|
+
--primary-focus: rgba(var(--primary-200-rgb), 0.2);
|
|
104
111
|
--primary-inverse: var(--primary-500-yiq);
|
|
105
112
|
--secondary: var(--secondary-500);
|
|
106
113
|
--secondary-hover: var(--secondary-700);
|
|
107
|
-
--secondary-focus: var(--secondary-
|
|
114
|
+
--secondary-focus: rgba(var(--secondary-200-rgb), 0.2);
|
|
108
115
|
--secondary-inverse: var(--secondary-500-yiq);
|
|
109
116
|
}
|
|
110
117
|
@media only screen and (prefers-color-scheme: dark) {
|
|
118
|
+
:root:not([data-theme=light]) {
|
|
119
|
+
--surface-color: var(--gray-800);
|
|
120
|
+
--surface-border-color: var(--gray-700);
|
|
121
|
+
}
|
|
111
122
|
:root:not([data-theme=light]) a {
|
|
112
123
|
--color: var(--primary-200);
|
|
113
124
|
}
|
|
@@ -115,10 +126,7 @@ Object.keys(brandColors).forEach((colorName) => {
|
|
|
115
126
|
--color: var(--primary-400);
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
[data-theme=light] a:is([aria-current], :hover, :active, :focus) {
|
|
122
|
-
--color: var(--primary-hover) !important;
|
|
129
|
+
body {
|
|
130
|
+
overflow-x: hidden;
|
|
123
131
|
}
|
|
124
132
|
</style>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type
|
|
2
|
+
import type CmsSocial from '../../types/cms-social';
|
|
3
|
+
import type { PageContext } from '../ssr-context';
|
|
3
4
|
import ecomUtils from '@ecomplus/utils';
|
|
4
5
|
|
|
5
6
|
export interface Props {
|
|
@@ -22,7 +23,7 @@ const title = state.meta_title || state.name || state.title || Astro.props.title
|
|
|
22
23
|
const description = state.meta_description || state.short_description || settings.description;
|
|
23
24
|
|
|
24
25
|
const canonicalUrl = new URL(Astro.url.pathname, Astro.site || `https://${domain}`);
|
|
25
|
-
const cmsSocial = cms('social') as
|
|
26
|
+
const cmsSocial = cms('social') as CmsSocial;
|
|
26
27
|
const ogLocale = lang.length === 2 ? lang : lang.substring(0, 2) + lang.slice(3).toUpperCase();
|
|
27
28
|
let ogImage: string | undefined;
|
|
28
29
|
if (apiDoc) {
|
|
@@ -47,7 +48,7 @@ if (!ogImage) {
|
|
|
47
48
|
<title>{title}</title>
|
|
48
49
|
<meta name="description" content={description}>
|
|
49
50
|
<meta name="author" content={settings.name}>
|
|
50
|
-
<meta name="generator" content=
|
|
51
|
+
<meta name="generator" content={Astro.generator} />
|
|
51
52
|
<link rel="canonical" href={canonicalUrl} />
|
|
52
53
|
<link rel="apple-touch-icon" href={settings.icon} />
|
|
53
54
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { PageContext } from '../ssr-context';
|
|
3
3
|
import Base from './Base.astro';
|
|
4
|
+
import Header from './PagesHeader.astro';
|
|
4
5
|
|
|
5
6
|
export interface Props {
|
|
6
7
|
pageContext: PageContext;
|
|
@@ -15,13 +16,7 @@ const { pageContext, title } = Astro.props as Props;
|
|
|
15
16
|
<slot name="before-head-end" />
|
|
16
17
|
</Fragment>
|
|
17
18
|
<slot name="header">
|
|
18
|
-
<
|
|
19
|
-
<div class="i-google-pay w-32" />
|
|
20
|
-
<div class="i-logos:apple bg-primary" />
|
|
21
|
-
<div class="i-heroicons:user bg-primary-300" />
|
|
22
|
-
<div class="i-user bg-primary-700" />
|
|
23
|
-
<div class="i-user bg-secondary-hover" />
|
|
24
|
-
<div class="i-user bg-contrast" />
|
|
19
|
+
<Header pageContext={pageContext} />
|
|
25
20
|
</slot>
|
|
26
21
|
<slot />
|
|
27
22
|
<Fragment slot="before-body-end">
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Categories } from '@cloudcommerce/api/types';
|
|
3
|
+
import type CmsHeader from '../../types/cms-header';
|
|
4
|
+
import type CmsContacts from '../../types/cms-contacts';
|
|
5
|
+
import type { PageContext } from '../ssr-context';
|
|
6
|
+
import getImage from '../helpers/image';
|
|
7
|
+
import TopBar, { Props as TopBarProps } from '../components/TopBar.vue';
|
|
8
|
+
import TheHeader from '../components/TheHeader.vue';
|
|
9
|
+
|
|
10
|
+
export interface Props {
|
|
11
|
+
pageContext: PageContext;
|
|
12
|
+
topBarProps?: Partial<TopBarProps>;
|
|
13
|
+
logoTransform?: {
|
|
14
|
+
width?: number;
|
|
15
|
+
height?: number;
|
|
16
|
+
quality?: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
declare global {
|
|
21
|
+
var TopBarProps: TopBarProps;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
pageContext: {
|
|
26
|
+
apiState,
|
|
27
|
+
settings,
|
|
28
|
+
cms,
|
|
29
|
+
},
|
|
30
|
+
topBarProps,
|
|
31
|
+
logoTransform,
|
|
32
|
+
} = Astro.props as Props;
|
|
33
|
+
const header = cms('header') as CmsHeader;
|
|
34
|
+
const contacts = cms('contacts') as CmsContacts;
|
|
35
|
+
const customThemeName = settings.theme.custom || '';
|
|
36
|
+
|
|
37
|
+
let headerCategories: Array<{ slug: string, name: string }> = [];
|
|
38
|
+
let isCategoriesNavFull: boolean | undefined;
|
|
39
|
+
if (header.categories_list) {
|
|
40
|
+
if (header.categories_list.featured.length) {
|
|
41
|
+
// Selected categories/collections/brands
|
|
42
|
+
headerCategories = header.categories_list.featured.map((pathAndName) => {
|
|
43
|
+
const [path, name] = pathAndName.split('?');
|
|
44
|
+
return { slug: path.slice(1), name };
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (header.categories_list.random) {
|
|
48
|
+
const mainCategories: Categories[] | undefined = apiState
|
|
49
|
+
.categories?.filter(({ parent }) => (!parent || !parent.slug));
|
|
50
|
+
if (mainCategories) {
|
|
51
|
+
for (let i = 0; i < header.categories_list.random && i < mainCategories.length; i++) {
|
|
52
|
+
if (!headerCategories.find(({ slug }) => mainCategories[i].slug === slug)) {
|
|
53
|
+
headerCategories.push({
|
|
54
|
+
slug: mainCategories[i].slug,
|
|
55
|
+
name: mainCategories[i].name,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
isCategoriesNavFull = header.categories_list.full_width;
|
|
62
|
+
}
|
|
63
|
+
const hasMegamenu: boolean | undefined = header.desktop_megamenu;
|
|
64
|
+
const isAlphabeticalOrderSubmenu: boolean | undefined = header.alphabetical_order_submenu;
|
|
65
|
+
const isFullWidthSubmenu: boolean | undefined = header.full_width_submenu;
|
|
66
|
+
|
|
67
|
+
globalThis.TopBarProps = {
|
|
68
|
+
marketingStripe: header.marketing_stripe,
|
|
69
|
+
pageLinks: header.contacts_stripe.pages,
|
|
70
|
+
hasPhoneLinks: header.contacts_stripe.phone_wpp,
|
|
71
|
+
hasNetworkLinks: header.contacts_stripe.socials,
|
|
72
|
+
contacts,
|
|
73
|
+
...Astro.props.topBarProps,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const logoWebpAttrs = await getImage({
|
|
77
|
+
src: settings.logo,
|
|
78
|
+
width: 150,
|
|
79
|
+
format: 'webp',
|
|
80
|
+
quality: 100,
|
|
81
|
+
...logoTransform,
|
|
82
|
+
});
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
<slot name="top-bar">
|
|
86
|
+
<TopBar {...globalThis.TopBarProps} />
|
|
87
|
+
</slot>
|
|
88
|
+
<slot name="header">
|
|
89
|
+
<TheHeader>
|
|
90
|
+
<img slot="logo" {...logoWebpAttrs} alt={`${settings.name} (logo)`} />
|
|
91
|
+
</TheHeader>
|
|
92
|
+
</slot>
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import type { AstroGlobal } from 'astro';
|
|
2
2
|
import type { BaseConfig } from '@cloudcommerce/config';
|
|
3
|
+
import type CmsSettings from '../types/cms-settings';
|
|
3
4
|
import api, { ApiError, ApiEndpoint } from '@cloudcommerce/api';
|
|
4
5
|
import _getConfig from '../../storefront.config.mjs';
|
|
5
|
-
import settings from '../../content/settings.json';
|
|
6
|
-
|
|
7
|
-
type CmsSettings = typeof settings;
|
|
8
6
|
|
|
9
7
|
type StorefrontConfig = {
|
|
10
8
|
storeId: BaseConfig['storeId'],
|
|
@@ -24,6 +22,10 @@ type StorefrontConfig = {
|
|
|
24
22
|
|
|
25
23
|
const getConfig: () => StorefrontConfig = _getConfig;
|
|
26
24
|
|
|
25
|
+
declare global {
|
|
26
|
+
// eslint-disable-next-line
|
|
27
|
+
var api_prefetch_endpoints: ApiEndpoint[];
|
|
28
|
+
}
|
|
27
29
|
if (!globalThis.api_prefetch_endpoints) {
|
|
28
30
|
globalThis.api_prefetch_endpoints = ['categories'];
|
|
29
31
|
}
|
|
@@ -76,7 +78,7 @@ const loadPageContext = async (Astro: AstroGlobal, {
|
|
|
76
78
|
apiState[`${apiResource}/${apiDoc._id}`] = apiDoc;
|
|
77
79
|
}
|
|
78
80
|
prefetchResponses.forEach(({ config: { endpoint }, data }) => {
|
|
79
|
-
apiState[endpoint] = data;
|
|
81
|
+
apiState[endpoint] = data.result || data;
|
|
80
82
|
});
|
|
81
83
|
} catch (err: any) {
|
|
82
84
|
const error: ApiError = err;
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
import ViewWildcard from '../lib/views/[...slug].astro';
|
|
3
3
|
import loadPageContext, { PageContext } from '../lib/ssr-context';
|
|
4
4
|
|
|
5
|
+
if (String(Astro.params.slug).endsWith('.css.map')) {
|
|
6
|
+
return new Response(null, { status: 404 });
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
let pageContext: PageContext;
|
|
6
10
|
let loadError: any;
|
|
7
11
|
try {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const genTailwindConfig = ({
|
|
2
|
+
colorVariants = [
|
|
3
|
+
'50',
|
|
4
|
+
...[...Array(9).keys()].map((i) => String((i + 1) * 100)),
|
|
5
|
+
],
|
|
6
|
+
} = {}) => ({
|
|
7
|
+
theme: {
|
|
8
|
+
extend: {
|
|
9
|
+
colors: {
|
|
10
|
+
// Color vars from Base.astro styles
|
|
11
|
+
...['primary', 'secondary', 'contrast'].reduce((colors, color) => {
|
|
12
|
+
const colorVariations = ['hover', 'focus', 'inverse'];
|
|
13
|
+
if (color !== 'contrast') {
|
|
14
|
+
colorVariations.push(...colorVariants);
|
|
15
|
+
}
|
|
16
|
+
colors[color] = colorVariations.reduce((colorPalette, variant) => {
|
|
17
|
+
colorPalette[variant] = `var(--${color}-${variant})`;
|
|
18
|
+
return colorPalette;
|
|
19
|
+
}, {
|
|
20
|
+
DEFAULT: `var(--${color})`,
|
|
21
|
+
});
|
|
22
|
+
return colors;
|
|
23
|
+
}, {}),
|
|
24
|
+
...['surface', 'muted'].reduce((colors, color) => ({
|
|
25
|
+
[color]: {
|
|
26
|
+
DEFAULT: `var(--${color}-color)`,
|
|
27
|
+
border: `var(--${color}-border-color)`,
|
|
28
|
+
},
|
|
29
|
+
...colors,
|
|
30
|
+
}), {}),
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
plugins: [
|
|
35
|
+
({ addUtilities }) => {
|
|
36
|
+
addUtilities({
|
|
37
|
+
// https://picocss.com/docs/containers.html
|
|
38
|
+
'.container-fluid': {
|
|
39
|
+
'max-width': 'var(--content-max-width)',
|
|
40
|
+
},
|
|
41
|
+
// https://picocss.com/docs/buttons.html
|
|
42
|
+
...['primary', 'secondary', 'contrast'].reduce((utilities, color) => ({
|
|
43
|
+
...utilities,
|
|
44
|
+
[`.${color}`]: {
|
|
45
|
+
'--background-color': `var(--${color})`,
|
|
46
|
+
'background-color': 'var(--background-color)',
|
|
47
|
+
color: `var(--${color}-inverse)`,
|
|
48
|
+
},
|
|
49
|
+
}), {}),
|
|
50
|
+
...['primary', 'secondary'].reduce((utilities, color) => {
|
|
51
|
+
colorVariants.forEach((variant) => {
|
|
52
|
+
const colorLabel = `${color}-${variant}`;
|
|
53
|
+
let textColor;
|
|
54
|
+
if (Number(variant) <= 100) {
|
|
55
|
+
textColor = 'var(--yiq-text-dark)';
|
|
56
|
+
} else if (Number(variant) >= 900) {
|
|
57
|
+
textColor = 'var(--yiq-text-light)';
|
|
58
|
+
} else {
|
|
59
|
+
textColor = `var(--${colorLabel}-yiq)`;
|
|
60
|
+
}
|
|
61
|
+
utilities[`.${colorLabel}`] = {
|
|
62
|
+
'background-color': `var(--${colorLabel})`,
|
|
63
|
+
color: textColor,
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
return utilities;
|
|
67
|
+
}, {}),
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const tailwindConfig = genTailwindConfig();
|
|
74
|
+
|
|
75
|
+
module.exports = { ...tailwindConfig, genTailwindConfig };
|
|
76
|
+
|
|
77
|
+
exports.genTailwindConfig = genTailwindConfig;
|
|
78
|
+
exports.tailwindConfig = tailwindConfig;
|