@farming-labs/astro-theme 0.0.2-beta.15 → 0.0.2-beta.17
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 +11 -4
- package/src/components/DocsContent.astro +3 -0
- package/src/components/DocsLayout.astro +16 -1
- package/src/components/DocsPage.astro +180 -20
- package/src/components/FloatingAIChat.astro +28 -13
- package/src/themes/colorful.d.ts +2 -0
- package/src/themes/colorful.js +42 -0
- package/styles/colorful-bundle.css +2 -0
- package/styles/colorful.css +148 -0
- package/styles/docs.css +71 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farming-labs/astro-theme",
|
|
3
|
-
"version": "0.0.2-beta.
|
|
3
|
+
"version": "0.0.2-beta.17",
|
|
4
4
|
"description": "Astro UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -25,12 +25,19 @@
|
|
|
25
25
|
"import": "./src/themes/darksharp.js",
|
|
26
26
|
"default": "./src/themes/darksharp.js"
|
|
27
27
|
},
|
|
28
|
+
"./colorful": {
|
|
29
|
+
"types": "./src/themes/colorful.d.ts",
|
|
30
|
+
"import": "./src/themes/colorful.js",
|
|
31
|
+
"default": "./src/themes/colorful.js"
|
|
32
|
+
},
|
|
28
33
|
"./css": "./styles/docs.css",
|
|
29
34
|
"./fumadocs/css": "./styles/docs.css",
|
|
30
35
|
"./styles/pixel-border.css": "./styles/pixel-border.css",
|
|
31
36
|
"./styles/darksharp.css": "./styles/darksharp.css",
|
|
32
37
|
"./pixel-border/css": "./styles/pixel-border-bundle.css",
|
|
33
|
-
"./darksharp/css": "./styles/darksharp-bundle.css"
|
|
38
|
+
"./darksharp/css": "./styles/darksharp-bundle.css",
|
|
39
|
+
"./styles/colorful.css": "./styles/colorful.css",
|
|
40
|
+
"./colorful/css": "./styles/colorful-bundle.css"
|
|
34
41
|
},
|
|
35
42
|
"typesVersions": {
|
|
36
43
|
"*": {
|
|
@@ -62,8 +69,8 @@
|
|
|
62
69
|
"license": "MIT",
|
|
63
70
|
"dependencies": {
|
|
64
71
|
"sugar-high": "^0.9.5",
|
|
65
|
-
"@farming-labs/
|
|
66
|
-
"@farming-labs/
|
|
72
|
+
"@farming-labs/docs": "0.0.2-beta.17",
|
|
73
|
+
"@farming-labs/astro": "0.0.2-beta.17"
|
|
67
74
|
},
|
|
68
75
|
"peerDependencies": {
|
|
69
76
|
"astro": ">=4.0.0"
|
|
@@ -8,6 +8,7 @@ const titleSuffix = config?.metadata?.titleTemplate
|
|
|
8
8
|
: " – Docs";
|
|
9
9
|
|
|
10
10
|
const tocEnabled = config?.theme?.ui?.layout?.toc?.enabled ?? true;
|
|
11
|
+
const tocStyle = config?.theme?.ui?.layout?.toc?.style ?? "default";
|
|
11
12
|
|
|
12
13
|
const breadcrumbEnabled = (() => {
|
|
13
14
|
const bc = config?.breadcrumb;
|
|
@@ -29,11 +30,13 @@ const showLastModified = !!data.lastModified;
|
|
|
29
30
|
<DocsPage
|
|
30
31
|
entry={config?.entry ?? "docs"}
|
|
31
32
|
tocEnabled={tocEnabled}
|
|
33
|
+
tocStyle={tocStyle}
|
|
32
34
|
breadcrumbEnabled={breadcrumbEnabled}
|
|
33
35
|
previousPage={data.previousPage}
|
|
34
36
|
nextPage={data.nextPage}
|
|
35
37
|
editOnGithub={showEditOnGithub ? data.editOnGithub : null}
|
|
36
38
|
lastModified={showLastModified ? data.lastModified : null}
|
|
37
39
|
>
|
|
40
|
+
{data.description && <p class="fd-page-description">{data.description}</p>}
|
|
38
41
|
<Fragment set:html={data.html} />
|
|
39
42
|
</DocsPage>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import ThemeToggle from "./ThemeToggle.astro";
|
|
3
|
+
import FloatingAIChat from "./FloatingAIChat.astro";
|
|
3
4
|
|
|
4
5
|
const { tree, config = null, title, titleUrl } = Astro.props;
|
|
5
6
|
|
|
@@ -60,7 +61,7 @@ function buildColorsCSS(colors?: Record<string, string | undefined>): string {
|
|
|
60
61
|
vars.push(`${COLOR_MAP[key]}: ${value};`);
|
|
61
62
|
}
|
|
62
63
|
if (vars.length === 0) return "";
|
|
63
|
-
return
|
|
64
|
+
return `.dark {\n ${vars.join("\n ")}\n}`;
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
function buildFontStyleVars(prefix: string, style?: { size?: string; weight?: string | number; lineHeight?: string; letterSpacing?: string }): string {
|
|
@@ -270,6 +271,20 @@ const showFloatingAI = aiConfig?.mode === "floating" && aiConfig?.enabled;
|
|
|
270
271
|
</main>
|
|
271
272
|
</div>
|
|
272
273
|
|
|
274
|
+
{showFloatingAI && (
|
|
275
|
+
<FloatingAIChat
|
|
276
|
+
api="/api/docs"
|
|
277
|
+
suggestedQuestions={aiConfig?.suggestedQuestions ?? []}
|
|
278
|
+
aiLabel={aiConfig?.aiLabel ?? "AI"}
|
|
279
|
+
position={aiConfig?.position ?? "bottom-right"}
|
|
280
|
+
floatingStyle={aiConfig?.floatingStyle ?? "panel"}
|
|
281
|
+
>
|
|
282
|
+
{Astro.slots.has("ai-trigger") && (
|
|
283
|
+
<slot name="ai-trigger" slot="trigger" />
|
|
284
|
+
)}
|
|
285
|
+
</FloatingAIChat>
|
|
286
|
+
)}
|
|
287
|
+
|
|
273
288
|
<script>
|
|
274
289
|
// Sidebar toggle
|
|
275
290
|
const menuBtn = document.getElementById('fd-menu-toggle');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
const {
|
|
3
3
|
tocEnabled = true,
|
|
4
|
+
tocStyle = "default",
|
|
4
5
|
breadcrumbEnabled = true,
|
|
5
6
|
entry = "docs",
|
|
6
7
|
previousPage = null,
|
|
@@ -10,16 +11,12 @@ const {
|
|
|
10
11
|
} = Astro.props;
|
|
11
12
|
|
|
12
13
|
const pathname = Astro.url.pathname;
|
|
13
|
-
const segments = pathname.split("/").filter(Boolean)
|
|
14
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
14
15
|
const parentLabel = segments.length >= 2 ? segments[segments.length - 2].replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase()) : "";
|
|
15
16
|
const currentLabel = segments.length >= 2 ? segments[segments.length - 1].replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase()) : "";
|
|
16
|
-
const parentUrl =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const parentSegment = segments[segments.length - 2];
|
|
20
|
-
const parentIndex = all.indexOf(parentSegment);
|
|
21
|
-
return "/" + all.slice(0, parentIndex + 1).join("/");
|
|
22
|
-
})();
|
|
17
|
+
const parentUrl = segments.length >= 2
|
|
18
|
+
? "/" + segments.slice(0, segments.length - 1).join("/")
|
|
19
|
+
: "";
|
|
23
20
|
---
|
|
24
21
|
|
|
25
22
|
<div class="fd-page">
|
|
@@ -89,7 +86,7 @@ const parentUrl = (() => {
|
|
|
89
86
|
|
|
90
87
|
{tocEnabled && (
|
|
91
88
|
<aside class="fd-toc">
|
|
92
|
-
<div class=
|
|
89
|
+
<div class={`fd-toc-inner ${tocStyle === "directional" ? "fd-toc-directional" : ""}`} data-toc-style={tocStyle}>
|
|
93
90
|
<h3 class="fd-toc-title">
|
|
94
91
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
95
92
|
<line x1="3" y1="6" x2="21" y2="6" />
|
|
@@ -98,42 +95,205 @@ const parentUrl = (() => {
|
|
|
98
95
|
</svg>
|
|
99
96
|
On this page
|
|
100
97
|
</h3>
|
|
101
|
-
<ul class=
|
|
98
|
+
<ul class={`fd-toc-list ${tocStyle === "directional" ? "fd-toc-clerk" : ""}`} id="fd-toc-list" style={tocStyle === "directional" ? "position:relative" : ""}></ul>
|
|
102
99
|
</div>
|
|
103
100
|
</aside>
|
|
104
101
|
)}
|
|
105
102
|
</div>
|
|
106
103
|
|
|
107
104
|
<script>
|
|
105
|
+
function getItemOffset(depth) {
|
|
106
|
+
if (depth <= 2) return 14;
|
|
107
|
+
if (depth === 3) return 26;
|
|
108
|
+
return 36;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function getLineOffset(depth) {
|
|
112
|
+
return depth >= 3 ? 10 : 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
108
115
|
function initDocsPage() {
|
|
109
|
-
// Scan headings for TOC
|
|
110
116
|
const container = document.querySelector('.fd-page-body');
|
|
111
117
|
const tocList = document.getElementById('fd-toc-list');
|
|
112
118
|
if (container && tocList) {
|
|
113
119
|
const headings = container.querySelectorAll('h2[id], h3[id], h4[id]');
|
|
114
120
|
tocList.innerHTML = '';
|
|
121
|
+
const isClerk = tocList.closest('[data-toc-style]')?.getAttribute('data-toc-style') === 'directional';
|
|
122
|
+
|
|
123
|
+
const tocItems = [];
|
|
115
124
|
headings.forEach(el => {
|
|
116
|
-
|
|
125
|
+
tocItems.push({
|
|
126
|
+
id: el.id,
|
|
127
|
+
title: el.textContent?.replace(/^#\s*/, '') || '',
|
|
128
|
+
depth: parseInt(el.tagName[1], 10),
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
tocItems.forEach((item, index) => {
|
|
117
133
|
const li = document.createElement('li');
|
|
118
134
|
li.className = 'fd-toc-item';
|
|
119
135
|
const a = document.createElement('a');
|
|
120
|
-
a.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
136
|
+
a.href = `#${item.id}`;
|
|
137
|
+
|
|
138
|
+
if (isClerk) {
|
|
139
|
+
a.className = 'fd-toc-link fd-toc-clerk-link';
|
|
140
|
+
a.style.position = 'relative';
|
|
141
|
+
a.style.paddingLeft = `${getItemOffset(item.depth)}px`;
|
|
142
|
+
a.style.paddingTop = '6px';
|
|
143
|
+
a.style.paddingBottom = '6px';
|
|
144
|
+
a.style.fontSize = item.depth <= 2 ? '14px' : '13px';
|
|
145
|
+
a.style.overflowWrap = 'anywhere';
|
|
146
|
+
|
|
147
|
+
const prevDepth = index > 0 ? tocItems[index - 1].depth : item.depth;
|
|
148
|
+
const nextDepth = index < tocItems.length - 1 ? tocItems[index + 1].depth : item.depth;
|
|
149
|
+
const lineDiv = document.createElement('div');
|
|
150
|
+
lineDiv.style.position = 'absolute';
|
|
151
|
+
lineDiv.style.left = `${getLineOffset(item.depth)}px`;
|
|
152
|
+
lineDiv.style.top = prevDepth !== item.depth ? '6px' : '0';
|
|
153
|
+
lineDiv.style.bottom = nextDepth !== item.depth ? '6px' : '0';
|
|
154
|
+
lineDiv.style.width = '1px';
|
|
155
|
+
lineDiv.style.background = 'hsla(0, 0%, 50%, 0.1)';
|
|
156
|
+
a.appendChild(lineDiv);
|
|
157
|
+
|
|
158
|
+
if (index > 0 && tocItems[index - 1].depth !== item.depth) {
|
|
159
|
+
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
160
|
+
svg.setAttribute('viewBox', '0 0 16 16');
|
|
161
|
+
svg.setAttribute('width', '16');
|
|
162
|
+
svg.setAttribute('height', '16');
|
|
163
|
+
svg.style.position = 'absolute';
|
|
164
|
+
svg.style.top = '-6px';
|
|
165
|
+
svg.style.left = '0';
|
|
166
|
+
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
|
|
167
|
+
line.setAttribute('x1', String(getLineOffset(tocItems[index - 1].depth)));
|
|
168
|
+
line.setAttribute('y1', '0');
|
|
169
|
+
line.setAttribute('x2', String(getLineOffset(item.depth)));
|
|
170
|
+
line.setAttribute('y2', '12');
|
|
171
|
+
line.setAttribute('stroke', 'hsla(0, 0%, 50%, 0.1)');
|
|
172
|
+
line.setAttribute('stroke-width', '1');
|
|
173
|
+
svg.appendChild(line);
|
|
174
|
+
a.appendChild(svg);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
a.appendChild(document.createTextNode(item.title));
|
|
178
|
+
} else {
|
|
179
|
+
a.className = 'fd-toc-link';
|
|
180
|
+
a.style.paddingLeft = `${12 + (item.depth - 2) * 12}px`;
|
|
181
|
+
a.textContent = item.title;
|
|
182
|
+
}
|
|
183
|
+
|
|
124
184
|
li.appendChild(a);
|
|
125
185
|
tocList.appendChild(li);
|
|
126
186
|
});
|
|
127
187
|
|
|
128
|
-
|
|
188
|
+
let maskEl = null;
|
|
189
|
+
let thumbEl = null;
|
|
190
|
+
|
|
191
|
+
if (isClerk) {
|
|
192
|
+
function buildSvgPath() {
|
|
193
|
+
const links = tocList.querySelectorAll('.fd-toc-clerk-link');
|
|
194
|
+
if (links.length === 0) return null;
|
|
195
|
+
const d = [];
|
|
196
|
+
let w = 0, h = 0;
|
|
197
|
+
links.forEach((el, i) => {
|
|
198
|
+
if (i >= tocItems.length) return;
|
|
199
|
+
const depth = tocItems[i].depth;
|
|
200
|
+
const x = getLineOffset(depth) + 1;
|
|
201
|
+
const styles = getComputedStyle(el);
|
|
202
|
+
const top = el.offsetTop + parseFloat(styles.paddingTop);
|
|
203
|
+
const bottom = el.offsetTop + el.clientHeight - parseFloat(styles.paddingBottom);
|
|
204
|
+
w = Math.max(x, w);
|
|
205
|
+
h = Math.max(h, bottom);
|
|
206
|
+
d.push(`${i === 0 ? "M" : "L"}${x} ${top}`);
|
|
207
|
+
d.push(`L${x} ${bottom}`);
|
|
208
|
+
});
|
|
209
|
+
return { path: d.join(" "), width: w + 1, height: h };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function updateThumb(activeSet) {
|
|
213
|
+
if (!thumbEl) return;
|
|
214
|
+
const links = tocList.querySelectorAll('.fd-toc-clerk-link');
|
|
215
|
+
if (activeSet.size === 0 || links.length === 0) {
|
|
216
|
+
thumbEl.style.marginTop = '0px';
|
|
217
|
+
thumbEl.style.height = '0px';
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
let upper = Infinity, lower = 0;
|
|
221
|
+
for (const id of activeSet) {
|
|
222
|
+
const el = tocList.querySelector(`a[href="#${id}"]`);
|
|
223
|
+
if (!el) continue;
|
|
224
|
+
const styles = getComputedStyle(el);
|
|
225
|
+
upper = Math.min(upper, el.offsetTop + parseFloat(styles.paddingTop));
|
|
226
|
+
lower = Math.max(lower, el.offsetTop + el.clientHeight - parseFloat(styles.paddingBottom));
|
|
227
|
+
}
|
|
228
|
+
if (upper === Infinity) {
|
|
229
|
+
thumbEl.style.marginTop = '0px';
|
|
230
|
+
thumbEl.style.height = '0px';
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
thumbEl.style.marginTop = `${upper}px`;
|
|
234
|
+
thumbEl.style.height = `${lower - upper}px`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
requestAnimationFrame(() => {
|
|
238
|
+
const svgData = buildSvgPath();
|
|
239
|
+
if (svgData) {
|
|
240
|
+
maskEl = document.createElement('div');
|
|
241
|
+
maskEl.className = 'fd-toc-clerk-mask';
|
|
242
|
+
maskEl.style.position = 'absolute';
|
|
243
|
+
maskEl.style.left = '0';
|
|
244
|
+
maskEl.style.top = '0';
|
|
245
|
+
maskEl.style.width = svgData.width + 'px';
|
|
246
|
+
maskEl.style.height = svgData.height + 'px';
|
|
247
|
+
maskEl.style.pointerEvents = 'none';
|
|
248
|
+
const maskSvg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${svgData.width} ${svgData.height}"><path d="${svgData.path}" stroke="black" stroke-width="1" fill="none"/></svg>`;
|
|
249
|
+
const maskUrl = `url("data:image/svg+xml,${encodeURIComponent(maskSvg)}")`;
|
|
250
|
+
maskEl.style.maskImage = maskUrl;
|
|
251
|
+
maskEl.style.webkitMaskImage = maskUrl;
|
|
252
|
+
maskEl.style.maskRepeat = 'no-repeat';
|
|
253
|
+
maskEl.style.webkitMaskRepeat = 'no-repeat';
|
|
254
|
+
|
|
255
|
+
thumbEl = document.createElement('div');
|
|
256
|
+
thumbEl.className = 'fd-toc-clerk-thumb';
|
|
257
|
+
thumbEl.style.background = 'var(--color-fd-primary)';
|
|
258
|
+
thumbEl.style.transition = 'all 0.15s';
|
|
259
|
+
thumbEl.style.willChange = 'height, margin-top';
|
|
260
|
+
thumbEl.style.marginTop = '0px';
|
|
261
|
+
thumbEl.style.height = '0px';
|
|
262
|
+
maskEl.appendChild(thumbEl);
|
|
263
|
+
tocList.appendChild(maskEl);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
var clerkActiveSet = new Set();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const activeSet = new Set();
|
|
271
|
+
|
|
129
272
|
const observer = new IntersectionObserver((entries) => {
|
|
130
273
|
for (const entry of entries) {
|
|
131
274
|
if (entry.isIntersecting) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
275
|
+
activeSet.add(entry.target.id);
|
|
276
|
+
} else {
|
|
277
|
+
activeSet.delete(entry.target.id);
|
|
135
278
|
}
|
|
136
279
|
}
|
|
280
|
+
|
|
281
|
+
if (isClerk) {
|
|
282
|
+
tocList.querySelectorAll('.fd-toc-clerk-link').forEach(link => {
|
|
283
|
+
const id = link.getAttribute('href')?.slice(1);
|
|
284
|
+
if (activeSet.has(id)) {
|
|
285
|
+
link.setAttribute('data-active', 'true');
|
|
286
|
+
} else {
|
|
287
|
+
link.removeAttribute('data-active');
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
if (typeof updateThumb === 'function') updateThumb(activeSet);
|
|
291
|
+
} else {
|
|
292
|
+
tocList.querySelectorAll('.fd-toc-link').forEach(link => {
|
|
293
|
+
const id = link.getAttribute('href')?.slice(1);
|
|
294
|
+
link.classList.toggle('fd-toc-link-active', activeSet.has(id));
|
|
295
|
+
});
|
|
296
|
+
}
|
|
137
297
|
}, { rootMargin: '-80px 0px -80% 0px' });
|
|
138
298
|
|
|
139
299
|
headings.forEach(el => observer.observe(el));
|
|
@@ -7,6 +7,8 @@ const {
|
|
|
7
7
|
floatingStyle = "panel",
|
|
8
8
|
} = Astro.props;
|
|
9
9
|
|
|
10
|
+
const hasCustomTrigger = Astro.slots.has("trigger");
|
|
11
|
+
|
|
10
12
|
const isFullModal = floatingStyle === "full-modal";
|
|
11
13
|
|
|
12
14
|
const BTN_POSITIONS: Record<string, string> = {
|
|
@@ -55,13 +57,19 @@ const containerStyle = getContainerStyle(floatingStyle, position);
|
|
|
55
57
|
|
|
56
58
|
<!-- Bottom input bar -->
|
|
57
59
|
<div class="fd-ai-fm-input-bar fd-ai-fm-input-bar--closed" id="fd-float-bar" style={btnStyle}>
|
|
58
|
-
|
|
59
|
-
<
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
60
|
+
{hasCustomTrigger ? (
|
|
61
|
+
<div id="fd-float-trigger" class="fd-ai-floating-trigger">
|
|
62
|
+
<slot name="trigger" />
|
|
63
|
+
</div>
|
|
64
|
+
) : (
|
|
65
|
+
<button id="fd-float-trigger" class="fd-ai-fm-trigger-btn" aria-label={`Ask ${aiLabel}`}>
|
|
66
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
67
|
+
<path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/>
|
|
68
|
+
<path d="M20 3v4"/><path d="M22 5h-4"/>
|
|
69
|
+
</svg>
|
|
70
|
+
<span>Ask {aiLabel}</span>
|
|
71
|
+
</button>
|
|
72
|
+
)}
|
|
65
73
|
|
|
66
74
|
<div id="fd-float-input-container" class="fd-ai-fm-input-container" style="display:none">
|
|
67
75
|
<div class="fd-ai-fm-input-wrap">
|
|
@@ -161,12 +169,19 @@ const containerStyle = getContainerStyle(floatingStyle, position);
|
|
|
161
169
|
</div>
|
|
162
170
|
|
|
163
171
|
<!-- Floating trigger button -->
|
|
164
|
-
|
|
165
|
-
<
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
{hasCustomTrigger ? (
|
|
173
|
+
<div id="fd-float-btn" class="fd-ai-floating-trigger" style={btnStyle}>
|
|
174
|
+
<slot name="trigger" />
|
|
175
|
+
</div>
|
|
176
|
+
) : (
|
|
177
|
+
<button id="fd-float-btn" class="fd-ai-floating-btn" style={btnStyle} aria-label={`Ask ${aiLabel}`}>
|
|
178
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
179
|
+
<path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/>
|
|
180
|
+
<path d="M20 3v4"/><path d="M22 5h-4"/>
|
|
181
|
+
</svg>
|
|
182
|
+
<span>Ask {aiLabel}</span>
|
|
183
|
+
</button>
|
|
184
|
+
)}
|
|
170
185
|
</Fragment>
|
|
171
186
|
)}
|
|
172
187
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createTheme } from "@farming-labs/docs";
|
|
2
|
+
|
|
3
|
+
const ColorfulUIDefaults = {
|
|
4
|
+
colors: {
|
|
5
|
+
primary: "hsl(40, 96%, 40%)",
|
|
6
|
+
background: "#ffffff",
|
|
7
|
+
muted: "#64748b",
|
|
8
|
+
border: "#e5e7eb",
|
|
9
|
+
},
|
|
10
|
+
typography: {
|
|
11
|
+
font: {
|
|
12
|
+
style: {
|
|
13
|
+
sans: "Inter, system-ui, sans-serif",
|
|
14
|
+
mono: "JetBrains Mono, monospace",
|
|
15
|
+
},
|
|
16
|
+
h1: { size: "1.875rem", weight: 700, lineHeight: "1.2", letterSpacing: "-0.02em" },
|
|
17
|
+
h2: { size: "1.5rem", weight: 600, lineHeight: "1.3" },
|
|
18
|
+
h3: { size: "1.25rem", weight: 600, lineHeight: "1.4" },
|
|
19
|
+
h4: { size: "1.125rem", weight: 600, lineHeight: "1.4" },
|
|
20
|
+
body: { size: "1rem", weight: 400, lineHeight: "1.75" },
|
|
21
|
+
small: { size: "0.875rem", weight: 400, lineHeight: "1.5" },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
layout: {
|
|
25
|
+
contentWidth: 768,
|
|
26
|
+
sidebarWidth: 260,
|
|
27
|
+
toc: { enabled: true, depth: 3, style: "directional" },
|
|
28
|
+
header: { height: 56, sticky: true },
|
|
29
|
+
},
|
|
30
|
+
components: {
|
|
31
|
+
Callout: { variant: "soft", icon: true },
|
|
32
|
+
CodeBlock: { showCopyButton: true },
|
|
33
|
+
Tabs: { style: "default" },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const colorful = createTheme({
|
|
38
|
+
name: "fumadocs-colorful",
|
|
39
|
+
ui: ColorfulUIDefaults,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export { ColorfulUIDefaults };
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/* @farming-labs/astro-theme — colorful theme overrides
|
|
2
|
+
* Fumadocs-inspired theme with warm yellow/amber accent colors.
|
|
3
|
+
* Import AFTER the base theme CSS (docs.css).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/* ─── Colorful yellow accent overrides ────────────────────────────── */
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
--color-fd-primary: hsl(40, 96%, 40%);
|
|
10
|
+
--color-fd-primary-foreground: hsl(0, 0%, 100%);
|
|
11
|
+
--color-fd-ring: hsl(40, 80%, 50%);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.dark {
|
|
15
|
+
--color-fd-primary: hsl(45, 100%, 60%);
|
|
16
|
+
--color-fd-primary-foreground: hsl(0, 0%, 5%);
|
|
17
|
+
--color-fd-ring: hsl(45, 90%, 55%);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* ─── Description under title ──────────────────────────────────────── */
|
|
21
|
+
|
|
22
|
+
.fd-page-description {
|
|
23
|
+
margin-bottom: 1rem;
|
|
24
|
+
font-size: 1.125rem;
|
|
25
|
+
line-height: 1.75;
|
|
26
|
+
color: var(--color-fd-muted-foreground);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/* ─── Sidebar dark overrides (fumadocs neutral) ────────────────────── */
|
|
30
|
+
|
|
31
|
+
.dark .fd-sidebar {
|
|
32
|
+
--color-fd-muted: hsl(0, 0%, 16%);
|
|
33
|
+
--color-fd-secondary: hsl(0, 0%, 18%);
|
|
34
|
+
--color-fd-muted-foreground: hsl(0, 0%, 72%);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* ─── Cards (fumadocs style) ────────────────────────────────────────── */
|
|
38
|
+
|
|
39
|
+
.fd-card {
|
|
40
|
+
display: block;
|
|
41
|
+
border-radius: 0.75rem;
|
|
42
|
+
border: 1px solid var(--color-fd-border);
|
|
43
|
+
background: var(--color-fd-card);
|
|
44
|
+
padding: 1rem;
|
|
45
|
+
font-size: 0.875rem;
|
|
46
|
+
color: var(--color-fd-card-foreground);
|
|
47
|
+
box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
|
48
|
+
transition: background-color 150ms, border-color 150ms;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.fd-card:hover {
|
|
52
|
+
background: var(--color-fd-accent);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.fd-card-icon {
|
|
56
|
+
margin-bottom: 0.5rem;
|
|
57
|
+
width: fit-content;
|
|
58
|
+
border-radius: 0.375rem;
|
|
59
|
+
border: 1px solid var(--color-fd-border);
|
|
60
|
+
padding: 0.375rem;
|
|
61
|
+
color: var(--color-fd-muted-foreground);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.fd-card-title {
|
|
65
|
+
font-weight: 500;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.fd-card-description {
|
|
69
|
+
color: var(--color-fd-muted-foreground);
|
|
70
|
+
margin-top: 0.25rem;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.fd-cards {
|
|
74
|
+
display: grid;
|
|
75
|
+
grid-template-columns: 1fr;
|
|
76
|
+
gap: 1rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@media (min-width: 640px) {
|
|
80
|
+
.fd-cards {
|
|
81
|
+
grid-template-columns: repeat(2, 1fr);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/* ─── Page nav cards ───────────────────────────────────────────────── */
|
|
86
|
+
|
|
87
|
+
.fd-page-nav-card {
|
|
88
|
+
border-radius: 0.75rem;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ─── Inline code ──────────────────────────────────────────────────── */
|
|
92
|
+
|
|
93
|
+
.fd-docs-content :not(pre) > code {
|
|
94
|
+
padding: 3px;
|
|
95
|
+
border: 1px solid var(--color-fd-border);
|
|
96
|
+
font-size: 13px;
|
|
97
|
+
border-radius: 5px;
|
|
98
|
+
background: var(--color-fd-muted);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* ─── Links in prose ───────────────────────────────────────────────── */
|
|
102
|
+
|
|
103
|
+
.fd-docs-content a:not(.fd-page-nav-card):not([class]) {
|
|
104
|
+
text-decoration: underline;
|
|
105
|
+
text-underline-offset: 3.5px;
|
|
106
|
+
text-decoration-color: var(--color-fd-primary);
|
|
107
|
+
text-decoration-thickness: 1.5px;
|
|
108
|
+
font-weight: 500;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ─── Tables (rounded) ─────────────────────────────────────────────── */
|
|
112
|
+
|
|
113
|
+
.fd-docs-content table {
|
|
114
|
+
border-collapse: separate;
|
|
115
|
+
border-spacing: 0;
|
|
116
|
+
background: var(--color-fd-card);
|
|
117
|
+
border-radius: 0.75rem;
|
|
118
|
+
border: 1px solid var(--color-fd-border);
|
|
119
|
+
overflow: hidden;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.fd-docs-content th {
|
|
123
|
+
background: var(--color-fd-muted);
|
|
124
|
+
font-weight: 600;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.fd-docs-content th,
|
|
128
|
+
.fd-docs-content td {
|
|
129
|
+
padding: 0.625rem;
|
|
130
|
+
border-bottom: 1px solid var(--color-fd-border);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.fd-docs-content tr:last-child td {
|
|
134
|
+
border-bottom: none;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* ─── Blockquotes ──────────────────────────────────────────────────── */
|
|
138
|
+
|
|
139
|
+
.fd-docs-content blockquote {
|
|
140
|
+
border-left: 2px solid var(--color-fd-primary);
|
|
141
|
+
padding-left: 1rem;
|
|
142
|
+
color: var(--color-fd-foreground);
|
|
143
|
+
font-style: normal;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.fd-docs-content hr {
|
|
147
|
+
border-color: var(--color-fd-border);
|
|
148
|
+
}
|
package/styles/docs.css
CHANGED
|
@@ -477,6 +477,37 @@ code, kbd, pre, samp {
|
|
|
477
477
|
border-left-color: var(--color-fd-primary);
|
|
478
478
|
}
|
|
479
479
|
|
|
480
|
+
/* ─── Clerk TOC (tree-line style) ────────────────────────────────────── */
|
|
481
|
+
|
|
482
|
+
.fd-toc-clerk {
|
|
483
|
+
border-left: none !important;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.fd-toc-clerk .fd-toc-link {
|
|
487
|
+
display: block;
|
|
488
|
+
border-left: none;
|
|
489
|
+
margin-left: 0;
|
|
490
|
+
color: var(--color-fd-muted-foreground);
|
|
491
|
+
text-decoration: none;
|
|
492
|
+
transition: color 0.15s;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
.fd-toc-clerk .fd-toc-link:hover {
|
|
496
|
+
color: var(--color-fd-foreground);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.fd-toc-clerk .fd-toc-link[data-active="true"] {
|
|
500
|
+
color: var(--color-fd-primary);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
.fd-toc-clerk-mask {
|
|
504
|
+
overflow: hidden;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.fd-toc-clerk-thumb {
|
|
508
|
+
width: 100%;
|
|
509
|
+
}
|
|
510
|
+
|
|
480
511
|
@media (max-width: 1279px) {
|
|
481
512
|
.fd-toc {
|
|
482
513
|
display: none;
|
|
@@ -497,6 +528,15 @@ code, kbd, pre, samp {
|
|
|
497
528
|
}
|
|
498
529
|
}
|
|
499
530
|
|
|
531
|
+
/* ─── Page description (frontmatter) ─────────────────────────────────── */
|
|
532
|
+
|
|
533
|
+
.fd-page-description {
|
|
534
|
+
margin-bottom: 1rem;
|
|
535
|
+
font-size: 1.125rem;
|
|
536
|
+
line-height: 1.75;
|
|
537
|
+
color: var(--color-fd-muted-foreground);
|
|
538
|
+
}
|
|
539
|
+
|
|
500
540
|
/* ─── Breadcrumb ─────────────────────────────────────────────────────── */
|
|
501
541
|
|
|
502
542
|
.fd-breadcrumb {
|
|
@@ -1749,11 +1789,6 @@ html.dark pre.shiki {
|
|
|
1749
1789
|
|
|
1750
1790
|
.fd-ai-floating-btn {
|
|
1751
1791
|
border-radius: 26px;
|
|
1752
|
-
box-shadow: 0 8px 32px rgba(99, 102, 241, 0.3);
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
.fd-ai-floating-btn:hover {
|
|
1756
|
-
box-shadow: 0 10px 40px rgba(99, 102, 241, 0.4);
|
|
1757
1792
|
}
|
|
1758
1793
|
|
|
1759
1794
|
.fd-ai-suggestion {
|
|
@@ -1802,24 +1837,32 @@ html.dark pre.shiki {
|
|
|
1802
1837
|
.fd-ai-floating-btn {
|
|
1803
1838
|
position: fixed;
|
|
1804
1839
|
z-index: 9997;
|
|
1805
|
-
width: 52px;
|
|
1806
|
-
height: 52px;
|
|
1807
|
-
border-radius: var(--radius, 26px);
|
|
1808
|
-
border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.1));
|
|
1809
|
-
background: var(--color-fd-primary, #6366f1);
|
|
1810
|
-
color: var(--color-fd-primary-foreground, #fff);
|
|
1811
|
-
cursor: pointer;
|
|
1812
1840
|
display: flex;
|
|
1813
1841
|
align-items: center;
|
|
1814
1842
|
justify-content: center;
|
|
1815
|
-
|
|
1816
|
-
|
|
1843
|
+
gap: 8px;
|
|
1844
|
+
padding: 8px 12px;
|
|
1845
|
+
height: 40px;
|
|
1846
|
+
border-radius: 16px;
|
|
1847
|
+
border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.1));
|
|
1848
|
+
background: color-mix(in srgb, var(--color-fd-secondary, #f4f4f5) 80%, transparent);
|
|
1849
|
+
backdrop-filter: blur(4px);
|
|
1850
|
+
color: var(--color-fd-muted-foreground, #71717a);
|
|
1851
|
+
cursor: pointer;
|
|
1852
|
+
font-size: 14px;
|
|
1853
|
+
box-shadow: 0 1px 3px color-mix(in srgb, var(--color-fd-background, #000) 20%, transparent);
|
|
1854
|
+
transition: transform 150ms, background 150ms, color 150ms;
|
|
1817
1855
|
animation: fd-ai-fade-in 300ms ease-out;
|
|
1818
1856
|
}
|
|
1819
1857
|
|
|
1820
1858
|
.fd-ai-floating-btn:hover {
|
|
1821
|
-
|
|
1822
|
-
|
|
1859
|
+
background: var(--color-fd-accent);
|
|
1860
|
+
color: var(--color-fd-accent-foreground);
|
|
1861
|
+
transform: scale(1.03);
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
.fd-ai-floating-btn:active {
|
|
1865
|
+
transform: scale(0.97);
|
|
1823
1866
|
}
|
|
1824
1867
|
|
|
1825
1868
|
.fd-ai-floating-trigger {
|
|
@@ -2153,24 +2196,28 @@ html.dark pre.shiki {
|
|
|
2153
2196
|
align-items: center;
|
|
2154
2197
|
justify-content: center;
|
|
2155
2198
|
gap: 8px;
|
|
2156
|
-
padding: 8px
|
|
2199
|
+
padding: 8px 12px;
|
|
2157
2200
|
height: 40px;
|
|
2158
|
-
border-radius:
|
|
2201
|
+
border-radius: 16px;
|
|
2159
2202
|
border: 1px solid var(--color-fd-border, rgba(255, 255, 255, 0.1));
|
|
2160
|
-
background: var(--color-fd-secondary,
|
|
2203
|
+
background: color-mix(in srgb, var(--color-fd-secondary, #f4f4f5) 80%, transparent);
|
|
2204
|
+
backdrop-filter: blur(4px);
|
|
2161
2205
|
color: var(--color-fd-muted-foreground, #71717a);
|
|
2162
2206
|
font-family: inherit;
|
|
2163
2207
|
font-size: 14px;
|
|
2164
2208
|
cursor: pointer;
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
transition: all 200ms;
|
|
2209
|
+
box-shadow: 0 1px 3px color-mix(in srgb, var(--color-fd-background, #000) 20%, transparent);
|
|
2210
|
+
transition: transform 150ms, background 150ms, color 150ms;
|
|
2168
2211
|
animation: fd-ai-fade-in 300ms ease-out;
|
|
2169
2212
|
white-space: nowrap;
|
|
2170
2213
|
}
|
|
2171
2214
|
|
|
2172
2215
|
.fd-ai-fm-trigger-btn:hover {
|
|
2173
|
-
background: var(--color-fd-accent
|
|
2174
|
-
color: var(--color-fd-accent-foreground
|
|
2216
|
+
background: var(--color-fd-accent);
|
|
2217
|
+
color: var(--color-fd-accent-foreground);
|
|
2175
2218
|
transform: scale(1.03);
|
|
2176
2219
|
}
|
|
2220
|
+
|
|
2221
|
+
.fd-ai-fm-trigger-btn:active {
|
|
2222
|
+
transform: scale(0.97);
|
|
2223
|
+
}
|