@eox/pages-theme-eox 1.0.0 → 1.1.1
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/CHANGELOG.md +17 -0
- package/README.md +40 -1
- package/cypress/support/mocks/helpers.js +15 -0
- package/package.json +1 -1
- package/src/components/CookieBanner.vue +19 -6
- package/src/components/CookieSettings.vue +35 -27
- package/src/components/DataTable.vue +5 -1
- package/src/components/FeatureSection.vue +8 -4
- package/src/components/Footer.cy.js +58 -0
- package/src/components/Footer.vue +10 -18
- package/src/components/MobileNavDropdown.vue +6 -5
- package/src/components/NavBar.cy.js +37 -0
- package/src/components/NavBar.vue +92 -8
- package/src/components/NavDropdown.vue +7 -6
- package/src/components/NotFound.vue +8 -2
- package/src/components/PricingTable.vue +24 -7
- package/src/components/Tutorial.cy.js +85 -0
- package/src/components/Tutorial.vue +162 -0
- package/src/helpers.js +25 -0
- package/src/index.js +2 -0
- package/src/vitepressConfig.mjs +147 -95
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.1.1](https://gitlab.eox.at/eox/hub/eoxhub-portal/compare/v1.1.0...v1.1.1) (2026-03-02)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- render (HTML) footer message correctly ([6ea74ae](https://gitlab.eox.at/eox/hub/eoxhub-portal/commit/6ea74ae9df24fda7b677d6daa1e740b1d1dd6d97))
|
|
8
|
+
|
|
9
|
+
# [1.1.0](https://gitlab.eox.at/eox/hub/eoxhub-portal/compare/v1.0.0...v1.1.0) (2026-02-16)
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- **style:** css adjustments ([f2dc9a1](https://gitlab.eox.at/eox/hub/eoxhub-portal/commit/f2dc9a1db294b018e49c07acdb0f030bd98e03bf))
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- i18n support ([27af579](https://gitlab.eox.at/eox/hub/eoxhub-portal/commit/27af579611046e81baac7f49e4dd05db8e1cac12))
|
|
18
|
+
- introduce tutorial component ([158c7fd](https://gitlab.eox.at/eox/hub/eoxhub-portal/commit/158c7fdeb137f7b5598e0aa9819cf4793a5c8d81))
|
|
19
|
+
|
|
3
20
|
# [1.0.0](https://gitlab.eox.at/eox/hub/eoxhub-portal/compare/v0.11.5...v1.0.0) (2026-01-20)
|
|
4
21
|
|
|
5
22
|
### Features
|
package/README.md
CHANGED
|
@@ -69,9 +69,48 @@ The following standard VitePress configurations are handled as follows:
|
|
|
69
69
|
- **Site Title**: Explicitly disabled (`siteTitle: false`). The theme relies on the logo for branding.
|
|
70
70
|
- **Logo**: Used for branding. Must be configured as an object `{ light: string, dark: string }`.
|
|
71
71
|
- **Nav**: Fully supported (see above).
|
|
72
|
-
- **Footer**: Supported. The theme uses `theme.footer.copyright` for the copyright text.
|
|
72
|
+
- **Footer**: Supported. The theme uses `theme.footer.message` for the footer message and `theme.footer.copyright` for the copyright text (both supporting HTML).
|
|
73
73
|
- **Dark Mode**: The theme enforces a specific appearance. `appearance: false` is set in the base config.
|
|
74
74
|
|
|
75
|
+
### Internationalization (i18n)
|
|
76
|
+
|
|
77
|
+
This theme leverages VitePress's native [i18n capabilities](https://vitepress.dev/guide/i18n) and extends them with a simplified configuration via `brandConfig`.
|
|
78
|
+
|
|
79
|
+
#### Multi-language Routing
|
|
80
|
+
|
|
81
|
+
You can define multiple locales in your `brandConfig`. The theme will automatically generate the corresponding VitePress routes and display a language switcher in the navigation bar.
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
// brandConfig
|
|
85
|
+
{
|
|
86
|
+
i18n: {
|
|
87
|
+
locale: {
|
|
88
|
+
en: {
|
|
89
|
+
"Read more about": "Read more about",
|
|
90
|
+
"Contact us": "Contact us"
|
|
91
|
+
},
|
|
92
|
+
de: {
|
|
93
|
+
"Read more about": "Mehr lesen über",
|
|
94
|
+
"Contact us": "Kontaktieren Sie uns"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
currentLocale: "en" // This language will be at the root URL (/)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### Translation Pattern
|
|
103
|
+
|
|
104
|
+
The theme uses a "string-as-key" pattern. Most hardcoded UI elements (buttons, footer labels, etc.) use their English text as a lookup key. If a translation is provided in the `brandConfig.i18n.locale` object, it will be used; otherwise, it falls back to the original English text.
|
|
105
|
+
|
|
106
|
+
Nested keys are also supported via dot-notation if needed (e.g., `legal.privacy`).
|
|
107
|
+
|
|
108
|
+
#### Language Switcher
|
|
109
|
+
|
|
110
|
+
- **Desktop**: Appears as a translate icon in the top navigation bar.
|
|
111
|
+
- **Mobile**: Appears as a dedicated section within the mobile menu.
|
|
112
|
+
- The current language is automatically detected based on the URL path (e.g., `/de/` for German).
|
|
113
|
+
|
|
75
114
|
**Note on Documentation Features**:
|
|
76
115
|
This theme is primarily designed for landing pages and product showcases.
|
|
77
116
|
|
|
@@ -33,6 +33,20 @@ window.__helpersMock = {
|
|
|
33
33
|
});
|
|
34
34
|
return list;
|
|
35
35
|
},
|
|
36
|
+
t: (key, i18n) => {
|
|
37
|
+
if (!i18n) return key;
|
|
38
|
+
const keys = key.split(".");
|
|
39
|
+
let result = i18n;
|
|
40
|
+
for (const k of keys) {
|
|
41
|
+
if (result && Object.prototype.hasOwnProperty.call(result, k)) {
|
|
42
|
+
result = result[k];
|
|
43
|
+
} else {
|
|
44
|
+
result = null;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result ? result : key;
|
|
49
|
+
},
|
|
36
50
|
};
|
|
37
51
|
|
|
38
52
|
export const trackEvent = (...args) => window.__helpersMock.trackEvent(...args);
|
|
@@ -46,3 +60,4 @@ export const showBanner = (...args) => window.__helpersMock.showBanner(...args);
|
|
|
46
60
|
export const isActive = (...args) => window.__helpersMock.isActive(...args);
|
|
47
61
|
export const getFlatList = (...args) =>
|
|
48
62
|
window.__helpersMock.getFlatList(...args);
|
|
63
|
+
export const t = (...args) => window.__helpersMock.t(...args);
|
package/package.json
CHANGED
|
@@ -3,21 +3,33 @@
|
|
|
3
3
|
class="cookie-banner card surface medium-margin medium-padding medium-elevate no-round"
|
|
4
4
|
>
|
|
5
5
|
<p class="small-text">
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
{{
|
|
7
|
+
t(
|
|
8
|
+
"We use optional cookies to improve your experience and for marketing. Read our",
|
|
9
|
+
theme.i18n,
|
|
10
|
+
)
|
|
11
|
+
}}
|
|
8
12
|
<a
|
|
9
13
|
:href="theme.theme.brandConfig?.legal?.privacyPolicy"
|
|
10
14
|
target="_blank"
|
|
11
15
|
class="link"
|
|
12
16
|
>
|
|
13
|
-
privacy policy
|
|
17
|
+
{{ t("privacy policy", theme.i18n) }}
|
|
14
18
|
</a>
|
|
15
|
-
|
|
19
|
+
{{ t("or", theme.i18n) }}
|
|
20
|
+
<a class="link" href="/cookie-settings">{{
|
|
21
|
+
t("manage cookies", theme.i18n)
|
|
22
|
+
}}</a
|
|
23
|
+
>.
|
|
16
24
|
</p>
|
|
17
25
|
<nav>
|
|
18
26
|
<div class="max"></div>
|
|
19
|
-
<button class="small" @click="accept">
|
|
20
|
-
|
|
27
|
+
<button class="small" @click="accept">
|
|
28
|
+
{{ t("Accept all", theme.i18n) }}
|
|
29
|
+
</button>
|
|
30
|
+
<button class="small" @click="decline">
|
|
31
|
+
{{ t("Reject all", theme.i18n) }}
|
|
32
|
+
</button>
|
|
21
33
|
</nav>
|
|
22
34
|
</div>
|
|
23
35
|
</template>
|
|
@@ -30,6 +42,7 @@ import {
|
|
|
30
42
|
declineCookies,
|
|
31
43
|
enableTracking,
|
|
32
44
|
showBanner,
|
|
45
|
+
t,
|
|
33
46
|
} from "../helpers";
|
|
34
47
|
|
|
35
48
|
const { theme } = useData();
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="VPPage">
|
|
3
|
-
<h1>Cookie Settings</h1>
|
|
3
|
+
<h1>{{ t("Cookie Settings", theme.i18n) }}</h1>
|
|
4
4
|
<p>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
{{
|
|
6
|
+
t(
|
|
7
|
+
"We use cookies and similar technologies to improve your experience and for marketing purposes. Review and manage your cookie settings below to control your privacy. For more information on how we use cookies, please see our",
|
|
8
|
+
theme.i18n,
|
|
9
|
+
)
|
|
10
|
+
}}
|
|
9
11
|
<a
|
|
10
12
|
class="link"
|
|
11
13
|
:href="
|
|
@@ -13,7 +15,7 @@
|
|
|
13
15
|
'https://eox.at/privacy-notice/'
|
|
14
16
|
"
|
|
15
17
|
target="_blank"
|
|
16
|
-
>Privacy Policy</a
|
|
18
|
+
>{{ t("Privacy Policy", theme.i18n) }}</a
|
|
17
19
|
>.
|
|
18
20
|
</p>
|
|
19
21
|
<div
|
|
@@ -40,17 +42,19 @@
|
|
|
40
42
|
<details>
|
|
41
43
|
<summary class="middle-align">
|
|
42
44
|
<p class="primary-text bold">
|
|
43
|
-
<span class="view">
|
|
45
|
+
<span class="view">{{ t("View", theme.i18n) }}</span
|
|
46
|
+
><span class="hide">{{ t("Hide", theme.i18n) }}</span>
|
|
47
|
+
{{ t("cookies", theme.i18n) }}
|
|
44
48
|
</p>
|
|
45
49
|
<i class="small mdi mdi-chevron-down"></i>
|
|
46
50
|
</summary>
|
|
47
51
|
<table>
|
|
48
52
|
<thead>
|
|
49
53
|
<tr>
|
|
50
|
-
<th class="min">Name</th>
|
|
51
|
-
<th>Domain</th>
|
|
52
|
-
<th>Type</th>
|
|
53
|
-
<th>Duration</th>
|
|
54
|
+
<th class="min">{{ t("Name", theme.i18n) }}</th>
|
|
55
|
+
<th>{{ t("Domain", theme.i18n) }}</th>
|
|
56
|
+
<th>{{ t("Type", theme.i18n) }}</th>
|
|
57
|
+
<th>{{ t("Duration", theme.i18n) }}</th>
|
|
54
58
|
</tr>
|
|
55
59
|
</thead>
|
|
56
60
|
<tbody>
|
|
@@ -59,8 +63,8 @@
|
|
|
59
63
|
<code>{{ cookie.Name }}</code>
|
|
60
64
|
</td>
|
|
61
65
|
<td>{{ cookie.Domain }}</td>
|
|
62
|
-
<td>{{ cookie.Type }}</td>
|
|
63
|
-
<td>{{ cookie.Duration }}</td>
|
|
66
|
+
<td>{{ t(cookie.Type, theme.i18n) }}</td>
|
|
67
|
+
<td>{{ t(cookie.Duration, theme.i18n) }}</td>
|
|
64
68
|
</tr>
|
|
65
69
|
</tbody>
|
|
66
70
|
</table>
|
|
@@ -101,11 +105,11 @@ details[open] summary .hide {
|
|
|
101
105
|
<script setup>
|
|
102
106
|
import { onMounted } from "vue";
|
|
103
107
|
import { useData, useRouter } from "vitepress";
|
|
104
|
-
import { enableTracking, showBanner } from "../helpers.js";
|
|
108
|
+
import { enableTracking, showBanner, t } from "../helpers.js";
|
|
105
109
|
const { theme } = useData();
|
|
106
110
|
const router = useRouter();
|
|
107
111
|
|
|
108
|
-
router.route.data.title = "Cookie Settings";
|
|
112
|
+
router.route.data.title = t("Cookie Settings", theme.value.i18n);
|
|
109
113
|
router.onBeforeRouteChange = (to) => {
|
|
110
114
|
if (to === "/cookie-settings") {
|
|
111
115
|
showBanner(false);
|
|
@@ -118,40 +122,44 @@ router.onBeforeRouteChange = (to) => {
|
|
|
118
122
|
};
|
|
119
123
|
|
|
120
124
|
const cookies = {
|
|
121
|
-
Essential: {
|
|
122
|
-
description:
|
|
125
|
+
[t("Essential", theme.value.i18n)]: {
|
|
126
|
+
description: t(
|
|
123
127
|
"Cookies that are strictly necessary for basic website or app functionality.",
|
|
128
|
+
theme.value.i18n,
|
|
129
|
+
),
|
|
124
130
|
required: true,
|
|
125
131
|
cookies: [
|
|
126
132
|
{
|
|
127
133
|
Name: "mtm_consent_removed",
|
|
128
134
|
Domain: `.${window.location.host}`,
|
|
129
|
-
Type: "Opt-out management",
|
|
130
|
-
Duration: "13 months",
|
|
135
|
+
Type: t("Opt-out management", theme.value.i18n),
|
|
136
|
+
Duration: t("13 months", theme.value.i18n),
|
|
131
137
|
},
|
|
132
138
|
{
|
|
133
139
|
Name: "mtm_consent",
|
|
134
140
|
Domain: `.${window.location.host}`,
|
|
135
|
-
Type: "Consent management",
|
|
136
|
-
Duration: "13 months",
|
|
141
|
+
Type: t("Consent management", theme.value.i18n),
|
|
142
|
+
Duration: t("13 months", theme.value.i18n),
|
|
137
143
|
},
|
|
138
144
|
],
|
|
139
145
|
},
|
|
140
|
-
Analytics: {
|
|
141
|
-
description:
|
|
146
|
+
[t("Analytics", theme.value.i18n)]: {
|
|
147
|
+
description: t(
|
|
142
148
|
"Cookies that are required for analyzing website or app usage.",
|
|
149
|
+
theme.value.i18n,
|
|
150
|
+
),
|
|
143
151
|
cookies: [
|
|
144
152
|
{
|
|
145
153
|
Name: "_pk_id",
|
|
146
154
|
Domain: `.${window.location.host}`,
|
|
147
|
-
Type: "First-party website analytics",
|
|
148
|
-
Duration: "13 months",
|
|
155
|
+
Type: t("First-party website analytics", theme.value.i18n),
|
|
156
|
+
Duration: t("13 months", theme.value.i18n),
|
|
149
157
|
},
|
|
150
158
|
{
|
|
151
159
|
Name: "_pk_ses",
|
|
152
160
|
Domain: `.${window.location.host}`,
|
|
153
|
-
Type: "First-party website analytics",
|
|
154
|
-
Duration: "30 minutes",
|
|
161
|
+
Type: t("First-party website analytics", theme.value.i18n),
|
|
162
|
+
Duration: t("30 minutes", theme.value.i18n),
|
|
155
163
|
},
|
|
156
164
|
],
|
|
157
165
|
},
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref } from "vue";
|
|
3
|
+
import { useData } from "vitepress";
|
|
4
|
+
import { t } from "../helpers";
|
|
5
|
+
|
|
6
|
+
const { theme } = useData();
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* @typedef {Object} TableRowData
|
|
@@ -51,7 +55,7 @@ const toggleRow = (index) => {
|
|
|
51
55
|
<thead>
|
|
52
56
|
<tr>
|
|
53
57
|
<th v-for="header in headers" :key="header">
|
|
54
|
-
{{ header }}
|
|
58
|
+
{{ t(header, theme.i18n) }}
|
|
55
59
|
</th>
|
|
56
60
|
</tr>
|
|
57
61
|
</thead>
|
|
@@ -25,7 +25,9 @@
|
|
|
25
25
|
:class="`button primary medium-elevate no-margin responsive-mobile`"
|
|
26
26
|
style="margin-right: 12px !important"
|
|
27
27
|
>
|
|
28
|
-
<span>{{
|
|
28
|
+
<span>{{
|
|
29
|
+
primaryButton || `${t("Read more about", theme.i18n)} ${title}`
|
|
30
|
+
}}</span>
|
|
29
31
|
<i class="mdi mdi-arrow-right"></i>
|
|
30
32
|
</a>
|
|
31
33
|
<a
|
|
@@ -35,7 +37,7 @@
|
|
|
35
37
|
class="button secondary medium-elevate no-margin responsive-mobile"
|
|
36
38
|
style="color: var(--on-surface); margin-top: 12px !important"
|
|
37
39
|
>
|
|
38
|
-
<span>{{ secondaryButton || "Contact sales" }}</span>
|
|
40
|
+
<span>{{ secondaryButton || t("Contact sales", theme.i18n) }}</span>
|
|
39
41
|
<i class="mdi mdi-arrow-right"></i>
|
|
40
42
|
</a>
|
|
41
43
|
<a
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
class="button border no-margin responsive-mobile"
|
|
46
48
|
style="color: var(--on-surface); margin-top: 12px !important"
|
|
47
49
|
>
|
|
48
|
-
<span>{{ altButton || "Contact sales" }}</span>
|
|
50
|
+
<span>{{ altButton || t("Contact sales", theme.i18n) }}</span>
|
|
49
51
|
</a>
|
|
50
52
|
</div>
|
|
51
53
|
</div>
|
|
@@ -68,7 +70,9 @@
|
|
|
68
70
|
</template>
|
|
69
71
|
|
|
70
72
|
<script setup>
|
|
71
|
-
import { withBase } from "vitepress";
|
|
73
|
+
import { withBase, useData } from "vitepress";
|
|
74
|
+
import { t } from "../helpers.js";
|
|
75
|
+
const { theme } = useData();
|
|
72
76
|
const props = defineProps([
|
|
73
77
|
"dark",
|
|
74
78
|
"icon",
|
|
@@ -12,6 +12,7 @@ describe("<Footer />", () => {
|
|
|
12
12
|
{ text: "Contact", link: "/contact" },
|
|
13
13
|
],
|
|
14
14
|
footer: {
|
|
15
|
+
message: 'Powered by <a href="https://eox.at">EOX</a>',
|
|
15
16
|
copyright: "© 2026 EOX",
|
|
16
17
|
},
|
|
17
18
|
theme: {
|
|
@@ -49,4 +50,61 @@ describe("<Footer />", () => {
|
|
|
49
50
|
);
|
|
50
51
|
cy.contains("a", "Privacy").should("have.attr", "href", "/privacy");
|
|
51
52
|
});
|
|
53
|
+
|
|
54
|
+
it("renders footer message with HTML content", () => {
|
|
55
|
+
__setMockData({
|
|
56
|
+
site: { title: "EOX Site" },
|
|
57
|
+
theme: {
|
|
58
|
+
logo: { light: "/logo.png" },
|
|
59
|
+
nav: [
|
|
60
|
+
{ text: "Link 1", link: "/link1" },
|
|
61
|
+
{ text: "Contact", link: "/contact" },
|
|
62
|
+
],
|
|
63
|
+
footer: {
|
|
64
|
+
message: 'Powered by <a href="https://eox.at">EOX</a>',
|
|
65
|
+
copyright: "© 2026 EOX",
|
|
66
|
+
},
|
|
67
|
+
theme: {
|
|
68
|
+
brandConfig: {},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
cy.mount(Footer);
|
|
73
|
+
cy.contains("p", "Powered by")
|
|
74
|
+
.find("a")
|
|
75
|
+
.should("have.attr", "href", "https://eox.at")
|
|
76
|
+
.and("contain", "EOX");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("renders i18n overrides", () => {
|
|
80
|
+
__setMockData({
|
|
81
|
+
site: { title: "EOX Site" },
|
|
82
|
+
theme: {
|
|
83
|
+
logo: { light: "/logo.png" },
|
|
84
|
+
nav: [],
|
|
85
|
+
footer: {
|
|
86
|
+
copyright: "© 2026 EOX",
|
|
87
|
+
},
|
|
88
|
+
i18n: {
|
|
89
|
+
About: "Über uns",
|
|
90
|
+
Legal: "Rechtliches",
|
|
91
|
+
"Powered by": "Unterstützt von",
|
|
92
|
+
},
|
|
93
|
+
theme: {
|
|
94
|
+
brandConfig: {},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
cy.mount(Footer);
|
|
99
|
+
cy.contains("Über uns").should("exist");
|
|
100
|
+
cy.contains("Rechtliches").should("exist");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("renders footer message with HTML content", () => {
|
|
104
|
+
cy.mount(Footer);
|
|
105
|
+
cy.contains("p", "Powered by")
|
|
106
|
+
.find("a")
|
|
107
|
+
.should("have.attr", "href", "https://eox.at")
|
|
108
|
+
.and("contain", "EOX");
|
|
109
|
+
});
|
|
52
110
|
});
|
|
@@ -22,18 +22,8 @@
|
|
|
22
22
|
theme.nav.find((i) => i.link && i.link.includes("contact")).text
|
|
23
23
|
}}</a
|
|
24
24
|
>
|
|
25
|
+
<p v-html="theme.footer.message"></p>
|
|
25
26
|
<p v-html="theme.footer.copyright"></p>
|
|
26
|
-
<p class="middle-align">
|
|
27
|
-
Powered by
|
|
28
|
-
<a
|
|
29
|
-
href="https://hub.eox.at"
|
|
30
|
-
target="_blank"
|
|
31
|
-
class="left-margin small-margin"
|
|
32
|
-
><img
|
|
33
|
-
src="https://hub.eox.at/hub/custom/logos/eoxhub.svg"
|
|
34
|
-
style="height: 25px"
|
|
35
|
-
/></a>
|
|
36
|
-
</p>
|
|
37
27
|
</div>
|
|
38
28
|
<div class="s12 l6">
|
|
39
29
|
<div class="grid large-line">
|
|
@@ -41,7 +31,7 @@
|
|
|
41
31
|
class="s6 l4"
|
|
42
32
|
v-if="theme.nav.filter((i) => !i.action && i.link).length"
|
|
43
33
|
>
|
|
44
|
-
<p class="bold">About</p>
|
|
34
|
+
<p class="bold">{{ t("About", theme.i18n) }}</p>
|
|
45
35
|
<p v-for="item in theme.nav.filter((i) => !i.action && i.link)">
|
|
46
36
|
<a
|
|
47
37
|
:href="withBase(item.link)"
|
|
@@ -65,7 +55,7 @@
|
|
|
65
55
|
</p>
|
|
66
56
|
</div>
|
|
67
57
|
<div class="s6 l4">
|
|
68
|
-
<p class="bold">Legal</p>
|
|
58
|
+
<p class="bold">{{ t("Legal", theme.i18n) }}</p>
|
|
69
59
|
<p>
|
|
70
60
|
<a
|
|
71
61
|
:href="
|
|
@@ -74,7 +64,7 @@
|
|
|
74
64
|
"
|
|
75
65
|
target="_blank"
|
|
76
66
|
class="link"
|
|
77
|
-
>About</a
|
|
67
|
+
>{{ t("About", theme.i18n) }}</a
|
|
78
68
|
>
|
|
79
69
|
</p>
|
|
80
70
|
<p>
|
|
@@ -85,7 +75,7 @@
|
|
|
85
75
|
"
|
|
86
76
|
target="_blank"
|
|
87
77
|
class="link"
|
|
88
|
-
>Terms & Conditions</a
|
|
78
|
+
>{{ t("Terms & Conditions", theme.i18n) }}</a
|
|
89
79
|
>
|
|
90
80
|
</p>
|
|
91
81
|
<p>
|
|
@@ -96,11 +86,13 @@
|
|
|
96
86
|
"
|
|
97
87
|
target="_blank"
|
|
98
88
|
class="link"
|
|
99
|
-
>Privacy</a
|
|
89
|
+
>{{ t("Privacy", theme.i18n) }}</a
|
|
100
90
|
>
|
|
101
91
|
</p>
|
|
102
92
|
<p v-if="theme.theme.brandConfig?.analytics">
|
|
103
|
-
<a href="/cookie-settings" class="link">
|
|
93
|
+
<a href="/cookie-settings" class="link">{{
|
|
94
|
+
t("Cookie settings", theme.i18n)
|
|
95
|
+
}}</a>
|
|
104
96
|
</p>
|
|
105
97
|
</div>
|
|
106
98
|
</div>
|
|
@@ -113,7 +105,7 @@
|
|
|
113
105
|
|
|
114
106
|
<script setup>
|
|
115
107
|
import { useData, withBase } from "vitepress";
|
|
116
|
-
import { trackEvent, getFlatList } from "../helpers";
|
|
108
|
+
import { trackEvent, getFlatList, t } from "../helpers";
|
|
117
109
|
const { site, theme } = useData();
|
|
118
110
|
</script>
|
|
119
111
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<details>
|
|
5
5
|
<summary>
|
|
6
6
|
<span class="max" :class="{ active: isActive(item, route.path) }">{{
|
|
7
|
-
item.text
|
|
7
|
+
t(item.text, theme.i18n)
|
|
8
8
|
}}</span>
|
|
9
9
|
<i class="mdi mdi-chevron-down"></i>
|
|
10
10
|
</summary>
|
|
@@ -23,18 +23,18 @@
|
|
|
23
23
|
data-ui="#mobile-menu"
|
|
24
24
|
:class="{ active: isActive(item, route.path) }"
|
|
25
25
|
>
|
|
26
|
-
<span>{{ item.text }}</span>
|
|
26
|
+
<span>{{ t(item.text, theme.i18n) }}</span>
|
|
27
27
|
</a>
|
|
28
28
|
<span v-else :class="{ active: isActive(item, route.path) }">{{
|
|
29
|
-
item.text
|
|
29
|
+
t(item.text, theme.i18n)
|
|
30
30
|
}}</span>
|
|
31
31
|
</li>
|
|
32
32
|
</template>
|
|
33
33
|
</template>
|
|
34
34
|
|
|
35
35
|
<script setup>
|
|
36
|
-
import { withBase, useRoute } from "vitepress";
|
|
37
|
-
import { isActive } from "../helpers";
|
|
36
|
+
import { withBase, useRoute, useData } from "vitepress";
|
|
37
|
+
import { isActive, t } from "../helpers";
|
|
38
38
|
|
|
39
39
|
defineProps({
|
|
40
40
|
items: {
|
|
@@ -44,4 +44,5 @@ defineProps({
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
const route = useRoute();
|
|
47
|
+
const { theme } = useData();
|
|
47
48
|
</script>
|
|
@@ -103,4 +103,41 @@ describe("<NavBar />", () => {
|
|
|
103
103
|
cy.get("dialog#mobile-menu .social-links").should("exist");
|
|
104
104
|
cy.get("dialog#mobile-menu .social-links a").should("have.length", 2);
|
|
105
105
|
});
|
|
106
|
+
|
|
107
|
+
it("renders language switcher when multiple locales are defined", () => {
|
|
108
|
+
__setMockData({
|
|
109
|
+
site: {
|
|
110
|
+
title: "EOX",
|
|
111
|
+
locales: {
|
|
112
|
+
root: { label: "English", lang: "en" },
|
|
113
|
+
de: { label: "German", lang: "de" },
|
|
114
|
+
},
|
|
115
|
+
localeIndex: "root",
|
|
116
|
+
},
|
|
117
|
+
theme: {
|
|
118
|
+
logo: { light: "/logo.png" },
|
|
119
|
+
nav: [],
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
cy.viewport(1920, 1080);
|
|
124
|
+
cy.mount(NavBar);
|
|
125
|
+
|
|
126
|
+
// Desktop
|
|
127
|
+
cy.get(".nav-desktop .mdi-translate").should("exist");
|
|
128
|
+
cy.get(".nav-desktop menu li").should("have.length", 2);
|
|
129
|
+
cy.get(".nav-desktop menu li").contains("English").should("exist");
|
|
130
|
+
cy.get(".nav-desktop menu li").contains("German").should("exist");
|
|
131
|
+
cy.get(".nav-desktop menu li.active").contains("English").should("exist");
|
|
132
|
+
|
|
133
|
+
// Mobile
|
|
134
|
+
cy.viewport(375, 667);
|
|
135
|
+
cy.get("#mobile-menu details summary").contains("English").should("exist");
|
|
136
|
+
cy.get("#mobile-menu details summary .mdi-translate").should("exist");
|
|
137
|
+
cy.get("#mobile-menu details ul li").should("have.length", 1);
|
|
138
|
+
cy.get("#mobile-menu details ul li").contains("German").should("exist");
|
|
139
|
+
cy.get("#mobile-menu details ul li")
|
|
140
|
+
.contains("English")
|
|
141
|
+
.should("not.exist");
|
|
142
|
+
});
|
|
106
143
|
});
|