task planner categories optimisation
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
All checks were successful
Deploy Sokko G / deploy (push) Successful in 7s
This commit is contained in:
parent
3dc5ed8733
commit
1d3bdd60f1
7 changed files with 217 additions and 37 deletions
|
|
@ -269,7 +269,9 @@ Type : `taskPlanner`
|
|||
"weeklyResetDay": 1,
|
||||
"resetTime": "00:00",
|
||||
"lastResetAt": 1760000000000,
|
||||
"hideCompleted": true,
|
||||
"categoryOrder": ["Raid", "Farm"],
|
||||
"collapsedCategories": ["Farm"],
|
||||
"tasks": [
|
||||
{
|
||||
"id": "task1",
|
||||
|
|
@ -309,10 +311,12 @@ Notes :
|
|||
- `sortMode` vaut `manual` ou `type`. Le tri par type affiche quotidiennes, hebdo, puis uniques.
|
||||
- `weeklyResetDay` suit les jours JavaScript : `0` dimanche, `1` lundi, ..., `6` samedi.
|
||||
- `resetTime` est global à l'outil et vaut `HH:MM`.
|
||||
- `hideCompleted` masque les tâches effectuées à l'affichage, ainsi que les catégories dont toutes les tâches sont effectuées.
|
||||
- `weeklyResetDay` sur une tâche hebdo surcharge le jour global.
|
||||
- `category` sur une tâche racine est facultatif. Les tâches enfants héritent de la catégorie effective de leur parent et ne stockent pas de catégorie propre.
|
||||
- Les tâches catégorisées sont regroupées par catégorie au niveau racine.
|
||||
- `categoryOrder` stocke l'ordre d'affichage des catégories utilisées. Les catégories absentes des tâches sont retirées à la normalisation.
|
||||
- `collapsedCategories` stocke les noms des catégories repliées.
|
||||
- `relations` stocke les parents directionnels. `fromTaskId` désigne la tâche enfant, `toTaskId` son parent.
|
||||
- une tâche ne conserve qu'un seul parent.
|
||||
- `prerequisite: true` marque aussi ce parent comme pré requis.
|
||||
|
|
@ -325,9 +329,11 @@ Stockage compact :
|
|||
- `weeklyResetDay` global est omis si la valeur vaut `1`.
|
||||
- `resetTime` est omis si la valeur vaut `00:00`.
|
||||
- `lastResetAt` est omis si la valeur vaut `0`.
|
||||
- `hideCompleted` est omis si `false`.
|
||||
- `description` est omis si vide.
|
||||
- `category` est omis si vide ou si la tâche a un parent.
|
||||
- `categoryOrder` est omis si aucune catégorie n'est utilisée.
|
||||
- `collapsedCategories` est omis si aucune catégorie n'est repliée.
|
||||
- `checked` et `checkedAt` sont omis si la tâche n'est pas effectuée.
|
||||
- `weeklyResetDay` unitaire est omis si non défini.
|
||||
- `relations` est omis si vide.
|
||||
|
|
|
|||
|
|
@ -192,8 +192,11 @@ export function validateSiteContent(site) {
|
|||
"toolboxes.modules.taskPlanner.settingsTitle",
|
||||
"toolboxes.modules.taskPlanner.settingsButtonLabel",
|
||||
"toolboxes.modules.taskPlanner.sortModeLabel",
|
||||
"toolboxes.modules.taskPlanner.hideCompletedTitle",
|
||||
"toolboxes.modules.taskPlanner.globalWeeklyResetDayLabel",
|
||||
"toolboxes.modules.taskPlanner.resetTimeLabel",
|
||||
"toolboxes.modules.taskPlanner.clearCompletedUniqueTitle",
|
||||
"toolboxes.modules.taskPlanner.clearCompletedUniqueButton",
|
||||
"toolboxes.modules.taskPlanner.titlePlaceholder",
|
||||
"toolboxes.modules.taskPlanner.titleLabel",
|
||||
"toolboxes.modules.taskPlanner.descriptionPlaceholder",
|
||||
|
|
@ -217,6 +220,8 @@ export function validateSiteContent(site) {
|
|||
"toolboxes.modules.taskPlanner.categoryLabel",
|
||||
"toolboxes.modules.taskPlanner.categoryPlaceholder",
|
||||
"toolboxes.modules.taskPlanner.categoryReorderTitle",
|
||||
"toolboxes.modules.taskPlanner.showCategoryTitle",
|
||||
"toolboxes.modules.taskPlanner.hideCategoryTitle",
|
||||
"toolboxes.modules.taskPlanner.taskWeeklyResetDayLabel",
|
||||
"toolboxes.modules.taskPlanner.inheritWeeklyResetDay",
|
||||
"toolboxes.modules.taskPlanner.linksLabel",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ test("task planner data normalizes invalid settings and relations", () => {
|
|||
sortMode: "unknown",
|
||||
weeklyResetDay: 9,
|
||||
resetTime: "27:80",
|
||||
hideCompleted: true,
|
||||
categoryOrder: ["Raid", "Missing", "Farm", "Raid"],
|
||||
collapsedCategories: ["Raid", "", "Raid"],
|
||||
tasks: [
|
||||
{ id: "task1", title: "Daily", type: "daily", checked: true, checkedAt: 1000, category: "Farm" },
|
||||
{ id: "task2", title: "Weekly", type: "weekly", weeklyResetDay: 4, category: "Raid" },
|
||||
|
|
@ -50,7 +52,9 @@ test("task planner data normalizes invalid settings and relations", () => {
|
|||
assert.equal(normalized.sortMode, "manual");
|
||||
assert.equal(normalized.weeklyResetDay, 1);
|
||||
assert.equal(normalized.resetTime, "00:00");
|
||||
assert.equal(normalized.hideCompleted, true);
|
||||
assert.deepEqual(normalized.categoryOrder, ["Raid"]);
|
||||
assert.deepEqual(normalized.collapsedCategories, ["Raid"]);
|
||||
assert.equal(normalized.tasks[0].category, undefined);
|
||||
assert.equal(normalized.tasks[1].weeklyResetDay, 4);
|
||||
assert.equal(normalized.tasks[1].category, "Raid");
|
||||
|
|
@ -65,6 +69,8 @@ test("task planner storage compacts defaults and export remaps task relations",
|
|||
sortMode: "type",
|
||||
weeklyResetDay: 1,
|
||||
resetTime: "00:00",
|
||||
hideCompleted: true,
|
||||
collapsedCategories: ["Raid"],
|
||||
tasks: [
|
||||
{ id: "task1", title: "Daily", description: "", type: "daily", checked: false },
|
||||
{ id: "task2", title: "Weekly", description: "Run", type: "weekly", checked: true, checkedAt: 2000, weeklyResetDay: 5, category: "Raid" }
|
||||
|
|
@ -78,6 +84,8 @@ test("task planner storage compacts defaults and export remaps task relations",
|
|||
assert.equal(compact.sortMode, "type");
|
||||
assert.equal(compact.weeklyResetDay, undefined);
|
||||
assert.equal(compact.resetTime, undefined);
|
||||
assert.equal(compact.hideCompleted, true);
|
||||
assert.deepEqual(compact.collapsedCategories, ["Raid"]);
|
||||
assert.deepEqual(compact.categoryOrder, ["Raid"]);
|
||||
assert.deepEqual(compact.tasks[0], { id: "task1", title: "Daily", type: "daily" });
|
||||
assert.equal(compact.tasks[1].category, "Raid");
|
||||
|
|
|
|||
|
|
@ -326,8 +326,11 @@
|
|||
"settingsTitle": "Réglages du planificateur",
|
||||
"settingsButtonLabel": "Paramètres des réinitialisations",
|
||||
"sortModeLabel": "Tri automatique par type",
|
||||
"hideCompletedTitle": "Masquer les tâches effectuées",
|
||||
"globalWeeklyResetDayLabel": "Reset hebdo",
|
||||
"resetTimeLabel": "Heure de reset",
|
||||
"clearCompletedUniqueTitle": "Nettoyer les tâches ponctuelles effectuées",
|
||||
"clearCompletedUniqueButton": "Nettoyer les tâches ponctuelles terminées",
|
||||
"titlePlaceholder": "Nouvelle tâche",
|
||||
"titleLabel": "Titre",
|
||||
"descriptionPlaceholder": "Description",
|
||||
|
|
@ -351,6 +354,8 @@
|
|||
"categoryLabel": "Catégorie",
|
||||
"categoryPlaceholder": "Nom de catégorie",
|
||||
"categoryReorderTitle": "Déplacer la catégorie",
|
||||
"showCategoryTitle": "Afficher cette catégorie",
|
||||
"hideCategoryTitle": "Réduire cette catégorie",
|
||||
"taskWeeklyResetDayLabel": "Jour hebdo",
|
||||
"inheritWeeklyResetDay": "Global",
|
||||
"linksLabel": "Parent",
|
||||
|
|
|
|||
|
|
@ -178,6 +178,31 @@ function countTaskTree(taskIds, tasks, parentMap) {
|
|||
return count;
|
||||
}
|
||||
|
||||
function getTaskTreeIds(taskIds, tasks, parentMap) {
|
||||
const ids = [];
|
||||
const visited = new Set();
|
||||
function visit(taskId) {
|
||||
if (visited.has(taskId)) return;
|
||||
visited.add(taskId);
|
||||
ids.push(taskId);
|
||||
tasks
|
||||
.filter((task) => (parentMap.get(task.id) || "") === taskId)
|
||||
.forEach((child) => visit(child.id));
|
||||
}
|
||||
taskIds.forEach(visit);
|
||||
return ids;
|
||||
}
|
||||
|
||||
function countCompletedTaskTree(taskIds, tasks, parentMap) {
|
||||
const taskIdsSet = new Set(getTaskTreeIds(taskIds, tasks, parentMap));
|
||||
return tasks.filter((task) => taskIdsSet.has(task.id) && task.checked).length;
|
||||
}
|
||||
|
||||
function isTaskTreeComplete(taskIds, tasks, parentMap) {
|
||||
const treeIds = getTaskTreeIds(taskIds, tasks, parentMap);
|
||||
return treeIds.length > 0 && treeIds.every((taskId) => getTaskById(tasks, taskId)?.checked);
|
||||
}
|
||||
|
||||
function getTaskCategoryGroups(tasks, parentMap, parentId, sortMode, categoryOrder) {
|
||||
const siblings = getTasksForParent(tasks, parentMap, parentId, sortMode);
|
||||
if (parentId) {
|
||||
|
|
@ -420,6 +445,21 @@ export function TaskPlannerModule({ toolboxId, moduleId, context, editing }) {
|
|||
save({ ...data, tasks, categoryOrder });
|
||||
}
|
||||
|
||||
function toggleCategoryCollapsed(category) {
|
||||
const collapsedCategories = data.collapsedCategories.includes(category)
|
||||
? data.collapsedCategories.filter((item) => item !== category)
|
||||
: [...data.collapsedCategories, category];
|
||||
save({ ...data, collapsedCategories });
|
||||
}
|
||||
|
||||
function clearCompletedUniqueTasks() {
|
||||
const removedTaskIds = new Set(data.tasks.filter((task) => task.type === "unique" && task.checked).map((task) => task.id));
|
||||
if (!removedTaskIds.size) return;
|
||||
const tasks = data.tasks.filter((task) => !removedTaskIds.has(task.id));
|
||||
const relations = data.relations.filter((relation) => !removedTaskIds.has(relation.fromTaskId) && !removedTaskIds.has(relation.toTaskId));
|
||||
save({ ...data, tasks, relations });
|
||||
}
|
||||
|
||||
function toggleSet(setter, taskId) {
|
||||
setter((current) => {
|
||||
const next = new Set(current);
|
||||
|
|
@ -459,6 +499,17 @@ export function TaskPlannerModule({ toolboxId, moduleId, context, editing }) {
|
|||
<Icon name="sort-time" />
|
||||
<i aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
className={`tool-split-scroll-toggle task-planner-hide-completed-toggle ${data.hideCompleted ? "active" : ""}`}
|
||||
type="button"
|
||||
onClick={() => save({ ...data, hideCompleted: !data.hideCompleted })}
|
||||
aria-pressed={data.hideCompleted}
|
||||
aria-label={textContent.hideCompletedTitle || "Masquer les tâches effectuées"}
|
||||
title={textContent.hideCompletedTitle || "Masquer les tâches effectuées"}
|
||||
>
|
||||
<Icon name={data.hideCompleted ? "eye-closed" : "eye-open"} />
|
||||
<i aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
className={`task-planner-settings-toggle ${settingsOpen ? "active" : ""}`}
|
||||
type="button"
|
||||
|
|
@ -494,6 +545,19 @@ export function TaskPlannerModule({ toolboxId, moduleId, context, editing }) {
|
|||
<span>{textContent.resetTimeLabel || "Heure de reset"}</span>
|
||||
<input type="time" value={data.resetTime} onChange={(event) => save({ ...data, resetTime: event.target.value || "00:00" })} />
|
||||
</label>
|
||||
<div className="task-planner-settings-actions">
|
||||
<button
|
||||
className="task-planner-clear-completed-button danger"
|
||||
type="button"
|
||||
onClick={clearCompletedUniqueTasks}
|
||||
disabled={!data.tasks.some((task) => task.type === "unique" && task.checked)}
|
||||
title={textContent.clearCompletedUniqueTitle || "Nettoyer les tâches ponctuelles terminées"}
|
||||
aria-label={textContent.clearCompletedUniqueTitle || "Nettoyer les tâches ponctuelles terminées"}
|
||||
>
|
||||
<Icon name="trash" />
|
||||
<span>{textContent.clearCompletedUniqueButton || "Nettoyer les tâches ponctuelles terminées"}</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
|
|
@ -523,6 +587,7 @@ export function TaskPlannerModule({ toolboxId, moduleId, context, editing }) {
|
|||
onRemoveLinkTarget={removeLinkTarget}
|
||||
onSetPrerequisite={setPrerequisite}
|
||||
onSetTaskCategory={setTaskCategory}
|
||||
onToggleCategoryCollapsed={toggleCategoryCollapsed}
|
||||
/>
|
||||
) : (
|
||||
<li className="task-planner-empty">{textContent.emptyTasks || "Aucune tâche planifiée."}</li>
|
||||
|
|
@ -556,6 +621,7 @@ function TaskPlannerBranch({
|
|||
onRemoveLinkTarget,
|
||||
onSetPrerequisite,
|
||||
onSetTaskCategory,
|
||||
onToggleCategoryCollapsed,
|
||||
visited = new Set()
|
||||
}) {
|
||||
const groupedTasks = getTaskCategoryGroups(tasks, parentMap, parentId, data.sortMode, data.categoryOrder);
|
||||
|
|
@ -563,8 +629,51 @@ function TaskPlannerBranch({
|
|||
if (!children.length) return null;
|
||||
const nextVisited = new Set([...visited, ...children.map((task) => task.id)]);
|
||||
|
||||
function hasVisibleDescendants(taskId, seen = new Set()) {
|
||||
if (seen.has(taskId)) return false;
|
||||
seen.add(taskId);
|
||||
return getTasksForParent(tasks, parentMap, taskId, data.sortMode).some((child) => !child.checked || hasVisibleDescendants(child.id, seen));
|
||||
}
|
||||
|
||||
function renderTask(task) {
|
||||
const nestedChildren = getTasksForParent(tasks, parentMap, task.id, data.sortMode).filter((child) => !nextVisited.has(child.id));
|
||||
const nestedBranch = nestedChildren.length ? (
|
||||
<TaskPlannerBranch
|
||||
parentId={task.id}
|
||||
parentMap={parentMap}
|
||||
tasks={tasks}
|
||||
data={data}
|
||||
draggingId={draggingId}
|
||||
dropTarget={dropTarget}
|
||||
draggingCategoryId={draggingCategoryId}
|
||||
categoryDropTarget={categoryDropTarget}
|
||||
textContent={textContent}
|
||||
openDescriptions={openDescriptions}
|
||||
openTaskSettings={openTaskSettings}
|
||||
prerequisiteNoticeTaskIds={prerequisiteNoticeTaskIds}
|
||||
onDragStart={onDragStart}
|
||||
onCategoryDragStart={onCategoryDragStart}
|
||||
onToggleDescription={onToggleDescription}
|
||||
onToggleSettings={onToggleSettings}
|
||||
onPrerequisiteNotice={onPrerequisiteNotice}
|
||||
onUpdateTask={onUpdateTask}
|
||||
onDeleteTask={onDeleteTask}
|
||||
onAddLinkTarget={onAddLinkTarget}
|
||||
onRemoveLinkTarget={onRemoveLinkTarget}
|
||||
onSetPrerequisite={onSetPrerequisite}
|
||||
onSetTaskCategory={onSetTaskCategory}
|
||||
onToggleCategoryCollapsed={onToggleCategoryCollapsed}
|
||||
visited={nextVisited}
|
||||
/>
|
||||
) : null;
|
||||
if (data.hideCompleted && task.checked) {
|
||||
if (!hasVisibleDescendants(task.id)) return null;
|
||||
return (
|
||||
<li className="task-planner-hidden-parent-children" key={`${task.id}:visible-children`}>
|
||||
<ul className="task-planner-list task-planner-child-list">{nestedBranch}</ul>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<TaskPlannerItem
|
||||
key={task.id}
|
||||
|
|
@ -591,34 +700,7 @@ function TaskPlannerBranch({
|
|||
onSetPrerequisite={onSetPrerequisite}
|
||||
onSetTaskCategory={onSetTaskCategory}
|
||||
>
|
||||
{nestedChildren.length ? (
|
||||
<TaskPlannerBranch
|
||||
parentId={task.id}
|
||||
parentMap={parentMap}
|
||||
tasks={tasks}
|
||||
data={data}
|
||||
draggingId={draggingId}
|
||||
dropTarget={dropTarget}
|
||||
draggingCategoryId={draggingCategoryId}
|
||||
categoryDropTarget={categoryDropTarget}
|
||||
textContent={textContent}
|
||||
openDescriptions={openDescriptions}
|
||||
openTaskSettings={openTaskSettings}
|
||||
prerequisiteNoticeTaskIds={prerequisiteNoticeTaskIds}
|
||||
onDragStart={onDragStart}
|
||||
onCategoryDragStart={onCategoryDragStart}
|
||||
onToggleDescription={onToggleDescription}
|
||||
onToggleSettings={onToggleSettings}
|
||||
onPrerequisiteNotice={onPrerequisiteNotice}
|
||||
onUpdateTask={onUpdateTask}
|
||||
onDeleteTask={onDeleteTask}
|
||||
onAddLinkTarget={onAddLinkTarget}
|
||||
onRemoveLinkTarget={onRemoveLinkTarget}
|
||||
onSetPrerequisite={onSetPrerequisite}
|
||||
onSetTaskCategory={onSetTaskCategory}
|
||||
visited={nextVisited}
|
||||
/>
|
||||
) : null}
|
||||
{nestedBranch}
|
||||
</TaskPlannerItem>
|
||||
);
|
||||
}
|
||||
|
|
@ -626,10 +708,15 @@ function TaskPlannerBranch({
|
|||
function renderCategory(group) {
|
||||
const groupTasks = group.tasks.filter((task) => !visited.has(task.id));
|
||||
if (!groupTasks.length) return null;
|
||||
if (data.hideCompleted && isTaskTreeComplete(groupTasks.map((task) => task.id), tasks, parentMap)) return null;
|
||||
const groupCount = countTaskTree(groupTasks.map((task) => task.id), tasks, parentMap);
|
||||
const groupCompletedCount = countCompletedTaskTree(groupTasks.map((task) => task.id), tasks, parentMap);
|
||||
const categoryId = getCategorySectionId(parentId, group.category);
|
||||
const isCollapsed = data.collapsedCategories.includes(group.category);
|
||||
const sectionClassName = [
|
||||
"task-planner-category-section",
|
||||
groupCompletedCount === groupCount ? "is-complete" : "",
|
||||
isCollapsed ? "is-collapsed" : "",
|
||||
draggingCategoryId === categoryId ? "is-dragging" : "",
|
||||
categoryDropTarget.id === categoryId || dropTarget.id === categoryId ? "is-drop-target" : "",
|
||||
(categoryDropTarget.id === categoryId && categoryDropTarget.placement === "after") || (dropTarget.id === categoryId && dropTarget.placement === "after") ? "drop-after" : ""
|
||||
|
|
@ -637,7 +724,7 @@ function TaskPlannerBranch({
|
|||
return (
|
||||
<li className={sectionClassName} key={`${parentId || "root"}:${group.category}`} data-parent-id={parentId} data-category={group.category}>
|
||||
<div className="checklist-section-header task-planner-category-header">
|
||||
<div>
|
||||
<div className="task-planner-category-title">
|
||||
<button
|
||||
className="task-planner-category-drag-handle"
|
||||
type="button"
|
||||
|
|
@ -649,11 +736,25 @@ function TaskPlannerBranch({
|
|||
</button>
|
||||
<h3>{group.category}</h3>
|
||||
</div>
|
||||
<span>{groupCount}</span>
|
||||
<div className="task-planner-category-actions">
|
||||
<span>{groupCompletedCount} / {groupCount}</span>
|
||||
<button
|
||||
className="checklist-section-collapse-button"
|
||||
type="button"
|
||||
onClick={() => onToggleCategoryCollapsed(group.category)}
|
||||
aria-expanded={!isCollapsed}
|
||||
title={isCollapsed ? textContent.showCategoryTitle || "Afficher cette catégorie" : textContent.hideCategoryTitle || "Réduire cette catégorie"}
|
||||
aria-label={isCollapsed ? textContent.showCategoryTitle || "Afficher cette catégorie" : textContent.hideCategoryTitle || "Réduire cette catégorie"}
|
||||
>
|
||||
<Icon name={isCollapsed ? "chevron-down" : "chevron-up"} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{!isCollapsed && (
|
||||
<ul className="task-planner-list">
|
||||
{groupTasks.map(renderTask)}
|
||||
{groupTasks.map(renderTask).filter(Boolean)}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,12 +384,17 @@ export function normalizeTaskPlannerData(data) {
|
|||
return normalized;
|
||||
});
|
||||
const taskIds = new Set(tasks.map((task) => task.id));
|
||||
const categoryOrder = normalizeTaskPlannerCategoryOrder(data?.categoryOrder, tasks);
|
||||
return {
|
||||
sortMode: TASK_SORT_MODES.has(data?.sortMode) ? data.sortMode : "manual",
|
||||
weeklyResetDay: normalizeWeekDay(data?.weeklyResetDay),
|
||||
resetTime: isClockTimeString(data?.resetTime) ? data.resetTime : DEFAULT_TASK_PLANNER_RESET_TIME,
|
||||
lastResetAt: normalizeTimestamp(data?.lastResetAt),
|
||||
categoryOrder: normalizeTaskPlannerCategoryOrder(data?.categoryOrder, tasks),
|
||||
hideCompleted: data?.hideCompleted === true,
|
||||
collapsedCategories: (Array.isArray(data?.collapsedCategories) ? data.collapsedCategories : [])
|
||||
.map((category) => String(category || "").trim())
|
||||
.filter((category, index, categories) => category && categoryOrder.includes(category) && categories.indexOf(category) === index),
|
||||
categoryOrder,
|
||||
tasks,
|
||||
relations: relations.filter((relation) => taskIds.has(relation.fromTaskId) && taskIds.has(relation.toTaskId))
|
||||
};
|
||||
|
|
@ -535,6 +540,8 @@ export function compactModuleDataForStorage(type, value) {
|
|||
if (normalized.weeklyResetDay !== DEFAULT_TASK_PLANNER_WEEKLY_RESET_DAY) compact.weeklyResetDay = normalized.weeklyResetDay;
|
||||
if (normalized.resetTime !== DEFAULT_TASK_PLANNER_RESET_TIME) compact.resetTime = normalized.resetTime;
|
||||
if (normalized.lastResetAt) compact.lastResetAt = normalized.lastResetAt;
|
||||
if (normalized.hideCompleted) compact.hideCompleted = true;
|
||||
if (normalized.collapsedCategories.length) compact.collapsedCategories = normalized.collapsedCategories;
|
||||
if (normalized.tasks.length) {
|
||||
compact.tasks = normalized.tasks.map((task) => {
|
||||
const compactTask = {
|
||||
|
|
|
|||
|
|
@ -1235,10 +1235,26 @@ textarea:focus {
|
|||
height: 16px;
|
||||
}
|
||||
|
||||
.task-planner-clear-completed-button {
|
||||
display: inline-flex;
|
||||
min-height: 38px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 0 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.task-planner-clear-completed-button .ui-icon {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.task-planner-settings {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(130px, 1fr) minmax(110px, 0.72fr);
|
||||
gap: 10px;
|
||||
align-items: end;
|
||||
padding: 12px;
|
||||
border: 1px solid rgba(165, 180, 252, 0.12);
|
||||
border-radius: var(--radius-md);
|
||||
|
|
@ -1247,6 +1263,12 @@ textarea:focus {
|
|||
rgba(7, 10, 24, 0.34);
|
||||
}
|
||||
|
||||
.task-planner-settings-actions {
|
||||
display: flex;
|
||||
grid-column: 1 / -1;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.task-planner-settings label,
|
||||
.task-planner-weekly-override {
|
||||
display: grid;
|
||||
|
|
@ -1318,7 +1340,18 @@ textarea:focus {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.task-planner-child-list > .task-planner-item::before {
|
||||
.task-planner-hidden-parent-children {
|
||||
position: relative;
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.task-planner-hidden-parent-children > .task-planner-child-list {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.task-planner-child-list > .task-planner-item::before,
|
||||
.task-planner-child-list > .task-planner-hidden-parent-children::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
|
|
@ -1351,7 +1384,7 @@ textarea:focus {
|
|||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.task-planner-category-header > div {
|
||||
.task-planner-category-title {
|
||||
display: inline-flex;
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
|
|
@ -1359,6 +1392,13 @@ textarea:focus {
|
|||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-planner-category-actions {
|
||||
display: inline-flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.task-planner-category-header h3 {
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
|
|
@ -1369,7 +1409,7 @@ textarea:focus {
|
|||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.task-planner-category-header > span {
|
||||
.task-planner-category-actions > span {
|
||||
flex: 0 0 auto;
|
||||
padding: 3px 9px;
|
||||
border: 1px solid rgba(246, 196, 83, 0.22);
|
||||
|
|
@ -1380,6 +1420,11 @@ textarea:focus {
|
|||
font-weight: 800;
|
||||
}
|
||||
|
||||
.task-planner-category-section.is-complete .task-planner-category-header h3 {
|
||||
color: var(--color-text-muted);
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.task-planner-category-section.is-dragging {
|
||||
cursor: grabbing;
|
||||
opacity: 0.58;
|
||||
|
|
@ -2426,6 +2471,7 @@ textarea:focus {
|
|||
.tool-split-entry > button.danger,
|
||||
.counter-actions button.danger,
|
||||
.link-item button.danger,
|
||||
.task-planner-clear-completed-button.danger,
|
||||
.task-planner-delete-button.danger {
|
||||
border-color: rgba(251, 113, 133, 0.2);
|
||||
background: rgba(21, 26, 48, 0.88);
|
||||
|
|
@ -2436,6 +2482,7 @@ textarea:focus {
|
|||
.tool-split-entry > button.danger:hover,
|
||||
.counter-actions button.danger:hover,
|
||||
.link-item button.danger:hover,
|
||||
.task-planner-clear-completed-button.danger:hover:not(:disabled),
|
||||
.task-planner-delete-button.danger:hover {
|
||||
border-color: rgba(251, 113, 133, 0.56);
|
||||
background:
|
||||
|
|
@ -2451,6 +2498,7 @@ textarea:focus {
|
|||
.tool-split-entry > button.danger:hover .ui-icon,
|
||||
.counter-actions button.danger:hover .ui-icon,
|
||||
.link-item button.danger:hover .ui-icon,
|
||||
.task-planner-clear-completed-button.danger:hover .ui-icon,
|
||||
.task-planner-delete-button.danger:hover .ui-icon {
|
||||
background-color: #fff;
|
||||
filter: drop-shadow(0 0 6px rgba(251, 113, 133, 0.26));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue