@eox/pages-theme-eox 2.0.0-alpha.3 → 2.0.0-alpha.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eox/pages-theme-eox",
3
- "version": "2.0.0-alpha.3",
3
+ "version": "2.0.0-alpha.5",
4
4
  "type": "module",
5
5
  "description": "Vitepress Theme with EOX branding",
6
6
  "main": "src/index.js",
@@ -49,10 +49,17 @@
49
49
  "
50
50
  :date="post.date"
51
51
  :authors="post.authors"
52
- :chips="post.tags ? post.tags.map((t) => ({ text: t })) : []"
52
+ :chips="
53
+ post.tags
54
+ ? post.tags.map((t) => ({
55
+ text: t,
56
+ link: withBase(`/tag/${t}/`),
57
+ }))
58
+ : []
59
+ "
53
60
  :link="{
54
61
  text: 'Read more',
55
- href: post.url,
62
+ href: withBase(post.url),
56
63
  target: '_self',
57
64
  }"
58
65
  variant="cover"
@@ -133,7 +140,7 @@
133
140
  <div class="sidebar-widget">
134
141
  <div class="sidebar-title-container">
135
142
  <h3 class="sidebar-title-inline">Hot tags</h3>
136
- <a href="/tag" class="see-all-link">
143
+ <a :href="withBase('/tag')" class="see-all-link">
137
144
  <span>see all</span>
138
145
  <i class="mdi mdi-arrow-right"></i>
139
146
  </a>
@@ -142,7 +149,7 @@
142
149
  <a
143
150
  v-for="tag in calculatedHotTags"
144
151
  :key="tag.name"
145
- :href="`/tag/${tag.name}/`"
152
+ :href="withBase(`/tag/${tag.name}/`)"
146
153
  :style="getTagStyle(tag.name)"
147
154
  class="sidebar-tag"
148
155
  >
@@ -157,7 +164,7 @@
157
164
 
158
165
  <script setup>
159
166
  import { ref, computed, onMounted, watch } from "vue";
160
- import { useRouter, useData } from "vitepress";
167
+ import { useRouter, useData, withBase } from "vitepress";
161
168
  import { data as posts } from "../posts.data.js";
162
169
  import { data as authorsList } from "../authors.data.js";
163
170
  import { getTagColor, getTagStyle } from "../tagUtils.js";
@@ -198,10 +205,17 @@ const postsPerPage = 9;
198
205
  // Form cover image URL correctly (prefixing filename with /images/)
199
206
  function getCoverImageUrl(coverImage) {
200
207
  if (!coverImage) return "";
201
- if (coverImage.startsWith("/") || coverImage.startsWith("http")) {
208
+ if (coverImage.startsWith("http") || coverImage.startsWith("//")) {
209
+ return coverImage;
210
+ }
211
+ const base = withBase("/");
212
+ if (base && base !== "/" && coverImage.startsWith(base)) {
202
213
  return coverImage;
203
214
  }
204
- return `/images/${coverImage}`;
215
+ const path = coverImage.startsWith("/")
216
+ ? coverImage
217
+ : `/images/${coverImage}`;
218
+ return withBase(path);
205
219
  }
206
220
 
207
221
  const tagFromParam = computed(() => {
@@ -40,7 +40,10 @@
40
40
  :key="authorId"
41
41
  class="author-item"
42
42
  >
43
- <a :href="`/author/${authorId}/`" class="author-link-active">
43
+ <a
44
+ :href="withBase(`/author/${authorId}/`)"
45
+ class="author-link-active"
46
+ >
44
47
  {{ getAuthorName(authorId) }}
45
48
  </a>
46
49
  <span v-if="idx < authors.length - 1" class="author-separator"
@@ -58,7 +61,7 @@
58
61
  <a
59
62
  v-for="tag in frontmatter.tags"
60
63
  :key="tag"
61
- :href="`/tag/${tag}/`"
64
+ :href="withBase(`/tag/${tag}/`)"
62
65
  :style="getTagStyle(tag)"
63
66
  class="post-tag"
64
67
  >
@@ -87,7 +90,7 @@
87
90
  <a
88
91
  v-for="tag in calculatedHotTags"
89
92
  :key="tag.name"
90
- :href="`/tag/${tag.name}/`"
93
+ :href="withBase(`/tag/${tag.name}/`)"
91
94
  :style="getTagStyle(tag.name)"
92
95
  class="sidebar-tag"
93
96
  >
@@ -106,7 +109,7 @@
106
109
  class="flex flex-col gap-1 border-b border-slate-100 last:border-none pb-3 last:pb-0"
107
110
  >
108
111
  <a
109
- :href="post.url"
112
+ :href="withBase(post.url)"
110
113
  class="text-sm font-semibold text-slate-900 hover:text-primary leading-snug transition-colors line-clamp-2"
111
114
  >
112
115
  {{ post.title }}
@@ -123,7 +126,7 @@
123
126
  </template>
124
127
 
125
128
  <script setup>
126
- import { useData } from "vitepress";
129
+ import { useData, withBase } from "vitepress";
127
130
  import { computed } from "vue";
128
131
  import { data as posts } from "../posts.data.js";
129
132
  import { data as authorsList } from "../authors.data.js";
@@ -145,10 +148,17 @@ const headers = computed(() => {
145
148
  // Form cover image URL correctly (prefixing filename with /images/)
146
149
  function getCoverImageUrl(coverImage) {
147
150
  if (!coverImage) return "";
148
- if (coverImage.startsWith("/") || coverImage.startsWith("http")) {
151
+ if (coverImage.startsWith("http") || coverImage.startsWith("//")) {
152
+ return coverImage;
153
+ }
154
+ const base = withBase("/");
155
+ if (base && base !== "/" && coverImage.startsWith(base)) {
149
156
  return coverImage;
150
157
  }
151
- return `/images/${coverImage}`;
158
+ const path = coverImage.startsWith("/")
159
+ ? coverImage
160
+ : `/images/${coverImage}`;
161
+ return withBase(path);
152
162
  }
153
163
 
154
164
  // Format publication date
@@ -18,7 +18,7 @@
18
18
  v-if="primaryButton"
19
19
  class="button extra small-margin responsive-mobile"
20
20
  :class="dark !== undefined ? 'surface' : 'primary'"
21
- :href="primaryLink"
21
+ :href="resolvedPrimaryLink"
22
22
  @click="
23
23
  trackEvent(['CTA', 'Click', 'CTA Section Primary', primaryButton])
24
24
  "
@@ -27,7 +27,7 @@
27
27
  <a
28
28
  v-if="secondaryButton"
29
29
  class="button extra small-margin secondary responsive-mobile"
30
- :href="secondaryLink"
30
+ :href="resolvedSecondaryLink"
31
31
  @click="
32
32
  trackEvent(['CTA', 'Click', 'CTA Section Secondary', secondaryButton])
33
33
  "
@@ -37,7 +37,7 @@
37
37
  v-if="altButton"
38
38
  class="button border extra small-margin responsive-mobile"
39
39
  :class="dark !== undefined ? 'white-text' : ''"
40
- :href="altLink"
40
+ :href="resolvedAltLink"
41
41
  @click="trackEvent(['CTA', 'Click', 'CTA Section Alt', altButton])"
42
42
  >{{ altButton }}</a
43
43
  >
@@ -49,6 +49,8 @@
49
49
  </template>
50
50
 
51
51
  <script setup>
52
+ import { computed } from "vue";
53
+ import { withBase } from "vitepress";
52
54
  import { trackEvent } from "../helpers";
53
55
  const props = defineProps([
54
56
  "dark",
@@ -61,6 +63,18 @@ const props = defineProps([
61
63
  "tagline",
62
64
  "title",
63
65
  ]);
66
+
67
+ function resolveLink(link) {
68
+ if (!link) return "";
69
+ if (link.startsWith("http") || link.startsWith("//")) return link;
70
+ const base = withBase("/");
71
+ if (base && base !== "/" && link.startsWith(base)) return link;
72
+ return link.startsWith("/") ? withBase(link) : withBase("/" + link);
73
+ }
74
+
75
+ const resolvedPrimaryLink = computed(() => resolveLink(props.primaryLink));
76
+ const resolvedSecondaryLink = computed(() => resolveLink(props.secondaryLink));
77
+ const resolvedAltLink = computed(() => resolveLink(props.altLink));
64
78
  </script>
65
79
 
66
80
  <style>
@@ -1,5 +1,6 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
+ import { withBase } from "vitepress";
3
4
  import { data as authorsList } from "../../authors.data.js";
4
5
  import { getTagColor } from "../../tagUtils.js";
5
6
 
@@ -53,6 +54,22 @@ const props = defineProps({
53
54
  },
54
55
  });
55
56
 
57
+ function resolveUrl(url) {
58
+ if (!url) return "";
59
+ if (url.startsWith("http") || url.startsWith("//")) return url;
60
+ const base = withBase("/");
61
+ if (base && base !== "/" && url.startsWith(base)) return url;
62
+ return url.startsWith("/") ? withBase(url) : withBase("/" + url);
63
+ }
64
+
65
+ const resolvedImage = computed(() => resolveUrl(props.image));
66
+ const resolvedLinkHref = computed(() =>
67
+ props.link?.href ? resolveUrl(props.link.href) : undefined,
68
+ );
69
+ const resolvedSecondaryLinkHref = computed(() =>
70
+ props.secondaryLink?.href ? resolveUrl(props.secondaryLink.href) : undefined,
71
+ );
72
+
56
73
  const iconStyle = {
57
74
  width: (props.icon?.width ?? 40) + "px",
58
75
  height: (props.icon?.height ?? 40) + "px",
@@ -133,8 +150,13 @@ function formatDate(dateString) {
133
150
  ]"
134
151
  >
135
152
  <!-- Cover Image for cover/blog/rich cards -->
136
- <a v-if="isCoverLayout" :href="link?.href" class="card-cover-link">
137
- <img :src="image" alt="" class="card-cover-image" loading="lazy" />
153
+ <a v-if="isCoverLayout" :href="resolvedLinkHref" class="card-cover-link">
154
+ <img
155
+ :src="resolvedImage"
156
+ alt=""
157
+ class="card-cover-image"
158
+ loading="lazy"
159
+ />
138
160
  </a>
139
161
 
140
162
  <div class="card-content-wrapper">
@@ -151,7 +173,7 @@ function formatDate(dateString) {
151
173
  <!-- Render small icon image only if NOT rendering a full cover image -->
152
174
  <img
153
175
  v-else-if="image && !isCoverLayout"
154
- :src="image"
176
+ :src="resolvedImage"
155
177
  alt=""
156
178
  class="icon"
157
179
  />
@@ -172,7 +194,7 @@ function formatDate(dateString) {
172
194
  :key="authorId"
173
195
  class="author-item"
174
196
  >
175
- <a :href="`/author/${authorId}/`" class="author-link">{{
197
+ <a :href="withBase(`/author/${authorId}/`)" class="author-link">{{
176
198
  getAuthorName(authorId)
177
199
  }}</a
178
200
  ><span v-if="idx < authors.length - 1" class="author-separator"
@@ -187,7 +209,13 @@ function formatDate(dateString) {
187
209
  <a
188
210
  v-for="chip in chips"
189
211
  :key="chip.text"
190
- :href="chip.link || chip.href || `/tag/${chip.text}/`"
212
+ :href="
213
+ chip.link
214
+ ? resolveUrl(chip.link)
215
+ : chip.href
216
+ ? resolveUrl(chip.href)
217
+ : withBase(`/tag/${chip.text}/`)
218
+ "
191
219
  :style="getTagStyle(chip.text)"
192
220
  class="tag-link"
193
221
  >
@@ -197,7 +225,7 @@ function formatDate(dateString) {
197
225
  </div>
198
226
 
199
227
  <h5 class="small card-title-text">
200
- <a v-if="link?.href" :href="link.href">{{ title }}</a>
228
+ <a v-if="resolvedLinkHref" :href="resolvedLinkHref">{{ title }}</a>
201
229
  <span v-else>{{ title }}</span>
202
230
  </h5>
203
231
 
@@ -210,7 +238,13 @@ function formatDate(dateString) {
210
238
  <template v-for="chip in chips" :key="chip.text">
211
239
  <a
212
240
  v-if="chip.link || chip.href"
213
- :href="chip.link || chip.href"
241
+ :href="
242
+ chip.link
243
+ ? resolveUrl(chip.link)
244
+ : chip.href
245
+ ? resolveUrl(chip.href)
246
+ : undefined
247
+ "
214
248
  :style="getTagStyle(chip.text)"
215
249
  class="chip small-chip border clickable-chip"
216
250
  :class="chip.class"
@@ -260,7 +294,7 @@ function formatDate(dateString) {
260
294
  >
261
295
  <a
262
296
  v-if="link && !!link.text"
263
- :href="link.href"
297
+ :href="resolvedLinkHref"
264
298
  :target="link.target ?? '_blank'"
265
299
  class="button transparent bold primary-text no-padding"
266
300
  >
@@ -271,7 +305,7 @@ function formatDate(dateString) {
271
305
  </a>
272
306
  <a
273
307
  v-if="secondaryLink"
274
- :href="secondaryLink.href"
308
+ :href="resolvedSecondaryLinkHref"
275
309
  :target="secondaryLink.target ?? '_blank'"
276
310
  class="button transparent primary-text no-padding secondary-link"
277
311
  >
@@ -1,5 +1,6 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
+ import { withBase } from "vitepress";
3
4
 
4
5
  const props = defineProps({
5
6
  title: String,
@@ -41,6 +42,22 @@ const props = defineProps({
41
42
  },
42
43
  });
43
44
 
45
+ function resolveUrl(url) {
46
+ if (!url) return "";
47
+ if (url.startsWith("http") || url.startsWith("//")) return url;
48
+ const base = withBase("/");
49
+ if (base && base !== "/" && url.startsWith(base)) return url;
50
+ return url.startsWith("/") ? withBase(url) : withBase("/" + url);
51
+ }
52
+
53
+ const resolvedImage = computed(() => resolveUrl(props.image));
54
+ const resolvedLinkHref = computed(() =>
55
+ props.link?.href ? resolveUrl(props.link.href) : undefined,
56
+ );
57
+ const resolvedSecondaryLinkHref = computed(() =>
58
+ props.secondaryLink?.href ? resolveUrl(props.secondaryLink.href) : undefined,
59
+ );
60
+
44
61
  const cardStyle = computed(() => ({
45
62
  minHeight: props.minHeight,
46
63
  }));
@@ -52,7 +69,12 @@ const cardStyle = computed(() => ({
52
69
  :class="link && !link.text ? 'small-elevate' : 'no-elevate'"
53
70
  :style="cardStyle"
54
71
  >
55
- <img v-if="image" :src="image" alt="" class="image-overlay-card-image" />
72
+ <img
73
+ v-if="image"
74
+ :src="resolvedImage"
75
+ alt=""
76
+ class="image-overlay-card-image"
77
+ />
56
78
  <div class="image-overlay-card-overlay"></div>
57
79
  <div class="image-overlay-card-content padding">
58
80
  <div style="padding-top: 3rem">
@@ -103,7 +125,7 @@ const cardStyle = computed(() => ({
103
125
  <a
104
126
  v-if="link && link.text"
105
127
  class="button small white black-text"
106
- :href="link.href"
128
+ :href="resolvedLinkHref"
107
129
  :target="link.target ?? '_blank'"
108
130
  >
109
131
  {{ link.text }}
@@ -111,7 +133,7 @@ const cardStyle = computed(() => ({
111
133
  <a
112
134
  v-if="secondaryLink"
113
135
  class="button small border white-text secondary-link"
114
- :href="secondaryLink.href"
136
+ :href="resolvedSecondaryLinkHref"
115
137
  :target="secondaryLink.target ?? '_blank'"
116
138
  >
117
139
  {{ secondaryLink.text }}
@@ -63,9 +63,36 @@ const resolveCardComponent = (variant) => {
63
63
 
64
64
  const { page, site } = useData();
65
65
 
66
+ function resolveUrl(url) {
67
+ if (!url) return "";
68
+ if (url.startsWith("http") || url.startsWith("//")) return url;
69
+ const base = withBase("/");
70
+ if (base && base !== "/" && url.startsWith(base)) return url;
71
+ return url.startsWith("/") ? withBase(url) : withBase("/" + url);
72
+ }
73
+
74
+ function normalizeFeature(feature) {
75
+ return {
76
+ ...feature,
77
+ image: resolveUrl(feature.image),
78
+ link: feature.link
79
+ ? {
80
+ ...feature.link,
81
+ href: resolveUrl(feature.link.href),
82
+ }
83
+ : undefined,
84
+ secondaryLink: feature.secondaryLink
85
+ ? {
86
+ ...feature.secondaryLink,
87
+ href: resolveUrl(feature.secondaryLink.href),
88
+ }
89
+ : undefined,
90
+ };
91
+ }
92
+
66
93
  const featuresExcerpts =
67
94
  cards && cards.length
68
- ? cards
95
+ ? cards.map(normalizeFeature)
69
96
  : features
70
97
  .map((f) => {
71
98
  if (import.meta.env.SSR) {
@@ -89,7 +116,7 @@ const featuresExcerpts =
89
116
  }
90
117
  : undefined,
91
118
  link: {
92
- href: f.url,
119
+ href: withBase(f.url),
93
120
  text: "Read more",
94
121
  target: "_self",
95
122
  },
@@ -14,7 +14,10 @@
14
14
  <a
15
15
  v-if="theme.nav.find((i) => i.link && i.link.includes('contact'))"
16
16
  :href="
17
- theme.nav.find((i) => i.link && i.link.includes('contact')).link
17
+ withBase(
18
+ theme.nav.find((i) => i.link && i.link.includes('contact'))
19
+ .link,
20
+ )
18
21
  "
19
22
  class="button small border no-margin"
20
23
  style="color: var(--on-surface)"
@@ -89,7 +92,7 @@
89
92
  >
90
93
  </p>
91
94
  <p v-if="theme.theme.brandConfig?.analytics">
92
- <a href="/cookie-settings" class="link">{{
95
+ <a :href="withBase('/cookie-settings')" class="link">{{
93
96
  t("Cookie settings", theme.i18n)
94
97
  }}</a>
95
98
  </p>
@@ -79,6 +79,7 @@
79
79
 
80
80
  <script setup>
81
81
  import { computed, ref } from "vue";
82
+ import { withBase } from "vitepress";
82
83
 
83
84
  const props = defineProps({
84
85
  images: {
@@ -90,14 +91,22 @@ const props = defineProps({
90
91
  const container = ref(null);
91
92
  const activeIndex = ref(0);
92
93
 
94
+ function resolveUrl(url) {
95
+ if (!url) return "";
96
+ if (url.startsWith("http") || url.startsWith("//")) return url;
97
+ const base = withBase("/");
98
+ if (base && base !== "/" && url.startsWith(base)) return url;
99
+ return url.startsWith("/") ? withBase(url) : withBase("/" + url);
100
+ }
101
+
93
102
  const normalizedImages = computed(() => {
94
103
  if (!props.images) return [];
95
104
  return props.images.map((img) => {
96
105
  if (typeof img === "string") {
97
- return { src: img, alt: "", caption: "" };
106
+ return { src: resolveUrl(img), alt: "", caption: "" };
98
107
  }
99
108
  return {
100
- src: img.src || "",
109
+ src: resolveUrl(img.src),
101
110
  alt: img.alt || "",
102
111
  caption: img.caption || "",
103
112
  };
@@ -9,7 +9,7 @@
9
9
  >
10
10
  <!-- Background Image (Original/Right) -->
11
11
  <img
12
- :src="compare"
12
+ :src="resolvedCompare"
13
13
  :alt="alt || 'Image comparison background'"
14
14
  class="compare-img compare-bg"
15
15
  />
@@ -22,7 +22,7 @@
22
22
  }"
23
23
  >
24
24
  <img
25
- :src="src"
25
+ :src="resolvedSrc"
26
26
  :alt="alt || 'Image comparison foreground'"
27
27
  class="compare-img compare-fg"
28
28
  />
@@ -61,7 +61,7 @@
61
61
  <!-- Standard Image Mode -->
62
62
  <img
63
63
  v-else
64
- :src="src"
64
+ :src="resolvedSrc"
65
65
  :alt="alt || 'Post image'"
66
66
  :style="{ maxWidth: width || '100%' }"
67
67
  class="standard-img"
@@ -78,7 +78,8 @@
78
78
  </template>
79
79
 
80
80
  <script setup>
81
- import { ref } from "vue";
81
+ import { ref, computed } from "vue";
82
+ import { withBase } from "vitepress";
82
83
 
83
84
  const props = defineProps({
84
85
  src: {
@@ -103,6 +104,17 @@ const props = defineProps({
103
104
  },
104
105
  });
105
106
 
107
+ function resolveUrl(url) {
108
+ if (!url) return "";
109
+ if (url.startsWith("http") || url.startsWith("//")) return url;
110
+ const base = withBase("/");
111
+ if (base && base !== "/" && url.startsWith(base)) return url;
112
+ return url.startsWith("/") ? withBase(url) : withBase("/" + url);
113
+ }
114
+
115
+ const resolvedSrc = computed(() => resolveUrl(props.src));
116
+ const resolvedCompare = computed(() => resolveUrl(props.compare));
117
+
106
118
  const sliderValue = ref(50);
107
119
  </script>
108
120
 
@@ -170,6 +170,7 @@
170
170
 
171
171
  <script setup>
172
172
  import { computed, ref, onMounted, onUnmounted } from "vue";
173
+ import { withBase } from "vitepress";
173
174
 
174
175
  const props = defineProps({
175
176
  images: {
@@ -192,6 +193,14 @@ const props = defineProps({
192
193
 
193
194
  const lightboxIndex = ref(null);
194
195
 
196
+ function resolveUrl(url) {
197
+ if (!url) return "";
198
+ if (url.startsWith("http") || url.startsWith("//")) return url;
199
+ const base = withBase("/");
200
+ if (base && base !== "/" && url.startsWith(base)) return url;
201
+ return url.startsWith("/") ? withBase(url) : withBase("/" + url);
202
+ }
203
+
195
204
  const layoutMode = computed(() => {
196
205
  // If explicitly 'grid', or if we detect link in image objects, default to grid
197
206
  if (props.layout === "grid") return "grid";
@@ -211,13 +220,23 @@ const normalizedImages = computed(() => {
211
220
  if (Array.isArray(props.images)) {
212
221
  return props.images.map((img) => {
213
222
  if (typeof img === "string") {
214
- return { src: img, alt: "", caption: "", link: "", width: "" };
223
+ return {
224
+ src: resolveUrl(img),
225
+ alt: "",
226
+ caption: "",
227
+ link: "",
228
+ width: "",
229
+ };
215
230
  }
216
231
  return {
217
- src: img.src || "",
232
+ src: resolveUrl(img.src),
218
233
  alt: img.alt || "",
219
234
  caption: img.caption || "",
220
- link: img.link || "",
235
+ link: img.link
236
+ ? img.link.startsWith("/")
237
+ ? withBase(img.link)
238
+ : img.link
239
+ : "",
221
240
  width: img.width || "",
222
241
  };
223
242
  });
@@ -227,7 +246,13 @@ const normalizedImages = computed(() => {
227
246
  .split(",")
228
247
  .map((img) => img.trim())
229
248
  .filter(Boolean)
230
- .map((src) => ({ src, alt: "", caption: "", link: "", width: "" }));
249
+ .map((src) => ({
250
+ src: resolveUrl(src),
251
+ alt: "",
252
+ caption: "",
253
+ link: "",
254
+ width: "",
255
+ }));
231
256
  }
232
257
  return [];
233
258
  });
@@ -2,7 +2,8 @@
2
2
  <section class="logo-section">
3
3
  <div ref="logo-row" class="logo-row">
4
4
  <component
5
- v-for="logo in logos"
5
+ v-for="logo in normalizedLogos"
6
+ :key="logo.alt"
6
7
  :is="logo.link ? 'a' : 'div'"
7
8
  :href="logo.link || undefined"
8
9
  :target="logo.target || undefined"
@@ -15,11 +16,29 @@
15
16
  </template>
16
17
 
17
18
  <script setup>
18
- import { useTemplateRef, onMounted } from "vue";
19
+ import { useTemplateRef, onMounted, computed } from "vue";
20
+ import { withBase } from "vitepress";
19
21
 
20
22
  const props = defineProps(["baseHeight", "logos", "strength"]);
21
23
  const logoRow = useTemplateRef("logo-row");
22
24
 
25
+ function resolveUrl(url) {
26
+ if (!url) return "";
27
+ if (url.startsWith("http") || url.startsWith("//")) return url;
28
+ const base = withBase("/");
29
+ if (base && base !== "/" && url.startsWith(base)) return url;
30
+ return url.startsWith("/") ? withBase(url) : withBase("/" + url);
31
+ }
32
+
33
+ const normalizedLogos = computed(() => {
34
+ if (!props.logos) return [];
35
+ return props.logos.map((logo) => ({
36
+ ...logo,
37
+ image: resolveUrl(logo.image),
38
+ link: logo.link ? resolveUrl(logo.link) : undefined,
39
+ }));
40
+ });
41
+
23
42
  onMounted(() => {
24
43
  // Function to update CSS variables and display values
25
44
  function updateVariables() {
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <div class="top-nav at-top row center-align">
3
3
  <nav class="large-padding no-margin center-align nav-mobile">
4
- <a href="/">
4
+ <a :href="withBase('/')">
5
5
  <img
6
6
  :src="withBase(theme.logo.light)"
7
7
  :alt="`${site.title} logo`"
@@ -20,7 +20,7 @@
20
20
  </button>
21
21
  <dialog id="mobile-menu" class="max">
22
22
  <nav>
23
- <a data-ui="#mobile-menu" href="/">
23
+ <a data-ui="#mobile-menu" :href="withBase('/')">
24
24
  <img
25
25
  :src="withBase(theme.logo.light)"
26
26
  :alt="`${site.title} logo`"
@@ -119,7 +119,7 @@
119
119
  </dialog>
120
120
  </nav>
121
121
  <nav class="large-padding no-margin center-align row holder nav-desktop">
122
- <a href="/">
122
+ <a :href="withBase('/')">
123
123
  <img
124
124
  :src="withBase(theme.logo.light)"
125
125
  :alt="`${site.title} logo`"
@@ -239,7 +239,7 @@ const langs = computed(() => {
239
239
  }
240
240
  return Object.entries(locales).map(([id, locale]) => {
241
241
  const currentPath = route.path;
242
- const base = withBase("");
242
+ const base = withBase("/");
243
243
  let pathRelativeToBase = currentPath;
244
244
  if (base !== "/" && currentPath.startsWith(base)) {
245
245
  pathRelativeToBase = currentPath.substring(base.length);
@@ -13,7 +13,7 @@
13
13
  <a
14
14
  v-for="tag in allTagsList"
15
15
  :key="tag.name"
16
- :href="`/tag/${tag.name}/`"
16
+ :href="withBase(`/tag/${tag.name}/`)"
17
17
  :style="getTagStyle(tag.name)"
18
18
  class="tag-item"
19
19
  >
@@ -58,7 +58,7 @@
58
58
  </ul>
59
59
  <p class="legend-note">
60
60
  For more detailed information on our technology solutions, visit the
61
- <a href="/software-products" class="legend-link"
61
+ <a :href="withBase('/solutions')" class="legend-link"
62
62
  >Solutions & Services</a
63
63
  >
64
64
  page.
@@ -69,6 +69,7 @@
69
69
 
70
70
  <script setup>
71
71
  import { computed } from "vue";
72
+ import { withBase } from "vitepress";
72
73
  import { data as posts } from "../posts.data.js";
73
74
  import { getTagColor, getTagStyle } from "../tagUtils.js";
74
75