fumapress 0.2.4 → 0.3.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.
Files changed (38) hide show
  1. package/css/generated.css +160 -8
  2. package/dist/_virtual/_rolldown/runtime.js +24 -0
  3. package/dist/adapters/mdx/schema.d.ts +39 -0
  4. package/dist/adapters/mdx/schema.js +9 -0
  5. package/dist/adapters/mdx.js +18 -0
  6. package/dist/components/blog-panel.js +56 -0
  7. package/dist/components/blog.js +60 -0
  8. package/dist/config.d.ts +22 -10
  9. package/dist/index.d.ts +3 -3
  10. package/dist/layouts/blog.d.ts +21 -0
  11. package/dist/layouts/blog.index.d.ts +15 -0
  12. package/dist/layouts/blog.index.js +36 -0
  13. package/dist/layouts/blog.js +85 -0
  14. package/dist/layouts/blog.tags.d.ts +19 -0
  15. package/dist/layouts/blog.tags.js +113 -0
  16. package/dist/layouts/docs.d.ts +9 -7
  17. package/dist/layouts/docs.js +43 -69
  18. package/dist/layouts/home.d.ts +20 -8
  19. package/dist/layouts/home.js +39 -19
  20. package/dist/layouts/notebook.d.ts +37 -0
  21. package/dist/layouts/notebook.js +59 -0
  22. package/dist/layouts/root.d.ts +1 -1
  23. package/dist/layouts/root.js +5 -6
  24. package/dist/layouts/switch.d.ts +11 -0
  25. package/dist/layouts/switch.js +25 -0
  26. package/dist/lib/cn.js +2 -0
  27. package/dist/lib/join-pathname.js +9 -0
  28. package/dist/lib/shared/blog.js +39 -0
  29. package/dist/lib/shared.d.ts +10 -4
  30. package/dist/lib/shared.js +51 -5
  31. package/dist/lib/types.d.ts +18 -6
  32. package/dist/node_modules/.pnpm/@fastify_deepmerge@3.2.1/node_modules/@fastify/deepmerge/index.js +108 -0
  33. package/dist/plugins/blog.d.ts +71 -0
  34. package/dist/plugins/blog.js +168 -0
  35. package/dist/router.d.ts +3 -4
  36. package/dist/router.js +32 -29
  37. package/dist/vite.js +5 -0
  38. package/package.json +26 -11
package/css/generated.css CHANGED
@@ -1,103 +1,255 @@
1
+ @source inline("---spacing");
2
+ @source inline("-translate-x-1/2");
1
3
  @source inline("@orama/orama");
2
4
  @source inline("absolutePath");
3
- @source inline("adapter");
5
+ @source inline("active:scale-95");
4
6
  @source inline("as");
5
7
  @source inline("async");
6
8
  @source inline("await");
9
+ @source inline("backdrop-blur-sm");
10
+ @source inline("bg-fd-card");
11
+ @source inline("bg-fd-primary");
12
+ @source inline("bg-fd-primary/10");
13
+ @source inline("bg-fd-secondary/80");
14
+ @source inline("blog");
15
+ @source inline("blogPosts");
7
16
  @source inline("body");
17
+ @source inline("border");
18
+ @source inline("border-2");
8
19
  @source inline("border-b");
20
+ @source inline("border-dashed");
21
+ @source inline("border-fd-primary");
22
+ @source inline("border-y");
23
+ @source inline("bottom-2");
24
+ @source inline("buttonVariants");
25
+ @source inline("children");
26
+ @source inline("class-variance-authority");
9
27
  @source inline("className");
10
28
  @source inline("client");
29
+ @source inline("cn");
11
30
  @source inline("const");
12
31
  @source inline("core:docs-layout");
13
32
  @source inline("core:home-layout");
33
+ @source inline("core:notebook-layout");
14
34
  @source inline("core:provider");
15
- @source inline("core:render-body");
16
- @source inline("core:render-toc");
35
+ @source inline("count");
17
36
  @source inline("create");
18
- @source inline("createDocsLayout");
37
+ @source inline("createBlogIndexPage");
38
+ @source inline("createBlogLayout");
39
+ @source inline("createBlogLayoutPage");
40
+ @source inline("createBlogTagPage");
41
+ @source inline("createBlogTagsPage");
42
+ @source inline("createDocsLayoutPage");
19
43
  @source inline("createHomeLayout");
44
+ @source inline("createHomeLayoutPage");
45
+ @source inline("createLayoutSwitch");
46
+ @source inline("createLayoutSwitchAuto");
47
+ @source inline("createNotebookLayoutPage");
20
48
  @source inline("createRootLayout");
49
+ @source inline("creationDate");
50
+ @source inline("ctx");
51
+ @source inline("currentDate");
52
+ @source inline("cva");
21
53
  @source inline("data");
22
54
  @source inline("data-version");
55
+ @source inline("date");
56
+ @source inline("decoration-fd-primary");
23
57
  @source inline("default");
58
+ @source inline("detect");
59
+ @source inline("detector");
60
+ @source inline("duration-150");
24
61
  @source inline("else");
25
62
  @source inline("empty");
63
+ @source inline("empty:hidden");
26
64
  @source inline("en");
27
65
  @source inline("english");
28
66
  @source inline("export");
29
67
  @source inline("extends");
68
+ @source inline("false");
69
+ @source inline("fixed");
30
70
  @source inline("flex");
71
+ @source inline("flex-1");
31
72
  @source inline("flex-col");
32
73
  @source inline("flex-row");
74
+ @source inline("flex-wrap");
33
75
  @source inline("flexsearchStaticClient");
76
+ @source inline("font-medium");
77
+ @source inline("font-mono");
78
+ @source inline("font-semibold");
34
79
  @source inline("for");
35
80
  @source inline("from");
36
81
  @source inline("fumadocs-core/source");
37
82
  @source inline("fumadocs-core/toc");
38
83
  @source inline("function");
84
+ @source inline("gap-1");
39
85
  @source inline("gap-2");
86
+ @source inline("gap-4");
87
+ @source inline("getCreationDate");
88
+ @source inline("getTags");
89
+ @source inline("ghost");
40
90
  @source inline("githubUrl");
91
+ @source inline("grid");
92
+ @source inline("grid-cols-1");
93
+ @source inline("grid-cols-2");
94
+ @source inline("groupTags");
95
+ @source inline("grouped");
41
96
  @source inline("hook");
42
97
  @source inline("hooks");
98
+ @source inline("hover:bg-fd-accent");
99
+ @source inline("hover:text-fd-accent-foreground");
100
+ @source inline("href");
43
101
  @source inline("i18n");
44
102
  @source inline("i18nConfig");
45
103
  @source inline("if");
46
104
  @source inline("import");
47
105
  @source inline("in");
106
+ @source inline("inherit");
107
+ @source inline("inline-flex");
48
108
  @source inline("interface");
49
109
  @source inline("isLoading");
110
+ @source inline("item");
50
111
  @source inline("items");
51
112
  @source inline("items-center");
113
+ @source inline("items-start");
114
+ @source inline("joinPathname");
115
+ @source inline("key");
52
116
  @source inline("lang");
53
117
  @source inline("language");
54
118
  @source inline("languages");
119
+ @source inline("lastModified");
120
+ @source inline("layout");
55
121
  @source inline("layoutData");
56
122
  @source inline("layoutProps");
123
+ @source inline("layouts");
124
+ @source inline("left-1/2");
125
+ @source inline("length");
57
126
  @source inline("let");
58
127
  @source inline("loaderConfig");
59
128
  @source inline("locale");
60
129
  @source inline("locales");
130
+ @source inline("lucide-react");
61
131
  @source inline("markdownUrl");
132
+ @source inline("matching");
133
+ @source inline("max-h-[min(600px,calc(100vh---spacing(30)))]");
134
+ @source inline("max-sm:-mx-4");
135
+ @source inline("max-w-[1400px]");
136
+ @source inline("max-w-[900px]");
137
+ @source inline("max-w-[calc(100%---spacing(4))]");
62
138
  @source inline("mb-0");
139
+ @source inline("md:grid-cols-3");
140
+ @source inline("md:grid-cols-4");
141
+ @source inline("md:p-8");
63
142
  @source inline("min-h-screen");
143
+ @source inline("min-w-0");
144
+ @source inline("ms-auto");
145
+ @source inline("mt-4");
146
+ @source inline("mt-6");
147
+ @source inline("mt-auto");
148
+ @source inline("mx-auto");
64
149
  @source inline("name");
150
+ @source inline("never");
65
151
  @source inline("new");
66
152
  @source inline("of");
153
+ @source inline("onClick");
154
+ @source inline("onCopy");
155
+ @source inline("onOpenChange");
67
156
  @source inline("onSearchChange");
157
+ @source inline("open");
68
158
  @source inline("option");
159
+ @source inline("options");
160
+ @source inline("orderedPosts");
161
+ @source inline("overline");
162
+ @source inline("p-1");
163
+ @source inline("p-4");
69
164
  @source inline("page");
70
165
  @source inline("pageProps");
166
+ @source inline("panelButtonVariants");
167
+ @source inline("pb-20");
71
168
  @source inline("pb-6");
169
+ @source inline("posts");
170
+ @source inline("primary");
171
+ @source inline("props");
172
+ @source inline("prose");
72
173
  @source inline("providerProps");
73
174
  @source inline("pt-2");
175
+ @source inline("pt-3.5");
176
+ @source inline("pt-4");
177
+ @source inline("pt-6");
178
+ @source inline("px-1.5");
179
+ @source inline("px-2");
180
+ @source inline("px-3");
181
+ @source inline("px-4");
182
+ @source inline("py-0.5");
183
+ @source inline("py-1");
184
+ @source inline("py-2");
74
185
  @source inline("query");
75
186
  @source inline("r");
76
187
  @source inline("react");
77
188
  @source inline("render");
78
189
  @source inline("renderCtx");
79
- @source inline("renderPageMeta");
80
190
  @source inline("renderRootMeta");
81
191
  @source inline("result");
82
192
  @source inline("return");
83
193
  @source inline("root");
84
- @source inline("satisfies");
194
+ @source inline("rotate-180");
195
+ @source inline("rounded-2xl");
196
+ @source inline("rounded-lg");
197
+ @source inline("rounded-xl");
85
198
  @source inline("schema");
86
199
  @source inline("search");
200
+ @source inline("setOpen");
201
+ @source inline("shadow-inner");
202
+ @source inline("shadow-md");
203
+ @source inline("shadow-sm");
204
+ @source inline("shrink-0");
205
+ @source inline("size-3.5");
206
+ @source inline("size-4");
207
+ @source inline("size-6");
208
+ @source inline("sm:border");
209
+ @source inline("sm:bottom-4");
210
+ @source inline("sm:grid-cols-3");
211
+ @source inline("sm:max-w-[400px]");
212
+ @source inline("sm:rounded-xl");
87
213
  @source inline("source");
88
214
  @source inline("specify");
89
215
  @source inline("static");
90
216
  @source inline("string");
91
217
  @source inline("styles");
218
+ @source inline("tags");
219
+ @source inline("tagsPath");
220
+ @source inline("text-2xl");
221
+ @source inline("text-3xl");
222
+ @source inline("text-fd-card-foreground");
223
+ @source inline("text-fd-muted-foreground");
224
+ @source inline("text-fd-primary");
225
+ @source inline("text-fd-primary-foreground");
226
+ @source inline("text-sm");
227
+ @source inline("text-xs");
92
228
  @source inline("the");
93
229
  @source inline("this");
94
- @source inline("throw");
230
+ @source inline("title");
231
+ @source inline("to");
95
232
  @source inline("toc");
233
+ @source inline("transition-all");
234
+ @source inline("transition-colors");
235
+ @source inline("transition-transform");
96
236
  @source inline("translations");
97
237
  @source inline("tree");
238
+ @source inline("truncate");
98
239
  @source inline("type");
99
240
  @source inline("undefined");
100
241
  @source inline("unstable_notFound");
242
+ @source inline("url");
101
243
  @source inline("use");
244
+ @source inline("useCopyButton");
102
245
  @source inline("useDocsSearch");
103
- @source inline("useI18n");
246
+ @source inline("useI18n");
247
+ @source inline("useState");
248
+ @source inline("useTOCItems");
249
+ @source inline("variant");
250
+ @source inline("w-full");
251
+ @source inline("waku");
252
+ @source inline("xl:grid-cols-4");
253
+ @source inline("xl:grid-cols-6");
254
+ @source inline("z-2");
255
+ @source inline("z-20");
@@ -0,0 +1,24 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ export { __commonJSMin, __toESM };
@@ -0,0 +1,39 @@
1
+ import * as base from "fumadocs-core/source/schema";
2
+ import z from "zod";
3
+
4
+ //#region src/adapters/mdx/schema.d.ts
5
+ declare const pageSchema: z.ZodObject<{
6
+ title: z.ZodString;
7
+ description: z.ZodOptional<z.ZodString>;
8
+ icon: z.ZodOptional<z.ZodString>;
9
+ full: z.ZodOptional<z.ZodBoolean>;
10
+ _openapi: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodCustom<base._JSONType, base._JSONType>>>;
11
+ }, z.core.$strip>;
12
+ declare const metaSchema: z.ZodObject<{
13
+ title: z.ZodOptional<z.ZodString>;
14
+ pages: z.ZodOptional<z.ZodArray<z.ZodString>>;
15
+ description: z.ZodOptional<z.ZodString>;
16
+ root: z.ZodOptional<z.ZodBoolean>;
17
+ defaultOpen: z.ZodOptional<z.ZodBoolean>;
18
+ collapsible: z.ZodOptional<z.ZodBoolean>;
19
+ icon: z.ZodOptional<z.ZodString>;
20
+ }, z.core.$strip>;
21
+ declare const blogPageSchema: z.ZodObject<{
22
+ title: z.ZodString;
23
+ description: z.ZodOptional<z.ZodString>;
24
+ icon: z.ZodOptional<z.ZodString>;
25
+ full: z.ZodOptional<z.ZodBoolean>;
26
+ _openapi: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodCustom<base._JSONType, base._JSONType>>>;
27
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
28
+ }, z.core.$strip>;
29
+ declare const blogMetaSchema: z.ZodObject<{
30
+ title: z.ZodOptional<z.ZodString>;
31
+ pages: z.ZodOptional<z.ZodArray<z.ZodString>>;
32
+ description: z.ZodOptional<z.ZodString>;
33
+ root: z.ZodOptional<z.ZodBoolean>;
34
+ defaultOpen: z.ZodOptional<z.ZodBoolean>;
35
+ collapsible: z.ZodOptional<z.ZodBoolean>;
36
+ icon: z.ZodOptional<z.ZodString>;
37
+ }, z.core.$strip>;
38
+ //#endregion
39
+ export { blogMetaSchema, blogPageSchema, metaSchema, pageSchema };
@@ -0,0 +1,9 @@
1
+ import * as base from "fumadocs-core/source/schema";
2
+ import z from "zod";
3
+ //#region src/adapters/mdx/schema.ts
4
+ const pageSchema = base.pageSchema;
5
+ const metaSchema = base.metaSchema;
6
+ const blogPageSchema = base.pageSchema.extend({ tags: z.array(z.string()).optional() });
7
+ const blogMetaSchema = base.metaSchema;
8
+ //#endregion
9
+ export { blogMetaSchema, blogPageSchema, metaSchema, pageSchema };
@@ -1,5 +1,6 @@
1
1
  import { createElement } from "react";
2
2
  import defaultMdxComponents, { createRelativeLink } from "fumadocs-ui/mdx";
3
+ import { z } from "zod/mini";
3
4
  //#region src/adapters/mdx.ts
4
5
  function fumadocsMdx(options) {
5
6
  const getMdxComponents = options?.getMdxComponents;
@@ -24,9 +25,26 @@ function fumadocsMdx(options) {
24
25
  async "core:render-toc"(page) {
25
26
  if (isSyncEntry(page.data)) return page.data.toc;
26
27
  if (isAsyncEntry(page.data)) return (await page.data.load()).toc;
28
+ },
29
+ "core:get-creation-date"(page) {
30
+ if (isSyncEntry(page.data) || isAsyncEntry(page.data)) return "date" in page.data && page.data.date instanceof Date ? page.data.date : void 0;
31
+ },
32
+ async "core:get-modified-date"(page) {
33
+ let data;
34
+ if (isSyncEntry(page.data)) data = page.data;
35
+ else if (isAsyncEntry(page.data)) data = await page.data.load();
36
+ else return;
37
+ return "lastModified" in data && data.lastModified instanceof Date ? data.lastModified : void 0;
38
+ },
39
+ "blog:get-tags"(page) {
40
+ if (isSyncEntry(page.data) || isAsyncEntry(page.data)) {
41
+ const parsed = tagsSchema.safeParse(page.data);
42
+ return parsed.success ? parsed.data.tags : void 0;
43
+ }
27
44
  }
28
45
  };
29
46
  }
47
+ const tagsSchema = z.looseObject({ tags: z.optional(z.array(z.string())) });
30
48
  function isSyncEntry(v) {
31
49
  return "info" in v && typeof v.info === "object" && "_exports" in v && typeof v._exports === "object";
32
50
  }
@@ -0,0 +1,56 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { useState } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { ChevronDown, ShareIcon } from "lucide-react";
6
+ import { TOCProvider, TOCScrollArea, useTOCItems } from "fumadocs-ui/components/toc";
7
+ import { TOCItem, TOCItems } from "fumadocs-ui/components/toc/clerk";
8
+ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
9
+ import { cva } from "class-variance-authority";
10
+ import { useCopyButton } from "fumadocs-ui/utils/use-copy-button";
11
+ //#region src/components/blog-panel.tsx
12
+ 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");
13
+ function BlogPanel() {
14
+ const items = useTOCItems();
15
+ const [open, setOpen] = useState(false);
16
+ const [isSuccessful, onCopy] = useCopyButton(() => {
17
+ if (navigator.share) return navigator.share({
18
+ title: document.title,
19
+ url: location.href
20
+ });
21
+ else return navigator.clipboard.writeText(location.href);
22
+ });
23
+ return /* @__PURE__ */ jsxs(Collapsible, {
24
+ open,
25
+ onOpenChange: setOpen,
26
+ className: "fixed w-full max-w-[calc(100%---spacing(4))] left-1/2 -translate-x-1/2 bottom-2 border shadow-md text-sm bg-fd-secondary/80 backdrop-blur-sm z-20 p-1 rounded-xl sm:max-w-[400px] sm:bottom-4",
27
+ children: [/* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx(TOCScrollArea, {
28
+ className: "max-h-[min(600px,calc(100vh---spacing(30)))]",
29
+ children: /* @__PURE__ */ jsx(TOCItems, { children: items.map((item) => /* @__PURE__ */ jsx(TOCItem, {
30
+ item,
31
+ onClick: () => setOpen(false)
32
+ }, item.url)) })
33
+ }) }), /* @__PURE__ */ jsxs("div", {
34
+ className: "flex flex-row gap-2",
35
+ children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
36
+ className: cn(panelButtonVariants(), "min-w-0"),
37
+ children: [/* @__PURE__ */ jsx("span", {
38
+ className: "truncate",
39
+ children: "Table of Contents"
40
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: cn("size-3.5 shrink-0 text-fd-muted-foreground transition-transform", open && "rotate-180") })]
41
+ }), /* @__PURE__ */ jsxs("button", {
42
+ className: cn(panelButtonVariants(), "ms-auto text-fd-muted-foreground"),
43
+ onClick: onCopy,
44
+ children: [/* @__PURE__ */ jsx(ShareIcon, { className: "size-3.5 shrink-0" }), isSuccessful ? "Copied" : "Share"]
45
+ })]
46
+ })]
47
+ });
48
+ }
49
+ function BlogProvider({ toc, children }) {
50
+ return /* @__PURE__ */ jsx(TOCProvider, {
51
+ toc,
52
+ children
53
+ });
54
+ }
55
+ //#endregion
56
+ export { BlogPanel, BlogProvider };
@@ -0,0 +1,60 @@
1
+ import { getCreationDate } from "../lib/shared.js";
2
+ import { cn } from "../lib/cn.js";
3
+ import { joinPathname } from "../lib/join-pathname.js";
4
+ import { Link } from "waku";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
7
+ import { CornerLeftUpIcon } from "lucide-react";
8
+ //#region src/components/blog.tsx
9
+ function BlogItem({ page, date }) {
10
+ return /* @__PURE__ */ jsxs(Link, {
11
+ to: page.url,
12
+ className: "flex flex-col bg-fd-card rounded-2xl border shadow-sm p-4 transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground",
13
+ children: [
14
+ /* @__PURE__ */ jsx("p", {
15
+ className: "font-medium",
16
+ children: page.data.title
17
+ }),
18
+ /* @__PURE__ */ jsx("p", {
19
+ className: "text-sm text-fd-muted-foreground",
20
+ children: page.data.description
21
+ }),
22
+ /* @__PURE__ */ jsx("p", {
23
+ className: "mt-auto pt-4 text-xs text-fd-primary",
24
+ children: date.toDateString()
25
+ })
26
+ ]
27
+ });
28
+ }
29
+ async function OrderedBlogGrid({ posts, ctx }) {
30
+ const currentDate = new Date(Date.now());
31
+ const orderedPosts = [];
32
+ for (const page of posts) {
33
+ const date = await getCreationDate(ctx, page);
34
+ orderedPosts.push({
35
+ page,
36
+ date: date ?? currentDate
37
+ });
38
+ }
39
+ orderedPosts.sort((a, b) => b.date.getTime() - a.date.getTime());
40
+ return /* @__PURE__ */ jsx("div", {
41
+ className: "grid grid-cols-1 gap-2 mt-4 md:grid-cols-3 xl:grid-cols-4",
42
+ children: orderedPosts.map(({ page, date }) => /* @__PURE__ */ jsx(BlogItem, {
43
+ page,
44
+ date
45
+ }, page.url))
46
+ });
47
+ }
48
+ function LinkToHome({ lang, blog }) {
49
+ if (!blog.indexPath) return;
50
+ return /* @__PURE__ */ jsxs(Link, {
51
+ to: lang ? joinPathname(lang, blog.indexPath) : blog.indexPath,
52
+ className: cn(buttonVariants({
53
+ variant: "ghost",
54
+ className: "text-fd-muted-foreground gap-2"
55
+ })),
56
+ children: [/* @__PURE__ */ jsx(CornerLeftUpIcon, { className: "size-3.5" }), "Back to Home"]
57
+ });
58
+ }
59
+ //#endregion
60
+ export { LinkToHome, OrderedBlogGrid };
package/dist/config.d.ts CHANGED
@@ -4,6 +4,7 @@ import { ComponentType, ReactNode } from "react";
4
4
  import { TranslationsOption } from "fumadocs-ui/contexts/i18n";
5
5
  import { LoaderConfig, LoaderOutput } from "fumadocs-core/source";
6
6
  import { I18nConfig } from "fumadocs-core/i18n";
7
+ import { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
7
8
 
8
9
  //#region src/config.d.ts
9
10
  interface ConfigContext {
@@ -26,31 +27,42 @@ interface Config<C extends ConfigContext = ConfigContext> {
26
27
  /** adapter for content sources, use `fumadocs-mdx` if not specified */
27
28
  adapters?: Adapter[];
28
29
  i18n?: I18nConfig$1<C["lang"]>;
29
- meta?: {
30
- /** render meta tags for any pages */root?: (this: AppContext<C>) => ReactNode; /** render meta tags for page */
31
- page?: (this: AppContext<C>, page: C["loaderConfig"]["page"]) => ReactNode;
32
- };
30
+ meta?: MetaConfig<C>;
33
31
  }
34
32
  interface Layouts<C extends ConfigContext = ConfigContext> {
35
- root: ComponentType<AppContext<C> & {
33
+ root: ComponentType<{
36
34
  lang?: string;
35
+ ctx: AppContext<C>;
37
36
  children: ReactNode;
38
37
  }>;
39
- page: ComponentType<AppContext<C> & {
38
+ page: ComponentType<{
40
39
  lang?: string;
40
+ ctx: AppContext<C>;
41
41
  slugs: string[];
42
42
  }>;
43
- notFound: ComponentType<AppContext<C> & {
43
+ notFound: ComponentType<{
44
44
  lang?: string;
45
+ ctx: AppContext<C>;
45
46
  }>;
47
+ /**
48
+ * Define default props for page layouts, will be merged with current props.
49
+ */
50
+ defaultProps?: (this: AppContext<C>, env: {
51
+ lang: string | undefined;
52
+ }) => Awaitable<Omit<BaseLayoutProps, "children">>;
46
53
  }
47
- interface I18nConfig$1<Lang extends string = string> extends Pick<I18nConfig<NoInfer<Lang>>, "fallbackLanguage" | "parser"> {
54
+ interface I18nConfig$1<Lang extends string = string> extends Pick<I18nConfig<NoInfer<Lang>>, "defaultLanguage" | "fallbackLanguage" | "parser"> {
48
55
  /** locale code -> language info */
49
56
  languages: { [K in Lang]: {
50
57
  displayName: string;
51
58
  translations?: TranslationsOption;
52
59
  } };
53
- defaultLanguage: NoInfer<Lang>;
60
+ }
61
+ interface MetaConfig<C extends ConfigContext = ConfigContext> {
62
+ /** render meta tags for any pages */
63
+ root?: (this: AppContext<C>) => ReactNode;
64
+ /** render meta tags for page */
65
+ page?: (this: AppContext<C>, page: C["loaderConfig"]["page"]) => ReactNode;
54
66
  }
55
67
  interface SiteConfig {
56
68
  /** full URL of app, used for metadata generation*/
@@ -81,4 +93,4 @@ declare function defineConfig<C extends LoaderConfig, L extends string = string>
81
93
  }>;
82
94
  declare function defineI18nConfig<Lang extends string>(config: I18nConfig$1<Lang>): I18nConfigBuilder<Lang>;
83
95
  //#endregion
84
- export { BuildMode, Config, ConfigBuilder, ConfigContext, I18nConfig$1 as I18nConfig, I18nConfigBuilder, Layouts, SiteConfig, defineConfig, defineI18nConfig };
96
+ export { BuildMode, Config, ConfigBuilder, ConfigContext, I18nConfig$1 as I18nConfig, I18nConfigBuilder, Layouts, MetaConfig, SiteConfig, defineConfig, defineI18nConfig };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { AppContext, AppContextData } from "./lib/shared.js";
2
- import { BuildMode, Config, ConfigBuilder, ConfigContext, I18nConfig, I18nConfigBuilder, Layouts, SiteConfig, defineConfig, defineI18nConfig } from "./config.js";
3
- import { Adapter, ServerPlugin } from "./lib/types.js";
4
- export { type Adapter, type AppContext, type AppContextData, BuildMode, Config, ConfigBuilder, ConfigContext, I18nConfig, I18nConfigBuilder, Layouts, type ServerPlugin, SiteConfig, defineConfig, defineI18nConfig };
2
+ import { BuildMode, Config, ConfigBuilder, ConfigContext, I18nConfig, I18nConfigBuilder, Layouts, MetaConfig, SiteConfig, defineConfig, defineI18nConfig } from "./config.js";
3
+ import { Adapter, RouteFns, ServerPlugin } from "./lib/types.js";
4
+ export { type Adapter, type AppContext, type AppContextData, BuildMode, Config, ConfigBuilder, ConfigContext, I18nConfig, I18nConfigBuilder, Layouts, MetaConfig, type RouteFns, type ServerPlugin, SiteConfig, defineConfig, defineI18nConfig };
@@ -0,0 +1,21 @@
1
+ import { HomeLayoutOptions } from "./home.js";
2
+ import { AppContext } from "../lib/shared.js";
3
+ import { ConfigContext } from "../config.js";
4
+ import { Awaitable } from "../lib/types.js";
5
+ import { BlogLayout, BlogLayoutPage } from "../plugins/blog.js";
6
+ import { ReactNode } from "react";
7
+ import { TOCItemType } from "fumadocs-core/toc";
8
+
9
+ //#region src/layouts/blog.d.ts
10
+ declare function createBlogLayout<C extends ConfigContext = ConfigContext>(options?: HomeLayoutOptions<C>): BlogLayout<C>;
11
+ interface BlogLayoutPageRenderData {
12
+ creationDate?: Date;
13
+ toc: TOCItemType[];
14
+ body: ReactNode;
15
+ }
16
+ interface BlogLayoutPageOptions<C extends ConfigContext = ConfigContext> {
17
+ render?: (this: AppContext<C>, page: C["loaderConfig"]["page"]) => Awaitable<Partial<BlogLayoutPageRenderData>>;
18
+ }
19
+ declare function createBlogLayoutPage<C extends ConfigContext = ConfigContext>(options?: BlogLayoutPageOptions<C>): BlogLayoutPage<C>;
20
+ //#endregion
21
+ export { BlogLayoutPageOptions, BlogLayoutPageRenderData, createBlogLayout, createBlogLayoutPage };
@@ -0,0 +1,15 @@
1
+ import { ConfigContext } from "../config.js";
2
+ import { BlogIndexPage } from "../plugins/blog.js";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/layouts/blog.index.d.ts
6
+ interface BlogIndexPageOptions {
7
+ heading?: ReactNode;
8
+ description?: ReactNode;
9
+ }
10
+ declare function createBlogIndexPage<C extends ConfigContext = ConfigContext>({
11
+ heading,
12
+ description
13
+ }?: BlogIndexPageOptions): BlogIndexPage<C>;
14
+ //#endregion
15
+ export { BlogIndexPageOptions, createBlogIndexPage };
@@ -0,0 +1,36 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import { joinPathname } from "../lib/join-pathname.js";
3
+ import { OrderedBlogGrid } from "../components/blog.js";
4
+ import { Link } from "waku";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
7
+ import { ListIcon } from "lucide-react";
8
+ //#region src/layouts/blog.index.tsx
9
+ function createBlogIndexPage({ heading, description } = {}) {
10
+ return async function BlogIndexPage({ lang, blog, ctx }) {
11
+ const source = await ctx.getLoader();
12
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
13
+ className: "flex flex-col gap-4 items-start border-2 border-dashed border-fd-primary rounded-xl bg-fd-primary/10 p-4 z-2 md:p-8",
14
+ children: [
15
+ /* @__PURE__ */ jsx("h1", {
16
+ className: "text-3xl font-semibold",
17
+ children: heading ?? "Blog"
18
+ }),
19
+ /* @__PURE__ */ jsx("p", {
20
+ className: "text-fd-primary overline decoration-fd-primary empty:hidden",
21
+ children: description
22
+ }),
23
+ blog.tagsPath !== false && /* @__PURE__ */ jsxs(Link, {
24
+ to: lang ? joinPathname(lang, blog.tagsPath) : blog.tagsPath,
25
+ className: cn(buttonVariants({ variant: "primary" }), "gap-2"),
26
+ children: [/* @__PURE__ */ jsx(ListIcon, { className: "size-4" }), "All Tags"]
27
+ })
28
+ ]
29
+ }), /* @__PURE__ */ jsx(OrderedBlogGrid, {
30
+ posts: source.getPages(lang).filter((page) => blog.isBlog.call(ctx, page)),
31
+ ctx
32
+ })] });
33
+ };
34
+ }
35
+ //#endregion
36
+ export { createBlogIndexPage };