feat: project scaffold — Vite + React + TS + test setup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-30 00:06:14 +00:00
parent f4fab89809
commit 6e83b16c4b
6 changed files with 123 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/assets/logos/logo-icon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MorseQuest</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;700&family=Open+Sans:wght@400;600&family=Source+Code+Pro:wght@400;600&display=swap" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+8
View File
@@ -0,0 +1,8 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<div>MorseQuest loading...</div>
</React.StrictMode>
)
+28
View File
@@ -0,0 +1,28 @@
// Mock AudioContext for tests
class MockAudioContext {
currentTime = 0
destination = {}
state: AudioContextState = 'running'
createOscillator() {
return {
connect: () => {},
start: () => {},
stop: () => {},
frequency: { value: 0 },
type: 'sine' as OscillatorType,
}
}
createGain() {
return {
connect: () => {},
gain: {
value: 1,
setValueAtTime: () => {},
linearRampToValueAtTime: () => {},
},
}
}
async resume() {}
async suspend() {}
}
;(global as any).AudioContext = MockAudioContext
+30
View File
@@ -0,0 +1,30 @@
{
"name": "morsequest",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "concurrently \"node --watch server/server.js\" \"vite\"",
"build": "vite build",
"start": "node server/server.js",
"test": "npm run test:server && npm run test:client",
"test:server": "node --test server/tests/db.test.js server/tests/auth.test.js server/tests/progress.test.js server/tests/admin.test.js",
"test:client": "vitest run"
},
"dependencies": {
"better-sqlite3": "^11.0.0",
"nodemailer": "^6.9.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/better-sqlite3": "^7.6.0",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^4.2.0",
"concurrently": "^8.2.0",
"jsdom": "^24.0.0",
"typescript": "^5.3.0",
"vite": "^5.1.0",
"vitest": "^1.3.0"
}
}
+19
View File
@@ -0,0 +1,19 @@
{
"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,
"noUnusedLocals": false,
"noUnusedParameters": false
},
"include": ["client/src"]
}
+22
View File
@@ -0,0 +1,22 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
root: 'client',
plugins: [react()],
build: {
outDir: 'dist',
emptyOutDir: true,
},
server: {
port: 5173,
proxy: {
'/api': 'http://localhost:3001',
},
},
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['src/test-setup.ts'],
},
})