@publish.os/nextjs 0.0.1-alpha.81 → 0.0.1-alpha.91
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/compiler-assets/nextjs/defaults/app/globals.css +1 -0
- package/compiler-assets/nextjs/defaults/group/index.tsx +50 -0
- package/compiler-assets/nextjs/defaults/group/layout.tsx +8 -8
- package/compiler-assets/nextjs/defaults/group/page.tsx +44 -43
- package/compiler-assets/nextjs/defaults/project/next.config.mjs +33 -13
- package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +10 -3
- package/compiler-assets/nextjs/defaults/root/css/animation.css +131 -0
- package/compiler-assets/nextjs/defaults/root/css/components/code-block.css +18 -0
- package/compiler-assets/nextjs/defaults/root/css/components/dialog.css +4 -1
- package/compiler-assets/nextjs/defaults/root/css/components/menu.css +1 -1
- package/compiler-assets/nextjs/defaults/root/css/components/navigation-menu.css +1 -1
- package/compiler-assets/nextjs/defaults/root/css/components/popover.css +1 -1
- package/compiler-assets/nextjs/defaults/root/css/components/select.css +1 -1
- package/compiler-assets/nextjs/defaults/root/css/components/tooltip.css +1 -1
- package/compiler-assets/nextjs/defaults/root/css/shadow.css +6 -25
- package/compiler-assets/nextjs/defaults/root/css/typography.css +51 -68
- package/compiler-assets/nextjs/defaults/root/globals.css +25 -0
- package/compiler-assets/nextjs/defaults/root/{page.tsx → index.tsx} +6 -2
- package/compiler-assets/nextjs/defaults/root/layout.tsx +7 -1
- package/compiler-assets/nextjs/defaults/root/theme.css +22 -22
- package/compiler-assets/nextjs/shims/document.tsx +38 -0
- package/compiler-assets/nextjs/shims/generated-group-page.tsx +19 -2
- package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +18 -2
- package/compiler-assets/nextjs/shims/global-layout.tsx +19 -85
- package/compiler-assets/nextjs/shims/global-not-found.tsx +69 -0
- package/compiler-assets/nextjs/shims/markdown-route.ts +2 -0
- package/compiler-assets/nextjs/shims/metadata-icons.tsx +39 -0
- package/compiler-assets/nextjs/shims/not-found-content.tsx +53 -0
- package/compiler-assets/nextjs/shims/not-found-navigation.tsx +60 -0
- package/compiler-assets/nextjs/shims/proxy.ts +143 -65
- package/compiler-assets/nextjs/shims/publish-os-theme-provider.tsx +76 -15
- package/compiler-assets/nextjs/shims/root-page.tsx +7 -1
- package/compiler-assets/nextjs/shims/site-fenced-code-block.tsx +30 -0
- package/compiler-assets/nextjs/shims/site-heading-level.tsx +14 -0
- package/compiler-assets/nextjs/shims/site-mdx-components.tsx +112 -0
- package/compiler-assets/nextjs/shims/site-mdx.tsx +17 -0
- package/compiler-assets/nextjs/shims/theme-defaults.css +41 -25
- package/dist/build-operation-5QMLXF7N.js +89 -0
- package/dist/{button-CFdx-ohV.d.ts → button-BdCScEKi.d.ts} +6 -6
- package/dist/capture-local-source-WGGDIUU2.js +258 -0
- package/dist/chunk-22RSSUNV.js +13 -0
- package/dist/chunk-4BC2L2KA.js +620 -0
- package/dist/chunk-5J3YUNRY.js +121 -0
- package/dist/chunk-5KAD7W53.js +248 -0
- package/dist/chunk-6C65KV7O.js +142 -0
- package/dist/chunk-6D2E6UMD.js +695 -0
- package/dist/chunk-7NY22B5U.js +161 -0
- package/dist/chunk-AI2UULNX.js +9 -0
- package/dist/chunk-EFO6AWXN.js +19 -0
- package/dist/chunk-F3AGNDF4.js +2377 -0
- package/dist/chunk-GBPLER5H.js +426 -0
- package/dist/chunk-IL4RJOKI.js +186 -0
- package/dist/chunk-NNBJZPFM.js +193 -0
- package/dist/chunk-ORIUWJBQ.js +58 -0
- package/dist/chunk-OXOFRXEI.js +7129 -0
- package/dist/chunk-UYGCOWRF.js +1709 -0
- package/dist/chunk-WL75GQ5M.js +80 -0
- package/dist/compiler.d.ts +54 -7
- package/dist/compiler.js +121 -13147
- package/dist/components/blocks/agent-actions.d.ts +81 -0
- package/dist/components/blocks/agent-actions.js +594 -0
- package/dist/components/blocks/toc.d.ts +43 -0
- package/dist/components/blocks/toc.js +136 -0
- package/dist/components/ui/button.d.ts +5 -0
- package/dist/components/ui/button.js +94 -0
- package/dist/compose-CVBJRAF6.js +16 -0
- package/dist/config/createNextConfig.js +27 -0
- package/dist/dev-operation-OSHHWRWK.js +1095 -0
- package/dist/framework-selection-ZVO323PK.js +11 -0
- package/dist/ide-support-CU6Z5PVR.js +16 -0
- package/dist/index.d.ts +55 -4
- package/dist/jsx-dev-runtime.d.ts +6 -0
- package/dist/jsx-dev-runtime.js +100 -0
- package/dist/jsx-runtime.d.ts +7 -0
- package/dist/jsx-runtime.js +97 -0
- package/dist/kernel/components/blocks/AgentActions.d.ts +35 -6
- package/dist/kernel/components/blocks/AgentActions.js +401 -150
- package/dist/kernel/components/blocks/agent-actions.d.ts +5 -0
- package/dist/kernel/components/blocks/agent-actions.js +594 -0
- package/dist/kernel/components/blocks/animated-icon-swap.js +1 -1
- package/dist/kernel/components/blocks/color-palette.js +4 -4
- package/dist/kernel/components/blocks/logo-block.js +3 -3
- package/dist/kernel/components/blocks/nav-breadcrumb.d.ts +10 -2
- package/dist/kernel/components/blocks/nav-breadcrumb.js +22 -7
- package/dist/kernel/components/blocks/navbar.d.ts +2 -2
- package/dist/kernel/components/blocks/navbar.js +406 -65
- package/dist/kernel/components/blocks/navigation-progress.js +6 -3
- package/dist/kernel/components/blocks/next-prev.d.ts +1 -1
- package/dist/kernel/components/blocks/next-prev.js +12 -24
- package/dist/kernel/components/blocks/page-list.d.ts +1 -1
- package/dist/kernel/components/blocks/page-list.js +7 -6
- package/dist/kernel/components/blocks/search.d.ts +83 -58
- package/dist/kernel/components/blocks/search.js +554 -428
- package/dist/kernel/components/blocks/sidebar-node.d.ts +2 -2
- package/dist/kernel/components/blocks/sidebar-node.js +12 -10
- package/dist/kernel/components/blocks/sidebar.d.ts +3 -3
- package/dist/kernel/components/blocks/sidebar.js +24 -14
- package/dist/kernel/components/blocks/theme-toggle.d.ts +2 -2
- package/dist/kernel/components/blocks/theme-toggle.js +47 -1
- package/dist/kernel/components/blocks/toc-client.d.ts +40 -0
- package/dist/kernel/components/blocks/toc-client.js +495 -0
- package/dist/kernel/components/blocks/toc.d.ts +19 -1
- package/dist/kernel/components/blocks/toc.js +122 -180
- package/dist/kernel/components/mdx/components/blockquote.js +2 -2
- package/dist/kernel/components/mdx/components/callout.d.ts +5 -7
- package/dist/kernel/components/mdx/components/callout.js +67 -36
- package/dist/kernel/components/mdx/components/code-block.d.ts +5 -2
- package/dist/kernel/components/mdx/components/code-block.js +106 -5
- package/dist/kernel/components/mdx/components/copy-code-button.d.ts +8 -0
- package/dist/kernel/components/mdx/components/copy-code-button.js +61 -0
- package/dist/kernel/components/mdx/components/figure-caption.d.ts +1 -1
- package/dist/kernel/components/mdx/components/figure-caption.js +4 -3
- package/dist/kernel/components/mdx/components/figure.d.ts +6 -2
- package/dist/kernel/components/mdx/components/figure.js +24 -14
- package/dist/kernel/components/mdx/components/footnotes.js +1 -1
- package/dist/kernel/components/mdx/components/heading-copy-link.js +4 -4
- package/dist/kernel/components/mdx/components/heading.js +6 -3
- package/dist/kernel/components/mdx/components/hr.js +2 -2
- package/dist/kernel/components/mdx/components/image-zoom.js +2 -2
- package/dist/kernel/components/mdx/components/image.d.ts +1 -1
- package/dist/kernel/components/mdx/components/image.js +94 -68
- package/dist/kernel/components/mdx/components/inline-code.js +2 -2
- package/dist/kernel/components/mdx/components/kbd.d.ts +2 -2
- package/dist/kernel/components/mdx/components/kbd.js +5 -4
- package/dist/kernel/components/mdx/components/link.d.ts +35 -4
- package/dist/kernel/components/mdx/components/link.js +3 -3
- package/dist/kernel/components/mdx/components/paragraph.js +2 -5
- package/dist/kernel/components/mdx/components/strikethrough.js +1 -1
- package/dist/kernel/components/mdx/components/table.js +2 -2
- package/dist/kernel/components/mdx/components/task-list.js +2 -2
- package/dist/kernel/components/mdx/components/video-player.d.ts +6 -2
- package/dist/kernel/components/mdx/components/video-player.js +8 -4
- package/dist/kernel/components/mdx/components/video.d.ts +5 -3
- package/dist/kernel/components/mdx/components/video.js +8 -6
- package/dist/kernel/components/mdx/error-boundary.js +2 -2
- package/dist/kernel/components/mdx/error-fallback.js +1 -1
- package/dist/kernel/components/mdx/mdx.d.ts +28 -14
- package/dist/kernel/components/mdx/mdx.js +336 -63
- package/dist/kernel/components/mdx/rehype-heading-ids.d.ts +1 -0
- package/dist/kernel/components/mdx/rehype-heading-ids.js +6 -4
- package/dist/kernel/components/next-image.d.ts +12 -0
- package/dist/kernel/components/next-image.js +61 -0
- package/dist/kernel/components/ui/accordion.js +1 -1
- package/dist/kernel/components/ui/breadcrumb-trail.d.ts +6 -23
- package/dist/kernel/components/ui/breadcrumb-trail.js +2 -2
- package/dist/kernel/components/ui/breadcrumb.d.ts +11 -3
- package/dist/kernel/components/ui/breadcrumb.js +10 -8
- package/dist/kernel/components/ui/button-group.js +8 -7
- package/dist/kernel/components/ui/button.d.ts +58 -6
- package/dist/kernel/components/ui/button.js +43 -39
- package/dist/kernel/components/ui/card.d.ts +2 -2
- package/dist/kernel/components/ui/card.js +1 -1
- package/dist/kernel/components/ui/dialog.js +1 -1
- package/dist/kernel/components/ui/drawer.d.ts +3 -1
- package/dist/kernel/components/ui/drawer.js +6 -2
- package/dist/kernel/components/ui/input.d.ts +2 -2
- package/dist/kernel/components/ui/input.js +1 -1
- package/dist/kernel/components/ui/kbd.js +10 -17
- package/dist/kernel/components/ui/link.d.ts +11 -3
- package/dist/kernel/components/ui/link.js +12 -11
- package/dist/kernel/components/ui/menu.js +6 -6
- package/dist/kernel/components/ui/mod-key.d.ts +10 -0
- package/dist/kernel/components/ui/mod-key.js +36 -0
- package/dist/kernel/components/ui/navigation-menu.js +3 -3
- package/dist/kernel/components/ui/popover.js +1 -1
- package/dist/kernel/components/ui/progress.js +2 -2
- package/dist/kernel/components/ui/scroll-area.js +5 -5
- package/dist/kernel/components/ui/select.js +8 -11
- package/dist/kernel/components/ui/separator.js +1 -1
- package/dist/kernel/components/ui/table.js +1 -1
- package/dist/kernel/components/ui/tabs.js +1 -1
- package/dist/kernel/components/ui/tag.js +1 -1
- package/dist/kernel/components/ui/text.d.ts +2 -2
- package/dist/kernel/components/ui/text.js +1 -1
- package/dist/kernel/components/ui/toast.js +1 -1
- package/dist/kernel/components/ui/tooltip.js +1 -1
- package/dist/kernel/defaults.registry.d.ts +11 -24
- package/dist/kernel/defaults.registry.js +11 -26
- package/dist/kernel/routes/agent/markdown.d.ts +3 -1
- package/dist/kernel/routes/agent/markdown.js +219 -48
- package/dist/kernel/routes/layouts/group.d.ts +1 -1
- package/dist/kernel/routes/layouts/group.js +5 -7
- package/dist/kernel/routes/metadata/feed.d.ts +1 -1
- package/dist/kernel/routes/metadata/feed.js +111 -81
- package/dist/kernel/routes/metadata/llms.d.ts +12 -3
- package/dist/kernel/routes/metadata/llms.js +156 -59
- package/dist/kernel/routes/metadata/og-image.js +1 -1
- package/dist/kernel/routes/metadata/robots.d.ts +1 -1
- package/dist/kernel/routes/metadata/robots.js +2 -2
- package/dist/kernel/routes/metadata/sitemap.d.ts +26 -4
- package/dist/kernel/routes/metadata/sitemap.js +206 -38
- package/dist/kernel/routes/not-found.d.ts +34 -0
- package/dist/kernel/routes/not-found.js +213 -0
- package/dist/kernel/routes/pages/group.d.ts +2 -2
- package/dist/kernel/routes/pages/group.js +21 -13
- package/dist/kernel/routes/pages/leaf.d.ts +28 -1
- package/dist/kernel/routes/pages/leaf.js +25 -16
- package/dist/kernel/routes/pages/root.js +19 -13
- package/dist/keyboard-shortcuts.js +1 -1
- package/dist/resolvers/manifest-resolver.js +29 -6
- package/dist/search.d.ts +6 -7
- package/dist/search.js +52 -29
- package/dist/{sidebar-types-Bgchdfd6.d.ts → sidebar-types-DKpR27II.d.ts} +1 -1
- package/dist/theme-scope.js +1 -1
- package/dist/{types-DHBm7-j6.d.ts → types-CJWRG05y.d.ts} +20 -1
- package/dist/{types-B_b3C0U6.d.ts → types-CUtrppxt.d.ts} +8 -2
- package/dist/{types-CIwwieNw.d.ts → types-J2w_puPF.d.ts} +11 -10
- package/dist/types.d.ts +15 -6
- package/dist/utils/heading-ids.js +30 -11
- package/dist/utils/toc-selection.d.ts +7 -0
- package/dist/utils/toc-selection.js +14 -0
- package/dist/validate-local-source-SV44DBQT.js +16 -0
- package/dist/validate-publish-os-source-NZJF3TB2.js +14 -0
- package/init/seed/minimal/.gitignore +1 -0
- package/init/seed/minimal/publish.os/assets/blog/hello-world.svg +13 -0
- package/init/seed/minimal/publish.os/assets/favicon.dark.svg +13 -0
- package/init/seed/minimal/publish.os/assets/favicon.svg +13 -0
- package/init/seed/minimal/publish.os/blog/content/hello-world.mdx +48 -0
- package/init/seed/minimal/publish.os/blog/content/series-a.mdx +11 -0
- package/init/seed/minimal/publish.os/blog/index.tsx +82 -0
- package/init/seed/minimal/publish.os/blog/layout.tsx +13 -0
- package/init/seed/minimal/publish.os/blog/page.tsx +76 -0
- package/init/seed/minimal/publish.os/components/blog/copy-link.tsx +64 -0
- package/init/seed/minimal/publish.os/docs/content/get-started.mdx +6 -11
- package/init/seed/minimal/publish.os/docs/content/groups.mdx +6 -7
- package/init/seed/minimal/publish.os/docs/content/{theme.mdx → themes.mdx} +14 -12
- package/init/seed/minimal/publish.os/publish.os.config.json +7 -7
- package/init/seed/minimal/publish.os/theme.css +52 -24
- package/init/seed/minimal/publish.os/tsconfig.json +3 -0
- package/init/seed/minimal/seed.json +12 -2
- package/init/seed/scratch/publish.os/docs/content/get-started.mdx +6 -0
- package/init/seed/scratch/publish.os/publish.os.config.json +4 -0
- package/init/seed/scratch/seed.json +5 -0
- package/package.json +55 -44
- package/release/app/phosphor/package.json +5 -5
- package/release/app/phosphor/pnpm-lock.yaml.template +553 -377
- package/release/app/phosphor/pnpm-workspace.yaml +3 -0
- package/release/compiler/package.json +5 -3
- package/release/compiler/pnpm-lock.yaml.template +500 -303
- package/release/compiler/pnpm-workspace.yaml +3 -0
- package/release/release.json +8 -37
- package/compiler-assets/nextjs/defaults/group/leaf.tsx +0 -48
- package/dist/icons.d.ts +0 -1
- package/dist/icons.js +0 -2
- package/dist/kernel/components/blocks/design-system-preview.d.ts +0 -61
- package/dist/kernel/components/blocks/design-system-preview.js +0 -648
- package/dist/kernel/components/blocks/link-playground.d.ts +0 -5
- package/dist/kernel/components/blocks/link-playground.js +0 -744
- package/dist/kernel/components/blocks/navigation-progress-playground.d.ts +0 -5
- package/dist/kernel/components/blocks/navigation-progress-playground.js +0 -629
- package/dist/kernel/components/mdx/components/pre.d.ts +0 -6
- package/dist/kernel/components/mdx/components/pre.js +0 -18
- package/dist/kernel/components/ui/meta-key.d.ts +0 -17
- package/dist/kernel/components/ui/meta-key.js +0 -9
- package/dist/kernel/components/ui/theme-toggle.d.ts +0 -24
- package/dist/kernel/components/ui/theme-toggle.js +0 -58
- package/dist/kernel/framework-icons.d.ts +0 -1
- package/dist/kernel/framework-icons.js +0 -39
- package/dist/link-CYaCRDb6.d.ts +0 -35
- package/release/app/lucide/package.json +0 -30
- package/release/app/lucide/pnpm-lock.yaml.template +0 -2905
- package/release/app/lucide/pnpm-workspace.yaml +0 -11
- package/release/app/tabler/package.json +0 -30
- package/release/app/tabler/pnpm-lock.yaml.template +0 -2911
- package/release/app/tabler/pnpm-workspace.yaml +0 -11
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Link } from "@components/ui/link";
|
|
2
|
+
import type { NotFoundScope } from "@publish.os/nextjs/kernel/routes/not-found";
|
|
3
|
+
|
|
4
|
+
export default function NotFoundContent({ scope }: { scope: NotFoundScope }) {
|
|
5
|
+
const sections = [
|
|
6
|
+
{ title: "Recommendations", links: scope.recommendations },
|
|
7
|
+
{ title: "For crawlers and agents", links: scope.indexes },
|
|
8
|
+
];
|
|
9
|
+
return (
|
|
10
|
+
<section
|
|
11
|
+
className="mx-auto flex w-full max-w-xl flex-1 flex-col items-center justify-center px-6 py-16 font-main sm:px-8 sm:py-24"
|
|
12
|
+
data-publishos-not-found={scope.id}
|
|
13
|
+
>
|
|
14
|
+
<h1 className="text-center font-mono text-8xl leading-none font-medium tracking-tight text-foreground-1 sm:text-9xl">
|
|
15
|
+
404<span className="sr-only"> — Page not found</span>
|
|
16
|
+
</h1>
|
|
17
|
+
<p className="mt-6 max-w-md text-center text-sm leading-6 text-pretty text-foreground-3">
|
|
18
|
+
This page does not exist. Please check the URL and try again.
|
|
19
|
+
</p>
|
|
20
|
+
<div className="mt-10 w-full space-y-8">
|
|
21
|
+
{sections.map(({ title, links }) =>
|
|
22
|
+
links.length ? (
|
|
23
|
+
<section aria-label={title} key={title}>
|
|
24
|
+
<h2 className="text-xs font-medium text-foreground-3">{title}</h2>
|
|
25
|
+
<ul className="mt-2 space-y-0">
|
|
26
|
+
{links.map((link) => (
|
|
27
|
+
<li className="flex items-baseline gap-3" key={link.href}>
|
|
28
|
+
<span
|
|
29
|
+
aria-hidden="true"
|
|
30
|
+
className="shrink-0 text-sm text-foreground-3"
|
|
31
|
+
>
|
|
32
|
+
-
|
|
33
|
+
</span>
|
|
34
|
+
<Link
|
|
35
|
+
className="inline-flex min-h-10 min-w-0 max-w-full items-center py-1 text-start wrap-anywhere"
|
|
36
|
+
href={link.href}
|
|
37
|
+
prefetch={false}
|
|
38
|
+
size="sm"
|
|
39
|
+
target="_self"
|
|
40
|
+
variant="link.inline"
|
|
41
|
+
>
|
|
42
|
+
{link.title}
|
|
43
|
+
</Link>
|
|
44
|
+
</li>
|
|
45
|
+
))}
|
|
46
|
+
</ul>
|
|
47
|
+
</section>
|
|
48
|
+
) : null,
|
|
49
|
+
)}
|
|
50
|
+
</div>
|
|
51
|
+
</section>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { MouseEvent, ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
/** Next's routing-level error document has no app-router tree to navigate from. */
|
|
6
|
+
export default function NotFoundNavigation({
|
|
7
|
+
children,
|
|
8
|
+
}: {
|
|
9
|
+
children: ReactNode;
|
|
10
|
+
}) {
|
|
11
|
+
function navigate(event: MouseEvent<HTMLDivElement>) {
|
|
12
|
+
if (
|
|
13
|
+
event.defaultPrevented ||
|
|
14
|
+
event.button !== 0 ||
|
|
15
|
+
event.altKey ||
|
|
16
|
+
event.ctrlKey ||
|
|
17
|
+
event.metaKey ||
|
|
18
|
+
event.shiftKey
|
|
19
|
+
)
|
|
20
|
+
return;
|
|
21
|
+
|
|
22
|
+
const target = event.target as Node;
|
|
23
|
+
const element =
|
|
24
|
+
target.nodeType === 1 ? (target as Element) : target.parentElement;
|
|
25
|
+
const link = element?.closest<HTMLAnchorElement>("a[href]");
|
|
26
|
+
const view = event.currentTarget.ownerDocument.defaultView;
|
|
27
|
+
if (
|
|
28
|
+
!link ||
|
|
29
|
+
!view ||
|
|
30
|
+
link.hasAttribute("download") ||
|
|
31
|
+
(link.target && link.target !== "_self")
|
|
32
|
+
)
|
|
33
|
+
return;
|
|
34
|
+
|
|
35
|
+
let destination: URL;
|
|
36
|
+
try {
|
|
37
|
+
destination = new URL(link.href, view.location.href);
|
|
38
|
+
} catch {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (
|
|
42
|
+
!["http:", "https:"].includes(destination.protocol) ||
|
|
43
|
+
destination.origin !== view.location.origin ||
|
|
44
|
+
(destination.pathname === view.location.pathname &&
|
|
45
|
+
destination.search === view.location.search &&
|
|
46
|
+
destination.hash)
|
|
47
|
+
)
|
|
48
|
+
return;
|
|
49
|
+
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
event.stopPropagation();
|
|
52
|
+
view.location.assign(destination.href);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div className="contents" onClickCapture={navigate}>
|
|
57
|
+
{children}
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createNotFoundTextResponse,
|
|
3
|
+
resolveNotFoundScope,
|
|
4
|
+
} from "@publish.os/nextjs/kernel/routes/not-found";
|
|
1
5
|
import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
|
|
2
6
|
import type { NextRequest } from "next/server";
|
|
3
7
|
import { NextResponse } from "next/server";
|
|
@@ -5,8 +9,12 @@ import { NextResponse } from "next/server";
|
|
|
5
9
|
const AGENT_USER_AGENT_PATTERN =
|
|
6
10
|
/\b(?:axios|got|node-fetch|undici|curl|wget|python-requests|httpx|aiohttp|claude-code|claudebot|claude|cursor|chatgpt|openai|perplexity|anthropic-ai)\b/i;
|
|
7
11
|
const INTERNAL_MARKDOWN_PREFIX = "/__publishos/md";
|
|
8
|
-
const
|
|
12
|
+
const FRAMEWORK_PREFIX = "__PUBLISHOS_FRAMEWORK_PREFIX__";
|
|
9
13
|
const TEXT_METHODS = new Set(["GET", "HEAD"]);
|
|
14
|
+
const PUBLIC_PATHS = new Set<string>(agentRouteConfig.publicPaths);
|
|
15
|
+
const MARKDOWN_PATHS = new Set<string>(agentRouteConfig.markdownPaths);
|
|
16
|
+
const OUTPUT_PATHS = new Set<string>(agentRouteConfig.outputPaths);
|
|
17
|
+
const NOT_FOUND_SCOPE_HEADER = "x-publishos-not-found-scope";
|
|
10
18
|
|
|
11
19
|
function debugAgentRoute(
|
|
12
20
|
event: string,
|
|
@@ -46,29 +54,6 @@ function markdownAlternatePath(pathname: string): string {
|
|
|
46
54
|
return normalized.endsWith(".md") ? normalized : `${normalized}.md`;
|
|
47
55
|
}
|
|
48
56
|
|
|
49
|
-
function markdownNotFoundBody(): string {
|
|
50
|
-
const links = [
|
|
51
|
-
agentRouteConfig.discoveryLinks.home
|
|
52
|
-
? `> Home: ${agentRouteConfig.discoveryLinks.home}`
|
|
53
|
-
: undefined,
|
|
54
|
-
agentRouteConfig.discoveryLinks.sitemap
|
|
55
|
-
? `> Sitemap: ${agentRouteConfig.discoveryLinks.sitemap}`
|
|
56
|
-
: undefined,
|
|
57
|
-
agentRouteConfig.discoveryLinks.llms
|
|
58
|
-
? `> LLMS index: ${agentRouteConfig.discoveryLinks.llms}`
|
|
59
|
-
: undefined,
|
|
60
|
-
].filter((line): line is string => Boolean(line));
|
|
61
|
-
|
|
62
|
-
return [
|
|
63
|
-
"# Not found",
|
|
64
|
-
"",
|
|
65
|
-
...links,
|
|
66
|
-
"",
|
|
67
|
-
"The requested Markdown page was not found.",
|
|
68
|
-
"",
|
|
69
|
-
].join("\n");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
57
|
function explicitAcceptQuality(accept: string, mimeType: string): number {
|
|
73
58
|
if (!accept) return 0;
|
|
74
59
|
|
|
@@ -100,8 +85,10 @@ function explicitAcceptQuality(accept: string, mimeType: string): number {
|
|
|
100
85
|
return bestQuality;
|
|
101
86
|
}
|
|
102
87
|
|
|
103
|
-
function
|
|
104
|
-
|
|
88
|
+
function negotiatedTextType(
|
|
89
|
+
request: NextRequest,
|
|
90
|
+
): "text/markdown; charset=utf-8" | "text/plain; charset=utf-8" | undefined {
|
|
91
|
+
if (!TEXT_METHODS.has(request.method)) return undefined;
|
|
105
92
|
|
|
106
93
|
const accept = request.headers.get("accept") ?? "";
|
|
107
94
|
const markdownQuality = agentRouteConfig.markdownAccept
|
|
@@ -112,12 +99,13 @@ function wantsMarkdown(request: NextRequest): boolean {
|
|
|
112
99
|
: 0;
|
|
113
100
|
const htmlQuality = explicitAcceptQuality(accept, "text/html");
|
|
114
101
|
|
|
115
|
-
if (markdownQuality > 0 && markdownQuality >= htmlQuality)
|
|
102
|
+
if (markdownQuality > 0 && markdownQuality >= htmlQuality) {
|
|
103
|
+
return "text/markdown; charset=utf-8";
|
|
104
|
+
}
|
|
116
105
|
if (plainQuality > 0 && htmlQuality === 0 && markdownQuality === 0) {
|
|
117
|
-
return
|
|
106
|
+
return "text/plain; charset=utf-8";
|
|
118
107
|
}
|
|
119
|
-
|
|
120
|
-
return false;
|
|
108
|
+
return undefined;
|
|
121
109
|
}
|
|
122
110
|
|
|
123
111
|
function looksLikeAgent(request: NextRequest): boolean {
|
|
@@ -139,7 +127,7 @@ function markdownRequestReason(
|
|
|
139
127
|
) {
|
|
140
128
|
return "extension";
|
|
141
129
|
}
|
|
142
|
-
if (
|
|
130
|
+
if (negotiatedTextType(request)) return "accept";
|
|
143
131
|
if (looksLikeAgent(request)) return "agent";
|
|
144
132
|
return undefined;
|
|
145
133
|
}
|
|
@@ -152,13 +140,11 @@ function isInternalMarkdownRoute(pathname: string): boolean {
|
|
|
152
140
|
}
|
|
153
141
|
|
|
154
142
|
function isStaticOrMetadataRoute(pathname: string): boolean {
|
|
143
|
+
if (OUTPUT_PATHS.has(normalizePagePath(pathname))) return true;
|
|
155
144
|
if (
|
|
156
|
-
pathname
|
|
157
|
-
pathname.startsWith(
|
|
158
|
-
pathname.startsWith("/
|
|
159
|
-
pathname.startsWith("/_publishos/logo/") ||
|
|
160
|
-
pathname.startsWith("/_publishos/og/") ||
|
|
161
|
-
pathname.startsWith("/assets/")
|
|
145
|
+
pathname === FRAMEWORK_PREFIX ||
|
|
146
|
+
pathname.startsWith(`${FRAMEWORK_PREFIX}/`) ||
|
|
147
|
+
pathname.startsWith("/_next/")
|
|
162
148
|
) {
|
|
163
149
|
return true;
|
|
164
150
|
}
|
|
@@ -176,21 +162,29 @@ function isStaticOrMetadataRoute(pathname: string): boolean {
|
|
|
176
162
|
return true;
|
|
177
163
|
}
|
|
178
164
|
|
|
179
|
-
return
|
|
165
|
+
return false;
|
|
180
166
|
}
|
|
181
167
|
|
|
182
|
-
function rewriteToMarkdown(
|
|
183
|
-
request
|
|
184
|
-
reason
|
|
185
|
-
|
|
186
|
-
|
|
168
|
+
function rewriteToMarkdown({
|
|
169
|
+
request,
|
|
170
|
+
reason,
|
|
171
|
+
requestHeaders,
|
|
172
|
+
}: {
|
|
173
|
+
request: NextRequest;
|
|
174
|
+
reason: "accept" | "agent" | "extension";
|
|
175
|
+
requestHeaders: Headers;
|
|
176
|
+
}): NextResponse {
|
|
177
|
+
const url = new URL(request.url);
|
|
187
178
|
url.pathname =
|
|
188
179
|
normalizePagePath(url.pathname) === "/"
|
|
189
180
|
? "/sitemap.md"
|
|
190
181
|
: markdownRoutePath(url.pathname);
|
|
182
|
+
const revision = request.nextUrl.searchParams.get("publishos_revision");
|
|
183
|
+
url.search = "";
|
|
184
|
+
url.hash = "";
|
|
185
|
+
if (revision) url.searchParams.set("publishos_revision", revision);
|
|
191
186
|
|
|
192
|
-
|
|
193
|
-
requestHeaders.set("x-publishos-agent-route", "markdown");
|
|
187
|
+
requestHeaders.set("accept", "text/markdown");
|
|
194
188
|
|
|
195
189
|
debugAgentRoute("md", {
|
|
196
190
|
accept: request.headers.get("accept") ?? undefined,
|
|
@@ -242,18 +236,28 @@ function withDiscoveryHeaders(
|
|
|
242
236
|
|
|
243
237
|
export function proxy(request: NextRequest) {
|
|
244
238
|
const { pathname } = request.nextUrl;
|
|
239
|
+
const requestHeaders = new Headers(request.headers);
|
|
240
|
+
requestHeaders.delete(NOT_FOUND_SCOPE_HEADER);
|
|
241
|
+
requestHeaders.delete("x-publishos-agent-route");
|
|
242
|
+
|
|
243
|
+
if (pathname === "/_not-found") {
|
|
244
|
+
requestHeaders.set(NOT_FOUND_SCOPE_HEADER, "none");
|
|
245
|
+
const response = NextResponse.next({
|
|
246
|
+
request: { headers: requestHeaders },
|
|
247
|
+
});
|
|
248
|
+
response.headers.set("x-robots-tag", "noindex");
|
|
249
|
+
response.headers.set("vary", "Accept, User-Agent");
|
|
250
|
+
return response;
|
|
251
|
+
}
|
|
245
252
|
|
|
246
253
|
if (isInternalMarkdownRoute(pathname)) {
|
|
247
|
-
if (request.headers.get("x-publishos-agent-route") === "markdown") {
|
|
248
|
-
return NextResponse.next();
|
|
249
|
-
}
|
|
250
254
|
if (!agentRouteConfig.blockInternalMarkdownRoute) {
|
|
251
255
|
debugAgentRoute("pass", {
|
|
252
256
|
method: request.method,
|
|
253
257
|
path: pathname,
|
|
254
258
|
reason: "allowed-internal",
|
|
255
259
|
});
|
|
256
|
-
return NextResponse.next();
|
|
260
|
+
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
257
261
|
}
|
|
258
262
|
|
|
259
263
|
debugAgentRoute("md", {
|
|
@@ -263,15 +267,7 @@ export function proxy(request: NextRequest) {
|
|
|
263
267
|
status: 404,
|
|
264
268
|
});
|
|
265
269
|
|
|
266
|
-
return
|
|
267
|
-
status: 404,
|
|
268
|
-
headers: {
|
|
269
|
-
"cache-control": "public, max-age=60, s-maxage=300",
|
|
270
|
-
"content-type": "text/markdown; charset=utf-8",
|
|
271
|
-
"x-content-type-options": "nosniff",
|
|
272
|
-
"x-robots-tag": "noindex",
|
|
273
|
-
},
|
|
274
|
-
});
|
|
270
|
+
return createNotFoundTextResponse({ method: request.method });
|
|
275
271
|
}
|
|
276
272
|
|
|
277
273
|
if (isStaticOrMetadataRoute(pathname)) {
|
|
@@ -280,12 +276,93 @@ export function proxy(request: NextRequest) {
|
|
|
280
276
|
path: pathname,
|
|
281
277
|
reason: "static-or-metadata",
|
|
282
278
|
});
|
|
283
|
-
return NextResponse.next();
|
|
279
|
+
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
284
280
|
}
|
|
285
281
|
|
|
286
282
|
const markdownReason = markdownRequestReason(request);
|
|
287
283
|
if (markdownReason) {
|
|
288
|
-
|
|
284
|
+
let htmlPath: string | undefined;
|
|
285
|
+
try {
|
|
286
|
+
const decoded = normalizePagePath(decodeURIComponent(pathname));
|
|
287
|
+
htmlPath = decoded.endsWith(".md")
|
|
288
|
+
? decoded.slice(0, -3) || "/"
|
|
289
|
+
: decoded;
|
|
290
|
+
} catch {
|
|
291
|
+
htmlPath = undefined;
|
|
292
|
+
}
|
|
293
|
+
const scope = resolveNotFoundScope({
|
|
294
|
+
scopes: agentRouteConfig.notFoundScopes,
|
|
295
|
+
pathname,
|
|
296
|
+
});
|
|
297
|
+
const hasArtifact =
|
|
298
|
+
htmlPath === "/"
|
|
299
|
+
? OUTPUT_PATHS.has("/sitemap.md")
|
|
300
|
+
: htmlPath !== undefined && MARKDOWN_PATHS.has(htmlPath);
|
|
301
|
+
if (!scope || !hasArtifact) {
|
|
302
|
+
const response = createNotFoundTextResponse({
|
|
303
|
+
scope,
|
|
304
|
+
pathname,
|
|
305
|
+
method: request.method,
|
|
306
|
+
contentType:
|
|
307
|
+
markdownReason === "accept" ? negotiatedTextType(request) : undefined,
|
|
308
|
+
vary: markdownReason !== "extension",
|
|
309
|
+
});
|
|
310
|
+
if (!agentRouteConfig.enabled || !agentRouteConfig.discoveryHeaders) {
|
|
311
|
+
for (const name of [
|
|
312
|
+
"link",
|
|
313
|
+
"x-publishos-llms",
|
|
314
|
+
"x-publishos-sitemap",
|
|
315
|
+
]) {
|
|
316
|
+
response.headers.delete(name);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return response;
|
|
320
|
+
}
|
|
321
|
+
return rewriteToMarkdown({
|
|
322
|
+
request,
|
|
323
|
+
reason: markdownReason,
|
|
324
|
+
requestHeaders,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
let pagePath: string;
|
|
329
|
+
try {
|
|
330
|
+
pagePath = normalizePagePath(decodeURIComponent(pathname));
|
|
331
|
+
} catch {
|
|
332
|
+
pagePath = pathname;
|
|
333
|
+
}
|
|
334
|
+
if (!PUBLIC_PATHS.has(pagePath)) {
|
|
335
|
+
// Select Next's error route before an unknown catch-all can stream.
|
|
336
|
+
const scope = resolveNotFoundScope({
|
|
337
|
+
scopes: agentRouteConfig.notFoundScopes,
|
|
338
|
+
pathname,
|
|
339
|
+
});
|
|
340
|
+
requestHeaders.set(NOT_FOUND_SCOPE_HEADER, scope?.id ?? "none");
|
|
341
|
+
const url = new URL(request.url);
|
|
342
|
+
url.pathname = "/_not-found";
|
|
343
|
+
url.search = "";
|
|
344
|
+
url.hash = "";
|
|
345
|
+
const response = NextResponse.rewrite(url, {
|
|
346
|
+
status: 404,
|
|
347
|
+
request: { headers: requestHeaders },
|
|
348
|
+
});
|
|
349
|
+
const recoveryHeaders = createNotFoundTextResponse({
|
|
350
|
+
scope,
|
|
351
|
+
pathname,
|
|
352
|
+
method: request.method,
|
|
353
|
+
vary: true,
|
|
354
|
+
}).headers;
|
|
355
|
+
for (const name of [
|
|
356
|
+
"x-robots-tag",
|
|
357
|
+
"vary",
|
|
358
|
+
...(agentRouteConfig.enabled && agentRouteConfig.discoveryHeaders
|
|
359
|
+
? ["link", "x-publishos-llms", "x-publishos-sitemap"]
|
|
360
|
+
: []),
|
|
361
|
+
]) {
|
|
362
|
+
const value = recoveryHeaders.get(name);
|
|
363
|
+
if (value) response.headers.set(name, value);
|
|
364
|
+
}
|
|
365
|
+
return response;
|
|
289
366
|
}
|
|
290
367
|
|
|
291
368
|
if (!agentRouteConfig.enabled || !agentRouteConfig.discoveryHeaders) {
|
|
@@ -296,7 +373,7 @@ export function proxy(request: NextRequest) {
|
|
|
296
373
|
? "discovery-disabled"
|
|
297
374
|
: "agent-routes-disabled",
|
|
298
375
|
});
|
|
299
|
-
return NextResponse.next();
|
|
376
|
+
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
300
377
|
}
|
|
301
378
|
|
|
302
379
|
debugAgentRoute("html", {
|
|
@@ -307,11 +384,12 @@ export function proxy(request: NextRequest) {
|
|
|
307
384
|
userAgent: request.headers.get("user-agent") ?? undefined,
|
|
308
385
|
});
|
|
309
386
|
|
|
310
|
-
return withDiscoveryHeaders(
|
|
387
|
+
return withDiscoveryHeaders(
|
|
388
|
+
NextResponse.next({ request: { headers: requestHeaders } }),
|
|
389
|
+
pathname,
|
|
390
|
+
);
|
|
311
391
|
}
|
|
312
392
|
|
|
313
393
|
export const config = {
|
|
314
|
-
matcher: [
|
|
315
|
-
"/((?!_next/static|_next/image|_next/webpack-hmr|_publishos/assets|_publishos/favicon|_publishos/logo|_publishos/og|assets).*)",
|
|
316
|
-
],
|
|
394
|
+
matcher: ["/__PUBLISHOS_MATCHER__"],
|
|
317
395
|
};
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
ROOT_FORCED_MODE,
|
|
7
7
|
routeThemes,
|
|
8
8
|
} from "@source/.theme.generated";
|
|
9
|
-
import {
|
|
9
|
+
import { usePathname } from "next/navigation";
|
|
10
10
|
import { ThemeProvider as NextThemes } from "next-themes";
|
|
11
|
-
import type
|
|
11
|
+
import { type ReactNode, Suspense, useLayoutEffect, useState } from "react";
|
|
12
12
|
|
|
13
13
|
type ForcedMode = "dark" | "light" | "none";
|
|
14
14
|
type RouteTheme = {
|
|
@@ -16,24 +16,20 @@ type RouteTheme = {
|
|
|
16
16
|
forcedMode?: ForcedMode;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
-
function selectedPathFromSegments(segments: readonly string[]): string {
|
|
20
|
-
const path = segments
|
|
21
|
-
.filter((segment) => segment !== "" && !segment.startsWith("("))
|
|
22
|
-
.join("/");
|
|
23
|
-
|
|
24
|
-
return path ? `/${path}` : "/";
|
|
25
|
-
}
|
|
26
|
-
|
|
27
19
|
function resolveRouteTheme(
|
|
28
|
-
|
|
20
|
+
pathname: string,
|
|
21
|
+
themes: Readonly<Record<string, RouteTheme>>,
|
|
29
22
|
): RouteTheme | undefined {
|
|
30
|
-
const selectedPath = selectedPathFromSegments(segments);
|
|
31
23
|
let match: RouteTheme | undefined;
|
|
32
24
|
let matchLength = 0;
|
|
33
25
|
|
|
34
|
-
const entries = Object.entries(
|
|
26
|
+
const entries = Object.entries(themes);
|
|
35
27
|
for (const [basePath, routeTheme] of entries) {
|
|
36
|
-
if (
|
|
28
|
+
if (
|
|
29
|
+
basePath === "/" ||
|
|
30
|
+
pathname === basePath ||
|
|
31
|
+
pathname.startsWith(`${basePath}/`)
|
|
32
|
+
) {
|
|
37
33
|
if (basePath.length > matchLength) {
|
|
38
34
|
match = routeTheme;
|
|
39
35
|
matchLength = basePath.length;
|
|
@@ -50,8 +46,57 @@ function effectiveForcedMode(routeTheme: RouteTheme | undefined): ForcedMode {
|
|
|
50
46
|
return ROOT_FORCED_MODE ?? "none";
|
|
51
47
|
}
|
|
52
48
|
|
|
49
|
+
function RouteThemeSync({
|
|
50
|
+
onChange,
|
|
51
|
+
}: {
|
|
52
|
+
onChange: (theme: RouteTheme | undefined) => void;
|
|
53
|
+
}) {
|
|
54
|
+
const routeTheme = resolveRouteTheme(usePathname(), routeThemes);
|
|
55
|
+
useLayoutEffect(() => onChange(routeTheme), [onChange, routeTheme]);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function initialRouteTheme(): RouteTheme | undefined {
|
|
60
|
+
return typeof window === "undefined"
|
|
61
|
+
? undefined
|
|
62
|
+
: resolveRouteTheme(window.location.pathname, routeThemes);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Both bootstrap and hydration use the same compiler-generated route mapping.
|
|
66
|
+
const initialThemeScript = `{
|
|
67
|
+
const route = (${resolveRouteTheme.toString()})(location.pathname, ${JSON.stringify(routeThemes).replaceAll("<", "\\u003c")});
|
|
68
|
+
document.currentScript.parentElement.setAttribute("data-group", route?.group ?? "");
|
|
69
|
+
const forcedMode = route?.forcedMode ?? ${JSON.stringify(ROOT_FORCED_MODE) ?? "undefined"};
|
|
70
|
+
let mode = ${JSON.stringify(ROOT_DEFAULT_MODE)};
|
|
71
|
+
try { mode = localStorage.getItem("theme") || mode; } catch {}
|
|
72
|
+
if (forcedMode && forcedMode !== "none") mode = forcedMode;
|
|
73
|
+
if (mode === "system") mode = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
74
|
+
if (mode === "light" || mode === "dark") {
|
|
75
|
+
const root = document.documentElement;
|
|
76
|
+
root.classList.remove("light", "dark");
|
|
77
|
+
root.classList.add(mode);
|
|
78
|
+
root.style.colorScheme = mode;
|
|
79
|
+
}
|
|
80
|
+
}`;
|
|
81
|
+
|
|
82
|
+
export function PublishOSThemeScope({
|
|
83
|
+
children,
|
|
84
|
+
group,
|
|
85
|
+
}: {
|
|
86
|
+
children: ReactNode;
|
|
87
|
+
group: string;
|
|
88
|
+
}) {
|
|
89
|
+
return (
|
|
90
|
+
<ThemeScopeProvider group={group}>
|
|
91
|
+
<div className="contents" data-theme-root="" data-group={group}>
|
|
92
|
+
{children}
|
|
93
|
+
</div>
|
|
94
|
+
</ThemeScopeProvider>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
53
98
|
export function PublishOSThemeProvider({ children }: { children: ReactNode }) {
|
|
54
|
-
const routeTheme =
|
|
99
|
+
const [routeTheme, setRouteTheme] = useState(initialRouteTheme);
|
|
55
100
|
const forcedMode = effectiveForcedMode(routeTheme);
|
|
56
101
|
const forcedTheme = forcedMode === "none" ? undefined : forcedMode;
|
|
57
102
|
|
|
@@ -62,13 +107,29 @@ export function PublishOSThemeProvider({ children }: { children: ReactNode }) {
|
|
|
62
107
|
disableTransitionOnChange
|
|
63
108
|
enableSystem
|
|
64
109
|
forcedTheme={forcedTheme}
|
|
110
|
+
scriptProps={{
|
|
111
|
+
type: typeof window === "undefined" ? "text/javascript" : "text/plain",
|
|
112
|
+
}}
|
|
65
113
|
>
|
|
66
114
|
<ThemeScopeProvider group={routeTheme?.group}>
|
|
67
115
|
<div
|
|
68
116
|
className="contents"
|
|
117
|
+
id="publish-os-theme-root"
|
|
69
118
|
data-theme-root=""
|
|
70
119
|
data-group={routeTheme?.group ?? ""}
|
|
120
|
+
suppressHydrationWarning
|
|
71
121
|
>
|
|
122
|
+
<script
|
|
123
|
+
type={
|
|
124
|
+
typeof window === "undefined" ? "text/javascript" : "text/plain"
|
|
125
|
+
}
|
|
126
|
+
suppressHydrationWarning
|
|
127
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: Compiler-only route metadata escapes HTML; the script must run before paint.
|
|
128
|
+
dangerouslySetInnerHTML={{ __html: initialThemeScript }}
|
|
129
|
+
/>
|
|
130
|
+
<Suspense fallback={null}>
|
|
131
|
+
<RouteThemeSync onChange={setRouteTheme} />
|
|
132
|
+
</Suspense>
|
|
72
133
|
{children}
|
|
73
134
|
</div>
|
|
74
135
|
</ThemeScopeProvider>
|
|
@@ -4,10 +4,16 @@ import {
|
|
|
4
4
|
createRootPage,
|
|
5
5
|
} from "@publish.os/nextjs/kernel/routes/pages/root";
|
|
6
6
|
import { ogManifest } from "@source/.publishos/og-manifest.generated";
|
|
7
|
-
import RootPage from "@source/
|
|
7
|
+
import RootPage from "@source/index";
|
|
8
8
|
import type { Metadata } from "next";
|
|
9
9
|
|
|
10
10
|
const route = { manifest, ogManifest, RootPage } as const;
|
|
11
11
|
|
|
12
12
|
export default createRootPage(route);
|
|
13
13
|
export const metadata: Metadata = createRootMetadata(route);
|
|
14
|
+
|
|
15
|
+
export const ensureStatic = "navigation";
|
|
16
|
+
|
|
17
|
+
// Next 16.4 still misclassifies redirect() during instant validation.
|
|
18
|
+
// Keep its HTTP response; ensureStatic independently validates prerendering.
|
|
19
|
+
export const instant = false;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CodeBlock } from "@components/mdx/code-block";
|
|
2
|
+
import { type HTMLAttributes, isValidElement, type ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
type CodeChildProps = {
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
className?: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function FencedCodeBlock({
|
|
11
|
+
children,
|
|
12
|
+
title,
|
|
13
|
+
...props
|
|
14
|
+
}: HTMLAttributes<HTMLElement>) {
|
|
15
|
+
const codeElement = isValidElement<CodeChildProps>(children)
|
|
16
|
+
? children
|
|
17
|
+
: null;
|
|
18
|
+
const code = codeElement?.props.children ?? children;
|
|
19
|
+
const language = /(?:^|\s)language-([^\s]+)/.exec(
|
|
20
|
+
codeElement?.props.className ?? "",
|
|
21
|
+
)?.[1];
|
|
22
|
+
return (
|
|
23
|
+
<CodeBlock
|
|
24
|
+
{...props}
|
|
25
|
+
code={typeof code === "string" ? code : ""}
|
|
26
|
+
language={language}
|
|
27
|
+
title={title ?? codeElement?.props.title}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ComponentType, HTMLAttributes } from "react";
|
|
2
|
+
|
|
3
|
+
type HeadingTag = "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
|
|
4
|
+
|
|
5
|
+
export function headingWithLevel(
|
|
6
|
+
Heading: ComponentType<
|
|
7
|
+
{ as: HeadingTag } & HTMLAttributes<HTMLHeadingElement>
|
|
8
|
+
>,
|
|
9
|
+
as: HeadingTag,
|
|
10
|
+
) {
|
|
11
|
+
return function HeadingLevel(props: HTMLAttributes<HTMLHeadingElement>) {
|
|
12
|
+
return <Heading as={as} {...props} />;
|
|
13
|
+
};
|
|
14
|
+
}
|