@eox/pages-theme-eox 1.0.0 → 1.1.0
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 +11 -0
- package/README.md +39 -0
- 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 +25 -0
- package/src/components/Footer.vue +10 -8
- 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 +141 -95
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
# [1.1.0](https://gitlab.eox.at/eox/hub/eoxhub-portal/compare/v1.0.0...v1.1.0) (2026-02-16)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
- **style:** css adjustments ([f2dc9a1](https://gitlab.eox.at/eox/hub/eoxhub-portal/commit/f2dc9a1db294b018e49c07acdb0f030bd98e03bf))
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- i18n support ([27af579](https://gitlab.eox.at/eox/hub/eoxhub-portal/commit/27af579611046e81baac7f49e4dd05db8e1cac12))
|
|
12
|
+
- introduce tutorial component ([158c7fd](https://gitlab.eox.at/eox/hub/eoxhub-portal/commit/158c7fdeb137f7b5598e0aa9819cf4793a5c8d81))
|
|
13
|
+
|
|
3
14
|
# [1.0.0](https://gitlab.eox.at/eox/hub/eoxhub-portal/compare/v0.11.5...v1.0.0) (2026-01-20)
|
|
4
15
|
|
|
5
16
|
### Features
|
package/README.md
CHANGED
|
@@ -72,6 +72,45 @@ The following standard VitePress configurations are handled as follows:
|
|
|
72
72
|
- **Footer**: Supported. The theme uses `theme.footer.copyright` for the copyright text.
|
|
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",
|
|
@@ -49,4 +49,29 @@ describe("<Footer />", () => {
|
|
|
49
49
|
);
|
|
50
50
|
cy.contains("a", "Privacy").should("have.attr", "href", "/privacy");
|
|
51
51
|
});
|
|
52
|
+
|
|
53
|
+
it("renders i18n overrides", () => {
|
|
54
|
+
__setMockData({
|
|
55
|
+
site: { title: "EOX Site" },
|
|
56
|
+
theme: {
|
|
57
|
+
logo: { light: "/logo.png" },
|
|
58
|
+
nav: [],
|
|
59
|
+
footer: {
|
|
60
|
+
copyright: "© 2026 EOX",
|
|
61
|
+
},
|
|
62
|
+
i18n: {
|
|
63
|
+
About: "Über uns",
|
|
64
|
+
Legal: "Rechtliches",
|
|
65
|
+
"Powered by": "Unterstützt von",
|
|
66
|
+
},
|
|
67
|
+
theme: {
|
|
68
|
+
brandConfig: {},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
cy.mount(Footer);
|
|
73
|
+
cy.contains("Über uns").should("exist");
|
|
74
|
+
cy.contains("Rechtliches").should("exist");
|
|
75
|
+
cy.contains("Unterstützt von").should("exist");
|
|
76
|
+
});
|
|
52
77
|
});
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
>
|
|
25
25
|
<p v-html="theme.footer.copyright"></p>
|
|
26
26
|
<p class="middle-align">
|
|
27
|
-
Powered by
|
|
27
|
+
{{ t("Powered by", theme.i18n) }}
|
|
28
28
|
<a
|
|
29
29
|
href="https://hub.eox.at"
|
|
30
30
|
target="_blank"
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
class="s6 l4"
|
|
42
42
|
v-if="theme.nav.filter((i) => !i.action && i.link).length"
|
|
43
43
|
>
|
|
44
|
-
<p class="bold">About</p>
|
|
44
|
+
<p class="bold">{{ t("About", theme.i18n) }}</p>
|
|
45
45
|
<p v-for="item in theme.nav.filter((i) => !i.action && i.link)">
|
|
46
46
|
<a
|
|
47
47
|
:href="withBase(item.link)"
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
</p>
|
|
66
66
|
</div>
|
|
67
67
|
<div class="s6 l4">
|
|
68
|
-
<p class="bold">Legal</p>
|
|
68
|
+
<p class="bold">{{ t("Legal", theme.i18n) }}</p>
|
|
69
69
|
<p>
|
|
70
70
|
<a
|
|
71
71
|
:href="
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"
|
|
75
75
|
target="_blank"
|
|
76
76
|
class="link"
|
|
77
|
-
>About</a
|
|
77
|
+
>{{ t("About", theme.i18n) }}</a
|
|
78
78
|
>
|
|
79
79
|
</p>
|
|
80
80
|
<p>
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"
|
|
86
86
|
target="_blank"
|
|
87
87
|
class="link"
|
|
88
|
-
>Terms & Conditions</a
|
|
88
|
+
>{{ t("Terms & Conditions", theme.i18n) }}</a
|
|
89
89
|
>
|
|
90
90
|
</p>
|
|
91
91
|
<p>
|
|
@@ -96,11 +96,13 @@
|
|
|
96
96
|
"
|
|
97
97
|
target="_blank"
|
|
98
98
|
class="link"
|
|
99
|
-
>Privacy</a
|
|
99
|
+
>{{ t("Privacy", theme.i18n) }}</a
|
|
100
100
|
>
|
|
101
101
|
</p>
|
|
102
102
|
<p v-if="theme.theme.brandConfig?.analytics">
|
|
103
|
-
<a href="/cookie-settings" class="link">
|
|
103
|
+
<a href="/cookie-settings" class="link">{{
|
|
104
|
+
t("Cookie settings", theme.i18n)
|
|
105
|
+
}}</a>
|
|
104
106
|
</p>
|
|
105
107
|
</div>
|
|
106
108
|
</div>
|
|
@@ -113,7 +115,7 @@
|
|
|
113
115
|
|
|
114
116
|
<script setup>
|
|
115
117
|
import { useData, withBase } from "vitepress";
|
|
116
|
-
import { trackEvent, getFlatList } from "../helpers";
|
|
118
|
+
import { trackEvent, getFlatList, t } from "../helpers";
|
|
117
119
|
const { site, theme } = useData();
|
|
118
120
|
</script>
|
|
119
121
|
|
|
@@ -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
|
});
|