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
@@ -0,0 +1,85 @@
1
+ import { getCreationDate, renderBody, renderPageMeta, renderToc } from "../lib/shared.js";
2
+ import { joinPathname } from "../lib/join-pathname.js";
3
+ import { LinkToHome } from "../components/blog.js";
4
+ import { getTags } from "../lib/shared/blog.js";
5
+ import { BlogPanel, BlogProvider } from "../components/blog-panel.js";
6
+ import { createHomeLayout } from "./home.js";
7
+ import { Link } from "waku";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { unstable_notFound } from "waku/router/server";
10
+ import { TagIcon } from "lucide-react";
11
+ //#region src/layouts/blog.tsx
12
+ function createBlogLayout(options) {
13
+ const HomeLayout = createHomeLayout(options);
14
+ return function BlogLayout({ children, ctx, lang }) {
15
+ return /* @__PURE__ */ jsx(HomeLayout, {
16
+ lang,
17
+ ctx,
18
+ children: /* @__PURE__ */ jsx("main", {
19
+ className: "flex flex-col w-full max-w-[1400px] flex-1 px-4 pt-6 pb-20 mx-auto",
20
+ children
21
+ })
22
+ });
23
+ };
24
+ }
25
+ function createBlogLayoutPage(options = {}) {
26
+ const { render } = options;
27
+ return async function BlogLayoutPage({ slugs, ctx, blog, lang }) {
28
+ const page = (await ctx.getLoader()).getPage(slugs, lang);
29
+ if (!page) unstable_notFound();
30
+ const tags = await getTags(ctx, page);
31
+ const _raw = await render?.call(ctx, page);
32
+ const result = {
33
+ body: _raw?.body ?? await renderBody(ctx, page, "[Fumapress] Please specify the `render` option in createBlogLayoutPage()"),
34
+ toc: _raw?.toc ?? await renderToc(ctx, page) ?? [],
35
+ creationDate: _raw?.creationDate ?? await getCreationDate(ctx, page)
36
+ };
37
+ return /* @__PURE__ */ jsxs(BlogProvider, {
38
+ toc: result.toc,
39
+ children: [
40
+ renderPageMeta(page, ctx),
41
+ /* @__PURE__ */ jsxs("div", {
42
+ className: "flex flex-col gap-4 items-center border-y px-4 pt-3.5 pb-6 bg-fd-card text-fd-card-foreground shadow-inner max-sm:-mx-4 sm:rounded-xl sm:border",
43
+ children: [
44
+ /* @__PURE__ */ jsx("div", {
45
+ className: "flex flex-row items-center gap-2 w-full max-w-[900px]",
46
+ children: /* @__PURE__ */ jsx(LinkToHome, {
47
+ blog,
48
+ lang
49
+ })
50
+ }),
51
+ /* @__PURE__ */ jsx("h1", {
52
+ className: "font-semibold text-2xl w-full max-w-[900px]",
53
+ children: page.data.title
54
+ }),
55
+ /* @__PURE__ */ jsx("p", {
56
+ className: "text-fd-muted-foreground w-full max-w-[900px]",
57
+ children: page.data.description
58
+ }),
59
+ tags && tags.length > 0 && /* @__PURE__ */ jsxs("div", {
60
+ className: "flex flex-row items-center gap-2 flex-wrap w-full max-w-[900px] text-sm text-fd-primary-foreground font-mono",
61
+ children: [/* @__PURE__ */ jsx(TagIcon, { className: "size-4 text-fd-muted-foreground" }), tags.map((t) => {
62
+ if (blog.tagsPath !== false) return /* @__PURE__ */ jsx(Link, {
63
+ to: joinPathname(lang ?? "", blog.tagsPath, t),
64
+ className: "px-1.5 py-0.5 rounded-lg bg-fd-primary",
65
+ children: t
66
+ }, t);
67
+ return /* @__PURE__ */ jsx("p", {
68
+ className: "px-1.5 py-0.5 rounded-lg bg-fd-primary",
69
+ children: t
70
+ }, t);
71
+ })]
72
+ })
73
+ ]
74
+ }),
75
+ /* @__PURE__ */ jsx("article", {
76
+ className: "prose mt-6 mx-auto w-full max-w-[900px]",
77
+ children: result.body
78
+ }),
79
+ /* @__PURE__ */ jsx(BlogPanel, {})
80
+ ]
81
+ });
82
+ };
83
+ }
84
+ //#endregion
85
+ export { createBlogLayout, createBlogLayoutPage };
@@ -0,0 +1,19 @@
1
+ import { ConfigContext } from "../config.js";
2
+ import { BlogTagPage, BlogTagsPage } from "../plugins/blog.js";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/layouts/blog.tags.d.ts
6
+ interface BlogTagsPageOptions {
7
+ heading?: ReactNode;
8
+ description?: ReactNode;
9
+ }
10
+ declare function createBlogTagsPage<C extends ConfigContext = ConfigContext>({
11
+ heading,
12
+ description
13
+ }?: BlogTagsPageOptions): BlogTagsPage<C>;
14
+ declare function createBlogTagPage<C extends ConfigContext = ConfigContext>({
15
+ heading,
16
+ description
17
+ }?: BlogTagsPageOptions): BlogTagPage<C>;
18
+ //#endregion
19
+ export { BlogTagsPageOptions, createBlogTagPage, createBlogTagsPage };
@@ -0,0 +1,113 @@
1
+ import { LinkToHome, OrderedBlogGrid } from "../components/blog.js";
2
+ import { getTags, groupTags } from "../lib/shared/blog.js";
3
+ import { Link } from "waku";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { NewspaperIcon, TagIcon } from "lucide-react";
6
+ //#region src/layouts/blog.tags.tsx
7
+ function createBlogTagsPage({ heading, description } = {}) {
8
+ return async function BlogTagsPage({ lang, blog, ctx }) {
9
+ const grouped = await groupTags(ctx, (await ctx.getLoader()).getPages(lang).filter((page) => blog.isBlog.call(ctx, page)));
10
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
11
+ className: "flex flex-col items-start gap-4 border-y px-4 pt-3.5 pb-6 bg-fd-card text-fd-card-foreground shadow-inner max-sm:-mx-4 sm:rounded-xl sm:border",
12
+ children: [
13
+ /* @__PURE__ */ jsx(LinkToHome, {
14
+ lang,
15
+ blog
16
+ }),
17
+ /* @__PURE__ */ jsx("h1", {
18
+ className: "font-semibold text-2xl",
19
+ children: heading ?? "All Tags"
20
+ }),
21
+ /* @__PURE__ */ jsx("p", {
22
+ className: "text-fd-muted-foreground empty:hidden",
23
+ children: description ?? /* @__PURE__ */ jsxs("span", {
24
+ className: "flex items-center gap-1",
25
+ children: [
26
+ /* @__PURE__ */ jsx(TagIcon, { className: "size-3.5 text-fd-primary" }),
27
+ /* @__PURE__ */ jsx("span", {
28
+ className: "text-fd-primary font-mono",
29
+ children: grouped.size
30
+ }),
31
+ " tags in total."
32
+ ]
33
+ })
34
+ })
35
+ ]
36
+ }), /* @__PURE__ */ jsx("div", {
37
+ className: "grid grid-cols-2 sm:grid-cols-3 gap-2 mt-4 md:grid-cols-4 xl:grid-cols-6",
38
+ children: Array.from(grouped.entries()).sort((a, b) => b[1] - a[1]).map(([tag, count]) => /* @__PURE__ */ jsxs(Link, {
39
+ to: `/blog/tags/${tag}`,
40
+ className: "flex flex-row items-center gap-2 bg-fd-card text-fd-card-foreground border font-mono rounded-lg px-2 py-1 transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground",
41
+ children: [
42
+ /* @__PURE__ */ jsx(TagIcon, { className: "size-3.5 text-fd-muted-foreground" }),
43
+ /* @__PURE__ */ jsx("p", {
44
+ className: "font-medium",
45
+ children: tag
46
+ }),
47
+ /* @__PURE__ */ jsx("p", {
48
+ className: "ms-auto text-sm text-fd-muted-foreground",
49
+ children: count
50
+ })
51
+ ]
52
+ }, tag))
53
+ })] });
54
+ };
55
+ }
56
+ function createBlogTagPage({ heading, description } = {}) {
57
+ return async function BlogTagsPage({ lang, tag, blog, ctx }) {
58
+ const source = await ctx.getLoader();
59
+ const posts = [];
60
+ for (const page of source.getPages(lang)) {
61
+ if (!blog.isBlog.call(ctx, page)) continue;
62
+ const tags = await getTags(ctx, page);
63
+ if (!tags || !tags.includes(tag)) continue;
64
+ posts.push(page);
65
+ }
66
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
67
+ className: "flex flex-col items-start gap-4 border-y p-4 pt-3.5 bg-fd-card text-fd-card-foreground shadow-inner max-sm:-mx-4 sm:rounded-xl sm:border",
68
+ children: [
69
+ /* @__PURE__ */ jsx(LinkToHome, {
70
+ lang,
71
+ blog
72
+ }),
73
+ /* @__PURE__ */ jsx("h1", {
74
+ className: "font-semibold text-2xl",
75
+ children: heading ?? /* @__PURE__ */ jsxs("span", {
76
+ className: "inline-flex gap-2 items-center",
77
+ children: [
78
+ /* @__PURE__ */ jsx(TagIcon, { className: "text-fd-primary size-6" }),
79
+ "Tag ",
80
+ /* @__PURE__ */ jsxs("span", {
81
+ className: "font-mono text-fd-primary",
82
+ children: [
83
+ "\"",
84
+ tag,
85
+ "\""
86
+ ]
87
+ })
88
+ ]
89
+ })
90
+ }),
91
+ /* @__PURE__ */ jsx("p", {
92
+ className: "text-fd-muted-foreground empty:hidden",
93
+ children: description ?? /* @__PURE__ */ jsxs("span", {
94
+ className: "inline-flex items-center gap-1",
95
+ children: [
96
+ /* @__PURE__ */ jsx(NewspaperIcon, { className: "text-fd-primary size-3.5" }),
97
+ /* @__PURE__ */ jsx("span", {
98
+ className: "font-mono text-fd-primary",
99
+ children: posts.length
100
+ }),
101
+ " matching blog posts."
102
+ ]
103
+ })
104
+ })
105
+ ]
106
+ }), /* @__PURE__ */ jsx(OrderedBlogGrid, {
107
+ posts,
108
+ ctx
109
+ })] });
110
+ };
111
+ }
112
+ //#endregion
113
+ export { createBlogTagPage, createBlogTagsPage };
@@ -1,4 +1,4 @@
1
- import { AppContext } from "../lib/shared.js";
1
+ import { AppContext, TransformChildren } from "../lib/shared.js";
2
2
  import { ConfigContext, Layouts } from "../config.js";
3
3
  import { Awaitable } from "../lib/types.js";
4
4
  import { ReactNode } from "react";
@@ -12,24 +12,26 @@ interface DocsLayoutOptions<C extends ConfigContext = ConfigContext> {
12
12
  lang?: string;
13
13
  }, page: C["loaderConfig"]["page"]) => Awaitable<{
14
14
  markdownUrl?: string;
15
+ lastModified?: Date | null;
15
16
  body?: ReactNode;
16
- layoutProps?: Partial<DocsLayoutProps>;
17
- pageProps?: DocsPageProps;
17
+ layoutProps?: Partial<TransformChildren<DocsLayoutProps>>;
18
+ pageProps?: TransformChildren<DocsPageProps>;
18
19
  }>;
19
20
  }
20
21
  interface DocsLayoutRenderData {
21
22
  markdownUrl?: string;
23
+ lastModified?: Date | null;
22
24
  body: ReactNode;
23
- layoutProps: DocsLayoutProps;
24
- pageProps: DocsPageProps;
25
+ layoutProps: TransformChildren<DocsLayoutProps>;
26
+ pageProps: TransformChildren<DocsPageProps>;
25
27
  }
26
28
  interface DocsLayoutContextData {
27
29
  renderers?: ((this: {
28
30
  page: Page;
29
31
  }, data: DocsLayoutRenderData) => Awaitable<DocsLayoutRenderData>)[];
30
32
  }
31
- declare function createDocsLayout<C extends ConfigContext = ConfigContext>({
33
+ declare function createDocsLayoutPage<C extends ConfigContext = ConfigContext>({
32
34
  render
33
35
  }?: DocsLayoutOptions<NoInfer<C>>): Layouts<C>["page"];
34
36
  //#endregion
35
- export { DocsLayoutContextData, DocsLayoutOptions, DocsLayoutRenderData, createDocsLayout };
37
+ export { DocsLayoutContextData, DocsLayoutOptions, DocsLayoutRenderData, createDocsLayoutPage };
@@ -1,85 +1,59 @@
1
- import { baseOptions, getGitHubFileUrl, renderPageMeta } from "../lib/shared.js";
1
+ import { baseLayoutProps, createTransformChildren, getGitHubFileUrl, getLastModifiedDate, mergeLayoutConfigs, renderBody, renderPageMeta, renderToc } from "../lib/shared.js";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { unstable_notFound } from "waku/router/server";
4
4
  import { DocsLayout } from "fumadocs-ui/layouts/docs";
5
- import { DocsBody, DocsDescription, DocsPage, DocsTitle, MarkdownCopyButton, ViewOptionsPopover } from "fumadocs-ui/layouts/docs/page";
5
+ import { DocsBody, DocsDescription, DocsPage, DocsTitle, MarkdownCopyButton, PageLastUpdate, ViewOptionsPopover } from "fumadocs-ui/layouts/docs/page";
6
6
  //#region src/layouts/docs.tsx
7
- function createDocsLayout({ render } = {}) {
8
- async function defaultRender(page) {
9
- let body;
10
- let toc;
11
- for (const adapter of this.adapters) {
12
- body = await adapter["core:render-body"]?.call(this, page);
13
- if (body !== void 0) break;
14
- }
15
- for (const adapter of this.adapters) {
16
- toc = await adapter["core:render-toc"]?.call(this, page);
17
- if (toc !== void 0) break;
18
- }
19
- if (body === void 0) throw new Error("[Fumapress] Please specify the `render` option in createDocsLayout()");
20
- return {
21
- body,
22
- pageProps: { toc }
23
- };
24
- }
25
- return async function Layout(props) {
26
- const { slugs, lang, getLoader, data: { "core:docs-layout": layoutData } } = props;
7
+ function createDocsLayoutPage({ render } = {}) {
8
+ const TDocsLayout = createTransformChildren(DocsLayout);
9
+ const TDocsPage = createTransformChildren(DocsPage);
10
+ return async function Layout({ slugs, lang, ctx }) {
11
+ const { getLoader, layouts, data: { "core:docs-layout": layoutData } } = ctx;
27
12
  const source = await getLoader();
28
13
  const page = source.getPage(slugs, lang);
29
14
  if (!page) unstable_notFound();
30
- const _raw = await (render ?? defaultRender).call(props, page);
31
- let result;
32
- if (_raw.body === void 0 || _raw.pageProps === void 0) {
33
- const _default = await defaultRender.call(props, page);
34
- result = {
35
- markdownUrl: _raw.markdownUrl,
36
- pageProps: _raw.pageProps ?? _default.pageProps,
37
- body: _raw.body ?? _default.body,
38
- layoutProps: {
39
- tree: source.getPageTree(lang),
40
- ..._raw.layoutProps ?? baseOptions(props)
41
- }
42
- };
43
- } else result = {
44
- body: _raw.body,
45
- pageProps: _raw.pageProps,
46
- markdownUrl: _raw.markdownUrl,
47
- layoutProps: {
48
- tree: source.getPageTree(lang),
49
- ..._raw.layoutProps ?? baseOptions(props)
50
- }
15
+ async function getLayoutProps(overrides) {
16
+ const inherit = await layouts.defaultProps?.call(ctx, { lang });
17
+ return mergeLayoutConfigs({ tree: source.getPageTree(lang) }, baseLayoutProps(ctx), inherit, overrides);
18
+ }
19
+ const _raw = await render?.call(ctx, page);
20
+ let result = {
21
+ ..._raw,
22
+ lastModified: _raw?.lastModified ?? await getLastModifiedDate(ctx, page),
23
+ pageProps: {
24
+ ..._raw?.pageProps,
25
+ toc: _raw?.pageProps?.toc ?? await renderToc(ctx, page)
26
+ },
27
+ body: _raw?.body ?? await renderBody(ctx, page, "[Fumapress] Please specify the `render` option in createDocsLayoutPage()"),
28
+ layoutProps: await getLayoutProps(_raw?.layoutProps)
51
29
  };
52
30
  if (layoutData?.renderers) {
53
31
  const renderCtx = { page };
54
32
  for (const r of layoutData.renderers) result = await r.call(renderCtx, result);
55
33
  }
56
- return /* @__PURE__ */ jsxs(DocsLayout, {
57
- ...result.layoutProps,
58
- children: [
59
- renderPageMeta(page, props),
60
- result.layoutProps.children,
61
- /* @__PURE__ */ jsxs(DocsPage, {
62
- ...result.pageProps,
63
- children: [
64
- result.pageProps.children,
65
- /* @__PURE__ */ jsx(DocsTitle, { children: page.data.title }),
66
- /* @__PURE__ */ jsx(DocsDescription, {
67
- className: "mb-0",
68
- children: page.data.description
69
- }),
70
- /* @__PURE__ */ jsxs("div", {
71
- className: "flex flex-row gap-2 items-center border-b pt-2 pb-6",
72
- children: [result.markdownUrl && /* @__PURE__ */ jsx(MarkdownCopyButton, { markdownUrl: result.markdownUrl }), /* @__PURE__ */ jsx(ViewOptionsPopover, {
73
- markdownUrl: result.markdownUrl,
74
- githubUrl: page.absolutePath ? getGitHubFileUrl(props, page.absolutePath) : void 0
75
- })]
76
- }),
77
- /* @__PURE__ */ jsx(DocsBody, { children: result.body })
78
- ]
79
- })
80
- ]
34
+ return /* @__PURE__ */ jsxs(TDocsLayout, {
35
+ props: result.layoutProps,
36
+ children: [renderPageMeta(page, ctx), /* @__PURE__ */ jsxs(TDocsPage, {
37
+ props: result.pageProps,
38
+ children: [
39
+ /* @__PURE__ */ jsx(DocsTitle, { children: page.data.title }),
40
+ /* @__PURE__ */ jsx(DocsDescription, {
41
+ className: "mb-0",
42
+ children: page.data.description
43
+ }),
44
+ /* @__PURE__ */ jsxs("div", {
45
+ className: "flex flex-row gap-2 items-center border-b pt-2 pb-6",
46
+ children: [result.markdownUrl && /* @__PURE__ */ jsx(MarkdownCopyButton, { markdownUrl: result.markdownUrl }), /* @__PURE__ */ jsx(ViewOptionsPopover, {
47
+ markdownUrl: result.markdownUrl,
48
+ githubUrl: page.absolutePath ? getGitHubFileUrl(ctx, page.absolutePath) : void 0
49
+ })]
50
+ }),
51
+ /* @__PURE__ */ jsx(DocsBody, { children: result.body }),
52
+ result.lastModified && /* @__PURE__ */ jsx(PageLastUpdate, { date: result.lastModified })
53
+ ]
54
+ })]
81
55
  });
82
56
  };
83
57
  }
84
58
  //#endregion
85
- export { createDocsLayout };
59
+ export { createDocsLayoutPage };
@@ -1,28 +1,40 @@
1
- import { AppContext } from "../lib/shared.js";
1
+ import { AppContext, TransformChildren } from "../lib/shared.js";
2
2
  import { ConfigContext, Layouts } from "../config.js";
3
3
  import { Awaitable } from "../lib/types.js";
4
- import { ReactNode } from "react";
4
+ import { ComponentType, ReactNode } from "react";
5
5
  import { HomeLayoutProps } from "fumadocs-ui/layouts/home";
6
6
  import { Page } from "fumadocs-core/source";
7
7
 
8
8
  //#region src/layouts/home.d.ts
9
- interface HomeLayoutOptions<C extends ConfigContext = ConfigContext> {
9
+ interface HomeLayoutPageOptions<C extends ConfigContext = ConfigContext> {
10
10
  render?: (this: AppContext<C>, page: C["loaderConfig"]["page"]) => Awaitable<{
11
11
  body?: ReactNode;
12
- layoutProps?: Partial<HomeLayoutProps>;
12
+ layoutProps?: TransformChildren<HomeLayoutProps>;
13
13
  }>;
14
14
  }
15
15
  interface HomeLayoutRenderData {
16
16
  body: ReactNode;
17
- layoutProps: HomeLayoutProps;
17
+ layoutProps: TransformChildren<HomeLayoutProps>;
18
18
  }
19
19
  interface HomeLayoutContextData {
20
20
  renderers?: ((this: {
21
- page: Page;
21
+ page: Page | undefined;
22
22
  }, data: HomeLayoutRenderData) => Awaitable<HomeLayoutRenderData>)[];
23
23
  }
24
+ declare function createHomeLayoutPage<C extends ConfigContext = ConfigContext>({
25
+ render
26
+ }?: HomeLayoutPageOptions<NoInfer<C>>): Layouts<C>["page"];
27
+ interface HomeLayoutOptions<C extends ConfigContext = ConfigContext> {
28
+ render?: (this: AppContext<C>) => Awaitable<{
29
+ layoutProps?: TransformChildren<HomeLayoutProps>;
30
+ }>;
31
+ }
24
32
  declare function createHomeLayout<C extends ConfigContext = ConfigContext>({
25
33
  render
26
- }: HomeLayoutOptions<NoInfer<C>>): Layouts<C>["page"];
34
+ }?: HomeLayoutOptions<C>): ComponentType<{
35
+ lang?: string;
36
+ children: ReactNode;
37
+ ctx: AppContext<C>;
38
+ }>;
27
39
  //#endregion
28
- export { HomeLayoutContextData, HomeLayoutOptions, HomeLayoutRenderData, createHomeLayout };
40
+ export { HomeLayoutContextData, HomeLayoutOptions, HomeLayoutPageOptions, HomeLayoutRenderData, createHomeLayout, createHomeLayoutPage };
@@ -1,34 +1,54 @@
1
- import { baseOptions, renderPageMeta } from "../lib/shared.js";
2
- import { jsxs } from "react/jsx-runtime";
1
+ import { baseLayoutProps, createTransformChildren, mergeLayoutConfigs, renderBody, renderPageMeta } from "../lib/shared.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import { unstable_notFound } from "waku/router/server";
4
4
  import { HomeLayout } from "fumadocs-ui/layouts/home";
5
5
  //#region src/layouts/home.tsx
6
- function createHomeLayout({ render }) {
7
- async function renderDefault(page) {
8
- for (const adapter of this.adapters) {
9
- const body = await adapter["core:render-body"]?.call(this, page);
10
- if (body !== void 0) return { body };
11
- }
12
- throw new Error("[Fumapress] Please specify the `render` option in createHomeLayout()");
13
- }
14
- return async function Layout(props) {
15
- const { slugs, lang, getLoader, data: { "core:home-layout": layoutData } } = props;
6
+ function createHomeLayoutPage({ render } = {}) {
7
+ const THomeLayout = createTransformChildren(HomeLayout);
8
+ return async function Layout({ slugs, lang, ctx }) {
9
+ const { getLoader, layouts, data: { "core:home-layout": layoutData } } = ctx;
16
10
  const page = (await getLoader()).getPage(slugs, lang);
17
11
  if (!page) unstable_notFound();
18
- const _raw = await (render ?? renderDefault).call(props, page);
12
+ async function getLayoutProps(overrides) {
13
+ const inherit = await layouts.defaultProps?.call(ctx, { lang });
14
+ return mergeLayoutConfigs(baseLayoutProps(ctx), inherit, overrides);
15
+ }
16
+ const _raw = await render?.call(ctx, page);
19
17
  let result = {
20
- body: _raw.body === void 0 ? (await renderDefault.call(props, page)).body : _raw.body,
21
- layoutProps: _raw.layoutProps ?? baseOptions(props)
18
+ body: _raw?.body ?? await renderBody(ctx, page, "[Fumapress] Please specify the `render` option in createHomeLayoutPage()"),
19
+ layoutProps: await getLayoutProps(_raw?.layoutProps)
22
20
  };
23
21
  if (layoutData?.renderers) {
24
22
  const renderCtx = { page };
25
23
  for (const r of layoutData.renderers) result = await r.call(renderCtx, result);
26
24
  }
27
- return /* @__PURE__ */ jsxs(HomeLayout, {
28
- ...result.layoutProps,
29
- children: [renderPageMeta(page, props), result.body]
25
+ return /* @__PURE__ */ jsxs(THomeLayout, {
26
+ props: result.layoutProps,
27
+ children: [renderPageMeta(page, ctx), result.body]
28
+ });
29
+ };
30
+ }
31
+ function createHomeLayout({ render } = {}) {
32
+ const THomeLayout = createTransformChildren(HomeLayout);
33
+ return async function Layout({ lang, children, ctx }) {
34
+ const { layouts, data: { "core:home-layout": layoutData } } = ctx;
35
+ async function getLayoutProps(overrides) {
36
+ const inherit = await layouts.defaultProps?.call(ctx, { lang });
37
+ return mergeLayoutConfigs(baseLayoutProps(ctx), inherit, overrides);
38
+ }
39
+ let result = {
40
+ body: children,
41
+ layoutProps: await getLayoutProps((await render?.call(ctx))?.layoutProps)
42
+ };
43
+ if (layoutData?.renderers) {
44
+ const renderCtx = { page: void 0 };
45
+ for (const r of layoutData.renderers) result = await r.call(renderCtx, result);
46
+ }
47
+ return /* @__PURE__ */ jsx(THomeLayout, {
48
+ props: result.layoutProps,
49
+ children: result.body
30
50
  });
31
51
  };
32
52
  }
33
53
  //#endregion
34
- export { createHomeLayout };
54
+ export { createHomeLayout, createHomeLayoutPage };
@@ -0,0 +1,37 @@
1
+ import { AppContext, TransformChildren } from "../lib/shared.js";
2
+ import { ConfigContext, Layouts } from "../config.js";
3
+ import { Awaitable } from "../lib/types.js";
4
+ import { ReactNode } from "react";
5
+ import { DocsLayoutProps } from "fumadocs-ui/layouts/notebook";
6
+ import { DocsPageProps } from "fumadocs-ui/layouts/notebook/page";
7
+ import { Page } from "fumadocs-core/source";
8
+
9
+ //#region src/layouts/notebook.d.ts
10
+ interface NotebookLayoutOptions<C extends ConfigContext = ConfigContext> {
11
+ render?: (this: AppContext<C> & {
12
+ lang?: string;
13
+ }, page: C["loaderConfig"]["page"]) => Awaitable<{
14
+ markdownUrl?: string;
15
+ lastModified?: Date | null;
16
+ body?: ReactNode;
17
+ layoutProps?: Partial<TransformChildren<DocsLayoutProps>>;
18
+ pageProps?: TransformChildren<DocsPageProps>;
19
+ }>;
20
+ }
21
+ interface NotebookLayoutRenderData {
22
+ markdownUrl?: string;
23
+ lastModified?: Date | null;
24
+ body: ReactNode;
25
+ layoutProps: TransformChildren<DocsLayoutProps>;
26
+ pageProps: TransformChildren<DocsPageProps>;
27
+ }
28
+ interface NotebookLayoutContextData {
29
+ renderers?: ((this: {
30
+ page: Page;
31
+ }, data: NotebookLayoutRenderData) => Awaitable<NotebookLayoutRenderData>)[];
32
+ }
33
+ declare function createNotebookLayoutPage<C extends ConfigContext = ConfigContext>({
34
+ render
35
+ }?: NotebookLayoutOptions<NoInfer<C>>): Layouts<C>["page"];
36
+ //#endregion
37
+ export { NotebookLayoutContextData, NotebookLayoutOptions, NotebookLayoutRenderData, createNotebookLayoutPage };
@@ -0,0 +1,59 @@
1
+ import { baseLayoutProps, createTransformChildren, getGitHubFileUrl, getLastModifiedDate, mergeLayoutConfigs, renderBody, renderPageMeta, renderToc } from "../lib/shared.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { unstable_notFound } from "waku/router/server";
4
+ import { DocsLayout } from "fumadocs-ui/layouts/notebook";
5
+ import { DocsBody, DocsDescription, DocsPage, DocsTitle, MarkdownCopyButton, PageLastUpdate, ViewOptionsPopover } from "fumadocs-ui/layouts/notebook/page";
6
+ //#region src/layouts/notebook.tsx
7
+ function createNotebookLayoutPage({ render } = {}) {
8
+ const TDocsLayout = createTransformChildren(DocsLayout);
9
+ const TDocsPage = createTransformChildren(DocsPage);
10
+ return async function Layout({ slugs, lang, ctx }) {
11
+ const { getLoader, layouts, data: { "core:notebook-layout": layoutData } } = ctx;
12
+ const source = await getLoader();
13
+ const page = source.getPage(slugs, lang);
14
+ if (!page) unstable_notFound();
15
+ async function getLayoutProps(overrides) {
16
+ const inherit = await layouts.defaultProps?.call(ctx, { lang });
17
+ return mergeLayoutConfigs({ tree: source.getPageTree(lang) }, baseLayoutProps(ctx), inherit, overrides);
18
+ }
19
+ const _raw = await render?.call(ctx, page);
20
+ let result = {
21
+ ..._raw,
22
+ lastModified: _raw?.lastModified ?? await getLastModifiedDate(ctx, page),
23
+ pageProps: {
24
+ ..._raw?.pageProps,
25
+ toc: _raw?.pageProps?.toc ?? await renderToc(ctx, page)
26
+ },
27
+ body: _raw?.body ?? await renderBody(ctx, page, "[Fumapress] Please specify the `render` option in createNotebookLayoutPage()"),
28
+ layoutProps: await getLayoutProps(_raw?.layoutProps)
29
+ };
30
+ if (layoutData?.renderers) {
31
+ const renderCtx = { page };
32
+ for (const r of layoutData.renderers) result = await r.call(renderCtx, result);
33
+ }
34
+ return /* @__PURE__ */ jsxs(TDocsLayout, {
35
+ props: result.layoutProps,
36
+ children: [renderPageMeta(page, ctx), /* @__PURE__ */ jsxs(TDocsPage, {
37
+ props: result.pageProps,
38
+ children: [
39
+ /* @__PURE__ */ jsx(DocsTitle, { children: page.data.title }),
40
+ /* @__PURE__ */ jsx(DocsDescription, {
41
+ className: "mb-0",
42
+ children: page.data.description
43
+ }),
44
+ /* @__PURE__ */ jsxs("div", {
45
+ className: "flex flex-row gap-2 items-center border-b pt-2 pb-6",
46
+ children: [result.markdownUrl && /* @__PURE__ */ jsx(MarkdownCopyButton, { markdownUrl: result.markdownUrl }), /* @__PURE__ */ jsx(ViewOptionsPopover, {
47
+ markdownUrl: result.markdownUrl,
48
+ githubUrl: page.absolutePath ? getGitHubFileUrl(ctx, page.absolutePath) : void 0
49
+ })]
50
+ }),
51
+ /* @__PURE__ */ jsx(DocsBody, { children: result.body }),
52
+ result.lastModified && /* @__PURE__ */ jsx(PageLastUpdate, { date: result.lastModified })
53
+ ]
54
+ })]
55
+ });
56
+ };
57
+ }
58
+ //#endregion
59
+ export { createNotebookLayoutPage };
@@ -3,7 +3,7 @@ import { RootProviderProps } from "fumadocs-ui/provider/waku";
3
3
 
4
4
  //#region src/layouts/root.d.ts
5
5
  interface RootLayoutOptions {
6
- providerProps?: RootProviderProps;
6
+ providerProps?: Omit<RootProviderProps, "children">;
7
7
  }
8
8
  declare function createRootLayout<C extends ConfigContext = ConfigContext>(options?: RootLayoutOptions): Layouts<C>["root"];
9
9
  //#endregion
@@ -4,12 +4,11 @@ import styles from "virtual:root.css?inline";
4
4
  import { RootProvider } from "fumadocs-ui/provider/waku";
5
5
  //#region src/layouts/root.tsx
6
6
  function createRootLayout(options) {
7
- return async function(props) {
8
- const { children, lang, i18nConfig, data } = props;
9
- const hooks = data["core:provider"];
7
+ return async function({ lang, ctx, children }) {
8
+ const hooks = ctx.data["core:provider"];
10
9
  let providerProps = { ...options?.providerProps };
11
- if (i18nConfig) {
12
- const { languages } = i18nConfig;
10
+ if (ctx.i18nConfig) {
11
+ const { languages } = ctx.i18nConfig;
13
12
  providerProps.i18n ??= {
14
13
  locale: lang,
15
14
  locales: Object.entries(languages).map(([k, v]) => ({
@@ -23,7 +22,7 @@ function createRootLayout(options) {
23
22
  return /* @__PURE__ */ jsxs("html", {
24
23
  lang: lang ?? "en",
25
24
  suppressHydrationWarning: true,
26
- children: [/* @__PURE__ */ jsxs("head", { children: [/* @__PURE__ */ jsx("style", { children: styles }), renderRootMeta(props)] }), /* @__PURE__ */ jsx("body", {
25
+ children: [/* @__PURE__ */ jsxs("head", { children: [/* @__PURE__ */ jsx("style", { children: styles }), renderRootMeta(ctx)] }), /* @__PURE__ */ jsx("body", {
27
26
  "data-version": "1.0",
28
27
  className: "flex flex-col min-h-screen",
29
28
  children: /* @__PURE__ */ jsx(RootProvider, {
@@ -0,0 +1,11 @@
1
+ import { AppContext } from "../lib/shared.js";
2
+ import { ConfigContext, Layouts } from "../config.js";
3
+ import { Page } from "fumadocs-core/source";
4
+
5
+ //#region src/layouts/switch.d.ts
6
+ declare function createLayoutSwitchAuto<C extends ConfigContext = ConfigContext>(layouts: Record<C["loaderConfig"]["page"] extends Page<infer Type extends string> ? Type : never, Layouts<C>["page"]>): Layouts<C>["page"];
7
+ declare function createLayoutSwitch<T extends string, C extends ConfigContext = ConfigContext>(/** detect layout from page */
8
+
9
+ detector: (this: AppContext<C>, page: C["loaderConfig"]["page"]) => T, layouts: Record<NoInfer<T>, Layouts<C>["page"]>): Layouts<C>["page"];
10
+ //#endregion
11
+ export { createLayoutSwitch, createLayoutSwitchAuto };