Ensure that you have implemented module 'Option' & 'Module Setting' in your backend.
| 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 |
Update: backend.php
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>
Insert SQL Record into wolf_module_setting:
Add 4 status for:
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);
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;
}
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;
}
});
}
})
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');
}
}
Copy all related files to your project and import sql table