Highlight task planner items near reset
All checks were successful
Deploy Sokko G / deploy (push) Successful in 14s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 14s
This commit is contained in:
parent
49ba0c4cb2
commit
e4cbe3e087
5 changed files with 80 additions and 2 deletions
|
|
@ -15,6 +15,7 @@ import {
|
|||
getTaskTitle,
|
||||
getTaskTypeLabel,
|
||||
getTasksForParent,
|
||||
isTaskResetSoon,
|
||||
isTaskTreeComplete
|
||||
} from "./taskPlannerUtils.js";
|
||||
|
||||
|
|
@ -23,6 +24,7 @@ export function TaskPlannerBranch({
|
|||
parentMap,
|
||||
tasks,
|
||||
data,
|
||||
nowMs,
|
||||
reorder,
|
||||
textContent,
|
||||
openDescriptions,
|
||||
|
|
@ -60,6 +62,7 @@ export function TaskPlannerBranch({
|
|||
parentMap={parentMap}
|
||||
tasks={tasks}
|
||||
data={data}
|
||||
nowMs={nowMs}
|
||||
reorder={reorder}
|
||||
textContent={textContent}
|
||||
openDescriptions={openDescriptions}
|
||||
|
|
@ -106,6 +109,7 @@ export function TaskPlannerBranch({
|
|||
task={task}
|
||||
tasks={tasks}
|
||||
data={data}
|
||||
nowMs={nowMs}
|
||||
parentMap={parentMap}
|
||||
parentId={parentId}
|
||||
reorder={reorder}
|
||||
|
|
@ -208,6 +212,7 @@ function TaskPlannerItem({
|
|||
task,
|
||||
tasks,
|
||||
data,
|
||||
nowMs,
|
||||
parentMap,
|
||||
parentId,
|
||||
reorder,
|
||||
|
|
@ -237,6 +242,7 @@ function TaskPlannerItem({
|
|||
const className = [
|
||||
"task-planner-item",
|
||||
task.checked ? "is-complete" : "",
|
||||
isTaskResetSoon(task, data, nowMs) ? "is-reset-soon" : "",
|
||||
missingPrerequisites.length ? "has-missing-prerequisite" : "",
|
||||
reorder.isItemDragging(task.id) ? "is-dragging" : "",
|
||||
reorder.isItemDropTarget(task.id) ? "is-drop-target" : "",
|
||||
|
|
@ -519,4 +525,3 @@ function LinksEditor({ label, relations, task, tasks, parentMap, relationTargets
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ export function TaskPlannerModule({ toolboxId, moduleId, context, editing }) {
|
|||
parentMap={parentMap}
|
||||
tasks={data.tasks}
|
||||
data={data}
|
||||
nowMs={nowMs}
|
||||
reorder={reorder}
|
||||
textContent={textContent}
|
||||
openDescriptions={openDescriptions}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
// Rôle : regroupe les constantes et helpers purs de l'outil task planner.
|
||||
export const TASK_TYPES = ["daily", "weekly", "unique"];
|
||||
const DAILY_RESET_SOON_MS = 6 * 60 * 60 * 1000;
|
||||
const WEEKLY_RESET_SOON_MS = 48 * 60 * 60 * 1000;
|
||||
|
||||
export const WEEK_DAYS = [
|
||||
{ value: 1, label: "Lundi" },
|
||||
{ value: 2, label: "Mardi" },
|
||||
|
|
@ -42,6 +45,39 @@ export function getLatestWeeklyReset(now, resetTime, weekDay) {
|
|||
return reset.getTime();
|
||||
}
|
||||
|
||||
export function getNextDailyReset(now, resetTime) {
|
||||
const { hours, minutes } = parseResetTime(resetTime);
|
||||
const reset = new Date(now);
|
||||
reset.setHours(hours, minutes, 0, 0);
|
||||
if (reset.getTime() <= now) reset.setDate(reset.getDate() + 1);
|
||||
return reset.getTime();
|
||||
}
|
||||
|
||||
export function getNextWeeklyReset(now, resetTime, weekDay) {
|
||||
const { hours, minutes } = parseResetTime(resetTime);
|
||||
const reset = new Date(now);
|
||||
reset.setHours(hours, minutes, 0, 0);
|
||||
const dayDiff = (weekDay - reset.getDay() + 7) % 7;
|
||||
reset.setDate(reset.getDate() + dayDiff);
|
||||
if (reset.getTime() <= now) reset.setDate(reset.getDate() + 7);
|
||||
return reset.getTime();
|
||||
}
|
||||
|
||||
export function getTaskResetTimeRemainingMs(task, data, now = Date.now()) {
|
||||
if (task.checked || task.type === "unique") return null;
|
||||
const nextResetAt = task.type === "daily"
|
||||
? getNextDailyReset(now, task.dailyResetTime || data.resetTime)
|
||||
: getNextWeeklyReset(now, data.resetTime, task.weeklyResetDay ?? data.weeklyResetDay);
|
||||
return Math.max(0, nextResetAt - now);
|
||||
}
|
||||
|
||||
export function isTaskResetSoon(task, data, now = Date.now()) {
|
||||
const remainingMs = getTaskResetTimeRemainingMs(task, data, now);
|
||||
if (remainingMs == null) return false;
|
||||
const threshold = task.type === "daily" ? DAILY_RESET_SOON_MS : WEEKLY_RESET_SOON_MS;
|
||||
return remainingMs <= threshold;
|
||||
}
|
||||
|
||||
export function applyDueResets(data, now = Date.now()) {
|
||||
let latestResetAt = data.lastResetAt;
|
||||
let changed = false;
|
||||
|
|
|
|||
|
|
@ -360,6 +360,37 @@
|
|||
rgba(5, 7, 17, 0.36);
|
||||
}
|
||||
|
||||
.task-planner-item.is-reset-soon:not(.is-complete) {
|
||||
border-color: rgba(34, 211, 238, 0.34);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgba(34, 211, 238, 0.07),
|
||||
0 0 0 rgba(34, 211, 238, 0);
|
||||
animation: task-planner-reset-soon-pulse 2600ms var(--ease-standard) infinite;
|
||||
}
|
||||
|
||||
@keyframes task-planner-reset-soon-pulse {
|
||||
0%,
|
||||
100% {
|
||||
border-color: rgba(34, 211, 238, 0.26);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgba(34, 211, 238, 0.05),
|
||||
0 0 0 rgba(34, 211, 238, 0);
|
||||
}
|
||||
|
||||
50% {
|
||||
border-color: rgba(34, 211, 238, 0.44);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgba(34, 211, 238, 0.1),
|
||||
0 0 12px rgba(34, 211, 238, 0.07);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.task-planner-item.is-reset-soon:not(.is-complete) {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.task-planner-line {
|
||||
display: grid;
|
||||
grid-template-columns: 30px 24px minmax(0, 1fr) 134px auto auto;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue