Component

Module

To-Do Lits

Ensure that you have implemented module 'Option' & 'Module Setting' in your backend.

Directory

File Folder Link
M - model files \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\app\models
V - views files \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\app\views\option
C - TodoController.php \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\app\controllers
ckeditor -> index.php \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\plugins
backend.php \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\app\layouts
style.css \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\admin\themes\black_and_white
backend.js & todo.js \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\admin\javascript
Image & Icon \\SYNAS\Allan\DOCUMENTATION\Module\To-Do List\rckuc\wolf\admin\images

SQL Tables

\\SYNAS\Allan\DOCUMENTATION\Module\To-Do List

 

Step 1

Update: backend.php

  • Insert scripts file in <head> section
  • Add new tab for "To-Do List"

 

And add -> Get data from 'Module Setting'

<head> <script type="text/javascript" src="<?php echo URI_PUBLIC; ?>wolf/admin/javascripts/todo.js"></script> </head> <!-- Add 'To-Do List' Tab --> <body id="body_<?php echo $ctrl.'_'.Dispatcher::getAction(); ?>"> <ul> <li id="page-plugin" class="plugin"><a href="<?php echo get_url('todo'); ?>"<?php if ($ctrl=='todo') echo ' class="current"'; ?>><?php echo __('To-Do List'); ?></a></li> </ul> ... ... ... ... <!-- Get data from Module Setting --> <input type="hidden" id="start_lunch_hour" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Lunch Start Time'), ENT_COMPAT, 'UTF-8'); ?>"> <input type="hidden" id="end_working_hour" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Working End Time'), ENT_COMPAT, 'UTF-8'); ?>"> <input type="hidden" id="early_reminder" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Enable Early Reminder'), ENT_COMPAT, 'UTF-8'); ?>"> <input type="hidden" id="early_reminder_minute" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Early Reminder Minute'), ENT_COMPAT, 'UTF-8'); ?>"> </body>
<head>
    <script type="text/javascript" src="<?php echo URI_PUBLIC; ?>wolf/admin/javascripts/todo.js"></script>
</head>

<!-- Add 'To-Do List' Tab -->
<body id="body_<?php echo $ctrl.'_'.Dispatcher::getAction(); ?>">
    <ul>
        <li id="page-plugin" class="plugin"><a href="<?php echo get_url('todo'); ?>"<?php if ($ctrl=='todo') echo ' class="current"'; ?>><?php echo __('To-Do List'); ?></a></li>
    </ul>

...
...
...
...

    <!-- Get data from Module Setting -->
    <input type="hidden" id="start_lunch_hour" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Lunch Start Time'), ENT_COMPAT, 'UTF-8'); ?>">
    <input type="hidden" id="end_working_hour" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Working End Time'), ENT_COMPAT, 'UTF-8'); ?>">
    <input type="hidden" id="early_reminder" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Enable Early Reminder'), ENT_COMPAT, 'UTF-8'); ?>">
    <input type="hidden" id="early_reminder_minute" value="<?php echo htmlentities(ModuleSetting::findSetting('todo', 'Early Reminder Minute'), ENT_COMPAT, 'UTF-8'); ?>">
</body>

Step 2

Insert SQL Record into wolf_module_setting:
Add 4 status for:

  • Lunch Start Time
  • Working End Time
  • Enable Early Reminder
  • Early Reminder Minute

    Or add manually in Module Setting Tab
INSERT INTO `wolf_module_setting` (`id`, `module`, `name`, `value_type`, `value`, `created_on`, `updated_on`, `created_by_id`, `updated_by_id`) VALUES (NULL, 'todo', 'Lunch Start Time', 'time', '13:00', NOW(), NULL, NULL, NULL); (NULL, 'todo', 'Working End Time', 'time', '18:00', NOW(), NULL, NULL, NULL); (NULL, 'todo', 'Enable Early Reminder', 'checkbox', '1', NOW(), NULL, NULL, NULL); (NULL, 'todo', 'Early Reminder Minute', 'number', '5', NOW(), NULL, NULL, NULL);
INSERT INTO `wolf_module_setting` (`id`, `module`, `name`, `value_type`, `value`, `created_on`, `updated_on`, `created_by_id`, `updated_by_id`) 
VALUES 
(NULL, 'todo', 'Lunch Start Time', 'time', '13:00', NOW(), NULL, NULL, NULL);
(NULL, 'todo', 'Working End Time', 'time', '18:00', NOW(), NULL, NULL, NULL);
(NULL, 'todo', 'Enable Early Reminder', 'checkbox', '1', NOW(), NULL, NULL, NULL);
(NULL, 'todo', 'Early Reminder Minute', 'number', '5', NOW(), NULL, NULL, NULL);

Step 3

Update: style.css

/* ADJUST HEADER TABS */ body#body_todo_index, body#body_todo_add, body#body_todo_edit, body#body_todo_project, body#body_todo_taskview, body#body_todo_report, body#body_todo_activity_log { min-width: 1265px; } #header #mainTabs{ height: auto; } #header #mainTabs a:link, #header #mainTabs a:visited { float: unset; } #header #mainTabs li { display: flex; white-space: nowrap; } #header #mainTabs li.right:not(.right ~ .right) { margin-left: auto; } #header #mainTabs ul { display: flex; flex-wrap: wrap; } /* TODO LIST */ :root { /* Section Color*/ --section-today: #FFF4CC; --section-today-in-progress: #ffe699; --section-overdue: #FFD6D6; --section-overdue-in-progress: #ffb3b3; --section-upcoming: #E0E7FF; --section-deferred: #F3E8FF; --section-completed: #DFF5E1; --section-cancelled: #E5E5E5; --section-archived: #d3d3d3; /* Priority Color*/ --task-urgent: #d0021b; --task-high: #f5a623; --task-normal: #4a90e2; --task-low: #7ed321; --task-undefied: gray; } #main { overflow: visible; } #body_todo_index #content-wrapper, #body_todo_project #content-wrapper, #body_todo_taskview #content-wrapper, #body_todo_report #content-wrapper, #body_todo_activity_log #content-wrapper, #body_todo_generate_report #content-wrapper { width: 98%; } h1 .add-new-button { position: absolute; top: 50%; right: 1rem; transform: translateY(-50%); } h1 a.add-new { text-decoration: none; background-color: #4a90e2; color: #fff; border-radius: 8px; padding: 0.5rem 1rem; font-size: 1rem; cursor: pointer; transition: all 0.2s; text-shadow: none; } h1 a.add-new:hover { background-color: #5babfc; } /* ---------- Start FORM ---------- */ .todo-name { width: 50% !important; } #body_todo_edit input[type="datetime-local"]:read-only { cursor: no-drop; } div.quick_button { position: absolute; top: 4.5rem; right: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.5rem; } div.quick_button img { height: 4rem; width: 4rem; cursor: pointer; } div.quick_button img:hover { opacity: 0.7; } #cke_todo_description { width: 100% !important; } .flex-row { display: flex; justify-content: space-between; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); border-radius: 0.5rem; padding: 0.5rem 1rem; margin-bottom: 0.5rem; } .flex-row p { margin: 0; } .flex-row > div > div { display: flex; align-items: center; gap: 1rem; } .flex-row > div { width: 250px; height: 65px; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 0.5rem; } .flex-row > div h3 { margin: 0; } div.estimate_hour > div { display: flex; align-items: center; gap: 0.8rem; } div.estimate_hour > div > div { display: flex; align-items: center; gap: 0.3rem; } div.estimate_hour > div input.textbox { width: 35px; } #dd_reason { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 1rem 2rem 1rem 3rem; border-radius: 1rem; background-color: white; z-index: 10; display: none; flex-direction: column; align-items: center; max-height: 80vh; overflow-y: auto; } #dd_reason p { margin: 0; } #close_dd_reason { height: 1.5rem; width: 1.5rem; position: absolute; top: 1rem; right: 1rem; cursor: pointer; } #close_dd_reason:hover { opacity: 0.7; } #dd_reason.active { display: flex; } #dd_reason li { padding-top: 0.3rem; margin-top: 0.3rem; border-top: 0.5px solid black; } #dd_reason li:first-child { border: none; } #dd_reason li > div { display: flex; align-items: center; gap: 1rem; } li#new_dd_change > div { margin-top: 0.3rem; } #dd_reason li div:nth-child(2) { align-items: flex-start; } #dd_reason li div label { width: 5rem !important; flex-shrink: 0; } #dd_reason li div textarea { flex: 1; padding: 0.5rem; } .dd_action { justify-content: flex-end; } div.dd_action > .save_loader { display: none; margin: 0; } button.action-btn { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 5px 14px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; } button.action-btn.save { background-color: green; } button.action-btn.cancel { background-color: gray; } button.action-btn:hover { opacity: 0.7; } #save_dd.inactive { cursor: no-drop; opacity: 0.5; } #new_dd_change { display: none; } .flex-row h3 { display: flex; gap: 1rem; } #dd_icon { display: none; height: 1rem; width: 1rem; cursor: pointer; } #dd_icon:hover { opacity: 0.7; } #dd_icon.active { display: block; } .dd_wrapper { display: flex; align-items: center; justify-content: center; gap: 0.5rem; } .dd_wrapper div.old { background-color: var(--section-overdue); } .dd_wrapper div.new { background-color: var(--section-completed); } /* --------------- START TODO TAG --------------- */ .tag_wrapper { box-sizing: border-box; width: max-content; min-width: 15rem; max-width: 100%; box-sizing: border-box; position: relative; } .tag_wrapper p { margin: 0; } .tag_wrapper * { box-sizing: border-box; } .tag_wrapper > * { width: 100%; } .tag_wrapper .tag-container { border: 1px solid #ccc; display: flex; padding: 0.3rem 0.5rem; } .tag_wrapper .tag-item-container { display: flex; align-items: center; justify-content: flex-start; flex-wrap: wrap; gap: 0.5rem; } .tag_wrapper .tag-item-container .tag-item { display: flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.25rem 0.5rem; border-radius: 0.5rem; background-color: #007bff; color: white; } .tag-item span.remove-tag { padding: 0.1rem; cursor: pointer; } .tag-item span.remove-tag:hover { color: black; } .tag_wrapper #tag_input { border: none; outline: none; } .tag_wrapper .tag_dropdown { display: none; position: absolute; background-color: white; border: 1px solid black; z-index: 10; } .tag_wrapper li { width: 100%; padding: 5px 10px; display: flex; align-items: center; justify-content: space-between; gap: 1rem; cursor: pointer; } .tag_wrapper li.hidden { display: none; } .tag_wrapper li:hover { background-color: lightgray; } button.action-btn.add { background-color: green; } button.action-btn.delete { background-color: red; } /* --------------- END TODO TAG --------------- */ /* Todo Comment */ #cke_comment-textarea { width: 100% !important; } .comment-item { display: flex; margin-bottom: 1rem; } .comment-item .edit-mode { display: none; } .comment-body { flex: 1; } .comment-header { display: flex; align-items: center; gap: 10px; font-size: 14px; } .comment-user { font-weight: 600; color: #111; } .comment-date { color: #777; } .comment-edited { color: #999; cursor: help; display: flex; align-items: center; gap: 0.3rem; } .comment-edited img { height: 1rem; width: 1rem; } .comment-content { margin: 6px 0; font-size: 14px; line-height: 1.5; color: #333; transition: all 0.3s; padding: 0.5rem; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); border-radius: 8px; } .comment-content p { margin: 0; } .comment-item.archive { display: none; } .comment-item.archive .comment-content, .comment-item.archive .comment-user, .comment-item.archive .comment-date { opacity: 0.3; } .comment-actions { font-size: 12px; display: flex; align-items: center; } .comment-actions a { text-decoration: none; background: none; border: none; cursor: pointer; padding: 3px 6px; border-radius: 4px; transition: background 0.2s, color 0.2s; } .comment-actions a:hover { background: rgba(79, 70, 229, 0.1); /* subtle hover background */ color: #3730a3; /* slightly darker on hover */ } .comment-actions .save_loader { display: none; margin: 0; } button#show_archived { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 10px 18px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; } button#show_archived:hover { background-color: #357ABD; } /* NEW COMMET */ .new-comment { display: flex; flex-direction: column; gap: 0.5rem; } #cke_comment-textarea, .new-comment > span, .edit-mode > span { width: 100% !important; } .comment-item div.edit-mode { flex-direction: column; margin-top: 0.5rem; gap: 0.5rem; } .comment-item div.edit-mode > div { display: flex; align-items: center; gap: 0.5rem; } .comment-item .edit-mode .save_loader { display: none; margin: 0; } .comment-item .edit-mode button, .new-comment > div > div > button { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 10px 18px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; } .comment-item .edit-mode button.update-btn { background-color: rgb(0, 163, 0); } .comment-item .edit-mode button.cancel-update-btn { background-color: rgb(155, 155, 155); } .comment-item .edit-mode button.update-btn:hover { background-color: green; } .comment-item .edit-mode button.cancel-update-btn:hover { background-color: gray; } .new-comment > div > div > .save_loader { display: none; } .new-comment > div > div > button:hover { background-color: #357ABD; } #new-reply-template { display: none; } a.log-btn.hidden { display: none; } .swal2-html-container span.info { font-size: smaller; color: #999; } /* TODO ATTACHMENT */ .att-item .textbox:read-only { background-color: #f4f4f4; } .att-item .textbox:read-only:focus { outline: none; } .att-item { display: flex; align-items: center; gap: 1rem; /* space between fields */ margin-bottom: 0.5rem; } /* Action button container */ .att-item .action-btn { display: flex; align-items: center; gap: 0.4rem; } /* Common button styling */ .att-item .action-btn a { display: inline-block; text-decoration: none; padding: 0.3rem 0.6rem; border-radius: 4px; font-size: 0.85rem; font-weight: 500; cursor: pointer; min-width: 4rem; text-align: center; } .att-item .action-btn .save_loader { display: none; margin: 0; } #add-att { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 0.3rem 0.6rem; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; } #add-att:hover { background-color: #357ABD; } /* Specific button colors */ .att-item .save-att, .att-item .update-att { background-color: #4CAF50; color: #fff; } .att-item .edit-att, .att-item .copy-att, .att-item .view-att { background-color: #2196F3; color: #fff; } .att-item .copy-att { display: none; } .att-item .cancel-edit-att { background-color: #f0ad4e; color: #fff; } .att-item .delete-att { background-color: #f44336; color: #fff; } /* Hover effects */ .att-item .action-btn a:hover { opacity: 0.85; } /* .new-att .action-btn a.update-att, */ .new-att .action-btn a.edit-att, .new-att .action-btn a.delete-att, /* .new-att, */ .att-item .action-btn a.update-att, .att-item .action-btn a.cancel-edit-att, .att-item .action-btn a.copy-att, .att-item .action-btn a.view-att { display: none; } /* ---------- End FORM ----------*/ /* ---------- Start Dashboard ----------*/ #body_todo_index .report-content { padding-top: 1rem; display: none; } #all-task td:nth-child(6) { white-space: nowrap; } #toggleReport { background-color: #4a90e2; color: #fff; border: none; padding: 0.5rem 1.2rem; border-radius: 0.45rem; font-size: 0.9rem; font-weight: 500; cursor: pointer; box-shadow: 0 2px 6px rgba(0,0,0,0.15); transition: all 0.2s ease; } #toggleReport:hover { background-color: #357ABD;; transform: translateY(-1px); } #toggleReport:active { transform: translateY(0); box-shadow: 0 1px 3px rgba(0,0,0,0.2); } /* .in-progress-task { display: flex; align-items: center; justify-content: space-between; background-color: var(--section-today-in-progress); border-radius: 8px; padding: 1rem; box-shadow: 0 4px 15px rgba(0,0,0,0.05); margin-bottom: 1rem; } .in-progress-task > div { display: flex; align-items: center; gap: 0.5rem; } .in-progress-task > div > p { margin: 0; } .in-progress-task.overdue { background-color: var(--section-overdue-in-progress); } .in-progress-task img { height: 3rem; } .in-progress-task img:hover { opacity: 0.7; } */ /* Banner Container */ .in-progress-task { width: 100%; background-color: var(--section-today-in-progress); padding: 0.3rem 1rem; border-radius: 12px; display: none; justify-content: space-between; align-items: center; gap: 1rem; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05); box-sizing: border-box; margin-bottom: 1rem; } .in-progress-task.active { display: flex; } /* Overdue State */ .in-progress-task.overdue { background-color: var(--section-overdue-in-progress); } .task-content { display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem; } .task-content h3 { margin: 0; } .task-content p { margin: 0; } .task-actions { display: flex; align-items: center; justify-content: center; gap: 1rem; } .task-actions a:hover { cursor: pointer; text-decoration: underline; } /* Header & Typography */ .task-header { display: flex; align-items: center; max-width: 85%; gap: 1rem; } p.taskStatus { white-space: nowrap; } a.view_project { font-weight: 600; } /* Tags Row */ .task-tags { display: flex; align-items: center; gap: 0.5rem; } .taskCategory, .taskPriority { font-size: 0.7rem; padding: 2px 8px; border-radius: 4px; background: #f7fafc; color: #4a5568; border: 1px solid #edf2f7; } /* Priority Colors */ .priority-Urgent { color: var(--task-urgent); } .priority-High { color: var(--task-high); } .priority-Normal { color: var(--task-normal); } .priority-Low { color: var(--task-low); } /* Horizontal Grid Layout */ .task-status { display: flex; gap: 0.5rem; } .status-item { position: relative; display: flex; align-items: center; gap: 0.5rem; border-radius: 0.5rem; padding: 0.3rem 0.8rem; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2); background-color: white !important; } .status-item label, .status-item:nth-child(-n+4) p { white-space: nowrap; } .in-progress-task.overdue .status-item { background-color: #ffc2c2; } .status-item p { font-weight: 600; } .in-progress-task.overdue .taskTimeLeft, .in-progress-task.overdue .taskTimeSpent { color: red; } .status-item:first-child { background-color: #DFF5E1 !important; border-right: 0.5rem solid green; /* align-items: flex-start; */ } .status-item:nth-child(2) { background-color: #FFD6D6 !important; border-right: 0.5rem solid red; /* align-items: flex-start; */ } /* Action Button */ .inProgressCompleteLink img, .inProgressPauseLink img { width: 2.5rem; height: 2.5rem; transition: transform 0.2s ease; } .inProgressCompleteLink img { opacity: 0.3; } .inProgressCompleteLink:hover img { transform: scale(1.1); opacity: 1; } .inProgressPauseLink:hover img { transform: scale(1.1); } .task-container { /* background-color: white; */ /* border-radius: 8px; */ padding: 1rem 0; /* margin-bottom: 30px; */ /* box-shadow: 0 4px 15px rgba(0,0,0,0.05); */ } .toolsbar { display: flex; gap: 0.5rem; align-items: center; justify-content: flex-end; } .toolsbar img { height: 1rem; width: 1rem; cursor: pointer; } .toolsbar img:hover { opacity: 0.7; } .task-container th, .task-container .filter_dataTable { background-color: unset !important; } .task-container table.index td { padding: 0 10px !important; border-bottom: 1px solid #ddd; border-top: none; } .dtrg-group { height: 35px; } /* start quick task */ tr.New.dtrg-group { display: none; } tr.quickTaskTr { height: 40px; } tr.quickTaskTr td { border-bottom: none !important; } tr.quickTaskTr td div.action-list { padding: 5px 10px !important; } .task-container .textbox { box-sizing: border-box; width: 100%; } .task-container .textbox:focus { outline: none; } .task-container input.textbox[type="text"] { padding-top: 6px; } .task-container input.textbox[type="datetime-local"] { font-family: inherit; font-size: 90%; padding: 0; opacity: 0; width: 0; height: 0; border: none; position: absolute; /* off the visible area */ top: 35px; left: 0; pointer-events: none; /* optional */ } /* Custom visible box styling */ .custom-dt-box { display: inline-flex; align-items: center; justify-content: space-between; width: 130px; padding: 5px 8px; border: 1px solid #ccc; background-color: white; font-family: inherit; font-size: 90%; text-align: center; user-select: none; text-align: left; } .task-container select.textbox { padding-left: 5px; } .task-container td:nth-child(3) .textbox, .task-container td:nth-child(4) .textbox, .task-container td:nth-child(5) .textbox, .task-container td:nth-child(6) .textbox { border-right: none; } .quickTaskTr td:nth-child(n+3):nth-child(-n+7) { padding: 0 !important; } /* end quick task */ .task-container tr.Today { background-color: var(--section-today);} .task-container tr.Today.in-progress { background-color: var(--section-today-in-progress);} .task-container tr.Overdue { background-color: var(--section-overdue);} .task-container tr.Overdue.in-progress { background-color: var(--section-overdue-in-progress);} .task-container tr.Upcoming { background-color: var(--section-upcoming);} .task-container tr.Deferred { background-color: var(--section-deferred);} .task-container tr.Completed { background-color: var(--section-completed);} .task-container tr.Cancelled { background-color: var(--section-cancelled);} .task-container tr.Archived { background-color: var(--section-archived);} .task-container tr.Today.in-progress td.status, .task-container tr.Overdue.in-progress td.status { position: relative; } .task-container tr.Today.in-progress td.status::after, .task-container tr.Overdue.in-progress td.status::after { content: ""; display: inline-block; width: 1.5em; text-align: left; animation: dots 1.5s steps(4, end) infinite; } @keyframes dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } 100% { content: ""; } } .task-container td.Urgent { color: var(--task-urgent);} /* .task-container td.High { color: var(--task-high);} .task-container td.Normal { color: var(--task-normal);} .task-container td.Low { color: var(--task-low);} */ .action-list img { height: 20px; width: 20px; } .action-list { height: 100%; display: flex; align-items: center; justify-content: center; gap: 0.5rem; position: relative; } .action-list > a.start_sweetalert, .action-list > a.pause_sweetalert, .action-list > div.deferred, .action-list > div.cancelled, .action-list > a.complete_sweetalert, .action-list > a.incomplete_sweetalert { display: none; } .action-list a.disable { opacity: 0.2; } .action-list a:hover { opacity: 0.7; } /* Popup menu */ .more-btn { cursor: pointer; display: inline-block; } .more-btn:hover { opacity: 0.7; } #more-opt-popup-template, #action-list-template { display: none; } .more-opt-popup { position: absolute; background: #fff; border: 1px solid #ddd !important; box-shadow: 0 4px 10px rgba(0,0,0,0.1); z-index: 1000; padding: 0 !important; width: max-content; } .more-opt-popup img { height: 20px; width: 20px; } .more-opt-popup a, .more-opt-popup div { display: flex; align-items: center; gap: 0.7rem; padding: 0.7rem 1rem; color: #333; text-decoration: none; font-size: 14px; cursor: pointer; } .more-opt-popup a:hover, .more-opt-popup div:hover { background: #f5f5f5; } .action-list .save-new-task { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 5px 14px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; } .action-list .save-new-task:hover { background-color: #357ABD; } .action-list .save_loader { display: none; margin: 0; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .save_loader { border: 0.1rem solid white; animation: spin .5s linear infinite; border-top: 0.1rem solid black; border-left: 0.1rem solid black; border-radius: 50%; width: 1rem; height: 1rem; margin: 0.5rem 0; } /* Todo Commet Popup*/ #comment-popup { display: none; position: fixed; top: 0; left: 0; height: 100%; width: 100%; background-color: rgba(0, 0, 0, 0.3); align-items: center; justify-content: center; } #comment-popup > form { background-color: white; min-width: 450px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 2rem; } #comment-popup > form > div { width: 100%; } #comment-popup > form textarea{ padding: 1rem; width: 100%; box-sizing: border-box; } #comment-popup .btn-group { justify-content: center; } #comment-popup .btn-group .save_loader { display: none; } /* Add Comment button */ #comment-popup button { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 10px 18px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; margin-top: 10px; } #comment-popup button.cancel { background-color: red; } #comment-popup button:hover { background-color: #357ABD; } #comment-popup button.cancel:hover { background-color: #d0021b; } /* ---------- End Dashboard ----------*/ /* ---------- Start Task View ----------*/ #body_todo_taskview td.date { white-space: nowrap; } .tab-wrapper { width: 100%; font-family: Arial, sans-serif; } .tab-wrapper .tabs { display: flex; border-bottom: 2px solid #ddd; margin: 0; padding: 0; list-style: none; } .tab-wrapper .tabs > button { color: #555; font-family: inherit; font-size: inherit; border: none; background-color: white; cursor: pointer; border-bottom: 3px solid transparent; padding: 10px 16px; } .tab-wrapper .tabs > button.active { border-bottom-color: #007bff; color: #007bff; font-weight: bold; } .tab-wrapper .tabs > div { display: none; align-items: center; gap: 0.5rem; padding-right: 1rem; border-bottom: 3px solid #007bff; } .tab-wrapper .tabs li { padding: 10px 16px; cursor: pointer; border-bottom: 3px solid transparent; color: #555; } .tab-wrapper .tabs > button:hover, .tab-wrapper .tabs > button:hover + div { background: #f5f5f5; } .tab-wrapper .tabs li:hover { background: #f5f5f5; } .tab-wrapper .tabs li.active { border-bottom-color: #007bff; color: #007bff; font-weight: bold; } .tab-wrapper .tabs li[data-target="#overdueView"].active { border-bottom-color: red; color: red; font-weight: bold; } #calendarView.tab-pane, #searchView.tab-pane { padding-top: 1rem; } .tab-pane { display: none; } .tab-pane.active { display: block; } .task-container.today { background-color: var(--section-today);} .task-container.overdue { background-color: var(--section-overdue);} .task-container.upcoming { background-color: var(--section-upcoming);} .task-container.completed { background-color: var(--section-completed);} .task-container.cancelled { background-color: var(--section-cancelled);} .task-container.deferred { background-color: var(--section-deferred);} .task-container.archived { background-color: var(--section-archived);} /* FullCalendar event coloring */ a.fc-event { cursor: pointer; } .fc-event.priority-Urgent { background-color: var(--task-urgent); border-color: var(--task-urgent); } .fc-event.priority-High { background-color: var(--task-high); border-color: var(--task-high); } .fc-event.priority-Normal { background-color: var(--task-normal); border-color: var(--task-normal); } .fc-event.priority-Low { background-color: var(--task-low); border-color: var(--task-low); } .fc-event.priority-Undefied { background-color: var(--task-undefied); border-color: var(--task-undefied); } /* .fc-event.status-Pending {} .fc-event.status-In_Progress {} .fc-event.status-Completed {} .fc-event.status-Deferred {} .fc-event.status-Cancelled {} .fc-event.status-Paused {} */ .calendar-legend { display: flex; gap: 12px; margin-bottom: 10px; font-size: 13px; } .legend-item { display: flex; align-items: center; gap: 6px; } .legend-item::before { content: ''; width: 15px; height: 15px; display: inline-block; } /* Priority colors */ .legend-item.urgent::before { background: var(--task-urgent);} .legend-item.high::before { background: var(--task-high);} .legend-item.normal::before { background: var(--task-normal);} .legend-item.low::before { background: var(--task-low);} .legend-item.undefied::before { background: var(--task-undefied);} .task-popup { max-width: 450px; text-align: left; font-size: 14px; } .task-popup p { margin: 6px 0; } .task-popup strong { color: #333; } /* Start Search View */ #search_form { position: relative; width: max-content; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 8px; padding: 10px; background: #f9f9f9; border-radius: 8px; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); } #search_form > div { display: flex; align-items: center; gap: 0.5rem; } #search_form button { border: none; background-color: unset; cursor: pointer; } #search_form button:hover { opacity: 0.7; } #search_form button img { height: 1.3rem; width: 1.3rem; } #searchTaskBtn #save_loader { display: none; margin: 0; } #searchView h4 { margin-bottom: 15px; font-size: 18px; font-weight: 600; } /* Remove default list styling */ #searchView ol { padding-left: 20px; margin: 0; } #searchView li { margin-bottom: 12px; padding: 12px; border-radius: 8px; transition: all 0.2s ease; background: #f9f9f9; transition: all 0.3s ease; } #searchView li:hover { transform: translateY(-3px); background-color: #eeeeee; } /* Link styling */ #searchView li a { text-decoration: none; color: inherit; display: block; } /* Task title */ #searchView h3 { margin: 0 0 6px 0; font-size: 16px; } /* Bottom meta row */ #searchView li div { display: flex; gap: 8px; font-size: 13px; color: #666; } /* Priority Left Border Indicator */ #searchView li.Urgent { border-left: 5px solid var(--task-urgent);} #searchView li.High { border-left: 5px solid var(--task-high);} #searchView li.Normal { border-left: 5px solid var(--task-normal);} #searchView li.Low { border-left: 5px solid var(--task-low);} #searchView li.undefined { border-left: 5px solid var(--task-undefied);} .highlight { background-color: #fff3a0; color: #000; padding: 0 2px; border-radius: 2px; } /* End Search View */ /* ACTIVITY LOG */ #all_changes_table, .details_table { width: 100%; table-layout: auto; white-space: nowrap; } .changes_alert { max-height: 80vh; max-width: 90vw; overflow-y: auto; } #all_changes_table th, #all_changes_table td, .details_table th, .details_table td { border: 1px solid black; padding: 0.3rem; min-width: 8rem; } #all_changes_table td div.changes_td { display: flex; flex-direction: column; gap: 1rem; } #all_changes_table .log_detail { display: flex; flex-direction: column; align-items: flex-start; margin: 0; max-width: 38rem; min-width: 15rem; overflow-x: auto; } td.changes { display: flex; align-items: center; justify-content: center; padding: 0 !important; } th div.action_list { display: inline-flex; align-items: center; gap: 1rem; margin-left: 1rem; } td.changes .save_loader, th div.action_list .save_loader { margin: 0; display: none; } button.view_all_changes, td.changes button { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 5px 12px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; margin-top: 0.1rem; } button.view_all_changes:hover, td.changes button:hover { background-color: #357ABD; } .sweet_alert_log { max-height: 25rem; overflow-y: auto; text-align: left; } .log_detail { margin-bottom: 1rem; } .log_detail div { width: max-content; } .view_log_detail { cursor: pointer; font-size: 14px; margin-left: 0.5rem; } .view_log_detail:hover { text-decoration: underline; } div.desc_changes { max-height: 10rem; max-width: 100%; overflow-y: auto; } .swal2-html-container div.old *, .swal2-html-container div.new * { all: unset; } .swal2-html-container div.old { background-color: var(--section-overdue); } .swal2-html-container div.new { background-color: var(--section-completed); } .swal2-html-container div.tag { display: flex; } /* REPORT */ #body_todo_report .report-content { margin-top: 1.5rem; } .report_loader { display: none; border: 0.3rem solid white; animation: spin_report .5s linear infinite; border-top: 0.3rem solid black; border-left: 0.3rem solid black; border-radius: 50%; width: 2rem; height: 2rem; z-index: 10; position: absolute; top: 50%; left: 50%; } @keyframes spin_report { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } #reportContent.loading { opacity: 0.3; pointer-events: none; } .report-content div.dt-buttons { float: unset; } .report-content .kpi-container { display: flex; gap: 1.5rem; margin-bottom: 1.5rem; } .report-content .kpi { width: 11.875%; background:#fff; padding: 1rem; border-radius: 0.5rem; box-shadow:0 2px 10px rgba(0,0,0,0.2); } .report-content .kpi:last-child { cursor: pointer; width: 5%; display: flex; gap: 0.5rem; flex-direction: column; align-items: center; justify-content: center; transition: all 0.3s ease; } .report-content .kpi:last-child img { width: 1.5rem; transition: all 0.3s ease; } .report-content .kpi:last-child:hover { background-color: #e6e6e6; } .report-content .kpi:last-child:hover > img { opacity: 0.7; } .report-content .kpi:last-child > img.active { transform: rotate(180deg); } .report-content .kpi h3 { margin:0; font-size:14px; color:#666; } .report-content .kpi p { margin:5px 0 0; font-size:22px; font-weight:bold; } .report-content .kpi-table { display: none; margin-bottom: 1.5rem; background:#fff; padding: 1rem; border-radius: 0.5rem; box-shadow:0 2px 10px rgba(0,0,0,0.2); } .report-content .kpi-table td { padding: 0 10px !important; border-bottom: 1px solid #ddd; border-top: none; } .report-content .insight { margin-bottom: 1.5rem; background:#fff; padding:15px; border-radius:8px; box-shadow:0 2px 10px rgba(0,0,0,0.2); } .report-content .insight h4 { margin-top: 0; } .report-content .chart-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem; } .report-content td { padding: 0 10px !important; white-space: nowrap; } .report-content .chart-grid > :nth-child(4) { grid-column: span 2; aspect-ratio: unset; } #overlay { display: none; position: fixed; inset: 0; background-color: rgba(0, 0, 0, 0.5); z-index: 9; } .report-content table th:first-child, .report-content table td:first-child { display: none; } .report-content .card { background:#fff; padding: 1rem; border-radius: 0.5rem; box-shadow:0 2px 10px rgba(0,0,0,0.2); box-sizing: border-box; aspect-ratio: 1 / 1; position: relative; display: flex; align-items: center; justify-content: center; } .report-content .chart-square, .report-content .chart-square canvas, .report-content .chart-rectangle, .report-content .chart-rectangle canvas { height: 100%; width: 100%; } .report-content .chart-rectangle { aspect-ratio: 2 / 1; } .kpi-table .chart-rectangle { display: none; height: 550px; } .show_detail_btn, .close_detail_btn { padding: 0.5rem; position: absolute; top: 0; right: 0; cursor: pointer; transition: all 0.3s ease; } .show_detail_btn { height: 2rem; } .close_detail_btn { height: 1.8rem; padding: 1rem; } .show_detail_btn:hover, .close_detail_btn:hover { transform: scale(1.05); } .report-content .popup_detail { box-sizing: border-box; display: none; background-color: white; padding: 1rem; border-radius: 0.5rem; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 10; overflow-y: auto; overflow-x: hidden; max-width: 90%; max-height: 90%; animation: grow 0.3s; flex-direction: column; align-items: center; justify-content: flex-start; } .report-content .popup_detail.active { display: flex; } @keyframes grow { 0% { transform: translate(-50%, -50%) scale(0); } 100% { transform: translate(-50%, -50%) scale(1); } } .report-content .popup_detail.scaleDown { animation: scaleDown 0.4s; } @keyframes scaleDown { 0% { transform: translate(-50%, -50%) scale(1); } 100% { transform: translate(-50%, -50%) scale(0); } } .report-content .detail_table { width: 100%; } .report-content .show_chart { border: none; padding: 0.5rem 1rem; border-radius: 0.5rem; cursor: pointer; background-color: #4a90e2; color: #fff; margin-bottom: 1rem; transition: all 0.3s ease; } .report-content .show_chart:hover { background-color: #357ABD; transform: translateY(-1px); } .popup_detail .clone_canvas { display: none; flex-shrink: 0; } /* =========== LIST OF REPORT =========== */ #listContent .report-list { padding: 0 2rem 1rem 2rem; } #listContent .report-list li { padding-top: 0.5rem; cursor: pointer; width: max-content; } #listContent .report-list li:hover { padding-top: 0.5rem; text-decoration: underline; } /* =========== GENERATE REPORT =========== */ .report_header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; } #filter_container { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1.5rem; padding: 1rem; border-radius: 0.5rem; box-shadow: 0 2px 10px rgba(0,0,0,0.2); background-color: rgb(235, 235, 235); margin-bottom: 2rem; } #filter_container h4 { flex: 0 0 100%; margin: 0; } #filter_container div { display: flex; align-items: center; gap: 0.5rem; } #filter_container div.group_by_option { display: none; } #filter_container .end_date_field { display: none; } button.end_date_btn, button.generate_report { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 5px 12px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; } button.end_date_btn { background-color: gray; padding: 3px 10px; display: none; } button.end_date_btn:hover { background-color: lightgray; } button.generate_report:hover { background-color: #357ABD; } button.generate_report.done { pointer-events: none; background-color: green; } #body_todo_generate_report div.dt-buttons { display: none; } #generate_table { display: none; } .export_btn { display: flex; align-items: center; gap: 0.5rem; } .export_btn .btn { background-color: #4a90e2; color: #fff; border-radius: 8px; padding: 0.5rem 1rem; border: none; cursor: pointer; transition: all 0.2s; } .export_btn .btn.excel { background-color: green; } .export_btn .btn.pdf { background-color: red; } .export_btn .btn:hover { opacity: 0.7; } #generate_table.loading { opacity: 0.3; pointer-events: none; } #generate_table .table_title { display: flex; flex-direction: column; align-items: center; justify-content: center; } #generate_table .subtitle { text-align: center; } #generate_table .table_header { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.5rem; padding-bottom: 1rem; } #generate_table .chart_container { display: none; } #generate_table .chart_container.active { display: flex; flex-direction: column; align-items: center; justify-content: center; } #generate_table .generate_canvas { display: none; width: 1100px; height: 550px; align-items: center; justify-content: center; } .toggle_chart_btn { background-color: #4a90e2; color: #fff; border: none; border-radius: 8px; padding: 5px 14px; font-size: 0.95rem; cursor: pointer; transition: all 0.2s; } #body_todo_generate_report th:first-child, #body_todo_generate_report td:first-child { display: none; } #body_todo_generate_report td { padding: 0 10px; }
/* ADJUST HEADER TABS */
body#body_todo_index,
body#body_todo_add,
body#body_todo_edit,
body#body_todo_project,
body#body_todo_taskview,
body#body_todo_report,
body#body_todo_activity_log {
  min-width: 1265px;
}

#header #mainTabs{
  height: auto;
}

#header #mainTabs a:link, #header #mainTabs a:visited {
  float: unset;
}

#header #mainTabs li {
  display: flex;
  white-space: nowrap;
}

#header #mainTabs li.right:not(.right ~ .right) {
  margin-left: auto;
}

#header #mainTabs ul {
  display: flex;
  flex-wrap: wrap;
}


/* TODO LIST */
:root {
  /* Section Color*/
  --section-today: #FFF4CC;
  --section-today-in-progress: #ffe699;
  --section-overdue: #FFD6D6;
  --section-overdue-in-progress: #ffb3b3;
  --section-upcoming: #E0E7FF;
  --section-deferred: #F3E8FF;
  --section-completed: #DFF5E1;
  --section-cancelled: #E5E5E5;
  --section-archived: #d3d3d3;

  /* Priority Color*/
  --task-urgent: #d0021b;
  --task-high: #f5a623;
  --task-normal: #4a90e2;
  --task-low: #7ed321;
  --task-undefied: gray;
}

#main {
  overflow: visible;
}

#body_todo_index #content-wrapper,
#body_todo_project #content-wrapper,
#body_todo_taskview #content-wrapper,
#body_todo_report #content-wrapper,
#body_todo_activity_log #content-wrapper,
#body_todo_generate_report #content-wrapper {
  width: 98%;
}

h1 .add-new-button {
  position: absolute;
  top: 50%;
  right: 1rem;
  transform: translateY(-50%);
}

h1 a.add-new {
  text-decoration: none;
  background-color: #4a90e2;
  color: #fff;
  border-radius: 8px;
  padding: 0.5rem 1rem;
  font-size: 1rem;
  cursor: pointer;
  transition: all 0.2s;
  text-shadow: none;
}

h1 a.add-new:hover {
  background-color: #5babfc;
}

/* ---------- Start FORM ---------- */
.todo-name {
  width: 50% !important;
}

#body_todo_edit input[type="datetime-local"]:read-only {
  cursor: no-drop;
}

div.quick_button {
  position: absolute;
  top: 4.5rem;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

div.quick_button img {
  height: 4rem;
  width: 4rem;
  cursor: pointer;
}

div.quick_button img:hover {
  opacity: 0.7;
}

#cke_todo_description {
  width: 100% !important;
}

.flex-row {
  display: flex;
  justify-content: space-between;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  border-radius: 0.5rem;
  padding: 0.5rem 1rem;
  margin-bottom: 0.5rem;
}

.flex-row p {
  margin: 0;
}

.flex-row > div > div {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.flex-row > div {
  width: 250px;
  height: 65px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.5rem;
}

.flex-row > div h3 {
  margin: 0;
}

div.estimate_hour > div {
  display: flex;
  align-items: center;
  gap: 0.8rem;
}

div.estimate_hour > div > div {
  display: flex;
  align-items: center;
  gap: 0.3rem;
}

div.estimate_hour > div input.textbox {
  width: 35px;
}

#dd_reason {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 1rem 2rem 1rem 3rem;
  border-radius: 1rem;
  background-color: white;
  z-index: 10;
  display: none;
  flex-direction: column;
  align-items: center;
  max-height: 80vh;
  overflow-y: auto;
}

#dd_reason p {
  margin: 0;
}

#close_dd_reason {
  height: 1.5rem;
  width: 1.5rem;
  position: absolute;
  top: 1rem;
  right: 1rem;
  cursor: pointer;
}

#close_dd_reason:hover {
  opacity: 0.7;
}

#dd_reason.active {
  display: flex;
}

#dd_reason li {
  padding-top: 0.3rem;
  margin-top: 0.3rem;
  border-top: 0.5px solid black;
}

#dd_reason li:first-child {
  border: none;
}

#dd_reason li > div {
  display: flex;
  align-items: center;
  gap: 1rem;
}

li#new_dd_change > div {
  margin-top: 0.3rem;
}

#dd_reason li div:nth-child(2) {
  align-items: flex-start;
}

#dd_reason li div label {
  width: 5rem !important;
  flex-shrink: 0;
}

#dd_reason li div textarea {
  flex: 1;
  padding: 0.5rem;
}

.dd_action {
  justify-content: flex-end;
}

div.dd_action > .save_loader {
  display: none;
  margin: 0;
}

button.action-btn {
    background-color: #4a90e2;
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 5px 14px;
    font-size: 0.95rem;
    cursor: pointer;
    transition: all 0.2s;
}

button.action-btn.save {
  background-color: green;
}

button.action-btn.cancel {
  background-color: gray;
}

button.action-btn:hover {
  opacity: 0.7;
}

#save_dd.inactive {
  cursor: no-drop;
  opacity: 0.5;
}

#new_dd_change {
  display: none;
}

.flex-row h3 {
  display: flex;
  gap: 1rem;
}

#dd_icon {
  display: none;
  height: 1rem;
  width: 1rem;
  cursor: pointer;
}

#dd_icon:hover {
  opacity: 0.7;
}

#dd_icon.active {
  display: block;
}

.dd_wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.dd_wrapper div.old {
  background-color: var(--section-overdue);
}

.dd_wrapper div.new {
  background-color: var(--section-completed);
}

/* --------------- START TODO TAG --------------- */
.tag_wrapper {
  box-sizing: border-box;
  width: max-content;
  min-width: 15rem;
  max-width: 100%;
  box-sizing: border-box;
  position: relative;
}

.tag_wrapper p {
  margin: 0;
}

.tag_wrapper * {
  box-sizing: border-box;
}

.tag_wrapper > * {
  width: 100%;
}

.tag_wrapper .tag-container {
  border: 1px solid #ccc;
  display: flex;
  padding: 0.3rem 0.5rem;
}

.tag_wrapper .tag-item-container {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.tag_wrapper .tag-item-container .tag-item {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.25rem 0.5rem;
  border-radius: 0.5rem;
  background-color: #007bff;
  color: white;
}

.tag-item span.remove-tag {
  padding: 0.1rem;
  cursor: pointer;
}

.tag-item span.remove-tag:hover {
  color: black;
}

.tag_wrapper #tag_input {
  border: none;
  outline: none;
}

.tag_wrapper .tag_dropdown {
  display: none;
  position: absolute;
  background-color: white;
  border: 1px solid black;
  z-index: 10;
}

.tag_wrapper li {
  width: 100%;
  padding: 5px 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  cursor: pointer;
}

.tag_wrapper li.hidden {
  display: none;
}

.tag_wrapper li:hover {
  background-color: lightgray;
}

button.action-btn.add {
  background-color: green;
}

button.action-btn.delete {
  background-color: red;
}

/* --------------- END TODO TAG --------------- */

/* Todo Comment */
#cke_comment-textarea {
  width: 100% !important;
}

.comment-item {
    display: flex;
    margin-bottom: 1rem;
}

.comment-item .edit-mode {
  display: none;
}

.comment-body {
    flex: 1;
}

.comment-header {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
}

.comment-user {
    font-weight: 600;
    color: #111;
}

.comment-date {
    color: #777;
}

.comment-edited {
    color: #999;
    cursor: help;
    display: flex;
    align-items: center;
    gap: 0.3rem;
}

.comment-edited img {
  height: 1rem;
  width: 1rem;
}

.comment-content {
    margin: 6px 0;
    font-size: 14px;
    line-height: 1.5;
    color: #333;
    transition: all 0.3s;
    padding: 0.5rem;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
    border-radius: 8px;
}

.comment-content p {
  margin: 0;
}

.comment-item.archive {
  display: none;
}

.comment-item.archive .comment-content,
.comment-item.archive .comment-user,
.comment-item.archive .comment-date {
  opacity: 0.3;
}

.comment-actions {
    font-size: 12px;
    display: flex;
    align-items: center;
}

.comment-actions a {
    text-decoration: none;
    background: none;
    border: none;
    cursor: pointer;
    padding: 3px 6px;
    border-radius: 4px;
    transition: background 0.2s, color 0.2s;
}

.comment-actions a:hover {
    background: rgba(79, 70, 229, 0.1); /* subtle hover background */
    color: #3730a3; /* slightly darker on hover */
}

.comment-actions .save_loader {
  display: none;
  margin: 0;
}

button#show_archived {
  background-color: #4a90e2;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 10px 18px;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.2s;
}

button#show_archived:hover {
  background-color: #357ABD;
}

/* NEW COMMET */
.new-comment {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

#cke_comment-textarea,
.new-comment > span,
.edit-mode > span {
  width: 100% !important;
}

.comment-item div.edit-mode {
  flex-direction: column;
  margin-top: 0.5rem;
  gap: 0.5rem;
}

.comment-item div.edit-mode > div {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.comment-item .edit-mode .save_loader {
  display: none;
  margin: 0;
}

.comment-item .edit-mode button,
.new-comment > div > div > button {
  background-color: #4a90e2;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 10px 18px;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.2s;
}

.comment-item .edit-mode button.update-btn {
  background-color: rgb(0, 163, 0);
}

.comment-item .edit-mode button.cancel-update-btn {
  background-color: rgb(155, 155, 155);
}

.comment-item .edit-mode button.update-btn:hover {
  background-color: green;
}

.comment-item .edit-mode button.cancel-update-btn:hover {
  background-color: gray;
}

.new-comment > div > div > .save_loader {
  display: none;
}

.new-comment > div > div > button:hover {
  background-color: #357ABD;
}

#new-reply-template {
  display: none;
}

a.log-btn.hidden {
  display: none;
}

.swal2-html-container span.info {
  font-size: smaller;
  color: #999;
}

/* TODO ATTACHMENT */
.att-item .textbox:read-only {
  background-color: #f4f4f4;
}

.att-item .textbox:read-only:focus {
  outline: none;
}

.att-item {
    display: flex;
    align-items: center;
    gap: 1rem; /* space between fields */
    margin-bottom: 0.5rem;
}

/* Action button container */
.att-item .action-btn {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

/* Common button styling */
.att-item .action-btn a {
    display: inline-block;
    text-decoration: none;
    padding: 0.3rem 0.6rem;
    border-radius: 4px;
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    min-width: 4rem;
    text-align: center;
}

.att-item .action-btn .save_loader {
  display: none;
  margin: 0;
}

#add-att {
  background-color: #4a90e2;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 0.3rem 0.6rem;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.2s;
}

#add-att:hover {
  background-color: #357ABD;
}

/* Specific button colors */
.att-item .save-att,
.att-item .update-att {
    background-color: #4CAF50;
    color: #fff;
}

.att-item .edit-att,
.att-item .copy-att,
.att-item .view-att {
    background-color: #2196F3;
    color: #fff;
}

.att-item .copy-att {
    display: none;
}

.att-item .cancel-edit-att {
    background-color: #f0ad4e;
    color: #fff;
}
.att-item .delete-att {
    background-color: #f44336;
    color: #fff;
}

/* Hover effects */
.att-item .action-btn a:hover {
    opacity: 0.85;
}

/* .new-att .action-btn a.update-att, */
.new-att .action-btn a.edit-att,
.new-att .action-btn a.delete-att,
/* .new-att, */
.att-item .action-btn a.update-att,
.att-item .action-btn a.cancel-edit-att,
.att-item .action-btn a.copy-att,
.att-item .action-btn a.view-att {
  display: none;
}
/* ---------- End FORM ----------*/

/* ---------- Start Dashboard ----------*/
#body_todo_index .report-content {
  padding-top: 1rem;
  display: none;
}

#all-task td:nth-child(6) {
  white-space: nowrap;
}

#toggleReport {
    background-color: #4a90e2;
    color: #fff;
    border: none;
    padding: 0.5rem 1.2rem;
    border-radius: 0.45rem;
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    box-shadow: 0 2px 6px rgba(0,0,0,0.15);
    transition: all 0.2s ease;
}

#toggleReport:hover {
    background-color: #357ABD;;
    transform: translateY(-1px);
}

#toggleReport:active {
    transform: translateY(0);
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}

/* .in-progress-task {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: var(--section-today-in-progress);
  border-radius: 8px;
  padding: 1rem;
  box-shadow: 0 4px 15px rgba(0,0,0,0.05);
  margin-bottom: 1rem;
}

.in-progress-task > div {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.in-progress-task > div > p {
  margin: 0;
}

.in-progress-task.overdue {
  background-color: var(--section-overdue-in-progress);
}

.in-progress-task img {
  height: 3rem;
}

.in-progress-task img:hover {
  opacity: 0.7;
} */


/* Banner Container */
.in-progress-task {
    width: 100%;
    background-color: var(--section-today-in-progress);
    padding: 0.3rem 1rem;
    border-radius: 12px;
    display: none;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
    box-sizing: border-box;
    margin-bottom: 1rem;
}

.in-progress-task.active {
  display: flex;
}

/* Overdue State */
.in-progress-task.overdue {
    background-color: var(--section-overdue-in-progress);
}

.task-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.3rem;
}

.task-content h3 {
  margin: 0;
}

.task-content p {
    margin: 0;
}

.task-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

.task-actions a:hover {
  cursor: pointer;
  text-decoration: underline;
}

/* Header & Typography */
.task-header {
    display: flex;
    align-items: center;
    max-width: 85%;
    gap: 1rem;
}

p.taskStatus {
  white-space: nowrap;
}

a.view_project {
  font-weight: 600;
}

/* Tags Row */
.task-tags {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.taskCategory, .taskPriority {
    font-size: 0.7rem;
    padding: 2px 8px;
    border-radius: 4px;
    background: #f7fafc;
    color: #4a5568;
    border: 1px solid #edf2f7;
}

/* Priority Colors */
.priority-Urgent { color: var(--task-urgent); }
.priority-High { color: var(--task-high); }
.priority-Normal { color: var(--task-normal); }
.priority-Low { color: var(--task-low); }

/* Horizontal Grid Layout */
.task-status {
    display: flex;
    gap: 0.5rem;
}

.status-item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border-radius: 0.5rem;
    padding: 0.3rem 0.8rem;
    box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
    background-color: white !important;
}

.status-item label,
.status-item:nth-child(-n+4) p {
  white-space: nowrap;
}

.in-progress-task.overdue .status-item {
  background-color: #ffc2c2;
}

.status-item p {
  font-weight: 600;
}

.in-progress-task.overdue .taskTimeLeft,
.in-progress-task.overdue .taskTimeSpent {
  color: red;
}

.status-item:first-child {
    background-color: #DFF5E1 !important;
    border-right: 0.5rem solid green;
    /* align-items: flex-start; */
  }
  
.status-item:nth-child(2) {
    background-color: #FFD6D6 !important;
    border-right: 0.5rem solid red;
    /* align-items: flex-start; */
}

/* Action Button */
.inProgressCompleteLink img,
.inProgressPauseLink img {
    width: 2.5rem;
    height: 2.5rem;
    transition: transform 0.2s ease;
}

.inProgressCompleteLink img {
  opacity: 0.3;
}

.inProgressCompleteLink:hover img {
    transform: scale(1.1);
    opacity: 1;
}

.inProgressPauseLink:hover img {
    transform: scale(1.1);
}

.task-container {
  /* background-color: white; */
  /* border-radius: 8px; */
  padding: 1rem 0;
  /* margin-bottom: 30px; */
  /* box-shadow: 0 4px 15px rgba(0,0,0,0.05); */
}

.toolsbar {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    justify-content: flex-end;
}

.toolsbar img {
  height: 1rem;
  width: 1rem;
  cursor: pointer;
}

.toolsbar img:hover {
  opacity: 0.7;
}

.task-container th,
.task-container .filter_dataTable {
  background-color: unset !important;
}

.task-container table.index td {
  padding: 0 10px !important;
  border-bottom: 1px solid #ddd;
  border-top: none;
}

.dtrg-group {
  height: 35px;
}

/*  start quick task */
tr.New.dtrg-group {
  display: none;
}

tr.quickTaskTr {
  height: 40px;
}

tr.quickTaskTr td {
  border-bottom: none !important;
}

tr.quickTaskTr td div.action-list {
  padding: 5px 10px !important;
}

.task-container .textbox {
  box-sizing: border-box;
  width: 100%;
}

.task-container .textbox:focus {
  outline: none;
}

.task-container input.textbox[type="text"] {
  padding-top: 6px;
}

.task-container input.textbox[type="datetime-local"] {
    font-family: inherit;
    font-size: 90%;
    padding: 0;
    opacity: 0;
    width: 0;
    height: 0;
    border: none;
    position: absolute; /* off the visible area */
    top: 35px;
    left: 0;
    pointer-events: none; /* optional */
}

/* Custom visible box styling */
.custom-dt-box {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    width: 130px;
    padding: 5px 8px;
    border: 1px solid #ccc;
    background-color: white;
    font-family: inherit;
    font-size: 90%;
    text-align: center;
    user-select: none;
    text-align: left;
}

.task-container select.textbox {
  padding-left: 5px;
}

.task-container td:nth-child(3) .textbox,
.task-container td:nth-child(4) .textbox,
.task-container td:nth-child(5) .textbox,
.task-container td:nth-child(6) .textbox {
  border-right: none;
}

.quickTaskTr td:nth-child(n+3):nth-child(-n+7) {
  padding: 0 !important;
}
/* end quick task */

.task-container tr.Today { background-color: var(--section-today);}
.task-container tr.Today.in-progress { background-color: var(--section-today-in-progress);}
.task-container tr.Overdue { background-color: var(--section-overdue);}
.task-container tr.Overdue.in-progress { background-color: var(--section-overdue-in-progress);}
.task-container tr.Upcoming { background-color: var(--section-upcoming);}
.task-container tr.Deferred { background-color: var(--section-deferred);}
.task-container tr.Completed { background-color: var(--section-completed);}
.task-container tr.Cancelled { background-color: var(--section-cancelled);}
.task-container tr.Archived { background-color: var(--section-archived);}

.task-container tr.Today.in-progress td.status,
.task-container tr.Overdue.in-progress td.status {
  position: relative;
}

.task-container tr.Today.in-progress td.status::after,
.task-container tr.Overdue.in-progress td.status::after {
  content: "";
  display: inline-block;
  width: 1.5em;
  text-align: left;
  animation: dots 1.5s steps(4, end) infinite;
}

@keyframes dots {
  0%   { content: ""; }
  25%  { content: "."; }
  50%  { content: ".."; }
  75%  { content: "..."; }
  100% { content: ""; }
}

.task-container td.Urgent { color: var(--task-urgent);}
/* .task-container td.High { color: var(--task-high);}
.task-container td.Normal { color: var(--task-normal);}
.task-container td.Low { color: var(--task-low);} */

.action-list img {
  height: 20px;
  width: 20px;
}

.action-list {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  position: relative;
}

.action-list > a.start_sweetalert,
.action-list > a.pause_sweetalert,
.action-list > div.deferred,
.action-list > div.cancelled,
.action-list > a.complete_sweetalert,
.action-list > a.incomplete_sweetalert {
  display: none;
}

.action-list a.disable {
  opacity: 0.2;
}

.action-list a:hover {
  opacity: 0.7;
}

/* Popup menu */
.more-btn {
  cursor: pointer;
  display: inline-block;
}

.more-btn:hover {
  opacity: 0.7;
}

#more-opt-popup-template,
#action-list-template {
  display: none;
}

.more-opt-popup {
  position: absolute;
  background: #fff;
  border: 1px solid #ddd !important;
  box-shadow: 0 4px 10px rgba(0,0,0,0.1);
  z-index: 1000;
  padding: 0 !important;
  width: max-content;
}

.more-opt-popup img {
  height: 20px;
  width: 20px;
}

.more-opt-popup a,
.more-opt-popup div {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.7rem 1rem;
  color: #333;
  text-decoration: none;
  font-size: 14px;
  cursor: pointer;
}

.more-opt-popup a:hover,
.more-opt-popup div:hover {
  background: #f5f5f5;
}

.action-list .save-new-task {
    background-color: #4a90e2;
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 5px 14px;
    font-size: 0.95rem;
    cursor: pointer;
    transition: all 0.2s;
}

.action-list .save-new-task:hover {
  background-color: #357ABD;
}

.action-list .save_loader {
  display: none;
  margin: 0;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.save_loader {
  border: 0.1rem solid white;
  animation: spin .5s linear infinite;
  border-top: 0.1rem solid black;
  border-left: 0.1rem solid black;
  border-radius: 50%;
  width: 1rem;
  height: 1rem;
  margin: 0.5rem 0;
}

/* Todo Commet Popup*/
#comment-popup {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.3);
  align-items: center;
  justify-content: center;
}

#comment-popup > form {
  background-color: white;
  min-width: 450px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

#comment-popup > form > div {
  width: 100%;
}

#comment-popup > form textarea{
  padding: 1rem;
  width: 100%;
  box-sizing: border-box;
}

#comment-popup .btn-group {
  justify-content: center;
}

#comment-popup .btn-group .save_loader {
  display: none;
}

/* Add Comment button */
#comment-popup button {
  background-color: #4a90e2;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 10px 18px;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.2s;
  margin-top: 10px;
}

#comment-popup button.cancel {
  background-color: red;
}

#comment-popup button:hover {
  background-color: #357ABD;
}

#comment-popup button.cancel:hover {
  background-color: #d0021b;
}
/* ---------- End Dashboard ----------*/

/* ---------- Start Task View ----------*/
#body_todo_taskview td.date {
  white-space: nowrap;
}

.tab-wrapper {
    width: 100%;
    font-family: Arial, sans-serif;
}

.tab-wrapper .tabs {
    display: flex;
    border-bottom: 2px solid #ddd;
    margin: 0;
    padding: 0;
    list-style: none;
}

.tab-wrapper .tabs > button {
  color: #555;
  font-family: inherit;
  font-size: inherit;
  border: none;
  background-color: white;
  cursor: pointer;
  border-bottom: 3px solid transparent;
  padding: 10px 16px;
}

.tab-wrapper .tabs > button.active {
  border-bottom-color: #007bff;
  color: #007bff;
  font-weight: bold;
}

.tab-wrapper .tabs > div {
  display: none;
  align-items: center;
  gap: 0.5rem;
  padding-right: 1rem;
  border-bottom: 3px solid #007bff;
}

.tab-wrapper .tabs li {
    padding: 10px 16px;
    cursor: pointer;
    border-bottom: 3px solid transparent;
    color: #555;
}

.tab-wrapper .tabs > button:hover,
.tab-wrapper .tabs > button:hover + div {
  background: #f5f5f5;
}

.tab-wrapper .tabs li:hover {
    background: #f5f5f5;
}

.tab-wrapper .tabs li.active {
    border-bottom-color: #007bff;
    color: #007bff;
    font-weight: bold;
}

.tab-wrapper .tabs li[data-target="#overdueView"].active {
    border-bottom-color: red;
    color: red;
    font-weight: bold;
}

#calendarView.tab-pane,
#searchView.tab-pane {
    padding-top: 1rem;
}

.tab-pane {
    display: none;
}

.tab-pane.active {
    display: block;
}

.task-container.today { background-color: var(--section-today);}
.task-container.overdue { background-color: var(--section-overdue);}
.task-container.upcoming { background-color: var(--section-upcoming);}
.task-container.completed { background-color: var(--section-completed);}
.task-container.cancelled { background-color: var(--section-cancelled);}
.task-container.deferred { background-color: var(--section-deferred);}
.task-container.archived { background-color: var(--section-archived);}

/* FullCalendar event coloring */
a.fc-event {
  cursor: pointer;
}

.fc-event.priority-Urgent {
    background-color: var(--task-urgent);
    border-color: var(--task-urgent);
}

.fc-event.priority-High {
    background-color: var(--task-high);
    border-color: var(--task-high);
}

.fc-event.priority-Normal {
    background-color: var(--task-normal);
    border-color: var(--task-normal);
}

.fc-event.priority-Low {
    background-color: var(--task-low);
    border-color: var(--task-low);
}

.fc-event.priority-Undefied {
    background-color: var(--task-undefied);
    border-color: var(--task-undefied);
}

/* .fc-event.status-Pending {}
.fc-event.status-In_Progress {}
.fc-event.status-Completed {}
.fc-event.status-Deferred {}
.fc-event.status-Cancelled {}
.fc-event.status-Paused {} */

.calendar-legend {
    display: flex;
    gap: 12px;
    margin-bottom: 10px;
    font-size: 13px;
}

.legend-item {
    display: flex;
    align-items: center;
    gap: 6px;
}

.legend-item::before {
    content: '';
    width: 15px;
    height: 15px;
    display: inline-block;
}

/* Priority colors */
.legend-item.urgent::before { background: var(--task-urgent);}
.legend-item.high::before { background: var(--task-high);}
.legend-item.normal::before { background: var(--task-normal);}
.legend-item.low::before { background: var(--task-low);}
.legend-item.undefied::before { background: var(--task-undefied);}

.task-popup {
    max-width: 450px;
    text-align: left;
    font-size: 14px;
}

.task-popup p {
    margin: 6px 0;
}

.task-popup strong {
    color: #333;
}

/* Start Search View */
#search_form {
    position: relative;
    width: max-content;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 8px;
    padding: 10px;
    background: #f9f9f9;
    border-radius: 8px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
}

#search_form > div {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

#search_form button {
    border: none;
    background-color: unset;
    cursor: pointer;
}

#search_form button:hover {
  opacity: 0.7;
}

#search_form button img {
    height: 1.3rem;
    width: 1.3rem;
}

#searchTaskBtn #save_loader {
  display: none;
  margin: 0;
}

#searchView h4 {
  margin-bottom: 15px;
  font-size: 18px;
  font-weight: 600;
}

/* Remove default list styling */
#searchView ol {
  padding-left: 20px;
  margin: 0;
}

#searchView li {
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 8px;
  transition: all 0.2s ease;
  background: #f9f9f9;
  transition: all 0.3s ease;
}

#searchView li:hover {
  transform: translateY(-3px);
  background-color: #eeeeee;
}

/* Link styling */
#searchView li a {
  text-decoration: none;
  color: inherit;
  display: block;
}

/* Task title */
#searchView h3 {
  margin: 0 0 6px 0;
  font-size: 16px;
}

/* Bottom meta row */
#searchView li div {
  display: flex;
  gap: 8px;
  font-size: 13px;
  color: #666;
}

/* Priority Left Border Indicator */

#searchView li.Urgent { border-left: 5px solid var(--task-urgent);}
#searchView li.High { border-left: 5px solid var(--task-high);}
#searchView li.Normal { border-left: 5px solid var(--task-normal);}
#searchView li.Low { border-left: 5px solid var(--task-low);}
#searchView li.undefined { border-left: 5px solid var(--task-undefied);}

.highlight {
    background-color: #fff3a0;
    color: #000;
    padding: 0 2px;
    border-radius: 2px;
}
/* End Search View */

/* ACTIVITY LOG */
#all_changes_table,
.details_table {
  width: 100%;
  table-layout: auto;
  white-space: nowrap;
}

.changes_alert {
  max-height: 80vh;
  max-width: 90vw;
  overflow-y: auto;
}

#all_changes_table th,
#all_changes_table td,
.details_table th,
.details_table td {
  border: 1px solid black;
  padding: 0.3rem;
  min-width: 8rem;
}

#all_changes_table td div.changes_td {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

#all_changes_table .log_detail {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin: 0;
    max-width: 38rem;
    min-width: 15rem;
    overflow-x: auto;
}

td.changes {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 !important;
}

th div.action_list {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  margin-left: 1rem;
}

td.changes .save_loader,
th div.action_list .save_loader {
  margin: 0;
  display: none;
}

button.view_all_changes,
td.changes button {
  background-color: #4a90e2;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 5px 12px;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.2s;
  margin-top: 0.1rem;
}

button.view_all_changes:hover,
td.changes button:hover {
  background-color: #357ABD;
}

.sweet_alert_log {
  max-height: 25rem;
  overflow-y: auto;
  text-align: left;
}

.log_detail {
  margin-bottom: 1rem;
}

.log_detail div {
  width: max-content;
}

.view_log_detail {
  cursor: pointer;
  font-size: 14px;
  margin-left: 0.5rem;
}

.view_log_detail:hover {
  text-decoration: underline;
}

div.desc_changes {
  max-height: 10rem;
  max-width: 100%;
  overflow-y: auto;
}

.swal2-html-container div.old *,
.swal2-html-container div.new * {
  all: unset;
}

.swal2-html-container div.old {
  background-color: var(--section-overdue);
}

.swal2-html-container div.new {
  background-color: var(--section-completed);
}

.swal2-html-container div.tag {
  display: flex;
}

/* REPORT */
#body_todo_report .report-content {
  margin-top: 1.5rem;
}

.report_loader {
  display: none;
  border: 0.3rem solid white;
  animation: spin_report .5s linear infinite;
  border-top: 0.3rem solid black;
  border-left: 0.3rem solid black;
  border-radius: 50%;
  width: 2rem;
  height: 2rem;
  z-index: 10;
  position: absolute;
  top: 50%;
  left: 50%;
}

@keyframes spin_report {
  0% { transform: translate(-50%, -50%) rotate(0deg); }
  100% { transform: translate(-50%, -50%) rotate(360deg); }
}

#reportContent.loading {
  opacity: 0.3;
  pointer-events: none;
}

.report-content div.dt-buttons {
  float: unset;
}

.report-content .kpi-container {
    display: flex;
    gap: 1.5rem;
    margin-bottom: 1.5rem;
}

.report-content .kpi {
    width: 11.875%;
    background:#fff;
    padding: 1rem;
    border-radius: 0.5rem;
    box-shadow:0 2px 10px rgba(0,0,0,0.2);
}

.report-content .kpi:last-child {
  cursor: pointer;
    width: 5%;
    display: flex;
    gap: 0.5rem;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transition: all 0.3s ease;
}

.report-content .kpi:last-child img {
  width: 1.5rem;
  transition: all 0.3s ease;
}

.report-content .kpi:last-child:hover {
  background-color: #e6e6e6;
}

.report-content .kpi:last-child:hover > img {
  opacity: 0.7;
}

.report-content .kpi:last-child > img.active {
  transform: rotate(180deg);
}

.report-content .kpi h3 {
    margin:0;
    font-size:14px;
    color:#666;
}

.report-content .kpi p {
    margin:5px 0 0;
    font-size:22px;
    font-weight:bold;
}

.report-content .kpi-table {
    display: none;
    margin-bottom: 1.5rem;
    background:#fff;
    padding: 1rem;
    border-radius: 0.5rem;
    box-shadow:0 2px 10px rgba(0,0,0,0.2);
}

.report-content .kpi-table td {
  padding: 0 10px !important;
  border-bottom: 1px solid #ddd;
  border-top: none;
}

.report-content .insight {
    margin-bottom: 1.5rem;
    background:#fff;
    padding:15px;
    border-radius:8px;
    box-shadow:0 2px 10px rgba(0,0,0,0.2);
}

.report-content .insight h4 {
  margin-top: 0;
}

.report-content .chart-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
    gap: 1.5rem;
}

.report-content td {
  padding: 0 10px !important;
  white-space: nowrap;
}

.report-content .chart-grid > :nth-child(4) {
  grid-column: span 2;
  aspect-ratio: unset;
}


#overlay {
  display: none;
  position: fixed;
  inset: 0; 
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 9;
}

.report-content table th:first-child, 
.report-content table td:first-child {
  display: none;
}

.report-content .card {
    background:#fff;
    padding: 1rem;
    border-radius: 0.5rem;
    box-shadow:0 2px 10px rgba(0,0,0,0.2);
    box-sizing: border-box;
    aspect-ratio: 1 / 1;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}

.report-content .chart-square,
.report-content .chart-square canvas,
.report-content .chart-rectangle,
.report-content .chart-rectangle canvas {
  height: 100%;
  width: 100%;
}

.report-content .chart-rectangle {
  aspect-ratio: 2 / 1;
}

.kpi-table .chart-rectangle {
  display: none;
  height: 550px;
}

.show_detail_btn,
.close_detail_btn {
  padding: 0.5rem;
  position: absolute;
  top: 0;
  right: 0;
  cursor: pointer;
  transition: all 0.3s ease;
}
  
.show_detail_btn {
  height: 2rem;
}

.close_detail_btn {
  height: 1.8rem;
  padding: 1rem;
} 

.show_detail_btn:hover,
.close_detail_btn:hover {
  transform: scale(1.05);
}

.report-content .popup_detail {
  box-sizing: border-box;
  display: none;
  background-color: white;
  padding: 1rem;
  border-radius: 0.5rem;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 10;
  overflow-y: auto;
  overflow-x: hidden;
  max-width: 90%;
  max-height: 90%;
  animation: grow 0.3s;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
}

.report-content .popup_detail.active {
  display: flex;
}

@keyframes grow {
  0% {
    transform: translate(-50%, -50%) scale(0);
  }
  100% {
    transform: translate(-50%, -50%) scale(1);
  }
}

.report-content .popup_detail.scaleDown {
  animation: scaleDown 0.4s;
}

@keyframes scaleDown {
  0% {
    transform: translate(-50%, -50%) scale(1);
  }
  100% {
    transform: translate(-50%, -50%) scale(0);
  }
}

.report-content .detail_table {
  width: 100%;
}

.report-content .show_chart {
    border: none;
    padding: 0.5rem 1rem;
    border-radius: 0.5rem;
    cursor: pointer;
    background-color: #4a90e2;
    color: #fff;
    margin-bottom: 1rem;
    transition: all 0.3s ease;
}

.report-content .show_chart:hover {
    background-color: #357ABD;
    transform: translateY(-1px);
} 

.popup_detail .clone_canvas {
  display: none;
  flex-shrink: 0;
}

/* =========== LIST OF REPORT =========== */
#listContent .report-list {
  padding: 0 2rem 1rem 2rem;
}

#listContent .report-list li {
  padding-top: 0.5rem;
  cursor: pointer;
  width: max-content;
}

#listContent .report-list li:hover {
  padding-top: 0.5rem;
  text-decoration: underline;
}

/* =========== GENERATE REPORT =========== */
.report_header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

#filter_container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1.5rem;
  padding: 1rem;
  border-radius: 0.5rem;
  box-shadow: 0 2px 10px rgba(0,0,0,0.2);
  background-color: rgb(235, 235, 235);
  margin-bottom: 2rem;
}

#filter_container h4 {
  flex: 0 0 100%;
  margin: 0;
}

#filter_container div {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

#filter_container div.group_by_option {
  display: none;
}

#filter_container .end_date_field {
  display: none;
}

button.end_date_btn,
button.generate_report {
  background-color: #4a90e2;
  color: #fff;
  border: none;
  border-radius: 8px;
  padding: 5px 12px;
  font-size: 0.95rem;
  cursor: pointer;
  transition: all 0.2s;
}

button.end_date_btn {
  background-color: gray;
  padding: 3px 10px;
  display: none;
}

button.end_date_btn:hover {
  background-color: lightgray;
}

button.generate_report:hover {
  background-color: #357ABD;
}

button.generate_report.done {
  pointer-events: none;
  background-color: green;
}

#body_todo_generate_report div.dt-buttons {
  display: none;
}

#generate_table {
  display: none;
}

.export_btn {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.export_btn .btn {
  background-color: #4a90e2;
  color: #fff;
  border-radius: 8px;
  padding: 0.5rem 1rem;
  border: none;
  cursor: pointer;
  transition: all 0.2s;
}

.export_btn .btn.excel {
  background-color: green;
}

.export_btn .btn.pdf {
  background-color: red;
}

.export_btn .btn:hover {
  opacity: 0.7;
}

#generate_table.loading {
  opacity: 0.3;
  pointer-events: none;
}

#generate_table .table_title {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

#generate_table .subtitle {
  text-align: center;
}

#generate_table .table_header {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding-bottom: 1rem;
}

#generate_table .chart_container {
  display: none;
}

#generate_table .chart_container.active {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

#generate_table .generate_canvas {
  display: none;
  width: 1100px;
  height: 550px;
  align-items: center;
  justify-content: center;
}

.toggle_chart_btn {
    background-color: #4a90e2;
    color: #fff;
    border: none;
    border-radius: 8px;
    padding: 5px 14px;
    font-size: 0.95rem;
    cursor: pointer;
    transition: all 0.2s;
}

#body_todo_generate_report th:first-child, 
#body_todo_generate_report td:first-child {
  display: none;
} 
 
#body_todo_generate_report td {
  padding: 0 10px;
}

Step 4

Update: backend.js

Update this part:

// alert when user navigate away

And paste this part:

// Notify User When Task Is In Progress Before 'Leaving', 'Lunch Break' And 'End Work Hour'

// alert when user navigate away $(document).ready(function() { let formChanged = false; let formSubmitting = false; // Detect any changes in the form $('form').on('input change', 'input:not([type="search"]), textarea, select', function (e) { // ignore DataTables search box explicitly & filter Box if ($(e.target).closest('.dataTables_filter').length) return; if ($(e.target).closest('.dataTables_length').length) return; if ($(e.target).closest('.filter_dataTable').length) return; if ($(e.target).closest('tr.quickTaskTr').length) return; if ($(e.target).closest('.bulk_action_checkbox').length) return; formChanged = true; }); $(document).on("click", "#cropConfirm", function() { if ($("#gallery_list").length) return; formChanged = true; }) // Before submitting, disable the alert $(document).on('submit', 'form', function () { formSubmitting = true; $("#loader_container").css("display", "flex"); }); // Before submitting, disable the alert $(document).on('mousedown', 'form #button_container input.button', function() { formSubmitting = true; }); $(window).on("beforeunload", function() { if (formChanged && !formSubmitting) { promptSubmit(); return 'You have unsaved changes. Are you sure you want to leave?'; } }) function promptSubmit() { Swal.fire({ html: `You have unsaved changes. Please save before leaving.`, icon: 'warning', showCancelButton: true, confirmButtonText: 'Ok', cancelButtonText: 'Cancel', confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', showCloseButton: true }).then((result) => { if (result.isConfirmed) { formSubmitting = true; $('input[name="commit"]').click(); } }); } }) // Notify User When Task Is In Progress Before 'Leaving', 'Lunch Break' And 'End Work Hour' $(document).ready(function() { // let originalTitle = document.title; // let isFlashing = false; // let interval; let isInternalNavigation = false; let earlyReminder = $("#early_reminder").val() == 1 ? true : false; let earlyReminderMinute = $("#early_reminder_minute").val(); // Request notification permission upfront if ("Notification" in window && Notification.permission === "default") { Notification.requestPermission(); } // Detect if href is internal $(document).on('mousedown', 'a', function() { const href = $(this).attr("href"); if (!href) return; if (href.startsWith("#") || href.startsWith("javascript:")) return; const url = new URL(href, window.location.origin); if (url.origin === window.location.origin) { isInternalNavigation = true; } else { isInternalNavigation = false; promptPauseTask(); } if (href.indexOf('logout') > 0 && hasActiveTask()) { isInternalNavigation = false; promptPauseTask(); } }) // Before submitting, disable the alert $(document).on('mousedown', 'form #button_container input.button', function() { isInternalNavigation = true; }); // detect Swal confirm $(document).on('mousedown', '.swal2-confirm', function () { isInternalNavigation = true; }); let isRefresh = false; // Detect keyboard refresh $(document).on("keydown", function (e) { if (e.key === "F5" || (e.ctrlKey && e.key.toLowerCase() === "r")) { isRefresh = true; } }); // Detect browser reload button click $(window).on("beforeunload", function(e) { const navType = performance.getEntriesByType("navigation")[0]?.type; if (navType === "reload") { isRefresh = true; } }); $(window).on("beforeunload", function (e) { if (hasActiveTask() && !isInternalNavigation && !isRefresh) { promptPauseTask(); desktopNotif("Please 'Paused' task before leaving work."); e.preventDefault(); e.returnValue = "Please 'Paused' task before leaving work."; return e.returnValue; } }) if (earlyReminder) { // Initialize session (run once) const today = new Date().toLocaleDateString('en-CA'); // local YYYY-MM-DD const storedDate = sessionStorage.getItem("alert_date"); if (storedDate !== today) { Object.keys(sessionStorage).forEach(key => { if (key.startsWith("alert_")) { sessionStorage.removeItem(key); } }); sessionStorage.setItem("alert_date", today); } // Run immediately + every minute checkTimeAlerts(); setInterval(() => checkTimeAlerts(earlyReminderMinute), 60000); } // ========== START - HELPER FUNCTION ========== // Check if any task is in progress (use function to get real time status) function hasActiveTask() { return $(".in-progress-task.active").length > 0; } // Send Desktop Notification function desktopNotif(message) { if (!("Notification" in window)) return; if (Notification.permission !== "granted") return; new Notification("Task Still Running!", { body: message }); } // Check if already alerted function hasAlerted(key) { return sessionStorage.getItem(key) === "1"; } // Mark as alerted function setAlerted(key) { sessionStorage.setItem(key, "1"); } // Check if a time (HH:mm) is within minuteInAdvance minutes function checkTimeAlertFor(timeVal, message, minuteInAdvance = 5, type = "") { if (!timeVal) return; const [hours, minutes] = timeVal.split(":").map(Number); const now = new Date(); const alertTime = new Date(); alertTime.setHours(hours, minutes, 0, 0); const diffMinutes = (alertTime - now) / 1000 / 60; const key = `alert_${type}_${timeVal}`; if (diffMinutes > 0 && diffMinutes <= minuteInAdvance) { if (!hasAlerted(key)) { desktopNotif(message); promptPauseTask(); setTimeout(() => { alert(message); }, 500); setAlerted(key); } } } // Main checker function checkTimeAlerts(minuteInAdvance = 5) { if (!hasActiveTask()) return; checkTimeAlertFor( $("#start_lunch_hour").val(), "Lunch break approaching! Make sure tasks are paused.", minuteInAdvance, "lunch" ); checkTimeAlertFor( $("#end_working_hour").val(), "Off-work time approaching! Make sure tasks are paused.", minuteInAdvance, "offwork" ); } // function promptPauseTask() { let pauseLink = $('input#pauseLink').val(); Swal.fire({ html: `Task still running. Pause it?`, icon: 'question', showCancelButton: true, confirmButtonText: 'Pause', cancelButtonText: 'Cancel', confirmButtonColor: 'green', cancelButtonColor: '#3085d6', showCloseButton: true }).then((result) => { if (result.isConfirmed) { window.location.href = pauseLink; } }); } })
// alert when user navigate away
$(document).ready(function() {
    let formChanged = false;
    let formSubmitting = false;

    // Detect any changes in the form
    $('form').on('input change', 'input:not([type="search"]), textarea, select', function (e) {
        // ignore DataTables search box explicitly & filter Box 
        if ($(e.target).closest('.dataTables_filter').length) return;
        if ($(e.target).closest('.dataTables_length').length) return;
        if ($(e.target).closest('.filter_dataTable').length) return;
        if ($(e.target).closest('tr.quickTaskTr').length) return;

        if ($(e.target).closest('.bulk_action_checkbox').length) return;

        formChanged = true;
    });

    $(document).on("click", "#cropConfirm", function() {
        if ($("#gallery_list").length) return;
        formChanged = true;
    })

    // Before submitting, disable the alert
    $(document).on('submit', 'form', function () {
        formSubmitting = true;
        $("#loader_container").css("display", "flex");
    });

    // Before submitting, disable the alert
    $(document).on('mousedown', 'form #button_container input.button', function() {
        formSubmitting = true;
    });

    $(window).on("beforeunload", function() {
        if (formChanged && !formSubmitting) {
            promptSubmit();
            return 'You have unsaved changes. Are you sure you want to leave?';
        }
    })

    function promptSubmit() {
        Swal.fire({
            html: `You have unsaved changes. Please save before leaving.`,
            icon: 'warning',
            showCancelButton: true,
            confirmButtonText: 'Ok',
            cancelButtonText: 'Cancel',
            confirmButtonColor: '#3085d6',
            cancelButtonColor: '#d33',
            showCloseButton: true
        }).then((result) => {
            if (result.isConfirmed) {
                formSubmitting = true;
                $('input[name="commit"]').click();
            }
        });
    }
})

// Notify User When Task Is In Progress Before 'Leaving', 'Lunch Break' And 'End Work Hour'
$(document).ready(function() {
    // let originalTitle = document.title;
    // let isFlashing = false;
    // let interval;

    let isInternalNavigation = false;
    let earlyReminder = $("#early_reminder").val() == 1 ? true : false;
    let earlyReminderMinute = $("#early_reminder_minute").val();

    // Request notification permission upfront
    if ("Notification" in window && Notification.permission === "default") {
        Notification.requestPermission();
    }

    // Detect if href is internal
    $(document).on('mousedown', 'a', function() {
        const href = $(this).attr("href");
        if (!href) return;
        if (href.startsWith("#") || href.startsWith("javascript:")) return;
        const url = new URL(href, window.location.origin);

        if (url.origin === window.location.origin) {
            isInternalNavigation = true;
        } else {
            isInternalNavigation = false;
            promptPauseTask();
        }
        
        if (href.indexOf('logout') > 0 && hasActiveTask()) {
            isInternalNavigation = false;
            promptPauseTask();
        }
    })

    // Before submitting, disable the alert
    $(document).on('mousedown', 'form #button_container input.button', function() {
        isInternalNavigation = true;
    });

    // detect Swal confirm
    $(document).on('mousedown', '.swal2-confirm', function () {
        isInternalNavigation = true;
    });

    let isRefresh = false;
    
    // Detect keyboard refresh
    $(document).on("keydown", function (e) {
        if (e.key === "F5" || (e.ctrlKey && e.key.toLowerCase() === "r")) {
            isRefresh = true;
        }
    });

    // Detect browser reload button click
    $(window).on("beforeunload", function(e) {
        const navType = performance.getEntriesByType("navigation")[0]?.type;
        if (navType === "reload") {
            isRefresh = true;
        }
    });
    
    $(window).on("beforeunload", function (e) {
        if (hasActiveTask() && !isInternalNavigation && !isRefresh) {
            promptPauseTask();
            desktopNotif("Please 'Paused' task before leaving work.");
            
            e.preventDefault();
            e.returnValue = "Please 'Paused' task before leaving work.";
            return e.returnValue;
        }
    })

    if (earlyReminder) {
        // Initialize session (run once)
        const today = new Date().toLocaleDateString('en-CA'); // local YYYY-MM-DD
        const storedDate = sessionStorage.getItem("alert_date");
    
        if (storedDate !== today) {
            Object.keys(sessionStorage).forEach(key => {
                if (key.startsWith("alert_")) {
                    sessionStorage.removeItem(key);
                }
            });
    
            sessionStorage.setItem("alert_date", today);
        }

        // Run immediately + every minute
        checkTimeAlerts();
        setInterval(() => checkTimeAlerts(earlyReminderMinute), 60000);
    }

    // ========== START - HELPER FUNCTION ==========
    // Check if any task is in progress (use function to get real time status)
    function hasActiveTask() {
        return $(".in-progress-task.active").length > 0;
    }

    // Send Desktop Notification
    function desktopNotif(message) {
        if (!("Notification" in window)) return;
        if (Notification.permission !== "granted") return;

        new Notification("Task Still Running!", { body: message });
    }

    // Check if already alerted
    function hasAlerted(key) {
        return sessionStorage.getItem(key) === "1";
    }

    // Mark as alerted
    function setAlerted(key) {
        sessionStorage.setItem(key, "1");
    }

    // Check if a time (HH:mm) is within minuteInAdvance minutes
    function checkTimeAlertFor(timeVal, message, minuteInAdvance = 5, type = "") {
        if (!timeVal) return;

        const [hours, minutes] = timeVal.split(":").map(Number);

        const now = new Date();
        const alertTime = new Date();
        alertTime.setHours(hours, minutes, 0, 0);

        const diffMinutes = (alertTime - now) / 1000 / 60;

        const key = `alert_${type}_${timeVal}`;

        if (diffMinutes > 0 && diffMinutes <= minuteInAdvance) {
            if (!hasAlerted(key)) {
                desktopNotif(message);
                promptPauseTask();
                setTimeout(() => {
                    alert(message);
                }, 500);
                setAlerted(key);
            }
        }
    }

    // Main checker
    function checkTimeAlerts(minuteInAdvance = 5) {
        if (!hasActiveTask()) return;

        checkTimeAlertFor(
            $("#start_lunch_hour").val(),
            "Lunch break approaching! Make sure tasks are paused.",
            minuteInAdvance,
            "lunch"
        );

        checkTimeAlertFor(
            $("#end_working_hour").val(),
            "Off-work time approaching! Make sure tasks are paused.",
            minuteInAdvance,
            "offwork"
        );
    }

    // 
    function promptPauseTask() {
        let pauseLink = $('input#pauseLink').val();

        Swal.fire({
            html: `Task still running. Pause it?`,
            icon: 'question',
            showCancelButton: true,
            confirmButtonText: 'Pause',
            cancelButtonText: 'Cancel',
            confirmButtonColor: 'green',
            cancelButtonColor: '#3085d6',
            showCloseButton: true
        }).then((result) => {
            if (result.isConfirmed) {
                window.location.href = pauseLink;
            }
        });
    }
})

Step 5

Update: wolf\plugins\ckeditor -> index.php
To enable Ckeditor

Update: function ckeditor_filter_setup()

in $controllers add 2 more fields for "|todo|todo_comment"

function ckeditor_filter_setup() { $config_path = (USE_MOD_REWRITE) ? 'ckeditor/' : '../../?/wolf/plugins/ckeditor/'; $controllers = '(page|snippet|donate|story|volunteer|project|documentation|source_code|announcement|form_builder|portfolio|testimonial|client|portfolio_section|portfolio_highlight|todo|todo_comment)'; $actions = '(add|edit|create|view|table)'; $pattern = '/^'.ADMIN_DIR.'\/'.$controllers.'\/'.$actions.'/'; if (preg_match($pattern, CURRENT_URI)) { Plugin::addJavascript('ckeditor', 'scripts/ckeditor/ckeditor.js'); Plugin::addJavascript('ckeditor', 'scripts/init.js'); /* nasty way of including scripts */ Plugin::$javascripts[] = $config_path.'ckeditor_config.js'; // load it AFTER ckeditor_config! // Plugin::addJavascript('ckeditor', 'scripts/user/config.js'); } }
function ckeditor_filter_setup() {
    $config_path = (USE_MOD_REWRITE) ? 'ckeditor/' : '../../?/wolf/plugins/ckeditor/';
    $controllers = '(page|snippet|donate|story|volunteer|project|documentation|source_code|announcement|form_builder|portfolio|testimonial|client|portfolio_section|portfolio_highlight|todo|todo_comment)';
    $actions = '(add|edit|create|view|table)';
    $pattern = '/^'.ADMIN_DIR.'\/'.$controllers.'\/'.$actions.'/';

    if (preg_match($pattern, CURRENT_URI)) {
        Plugin::addJavascript('ckeditor', 'scripts/ckeditor/ckeditor.js');
        Plugin::addJavascript('ckeditor', 'scripts/init.js');
        /* nasty way of including scripts */
        Plugin::$javascripts[] = $config_path.'ckeditor_config.js';
        // load it AFTER ckeditor_config!
//         Plugin::addJavascript('ckeditor', 'scripts/user/config.js');
    }

}

Step 6

Copy all related files to your project and import sql table

Code Copied To Clipboard!