| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Todo List Admin Dashboard</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <script> |
| tailwind.config = { |
| darkMode: 'class', |
| theme: { |
| extend: { |
| spacing: { |
| '128': '32rem', |
| '144': '36rem', |
| } |
| } |
| } |
| } |
| </script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .sidebar { |
| transition: all 0.3s ease; |
| width: 260px; |
| min-width: 260px; |
| } |
| .sidebar.collapsed { |
| width: 70px; |
| min-width: 70px; |
| } |
| .sidebar.collapsed .sidebar-text { |
| display: none; |
| } |
| .sidebar.collapsed .logo-text { |
| display: none; |
| } |
| .sidebar.collapsed .menu-item { |
| justify-content: center; |
| padding-left: 0; |
| padding-right: 0; |
| } |
| .sidebar.collapsed .menu-item i { |
| margin-right: 0; |
| } |
| .sidebar.collapsed .user-info { |
| flex-direction: column; |
| align-items: center; |
| padding: 0.5rem; |
| } |
| .sidebar.collapsed .user-avatar { |
| margin-right: 0; |
| margin-bottom: 0.5rem; |
| } |
| .sidebar.collapsed .user-details { |
| display: none; |
| } |
| .sidebar.collapsed .toggle-btn { |
| margin-left: 0; |
| justify-content: center; |
| } |
| .sidebar.collapsed .projects-title { |
| display: none; |
| } |
| .sidebar.collapsed .project-item span:last-child { |
| display: none; |
| } |
| .sidebar.collapsed .project-item { |
| justify-content: center; |
| } |
| .sidebar.collapsed .logout-btn span { |
| display: none; |
| } |
| .sidebar.collapsed .logout-btn { |
| justify-content: center; |
| } |
| .main-content { |
| transition: all 0.3s ease; |
| } |
| .main-content.expanded { |
| } |
| .todo-item:hover .todo-actions { |
| opacity: 1; |
| } |
| .todo-actions { |
| opacity: 0; |
| transition: opacity 0.2s ease; |
| } |
| .priority-high { |
| border-left: 4px solid #ef4444; |
| } |
| .priority-medium { |
| border-left: 4px solid #f59e0b; |
| } |
| .priority-low { |
| border-left: 4px solid #10b981; |
| } |
| |
| |
| .mobile-menu-button { |
| display: none; |
| } |
| |
| @media (max-width: 1024px) { |
| .sidebar { |
| position: fixed; |
| z-index: 50; |
| height: 100vh; |
| transform: translateX(-100%); |
| transition: transform 0.3s ease; |
| } |
| .sidebar.open { |
| transform: translateX(0); |
| } |
| .mobile-menu-button { |
| display: block; |
| } |
| .main-content { |
| margin-left: 0; |
| } |
| .stats-grid { |
| grid-template-columns: repeat(2, 1fr); |
| } |
| } |
| |
| @media (max-width: 640px) { |
| .stats-grid { |
| grid-template-columns: 1fr; |
| } |
| .header-actions { |
| display: none; |
| } |
| .mobile-header-actions { |
| display: flex; |
| } |
| .filter-controls { |
| flex-direction: column; |
| gap: 0.5rem; |
| } |
| .filter-controls > div { |
| width: 100%; |
| } |
| .task-modal-content { |
| width: 95%; |
| margin: 0.5rem auto; |
| } |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100 font-sans dark:bg-gray-900"> |
| <div class="flex h-screen overflow-hidden"> |
| |
| <div class="md:hidden fixed top-4 left-4 z-50"> |
| <button id="mobileMenuButton" class="mobile-menu-button p-2 rounded-md bg-white shadow text-gray-700 dark:bg-gray-800 dark:text-white"> |
| <i class="fas fa-bars"></i> |
| </button> |
| </div> |
| |
| |
| <div id="sidebar" class="sidebar bg-indigo-800 text-white flex-shrink-0 flex flex-col dark:bg-gray-800"> |
| <div class="p-4 flex items-center space-x-3 border-b border-indigo-700 dark:border-gray-700"> |
| <div class="w-8 h-8 rounded-full bg-indigo-600 flex items-center justify-center"> |
| <i class="fas fa-check"></i> |
| </div> |
| <span class="logo-text text-xl font-bold">Todo Admin</span> |
| </div> |
| |
| <div class="p-4 border-b border-indigo-700 dark:border-gray-700 user-info flex items-center justify-between"> |
| <div class="flex items-center"> |
| <div class="w-10 h-10 rounded-full bg-indigo-600 flex items-center justify-center user-avatar"> |
| <i class="fas fa-user"></i> |
| </div> |
| <div class="user-details ml-3"> |
| <div class="sidebar-text font-medium">Admin User</div> |
| <div class="sidebar-text text-xs text-indigo-300 dark:text-gray-400">Administrator</div> |
| </div> |
| </div> |
| <button id="toggleSidebar" class="text-indigo-300 hover:text-white toggle-btn dark:text-gray-400"> |
| <i class="fas fa-chevron-left"></i> |
| </button> |
| </div> |
| |
| <nav class="flex-1 overflow-y-auto py-4"> |
| <div class="space-y-1 px-2"> |
| <a href="#" class="menu-item flex items-center px-3 py-2 bg-indigo-900 rounded-md text-white dark:bg-gray-700"> |
| <i class="fas fa-tachometer-alt w-5 mr-3"></i> |
| <span class="sidebar-text">Dashboard</span> |
| </a> |
| <a href="#" class="menu-item flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700"> |
| <i class="fas fa-tasks w-5 mr-3"></i> |
| <span class="sidebar-text">All Tasks</span> |
| <span id="totalTasksBadge" class="ml-auto bg-indigo-600 text-xs px-2 py-0.5 rounded-full dark:bg-gray-600">0</span> |
| </a> |
| <a href="#" class="menu-item flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700"> |
| <i class="fas fa-calendar-alt w-5 mr-3"></i> |
| <span class="sidebar-text">Calendar</span> |
| </a> |
| <a href="#" class="menu-item flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700"> |
| <i class="fas fa-users w-5 mr-3"></i> |
| <span class="sidebar-text">Users</span> |
| </a> |
| <a href="#" class="menu-item flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700"> |
| <i class="fas fa-cog w-5 mr-3"></i> |
| <span class="sidebar-text">Settings</span> |
| </a> |
| </div> |
| |
| <div class="px-4 mt-8"> |
| <h3 class="sidebar-text projects-title text-xs uppercase font-semibold text-indigo-400 mb-2 dark:text-gray-400">Projects</h3> |
| <div class="space-y-1"> |
| <a href="#" class="project-item flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700"> |
| <span class="w-2 h-2 rounded-full bg-green-400 mr-3"></span> |
| <span class="sidebar-text">Website Redesign</span> |
| </a> |
| <a href="#" class="project-item flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700"> |
| <span class="w-2 h-2 rounded-full bg-blue-400 mr-3"></span> |
| <span class="sidebar-text">Mobile App</span> |
| </a> |
| <a href="#" class="project-item flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700"> |
| <span class="w-2 h-2 rounded-full bg-purple-400 mr-3"></span> |
| <span class="sidebar-text">Marketing</span> |
| </a> |
| </div> |
| </div> |
| </nav> |
| |
| <div class="p-4 border-t border-indigo-700 dark:border-gray-700"> |
| <button class="logout-btn flex items-center px-3 py-2 hover:bg-indigo-700 rounded-md text-indigo-100 hover:text-white dark:hover:bg-gray-700 w-full"> |
| <i class="fas fa-sign-out-alt w-5 mr-3"></i> |
| <span class="sidebar-text">Logout</span> |
| </button> |
| </div> |
| </div> |
| |
| |
| <div class="main-content flex-1 flex flex-col overflow-hidden"> |
| |
| <header class="bg-white shadow-sm dark:bg-gray-800"> |
| <div class="px-4 sm:px-6 py-4 flex items-center justify-between"> |
| <h1 class="text-xl sm:text-2xl font-semibold text-gray-800 dark:text-white">Task Dashboard</h1> |
| |
| <div class="flex items-center space-x-2 sm:space-x-4"> |
| |
| <div class="mobile-header-actions hidden"> |
| <button id="mobileDarkModeToggle" class="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700"> |
| <i id="mobileDarkModeIcon" class="fas fa-moon text-gray-500 dark:text-yellow-300"></i> |
| </button> |
| </div> |
| |
| |
| <div class="header-actions flex items-center space-x-2 sm:space-x-4"> |
| <button id="toggleDarkMode" class="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700"> |
| <i id="darkModeIcon" class="fas fa-moon text-gray-500 dark:text-yellow-300"></i> |
| </button> |
| <div class="relative"> |
| <button class="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700"> |
| <i class="fas fa-bell text-gray-500 dark:text-gray-300"></i> |
| <span class="absolute top-0 right-0 w-2 h-2 rounded-full bg-red-500"></span> |
| </button> |
| </div> |
| <div class="relative"> |
| <button class="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700"> |
| <i class="fas fa-envelope text-gray-500 dark:text-gray-300"></i> |
| <span class="absolute top-0 right-0 w-2 h-2 rounded-full bg-blue-500"></span> |
| </button> |
| </div> |
| <div class="relative"> |
| <button id="userMenuButton" class="flex items-center space-x-2"> |
| <div class="w-8 h-8 rounded-full bg-indigo-100 dark:bg-gray-700 flex items-center justify-center"> |
| <i class="fas fa-user text-indigo-600 dark:text-gray-300"></i> |
| </div> |
| <span class="hidden sm:inline text-sm font-medium dark:text-white">Admin</span> |
| <i class="fas fa-chevron-down text-xs dark:text-gray-300"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
| </header> |
| |
| |
| <main class="flex-1 overflow-y-auto p-4 sm:p-6"> |
| |
| <div class="stats-grid grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6 mb-6"> |
| <div class="bg-white rounded-lg shadow p-4 sm:p-6 dark:bg-gray-800"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="text-gray-500 text-sm dark:text-gray-300">Total Tasks</p> |
| <h3 id="totalTasksCount" class="text-xl sm:text-2xl font-bold dark:text-white">0</h3> |
| </div> |
| <div class="p-2 sm:p-3 rounded-full bg-indigo-100 text-indigo-600 dark:bg-gray-700 dark:text-indigo-300"> |
| <i class="fas fa-tasks"></i> |
| </div> |
| </div> |
| <div class="mt-2 sm:mt-4"> |
| <div class="flex items-center text-xs sm:text-sm text-green-500 dark:text-green-400"> |
| <i class="fas fa-arrow-up mr-1"></i> |
| <span>12% from last week</span> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-lg shadow p-4 sm:p-6 dark:bg-gray-800"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="text-gray-500 text-sm dark:text-gray-300">Completed</p> |
| <h3 id="completedTasksCount" class="text-xl sm:text-2xl font-bold dark:text-white">0</h3> |
| </div> |
| <div class="p-2 sm:p-3 rounded-full bg-green-100 text-green-600 dark:bg-gray-700 dark:text-green-300"> |
| <i class="fas fa-check-circle"></i> |
| </div> |
| </div> |
| <div class="mt-2 sm:mt-4"> |
| <div class="flex items-center text-xs sm:text-sm text-green-500 dark:text-green-400"> |
| <i class="fas fa-arrow-up mr-1"></i> |
| <span>8% from last week</span> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-lg shadow p-4 sm:p-6 dark:bg-gray-800"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="text-gray-500 text-sm dark:text-gray-300">In Progress</p> |
| <h3 id="inProgressTasksCount" class="text-xl sm:text-2xl font-bold dark:text-white">0</h3> |
| </div> |
| <div class="p-2 sm:p-3 rounded-full bg-yellow-100 text-yellow-600 dark:bg-gray-7s00 dark:text-yellow-300"> |
| <i class="fas fa-spinner"></i> |
| </div> |
| </div> |
| <div class="mt-2 sm:mt-4"> |
| <div class="flex items-center text-xs sm:text-sm text-red-500 dark:text-red-400"> |
| <i class="fas fa-arrow-down mr-1"></i> |
| <span>3% from last week</span> |
| </div> |
| </div> |
| </div> |
| |
| <div class="bg-white rounded-lg shadow p-4 sm:p-6 dark:bg-gray-800"> |
| <div class="flex items-center justify-between"> |
| <div> |
| <p class="text-gray-500 text-sm dark:text-gray-300">Overdue</p> |
| <h3 id="overdueTasksCount" class="text-xl sm:text-2xl font-bold dark:text-white">0</h3> |
| </div> |
| <div class="p-2 sm:p-3 rounded-full bg-red-100 text-red-600 dark:bg-gray-700 dark:text-red-300"> |
| <i class="fas fa-exclamation-circle"></i> |
| </div> |
| </div> |
| <div class="mt-2 sm:mt-4"> |
| <div class="flex items-center text-xs sm:text-sm text-green-500 dark:text-green-400"> |
| <i class="fas fa-arrow-down mr-1"></i> |
| <span>2% from last week</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div class="bg-white rounded-lg shadow mb-6 dark:bg-gray-800"> |
| <div class="p-4 sm:p-6 border-b border-gray-200 dark:border-gray-700"> |
| <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4"> |
| <h2 class="text-lg font-semibold dark:text-white">Tasks</h2> |
| <div class="filter-controls flex flex-col sm:flex-row sm:space-x-3"> |
| <div class="relative flex-1"> |
| <select id="projectFilter" class="appearance-none bg-gray-100 border border-gray-200 rounded-md py-2 pl-3 pr-8 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white w-full"> |
| <option value="all">All Projects</option> |
| <option value="Website Redesign">Website Redesign</option> |
| <option value="Mobile App">Mobile App</option> |
| <option value="Marketing">Marketing</option> |
| </select> |
| <div class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none"> |
| <i class="fas fa-chevron-down text-xs text-gray-500 dark:text-gray-300"></i> |
| </div> |
| </div> |
| <div class="relative flex-1"> |
| <select id="statusFilter" class="appearance-none bg-gray-100 border border-gray-200 rounded-md py-2 pl-3 pr-8 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white w-full"> |
| <option value="all">All Status</option> |
| <option value="completed">Completed</option> |
| <option value="in-progress">In Progress</option> |
| <option value="pending">Pending</option> |
| </select> |
| <div class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none"> |
| <i class="fas fa-chevron-down text-xs text-gray-500 dark:text-gray-300"></i> |
| </div> |
| </div> |
| <button id="addTaskBtn" class="bg-indigo-600 hover:bg-indigo-700 text-white px-4 py-2 rounded-md text-sm font-medium flex items-center justify-center dark:bg-indigo-700 dark:hover:bg-indigo-800"> |
| <i class="fas fa-plus mr-2"></i> <span class="hidden sm:inline">Add Task</span> |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="taskListContainer" class="divide-y divide-gray-200 dark:divide-gray-700"> |
| |
| </div> |
| |
| |
| <div class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 dark:bg-gray-800 dark:border-gray-700"> |
| <div class="flex-1 flex justify-between sm:hidden"> |
| <a href="#" class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:hover:bg-gray-700"> |
| Previous |
| </a> |
| <a href="#" class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:hover:bg-gray-700"> |
| Next |
| </a> |
| </div> |
| <div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between"> |
| <div> |
| <p id="paginationInfo" class="text-sm text-gray-700 dark:text-gray-300"> |
| Showing <span class="font-medium">0</span> to <span class="font-medium">0</span> of <span class="font-medium">0</span> results |
| </p> |
| </div> |
| <div> |
| <nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination"> |
| <a href="#" class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"> |
| <span class="sr-only">Previous</span> |
| <i class="fas fa-chevron-left"></i> |
| </a> |
| <a href="#" aria-current="page" class="z-10 bg-indigo-50 border-indigo-500 text-indigo-600 relative inline-flex items-center px-4 py-2 border text-sm font-medium dark:bg-gray-700 dark:border-gray-600 dark:text-indigo-300"> |
| 1 |
| </a> |
| <a href="#" class="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"> |
| 2 |
| </a> |
| <a href="#" class="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"> |
| 3 |
| </a> |
| <span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300"> |
| ... |
| </span> |
| <a href="#" class="bg-white border-gray-300 text-gray-500 hover:bg-gray-50 relative inline-flex items-center px-4 py-2 border text-sm font-medium dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"> |
| 8 |
| </a> |
| <a href="#" class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-700"> |
| <span class="sr-only">Next</span> |
| <i class="fas fa-chevron-right"></i> |
| </a> |
| </nav> |
| </div> |
| </div> |
| </div> |
| </div> |
| </main> |
| </div> |
| </div> |
| |
| |
| <div id="taskModal" class="fixed inset-0 overflow-y-auto hidden z-50"> |
| <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
| <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |
| <div class="absolute inset-0 bg-gray-500 opacity-75 dark:bg-gray-900 dark:opacity-90"></div> |
| </div> |
| |
| <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span> |
| |
| <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg w-full task-modal-content"> |
| <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 dark:bg-gray-800"> |
| <div class="sm:flex sm:items-start"> |
| <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full"> |
| <h3 class="text-lg leading-6 font-medium text-gray-900 mb-4 dark:text-white" id="modal-title"> |
| Add New Task |
| </h3> |
| <form id="taskForm"> |
| <div class="mb-4"> |
| <label for="taskTitle" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Task Title</label> |
| <input type="text" id="taskTitle" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white" placeholder="Enter task title" required> |
| </div> |
| |
| <div class="mb-4"> |
| <label for="taskDescription" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Description</label> |
| <textarea id="taskDescription" rows="3" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white" placeholder="Enter task description"></textarea> |
| </div> |
| |
| <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4"> |
| <div> |
| <label for="taskPriority" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Priority</label> |
| <select id="taskPriority" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| <option value="low">Low</option> |
| <option value="medium" selected>Medium</option> |
| <option value="high">High</option> |
| </select> |
| </div> |
| |
| <div> |
| <label for="taskProject" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Project</label> |
| <select id="taskProject" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| <option>Website Redesign</option> |
| <option>Mobile App</option> |
| <option>Marketing</option> |
| </select> |
| </div> |
| </div> |
| |
| <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4"> |
| <div> |
| <label for="taskDueDate" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Due Date</label> |
| <input type="date" id="taskDueDate" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| </div> |
| |
| <div> |
| <label for="taskAssignee" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Assignee</label> |
| <select id="taskAssignee" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| <option>John D.</option> |
| <option>Sarah M.</option> |
| <option>Mike T.</option> |
| <option>Lisa K.</option> |
| </select> |
| </div> |
| </div> |
| </form> |
| </div> |
| </div> |
| </div> |
| <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse dark:bg-gray-700"> |
| <button type="button" id="saveTaskBtn" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm dark:bg-indigo-700 dark:hover:bg-indigo-800"> |
| Save Task |
| </button> |
| <button type="button" id="cancelTaskBtn" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm dark:bg-gray-600 dark:border-gray-500 dark:text-white dark:hover:bg-gray-500"> |
| Cancel |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| |
| <div id="editTaskModal" class="fixed inset-0 overflow-y-auto hidden z-50"> |
| <div class="flex items-center justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> |
| <div class="fixed inset-0 transition-opacity" aria-hidden="true"> |
| <div class="absolute inset-0 bg-gray-500 opacity-75 dark:bg-gray-900 dark:opacity-90"></div> |
| </div> |
| |
| <span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span> |
| |
| <div class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg w-full task-modal-content"> |
| <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 dark:bg-gray-800"> |
| <div class="sm:flex sm:items-start"> |
| <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left w-full"> |
| <h3 class="text-lg leading-6 font-medium text-gray-900 mb-4 dark:text-white">Edit Task</h3> |
| <form id="editTaskForm"> |
| <input type="hidden" id="editTaskId"> |
| <div class="mb-4"> |
| <label for="editTaskTitle" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Task Title</label> |
| <input type="text" id="editTaskTitle" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white" placeholder="Enter task title" required> |
| </div> |
| |
| <div class="mb-4"> |
| <label for="editTaskDescription" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Description</label> |
| <textarea id="editTaskDescription" rows="3" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white" placeholder="Enter task description"></textarea> |
| </div> |
| |
| <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4"> |
| <div> |
| <label for="editTaskPriority" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Priority</label> |
| <select id="editTaskPriority" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| <option value="low">Low</option> |
| <option value="medium">Medium</option> |
| <option value="high">High</option> |
| </select> |
| </div> |
| |
| <div> |
| <label for="editTaskProject" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Project</label> |
| <select id="editTaskProject" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| <option>Website Redesign</option> |
| <option>Mobile App</option> |
| <option>Marketing</option> |
| </select> |
| </div> |
| </div> |
| |
| <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4"> |
| <div> |
| <label for="editTaskDueDate" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Due Date</label> |
| <input type="date" id="editTaskDueDate" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| </div> |
| |
| <div> |
| <label for="editTaskAssignee" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Assignee</label> |
| <select id="editTaskAssignee" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| <option>John D.</option> |
| <option>Sarah M.</option> |
| <option>Mike T.</option> |
| <option>Lisa K.</option> |
| </select> |
| </div> |
| </div> |
| |
| <div class="mb-4"> |
| <label for="editTaskStatus" class="block text-sm font-medium text-gray-700 mb-1 dark:text-gray-300">Status</label> |
| <select id="editTaskStatus" class="shadow-sm focus:ring-indigo-500 focus:border-indigo-500 block w-full sm:text-sm border-gray-300 rounded-md p-2 border dark:bg-gray-700 dark:border-gray-600 dark:text-white"> |
| <option value="pending">Pending</option> |
| <option value="in-progress">In Progress</option> |
| <option value="completed">Completed</option> |
| </select> |
| </div> |
| </form> |
| </div> |
| </div> |
| </div> |
| <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse dark:bg-gray-700"> |
| <button type="button" id="updateTaskBtn" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-indigo-600 text-base font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:ml-3 sm:w-auto sm:text-sm dark:bg-indigo-700 dark:hover:bg-indigo-800"> |
| Update Task |
| </button> |
| <button type="button" id="cancelEditTaskBtn" class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm dark:bg-gray-600 dark:border-gray-500 dark:text-white dark:hover:bg-gray-500"> |
| Cancel |
| </button> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <script> |
| |
| let tasks = JSON.parse(localStorage.getItem('tasks')) || []; |
| |
| |
| const taskModal = document.getElementById('taskModal'); |
| const editTaskModal = document.getElementById('editTaskModal'); |
| const addTaskBtn = document.getElementById('addTaskBtn'); |
| const saveTaskBtn = document.getElementById('saveTaskBtn'); |
| const cancelTaskBtn = document.getElementById('cancelTaskBtn'); |
| const updateTaskBtn = document.getElementById('updateTaskBtn'); |
| const cancelEditTaskBtn = document.getElementById('cancelEditTaskBtn'); |
| const taskForm = document.getElementById('taskForm'); |
| const editTaskForm = document.getElementById('editTaskForm'); |
| const taskListContainer = document.getElementById('taskListContainer'); |
| const projectFilter = document.getElementById('projectFilter'); |
| const statusFilter = document.getElementById('statusFilter'); |
| const toggleSidebarBtn = document.getElementById('toggleSidebar'); |
| const sidebar = document.getElementById('sidebar'); |
| const mainContent = document.querySelector('.main-content'); |
| const toggleDarkModeBtn = document.getElementById('toggleDarkMode'); |
| const darkModeIcon = document.getElementById('darkModeIcon'); |
| const mobileMenuButton = document.getElementById('mobileMenuButton'); |
| const mobileDarkModeToggle = document.getElementById('mobileDarkModeToggle'); |
| const mobileDarkModeIcon = document.getElementById('mobileDarkModeIcon'); |
| |
| |
| const totalTasksCount = document.getElementById('totalTasksCount'); |
| const completedTasksCount = document.getElementById('completedTasksCount'); |
| const inProgressTasksCount = document.getElementById('inProgressTasksCount'); |
| const overdueTasksCount = document.getElementById('overdueTasksCount'); |
| const totalTasksBadge = document.getElementById('totalTasksBadge'); |
| |
| |
| const currentTheme = localStorage.getItem('theme') || 'light'; |
| if (currentTheme === 'dark') { |
| document.documentElement.classList.add('dark'); |
| darkModeIcon.classList.remove('fa-moon'); |
| darkModeIcon.classList.add('fa-sun'); |
| mobileDarkModeIcon.classList.remove('fa-moon'); |
| mobileDarkModeIcon.classList.add('fa-sun'); |
| } |
| |
| |
| function toggleDarkMode() { |
| if (document.documentElement.classList.contains('dark')) { |
| document.documentElement.classList.remove('dark'); |
| localStorage.setItem('theme', 'light'); |
| darkModeIcon.classList.remove('fa-sun'); |
| darkModeIcon.classList.add('fa-moon'); |
| mobileDarkModeIcon.classList.remove('fa-sun'); |
| mobileDarkModeIcon.classList.add('fa-moon'); |
| } else { |
| document.documentElement.classList.add('dark'); |
| localStorage.setItem('theme', 'dark'); |
| darkModeIcon.classList.remove('fa-moon'); |
| darkModeIcon.classList.add('fa-sun'); |
| mobileDarkModeIcon.classList.remove('fa-moon'); |
| mobileDarkModeIcon.classList.add('fa-sun'); |
| } |
| } |
| |
| toggleDarkModeBtn.addEventListener('click', toggleDarkMode); |
| mobileDarkModeToggle.addEventListener('click', toggleDarkMode); |
| |
| |
| toggleSidebarBtn.addEventListener('click', function() { |
| sidebar.classList.toggle('collapsed'); |
| mainContent.classList.toggle('expanded'); |
| |
| |
| const icon = this.querySelector('i'); |
| if (sidebar.classList.contains('collapsed')) { |
| icon.classList.remove('fa-chevron-left'); |
| icon.classList.add('fa-chevron-right'); |
| } else { |
| icon.classList.remove('fa-chevron-right'); |
| icon.classList.add('fa-chevron-left'); |
| } |
| }); |
| |
| |
| mobileMenuButton.addEventListener('click', function() { |
| sidebar.classList.toggle('open'); |
| }); |
| |
| |
| document.addEventListener('click', function(event) { |
| const isClickInsideSidebar = sidebar.contains(event.target); |
| const isClickInsideMobileButton = mobileMenuButton.contains(event.target); |
| |
| if (!isClickInsideSidebar && !isClickInsideMobileButton && window.innerWidth <= 1024) { |
| sidebar.classList.remove('open'); |
| } |
| }); |
| |
| |
| addTaskBtn.addEventListener('click', () => { |
| taskModal.classList.remove('hidden'); |
| }); |
| |
| cancelTaskBtn.addEventListener('click', () => { |
| taskModal.classList.add('hidden'); |
| taskForm.reset(); |
| }); |
| |
| cancelEditTaskBtn.addEventListener('click', () => { |
| editTaskModal.classList.add('hidden'); |
| editTaskForm.reset(); |
| }); |
| |
| |
| window.addEventListener('click', (event) => { |
| if (event.target === taskModal) { |
| taskModal.classList.add('hidden'); |
| taskForm.reset(); |
| } |
| if (event.target === editTaskModal) { |
| editTaskModal.classList.add('hidden'); |
| editTaskForm.reset(); |
| } |
| }); |
| |
| |
| saveTaskBtn.addEventListener('click', () => { |
| if (!taskForm.checkValidity()) { |
| alert('Please fill in all required fields'); |
| return; |
| } |
| |
| const newTask = { |
| id: Date.now().toString(), |
| title: document.getElementById('taskTitle').value, |
| description: document.getElementById('taskDescription').value, |
| priority: document.getElementById('taskPriority').value, |
| project: document.getElementById('taskProject').value, |
| dueDate: document.getElementById('taskDueDate').value, |
| assignee: document.getElementById('taskAssignee').value, |
| status: 'pending', |
| createdAt: new Date().toISOString() |
| }; |
| |
| tasks.push(newTask); |
| saveTasks(); |
| renderTasks(); |
| |
| taskModal.classList.add('hidden'); |
| taskForm.reset(); |
| }); |
| |
| |
| updateTaskBtn.addEventListener('click', () => { |
| const taskId = document.getElementById('editTaskId').value; |
| const taskIndex = tasks.findIndex(task => task.id === taskId); |
| |
| if (taskIndex !== -1) { |
| tasks[taskIndex] = { |
| ...tasks[taskIndex], |
| title: document.getElementById('editTaskTitle').value, |
| description: document.getElementById('editTaskDescription').value, |
| priority: document.getElementById('editTaskPriority').value, |
| project: document.getElementById('editTaskProject').value, |
| dueDate: document.getElementById('editTaskDueDate').value, |
| assignee: document.getElementById('editTaskAssignee').value, |
| status: document.getElementById('editTaskStatus').value |
| }; |
| |
| saveTasks(); |
| renderTasks(); |
| editTaskModal.classList.add('hidden'); |
| } |
| }); |
| |
| |
| projectFilter.addEventListener('change', renderTasks); |
| statusFilter.addEventListener('change', renderTasks); |
| |
| |
| function saveTasks() { |
| localStorage.setItem('tasks', JSON.stringify(tasks)); |
| updateStats(); |
| } |
| |
| |
| function renderTasks() { |
| const projectFilterValue = projectFilter.value; |
| const statusFilterValue = statusFilter.value; |
| |
| let filteredTasks = [...tasks]; |
| |
| if (projectFilterValue !== 'all') { |
| filteredTasks = filteredTasks.filter(task => task.project === projectFilterValue); |
| } |
| |
| if (statusFilterValue !== 'all') { |
| filteredTasks = filteredTasks.filter(task => task.status === statusFilterValue); |
| } |
| |
| |
| filteredTasks.sort((a, b) => { |
| const priorityOrder = { high: 3, medium: 2, low: 1 }; |
| if (priorityOrder[b.priority] !== priorityOrder[a.priority]) { |
| return priorityOrder[b.priority] - priorityOrder[a.priority]; |
| } |
| |
| if (!a.dueDate && !b.dueDate) return 0; |
| if (!a.dueDate) return 1; |
| if (!b.dueDate) return -1; |
| |
| return new Date(a.dueDate) - new Date(b.dueDate); |
| }); |
| |
| taskListContainer.innerHTML = ''; |
| |
| if (filteredTasks.length === 0) { |
| taskListContainer.innerHTML = ` |
| <div class="p-8 text-center"> |
| <i class="fas fa-tasks text-4xl text-gray-300 dark:text-gray-500 mb-4"></i> |
| <p class="text-gray-500 dark:text-gray-400">No tasks found. Create a new task to get started!</p> |
| </div> |
| `; |
| return; |
| } |
| |
| filteredTasks.forEach(task => { |
| const priorityClass = task.priority === 'high' ? 'priority-high' : |
| task.priority === 'medium' ? 'priority-medium' : 'priority-low'; |
| |
| const isCompleted = task.status === 'completed'; |
| const lineThroughClass = isCompleted ? 'line-through' : ''; |
| |
| const priorityBadgeColor = task.priority === 'high' ? 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300' : |
| task.priority === 'medium' ? 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300' : 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300'; |
| |
| const projectBadgeColor = task.project === 'Website Redesign' ? 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900 dark:text-indigo-300' : |
| task.project === 'Mobile App' ? 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300' : 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300'; |
| |
| const statusBadge = task.status === 'completed' ? |
| '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300">Completed</span>' : |
| task.status === 'in-progress' ? |
| '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300">In Progress</span>' : |
| ''; |
| |
| const overdueBadge = task.dueDate && new Date(task.dueDate) < new Date() && task.status !== 'completed' ? |
| '<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300">Overdue</span>' : ''; |
| |
| const taskElement = document.createElement('div'); |
| taskElement.className = `todo-item ${priorityClass} p-4 hover:bg-gray-50 flex items-start dark:hover:bg-gray-700`; |
| taskElement.innerHTML = ` |
| <div class="flex items-center h-5 mr-3 mt-1"> |
| <input type="checkbox" class="task-checkbox h-4 w-4 text-indigo-600 rounded focus:ring-indigo-500 dark:text-indigo-400" ${isCompleted ? 'checked' : ''} data-id="${task.id}"> |
| </div> |
| <div class="flex-1 min-w-0"> |
| <div class="flex items-center justify-between"> |
| <p class="text-sm font-medium text-gray-900 truncate ${lineThroughClass} dark:text-white"> |
| ${task.title} |
| </p> |
| <div class="todo-actions flex space-x-2 ml-2"> |
| <button class="edit-task-btn text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400" data-id="${task.id}"> |
| <i class="fas fa-pencil-alt text-xs"></i> |
| </button> |
| <button class="delete-task-btn text-gray-400 hover:text-red-600 dark:hover:text-red-400" data-id="${task.id}"> |
| <i class="fas fa-trash-alt text-xs"></i> |
| </button> |
| </div> |
| </div> |
| ${task.description ? ` |
| <p class="text-sm text-gray-500 mt-1 ${lineThroughClass} dark:text-gray-300"> |
| ${task.description} |
| </p> |
| ` : ''} |
| <div class="mt-2 flex flex-wrap items-center"> |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${priorityBadgeColor} mr-2 mb-1"> |
| ${task.priority.charAt(0).toUpperCase() + task.priority.slice(1)} |
| </span> |
| <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${projectBadgeColor} mr-2 mb-1"> |
| ${task.project} |
| </span> |
| ${task.dueDate ? ` |
| <span class="text-xs text-gray-500 mr-2 mb-1 flex items-center dark:text-gray-400"> |
| <i class="fas fa-calendar-alt mr-1"></i> Due: ${formatDate(task.dueDate)} |
| </span> |
| ` : ''} |
| <span class="text-xs text-gray-500 mr-2 mb-1 flex items-center dark:text-gray-400"> |
| <i class="fas fa-user mr-1"></i> ${task.assignee} |
| </span> |
| ${statusBadge} |
| ${overdueBadge} |
| </div> |
| </div> |
| `; |
| |
| taskListContainer.appendChild(taskElement); |
| }); |
| |
| |
| document.querySelectorAll('.task-checkbox').forEach(checkbox => { |
| checkbox.addEventListener('change', function() { |
| const taskId = this.getAttribute('data-id'); |
| const taskIndex = tasks.findIndex(task => task.id === taskId); |
| |
| if (taskIndex !== -1) { |
| tasks[taskIndex].status = this.checked ? 'completed' : 'pending'; |
| saveTasks(); |
| renderTasks(); |
| } |
| }); |
| }); |
| |
| document.querySelectorAll('.edit-task-btn').forEach(btn => { |
| btn.addEventListener('click', function() { |
| const taskId = this.getAttribute('data-id'); |
| const task = tasks.find(task => task.id === taskId); |
| |
| if (task) { |
| document.getElementById('editTaskId').value = task.id; |
| document.getElementById('editTaskTitle').value = task.title; |
| document.getElementById('editTaskDescription').value = task.description || ''; |
| document.getElementById('editTaskPriority').value = task.priority; |
| document.getElementById('editTaskProject').value = task.project; |
| document.getElementById('editTaskDueDate').value = task.dueDate || ''; |
| document.getElementById('editTaskAssignee').value = task.assignee; |
| document.getElementById('editTaskStatus').value = task.status; |
| |
| editTaskModal.classList.remove('hidden'); |
| } |
| }); |
| }); |
| |
| document.querySelectorAll('.delete-task-btn').forEach(btn => { |
| btn.addEventListener('click', function() { |
| if (confirm('Are you sure you want to delete this task?')) { |
| const taskId = this.getAttribute('data-id'); |
| tasks = tasks.filter(task => task.id !== taskId); |
| saveTasks(); |
| renderTasks(); |
| } |
| }); |
| }); |
| |
| |
| document.getElementById('paginationInfo').innerHTML = ` |
| Showing <span class="font-medium">1</span> to <span class="font-medium">${filteredTasks.length}</span> of <span class="font-medium">${filteredTasks.length}</span> results |
| `; |
| } |
| |
| |
| function updateStats() { |
| const total = tasks.length; |
| const completed = tasks.filter(task => task.status === 'completed').length; |
| const inProgress = tasks.filter(task => task.status === 'in-progress').length; |
| const overdue = tasks.filter(task => |
| task.dueDate && |
| new Date(task.dueDate) < new Date() && |
| task.status !== 'completed' |
| ).length; |
| |
| totalTasksCount.textContent = total; |
| completedTasksCount.textContent = completed; |
| inProgressTasksCount.textContent = inProgress; |
| overdueTasksCount.textContent = overdue; |
| totalTasksBadge.textContent = total; |
| } |
| |
| |
| function formatDate(dateString) { |
| const options = { year: 'numeric', month: 'short', day: 'numeric' }; |
| return new Date(dateString).toLocaleDateString(undefined, options); |
| } |
| |
| |
| function init() { |
| |
| if (tasks.length === 0) { |
| tasks = [ |
| { |
| id: '1', |
| title: 'Implement user authentication system', |
| description: 'Create secure login and registration pages with JWT authentication', |
| priority: 'high', |
| project: 'Website Redesign', |
| dueDate: '2023-07-15', |
| assignee: 'John D.', |
| status: 'pending', |
| createdAt: '2023-06-01' |
| }, |
| { |
| id: '2', |
| title: 'Design mobile app dashboard', |
| description: 'Create wireframes and high-fidelity mockups for the main dashboard', |
| priority: 'medium', |
| project: 'Mobile App', |
| dueDate: '2023-07-20', |
| assignee: 'Sarah M.', |
| status: 'in-progress', |
| createdAt: '2023-06-05' |
| }, |
| { |
| id: '3', |
| title: 'Update documentation', |
| description: 'Update API documentation with the latest endpoints', |
| priority: 'low', |
| project: 'Website Redesign', |
| dueDate: '2023-07-10', |
| assignee: 'Mike T.', |
| status: 'completed', |
| createdAt: '2023-05-28' |
| } |
| ]; |
| saveTasks(); |
| } |
| |
| renderTasks(); |
| updateStats(); |
| } |
| |
| |
| init(); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ffkj09/todo-list" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |