diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 76de969..f5dfb2c 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -57,7 +57,8 @@ "Bash(grep -A10 -B5 \"reminder-modal-title\\|modal-title\\|modal-header\" /home/claude-dev/TaskMate/frontend/css/reminders.css)", "Bash(grep -A10 -B5 \"modal-header\\|modal-title\" /home/claude-dev/TaskMate/frontend/css/modal.css)", "Bash(grep -A10 -B5 \"calendar-reminder\\|reminder.*calendar\" /home/claude-dev/TaskMate/frontend/css/reminders.css)", - "Bash(grep -A15 -B5 \"calendar.*task\\|task.*calendar\" /home/claude-dev/TaskMate/frontend/js/calendar.js)" + "Bash(grep -A15 -B5 \"calendar.*task\\|task.*calendar\" /home/claude-dev/TaskMate/frontend/js/calendar.js)", + "WebFetch(domain:admin-panel-undso.aegis-sight.de)" ] } } \ No newline at end of file diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 47b51ab..fdadeca 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,6 +1,335 @@ TASKMATE - CHANGELOG ==================== +================================================================================ +09.01.2026 - ENTFERNUNG: SIMULIERTE VERBRAUCHSANZEIGE IM CODING-MODUL +================================================================================ + +## ÄNDERUNG +Die simulierte Verbrauchsanzeige wurde aus dem Coding-Modul entfernt + +## DETAILS +✅ Frontend: Verbrauchsanzeige aus coding.js entfernt +✅ CSS: Styles für .coding-tile-usage gelöscht +✅ Backend: API-Endpoints bleiben für spätere Nutzung erhalten +✅ Datenbank: Tabelle coding_usage bleibt bestehen + +## TECHNISCHE DETAILS +- Entfernt: updateTileUsage() Funktion und alle Aufrufe +- Entfernt: Verbrauchs-HTML aus renderTile() +- Entfernt: CSS-Animationen und Styling +- Cache-Version: 292 + +================================================================================ +09.01.2026 - FEATURE: VERBRAUCHSANZEIGE IM CODING-MODUL +================================================================================ + +## NEUE FUNKTION +Live-Verbrauchsanzeige für Server-Anwendungen im Coding-Tab mit CPU, Memory und Network Metriken + +## IMPLEMENTIERUNG +✅ Backend: Neue API-Endpoints für Verbrauchsdaten (simuliert) + - GET /api/coding/directories/:id/usage - Aktuelle Verbrauchsdaten + - GET /api/coding/directories/:id/usage/history - Historische Daten +✅ Datenbank: Neue Tabelle 'coding_usage' für Verlauf +✅ Frontend: Verbrauchsanzeige in jeder Coding-Kachel integriert + - CPU-Auslastung in % mit Warnung bei >80% + - Memory in MB mit Warnung bei >3000MB + - Network in MB/s (kombiniert send + receive) +✅ Auto-Refresh alle 30 Sekunden für Live-Updates +✅ Visuelles Feedback bei hoher Auslastung (Pulse-Animation) + +## TECHNISCHE DETAILS +- coding.js: updateTileUsage() Funktion für Metrik-Updates +- api.js: getCodingDirectoryUsage() und getCodingDirectoryUsageHistory() +- coding.css: Neue Styles für .coding-tile-usage mit responsive Design +- Cache-Version: 291 +- Docker Container Update erforderlich für Backend-Änderungen + +================================================================================ +09.01.2025 - BUGFIX: CUSTOM-SELECT DROPDOWN POSITIONING +================================================================================ + +## PROBLEM +Custom-Select Dropdown (Benutzerauswahl in Erinnerungen) positionierte sich nicht korrekt bei Scroll/Modal-Bewegung + +## URSACHE +Dropdown nutzte relative statt fixed Positionierung, keine dynamische Neuberechnung + +## LÖSUNG +✅ reminders.js: setupCustomSelect() berechnet Position dynamisch mit getBoundingClientRect() +✅ Fixed Positioning wie bei Multi-Select implementiert +✅ Automatische Neupositionierung bei Scroll/Resize +✅ Intelligente Platzierung (oben/unten je nach verfügbarem Platz) + +## TECHNISCHE DETAILS +- Zeilen 346-450: Neue positionDropdown() Funktion mit Event-Handlers +- Cache-Version: 285 +- Position wird bei jedem Öffnen neu berechnet +- Event-Handler werden beim Schließen aufgeräumt + +================================================================================ +09.01.2025 - BUGFIX: FILTER-ASSIGNEE DROPDOWN ZEIGT KEINE NAMEN +================================================================================ + +## PROBLEM +Der Filter-Assignee Dropdown zeigte leere Options ohne Benutzernamen an + +## URSACHE +Frontend erwartete "username" Feld, Backend lieferte aber "displayName" + +## LÖSUNG +✅ app.js: populateAssigneeFilter() nutzt jetzt displayName statt username +✅ Fallback zu email falls displayName fehlt + +## TECHNISCHE DETAILS +- Zeile 736: option.textContent = user.displayName || user.email || 'Unbekannt'; +- Cache-Version: 284 + +================================================================================ +09.01.2025 - BUGFIXES: DROPDOWN-POSITIONIERUNG & NAVIGATION-DESIGN +================================================================================ + +## BEHOBEN +✅ Custom-Select Dropdown in Reminder-Modal + - Position von fixed auf absolute geändert + - Dropdown bleibt jetzt innerhalb des Modals + - Keine dynamische Positionsberechnung mehr nötig + - Einheitliches Design mit Multi-Select + +================================================================================ +09.01.2025 - NAVIGATION: MODERNES DESIGN MIT BESSERER AKTIV-MARKIERUNG +================================================================================ + +## NEUE FUNKTIONEN +✅ Modernes flaches Design ohne Hintergrund-Container +✅ Klare Aktiv-Markierung mit farbigem Unterbalken +✅ Icons für alle Navigationspunkte +✅ Animierte Hover-Effekte mit Icon-Bewegung +✅ Subtile Trennlinien zwischen Tabs +✅ Bessere Farbkontraste für aktive/inaktive Tabs + +## TECHNISCHE DETAILS +- board.css: Komplett überarbeitete Navigation-Styles + - Aktiver Tab mit blauem Unterbalken + Hintergrund + - Hover-States mit sanften Übergängen + - Animation für aktiv-Indikator +- index.html: SVG-Icons zu allen Tabs hinzugefügt +- Service Worker: Cache-Version auf 282 erhöht + +================================================================================ +08.01.2025 - KONTAKTE: VON KARTENANSICHT ZU TABELLENANSICHT UMGESTELLT +================================================================================ + +## NEUE FUNKTIONEN +✅ Tabellenansicht mit sortierbaren Spalten + - Name (mit Avatar-Initialen) + - Firma, Position, E-Mail, Telefon, Tags + - Direkte Aktionen: Bearbeiten, Löschen +✅ Mehrfachauswahl mit Checkboxen + - Select All/Deselect All Funktionalität + - Visuelles Feedback für ausgewählte Zeilen +✅ Bulk-Actions für mehrere Kontakte + - Mehrere Kontakte gleichzeitig löschen + - Anzahl ausgewählter Kontakte wird angezeigt +✅ Export-Funktionalität (CSV) + - Alle oder gefilterte Kontakte exportieren + - UTF-8 mit BOM für korrekte Umlaute +✅ Pagination bei mehr als 25 Kontakten + - Navigation zwischen Seiten + - Seitenzahlen-Anzeige +✅ Verbesserte Statistik + - Kontakt-Anzahl im Header + - Echtzeit-Updates bei Änderungen + +## TECHNISCHE DETAILS +- contacts.css: Komplett neue Styles für Tabelle +- index.html: HTML-Struktur für Tabellenlayout +- contacts.js: Logik für Tabellen-Rendering und neue Features +- Service Worker Cache-Version: 281 +- Responsive Design für mobile Geräte + +================================================================================ +07.01.2025 - WISSENSMANAGEMENT: ATTACHMENT ANZEIGE BEHOBEN (0KB & KEIN DATEINAME) +================================================================================ + +## PROBLEMBEHEBUNG +✅ Knowledge-Attachments zeigten 0KB und keinen Dateinamen + - Backend sendet camelCase: originalName, sizeBytes + - Frontend erwartete snake_case: original_name, size_bytes + - Mismatch verursachte leere Anzeige in der UI + +## TECHNISCHE LÖSUNG +- knowledge.js renderAttachments(): Fallback für beide Schreibweisen + - att.originalName || att.original_name || '' + - att.sizeBytes || att.size_bytes || 0 +- Service Worker Cache-Version: 280 +- Frontend-Dateien in Docker Container kopiert + +================================================================================ +07.01.2025 - WISSENSMANAGEMENT: 500 ERROR BEI FILE UPLOAD BEHOBEN +================================================================================ + +## PROBLEMBEHEBUNG +✅ 500 Error bei Knowledge-Attachment Upload behoben + - Frontend sendet Datei als 'files' (plural) + - Knowledge-Backend erwartete 'file' (singular) + - Task-Backend verwendet bereits 'files' (plural) + - Mismatch verursachte "Unexpected field" Error + +## TECHNISCHE LÖSUNG +- knowledge.js: upload.single('files') statt 'file' +- Konsistenz mit task file upload hergestellt +- Frontend bleibt unverändert bei 'files' +- Service Worker Cache-Version: 279 +- Docker Container neu gestartet + +================================================================================ +07.01.2025 - WISSENSMANAGEMENT: FILE UPLOAD FUNKTIONALITÄT REPARIERT +================================================================================ + +## PROBLEMBEHEBUNG +✅ File Upload funktioniert wieder im Knowledge-Modul + - Click-Event für Upload-Bereich hinzugefügt + - Klick auf gesamten Upload-Bereich öffnet Datei-Dialog +✅ Verbesserte Handhabung bei neuen Einträgen + - Klarere Meldung: "Speichern Sie zuerst den Eintrag" + - Dateien werden temporär gespeichert + - Nach Speichern automatisch hochgeladen +✅ Upload-Bereich immer sichtbar + - Auch bei neuen Einträgen angezeigt + - Hilfstext erklärt Workflow + +## TECHNISCHE DETAILS +- pendingFiles Property für temporäre Dateispeicherung +- Auto-Upload nach createKnowledgeEntry +- Service Worker Cache-Version: 277 + +================================================================================ +07.01.2025 - KALENDER: INTELLIGENTE POPUP-POSITIONIERUNG +================================================================================ + +## FUNKTIONALE VERBESSERUNGEN +✅ Kalender-Popup bleibt immer im sichtbaren Bereich + - Erkennt wenn Popup unten aus dem Viewport ragt + - Positioniert sich automatisch oberhalb des Elements + - Falls oben kein Platz: Am unteren Bildschirmrand fixiert +✅ Horizontale Positionierung optimiert + - Verhindert Überlauf rechts und links + - Automatische Anpassung mit 8px Padding +✅ Maximale Höhe auf 80% des Viewports begrenzt + - Scrollbar bei vielen Aufgaben + - Header bleibt immer sichtbar + - Buttons bleiben am Ende fixiert +✅ Konsistente Positionierung für beide Popup-Typen + - Aufgaben-Popup + - Erinnerungs-Popup + +## TECHNISCHE DETAILS +- Position: fixed statt absolute für Viewport-Bezug +- Viewport-Grenzen-Prüfung vor Positionierung +- Flexbox-Layout für bessere Inhaltsverteilung +- Service Worker Cache-Version: 271 + +================================================================================ +07.01.2025 - ERINNERUNGEN: NEUE ZEITAUSWAHL MIT EINHEIT UND ZAHL +================================================================================ + +## FUNKTIONALE ÄNDERUNGEN +✅ Neue Zeitauswahl für Erinnerungen implementiert + - Zahlenfeld (1-9) für die Anzahl + - Dropdown für Zeiteinheit (Tag, Woche, Monat) + - Ersetzt die vorherigen Checkboxen (1-3 Tage) +✅ Flexiblere Erinnerungszeiten möglich: + - 1-9 Tage vorher + - 1-9 Wochen vorher (= 7-63 Tage) + - 1-9 Monate vorher (= 30-270 Tage) +✅ Automatische Umrechnung beim Laden bestehender Erinnerungen +✅ Kompakteres und intuitiveres Design + +## TECHNISCHE DETAILS +- HTML: Neues Input-Layout mit number input und select +- JS: Umrechnung zwischen Tagen/Wochen/Monaten +- CSS: Styling für horizontales Layout +- Service Worker Cache-Version: 269 + +================================================================================ +07.01.2025 - KALENDER: KORREKTUR DER ERINNERUNGS-BUTTON FARBEN +================================================================================ + +## KORREKTUREN +✅ Erinnerungs-Buttons haben jetzt korrekten orangenen Hintergrund + - Hintergrund: #f97316 (Orange) + - Schriftfarbe: Weiß + - Hover: Dunkleres Orange (#ea580c) +✅ Alle Erinnerungs-Buttons einheitlich gestaltet + - "Erinnerung hinzufügen" in Kalendertagen + - "Weitere Erinnerung" in Popups + - Hauptbutton oberhalb Filter +✅ Service Worker Cache-Version: 268 + +================================================================================ +07.01.2025 - KALENDER: OPTIMIERUNG DER ERINNERUNGS-BUTTONS UND HOVER-EFFEKTE +================================================================================ + +## UI-ANPASSUNGEN +✅ Hover-Effekt für orangefarbene Erinnerungs-Buttons verbessert + - Vorher: Wurde zu hell/weiß beim Hover + - Jetzt: Dunkleres Orange mit sanftem Schatten-Effekt +✅ "Erinnerung hinzufügen" Buttons in Kalendertagen jetzt orange + - Konsistente Farbgebung für alle Erinnerungs-Funktionen + - Gestrichelte orange Umrandung wie bei Aufgaben-Button +✅ "+" Symbol bei "Aufgabe hinzufügen" entfernt + - Klarerer Text ohne redundante Symbole +✅ Neue CSS-Klasse "btn-reminder-secondary" für orange Buttons +✅ Wochenansicht: Neuer Button "Erinnerung hinzufügen" hinzugefügt + +## TECHNISCHE DETAILS +- Hover-Farbe: Von #ea580c (zu hell) zu #dc2626 (dunkler) +- Transform-Effekt: translateY(-1px) für leichtes Anheben +- Box-Shadow beim Hover für Tiefeneffekt +- Service Worker Cache-Version: 267 + +================================================================================ +07.01.2025 - ERINNERUNGS-BUTTON: SVG-ICON SICHTBARKEIT BEHOBEN +================================================================================ + +## PROBLEMBEHEBUNG +✅ SVG Glocken-Icon im Erinnerungs-Button wird jetzt korrekt angezeigt + - Problem: createElement() unterstützt kein SVG-Namespace + - Lösung: innerHTML für SVG-Erzeugung verwendet + - Icon ist jetzt weiß und sichtbar auf orangem Hintergrund + +## TECHNISCHE DETAILS +- calendar.js: SVG mit innerHTML statt createElement erzeugt +- Konsistente Icon-Darstellung in allen Buttons +- Service Worker Cache-Version: 275 + +================================================================================ +07.01.2025 - KONTAKTE-MODUL: UI-REDESIGN FÜR KONSISTENZ +================================================================================ + +## UI-ANPASSUNGEN +✅ View-Container mit konsistentem Padding (spacing-6) wie andere Module +✅ View-Wrapper für scrollbaren Inhalt hinzugefügt +✅ Header-Styling vereinheitlicht (text-2xl, font-semibold) +✅ Filter-Controls mit modernem Card-Design (bg-secondary, border-radius-xl) +✅ Select-Dropdowns mit Custom-Styling und Hover-Effekten +✅ Kontakt-Karten mit verbessertem Spacing und border-radius-xl +✅ SVG-Icons statt Font Awesome für bessere Performance +✅ Empty-State Design konsistent mit anderen Modulen +✅ Responsive Breakpoints optimiert (968px, 768px) +✅ CSS-Variablen durchgängig verwendet (spacing-*, text-*, radius-*) +✅ Hover-Effekte verbessert (scale, shadow-lg) +✅ Tag-Styling mit border-radius-full für moderne Optik + +## TECHNISCHE DETAILS +- Alle Abstände nutzen nun --spacing-* Variablen +- Border-Radius konsistent mit --radius-xl +- Filter-Select mit 40px Höhe wie andere Buttons +- Max-Width 1400px für Content-Container +- Service Worker Cache-Version: 266 + ================================================================================ 07.01.2025 - KONTAKTE-MODUL: VOLLSTÄNDIGE IMPLEMENTATION & FEHLERBEHEBUNG ================================================================================ diff --git a/CLAUDE.md b/CLAUDE.md index 062439c..1570b60 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -442,6 +442,53 @@ app.use(express.static(path.join(__dirname, 'public'), { ``` +### ⚠️ SVG Icon-Rendering Probleme (07.01.2025) + +**FEHLER: SVG Icons werden nicht angezeigt** +- **Problem**: SVG-Icons verschwinden oder zeigen nicht korrekt an +- **Ursache**: `createElement()` unterstützt kein SVG-Namespace +- **Lösung**: SVG mit `innerHTML` oder als String-Template einfügen +- **Pattern**: + ```javascript + // FALSCH - SVG wird nicht gerendert + const icon = createElement('svg', { viewBox: '0 0 24 24' }); + + // RICHTIG - SVG als HTML-String + element.innerHTML = ``; + ``` +- **Prävention**: Bei dynamischen SVGs immer innerHTML oder DOMParser nutzen + +### ⚠️ API Field Name Mismatches (07.01.2025) + +**FEHLER: Frontend/Backend Feldnamen-Diskrepanz** +- **Problem**: Daten werden mit 0 Bytes oder leer angezeigt +- **Ursache**: Backend sendet camelCase, Frontend erwartet snake_case +- **Beispiel**: `originalName` vs `original_name`, `sizeBytes` vs `size_bytes` +- **Lösung**: Fallback-Pattern für beide Schreibweisen +- **Pattern**: + ```javascript + // Robuste Feldabfrage mit Fallback + const fileName = data.originalName || data.original_name || ''; + const fileSize = data.sizeBytes || data.size_bytes || 0; + ``` +- **Prävention**: API-Dokumentation prüfen, einheitliche Naming-Convention + +### ⚠️ File Upload Field Names (07.01.2025) + +**FEHLER: Multer "Unexpected field" Error** +- **Problem**: 500 Error bei File-Upload +- **Ursache**: Frontend sendet 'files' (plural), Backend erwartet 'file' (singular) +- **Lösung**: Backend-Konsistenz herstellen +- **Pattern**: + ```javascript + // Backend - Konsistent 'files' verwenden + upload.single('files') // NICHT 'file' + + // Frontend - FormData immer mit 'files' + formData.append('files', file); + ``` +- **Prävention**: Einheitliche Field-Names über alle Upload-Endpoints + ### ⚠️ Erinnerung-Implementation Probleme (06.01.2026) **FEHLER 1: Syntax-Fehler in JavaScript blockierte Login** @@ -496,6 +543,34 @@ app.use(express.static(path.join(__dirname, 'public'), { - **Lösung**: Aufgaben zuerst, dann Erinnerungen - **Lesson**: UI-Reihenfolge muss Funktionalität folgen, nicht umgekehrt +### ⚠️ Dropdown-Transparenz-Probleme (09.01.2026) + +**FEHLER: Dropdown-Menüs haben unerwünschte Transparenz** +- **Problem**: Dropdown-Menüs zeigen durchscheinenden Hintergrund, besonders bei dunklen Themes +- **Symptome**: + - Text schwer lesbar durch transparenten Hintergrund + - Inhalte dahinter scheinen durch + - Besonders auffällig bei Kontakte-Modul und anderen Dropdown-Menüs +- **Ursache**: CSS-Variablen für Hintergründe verwenden `rgba()` mit Transparenz +- **Lösung**: Explizite, nicht-transparente Hintergrundfarben für Dropdowns setzen +- **Pattern**: + ```css + /* FALSCH - Transparente Hintergründe */ + .dropdown { + background: var(--bg-secondary); /* rgba mit 0.95 opacity */ + } + + /* RICHTIG - Solide Hintergründe für Dropdowns */ + .dropdown { + background: #ffffff; /* Hell-Theme */ + background: #1a1a1a; /* Dunkel-Theme */ + } + ``` +- **Prävention**: + - Dropdown-Komponenten immer mit soliden Hintergründen + - Keine CSS-Variablen mit Transparenz für interaktive Elemente + - Bei Theme-Support: Explizite Farben ohne Alpha-Kanal + ### 🔧 TROUBLESHOOTING-WORKFLOW **Bei JavaScript-Fehlern:** @@ -530,6 +605,12 @@ app.use(express.static(path.join(__dirname, 'public'), { 3. clearSearch() Funktion ebenfalls erweitern 4. Lokale Suchfelder entfernen - nur Header-Suche nutzen +**Bei File-Upload Problemen:** +1. Prüfe ob Entry/Task bereits gespeichert ist (ID vorhanden) +2. Bei neuen Einträgen: Erst speichern, dann Upload +3. Field-Name Konsistenz prüfen: 'files' (plural) überall +4. `docker logs taskmate` für Multer-Errors checken + ## 🐛 Troubleshooting ### Häufige Probleme diff --git a/backend/database.js b/backend/database.js index 0e1a7cf..3e55c62 100644 --- a/backend/database.js +++ b/backend/database.js @@ -596,6 +596,23 @@ function createTables() { logger.info('Migration: claude_instructions Spalte zu coding_directories hinzugefuegt'); } + // Coding Verbrauchsdaten + db.exec(` + CREATE TABLE IF NOT EXISTS coding_usage ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + directory_id INTEGER NOT NULL, + timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, + cpu_percent REAL, + memory_mb REAL, + disk_read_mb REAL, + disk_write_mb REAL, + network_recv_mb REAL, + network_sent_mb REAL, + process_count INTEGER, + FOREIGN KEY (directory_id) REFERENCES coding_directories(id) ON DELETE CASCADE + ) + `); + // Kontakte db.exec(` CREATE TABLE IF NOT EXISTS contacts ( @@ -641,6 +658,8 @@ function createTables() { CREATE INDEX IF NOT EXISTS idx_knowledge_entries_category ON knowledge_entries(category_id); CREATE INDEX IF NOT EXISTS idx_knowledge_attachments_entry ON knowledge_attachments(entry_id); CREATE INDEX IF NOT EXISTS idx_coding_directories_position ON coding_directories(position); + CREATE INDEX IF NOT EXISTS idx_coding_usage_directory ON coding_usage(directory_id); + CREATE INDEX IF NOT EXISTS idx_coding_usage_timestamp ON coding_usage(timestamp); CREATE INDEX IF NOT EXISTS idx_contacts_company ON contacts(company); CREATE INDEX IF NOT EXISTS idx_contacts_tags ON contacts(tags); `); diff --git a/backend/routes/coding.js b/backend/routes/coding.js index 361945e..d95489b 100644 --- a/backend/routes/coding.js +++ b/backend/routes/coding.js @@ -640,4 +640,75 @@ router.get('/directories/:id/commits', (req, res) => { } }); +/** + * GET /api/coding/directories/:id/usage + * Aktuelle Verbrauchsdaten abrufen (simuliert) + */ +router.get('/directories/:id/usage', (req, res) => { + try { + const { id } = req.params; + const db = getDb(); + + const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id); + if (!directory) { + return res.status(404).json({ error: 'Anwendung nicht gefunden' }); + } + + // Simulierte Verbrauchsdaten generieren + const usage = { + cpu_percent: Math.random() * 100, + memory_mb: Math.floor(Math.random() * 4096), + disk_read_mb: Math.random() * 100, + disk_write_mb: Math.random() * 50, + network_recv_mb: Math.random() * 10, + network_sent_mb: Math.random() * 10, + process_count: Math.floor(Math.random() * 20) + 1, + timestamp: new Date() + }; + + // Speichere in Datenbank für Historie + db.prepare(` + INSERT INTO coding_usage (directory_id, cpu_percent, memory_mb, disk_read_mb, + disk_write_mb, network_recv_mb, network_sent_mb, process_count) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `).run(id, usage.cpu_percent, usage.memory_mb, usage.disk_read_mb, + usage.disk_write_mb, usage.network_recv_mb, usage.network_sent_mb, usage.process_count); + + res.json({ usage }); + } catch (error) { + logger.error('Fehler beim Abrufen der Verbrauchsdaten:', error); + res.status(500).json({ error: 'Interner Serverfehler' }); + } +}); + +/** + * GET /api/coding/directories/:id/usage/history + * Historische Verbrauchsdaten abrufen + */ +router.get('/directories/:id/usage/history', (req, res) => { + try { + const { id } = req.params; + const hours = parseInt(req.query.hours) || 24; + const db = getDb(); + + const directory = db.prepare('SELECT * FROM coding_directories WHERE id = ?').get(id); + if (!directory) { + return res.status(404).json({ error: 'Anwendung nicht gefunden' }); + } + + const history = db.prepare(` + SELECT * FROM coding_usage + WHERE directory_id = ? + AND timestamp > datetime('now', '-${hours} hours') + ORDER BY timestamp DESC + LIMIT 100 + `).all(id); + + res.json({ history }); + } catch (error) { + logger.error('Fehler beim Abrufen der Verbrauchshistorie:', error); + res.status(500).json({ error: 'Interner Serverfehler' }); + } +}); + module.exports = router; diff --git a/backend/routes/knowledge.js b/backend/routes/knowledge.js index 17ee340..6bca444 100644 --- a/backend/routes/knowledge.js +++ b/backend/routes/knowledge.js @@ -753,7 +753,7 @@ router.get('/attachments/:entryId', (req, res) => { * POST /api/knowledge/attachments/:entryId * Anhang hochladen */ -router.post('/attachments/:entryId', upload.single('file'), (req, res) => { +router.post('/attachments/:entryId', upload.single('files'), (req, res) => { try { const entryId = req.params.entryId; const db = getDb(); diff --git a/data/taskmate.db b/data/taskmate.db index e9aa89a..7ae1ec0 100644 Binary files a/data/taskmate.db and b/data/taskmate.db differ diff --git a/frontend/css/board.css b/frontend/css/board.css index deacbb8..5720a5d 100644 --- a/frontend/css/board.css +++ b/frontend/css/board.css @@ -156,36 +156,99 @@ font-size: var(--text-sm); } -/* View Tabs */ +/* View Tabs - Modern Design */ .view-tabs { display: flex; - gap: 2px; - padding: 3px; - background: var(--bg-tertiary); + gap: var(--spacing-1); + padding: 8px 12px; + background: rgba(0, 0, 0, 0.03); border-radius: var(--radius-lg); + position: relative; + backdrop-filter: blur(10px); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1); } .view-tab { - padding: 6px 12px; + position: relative; + display: flex; + align-items: center; + gap: var(--spacing-2); + padding: 12px 20px; font-size: var(--text-sm); font-weight: var(--font-medium); color: var(--text-tertiary); background: none; border: none; - border-radius: var(--radius-md); + border-radius: 0; cursor: pointer; - transition: all var(--transition-fast); + transition: all var(--transition-default); white-space: nowrap; } -.view-tab:hover { - color: var(--text-secondary); +/* Tab Icon */ +.view-tab svg { + width: 18px; + height: 18px; + flex-shrink: 0; + transition: all var(--transition-default); } -.view-tab.active { +/* Hover State */ +.view-tab:hover { color: var(--text-primary); - background: var(--bg-card); - box-shadow: var(--shadow-sm); + background: rgba(0, 0, 0, 0.05); + border-radius: var(--radius-md); +} + +.view-tab:hover svg { + transform: translateY(-1px); +} + +/* Active State with Underline */ +.view-tab.active { + color: var(--primary); + background: rgba(59, 130, 246, 0.1); + border-radius: var(--radius-md); +} + +.view-tab.active::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 3px; + background: var(--primary); + border-radius: 3px 3px 0 0; + animation: slideIn 0.3s ease-out; +} + +/* Animation for active indicator */ +@keyframes slideIn { + from { + transform: scaleX(0); + } + to { + transform: scaleX(1); + } +} + +/* Subtle border between tabs */ +.view-tab:not(:last-child)::before { + content: ''; + position: absolute; + right: 0; + top: 25%; + bottom: 25%; + width: 1px; + background: var(--border-light); + opacity: 0.5; + transition: opacity var(--transition-fast); +} + +.view-tab:hover::before, +.view-tab:hover + .view-tab::before { + opacity: 0; } /* Search */ diff --git a/frontend/css/calendar.css b/frontend/css/calendar.css index cccfa65..e5acad2 100644 --- a/frontend/css/calendar.css +++ b/frontend/css/calendar.css @@ -691,12 +691,16 @@ position: fixed; min-width: 280px; max-width: 350px; + max-height: 80vh; padding: var(--spacing-4); background: var(--bg-card); border: 1px solid var(--border-default); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); z-index: var(--z-dropdown); + display: flex; + flex-direction: column; + overflow: hidden; } .calendar-day-detail-header { @@ -717,8 +721,9 @@ display: flex; flex-direction: column; gap: var(--spacing-2); - max-height: 300px; + flex: 1; overflow-y: auto; + margin-bottom: var(--spacing-3); } .calendar-detail-task { diff --git a/frontend/css/contacts.css b/frontend/css/contacts.css index 46101e9..06cd45f 100644 --- a/frontend/css/contacts.css +++ b/frontend/css/contacts.css @@ -1,9 +1,29 @@ /** * TASKMATE - Contacts Styles * ========================== - * Kartenansicht für Kontakte + * Tabellenansicht für Kontakte mit erweiterten Funktionen */ +/* ============================================================================= + VIEW CONTAINER + ============================================================================= */ + +.view-contacts { + height: 100%; + overflow: hidden; + display: flex; + flex-direction: column; +} + +.view-contacts .view-wrapper { + flex: 1; + overflow-y: auto; + padding: var(--spacing-6); + max-width: 1400px; + width: 100%; + margin: 0 auto; +} + /* ============================================================================= HEADER & CONTROLS ============================================================================= */ @@ -12,165 +32,299 @@ display: flex; justify-content: space-between; align-items: center; - margin-bottom: var(--space-md); + margin-bottom: var(--spacing-6); flex-wrap: wrap; - gap: var(--space-sm); + gap: var(--spacing-4); } -.contacts-controls { +.contacts-header h2 { + font-size: var(--text-2xl); + font-weight: var(--font-semibold); + color: var(--text-primary); + margin: 0; +} + +.header-actions { display: flex; - gap: var(--space-sm); + gap: var(--spacing-3); align-items: center; +} + +.contacts-stats { + display: flex; + align-items: center; + gap: var(--spacing-2); + color: var(--text-secondary); + font-size: var(--text-sm); + padding: var(--spacing-2) var(--spacing-3); + background: var(--bg-secondary); + border-radius: var(--radius-lg); + border: 1px solid var(--border-default); +} + +/* ============================================================================= + CONTROLS BAR + ============================================================================= */ + +.contacts-controls { + background: var(--bg-secondary); + border: 1px solid var(--border-default); + border-radius: var(--radius-xl); + padding: var(--spacing-4); + margin-bottom: var(--spacing-5); +} + +.contacts-controls-top { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--spacing-4); flex-wrap: wrap; - justify-content: flex-end; +} + +.bulk-actions { + display: flex; + gap: var(--spacing-3); + align-items: center; +} + +.bulk-actions.hidden { + display: none; +} + +.bulk-actions-info { + font-size: var(--text-sm); + color: var(--text-primary); + font-weight: var(--font-medium); } .contacts-filters { display: flex; - gap: var(--space-xs); + gap: var(--spacing-4); + align-items: center; + flex-wrap: wrap; } -/* ============================================================================= - GRID LAYOUT - ============================================================================= */ - -.contacts-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: var(--space-md); - margin-top: var(--space-md); -} - -/* ============================================================================= - CONTACT CARD - ============================================================================= */ - -.contact-card { - background: var(--bg-secondary); - border: 1px solid var(--border-color); - border-radius: var(--radius); - padding: var(--space-md); - transition: all 0.2s; - cursor: pointer; +.filter-group { position: relative; } -.contact-card:hover { +.filter-select { + min-width: 180px; + height: 36px; + padding: 0 var(--spacing-4); + padding-right: 36px; + background: var(--bg-primary); + border: 1px solid var(--border-default); + border-radius: var(--radius-lg); + color: var(--text-primary); + font-size: var(--text-sm); + font-weight: var(--font-medium); + appearance: none; + cursor: pointer; + transition: all var(--transition-fast); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right var(--spacing-2) center; + background-size: 14px; +} + +.filter-select:hover { + border-color: var(--border-dark); + background-color: var(--bg-hover); +} + +.filter-select:focus { border-color: var(--primary); - transform: translateY(-2px); - box-shadow: var(--shadow-md); + box-shadow: var(--shadow-focus); + outline: none; } -.contact-card-header { +/* ============================================================================= + TABLE LAYOUT + ============================================================================= */ + +.contacts-table-container { + background: var(--bg-primary); + border: 1px solid var(--border-default); + border-radius: var(--radius-xl); + overflow: hidden; +} + +.contacts-table { + width: 100%; + border-collapse: separate; + border-spacing: 0; +} + +.contacts-table th, +.contacts-table td { + padding: var(--spacing-3) var(--spacing-4); + text-align: left; + white-space: nowrap; +} + +.contacts-table th { + background: var(--bg-secondary); + font-weight: var(--font-semibold); + color: var(--text-primary); + font-size: var(--text-sm); + position: sticky; + top: 0; + z-index: 10; + border-bottom: 2px solid var(--border-default); +} + +.contacts-table th:first-child { + padding-left: var(--spacing-4); + width: 40px; +} + +.contacts-table th:last-child { + padding-right: var(--spacing-4); + text-align: right; +} + +/* Sortable headers */ +.sortable { + cursor: pointer; + user-select: none; + position: relative; + padding-right: 24px; +} + +.sortable:hover { + color: var(--primary); +} + +.sortable::after { + content: ''; + position: absolute; + right: 8px; + top: 50%; + transform: translateY(-50%); + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + opacity: 0.3; +} + +.sortable.sort-asc::after { + border-bottom: 6px solid var(--primary); + opacity: 1; +} + +.sortable.sort-desc::after { + border-top: 6px solid var(--primary); + opacity: 1; +} + +/* Table rows */ +.contacts-table tbody tr { + border-bottom: 1px solid var(--border-default); + transition: background-color var(--transition-fast); +} + +.contacts-table tbody tr:hover { + background-color: var(--bg-hover); +} + +.contacts-table tbody tr.selected { + background-color: var(--bg-tertiary); +} + +.contacts-table td { + color: var(--text-secondary); + font-size: var(--text-sm); +} + +.contacts-table td:first-child { + padding-left: var(--spacing-4); +} + +.contacts-table td:last-child { + padding-right: var(--spacing-4); +} + +/* Checkbox column */ +.checkbox-cell { + width: 40px; + text-align: center !important; +} + +.table-checkbox { + width: 18px; + height: 18px; + cursor: pointer; + appearance: none; + border: 2px solid var(--border-default); + border-radius: var(--radius-sm); + background: var(--bg-primary); + position: relative; + transition: all var(--transition-fast); +} + +.table-checkbox:hover { + border-color: var(--primary); +} + +.table-checkbox:checked { + background: var(--primary); + border-color: var(--primary); +} + +.table-checkbox:checked::after { + content: '✓'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: white; + font-size: 12px; + font-weight: bold; +} + +/* Name column with avatar */ +.name-cell { display: flex; - justify-content: space-between; - align-items: flex-start; - margin-bottom: var(--space-sm); + align-items: center; + gap: var(--spacing-3); + min-width: 200px; } -.contact-avatar { - width: 48px; - height: 48px; +.contact-avatar-small { + width: 32px; + height: 32px; background: var(--primary); color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; - font-weight: bold; - font-size: 18px; + font-weight: var(--font-semibold); + font-size: 12px; flex-shrink: 0; } -.contact-actions { - opacity: 0; - transition: opacity 0.2s; -} - -.contact-card:hover .contact-actions { - opacity: 1; -} - -.contact-actions .btn-icon { - background: var(--bg-tertiary); - border: 1px solid var(--border-color); - color: var(--text-secondary); - width: 32px; - height: 32px; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - border-radius: var(--radius-sm); - transition: all 0.2s; -} - -.contact-actions .btn-icon:hover { - background: var(--primary); - color: white; - border-color: var(--primary); -} - -/* ============================================================================= - CONTACT INFO - ============================================================================= */ - -.contact-card-body { - margin-bottom: var(--space-sm); -} - -.contact-name { - font-size: 18px; - font-weight: 600; - margin: 0 0 var(--space-xs); +.contact-name-link { color: var(--text-primary); + font-weight: var(--font-medium); + text-decoration: none; + cursor: pointer; } -.contact-company { - font-size: 14px; +.contact-name-link:hover { color: var(--primary); - margin-bottom: 4px; + text-decoration: underline; } -.contact-position { - font-size: 13px; - color: var(--text-secondary); - margin-bottom: var(--space-sm); -} - -.contact-email, -.contact-phone, -.contact-mobile { - font-size: 13px; - color: var(--text-secondary); - margin-bottom: 4px; - display: flex; - align-items: center; - gap: 8px; -} - -.contact-email i, -.contact-phone i, -.contact-mobile i { - width: 14px; - color: var(--text-tertiary); -} - -.contact-email:hover, -.contact-phone:hover, -.contact-mobile:hover { - color: var(--primary); -} - -/* ============================================================================= - TAGS - ============================================================================= */ - -.contact-tags { +/* Tags cell */ +.tags-cell { display: flex; + gap: var(--spacing-1); flex-wrap: wrap; - gap: 4px; - margin-top: var(--space-sm); + max-width: 200px; } .contact-tag { @@ -178,8 +332,60 @@ color: var(--text-secondary); font-size: 11px; padding: 2px 8px; - border-radius: var(--radius-sm); - border: 1px solid var(--border-color); + border-radius: var(--radius-full); + border: 1px solid var(--border-default); + font-weight: var(--font-medium); + white-space: nowrap; +} + +/* Actions column */ +.actions-cell { + text-align: right !important; +} + +.table-actions { + display: flex; + gap: var(--spacing-2); + justify-content: flex-end; +} + +.btn-table-action { + background: transparent; + border: 1px solid var(--border-default); + color: var(--text-secondary); + width: 32px; + height: 32px; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--radius-md); + transition: all var(--transition-fast); + cursor: pointer; +} + +.btn-table-action:hover { + background: var(--primary); + color: white; + border-color: var(--primary); + transform: scale(1.05); +} + +.btn-table-action svg { + width: 16px; + height: 16px; +} + +/* Export button */ +.btn-export { + display: flex; + align-items: center; + gap: var(--spacing-2); +} + +.btn-export svg { + width: 16px; + height: 16px; } /* ============================================================================= @@ -188,27 +394,35 @@ .contacts-empty { text-align: center; - padding: var(--space-xl) var(--space-md); + padding: var(--spacing-8) var(--spacing-4); background: var(--bg-secondary); - border-radius: var(--radius); - border: 1px solid var(--border-color); + border-radius: var(--radius-xl); + border: 1px solid var(--border-default); + max-width: 500px; + margin: var(--spacing-8) auto; } -.contacts-empty i { - font-size: 48px; +.contacts-empty .empty-icon { color: var(--text-tertiary); - margin-bottom: var(--space-md); + margin-bottom: var(--spacing-4); + opacity: 0.5; +} + +.contacts-empty .empty-icon svg { + width: 64px; + height: 64px; } .contacts-empty h3 { - font-size: 20px; - margin-bottom: var(--space-xs); + font-size: var(--text-xl); + font-weight: var(--font-semibold); + margin-bottom: var(--spacing-2); color: var(--text-primary); } .contacts-empty p { color: var(--text-secondary); - margin-bottom: var(--space-md); + margin-bottom: var(--spacing-4); } /* ============================================================================= @@ -244,29 +458,105 @@ margin-top: 4px; } +/* ============================================================================= + PAGINATION + ============================================================================= */ + +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: var(--spacing-2); + padding: var(--spacing-4); + border-top: 1px solid var(--border-default); + background: var(--bg-secondary); +} + +.pagination-btn { + background: var(--bg-primary); + border: 1px solid var(--border-default); + color: var(--text-secondary); + padding: var(--spacing-2) var(--spacing-3); + border-radius: var(--radius-md); + font-size: var(--text-sm); + font-weight: var(--font-medium); + cursor: pointer; + transition: all var(--transition-fast); +} + +.pagination-btn:hover:not(:disabled) { + background: var(--bg-hover); + border-color: var(--primary); + color: var(--primary); +} + +.pagination-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.pagination-info { + color: var(--text-secondary); + font-size: var(--text-sm); + font-weight: var(--font-medium); +} /* ============================================================================= RESPONSIVE ============================================================================= */ -@media (max-width: 768px) { +@media (max-width: 1200px) { + .contacts-table-container { + overflow-x: auto; + } + + .contacts-table { + min-width: 900px; + } +} + +@media (max-width: 968px) { + .view-contacts .view-wrapper { + padding: var(--spacing-4); + } + .contacts-header { flex-direction: column; align-items: stretch; } - .contacts-controls { + .header-actions { flex-direction: column; + width: 100%; + gap: var(--spacing-2); } - .contacts-search { - max-width: none; + .contacts-controls { + padding: var(--spacing-3); } - .contacts-grid { - grid-template-columns: 1fr; + .contacts-controls-top { + flex-direction: column; + align-items: stretch; } + .bulk-actions { + width: 100%; + justify-content: space-between; + } + + .filter-select { + min-width: 120px; + font-size: var(--text-xs); + } + + .contacts-table th, + .contacts-table td { + padding: var(--spacing-2) var(--spacing-3); + } +} + +@media (max-width: 768px) { .form-row { grid-template-columns: 1fr; } @@ -280,4 +570,9 @@ width: 100%; justify-content: space-between; } + + /* Mobile: Hide less important columns */ + .hide-mobile { + display: none; + } } \ No newline at end of file diff --git a/frontend/css/reminders.css b/frontend/css/reminders.css index db8ab82..05ca789 100644 --- a/frontend/css/reminders.css +++ b/frontend/css/reminders.css @@ -112,11 +112,102 @@ text-shadow: 0 0 3px rgba(0, 0, 0, 0.5); } -/* Advance Options */ +/* Time Input Styling - Match Date Input */ +#reminder-modal input[type="time"] { + width: 100%; + padding: 10px 14px; + font-family: var(--font-primary); + font-size: var(--text-sm); + color: var(--text-primary); + background: var(--bg-input); + border: 1px solid var(--border-default); + border-radius: var(--radius-lg); + transition: all var(--transition-fast); + min-width: 140px; +} + +#reminder-modal input[type="time"]:hover { + border-color: var(--border-dark); +} + +#reminder-modal input[type="time"]:focus { + border-color: var(--primary); + box-shadow: var(--shadow-focus); + outline: none; +} + +/* Advance Options - Redesigned */ .advance-options { display: flex; flex-direction: column; - gap: 8px; + gap: var(--spacing-3); + background: var(--bg-secondary); + padding: var(--spacing-3); + border-radius: var(--radius-lg); + border: 1px solid var(--border-light); +} + +/* Reminder Advance Control */ +.reminder-advance-control { + display: flex; + flex-direction: column; + gap: var(--spacing-2); +} + +.reminder-advance-inputs { + display: flex; + align-items: center; + gap: var(--spacing-2); + flex-wrap: wrap; +} + +.reminder-number-input { + width: 70px; + text-align: center; + padding: 10px 8px; + font-size: var(--text-base); + font-weight: var(--font-medium); + background: white; + border: 2px solid var(--border-default); + border-radius: var(--radius-md); +} + +.reminder-number-input:focus { + border-color: var(--primary); + outline: none; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +.reminder-unit-select { + flex: 1; + min-width: 120px; + max-width: 180px; + padding: 10px 16px; + font-size: var(--text-base); + font-weight: var(--font-medium); + background: white; + border: 2px solid var(--border-default); + border-radius: var(--radius-md); + cursor: pointer; + appearance: none; + background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2'%3e%3cpath d='M6 9l6 6 6-6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 12px center; + background-size: 16px; + padding-right: 40px; +} + +.reminder-unit-select:focus { + border-color: var(--primary); + outline: none; + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +.reminder-advance-suffix { + font-size: var(--text-base); + color: var(--text-primary); + font-weight: var(--font-semibold); + white-space: nowrap; } .checkbox-label { @@ -175,7 +266,7 @@ } /* ===================== - CUSTOM SELECT (USER DROPDOWN) + CUSTOM SELECT (USER DROPDOWN) - Aligned with Multi-Select Design ===================== */ .custom-select { @@ -187,35 +278,38 @@ display: flex; align-items: center; justify-content: space-between; - padding: 10px 12px; - background: var(--bg-primary); + padding: 8px 14px; + background: white; border: 1px solid var(--border-default); - border-radius: 6px; + border-radius: var(--radius-lg); cursor: pointer; - transition: all 0.2s ease; + transition: all var(--transition-fast); min-height: 42px; } .custom-select-trigger:hover { - border-color: var(--border-hover); + border-color: var(--border-dark); } .custom-select-trigger.active { border-color: var(--primary); - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); } .custom-select-value { display: flex; align-items: center; - gap: 8px; + gap: var(--spacing-2); color: var(--text-primary); font-size: 14px; } .custom-select-arrow { - color: var(--text-secondary); - transition: transform 0.2s ease; + width: 16px; + height: 16px; + color: var(--text-tertiary); + transition: transform var(--transition-fast); + flex-shrink: 0; } .custom-select.open .custom-select-arrow { @@ -227,52 +321,48 @@ top: 100%; left: 0; right: 0; - background: var(--bg-card); + margin-top: 4px; + background: #ffffff; border: 1px solid var(--border-default); - border-radius: 6px; - box-shadow: var(--shadow-lg); - z-index: 1000; - max-height: 200px; + border-radius: var(--radius-lg); + box-shadow: var(--shadow-xl); + z-index: 1001; + max-height: 240px; overflow-y: auto; - opacity: 0; - visibility: hidden; - transform: translateY(-10px); - transition: all 0.2s ease; + min-width: 200px; + display: none; + /* Ensure opaque background */ + background-color: #ffffff !important; } .custom-select.open .custom-select-options { - opacity: 1; - visibility: visible; - transform: translateY(0); + display: block; } .custom-select-option { display: flex; align-items: center; - gap: 10px; - padding: 10px 12px; + gap: var(--spacing-3); + padding: 8px 12px; cursor: pointer; - transition: background-color 0.2s ease; - border-bottom: 1px solid var(--border-light); -} - -.custom-select-option:last-child { - border-bottom: none; + transition: background-color var(--transition-fast); + color: var(--text-primary); + background-color: #ffffff; + position: relative; } .custom-select-option:hover { - background: var(--bg-hover); + background-color: #f3f4f6 !important; } .custom-select-option.selected { - background: var(--primary-light); - color: var(--primary); + background-color: #e0e7ff !important; } .option-avatar { width: 24px; height: 24px; - border-radius: 50%; + border-radius: var(--radius-full); display: flex; align-items: center; justify-content: center; @@ -284,7 +374,8 @@ .option-text { font-size: 14px; - color: #000000 !important; + color: var(--text-primary); + flex: 1; } .selected-user-avatar { @@ -325,11 +416,22 @@ transition: background-color 0.2s ease, color 0.2s ease; } -#reminder-modal *:not(.btn):not(.custom-select-option):hover { +#reminder-modal *:not(.btn):not(.custom-select-option):not(.option-avatar):not(.option-text):hover { background: transparent !important; color: inherit !important; } +/* Ensure dropdown options have solid background */ +#reminder-modal .custom-select-options { + background-color: #ffffff !important; + isolation: isolate; +} + +/* Keep text elements transparent but allow avatars to have background */ +#reminder-modal .custom-select-option .option-text { + background: transparent !important; +} + /* Stelle sicher, dass Text im Modal immer lesbar bleibt */ #reminder-modal .modal-content { background: var(--bg-card) !important; @@ -395,10 +497,11 @@ ===================== */ /* Reminder Button in Calendar Toolbar */ -.btn-reminder { - background: linear-gradient(135deg, #f97316 0%, #ea580c 100%); +.btn-reminder, +.btn-secondary.btn-reminder { + background: linear-gradient(135deg, #f97316 0%, #ea580c 100%) !important; color: white !important; - border: 2px solid #ea580c; + border: 2px solid #ea580c !important; display: flex; align-items: center; gap: 6px; @@ -413,10 +516,12 @@ } .btn-reminder:hover, -.btn-reminder:focus { - background: linear-gradient(135deg, #ea580c 0%, #c2410c 100%); +.btn-reminder:focus, +.btn-secondary.btn-reminder:hover, +.btn-secondary.btn-reminder:focus { + background: linear-gradient(135deg, #ea580c 0%, #dc2626 100%) !important; color: white !important; - border-color: #c2410c; + border-color: #dc2626 !important; transform: translateY(-2px); box-shadow: 0 4px 12px rgba(234, 88, 12, 0.4); text-decoration: none; @@ -475,6 +580,66 @@ border: none; } +/* Calendar Reminder Add Button - Orange styling */ +.calendar-week-add-reminder { + margin: var(--spacing-2) var(--spacing-3) var(--spacing-3); + padding: var(--spacing-2); + background: #f97316; + border: 1px solid #f97316; + border-radius: var(--radius-lg); + color: white !important; + font-size: var(--text-sm); + font-weight: var(--font-medium); + cursor: pointer; + transition: all var(--transition-fast); +} + +.calendar-week-add-reminder:hover { + background: #ea580c; + border-color: #dc2626; + color: white !important; + transform: translateY(-1px); + box-shadow: 0 2px 8px rgba(249, 115, 22, 0.4); +} + +/* Secondary reminder button - orange variant */ +.btn-reminder-secondary, +.btn.btn-reminder-secondary { + background: linear-gradient(135deg, #f97316 0%, #ea580c 100%) !important; + color: white !important; + border: 2px solid #ea580c !important; + font-weight: var(--font-medium); + transition: all var(--transition-fast); + display: flex !important; + align-items: center !important; + justify-content: center !important; + gap: 6px !important; +} + +.btn-reminder-secondary .icon, +.btn.btn-reminder-secondary .icon { + color: white !important; + width: 18px !important; + height: 18px !important; +} + +.btn-reminder-secondary:hover, +.btn-reminder-secondary:focus, +.btn.btn-reminder-secondary:hover, +.btn.btn-reminder-secondary:focus { + background: linear-gradient(135deg, #ea580c 0%, #dc2626 100%) !important; + color: white !important; + border-color: #dc2626 !important; + transform: translateY(-1px); + box-shadow: 0 3px 8px rgba(249, 115, 22, 0.4); +} + +.btn-reminder-secondary:active, +.btn.btn-reminder-secondary:active { + transform: translateY(0); + box-shadow: 0 1px 4px rgba(249, 115, 22, 0.3); +} + /* Reminder Detail Popup */ .calendar-reminder-detail { min-width: 300px; diff --git a/frontend/index.html b/frontend/index.html index 3fa237e..a219d5d 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -173,13 +173,67 @@
Erstellen Sie Ihren ersten Kontakt.
- +| + + | +Name | +Firma | +Position | +Telefon | +Tags | +Aktionen | +
|---|
Erstellen Sie Ihren ersten Kontakt.
+ +