feat: project scaffold with tabs, styles and package.json

This commit is contained in:
Ferdinand
2026-04-08 10:40:32 +02:00
parent 0997689d82
commit f306c634d5
4 changed files with 121 additions and 0 deletions

29
index.html Normal file
View File

@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Morning Meeting Planner</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdn.sheetjs.com/xlsx-0.20.3/package/dist/xlsx.full.min.js"></script>
</head>
<body>
<header>
<h1>Morning Meeting Planner</h1>
</header>
<nav class="tabs">
<button class="tab-btn active" data-tab="employees">Mitarbeiter</button>
<button class="tab-btn" data-tab="planning">Monatsplanung</button>
<button class="tab-btn" data-tab="data">Daten</button>
</nav>
<main>
<section id="tab-employees" class="tab-content"></section>
<section id="tab-planning" class="tab-content hidden"></section>
<section id="tab-data" class="tab-content hidden"></section>
</main>
<script type="module" src="js/app.js"></script>
</body>
</html>

25
js/app.js Normal file
View File

@@ -0,0 +1,25 @@
import { renderEmployees } from './employees.js';
import { renderCalendar } from './calendar.js';
import { renderDataTab } from './history.js';
// Shared mutable state — imported by all other modules
export const state = {
employees: [],
calendar: { holidays: [], companyClosures: [] },
history: []
};
// Tab switching
document.querySelectorAll('.tab-btn').forEach(btn => {
btn.addEventListener('click', () => {
const tab = btn.dataset.tab;
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(s => s.classList.add('hidden'));
btn.classList.add('active');
document.getElementById('tab-' + tab).classList.remove('hidden');
if (tab === 'planning') renderCalendar();
if (tab === 'data') renderDataTab();
});
});
renderEmployees();

9
package.json Normal file
View File

@@ -0,0 +1,9 @@
{
"name": "morning-meeting-planner",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "npx serve . -p 3000",
"test": "node tests/algorithm.test.mjs"
}
}

58
style.css Normal file
View File

@@ -0,0 +1,58 @@
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: system-ui, sans-serif;
font-size: 14px;
color: #1a1a1a;
background: #f5f5f5;
}
header { background: #2563eb; color: white; padding: 16px 24px; }
header h1 { font-size: 18px; font-weight: 600; }
.tabs { display: flex; gap: 2px; background: #e5e7eb; padding: 8px 24px 0; }
.tab-btn {
padding: 8px 20px; border: none; background: #d1d5db;
cursor: pointer; border-radius: 6px 6px 0 0; font-size: 14px; color: #374151;
}
.tab-btn.active { background: white; color: #2563eb; font-weight: 600; }
.tab-content { background: white; min-height: calc(100vh - 100px); padding: 24px; }
.hidden { display: none; }
button {
cursor: pointer; padding: 6px 14px; border-radius: 4px;
border: 1px solid #d1d5db; background: white; font-size: 13px;
}
button.primary { background: #2563eb; color: white; border-color: #2563eb; }
button.danger { background: #ef4444; color: white; border-color: #ef4444; }
input, select { padding: 5px 8px; border: 1px solid #d1d5db; border-radius: 4px; font-size: 13px; }
table { border-collapse: collapse; width: 100%; }
th, td { text-align: left; padding: 8px 12px; border-bottom: 1px solid #e5e7eb; }
th { background: #f9fafb; font-weight: 600; }
.section-title { font-size: 16px; font-weight: 600; margin-bottom: 16px; }
.row { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.calendar-outer { overflow-x: auto; }
.calendar-header-grid { display: grid; grid-template-columns: repeat(7,1fr); gap: 6px; margin-bottom: 6px; }
.calendar-body-grid { display: grid; grid-template-columns: repeat(7,1fr); gap: 6px; }
.cal-day { border: 1px solid #e5e7eb; border-radius: 6px; padding: 8px; background: white; min-height: 80px; }
.cal-day.weekend { background: #f3f4f6; color: #9ca3af; }
.cal-day.holiday { background: #fef3c7; }
.cal-day.closure { background: #fee2e2; }
.cal-day.empty-cell { border: none; background: transparent; min-height: 0; }
.day-num { font-weight: 600; font-size: 13px; }
.day-tag { font-size: 10px; color: #6b7280; }
.employee-item { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid #f3f4f6; }
.employee-name { font-weight: 500; flex: 1; }
.constraint-form { background: #f9fafb; padding: 16px; border-radius: 8px; margin-top: 4px; margin-bottom: 8px; }
.constraint-form label { display: block; margin-bottom: 4px; font-size: 12px; color: #6b7280; }
.constraint-row { margin-bottom: 12px; }
.day-toggle-group { display: flex; gap: 4px; }
.day-toggle {
width: 32px; height: 32px; border-radius: 50%; border: 1px solid #d1d5db;
background: white; font-size: 11px; cursor: pointer;
}
.day-toggle.active { background: #2563eb; color: white; border-color: #2563eb; }