@@ -41,6 +41,7 @@ const VERSION: string = pkg.version;
4141// Types
4242type PMName = "npm" | "pnpm" | "yarn" | "bun" ;
4343type Framework = "vanilla" | "react" | "preact" ;
44+ type AppMode = "ssr" | "spa" ;
4445type Language = "typescript" | "javascript" ;
4546type TailwindPreset = "none" | "basic" | "shadcn" ;
4647
@@ -182,12 +183,14 @@ function validateProjectName(name: string): true | string {
182183// Template copying
183184function copyTemplate (
184185 framework : Framework ,
186+ appMode : AppMode ,
185187 language : Language ,
186188 projectDir : string ,
187189 projectName : string ,
188190) : void {
189191 const lang = language === "typescript" ? "ts" : "js" ;
190- const templateName = `template-${ framework } -${ lang } ` ;
192+ const suffix = appMode === "spa" && framework !== "vanilla" ? "-spa" : "" ;
193+ const templateName = `template-${ framework } ${ suffix } -${ lang } ` ;
191194 const templateDir = resolve ( __dirname , ".." , templateName ) ;
192195
193196 if ( ! existsSync ( templateDir ) ) {
@@ -422,6 +425,7 @@ function injectCSSImport(entryFilePath: string): void {
422425function scaffoldTailwind (
423426 projectDir : string ,
424427 framework : Framework ,
428+ appMode : AppMode ,
425429 lang : Language ,
426430 preset : TailwindPreset ,
427431) : void {
@@ -451,6 +455,9 @@ function scaffoldTailwind(
451455 if ( framework === "vanilla" ) {
452456 const ext = ts ? "ts" : "js" ;
453457 injectCSSImport ( join ( projectDir , "src" , `index.${ ext } ` ) ) ;
458+ } else if ( appMode === "spa" ) {
459+ const jsxExt = ts ? "tsx" : "jsx" ;
460+ injectCSSImport ( join ( projectDir , "src" , `main.${ jsxExt } ` ) ) ;
454461 } else {
455462 const jsxExt = ts ? "tsx" : "jsx" ;
456463 injectCSSImport ( join ( projectDir , "src" , "routes" , `layout.${ jsxExt } ` ) ) ;
@@ -507,7 +514,25 @@ async function main(): Promise<void> {
507514 ] ,
508515 } ) ;
509516
510- // 3. Variant
517+ // 3. Rendering mode (React / Preact only)
518+ let appMode : AppMode = framework === "vanilla" ? "spa" : "ssr" ;
519+ if ( framework === "react" || framework === "preact" ) {
520+ appMode = await select < AppMode > ( {
521+ message : "Rendering mode:" ,
522+ choices : [
523+ {
524+ name : `${ pc . green ( "SSR" ) } ${ pc . dim ( "(server-side rendering)" ) } ` ,
525+ value : "ssr" as AppMode ,
526+ } ,
527+ {
528+ name : `${ pc . yellow ( "SPA" ) } ${ pc . dim ( "(single-page application)" ) } ` ,
529+ value : "spa" as AppMode ,
530+ } ,
531+ ] ,
532+ } ) ;
533+ }
534+
535+ // 4. Variant
511536 const language = await select < Language > ( {
512537 message : "Select a variant:" ,
513538 choices : [
@@ -516,7 +541,7 @@ async function main(): Promise<void> {
516541 ] ,
517542 } ) ;
518543
519- // 4 . Tailwind
544+ // 5 . Tailwind
520545 const tailwind = await select < TailwindPreset > ( {
521546 message : "Add Tailwind CSS?" ,
522547 choices : [
@@ -529,7 +554,7 @@ async function main(): Promise<void> {
529554 ] ,
530555 } ) ;
531556
532- // 5 . Package manager
557+ // 6 . Package manager
533558 const detectedPM = pmOverride || ( await autoDetectPM ( ) ) ;
534559 const pmChoices : { name : string ; value : PMName } [ ] = [
535560 { name : "npm" , value : "npm" } ,
@@ -546,7 +571,7 @@ async function main(): Promise<void> {
546571 default : detectedPM ,
547572 } ) ;
548573
549- // 6 . Install?
574+ // 7 . Install?
550575 const shouldInstall = skipInstall
551576 ? false
552577 : await confirm ( {
@@ -560,8 +585,8 @@ async function main(): Promise<void> {
560585 console . log ( ) ;
561586
562587 mkdirSync ( projectDir , { recursive : true } ) ;
563- copyTemplate ( framework , language , projectDir , projectName ) ;
564- scaffoldTailwind ( projectDir , framework , language , tailwind ) ;
588+ copyTemplate ( framework , appMode , language , projectDir , projectName ) ;
589+ scaffoldTailwind ( projectDir , framework , appMode , language , tailwind ) ;
565590
566591 // ── Install ─────────────────────────────────────────────────────────
567592 if ( shouldInstall ) {
0 commit comments