@farming-labs/theme 0.0.2-beta.22 → 0.0.2-beta.24
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/dist/ai-search-dialog.d.mts +7 -0
- package/dist/ai-search-dialog.mjs +156 -35
- package/dist/docs-ai-features.d.mts +2 -0
- package/dist/docs-ai-features.mjs +9 -13
- package/dist/docs-api.d.mts +7 -6
- package/dist/docs-api.mjs +73 -4
- package/dist/docs-layout.mjs +4 -0
- package/dist/docs-page-client.d.mts +3 -0
- package/dist/docs-page-client.mjs +25 -6
- package/dist/search.d.mts +1 -1
- package/package.json +2 -2
- package/styles/ai.css +258 -61
- package/styles/base.css +23 -0
- package/styles/darksharp.css +1 -1
- package/styles/pixel-border.css +26 -7
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
//#region src/ai-search-dialog.d.ts
|
|
2
|
+
type LoaderVariant = "shimmer-dots" | "circular" | "dots" | "typing" | "wave" | "bars" | "pulse" | "pulse-dot" | "terminal" | "text-blink" | "text-shimmer" | "loading-dots";
|
|
2
3
|
declare function DocsSearchDialog({
|
|
3
4
|
open,
|
|
4
5
|
onOpenChange,
|
|
5
6
|
api,
|
|
6
7
|
suggestedQuestions,
|
|
7
8
|
aiLabel,
|
|
9
|
+
loaderVariant,
|
|
8
10
|
loadingComponentHtml
|
|
9
11
|
}: {
|
|
10
12
|
open: boolean;
|
|
@@ -12,6 +14,7 @@ declare function DocsSearchDialog({
|
|
|
12
14
|
api?: string;
|
|
13
15
|
suggestedQuestions?: string[];
|
|
14
16
|
aiLabel?: string;
|
|
17
|
+
loaderVariant?: LoaderVariant;
|
|
15
18
|
loadingComponentHtml?: string;
|
|
16
19
|
}): any;
|
|
17
20
|
type FloatingPosition = "bottom-right" | "bottom-left" | "bottom-center";
|
|
@@ -23,6 +26,7 @@ declare function FloatingAIChat({
|
|
|
23
26
|
triggerComponentHtml,
|
|
24
27
|
suggestedQuestions,
|
|
25
28
|
aiLabel,
|
|
29
|
+
loaderVariant,
|
|
26
30
|
loadingComponentHtml
|
|
27
31
|
}: {
|
|
28
32
|
api?: string;
|
|
@@ -31,6 +35,7 @@ declare function FloatingAIChat({
|
|
|
31
35
|
triggerComponentHtml?: string;
|
|
32
36
|
suggestedQuestions?: string[];
|
|
33
37
|
aiLabel?: string;
|
|
38
|
+
loaderVariant?: LoaderVariant;
|
|
34
39
|
loadingComponentHtml?: string;
|
|
35
40
|
}): any;
|
|
36
41
|
declare function AIModalDialog({
|
|
@@ -39,6 +44,7 @@ declare function AIModalDialog({
|
|
|
39
44
|
api,
|
|
40
45
|
suggestedQuestions,
|
|
41
46
|
aiLabel,
|
|
47
|
+
loaderVariant,
|
|
42
48
|
loadingComponentHtml
|
|
43
49
|
}: {
|
|
44
50
|
open: boolean;
|
|
@@ -46,6 +52,7 @@ declare function AIModalDialog({
|
|
|
46
52
|
api?: string;
|
|
47
53
|
suggestedQuestions?: string[];
|
|
48
54
|
aiLabel?: string;
|
|
55
|
+
loaderVariant?: LoaderVariant;
|
|
49
56
|
loadingComponentHtml?: string;
|
|
50
57
|
}): any;
|
|
51
58
|
//#endregion
|
|
@@ -143,33 +143,145 @@ function XIcon() {
|
|
|
143
143
|
children: [/* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }), /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })]
|
|
144
144
|
});
|
|
145
145
|
}
|
|
146
|
-
function
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
className: "fd-ai-
|
|
151
|
-
children: [
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
146
|
+
function LoaderIndicator({ variant = "shimmer-dots" }) {
|
|
147
|
+
const text = "Thinking";
|
|
148
|
+
switch (variant) {
|
|
149
|
+
case "circular": return /* @__PURE__ */ jsxs("div", {
|
|
150
|
+
className: "fd-ai-loader",
|
|
151
|
+
children: [/* @__PURE__ */ jsx("div", { className: "fd-ai-loader-circular" }), /* @__PURE__ */ jsx("span", {
|
|
152
|
+
className: "sr-only",
|
|
153
|
+
children: "Loading"
|
|
154
|
+
})]
|
|
155
|
+
});
|
|
156
|
+
case "dots": return /* @__PURE__ */ jsx("div", {
|
|
157
|
+
className: "fd-ai-loader",
|
|
158
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
159
|
+
className: "fd-ai-loader-dots",
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-bounce-dot" }),
|
|
162
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-bounce-dot" }),
|
|
163
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-bounce-dot" })
|
|
164
|
+
]
|
|
165
|
+
})
|
|
166
|
+
});
|
|
167
|
+
case "typing": return /* @__PURE__ */ jsx("div", {
|
|
168
|
+
className: "fd-ai-loader",
|
|
169
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
170
|
+
className: "fd-ai-loader-typing-dots",
|
|
171
|
+
children: [
|
|
172
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" }),
|
|
173
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" }),
|
|
174
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" })
|
|
175
|
+
]
|
|
176
|
+
})
|
|
177
|
+
});
|
|
178
|
+
case "wave": return /* @__PURE__ */ jsx("div", {
|
|
179
|
+
className: "fd-ai-loader",
|
|
180
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
181
|
+
className: "fd-ai-loader-wave",
|
|
182
|
+
children: [
|
|
183
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-wave-bar" }),
|
|
184
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-wave-bar" }),
|
|
185
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-wave-bar" }),
|
|
186
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-wave-bar" }),
|
|
187
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-wave-bar" })
|
|
188
|
+
]
|
|
189
|
+
})
|
|
190
|
+
});
|
|
191
|
+
case "bars": return /* @__PURE__ */ jsx("div", {
|
|
192
|
+
className: "fd-ai-loader",
|
|
193
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
194
|
+
className: "fd-ai-loader-bars",
|
|
195
|
+
children: [
|
|
196
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-bar" }),
|
|
197
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-bar" }),
|
|
198
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-bar" })
|
|
199
|
+
]
|
|
200
|
+
})
|
|
201
|
+
});
|
|
202
|
+
case "pulse": return /* @__PURE__ */ jsx("div", {
|
|
203
|
+
className: "fd-ai-loader",
|
|
204
|
+
children: /* @__PURE__ */ jsx("div", { className: "fd-ai-loader-pulse" })
|
|
205
|
+
});
|
|
206
|
+
case "pulse-dot": return /* @__PURE__ */ jsx("div", {
|
|
207
|
+
className: "fd-ai-loader",
|
|
208
|
+
children: /* @__PURE__ */ jsx("div", { className: "fd-ai-loader-pulse-dot" })
|
|
209
|
+
});
|
|
210
|
+
case "terminal": return /* @__PURE__ */ jsx("div", {
|
|
211
|
+
className: "fd-ai-loader",
|
|
212
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
213
|
+
className: "fd-ai-loader-terminal",
|
|
214
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
215
|
+
className: "fd-ai-loader-terminal-prompt",
|
|
216
|
+
children: ">"
|
|
217
|
+
}), /* @__PURE__ */ jsx("span", { className: "fd-ai-loader-terminal-cursor" })]
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
case "text-blink": return /* @__PURE__ */ jsx("div", {
|
|
221
|
+
className: "fd-ai-loader",
|
|
222
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
223
|
+
className: "fd-ai-loader-text-blink",
|
|
224
|
+
children: text
|
|
225
|
+
})
|
|
226
|
+
});
|
|
227
|
+
case "text-shimmer": return /* @__PURE__ */ jsx("div", {
|
|
228
|
+
className: "fd-ai-loader",
|
|
229
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
230
|
+
className: "fd-ai-loader-shimmer-text",
|
|
231
|
+
children: text
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
case "loading-dots": return /* @__PURE__ */ jsxs("div", {
|
|
235
|
+
className: "fd-ai-loader",
|
|
236
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
237
|
+
className: "fd-ai-loader-text",
|
|
238
|
+
children: text
|
|
239
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
240
|
+
className: "fd-ai-loader-text-dots",
|
|
241
|
+
children: [
|
|
242
|
+
/* @__PURE__ */ jsx("span", {
|
|
243
|
+
className: "fd-ai-loader-text-dot",
|
|
244
|
+
children: "."
|
|
245
|
+
}),
|
|
246
|
+
/* @__PURE__ */ jsx("span", {
|
|
247
|
+
className: "fd-ai-loader-text-dot",
|
|
248
|
+
children: "."
|
|
249
|
+
}),
|
|
250
|
+
/* @__PURE__ */ jsx("span", {
|
|
251
|
+
className: "fd-ai-loader-text-dot",
|
|
252
|
+
children: "."
|
|
253
|
+
})
|
|
254
|
+
]
|
|
255
|
+
})]
|
|
256
|
+
});
|
|
257
|
+
default: return /* @__PURE__ */ jsxs("div", {
|
|
258
|
+
className: "fd-ai-loader",
|
|
259
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
260
|
+
className: "fd-ai-loader-shimmer-text",
|
|
261
|
+
children: text
|
|
262
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
263
|
+
className: "fd-ai-loader-typing-dots",
|
|
264
|
+
children: [
|
|
265
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" }),
|
|
266
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" }),
|
|
267
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" })
|
|
268
|
+
]
|
|
269
|
+
})]
|
|
270
|
+
});
|
|
271
|
+
}
|
|
161
272
|
}
|
|
162
|
-
function
|
|
273
|
+
function InlineLoaderDots() {
|
|
163
274
|
return /* @__PURE__ */ jsxs("span", {
|
|
164
|
-
className: "fd-ai-
|
|
275
|
+
className: "fd-ai-loader-typing-dots",
|
|
276
|
+
style: { marginLeft: 0 },
|
|
165
277
|
children: [
|
|
166
|
-
/* @__PURE__ */ jsx("span", { className: "fd-ai-
|
|
167
|
-
/* @__PURE__ */ jsx("span", { className: "fd-ai-
|
|
168
|
-
/* @__PURE__ */ jsx("span", { className: "fd-ai-
|
|
278
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" }),
|
|
279
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" }),
|
|
280
|
+
/* @__PURE__ */ jsx("span", { className: "fd-ai-loader-typing-dot" })
|
|
169
281
|
]
|
|
170
282
|
});
|
|
171
283
|
}
|
|
172
|
-
function AIChat({ api, messages, setMessages, aiInput, setAiInput, isStreaming, setIsStreaming, suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
284
|
+
function AIChat({ api, messages, setMessages, aiInput, setAiInput, isStreaming, setIsStreaming, suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml }) {
|
|
173
285
|
const label = aiLabel || "AI";
|
|
174
286
|
const aiInputRef = useRef(null);
|
|
175
287
|
const messagesEndRef = useRef(null);
|
|
@@ -311,7 +423,13 @@ function AIChat({ api, messages, setMessages, aiInput, setAiInput, isStreaming,
|
|
|
311
423
|
children: msg.content
|
|
312
424
|
}) : /* @__PURE__ */ jsx("div", {
|
|
313
425
|
className: "fd-ai-bubble-ai",
|
|
314
|
-
children: msg.content ? /* @__PURE__ */ jsx("div", {
|
|
426
|
+
children: msg.content ? /* @__PURE__ */ jsx("div", {
|
|
427
|
+
className: isStreaming && i === messages.length - 1 ? "fd-ai-streaming" : void 0,
|
|
428
|
+
dangerouslySetInnerHTML: { __html: renderMarkdown(msg.content) }
|
|
429
|
+
}) : loadingComponentHtml ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: loadingComponentHtml } }) : /* @__PURE__ */ jsx(LoaderIndicator, {
|
|
430
|
+
variant: loaderVariant,
|
|
431
|
+
label
|
|
432
|
+
})
|
|
315
433
|
})]
|
|
316
434
|
}, i)), /* @__PURE__ */ jsx("div", { ref: messagesEndRef })]
|
|
317
435
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -353,7 +471,7 @@ function AIChat({ api, messages, setMessages, aiInput, setAiInput, isStreaming,
|
|
|
353
471
|
})]
|
|
354
472
|
});
|
|
355
473
|
}
|
|
356
|
-
function DocsSearchDialog({ open, onOpenChange, api = "/api/docs", suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
474
|
+
function DocsSearchDialog({ open, onOpenChange, api = "/api/docs", suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml }) {
|
|
357
475
|
const [tab, setTab] = useState("search");
|
|
358
476
|
const [searchQuery, setSearchQuery] = useState("");
|
|
359
477
|
const [searchResults, setSearchResults] = useState([]);
|
|
@@ -496,7 +614,7 @@ function DocsSearchDialog({ open, onOpenChange, api = "/api/docs", suggestedQues
|
|
|
496
614
|
onKeyDown: handleSearchKeyDown,
|
|
497
615
|
className: "fd-ai-input"
|
|
498
616
|
}),
|
|
499
|
-
isSearching && /* @__PURE__ */ jsx(
|
|
617
|
+
isSearching && /* @__PURE__ */ jsx(InlineLoaderDots, {})
|
|
500
618
|
]
|
|
501
619
|
}), /* @__PURE__ */ jsx("div", {
|
|
502
620
|
className: "fd-ai-results",
|
|
@@ -528,6 +646,7 @@ function DocsSearchDialog({ open, onOpenChange, api = "/api/docs", suggestedQues
|
|
|
528
646
|
setIsStreaming,
|
|
529
647
|
suggestedQuestions,
|
|
530
648
|
aiLabel,
|
|
649
|
+
loaderVariant,
|
|
531
650
|
loadingComponentHtml
|
|
532
651
|
})
|
|
533
652
|
]
|
|
@@ -602,7 +721,7 @@ function getContainerStyles(style, position) {
|
|
|
602
721
|
function getAnimation(style) {
|
|
603
722
|
return style === "modal" ? "fd-ai-float-center-in 200ms ease-out" : "fd-ai-float-in 200ms ease-out";
|
|
604
723
|
}
|
|
605
|
-
function FloatingAIChat({ api = "/api/docs", position = "bottom-right", floatingStyle = "panel", triggerComponentHtml, suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
724
|
+
function FloatingAIChat({ api = "/api/docs", position = "bottom-right", floatingStyle = "panel", triggerComponentHtml, suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml }) {
|
|
606
725
|
const [mounted, setMounted] = useState(false);
|
|
607
726
|
const [isOpen, setIsOpen] = useState(false);
|
|
608
727
|
const [messages, setMessages] = useState([]);
|
|
@@ -640,6 +759,7 @@ function FloatingAIChat({ api = "/api/docs", position = "bottom-right", floating
|
|
|
640
759
|
setIsStreaming,
|
|
641
760
|
suggestedQuestions,
|
|
642
761
|
aiLabel,
|
|
762
|
+
loaderVariant,
|
|
643
763
|
loadingComponentHtml,
|
|
644
764
|
triggerComponentHtml,
|
|
645
765
|
position
|
|
@@ -688,6 +808,7 @@ function FloatingAIChat({ api = "/api/docs", position = "bottom-right", floating
|
|
|
688
808
|
setIsStreaming,
|
|
689
809
|
suggestedQuestions,
|
|
690
810
|
aiLabel,
|
|
811
|
+
loaderVariant,
|
|
691
812
|
loadingComponentHtml
|
|
692
813
|
})]
|
|
693
814
|
}),
|
|
@@ -705,7 +826,7 @@ function FloatingAIChat({ api = "/api/docs", position = "bottom-right", floating
|
|
|
705
826
|
}))
|
|
706
827
|
] }), document.body);
|
|
707
828
|
}
|
|
708
|
-
function FullModalAIChat({ api, isOpen, setIsOpen, messages, setMessages, aiInput, setAiInput, isStreaming, setIsStreaming, suggestedQuestions, aiLabel, loadingComponentHtml, triggerComponentHtml, position }) {
|
|
829
|
+
function FullModalAIChat({ api, isOpen, setIsOpen, messages, setMessages, aiInput, setAiInput, isStreaming, setIsStreaming, suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml, triggerComponentHtml, position }) {
|
|
709
830
|
const label = aiLabel || "AI";
|
|
710
831
|
const inputRef = useRef(null);
|
|
711
832
|
const listRef = useRef(null);
|
|
@@ -831,13 +952,12 @@ function FullModalAIChat({ api, isOpen, setIsOpen, messages, setMessages, aiInpu
|
|
|
831
952
|
children: msg.role === "user" ? "you" : label
|
|
832
953
|
}), /* @__PURE__ */ jsx("div", {
|
|
833
954
|
className: "fd-ai-fm-msg-content",
|
|
834
|
-
children: msg.content ? /* @__PURE__ */ jsx("div", {
|
|
835
|
-
className: "fd-ai-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
]
|
|
955
|
+
children: msg.content ? /* @__PURE__ */ jsx("div", {
|
|
956
|
+
className: isStreaming && i === messages.length - 1 ? "fd-ai-streaming" : void 0,
|
|
957
|
+
dangerouslySetInnerHTML: { __html: renderMarkdown(msg.content) }
|
|
958
|
+
}) : loadingComponentHtml ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: loadingComponentHtml } }) : /* @__PURE__ */ jsx(LoaderIndicator, {
|
|
959
|
+
variant: loaderVariant,
|
|
960
|
+
label
|
|
841
961
|
})
|
|
842
962
|
})]
|
|
843
963
|
}, i))
|
|
@@ -871,7 +991,7 @@ function FullModalAIChat({ api, isOpen, setIsOpen, messages, setMessages, aiInpu
|
|
|
871
991
|
}), isStreaming ? /* @__PURE__ */ jsx("button", {
|
|
872
992
|
className: "fd-ai-fm-send-btn",
|
|
873
993
|
onClick: () => setIsStreaming(false),
|
|
874
|
-
children: /* @__PURE__ */ jsx(
|
|
994
|
+
children: /* @__PURE__ */ jsx(InlineLoaderDots, {})
|
|
875
995
|
}) : /* @__PURE__ */ jsx("button", {
|
|
876
996
|
className: "fd-ai-fm-send-btn",
|
|
877
997
|
"data-active": canSend,
|
|
@@ -932,7 +1052,7 @@ function TrashIcon() {
|
|
|
932
1052
|
]
|
|
933
1053
|
});
|
|
934
1054
|
}
|
|
935
|
-
function AIModalDialog({ open, onOpenChange, api = "/api/docs", suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
1055
|
+
function AIModalDialog({ open, onOpenChange, api = "/api/docs", suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml }) {
|
|
936
1056
|
const [messages, setMessages] = useState([]);
|
|
937
1057
|
const [aiInput, setAiInput] = useState("");
|
|
938
1058
|
const [isStreaming, setIsStreaming] = useState(false);
|
|
@@ -999,6 +1119,7 @@ function AIModalDialog({ open, onOpenChange, api = "/api/docs", suggestedQuestio
|
|
|
999
1119
|
setIsStreaming,
|
|
1000
1120
|
suggestedQuestions,
|
|
1001
1121
|
aiLabel,
|
|
1122
|
+
loaderVariant,
|
|
1002
1123
|
loadingComponentHtml
|
|
1003
1124
|
}),
|
|
1004
1125
|
/* @__PURE__ */ jsx("div", {
|
|
@@ -8,6 +8,7 @@ interface DocsAIFeaturesProps {
|
|
|
8
8
|
triggerComponentHtml?: string;
|
|
9
9
|
suggestedQuestions?: string[];
|
|
10
10
|
aiLabel?: string;
|
|
11
|
+
loaderVariant?: string;
|
|
11
12
|
loadingComponentHtml?: string;
|
|
12
13
|
}
|
|
13
14
|
declare function DocsAIFeatures({
|
|
@@ -17,6 +18,7 @@ declare function DocsAIFeatures({
|
|
|
17
18
|
triggerComponentHtml,
|
|
18
19
|
suggestedQuestions,
|
|
19
20
|
aiLabel,
|
|
21
|
+
loaderVariant,
|
|
20
22
|
loadingComponentHtml
|
|
21
23
|
}: DocsAIFeaturesProps): react_jsx_runtime0.JSX.Element;
|
|
22
24
|
//#endregion
|
|
@@ -19,15 +19,17 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
19
19
|
* This component is rendered inside the docs layout so the user's root layout
|
|
20
20
|
* never needs to be modified — AI features work purely from `docs.config.tsx`.
|
|
21
21
|
*/
|
|
22
|
-
function DocsAIFeatures({ mode, position = "bottom-right", floatingStyle = "panel", triggerComponentHtml, suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
22
|
+
function DocsAIFeatures({ mode, position = "bottom-right", floatingStyle = "panel", triggerComponentHtml, suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml }) {
|
|
23
23
|
if (mode === "search") return /* @__PURE__ */ jsx(SearchModeAI, {
|
|
24
24
|
suggestedQuestions,
|
|
25
25
|
aiLabel,
|
|
26
|
+
loaderVariant,
|
|
26
27
|
loadingComponentHtml
|
|
27
28
|
});
|
|
28
29
|
if (mode === "sidebar-icon") return /* @__PURE__ */ jsx(SidebarIconModeAI, {
|
|
29
30
|
suggestedQuestions,
|
|
30
31
|
aiLabel,
|
|
32
|
+
loaderVariant,
|
|
31
33
|
loadingComponentHtml
|
|
32
34
|
});
|
|
33
35
|
return /* @__PURE__ */ jsx(FloatingAIChat, {
|
|
@@ -37,15 +39,11 @@ function DocsAIFeatures({ mode, position = "bottom-right", floatingStyle = "pane
|
|
|
37
39
|
triggerComponentHtml,
|
|
38
40
|
suggestedQuestions,
|
|
39
41
|
aiLabel,
|
|
42
|
+
loaderVariant,
|
|
40
43
|
loadingComponentHtml
|
|
41
44
|
});
|
|
42
45
|
}
|
|
43
|
-
|
|
44
|
-
* Search mode: intercepts Cmd+K / Ctrl+K globally and opens the
|
|
45
|
-
* custom search dialog (with Search + Ask AI tabs) instead of
|
|
46
|
-
* fumadocs' built-in search dialog.
|
|
47
|
-
*/
|
|
48
|
-
function SearchModeAI({ suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
46
|
+
function SearchModeAI({ suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml }) {
|
|
49
47
|
const [open, setOpen] = useState(false);
|
|
50
48
|
useEffect(() => {
|
|
51
49
|
function handler(e) {
|
|
@@ -80,15 +78,11 @@ function SearchModeAI({ suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
|
80
78
|
api: "/api/docs",
|
|
81
79
|
suggestedQuestions,
|
|
82
80
|
aiLabel,
|
|
81
|
+
loaderVariant,
|
|
83
82
|
loadingComponentHtml
|
|
84
83
|
});
|
|
85
84
|
}
|
|
86
|
-
|
|
87
|
-
* Sidebar-icon mode: injects a sparkle icon button next to the search bar
|
|
88
|
-
* in the sidebar header. The search button opens the Cmd+K search dialog,
|
|
89
|
-
* and the AI sparkle button opens a pure AI modal (no search tabs).
|
|
90
|
-
*/
|
|
91
|
-
function SidebarIconModeAI({ suggestedQuestions, aiLabel, loadingComponentHtml }) {
|
|
85
|
+
function SidebarIconModeAI({ suggestedQuestions, aiLabel, loaderVariant, loadingComponentHtml }) {
|
|
92
86
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
93
87
|
const [aiOpen, setAiOpen] = useState(false);
|
|
94
88
|
useEffect(() => {
|
|
@@ -123,6 +117,7 @@ function SidebarIconModeAI({ suggestedQuestions, aiLabel, loadingComponentHtml }
|
|
|
123
117
|
api: "/api/docs",
|
|
124
118
|
suggestedQuestions,
|
|
125
119
|
aiLabel,
|
|
120
|
+
loaderVariant,
|
|
126
121
|
loadingComponentHtml
|
|
127
122
|
}), /* @__PURE__ */ jsx(AIModalDialog, {
|
|
128
123
|
open: aiOpen,
|
|
@@ -130,6 +125,7 @@ function SidebarIconModeAI({ suggestedQuestions, aiLabel, loadingComponentHtml }
|
|
|
130
125
|
api: "/api/docs",
|
|
131
126
|
suggestedQuestions,
|
|
132
127
|
aiLabel,
|
|
128
|
+
loaderVariant,
|
|
133
129
|
loadingComponentHtml
|
|
134
130
|
})] });
|
|
135
131
|
}
|
package/dist/docs-api.d.mts
CHANGED
|
@@ -38,12 +38,14 @@ interface DocsAPIOptions {
|
|
|
38
38
|
* Create a unified docs API route handler.
|
|
39
39
|
*
|
|
40
40
|
* Returns `{ GET, POST }` for use in a Next.js route handler:
|
|
41
|
-
* - **GET
|
|
42
|
-
* - **
|
|
41
|
+
* - **GET ?query=…** → full-text search
|
|
42
|
+
* - **GET ?format=llms** → llms.txt (concise page listing)
|
|
43
|
+
* - **GET ?format=llms-full** → llms-full.txt (full page content)
|
|
44
|
+
* - **POST** → AI-powered chat with RAG
|
|
43
45
|
*
|
|
44
46
|
* @example
|
|
45
47
|
* ```ts
|
|
46
|
-
* // app/api/docs/route.ts
|
|
48
|
+
* // app/api/docs/route.ts (auto-generated by withDocs)
|
|
47
49
|
* import { createDocsAPI } from "@farming-labs/theme/api";
|
|
48
50
|
* export const { GET, POST } = createDocsAPI();
|
|
49
51
|
* export const revalidate = false;
|
|
@@ -53,10 +55,9 @@ interface DocsAPIOptions {
|
|
|
53
55
|
*/
|
|
54
56
|
declare function createDocsAPI(options?: DocsAPIOptions): {
|
|
55
57
|
/**
|
|
56
|
-
* GET handler — full
|
|
57
|
-
* Query: `?query=search+term`
|
|
58
|
+
* GET handler — search, llms.txt, or llms-full.txt depending on query params.
|
|
58
59
|
*/
|
|
59
|
-
GET
|
|
60
|
+
GET(request: Request): Response | Promise<Response>;
|
|
60
61
|
/**
|
|
61
62
|
* POST handler — AI chat with RAG.
|
|
62
63
|
* Body: `{ messages: [{ role: "user", content: "How do I …?" }] }`
|
package/dist/docs-api.mjs
CHANGED
|
@@ -163,16 +163,64 @@ async function handleAskAI(request, indexes, searchServer, aiConfig) {
|
|
|
163
163
|
Connection: "keep-alive"
|
|
164
164
|
} });
|
|
165
165
|
}
|
|
166
|
+
function readLlmsTxtConfig(root) {
|
|
167
|
+
for (const ext of FILE_EXTS) {
|
|
168
|
+
const configPath = path.join(root, `docs.config.${ext}`);
|
|
169
|
+
if (fs.existsSync(configPath)) try {
|
|
170
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
171
|
+
if (!content.includes("llmsTxt")) return { enabled: false };
|
|
172
|
+
if (/llmsTxt\s*:\s*true/.test(content)) return { enabled: true };
|
|
173
|
+
const enabledMatch = content.match(/llmsTxt\s*:\s*\{[^}]*enabled\s*:\s*(true|false)/s);
|
|
174
|
+
if (enabledMatch && enabledMatch[1] === "false") return { enabled: false };
|
|
175
|
+
const baseUrlMatch = content.match(/llmsTxt\s*:\s*\{[^}]*baseUrl\s*:\s*["']([^"']+)["']/s);
|
|
176
|
+
const siteTitleMatch = content.match(/llmsTxt\s*:\s*\{[^}]*siteTitle\s*:\s*["']([^"']+)["']/s);
|
|
177
|
+
const siteDescMatch = content.match(/llmsTxt\s*:\s*\{[^}]*siteDescription\s*:\s*["']([^"']+)["']/s);
|
|
178
|
+
const navTitleMatch = content.match(/nav\s*:\s*\{[^}]*title\s*:\s*["']([^"']+)["']/s);
|
|
179
|
+
return {
|
|
180
|
+
enabled: true,
|
|
181
|
+
baseUrl: baseUrlMatch?.[1],
|
|
182
|
+
siteTitle: siteTitleMatch?.[1] ?? navTitleMatch?.[1],
|
|
183
|
+
siteDescription: siteDescMatch?.[1]
|
|
184
|
+
};
|
|
185
|
+
} catch {}
|
|
186
|
+
}
|
|
187
|
+
return { enabled: false };
|
|
188
|
+
}
|
|
189
|
+
function generateLlmsTxt(indexes, options) {
|
|
190
|
+
const { siteTitle = "Documentation", siteDescription, baseUrl = "" } = options;
|
|
191
|
+
let llmsTxt = `# ${siteTitle}\n\n`;
|
|
192
|
+
if (siteDescription) llmsTxt += `> ${siteDescription}\n\n`;
|
|
193
|
+
llmsTxt += `## Pages\n\n`;
|
|
194
|
+
for (const page of indexes) {
|
|
195
|
+
llmsTxt += `- [${page.title}](${baseUrl}${page.url})`;
|
|
196
|
+
if (page.description) llmsTxt += `: ${page.description}`;
|
|
197
|
+
llmsTxt += `\n`;
|
|
198
|
+
}
|
|
199
|
+
let llmsFullTxt = `# ${siteTitle}\n\n`;
|
|
200
|
+
if (siteDescription) llmsFullTxt += `> ${siteDescription}\n\n`;
|
|
201
|
+
for (const page of indexes) {
|
|
202
|
+
llmsFullTxt += `## ${page.title}\n\n`;
|
|
203
|
+
llmsFullTxt += `URL: ${baseUrl}${page.url}\n\n`;
|
|
204
|
+
if (page.description) llmsFullTxt += `${page.description}\n\n`;
|
|
205
|
+
llmsFullTxt += `${page.content}\n\n---\n\n`;
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
llmsTxt,
|
|
209
|
+
llmsFullTxt
|
|
210
|
+
};
|
|
211
|
+
}
|
|
166
212
|
/**
|
|
167
213
|
* Create a unified docs API route handler.
|
|
168
214
|
*
|
|
169
215
|
* Returns `{ GET, POST }` for use in a Next.js route handler:
|
|
170
|
-
* - **GET
|
|
171
|
-
* - **
|
|
216
|
+
* - **GET ?query=…** → full-text search
|
|
217
|
+
* - **GET ?format=llms** → llms.txt (concise page listing)
|
|
218
|
+
* - **GET ?format=llms-full** → llms-full.txt (full page content)
|
|
219
|
+
* - **POST** → AI-powered chat with RAG
|
|
172
220
|
*
|
|
173
221
|
* @example
|
|
174
222
|
* ```ts
|
|
175
|
-
* // app/api/docs/route.ts
|
|
223
|
+
* // app/api/docs/route.ts (auto-generated by withDocs)
|
|
176
224
|
* import { createDocsAPI } from "@farming-labs/theme/api";
|
|
177
225
|
* export const { GET, POST } = createDocsAPI();
|
|
178
226
|
* export const revalidate = false;
|
|
@@ -186,13 +234,34 @@ function createDocsAPI(options) {
|
|
|
186
234
|
const docsDir = path.join(root, "app", entry);
|
|
187
235
|
const language = options?.language ?? "english";
|
|
188
236
|
const aiConfig = options?.ai ?? readAIConfig(root);
|
|
237
|
+
const llmsConfig = readLlmsTxtConfig(root);
|
|
189
238
|
const indexes = scanDocsDir(docsDir, entry);
|
|
239
|
+
let _llmsCache = null;
|
|
240
|
+
function getLlmsContent() {
|
|
241
|
+
if (!_llmsCache) _llmsCache = generateLlmsTxt(indexes, {
|
|
242
|
+
siteTitle: llmsConfig.siteTitle ?? "Documentation",
|
|
243
|
+
siteDescription: llmsConfig.siteDescription,
|
|
244
|
+
baseUrl: llmsConfig.baseUrl ?? ""
|
|
245
|
+
});
|
|
246
|
+
return _llmsCache;
|
|
247
|
+
}
|
|
190
248
|
const searchAPI = createSearchAPI("simple", {
|
|
191
249
|
language,
|
|
192
250
|
indexes
|
|
193
251
|
});
|
|
194
252
|
return {
|
|
195
|
-
GET
|
|
253
|
+
GET(request) {
|
|
254
|
+
const format = new URL(request.url).searchParams.get("format");
|
|
255
|
+
if (format === "llms") return new Response(getLlmsContent().llmsTxt, { headers: {
|
|
256
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
257
|
+
"Cache-Control": "public, max-age=3600"
|
|
258
|
+
} });
|
|
259
|
+
if (format === "llms-full") return new Response(getLlmsContent().llmsFullTxt, { headers: {
|
|
260
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
261
|
+
"Cache-Control": "public, max-age=3600"
|
|
262
|
+
} });
|
|
263
|
+
return searchAPI.GET(request);
|
|
264
|
+
},
|
|
196
265
|
async POST(request) {
|
|
197
266
|
if (!aiConfig.enabled) return Response.json({ error: "AI is not enabled. Set `ai: { enabled: true }` in your docs.config to enable it." }, { status: 404 });
|
|
198
267
|
return handleAskAI(request, indexes, searchAPI, aiConfig);
|
package/dist/docs-layout.mjs
CHANGED
|
@@ -357,6 +357,7 @@ function createDocsLayout(config) {
|
|
|
357
357
|
const lastUpdatedRaw = config.lastUpdated;
|
|
358
358
|
const lastUpdatedEnabled = lastUpdatedRaw !== false && (typeof lastUpdatedRaw !== "object" || lastUpdatedRaw.enabled !== false);
|
|
359
359
|
const lastUpdatedPosition = typeof lastUpdatedRaw === "object" ? lastUpdatedRaw.position ?? "footer" : "footer";
|
|
360
|
+
const llmsTxtEnabled = resolveBool(config.llmsTxt);
|
|
360
361
|
const openDocsProviders = (typeof pageActions?.openDocs === "object" && pageActions.openDocs.providers ? pageActions.openDocs.providers : void 0)?.map((p) => ({
|
|
361
362
|
name: p.name,
|
|
362
363
|
urlTemplate: p.urlTemplate,
|
|
@@ -374,6 +375,7 @@ function createDocsLayout(config) {
|
|
|
374
375
|
const aiTriggerComponentHtml = aiConfig?.triggerComponent ? serializeIcon(aiConfig.triggerComponent) : void 0;
|
|
375
376
|
const aiSuggestedQuestions = aiConfig?.suggestedQuestions;
|
|
376
377
|
const aiLabel = aiConfig?.aiLabel;
|
|
378
|
+
const aiLoaderVariant = aiConfig?.loader;
|
|
377
379
|
const aiLoadingComponentHtml = typeof aiConfig?.loadingComponent === "function" ? serializeIcon(aiConfig.loadingComponent({ name: aiLabel || "AI" })) : void 0;
|
|
378
380
|
const lastModifiedMap = buildLastModifiedMap(config.entry);
|
|
379
381
|
const descriptionMap = buildDescriptionMap(config.entry);
|
|
@@ -400,6 +402,7 @@ function createDocsLayout(config) {
|
|
|
400
402
|
triggerComponentHtml: aiTriggerComponentHtml,
|
|
401
403
|
suggestedQuestions: aiSuggestedQuestions,
|
|
402
404
|
aiLabel,
|
|
405
|
+
loaderVariant: aiLoaderVariant,
|
|
403
406
|
loadingComponentHtml: aiLoadingComponentHtml
|
|
404
407
|
}),
|
|
405
408
|
/* @__PURE__ */ jsx(DocsPageClient, {
|
|
@@ -418,6 +421,7 @@ function createDocsLayout(config) {
|
|
|
418
421
|
lastModifiedMap,
|
|
419
422
|
lastUpdatedEnabled,
|
|
420
423
|
lastUpdatedPosition,
|
|
424
|
+
llmsTxtEnabled,
|
|
421
425
|
descriptionMap,
|
|
422
426
|
children
|
|
423
427
|
})
|
|
@@ -33,6 +33,8 @@ interface DocsPageClientProps {
|
|
|
33
33
|
lastUpdatedEnabled?: boolean;
|
|
34
34
|
/** Where to show the "Last updated" date: "footer" (next to Edit on GitHub) or "below-title" */
|
|
35
35
|
lastUpdatedPosition?: "footer" | "below-title";
|
|
36
|
+
/** Whether llms.txt is enabled — shows links in footer */
|
|
37
|
+
llmsTxtEnabled?: boolean;
|
|
36
38
|
/** Map of pathname → frontmatter description */
|
|
37
39
|
descriptionMap?: Record<string, string>;
|
|
38
40
|
/** Frontmatter description to display below the page title (overrides descriptionMap) */
|
|
@@ -55,6 +57,7 @@ declare function DocsPageClient({
|
|
|
55
57
|
lastModifiedMap,
|
|
56
58
|
lastUpdatedEnabled,
|
|
57
59
|
lastUpdatedPosition,
|
|
60
|
+
llmsTxtEnabled,
|
|
58
61
|
descriptionMap,
|
|
59
62
|
description,
|
|
60
63
|
children
|
|
@@ -63,7 +63,7 @@ function buildGithubFileUrl(githubUrl, branch, pathname, directory) {
|
|
|
63
63
|
const segments = pathname.replace(/^\//, "").replace(/\/$/, "");
|
|
64
64
|
return `${githubUrl}/tree/${branch}/${directory ? `${directory}/` : ""}app/${segments}/page.mdx`;
|
|
65
65
|
}
|
|
66
|
-
function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, entry = "docs", copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, githubBranch = "main", githubDirectory, lastModifiedMap, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", descriptionMap, description, children }) {
|
|
66
|
+
function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled = true, entry = "docs", copyMarkdown = false, openDocs = false, openDocsProviders, pageActionsPosition = "below-title", pageActionsAlignment = "left", githubUrl, githubBranch = "main", githubDirectory, lastModifiedMap, lastUpdatedEnabled = true, lastUpdatedPosition = "footer", llmsTxtEnabled = false, descriptionMap, description, children }) {
|
|
67
67
|
const fdTocStyle = tocStyle === "directional" ? "clerk" : void 0;
|
|
68
68
|
const [toc, setToc] = useState([]);
|
|
69
69
|
const pathname = usePathname();
|
|
@@ -109,7 +109,7 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
|
|
|
109
109
|
const lastModified = lastUpdatedEnabled ? lastModifiedMap?.[normalizedPath] : void 0;
|
|
110
110
|
const showLastUpdatedBelowTitle = !!lastModified && lastUpdatedPosition === "below-title";
|
|
111
111
|
const showLastUpdatedInFooter = !!lastModified && lastUpdatedPosition === "footer";
|
|
112
|
-
const showFooter = !!githubFileUrl || showLastUpdatedInFooter;
|
|
112
|
+
const showFooter = !!githubFileUrl || showLastUpdatedInFooter || llmsTxtEnabled;
|
|
113
113
|
const needsBelowTitleBlock = showLastUpdatedBelowTitle || showActions;
|
|
114
114
|
useEffect(() => {
|
|
115
115
|
if (!needsBelowTitleBlock) return;
|
|
@@ -188,10 +188,29 @@ function DocsPageClient({ tocEnabled, tocStyle = "default", breadcrumbEnabled =
|
|
|
188
188
|
children
|
|
189
189
|
}), showFooter && /* @__PURE__ */ jsxs("div", {
|
|
190
190
|
className: "not-prose fd-page-footer",
|
|
191
|
-
children: [
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
children: [
|
|
192
|
+
githubFileUrl && /* @__PURE__ */ jsx(EditOnGitHub, { href: githubFileUrl }),
|
|
193
|
+
llmsTxtEnabled && /* @__PURE__ */ jsxs("span", {
|
|
194
|
+
className: "fd-llms-txt-links",
|
|
195
|
+
children: [/* @__PURE__ */ jsx("a", {
|
|
196
|
+
href: "/api/docs?format=llms",
|
|
197
|
+
target: "_blank",
|
|
198
|
+
rel: "noopener noreferrer",
|
|
199
|
+
className: "fd-llms-txt-link",
|
|
200
|
+
children: "llms.txt"
|
|
201
|
+
}), /* @__PURE__ */ jsx("a", {
|
|
202
|
+
href: "/api/docs?format=llms-full",
|
|
203
|
+
target: "_blank",
|
|
204
|
+
rel: "noopener noreferrer",
|
|
205
|
+
className: "fd-llms-txt-link",
|
|
206
|
+
children: "llms-full.txt"
|
|
207
|
+
})]
|
|
208
|
+
}),
|
|
209
|
+
showLastUpdatedInFooter && lastModified && /* @__PURE__ */ jsxs("span", {
|
|
210
|
+
className: "fd-last-updated-footer",
|
|
211
|
+
children: ["Last updated ", lastModified]
|
|
212
|
+
})
|
|
213
|
+
]
|
|
195
214
|
})]
|
|
196
215
|
})
|
|
197
216
|
]
|
package/dist/search.d.mts
CHANGED
|
@@ -27,7 +27,7 @@ declare function createDocsSearchAPI(options?: {
|
|
|
27
27
|
entry?: string;
|
|
28
28
|
language?: string;
|
|
29
29
|
}): {
|
|
30
|
-
GET
|
|
30
|
+
GET(request: Request): Response | Promise<Response>;
|
|
31
31
|
POST(request: Request): Promise<Response>;
|
|
32
32
|
};
|
|
33
33
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farming-labs/theme",
|
|
3
|
-
"version": "0.0.2-beta.
|
|
3
|
+
"version": "0.0.2-beta.24",
|
|
4
4
|
"description": "Theme package for @farming-labs/docs — layout, provider, MDX components, and styles",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"next": ">=14.0.0",
|
|
99
99
|
"tsdown": "^0.20.3",
|
|
100
100
|
"typescript": "^5.9.3",
|
|
101
|
-
"@farming-labs/docs": "0.0.2-beta.
|
|
101
|
+
"@farming-labs/docs": "0.0.2-beta.24"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"@farming-labs/docs": ">=0.0.1",
|
package/styles/ai.css
CHANGED
|
@@ -7,19 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
/* ─── Animations ─────────────────────────────────────────────────── */
|
|
9
9
|
|
|
10
|
-
@keyframes fd-ai-dot {
|
|
11
|
-
0%,
|
|
12
|
-
80%,
|
|
13
|
-
100% {
|
|
14
|
-
transform: scale(0);
|
|
15
|
-
opacity: 0.5;
|
|
16
|
-
}
|
|
17
|
-
40% {
|
|
18
|
-
transform: scale(1);
|
|
19
|
-
opacity: 1;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
10
|
@keyframes fd-ai-fade-in {
|
|
24
11
|
from {
|
|
25
12
|
opacity: 0;
|
|
@@ -343,6 +330,12 @@
|
|
|
343
330
|
line-height: 1.6;
|
|
344
331
|
max-width: 95%;
|
|
345
332
|
word-break: break-word;
|
|
333
|
+
animation: fd-ai-msg-in 300ms ease-out;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
@keyframes fd-ai-msg-in {
|
|
337
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
338
|
+
to { opacity: 1; transform: translateY(0); }
|
|
346
339
|
}
|
|
347
340
|
|
|
348
341
|
/* ─── Chat input ─────────────────────────────────────────────────── */
|
|
@@ -397,38 +390,274 @@
|
|
|
397
390
|
color: var(--color-fd-primary-foreground, #fff);
|
|
398
391
|
}
|
|
399
392
|
|
|
400
|
-
/*
|
|
393
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
394
|
+
* AI Loader variants — fd-ai-loader-*
|
|
395
|
+
* Default: "shimmer-dots" (shimmer text + typing dots in a row)
|
|
396
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
401
397
|
|
|
402
|
-
.fd-ai-
|
|
398
|
+
.fd-ai-loader {
|
|
403
399
|
display: inline-flex;
|
|
400
|
+
align-items: center;
|
|
404
401
|
gap: 6px;
|
|
402
|
+
animation: fd-ai-loader-in 300ms ease-out;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
@keyframes fd-ai-loader-in {
|
|
406
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
407
|
+
to { opacity: 1; transform: translateY(0); }
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/* ── shimmer-dots (default): shimmer text + typing dots ──────────── */
|
|
411
|
+
|
|
412
|
+
.fd-ai-loader-shimmer-text {
|
|
413
|
+
font-size: 13px;
|
|
414
|
+
font-weight: 500;
|
|
415
|
+
background: linear-gradient(
|
|
416
|
+
to right,
|
|
417
|
+
var(--color-fd-muted-foreground, #888) 40%,
|
|
418
|
+
var(--color-fd-foreground, #fff) 60%,
|
|
419
|
+
var(--color-fd-muted-foreground, #888) 80%
|
|
420
|
+
);
|
|
421
|
+
background-size: 200% auto;
|
|
422
|
+
background-clip: text;
|
|
423
|
+
-webkit-background-clip: text;
|
|
424
|
+
color: transparent;
|
|
425
|
+
animation: fd-ai-shimmer-text 3s linear infinite;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
@keyframes fd-ai-shimmer-text {
|
|
429
|
+
0% { background-position: 150% center; }
|
|
430
|
+
100% { background-position: -150% center; }
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.fd-ai-loader-typing-dots {
|
|
434
|
+
display: inline-flex;
|
|
405
435
|
align-items: center;
|
|
436
|
+
gap: 2px;
|
|
406
437
|
}
|
|
407
438
|
|
|
408
|
-
.fd-ai-
|
|
409
|
-
|
|
410
|
-
|
|
439
|
+
.fd-ai-loader-typing-dot {
|
|
440
|
+
width: 4px;
|
|
441
|
+
height: 4px;
|
|
442
|
+
border-radius: 50%;
|
|
443
|
+
background: var(--color-fd-primary, #6366f1);
|
|
444
|
+
animation: fd-ai-typing 1s infinite;
|
|
411
445
|
}
|
|
412
446
|
|
|
413
|
-
.fd-ai-
|
|
447
|
+
.fd-ai-loader-typing-dot:nth-child(2) { animation-delay: 250ms; }
|
|
448
|
+
.fd-ai-loader-typing-dot:nth-child(3) { animation-delay: 500ms; }
|
|
449
|
+
|
|
450
|
+
@keyframes fd-ai-typing {
|
|
451
|
+
0%, 100% { transform: translateY(0); opacity: 0.5; }
|
|
452
|
+
50% { transform: translateY(-2px); opacity: 1; }
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* ── circular: spinning ring ─────────────────────────────────────── */
|
|
456
|
+
|
|
457
|
+
.fd-ai-loader-circular {
|
|
458
|
+
width: 16px;
|
|
459
|
+
height: 16px;
|
|
460
|
+
border: 2px solid var(--color-fd-primary, #6366f1);
|
|
461
|
+
border-top-color: transparent;
|
|
462
|
+
border-radius: 50%;
|
|
463
|
+
animation: fd-ai-spin 0.8s linear infinite;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
@keyframes fd-ai-spin {
|
|
467
|
+
to { transform: rotate(360deg); }
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* ── dots: bouncing dots ─────────────────────────────────────────── */
|
|
471
|
+
|
|
472
|
+
.fd-ai-loader-dots {
|
|
414
473
|
display: inline-flex;
|
|
474
|
+
align-items: center;
|
|
415
475
|
gap: 3px;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.fd-ai-loader-bounce-dot {
|
|
479
|
+
width: 6px;
|
|
480
|
+
height: 6px;
|
|
481
|
+
border-radius: 50%;
|
|
482
|
+
background: var(--color-fd-primary, #6366f1);
|
|
483
|
+
animation: fd-ai-bounce-dots 1.4s ease-in-out infinite;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.fd-ai-loader-bounce-dot:nth-child(2) { animation-delay: 160ms; }
|
|
487
|
+
.fd-ai-loader-bounce-dot:nth-child(3) { animation-delay: 320ms; }
|
|
488
|
+
|
|
489
|
+
@keyframes fd-ai-bounce-dots {
|
|
490
|
+
0%, 100% { transform: scale(0.8); opacity: 0.5; }
|
|
491
|
+
50% { transform: scale(1.2); opacity: 1; }
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/* ── wave: wave bars ─────────────────────────────────────────────── */
|
|
495
|
+
|
|
496
|
+
.fd-ai-loader-wave {
|
|
497
|
+
display: inline-flex;
|
|
416
498
|
align-items: center;
|
|
499
|
+
gap: 2px;
|
|
500
|
+
height: 16px;
|
|
417
501
|
}
|
|
418
502
|
|
|
419
|
-
.fd-ai-
|
|
420
|
-
width:
|
|
421
|
-
|
|
503
|
+
.fd-ai-loader-wave-bar {
|
|
504
|
+
width: 2px;
|
|
505
|
+
border-radius: 2px;
|
|
506
|
+
background: var(--color-fd-primary, #6366f1);
|
|
507
|
+
animation: fd-ai-wave 1s ease-in-out infinite;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.fd-ai-loader-wave-bar:nth-child(1) { height: 6px; animation-delay: 0ms; }
|
|
511
|
+
.fd-ai-loader-wave-bar:nth-child(2) { height: 10px; animation-delay: 100ms; }
|
|
512
|
+
.fd-ai-loader-wave-bar:nth-child(3) { height: 14px; animation-delay: 200ms; }
|
|
513
|
+
.fd-ai-loader-wave-bar:nth-child(4) { height: 10px; animation-delay: 300ms; }
|
|
514
|
+
.fd-ai-loader-wave-bar:nth-child(5) { height: 6px; animation-delay: 400ms; }
|
|
515
|
+
|
|
516
|
+
@keyframes fd-ai-wave {
|
|
517
|
+
0%, 100% { transform: scaleY(1); }
|
|
518
|
+
50% { transform: scaleY(0.6); }
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/* ── pulse: pulsing ring ─────────────────────────────────────────── */
|
|
522
|
+
|
|
523
|
+
.fd-ai-loader-pulse {
|
|
524
|
+
width: 16px;
|
|
525
|
+
height: 16px;
|
|
526
|
+
border: 2px solid var(--color-fd-primary, #6366f1);
|
|
422
527
|
border-radius: 50%;
|
|
423
|
-
|
|
424
|
-
|
|
528
|
+
animation: fd-ai-pulse 1.5s ease-in-out infinite;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
@keyframes fd-ai-pulse {
|
|
532
|
+
0%, 100% { transform: scale(0.95); opacity: 0.8; }
|
|
533
|
+
50% { transform: scale(1.05); opacity: 0.4; }
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/* ── pulse-dot: pulsing dot ──────────────────────────────────────── */
|
|
537
|
+
|
|
538
|
+
.fd-ai-loader-pulse-dot {
|
|
539
|
+
width: 8px;
|
|
540
|
+
height: 8px;
|
|
541
|
+
border-radius: 50%;
|
|
542
|
+
background: var(--color-fd-primary, #6366f1);
|
|
543
|
+
animation: fd-ai-pulse-dot 1.2s ease-in-out infinite;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
@keyframes fd-ai-pulse-dot {
|
|
547
|
+
0%, 100% { transform: scale(1); opacity: 0.8; }
|
|
548
|
+
50% { transform: scale(1.5); opacity: 1; }
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/* ── terminal: blinking cursor ───────────────────────────────────── */
|
|
552
|
+
|
|
553
|
+
.fd-ai-loader-terminal {
|
|
554
|
+
display: inline-flex;
|
|
555
|
+
align-items: center;
|
|
556
|
+
gap: 3px;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
.fd-ai-loader-terminal-prompt {
|
|
560
|
+
font-family: var(--fd-font-mono, ui-monospace, monospace);
|
|
561
|
+
font-size: 13px;
|
|
562
|
+
color: var(--color-fd-primary, #6366f1);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.fd-ai-loader-terminal-cursor {
|
|
566
|
+
width: 7px;
|
|
567
|
+
height: 14px;
|
|
568
|
+
background: var(--color-fd-primary, #6366f1);
|
|
569
|
+
animation: fd-ai-blink 1s step-end infinite;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
@keyframes fd-ai-blink {
|
|
573
|
+
0%, 100% { opacity: 1; }
|
|
574
|
+
50% { opacity: 0; }
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* ── text-shimmer: shimmer text only ─────────────────────────────── */
|
|
578
|
+
/* (reuses .fd-ai-loader-shimmer-text above) */
|
|
579
|
+
|
|
580
|
+
/* ── text-blink: blinking text ───────────────────────────────────── */
|
|
581
|
+
|
|
582
|
+
.fd-ai-loader-text-blink {
|
|
583
|
+
font-size: 13px;
|
|
584
|
+
font-weight: 500;
|
|
585
|
+
animation: fd-ai-text-blink 2s ease-in-out infinite;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
@keyframes fd-ai-text-blink {
|
|
589
|
+
0%, 100% { color: var(--color-fd-primary, #6366f1); }
|
|
590
|
+
50% { color: var(--color-fd-muted-foreground, #888); }
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* ── loading-dots: "Thinking..." with animated dots ──────────────── */
|
|
594
|
+
|
|
595
|
+
.fd-ai-loader-text {
|
|
596
|
+
font-size: 13px;
|
|
597
|
+
font-weight: 500;
|
|
598
|
+
color: var(--color-fd-primary, #6366f1);
|
|
425
599
|
}
|
|
426
600
|
|
|
427
|
-
.fd-ai-
|
|
428
|
-
|
|
601
|
+
.fd-ai-loader-text-dots {
|
|
602
|
+
display: inline-flex;
|
|
429
603
|
}
|
|
430
|
-
|
|
431
|
-
|
|
604
|
+
|
|
605
|
+
.fd-ai-loader-text-dot {
|
|
606
|
+
font-size: 13px;
|
|
607
|
+
font-weight: 500;
|
|
608
|
+
color: var(--color-fd-primary, #6366f1);
|
|
609
|
+
animation: fd-ai-loading-dots 1.4s infinite;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.fd-ai-loader-text-dot:nth-child(1) { animation-delay: 200ms; }
|
|
613
|
+
.fd-ai-loader-text-dot:nth-child(2) { animation-delay: 400ms; }
|
|
614
|
+
.fd-ai-loader-text-dot:nth-child(3) { animation-delay: 600ms; }
|
|
615
|
+
|
|
616
|
+
@keyframes fd-ai-loading-dots {
|
|
617
|
+
0%, 100% { opacity: 0; }
|
|
618
|
+
50% { opacity: 1; }
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/* ── bars: thick wave bars ───────────────────────────────────────── */
|
|
622
|
+
|
|
623
|
+
.fd-ai-loader-bars {
|
|
624
|
+
display: inline-flex;
|
|
625
|
+
align-items: stretch;
|
|
626
|
+
gap: 3px;
|
|
627
|
+
height: 16px;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.fd-ai-loader-bar {
|
|
631
|
+
width: 4px;
|
|
632
|
+
background: var(--color-fd-primary, #6366f1);
|
|
633
|
+
animation: fd-ai-wave-bars 1.2s ease-in-out infinite;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
.fd-ai-loader-bar:nth-child(1) { animation-delay: 0s; }
|
|
637
|
+
.fd-ai-loader-bar:nth-child(2) { animation-delay: 0.2s; }
|
|
638
|
+
.fd-ai-loader-bar:nth-child(3) { animation-delay: 0.4s; }
|
|
639
|
+
|
|
640
|
+
@keyframes fd-ai-wave-bars {
|
|
641
|
+
0%, 100% { transform: scaleY(1); opacity: 0.5; }
|
|
642
|
+
50% { transform: scaleY(0.6); opacity: 1; }
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/* ─── Streaming cursor ───────────────────────────────────────────── */
|
|
646
|
+
|
|
647
|
+
.fd-ai-streaming::after {
|
|
648
|
+
content: "";
|
|
649
|
+
display: inline-block;
|
|
650
|
+
width: 2px;
|
|
651
|
+
height: 1em;
|
|
652
|
+
background: var(--color-fd-primary, #6366f1);
|
|
653
|
+
margin-left: 2px;
|
|
654
|
+
vertical-align: text-bottom;
|
|
655
|
+
animation: fd-ai-cursor-blink 0.8s step-end infinite;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
@keyframes fd-ai-cursor-blink {
|
|
659
|
+
0%, 100% { opacity: 1; }
|
|
660
|
+
50% { opacity: 0; }
|
|
432
661
|
}
|
|
433
662
|
|
|
434
663
|
/* ─── Floating trigger button ────────────────────────────────────── */
|
|
@@ -747,39 +976,7 @@
|
|
|
747
976
|
|
|
748
977
|
/* ─── Thinking dots ──────────────────────────────────────────────── */
|
|
749
978
|
|
|
750
|
-
.fd-ai-
|
|
751
|
-
display: flex;
|
|
752
|
-
gap: 4px;
|
|
753
|
-
align-items: center;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
.fd-ai-fm-thinking-dot {
|
|
757
|
-
width: 6px;
|
|
758
|
-
height: 6px;
|
|
759
|
-
border-radius: 9999px;
|
|
760
|
-
background: var(--color-fd-primary, #6366f1);
|
|
761
|
-
animation: fd-ai-fm-bounce 1s infinite ease-in-out;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
.fd-ai-fm-thinking-dot:nth-child(2) {
|
|
765
|
-
animation-delay: 150ms;
|
|
766
|
-
}
|
|
767
|
-
.fd-ai-fm-thinking-dot:nth-child(3) {
|
|
768
|
-
animation-delay: 300ms;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
@keyframes fd-ai-fm-bounce {
|
|
772
|
-
0%,
|
|
773
|
-
80%,
|
|
774
|
-
100% {
|
|
775
|
-
transform: scale(0.6);
|
|
776
|
-
opacity: 0.4;
|
|
777
|
-
}
|
|
778
|
-
40% {
|
|
779
|
-
transform: scale(1);
|
|
780
|
-
opacity: 1;
|
|
781
|
-
}
|
|
782
|
-
}
|
|
979
|
+
/* Full-modal now uses the shared .fd-ai-loader indicator */
|
|
783
980
|
|
|
784
981
|
/* ─── Bottom input bar ───────────────────────────────────────────── */
|
|
785
982
|
|
package/styles/base.css
CHANGED
|
@@ -409,6 +409,29 @@ figure.shiki:has(figcaption) figcaption {
|
|
|
409
409
|
margin-left: auto;
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
+
.fd-llms-txt-links {
|
|
413
|
+
display: inline-flex;
|
|
414
|
+
align-items: center;
|
|
415
|
+
gap: 0.5rem;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.fd-llms-txt-link {
|
|
419
|
+
color: var(--color-fd-muted-foreground, hsl(0 0% 45%));
|
|
420
|
+
font-size: 0.75rem;
|
|
421
|
+
font-family: var(--fd-font-mono, ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace);
|
|
422
|
+
text-decoration: none;
|
|
423
|
+
padding: 0.125rem 0.375rem;
|
|
424
|
+
border-radius: 0.25rem;
|
|
425
|
+
border: 1px solid var(--color-fd-border, hsl(0 0% 80% / 50%));
|
|
426
|
+
transition: color 150ms, border-color 150ms;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.fd-llms-txt-link:hover {
|
|
430
|
+
/* color: var(--color-fd-foreground, hsl(0 0% 10%));
|
|
431
|
+
border-color: var(--color-fd-foreground, hsl(0 0% 10%)); */
|
|
432
|
+
text-decoration: none;
|
|
433
|
+
}
|
|
434
|
+
|
|
412
435
|
/* ─── Code block copy button: show on hover ────────────────────────── */
|
|
413
436
|
|
|
414
437
|
figure.shiki > button,
|
package/styles/darksharp.css
CHANGED
package/styles/pixel-border.css
CHANGED
|
@@ -425,6 +425,29 @@ figure.shiki > div:first-child {
|
|
|
425
425
|
font-family: var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace));
|
|
426
426
|
text-transform: uppercase;
|
|
427
427
|
}
|
|
428
|
+
/* llms.txt links */
|
|
429
|
+
.fd-llms-txt-links {
|
|
430
|
+
display: inline-flex;
|
|
431
|
+
align-items: center;
|
|
432
|
+
gap: 0.5rem;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.fd-llms-txt-link {
|
|
436
|
+
color: var(--color-fd-muted-foreground, hsl(0 0% 45%));
|
|
437
|
+
font-size: 0.65rem !important;
|
|
438
|
+
font-family: var(--fd-font-mono, ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace);
|
|
439
|
+
text-decoration: none;
|
|
440
|
+
padding: 0.015rem 0.4rem !important;
|
|
441
|
+
border-radius: 0px !important;
|
|
442
|
+
border: 0.5px solid var(--color-fd-border, hsl(0 0% 80% / 50%));
|
|
443
|
+
transition: color 150ms, border-color 150ms;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.fd-llms-txt-link:hover {
|
|
447
|
+
color: var(--color-fd-foreground, hsl(0 0% 10%)) !important;
|
|
448
|
+
border: 0.5px solid var(--color-fd-muted-foreground, hsl(0 0% 10% / 10%)) !important;
|
|
449
|
+
text-decoration: none;
|
|
450
|
+
}
|
|
428
451
|
|
|
429
452
|
/* ─── Page Actions (pixel-border overrides) ───────────────────────── */
|
|
430
453
|
|
|
@@ -533,13 +556,13 @@ figure.shiki > div:first-child {
|
|
|
533
556
|
letter-spacing: 0.06em;
|
|
534
557
|
}
|
|
535
558
|
|
|
536
|
-
.fd-ai-
|
|
559
|
+
.fd-ai-loader-shimmer-text {
|
|
537
560
|
text-transform: uppercase;
|
|
538
561
|
letter-spacing: 0.04em;
|
|
539
562
|
font-size: 11px;
|
|
540
563
|
}
|
|
541
564
|
|
|
542
|
-
.fd-ai-
|
|
565
|
+
.fd-ai-loader-typing-dot {
|
|
543
566
|
border-radius: 0;
|
|
544
567
|
width: 4px;
|
|
545
568
|
height: 4px;
|
|
@@ -617,11 +640,7 @@ figure.shiki > div:first-child {
|
|
|
617
640
|
font-size: 11px;
|
|
618
641
|
}
|
|
619
642
|
|
|
620
|
-
.fd-ai-
|
|
621
|
-
border-radius: 0;
|
|
622
|
-
width: 5px;
|
|
623
|
-
height: 5px;
|
|
624
|
-
}
|
|
643
|
+
/* Full-modal now uses .fd-ai-loader-typing-dot (see above) */
|
|
625
644
|
|
|
626
645
|
/* ─── Code blocks (pixel-border) ─────────────────────────────────── */
|
|
627
646
|
|