feat(01-03): wire components in App with Vite + Preact setup

- Create App.jsx importing PersonForm and PeopleList
- Create main.jsx entry point for Preact render
- Add index.html as app entry point
- Add basic CSS styles for layout
- Configure Vite with @preact/preset-vite
- Update vitest config for Preact/jsdom environment
- Add missing dependencies (preact, vite, @preact/preset-vite)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 02:46:25 +00:00
parent 5cf7decd95
commit 708ec8d520
8 changed files with 1689 additions and 188 deletions
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bill Splitter</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
+1565 -187
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -11,10 +11,13 @@
"test:run": "vitest run"
},
"devDependencies": {
"@preact/preset-vite": "^2.8.0",
"jsdom": "^28.1.0",
"vite": "^5.0.0",
"vitest": "^4.0.18"
},
"dependencies": {
"@preact/signals": "^2.8.2"
"@preact/signals": "^2.8.2",
"preact": "^10.19.0"
}
}
+16
View File
@@ -0,0 +1,16 @@
import { PersonForm } from './components/people/PersonForm.jsx';
import { PeopleList } from './components/people/PeopleList.jsx';
export function App() {
return (
<div class="app">
<h1>Bill Splitter</h1>
<section class="people-section">
<h2>People</h2>
<PersonForm />
<PeopleList />
</section>
</div>
);
}
+5
View File
@@ -0,0 +1,5 @@
import { render } from 'preact';
import { App } from './app.jsx';
import './styles/index.css';
render(<App />, document.getElementById('app'));
+79
View File
@@ -0,0 +1,79 @@
* {
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.app h1 {
color: #333;
margin-bottom: 20px;
}
.people-section {
background: #f5f5f5;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
}
.people-section h2 {
margin-top: 0;
color: #555;
}
.person-form {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.person-form input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.person-form button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
.person-form button:hover {
background: #0056b3;
}
.error {
color: #dc3545;
margin: 10px 0 0;
font-size: 14px;
}
.people-list {
list-style: none;
padding: 0;
margin: 0;
}
.people-list li {
padding: 10px;
background: white;
border-radius: 4px;
margin-bottom: 5px;
}
.empty-state {
color: #666;
font-style: italic;
}
+6
View File
@@ -0,0 +1,6 @@
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';
export default defineConfig({
plugins: [preact()],
});
+2
View File
@@ -1,6 +1,8 @@
import { defineConfig } from 'vitest/config';
import preact from '@preact/preset-vite';
export default defineConfig({
plugins: [preact()],
test: {
environment: 'jsdom',
globals: true,