@publish.os/nextjs 0.0.1-alpha.90 → 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.
Files changed (223) hide show
  1. package/compiler-assets/nextjs/defaults/group/layout.tsx +1 -5
  2. package/compiler-assets/nextjs/defaults/group/page.tsx +31 -22
  3. package/compiler-assets/nextjs/defaults/project/next.config.mjs +19 -10
  4. package/compiler-assets/nextjs/defaults/project/tsconfig.json.template +10 -0
  5. package/compiler-assets/nextjs/defaults/root/css/components/code-block.css +18 -0
  6. package/compiler-assets/nextjs/shims/document.tsx +38 -0
  7. package/compiler-assets/nextjs/shims/generated-leaf-page.tsx +2 -0
  8. package/compiler-assets/nextjs/shims/global-layout.tsx +8 -42
  9. package/compiler-assets/nextjs/shims/global-not-found.tsx +69 -0
  10. package/compiler-assets/nextjs/shims/markdown-route.ts +2 -0
  11. package/compiler-assets/nextjs/shims/metadata-icons.tsx +39 -0
  12. package/compiler-assets/nextjs/shims/not-found-content.tsx +53 -0
  13. package/compiler-assets/nextjs/shims/not-found-navigation.tsx +60 -0
  14. package/compiler-assets/nextjs/shims/proxy.ts +126 -60
  15. package/compiler-assets/nextjs/shims/site-fenced-code-block.tsx +2 -6
  16. package/compiler-assets/nextjs/shims/site-mdx-components.tsx +28 -16
  17. package/compiler-assets/nextjs/shims/site-mdx.tsx +6 -1
  18. package/dist/{build-operation-2JAYBSKF.js → build-operation-5QMLXF7N.js} +29 -23
  19. package/dist/{button-c3WGnxIj.d.ts → button-BdCScEKi.d.ts} +3 -3
  20. package/dist/capture-local-source-WGGDIUU2.js +258 -0
  21. package/dist/chunk-22RSSUNV.js +13 -0
  22. package/dist/{chunk-WKTEO6RS.js → chunk-4BC2L2KA.js} +46 -12
  23. package/dist/{chunk-WDY4IK6Z.js → chunk-5J3YUNRY.js} +3 -10
  24. package/dist/chunk-5KAD7W53.js +248 -0
  25. package/dist/{chunk-DWA3ZRGW.js → chunk-6C65KV7O.js} +2 -2
  26. package/dist/{chunk-GGKFQ3MA.js → chunk-6D2E6UMD.js} +144 -70
  27. package/dist/{chunk-7OGTPSKI.js → chunk-7NY22B5U.js} +8 -3
  28. package/dist/chunk-EFO6AWXN.js +19 -0
  29. package/dist/{chunk-726GV2NF.js → chunk-F3AGNDF4.js} +100 -67
  30. package/dist/chunk-GBPLER5H.js +426 -0
  31. package/dist/chunk-IL4RJOKI.js +186 -0
  32. package/dist/{chunk-DLDFHU7Y.js → chunk-NNBJZPFM.js} +4 -2
  33. package/dist/{chunk-VO2I7MTM.js → chunk-ORIUWJBQ.js} +8 -6
  34. package/dist/{chunk-H6XILMZX.js → chunk-OXOFRXEI.js} +1806 -831
  35. package/dist/chunk-UYGCOWRF.js +1709 -0
  36. package/dist/{chunk-YLTOLYWM.js → chunk-WL75GQ5M.js} +6 -18
  37. package/dist/compiler.d.ts +15 -2
  38. package/dist/compiler.js +90 -21
  39. package/dist/components/blocks/agent-actions.d.ts +81 -0
  40. package/dist/components/blocks/agent-actions.js +594 -0
  41. package/dist/components/blocks/toc.d.ts +43 -0
  42. package/dist/components/blocks/toc.js +136 -0
  43. package/dist/components/ui/button.d.ts +5 -0
  44. package/dist/components/ui/button.js +94 -0
  45. package/dist/compose-CVBJRAF6.js +16 -0
  46. package/dist/config/createNextConfig.js +17 -3
  47. package/dist/{dev-operation-TZDVJCN7.js → dev-operation-OSHHWRWK.js} +121 -81
  48. package/dist/{framework-selection-X4U6Y6QC.js → framework-selection-ZVO323PK.js} +3 -2
  49. package/dist/ide-support-CU6Z5PVR.js +16 -0
  50. package/dist/index.d.ts +40 -1
  51. package/dist/jsx-dev-runtime.d.ts +6 -0
  52. package/dist/jsx-dev-runtime.js +100 -0
  53. package/dist/jsx-runtime.d.ts +7 -0
  54. package/dist/jsx-runtime.js +97 -0
  55. package/dist/kernel/components/blocks/AgentActions.d.ts +35 -6
  56. package/dist/kernel/components/blocks/AgentActions.js +383 -142
  57. package/dist/kernel/components/blocks/agent-actions.d.ts +5 -0
  58. package/dist/kernel/components/blocks/agent-actions.js +594 -0
  59. package/dist/kernel/components/blocks/animated-icon-swap.js +1 -1
  60. package/dist/kernel/components/blocks/color-palette.js +4 -4
  61. package/dist/kernel/components/blocks/logo-block.js +1 -1
  62. package/dist/kernel/components/blocks/nav-breadcrumb.js +2 -2
  63. package/dist/kernel/components/blocks/navbar.js +17 -17
  64. package/dist/kernel/components/blocks/navigation-progress.js +2 -2
  65. package/dist/kernel/components/blocks/next-prev.js +1 -1
  66. package/dist/kernel/components/blocks/page-list.js +2 -2
  67. package/dist/kernel/components/blocks/search.d.ts +1 -1
  68. package/dist/kernel/components/blocks/search.js +16 -17
  69. package/dist/kernel/components/blocks/sidebar-node.js +1 -1
  70. package/dist/kernel/components/blocks/sidebar.js +7 -4
  71. package/dist/kernel/components/blocks/theme-toggle.d.ts +1 -1
  72. package/dist/kernel/components/blocks/theme-toggle.js +5 -5
  73. package/dist/kernel/components/blocks/toc-client.d.ts +40 -0
  74. package/dist/kernel/components/blocks/toc-client.js +495 -0
  75. package/dist/kernel/components/blocks/toc.d.ts +19 -1
  76. package/dist/kernel/components/blocks/toc.js +121 -179
  77. package/dist/kernel/components/mdx/components/blockquote.js +1 -1
  78. package/dist/kernel/components/mdx/components/callout.js +1 -1
  79. package/dist/kernel/components/mdx/components/code-block.js +2 -2
  80. package/dist/kernel/components/mdx/components/copy-code-button.js +5 -4
  81. package/dist/kernel/components/mdx/components/figure-caption.d.ts +1 -1
  82. package/dist/kernel/components/mdx/components/figure-caption.js +3 -2
  83. package/dist/kernel/components/mdx/components/figure.d.ts +6 -2
  84. package/dist/kernel/components/mdx/components/figure.js +23 -13
  85. package/dist/kernel/components/mdx/components/footnotes.js +1 -1
  86. package/dist/kernel/components/mdx/components/heading-copy-link.js +1 -1
  87. package/dist/kernel/components/mdx/components/heading.js +6 -3
  88. package/dist/kernel/components/mdx/components/hr.js +2 -2
  89. package/dist/kernel/components/mdx/components/image-zoom.js +1 -1
  90. package/dist/kernel/components/mdx/components/image.d.ts +1 -1
  91. package/dist/kernel/components/mdx/components/image.js +21 -16
  92. package/dist/kernel/components/mdx/components/inline-code.js +1 -1
  93. package/dist/kernel/components/mdx/components/kbd.js +2 -2
  94. package/dist/kernel/components/mdx/components/link.d.ts +3 -3
  95. package/dist/kernel/components/mdx/components/link.js +2 -2
  96. package/dist/kernel/components/mdx/components/paragraph.js +1 -1
  97. package/dist/kernel/components/mdx/components/strikethrough.js +1 -1
  98. package/dist/kernel/components/mdx/components/table.js +2 -2
  99. package/dist/kernel/components/mdx/components/task-list.js +1 -1
  100. package/dist/kernel/components/mdx/components/video-player.d.ts +6 -2
  101. package/dist/kernel/components/mdx/components/video-player.js +6 -2
  102. package/dist/kernel/components/mdx/components/video.d.ts +5 -3
  103. package/dist/kernel/components/mdx/components/video.js +7 -5
  104. package/dist/kernel/components/mdx/error-boundary.d.ts +1 -1
  105. package/dist/kernel/components/mdx/error-boundary.js +2 -2
  106. package/dist/kernel/components/mdx/error-fallback.js +1 -1
  107. package/dist/kernel/components/mdx/mdx.d.ts +20 -10
  108. package/dist/kernel/components/mdx/mdx.js +231 -34
  109. package/dist/kernel/components/mdx/rehype-heading-ids.d.ts +1 -0
  110. package/dist/kernel/components/mdx/rehype-heading-ids.js +5 -3
  111. package/dist/kernel/components/mdx/types.d.ts +1 -1
  112. package/dist/kernel/components/next-image.d.ts +12 -0
  113. package/dist/kernel/components/next-image.js +61 -0
  114. package/dist/kernel/components/ui/accordion.js +1 -1
  115. package/dist/kernel/components/ui/breadcrumb-trail.d.ts +2 -2
  116. package/dist/kernel/components/ui/breadcrumb-trail.js +2 -2
  117. package/dist/kernel/components/ui/breadcrumb.d.ts +1 -1
  118. package/dist/kernel/components/ui/breadcrumb.js +4 -4
  119. package/dist/kernel/components/ui/button-group.d.ts +1 -1
  120. package/dist/kernel/components/ui/button-group.js +3 -3
  121. package/dist/kernel/components/ui/button.d.ts +56 -4
  122. package/dist/kernel/components/ui/button.js +43 -39
  123. package/dist/kernel/components/ui/card.js +1 -1
  124. package/dist/kernel/components/ui/dialog.js +1 -1
  125. package/dist/kernel/components/ui/drawer.js +1 -1
  126. package/dist/kernel/components/ui/input.d.ts +2 -2
  127. package/dist/kernel/components/ui/input.js +1 -1
  128. package/dist/kernel/components/ui/kbd.d.ts +1 -1
  129. package/dist/kernel/components/ui/kbd.js +1 -1
  130. package/dist/kernel/components/ui/link.d.ts +8 -2
  131. package/dist/kernel/components/ui/link.js +2 -2
  132. package/dist/kernel/components/ui/menu.js +1 -1
  133. package/dist/kernel/components/ui/mod-key.js +2 -2
  134. package/dist/kernel/components/ui/navigation-menu.js +1 -1
  135. package/dist/kernel/components/ui/popover.js +1 -1
  136. package/dist/kernel/components/ui/progress.js +1 -1
  137. package/dist/kernel/components/ui/scroll-area.d.ts +8 -8
  138. package/dist/kernel/components/ui/scroll-area.js +1 -1
  139. package/dist/kernel/components/ui/select.js +1 -1
  140. package/dist/kernel/components/ui/separator.js +1 -1
  141. package/dist/kernel/components/ui/table.js +1 -1
  142. package/dist/kernel/components/ui/tabs.js +1 -1
  143. package/dist/kernel/components/ui/tag.js +1 -1
  144. package/dist/kernel/components/ui/text.d.ts +1 -1
  145. package/dist/kernel/components/ui/text.js +1 -1
  146. package/dist/kernel/components/ui/toast.js +1 -1
  147. package/dist/kernel/components/ui/tooltip.js +1 -1
  148. package/dist/kernel/defaults.registry.d.ts +2 -15
  149. package/dist/kernel/defaults.registry.js +2 -17
  150. package/dist/kernel/routes/agent/markdown.d.ts +3 -0
  151. package/dist/kernel/routes/agent/markdown.js +219 -48
  152. package/dist/kernel/routes/layouts/group.d.ts +1 -1
  153. package/dist/kernel/routes/layouts/group.js +5 -7
  154. package/dist/kernel/routes/metadata/feed.d.ts +1 -1
  155. package/dist/kernel/routes/metadata/feed.js +109 -83
  156. package/dist/kernel/routes/metadata/llms.d.ts +11 -3
  157. package/dist/kernel/routes/metadata/llms.js +154 -57
  158. package/dist/kernel/routes/metadata/og-image.js +1 -1
  159. package/dist/kernel/routes/metadata/robots.d.ts +1 -1
  160. package/dist/kernel/routes/metadata/sitemap.d.ts +22 -3
  161. package/dist/kernel/routes/metadata/sitemap.js +183 -43
  162. package/dist/kernel/routes/not-found.d.ts +34 -0
  163. package/dist/kernel/routes/not-found.js +213 -0
  164. package/dist/kernel/routes/pages/group.d.ts +2 -2
  165. package/dist/kernel/routes/pages/group.js +1 -1
  166. package/dist/kernel/routes/pages/leaf.d.ts +30 -3
  167. package/dist/kernel/routes/pages/leaf.js +5 -4
  168. package/dist/kernel/routes/pages/root.d.ts +2 -2
  169. package/dist/kernel/routes/pages/root.js +1 -1
  170. package/dist/keyboard-shortcuts.js +1 -1
  171. package/dist/route-metadata-og-image-BeKKFHg7.d.ts +58 -0
  172. package/dist/search.js +7 -9
  173. package/dist/theme-scope.js +1 -1
  174. package/dist/{types-BzkZty3r.d.ts → types-J2w_puPF.d.ts} +1 -20
  175. package/dist/types-sM2g9nW0.d.ts +12 -0
  176. package/dist/types.d.ts +1 -0
  177. package/dist/utils/heading-ids.js +30 -11
  178. package/dist/utils/toc-selection.d.ts +7 -0
  179. package/dist/utils/toc-selection.js +14 -0
  180. package/dist/validate-local-source-SV44DBQT.js +16 -0
  181. package/dist/validate-publish-os-source-NZJF3TB2.js +14 -0
  182. package/init/seed/minimal/publish.os/assets/blog/hello-world.svg +13 -0
  183. package/init/seed/minimal/publish.os/assets/favicon.dark.svg +13 -0
  184. package/init/seed/minimal/publish.os/assets/favicon.svg +13 -0
  185. package/init/seed/minimal/publish.os/blog/content/hello-world.mdx +48 -0
  186. package/init/seed/minimal/publish.os/blog/content/series-a.mdx +11 -0
  187. package/init/seed/minimal/publish.os/blog/index.tsx +82 -0
  188. package/init/seed/minimal/publish.os/blog/layout.tsx +13 -0
  189. package/init/seed/minimal/publish.os/blog/page.tsx +76 -0
  190. package/init/seed/minimal/publish.os/components/blog/copy-link.tsx +64 -0
  191. package/init/seed/minimal/publish.os/docs/content/get-started.mdx +2 -3
  192. package/init/seed/minimal/publish.os/docs/content/groups.mdx +5 -6
  193. package/init/seed/minimal/publish.os/publish.os.config.json +6 -2
  194. package/init/seed/minimal/publish.os/theme.css +3 -3
  195. package/init/seed/minimal/seed.json +11 -4
  196. package/init/seed/scratch/publish.os/docs/content/get-started.mdx +1 -1
  197. package/init/seed/scratch/publish.os/publish.os.config.json +1 -1
  198. package/package.json +45 -20
  199. package/release/app/phosphor/package.json +3 -3
  200. package/release/app/phosphor/pnpm-lock.yaml.template +88 -75
  201. package/release/compiler/package.json +5 -3
  202. package/release/compiler/pnpm-lock.yaml.template +118 -74
  203. package/release/release.json +6 -6
  204. package/dist/button-CtzUJB8u.d.ts +0 -11
  205. package/dist/chunk-535TM4A5.js +0 -1455
  206. package/dist/chunk-B2V22WRT.js +0 -297
  207. package/dist/chunk-NECL5IBJ.js +0 -318
  208. package/dist/chunk-SVYGXXYR.js +0 -36
  209. package/dist/chunk-UF6ATARM.js +0 -1100
  210. package/dist/compose-NN23UJGC.js +0 -13
  211. package/dist/ide-support-ZNW7ODFY.js +0 -15
  212. package/dist/kernel/components/blocks/design-system-preview.d.ts +0 -61
  213. package/dist/kernel/components/blocks/design-system-preview.js +0 -667
  214. package/dist/kernel/components/blocks/link-playground.d.ts +0 -5
  215. package/dist/kernel/components/blocks/link-playground.js +0 -744
  216. package/dist/kernel/components/blocks/navigation-progress-playground.d.ts +0 -5
  217. package/dist/kernel/components/blocks/navigation-progress-playground.js +0 -629
  218. package/dist/kernel/components/ui/theme-toggle.d.ts +0 -24
  219. package/dist/kernel/components/ui/theme-toggle.js +0 -53
  220. package/dist/validate-local-source-XRL2Y7XE.js +0 -14
  221. package/dist/validate-publish-os-source-DAPZ4QGE.js +0 -12
  222. package/init/seed/minimal/publish.os/assets/favicon/favicon.dark.png +0 -0
  223. package/init/seed/minimal/publish.os/assets/favicon/favicon.png +0 -0
@@ -3,7 +3,7 @@ import type { LayoutProps } from "@publish.os/nextjs/types";
3
3
  import { log } from "@source/_internal/logger";
4
4
 
5
5
  export default function GroupLayout(props: LayoutProps) {
6
- const { children, currentPath, group, node, site, tree } = props;
6
+ const { children, currentPath, group, node, tree } = props;
7
7
  log.debug("[default:group-layout]", { currentPath, group });
8
8
 
9
9
  return (
@@ -18,10 +18,6 @@ export default function GroupLayout(props: LayoutProps) {
18
18
  >
19
19
  {children}
20
20
  </main>
21
- <aside
22
- aria-label={`${site.name} secondary navigation`}
23
- className="hidden bg-surface-1 xl:block"
24
- />
25
21
  </section>
26
22
  );
27
23
  }
@@ -1,5 +1,6 @@
1
- import { AgentActions } from "@components/blocks/AgentActions";
1
+ import { AgentActions } from "@components/blocks/agent-actions";
2
2
  import { NextPrev } from "@components/blocks/next-prev";
3
+ import { Toc } from "@components/blocks/toc";
3
4
  import { MDX } from "@publish.os/nextjs/mdx";
4
5
  import type { PageProps } from "@publish.os/nextjs/types";
5
6
  import { log } from "@source/_internal/logger";
@@ -14,28 +15,36 @@ export default async function ContentPage(props: PageProps) {
14
15
  : undefined;
15
16
 
16
17
  return (
17
- <div className="flex min-h-[calc(100vh-var(--layout-global-nav-height))] min-w-0 flex-1 flex-col px-6 py-10 text-foreground-1 lg:px-10 supports-[height:100dvh]:min-h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:min-h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:min-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
18
- <div className="mx-auto flex w-full max-w-(--layout-content-max-width) flex-1 flex-col">
19
- <article className="min-h-0 min-w-0 flex-1">
20
- <h1 className="text-3xl font-semibold tracking-tight text-foreground-1">
21
- {props.page.title}
22
- </h1>
23
- <AgentActions
24
- className="mt-4"
25
- markdown={props.page.body}
26
- pagePath={props.currentPath}
27
- siteUrl={props.site.origin}
28
- sourceUrl={sourceUrl}
18
+ <div className="relative flex min-h-[calc(100vh-var(--layout-global-nav-height))] min-w-0 flex-1 flex-col text-foreground-1 supports-[height:100dvh]:min-h-[calc(100dvh-var(--layout-global-nav-height))] supports-[top:anchor-size(--global-navbar_height)]:min-h-[calc(100vh-anchor-size(--global-navbar_height,3.5rem))] supports-[top:anchor-size(--global-navbar_height)]:supports-[height:100dvh]:min-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem))]">
19
+ <Toc
20
+ content={props.page.body}
21
+ desktopClassName="xl:absolute xl:inset-y-0 xl:start-full xl:w-(--layout-toc-width) xl:px-3 xl:py-10"
22
+ desktopListClassName="xl:sticky xl:top-[calc(var(--layout-global-nav-height)_+_1.5rem)] xl:max-h-[calc(100dvh-var(--layout-global-nav-height)-3rem)] xl:overflow-y-auto supports-[top:anchor-size(--global-navbar_height)]:xl:top-[calc(anchor-size(--global-navbar_height,3.5rem)_+_1.5rem)] supports-[top:anchor-size(--global-navbar_height)]:xl:max-h-[calc(100dvh-anchor-size(--global-navbar_height,3.5rem)-3rem)]"
23
+ mobileQuery="(max-width: 1279px)"
24
+ />
25
+ <div className="flex min-w-0 flex-1 flex-col px-6 py-10 lg:px-10">
26
+ <div className="mx-auto flex w-full max-w-(--layout-content-max-width) flex-1 flex-col">
27
+ <article className="min-h-0 min-w-0 flex-1">
28
+ <h1 className="text-3xl font-semibold tracking-tight text-foreground-1">
29
+ {props.page.title}
30
+ </h1>
31
+ <AgentActions
32
+ className="mt-4"
33
+ markdownRevision={props.markdownRevision}
34
+ pagePath={props.currentPath}
35
+ siteUrl={props.site.origin}
36
+ sourceUrl={sourceUrl}
37
+ />
38
+ <div className="mt-6">
39
+ <MDX page={props.page} />
40
+ </div>
41
+ </article>
42
+ <NextPrev
43
+ className="mt-auto pt-12"
44
+ currentPath={props.currentPath}
45
+ tree={props.tree}
29
46
  />
30
- <div className="mt-6">
31
- <MDX page={props.page} />
32
- </div>
33
- </article>
34
- <NextPrev
35
- className="mt-auto pt-12"
36
- currentPath={props.currentPath}
37
- tree={props.tree}
38
- />
47
+ </div>
39
48
  </div>
40
49
  </div>
41
50
  );
@@ -4,37 +4,46 @@ import { dirname } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
6
6
  const projectRoot = dirname(fileURLToPath(import.meta.url));
7
- const ASSET_PREFIX = "__PUBLISHOS_ASSET_PREFIX__";
7
+ const INTERNAL_PREFIX = "__PUBLISHOS_INTERNAL_PREFIX__";
8
+ const SOURCE_ASSET_PREFIX = "__PUBLISHOS_SOURCE_ASSET_PREFIX__";
8
9
  const IMAGE_OPTIMIZER_PATH = "__PUBLISHOS_IMAGE_PATH__";
9
10
  const NEXT_IMAGE_OPTIMIZER_PATH = "__PUBLISHOS_NEXT_IMAGE_PATH__";
10
11
 
11
12
  /** @type {import("next").NextConfig} */
12
13
  export default {
13
- assetPrefix: ASSET_PREFIX,
14
+ assetPrefix: INTERNAL_PREFIX,
14
15
  cacheComponents: true,
16
+ // Preserve loopback origins so internal rewrites do not proxy back into this app.
17
+ skipProxyUrlNormalize: true,
18
+ experimental: { globalNotFound: true },
15
19
  partialPrefetching: false,
20
+ // macOS native notifications can delay preview updates. Use Next's fallback.
21
+ watchOptions:
22
+ process.platform === "darwin" ? { pollIntervalMs: 1_000 } : undefined,
16
23
  // Relocating Shiki as an external loses its pnpm-owned dependencies.
17
24
  transpilePackages: ["shiki"],
18
25
  turbopack: {
19
26
  resolveAlias: {
20
27
  "@publish.os/nextjs/mdx": "./source/.publishos/mdx.tsx",
28
+ "next/image": "@publish.os/nextjs/kernel/components/next-image",
29
+ ...__PUBLISHOS_COMPONENT_ALIASES__,
21
30
  },
22
31
  root: projectRoot,
23
32
  },
33
+ webpack(config) {
34
+ config.resolve.alias["next/image"] =
35
+ "@publish.os/nextjs/kernel/components/next-image";
36
+ return config;
37
+ },
24
38
  images: {
25
39
  dangerouslyAllowSVG: false,
26
40
  deviceSizes: [640, 828, 1080, 1200, 1600, 1920, 2560, 3840],
27
41
  formats: ["image/webp"],
28
42
  imageSizes: [32, 48, 64, 96, 128, 256, 384],
29
43
  path: IMAGE_OPTIMIZER_PATH,
30
- localPatterns: [
31
- {
32
- pathname: `${ASSET_PREFIX}/_publishos/assets/**/images/**`,
33
- search: "",
34
- },
35
- { pathname: `${ASSET_PREFIX}/assets/images/**`, search: "" },
36
- ],
37
- minimumCacheTTL: 2678400,
44
+ localPatterns: [{ pathname: `${SOURCE_ASSET_PREFIX}/**` }],
45
+ remotePatterns: [],
46
+ minimumCacheTTL: 0,
38
47
  qualities: [50, 60, 75, 85, 95, 100],
39
48
  },
40
49
  async rewrites() {
@@ -4,6 +4,7 @@
4
4
  "lib": ["dom", "dom.iterable", "esnext"],
5
5
  "module": "esnext",
6
6
  "moduleResolution": "bundler",
7
+ "jsxImportSource": "@publish.os/nextjs",
7
8
  "jsx": "react-jsx",
8
9
  "allowJs": true,
9
10
  "strict": true,
@@ -17,6 +18,15 @@
17
18
  "paths": {
18
19
  "@app/*": ["./app/*"],
19
20
  "@publish.os/nextjs/mdx": ["./source/.publishos/mdx"],
21
+ "@publish.os/nextjs/components/ui/button": [
22
+ "./node_modules/@publish.os/nextjs/dist/kernel/components/ui/button"
23
+ ],
24
+ "@publish.os/nextjs/components/blocks/toc": [
25
+ "./node_modules/@publish.os/nextjs/dist/kernel/components/blocks/toc"
26
+ ],
27
+ "@publish.os/nextjs/components/blocks/agent-actions": [
28
+ "./node_modules/@publish.os/nextjs/dist/kernel/components/blocks/agent-actions"
29
+ ],
20
30
  "@components/*": [
21
31
  "./source/components/*",
22
32
  "./node_modules/@publish.os/nextjs/dist/kernel/components/*"
@@ -0,0 +1,18 @@
1
+ [data-slot="copy-code-button"] {
2
+ transition: opacity 150ms ease-out;
3
+ }
4
+
5
+ @media (hover: hover) and (pointer: fine) and (any-pointer: fine) and (
6
+ any-hover: hover
7
+ ) and (not (any-pointer: coarse)) {
8
+ [data-slot="code-block"]:not(:hover):not(:focus-within)
9
+ [data-slot="copy-code-button"]:not([data-copied="true"]) {
10
+ opacity: 0;
11
+ }
12
+ }
13
+
14
+ @media (prefers-reduced-motion: reduce) {
15
+ [data-slot="copy-code-button"] {
16
+ transition: none;
17
+ }
18
+ }
@@ -0,0 +1,38 @@
1
+ import { Providers } from "@app/providers";
2
+ import manifest from "@manifest";
3
+ import { preloadRootFonts, rootFontClassName } from "@source/.fonts.generated";
4
+ import RootLayout from "@source/layout";
5
+ import { type ComponentType, Fragment, type ReactNode } from "react";
6
+ import "@source/.fonts.generated.css";
7
+ import "@app/globals.css";
8
+
9
+ /** Shared document and authored shell for successful pages and routing-level 404s. */
10
+ export default function SiteDocument({
11
+ children,
12
+ head,
13
+ beforeShell,
14
+ bodyWrapper: BodyWrapper = Fragment,
15
+ }: {
16
+ children: ReactNode;
17
+ head?: ReactNode;
18
+ beforeShell?: ReactNode;
19
+ bodyWrapper?: ComponentType<{ children: ReactNode }>;
20
+ }) {
21
+ preloadRootFonts();
22
+ return (
23
+ <html className={rootFontClassName} lang="en" suppressHydrationWarning>
24
+ {/* biome-ignore lint/style/noHeadElement: global-not-found owns a full document outside the Next metadata layout tree. */}
25
+ {head ? <head>{head}</head> : null}
26
+ <body className="publish-os-app-root">
27
+ {beforeShell}
28
+ <BodyWrapper>
29
+ <Providers>
30
+ <RootLayout site={manifest.site} tree={manifest.tree}>
31
+ {children}
32
+ </RootLayout>
33
+ </Providers>
34
+ </BodyWrapper>
35
+ </body>
36
+ </html>
37
+ );
38
+ }
@@ -5,6 +5,7 @@ import {
5
5
  createLeafPage,
6
6
  createLeafStaticParams,
7
7
  } from "@publish.os/nextjs/kernel/routes/pages/leaf";
8
+ import { markdownArtifactManifest } from "@source/.publishos/markdown-index.generated";
8
9
  import { ogManifest } from "@source/.publishos/og-manifest.generated";
9
10
  import { groupThemes } from "@source/.theme.generated";
10
11
  import Leaf from "@source/__PUBLISHOS_OWNER_KEY__/page";
@@ -13,6 +14,7 @@ import { PoweredByFooter } from "@source/_internal/powered-by-footer.generated";
13
14
  const route = {
14
15
  group: __PUBLISHOS_GROUP_KEY__,
15
16
  manifest,
17
+ markdownArtifactManifest,
16
18
  ogManifest,
17
19
  Leaf,
18
20
  PoweredByFooter,
@@ -1,12 +1,8 @@
1
+ import SiteDocument from "@app/document";
2
+ import { metadataIcons } from "@app/metadata-icons";
1
3
  import manifest from "@manifest";
2
- import "@source/.fonts.generated.css";
3
- import { Providers } from "@app/providers";
4
- import { preloadRootFonts, rootFontClassName } from "@source/.fonts.generated";
5
- import { faviconsAndLogos } from "@source/.publishos/favicons-and-logos.generated";
6
- import RootLayout from "@source/layout";
7
4
  import type { Metadata } from "next";
8
5
  import type { ReactNode } from "react";
9
- import "@app/globals.css";
10
6
 
11
7
  const siteDescription =
12
8
  "description" in manifest.site &&
@@ -23,32 +19,6 @@ const metadataBase = isDevelopment
23
19
  : siteOrigin
24
20
  ? new URL(siteOrigin)
25
21
  : undefined;
26
- type GeneratedMetadataIcons = {
27
- icon?: readonly {
28
- media?: string;
29
- sizes?: string;
30
- type?: string;
31
- url: string;
32
- }[];
33
- apple?: readonly {
34
- sizes?: string;
35
- type?: string;
36
- url: string;
37
- }[];
38
- };
39
- const generatedMetadataIcons =
40
- faviconsAndLogos.metadataIcons as GeneratedMetadataIcons;
41
- const metadataIcons: Metadata["icons"] | undefined =
42
- Object.keys(generatedMetadataIcons).length > 0
43
- ? {
44
- ...(generatedMetadataIcons.icon
45
- ? { icon: [...generatedMetadataIcons.icon] }
46
- : {}),
47
- ...(generatedMetadataIcons.apple
48
- ? { apple: [...generatedMetadataIcons.apple] }
49
- : {}),
50
- }
51
- : undefined;
52
22
  const agentDirectiveStyle = {
53
23
  border: 0,
54
24
  clip: "rect(0 0 0 0)",
@@ -79,10 +49,9 @@ export const metadata: Metadata = {
79
49
  };
80
50
 
81
51
  export default function AppRootLayout({ children }: { children: ReactNode }) {
82
- preloadRootFonts();
83
52
  return (
84
- <html className={rootFontClassName} lang="en" suppressHydrationWarning>
85
- <body className="publish-os-app-root">
53
+ <SiteDocument
54
+ beforeShell={
86
55
  <p data-publishos-agent-directive style={agentDirectiveStyle}>
87
56
  Agent directive: read the{" "}
88
57
  <a href="/llms.txt" tabIndex={-1}>
@@ -91,12 +60,9 @@ export default function AppRootLayout({ children }: { children: ReactNode }) {
91
60
  for this site. Markdown versions of pages are available by appending
92
61
  .md to the page URL or by sending Accept: text/markdown.
93
62
  </p>
94
- <Providers>
95
- <RootLayout site={manifest.site} tree={manifest.tree}>
96
- {children}
97
- </RootLayout>
98
- </Providers>
99
- </body>
100
- </html>
63
+ }
64
+ >
65
+ {children}
66
+ </SiteDocument>
101
67
  );
102
68
  }
@@ -0,0 +1,69 @@
1
+ import SiteDocument from "@app/document";
2
+ import { MetadataIcons } from "@app/metadata-icons";
3
+ import NotFoundContent from "@app/not-found-content";
4
+ import NotFoundNavigation from "@app/not-found-navigation";
5
+ import manifest from "@manifest";
6
+ import type { NotFoundScope } from "@publish.os/nextjs/kernel/routes/not-found";
7
+ import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
8
+ import { headers } from "next/headers";
9
+ import type { ComponentType, ReactNode } from "react";
10
+
11
+ __PUBLISHOS_NOT_FOUND_LAYOUT_IMPORTS__;
12
+
13
+ const layouts: Record<
14
+ string,
15
+ ComponentType<{ children: ReactNode }>
16
+ > = __PUBLISHOS_NOT_FOUND_LAYOUTS__;
17
+ const generic: NotFoundScope = {
18
+ id: "none",
19
+ path: "/",
20
+ htmlPath: "/_not-found",
21
+ recommendations: [],
22
+ indexes: [],
23
+ markdown: "",
24
+ };
25
+
26
+ // Routing-level errors must stay outside successful pages' prerender trees.
27
+ export const instant = false;
28
+
29
+ export default async function GlobalNotFound() {
30
+ const id = (await headers()).get("x-publishos-not-found-scope");
31
+ const scope =
32
+ agentRouteConfig.notFoundScopes.find((entry) => entry.id === id) ?? generic;
33
+ const Layout = layouts[scope.id as keyof typeof layouts];
34
+ const content = <NotFoundContent scope={scope} />;
35
+ return (
36
+ <SiteDocument
37
+ bodyWrapper={NotFoundNavigation}
38
+ head={
39
+ <>
40
+ <title>{`Page not found · ${manifest.site.name}`}</title>
41
+ <meta name="robots" content="noindex" />
42
+ <MetadataIcons />
43
+ {agentRouteConfig.enabled && agentRouteConfig.discoveryHeaders ? (
44
+ <>
45
+ {scope.describedBy ? (
46
+ <link href={scope.describedBy} rel="describedby" />
47
+ ) : null}
48
+ {scope.indexes.map((link) => (
49
+ <link href={link.href} key={link.href} rel="related" />
50
+ ))}
51
+ </>
52
+ ) : null}
53
+ </>
54
+ }
55
+ >
56
+ {Layout ? (
57
+ <Layout>{content}</Layout>
58
+ ) : (
59
+ <main
60
+ className="flex min-h-0 flex-1 flex-col"
61
+ id="main-content"
62
+ tabIndex={-1}
63
+ >
64
+ {content}
65
+ </main>
66
+ )}
67
+ </SiteDocument>
68
+ );
69
+ }
@@ -1,4 +1,5 @@
1
1
  import { createMarkdownRouteHandlers } from "@publish.os/nextjs/kernel/routes/agent/markdown";
2
+ import { agentRouteConfig } from "@source/.publishos/agent-route-config.generated";
2
3
  import {
3
4
  loadMarkdownArtifact,
4
5
  markdownArtifactManifest,
@@ -11,6 +12,7 @@ const handlers = createMarkdownRouteHandlers(
11
12
  },
12
13
  {
13
14
  discoveryLinks: __PUBLISHOS_MARKDOWN_DISCOVERY_LINKS__,
15
+ notFoundScopes: agentRouteConfig.notFoundScopes,
14
16
  },
15
17
  );
16
18
 
@@ -0,0 +1,39 @@
1
+ import { faviconsAndLogos } from "@source/.publishos/favicons-and-logos.generated";
2
+ import type { Metadata } from "next";
3
+
4
+ type GeneratedMetadataIcons = {
5
+ icon?: readonly {
6
+ media?: string;
7
+ sizes?: string;
8
+ type?: string;
9
+ url: string;
10
+ }[];
11
+ apple?: readonly {
12
+ sizes?: string;
13
+ type?: string;
14
+ url: string;
15
+ }[];
16
+ };
17
+
18
+ const generated = faviconsAndLogos.metadataIcons as GeneratedMetadataIcons;
19
+
20
+ export const metadataIcons = Object.keys(generated).length
21
+ ? ({
22
+ ...(generated.icon ? { icon: [...generated.icon] } : {}),
23
+ ...(generated.apple ? { apple: [...generated.apple] } : {}),
24
+ } satisfies Metadata["icons"])
25
+ : undefined;
26
+
27
+ /** Global errors bypass Next's layout metadata but use the same resolved icons. */
28
+ export function MetadataIcons() {
29
+ return (
30
+ <>
31
+ {metadataIcons?.icon?.map(({ url, ...attributes }) => (
32
+ <link href={url} key={url} rel="icon" {...attributes} />
33
+ ))}
34
+ {metadataIcons?.apple?.map(({ url, ...attributes }) => (
35
+ <link href={url} key={url} rel="apple-touch-icon" {...attributes} />
36
+ ))}
37
+ </>
38
+ );
39
+ }
@@ -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
+ }