@rahuldshetty/inscribe 0.0.2 → 0.0.3
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/cli/api/builder.ts +11 -3
- package/cli/api/renderer.ts +19 -6
- package/cli/schemas/inscribe.ts +1 -0
- package/cli/utils/markdown.ts +29 -3
- package/package.json +4 -2
- package/template/inscribe.yaml +1 -0
- package/template/layouts/blog.njk +2 -2
- package/template/layouts/blog_index.njk +2 -2
- package/template/layouts/doc.njk +4 -4
- package/template/layouts/doc_index.njk +5 -5
- package/template/layouts/home.njk +2 -2
- package/template/layouts/partials/header.njk +4 -4
package/cli/api/builder.ts
CHANGED
|
@@ -14,6 +14,14 @@ export interface BuildOptions {
|
|
|
14
14
|
env: string;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
const normalizeUrl = (url: string, config: InscribeConfig) => {
|
|
18
|
+
if (url.startsWith('http')) return url;
|
|
19
|
+
let base = config.base_url || '/';
|
|
20
|
+
if (!base.endsWith('/')) base += '/';
|
|
21
|
+
const suffix = url.startsWith('/') ? url.slice(1) : url;
|
|
22
|
+
return base + suffix;
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
const buildSection = async (
|
|
18
26
|
type: 'blog' | 'doc',
|
|
19
27
|
sourceDir: string,
|
|
@@ -102,7 +110,7 @@ export async function build(options: BuildOptions) {
|
|
|
102
110
|
if (isRelease) blogIndex = await minifyHtml(blogIndex);
|
|
103
111
|
await fs.writeFile(path.join(outputDir, "blogs", "index.html"), blogIndex);
|
|
104
112
|
|
|
105
|
-
if (!redirectUrl) redirectUrl = "/blogs/";
|
|
113
|
+
if (!redirectUrl) redirectUrl = normalizeUrl("/blogs/", inscribe);
|
|
106
114
|
}
|
|
107
115
|
|
|
108
116
|
// Build docs
|
|
@@ -120,11 +128,11 @@ export async function build(options: BuildOptions) {
|
|
|
120
128
|
if (docs.length > 0) {
|
|
121
129
|
const firstLevelDoc = docs.find(p => !((p as any).relativePath).includes('/') && !((p as any).relativePath).includes('\\'));
|
|
122
130
|
const firstDocSlug = (firstLevelDoc || docs[0]).metadata.slug;
|
|
123
|
-
const redirectHtml = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url
|
|
131
|
+
const redirectHtml = `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${normalizeUrl(`/doc/${firstDocSlug}`, inscribe)}"></head><body>Redirecting...</body></html>`;
|
|
124
132
|
await fs.writeFile(path.join(outputDir, "docs", "index.html"), redirectHtml);
|
|
125
133
|
}
|
|
126
134
|
|
|
127
|
-
if (!redirectUrl) redirectUrl = "/docs/";
|
|
135
|
+
if (!redirectUrl) redirectUrl = normalizeUrl("/docs/", inscribe);
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
// Generate index.html
|
package/cli/api/renderer.ts
CHANGED
|
@@ -26,16 +26,29 @@ export const parseBlogPost = async (filePath: string) => {
|
|
|
26
26
|
* 1. User project layouts
|
|
27
27
|
* 2. CLI built-in layouts
|
|
28
28
|
*/
|
|
29
|
-
const getRenderer = (sourceDir: string) => {
|
|
29
|
+
const getRenderer = (sourceDir: string, config: InscribeConfig) => {
|
|
30
30
|
const userLayouts = path.resolve(sourceDir, "layouts");
|
|
31
31
|
const builtInLayouts = path.resolve(__dirname, "../../template/layouts");
|
|
32
32
|
|
|
33
33
|
const searchPaths = [userLayouts, builtInLayouts];
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
const env = new nunjucks.Environment(
|
|
36
36
|
new nunjucks.FileSystemLoader(searchPaths),
|
|
37
37
|
{ autoescape: true }
|
|
38
38
|
);
|
|
39
|
+
|
|
40
|
+
env.addFilter('url', (urlPath: string) => {
|
|
41
|
+
if (!urlPath) return urlPath;
|
|
42
|
+
if (urlPath.startsWith('http') || urlPath.startsWith('//') || urlPath.startsWith('data:')) return urlPath;
|
|
43
|
+
|
|
44
|
+
let base = config.base_url || '/';
|
|
45
|
+
if (!base.endsWith('/')) base += '/';
|
|
46
|
+
|
|
47
|
+
const pathSuffix = urlPath.startsWith('/') ? urlPath.slice(1) : urlPath;
|
|
48
|
+
return base + pathSuffix;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return env;
|
|
39
52
|
};
|
|
40
53
|
|
|
41
54
|
import { FolderMetadata } from "../schemas/folder";
|
|
@@ -127,8 +140,8 @@ export const renderSectionPage = async (
|
|
|
127
140
|
navState: NavState,
|
|
128
141
|
isDev: boolean = false
|
|
129
142
|
) => {
|
|
130
|
-
const html = await markdown2HTML(post.markdown, post.isMDX);
|
|
131
|
-
const env = getRenderer(sourceDir);
|
|
143
|
+
const html = await markdown2HTML(post.markdown, post.isMDX, inscribe);
|
|
144
|
+
const env = getRenderer(sourceDir, inscribe);
|
|
132
145
|
const themeCSS = resolveThemeCSS(inscribe.theme ?? 'default', sourceDir);
|
|
133
146
|
|
|
134
147
|
const template = type === 'blog' ? "blog.njk" : "doc.njk";
|
|
@@ -160,7 +173,7 @@ export const renderSectionIndexPage = (
|
|
|
160
173
|
navState: NavState,
|
|
161
174
|
isDev: boolean = false
|
|
162
175
|
) => {
|
|
163
|
-
const env = getRenderer(sourceDir);
|
|
176
|
+
const env = getRenderer(sourceDir, inscribe);
|
|
164
177
|
const themeCSS = resolveThemeCSS(inscribe.theme ?? 'default', sourceDir);
|
|
165
178
|
|
|
166
179
|
const template = type === 'blog' ? "blog_index.njk" : "doc_index.njk";
|
|
@@ -187,7 +200,7 @@ export const renderHomePage = (
|
|
|
187
200
|
navState: NavState,
|
|
188
201
|
isDev: boolean = false
|
|
189
202
|
) => {
|
|
190
|
-
const env = getRenderer(sourceDir);
|
|
203
|
+
const env = getRenderer(sourceDir, inscribe);
|
|
191
204
|
const themeCSS = resolveThemeCSS(inscribe.theme ?? 'default', sourceDir);
|
|
192
205
|
|
|
193
206
|
return env.render("home.njk", {
|
package/cli/schemas/inscribe.ts
CHANGED
|
@@ -9,6 +9,7 @@ export const InscribeSchema = z.object({
|
|
|
9
9
|
blog_path: z.string().default('blog').optional(),
|
|
10
10
|
doc_path: z.string().default('docs').optional(),
|
|
11
11
|
show_doc_nav: z.preprocess((val) => (typeof val === "string" ? val.toLowerCase() === "true" : val), z.boolean()).default(true).optional(),
|
|
12
|
+
base_url: z.string().default('/').optional(),
|
|
12
13
|
})
|
|
13
14
|
|
|
14
15
|
export type InscribeConfig = z.infer<typeof InscribeSchema>;
|
package/cli/utils/markdown.ts
CHANGED
|
@@ -46,7 +46,33 @@ export function parseFrontMatter(content: string) {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
import { InscribeConfig } from "../schemas/inscribe";
|
|
50
|
+
|
|
51
|
+
export const markdown2HTML = async (content: string, isMDX: boolean = false, config?: InscribeConfig) => {
|
|
52
|
+
const base = config?.base_url || '/';
|
|
53
|
+
const normalizedBase = base.endsWith('/') ? base : base + '/';
|
|
54
|
+
|
|
55
|
+
const renderer = new marked.Renderer();
|
|
56
|
+
|
|
57
|
+
// Custom renderer to handle base_url for links and images
|
|
58
|
+
renderer.link = ({ href, title, text }: any) => {
|
|
59
|
+
let finalHref = href;
|
|
60
|
+
if (href && !href.startsWith('http') && !href.startsWith('//') && !href.startsWith('#')) {
|
|
61
|
+
const pathSuffix = href.startsWith('/') ? href.slice(1) : href;
|
|
62
|
+
finalHref = normalizedBase + pathSuffix;
|
|
63
|
+
}
|
|
64
|
+
return `<a href="${finalHref}"${title ? ` title="${title}"` : ""}>${text}</a>`;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
renderer.image = ({ href, title, text }: any) => {
|
|
68
|
+
let finalHref = href;
|
|
69
|
+
if (href && !href.startsWith('http') && !href.startsWith('//') && !href.startsWith('data:')) {
|
|
70
|
+
const pathSuffix = href.startsWith('/') ? href.slice(1) : href;
|
|
71
|
+
finalHref = normalizedBase + pathSuffix;
|
|
72
|
+
}
|
|
73
|
+
return `<img src="${finalHref}" alt="${text || ""}"${title ? ` title="${title}"` : ""}>`;
|
|
74
|
+
};
|
|
75
|
+
|
|
50
76
|
if (isMDX) {
|
|
51
77
|
try {
|
|
52
78
|
// compile MDX -> JS
|
|
@@ -64,9 +90,9 @@ export const markdown2HTML = async (content: string, isMDX: boolean = false) =>
|
|
|
64
90
|
return html;
|
|
65
91
|
} catch (e) {
|
|
66
92
|
console.error("MDX compilation error:", e);
|
|
67
|
-
return await marked(content);
|
|
93
|
+
return await marked(content, { renderer });
|
|
68
94
|
}
|
|
69
95
|
}
|
|
70
|
-
const html = await marked(content)
|
|
96
|
+
const html = await marked(content, { renderer })
|
|
71
97
|
return html;
|
|
72
98
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rahuldshetty/inscribe",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"description": "A minimalist Static Site Generator (SSG) for blogs and documentation.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"lint": "prettier --check . && eslint .",
|
|
35
35
|
"format": "prettier --write .",
|
|
36
36
|
"inscribe": "bun ./cli/index.ts",
|
|
37
|
-
"build:cli": "bun build ./cli/index.ts --outdir ./dist --target bun"
|
|
37
|
+
"build:cli": "bun build ./cli/index.ts --outdir ./dist --target bun",
|
|
38
|
+
"doc:deploy": "bun inscribe build docs --output docs-dist && gh-pages -d docs-dist"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@eslint/compat": "^2.0.2",
|
|
@@ -60,6 +61,7 @@
|
|
|
60
61
|
"clerc": "^1.3.1",
|
|
61
62
|
"dompurify": "^3.3.2",
|
|
62
63
|
"fs-extra": "^11.3.4",
|
|
64
|
+
"gh-pages": "^6.3.0",
|
|
63
65
|
"html-minifier-terser": "^7.2.0",
|
|
64
66
|
"jsdom": "^28.1.0",
|
|
65
67
|
"marked": "^17.0.4",
|
package/template/inscribe.yaml
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
{% if blog.metadata.cover %}
|
|
43
43
|
<figure class="mb-10 -mx-6 sm:-mx-12">
|
|
44
44
|
<img
|
|
45
|
-
src="{{ blog.metadata.cover }}"
|
|
45
|
+
src="{{ blog.metadata.cover | url }}"
|
|
46
46
|
alt="{{ blog.metadata.cover_alt or blog.metadata.title }}"
|
|
47
47
|
class="w-full object-cover rounded-none sm:rounded-xl max-h-[480px]"
|
|
48
48
|
/>
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
<hr class="my-12 border-[var(--color-border)]" />
|
|
66
66
|
|
|
67
67
|
<footer class="flex items-center justify-between text-sm text-[var(--color-muted)]">
|
|
68
|
-
<a href="/"
|
|
68
|
+
<a href="{{ '/blogs/' | url }}"
|
|
69
69
|
class="hover:text-[var(--color-text)] transition-colors flex items-center gap-1.5 font-medium">
|
|
70
70
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
71
71
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<ul class="divide-y divide-[var(--color-border)]">
|
|
18
18
|
{% for blog in blogs %}
|
|
19
19
|
<li>
|
|
20
|
-
<a href="/blog/
|
|
20
|
+
<a href="{{ ('/blog/' + blog.metadata.slug) | url }}"
|
|
21
21
|
class="group flex items-start justify-between gap-6 py-7 hover:no-underline">
|
|
22
22
|
|
|
23
23
|
{# Text content #}
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
{% if blog.metadata.cover %}
|
|
56
56
|
<div class="flex-shrink-0 w-24 h-16 sm:w-32 sm:h-20 rounded-lg overflow-hidden bg-[var(--color-tag-bg)]">
|
|
57
57
|
<img
|
|
58
|
-
src="{{ blog.metadata.cover }}"
|
|
58
|
+
src="{{ blog.metadata.cover | url }}"
|
|
59
59
|
alt="{{ blog.metadata.title }}"
|
|
60
60
|
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
|
|
61
61
|
/>
|
package/template/layouts/doc.njk
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
{{ renderNode(item.node, depth + 1, currentDirPath) }}
|
|
28
28
|
{% else %}
|
|
29
29
|
<div class="rounded-md hover:bg-[var(--color-tag-bg)] transition-all">
|
|
30
|
-
<a href="/doc/
|
|
30
|
+
<a href="{{ ('/doc/' + item.post.metadata.slug) | url }}"
|
|
31
31
|
style="padding-left: {{ (depth + 1) * 16 + 8 }}px"
|
|
32
32
|
class="text-sm py-1.5 block transition-colors {% if item.post.metadata.slug == doc.metadata.slug %}text-[var(--color-text)] font-semibold border-l-2 border-[var(--color-text)] -ml-[2px]!{% else %}text-[var(--color-muted)] hover:text-[var(--color-text)]{% endif %}">
|
|
33
33
|
{{ item.post.metadata.title }}
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
{{ renderNode(item.node, depth, currentDirPath) }}
|
|
45
45
|
{% else %}
|
|
46
46
|
<div class="rounded-md hover:bg-[var(--color-tag-bg)] transition-all">
|
|
47
|
-
<a href="/doc/
|
|
47
|
+
<a href="{{ ('/doc/' + item.post.metadata.slug) | url }}"
|
|
48
48
|
style="padding-left: {{ depth * 16 + 8 }}px"
|
|
49
49
|
class="text-sm py-1.5 block transition-colors {% if item.post.metadata.slug == doc.metadata.slug %}text-[var(--color-text)] font-semibold border-l-2 border-[var(--color-text)] -ml-[2px]!{% else %}text-[var(--color-muted)] hover:text-[var(--color-text)]{% endif %}">
|
|
50
50
|
{{ item.post.metadata.title }}
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
{% if blog.metadata.cover %}
|
|
70
70
|
<figure class="mb-10 -mx-6 sm:-mx-12">
|
|
71
71
|
<img
|
|
72
|
-
src="{{ blog.metadata.cover }}"
|
|
72
|
+
src="{{ blog.metadata.cover | url }}"
|
|
73
73
|
alt="{{ blog.metadata.cover_alt or blog.metadata.title }}"
|
|
74
74
|
class="w-full object-cover rounded-none sm:rounded-xl max-h-[480px]"
|
|
75
75
|
/>
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
<hr class="my-12 border-[var(--color-border)]" />
|
|
93
93
|
|
|
94
94
|
<footer class="flex items-center justify-between text-sm text-[var(--color-muted)]">
|
|
95
|
-
<a href="/docs/"
|
|
95
|
+
<a href="{{ '/docs/' | url }}"
|
|
96
96
|
class="hover:text-[var(--color-text)] transition-colors flex items-center gap-1.5 font-medium">
|
|
97
97
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
98
98
|
<path stroke-linecap="round" stroke-linejoin="round" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{% extends "base.njk" %}
|
|
2
2
|
|
|
3
|
-
{% block title %}{{ config.title }} —
|
|
3
|
+
{% block title %}{{ config.title }} — Documentation{% endblock %}
|
|
4
4
|
|
|
5
5
|
{% block content %}
|
|
6
6
|
<div class="min-h-screen bg-[var(--color-bg)] w-full max-w-[1400px] mx-auto flex flex-col md:flex-row md:px-8">
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
{{ renderNode(item.node, depth + 1, currentDirPath) }}
|
|
28
28
|
{% else %}
|
|
29
29
|
<div class="rounded-md hover:bg-[var(--color-tag-bg)] transition-all">
|
|
30
|
-
<a href="/doc/
|
|
30
|
+
<a href="{{ ('/doc/' + item.post.metadata.slug) | url }}"
|
|
31
31
|
style="padding-left: {{ (depth + 1) * 16 + 8 }}px"
|
|
32
32
|
class="text-sm py-1.5 block text-[var(--color-muted)] hover:text-[var(--color-text)] transition-colors">
|
|
33
33
|
{{ item.post.metadata.title }}
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
{{ renderNode(item.node, depth, currentDirPath) }}
|
|
45
45
|
{% else %}
|
|
46
46
|
<div class="rounded-md hover:bg-[var(--color-tag-bg)] transition-all">
|
|
47
|
-
<a href="/doc/
|
|
47
|
+
<a href="{{ ('/doc/' + item.post.metadata.slug) | url }}"
|
|
48
48
|
style="padding-left: {{ depth * 16 + 8 }}px"
|
|
49
49
|
class="text-sm py-1.5 block text-[var(--color-muted)] hover:text-[var(--color-text)] transition-colors">
|
|
50
50
|
{{ item.post.metadata.title }}
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
<ul class="divide-y divide-[var(--color-border)]">
|
|
75
75
|
{% for item in docs %}
|
|
76
76
|
<li>
|
|
77
|
-
<a href="
|
|
77
|
+
<a href="{{ ('/doc/' + item.metadata.slug) | url }}"
|
|
78
78
|
class="group flex items-start justify-between gap-6 py-7 hover:no-underline">
|
|
79
79
|
|
|
80
80
|
{# Text content #}
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
{% if item.metadata.cover %}
|
|
113
113
|
<div class="flex-shrink-0 w-24 h-16 sm:w-32 sm:h-20 rounded-lg overflow-hidden bg-[var(--color-tag-bg)]">
|
|
114
114
|
<img
|
|
115
|
-
src="{{ item.metadata.cover }}"
|
|
115
|
+
src="{{ item.metadata.cover | url }}"
|
|
116
116
|
alt="{{ item.metadata.title }}"
|
|
117
117
|
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
|
|
118
118
|
/>
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
</p>
|
|
14
14
|
<div class="flex flex-col sm:flex-row gap-4 items-center justify-center">
|
|
15
15
|
{% if navState.hasBlog %}
|
|
16
|
-
<a href="/blogs/" class="px-8 py-3 w-full sm:w-auto text-lg font-medium text-[var(--color-bg)] bg-[var(--color-text)] rounded-full hover:opacity-90 transition-opacity">
|
|
16
|
+
<a href="{{ '/blogs/' | url }}" class="px-8 py-3 w-full sm:w-auto text-lg font-medium text-[var(--color-bg)] bg-[var(--color-text)] rounded-full hover:opacity-90 transition-opacity">
|
|
17
17
|
Read the Blog
|
|
18
18
|
</a>
|
|
19
19
|
{% endif %}
|
|
20
20
|
{% if navState.hasDocs %}
|
|
21
|
-
<a href="/docs/" class="px-8 py-3 w-full sm:w-auto text-lg font-medium text-[var(--color-text)] bg-[var(--color-border)] rounded-full hover:bg-[var(--color-muted)] hover:text-white transition-colors">
|
|
21
|
+
<a href="{{ '/docs/' | url }}" class="px-8 py-3 w-full sm:w-auto text-lg font-medium text-[var(--color-text)] bg-[var(--color-border)] rounded-full hover:bg-[var(--color-muted)] hover:text-white transition-colors">
|
|
22
22
|
Documentation
|
|
23
23
|
</a>
|
|
24
24
|
{% endif %}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<nav class="sticky top-0 z-50 border-b border-[var(--color-border)] backdrop-blur-sm"
|
|
4
4
|
style="background-color: var(--color-bg-nav);">
|
|
5
5
|
<div class="max-w-4xl mx-auto px-6 h-14 flex items-center justify-between">
|
|
6
|
-
<a href="/" class="text-lg font-bold text-[var(--color-text)] flex items-center gap-2 hover:opacity-80 transition-opacity">
|
|
6
|
+
<a href="{{ '/' | url }}" class="text-lg font-bold text-[var(--color-text)] flex items-center gap-2 hover:opacity-80 transition-opacity">
|
|
7
7
|
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 text-[var(--color-accent)]" viewBox="0 0 20 20" fill="currentColor">
|
|
8
8
|
<path fill-rule="evenodd" d="M4 4a2 2 0 012-2h8a2 2 0 012 2v12a1 1 0 110 2h-3a1 1 0 01-1-1v-2a1 1 0 00-1-1H9a1 1 0 00-1 1v2a1 1 0 01-1 1H4a1 1 0 110-2V4zm3 1h2v2H7V5zm2 4H7v2h2V9zm2-4h2v2h-2V5zm2 4h-2v2h2V9z" clip-rule="evenodd" />
|
|
9
9
|
</svg>
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
</a>
|
|
12
12
|
<div class="flex gap-6 items-center">
|
|
13
13
|
{% if navState.hasHome %}
|
|
14
|
-
<a href="/" class="text-sm font-medium text-[var(--color-muted)] hover:text-[var(--color-accent)] transition-colors">Home</a>
|
|
14
|
+
<a href="{{ '/' | url }}" class="text-sm font-medium text-[var(--color-muted)] hover:text-[var(--color-accent)] transition-colors">Home</a>
|
|
15
15
|
{% endif %}
|
|
16
16
|
{% if navState.hasDocs %}
|
|
17
|
-
<a href="/docs/" class="text-sm font-medium text-[var(--color-muted)] hover:text-[var(--color-accent)] transition-colors">Docs</a>
|
|
17
|
+
<a href="{{ '/docs/' | url }}" class="text-sm font-medium text-[var(--color-muted)] hover:text-[var(--color-accent)] transition-colors">Docs</a>
|
|
18
18
|
{% endif %}
|
|
19
19
|
{% if navState.hasBlog %}
|
|
20
|
-
<a href="/blogs/" class="text-sm font-medium text-[var(--color-muted)] hover:text-[var(--color-accent)] transition-colors">Blogs</a>
|
|
20
|
+
<a href="{{ '/blogs/' | url }}" class="text-sm font-medium text-[var(--color-muted)] hover:text-[var(--color-accent)] transition-colors">Blogs</a>
|
|
21
21
|
{% endif %}
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|