155 lines
4.8 KiB
TypeScript
155 lines
4.8 KiB
TypeScript
/**
|
|
* Scaffolder template catalog.
|
|
*
|
|
* Templates are pure data — `(projectName) => { [relativePath]: contents }`. New
|
|
* templates are added by appending to `TEMPLATES`; the rest of the scaffolder
|
|
* (validation, IO, command UX) does not need to change.
|
|
*
|
|
* This intentionally mirrors the static/vite-vanilla/vite-react options that
|
|
* Connect_origin's Developer agent ships, but split out of the giant inline
|
|
* function so each template body is grep-friendly.
|
|
*/
|
|
|
|
export type ProjectTemplateId = 'static' | 'vite-vanilla' | 'vite-react';
|
|
|
|
export interface ProjectTemplate {
|
|
id: ProjectTemplateId;
|
|
label: string;
|
|
detail: string;
|
|
/** Returns map of `relativePath -> fileContents`. Project name is already sanitized. */
|
|
files(name: string): Record<string, string>;
|
|
}
|
|
|
|
const README = (name: string, template: string) =>
|
|
`# ${name}\n\n` +
|
|
`Astra의 Project Scaffolder가 ${new Date().toISOString().slice(0, 10)}에 \`${template}\` 템플릿으로 생성한 프로젝트입니다.\n`;
|
|
|
|
export const TEMPLATES: ProjectTemplate[] = [
|
|
{
|
|
id: 'static',
|
|
label: 'static',
|
|
detail: 'index.html 한 장 (Tailwind CDN)',
|
|
files: (name) => ({
|
|
'site/index.html':
|
|
`<!doctype html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<title>${name}</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
</head>
|
|
<body class="bg-zinc-950 text-zinc-100 min-h-screen flex items-center justify-center">
|
|
<main class="text-center space-y-4">
|
|
<h1 class="text-4xl font-bold">${name}</h1>
|
|
<p class="text-zinc-400">Astra · Project Scaffolder</p>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
`,
|
|
'README.md': README(name, 'static'),
|
|
}),
|
|
},
|
|
{
|
|
id: 'vite-vanilla',
|
|
label: 'vite-vanilla',
|
|
detail: 'Vite + 순수 JS',
|
|
files: (name) => ({
|
|
'site/package.json': JSON.stringify({
|
|
name,
|
|
private: true,
|
|
type: 'module',
|
|
scripts: { dev: 'vite', build: 'vite build', preview: 'vite preview' },
|
|
devDependencies: { vite: '^5.0.0' },
|
|
}, null, 2) + '\n',
|
|
'site/index.html':
|
|
`<!doctype html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>${name}</title>
|
|
</head>
|
|
<body>
|
|
<h1>${name}</h1>
|
|
<script type="module" src="/main.js"></script>
|
|
</body>
|
|
</html>
|
|
`,
|
|
'site/main.js':
|
|
`document.querySelector('h1').addEventListener('click', () => {
|
|
console.log('hi from ${name}');
|
|
});
|
|
`,
|
|
'README.md': README(name, 'vite-vanilla'),
|
|
}),
|
|
},
|
|
{
|
|
id: 'vite-react',
|
|
label: 'vite-react',
|
|
detail: 'Vite + React + TypeScript',
|
|
files: (name) => ({
|
|
'site/package.json': JSON.stringify({
|
|
name,
|
|
private: true,
|
|
type: 'module',
|
|
scripts: { dev: 'vite', build: 'tsc && vite build', preview: 'vite preview' },
|
|
dependencies: { react: '^18.3.0', 'react-dom': '^18.3.0' },
|
|
devDependencies: {
|
|
'@types/react': '^18.3.0',
|
|
'@types/react-dom': '^18.3.0',
|
|
'@vitejs/plugin-react': '^4.3.0',
|
|
typescript: '^5.4.0',
|
|
vite: '^5.0.0',
|
|
},
|
|
}, null, 2) + '\n',
|
|
'site/tsconfig.json': JSON.stringify({
|
|
compilerOptions: {
|
|
target: 'ES2020',
|
|
useDefineForClassFields: true,
|
|
lib: ['ES2020', 'DOM', 'DOM.Iterable'],
|
|
module: 'ESNext',
|
|
skipLibCheck: true,
|
|
moduleResolution: 'bundler',
|
|
allowImportingTsExtensions: true,
|
|
resolveJsonModule: true,
|
|
isolatedModules: true,
|
|
noEmit: true,
|
|
jsx: 'react-jsx',
|
|
strict: true,
|
|
},
|
|
include: ['src'],
|
|
}, null, 2) + '\n',
|
|
'site/vite.config.ts':
|
|
`import { defineConfig } from 'vite';
|
|
import react from '@vitejs/plugin-react';
|
|
export default defineConfig({ plugins: [react()] });
|
|
`,
|
|
'site/index.html':
|
|
`<!doctype html>
|
|
<html lang="ko">
|
|
<head><meta charset="utf-8"><title>${name}</title></head>
|
|
<body>
|
|
<div id="root"></div>
|
|
<script type="module" src="/src/main.tsx"></script>
|
|
</body>
|
|
</html>
|
|
`,
|
|
'site/src/main.tsx':
|
|
`import React from 'react';
|
|
import { createRoot } from 'react-dom/client';
|
|
|
|
function App() {
|
|
return <h1>${name}</h1>;
|
|
}
|
|
|
|
createRoot(document.getElementById('root')!).render(<App />);
|
|
`,
|
|
'README.md': README(name, 'vite-react'),
|
|
}),
|
|
},
|
|
];
|
|
|
|
export function findTemplate(id: string): ProjectTemplate | undefined {
|
|
return TEMPLATES.find(t => t.id === id);
|
|
}
|