create-kywi-app 0.7.0 → 0.7.1
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/lib/templates.mjs +58 -7
- package/package.json +1 -1
package/lib/templates.mjs
CHANGED
|
@@ -1087,11 +1087,57 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
1087
1087
|
`
|
|
1088
1088
|
}
|
|
1089
1089
|
|
|
1090
|
+
/**
|
|
1091
|
+
* Client-side wrapper around core's SHARED nav renderer — the same component the
|
|
1092
|
+
* `navigation` module uses — so the site header and footer get identical markup,
|
|
1093
|
+
* CSS (`.kywi-nav-*`) and @kywi-software/js enhancement to any nav placed in a
|
|
1094
|
+
* page body. `items` is whatever app/(site)/layout.tsx resolved server-side (the
|
|
1095
|
+
* owner-managed menu, or the site tree as fallback); nothing is decided here.
|
|
1096
|
+
*
|
|
1097
|
+
* WHY THIS FILE EXISTS — it is `'use client'` on purpose, and the layout that
|
|
1098
|
+
* renders it is a Server Component. `BUILT_IN_MODULE_COMPONENTS` is exported
|
|
1099
|
+
* from one of core's `'use client'` modules, so a Server Component that imports
|
|
1100
|
+
* the map gets a client *reference*, not a real object:
|
|
1101
|
+
* `BUILT_IN_MODULE_COMPONENTS.navigation` reads back `undefined` there and React
|
|
1102
|
+
* throws "Element type is invalid… got: undefined" on every page (kywi-cms#112
|
|
1103
|
+
* follow-up). Crossing the boundary here, in a client module, is what makes the
|
|
1104
|
+
* lookup resolve to the real component — mirrors apps/reference/components/nav.tsx.
|
|
1105
|
+
*/
|
|
1106
|
+
function siteNavComponent() {
|
|
1107
|
+
return `'use client'
|
|
1108
|
+
|
|
1109
|
+
import React from 'react'
|
|
1110
|
+
import { BUILT_IN_MODULE_COMPONENTS } from '@kywi-software/core/layout'
|
|
1111
|
+
import type { NavMenuItem } from '@kywi-software/core/nav'
|
|
1112
|
+
|
|
1113
|
+
// BUILT_IN_MODULE_COMPONENTS is a Record<string, …>, so a literal-key lookup is
|
|
1114
|
+
// typed as possibly-undefined under noUncheckedIndexedAccess; 'navigation' is
|
|
1115
|
+
// always present — it's one of core's own built-in modules, not user data.
|
|
1116
|
+
const NavRenderer = BUILT_IN_MODULE_COMPONENTS.navigation!
|
|
1117
|
+
|
|
1118
|
+
export interface SiteNavProps {
|
|
1119
|
+
items: NavMenuItem[]
|
|
1120
|
+
/** \`horizontal\`/\`mega\`/\`vertical\` for the header bar, \`footer\` for the footer columns. */
|
|
1121
|
+
variant: 'horizontal' | 'mega' | 'vertical' | 'footer'
|
|
1122
|
+
ariaLabel: string
|
|
1123
|
+
depth?: number
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/** Renders one resolved menu (header or footer) through core's shared nav renderer. */
|
|
1127
|
+
export function SiteNav({ items, variant, ariaLabel, depth }: SiteNavProps) {
|
|
1128
|
+
if (items.length === 0) return null
|
|
1129
|
+
return (
|
|
1130
|
+
<NavRenderer props={{ items, variant, ariaLabel, ...(depth ? { depth } : {}) }} />
|
|
1131
|
+
)
|
|
1132
|
+
}
|
|
1133
|
+
`
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1090
1136
|
/** @param {Answers} a — coupled public site shell. */
|
|
1091
1137
|
function siteLayout(a) {
|
|
1092
1138
|
return `import React from 'react'
|
|
1093
1139
|
import { headers } from 'next/headers'
|
|
1094
|
-
import { themeTokenStyleBlock
|
|
1140
|
+
import { themeTokenStyleBlock } from '@kywi-software/core/layout'
|
|
1095
1141
|
import { navTreeToMenuItems, normalizePath } from '@kywi-software/core/nav'
|
|
1096
1142
|
// Neutral, token-driven defaults for everything Kywi renders (prose, the layout
|
|
1097
1143
|
// grid + modules, forms, the edit overlay). Restyle via theme tokens, not by
|
|
@@ -1101,6 +1147,7 @@ import '@kywi-software/core/site/styles.css'
|
|
|
1101
1147
|
import './site.css'
|
|
1102
1148
|
import config from '../../kywi.config'
|
|
1103
1149
|
import { getKywi } from '../../lib/kywi'
|
|
1150
|
+
import { SiteNav } from '../../components/site-nav'
|
|
1104
1151
|
|
|
1105
1152
|
/**
|
|
1106
1153
|
* Public site shell. Header + footer carry this project's brand; edit them (and
|
|
@@ -1113,7 +1160,8 @@ import { getKywi } from '../../lib/kywi'
|
|
|
1113
1160
|
* of the box — and the footer renders a \`'footer'\` menu when one exists. NEVER
|
|
1114
1161
|
* hardcode this list: a menu item's href resolves from its linked page and
|
|
1115
1162
|
* can never drift the way a pasted URL can (see AGENTS.md → Navigation).
|
|
1116
|
-
* Rendered through core's shared nav renderer
|
|
1163
|
+
* Rendered through core's shared nav renderer via the generated
|
|
1164
|
+
* \`components/site-nav.tsx\` (a \`'use client'\` wrapper — see that file for why)
|
|
1117
1165
|
* rather than bespoke markup, so it gets the same CSS and \`@kywi-software/js\`
|
|
1118
1166
|
* enhancement as a \`navigation\` module placed in the page body.
|
|
1119
1167
|
*
|
|
@@ -1126,8 +1174,6 @@ const siteTheme =
|
|
|
1126
1174
|
config.themes.find((t) => t.name === config.sites[0]?.theme) ?? config.themes[0]
|
|
1127
1175
|
const themeVars = themeTokenStyleBlock(siteTheme?.tokens)
|
|
1128
1176
|
|
|
1129
|
-
const NavRenderer = BUILT_IN_MODULE_COMPONENTS.navigation
|
|
1130
|
-
|
|
1131
1177
|
// Content edits (a renamed page, a reordered menu) must show up without a
|
|
1132
1178
|
// restart — same reasoning as the page route.
|
|
1133
1179
|
export const dynamic = 'force-dynamic'
|
|
@@ -1155,7 +1201,7 @@ export default async function SiteLayout({ children }: { children: React.ReactNo
|
|
|
1155
1201
|
<a className="site-brand" href="/">${escapeJsxText(a.projectName)}</a>
|
|
1156
1202
|
<div className="site-nav">
|
|
1157
1203
|
{headerItems.length > 0 && (
|
|
1158
|
-
<
|
|
1204
|
+
<SiteNav items={headerItems} variant="horizontal" ariaLabel="Primary" depth={2} />
|
|
1159
1205
|
)}
|
|
1160
1206
|
<a className="site-nav__admin" href="/admin">Admin →</a>
|
|
1161
1207
|
</div>
|
|
@@ -1167,7 +1213,7 @@ export default async function SiteLayout({ children }: { children: React.ReactNo
|
|
|
1167
1213
|
<footer className="site-footer">
|
|
1168
1214
|
<div className="site-footer__inner">
|
|
1169
1215
|
{footerItems && footerItems.length > 0 && (
|
|
1170
|
-
<
|
|
1216
|
+
<SiteNav items={footerItems} variant="footer" ariaLabel="Footer" />
|
|
1171
1217
|
)}
|
|
1172
1218
|
<p className="site-footer__credit">Powered by <a href="https://kywi.dev">Kywi CMS</a></p>
|
|
1173
1219
|
</div>
|
|
@@ -2292,7 +2338,7 @@ lib/config.ts single import path for kywi.config.ts
|
|
|
2292
2338
|
app/api/v1/[...kywi]/route.ts the versioned API (delegates to core)
|
|
2293
2339
|
app/admin/[[...admin]]/page.tsx mounts the FULL core admin (all surfaces) at /admin
|
|
2294
2340
|
lib/modules.tsx custom (defineModule) module renderers (admin + public)
|
|
2295
|
-
app/{llms,robots,sitemap,…} root AX routes (llms.txt, robots.txt, sitemap.xml, …)${a.mode === 'coupled' ? '\napp/(site)/layout.tsx public shell: theme tokens + your header/footer\napp/(site)/site.css your site chrome styles (edit freely)\napp/(site)/[[...slug]]/page.tsx renders published pages (layout + SEO + JSON-LD + i18n)\nlib/site.ts public-render helpers: path/locale resolution, feeds, personalization\ncomponents/personalization-runtime.tsx optional client runtime (self-ID widget, live re-eval)\napp/(site)/kywi-front-edit.tsx front-of-site editor: browse toolbar + in-place Layout editor (?kywi-edit=1, lazy-loaded)' : '\napp/page.tsx returns 404 (no public rendering in this mode)'}
|
|
2341
|
+
app/{llms,robots,sitemap,…} root AX routes (llms.txt, robots.txt, sitemap.xml, …)${a.mode === 'coupled' ? '\napp/(site)/layout.tsx public shell: theme tokens + your header/footer\napp/(site)/site.css your site chrome styles (edit freely)\napp/(site)/[[...slug]]/page.tsx renders published pages (layout + SEO + JSON-LD + i18n)\nlib/site.ts public-render helpers: path/locale resolution, feeds, personalization\ncomponents/site-nav.tsx client wrapper around the shared nav renderer (header + footer)\ncomponents/personalization-runtime.tsx optional client runtime (self-ID widget, live re-eval)\napp/(site)/kywi-front-edit.tsx front-of-site editor: browse toolbar + in-place Layout editor (?kywi-edit=1, lazy-loaded)' : '\napp/page.tsx returns 404 (no public rendering in this mode)'}
|
|
2296
2342
|
\`\`\`
|
|
2297
2343
|
`
|
|
2298
2344
|
}
|
|
@@ -2676,6 +2722,11 @@ export function buildFileSet(answers) {
|
|
|
2676
2722
|
// page at its slug. More-specific /admin and /api routes take precedence.
|
|
2677
2723
|
files['app/(site)/layout.tsx'] = siteLayout(answers)
|
|
2678
2724
|
files['app/(site)/site.css'] = siteStyles(answers)
|
|
2725
|
+
// 'use client' wrapper around core's shared nav renderer — required because
|
|
2726
|
+
// BUILT_IN_MODULE_COMPONENTS is exported from a 'use client' core module, so
|
|
2727
|
+
// the (Server Component) site layout above must render it through here
|
|
2728
|
+
// rather than looking it up directly (see siteNavComponent's doc comment).
|
|
2729
|
+
files['components/site-nav.tsx'] = siteNavComponent()
|
|
2679
2730
|
files['app/(site)/[[...slug]]/page.tsx'] = siteSlugPage()
|
|
2680
2731
|
// Public-render helpers: path/locale resolution, feed + component resolvers,
|
|
2681
2732
|
// personalization + experiments.
|
package/package.json
CHANGED