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.
Files changed (59) hide show
  1. package/.vscode/extensions.json +1 -1
  2. package/.vscode/settings.json +2 -3
  3. package/CHANGELOG.md +27 -0
  4. package/package.json +6 -6
  5. package/packages/api/lib/api.d.ts +8 -0
  6. package/packages/api/lib/api.js +24 -3
  7. package/packages/api/lib/api.js.map +1 -1
  8. package/packages/api/lib/types.d.ts +2 -0
  9. package/packages/api/package.json +6 -1
  10. package/packages/api/src/api.ts +31 -3
  11. package/packages/api/src/types.ts +2 -0
  12. package/packages/api/types.ts +2 -0
  13. package/packages/apps/correios/package.json +1 -1
  14. package/packages/apps/custom-shipping/package.json +1 -1
  15. package/packages/apps/discounts/package.json +1 -1
  16. package/packages/apps/frenet/package.json +1 -1
  17. package/packages/apps/tiny-erp/package.json +1 -1
  18. package/packages/cli/package.json +1 -1
  19. package/packages/config/package.json +1 -1
  20. package/packages/events/package.json +1 -1
  21. package/packages/firebase/lib/init.d.ts +1 -1
  22. package/packages/firebase/lib/init.js +1 -1
  23. package/packages/firebase/lib/init.js.map +1 -1
  24. package/packages/firebase/package.json +1 -1
  25. package/packages/firebase/src/init.ts +1 -1
  26. package/packages/modules/package.json +1 -1
  27. package/packages/passport/package.json +1 -1
  28. package/packages/ssr/package.json +1 -1
  29. package/packages/storefront/content/header.json +3 -1
  30. package/packages/storefront/dist/client/assets/_...2fc8f657.css +1 -0
  31. package/packages/storefront/dist/client/assets/{_...11681504.css → _...7af61807.css} +1 -1
  32. package/packages/storefront/dist/client/sw.js +1 -1
  33. package/packages/storefront/dist/client/{workbox-8b24c3ff.js → workbox-361aba39.js} +1 -1
  34. package/packages/storefront/dist/server/entry.mjs +605 -94
  35. package/packages/storefront/package.json +8 -7
  36. package/packages/storefront/src/env.d.ts +1 -1
  37. package/packages/storefront/src/lib/components/TheHeader.vue +15 -0
  38. package/packages/storefront/src/lib/components/TopBar.vue +141 -0
  39. package/packages/storefront/src/lib/helpers/image.ts +36 -0
  40. package/packages/storefront/src/lib/layouts/Base.astro +24 -16
  41. package/packages/storefront/src/lib/layouts/{meta/Head.astro → BaseHead.astro} +4 -3
  42. package/packages/storefront/src/lib/layouts/{meta/Json.astro → BaseStateJson.astro} +1 -1
  43. package/packages/storefront/src/lib/layouts/Pages.astro +2 -7
  44. package/packages/storefront/src/lib/layouts/PagesHeader.astro +92 -0
  45. package/packages/storefront/src/lib/ssr-context.ts +6 -4
  46. package/packages/storefront/src/pages/[...slug].astro +4 -0
  47. package/packages/storefront/src/types/cms-code.d.ts +5 -0
  48. package/packages/storefront/src/types/cms-contacts.d.ts +5 -0
  49. package/packages/storefront/src/types/cms-header.d.ts +5 -0
  50. package/packages/storefront/src/types/cms-settings.d.ts +5 -0
  51. package/packages/storefront/src/types/cms-social.d.ts +5 -0
  52. package/packages/storefront/tailwind.config.cjs +78 -0
  53. package/packages/storefront/uno.config.ts +55 -30
  54. package/packages/types/index.ts +1 -1
  55. package/packages/types/package.json +1 -1
  56. package/tsconfig.json +2 -1
  57. package/packages/storefront/dist/client/assets/_...65ca64e2.css +0 -1
  58. package/packages/storefront/src/html.d.ts +0 -23
  59. 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.83",
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.0",
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-attributify": "^0.45.21",
42
- "@unocss/preset-icons": "^0.45.21",
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.0",
49
- "unocss": "^0.45.21",
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"
@@ -1,3 +1,3 @@
1
- /// <reference types="astro/client" />
1
+ /// <reference types="@astrojs/image/client" />
2
2
  /// <reference types="vite-plugin-pwa/client" />
3
3
  /// <reference types="../client" />
@@ -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 MetaHead from './meta/Head.astro';
5
- import MetaJson from './meta/Json.astro';
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 typeof import('../../../content/code.json');
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(colorLabel) > 100 && Number(colorLabel) < 900) {
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
- <MetaHead pageContext={pageContext} title={title} />
60
- <MetaJson pageContext={pageContext} />
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: #6c757d;
94
- --gray-dark: #343a40;
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-dark);
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-50);
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-50);
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
- [data-theme=light] a {
119
- --color: var(--primary) !important;
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 { PageContext } from '../../ssr-context';
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 typeof import('../../../../content/social.json');
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="E-Com Plus Cloud Commerce">
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,5 +1,5 @@
1
1
  ---
2
- import type { PageContext } from '../../ssr-context';
2
+ import type { PageContext } from '../ssr-context';
3
3
  import ecomUtils from '@ecomplus/utils';
4
4
 
5
5
  export interface Props {
@@ -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
- <div class="i-shopping-cart" text="sky-400" />
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,5 @@
1
+ type CmsCode = typeof import('../../content/code.json');
2
+
3
+ export default CmsCode;
4
+
5
+ export type { CmsCode };
@@ -0,0 +1,5 @@
1
+ type CmsContacts = typeof import('../../content/contacts.json');
2
+
3
+ export default CmsContacts;
4
+
5
+ export type { CmsContacts };
@@ -0,0 +1,5 @@
1
+ type CmsHeader = typeof import('../../content/header.json');
2
+
3
+ export default CmsHeader;
4
+
5
+ export type { CmsHeader };
@@ -0,0 +1,5 @@
1
+ type CmsSettings = typeof import('../../content/settings.json');
2
+
3
+ export default CmsSettings;
4
+
5
+ export type { CmsSettings };
@@ -0,0 +1,5 @@
1
+ type CmsSocial = typeof import('../../content/social.json');
2
+
3
+ export default CmsSocial;
4
+
5
+ export type { CmsSocial };
@@ -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;