@eox/pages-theme-eox 2.0.0-alpha.3 → 2.0.0-alpha.4
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 +1 -1
- package/src/components/BlogList.vue +17 -7
- package/src/components/BlogPost.vue +13 -7
- package/src/components/CTASection.vue +15 -3
- package/src/components/FeatureCard/Index.vue +41 -9
- package/src/components/FeatureCard/Poster.vue +23 -3
- package/src/components/FeaturesGallery.vue +31 -2
- package/src/components/Footer.vue +5 -2
- package/src/components/ImageCarousel.vue +9 -2
- package/src/components/ImageElement.vue +14 -4
- package/src/components/ImageGallery.vue +27 -4
- package/src/components/LogoSection.vue +19 -2
- package/src/components/NavBar.vue +3 -3
- package/src/components/TagList.vue +3 -2
package/package.json
CHANGED
|
@@ -49,10 +49,17 @@
|
|
|
49
49
|
"
|
|
50
50
|
:date="post.date"
|
|
51
51
|
:authors="post.authors"
|
|
52
|
-
:chips="
|
|
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,13 @@ 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("
|
|
208
|
+
if (coverImage.startsWith("http") || coverImage.startsWith("//")) {
|
|
202
209
|
return coverImage;
|
|
203
210
|
}
|
|
204
|
-
|
|
211
|
+
const path = coverImage.startsWith("/")
|
|
212
|
+
? coverImage
|
|
213
|
+
: `/images/${coverImage}`;
|
|
214
|
+
return withBase(path);
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
const tagFromParam = computed(() => {
|
|
@@ -40,7 +40,10 @@
|
|
|
40
40
|
:key="authorId"
|
|
41
41
|
class="author-item"
|
|
42
42
|
>
|
|
43
|
-
<a
|
|
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,13 @@ 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("
|
|
151
|
+
if (coverImage.startsWith("http") || coverImage.startsWith("//")) {
|
|
149
152
|
return coverImage;
|
|
150
153
|
}
|
|
151
|
-
|
|
154
|
+
const path = coverImage.startsWith("/")
|
|
155
|
+
? coverImage
|
|
156
|
+
: `/images/${coverImage}`;
|
|
157
|
+
return withBase(path);
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
// 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="
|
|
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="
|
|
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="
|
|
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,16 @@ 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
|
+
return link.startsWith("/") ? withBase(link) : withBase("/" + link);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const resolvedPrimaryLink = computed(() => resolveLink(props.primaryLink));
|
|
74
|
+
const resolvedSecondaryLink = computed(() => resolveLink(props.secondaryLink));
|
|
75
|
+
const resolvedAltLink = computed(() => resolveLink(props.altLink));
|
|
64
76
|
</script>
|
|
65
77
|
|
|
66
78
|
<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,20 @@ 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
|
+
return url.startsWith("/") ? withBase(url) : withBase("/" + url);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const resolvedImage = computed(() => resolveUrl(props.image));
|
|
64
|
+
const resolvedLinkHref = computed(() =>
|
|
65
|
+
props.link?.href ? resolveUrl(props.link.href) : undefined,
|
|
66
|
+
);
|
|
67
|
+
const resolvedSecondaryLinkHref = computed(() =>
|
|
68
|
+
props.secondaryLink?.href ? resolveUrl(props.secondaryLink.href) : undefined,
|
|
69
|
+
);
|
|
70
|
+
|
|
56
71
|
const iconStyle = {
|
|
57
72
|
width: (props.icon?.width ?? 40) + "px",
|
|
58
73
|
height: (props.icon?.height ?? 40) + "px",
|
|
@@ -133,8 +148,13 @@ function formatDate(dateString) {
|
|
|
133
148
|
]"
|
|
134
149
|
>
|
|
135
150
|
<!-- Cover Image for cover/blog/rich cards -->
|
|
136
|
-
<a v-if="isCoverLayout" :href="
|
|
137
|
-
<img
|
|
151
|
+
<a v-if="isCoverLayout" :href="resolvedLinkHref" class="card-cover-link">
|
|
152
|
+
<img
|
|
153
|
+
:src="resolvedImage"
|
|
154
|
+
alt=""
|
|
155
|
+
class="card-cover-image"
|
|
156
|
+
loading="lazy"
|
|
157
|
+
/>
|
|
138
158
|
</a>
|
|
139
159
|
|
|
140
160
|
<div class="card-content-wrapper">
|
|
@@ -151,7 +171,7 @@ function formatDate(dateString) {
|
|
|
151
171
|
<!-- Render small icon image only if NOT rendering a full cover image -->
|
|
152
172
|
<img
|
|
153
173
|
v-else-if="image && !isCoverLayout"
|
|
154
|
-
:src="
|
|
174
|
+
:src="resolvedImage"
|
|
155
175
|
alt=""
|
|
156
176
|
class="icon"
|
|
157
177
|
/>
|
|
@@ -172,7 +192,7 @@ function formatDate(dateString) {
|
|
|
172
192
|
:key="authorId"
|
|
173
193
|
class="author-item"
|
|
174
194
|
>
|
|
175
|
-
<a :href="`/author/${authorId}/`" class="author-link">{{
|
|
195
|
+
<a :href="withBase(`/author/${authorId}/`)" class="author-link">{{
|
|
176
196
|
getAuthorName(authorId)
|
|
177
197
|
}}</a
|
|
178
198
|
><span v-if="idx < authors.length - 1" class="author-separator"
|
|
@@ -187,7 +207,13 @@ function formatDate(dateString) {
|
|
|
187
207
|
<a
|
|
188
208
|
v-for="chip in chips"
|
|
189
209
|
:key="chip.text"
|
|
190
|
-
:href="
|
|
210
|
+
:href="
|
|
211
|
+
chip.link
|
|
212
|
+
? resolveUrl(chip.link)
|
|
213
|
+
: chip.href
|
|
214
|
+
? resolveUrl(chip.href)
|
|
215
|
+
: withBase(`/tag/${chip.text}/`)
|
|
216
|
+
"
|
|
191
217
|
:style="getTagStyle(chip.text)"
|
|
192
218
|
class="tag-link"
|
|
193
219
|
>
|
|
@@ -197,7 +223,7 @@ function formatDate(dateString) {
|
|
|
197
223
|
</div>
|
|
198
224
|
|
|
199
225
|
<h5 class="small card-title-text">
|
|
200
|
-
<a v-if="
|
|
226
|
+
<a v-if="resolvedLinkHref" :href="resolvedLinkHref">{{ title }}</a>
|
|
201
227
|
<span v-else>{{ title }}</span>
|
|
202
228
|
</h5>
|
|
203
229
|
|
|
@@ -210,7 +236,13 @@ function formatDate(dateString) {
|
|
|
210
236
|
<template v-for="chip in chips" :key="chip.text">
|
|
211
237
|
<a
|
|
212
238
|
v-if="chip.link || chip.href"
|
|
213
|
-
:href="
|
|
239
|
+
:href="
|
|
240
|
+
chip.link
|
|
241
|
+
? resolveUrl(chip.link)
|
|
242
|
+
: chip.href
|
|
243
|
+
? resolveUrl(chip.href)
|
|
244
|
+
: undefined
|
|
245
|
+
"
|
|
214
246
|
:style="getTagStyle(chip.text)"
|
|
215
247
|
class="chip small-chip border clickable-chip"
|
|
216
248
|
:class="chip.class"
|
|
@@ -260,7 +292,7 @@ function formatDate(dateString) {
|
|
|
260
292
|
>
|
|
261
293
|
<a
|
|
262
294
|
v-if="link && !!link.text"
|
|
263
|
-
:href="
|
|
295
|
+
:href="resolvedLinkHref"
|
|
264
296
|
:target="link.target ?? '_blank'"
|
|
265
297
|
class="button transparent bold primary-text no-padding"
|
|
266
298
|
>
|
|
@@ -271,7 +303,7 @@ function formatDate(dateString) {
|
|
|
271
303
|
</a>
|
|
272
304
|
<a
|
|
273
305
|
v-if="secondaryLink"
|
|
274
|
-
:href="
|
|
306
|
+
:href="resolvedSecondaryLinkHref"
|
|
275
307
|
:target="secondaryLink.target ?? '_blank'"
|
|
276
308
|
class="button transparent primary-text no-padding secondary-link"
|
|
277
309
|
>
|
|
@@ -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,20 @@ 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
|
+
return url.startsWith("/") ? withBase(url) : withBase("/" + url);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const resolvedImage = computed(() => resolveUrl(props.image));
|
|
52
|
+
const resolvedLinkHref = computed(() =>
|
|
53
|
+
props.link?.href ? resolveUrl(props.link.href) : undefined,
|
|
54
|
+
);
|
|
55
|
+
const resolvedSecondaryLinkHref = computed(() =>
|
|
56
|
+
props.secondaryLink?.href ? resolveUrl(props.secondaryLink.href) : undefined,
|
|
57
|
+
);
|
|
58
|
+
|
|
44
59
|
const cardStyle = computed(() => ({
|
|
45
60
|
minHeight: props.minHeight,
|
|
46
61
|
}));
|
|
@@ -52,7 +67,12 @@ const cardStyle = computed(() => ({
|
|
|
52
67
|
:class="link && !link.text ? 'small-elevate' : 'no-elevate'"
|
|
53
68
|
:style="cardStyle"
|
|
54
69
|
>
|
|
55
|
-
<img
|
|
70
|
+
<img
|
|
71
|
+
v-if="image"
|
|
72
|
+
:src="resolvedImage"
|
|
73
|
+
alt=""
|
|
74
|
+
class="image-overlay-card-image"
|
|
75
|
+
/>
|
|
56
76
|
<div class="image-overlay-card-overlay"></div>
|
|
57
77
|
<div class="image-overlay-card-content padding">
|
|
58
78
|
<div style="padding-top: 3rem">
|
|
@@ -103,7 +123,7 @@ const cardStyle = computed(() => ({
|
|
|
103
123
|
<a
|
|
104
124
|
v-if="link && link.text"
|
|
105
125
|
class="button small white black-text"
|
|
106
|
-
:href="
|
|
126
|
+
:href="resolvedLinkHref"
|
|
107
127
|
:target="link.target ?? '_blank'"
|
|
108
128
|
>
|
|
109
129
|
{{ link.text }}
|
|
@@ -111,7 +131,7 @@ const cardStyle = computed(() => ({
|
|
|
111
131
|
<a
|
|
112
132
|
v-if="secondaryLink"
|
|
113
133
|
class="button small border white-text secondary-link"
|
|
114
|
-
:href="
|
|
134
|
+
:href="resolvedSecondaryLinkHref"
|
|
115
135
|
:target="secondaryLink.target ?? '_blank'"
|
|
116
136
|
>
|
|
117
137
|
{{ secondaryLink.text }}
|
|
@@ -63,9 +63,38 @@ const resolveCardComponent = (variant) => {
|
|
|
63
63
|
|
|
64
64
|
const { page, site } = useData();
|
|
65
65
|
|
|
66
|
+
function normalizeFeature(feature) {
|
|
67
|
+
return {
|
|
68
|
+
...feature,
|
|
69
|
+
image:
|
|
70
|
+
feature.image && feature.image.startsWith("/")
|
|
71
|
+
? withBase(feature.image)
|
|
72
|
+
: feature.image,
|
|
73
|
+
link: feature.link
|
|
74
|
+
? {
|
|
75
|
+
...feature.link,
|
|
76
|
+
href:
|
|
77
|
+
feature.link.href && feature.link.href.startsWith("/")
|
|
78
|
+
? withBase(feature.link.href)
|
|
79
|
+
: feature.link.href,
|
|
80
|
+
}
|
|
81
|
+
: undefined,
|
|
82
|
+
secondaryLink: feature.secondaryLink
|
|
83
|
+
? {
|
|
84
|
+
...feature.secondaryLink,
|
|
85
|
+
href:
|
|
86
|
+
feature.secondaryLink.href &&
|
|
87
|
+
feature.secondaryLink.href.startsWith("/")
|
|
88
|
+
? withBase(feature.secondaryLink.href)
|
|
89
|
+
: feature.secondaryLink.href,
|
|
90
|
+
}
|
|
91
|
+
: undefined,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
66
95
|
const featuresExcerpts =
|
|
67
96
|
cards && cards.length
|
|
68
|
-
? cards
|
|
97
|
+
? cards.map(normalizeFeature)
|
|
69
98
|
: features
|
|
70
99
|
.map((f) => {
|
|
71
100
|
if (import.meta.env.SSR) {
|
|
@@ -89,7 +118,7 @@ const featuresExcerpts =
|
|
|
89
118
|
}
|
|
90
119
|
: undefined,
|
|
91
120
|
link: {
|
|
92
|
-
href: f.url,
|
|
121
|
+
href: withBase(f.url),
|
|
93
122
|
text: "Read more",
|
|
94
123
|
target: "_self",
|
|
95
124
|
},
|
|
@@ -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
|
-
|
|
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,20 @@ 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
|
+
return url.startsWith("/") ? withBase(url) : withBase("/" + url);
|
|
98
|
+
}
|
|
99
|
+
|
|
93
100
|
const normalizedImages = computed(() => {
|
|
94
101
|
if (!props.images) return [];
|
|
95
102
|
return props.images.map((img) => {
|
|
96
103
|
if (typeof img === "string") {
|
|
97
|
-
return { src: img, alt: "", caption: "" };
|
|
104
|
+
return { src: resolveUrl(img), alt: "", caption: "" };
|
|
98
105
|
}
|
|
99
106
|
return {
|
|
100
|
-
src: img.src
|
|
107
|
+
src: resolveUrl(img.src),
|
|
101
108
|
alt: img.alt || "",
|
|
102
109
|
caption: img.caption || "",
|
|
103
110
|
};
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
>
|
|
10
10
|
<!-- Background Image (Original/Right) -->
|
|
11
11
|
<img
|
|
12
|
-
:src="
|
|
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="
|
|
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="
|
|
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,15 @@ 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
|
+
return url.startsWith("/") ? withBase(url) : withBase("/" + url);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const resolvedSrc = computed(() => resolveUrl(props.src));
|
|
114
|
+
const resolvedCompare = computed(() => resolveUrl(props.compare));
|
|
115
|
+
|
|
106
116
|
const sliderValue = ref(50);
|
|
107
117
|
</script>
|
|
108
118
|
|
|
@@ -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,12 @@ 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
|
+
return url.startsWith("/") ? withBase(url) : withBase("/" + url);
|
|
200
|
+
}
|
|
201
|
+
|
|
195
202
|
const layoutMode = computed(() => {
|
|
196
203
|
// If explicitly 'grid', or if we detect link in image objects, default to grid
|
|
197
204
|
if (props.layout === "grid") return "grid";
|
|
@@ -211,13 +218,23 @@ const normalizedImages = computed(() => {
|
|
|
211
218
|
if (Array.isArray(props.images)) {
|
|
212
219
|
return props.images.map((img) => {
|
|
213
220
|
if (typeof img === "string") {
|
|
214
|
-
return {
|
|
221
|
+
return {
|
|
222
|
+
src: resolveUrl(img),
|
|
223
|
+
alt: "",
|
|
224
|
+
caption: "",
|
|
225
|
+
link: "",
|
|
226
|
+
width: "",
|
|
227
|
+
};
|
|
215
228
|
}
|
|
216
229
|
return {
|
|
217
|
-
src: img.src
|
|
230
|
+
src: resolveUrl(img.src),
|
|
218
231
|
alt: img.alt || "",
|
|
219
232
|
caption: img.caption || "",
|
|
220
|
-
link: img.link
|
|
233
|
+
link: img.link
|
|
234
|
+
? img.link.startsWith("/")
|
|
235
|
+
? withBase(img.link)
|
|
236
|
+
: img.link
|
|
237
|
+
: "",
|
|
221
238
|
width: img.width || "",
|
|
222
239
|
};
|
|
223
240
|
});
|
|
@@ -227,7 +244,13 @@ const normalizedImages = computed(() => {
|
|
|
227
244
|
.split(",")
|
|
228
245
|
.map((img) => img.trim())
|
|
229
246
|
.filter(Boolean)
|
|
230
|
-
.map((src) => ({
|
|
247
|
+
.map((src) => ({
|
|
248
|
+
src: resolveUrl(src),
|
|
249
|
+
alt: "",
|
|
250
|
+
caption: "",
|
|
251
|
+
link: "",
|
|
252
|
+
width: "",
|
|
253
|
+
}));
|
|
231
254
|
}
|
|
232
255
|
return [];
|
|
233
256
|
});
|
|
@@ -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
|
|
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,27 @@
|
|
|
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
|
+
return url.startsWith("/") ? withBase(url) : withBase("/" + url);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const normalizedLogos = computed(() => {
|
|
32
|
+
if (!props.logos) return [];
|
|
33
|
+
return props.logos.map((logo) => ({
|
|
34
|
+
...logo,
|
|
35
|
+
image: resolveUrl(logo.image),
|
|
36
|
+
link: logo.link ? resolveUrl(logo.link) : undefined,
|
|
37
|
+
}));
|
|
38
|
+
});
|
|
39
|
+
|
|
23
40
|
onMounted(() => {
|
|
24
41
|
// Function to update CSS variables and display values
|
|
25
42
|
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`"
|
|
@@ -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="/
|
|
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
|
|