| name | project-scaffold |
| description | Scaffold a Vite + TypeScript personal dashboard project with the correct directory structure, dependencies, and configuration files. |
Project Scaffold
Set up a new Vite + TypeScript project for a personal daily monitoring dashboard.
Directory Structure
my-daily-monitor/
├── index.html
├── package.json
├── tsconfig.json
├── vite.config.ts
├── api/ # Serverless API proxy endpoints (Vercel)
│ └── stocks.ts
├── src/
│ ├── main.ts # Entry point
│ ├── components/ # Panel components
│ │ ├── Panel.ts # Base panel class
│ │ ├── StockPanel.ts
│ │ ├── NewsPanel.ts
│ │ └── index.ts
│ ├── services/ # Data fetching services
│ │ ├── stock-market.ts
│ │ ├── news.ts
│ │ └── index.ts
│ ├── utils/ # Utilities
│ │ ├── circuit-breaker.ts
│ │ ├── sparkline.ts
│ │ ├── format.ts
│ │ └── index.ts
│ ├── config/ # Panel config, API endpoints
│ │ └── panels.ts
│ └── styles/
│ └── main.css
└── skills/ # OpenSpace skill files
package.json
{
"name": "my-daily-monitor",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"devDependencies": {
"typescript": "^5.7.2",
"vite": "^6.0.7"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
"noEmit": true,
vite.config.ts
import { defineConfig } from 'vite';
import { resolve } from 'path';
export default defineConfig({
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
},
},
server: {
port: 5173,
},
});
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Daily Monitor</title>
<link rel="stylesheet" href="/src/styles/main.css" />
</head>
<body>
<div id="app">
<header class="app-header">
<h1>My Daily Monitor</h1>
<span class="app-clock" id="headerClock"></span>
</header>
<main class="main-content">
<div class="panels-grid" id=>
src/main.ts (Entry Point)
import './styles/main.css';
import { StockPanel } from './components/StockPanel';
import { NewsPanel } from './components/NewsPanel';
const grid = document.getElementById('panelsGrid')!;
const panels = [
new StockPanel(),
new NewsPanel(),
];
for (const panel of panels) {
grid.appendChild(panel.getElement());
}
function updateClock(): void {
const el = document.getElementById('headerClock');
if (el) el.textContent = new Date().toLocaleTimeString();
}
updateClock();
setInterval(updateClock, 1000);
Key Conventions
- No framework — vanilla TypeScript with DOM API
- Each panel is a class in
src/components/
- Each service is a module in
src/services/
- CSS uses custom properties for theming
- Vite handles bundling, HMR, and path aliases
- API proxy endpoints go in
api/ for serverless deployment
- Panel config in
src/config/panels.ts controls which panels are enabled