140 lines
5.0 KiB
TypeScript
140 lines
5.0 KiB
TypeScript
import { dirname, join } from 'node:path';
|
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
import type { ProjectType } from '../../shared/project-config';
|
|
import vitePackageJson from './project-templates/vite/package.json';
|
|
import vitePackageLock from './project-templates/vite/package-lock.json';
|
|
|
|
const VITE_CONFIG = `import { defineConfig } from 'vite';
|
|
|
|
export default defineConfig({
|
|
base: './',
|
|
});
|
|
`;
|
|
|
|
const MINI_GAME_FILES: Record<string, string> = {
|
|
'index.html': `<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
|
<title>Makelore 小游戏</title>
|
|
<style>
|
|
* { box-sizing: border-box; }
|
|
html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; background: #10233d; }
|
|
body { display: grid; place-items: center; font-family: system-ui, sans-serif; }
|
|
#game { width: 100%; height: 100%; touch-action: none; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<canvas id="game" aria-label="Makelore 小游戏画布"></canvas>
|
|
<script type="module" src="/game.js"></script>
|
|
</body>
|
|
</html>
|
|
`,
|
|
'game.json': `${JSON.stringify({ deviceOrientation: 'portrait', showStatusBar: false }, null, 2)}\n`,
|
|
'game.js': `const canvas = document.querySelector('#game');
|
|
const context = canvas.getContext('2d');
|
|
|
|
function render() {
|
|
const ratio = window.devicePixelRatio || 1;
|
|
const width = window.innerWidth;
|
|
const height = window.innerHeight;
|
|
canvas.width = Math.round(width * ratio);
|
|
canvas.height = Math.round(height * ratio);
|
|
context.setTransform(ratio, 0, 0, ratio, 0, 0);
|
|
|
|
const gradient = context.createLinearGradient(0, 0, 0, height);
|
|
gradient.addColorStop(0, '#10233d');
|
|
gradient.addColorStop(1, '#3a5578');
|
|
context.fillStyle = gradient;
|
|
context.fillRect(0, 0, width, height);
|
|
|
|
context.textAlign = 'center';
|
|
context.fillStyle = '#ffffff';
|
|
context.font = '700 28px system-ui, sans-serif';
|
|
context.fillText('Makelore 小游戏', width / 2, height / 2 - 10);
|
|
context.fillStyle = '#f6b45f';
|
|
context.font = '16px system-ui, sans-serif';
|
|
context.fillText('点击画布,开始创造', width / 2, height / 2 + 26);
|
|
}
|
|
|
|
canvas.addEventListener('pointerdown', (event) => {
|
|
context.beginPath();
|
|
context.fillStyle = '#f26a3d';
|
|
context.arc(event.clientX, event.clientY, 18, 0, Math.PI * 2);
|
|
context.fill();
|
|
});
|
|
window.addEventListener('resize', render);
|
|
render();
|
|
`,
|
|
};
|
|
|
|
const MINI_PROGRAM_FILES: Record<string, string> = {
|
|
'index.html': `<!doctype html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Makelore 小程序</title>
|
|
</head>
|
|
<body>
|
|
<main id="app"></main>
|
|
<script type="module" src="/pages/index/index.js"></script>
|
|
</body>
|
|
</html>
|
|
`,
|
|
'app.json': `${JSON.stringify({ pages: ['pages/index/index'], window: { navigationBarTitleText: 'Makelore 小程序' } }, null, 2)}\n`,
|
|
'app.js': `export const app = {
|
|
globalData: {
|
|
platform: 'makelore',
|
|
},
|
|
};
|
|
`,
|
|
'pages/index/index.json': `${JSON.stringify({ navigationBarTitleText: '首页' }, null, 2)}\n`,
|
|
'pages/index/index.css': `:root {
|
|
color: #24364b;
|
|
background: #f4f7fb;
|
|
font-family: system-ui, sans-serif;
|
|
}
|
|
|
|
body { margin: 0; }
|
|
.page { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
|
|
.card { width: min(420px, 100%); border: 1px solid #d8e1ec; border-radius: 20px; background: #fff; padding: 28px; text-align: center; box-shadow: 0 16px 48px rgb(36 54 75 / 10%); }
|
|
button { border: 0; border-radius: 12px; background: #3a5578; color: #fff; padding: 12px 18px; font: inherit; font-weight: 700; cursor: pointer; }
|
|
`,
|
|
'pages/index/index.js': `import { app } from '../../app.js';
|
|
import './index.css';
|
|
|
|
const root = document.querySelector('#app');
|
|
let count = 0;
|
|
root.innerHTML = \`<section class="page"><div class="card"><p>运行于 \${app.globalData.platform}</p><h1>Makelore 小程序</h1><p id="count">已点击 0 次</p><button type="button">点我试试</button></div></section>\`;
|
|
root.querySelector('button').addEventListener('click', () => {
|
|
count += 1;
|
|
root.querySelector('#count').textContent = \`已点击 \${count} 次\`;
|
|
});
|
|
`,
|
|
};
|
|
|
|
function serializeJson(value: unknown): string {
|
|
return `${JSON.stringify(value, null, 2)}\n`;
|
|
}
|
|
|
|
export async function createPublishableProjectTemplate(
|
|
projectPath: string,
|
|
projectType: Exclude<ProjectType, 'custom'>,
|
|
): Promise<void> {
|
|
const files = projectType === 'mini_game' ? MINI_GAME_FILES : MINI_PROGRAM_FILES;
|
|
const templateFiles: Record<string, string> = {
|
|
'package.json': serializeJson(vitePackageJson),
|
|
'package-lock.json': serializeJson(vitePackageLock),
|
|
'vite.config.js': VITE_CONFIG,
|
|
...files,
|
|
};
|
|
|
|
for (const [relativePath, content] of Object.entries(templateFiles)) {
|
|
const filePath = join(projectPath, relativePath);
|
|
await mkdir(dirname(filePath), { recursive: true });
|
|
await writeFile(filePath, content, { encoding: 'utf8', flag: 'wx' });
|
|
}
|
|
}
|