spoko-design-system 0.3.2 → 0.3.8

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/README.md CHANGED
@@ -66,7 +66,7 @@ export const SIDEBAR = [
66
66
  { text: "Introduction", link: "/core/introduction" },
67
67
  ...,
68
68
  { text: "Components", header: true },
69
- { text: "Buttons", link: "/components/jumbatron" },
69
+ { text: "Buttons", link: "/components/jumbotron" },
70
70
  ...,
71
71
  { text: "New section", header: true },
72
72
  { text: "New component", link: "/new-section/new-component.md" },
@@ -81,7 +81,7 @@ You're free to organize the pages however you want.
81
81
 
82
82
  ### Customizing Core section (colors, typography, shadows...)
83
83
 
84
- If you want to customize the default colors, typography or shadows you can find the configuration file at `src/config/design.config.ts`. I think I have prepared enough shades of blue ;-)
84
+ If you want to customize the default colors, typography or shadows you can find the configuration file at uno.config.ts`. I think I have prepared enough shades of blue ;-)
85
85
 
86
86
  Feel free to add new pages to the Core section
87
87
 
package/astro.config.mjs CHANGED
@@ -10,6 +10,9 @@ import pagefind from "astro-pagefind";
10
10
  import AstroPWA from '@vite-pwa/astro';
11
11
  import metaTags from "astro-meta-tags";
12
12
  import playformInline from "@playform/inline";
13
+ import { createSdsConfig } from './uno-config';
14
+
15
+ const unoConfig = createSdsConfig();
13
16
 
14
17
  // https://astro.build/config
15
18
  export default defineConfig({
@@ -72,8 +75,10 @@ export default defineConfig({
72
75
  experimental: {
73
76
  directoryAndTrailingSlashHandler: true
74
77
  }
75
- }), UnoCSS({
76
- injectReset: true
78
+ }),
79
+ UnoCSS({
80
+ injectReset: true,
81
+ ...unoConfig
77
82
  }),
78
83
  icon(iconConfig),
79
84
  metaTags(),
package/index.ts CHANGED
@@ -8,7 +8,7 @@ export { default as FuckRussia } from './src/components/FuckRussia.vue';
8
8
  export { default as FlagPL } from './src/components/flags/FlagPL.vue';
9
9
  export { default as Badges } from './src/components/Badges.vue';
10
10
  export { default as SlimBanner } from './src/components/SlimBanner.vue';
11
- export { default as Jumbatron } from './src/components/Jumbatron.vue';
11
+ export { default as Jumbotron } from './src/components/Jumbotron.astro';
12
12
  export { default as Button } from './src/components/Button.vue';
13
13
  export { default as Breadcrumbs } from './src/components/Breadcrumbs.vue';
14
14
  export { default as ProductDetailsList } from './src/components/ProductDetailsList.vue';
package/package.json CHANGED
@@ -1,119 +1,119 @@
1
- {
2
- "name": "spoko-design-system",
3
- "version": "0.3.02",
4
- "private": false,
5
- "main": "./index.ts",
6
- "module": "./index.ts",
7
- "types": "./index.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./index.ts",
11
- "require": "./index.ts"
12
- },
13
- "./styles/*": "./src/styles/*",
14
- "./icons": "./icon.config.ts",
15
- "./icon-collections": "./icon.collections.ts",
16
- "./uno-config": "./uno-config/index.ts"
17
- },
18
- "scripts": {
19
- "dev": "astro dev",
20
- "start": "astro dev",
21
- "build": "astro build",
22
- "preview": "astro preview"
23
- },
24
- "repository": {
25
- "type": "git",
26
- "url": "https://github.com/polo-blue/sds"
27
- },
28
- "author": {
29
- "name": "spokospace",
30
- "email": "szymon@spoko.space",
31
- "url": "https://spoko.space"
32
- },
33
- "homepage": "https://sds.spoko.space/",
34
- "license": "MIT",
35
- "keywords": [
36
- "astro-starter",
37
- "seo",
38
- "astro",
39
- "sds design system",
40
- "spoko design system"
41
- ],
42
- "dependencies": {
43
- "@algolia/client-search": "^5.20.2",
44
- "@astrojs/mdx": "^4.0.8",
45
- "@astrojs/node": "^9.0.2",
46
- "@astrojs/sitemap": "^3.2.1",
47
- "@astrojs/ts-plugin": "^1.10.4",
48
- "@astrojs/vue": "^5.0.6",
49
- "@docsearch/css": "^3.8.3",
50
- "@iconify-json/ant-design": "^1.2.5",
51
- "@iconify-json/bi": "^1.2.2",
52
- "@iconify-json/bx": "^1.2.2",
53
- "@iconify-json/carbon": "^1.2.6",
54
- "@iconify-json/circle-flags": "^1.2.6",
55
- "@iconify-json/ei": "^1.2.2",
56
- "@iconify-json/el": "^1.2.1",
57
- "@iconify-json/eos-icons": "^1.2.2",
58
- "@iconify-json/et": "^1.2.1",
59
- "@iconify-json/flowbite": "^1.2.4",
60
- "@iconify-json/fluent": "^1.2.13",
61
- "@iconify-json/fluent-emoji": "1.2.3",
62
- "@iconify-json/ic": "^1.2.2",
63
- "@iconify-json/icon-park-outline": "^1.2.2",
64
- "@iconify-json/la": "^1.2.1",
65
- "@iconify-json/material-symbols-light": "^1.2.14",
66
- "@iconify-json/mdi": "^1.2.3",
67
- "@iconify-json/noto-v1": "^1.2.1",
68
- "@iconify-json/octicon": "^1.2.4",
69
- "@iconify-json/ph": "^1.2.2",
70
- "@iconify-json/simple-icons": "^1.2.24",
71
- "@iconify-json/system-uicons": "^1.2.2",
72
- "@iconify-json/uil": "^1.2.3",
73
- "@iconify/json": "^2.2.305",
74
- "@iconify/vue": "^4.3.0",
75
- "@playform/compress": "^0.1.7",
76
- "@playform/inline": "^0.1.1",
77
- "@types/node": "^22.13.1",
78
- "@unocss/astro": "^65.4.3",
79
- "@unocss/preset-attributify": "^65.4.3",
80
- "@unocss/preset-typography": "^65.4.3",
81
- "@unocss/preset-uno": "^65.4.3",
82
- "@unocss/preset-web-fonts": "^65.4.3",
83
- "@unocss/preset-wind": "^65.4.3",
84
- "@unocss/reset": "^65.4.3",
85
- "@vite-pwa/astro": "^0.5.0",
86
- "@vueuse/core": "^12.5.0",
87
- "astro-i18next": "1.0.0-beta.21",
88
- "astro-icon": "^1.1.5",
89
- "astro-meta-tags": "^0.3.1",
90
- "astro-navbar": "^2.3.9",
91
- "astro-pagefind": "^1.8.0",
92
- "astro-remote": "^0.3.3",
93
- "dotenv": "^16.4.7",
94
- "i18next": "^24.2.2",
95
- "i18next-browser-languagedetector": "^8.0.2",
96
- "i18next-fs-backend": "^2.6.0",
97
- "i18next-http-backend": "^3.0.2",
98
- "i18next-vue": "^5.0.0",
99
- "swiper": "^11.2.2",
100
- "unocss": "^65.4.3",
101
- "vite": "^6.1.0",
102
- "vue": "^3.5.13"
103
- },
104
- "devDependencies": {
105
- "@unocss/transformer-variant-group": "^65.4.3",
106
- "@vitejs/plugin-vue": "^5.2.1",
107
- "@vue/compiler-sfc": "^3.5.13",
108
- "astro": "^5.2.5",
109
- "unocss": "^0.65.0"
110
- },
111
- "packageManager": "pnpm@9.15.3",
112
- "pnpm": {
113
- "default": "8.15.2",
114
- "overrides": {
115
- "file-type@>=17.0.0 <17.1.3": ">=17.1.3",
116
- "sharp@<0.30.5": ">=0.30.5"
117
- }
118
- }
119
- }
1
+ {
2
+ "name": "spoko-design-system",
3
+ "version": "0.3.08",
4
+ "private": false,
5
+ "main": "./index.ts",
6
+ "module": "./index.ts",
7
+ "types": "./index.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./index.ts",
11
+ "require": "./index.ts"
12
+ },
13
+ "./styles/*": "./src/styles/*",
14
+ "./icons": "./icon.config.ts",
15
+ "./icon-collections": "./icon.collections.ts",
16
+ "./uno-config": "./uno-config/index.ts"
17
+ },
18
+ "scripts": {
19
+ "dev": "astro dev",
20
+ "start": "astro dev",
21
+ "build": "astro build",
22
+ "preview": "astro preview"
23
+ },
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "https://github.com/polo-blue/sds"
27
+ },
28
+ "author": {
29
+ "name": "spokospace",
30
+ "email": "szymon@spoko.space",
31
+ "url": "https://spoko.space"
32
+ },
33
+ "homepage": "https://sds.spoko.space/",
34
+ "license": "MIT",
35
+ "keywords": [
36
+ "astro-starter",
37
+ "seo",
38
+ "astro",
39
+ "sds design system",
40
+ "spoko design system"
41
+ ],
42
+ "dependencies": {
43
+ "@algolia/client-search": "^5.20.2",
44
+ "@astrojs/mdx": "^4.0.8",
45
+ "@astrojs/node": "^9.1.0",
46
+ "@astrojs/sitemap": "^3.2.1",
47
+ "@astrojs/ts-plugin": "^1.10.4",
48
+ "@astrojs/vue": "^5.0.6",
49
+ "@docsearch/css": "^3.8.3",
50
+ "@iconify-json/ant-design": "^1.2.5",
51
+ "@iconify-json/bi": "^1.2.2",
52
+ "@iconify-json/bx": "^1.2.2",
53
+ "@iconify-json/carbon": "^1.2.7",
54
+ "@iconify-json/circle-flags": "^1.2.6",
55
+ "@iconify-json/ei": "^1.2.2",
56
+ "@iconify-json/el": "^1.2.1",
57
+ "@iconify-json/eos-icons": "^1.2.2",
58
+ "@iconify-json/et": "^1.2.1",
59
+ "@iconify-json/flowbite": "^1.2.4",
60
+ "@iconify-json/fluent": "^1.2.13",
61
+ "@iconify-json/fluent-emoji": "1.2.3",
62
+ "@iconify-json/ic": "^1.2.2",
63
+ "@iconify-json/icon-park-outline": "^1.2.2",
64
+ "@iconify-json/la": "^1.2.1",
65
+ "@iconify-json/material-symbols-light": "^1.2.14",
66
+ "@iconify-json/mdi": "^1.2.3",
67
+ "@iconify-json/noto-v1": "^1.2.1",
68
+ "@iconify-json/octicon": "^1.2.4",
69
+ "@iconify-json/ph": "^1.2.2",
70
+ "@iconify-json/simple-icons": "^1.2.24",
71
+ "@iconify-json/system-uicons": "^1.2.2",
72
+ "@iconify-json/uil": "^1.2.3",
73
+ "@iconify/json": "^2.2.306",
74
+ "@iconify/vue": "^4.3.0",
75
+ "@playform/compress": "^0.1.7",
76
+ "@playform/inline": "^0.1.1",
77
+ "@types/node": "^22.13.3",
78
+ "@unocss/astro": "^65.4.3",
79
+ "@unocss/preset-attributify": "^65.4.3",
80
+ "@unocss/preset-typography": "^65.4.3",
81
+ "@unocss/preset-uno": "^65.4.3",
82
+ "@unocss/preset-web-fonts": "^65.4.3",
83
+ "@unocss/preset-wind": "^65.4.3",
84
+ "@unocss/reset": "^65.4.3",
85
+ "@vite-pwa/astro": "^0.5.0",
86
+ "@vueuse/core": "^12.5.0",
87
+ "astro-i18next": "1.0.0-beta.21",
88
+ "astro-icon": "^1.1.5",
89
+ "astro-meta-tags": "^0.3.1",
90
+ "astro-navbar": "^2.3.9",
91
+ "astro-pagefind": "^1.8.0",
92
+ "astro-remote": "^0.3.3",
93
+ "dotenv": "^16.4.7",
94
+ "i18next": "^24.2.2",
95
+ "i18next-browser-languagedetector": "^8.0.2",
96
+ "i18next-fs-backend": "^2.6.0",
97
+ "i18next-http-backend": "^3.0.2",
98
+ "i18next-vue": "^5.1.0",
99
+ "swiper": "^11.2.3",
100
+ "unocss": "^65.4.3",
101
+ "vite": "^6.1.0",
102
+ "vue": "^3.5.13"
103
+ },
104
+ "devDependencies": {
105
+ "@unocss/transformer-variant-group": "^65.4.3",
106
+ "@vitejs/plugin-vue": "^5.2.1",
107
+ "@vue/compiler-sfc": "^3.5.13",
108
+ "astro": "^5.3.0",
109
+ "unocss": "^0.65.0"
110
+ },
111
+ "packageManager": "pnpm@9.15.3",
112
+ "pnpm": {
113
+ "default": "8.15.2",
114
+ "overrides": {
115
+ "file-type@>=17.0.0 <17.1.3": ">=17.1.3",
116
+ "sharp@<0.30.5": ">=0.30.5"
117
+ }
118
+ }
119
+ }
@@ -8,23 +8,22 @@ const { category, subcategory, subtitle, subsubtitle, titleSmall, locale, showVi
8
8
 
9
9
  // Compute base URL for localization
10
10
  const baseURL = locale === 'en' ? '' : `/${locale}`;
11
-
11
+
12
12
  ---
13
13
 
14
14
  <div
15
- ref="el"
16
15
  class="flex flex-nowrap items-center pr-3 sm:pb-3 sm:pt-4 md:pl-4 relative z-10-off bg-neutral-lightest md:bg-white"
17
16
  transition:name="category-details"
18
17
  transition:animate="fade"
19
18
  >
20
- <CategorySidebarToggler onclick="toggleSidebar()" client:load>
21
- <!-- First icon - visible only on desktop when sidebar is expanded -->
19
+ <CategorySidebarToggler onclick="toggleSidebar()">
20
+ <!-- Desktop expanded - initially visible -->
22
21
  <Icon
23
22
  name="ant-design:menu-fold-outlined"
24
- class="toggler-btn hidden md:[&:not(.hidden)]:block"
23
+ class="toggler-btn md:[&:not(.hidden)]:block"
25
24
  aria-hidden="true"
26
25
  />
27
- <!-- Second icon - visible only on desktop when sidebar is collapsed -->
26
+ <!-- Desktop collapsed - initially hidden -->
28
27
  <Icon
29
28
  name="ant-design:menu-unfold-outlined"
30
29
  class="toggler-btn hidden md:[&:not(.hidden)]:block"
@@ -67,70 +66,61 @@ const baseURL = locale === 'en' ? '' : `/${locale}`;
67
66
  ) : (
68
67
  <h1 class="text-lg py-2.5 sm:py-0 whitespace-nowrap">
69
68
  {category.name}
70
- {titleSmall && <small>{titleSmall}</small>}
69
+ {titleSmall && (<small>{titleSmall}</small>)}
71
70
  <span class="sr-only"> {t('catalog.extra-short')}</span>
72
71
  </h1>
73
72
  )}
74
73
  </div>
75
74
 
76
- <CategoryViewToggler {...viewerLabels} showViewToggler={showViewToggler} class="hidden lg:flex items-center gap-2 ml-auto" />
75
+ { showViewToggler && ( <CategoryViewToggler {...viewerLabels} class="hidden lg:flex items-center gap-2 ml-auto" /> ) }
76
+
77
77
  </div>
78
78
 
79
79
  <script is:inline>
80
+ function initializeSidebar() {
81
+ const sidebar = document.getElementById('sidebar');
82
+ const savedState = localStorage.getItem('sidebarState') || 'open';
83
+
84
+ if (sidebar) {
85
+ sidebar.classList.toggle('collapsed', savedState === 'closed');
86
+
87
+ const togglers = document.querySelectorAll('.toggler-btn');
88
+ if (togglers.length >= 2) {
89
+ const isCollapsed = savedState === 'closed';
90
+ togglers[0].classList.toggle('hidden', isCollapsed);
91
+ togglers[1].classList.toggle('hidden', !isCollapsed);
92
+ }
93
+ }
94
+ }
95
+
80
96
  function toggleSidebar() {
81
97
  const sidebar = document.getElementById('sidebar');
82
98
  const togglers = document.querySelectorAll('.toggler-btn');
83
99
  const isMobile = window.matchMedia("(max-width: 768px)").matches;
84
-
100
+
85
101
  if (sidebar) {
86
102
  if (isMobile) {
87
- // On mobile just toggle classes without localStorage
88
- document.body.classList.toggle('overflow-hidden');
89
- sidebar.classList.toggle('show');
103
+ const isShown = sidebar.classList.toggle('show');
104
+ document.body.classList.toggle('overflow-hidden', isShown);
90
105
  } else {
91
- // On desktop save the state
106
+ const isCollapsed = sidebar.classList.toggle('collapsed');
92
107
  document.body.classList.remove('overflow-hidden');
93
- sidebar.classList.toggle('collapsed');
94
- localStorage.setItem('sidebarState', sidebar.classList.contains('collapsed') ? 'closed' : 'open');
108
+ localStorage.setItem('sidebarState', isCollapsed ? 'closed' : 'open');
95
109
 
96
- // Toggle visibility of buttons on desktop
97
- togglers.forEach(btn => btn.classList.toggle('hidden'));
98
- }
99
- }
100
- }
101
-
102
- function handlePageLoad() {
103
- const sidebar = document.getElementById('sidebar');
104
- const togglers = document.querySelectorAll('.toggler-btn');
105
- const isMobile = window.matchMedia("(max-width: 768px)").matches;
106
-
107
- if (sidebar && !isMobile) {
108
- const savedState = localStorage.getItem('sidebarState');
109
-
110
- if (savedState === 'open') {
111
- sidebar.classList.remove('collapsed');
112
- // Show correct button on desktop
113
- if (togglers.length >= 2) {
114
- togglers[0].classList.remove('hidden'); // menu-fold
115
- togglers[1].classList.add('hidden'); // menu-unfold
116
- }
117
- } else if (savedState === 'closed') {
118
- sidebar.classList.add('collapsed');
119
- // Show correct button on desktop
120
110
  if (togglers.length >= 2) {
121
- togglers[0].classList.add('hidden'); // menu-fold
122
- togglers[1].classList.remove('hidden'); // menu-unfold
111
+ togglers[0].classList.toggle('hidden', isCollapsed);
112
+ togglers[1].classList.toggle('hidden', !isCollapsed);
123
113
  }
124
114
  }
125
115
  }
126
116
  }
127
-
128
- // Remove previous listener if exists
129
- // document.removeEventListener('astro:page-load', handlePageLoad);
130
- // Add new listener
131
- // document.addEventListener('astro:page-load', handlePageLoad);
132
- document.addEventListener('astro:page-load', handlePageLoad, { once: true });
133
117
 
134
- // Initial call to set up the initial state
135
- handlePageLoad();
136
- </script>
118
+ document.addEventListener('DOMContentLoaded', initializeSidebar);
119
+ document.addEventListener('astro:page-load', initializeSidebar, { once: true });
120
+ </script>
121
+
122
+ <style>
123
+ .toggler-btn {
124
+ @apply md:-mt-0.5;
125
+ }
126
+ </style>
@@ -1,7 +1,7 @@
1
1
 
2
2
  <template>
3
3
  <button
4
- class="category-toggler"
4
+ class="category-toggler md:w-8"
5
5
  type="button"
6
6
  aria-label="toggle menu"
7
7
  >
@@ -7,7 +7,6 @@ interface Props {
7
7
  gridText: string; // "Grid"
8
8
  listAriaLabel: string; // "List view"
9
9
  gridAriaLabel: string; // "Grid view"
10
- showViewToggler: boolean;
11
10
  class?: string;
12
11
  }
13
12
 
@@ -17,13 +16,10 @@ const {
17
16
  gridText,
18
17
  listAriaLabel,
19
18
  gridAriaLabel,
20
- showViewToggler,
21
19
  class: className
22
20
  } = Astro.props;
23
21
  ---
24
22
 
25
- {
26
- showViewToggler &&
27
23
  <div class:list={[ className ]}>
28
24
  <span class="text-slate-default text-sm">{showText}</span>
29
25
  <div class="flex border rounded">
@@ -45,9 +41,9 @@ const {
45
41
  </button>
46
42
  </div>
47
43
  </div>
48
- }
49
44
 
50
- <script define:vars={{ showViewToggler }}>
45
+
46
+ <script >
51
47
  function handleViewToggle(e) {
52
48
  const button = e.currentTarget;
53
49
  if (!(button instanceof HTMLElement)) return;
@@ -72,7 +68,6 @@ const {
72
68
  }
73
69
 
74
70
  document.addEventListener('astro:page-load', () => {
75
- if (!showViewToggler) return;
76
71
 
77
72
  updateUI(localStorage.getItem('categoryView') || 'list');
78
73
  document.querySelectorAll('.view-toggle')
@@ -9,7 +9,7 @@ defineProps<{
9
9
  <component
10
10
  :is="active ? 'div' : 'a'"
11
11
  :class="[
12
- 'w-full text-base font-medium py-2 pl-6 pr-2 hover:(bg-gray-50 sm:bg-inherit)',
12
+ 'w-full block text-base font-medium py-2 pl-6 pr-2 hover:(bg-gray-50 sm:bg-inherit)',
13
13
  'sm:(w-auto text-sm pr-3) md:(py-0.5 pr-4)',
14
14
  active ? 's-active' : 'text-gray-300'
15
15
  ]"
@@ -0,0 +1,153 @@
1
+ ---
2
+ import type { Author, Category } from './types';
3
+ import DefaultVariant from './variants/Default.astro';
4
+ import HeroVariant from './variants/Hero.astro';
5
+ import PostVariant from './variants/Post.astro';
6
+ import PostSplitVariant from './variants/PostSplit.astro';
7
+
8
+ interface Props {
9
+ variant?: "default" | "hero" | "post" | "post-split";
10
+ title?: string;
11
+ image?: string;
12
+ small?: boolean;
13
+ description?: string;
14
+ info?: string;
15
+ date?: string;
16
+ author?: Author;
17
+ categories?: Category[];
18
+ backgroundClass?: string;
19
+ }
20
+
21
+ const {
22
+ variant = "default",
23
+ title = "",
24
+ image,
25
+ small = false,
26
+ description,
27
+ info,
28
+ date,
29
+ author,
30
+ categories = [],
31
+ backgroundClass = 'bg-blue-darker'
32
+ } = Astro.props;
33
+
34
+ // Helper (function to check if a slot has content)
35
+ const hasSlotContent = async (slotName) => {
36
+ const slot = await Astro.slots.render(slotName);
37
+ return slot?.trim().length > 0;
38
+ };
39
+
40
+ // Get content status
41
+ const hasIntroContent = await hasSlotContent('intro');
42
+ const hasSubtitleContent = await hasSlotContent('subtitle');
43
+ const hasCtaContent = await hasSlotContent('cta-content');
44
+
45
+ // Content helpers
46
+ const hasMetadata = author || date;
47
+ const hasCategories = categories.length > 0;
48
+
49
+ // Props to pass to variants
50
+ const commonProps = {
51
+ title,
52
+ image,
53
+ hasIntroContent,
54
+ hasSubtitleContent,
55
+ hasCtaContent,
56
+ hasMetadata,
57
+ hasCategories,
58
+ backgroundClass,
59
+ };
60
+ ---
61
+
62
+ {variant === "default" && (
63
+ <DefaultVariant
64
+ {...commonProps}
65
+ small={small}
66
+ >
67
+ <slot name="intro" slot="intro" />
68
+ <slot name="subtitle" slot="subtitle" />
69
+ <slot name="cta-content" slot="cta-content" />
70
+ </DefaultVariant>
71
+ )}
72
+
73
+ {variant === "hero" && (
74
+ <HeroVariant
75
+ {...commonProps}
76
+ description={description}
77
+ info={info}
78
+ />
79
+ )}
80
+
81
+ {variant === "post" && (
82
+ <PostVariant
83
+ {...commonProps}
84
+ author={author}
85
+ date={date}
86
+ categories={categories}
87
+ />
88
+ )}
89
+
90
+ {variant === "post-split" && (
91
+ <PostSplitVariant
92
+ {...commonProps}
93
+ author={author}
94
+ date={date}
95
+ categories={categories}
96
+ />
97
+ )}
98
+
99
+ <style is:global>
100
+ .bg-vw {
101
+ background: radial-gradient(circle at 50% 85%, #00437a 0%, #001e50 100%);
102
+ }
103
+
104
+ .featured-image-overlay {
105
+ @apply absolute top-0 bottom-0 left-0 right-0 overflow-hidden w-full bg-gray-100 z-1;
106
+
107
+ &:before,
108
+ &:after {
109
+ @apply content-empty top-0 bottom-0 left-0 right-0 absolute;
110
+ }
111
+
112
+ &:before {
113
+ z-index: 5;
114
+ background: linear-gradient(
115
+ 0deg,
116
+ rgba(0, 0, 0, 0.95),
117
+ transparent 30%,
118
+ transparent 70%,
119
+ rgba(0, 0, 0, 0.95)
120
+ );
121
+ opacity: 0.5;
122
+ }
123
+
124
+ &:after {
125
+ background: radial-gradient(circle at 50% 85%, #00437a 0, #001e50 100%);
126
+ opacity: 0.8;
127
+ }
128
+ }
129
+
130
+ .featured-image {
131
+ width: 100%;
132
+ @apply bg-blue-900;
133
+
134
+ img {
135
+ width: 100%;
136
+ object-fit: cover;
137
+ max-width: 100%;
138
+ display: block;
139
+ }
140
+ }
141
+
142
+ h1 {
143
+ b {
144
+ @apply font-headregular whitespace-nowrap;
145
+ }
146
+ small {
147
+ @apply text-6 whitespace-nowrap;
148
+ }
149
+ span {
150
+ @apply text-accent-light;
151
+ }
152
+ }
153
+ </style>
File without changes
@@ -0,0 +1,29 @@
1
+ // types.ts
2
+ export interface Author {
3
+ firstName?: string;
4
+ name: string;
5
+ }
6
+
7
+ export interface Category {
8
+ name: string;
9
+ uri: string;
10
+ }
11
+
12
+ export interface Props {
13
+ // Common props
14
+ variant?: "default" | "hero" | "post" | "post-split";
15
+ title?: string;
16
+ image?: string;
17
+ backgroundClass?: string;
18
+
19
+
20
+ // Default & Hero variant props
21
+ small?: boolean;
22
+ description?: string;
23
+ info?: string;
24
+
25
+ // Post variants props
26
+ date?: string;
27
+ author?: Author;
28
+ categories?: Category[];
29
+ }