create-kudzu 0.1.63 → 0.1.64
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/README.md +1 -1
- package/index.mjs +158 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,6 @@ cd my-app
|
|
|
8
8
|
npm run dev
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The generated project
|
|
11
|
+
The generated project is a working showcase with reusable components, an interactive state example, a zero-JavaScript static route, page metadata, responsive source CSS, and `npm run check`. Configuration remains optional until the app needs custom assets, document defaults, navigation, or build hooks.
|
|
12
12
|
|
|
13
13
|
Use `--no-install` to create the files without installing dependencies.
|
package/index.mjs
CHANGED
|
@@ -15,7 +15,10 @@ try {
|
|
|
15
15
|
if (error.code !== "ENOENT") throw error
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
await
|
|
18
|
+
await Promise.all([
|
|
19
|
+
mkdir(resolve(root, "src/components"), { recursive: true }),
|
|
20
|
+
mkdir(resolve(root, "src/pages"), { recursive: true })
|
|
21
|
+
])
|
|
19
22
|
|
|
20
23
|
const name = basename(root).toLowerCase().replace(/[^a-z0-9._-]+/g, "-") || "kudzu-app"
|
|
21
24
|
const files = {
|
|
@@ -31,6 +34,9 @@ const files = {
|
|
|
31
34
|
},
|
|
32
35
|
dependencies: {
|
|
33
36
|
"@kudzujs/core": "^0.7.9"
|
|
37
|
+
},
|
|
38
|
+
devDependencies: {
|
|
39
|
+
typescript: "^5.9.2"
|
|
34
40
|
}
|
|
35
41
|
}, null, 2)}\n`,
|
|
36
42
|
"tsconfig.json": `${JSON.stringify({
|
|
@@ -44,40 +50,172 @@ const files = {
|
|
|
44
50
|
}
|
|
45
51
|
}, null, 2)}\n`,
|
|
46
52
|
".gitignore": "node_modules/\ndist/\n.kudzu/\n",
|
|
53
|
+
"src/components/SiteHeader.tsx": `export function SiteHeader({ current }: { current: "home" | "about" }) {
|
|
54
|
+
return <header className="site-header">
|
|
55
|
+
<a className="brand" href="/"><span>K</span>Kudzu</a>
|
|
56
|
+
<nav aria-label="Main navigation">
|
|
57
|
+
<a className={current === "home" ? "active" : ""} href="/">Showcase</a>
|
|
58
|
+
<a className={current === "about" ? "active" : ""} href="/about">Static route</a>
|
|
59
|
+
<a href="https://kudzujs.cloud/docs">Docs</a>
|
|
60
|
+
</nav>
|
|
61
|
+
</header>
|
|
62
|
+
}
|
|
63
|
+
`,
|
|
64
|
+
"src/components/CapabilityCard.tsx": `type Props = { number: string; title: string; description: string; output: string }
|
|
65
|
+
|
|
66
|
+
export function CapabilityCard({ number, title, description, output }: Props) {
|
|
67
|
+
return <article className="capability-card">
|
|
68
|
+
<span>{number}</span>
|
|
69
|
+
<h3>{title}</h3>
|
|
70
|
+
<p>{description}</p>
|
|
71
|
+
<code>{output}</code>
|
|
72
|
+
</article>
|
|
73
|
+
}
|
|
74
|
+
`,
|
|
47
75
|
"src/pages/index.tsx": `import { useState } from "@kudzujs/core"
|
|
76
|
+
import { CapabilityCard } from "../components/CapabilityCard"
|
|
77
|
+
import { SiteHeader } from "../components/SiteHeader"
|
|
48
78
|
|
|
49
79
|
export const metadata = {
|
|
50
|
-
title: "${name}",
|
|
51
|
-
description: "
|
|
80
|
+
title: "${name} | Built with Kudzu",
|
|
81
|
+
description: "A working Kudzu starter with static HTML and direct interactions",
|
|
82
|
+
themeColor: "#b7ff5a"
|
|
52
83
|
}
|
|
53
84
|
|
|
54
85
|
export default function HomePage() {
|
|
55
86
|
const [count, setCount] = useState(0)
|
|
56
87
|
|
|
57
|
-
return
|
|
88
|
+
return <>
|
|
89
|
+
<SiteHeader current="home" />
|
|
58
90
|
<main>
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
91
|
+
<section className="hero">
|
|
92
|
+
<p className="eyebrow">HTML-FIRST TSX</p>
|
|
93
|
+
<h1>Keep the components.<br /><em>Lose the runtime.</em></h1>
|
|
94
|
+
<p className="intro">Edit the components, routes, state, metadata, and source CSS already working in this project.</p>
|
|
95
|
+
<div className="hero-actions">
|
|
96
|
+
<a className="primary" href="#capabilities">Explore the starter</a>
|
|
97
|
+
<a href="https://kudzujs.cloud/docs">Read the docs -></a>
|
|
98
|
+
</div>
|
|
99
|
+
</section>
|
|
100
|
+
|
|
101
|
+
<section className="signals" aria-label="Kudzu output">
|
|
102
|
+
<div><strong>0 B</strong><span>JS on static routes</span></div>
|
|
103
|
+
<div><strong>TSX</strong><span>Function components</span></div>
|
|
104
|
+
<div><strong>direct</strong><span>DOM updates</span></div>
|
|
105
|
+
</section>
|
|
106
|
+
|
|
107
|
+
<section className="demo">
|
|
108
|
+
<div>
|
|
109
|
+
<p className="eyebrow">LIVE STATE</p>
|
|
110
|
+
<h2>Only interactive pages ship behavior.</h2>
|
|
111
|
+
<p>This counter uses familiar <code>useState</code>. Kudzu compiles only the page-specific ESM needed for direct DOM updates.</p>
|
|
112
|
+
</div>
|
|
113
|
+
<div className="counter">
|
|
114
|
+
<span>Growth count</span><strong>{count}</strong>
|
|
115
|
+
<div>
|
|
116
|
+
<button onClick={() => setCount(count + 1)}>Grow +1</button>
|
|
117
|
+
<button onClick={() => { setCount(count + 1); setCount(count + 1) }}>Grow +2</button>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</section>
|
|
121
|
+
|
|
122
|
+
<section className="capabilities" id="capabilities">
|
|
123
|
+
<div className="section-heading"><p className="eyebrow">INCLUDED EXAMPLES</p><h2>Start by changing real code.</h2></div>
|
|
124
|
+
<div className="capability-grid">
|
|
125
|
+
<CapabilityCard number="01" title="File routes" description="Every TSX file under src/pages becomes a route." output="pages/about.tsx -> /about" />
|
|
126
|
+
<CapabilityCard number="02" title="Components" description="Compose ordinary typed function components and props." output="components/SiteHeader.tsx" />
|
|
127
|
+
<CapabilityCard number="03" title="Static HTML" description="Pages without browser behavior emit no JavaScript." output="about.html + 0 B JS" />
|
|
128
|
+
<CapabilityCard number="04" title="Local state" description="Use React-shaped state and synchronous event handlers." output="useState(0)" />
|
|
129
|
+
<CapabilityCard number="05" title="Metadata" description="Export page titles, descriptions, and theme colors." output="export const metadata" />
|
|
130
|
+
<CapabilityCard number="06" title="Source CSS" description="CSS under src is emitted and linked automatically." output="src/style.css" />
|
|
131
|
+
</div>
|
|
132
|
+
</section>
|
|
62
133
|
</main>
|
|
63
|
-
|
|
134
|
+
<footer><span>Built with Kudzu</span><a href="https://github.com/kudzujs/kudzu">GitHub -></a></footer>
|
|
135
|
+
</>
|
|
64
136
|
}
|
|
65
137
|
`,
|
|
66
|
-
"src/
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
font-family: system-ui, sans-serif;
|
|
70
|
-
}
|
|
138
|
+
"src/pages/about.tsx": `import { SiteHeader } from "../components/SiteHeader"
|
|
139
|
+
|
|
140
|
+
export const metadata = { title: "Static route | ${name}", description: "A zero-JavaScript Kudzu route" }
|
|
71
141
|
|
|
142
|
+
export default function AboutPage() {
|
|
143
|
+
return <>
|
|
144
|
+
<SiteHeader current="about" />
|
|
145
|
+
<main className="static-page">
|
|
146
|
+
<p className="eyebrow">ZERO-JAVASCRIPT ROUTE</p>
|
|
147
|
+
<h1>This page is already complete.</h1>
|
|
148
|
+
<p>There are no hooks or event handlers here, so Kudzu emits HTML and CSS without client JavaScript.</p>
|
|
149
|
+
<a className="primary" href="/">Back to the showcase</a>
|
|
150
|
+
</main>
|
|
151
|
+
</>
|
|
152
|
+
}
|
|
153
|
+
`,
|
|
154
|
+
"src/style.css": `:root { color: #f3f5ed; background: #0b0d0a; font-family: Inter, ui-sans-serif, system-ui, sans-serif; font-synthesis: none; }
|
|
155
|
+
* { box-sizing: border-box; }
|
|
156
|
+
html { scroll-behavior: smooth; }
|
|
72
157
|
body { margin: 0; }
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
158
|
+
a { color: inherit; }
|
|
159
|
+
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
160
|
+
.site-header, main, footer { width: min(1120px, calc(100% - 40px)); margin-inline: auto; }
|
|
161
|
+
.site-header { display: flex; align-items: center; justify-content: space-between; padding: 24px 0; }
|
|
162
|
+
.brand { display: flex; gap: 10px; align-items: center; font-weight: 800; text-decoration: none; }
|
|
163
|
+
.brand span { display: grid; width: 34px; height: 34px; place-items: center; color: #0b0d0a; background: #b7ff5a; border-radius: 50%; }
|
|
164
|
+
nav { display: flex; gap: 24px; font-size: .9rem; }
|
|
165
|
+
nav a { color: #9da496; text-decoration: none; }
|
|
166
|
+
nav a:hover, nav a.active { color: #f3f5ed; }
|
|
167
|
+
.hero { min-height: 620px; padding: 120px 0 80px; border-top: 1px solid #252a22; }
|
|
168
|
+
.eyebrow { color: #b7ff5a; font: 700 .75rem/1 ui-monospace, monospace; letter-spacing: .14em; }
|
|
169
|
+
h1, h2, h3, p { margin-top: 0; }
|
|
170
|
+
h1 { max-width: 950px; margin-bottom: 28px; font-size: clamp(3.6rem, 9vw, 7.8rem); line-height: .9; letter-spacing: -.07em; }
|
|
171
|
+
h1 em { color: #b7ff5a; font-style: normal; }
|
|
172
|
+
.intro { max-width: 680px; color: #aeb5a7; font-size: clamp(1.1rem, 2vw, 1.4rem); line-height: 1.6; }
|
|
173
|
+
.hero-actions { display: flex; gap: 24px; align-items: center; margin-top: 38px; }
|
|
174
|
+
.hero-actions a { text-underline-offset: 5px; }
|
|
175
|
+
.primary { display: inline-block; padding: 14px 20px; color: #0b0d0a; background: #b7ff5a; border-radius: 3px; font-weight: 800; text-decoration: none; }
|
|
176
|
+
.signals { display: grid; grid-template-columns: repeat(3, 1fr); border-block: 1px solid #252a22; }
|
|
177
|
+
.signals div { display: grid; gap: 7px; padding: 32px; border-right: 1px solid #252a22; }
|
|
178
|
+
.signals div:last-child { border: 0; }
|
|
179
|
+
.signals strong { font-size: 1.6rem; }
|
|
180
|
+
.signals span { color: #899083; font-size: .85rem; }
|
|
181
|
+
.demo { display: grid; grid-template-columns: 1.2fr .8fr; gap: 80px; align-items: center; padding: 120px 0; }
|
|
182
|
+
.demo h2, .section-heading h2 { max-width: 700px; font-size: clamp(2.5rem, 6vw, 5rem); line-height: .98; letter-spacing: -.055em; }
|
|
183
|
+
.demo p:not(.eyebrow) { max-width: 580px; color: #9da496; line-height: 1.7; }
|
|
184
|
+
.counter { display: grid; gap: 20px; padding: 30px; background: #141712; border: 1px solid #30352c; }
|
|
185
|
+
.counter > span { color: #9da496; font-size: .8rem; text-transform: uppercase; letter-spacing: .12em; }
|
|
186
|
+
.counter strong { color: #b7ff5a; font: 700 7rem/.9 ui-monospace, monospace; }
|
|
187
|
+
.counter div { display: flex; gap: 10px; }
|
|
188
|
+
button { padding: 12px 16px; color: #f3f5ed; background: #242a20; border: 1px solid #40483a; border-radius: 3px; cursor: pointer; }
|
|
189
|
+
button:hover { color: #0b0d0a; background: #b7ff5a; }
|
|
190
|
+
.capabilities { padding: 40px 0 120px; }
|
|
191
|
+
.section-heading { margin-bottom: 52px; }
|
|
192
|
+
.capability-grid { display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px solid #30352c; border-left: 1px solid #30352c; }
|
|
193
|
+
.capability-card { min-height: 260px; padding: 28px; border-right: 1px solid #30352c; border-bottom: 1px solid #30352c; }
|
|
194
|
+
.capability-card > span { color: #b7ff5a; font: .75rem ui-monospace, monospace; }
|
|
195
|
+
.capability-card h3 { margin: 44px 0 12px; font-size: 1.35rem; }
|
|
196
|
+
.capability-card p { min-height: 48px; color: #929a8b; line-height: 1.5; }
|
|
197
|
+
.capability-card code { color: #cbd1c4; font-size: .78rem; }
|
|
198
|
+
footer { display: flex; justify-content: space-between; padding: 28px 0 50px; color: #899083; border-top: 1px solid #252a22; }
|
|
199
|
+
.static-page { min-height: calc(100vh - 90px); padding: 14vh 0; border-top: 1px solid #252a22; }
|
|
200
|
+
.static-page h1 { max-width: 850px; font-size: clamp(3.5rem, 9vw, 7rem); }
|
|
201
|
+
.static-page > p:not(.eyebrow) { max-width: 650px; margin-bottom: 36px; color: #aeb5a7; font-size: 1.2rem; line-height: 1.7; }
|
|
202
|
+
@media (max-width: 760px) {
|
|
203
|
+
.site-header { align-items: flex-start; }
|
|
204
|
+
nav { gap: 12px; font-size: .78rem; }
|
|
205
|
+
.hero { min-height: auto; padding: 80px 0; }
|
|
206
|
+
.signals, .capability-grid { grid-template-columns: 1fr; }
|
|
207
|
+
.signals div { border-right: 0; border-bottom: 1px solid #252a22; }
|
|
208
|
+
.demo { grid-template-columns: 1fr; gap: 40px; padding: 80px 0; }
|
|
209
|
+
}
|
|
77
210
|
`,
|
|
78
211
|
"README.md": `# ${name}
|
|
79
212
|
|
|
80
|
-
|
|
213
|
+
This starter is a working Kudzu showcase, not an empty scaffold.
|
|
214
|
+
|
|
215
|
+
- \`src/pages/index.tsx\` demonstrates metadata, state, handlers, and component composition.
|
|
216
|
+
- \`src/pages/about.tsx\` is a static route that ships zero client JavaScript.
|
|
217
|
+
- \`src/components\` contains reusable typed function components.
|
|
218
|
+
- \`src/style.css\` is emitted and linked automatically.
|
|
81
219
|
|
|
82
220
|
\`kudzu.config.mjs\` is optional. Add it only when the project needs a base path, external public directory, transformed source styles, global metadata, navigation groups, or post-build artifacts.
|
|
83
221
|
|
|
@@ -86,6 +224,8 @@ npm run dev
|
|
|
86
224
|
npm run check
|
|
87
225
|
npm run build
|
|
88
226
|
\`\`\`
|
|
227
|
+
|
|
228
|
+
Documentation: https://kudzujs.cloud/docs
|
|
89
229
|
`
|
|
90
230
|
}
|
|
91
231
|
|