From f306c634d5b275ef7c73110c61113b64b27edc3e Mon Sep 17 00:00:00 2001 From: Ferdinand Date: Wed, 8 Apr 2026 10:40:32 +0200 Subject: [PATCH] feat: project scaffold with tabs, styles and package.json --- index.html | 29 ++++++++++++++++++++++++++ js/app.js | 25 ++++++++++++++++++++++ package.json | 9 ++++++++ style.css | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 index.html create mode 100644 js/app.js create mode 100644 package.json create mode 100644 style.css diff --git a/index.html b/index.html new file mode 100644 index 0000000..45b3c79 --- /dev/null +++ b/index.html @@ -0,0 +1,29 @@ + + + + + + Morning Meeting Planner + + + + +
+

Morning Meeting Planner

+
+ + + +
+
+ + +
+ + + + diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000..d5d94e3 --- /dev/null +++ b/js/app.js @@ -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(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..9223395 --- /dev/null +++ b/package.json @@ -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" + } +} diff --git a/style.css b/style.css new file mode 100644 index 0000000..02c82a5 --- /dev/null +++ b/style.css @@ -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; }