@barodoc/theme-docs 3.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -2
- package/src/components/Breadcrumb.astro +8 -8
- package/src/components/CodeCopy.astro +14 -13
- package/src/components/Contributors.astro +71 -0
- package/src/components/DocHeader.tsx +24 -24
- package/src/components/DocsSidebar.tsx +11 -15
- package/src/components/KeyboardShortcuts.astro +108 -0
- package/src/components/LanguageSwitcher.astro +3 -3
- package/src/components/MobileNavSheet.tsx +1 -1
- package/src/components/Search.tsx +10 -10
- package/src/components/SearchDialog.tsx +8 -8
- package/src/components/TableOfContents.astro +5 -5
- package/src/components/ThemeToggle.tsx +4 -4
- package/src/components/VersionSwitcher.tsx +79 -0
- package/src/components/api/ApiEndpoint.astro +5 -5
- package/src/components/api/ApiParam.astro +4 -4
- package/src/components/api/ApiParams.astro +3 -3
- package/src/components/api/ApiResponse.astro +2 -2
- package/src/components/index.ts +5 -0
- package/src/components/mdx/Accordion.tsx +6 -6
- package/src/components/mdx/ApiPlayground.tsx +200 -0
- package/src/components/mdx/Badge.tsx +1 -1
- package/src/components/mdx/Callout.astro +20 -20
- package/src/components/mdx/Card.astro +5 -5
- package/src/components/mdx/CodeGroup.astro +23 -20
- package/src/components/mdx/CodeGroup.tsx +6 -6
- package/src/components/mdx/DocAccordion.tsx +5 -5
- package/src/components/mdx/DocCard.tsx +2 -2
- package/src/components/mdx/DocTabs.tsx +3 -3
- package/src/components/mdx/Expandable.tsx +11 -11
- package/src/components/mdx/FileTree.tsx +6 -6
- package/src/components/mdx/Frame.tsx +2 -2
- package/src/components/mdx/ImageZoom.tsx +35 -0
- package/src/components/mdx/Mermaid.tsx +3 -3
- package/src/components/mdx/ParamField.tsx +7 -7
- package/src/components/mdx/ResponseField.tsx +6 -6
- package/src/components/mdx/Step.astro +2 -2
- package/src/components/mdx/Steps.astro +3 -3
- package/src/components/mdx/Steps.tsx +10 -19
- package/src/components/mdx/Tabs.tsx +5 -8
- package/src/components/mdx/Tooltip.tsx +20 -19
- package/src/components/mdx/Video.tsx +71 -0
- package/src/components/ui/accordion.tsx +2 -2
- package/src/components/ui/alert.tsx +1 -1
- package/src/components/ui/button.tsx +3 -3
- package/src/components/ui/card.tsx +2 -2
- package/src/components/ui/dialog.tsx +2 -2
- package/src/components/ui/scroll-area.tsx +1 -1
- package/src/components/ui/separator.tsx +1 -1
- package/src/components/ui/sheet.tsx +3 -3
- package/src/components/ui/tabs.tsx +2 -2
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/index.ts +33 -1
- package/src/layouts/BaseLayout.astro +10 -1
- package/src/layouts/BlogLayout.astro +93 -0
- package/src/layouts/DocsLayout.astro +72 -23
- package/src/pages/404.astro +5 -5
- package/src/pages/blog/[...slug].astro +39 -0
- package/src/pages/blog/index.astro +92 -0
- package/src/pages/changelog/index.astro +72 -0
- package/src/pages/docs/[...slug].astro +6 -2
- package/src/pages/index.astro +21 -21
- package/src/styles/global.css +1041 -166
|
@@ -7,6 +7,8 @@ import MobileNav from "../components/MobileNav.astro";
|
|
|
7
7
|
import CodeCopy from "../components/CodeCopy.astro";
|
|
8
8
|
import Breadcrumb from "../components/Breadcrumb.astro";
|
|
9
9
|
import Banner from "../components/Banner.astro";
|
|
10
|
+
import KeyboardShortcuts from "../components/KeyboardShortcuts.astro";
|
|
11
|
+
import Contributors from "../components/Contributors.astro";
|
|
10
12
|
import { defaultLocale } from "virtual:barodoc/i18n";
|
|
11
13
|
import { getLocaleFromPath } from "@barodoc/core";
|
|
12
14
|
import config from "virtual:barodoc/config";
|
|
@@ -30,9 +32,11 @@ interface Props {
|
|
|
30
32
|
editUrl?: string | null;
|
|
31
33
|
lastUpdated?: Date | null;
|
|
32
34
|
breadcrumbs?: BreadcrumbItem[];
|
|
35
|
+
readingTime?: string;
|
|
36
|
+
filePath?: string;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
const { title, description, headings = [], prevPage, nextPage, editUrl, lastUpdated, breadcrumbs = [] } = Astro.props;
|
|
39
|
+
const { title, description, headings = [], prevPage, nextPage, editUrl, lastUpdated, breadcrumbs = [], readingTime, filePath } = Astro.props;
|
|
36
40
|
const currentPath = Astro.url.pathname;
|
|
37
41
|
|
|
38
42
|
// Get locale from path
|
|
@@ -48,40 +52,48 @@ const feedbackEndpoint = config.feedback?.endpoint;
|
|
|
48
52
|
<Header currentLocale={currentLocale} currentPath={currentPath} />
|
|
49
53
|
|
|
50
54
|
<!-- Centered container for docs layout -->
|
|
51
|
-
<div class="w-full min-w-0 min-h-[calc(100vh-3.5rem)] flex justify-center overflow-x-
|
|
52
|
-
<div class="flex w-full max-w-[
|
|
55
|
+
<div class="w-full min-w-0 min-h-[calc(100vh-3.5rem)] flex justify-center overflow-x-clip">
|
|
56
|
+
<div class="flex w-full max-w-[1280px] min-w-0">
|
|
53
57
|
<!-- Desktop Sidebar -->
|
|
54
|
-
<aside class="hidden lg:block w-[
|
|
55
|
-
<div class="sticky top-14 h-[calc(100vh-3.5rem)] overflow-y-auto
|
|
58
|
+
<aside class="hidden lg:block w-[240px] shrink-0 border-r border-[var(--bd-border)]">
|
|
59
|
+
<div class="sticky top-14 h-[calc(100vh-3.5rem)] overflow-y-auto overscroll-contain pt-2 pb-8 px-4 sidebar-scroll">
|
|
56
60
|
<Sidebar currentPath={currentPath} currentLocale={currentLocale} />
|
|
57
61
|
</div>
|
|
58
62
|
</aside>
|
|
59
63
|
|
|
60
|
-
<!-- Main Content
|
|
61
|
-
<main class="flex-1 min-w-0
|
|
62
|
-
<div class="px-4 py-
|
|
64
|
+
<!-- Main Content -->
|
|
65
|
+
<main class="flex-1 min-w-0 max-w-[768px]">
|
|
66
|
+
<div class="px-4 py-8 sm:px-6 sm:py-10 lg:px-10 lg:py-10">
|
|
63
67
|
{breadcrumbs.length > 0 && <Breadcrumb items={breadcrumbs} />}
|
|
68
|
+
{readingTime && (
|
|
69
|
+
<div class="bd-reading-time mb-4">
|
|
70
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
71
|
+
<circle cx="12" cy="12" r="10" /><polyline points="12 6 12 12 16 14" />
|
|
72
|
+
</svg>
|
|
73
|
+
<span>{readingTime}</span>
|
|
74
|
+
</div>
|
|
75
|
+
)}
|
|
64
76
|
<article class="prose prose-gray dark:prose-invert max-w-none min-w-0 overflow-x-auto">
|
|
65
77
|
<slot />
|
|
66
78
|
</article>
|
|
67
79
|
|
|
68
80
|
<!-- Page Navigation -->
|
|
69
81
|
{(prevPage || nextPage) && (
|
|
70
|
-
<nav class="mt-
|
|
82
|
+
<nav class="mt-12 pt-8 border-t border-[var(--bd-border)]" aria-label="Page navigation">
|
|
71
83
|
<div class="grid grid-cols-2 gap-4">
|
|
72
84
|
<div class="col-span-1">
|
|
73
85
|
{prevPage && (
|
|
74
86
|
<a
|
|
75
87
|
href={prevPage.href}
|
|
76
|
-
class="group flex flex-col gap-1 p-
|
|
88
|
+
class="group flex flex-col gap-1.5 p-4 rounded-lg border border-[var(--bd-border)] hover:border-primary-400/50 dark:hover:border-primary-500/40 hover:shadow-[var(--bd-shadow-sm)] transition-all"
|
|
77
89
|
>
|
|
78
|
-
<span class="text-xs text-[var(--
|
|
90
|
+
<span class="text-xs font-medium text-[var(--bd-text-muted)] flex items-center gap-1">
|
|
79
91
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
80
92
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
|
81
93
|
</svg>
|
|
82
94
|
Previous
|
|
83
95
|
</span>
|
|
84
|
-
<span class="text-sm font-medium text-[var(--
|
|
96
|
+
<span class="text-sm font-medium text-[var(--bd-text)] group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors">
|
|
85
97
|
{prevPage.title}
|
|
86
98
|
</span>
|
|
87
99
|
</a>
|
|
@@ -91,15 +103,15 @@ const feedbackEndpoint = config.feedback?.endpoint;
|
|
|
91
103
|
{nextPage && (
|
|
92
104
|
<a
|
|
93
105
|
href={nextPage.href}
|
|
94
|
-
class="group flex flex-col gap-1 p-
|
|
106
|
+
class="group flex flex-col gap-1.5 p-4 rounded-lg border border-[var(--bd-border)] hover:border-primary-400/50 dark:hover:border-primary-500/40 hover:shadow-[var(--bd-shadow-sm)] transition-all text-right"
|
|
95
107
|
>
|
|
96
|
-
<span class="text-xs text-[var(--
|
|
108
|
+
<span class="text-xs font-medium text-[var(--bd-text-muted)] flex items-center gap-1 justify-end">
|
|
97
109
|
Next
|
|
98
110
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
99
111
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
|
|
100
112
|
</svg>
|
|
101
113
|
</span>
|
|
102
|
-
<span class="text-sm font-medium text-[var(--
|
|
114
|
+
<span class="text-sm font-medium text-[var(--bd-text)] group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors">
|
|
103
115
|
{nextPage.title}
|
|
104
116
|
</span>
|
|
105
117
|
</a>
|
|
@@ -110,8 +122,9 @@ const feedbackEndpoint = config.feedback?.endpoint;
|
|
|
110
122
|
)}
|
|
111
123
|
|
|
112
124
|
<!-- Page footer -->
|
|
113
|
-
<footer class="mt-
|
|
114
|
-
<
|
|
125
|
+
<footer class="mt-8 pt-6 border-t border-[var(--bd-border-subtle)] flex flex-col gap-3">
|
|
126
|
+
{filePath && <Contributors filePath={filePath} />}
|
|
127
|
+
<div class="flex flex-wrap items-center justify-between gap-2 text-[13px] text-[var(--bd-text-muted)]">
|
|
115
128
|
{lastUpdated && (
|
|
116
129
|
<span>
|
|
117
130
|
Last updated: <time datetime={lastUpdated.toISOString()}>
|
|
@@ -124,7 +137,7 @@ const feedbackEndpoint = config.feedback?.endpoint;
|
|
|
124
137
|
href={editUrl}
|
|
125
138
|
target="_blank"
|
|
126
139
|
rel="noopener noreferrer"
|
|
127
|
-
class="inline-flex items-center gap-1 text-primary-600 dark:text-primary-400
|
|
140
|
+
class="inline-flex items-center gap-1.5 text-[var(--bd-text-secondary)] hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
|
128
141
|
>
|
|
129
142
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
130
143
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
|
|
@@ -134,12 +147,12 @@ const feedbackEndpoint = config.feedback?.endpoint;
|
|
|
134
147
|
)}
|
|
135
148
|
</div>
|
|
136
149
|
{hasFeedback && (
|
|
137
|
-
<div class="doc-feedback flex items-center gap-3 text-sm text-[var(--
|
|
150
|
+
<div class="doc-feedback flex items-center gap-3 text-sm text-[var(--bd-text-muted)]" data-endpoint={feedbackEndpoint}>
|
|
138
151
|
<span>Was this page helpful?</span>
|
|
139
|
-
<button type="button" class="feedback-btn inline-flex items-center gap-1 px-2 py-1 rounded border border-[var(--
|
|
152
|
+
<button type="button" class="feedback-btn inline-flex items-center gap-1 px-2 py-1 rounded border border-[var(--bd-border)] hover:bg-[var(--bd-bg-subtle)] transition-colors" data-value="yes" aria-label="Yes">
|
|
140
153
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 9V5a3 3 0 00-3-3l-4 9v11h11.28a2 2 0 002-1.7l1.38-9a2 2 0 00-2-2.3H14z" /></svg>
|
|
141
154
|
</button>
|
|
142
|
-
<button type="button" class="feedback-btn inline-flex items-center gap-1 px-2 py-1 rounded border border-[var(--
|
|
155
|
+
<button type="button" class="feedback-btn inline-flex items-center gap-1 px-2 py-1 rounded border border-[var(--bd-border)] hover:bg-[var(--bd-bg-subtle)] transition-colors" data-value="no" aria-label="No">
|
|
143
156
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 15v3.586a1 1 0 01-.293.707l-2 2A1 1 0 016 20.586V15m4 0h5.17a2 2 0 001.98-1.742l1.08-7.56A1 1 0 0017.242 4.5H10m0 10.5V4.5m0 0H7.5A2.5 2.5 0 005 7v3" /></svg>
|
|
144
157
|
</button>
|
|
145
158
|
<span class="feedback-thanks hidden text-green-600 dark:text-green-400">Thanks for your feedback!</span>
|
|
@@ -151,8 +164,8 @@ const feedbackEndpoint = config.feedback?.endpoint;
|
|
|
151
164
|
|
|
152
165
|
<!-- Table of Contents -->
|
|
153
166
|
{headings.length > 0 && (
|
|
154
|
-
<aside class="hidden xl:block w-[
|
|
155
|
-
<div class="sticky top-14 h-[calc(100vh-3.5rem)] overflow-y-auto py-
|
|
167
|
+
<aside class="hidden xl:block w-[220px] shrink-0">
|
|
168
|
+
<div class="sticky top-14 h-[calc(100vh-3.5rem)] overflow-y-auto py-10 pl-8">
|
|
156
169
|
<TableOfContents headings={headings} />
|
|
157
170
|
</div>
|
|
158
171
|
</aside>
|
|
@@ -166,6 +179,42 @@ const feedbackEndpoint = config.feedback?.endpoint;
|
|
|
166
179
|
<!-- Code copy functionality -->
|
|
167
180
|
<CodeCopy />
|
|
168
181
|
|
|
182
|
+
<!-- Keyboard shortcuts -->
|
|
183
|
+
<KeyboardShortcuts />
|
|
184
|
+
|
|
185
|
+
<!-- Image zoom for all prose images -->
|
|
186
|
+
<script>
|
|
187
|
+
async function initImageZoom() {
|
|
188
|
+
const images = document.querySelectorAll('.prose img:not(.bd-no-zoom):not(.medium-zoom-image)');
|
|
189
|
+
if (images.length === 0) return;
|
|
190
|
+
const { default: mediumZoom } = await import('medium-zoom');
|
|
191
|
+
mediumZoom(images as any, {
|
|
192
|
+
margin: 24,
|
|
193
|
+
background: 'var(--bd-bg)',
|
|
194
|
+
scrollOffset: 0,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
initImageZoom();
|
|
198
|
+
document.addEventListener('astro:page-load', initImageZoom);
|
|
199
|
+
</script>
|
|
200
|
+
|
|
201
|
+
<!-- Heading anchor links -->
|
|
202
|
+
<script>
|
|
203
|
+
function initHeadingAnchors() {
|
|
204
|
+
document.querySelectorAll('.prose h2[id], .prose h3[id], .prose h4[id]').forEach((heading) => {
|
|
205
|
+
if (heading.querySelector('.heading-anchor')) return;
|
|
206
|
+
const anchor = document.createElement('a');
|
|
207
|
+
anchor.className = 'heading-anchor';
|
|
208
|
+
anchor.href = `#${heading.id}`;
|
|
209
|
+
anchor.textContent = '#';
|
|
210
|
+
anchor.setAttribute('aria-label', `Link to ${heading.textContent}`);
|
|
211
|
+
heading.appendChild(anchor);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
initHeadingAnchors();
|
|
215
|
+
document.addEventListener('astro:page-load', initHeadingAnchors);
|
|
216
|
+
</script>
|
|
217
|
+
|
|
169
218
|
{hasFeedback && (
|
|
170
219
|
<script>
|
|
171
220
|
function initFeedback() {
|
package/src/pages/404.astro
CHANGED
|
@@ -8,10 +8,10 @@ const pathname = new URL(Astro.request.url).pathname;
|
|
|
8
8
|
<BaseLayout title={`${config.name} · Page not found`} description="The page you are looking for does not exist.">
|
|
9
9
|
<div class="min-h-screen flex flex-col items-center justify-center px-4">
|
|
10
10
|
<div class="text-center max-w-md">
|
|
11
|
-
<p class="text-8xl font-bold text-[var(--
|
|
12
|
-
<h1 class="text-2xl font-semibold text-[var(--
|
|
13
|
-
<p class="text-[var(--
|
|
14
|
-
The page at <code class="text-sm bg-[var(--
|
|
11
|
+
<p class="text-8xl font-bold text-[var(--bd-text-muted)] select-none" aria-hidden="true">404</p>
|
|
12
|
+
<h1 class="text-2xl font-semibold text-[var(--bd-text)] mt-4">Page not found</h1>
|
|
13
|
+
<p class="text-[var(--bd-text-secondary)] mt-2">
|
|
14
|
+
The page at <code class="text-sm bg-[var(--bd-bg-subtle)] px-2 py-1 rounded break-all">{pathname}</code> does not exist.
|
|
15
15
|
</p>
|
|
16
16
|
<div class="flex flex-col sm:flex-row items-center justify-center gap-3 mt-8">
|
|
17
17
|
<a
|
|
@@ -22,7 +22,7 @@ const pathname = new URL(Astro.request.url).pathname;
|
|
|
22
22
|
</a>
|
|
23
23
|
<a
|
|
24
24
|
href="/docs/introduction"
|
|
25
|
-
class="px-5 py-2.5 border border-[var(--
|
|
25
|
+
class="px-5 py-2.5 border border-[var(--bd-border)] text-[var(--bd-text)] rounded-xl hover:bg-[var(--bd-bg-subtle)] transition-colors font-medium"
|
|
26
26
|
>
|
|
27
27
|
Documentation
|
|
28
28
|
</a>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getCollection } from "astro:content";
|
|
3
|
+
import BlogLayout from "../../layouts/BlogLayout.astro";
|
|
4
|
+
import readingTime from "reading-time";
|
|
5
|
+
|
|
6
|
+
export async function getStaticPaths() {
|
|
7
|
+
let posts: Awaited<ReturnType<typeof getCollection<"blog">>> = [];
|
|
8
|
+
try {
|
|
9
|
+
posts = await getCollection("blog");
|
|
10
|
+
} catch {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return posts.map((post) => ({
|
|
15
|
+
params: { slug: post.slug },
|
|
16
|
+
props: { post },
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
post: Awaited<ReturnType<typeof getCollection<"blog">>>[number];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const { post } = Astro.props;
|
|
25
|
+
const { Content } = await post.render();
|
|
26
|
+
const readTime = readingTime(post.body ?? "");
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
<BlogLayout
|
|
30
|
+
title={post.data.title}
|
|
31
|
+
description={post.data.description || post.data.excerpt}
|
|
32
|
+
date={post.data.date ? new Date(post.data.date) : undefined}
|
|
33
|
+
author={post.data.author}
|
|
34
|
+
image={post.data.image}
|
|
35
|
+
tags={post.data.tags}
|
|
36
|
+
readingTime={readTime.text}
|
|
37
|
+
>
|
|
38
|
+
<Content />
|
|
39
|
+
</BlogLayout>
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getCollection } from "astro:content";
|
|
3
|
+
import BaseLayout from "../../layouts/BaseLayout.astro";
|
|
4
|
+
import Header from "../../components/Header.astro";
|
|
5
|
+
import Banner from "../../components/Banner.astro";
|
|
6
|
+
import { defaultLocale } from "virtual:barodoc/i18n";
|
|
7
|
+
import { getLocaleFromPath } from "@barodoc/core";
|
|
8
|
+
import config from "virtual:barodoc/config";
|
|
9
|
+
|
|
10
|
+
const currentPath = Astro.url.pathname;
|
|
11
|
+
const i18nConfig = { defaultLocale, locales: [defaultLocale] };
|
|
12
|
+
const currentLocale = getLocaleFromPath(currentPath, i18nConfig);
|
|
13
|
+
|
|
14
|
+
let posts: Awaited<ReturnType<typeof getCollection<"blog">>> = [];
|
|
15
|
+
try {
|
|
16
|
+
posts = await getCollection("blog");
|
|
17
|
+
} catch {
|
|
18
|
+
// blog collection may not exist
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const sortedPosts = posts.sort((a, b) => {
|
|
22
|
+
const dateA = a.data.date ? new Date(a.data.date).getTime() : 0;
|
|
23
|
+
const dateB = b.data.date ? new Date(b.data.date).getTime() : 0;
|
|
24
|
+
return dateB - dateA;
|
|
25
|
+
});
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
<BaseLayout title={`Blog - ${config.name}`} description="Latest blog posts and updates">
|
|
29
|
+
<Banner />
|
|
30
|
+
<Header currentLocale={currentLocale} currentPath={currentPath} />
|
|
31
|
+
|
|
32
|
+
<div class="w-full min-w-0 min-h-[calc(100vh-3.5rem)] flex justify-center">
|
|
33
|
+
<div class="w-full max-w-[960px] px-4 py-10 sm:px-6 lg:px-8">
|
|
34
|
+
<header class="mb-10">
|
|
35
|
+
<h1 class="text-3xl font-bold tracking-tight text-[var(--bd-text-heading)]">Blog</h1>
|
|
36
|
+
<p class="mt-2 text-[var(--bd-text-secondary)]">Latest posts and updates</p>
|
|
37
|
+
</header>
|
|
38
|
+
|
|
39
|
+
{sortedPosts.length === 0 ? (
|
|
40
|
+
<p class="text-[var(--bd-text-muted)]">No posts yet.</p>
|
|
41
|
+
) : (
|
|
42
|
+
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
43
|
+
{sortedPosts.map((post) => (
|
|
44
|
+
<a
|
|
45
|
+
href={`/blog/${post.slug}`}
|
|
46
|
+
class="group flex flex-col rounded-lg border border-[var(--bd-border)] hover:border-primary-400/50 dark:hover:border-primary-500/40 hover:shadow-[var(--bd-shadow-sm)] transition-all overflow-hidden"
|
|
47
|
+
>
|
|
48
|
+
{post.data.image && (
|
|
49
|
+
<div class="aspect-[16/9] overflow-hidden bg-[var(--bd-bg-subtle)]">
|
|
50
|
+
<img
|
|
51
|
+
src={post.data.image}
|
|
52
|
+
alt={post.data.title}
|
|
53
|
+
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
|
|
54
|
+
loading="lazy"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
)}
|
|
58
|
+
<div class="flex flex-col gap-2 p-5">
|
|
59
|
+
{post.data.tags && post.data.tags.length > 0 && (
|
|
60
|
+
<div class="flex flex-wrap gap-1.5">
|
|
61
|
+
{post.data.tags.slice(0, 3).map((tag: string) => (
|
|
62
|
+
<span class="text-[11px] font-medium px-2 py-0.5 rounded-full bg-primary-50 text-primary-700 dark:bg-primary-950 dark:text-primary-300">
|
|
63
|
+
{tag}
|
|
64
|
+
</span>
|
|
65
|
+
))}
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
<h2 class="text-base font-semibold text-[var(--bd-text)] group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors leading-snug">
|
|
69
|
+
{post.data.title}
|
|
70
|
+
</h2>
|
|
71
|
+
{post.data.excerpt && (
|
|
72
|
+
<p class="text-sm text-[var(--bd-text-muted)] line-clamp-2">
|
|
73
|
+
{post.data.excerpt}
|
|
74
|
+
</p>
|
|
75
|
+
)}
|
|
76
|
+
<div class="mt-auto pt-2 flex items-center gap-2 text-xs text-[var(--bd-text-muted)]">
|
|
77
|
+
{post.data.author && <span>{post.data.author}</span>}
|
|
78
|
+
{post.data.author && post.data.date && <span>·</span>}
|
|
79
|
+
{post.data.date && (
|
|
80
|
+
<time datetime={new Date(post.data.date).toISOString()}>
|
|
81
|
+
{new Date(post.data.date).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" })}
|
|
82
|
+
</time>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</a>
|
|
87
|
+
))}
|
|
88
|
+
</div>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
</BaseLayout>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getCollection } from "astro:content";
|
|
3
|
+
import BaseLayout from "../../layouts/BaseLayout.astro";
|
|
4
|
+
import Header from "../../components/Header.astro";
|
|
5
|
+
import Banner from "../../components/Banner.astro";
|
|
6
|
+
import { defaultLocale } from "virtual:barodoc/i18n";
|
|
7
|
+
import { getLocaleFromPath } from "@barodoc/core";
|
|
8
|
+
import config from "virtual:barodoc/config";
|
|
9
|
+
|
|
10
|
+
const currentPath = Astro.url.pathname;
|
|
11
|
+
const i18nConfig = { defaultLocale, locales: [defaultLocale] };
|
|
12
|
+
const currentLocale = getLocaleFromPath(currentPath, i18nConfig);
|
|
13
|
+
|
|
14
|
+
let entries: Awaited<ReturnType<typeof getCollection<"changelog">>> = [];
|
|
15
|
+
try {
|
|
16
|
+
entries = await getCollection("changelog");
|
|
17
|
+
} catch {
|
|
18
|
+
// changelog collection may not exist
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const sorted = entries.sort((a, b) => {
|
|
22
|
+
return new Date(b.data.date).getTime() - new Date(a.data.date).getTime();
|
|
23
|
+
});
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
<BaseLayout title={`Changelog - ${config.name}`} description="Release history and changelog">
|
|
27
|
+
<Banner />
|
|
28
|
+
<Header currentLocale={currentLocale} currentPath={currentPath} />
|
|
29
|
+
|
|
30
|
+
<div class="w-full min-w-0 min-h-[calc(100vh-3.5rem)] flex justify-center">
|
|
31
|
+
<div class="w-full max-w-[720px] px-4 py-10 sm:px-6 lg:px-8">
|
|
32
|
+
<header class="mb-10">
|
|
33
|
+
<h1 class="text-3xl font-bold tracking-tight text-[var(--bd-text-heading)]">Changelog</h1>
|
|
34
|
+
<p class="mt-2 text-[var(--bd-text-secondary)]">Release history and notable changes</p>
|
|
35
|
+
</header>
|
|
36
|
+
|
|
37
|
+
{sorted.length === 0 ? (
|
|
38
|
+
<p class="text-[var(--bd-text-muted)]">No changelog entries yet.</p>
|
|
39
|
+
) : (
|
|
40
|
+
<div class="bd-changelog-timeline">
|
|
41
|
+
{sorted.map(async (entry) => {
|
|
42
|
+
const { Content } = await entry.render();
|
|
43
|
+
return (
|
|
44
|
+
<article class="bd-changelog-entry">
|
|
45
|
+
<div class="bd-changelog-marker">
|
|
46
|
+
<div class="bd-changelog-dot" />
|
|
47
|
+
<div class="bd-changelog-line" />
|
|
48
|
+
</div>
|
|
49
|
+
<div class="bd-changelog-content">
|
|
50
|
+
<div class="bd-changelog-header">
|
|
51
|
+
<span class="bd-changelog-version">{entry.data.version}</span>
|
|
52
|
+
<time class="bd-changelog-date" datetime={new Date(entry.data.date).toISOString()}>
|
|
53
|
+
{new Date(entry.data.date).toLocaleDateString("en-US", {
|
|
54
|
+
year: "numeric", month: "long", day: "numeric",
|
|
55
|
+
})}
|
|
56
|
+
</time>
|
|
57
|
+
</div>
|
|
58
|
+
{entry.data.title && (
|
|
59
|
+
<h2 class="bd-changelog-title">{entry.data.title}</h2>
|
|
60
|
+
)}
|
|
61
|
+
<div class="prose prose-sm prose-gray dark:prose-invert max-w-none bd-changelog-body">
|
|
62
|
+
<Content />
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</article>
|
|
66
|
+
);
|
|
67
|
+
})}
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</BaseLayout>
|
|
@@ -4,6 +4,7 @@ import DocsLayout from "../../layouts/DocsLayout.astro";
|
|
|
4
4
|
import config from "virtual:barodoc/config";
|
|
5
5
|
import { defaultLocale, locales } from "virtual:barodoc/i18n";
|
|
6
6
|
import { getLocalizedNavGroup } from "@barodoc/core";
|
|
7
|
+
import readingTime from "reading-time";
|
|
7
8
|
|
|
8
9
|
export async function getStaticPaths() {
|
|
9
10
|
const docs = await getCollection("docs");
|
|
@@ -41,6 +42,7 @@ interface Props {
|
|
|
41
42
|
|
|
42
43
|
const { doc, locale, cleanSlug } = Astro.props;
|
|
43
44
|
const { Content, headings } = await doc.render();
|
|
45
|
+
const readTime = readingTime(doc.body ?? "");
|
|
44
46
|
|
|
45
47
|
// Find the category (navigation group) for this page
|
|
46
48
|
function findCategory(slug: string): string | null {
|
|
@@ -122,15 +124,17 @@ breadcrumbs.push({ label: doc.data.title });
|
|
|
122
124
|
editUrl={editUrl}
|
|
123
125
|
lastUpdated={lastUpdated}
|
|
124
126
|
breadcrumbs={breadcrumbs}
|
|
127
|
+
readingTime={readTime.text}
|
|
128
|
+
filePath={doc.id}
|
|
125
129
|
>
|
|
126
130
|
{category && (
|
|
127
|
-
<p class="text-xs font-
|
|
131
|
+
<p class="text-xs font-semibold uppercase tracking-widest text-primary-600 dark:text-primary-400 mb-3">
|
|
128
132
|
{category}
|
|
129
133
|
</p>
|
|
130
134
|
)}
|
|
131
135
|
<h1>{doc.data.title}</h1>
|
|
132
136
|
{doc.data.description && (
|
|
133
|
-
<p class="lead text-
|
|
137
|
+
<p class="lead text-base text-[var(--bd-text-secondary)] mt-2 mb-6 leading-relaxed">
|
|
134
138
|
{doc.data.description}
|
|
135
139
|
</p>
|
|
136
140
|
)}
|
package/src/pages/index.astro
CHANGED
|
@@ -40,10 +40,10 @@ const features = [
|
|
|
40
40
|
<BaseLayout title={config.name}>
|
|
41
41
|
<div class="min-h-screen flex flex-col">
|
|
42
42
|
<!-- Header -->
|
|
43
|
-
<header class="sticky top-0 z-50 border-b border-[var(--
|
|
43
|
+
<header class="sticky top-0 z-50 border-b border-[var(--bd-border)] bg-[var(--bd-bg)]/95 backdrop-blur-md">
|
|
44
44
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
45
45
|
<div class="flex h-16 items-center justify-between">
|
|
46
|
-
<a href="/" class="flex items-center gap-2.5 font-semibold text-[var(--
|
|
46
|
+
<a href="/" class="flex items-center gap-2.5 font-semibold text-[var(--bd-text)]">
|
|
47
47
|
{config.logo && <img src={config.logo} alt={config.name} class="h-7 w-7" />}
|
|
48
48
|
<span class="text-lg">{config.name}</span>
|
|
49
49
|
</a>
|
|
@@ -53,7 +53,7 @@ const features = [
|
|
|
53
53
|
href={config.topbar.github}
|
|
54
54
|
target="_blank"
|
|
55
55
|
rel="noopener noreferrer"
|
|
56
|
-
class="p-2.5 rounded-xl text-[var(--
|
|
56
|
+
class="p-2.5 rounded-xl text-[var(--bd-text-secondary)] hover:text-[var(--bd-text)] hover:bg-[var(--bd-bg-subtle)] transition-all"
|
|
57
57
|
aria-label="GitHub"
|
|
58
58
|
>
|
|
59
59
|
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
|
@@ -91,12 +91,12 @@ const features = [
|
|
|
91
91
|
<span class="text-sm font-medium text-primary-700 dark:text-primary-300">Powered by Astro</span>
|
|
92
92
|
</div>
|
|
93
93
|
|
|
94
|
-
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight text-[var(--
|
|
94
|
+
<h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight text-[var(--bd-text)] mb-6 leading-tight">
|
|
95
95
|
Build beautiful
|
|
96
96
|
<span class="text-transparent bg-clip-text bg-gradient-to-r from-primary-600 to-primary-400"> documentation</span>
|
|
97
97
|
</h1>
|
|
98
98
|
|
|
99
|
-
<p class="text-lg sm:text-xl text-[var(--
|
|
99
|
+
<p class="text-lg sm:text-xl text-[var(--bd-text-secondary)] mb-10 max-w-2xl mx-auto leading-relaxed">
|
|
100
100
|
Create stunning documentation sites with MDX, Astro, and Tailwind CSS.
|
|
101
101
|
Deploy anywhere with static site generation.
|
|
102
102
|
</p>
|
|
@@ -110,19 +110,19 @@ const features = [
|
|
|
110
110
|
</a>
|
|
111
111
|
<a
|
|
112
112
|
href="/docs/quickstart"
|
|
113
|
-
class="w-full sm:w-auto px-8 py-3.5 border border-[var(--
|
|
113
|
+
class="w-full sm:w-auto px-8 py-3.5 border border-[var(--bd-border)] text-[var(--bd-text)] rounded-xl hover:bg-[var(--bd-bg-subtle)] hover:border-[var(--bd-text-muted)] transition-all font-medium"
|
|
114
114
|
>
|
|
115
115
|
Quick Start
|
|
116
116
|
</a>
|
|
117
117
|
</div>
|
|
118
118
|
|
|
119
119
|
<!-- Install command -->
|
|
120
|
-
<div class="mt-12 inline-flex items-center gap-3 px-5 py-3 bg-[var(--
|
|
121
|
-
<code class="text-sm text-[var(--
|
|
120
|
+
<div class="mt-12 inline-flex items-center gap-3 px-5 py-3 bg-[var(--bd-bg-subtle)] border border-[var(--bd-border)] rounded-xl">
|
|
121
|
+
<code class="text-sm text-[var(--bd-text-secondary)] font-mono">
|
|
122
122
|
npx create-barodoc my-docs
|
|
123
123
|
</code>
|
|
124
124
|
<button
|
|
125
|
-
class="p-1.5 rounded-lg hover:bg-[var(--
|
|
125
|
+
class="p-1.5 rounded-lg hover:bg-[var(--bd-bg-muted)] text-[var(--bd-text-muted)] hover:text-[var(--bd-text)] transition-colors"
|
|
126
126
|
onclick="navigator.clipboard.writeText('npx create-barodoc my-docs')"
|
|
127
127
|
aria-label="Copy command"
|
|
128
128
|
>
|
|
@@ -136,27 +136,27 @@ const features = [
|
|
|
136
136
|
</div>
|
|
137
137
|
|
|
138
138
|
<!-- Features Section -->
|
|
139
|
-
<div class="py-20 bg-[var(--
|
|
139
|
+
<div class="py-20 bg-[var(--bd-bg-subtle)] border-y border-[var(--bd-border)]">
|
|
140
140
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
141
141
|
<div class="text-center mb-16">
|
|
142
|
-
<h2 class="text-3xl font-bold text-[var(--
|
|
142
|
+
<h2 class="text-3xl font-bold text-[var(--bd-text)] mb-4">
|
|
143
143
|
Everything you need
|
|
144
144
|
</h2>
|
|
145
|
-
<p class="text-lg text-[var(--
|
|
145
|
+
<p class="text-lg text-[var(--bd-text-secondary)] max-w-2xl mx-auto">
|
|
146
146
|
Barodoc comes with all the features you need to create beautiful documentation.
|
|
147
147
|
</p>
|
|
148
148
|
</div>
|
|
149
149
|
|
|
150
150
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
151
151
|
{features.map((feature) => (
|
|
152
|
-
<div class="group p-6 bg-[var(--
|
|
152
|
+
<div class="group p-6 bg-[var(--bd-bg)] rounded-2xl border border-[var(--bd-border)] hover:border-primary-300 dark:hover:border-primary-700 hover:shadow-lg transition-all duration-200">
|
|
153
153
|
<div class="flex items-center justify-center w-12 h-12 rounded-xl bg-primary-50 dark:bg-primary-950/50 mb-4 group-hover:scale-110 transition-transform">
|
|
154
154
|
<span class="text-2xl">{feature.icon}</span>
|
|
155
155
|
</div>
|
|
156
|
-
<h3 class="text-lg font-semibold text-[var(--
|
|
156
|
+
<h3 class="text-lg font-semibold text-[var(--bd-text)] mb-2">
|
|
157
157
|
{feature.title}
|
|
158
158
|
</h3>
|
|
159
|
-
<p class="text-sm text-[var(--
|
|
159
|
+
<p class="text-sm text-[var(--bd-text-secondary)] leading-relaxed">
|
|
160
160
|
{feature.description}
|
|
161
161
|
</p>
|
|
162
162
|
</div>
|
|
@@ -168,10 +168,10 @@ const features = [
|
|
|
168
168
|
<!-- CTA Section -->
|
|
169
169
|
<div class="py-20">
|
|
170
170
|
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
|
171
|
-
<h2 class="text-3xl font-bold text-[var(--
|
|
171
|
+
<h2 class="text-3xl font-bold text-[var(--bd-text)] mb-4">
|
|
172
172
|
Ready to get started?
|
|
173
173
|
</h2>
|
|
174
|
-
<p class="text-lg text-[var(--
|
|
174
|
+
<p class="text-lg text-[var(--bd-text-secondary)] mb-8">
|
|
175
175
|
Create your documentation site in minutes.
|
|
176
176
|
</p>
|
|
177
177
|
<a
|
|
@@ -185,10 +185,10 @@ const features = [
|
|
|
185
185
|
</main>
|
|
186
186
|
|
|
187
187
|
<!-- Footer -->
|
|
188
|
-
<footer class="border-t border-[var(--
|
|
188
|
+
<footer class="border-t border-[var(--bd-border)] bg-[var(--bd-bg-subtle)]">
|
|
189
189
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
190
190
|
<div class="flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
191
|
-
<div class="flex items-center gap-2 text-[var(--
|
|
191
|
+
<div class="flex items-center gap-2 text-[var(--bd-text-secondary)]">
|
|
192
192
|
{config.logo && <img src={config.logo} alt={config.name} class="h-5 w-5 opacity-60" />}
|
|
193
193
|
<span class="text-sm">Built with Barodoc</span>
|
|
194
194
|
</div>
|
|
@@ -198,14 +198,14 @@ const features = [
|
|
|
198
198
|
href={config.topbar.github}
|
|
199
199
|
target="_blank"
|
|
200
200
|
rel="noopener noreferrer"
|
|
201
|
-
class="text-sm text-[var(--
|
|
201
|
+
class="text-sm text-[var(--bd-text-secondary)] hover:text-[var(--bd-text)] transition-colors"
|
|
202
202
|
>
|
|
203
203
|
GitHub
|
|
204
204
|
</a>
|
|
205
205
|
)}
|
|
206
206
|
<a
|
|
207
207
|
href="/docs/introduction"
|
|
208
|
-
class="text-sm text-[var(--
|
|
208
|
+
class="text-sm text-[var(--bd-text-secondary)] hover:text-[var(--bd-text)] transition-colors"
|
|
209
209
|
>
|
|
210
210
|
Documentation
|
|
211
211
|
</a>
|