@eox/pages-theme-eox 1.9.0 → 2.0.0-alpha.10
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/.gitlab-ci.yml +4 -1
- package/README.md +88 -11
- package/cypress/support/mocks/authors.data.js +14 -0
- package/cypress/support/mocks/helpers.js +65 -4
- package/cypress/support/mocks/vitepress.js +8 -1
- package/cypress.config.js +14 -0
- package/package.json +3 -1
- package/src/Layout.vue +69 -1
- package/src/authors.data.js +14 -0
- package/src/components/BlogList.vue +655 -0
- package/src/components/BlogPost.vue +472 -0
- package/src/components/CTASection.vue +18 -4
- package/src/components/FeatureCard/Index.vue +462 -31
- package/src/components/FeatureCard/Poster.vue +25 -3
- package/src/components/FeatureSection.cy.js +16 -0
- package/src/components/FeatureSection.vue +3 -8
- package/src/components/FeaturesGallery.vue +34 -2
- package/src/components/Footer.cy.js +52 -2
- package/src/components/Footer.vue +17 -5
- package/src/components/HeroSection.cy.js +20 -0
- package/src/components/HeroSection.vue +140 -25
- package/src/components/ImageCarousel.vue +11 -2
- package/src/components/ImageElement.vue +16 -4
- package/src/components/ImageGallery.vue +29 -4
- package/src/components/LogoSection.vue +26 -3
- package/src/components/MobileNavDropdown.vue +13 -3
- package/src/components/NavBar.cy.js +15 -0
- package/src/components/NavBar.vue +149 -21
- package/src/components/NavDropdown.vue +12 -2
- package/src/components/OpenPositions.vue +292 -0
- package/src/components/SectionHeader.cy.js +54 -0
- package/src/components/SectionHeader.vue +115 -0
- package/src/components/TagList.vue +311 -0
- package/src/components/TeamPage.vue +347 -0
- package/src/components/TestimonialsSection.cy.js +76 -0
- package/src/components/TestimonialsSection.vue +368 -0
- package/src/components/TextSection.cy.js +115 -0
- package/src/components/TextSection.vue +396 -0
- package/src/helpers.js +182 -37
- package/src/helpers.test.js +181 -0
- package/src/index.js +16 -0
- package/src/pages/author/[author].md +5 -0
- package/src/pages/author/[author].paths.js +60 -0
- package/src/pages/blog.md +5 -0
- package/src/pages/tag/[tag].md +5 -0
- package/src/pages/tag/[tag].paths.js +49 -0
- package/src/pages/tag.md +5 -0
- package/src/pages/team.md +5 -0
- package/src/posts.data.js +134 -0
- package/src/style.css +389 -8
- package/src/tagUtils.js +148 -0
- package/src/team.data.js +1 -1
- package/src/vitepressConfig.mjs +101 -1
package/.gitlab-ci.yml
CHANGED
|
@@ -10,9 +10,11 @@ cache:
|
|
|
10
10
|
- package-lock.json
|
|
11
11
|
paths:
|
|
12
12
|
- .npm/
|
|
13
|
+
- .cache/Cypress
|
|
13
14
|
|
|
14
15
|
variables:
|
|
15
16
|
npm_config_cache: "$CI_PROJECT_DIR/.npm"
|
|
17
|
+
CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/.cache/Cypress"
|
|
16
18
|
|
|
17
19
|
security:
|
|
18
20
|
stage: security
|
|
@@ -33,6 +35,7 @@ test:
|
|
|
33
35
|
stage: test
|
|
34
36
|
script:
|
|
35
37
|
- npm ci
|
|
36
|
-
-
|
|
38
|
+
- npx cypress install
|
|
39
|
+
- npm run test
|
|
37
40
|
rules:
|
|
38
41
|
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'main'
|
package/README.md
CHANGED
|
@@ -145,26 +145,40 @@ The theme provides several built-in components and layout features. Some are dri
|
|
|
145
145
|
|
|
146
146
|
### Hero Section
|
|
147
147
|
|
|
148
|
-
To add a Hero section to the top of a page, use the `hero` frontmatter object.
|
|
148
|
+
To add a Hero section to the top of a page, use the `hero` frontmatter object. Heros feature a dark gradient transitioning from **DARK (top) to LIGHT (bottom)** (`.hero-gradient-bg`), allowing the top navigation bar to seamlessly sit transparently over the hero. On the landing page, the hero is larger and incorporates an isometric line pattern.
|
|
149
149
|
|
|
150
150
|
```yaml
|
|
151
151
|
---
|
|
152
152
|
hero:
|
|
153
|
-
title: "Welcome to My Site"
|
|
154
|
-
tagline: "Building the future of
|
|
153
|
+
text: "Welcome to My Site" # or title: "Welcome to My Site"
|
|
154
|
+
tagline: "Building the future of geospatial engineering"
|
|
155
155
|
image:
|
|
156
156
|
src: "/hero-image.png"
|
|
157
157
|
alt: "Hero Image"
|
|
158
158
|
actions:
|
|
159
159
|
- text: "Get Started"
|
|
160
160
|
link: "/start"
|
|
161
|
-
|
|
161
|
+
theme: "brand" # "brand" (primary surface), "secondary", or "alt" (bordered)
|
|
162
162
|
- text: "Learn More"
|
|
163
163
|
link: "/about"
|
|
164
|
-
|
|
164
|
+
theme: "secondary"
|
|
165
165
|
---
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
+
#### Hero on Aggregator Pages (`blog`, `team`, `tags`)
|
|
169
|
+
|
|
170
|
+
Pages using aggregator layouts (`layout: team`, `layout: blog`, or `layout: tags`) support optional heroes:
|
|
171
|
+
|
|
172
|
+
- **Without Hero (when `hero` is omitted or `hero: false`)**: The page renders a standard in-page header title beneath the solid top navigation bar.
|
|
173
|
+
- **With Hero (`hero: true` or custom `hero: { text, tagline, ... }`)**: The page renders the full dark hero with the `#000C14` → `#004170` gradient spanning seamlessly behind the transparent navigation bar. Setting `hero: true` automatically supplies appropriate layout titles (including dynamic `Tag: <tag>` and `Author: <author>` for filtered blog listings). Custom text, taglines, images, and actions can also be provided via the `hero` frontmatter object.
|
|
174
|
+
|
|
175
|
+
#### Gradient Design Standards
|
|
176
|
+
|
|
177
|
+
The theme standardizes two distinct gradient directions for dark visual elements using `#000C14` and `#004170`:
|
|
178
|
+
|
|
179
|
+
- **Hero Gradient (`.hero-gradient-bg`)**: Always transitions from **DARK (top) to LIGHT (bottom)**, running from `#000C14` (top) to `#004170` (bottom). Used for the landing page hero and all sub-page heroes. This anchors the fixed header area with dark contrast under navigation links while flowing naturally into lighter content below.
|
|
180
|
+
- **Dark Sections Gradient (`.primary-gradient-bg` / `.dark-section-gradient-bg`)**: Used in intermediate dark page sections further down the page (such as `<CTASection dark>`, feature highlights, or dark showcase galleries). Always transitions from **LIGHT (top) to DARK (bottom)**, running from `#004170` (top) to `#000C14` (bottom).
|
|
181
|
+
|
|
168
182
|
### Feature Section
|
|
169
183
|
|
|
170
184
|
Use the `<FeatureSection>` component to highlight specific features.
|
|
@@ -223,7 +237,7 @@ A flexible pricing table component.
|
|
|
223
237
|
|
|
224
238
|
#### CTA Section
|
|
225
239
|
|
|
226
|
-
A Call-to-Action section typically placed at the bottom of a page to encourage user engagement.
|
|
240
|
+
A Call-to-Action section typically placed at the bottom of a page to encourage user engagement. By default, it renders with a clean white (`surface-container-lowest`) background, or a dark gradient when the `dark` prop is passed.
|
|
227
241
|
|
|
228
242
|
```html
|
|
229
243
|
<CTASection
|
|
@@ -239,6 +253,19 @@ A Call-to-Action section typically placed at the bottom of a page to encourage u
|
|
|
239
253
|
/>
|
|
240
254
|
```
|
|
241
255
|
|
|
256
|
+
#### Section Header
|
|
257
|
+
|
|
258
|
+
A standardized three-tier header block for page sections, matching EOX design tokens with a tag badge, a large display title, and an optional subtitle description. Supports light/dark context modes automatically.
|
|
259
|
+
|
|
260
|
+
```html
|
|
261
|
+
<SectionHeader
|
|
262
|
+
tag="Viewing Ready & Basic"
|
|
263
|
+
icon="mdi-star-check-outline"
|
|
264
|
+
title="What our users say about Viewing Products"
|
|
265
|
+
subtitle="Optional paragraph providing context and detail for this section."
|
|
266
|
+
/>
|
|
267
|
+
```
|
|
268
|
+
|
|
242
269
|
#### Logo Section
|
|
243
270
|
|
|
244
271
|
Displays a grid of client or partner logos. It automatically handles logo sizing.
|
|
@@ -321,7 +348,7 @@ A standard content card with an icon or image, title, optional chips, metadata,
|
|
|
321
348
|
section-title="All Features"
|
|
322
349
|
variant="default"
|
|
323
350
|
columns="3/2/1"
|
|
324
|
-
background="surface-container-
|
|
351
|
+
background="surface-container-lowest"
|
|
325
352
|
:cards="[
|
|
326
353
|
{
|
|
327
354
|
id: 1,
|
|
@@ -559,7 +586,14 @@ feedback: false
|
|
|
559
586
|
The theme exports a set of shared utility and helper functions from its helpers module. You can import and use these helpers in your custom VitePress components, checkout pages, or inline script setups:
|
|
560
587
|
|
|
561
588
|
```javascript
|
|
562
|
-
import {
|
|
589
|
+
import {
|
|
590
|
+
formatPrice,
|
|
591
|
+
trackEvent,
|
|
592
|
+
trackPageView,
|
|
593
|
+
trackSiteSearch,
|
|
594
|
+
normalizeTrackingUrl,
|
|
595
|
+
t,
|
|
596
|
+
} from "@eox/pages-theme-eox/src/helpers";
|
|
563
597
|
```
|
|
564
598
|
|
|
565
599
|
### Available Helpers
|
|
@@ -585,12 +619,12 @@ formatPrice(12000, "en"); // "€ 12,000.-"
|
|
|
585
619
|
formatPrice(49.99, "de"); // "€ 49,99"
|
|
586
620
|
```
|
|
587
621
|
|
|
588
|
-
#### `trackEvent(eventDetails)`
|
|
622
|
+
#### `trackEvent(eventDetails, ...rest)`
|
|
589
623
|
|
|
590
|
-
Sends a custom tracking event to Matomo Analytics.
|
|
624
|
+
Sends a custom tracking event to Matomo Analytics. Automatically normalizes any path strings passed in category, action, or name.
|
|
591
625
|
|
|
592
626
|
- **Parameters**:
|
|
593
|
-
- `eventDetails` (`Array<string
|
|
627
|
+
- `eventDetails` (`Array<string|number>|string`): An array `[Category, Action, Name?, Value?]` or positional arguments `(category, action, name, value)`.
|
|
594
628
|
|
|
595
629
|
##### Example Usage:
|
|
596
630
|
|
|
@@ -598,8 +632,51 @@ Sends a custom tracking event to Matomo Analytics.
|
|
|
598
632
|
import { trackEvent } from "@eox/pages-theme-eox/src/helpers";
|
|
599
633
|
|
|
600
634
|
trackEvent(["CTA", "Click", "Technical Specifications", "Viewing Ready"]);
|
|
635
|
+
trackEvent("indicators", "select_indicator", "N1_NO2");
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
#### `trackPageView(options)`
|
|
639
|
+
|
|
640
|
+
Tracks a pageview with normalized path (trailing slash stripped, transient parameters removed) and custom document title.
|
|
641
|
+
|
|
642
|
+
- **Parameters**:
|
|
643
|
+
- `options` (`Object|string`): Vitepress router object, `{ path, title }` options object, or custom path string.
|
|
644
|
+
|
|
645
|
+
##### Example Usage:
|
|
646
|
+
|
|
647
|
+
```javascript
|
|
648
|
+
import { trackPageView } from "@eox/pages-theme-eox/src/helpers";
|
|
649
|
+
|
|
650
|
+
trackPageView({ path: "/explore/", title: "Explore" });
|
|
651
|
+
// Sends normalized URL "/explore" to Matomo
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
#### `trackSiteSearch(keyword, category, resultsCount)`
|
|
655
|
+
|
|
656
|
+
Sends search keyword telemetry to Matomo Site Search reports.
|
|
657
|
+
|
|
658
|
+
- **Parameters**:
|
|
659
|
+
- `keyword` (`string`): Searched term.
|
|
660
|
+
- `category` (`string|boolean`): Category (optional, e.g. `'indicators'`, `'stories'`).
|
|
661
|
+
- `resultsCount` (`number`): Number of search results returned.
|
|
662
|
+
|
|
663
|
+
##### Example Usage:
|
|
664
|
+
|
|
665
|
+
```javascript
|
|
666
|
+
import { trackSiteSearch } from "@eox/pages-theme-eox/src/helpers";
|
|
667
|
+
|
|
668
|
+
trackSiteSearch("methane", "indicators", 4);
|
|
601
669
|
```
|
|
602
670
|
|
|
671
|
+
#### `normalizeTrackingUrl(inputUrl, options)`
|
|
672
|
+
|
|
673
|
+
Pure helper that strips trailing slashes (e.g., `/explore/` -> `/explore`), strips volatile coordinate query params (`x`, `y`, `z`), and sorts remaining query parameters.
|
|
674
|
+
|
|
675
|
+
- **Parameters**:
|
|
676
|
+
- `inputUrl` (`string`): URL or path to normalize.
|
|
677
|
+
- `options` (`Object`): Optional configuration (`ignoredParams`, `stripTrailingSlash`).
|
|
678
|
+
- **Returns**: `string` - Normalized URL string.
|
|
679
|
+
|
|
603
680
|
#### `t(key, i18n)`
|
|
604
681
|
|
|
605
682
|
Retrieves localized translation strings from an i18n mapping object using dot-notation. Falls back to the key itself if no translation is defined.
|
|
@@ -1,7 +1,40 @@
|
|
|
1
1
|
// Mock generic helpers
|
|
2
2
|
// We delegate to a global object to allow spying in tests
|
|
3
3
|
window.__helpersMock = {
|
|
4
|
-
trackEvent: (details) => {},
|
|
4
|
+
trackEvent: (details, ...rest) => {},
|
|
5
|
+
trackPageView: (options) => {},
|
|
6
|
+
trackSiteSearch: (keyword, category, count) => {},
|
|
7
|
+
normalizeTrackingUrl: (url, options) => {
|
|
8
|
+
if (!url || typeof url !== "string") return url;
|
|
9
|
+
const { ignoredParams = ["x", "y", "z"], stripTrailingSlash = true } =
|
|
10
|
+
options || {};
|
|
11
|
+
try {
|
|
12
|
+
const base =
|
|
13
|
+
typeof window !== "undefined" && window.location?.href
|
|
14
|
+
? window.location.href
|
|
15
|
+
: "https://eox.at";
|
|
16
|
+
const u = new URL(url, base);
|
|
17
|
+
let pathname = u.pathname;
|
|
18
|
+
if (stripTrailingSlash && pathname.length > 1 && pathname.endsWith("/")) {
|
|
19
|
+
pathname = pathname.replace(/\/+$/, "");
|
|
20
|
+
}
|
|
21
|
+
const searchParams = new URLSearchParams(u.search);
|
|
22
|
+
for (const key of ignoredParams) {
|
|
23
|
+
searchParams.delete(key);
|
|
24
|
+
}
|
|
25
|
+
searchParams.sort();
|
|
26
|
+
const search = searchParams.toString();
|
|
27
|
+
const isRelative = !/^https?:\/\//i.test(url);
|
|
28
|
+
if (isRelative) {
|
|
29
|
+
return pathname + (search ? `?${search}` : "");
|
|
30
|
+
}
|
|
31
|
+
u.pathname = pathname;
|
|
32
|
+
u.search = search ? `?${search}` : "";
|
|
33
|
+
return u.toString();
|
|
34
|
+
} catch {
|
|
35
|
+
return url;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
5
38
|
acceptCookies: (router) => {},
|
|
6
39
|
declineCookies: (router) => {},
|
|
7
40
|
enableTracking: (enable, router) => {},
|
|
@@ -15,9 +48,31 @@ window.__helpersMock = {
|
|
|
15
48
|
}
|
|
16
49
|
},
|
|
17
50
|
isActive: (item, path) => {
|
|
18
|
-
if (item
|
|
19
|
-
if (item.
|
|
20
|
-
|
|
51
|
+
if (!item || !path) return false;
|
|
52
|
+
if (item.activeMatch) {
|
|
53
|
+
try {
|
|
54
|
+
return new RegExp(item.activeMatch).test(path);
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (
|
|
60
|
+
item.items &&
|
|
61
|
+
item.items.some((sub) => window.__helpersMock.isActive(sub, path))
|
|
62
|
+
) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
if (item.link) {
|
|
66
|
+
const normalize = (p) =>
|
|
67
|
+
decodeURI(p)
|
|
68
|
+
.replace(/[?#].*$/, "")
|
|
69
|
+
.replace(/\.html$/, "")
|
|
70
|
+
.replace(/\/$/, "");
|
|
71
|
+
const linkPath = normalize(item.link);
|
|
72
|
+
const currentPath = normalize(path);
|
|
73
|
+
if (linkPath === currentPath) return true;
|
|
74
|
+
if (linkPath === "") return currentPath === "";
|
|
75
|
+
return currentPath === linkPath || currentPath.startsWith(linkPath + "/");
|
|
21
76
|
}
|
|
22
77
|
return false;
|
|
23
78
|
},
|
|
@@ -94,6 +149,12 @@ window.__helpersMock = {
|
|
|
94
149
|
};
|
|
95
150
|
|
|
96
151
|
export const trackEvent = (...args) => window.__helpersMock.trackEvent(...args);
|
|
152
|
+
export const trackPageView = (...args) =>
|
|
153
|
+
window.__helpersMock.trackPageView(...args);
|
|
154
|
+
export const trackSiteSearch = (...args) =>
|
|
155
|
+
window.__helpersMock.trackSiteSearch(...args);
|
|
156
|
+
export const normalizeTrackingUrl = (...args) =>
|
|
157
|
+
window.__helpersMock.normalizeTrackingUrl(...args);
|
|
97
158
|
export const acceptCookies = (...args) =>
|
|
98
159
|
window.__helpersMock.acceptCookies(...args);
|
|
99
160
|
export const declineCookies = (...args) =>
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import { reactive, ref } from "vue";
|
|
1
|
+
import { reactive, ref, defineComponent, h } from "vue";
|
|
2
|
+
|
|
3
|
+
export const VPNavBarSearch = defineComponent({
|
|
4
|
+
name: "VPNavBarSearch",
|
|
5
|
+
render() {
|
|
6
|
+
return h("div", { class: "VPNavBarSearch" }, "Search");
|
|
7
|
+
},
|
|
8
|
+
});
|
|
2
9
|
|
|
3
10
|
const site = ref({
|
|
4
11
|
title: "Test Site",
|
package/cypress.config.js
CHANGED
|
@@ -10,6 +10,11 @@ export default defineConfig({
|
|
|
10
10
|
viteConfig: {
|
|
11
11
|
resolve: {
|
|
12
12
|
alias: {
|
|
13
|
+
// Alias vitepress/theme to our mock
|
|
14
|
+
"vitepress/theme": path.resolve(
|
|
15
|
+
__dirname,
|
|
16
|
+
"cypress/support/mocks/vitepress.js",
|
|
17
|
+
),
|
|
13
18
|
// Alias vitepress to our mock
|
|
14
19
|
vitepress: path.resolve(
|
|
15
20
|
__dirname,
|
|
@@ -29,6 +34,15 @@ export default defineConfig({
|
|
|
29
34
|
__dirname,
|
|
30
35
|
"cypress/support/mocks/features.data.js",
|
|
31
36
|
),
|
|
37
|
+
// Alias authors.data.js to our mock
|
|
38
|
+
"../authors.data.js": path.resolve(
|
|
39
|
+
__dirname,
|
|
40
|
+
"cypress/support/mocks/authors.data.js",
|
|
41
|
+
),
|
|
42
|
+
"../../authors.data.js": path.resolve(
|
|
43
|
+
__dirname,
|
|
44
|
+
"cypress/support/mocks/authors.data.js",
|
|
45
|
+
),
|
|
32
46
|
},
|
|
33
47
|
},
|
|
34
48
|
plugins: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eox/pages-theme-eox",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vitepress Theme with EOX branding",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"format": "npx prettier --write .",
|
|
14
14
|
"format:check": "npx prettier --check .",
|
|
15
|
+
"test": "npm run test:unit && npm run test:component",
|
|
16
|
+
"test:unit": "node --test src/helpers.test.js",
|
|
15
17
|
"test:component": "cypress run --component",
|
|
16
18
|
"release": "release-it"
|
|
17
19
|
},
|
package/src/Layout.vue
CHANGED
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<div
|
|
3
|
+
v-if="frontmatter.layout === 'blog'"
|
|
4
|
+
class="Layout layout-blog min-h-screen flex flex-col"
|
|
5
|
+
>
|
|
6
|
+
<NavBar />
|
|
7
|
+
<NewsBanner v-if="theme.newsBanner" :content="theme.newsBanner" />
|
|
8
|
+
<HeroSection />
|
|
9
|
+
<main class="flex-grow">
|
|
10
|
+
<BlogList />
|
|
11
|
+
<CTASection
|
|
12
|
+
v-if="frontmatter.cta !== false"
|
|
13
|
+
title="Interested in applying EO data to your use case?"
|
|
14
|
+
tagline="Let's build cloud-native systems, interactive maps, or customized Sentinel data layers together. Reach out to discuss your project requirements."
|
|
15
|
+
primaryButton="Contact us"
|
|
16
|
+
primaryLink="/contact"
|
|
17
|
+
dark
|
|
18
|
+
/>
|
|
19
|
+
</main>
|
|
20
|
+
<Footer v-if="frontmatter.footer !== false" />
|
|
21
|
+
<CookieBanner v-if="theme.theme.brandConfig?.analytics"></CookieBanner>
|
|
22
|
+
</div>
|
|
23
|
+
<div
|
|
24
|
+
v-else-if="frontmatter.layout === 'tags'"
|
|
25
|
+
class="Layout layout-tags min-h-screen flex flex-col"
|
|
26
|
+
>
|
|
27
|
+
<NavBar />
|
|
28
|
+
<NewsBanner v-if="theme.newsBanner" :content="theme.newsBanner" />
|
|
29
|
+
<HeroSection />
|
|
30
|
+
<main class="flex-grow">
|
|
31
|
+
<TagList />
|
|
32
|
+
</main>
|
|
33
|
+
<Footer v-if="frontmatter.footer !== false" />
|
|
34
|
+
<CookieBanner v-if="theme.theme.brandConfig?.analytics"></CookieBanner>
|
|
35
|
+
</div>
|
|
36
|
+
<div
|
|
37
|
+
v-else-if="frontmatter.layout === 'team'"
|
|
38
|
+
class="Layout layout-team min-h-screen flex flex-col"
|
|
39
|
+
>
|
|
40
|
+
<NavBar />
|
|
41
|
+
<NewsBanner v-if="theme.newsBanner" :content="theme.newsBanner" />
|
|
42
|
+
<HeroSection />
|
|
43
|
+
<main class="flex-grow">
|
|
44
|
+
<TeamPage />
|
|
45
|
+
</main>
|
|
46
|
+
<Footer v-if="frontmatter.footer !== false" />
|
|
47
|
+
<CookieBanner v-if="theme.theme.brandConfig?.analytics"></CookieBanner>
|
|
48
|
+
</div>
|
|
49
|
+
<div
|
|
50
|
+
v-else-if="frontmatter.layout === 'post' || isBlogPost"
|
|
51
|
+
class="layout-post min-h-screen flex flex-col"
|
|
52
|
+
>
|
|
53
|
+
<NavBar />
|
|
54
|
+
<NewsBanner v-if="theme.newsBanner" :content="theme.newsBanner" />
|
|
55
|
+
<main class="flex-grow">
|
|
56
|
+
<BlogPost />
|
|
57
|
+
</main>
|
|
58
|
+
<Footer v-if="frontmatter.footer !== false" />
|
|
59
|
+
<CookieBanner v-if="theme.theme.brandConfig?.analytics"></CookieBanner>
|
|
60
|
+
</div>
|
|
61
|
+
<Layout v-else :class="`layout-${frontmatter.layout}`">
|
|
3
62
|
<template #layout-top>
|
|
4
63
|
<slot name="layout-top"></slot>
|
|
5
64
|
<NavBar />
|
|
@@ -33,11 +92,20 @@
|
|
|
33
92
|
</template>
|
|
34
93
|
|
|
35
94
|
<script setup>
|
|
95
|
+
import { computed } from "vue";
|
|
36
96
|
import DefaultTheme from "vitepress/theme";
|
|
37
97
|
import { useData, useRouter } from "vitepress";
|
|
38
98
|
const { Layout } = DefaultTheme;
|
|
39
99
|
const { frontmatter, page, theme } = useData();
|
|
40
100
|
const router = useRouter();
|
|
101
|
+
|
|
102
|
+
const isBlogPost = computed(() => {
|
|
103
|
+
return (
|
|
104
|
+
frontmatter.value.layout === "post" ||
|
|
105
|
+
page.value.relativePath.startsWith("_posts/") ||
|
|
106
|
+
/^\d{4}\/\d{2}\//.test(page.value.relativePath)
|
|
107
|
+
);
|
|
108
|
+
});
|
|
41
109
|
</script>
|
|
42
110
|
|
|
43
111
|
<style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createContentLoader } from "vitepress";
|
|
2
|
+
|
|
3
|
+
export default createContentLoader("_team/*.md", {
|
|
4
|
+
transform(rawData) {
|
|
5
|
+
return rawData.map((page) => {
|
|
6
|
+
return {
|
|
7
|
+
id: page.frontmatter.id || "",
|
|
8
|
+
name: page.frontmatter.title || "",
|
|
9
|
+
url: page.url,
|
|
10
|
+
guest: page.frontmatter.guest || false,
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
},
|
|
14
|
+
});
|