From 769a64f612890e9f99e307ecad93d18098c3d1fe Mon Sep 17 00:00:00 2001 From: tusuii Date: Sun, 15 Feb 2026 11:43:17 +0530 Subject: [PATCH] feat: add drag-and-drop to Kanban board - Implement native HTML5 Drag and Drop API on task cards - Cards show grab cursor and reduce opacity while dragging - Drop zones highlight with indigo glow and pulse animation - Moving a task updates its status and logs an activity entry - Added handleMoveTask to App.tsx with STATUS_LABELS import - CSS: drag-over styles, pulse keyframes, grab/grabbing cursors --- src/App.tsx | 12 +- src/Kanban.tsx | 69 +- src/index.css | 2107 ++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 1932 insertions(+), 256 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 31d595f..9d0bad6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { SEED_TASKS } from './data'; +import { SEED_TASKS, STATUS_LABELS } from './data'; import type { Task, User, Status } from './data'; import { LoginPage } from './Login'; import { Sidebar } from './Sidebar'; @@ -80,6 +80,13 @@ export default function App() { setTasks(prev => prev.map(t => t.id === taskId ? { ...t, status: t.status === 'done' ? 'todo' : 'done' as Status } : t)); }; + const handleMoveTask = (taskId: string, newStatus: Status) => { + setTasks(prev => prev.map(t => t.id === taskId ? { + ...t, status: newStatus, + activity: [...t.activity, { id: `a${Date.now()}`, text: `🔄 ${currentUser.name} moved task to ${STATUS_LABELS[newStatus]}`, timestamp: new Date().toISOString() }] + } : t)); + }; + const displayPage = VIEW_PAGES.includes(activePage) ? activeView : activePage; const filteredMyTasks = tasks.filter(t => t.assignee === currentUser.id); @@ -100,7 +107,8 @@ export default function App() { )} {displayPage === 'kanban' && ( + onAddTask={handleKanbanAdd} filterUser={filterUser} searchQuery={searchQuery} + onMoveTask={handleMoveTask} /> )} {displayPage === 'list' && ( void }) { +function TaskCard({ task, onClick, onDragStart }: { task: Task; onClick: () => void; onDragStart: (e: React.DragEvent, task: Task) => void }) { const p = PRIORITY_COLORS[task.priority]; const due = new Date(task.dueDate + 'T00:00:00'); const overdue = due < new Date() && task.status !== 'done'; const commCount = task.comments.length; return ( -
+
onDragStart(e, task)} + onDragEnd={e => (e.currentTarget as HTMLElement).style.opacity = '1'} + onClick={onClick}>
{task.title} @@ -27,12 +32,20 @@ function TaskCard({ task, onClick }: { task: Task; onClick: () => void }) { ); } -function KanbanColumn({ status, statusLabel, tasks, color, onTaskClick, onAddTask }: { +function KanbanColumn({ status, statusLabel, tasks, color, onTaskClick, onAddTask, onDragStart, onDrop, isDragOver, onDragOver, onDragLeave }: { status: Status; statusLabel: string; tasks: Task[]; color: string; onTaskClick: (t: Task) => void; onAddTask: (s: Status) => void; + onDragStart: (e: React.DragEvent, task: Task) => void; + onDrop: (e: React.DragEvent, status: Status) => void; + isDragOver: boolean; + onDragOver: (e: React.DragEvent, status: Status) => void; + onDragLeave: (e: React.DragEvent) => void; }) { return ( -
+
onDragOver(e, status)} + onDragLeave={onDragLeave} + onDrop={e => onDrop(e, status)}>
{statusLabel} @@ -41,9 +54,11 @@ function KanbanColumn({ status, statusLabel, tasks, color, onTaskClick, onAddTas
{tasks.length === 0 ? ( -
No tasks here · Click + to add one
+
+ {isDragOver ? '⬇ Drop task here' : 'No tasks here · Click + to add one'} +
) : ( - tasks.map(t => onTaskClick(t)} />) + tasks.map(t => onTaskClick(t)} onDragStart={onDragStart} />) )}
@@ -53,20 +68,58 @@ function KanbanColumn({ status, statusLabel, tasks, color, onTaskClick, onAddTas interface KanbanProps { tasks: Task[]; currentUser: User; onTaskClick: (t: Task) => void; onAddTask: (s: Status) => void; filterUser: string | null; searchQuery: string; + onMoveTask: (taskId: string, newStatus: Status) => void; } -export function KanbanBoard({ tasks, currentUser, onTaskClick, onAddTask, filterUser, searchQuery }: KanbanProps) { +export function KanbanBoard({ tasks, currentUser, onTaskClick, onAddTask, filterUser, searchQuery, onMoveTask }: KanbanProps) { + const [dragOverColumn, setDragOverColumn] = useState(null); + let filtered = tasks; if (currentUser.role === 'employee') filtered = filtered.filter(t => t.assignee === currentUser.id); if (filterUser) filtered = filtered.filter(t => t.assignee === filterUser); if (searchQuery) filtered = filtered.filter(t => t.title.toLowerCase().includes(searchQuery.toLowerCase())); + const handleDragStart = (e: React.DragEvent, task: Task) => { + e.dataTransfer.setData('text/plain', task.id); + e.dataTransfer.effectAllowed = 'move'; + (e.currentTarget as HTMLElement).style.opacity = '0.4'; + }; + + const handleDragOver = (e: React.DragEvent, status: Status) => { + e.preventDefault(); + e.dataTransfer.dropEffect = 'move'; + setDragOverColumn(status); + }; + + const handleDragLeave = (e: React.DragEvent) => { + // Only clear if leaving the column entirely (not entering a child) + const related = e.relatedTarget as HTMLElement | null; + if (!related || !(e.currentTarget as HTMLElement).contains(related)) { + setDragOverColumn(null); + } + }; + + const handleDrop = (e: React.DragEvent, newStatus: Status) => { + e.preventDefault(); + const taskId = e.dataTransfer.getData('text/plain'); + const task = tasks.find(t => t.id === taskId); + if (task && task.status !== newStatus) { + onMoveTask(taskId, newStatus); + } + setDragOverColumn(null); + }; + const statuses: Status[] = ['todo', 'inprogress', 'review', 'done']; return (
{statuses.map(s => ( t.status === s)} onTaskClick={onTaskClick} onAddTask={onAddTask} /> + tasks={filtered.filter(t => t.status === s)} onTaskClick={onTaskClick} onAddTask={onAddTask} + onDragStart={handleDragStart} + onDrop={handleDrop} + isDragOver={dragOverColumn === s} + onDragOver={handleDragOver} + onDragLeave={handleDragLeave} /> ))}
); diff --git a/src/index.css b/src/index.css index ce55f13..4ed30d8 100644 --- a/src/index.css +++ b/src/index.css @@ -11,19 +11,29 @@ --text-secondary: #94a3b8; --accent: #6366f1; --accent-hover: #4f46e5; - --accent-glow: rgba(99,102,241,0.3); - --accent-bg: rgba(99,102,241,0.15); - --critical: #ef4444; --critical-bg: rgba(239,68,68,0.13); - --high: #f97316; --high-bg: rgba(249,115,22,0.13); - --medium: #eab308; --medium-bg: rgba(234,179,8,0.13); - --low: #22c55e; --low-bg: rgba(34,197,94,0.13); + --accent-glow: rgba(99, 102, 241, 0.3); + --accent-bg: rgba(99, 102, 241, 0.15); + --critical: #ef4444; + --critical-bg: rgba(239, 68, 68, 0.13); + --high: #f97316; + --high-bg: rgba(249, 115, 22, 0.13); + --medium: #eab308; + --medium-bg: rgba(234, 179, 8, 0.13); + --low: #22c55e; + --low-bg: rgba(34, 197, 94, 0.13); --status-todo: #64748b; --status-inprogress: #818cf8; --status-review: #f59e0b; --status-done: #22c55e; } -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} body { font-family: 'DM Sans', sans-serif; @@ -33,285 +43,1890 @@ body { -webkit-font-smoothing: antialiased; } -::-webkit-scrollbar { width: 6px; height: 6px; } -::-webkit-scrollbar-track { background: var(--bg-surface); } -::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } +::-webkit-scrollbar { + width: 6px; + height: 6px; +} -@keyframes slideIn { from { transform: translateX(40px); opacity: 0; } to { transform: translateX(0); opacity: 1; } } -@keyframes fadeUp { from { transform: translateY(24px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } -@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } +::-webkit-scrollbar-track { + background: var(--bg-surface); +} + +::-webkit-scrollbar-thumb { + background: var(--border); + border-radius: 3px; +} + +@keyframes slideIn { + from { + transform: translateX(40px); + opacity: 0; + } + + to { + transform: translateX(0); + opacity: 1; + } +} + +@keyframes fadeUp { + from { + transform: translateY(24px); + opacity: 0; + } + + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} /* LOGIN */ -.login-bg { min-height: 100vh; display: flex; align-items: center; justify-content: center; background: radial-gradient(ellipse at center, #0d1a3a 0%, #060b18 70%); } -.login-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 16px; padding: 40px; width: 400px; animation: fadeUp 0.4s ease; } -.login-logo { display: flex; align-items: center; justify-content: center; gap: 10px; margin-bottom: 8px; } -.login-logo-icon { width: 44px; height: 44px; background: var(--accent); border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 22px; } -.login-title { font-size: 22px; font-weight: 800; } -.login-tagline { text-align: center; color: var(--text-muted); font-size: 13px; margin-bottom: 20px; } -.login-divider { height: 1px; background: var(--border); margin: 16px 0; } -.login-label { font-size: 13px; font-weight: 600; color: var(--text-secondary); margin-bottom: 6px; display: block; } -.login-input-wrap { position: relative; margin-bottom: 16px; } -.login-input { width: 100%; padding: 10px 14px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; color: var(--text-primary); font-size: 14px; font-family: inherit; outline: none; transition: border-color 0.15s; } -.login-input:focus { border-color: var(--accent); } -.login-input.error { border-color: var(--critical); } -.login-eye { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 16px; } -.login-btn { width: 100%; padding: 12px; background: var(--accent); color: #fff; border: none; border-radius: 10px; font-size: 14px; font-weight: 700; font-family: inherit; cursor: pointer; box-shadow: 0 0 20px var(--accent-glow); transition: background 0.15s; } -.login-btn:hover { background: var(--accent-hover); } -.login-hint { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 10px 14px; font-size: 12px; color: var(--text-muted); margin-top: 16px; text-align: center; } -.login-error { color: var(--critical); font-size: 12px; margin-top: 8px; text-align: center; } +.login-bg { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background: radial-gradient(ellipse at center, #0d1a3a 0%, #060b18 70%); +} + +.login-card { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 16px; + padding: 40px; + width: 400px; + animation: fadeUp 0.4s ease; +} + +.login-logo { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + margin-bottom: 8px; +} + +.login-logo-icon { + width: 44px; + height: 44px; + background: var(--accent); + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + font-size: 22px; +} + +.login-title { + font-size: 22px; + font-weight: 800; +} + +.login-tagline { + text-align: center; + color: var(--text-muted); + font-size: 13px; + margin-bottom: 20px; +} + +.login-divider { + height: 1px; + background: var(--border); + margin: 16px 0; +} + +.login-label { + font-size: 13px; + font-weight: 600; + color: var(--text-secondary); + margin-bottom: 6px; + display: block; +} + +.login-input-wrap { + position: relative; + margin-bottom: 16px; +} + +.login-input { + width: 100%; + padding: 10px 14px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + color: var(--text-primary); + font-size: 14px; + font-family: inherit; + outline: none; + transition: border-color 0.15s; +} + +.login-input:focus { + border-color: var(--accent); +} + +.login-input.error { + border-color: var(--critical); +} + +.login-eye { + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-50%); + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 16px; +} + +.login-btn { + width: 100%; + padding: 12px; + background: var(--accent); + color: #fff; + border: none; + border-radius: 10px; + font-size: 14px; + font-weight: 700; + font-family: inherit; + cursor: pointer; + box-shadow: 0 0 20px var(--accent-glow); + transition: background 0.15s; +} + +.login-btn:hover { + background: var(--accent-hover); +} + +.login-hint { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + padding: 10px 14px; + font-size: 12px; + color: var(--text-muted); + margin-top: 16px; + text-align: center; +} + +.login-error { + color: var(--critical); + font-size: 12px; + margin-top: 8px; + text-align: center; +} /* APP SHELL */ -.app-shell { display: flex; flex-direction: column; height: 100vh; background: var(--bg-base); } -.app-body { display: flex; flex: 1; overflow: hidden; } -.main-content { flex: 1; overflow-y: auto; padding: 0; } +.app-shell { + display: flex; + flex-direction: column; + height: 100vh; + background: var(--bg-base); +} + +.app-body { + display: flex; + flex: 1; + overflow: hidden; +} + +.main-content { + flex: 1; + overflow-y: auto; + padding: 0; +} /* SIDEBAR */ -.sidebar { width: 240px; min-width: 240px; background: var(--bg-surface); border-right: 1px solid var(--border); display: flex; flex-direction: column; height: 100%; } -.sidebar-logo { padding: 16px 20px; display: flex; align-items: center; gap: 10px; } -.sidebar-logo-icon { width: 32px; height: 32px; background: var(--accent); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 16px; } -.sidebar-logo-text { font-size: 16px; font-weight: 800; } -.sidebar-divider { height: 1px; background: var(--border); margin: 0 16px; } -.sidebar-section-label { font-size: 10px; font-weight: 700; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.1em; padding: 16px 20px 8px; } -.sidebar-nav { flex: 1; display: flex; flex-direction: column; } -.sidebar-item { display: flex; align-items: center; gap: 10px; padding: 10px 16px; margin: 2px 8px; border-radius: 8px; cursor: pointer; font-size: 13px; font-weight: 600; color: var(--text-muted); transition: all 0.15s; border-left: 3px solid transparent; text-decoration: none; } -.sidebar-item:hover { color: #e2e8f0; background: rgba(255,255,255,0.04); } -.sidebar-item.active { background: var(--accent-bg); color: #818cf8; border-left-color: var(--accent); } -.sidebar-item-icon { font-size: 18px; width: 20px; text-align: center; } -.sidebar-profile { padding: 16px; border-top: 1px solid var(--border); display: flex; align-items: center; gap: 10px; } -.sidebar-profile-info { flex: 1; } -.sidebar-profile-name { font-size: 13px; font-weight: 600; color: #e2e8f0; } -.sidebar-signout { background: none; border: none; color: var(--text-muted); font-size: 11px; cursor: pointer; font-family: inherit; padding: 0; transition: color 0.15s; } -.sidebar-signout:hover { color: var(--critical); } +.sidebar { + width: 240px; + min-width: 240px; + background: var(--bg-surface); + border-right: 1px solid var(--border); + display: flex; + flex-direction: column; + height: 100%; +} + +.sidebar-logo { + padding: 16px 20px; + display: flex; + align-items: center; + gap: 10px; +} + +.sidebar-logo-icon { + width: 32px; + height: 32px; + background: var(--accent); + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; +} + +.sidebar-logo-text { + font-size: 16px; + font-weight: 800; +} + +.sidebar-divider { + height: 1px; + background: var(--border); + margin: 0 16px; +} + +.sidebar-section-label { + font-size: 10px; + font-weight: 700; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.1em; + padding: 16px 20px 8px; +} + +.sidebar-nav { + flex: 1; + display: flex; + flex-direction: column; +} + +.sidebar-item { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 16px; + margin: 2px 8px; + border-radius: 8px; + cursor: pointer; + font-size: 13px; + font-weight: 600; + color: var(--text-muted); + transition: all 0.15s; + border-left: 3px solid transparent; + text-decoration: none; +} + +.sidebar-item:hover { + color: #e2e8f0; + background: rgba(255, 255, 255, 0.04); +} + +.sidebar-item.active { + background: var(--accent-bg); + color: #818cf8; + border-left-color: var(--accent); +} + +.sidebar-item-icon { + font-size: 18px; + width: 20px; + text-align: center; +} + +.sidebar-profile { + padding: 16px; + border-top: 1px solid var(--border); + display: flex; + align-items: center; + gap: 10px; +} + +.sidebar-profile-info { + flex: 1; +} + +.sidebar-profile-name { + font-size: 13px; + font-weight: 600; + color: #e2e8f0; +} + +.sidebar-signout { + background: none; + border: none; + color: var(--text-muted); + font-size: 11px; + cursor: pointer; + font-family: inherit; + padding: 0; + transition: color 0.15s; +} + +.sidebar-signout:hover { + color: var(--critical); +} /* NAVBAR */ -.top-navbar { height: 56px; min-height: 56px; background: var(--bg-surface); border-bottom: 1px solid var(--border); display: flex; align-items: center; padding: 0 20px; gap: 16px; position: sticky; top: 0; z-index: 50; } -.navbar-title { font-size: 16px; font-weight: 700; white-space: nowrap; } -.navbar-search { flex: 0 0 220px; margin: 0 auto; position: relative; } -.navbar-search input { width: 100%; padding: 7px 12px 7px 32px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; color: var(--text-primary); font-size: 12px; font-family: inherit; outline: none; } -.navbar-search-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--text-muted); font-size: 13px; } -.navbar-right { display: flex; align-items: center; gap: 12px; margin-left: auto; } -.filter-chips { display: flex; align-items: center; gap: 6px; } -.filter-chip { width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 9px; font-weight: 700; cursor: pointer; border: 2px solid transparent; transition: all 0.15s; } -.filter-chip.active { box-shadow: 0 0 0 2px var(--accent); } -.filter-chip-all { padding: 4px 12px; border-radius: 14px; font-size: 11px; font-weight: 600; cursor: pointer; background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted); transition: all 0.15s; width: auto; height: auto; } -.filter-chip-all.active { background: var(--accent-bg); color: var(--accent); border-color: var(--accent); } -.notif-btn { position: relative; background: none; border: none; color: var(--text-muted); font-size: 18px; cursor: pointer; transition: color 0.15s; } -.notif-btn:hover { color: var(--text-primary); } -.notif-badge { position: absolute; top: -4px; right: -6px; background: var(--critical); color: #fff; font-size: 9px; font-weight: 700; width: 16px; height: 16px; border-radius: 50%; display: flex; align-items: center; justify-content: center; } -.new-task-btn { padding: 8px 16px; background: var(--accent); color: #fff; border: none; border-radius: 8px; font-size: 13px; font-weight: 700; font-family: inherit; cursor: pointer; box-shadow: 0 0 20px var(--accent-glow); transition: background 0.15s; white-space: nowrap; } -.new-task-btn:hover { background: var(--accent-hover); } +.top-navbar { + height: 56px; + min-height: 56px; + background: var(--bg-surface); + border-bottom: 1px solid var(--border); + display: flex; + align-items: center; + padding: 0 20px; + gap: 16px; + position: sticky; + top: 0; + z-index: 50; +} + +.navbar-title { + font-size: 16px; + font-weight: 700; + white-space: nowrap; +} + +.navbar-search { + flex: 0 0 220px; + margin: 0 auto; + position: relative; +} + +.navbar-search input { + width: 100%; + padding: 7px 12px 7px 32px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + color: var(--text-primary); + font-size: 12px; + font-family: inherit; + outline: none; +} + +.navbar-search-icon { + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); + color: var(--text-muted); + font-size: 13px; +} + +.navbar-right { + display: flex; + align-items: center; + gap: 12px; + margin-left: auto; +} + +.filter-chips { + display: flex; + align-items: center; + gap: 6px; +} + +.filter-chip { + width: 28px; + height: 28px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 9px; + font-weight: 700; + cursor: pointer; + border: 2px solid transparent; + transition: all 0.15s; +} + +.filter-chip.active { + box-shadow: 0 0 0 2px var(--accent); +} + +.filter-chip-all { + padding: 4px 12px; + border-radius: 14px; + font-size: 11px; + font-weight: 600; + cursor: pointer; + background: var(--bg-card); + border: 1px solid var(--border); + color: var(--text-muted); + transition: all 0.15s; + width: auto; + height: auto; +} + +.filter-chip-all.active { + background: var(--accent-bg); + color: var(--accent); + border-color: var(--accent); +} + +.notif-btn { + position: relative; + background: none; + border: none; + color: var(--text-muted); + font-size: 18px; + cursor: pointer; + transition: color 0.15s; +} + +.notif-btn:hover { + color: var(--text-primary); +} + +.notif-badge { + position: absolute; + top: -4px; + right: -6px; + background: var(--critical); + color: #fff; + font-size: 9px; + font-weight: 700; + width: 16px; + height: 16px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; +} + +.new-task-btn { + padding: 8px 16px; + background: var(--accent); + color: #fff; + border: none; + border-radius: 8px; + font-size: 13px; + font-weight: 700; + font-family: inherit; + cursor: pointer; + box-shadow: 0 0 20px var(--accent-glow); + transition: background 0.15s; + white-space: nowrap; +} + +.new-task-btn:hover { + background: var(--accent-hover); +} /* BOTTOM TOGGLE */ -.bottom-bar { height: 48px; min-height: 48px; background: var(--bg-surface); border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: center; } -.toggle-pill { display: flex; background: var(--bg-card); border: 1px solid var(--border); border-radius: 40px; padding: 4px; } -.toggle-btn { width: 120px; height: 40px; border: none; border-radius: 36px; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; cursor: pointer; font-family: inherit; transition: all 0.15s; background: transparent; color: var(--text-muted); display: flex; align-items: center; justify-content: center; gap: 6px; } -.toggle-btn.active { background: var(--accent); color: #fff; box-shadow: 0 0 16px rgba(99,102,241,0.4); } -.toggle-btn:not(.active):hover { color: #e2e8f0; } +.bottom-bar { + height: 48px; + min-height: 48px; + background: var(--bg-surface); + border-top: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: center; +} + +.toggle-pill { + display: flex; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 40px; + padding: 4px; +} + +.toggle-btn { + width: 120px; + height: 40px; + border: none; + border-radius: 36px; + font-size: 12px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + cursor: pointer; + font-family: inherit; + transition: all 0.15s; + background: transparent; + color: var(--text-muted); + display: flex; + align-items: center; + justify-content: center; + gap: 6px; +} + +.toggle-btn.active { + background: var(--accent); + color: #fff; + box-shadow: 0 0 16px rgba(99, 102, 241, 0.4); +} + +.toggle-btn:not(.active):hover { + color: #e2e8f0; +} /* AVATAR */ -.avatar { border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; color: #fff; flex-shrink: 0; } +.avatar { + border-radius: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + font-weight: 700; + color: #fff; + flex-shrink: 0; +} /* BADGES */ -.priority-badge, .status-badge { padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; display: inline-flex; align-items: center; gap: 4px; } -.role-badge { padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 600; } -.tag-pill { padding: 2px 8px; border-radius: 6px; font-size: 10px; background: var(--bg-card); border: 1px solid var(--border); color: var(--text-secondary); } +.priority-badge, +.status-badge { + padding: 2px 8px; + border-radius: 10px; + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.05em; + display: inline-flex; + align-items: center; + gap: 4px; +} + +.role-badge { + padding: 2px 8px; + border-radius: 10px; + font-size: 10px; + font-weight: 600; +} + +.tag-pill { + padding: 2px 8px; + border-radius: 6px; + font-size: 10px; + background: var(--bg-card); + border: 1px solid var(--border); + color: var(--text-secondary); +} /* CALENDAR */ -.calendar-toolbar { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; } -.cal-nav { display: flex; align-items: center; gap: 12px; } -.cal-nav-btn { background: none; border: 1px solid var(--border-muted); color: var(--text-secondary); width: 32px; height: 32px; border-radius: 8px; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; transition: all 0.15s; } -.cal-nav-btn:hover { border-color: var(--accent); color: var(--accent); } -.cal-month-label { font-size: 18px; font-weight: 700; min-width: 180px; text-align: center; } -.cal-today-btn { padding: 6px 14px; background: none; border: 1px solid var(--border-muted); color: var(--text-secondary); border-radius: 8px; font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; transition: all 0.15s; } -.cal-today-btn:hover { border-color: var(--accent); color: var(--accent); } -.cal-view-toggle { display: flex; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; } -.cal-view-btn { padding: 6px 14px; background: none; border: none; color: var(--text-muted); font-size: 12px; font-weight: 600; cursor: pointer; font-family: inherit; transition: all 0.15s; } -.cal-view-btn.active { background: var(--accent); color: #fff; } -.month-grid { display: grid; grid-template-columns: repeat(7, 1fr); flex: 1; } -.month-grid-header { font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: #475569; text-align: center; padding: 8px; border-bottom: 1px solid var(--border); } -.day-cell { background: var(--bg-surface); border: 1px solid var(--border); min-height: 120px; padding: 4px; cursor: pointer; transition: background 0.15s; position: relative; } -.day-cell:hover { background: #0d1629; } -.day-number { font-size: 13px; padding: 4px 8px; color: var(--text-secondary); } -.day-number.today { background: var(--accent); color: #fff; font-weight: 700; width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; padding: 0; } -.day-number.other-month { color: var(--border); } -.day-tasks { display: flex; flex-direction: column; gap: 3px; padding: 2px 4px; } +.calendar-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 20px; +} + +.cal-nav { + display: flex; + align-items: center; + gap: 12px; +} + +.cal-nav-btn { + background: none; + border: 1px solid var(--border-muted); + color: var(--text-secondary); + width: 32px; + height: 32px; + border-radius: 8px; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.15s; +} + +.cal-nav-btn:hover { + border-color: var(--accent); + color: var(--accent); +} + +.cal-month-label { + font-size: 18px; + font-weight: 700; + min-width: 180px; + text-align: center; +} + +.cal-today-btn { + padding: 6px 14px; + background: none; + border: 1px solid var(--border-muted); + color: var(--text-secondary); + border-radius: 8px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: all 0.15s; +} + +.cal-today-btn:hover { + border-color: var(--accent); + color: var(--accent); +} + +.cal-view-toggle { + display: flex; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + overflow: hidden; +} + +.cal-view-btn { + padding: 6px 14px; + background: none; + border: none; + color: var(--text-muted); + font-size: 12px; + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: all 0.15s; +} + +.cal-view-btn.active { + background: var(--accent); + color: #fff; +} + +.month-grid { + display: grid; + grid-template-columns: repeat(7, 1fr); + flex: 1; +} + +.month-grid-header { + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.1em; + color: #475569; + text-align: center; + padding: 8px; + border-bottom: 1px solid var(--border); +} + +.day-cell { + background: var(--bg-surface); + border: 1px solid var(--border); + min-height: 120px; + padding: 4px; + cursor: pointer; + transition: background 0.15s; + position: relative; +} + +.day-cell:hover { + background: #0d1629; +} + +.day-number { + font-size: 13px; + padding: 4px 8px; + color: var(--text-secondary); +} + +.day-number.today { + background: var(--accent); + color: #fff; + font-weight: 700; + width: 26px; + height: 26px; + border-radius: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; +} + +.day-number.other-month { + color: var(--border); +} + +.day-tasks { + display: flex; + flex-direction: column; + gap: 3px; + padding: 2px 4px; +} /* TASK CHIP */ -.task-chip { height: 22px; border-radius: 4px; padding: 0 8px; display: flex; align-items: center; gap: 6px; cursor: pointer; transition: all 0.15s; animation: fadeIn 0.15s ease; border-left: 3px solid; } -.task-chip:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.4); filter: brightness(1.2); } -.task-chip-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; } -.task-chip-title { font-size: 11px; color: #e2e8f0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; } -.task-chip-avatar { width: 14px; height: 14px; font-size: 6px; flex-shrink: 0; } -.more-tasks-link { font-size: 11px; color: var(--accent); cursor: pointer; padding: 2px 8px; } -.more-tasks-link:hover { text-decoration: underline; } +.task-chip { + height: 22px; + border-radius: 4px; + padding: 0 8px; + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; + transition: all 0.15s; + animation: fadeIn 0.15s ease; + border-left: 3px solid; +} + +.task-chip:hover { + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + filter: brightness(1.2); +} + +.task-chip-dot { + width: 6px; + height: 6px; + border-radius: 50%; + flex-shrink: 0; +} + +.task-chip-title { + font-size: 11px; + color: #e2e8f0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + flex: 1; +} + +.task-chip-avatar { + width: 14px; + height: 14px; + font-size: 6px; + flex-shrink: 0; +} + +.more-tasks-link { + font-size: 11px; + color: var(--accent); + cursor: pointer; + padding: 2px 8px; +} + +.more-tasks-link:hover { + text-decoration: underline; +} /* QUICK ADD */ -.quick-add-panel { position: absolute; z-index: 200; background: var(--bg-card); border: 1px solid var(--border-muted); border-radius: 12px; padding: 16px; width: 320px; box-shadow: 0 12px 40px rgba(0,0,0,0.6); animation: fadeUp 0.15s ease; } -.quick-add-header { font-size: 12px; color: var(--text-muted); margin-bottom: 10px; } -.quick-add-close { position: absolute; top: 8px; right: 8px; background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 16px; } -.quick-add-input { width: 100%; padding: 8px 10px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 13px; font-family: inherit; outline: none; margin-bottom: 10px; } -.quick-add-row { display: flex; gap: 8px; margin-bottom: 10px; } -.quick-add-select { flex: 1; padding: 6px 8px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 11px; font-family: inherit; } -.quick-add-actions { display: flex; align-items: center; gap: 10px; } -.quick-add-submit { padding: 6px 14px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-size: 12px; font-weight: 700; cursor: pointer; font-family: inherit; } -.quick-add-link { font-size: 11px; color: var(--accent); cursor: pointer; background: none; border: none; font-family: inherit; } +.quick-add-panel { + position: absolute; + z-index: 200; + background: var(--bg-card); + border: 1px solid var(--border-muted); + border-radius: 12px; + padding: 16px; + width: 320px; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6); + animation: fadeUp 0.15s ease; +} + +.quick-add-header { + font-size: 12px; + color: var(--text-muted); + margin-bottom: 10px; +} + +.quick-add-close { + position: absolute; + top: 8px; + right: 8px; + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 16px; +} + +.quick-add-input { + width: 100%; + padding: 8px 10px; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 6px; + color: var(--text-primary); + font-size: 13px; + font-family: inherit; + outline: none; + margin-bottom: 10px; +} + +.quick-add-row { + display: flex; + gap: 8px; + margin-bottom: 10px; +} + +.quick-add-select { + flex: 1; + padding: 6px 8px; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 6px; + color: var(--text-primary); + font-size: 11px; + font-family: inherit; +} + +.quick-add-actions { + display: flex; + align-items: center; + gap: 10px; +} + +.quick-add-submit { + padding: 6px 14px; + background: var(--accent); + color: #fff; + border: none; + border-radius: 6px; + font-size: 12px; + font-weight: 700; + cursor: pointer; + font-family: inherit; +} + +.quick-add-link { + font-size: 11px; + color: var(--accent); + cursor: pointer; + background: none; + border: none; + font-family: inherit; +} /* WEEK VIEW */ -.week-grid { display: grid; grid-template-columns: repeat(7, 1fr); flex: 1; } -.week-header-cell { text-align: center; padding: 8px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: #475569; border-bottom: 1px solid var(--border); } -.week-header-cell.today { background: var(--accent); color: #fff; border-radius: 8px 8px 0 0; } -.week-day-cell { background: var(--bg-surface); border: 1px solid var(--border); min-height: 200px; padding: 8px; cursor: pointer; transition: background 0.15s; position: relative; } -.week-day-cell:hover { background: #0d1629; } -.week-chip { height: 28px; border-radius: 4px; padding: 4px 8px; display: flex; align-items: center; gap: 6px; cursor: pointer; transition: all 0.15s; border-left: 3px solid; margin-bottom: 4px; } +.week-grid { + display: grid; + grid-template-columns: repeat(7, 1fr); + flex: 1; +} + +.week-header-cell { + text-align: center; + padding: 8px; + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.1em; + color: #475569; + border-bottom: 1px solid var(--border); +} + +.week-header-cell.today { + background: var(--accent); + color: #fff; + border-radius: 8px 8px 0 0; +} + +.week-day-cell { + background: var(--bg-surface); + border: 1px solid var(--border); + min-height: 200px; + padding: 8px; + cursor: pointer; + transition: background 0.15s; + position: relative; +} + +.week-day-cell:hover { + background: #0d1629; +} + +.week-chip { + height: 28px; + border-radius: 4px; + padding: 4px 8px; + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; + transition: all 0.15s; + border-left: 3px solid; + margin-bottom: 4px; +} /* KANBAN */ -.kanban-board { display: flex; gap: 16px; padding: 16px 20px; flex: 1; overflow-x: auto; } -.kanban-column { flex: 1; min-width: 260px; background: var(--bg-surface); border-radius: 12px; border: 1px solid var(--border); display: flex; flex-direction: column; } -.kanban-col-header { display: flex; align-items: center; gap: 8px; padding: 14px 16px; border-bottom: 1px solid var(--border); } -.kanban-col-dot { width: 8px; height: 8px; border-radius: 50%; } -.kanban-col-label { font-size: 12px; font-weight: 700; text-transform: uppercase; flex: 1; } -.kanban-col-count { font-size: 11px; color: var(--text-muted); background: var(--bg-card); padding: 1px 8px; border-radius: 10px; } -.kanban-col-add { background: none; border: 1px solid var(--border); color: var(--text-muted); width: 24px; height: 24px; border-radius: 6px; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; transition: all 0.15s; } -.kanban-col-add:hover { border-color: var(--accent); color: var(--accent); } -.kanban-col-body { padding: 10px; flex: 1; overflow-y: auto; } -.kanban-empty { border: 1px dashed var(--border-muted); border-radius: 8px; padding: 20px; text-align: center; color: var(--text-muted); font-size: 12px; } +.kanban-board { + display: flex; + gap: 16px; + padding: 16px 20px; + flex: 1; + overflow-x: auto; +} + +.kanban-column { + flex: 1; + min-width: 260px; + background: var(--bg-surface); + border-radius: 12px; + border: 1px solid var(--border); + display: flex; + flex-direction: column; +} + +.kanban-col-header { + display: flex; + align-items: center; + gap: 8px; + padding: 14px 16px; + border-bottom: 1px solid var(--border); +} + +.kanban-col-dot { + width: 8px; + height: 8px; + border-radius: 50%; +} + +.kanban-col-label { + font-size: 12px; + font-weight: 700; + text-transform: uppercase; + flex: 1; +} + +.kanban-col-count { + font-size: 11px; + color: var(--text-muted); + background: var(--bg-card); + padding: 1px 8px; + border-radius: 10px; +} + +.kanban-col-add { + background: none; + border: 1px solid var(--border); + color: var(--text-muted); + width: 24px; + height: 24px; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.15s; +} + +.kanban-col-add:hover { + border-color: var(--accent); + color: var(--accent); +} + +.kanban-col-body { + padding: 10px; + flex: 1; + overflow-y: auto; + min-height: 80px; +} + +.kanban-empty { + border: 1px dashed var(--border-muted); + border-radius: 8px; + padding: 20px; + text-align: center; + color: var(--text-muted); + font-size: 12px; + transition: all 0.2s; +} + +/* DRAG AND DROP */ +.kanban-column-drag-over { + border-color: var(--accent); + box-shadow: 0 0 24px var(--accent-glow), inset 0 0 12px rgba(99, 102, 241, 0.08); + background: rgba(99, 102, 241, 0.04); +} + +.kanban-column-drag-over .kanban-col-body { + background: rgba(99, 102, 241, 0.03); + border-radius: 0 0 12px 12px; +} + +.kanban-empty-active { + border-color: var(--accent); + color: var(--accent); + background: var(--accent-bg); + animation: dragPulse 1s ease infinite; +} + +.task-card { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 10px; + padding: 14px 16px; + margin-bottom: 10px; + cursor: grab; + transition: all 0.15s; + border-left: 3px solid; + user-select: none; +} + +.task-card:active { + cursor: grabbing; +} + +@keyframes dragPulse { + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.6; + } +} /* TASK CARD */ -.task-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; margin-bottom: 10px; cursor: pointer; transition: all 0.15s; border-left: 3px solid; } -.task-card:hover { background: var(--border); transform: translateY(-1px); box-shadow: 0 6px 24px rgba(0,0,0,0.4); } -.task-card-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; } -.task-card-title { font-size: 13px; font-weight: 600; color: #e2e8f0; flex: 1; } -.task-card-badges { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; } -.task-card-meta { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--text-muted); } -.task-card-overdue { color: var(--critical); } -.progress-bar-wrap { margin-bottom: 4px; } -.progress-bar-text { font-size: 10px; color: var(--text-muted); margin-bottom: 2px; } -.progress-bar { height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; } -.progress-bar-fill { height: 100%; border-radius: 2px; transition: width 0.3s; } +.task-card:hover { + background: var(--border); + transform: translateY(-1px); + box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4); +} + +.task-card-row { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 6px; +} + +.task-card-title { + font-size: 13px; + font-weight: 600; + color: #e2e8f0; + flex: 1; +} + +.task-card-badges { + display: flex; + flex-wrap: wrap; + gap: 4px; + margin-bottom: 6px; +} + +.task-card-meta { + display: flex; + align-items: center; + gap: 10px; + font-size: 11px; + color: var(--text-muted); +} + +.task-card-overdue { + color: var(--critical); +} + +.progress-bar-wrap { + margin-bottom: 4px; +} + +.progress-bar-text { + font-size: 10px; + color: var(--text-muted); + margin-bottom: 2px; +} + +.progress-bar { + height: 4px; + background: var(--border); + border-radius: 2px; + overflow: hidden; +} + +.progress-bar-fill { + height: 100%; + border-radius: 2px; + transition: width 0.3s; +} /* LIST VIEW */ -.list-view { padding: 16px 20px; } -.list-sort-row { display: flex; gap: 8px; margin-bottom: 12px; align-items: center; font-size: 12px; color: var(--text-muted); } -.list-sort-btn { padding: 4px 10px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; color: var(--text-muted); font-size: 11px; font-weight: 600; cursor: pointer; font-family: inherit; transition: all 0.15s; } -.list-sort-btn.active { border-color: var(--accent); color: var(--accent); } -.list-table { width: 100%; border-collapse: collapse; } -.list-table th { background: var(--bg-card); border-bottom: 1px solid var(--border); padding: 10px 12px; font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--text-muted); text-align: left; position: sticky; top: 0; } -.list-table td { padding: 10px 12px; font-size: 13px; border-bottom: 1px solid var(--border); } -.list-table tr:nth-child(odd) td { background: var(--bg-surface); } -.list-table tr:nth-child(even) td { background: #0d1120; } -.list-table tr:hover td { background: var(--border) !important; cursor: pointer; } -.list-actions-btn { background: none; border: none; color: var(--text-muted); cursor: pointer; font-size: 16px; position: relative; } -.list-dropdown { position: absolute; right: 0; top: 100%; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 4px; min-width: 120px; z-index: 100; box-shadow: 0 8px 24px rgba(0,0,0,0.4); } -.list-dropdown-item { display: block; width: 100%; padding: 6px 12px; background: none; border: none; color: var(--text-secondary); font-size: 12px; text-align: left; cursor: pointer; border-radius: 4px; font-family: inherit; } -.list-dropdown-item:hover { background: var(--accent-bg); color: var(--accent); } +.list-view { + padding: 16px 20px; +} + +.list-sort-row { + display: flex; + gap: 8px; + margin-bottom: 12px; + align-items: center; + font-size: 12px; + color: var(--text-muted); +} + +.list-sort-btn { + padding: 4px 10px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 6px; + color: var(--text-muted); + font-size: 11px; + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: all 0.15s; +} + +.list-sort-btn.active { + border-color: var(--accent); + color: var(--accent); +} + +.list-table { + width: 100%; + border-collapse: collapse; +} + +.list-table th { + background: var(--bg-card); + border-bottom: 1px solid var(--border); + padding: 10px 12px; + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + color: var(--text-muted); + text-align: left; + position: sticky; + top: 0; +} + +.list-table td { + padding: 10px 12px; + font-size: 13px; + border-bottom: 1px solid var(--border); +} + +.list-table tr:nth-child(odd) td { + background: var(--bg-surface); +} + +.list-table tr:nth-child(even) td { + background: #0d1120; +} + +.list-table tr:hover td { + background: var(--border) !important; + cursor: pointer; +} + +.list-actions-btn { + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 16px; + position: relative; +} + +.list-dropdown { + position: absolute; + right: 0; + top: 100%; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + padding: 4px; + min-width: 120px; + z-index: 100; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); +} + +.list-dropdown-item { + display: block; + width: 100%; + padding: 6px 12px; + background: none; + border: none; + color: var(--text-secondary); + font-size: 12px; + text-align: left; + cursor: pointer; + border-radius: 4px; + font-family: inherit; +} + +.list-dropdown-item:hover { + background: var(--accent-bg); + color: var(--accent); +} /* DRAWER */ -.drawer-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(4px); z-index: 100; animation: fadeIn 0.15s; } -.drawer { position: fixed; right: 0; top: 0; bottom: 0; width: 520px; background: var(--bg-surface); border-left: 1px solid var(--border); z-index: 101; animation: slideIn 0.2s ease; overflow-y: auto; display: flex; flex-direction: column; } -.drawer-header { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px; border-bottom: 1px solid var(--border); } -.drawer-header-label { font-size: 11px; text-transform: uppercase; color: var(--text-muted); letter-spacing: 0.05em; } -.drawer-close { background: var(--border); border: none; color: var(--text-secondary); width: 28px; height: 28px; border-radius: 6px; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; } -.drawer-body { padding: 20px; flex: 1; } -.drawer-title { font-size: 18px; font-weight: 700; margin-bottom: 6px; } -.drawer-desc { font-size: 13px; color: var(--text-muted); line-height: 1.6; margin-bottom: 16px; } -.drawer-meta { background: var(--bg-card); border-radius: 10px; padding: 16px; display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 16px; } -.drawer-meta-label { font-size: 10px; text-transform: uppercase; color: var(--text-muted); margin-bottom: 4px; } -.drawer-meta-val { font-size: 13px; display: flex; align-items: center; gap: 6px; } -.drawer-select { padding: 4px 8px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 12px; font-family: inherit; } -.drawer-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; } -.drawer-section { margin-bottom: 20px; } -.drawer-section-title { font-size: 13px; font-weight: 700; margin-bottom: 10px; display: flex; align-items: center; gap: 8px; } -.subtask-row { display: flex; align-items: center; gap: 8px; padding: 6px 0; cursor: pointer; transition: background 0.15s; border-radius: 4px; } -.subtask-row:hover { background: rgba(255,255,255,0.03); } -.subtask-checkbox { width: 16px; height: 16px; border: 1.5px solid var(--border-muted); border-radius: 4px; cursor: pointer; accent-color: var(--status-done); } -.subtask-text { font-size: 13px; } -.subtask-text.done { text-decoration: line-through; color: var(--text-muted); } -.subtask-add { display: flex; gap: 8px; margin-top: 8px; } -.subtask-add input { flex: 1; padding: 6px 10px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 12px; font-family: inherit; outline: none; } -.subtask-add button { padding: 6px 12px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-size: 11px; font-weight: 700; cursor: pointer; font-family: inherit; } -.comment-item { display: flex; gap: 10px; margin-bottom: 14px; } -.comment-bubble { background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; flex: 1; } -.comment-header { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; } -.comment-name { font-size: 12px; font-weight: 700; } -.comment-time { font-size: 10px; color: var(--text-muted); } -.comment-text { font-size: 12px; color: var(--text-secondary); } -.comment-input-row { display: flex; gap: 8px; align-items: center; } -.comment-input-row input { flex: 1; padding: 8px 10px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; color: var(--text-primary); font-size: 12px; font-family: inherit; outline: none; } -.comment-input-row button { padding: 8px 14px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-size: 12px; font-weight: 700; cursor: pointer; font-family: inherit; } -.activity-item { display: flex; gap: 10px; position: relative; padding-left: 16px; margin-bottom: 10px; } -.activity-item::before { content: ''; position: absolute; left: 3px; top: 8px; width: 6px; height: 6px; border-radius: 50%; background: var(--border-muted); } -.activity-item::after { content: ''; position: absolute; left: 5px; top: 16px; width: 2px; height: calc(100% + 4px); background: var(--border); } -.activity-item:last-child::after { display: none; } -.activity-text { font-size: 11px; color: #475569; } +.drawer-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + backdrop-filter: blur(4px); + z-index: 100; + animation: fadeIn 0.15s; +} + +.drawer { + position: fixed; + right: 0; + top: 0; + bottom: 0; + width: 520px; + background: var(--bg-surface); + border-left: 1px solid var(--border); + z-index: 101; + animation: slideIn 0.2s ease; + overflow-y: auto; + display: flex; + flex-direction: column; +} + +.drawer-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 20px; + border-bottom: 1px solid var(--border); +} + +.drawer-header-label { + font-size: 11px; + text-transform: uppercase; + color: var(--text-muted); + letter-spacing: 0.05em; +} + +.drawer-close { + background: var(--border); + border: none; + color: var(--text-secondary); + width: 28px; + height: 28px; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; +} + +.drawer-body { + padding: 20px; + flex: 1; +} + +.drawer-title { + font-size: 18px; + font-weight: 700; + margin-bottom: 6px; +} + +.drawer-desc { + font-size: 13px; + color: var(--text-muted); + line-height: 1.6; + margin-bottom: 16px; +} + +.drawer-meta { + background: var(--bg-card); + border-radius: 10px; + padding: 16px; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 14px; + margin-bottom: 16px; +} + +.drawer-meta-label { + font-size: 10px; + text-transform: uppercase; + color: var(--text-muted); + margin-bottom: 4px; +} + +.drawer-meta-val { + font-size: 13px; + display: flex; + align-items: center; + gap: 6px; +} + +.drawer-select { + padding: 4px 8px; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 6px; + color: var(--text-primary); + font-size: 12px; + font-family: inherit; +} + +.drawer-tags { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-bottom: 16px; +} + +.drawer-section { + margin-bottom: 20px; +} + +.drawer-section-title { + font-size: 13px; + font-weight: 700; + margin-bottom: 10px; + display: flex; + align-items: center; + gap: 8px; +} + +.subtask-row { + display: flex; + align-items: center; + gap: 8px; + padding: 6px 0; + cursor: pointer; + transition: background 0.15s; + border-radius: 4px; +} + +.subtask-row:hover { + background: rgba(255, 255, 255, 0.03); +} + +.subtask-checkbox { + width: 16px; + height: 16px; + border: 1.5px solid var(--border-muted); + border-radius: 4px; + cursor: pointer; + accent-color: var(--status-done); +} + +.subtask-text { + font-size: 13px; +} + +.subtask-text.done { + text-decoration: line-through; + color: var(--text-muted); +} + +.subtask-add { + display: flex; + gap: 8px; + margin-top: 8px; +} + +.subtask-add input { + flex: 1; + padding: 6px 10px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 6px; + color: var(--text-primary); + font-size: 12px; + font-family: inherit; + outline: none; +} + +.subtask-add button { + padding: 6px 12px; + background: var(--accent); + color: #fff; + border: none; + border-radius: 6px; + font-size: 11px; + font-weight: 700; + cursor: pointer; + font-family: inherit; +} + +.comment-item { + display: flex; + gap: 10px; + margin-bottom: 14px; +} + +.comment-bubble { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + padding: 8px 12px; + flex: 1; +} + +.comment-header { + display: flex; + align-items: center; + gap: 6px; + margin-bottom: 4px; +} + +.comment-name { + font-size: 12px; + font-weight: 700; +} + +.comment-time { + font-size: 10px; + color: var(--text-muted); +} + +.comment-text { + font-size: 12px; + color: var(--text-secondary); +} + +.comment-input-row { + display: flex; + gap: 8px; + align-items: center; +} + +.comment-input-row input { + flex: 1; + padding: 8px 10px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 6px; + color: var(--text-primary); + font-size: 12px; + font-family: inherit; + outline: none; +} + +.comment-input-row button { + padding: 8px 14px; + background: var(--accent); + color: #fff; + border: none; + border-radius: 6px; + font-size: 12px; + font-weight: 700; + cursor: pointer; + font-family: inherit; +} + +.activity-item { + display: flex; + gap: 10px; + position: relative; + padding-left: 16px; + margin-bottom: 10px; +} + +.activity-item::before { + content: ''; + position: absolute; + left: 3px; + top: 8px; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--border-muted); +} + +.activity-item::after { + content: ''; + position: absolute; + left: 5px; + top: 16px; + width: 2px; + height: calc(100% + 4px); + background: var(--border); +} + +.activity-item:last-child::after { + display: none; +} + +.activity-text { + font-size: 11px; + color: #475569; +} /* MODAL */ -.modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.6); backdrop-filter: blur(4px); z-index: 200; display: flex; align-items: center; justify-content: center; animation: fadeIn 0.15s; } -.modal { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 16px; width: 480px; max-height: 90vh; overflow-y: auto; animation: fadeUp 0.2s ease; } -.modal-header { display: flex; align-items: center; justify-content: space-between; padding: 20px 24px; border-bottom: 1px solid var(--border); } -.modal-header h2 { font-size: 16px; font-weight: 700; } -.modal-body { padding: 24px; } -.modal-field { margin-bottom: 14px; } -.modal-field label { font-size: 12px; font-weight: 600; color: var(--text-secondary); display: block; margin-bottom: 4px; } -.modal-input { width: 100%; padding: 8px 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; color: var(--text-primary); font-size: 13px; font-family: inherit; outline: none; } -.modal-input:focus { border-color: var(--accent); } -.modal-input.error { border-color: var(--critical); } -.modal-input-textarea { resize: vertical; min-height: 60px; } -.modal-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; } -.modal-footer { display: flex; justify-content: flex-end; gap: 10px; padding: 16px 24px; border-top: 1px solid var(--border); } -.btn-ghost { padding: 8px 18px; background: none; border: 1px solid var(--border); border-radius: 8px; color: var(--text-secondary); font-size: 13px; font-weight: 600; cursor: pointer; font-family: inherit; transition: all 0.15s; } -.btn-ghost:hover { border-color: var(--text-muted); } -.btn-primary { padding: 8px 18px; background: var(--accent); border: none; border-radius: 8px; color: #fff; font-size: 13px; font-weight: 700; cursor: pointer; font-family: inherit; box-shadow: 0 0 16px var(--accent-glow); transition: background 0.15s; } -.btn-primary:hover { background: var(--accent-hover); } +.modal-backdrop { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(4px); + z-index: 200; + display: flex; + align-items: center; + justify-content: center; + animation: fadeIn 0.15s; +} + +.modal { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 16px; + width: 480px; + max-height: 90vh; + overflow-y: auto; + animation: fadeUp 0.2s ease; +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 24px; + border-bottom: 1px solid var(--border); +} + +.modal-header h2 { + font-size: 16px; + font-weight: 700; +} + +.modal-body { + padding: 24px; +} + +.modal-field { + margin-bottom: 14px; +} + +.modal-field label { + font-size: 12px; + font-weight: 600; + color: var(--text-secondary); + display: block; + margin-bottom: 4px; +} + +.modal-input { + width: 100%; + padding: 8px 12px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + color: var(--text-primary); + font-size: 13px; + font-family: inherit; + outline: none; +} + +.modal-input:focus { + border-color: var(--accent); +} + +.modal-input.error { + border-color: var(--critical); +} + +.modal-input-textarea { + resize: vertical; + min-height: 60px; +} + +.modal-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 14px; +} + +.modal-footer { + display: flex; + justify-content: flex-end; + gap: 10px; + padding: 16px 24px; + border-top: 1px solid var(--border); +} + +.btn-ghost { + padding: 8px 18px; + background: none; + border: 1px solid var(--border); + border-radius: 8px; + color: var(--text-secondary); + font-size: 13px; + font-weight: 600; + cursor: pointer; + font-family: inherit; + transition: all 0.15s; +} + +.btn-ghost:hover { + border-color: var(--text-muted); +} + +.btn-primary { + padding: 8px 18px; + background: var(--accent); + border: none; + border-radius: 8px; + color: #fff; + font-size: 13px; + font-weight: 700; + cursor: pointer; + font-family: inherit; + box-shadow: 0 0 16px var(--accent-glow); + transition: background 0.15s; +} + +.btn-primary:hover { + background: var(--accent-hover); +} /* DASHBOARD */ -.dashboard { padding: 20px; } -.stats-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; } -.stat-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 12px; padding: 20px; } -.stat-card-num { font-size: 32px; font-weight: 800; } -.stat-card-label { font-size: 11px; text-transform: uppercase; color: var(--text-muted); margin-top: 4px; } -.workload-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 12px; padding: 20px; margin-bottom: 16px; } -.workload-card-title { font-size: 14px; font-weight: 700; margin-bottom: 16px; } -.workload-row { display: flex; align-items: center; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border); } -.workload-row:last-child { border-bottom: none; } -.workload-name { font-size: 13px; font-weight: 600; min-width: 120px; } -.workload-dept { font-size: 11px; color: var(--text-muted); min-width: 80px; } -.workload-bar { flex: 1; } -.workload-badges { display: flex; gap: 4px; } -.priority-bar-wrap { margin-bottom: 8px; } -.priority-bar { height: 24px; border-radius: 6px; display: flex; overflow: hidden; } -.priority-segment { display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: #fff; } -.deadline-item { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); } -.deadline-item.overdue { background: rgba(239,68,68,0.08); border-radius: 6px; padding: 8px; } -.progress-ring { margin: 20px auto; display: block; } +.dashboard { + padding: 20px; +} + +.stats-row { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 16px; + margin-bottom: 24px; +} + +.stat-card { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 20px; +} + +.stat-card-num { + font-size: 32px; + font-weight: 800; +} + +.stat-card-label { + font-size: 11px; + text-transform: uppercase; + color: var(--text-muted); + margin-top: 4px; +} + +.workload-card { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 20px; + margin-bottom: 16px; +} + +.workload-card-title { + font-size: 14px; + font-weight: 700; + margin-bottom: 16px; +} + +.workload-row { + display: flex; + align-items: center; + gap: 12px; + padding: 8px 0; + border-bottom: 1px solid var(--border); +} + +.workload-row:last-child { + border-bottom: none; +} + +.workload-name { + font-size: 13px; + font-weight: 600; + min-width: 120px; +} + +.workload-dept { + font-size: 11px; + color: var(--text-muted); + min-width: 80px; +} + +.workload-bar { + flex: 1; +} + +.workload-badges { + display: flex; + gap: 4px; +} + +.priority-bar-wrap { + margin-bottom: 8px; +} + +.priority-bar { + height: 24px; + border-radius: 6px; + display: flex; + overflow: hidden; +} + +.priority-segment { + display: flex; + align-items: center; + justify-content: center; + font-size: 10px; + font-weight: 700; + color: #fff; +} + +.deadline-item { + display: flex; + align-items: center; + gap: 10px; + padding: 8px 0; + border-bottom: 1px solid var(--border); +} + +.deadline-item.overdue { + background: rgba(239, 68, 68, 0.08); + border-radius: 6px; + padding: 8px; +} + +.progress-ring { + margin: 20px auto; + display: block; +} /* TEAM TASKS */ -.team-tasks { padding: 20px; } -.team-group { margin-bottom: 16px; } -.team-group-header { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: var(--bg-surface); border: 1px solid var(--border); border-radius: 8px; cursor: pointer; transition: background 0.15s; } -.team-group-header:hover { background: var(--bg-card); } -.team-group-name { font-size: 14px; font-weight: 600; flex: 1; } -.team-group-count { font-size: 12px; color: var(--text-muted); } -.team-group-tasks { padding: 8px 0 8px 42px; } -.team-task-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; } -.team-task-title { font-size: 13px; flex: 1; } +.team-tasks { + padding: 20px; +} + +.team-group { + margin-bottom: 16px; +} + +.team-group-header { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 12px; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 8px; + cursor: pointer; + transition: background 0.15s; +} + +.team-group-header:hover { + background: var(--bg-card); +} + +.team-group-name { + font-size: 14px; + font-weight: 600; + flex: 1; +} + +.team-group-count { + font-size: 12px; + color: var(--text-muted); +} + +.team-group-tasks { + padding: 8px 0 8px 42px; +} + +.team-task-row { + display: flex; + align-items: center; + gap: 10px; + padding: 6px 0; +} + +.team-task-title { + font-size: 13px; + flex: 1; +} /* REPORTS */ -.reports { padding: 20px; } -.charts-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } -.chart-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: 12px; padding: 20px; } -.chart-card-title { font-size: 14px; font-weight: 700; margin-bottom: 16px; } +.reports { + padding: 20px; +} + +.charts-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; +} + +.chart-card { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 20px; +} + +.chart-card-title { + font-size: 14px; + font-weight: 700; + margin-bottom: 16px; +} /* MEMBERS */ -.members-page { padding: 20px; } -.members-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; } -.members-header h2 { font-size: 18px; font-weight: 700; } -.members-table { width: 100%; border-collapse: collapse; } -.members-table th { background: var(--bg-card); border-bottom: 1px solid var(--border); padding: 10px 12px; font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--text-muted); text-align: left; } -.members-table td { padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 13px; } -.members-table tr:hover td { background: var(--bg-card); cursor: pointer; } -.member-expand { padding: 12px 16px; background: var(--bg-card); } -.invite-modal { width: 380px; } +.members-page { + padding: 20px; +} + +.members-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; +} + +.members-header h2 { + font-size: 18px; + font-weight: 700; +} + +.members-table { + width: 100%; + border-collapse: collapse; +} + +.members-table th { + background: var(--bg-card); + border-bottom: 1px solid var(--border); + padding: 10px 12px; + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + color: var(--text-muted); + text-align: left; +} + +.members-table td { + padding: 10px 12px; + border-bottom: 1px solid var(--border); + font-size: 13px; +} + +.members-table tr:hover td { + background: var(--bg-card); + cursor: pointer; +} + +.member-expand { + padding: 12px 16px; + background: var(--bg-card); +} + +.invite-modal { + width: 380px; +} /* MORE TASKS POPOVER */ -.more-popover { position: absolute; z-index: 150; background: var(--bg-card); border: 1px solid var(--border-muted); border-radius: 10px; padding: 10px; width: 260px; box-shadow: 0 8px 32px rgba(0,0,0,0.5); animation: fadeUp 0.15s ease; } -.more-popover-title { font-size: 11px; color: var(--text-muted); margin-bottom: 8px; font-weight: 600; } +.more-popover { + position: absolute; + z-index: 150; + background: var(--bg-card); + border: 1px solid var(--border-muted); + border-radius: 10px; + padding: 10px; + width: 260px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); + animation: fadeUp 0.15s ease; +} + +.more-popover-title { + font-size: 11px; + color: var(--text-muted); + margin-bottom: 8px; + font-weight: 600; +} \ No newline at end of file