@eox/pages-theme-eox 2.0.0-alpha.2 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eox/pages-theme-eox",
3
- "version": "2.0.0-alpha.2",
3
+ "version": "2.0.0-alpha.4",
4
4
  "type": "module",
5
5
  "description": "Vitepress Theme with EOX branding",
6
6
  "main": "src/index.js",
@@ -4,9 +4,7 @@
4
4
  <div class="blog-landing-header" role="banner">
5
5
  <div class="flex flex-col md:flex-row md:items-end justify-between gap-6">
6
6
  <div>
7
- <h1 class="blog-landing-title">
8
- EOX Blog
9
- </h1>
7
+ <h1 class="blog-landing-title">EOX Blog</h1>
10
8
  <p class="blog-landing-subtitle">
11
9
  Insights, updates, and deep dives from our geospatial experts.
12
10
  </p>
@@ -14,10 +12,7 @@
14
12
  </div>
15
13
 
16
14
  <!-- Active Filter Banner -->
17
- <div
18
- v-if="activeTag || activeAuthor"
19
- class="active-filter-banner"
20
- >
15
+ <div v-if="activeTag || activeAuthor" class="active-filter-banner">
21
16
  <span class="filter-label">Active filter:</span>
22
17
  <span
23
18
  v-if="activeTag"
@@ -32,10 +27,7 @@
32
27
  >
33
28
  Author: {{ getAuthorName(activeAuthor) }}
34
29
  </span>
35
- <button
36
- @click="clearFilters"
37
- class="clear-filter-btn"
38
- >
30
+ <button @click="clearFilters" class="clear-filter-btn">
39
31
  <i class="mdi mdi-close-circle"></i>
40
32
  <span>Clear Filter</span>
41
33
  </button>
@@ -52,14 +44,23 @@
52
44
  :key="post.url"
53
45
  :title="post.title"
54
46
  :content="post.excerpt"
55
- :image="post.coverImage ? getCoverImageUrl(post.coverImage) : undefined"
47
+ :image="
48
+ post.coverImage ? getCoverImageUrl(post.coverImage) : undefined
49
+ "
56
50
  :date="post.date"
57
51
  :authors="post.authors"
58
- :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
+ "
59
60
  :link="{
60
61
  text: 'Read more',
61
- href: post.url,
62
- target: '_self'
62
+ href: withBase(post.url),
63
+ target: '_self',
63
64
  }"
64
65
  variant="cover"
65
66
  class="h-full bg-surface-container-low"
@@ -87,18 +88,18 @@
87
88
  <!-- Pagination -->
88
89
  <nav
89
90
  v-if="totalPages > 1"
90
- class="mt-16 flex justify-center items-center gap-2"
91
+ class="mt-16 flex justify-center items-center gap-1 sm:gap-2"
91
92
  >
92
93
  <button
93
94
  @click="changePage(currentPage - 1)"
94
95
  :disabled="currentPage === 1"
95
- class="p-2.5 rounded-xl border border-slate-200 text-slate-600 hover:bg-slate-50 disabled:opacity-40 disabled:hover:bg-transparent disabled:cursor-not-allowed transition-colors"
96
+ class="min-w-[32px] sm:min-w-[40px] h-[32px] sm:h-[40px] flex items-center justify-center rounded-xl border border-slate-200 text-slate-600 hover:bg-slate-50 disabled:opacity-40 disabled:hover:bg-transparent disabled:cursor-not-allowed transition-colors"
96
97
  >
97
98
  <span class="sr-only">Previous</span>
98
99
  <i class="mdi mdi-chevron-left text-lg"></i>
99
100
  </button>
100
101
 
101
- <div class="flex items-center gap-1.5">
102
+ <div class="flex items-center gap-1 sm:gap-1.5">
102
103
  <button
103
104
  v-for="page in visiblePages"
104
105
  :key="page"
@@ -108,7 +109,7 @@
108
109
  ? 'bg-primary text-white border-primary shadow-sm'
109
110
  : 'border-slate-200 text-slate-600 hover:bg-slate-50',
110
111
  ]"
111
- class="min-w-[40px] h-[40px] px-3 font-semibold text-sm rounded-xl border flex items-center justify-center transition-all duration-150"
112
+ class="min-w-[32px] sm:min-w-[40px] h-[32px] sm:h-[40px] px-2 sm:px-3 font-semibold text-sm rounded-xl border flex items-center justify-center transition-all duration-150"
112
113
  >
113
114
  {{ page }}
114
115
  </button>
@@ -117,7 +118,7 @@
117
118
  <button
118
119
  @click="changePage(currentPage + 1)"
119
120
  :disabled="currentPage === totalPages"
120
- class="p-2.5 rounded-xl border border-slate-200 text-slate-600 hover:bg-slate-50 disabled:opacity-40 disabled:hover:bg-transparent disabled:cursor-not-allowed transition-colors"
121
+ class="min-w-[32px] sm:min-w-[40px] h-[32px] sm:h-[40px] flex items-center justify-center rounded-xl border border-slate-200 text-slate-600 hover:bg-slate-50 disabled:opacity-40 disabled:hover:bg-transparent disabled:cursor-not-allowed transition-colors"
121
122
  >
122
123
  <span class="sr-only">Next</span>
123
124
  <i class="mdi mdi-chevron-right text-lg"></i>
@@ -129,9 +130,7 @@
129
130
  <aside class="blog-sidebar-col">
130
131
  <!-- Search widget -->
131
132
  <div class="sidebar-widget">
132
- <h3 class="sidebar-title">
133
- Search
134
- </h3>
133
+ <h3 class="sidebar-title">Search</h3>
135
134
  <div class="search-container">
136
135
  <VPNavBarSearch class="search" />
137
136
  </div>
@@ -140,10 +139,8 @@
140
139
  <!-- Hot Tags -->
141
140
  <div class="sidebar-widget">
142
141
  <div class="sidebar-title-container">
143
- <h3 class="sidebar-title-inline">
144
- Hot tags
145
- </h3>
146
- <a href="/tag" class="see-all-link">
142
+ <h3 class="sidebar-title-inline">Hot tags</h3>
143
+ <a :href="withBase('/tag')" class="see-all-link">
147
144
  <span>see all</span>
148
145
  <i class="mdi mdi-arrow-right"></i>
149
146
  </a>
@@ -152,7 +149,7 @@
152
149
  <a
153
150
  v-for="tag in calculatedHotTags"
154
151
  :key="tag.name"
155
- :href="`/tag/${tag.name}/`"
152
+ :href="withBase(`/tag/${tag.name}/`)"
156
153
  :style="getTagStyle(tag.name)"
157
154
  class="sidebar-tag"
158
155
  >
@@ -167,7 +164,7 @@
167
164
 
168
165
  <script setup>
169
166
  import { ref, computed, onMounted, watch } from "vue";
170
- import { useRouter, useData } from "vitepress";
167
+ import { useRouter, useData, withBase } from "vitepress";
171
168
  import { data as posts } from "../posts.data.js";
172
169
  import { data as authorsList } from "../authors.data.js";
173
170
  import { getTagColor, getTagStyle } from "../tagUtils.js";
@@ -208,10 +205,13 @@ const postsPerPage = 9;
208
205
  // Form cover image URL correctly (prefixing filename with /images/)
209
206
  function getCoverImageUrl(coverImage) {
210
207
  if (!coverImage) return "";
211
- if (coverImage.startsWith("/") || coverImage.startsWith("http")) {
208
+ if (coverImage.startsWith("http") || coverImage.startsWith("//")) {
212
209
  return coverImage;
213
210
  }
214
- return `/images/${coverImage}`;
211
+ const path = coverImage.startsWith("/")
212
+ ? coverImage
213
+ : `/images/${coverImage}`;
214
+ return withBase(path);
215
215
  }
216
216
 
217
217
  const tagFromParam = computed(() => {
@@ -522,7 +522,9 @@ function clearFilters() {
522
522
  border-radius: 4px !important;
523
523
  text-decoration: none !important;
524
524
  line-height: 1.2 !important;
525
- transition: opacity 0.2s ease, transform 0.1s ease !important;
525
+ transition:
526
+ opacity 0.2s ease,
527
+ transform 0.1s ease !important;
526
528
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) !important;
527
529
  }
528
530
 
@@ -584,7 +586,7 @@ function clearFilters() {
584
586
  padding: 0 !important;
585
587
  margin: 0 !important;
586
588
  margin-left: 0.5rem !important;
587
-
589
+
588
590
  display: inline-flex !important;
589
591
  align-items: center !important;
590
592
  gap: 0.375rem !important;
@@ -30,7 +30,7 @@
30
30
  {{ formatDate(frontmatter.date) }}
31
31
  </time>
32
32
  </span>
33
-
33
+
34
34
  <!-- Author Span -->
35
35
  <span v-if="authors && authors.length" class="metadata-item">
36
36
  <i class="mdi mdi-account-outline metadata-icon"></i>
@@ -41,12 +41,14 @@
41
41
  class="author-item"
42
42
  >
43
43
  <a
44
- :href="`/author/${authorId}/`"
44
+ :href="withBase(`/author/${authorId}/`)"
45
45
  class="author-link-active"
46
46
  >
47
47
  {{ getAuthorName(authorId) }}
48
48
  </a>
49
- <span v-if="idx < authors.length - 1" class="author-separator">,</span>
49
+ <span v-if="idx < authors.length - 1" class="author-separator"
50
+ >,</span
51
+ >
50
52
  </span>
51
53
  </span>
52
54
  </div>
@@ -59,7 +61,7 @@
59
61
  <a
60
62
  v-for="tag in frontmatter.tags"
61
63
  :key="tag"
62
- :href="`/tag/${tag}/`"
64
+ :href="withBase(`/tag/${tag}/`)"
63
65
  :style="getTagStyle(tag)"
64
66
  class="post-tag"
65
67
  >
@@ -77,23 +79,18 @@
77
79
  <!-- Sidebar Column -->
78
80
  <div class="blog-sidebar-col">
79
81
  <!-- Table of Contents (On This Page) -->
80
- <div
81
- v-if="headers && headers.length"
82
- class="toc-container"
83
- >
82
+ <div v-if="headers && headers.length" class="toc-container">
84
83
  <VPDocAsideOutline />
85
84
  </div>
86
85
 
87
86
  <!-- Hot Tags -->
88
87
  <div class="sidebar-widget">
89
- <h3 class="sidebar-title">
90
- Hot tags
91
- </h3>
88
+ <h3 class="sidebar-title">Hot tags</h3>
92
89
  <div class="sidebar-tags-container">
93
90
  <a
94
91
  v-for="tag in calculatedHotTags"
95
92
  :key="tag.name"
96
- :href="`/tag/${tag.name}/`"
93
+ :href="withBase(`/tag/${tag.name}/`)"
97
94
  :style="getTagStyle(tag.name)"
98
95
  class="sidebar-tag"
99
96
  >
@@ -104,9 +101,7 @@
104
101
 
105
102
  <!-- Recent Posts -->
106
103
  <div class="sidebar-widget">
107
- <h3 class="sidebar-title">
108
- Recent posts
109
- </h3>
104
+ <h3 class="sidebar-title">Recent posts</h3>
110
105
  <div class="space-y-4">
111
106
  <div
112
107
  v-for="post in calculatedRecentPosts"
@@ -114,7 +109,7 @@
114
109
  class="flex flex-col gap-1 border-b border-slate-100 last:border-none pb-3 last:pb-0"
115
110
  >
116
111
  <a
117
- :href="post.url"
112
+ :href="withBase(post.url)"
118
113
  class="text-sm font-semibold text-slate-900 hover:text-primary leading-snug transition-colors line-clamp-2"
119
114
  >
120
115
  {{ post.title }}
@@ -131,7 +126,7 @@
131
126
  </template>
132
127
 
133
128
  <script setup>
134
- import { useData } from "vitepress";
129
+ import { useData, withBase } from "vitepress";
135
130
  import { computed } from "vue";
136
131
  import { data as posts } from "../posts.data.js";
137
132
  import { data as authorsList } from "../authors.data.js";
@@ -153,10 +148,13 @@ const headers = computed(() => {
153
148
  // Form cover image URL correctly (prefixing filename with /images/)
154
149
  function getCoverImageUrl(coverImage) {
155
150
  if (!coverImage) return "";
156
- if (coverImage.startsWith("/") || coverImage.startsWith("http")) {
151
+ if (coverImage.startsWith("http") || coverImage.startsWith("//")) {
157
152
  return coverImage;
158
153
  }
159
- return `/images/${coverImage}`;
154
+ const path = coverImage.startsWith("/")
155
+ ? coverImage
156
+ : `/images/${coverImage}`;
157
+ return withBase(path);
160
158
  }
161
159
 
162
160
  // Format publication date
@@ -320,7 +318,9 @@ const calculatedHotTags = computed(() => {
320
318
  align-items: center;
321
319
  justify-content: center;
322
320
  height: 100%;
323
- transform: translateY(0.5px); /* Micro-adjustment for perfect vertical alignment */
321
+ transform: translateY(
322
+ 0.5px
323
+ ); /* Micro-adjustment for perfect vertical alignment */
324
324
  }
325
325
 
326
326
  .metadata-text {
@@ -343,7 +343,9 @@ const calculatedHotTags = computed(() => {
343
343
  font-weight: 600;
344
344
  color: var(--vp-c-brand, #004170) !important;
345
345
  text-decoration: none;
346
- transition: color 0.15s ease, text-decoration 0.15s ease;
346
+ transition:
347
+ color 0.15s ease,
348
+ text-decoration 0.15s ease;
347
349
  line-height: 1.2;
348
350
  }
349
351
 
@@ -391,7 +393,9 @@ const calculatedHotTags = computed(() => {
391
393
  border-radius: 4px !important;
392
394
  text-decoration: none !important;
393
395
  line-height: 1.2 !important;
394
- transition: opacity 0.2s ease, transform 0.1s ease !important;
396
+ transition:
397
+ opacity 0.2s ease,
398
+ transform 0.1s ease !important;
395
399
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) !important;
396
400
  }
397
401
 
@@ -416,7 +420,9 @@ const calculatedHotTags = computed(() => {
416
420
  border-radius: 4px !important;
417
421
  text-decoration: none !important;
418
422
  line-height: 1.2 !important;
419
- transition: opacity 0.2s ease, transform 0.1s ease !important;
423
+ transition:
424
+ opacity 0.2s ease,
425
+ transform 0.1s ease !important;
420
426
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) !important;
421
427
  }
422
428
 
@@ -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,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",
@@ -60,7 +75,10 @@ const iconStyle = {
60
75
 
61
76
  // Check if we should render a full-width cover image
62
77
  const isCoverLayout = computed(() => {
63
- return props.image && (props.variant === "cover" || props.date || props.authors.length);
78
+ return (
79
+ props.image &&
80
+ (props.variant === "cover" || props.date || props.authors.length)
81
+ );
64
82
  });
65
83
 
66
84
  // Check if the card itself is fully clickable (has a link but NO link text)
@@ -71,7 +89,7 @@ const isClickableCard = computed(() => {
71
89
  function getAuthorName(authorId) {
72
90
  if (!authorId) return "EOX Experts";
73
91
  const author = authorsList.find(
74
- (a) => a.id.toLowerCase().trim() === authorId.toLowerCase().trim()
92
+ (a) => a.id.toLowerCase().trim() === authorId.toLowerCase().trim(),
75
93
  );
76
94
  return author ? author.name : authorId;
77
95
  }
@@ -82,31 +100,31 @@ function getTagStyle(tag) {
82
100
  return {
83
101
  backgroundColor: "rgba(255, 94, 94, 0.15)",
84
102
  border: "1px solid rgb(255, 94, 94)",
85
- color: "#d32f2f"
103
+ color: "#d32f2f",
86
104
  };
87
105
  } else if (color.startsWith("rgb(0, 177, 176)")) {
88
106
  return {
89
107
  backgroundColor: "rgba(0, 177, 176, 0.15)",
90
108
  border: "1px solid rgb(0, 177, 176)",
91
- color: "#00796b"
109
+ color: "#00796b",
92
110
  };
93
111
  } else if (color.startsWith("rgb(219, 173, 66)")) {
94
112
  return {
95
113
  backgroundColor: "rgba(219, 173, 66, 0.15)",
96
114
  border: "1px solid rgb(219, 173, 66)",
97
- color: "#f57c00"
115
+ color: "#f57c00",
98
116
  };
99
117
  } else if (color.startsWith("rgb(218, 71, 228)")) {
100
118
  return {
101
119
  backgroundColor: "rgba(218, 71, 228, 0.15)",
102
120
  border: "1px solid rgb(218, 71, 228)",
103
- color: "#c2185b"
121
+ color: "#c2185b",
104
122
  };
105
123
  }
106
124
  return {
107
125
  backgroundColor: "rgba(0, 0, 0, 0.05)",
108
126
  border: "1px solid rgba(0, 0, 0, 0.1)",
109
- color: "#475569"
127
+ color: "#475569",
110
128
  };
111
129
  }
112
130
 
@@ -126,12 +144,17 @@ function formatDate(dateString) {
126
144
  class="vertical large-padding no-margin theme-feature-card"
127
145
  :class="[
128
146
  isClickableCard ? 'small-elevate clickable-card' : 'no-elevate',
129
- isCoverLayout ? 'has-cover-image' : ''
147
+ isCoverLayout ? 'has-cover-image' : '',
130
148
  ]"
131
149
  >
132
150
  <!-- Cover Image for cover/blog/rich cards -->
133
- <a v-if="isCoverLayout" :href="link?.href" class="card-cover-link">
134
- <img :src="image" alt="" class="card-cover-image" loading="lazy" />
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
+ />
135
158
  </a>
136
159
 
137
160
  <div class="card-content-wrapper">
@@ -146,7 +169,12 @@ function formatDate(dateString) {
146
169
  class="icon"
147
170
  ></div>
148
171
  <!-- Render small icon image only if NOT rendering a full cover image -->
149
- <img v-else-if="image && !isCoverLayout" :src="image" alt="" class="icon" />
172
+ <img
173
+ v-else-if="image && !isCoverLayout"
174
+ :src="resolvedImage"
175
+ alt=""
176
+ class="icon"
177
+ />
150
178
 
151
179
  <!-- Metadata & Tags directly under place/author -->
152
180
  <div v-if="date || (authors && authors.length)" class="metadata-wrapper">
@@ -159,18 +187,33 @@ function formatDate(dateString) {
159
187
  <span class="author-icon">
160
188
  <i class="mdi mdi-account-outline"></i>
161
189
  </span>
162
- <span v-for="(authorId, idx) in authors" :key="authorId" class="author-item">
163
- <a :href="`/author/${authorId}/`" class="author-link">{{ getAuthorName(authorId) }}</a><span v-if="idx < authors.length - 1" class="author-separator">,</span>
190
+ <span
191
+ v-for="(authorId, idx) in authors"
192
+ :key="authorId"
193
+ class="author-item"
194
+ >
195
+ <a :href="withBase(`/author/${authorId}/`)" class="author-link">{{
196
+ getAuthorName(authorId)
197
+ }}</a
198
+ ><span v-if="idx < authors.length - 1" class="author-separator"
199
+ >,</span
200
+ >
164
201
  </span>
165
202
  </span>
166
203
  </div>
167
204
 
168
205
  <!-- Tags directly under metadata if chips are provided and this is a rich card -->
169
206
  <div v-if="chips && chips.length" class="blog-tags-container">
170
- <a
171
- v-for="chip in chips"
207
+ <a
208
+ v-for="chip in chips"
172
209
  :key="chip.text"
173
- :href="chip.link || chip.href || `/tag/${chip.text}/`"
210
+ :href="
211
+ chip.link
212
+ ? resolveUrl(chip.link)
213
+ : chip.href
214
+ ? resolveUrl(chip.href)
215
+ : withBase(`/tag/${chip.text}/`)
216
+ "
174
217
  :style="getTagStyle(chip.text)"
175
218
  class="tag-link"
176
219
  >
@@ -180,7 +223,7 @@ function formatDate(dateString) {
180
223
  </div>
181
224
 
182
225
  <h5 class="small card-title-text">
183
- <a v-if="link?.href" :href="link.href">{{ title }}</a>
226
+ <a v-if="resolvedLinkHref" :href="resolvedLinkHref">{{ title }}</a>
184
227
  <span v-else>{{ title }}</span>
185
228
  </h5>
186
229
 
@@ -193,7 +236,13 @@ function formatDate(dateString) {
193
236
  <template v-for="chip in chips" :key="chip.text">
194
237
  <a
195
238
  v-if="chip.link || chip.href"
196
- :href="chip.link || chip.href"
239
+ :href="
240
+ chip.link
241
+ ? resolveUrl(chip.link)
242
+ : chip.href
243
+ ? resolveUrl(chip.href)
244
+ : undefined
245
+ "
197
246
  :style="getTagStyle(chip.text)"
198
247
  class="chip small-chip border clickable-chip"
199
248
  :class="chip.class"
@@ -211,7 +260,10 @@ function formatDate(dateString) {
211
260
  </template>
212
261
  </div>
213
262
 
214
- <p v-if="metadata && metadata.length && !date && !authors.length" class="small-text">
263
+ <p
264
+ v-if="metadata && metadata.length && !date && !authors.length"
265
+ class="small-text"
266
+ >
215
267
  <span
216
268
  v-for="(item, index) in metadata"
217
269
  :key="index"
@@ -240,7 +292,7 @@ function formatDate(dateString) {
240
292
  >
241
293
  <a
242
294
  v-if="link && !!link.text"
243
- :href="link.href"
295
+ :href="resolvedLinkHref"
244
296
  :target="link.target ?? '_blank'"
245
297
  class="button transparent bold primary-text no-padding"
246
298
  >
@@ -251,7 +303,7 @@ function formatDate(dateString) {
251
303
  </a>
252
304
  <a
253
305
  v-if="secondaryLink"
254
- :href="secondaryLink.href"
306
+ :href="resolvedSecondaryLinkHref"
255
307
  :target="secondaryLink.target ?? '_blank'"
256
308
  class="button transparent primary-text no-padding secondary-link"
257
309
  >
@@ -295,13 +347,17 @@ function formatDate(dateString) {
295
347
  /* Clickable Cards Hover System */
296
348
  .theme-feature-card.clickable-card {
297
349
  cursor: pointer;
298
- transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) !important;
350
+ transition:
351
+ transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),
352
+ box-shadow 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) !important;
299
353
  will-change: transform, box-shadow;
300
354
  }
301
355
 
302
356
  .theme-feature-card.clickable-card:hover {
303
357
  transform: translateY(-4px) !important;
304
- box-shadow: 0 12px 28px rgba(0, 0, 0, 0.12), 0 4px 8px rgba(0, 0, 0, 0.04) !important;
358
+ box-shadow:
359
+ 0 12px 28px rgba(0, 0, 0, 0.12),
360
+ 0 4px 8px rgba(0, 0, 0, 0.04) !important;
305
361
  }
306
362
 
307
363
  .small-chip {
@@ -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 v-if="image" :src="image" alt="" class="image-overlay-card-image" />
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="link.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="secondaryLink.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
- 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>
@@ -26,7 +26,7 @@
26
26
  style="grid-area: image"
27
27
  :src="withBase(frontmatter.hero.image.src)"
28
28
  />
29
- <div class="title" style="grid-area: title; align-content: end">
29
+ <div class="title" style="grid-area: title">
30
30
  <h1 class="bold" style="font-size: clamp(2.25rem, 5vw, 3.3rem)">
31
31
  {{ frontmatter.hero.text }}
32
32
  </h1>
@@ -77,15 +77,15 @@ const { frontmatter } = useData();
77
77
 
78
78
  <style scoped>
79
79
  header {
80
+ position: relative;
80
81
  margin-top: calc(var(--vp-nav-height) * -1);
81
- padding-top: 10rem !important;
82
- padding-bottom: 10rem !important;
83
- height: 76dvh;
84
- max-height: 1000px;
82
+ padding-top: calc(var(--vp-nav-height) + 3.5rem) !important;
83
+ padding-bottom: 4.5rem !important;
84
+ min-height: 380px;
85
85
  }
86
86
  @media (max-width: 1024px) {
87
87
  header {
88
- padding: 0 1.5rem !important;
88
+ padding: calc(var(--vp-nav-height) + 2rem) 1.5rem 3rem !important;
89
89
  }
90
90
  header h1.large {
91
91
  font-size: 3rem;
@@ -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="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,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 { src: img, alt: "", caption: "", link: "", width: "" };
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) => ({ src, alt: "", caption: "", link: "", width: "" }));
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 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,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`"
@@ -1,9 +1,7 @@
1
1
  <template>
2
2
  <div class="tags-page">
3
3
  <header class="tags-header">
4
- <h1 class="tags-title">
5
- Blog Tags
6
- </h1>
4
+ <h1 class="tags-title">Blog Tags</h1>
7
5
  <p class="tags-subtitle">
8
6
  Explore our blog posts by topics and technology pillars.
9
7
  </p>
@@ -15,7 +13,7 @@
15
13
  <a
16
14
  v-for="tag in allTagsList"
17
15
  :key="tag.name"
18
- :href="`/tag/${tag.name}/`"
16
+ :href="withBase(`/tag/${tag.name}/`)"
19
17
  :style="getTagStyle(tag.name)"
20
18
  class="tag-item"
21
19
  >
@@ -60,7 +58,9 @@
60
58
  </ul>
61
59
  <p class="legend-note">
62
60
  For more detailed information on our technology solutions, visit the
63
- <a href="/software-products" class="legend-link">Solutions & Services</a>
61
+ <a :href="withBase('/solutions')" class="legend-link"
62
+ >Solutions & Services</a
63
+ >
64
64
  page.
65
65
  </p>
66
66
  </footer>
@@ -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
 
@@ -180,7 +181,9 @@ const allTagsList = computed(() => {
180
181
  padding: 2.5rem 2rem;
181
182
  border-radius: 1rem;
182
183
  border: 1px solid rgba(226, 232, 240, 0.5); /* border-slate-100/50 */
183
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.05), 0 1px 2px -1px rgba(0, 0, 0, 0.05); /* shadow-sm */
184
+ box-shadow:
185
+ 0 1px 3px 0 rgba(0, 0, 0, 0.05),
186
+ 0 1px 2px -1px rgba(0, 0, 0, 0.05); /* shadow-sm */
184
187
  margin-bottom: 3rem;
185
188
  }
186
189
 
@@ -202,14 +205,19 @@ const allTagsList = computed(() => {
202
205
  border-radius: 4px; /* small rounding to distinguish from full-rounded buttons */
203
206
  text-decoration: none !important;
204
207
  line-height: 1.2;
205
- transition: opacity 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;
208
+ transition:
209
+ opacity 0.2s ease,
210
+ transform 0.15s ease,
211
+ box-shadow 0.2s ease;
206
212
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
207
213
  }
208
214
 
209
215
  .tag-item:hover {
210
216
  opacity: 0.85;
211
217
  transform: translateY(-1px);
212
- box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
218
+ box-shadow:
219
+ 0 4px 6px -1px rgba(0, 0, 0, 0.05),
220
+ 0 2px 4px -2px rgba(0, 0, 0, 0.05);
213
221
  }
214
222
 
215
223
  .tag-count {
@@ -26,12 +26,20 @@
26
26
  v-for="member in sortedTeamMembers"
27
27
  :key="member.id"
28
28
  :title="member.name"
29
- :image="member.image ? withBase(member.image) : withBase('/images/team/new_member.jpg')"
30
- :link="memberHasPosts(member.id) ? {
31
- text: 'View blog posts',
32
- href: `/author/${member.id}/`,
33
- target: '_self'
34
- } : undefined"
29
+ :image="
30
+ member.image
31
+ ? withBase(member.image)
32
+ : withBase('/images/team/new_member.jpg')
33
+ "
34
+ :link="
35
+ memberHasPosts(member.id)
36
+ ? {
37
+ text: 'View blog posts',
38
+ href: `/author/${member.id}/`,
39
+ target: '_self',
40
+ }
41
+ : undefined
42
+ "
35
43
  variant="cover"
36
44
  class="bg-surface-container-low team-member-card"
37
45
  >
@@ -43,11 +51,7 @@
43
51
  <span class="member-divider"></span>
44
52
 
45
53
  <!-- Description / Bio -->
46
- <span
47
- v-if="member.bio"
48
- class="member-bio"
49
- v-html="member.bio"
50
- ></span>
54
+ <span v-if="member.bio" class="member-bio" v-html="member.bio"></span>
51
55
 
52
56
  <!-- Social Links row at the bottom of slot -->
53
57
  <span class="member-footer">
package/src/style.css CHANGED
@@ -374,7 +374,11 @@ eox-feedback-button {
374
374
  }
375
375
 
376
376
  /* Constrain standard reading elements to 1000px max-width, while letting full-width custom page components span 1200px */
377
- .layout-page .VPPage > div > div > :is(p, ul, ol, blockquote, h1, h2, h3, h4, h5, h6, pre, table) {
377
+ .layout-page
378
+ .VPPage
379
+ > div
380
+ > div
381
+ > :is(p, ul, ol, blockquote, h1, h2, h3, h4, h5, h6, pre, table) {
378
382
  max-width: 1000px;
379
383
  margin-inline-start: 0;
380
384
  margin-inline-end: auto;
@@ -473,7 +477,9 @@ eox-feedback-button {
473
477
  text-decoration: underline;
474
478
  text-underline-offset: 3px;
475
479
  text-decoration-thickness: 1px;
476
- transition: color 0.2s ease, text-decoration-color 0.2s ease;
480
+ transition:
481
+ color 0.2s ease,
482
+ text-decoration-color 0.2s ease;
477
483
  }
478
484
 
479
485
  .layout-page .VPPage a:not(.button):hover {
@@ -505,3 +511,57 @@ eox-feedback-button {
505
511
  overflow-x: auto;
506
512
  }
507
513
 
514
+ /* Local Search styles overrides */
515
+ .VPLocalSearchBox .search-actions button {
516
+ height: 36px !important;
517
+ width: 36px !important;
518
+ min-width: 0 !important;
519
+ max-width: none !important;
520
+ border-radius: 50% !important;
521
+ padding: 0 !important;
522
+ display: inline-flex !important;
523
+ align-items: center !important;
524
+ justify-content: center !important;
525
+ border: none !important;
526
+ background: transparent !important;
527
+ box-shadow: none !important;
528
+ color: var(--vp-c-text-2) !important;
529
+ transition:
530
+ background-color 0.15s,
531
+ color 0.15s !important;
532
+ }
533
+
534
+ .VPLocalSearchBox .search-actions button:not([disabled]):hover {
535
+ background-color: var(--vp-c-default-soft) !important;
536
+ color: var(--vp-c-brand-1) !important;
537
+ }
538
+
539
+ .VPLocalSearchBox .search-actions button:disabled {
540
+ opacity: 0.37 !important;
541
+ background: transparent !important;
542
+ color: var(--vp-c-text-3) !important;
543
+ }
544
+
545
+ .VPLocalSearchBox .results {
546
+ list-style: none !important;
547
+ padding-left: 0 !important;
548
+ margin: 0 !important;
549
+ }
550
+
551
+ .VPLocalSearchBox .results li {
552
+ list-style: none !important;
553
+ margin: 0 !important;
554
+ }
555
+
556
+ /* Screen Reader Only Utility */
557
+ .sr-only {
558
+ position: absolute !important;
559
+ width: 1px !important;
560
+ height: 1px !important;
561
+ padding: 0 !important;
562
+ margin: -1px !important;
563
+ overflow: hidden !important;
564
+ clip: rect(0, 0, 0, 0) !important;
565
+ white-space: nowrap !important;
566
+ border-width: 0 !important;
567
+ }
package/src/tagUtils.js CHANGED
@@ -103,31 +103,31 @@ export function getTagStyle(tag) {
103
103
  return {
104
104
  backgroundColor: "rgba(255, 94, 94, 0.15)",
105
105
  border: "1px solid rgb(255, 94, 94)",
106
- color: "#d32f2f"
106
+ color: "#d32f2f",
107
107
  };
108
108
  } else if (color.startsWith("rgb(0, 177, 176)")) {
109
109
  return {
110
110
  backgroundColor: "rgba(0, 177, 176, 0.15)",
111
111
  border: "1px solid rgb(0, 177, 176)",
112
- color: "#00796b"
112
+ color: "#00796b",
113
113
  };
114
114
  } else if (color.startsWith("rgb(219, 173, 66)")) {
115
115
  return {
116
116
  backgroundColor: "rgba(219, 173, 66, 0.15)",
117
117
  border: "1px solid rgb(219, 173, 66)",
118
- color: "#f57c00"
118
+ color: "#f57c00",
119
119
  };
120
120
  } else if (color.startsWith("rgb(218, 71, 228)")) {
121
121
  return {
122
122
  backgroundColor: "rgba(218, 71, 228, 0.15)",
123
123
  border: "1px solid rgb(218, 71, 228)",
124
- color: "#c2185b"
124
+ color: "#c2185b",
125
125
  };
126
126
  }
127
127
  return {
128
128
  backgroundColor: "rgba(0, 0, 0, 0.05)",
129
129
  border: "1px solid rgba(0, 0, 0, 0.1)",
130
- color: "#475569"
130
+ color: "#475569",
131
131
  };
132
132
  }
133
133
 
@@ -98,8 +98,8 @@ export const generate = (brandConfig) => {
98
98
  cleanUrls: true,
99
99
  markdown: {
100
100
  headers: {
101
- level: [2, 3, 4, 5, 6]
102
- }
101
+ level: [2, 3, 4, 5, 6],
102
+ },
103
103
  },
104
104
  rewrites: {
105
105
  ...getBlogRewrites(),