fumapress 0.5.4 → 0.6.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/css/generated.css CHANGED
@@ -1,523 +1 @@
1
- @source inline("!ctx");
2
- @source inline("!sizes");
3
- @source inline("---spacing");
4
- @source inline("-translate-x-1/2");
5
- @source inline("@default");
6
- @source inline("@orama/orama");
7
- @source inline("a");
8
- @source inline("above");
9
- @source inline("absolutePath");
10
- @source inline("accepts");
11
- @source inline("active:scale-95");
12
- @source inline("actually");
13
- @source inline("all");
14
- @source inline("allSizes");
15
- @source inline("allTags");
16
- @source inline("allowed");
17
- @source inline("allows");
18
- @source inline("always");
19
- @source inline("and");
20
- @source inline("and/or");
21
- @source inline("any");
22
- @source inline("app");
23
- @source inline("are");
24
- @source inline("as");
25
- @source inline("associated");
26
- @source inline("assumes");
27
- @source inline("async");
28
- @source inline("attribute");
29
- @source inline("attributes");
30
- @source inline("await");
31
- @source inline("backToHome");
32
- @source inline("backdrop-blur-sm");
33
- @source inline("base");
34
- @source inline("basePathname");
35
- @source inline("be");
36
- @source inline("because");
37
- @source inline("before");
38
- @source inline("between");
39
- @source inline("bg-fd-card");
40
- @source inline("bg-fd-primary");
41
- @source inline("bg-fd-primary/10");
42
- @source inline("bg-fd-secondary/80");
43
- @source inline("blog");
44
- @source inline("blogPosts");
45
- @source inline("blue");
46
- @source inline("body");
47
- @source inline("border");
48
- @source inline("border-2");
49
- @source inline("border-b");
50
- @source inline("border-dashed");
51
- @source inline("border-fd-primary");
52
- @source inline("border-y");
53
- @source inline("bottom-2");
54
- @source inline("browsers");
55
- @source inline("bug");
56
- @source inline("buildImageUrl");
57
- @source inline("but");
58
- @source inline("buttonVariants");
59
- @source inline("by");
60
- @source inline("can");
61
- @source inline("canOptimize");
62
- @source inline("cannot");
63
- @source inline("cases");
64
- @source inline("cause");
65
- @source inline("causes");
66
- @source inline("change");
67
- @source inline("check");
68
- @source inline("children");
69
- @source inline("class-variance-authority");
70
- @source inline("className");
71
- @source inline("client");
72
- @source inline("cn");
73
- @source inline("component");
74
- @source inline("components");
75
- @source inline("conditions");
76
- @source inline("config");
77
- @source inline("const");
78
- @source inline("content");
79
- @source inline("copied");
80
- @source inline("copies");
81
- @source inline("copy");
82
- @source inline("copyright");
83
- @source inline("core:docs-layout");
84
- @source inline("core:home-layout");
85
- @source inline("core:notebook-layout");
86
- @source inline("core:provider");
87
- @source inline("count");
88
- @source inline("create");
89
- @source inline("createBlogIndexPage");
90
- @source inline("createBlogLayout");
91
- @source inline("createBlogLayoutPage");
92
- @source inline("createBlogTagPage");
93
- @source inline("createBlogTagsPage");
94
- @source inline("createClientAPIPage");
95
- @source inline("createContext");
96
- @source inline("createDocsLayoutPage");
97
- @source inline("createHomeLayout");
98
- @source inline("createHomeLayoutPage");
99
- @source inline("createLayoutSwitch");
100
- @source inline("createLayoutSwitchAuto");
101
- @source inline("createNotebookLayoutPage");
102
- @source inline("createRootLayout");
103
- @source inline("creationDate");
104
- @source inline("crossOrigin");
105
- @source inline("ctx");
106
- @source inline("current");
107
- @source inline("currentDate");
108
- @source inline("cva");
109
- @source inline("data");
110
- @source inline("data-fd-home-layout-container");
111
- @source inline("data-version");
112
- @source inline("date");
113
- @source inline("deal");
114
- @source inline("decoded");
115
- @source inline("decoration-fd-primary");
116
- @source inline("default");
117
- @source inline("defaultQuality");
118
- @source inline("defaultWidth");
119
- @source inline("defined");
120
- @source inline("detail");
121
- @source inline("detect");
122
- @source inline("detector");
123
- @source inline("deviceSizes");
124
- @source inline("do");
125
- @source inline("documentation");
126
- @source inline("duration-150");
127
- @source inline("eager");
128
- @source inline("edge");
129
- @source inline("else");
130
- @source inline("empty");
131
- @source inline("empty:hidden");
132
- @source inline("en");
133
- @source inline("english");
134
- @source inline("even");
135
- @source inline("except");
136
- @source inline("export");
137
- @source inline("extends");
138
- @source inline("eye");
139
- @source inline("false");
140
- @source inline("fetch");
141
- @source inline("fetchPriority");
142
- @source inline("files");
143
- @source inline("find");
144
- @source inline("first");
145
- @source inline("fixed");
146
- @source inline("flex");
147
- @source inline("flex-1");
148
- @source inline("flex-col");
149
- @source inline("flex-row");
150
- @source inline("flex-wrap");
151
- @source inline("flexsearchStaticClient");
152
- @source inline("fn");
153
- @source inline("following");
154
- @source inline("font-medium");
155
- @source inline("font-mono");
156
- @source inline("font-semibold");
157
- @source inline("for");
158
- @source inline("framework");
159
- @source inline("free");
160
- @source inline("from");
161
- @source inline("fromPathname");
162
- @source inline("full");
163
- @source inline("fumadocs-core/framework");
164
- @source inline("fumadocs-core/i18n");
165
- @source inline("fumadocs-core/source");
166
- @source inline("fumadocs-core/toc");
167
- @source inline("fumadocs-ui/i18n");
168
- @source inline("fumapress");
169
- @source inline("function");
170
- @source inline("furnished");
171
- @source inline("gap-1");
172
- @source inline("gap-2");
173
- @source inline("gap-4");
174
- @source inline("generate");
175
- @source inline("generatedProps");
176
- @source inline("getBlogContext");
177
- @source inline("getLayoutProps");
178
- @source inline("getPressContext");
179
- @source inline("getTags");
180
- @source inline("ghost");
181
- @source inline("githubUrl");
182
- @source inline("given");
183
- @source inline("global");
184
- @source inline("green");
185
- @source inline("grid");
186
- @source inline("grid-cols-1");
187
- @source inline("grid-cols-2");
188
- @source inline("groupTags");
189
- @source inline("grouped");
190
- @source inline("h-12");
191
- @source inline("height");
192
- @source inline("hereby");
193
- @source inline("high");
194
- @source inline("hook");
195
- @source inline("hooks");
196
- @source inline("hostname");
197
- @source inline("hover:bg-fd-accent");
198
- @source inline("hover:text-fd-accent-foreground");
199
- @source inline("how");
200
- @source inline("href");
201
- @source inline("html");
202
- @source inline("human");
203
- @source inline("i");
204
- @source inline("i18n");
205
- @source inline("if");
206
- @source inline("image");
207
- @source inline("imageSizes");
208
- @source inline("imageSrcSet");
209
- @source inline("images");
210
- @source inline("imagesrcset");
211
- @source inline("immediately");
212
- @source inline("import");
213
- @source inline("in");
214
- @source inline("included");
215
- @source inline("including");
216
- @source inline("incorrect");
217
- @source inline("indexPath");
218
- @source inline("indicates");
219
- @source inline("inherit");
220
- @source inline("inheritLayoutProps");
221
- @source inline("inherited");
222
- @source inline("inline-flex");
223
- @source inline("integer");
224
- @source inline("intended");
225
- @source inline("interface");
226
- @source inline("is");
227
- @source inline("isBlog");
228
- @source inline("isLoading");
229
- @source inline("it");
230
- @source inline("item");
231
- @source inline("items");
232
- @source inline("items-center");
233
- @source inline("items-start");
234
- @source inline("joinPathname");
235
- @source inline("js");
236
- @source inline("keep");
237
- @source inline("key");
238
- @source inline("keyof");
239
- @source inline("kind");
240
- @source inline("label");
241
- @source inline("lang");
242
- @source inline("language");
243
- @source inline("last");
244
- @source inline("lastModified");
245
- @source inline("layout");
246
- @source inline("layoutData");
247
- @source inline("layoutProps");
248
- @source inline("layouts");
249
- @source inline("left-1/2");
250
- @source inline("length");
251
- @source inline("let");
252
- @source inline("level");
253
- @source inline("like");
254
- @source inline("limitation");
255
- @source inline("link");
256
- @source inline("loading");
257
- @source inline("locale");
258
- @source inline("lucide-react");
259
- @source inline("magnifying");
260
- @source inline("markdownUrl");
261
- @source inline("matchingBlogPosts");
262
- @source inline("max-h-[min(600px,calc(100vh---spacing(30)))]");
263
- @source inline("max-sm:-mx-4");
264
- @source inline("max-w-[1400px]");
265
- @source inline("max-w-[900px]");
266
- @source inline("max-w-[calc(100%---spacing(4))]");
267
- @source inline("mb-0");
268
- @source inline("md:grid-cols-3");
269
- @source inline("md:grid-cols-4");
270
- @source inline("md:p-8");
271
- @source inline("means");
272
- @source inline("min-h-screen");
273
- @source inline("min-w-0");
274
- @source inline("minIndex");
275
- @source inline("minRatio");
276
- @source inline("minSize");
277
- @source inline("more");
278
- @source inline("most");
279
- @source inline("ms-auto");
280
- @source inline("mt-4");
281
- @source inline("mt-6");
282
- @source inline("mt-auto");
283
- @source inline("multiple");
284
- @source inline("mx-auto");
285
- @source inline("name");
286
- @source inline("navigation");
287
- @source inline("never");
288
- @source inline("new");
289
- @source inline("normal");
290
- @source inline("not");
291
- @source inline("notice");
292
- @source inline("number");
293
- @source inline("object");
294
- @source inline("obtaining");
295
- @source inline("of");
296
- @source inline("omit");
297
- @source inline("on");
298
- @source inline("onClick");
299
- @source inline("onCopy");
300
- @source inline("onOpenChange");
301
- @source inline("onSearchChange");
302
- @source inline("only");
303
- @source inline("open");
304
- @source inline("optimized");
305
- @source inline("option");
306
- @source inline("options");
307
- @source inline("or");
308
- @source inline("orderedPosts");
309
- @source inline("outer");
310
- @source inline("overline");
311
- @source inline("p");
312
- @source inline("p-1");
313
- @source inline("p-4");
314
- @source inline("page");
315
- @source inline("pageProps");
316
- @source inline("panelButtonVariants");
317
- @source inline("params");
318
- @source inline("parsed");
319
- @source inline("path");
320
- @source inline("path/hash");
321
- @source inline("pathname");
322
- @source inline("payload");
323
- @source inline("pb-6");
324
- @source inline("percent");
325
- @source inline("percentSizes");
326
- @source inline("permission");
327
- @source inline("permit");
328
- @source inline("person");
329
- @source inline("persons");
330
- @source inline("portions");
331
- @source inline("posts");
332
- @source inline("potentially");
333
- @source inline("preload");
334
- @source inline("preloadElement");
335
- @source inline("preloadOptions");
336
- @source inline("primary");
337
- @source inline("production");
338
- @source inline("prop");
339
- @source inline("props");
340
- @source inline("prose");
341
- @source inline("provider");
342
- @source inline("providerProps");
343
- @source inline("pt-2");
344
- @source inline("pt-3.5");
345
- @source inline("pt-4");
346
- @source inline("push");
347
- @source inline("px-1.5");
348
- @source inline("px-2");
349
- @source inline("px-3");
350
- @source inline("px-4");
351
- @source inline("py-0.5");
352
- @source inline("py-1");
353
- @source inline("py-2");
354
- @source inline("py-6");
355
- @source inline("quality");
356
- @source inline("query");
357
- @source inline("query-only");
358
- @source inline("r");
359
- @source inline("react");
360
- @source inline("react-dom");
361
- @source inline("received");
362
- @source inline("red");
363
- @source inline("reference");
364
- @source inline("referrerPolicy");
365
- @source inline("refresh");
366
- @source inline("rel");
367
- @source inline("relative");
368
- @source inline("relevant");
369
- @source inline("render");
370
- @source inline("renderCtx");
371
- @source inline("renderRootMeta");
372
- @source inline("replacements");
373
- @source inline("reproduced");
374
- @source inline("requests");
375
- @source inline("resolution");
376
- @source inline("resolve");
377
- @source inline("resolved");
378
- @source inline("rest");
379
- @source inline("result");
380
- @source inline("return");
381
- @source inline("rights");
382
- @source inline("root");
383
- @source inline("rotate-180");
384
- @source inline("rounded-2xl");
385
- @source inline("rounded-lg");
386
- @source inline("rounded-xl");
387
- @source inline("router");
388
- @source inline("run");
389
- @source inline("s");
390
- @source inline("satisfies");
391
- @source inline("say");
392
- @source inline("schema");
393
- @source inline("schemaId");
394
- @source inline("screens");
395
- @source inline("scroll");
396
- @source inline("search");
397
- @source inline("see");
398
- @source inline("sell");
399
- @source inline("server");
400
- @source inline("setOpen");
401
- @source inline("shadow-inner");
402
- @source inline("shadow-md");
403
- @source inline("shadow-sm");
404
- @source inline("shall");
405
- @source inline("should");
406
- @source inline("shrink-0");
407
- @source inline("significantly");
408
- @source inline("size-3.5");
409
- @source inline("size-4");
410
- @source inline("size-6");
411
- @source inline("sizes");
412
- @source inline("sm:border");
413
- @source inline("sm:bottom-4");
414
- @source inline("sm:grid-cols-3");
415
- @source inline("sm:max-w-[400px]");
416
- @source inline("sm:rounded-xl");
417
- @source inline("so");
418
- @source inline("software");
419
- @source inline("something");
420
- @source inline("source");
421
- @source inline("specified");
422
- @source inline("specify");
423
- @source inline("src");
424
- @source inline("srcSet");
425
- @source inline("srcset");
426
- @source inline("start");
427
- @source inline("static");
428
- @source inline("string");
429
- @source inline("styleTag");
430
- @source inline("stylesHref");
431
- @source inline("stylesInline");
432
- @source inline("stylesheet");
433
- @source inline("subject");
434
- @source inline("subset");
435
- @source inline("substantial");
436
- @source inline("support");
437
- @source inline("supported");
438
- @source inline("sure");
439
- @source inline("swap");
440
- @source inline("t");
441
- @source inline("tag");
442
- @source inline("tagTitle");
443
- @source inline("tags");
444
- @source inline("tagsInTotal");
445
- @source inline("tagsPath");
446
- @source inline("takes");
447
- @source inline("text");
448
- @source inline("text-2xl");
449
- @source inline("text-3xl");
450
- @source inline("text-fd-card-foreground");
451
- @source inline("text-fd-muted-foreground");
452
- @source inline("text-fd-primary");
453
- @source inline("text-fd-primary-foreground");
454
- @source inline("text-sm");
455
- @source inline("text-xs");
456
- @source inline("that");
457
- @source inline("the");
458
- @source inline("they");
459
- @source inline("this");
460
- @source inline("those");
461
- @source inline("though");
462
- @source inline("throw");
463
- @source inline("title");
464
- @source inline("to");
465
- @source inline("toc");
466
- @source inline("took");
467
- @source inline("transition-all");
468
- @source inline("transition-colors");
469
- @source inline("transition-transform");
470
- @source inline("translated");
471
- @source inline("translationsConfig");
472
- @source inline("tree");
473
- @source inline("true");
474
- @source inline("truncate");
475
- @source inline("type");
476
- @source inline("typeof");
477
- @source inline("uiTranslations");
478
- @source inline("undefined");
479
- @source inline("unnecessary");
480
- @source inline("unoptimized");
481
- @source inline("unstable_notFound");
482
- @source inline("updated");
483
- @source inline("updates");
484
- @source inline("url");
485
- @source inline("use");
486
- @source inline("useCopyButton");
487
- @source inline("useDocsSearch");
488
- @source inline("useI18n");
489
- @source inline("useMemo");
490
- @source inline("useRouter");
491
- @source inline("useState");
492
- @source inline("useTOCItems");
493
- @source inline("useTranslations");
494
- @source inline("useTranslationsBase");
495
- @source inline("used");
496
- @source inline("v");
497
- @source inline("valid");
498
- @source inline("value");
499
- @source inline("values");
500
- @source inline("variant");
501
- @source inline("viewport");
502
- @source inline("viewportWidthRe");
503
- @source inline("visually");
504
- @source inline("vs");
505
- @source inline("vw");
506
- @source inline("w");
507
- @source inline("w-full");
508
- @source inline("waku");
509
- @source inline("wasteful");
510
- @source inline("we");
511
- @source inline("whom");
512
- @source inline("width");
513
- @source inline("widths");
514
- @source inline("will");
515
- @source inline("without");
516
- @source inline("would");
517
- @source inline("wrapper");
518
- @source inline("x");
519
- @source inline("xl:grid-cols-4");
520
- @source inline("xl:grid-cols-6");
521
- @source inline("you");
522
- @source inline("z-2");
523
- @source inline("z-20");
1
+ @source inline("!ctx !sizes ---spacing -translate-x-1/2 @default @fuma-translate/react @orama/orama a above absolute absolutePath accepts active:scale-95 actually all allSizes allowed allows always and and/or any app are as associated assumes async attribute attributes await backdrop-blur-sm base basePathname be because before between bg-fd-card bg-fd-primary bg-fd-primary/10 bg-fd-secondary/80 blog blogPosts blue body border border-2 border-b border-dashed border-fd-primary border-y bottom-2 browsers bug buildImageUrl but buttonVariants by can canOptimize cannot cases cause causes change check children class-variance-authority className client cn component conditions config const content copies copy copyright core:docs-layout core:home-layout core:notebook-layout core:provider count create createBlogIndexPage createBlogLayout createBlogLayoutPage createBlogTagPage createBlogTagsPage createContext createDocsLayoutPage createHomeLayout createHomeLayoutPage createLayoutSwitch createLayoutSwitchAuto createNotebookLayoutPage createOpenAPIPage createRootLayout creationDate crossOrigin ctx currentDate cva data data-fd-home-layout-container data-version date deal decoration-fd-primary default defaultQuality defaultWidth detail detect detector deviceSizes do documentation duration-150 eager edge else empty empty:hidden en english even except export extends eye false fetch fetchPriority files first fixed flex flex-1 flex-col flex-row flex-wrap flexsearchStaticClient fn following font-medium font-mono font-semibold for framework free from fromPathname full fumadocs-core/framework fumadocs-core/source fumadocs-core/toc fumadocs-openapi/ui fumadocs-ui/i18n function furnished gap-1 gap-2 gap-4 generate generatedProps getBlogContext getLayoutProps getPressContext getTags ghost githubUrl given global green grid grid-cols-1 grid-cols-2 groupTags grouped h-12 height hereby high hook hooks hostname hover:bg-fd-accent hover:text-fd-accent-foreground how href html human i i18n if image imageSizes imageSrcSet images imagesrcset immediately import in included including incorrect indexPath indicates inherit inheritLayoutProps inherited inline-flex integer intended interface is isBlog isLoading it item items items-center items-start joinPathname js keep key kind lang language last lastModified layout layoutData layoutProps layouts left-1/2 length let level like limitation link loading locale lucide-react magnifying markdownUrl matching max-h-[min(600px,calc(100vh---spacing(30)))] max-sm:-mx-4 max-w-[1400px] max-w-[900px] max-w-[calc(100%---spacing(4))] mb-0 md:grid-cols-3 md:grid-cols-4 md:p-8 means min-h-screen min-w-0 minIndex minRatio minSize more most ms-auto mt-4 mt-6 mt-auto multiple mx-auto name navigation never new normal not note notice number object obtaining of omit on onClick onCopy onOpenChange onSearchChange only open optimized option options or oramaStaticClient orderedPosts outer overline p p-1 p-4 page pageProps panel panelButtonVariants params parsed path path/hash pathname pb-6 percent percentSizes permission permit person persons portions posts potentially prefetch preload preloadElement preloadOptions primary production prop props prose provider providerProps pt-2 pt-3.5 pt-4 push px-1.5 px-2 px-3 px-4 py-0.5 py-1 py-2 py-6 quality query query-only r react react-dom received red reference referrerPolicy refresh rel relative relevant render renderCtx renderRootMeta reproduced requests resolution resolve resolveBaseUrl resolved rest result return rights root rotate-180 rounded-2xl rounded-lg rounded-xl router run s satisfies say schema screens scroll search see sell setOpen shadow-inner shadow-md shadow-sm shall should shrink-0 significantly size-3.5 size-4 size-6 sizes sm:border sm:bottom-4 sm:grid-cols-3 sm:max-w-[400px] sm:rounded-xl software something source specified specify src srcSet srcset start string styleTag stylesHref stylesInline stylesheet subject subset substantial support supported swap tag tags tagsPath takes text text-2xl text-3xl text-fd-card-foreground text-fd-muted-foreground text-fd-primary text-fd-primary-foreground text-sm text-xs that the they this those though throw title to toc took transition-all transition-colors transition-transform translationsConfig tree true truncate type typeof uiTranslations undefined unnecessary unoptimized unstable_notFound unstable_prefetchOnEnter updated updates url use useCopyButton useDocsSearch useI18n useMemo useRouter useState useTOCItems used v valid value values variables variant viewport viewportWidthRe visually vs vw w w-full waku wasteful we whom width widths will with without would wrapper x xl:grid-cols-4 xl:grid-cols-6 z-2 z-20");
@@ -0,0 +1,14 @@
1
+ //#region src/.translations/index.d.ts
2
+ type Translations = {
3
+ "All Tags(blog tags page)": string;
4
+ "Back to Home(blog)": string;
5
+ "Blog(blog)": string;
6
+ "Copied(blog panel)": string;
7
+ "Share(blog panel)": string;
8
+ "Table of Contents(blog panel)": string;
9
+ "Tag \"{tag}\"(blog tag page)": string;
10
+ "{count} matching blog posts.(blog tag page)": string;
11
+ "{count} tags in total.(blog tags page)": string;
12
+ };
13
+ //#endregion
14
+ export { Translations };
@@ -0,0 +1,14 @@
1
+ //#region src/.translations/keys.json
2
+ var keys_default = [
3
+ "All Tags(blog tags page)",
4
+ "Back to Home(blog)",
5
+ "Blog(blog)",
6
+ "Copied(blog panel)",
7
+ "Share(blog panel)",
8
+ "Table of Contents(blog panel)",
9
+ "Tag \"{tag}\"(blog tag page)",
10
+ "{count} matching blog posts.(blog tag page)",
11
+ "{count} tags in total.(blog tags page)"
12
+ ];
13
+ //#endregion
14
+ export { keys_default as default };
@@ -1,18 +1,17 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/cn.js";
3
- import { useTranslations } from "./i18n.js";
4
3
  import { jsx, jsxs } from "react/jsx-runtime";
5
4
  import { useState } from "react";
6
5
  import { ChevronDown, ShareIcon } from "lucide-react";
7
6
  import { TOCProvider, TOCScrollArea, useTOCItems } from "fumadocs-ui/components/toc";
8
- import { TOCItem, TOCItems } from "fumadocs-ui/components/toc/clerk";
7
+ import { TOCItem, TOCItems } from "fumadocs-ui/components/toc/default";
9
8
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
10
9
  import { cva } from "class-variance-authority";
11
10
  import { useCopyButton } from "fumadocs-ui/utils/use-copy-button";
11
+ import { T } from "@fuma-translate/react";
12
12
  //#region src/components/blog-panel.tsx
13
13
  const panelButtonVariants = cva("inline-flex items-center font-medium gap-2 px-3 py-2 transition-all duration-150 rounded-lg hover:text-fd-accent-foreground hover:bg-fd-accent active:scale-95");
14
14
  function BlogPanel() {
15
- const t = useTranslations();
16
15
  const items = useTOCItems();
17
16
  const [open, setOpen] = useState(false);
18
17
  const [isSuccessful, onCopy] = useCopyButton(() => {
@@ -38,12 +37,21 @@ function BlogPanel() {
38
37
  className: cn(panelButtonVariants(), "min-w-0"),
39
38
  children: [/* @__PURE__ */ jsx("span", {
40
39
  className: "truncate",
41
- children: t.tableOfContents
40
+ children: /* @__PURE__ */ jsx(T, {
41
+ text: "Table of Contents",
42
+ note: "blog panel"
43
+ })
42
44
  }), /* @__PURE__ */ jsx(ChevronDown, { className: cn("size-3.5 shrink-0 text-fd-muted-foreground transition-transform", open && "rotate-180") })]
43
45
  }), /* @__PURE__ */ jsxs("button", {
44
46
  className: cn(panelButtonVariants(), "ms-auto text-fd-muted-foreground"),
45
47
  onClick: onCopy,
46
- children: [/* @__PURE__ */ jsx(ShareIcon, { className: "size-3.5 shrink-0" }), isSuccessful ? t.copied : t.share]
48
+ children: [/* @__PURE__ */ jsx(ShareIcon, { className: "size-3.5 shrink-0" }), isSuccessful ? /* @__PURE__ */ jsx(T, {
49
+ text: "Copied",
50
+ note: "blog panel"
51
+ }) : /* @__PURE__ */ jsx(T, {
52
+ text: "Share",
53
+ note: "blog panel"
54
+ })]
47
55
  })]
48
56
  })]
49
57
  });
@@ -1,11 +1,11 @@
1
1
  import { Link } from "./link.js";
2
+ import { joinPathname } from "../lib/pathname.js";
2
3
  import { getCreationDate, getPressContext } from "../lib/shared.js";
3
4
  import { cn } from "../lib/cn.js";
4
- import { I18nLabel } from "./i18n.js";
5
- import { joinPathname } from "../lib/pathname.js";
6
5
  import { getBlogContext } from "../plugins/blog.js";
7
6
  import { jsx, jsxs } from "react/jsx-runtime";
8
7
  import { CornerLeftUpIcon } from "lucide-react";
8
+ import { T } from "@fuma-translate/react";
9
9
  import { buttonVariants } from "fumadocs-ui/components/ui/button";
10
10
  //#region src/components/blog.tsx
11
11
  function BlogItem({ page, date }) {
@@ -57,7 +57,10 @@ function LinkToHome({ lang }) {
57
57
  variant: "ghost",
58
58
  className: "text-fd-muted-foreground gap-2"
59
59
  })),
60
- children: [/* @__PURE__ */ jsx(CornerLeftUpIcon, { className: "size-3.5" }), /* @__PURE__ */ jsx(I18nLabel, { label: "backToHome" })]
60
+ children: [/* @__PURE__ */ jsx(CornerLeftUpIcon, { className: "size-3.5" }), /* @__PURE__ */ jsx(T, {
61
+ text: "Back to Home",
62
+ note: "blog"
63
+ })]
61
64
  });
62
65
  }
63
66
  //#endregion
@@ -1,13 +1,17 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../lib/pathname.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useI18n } from "fumadocs-ui/contexts/i18n";
4
4
  import { SearchDialog, SearchDialogClose, SearchDialogContent, SearchDialogHeader, SearchDialogIcon, SearchDialogInput, SearchDialogList, SearchDialogOverlay } from "fumadocs-ui/components/dialog/search";
5
5
  import { useDocsSearch } from "fumadocs-core/search/client";
6
6
  import { flexsearchStaticClient } from "fumadocs-core/search/client/flexsearch-static";
7
+ import { useI18n } from "fumadocs-ui/contexts/i18n";
7
8
  //#region src/components/flexsearch-static.tsx
8
9
  function DefaultSearchDialog(props) {
9
10
  const { locale } = useI18n();
10
- const { search, setSearch, query } = useDocsSearch({ client: flexsearchStaticClient({ locale }) });
11
+ const { search, setSearch, query } = useDocsSearch({ client: flexsearchStaticClient({
12
+ locale,
13
+ from: resolveBaseUrl(import.meta.env.BASE_URL, "/api/search")
14
+ }) });
11
15
  return /* @__PURE__ */ jsxs(SearchDialog, {
12
16
  search,
13
17
  onSearchChange: setSearch,
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../lib/pathname.js";
2
3
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
4
  import { createContext, use, useMemo } from "react";
4
5
  import ReactDOM from "react-dom";
@@ -11,14 +12,14 @@ function parseLength(v) {
11
12
  return parsed;
12
13
  }
13
14
  /**
14
- * resolve src to a full pathname if relative
15
+ * resolve src to a full pathname with base URL included (or keep absolute URLs as-is)
15
16
  */
16
17
  function normalizeSrc(src, basePathname) {
17
- if (src.startsWith("http://") || src.startsWith("https://")) return src;
18
+ if (src.startsWith("http://") || src.startsWith("https://") || src.startsWith("data:")) return src;
18
19
  const base = new URL(basePathname, "http://localhost");
19
20
  const resolved = new URL(src, base);
20
21
  if (resolved.hostname !== base.hostname) throw new Error(`The src attribute "${src}" is not a valid relative path`);
21
- return resolved.pathname;
22
+ return resolveBaseUrl(import.meta.env.BASE_URL, resolved.pathname);
22
23
  }
23
24
  const ImageContext = createContext(null);
24
25
  function ImageProvider({ provider, children }) {
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { createClientAPIPage } from "fumadocs-openapi/ui/create-client";
2
+ import { createOpenAPIPage } from "fumadocs-openapi/ui";
3
3
  //#region src/components/openapi.tsx
4
- var openapi_default = createClientAPIPage();
4
+ var openapi_default = createOpenAPIPage();
5
5
  //#endregion
6
6
  export { openapi_default as default };
@@ -1,8 +1,10 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../lib/pathname.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useI18n } from "fumadocs-ui/contexts/i18n";
4
4
  import { SearchDialog, SearchDialogClose, SearchDialogContent, SearchDialogHeader, SearchDialogIcon, SearchDialogInput, SearchDialogList, SearchDialogOverlay } from "fumadocs-ui/components/dialog/search";
5
5
  import { useDocsSearch } from "fumadocs-core/search/client";
6
+ import { useI18n } from "fumadocs-ui/contexts/i18n";
7
+ import { oramaStaticClient } from "fumadocs-core/search/client/orama-static";
6
8
  import { create } from "@orama/orama";
7
9
  //#region src/components/orama-search-static.tsx
8
10
  function initOrama() {
@@ -13,11 +15,11 @@ function initOrama() {
13
15
  }
14
16
  function DefaultSearchDialog(props) {
15
17
  const { locale } = useI18n();
16
- const { search, setSearch, query } = useDocsSearch({
17
- type: "static",
18
+ const { search, setSearch, query } = useDocsSearch({ client: oramaStaticClient({
18
19
  initOrama,
19
- locale
20
- });
20
+ locale,
21
+ from: resolveBaseUrl(import.meta.env.BASE_URL, "/api/search")
22
+ }) });
21
23
  return /* @__PURE__ */ jsxs(SearchDialog, {
22
24
  search,
23
25
  onSearchChange: setSearch,
@@ -27,7 +27,10 @@ const framework = {
27
27
  loading: priority ? "eager" : void 0,
28
28
  ...props
29
29
  }),
30
- Link
30
+ Link: ({ prefetch = true, ...props }) => /* @__PURE__ */ jsx(Link, {
31
+ unstable_prefetchOnEnter: prefetch,
32
+ ...props
33
+ })
31
34
  };
32
35
  function PressProvider(props) {
33
36
  return /* @__PURE__ */ jsx(FrameworkProvider, {
package/dist/config.d.ts CHANGED
@@ -22,7 +22,6 @@ interface BaseConfig<C extends ConfigContext> {
22
22
  */
23
23
  mode?: BuildMode;
24
24
  site?: SiteConfig;
25
- translations?: (C["i18n"] extends I18nConfig<infer Lang> ? TranslationsAPI<Lang> : never) | SingularTranslationsAPI;
26
25
  meta?: {
27
26
  /** render meta tags for any pages */root?: (this: AppContext<C>) => ReactNode; /** render meta tags for page */
28
27
  page?: (this: AppContext<C>, page: C["page"]) => ReactNode;
@@ -40,9 +39,10 @@ interface ConfigWithLoader<L extends LoaderConfig = LoaderConfig> extends BaseCo
40
39
  * @deprecated Pass content sources directly to `content` instead.
41
40
  */
42
41
  loader?: LoaderOutput<L>;
42
+ translations?: (L["i18n"] extends I18nConfig<infer Lang> ? TranslationsAPI<Lang, any> : never) | SingularTranslationsAPI<any>;
43
43
  }
44
- interface ConfigWithContent<I extends _Internal.AnyInput = _Internal.AnyInput, I18n extends I18nConfig | undefined = I18nConfig | undefined> extends BaseConfig<{
45
- i18n: I18n;
44
+ interface ConfigWithContent<I extends _Internal.AnyInput = _Internal.AnyInput, Lang extends string | undefined = string | undefined> extends BaseConfig<{
45
+ i18n: [Lang] extends [string] ? I18nConfig<Lang> : undefined;
46
46
  meta: _Internal.GenerateMeta<NoInfer<I>>;
47
47
  page: _Internal.GeneratePage<NoInfer<I>>;
48
48
  source: I extends Record<infer K, SourceUnion> ? K : undefined;
@@ -50,9 +50,10 @@ interface ConfigWithContent<I extends _Internal.AnyInput = _Internal.AnyInput, I
50
50
  /** The content sources */
51
51
  content: I;
52
52
  /** i18n config for core, optional when `translations` is specified */
53
- i18n?: I18n;
53
+ i18n?: [Lang] extends [string] ? I18nConfig<Lang> : undefined;
54
+ translations?: ([Lang] extends [string] ? TranslationsAPI<Lang, any> : never) | SingularTranslationsAPI<any>;
54
55
  /** Options for Fumadocs Loader API */
55
- loaderOptions?: Omit<PressLoaderOptions<_Internal.GenerateStorage<I>, I18n>, "baseUrl" | "i18n"> & {
56
+ loaderOptions?: Omit<PressLoaderOptions<_Internal.GenerateStorage<I>, [Lang] extends [string] ? I18nConfig<Lang> : undefined>, "baseUrl" | "i18n"> & {
56
57
  /**
57
58
  * Always revalidate all dynamic content sources in `content` (on each request).
58
59
  * By default, you can revalidate manually with `getPressContext<Ctx>().revalidateLoader(...)`.
@@ -118,11 +119,11 @@ interface ConfigBuilder<C extends ConfigContext = ConfigContext> {
118
119
  /** Add adapter for content sources */
119
120
  useAdapters: (...adapters: Adapter<C>[]) => ConfigBuilder<C>;
120
121
  }
121
- declare function defineConfig<I extends _Internal.AnyInput, I18n extends I18nConfig | undefined = undefined>(config: ConfigWithContent<I, I18n>): ConfigBuilder<{
122
+ declare function defineConfig<I extends _Internal.AnyInput, Lang extends string | undefined = undefined>(config: ConfigWithContent<I, Lang>): ConfigBuilder<{
122
123
  meta: _Internal.GenerateMeta<I>;
123
124
  page: _Internal.GeneratePage<I>;
124
125
  source: I extends Record<infer K, SourceUnion> ? K : undefined;
125
- i18n: I18n;
126
+ i18n: [Lang] extends [string] ? I18nConfig<Lang> : undefined;
126
127
  }>;
127
128
  declare function defineConfig<L extends LoaderConfig>(config?: ConfigWithLoader<L>): ConfigBuilder<{
128
129
  i18n: L["i18n"];
package/dist/i18n.d.ts CHANGED
@@ -1,18 +1,7 @@
1
- import { TranslationValue, TranslationsAPIExtension } from "fumadocs-core/i18n";
1
+ import { Translations } from "./.translations/index.js";
2
+ import { TranslationExtension } from "fumadocs-core/i18n";
2
3
 
3
4
  //#region src/i18n.d.ts
4
- declare const defaultTranslations: {
5
- blog: string;
6
- allTags: string;
7
- tagsInTotal: TranslationValue<"count">;
8
- tagTitle: TranslationValue<"tag">;
9
- matchingBlogPosts: TranslationValue<"count">;
10
- backToHome: string;
11
- tableOfContents: string;
12
- share: string;
13
- copied: string;
14
- };
15
- type Translations = typeof defaultTranslations;
16
- declare function fumapressTranslations(): TranslationsAPIExtension<"fumapress", Translations>;
5
+ declare function fumapressTranslations(): TranslationExtension<keyof Translations>;
17
6
  //#endregion
18
- export { Translations, defaultTranslations, fumapressTranslations };
7
+ export { type Translations, fumapressTranslations };
package/dist/i18n.js CHANGED
@@ -1,20 +1,7 @@
1
+ import keys_default from "./.translations/keys.js";
1
2
  //#region src/i18n.ts
2
- const defaultTranslations = {
3
- blog: "Blog",
4
- allTags: "All Tags",
5
- tagsInTotal: "{count} tags in total.",
6
- tagTitle: "Tag \"{tag}\"",
7
- matchingBlogPosts: "{count} matching blog posts.",
8
- backToHome: "Back to Home",
9
- tableOfContents: "Table of Contents",
10
- share: "Share",
11
- copied: "Copied"
12
- };
13
3
  function fumapressTranslations() {
14
- return {
15
- namespace: "fumapress",
16
- defaultValue: defaultTranslations
17
- };
4
+ return { keys: keys_default };
18
5
  }
19
6
  //#endregion
20
- export { defaultTranslations, fumapressTranslations };
7
+ export { fumapressTranslations };
@@ -1,12 +1,12 @@
1
1
  import { Link } from "../components/link.js";
2
+ import { joinPathname } from "../lib/pathname.js";
2
3
  import { getPressContext } from "../lib/shared.js";
3
4
  import { cn } from "../lib/cn.js";
4
- import { I18nLabel } from "../components/i18n.js";
5
- import { joinPathname } from "../lib/pathname.js";
6
5
  import { getBlogContext } from "../plugins/blog.js";
7
6
  import { OrderedBlogGrid } from "../components/blog.js";
8
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
8
  import { ListIcon } from "lucide-react";
9
+ import { T } from "@fuma-translate/react";
10
10
  import { buttonVariants } from "fumadocs-ui/components/ui/button";
11
11
  //#region src/layouts/blog.index.tsx
12
12
  function createBlogIndexPage({ heading, description } = {}) {
@@ -19,7 +19,10 @@ function createBlogIndexPage({ heading, description } = {}) {
19
19
  children: [
20
20
  /* @__PURE__ */ jsx("h1", {
21
21
  className: "text-3xl font-semibold",
22
- children: heading ?? /* @__PURE__ */ jsx(I18nLabel, { label: "blog" })
22
+ children: heading ?? /* @__PURE__ */ jsx(T, {
23
+ text: "Blog",
24
+ note: "blog"
25
+ })
23
26
  }),
24
27
  /* @__PURE__ */ jsx("p", {
25
28
  className: "text-fd-primary overline decoration-fd-primary empty:hidden",
@@ -28,7 +31,10 @@ function createBlogIndexPage({ heading, description } = {}) {
28
31
  tagsPath !== false && /* @__PURE__ */ jsxs(Link, {
29
32
  href: lang ? joinPathname(lang, tagsPath) : tagsPath,
30
33
  className: cn(buttonVariants({ variant: "primary" }), "gap-2"),
31
- children: [/* @__PURE__ */ jsx(ListIcon, { className: "size-4" }), /* @__PURE__ */ jsx(I18nLabel, { label: "allTags" })]
34
+ children: [/* @__PURE__ */ jsx(ListIcon, { className: "size-4" }), /* @__PURE__ */ jsx(T, {
35
+ text: "All Tags",
36
+ note: "blog tags page"
37
+ })]
32
38
  })
33
39
  ]
34
40
  }), /* @__PURE__ */ jsx(OrderedBlogGrid, { posts: source.getPages(lang).filter(isBlog.bind(ctx)) })] });
@@ -1,8 +1,8 @@
1
1
  import { Link } from "../components/link.js";
2
+ import { joinPathname } from "../lib/pathname.js";
2
3
  import { getCreationDate, getPressContext, renderBody, renderPageMeta, renderToc } from "../lib/shared.js";
3
4
  import { BlogPanel, BlogProvider } from "../components/blog-panel.js";
4
5
  import { getTags } from "../lib/shared/blog.js";
5
- import { joinPathname } from "../lib/pathname.js";
6
6
  import { createHomeLayout } from "./home.js";
7
7
  import { getBlogContext } from "../plugins/blog.js";
8
8
  import { LinkToHome } from "../components/blog.js";
@@ -1,11 +1,11 @@
1
1
  import { Link } from "../components/link.js";
2
2
  import { getPressContext } from "../lib/shared.js";
3
- import { I18nLabel } from "../components/i18n.js";
4
3
  import { getTags, groupTags } from "../lib/shared/blog.js";
5
4
  import { getBlogContext } from "../plugins/blog.js";
6
5
  import { LinkToHome, OrderedBlogGrid } from "../components/blog.js";
7
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
7
  import { NewspaperIcon, TagIcon } from "lucide-react";
8
+ import { T } from "@fuma-translate/react";
9
9
  //#region src/layouts/blog.tags.tsx
10
10
  function createBlogTagsPage({ heading, description } = {}) {
11
11
  return async function BlogTagsPage({ lang }) {
@@ -18,15 +18,19 @@ function createBlogTagsPage({ heading, description } = {}) {
18
18
  /* @__PURE__ */ jsx(LinkToHome, { lang }),
19
19
  /* @__PURE__ */ jsx("h1", {
20
20
  className: "font-semibold text-2xl",
21
- children: heading ?? /* @__PURE__ */ jsx(I18nLabel, { label: "allTags" })
21
+ children: heading ?? /* @__PURE__ */ jsx(T, {
22
+ text: "All Tags",
23
+ note: "blog tags page"
24
+ })
22
25
  }),
23
26
  /* @__PURE__ */ jsx("p", {
24
27
  className: "text-fd-muted-foreground empty:hidden",
25
28
  children: description ?? /* @__PURE__ */ jsxs("span", {
26
29
  className: "flex items-center gap-1",
27
- children: [/* @__PURE__ */ jsx(TagIcon, { className: "size-3.5 text-fd-primary" }), /* @__PURE__ */ jsx(I18nLabel, {
28
- label: "tagsInTotal",
29
- replacements: { count: String(grouped.size) }
30
+ children: [/* @__PURE__ */ jsx(TagIcon, { className: "size-3.5 text-fd-primary" }), /* @__PURE__ */ jsx(T, {
31
+ text: "{count} tags in total.",
32
+ note: "blog tags page",
33
+ variables: { count: String(grouped.size) }
30
34
  })]
31
35
  })
32
36
  })
@@ -71,9 +75,10 @@ function createBlogTagPage({ heading, description } = {}) {
71
75
  className: "font-semibold text-2xl",
72
76
  children: heading ?? /* @__PURE__ */ jsxs("span", {
73
77
  className: "inline-flex gap-2 items-center",
74
- children: [/* @__PURE__ */ jsx(TagIcon, { className: "text-fd-primary size-6" }), /* @__PURE__ */ jsx(I18nLabel, {
75
- label: "tagTitle",
76
- replacements: { tag }
78
+ children: [/* @__PURE__ */ jsx(TagIcon, { className: "text-fd-primary size-6" }), /* @__PURE__ */ jsx(T, {
79
+ text: "Tag \"{tag}\"",
80
+ note: "blog tag page",
81
+ variables: { tag }
77
82
  })]
78
83
  })
79
84
  }),
@@ -81,9 +86,10 @@ function createBlogTagPage({ heading, description } = {}) {
81
86
  className: "text-fd-muted-foreground empty:hidden",
82
87
  children: description ?? /* @__PURE__ */ jsxs("span", {
83
88
  className: "inline-flex items-center gap-1",
84
- children: [/* @__PURE__ */ jsx(NewspaperIcon, { className: "text-fd-primary size-3.5" }), /* @__PURE__ */ jsx(I18nLabel, {
85
- label: "matchingBlogPosts",
86
- replacements: { count: String(posts.length) }
89
+ children: [/* @__PURE__ */ jsx(NewspaperIcon, { className: "text-fd-primary size-3.5" }), /* @__PURE__ */ jsx(T, {
90
+ text: "{count} matching blog posts.",
91
+ note: "blog tag page",
92
+ variables: { count: String(posts.length) }
87
93
  })]
88
94
  })
89
95
  })
@@ -1,4 +1,5 @@
1
1
  //#region src/lib/pathname.ts
2
+ /** Join multiple (full) pathnames */
2
3
  function joinPathname(...paths) {
3
4
  const segs = [];
4
5
  for (let p of paths) {
@@ -10,8 +11,14 @@ function joinPathname(...paths) {
10
11
  }
11
12
  const PATHNAME_SEGMENT_REGEX = /^[A-Za-z0-9\-._~!$&'()*+,;=:@]+$/;
12
13
  /** Check if the string is a full pathname (one that does not include `.` or `..`) */
13
- function isPlainPathname(s) {
14
+ function isFullPathname(s) {
14
15
  return s.startsWith("/") && s.slice(1).split("/").every((seg) => seg !== "." && seg !== ".." && PATHNAME_SEGMENT_REGEX.test(seg));
15
16
  }
17
+ /** add base URL to pathname */
18
+ function resolveBaseUrl(base, pathname) {
19
+ if (base.endsWith("/")) base = base.slice(0, -1);
20
+ if (pathname.startsWith("/")) pathname = pathname.slice(1);
21
+ return `${base}/${pathname}`;
22
+ }
16
23
  //#endregion
17
- export { isPlainPathname, joinPathname };
24
+ export { isFullPathname, joinPathname, resolveBaseUrl };
@@ -3,6 +3,7 @@ import { Adapter, AppContextData, Awaitable, ServerPlugin } from "./types.js";
3
3
  import { ReactNode } from "react";
4
4
  import { LoaderOutput } from "fumadocs-core/source";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
+ import { I18nConfig, SingularTranslationsAPI, TranslationsAPI } from "fumadocs-core/i18n";
6
7
 
7
8
  //#region src/lib/shared.d.ts
8
9
  interface AppContext<C extends ConfigContext = ConfigContext> {
@@ -21,7 +22,7 @@ interface AppContext<C extends ConfigContext = ConfigContext> {
21
22
  * custom data in app context, can be referenced from plugins/pages etc
22
23
  */
23
24
  data: AppContextData & Record<string, unknown>;
24
- translationsConfig?: BaseConfig<C>["translations"];
25
+ translationsConfig?: (C["i18n"] extends I18nConfig<infer Lang> ? TranslationsAPI<Lang> : never) | SingularTranslationsAPI;
25
26
  i18nConfig?: C["i18n"];
26
27
  metaConfig?: BaseConfig<C>["meta"];
27
28
  siteConfig: {
@@ -6,8 +6,8 @@ import { NotebookLayoutContextData } from "../layouts/notebook.js";
6
6
  import { RootLayoutContextData } from "../layouts/root.js";
7
7
  import { ReactNode } from "react";
8
8
  import { ContentStorage, LoaderOptions, LoaderPluginOption, Page } from "fumadocs-core/source";
9
- import { I18nConfig } from "fumadocs-core/i18n";
10
9
  import { CreateApi, CreateInterceptor, CreateLayout, CreatePage, CreateRoot, CreateSlice, createPages } from "waku/router/server";
10
+ import { I18nConfig } from "fumadocs-core/i18n";
11
11
  import { StructuredData } from "fumadocs-core/mdx-plugins";
12
12
  import { TOCItemType } from "fumadocs-core/toc";
13
13
  import { Hono } from "hono/tiny";
@@ -1,5 +1,5 @@
1
- import { groupTags, groupTagsI18n } from "../lib/shared/blog.js";
2
1
  import { joinPathname } from "../lib/pathname.js";
2
+ import { groupTags, groupTagsI18n } from "../lib/shared/blog.js";
3
3
  import { createBlogLayout, createBlogLayoutPage } from "../layouts/blog.js";
4
4
  import { createBlogTagPage, createBlogTagsPage } from "../layouts/blog.tags.js";
5
5
  import { createBlogIndexPage } from "../layouts/blog.index.js";
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { ImageProvider } from "../../components/image.js";
3
2
  import { joinPathname } from "../../lib/pathname.js";
3
+ import { ImageProvider } from "../../components/image.js";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { useMemo } from "react";
6
6
  //#region src/plugins/image/cloudflare.client.tsx
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { resolveBaseUrl } from "../../lib/pathname.js";
2
3
  import { ImageProvider } from "../../components/image.js";
3
4
  import { validateImageSrc } from "./self-hosted.utils.js";
4
5
  import { jsx } from "react/jsx-runtime";
@@ -16,7 +17,7 @@ function createProvider(config) {
16
17
  width: String(width),
17
18
  quality: String(quality)
18
19
  });
19
- return `${config.path}?${params.toString()}`;
20
+ return `${resolveBaseUrl(import.meta.env.BASE_URL, config.path)}?${params.toString()}`;
20
21
  },
21
22
  validate(src) {
22
23
  if (import.meta.env.DEV) {
@@ -1,5 +1,5 @@
1
1
  import { __toESM } from "../../_virtual/_rolldown/runtime.js";
2
- import { isPlainPathname } from "../../lib/pathname.js";
2
+ import { isFullPathname } from "../../lib/pathname.js";
3
3
  import { require_http_cache_semantics } from "../../node_modules/.pnpm/http-cache-semantics@4.2.0/node_modules/http-cache-semantics/index.js";
4
4
  //#region src/plugins/image/self-hosted.utils.ts
5
5
  var import_http_cache_semantics = /* @__PURE__ */ __toESM(require_http_cache_semantics(), 1);
@@ -253,7 +253,7 @@ function validateImageSrc(config, src) {
253
253
  };
254
254
  return { allowed: true };
255
255
  }
256
- if (isPlainPathname(src)) return { allowed: true };
256
+ if (isFullPathname(src)) return { allowed: true };
257
257
  return {
258
258
  allowed: false,
259
259
  reason: `Image URL "${src}" is not normalized`
@@ -1,7 +1,7 @@
1
1
  import { ConfigContext } from "../config.js";
2
2
  import { Awaitable, ServerPlugin } from "../lib/types.js";
3
3
  import { FC } from "react";
4
- import { ClientApiPageProps } from "fumadocs-openapi/ui/create-client";
4
+ import { OpenAPIPageProps } from "fumadocs-openapi/ui";
5
5
  import { OpenAPIServer } from "fumadocs-openapi/server";
6
6
 
7
7
  //#region src/plugins/openapi.d.ts
@@ -10,7 +10,7 @@ interface OpenAPIOptions {
10
10
  /** do not add the loader plugin for OpenAPI integration */
11
11
  disableLoaderPlugin?: boolean;
12
12
  /** must be a client component */
13
- ClientAPIPage?: FC<ClientApiPageProps>;
13
+ ClientAPIPage?: FC<OpenAPIPageProps>;
14
14
  /**
15
15
  * Create proxy server.
16
16
  *
@@ -1,5 +1,4 @@
1
- import { isPlainPathname } from "../lib/pathname.js";
2
- import { PayloadProvider, WithPayload } from "../components/openapi.payload.js";
1
+ import { isFullPathname, resolveBaseUrl } from "../lib/pathname.js";
3
2
  import { jsx } from "react/jsx-runtime";
4
3
  import { openapiTranslations } from "fumadocs-openapi/i18n";
5
4
  //#region src/plugins/openapi.tsx
@@ -14,17 +13,6 @@ function openapiPlugin(options) {
14
13
  return data;
15
14
  });
16
15
  }
17
- async function ServerPayloadProvider({ children }) {
18
- const payload = {};
19
- for (const [schemaId, schema] of Object.entries(await server.getSchemas())) payload[schemaId] = {
20
- bundled: schema.bundled,
21
- proxyUrl: server.options.proxyUrl
22
- };
23
- return /* @__PURE__ */ jsx(PayloadProvider, {
24
- payload: JSON.stringify(payload),
25
- children
26
- });
27
- }
28
16
  return {
29
17
  name: "core:openapi",
30
18
  init() {
@@ -33,10 +21,6 @@ function openapiPlugin(options) {
33
21
  initRenderers(this.data["core:notebook-layout"] ??= {});
34
22
  if (this.translationsConfig) this.translationsConfig.extend(openapiTranslations());
35
23
  },
36
- renderPage({ page, fallback }) {
37
- if (!isOpenAPI(page.data)) return;
38
- return /* @__PURE__ */ jsx(ServerPayloadProvider, { children: fallback });
39
- },
40
24
  configureLoader(options) {
41
25
  if (!disableLoaderPlugin) {
42
26
  options.plugins ??= [];
@@ -46,7 +30,7 @@ function openapiPlugin(options) {
46
30
  },
47
31
  async createPages({ createApi }) {
48
32
  const proxyUrl = server.options.proxyUrl;
49
- const { createProxy = typeof proxyUrl === "string" && isPlainPathname(proxyUrl) } = options;
33
+ const { createProxy = typeof proxyUrl === "string" && isFullPathname(proxyUrl) } = options;
50
34
  if (createProxy) {
51
35
  if (!proxyUrl) throw new Error(`[Fumapress] The "proxyUrl" option in createOpenAPI() is required to create proxy server`);
52
36
  if (this.mode === "static") throw new Error(`[Fumapress] static mode is not compatible with proxy server`);
@@ -64,11 +48,13 @@ function adapter(options) {
64
48
  async "core:render-body"(page) {
65
49
  if (isOpenAPI(page.data)) {
66
50
  const ClientAPIPage = options.ClientAPIPage ?? (await import("../components/openapi.js")).default;
67
- const props = page.data.getAPIPageProps();
68
- return /* @__PURE__ */ jsx(WithPayload, {
69
- schemaId: props.document,
70
- Comp: ClientAPIPage,
71
- props
51
+ const { payload, ...props } = page.data.getOpenAPIPageProps();
52
+ return /* @__PURE__ */ jsx(ClientAPIPage, {
53
+ payload: {
54
+ ...payload,
55
+ proxyUrl: payload.proxyUrl && isFullPathname(payload.proxyUrl) ? resolveBaseUrl(import.meta.env.BASE_URL, payload.proxyUrl) : payload.proxyUrl
56
+ },
57
+ ...props
72
58
  });
73
59
  }
74
60
  },
@@ -2,7 +2,7 @@ import { appContext, initApp } from "../lib/shared.js";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { Fragment as Fragment$1 } from "react";
4
4
  import { createPages } from "waku";
5
- import { unstable_notFound, unstable_notFound as notFound, unstable_redirect as redirect } from "waku/router/server";
5
+ import { unstable_notFound, unstable_notFound as notFound, unstable_redirect, unstable_redirect as redirect } from "waku/router/server";
6
6
  //#region src/router/index.tsx
7
7
  async function createRouter(userConfig) {
8
8
  const context = await initApp(userConfig);
@@ -87,14 +87,10 @@ async function createRouter(userConfig) {
87
87
  staticPaths: Object.keys(context.i18nConfig.languages),
88
88
  component: layouts.notFound
89
89
  });
90
- const defaultLanguage = context.i18nConfig.defaultLanguage;
91
- fns.createPage({
92
- render: defaultRenderMode,
90
+ if (context.mode !== "static") fns.createPage({
91
+ render: "dynamic",
93
92
  path: "/404",
94
- staticPaths: [],
95
- component() {
96
- return /* @__PURE__ */ jsx(layouts.notFound, { lang: defaultLanguage });
97
- }
93
+ component: () => unstable_redirect(`/${context.i18nConfig.defaultLanguage}`)
98
94
  });
99
95
  } else {
100
96
  fns.createRoot({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fumapress",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "description": "An opinionated docs framework powered by Fumadocs",
5
5
  "keywords": [
6
6
  "Docs",
@@ -55,8 +55,9 @@
55
55
  "access": "public"
56
56
  },
57
57
  "dependencies": {
58
+ "@fuma-translate/react": "^1.0.2",
58
59
  "@orama/orama": "^3.1.18",
59
- "@takumi-rs/image-response": "^1.7.0",
60
+ "@takumi-rs/image-response": "^1.8.1",
60
61
  "class-variance-authority": "^0.7.1",
61
62
  "flexsearch": "^0.8.212",
62
63
  "lucide-react": "^1.17.0",
@@ -69,35 +70,35 @@
69
70
  "@fastify/deepmerge": "^3.2.1",
70
71
  "@tailwindcss/oxide": "^4.3.0",
71
72
  "@types/http-cache-semantics": "^4.2.0",
72
- "@types/mdx": "^2.0.13",
73
- "@types/node": "^25.9.1",
74
- "@types/react": "^19.2.16",
73
+ "@types/mdx": "^2.0.14",
74
+ "@types/node": "^25.9.3",
75
+ "@types/react": "^19.2.17",
75
76
  "@types/react-dom": "^19.2.3",
76
- "fumadocs-core": "^16.9.3",
77
- "fumadocs-mdx": "^15.0.11",
78
- "fumadocs-openapi": "^10.10.3",
79
- "fumadocs-ui": "^16.9.3",
80
- "hono": "^4.12.23",
77
+ "fumadocs-core": "^16.10.2",
78
+ "fumadocs-mdx": "^15.0.12",
79
+ "fumadocs-openapi": "^11.0.1",
80
+ "fumadocs-ui": "^16.10.2",
81
+ "hono": "^4.12.25",
81
82
  "http-cache-semantics": "^4.2.0",
82
83
  "react": "^19.2.7",
83
84
  "react-dom": "^19.2.7",
84
- "sharp": "^0.34.5",
85
+ "sharp": "^0.35.1",
85
86
  "tsdown": "0.22.2",
86
87
  "typescript": "^6.0.3",
87
- "waku": "1.0.0-beta.2"
88
+ "waku": "1.0.0-beta.3"
88
89
  },
89
90
  "peerDependencies": {
90
91
  "@types/mdx": "*",
91
92
  "@types/react": "*",
92
- "fumadocs-core": "^16.9.3",
93
+ "fumadocs-core": "^16.10.0",
93
94
  "fumadocs-mdx": "^15.0.0",
94
- "fumadocs-openapi": "^10.8.0",
95
- "fumadocs-ui": "^16.9.3",
95
+ "fumadocs-openapi": "^11.0.0",
96
+ "fumadocs-ui": "^16.10.0",
96
97
  "hono": "*",
97
98
  "react": "^19.2.0",
98
99
  "react-dom": "^19.2.0",
99
100
  "sharp": "^0.34.0",
100
- "waku": "1.0.0-beta.2"
101
+ "waku": "1.0.0-beta.3"
101
102
  },
102
103
  "peerDependenciesMeta": {
103
104
  "sharp": {
@@ -1,16 +0,0 @@
1
- "use client";
2
- import { defaultTranslations } from "../i18n.js";
3
- import { renderTranslation } from "fumadocs-core/i18n";
4
- import { useTranslations } from "fumadocs-ui/contexts/i18n";
5
- //#region src/components/i18n.tsx
6
- function useTranslations$1() {
7
- return useTranslations("fumapress") ?? defaultTranslations;
8
- }
9
- /**
10
- * Renders a translated string. Use in server components so the label is resolved on the client from the current locale.
11
- */
12
- function I18nLabel({ label, replacements }) {
13
- return renderTranslation(useTranslations$1()[label], replacements);
14
- }
15
- //#endregion
16
- export { I18nLabel, useTranslations$1 as useTranslations };
@@ -1,21 +0,0 @@
1
- "use client";
2
- import { jsx } from "react/jsx-runtime";
3
- import { createContext, use, useMemo } from "react";
4
- //#region src/components/openapi.payload.tsx
5
- const Context = createContext(null);
6
- function PayloadProvider({ payload, children }) {
7
- return /* @__PURE__ */ jsx(Context, {
8
- value: useMemo(() => JSON.parse(payload), [payload]),
9
- children
10
- });
11
- }
12
- function WithPayload({ schemaId, Comp, props }) {
13
- const payload = use(Context)?.[schemaId];
14
- if (!payload) throw new Error(`[Fumapress] Failed to find OpenAPI payload for schema "${schemaId}", do you sure it is defined in createOpenAPI()?`);
15
- return /* @__PURE__ */ jsx(Comp, {
16
- payload,
17
- ...props
18
- });
19
- }
20
- //#endregion
21
- export { PayloadProvider, WithPayload };