mirror of
https://github.com/poanse/obsidian-taskmap.git
synced 2026-07-22 14:00:24 +00:00
fixes
This commit is contained in:
parent
457e946288
commit
275ea93d21
9 changed files with 101 additions and 45 deletions
|
|
@ -78,14 +78,35 @@ export class Context {
|
|||
}
|
||||
|
||||
public isTaskBlocked(taskId: TaskId) {
|
||||
return this.projectData.blockerPairs.some((p) => p.blocked === taskId);
|
||||
if (this.projectData.getTask(taskId).status === StatusCode.DONE) {
|
||||
return false;
|
||||
}
|
||||
return this.projectData.blockerPairs
|
||||
.filter((p) => p.blocked === taskId)
|
||||
.some(
|
||||
(p) =>
|
||||
this.projectData.getTask(p.blocker).status !==
|
||||
StatusCode.DONE,
|
||||
);
|
||||
}
|
||||
|
||||
public isTaskBlocking(taskId: TaskId) {
|
||||
return this.projectData.blockerPairs.some((p) => p.blocker === taskId);
|
||||
if (this.projectData.getTask(taskId).status === StatusCode.DONE) {
|
||||
return false;
|
||||
}
|
||||
return this.projectData.blockerPairs
|
||||
.filter((p) => p.blocker === taskId)
|
||||
.some(
|
||||
(p) =>
|
||||
this.projectData.getTask(p.blocked).status !==
|
||||
StatusCode.DONE,
|
||||
);
|
||||
}
|
||||
|
||||
public isBlockerHighlighted = (taskId: TaskId) => {
|
||||
if (this.projectData.getTask(taskId).status === StatusCode.DONE) {
|
||||
return false;
|
||||
}
|
||||
if (this.chosenBlockedId !== NoTaskId) {
|
||||
return (
|
||||
this.chosenBlockedId === taskId ||
|
||||
|
|
@ -195,7 +216,6 @@ export class Context {
|
|||
|
||||
public startReparenting(taskId: TaskId) {
|
||||
this.reparentingTaskId = taskId;
|
||||
this.selectedTaskId = NoTaskId;
|
||||
}
|
||||
|
||||
public cancelReparenting() {
|
||||
|
|
@ -221,7 +241,6 @@ export class Context {
|
|||
}
|
||||
this.projectData.changeParent(this.reparentingTaskId, newParentId);
|
||||
this.updateTaskPositions();
|
||||
this.cancelReparenting();
|
||||
}
|
||||
|
||||
public changeFocusedTask(taskId: TaskId): void {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ export class ProjectData {
|
|||
depth: this.getTask(parentId).depth + 1,
|
||||
});
|
||||
this.curTaskId++;
|
||||
this.recalculateStatusRecursive(parentId);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
|
@ -73,14 +74,17 @@ export class ProjectData {
|
|||
t.parentId = parentTask.taskId;
|
||||
t.depth = parentTask.depth + 1;
|
||||
});
|
||||
this.recalcPriorities(this.getTask(id).parentId);
|
||||
this.recalcPriorities(task.parentId);
|
||||
this.recalculateStatusRecursive(task.parentId);
|
||||
}
|
||||
|
||||
public removeTaskBranch(id: number) {
|
||||
this.getDescendantIds(id).forEach(
|
||||
(taskId) => (this.getTask(taskId).deleted = true),
|
||||
);
|
||||
this.recalcPriorities(this.getTask(id).parentId);
|
||||
const parentId = this.getTask(id).parentId;
|
||||
this.recalcPriorities(parentId);
|
||||
this.recalculateStatusRecursive(parentId);
|
||||
}
|
||||
|
||||
public getDescendantIds(taskId: number, includeDeleted: boolean = false) {
|
||||
|
|
@ -161,10 +165,12 @@ export class ProjectData {
|
|||
this.recalculateStatusRecursive(task.parentId);
|
||||
}
|
||||
|
||||
public changeParent(taskId: TaskId, parentId: TaskId) {
|
||||
public changeParent(taskId: TaskId, newParentId: TaskId) {
|
||||
const taskData = this.getTask(taskId);
|
||||
taskData.parentId = parentId;
|
||||
this.recalculateStatusRecursive(parentId);
|
||||
const oldParentId = taskData.parentId;
|
||||
taskData.parentId = newParentId;
|
||||
this.recalculateStatusRecursive(oldParentId);
|
||||
this.recalculateStatusRecursive(newParentId);
|
||||
[taskId, ...this.getDescendantIds(taskId)].forEach((taskId) => {
|
||||
const task = this.getTask(taskId);
|
||||
task.depth = this.getTask(task.parentId).depth + 1;
|
||||
|
|
@ -185,6 +191,9 @@ export class ProjectData {
|
|||
|
||||
public calculateStatus(taskId: TaskId) {
|
||||
const children = this.getChildren(taskId).map((x) => this.getTask(x));
|
||||
if (children.length === 0) {
|
||||
return this.getTask(taskId).status;
|
||||
}
|
||||
const counts = [0, 0, 0, 0];
|
||||
children.forEach((t) => (counts[t.status] += 1));
|
||||
if (counts[StatusCode.DONE] == children.length) {
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ export function getTooltipText(code: IconCode) {
|
|||
return "Add blocker task";
|
||||
case IconCode.LOCK:
|
||||
return "Block another task";
|
||||
case IconCode.REMOVE:
|
||||
case IconCode.REMOVE_SUBMENU:
|
||||
return "Remove";
|
||||
case IconCode.REMOVE_SINGLE:
|
||||
return "Remove single task";
|
||||
case IconCode.REMOVE_MULTIPLE:
|
||||
return "Remove task branch";
|
||||
case IconCode.STATUS:
|
||||
case IconCode.STATUS_SUBMENU:
|
||||
return "Status";
|
||||
case IconCode.STATUS_DRAFT:
|
||||
return "Draft";
|
||||
|
|
|
|||
|
|
@ -25,7 +25,13 @@
|
|||
let isPressedDown = $state(false);
|
||||
let isPressed = $derived(context.pressedButtonCode == iconCode);
|
||||
|
||||
const stateful = [IconCode.REMOVE, IconCode.STATUS, IconCode.KEY, IconCode.LOCK].contains(iconCode);
|
||||
const stateful = [
|
||||
IconCode.REMOVE_SUBMENU,
|
||||
IconCode.STATUS_SUBMENU,
|
||||
IconCode.KEY,
|
||||
IconCode.LOCK,
|
||||
IconCode.REPARENT
|
||||
].contains(iconCode);
|
||||
|
||||
function onpointerdown(event: MouseEvent) {
|
||||
isPressedDown = true;
|
||||
|
|
@ -41,6 +47,7 @@
|
|||
(context.isReparentingOn() && [IconCode.LOCK, IconCode.KEY].contains(iconCode))
|
||||
|| (context.chosenBlockerId !== NoTaskId && [IconCode.REPARENT].contains(iconCode))
|
||||
|| (context.chosenBlockedId !== NoTaskId && [IconCode.REPARENT].contains(iconCode))
|
||||
|| (iconCode === IconCode.STATUS_DONE && context.isTaskBlocked(context.selectedTaskId))
|
||||
);
|
||||
|
||||
function onpointerup(event: MouseEvent) {
|
||||
|
|
@ -88,7 +95,7 @@
|
|||
let classString = $derived(`
|
||||
${(isPressed && !isButtonDisabled) ? 'is-pressed-up ': ''}
|
||||
${(isPressedDown && !isButtonDisabled) ? 'is-pressed-down ': '' }
|
||||
${iconCode === IconCode.STATUS ? classStringFromStatusCode(context.toolbarStatus) + ' ': ""}
|
||||
${iconCode === IconCode.STATUS_SUBMENU ? classStringFromStatusCode(context.toolbarStatus) + ' ': ""}
|
||||
`);
|
||||
</script>
|
||||
|
||||
|
|
@ -116,10 +123,10 @@
|
|||
<path d="M2.56174 6.15378V3.84616C2.56174 3.07296 3.18893 2.44577 3.96213 2.44577H4.80881V3.24655H3.96213C3.63076 3.24655 3.36252 3.51479 3.36252 3.84616V6.15378C3.36252 6.48515 3.63076 6.75436 3.96213 6.75436H4.80881V7.55417H3.96213C3.18893 7.55417 2.56174 6.92698 2.56174 6.15378Z"/>
|
||||
<path d="M2.96191 4.59954V5.40033H0.5V4.59954H2.96191Z"/>
|
||||
</svg>
|
||||
{:else if iconCode === IconCode.REMOVE}
|
||||
{:else if iconCode === IconCode.REMOVE_SUBMENU}
|
||||
<Trash2 class={classString}/>
|
||||
{:else if iconCode === IconCode.KEY}
|
||||
<KeyRound class={classString}/>
|
||||
<KeyRound class={classString} style="transform: rotate(-90deg) scale(-1, 1);"/>
|
||||
{:else if iconCode === IconCode.LOCK}
|
||||
<LockKeyhole class={classString}/>
|
||||
{:else if iconCode === IconCode.REPARENT}
|
||||
|
|
@ -128,7 +135,7 @@
|
|||
<LocateFixed class={classString + " focus"}/>
|
||||
{:else if iconCode === IconCode.CREATE_LINKED_NOTE}
|
||||
<SquareArrowOutUpRight class={classString}/>
|
||||
{:else if iconCode === IconCode.STATUS}
|
||||
{:else if iconCode === IconCode.STATUS_SUBMENU}
|
||||
<Circle class={classString}/>
|
||||
{:else if iconCode === IconCode.STATUS_DRAFT}
|
||||
<Circle class={classString + " draft"}/>
|
||||
|
|
@ -202,6 +209,9 @@
|
|||
:global(svg) {
|
||||
stroke: grey;
|
||||
}
|
||||
:global(svg.done) {
|
||||
stroke: color-mix(in srgb, #30623E 100%, #000000 50%);
|
||||
}
|
||||
}
|
||||
|
||||
.button:hover:not(.disabled){
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
let midX = $derived(
|
||||
isBlockerConnection
|
||||
? (context.chosenBlockerId !== NoTaskId
|
||||
? endPoint.x + (isStartTaskDepthLE(startTaskId, endTaskId) ? -1 : 1) * (ParentToChildHorizontalShift - TASK_SIZE.width) / 2
|
||||
? endPoint.x + (isStartTaskDepthLE(endTaskId, startTaskId) ? 1 : -1) * (ParentToChildHorizontalShift - TASK_SIZE.width) / 2
|
||||
: startPoint.x + (isStartTaskDepthLE(startTaskId, endTaskId) ? 1 : -1) * (ParentToChildHorizontalShift - TASK_SIZE.width) / 2
|
||||
)
|
||||
: (startPoint.x + endPoint.x) / 2
|
||||
|
|
|
|||
|
|
@ -156,21 +156,24 @@
|
|||
&& !(context.chosenBlockerId !== NoTaskId)}
|
||||
<HideBranchButton {context} {taskId} />
|
||||
{/if}
|
||||
{#if context.isTaskBlocking(taskId) && taskData.status !== StatusCode.DONE}
|
||||
{#if context.isTaskBlocking(taskId)}
|
||||
<div
|
||||
class="icon-container"
|
||||
style="
|
||||
top: 4px;
|
||||
"
|
||||
>
|
||||
<KeyRound class={
|
||||
classStringFromStatusCode(taskData.status)
|
||||
+ (isBlockerHighlight ? ' blocker-highlight' : '')
|
||||
+ (isUnselected ? ' unselect' : '')
|
||||
}/>
|
||||
<KeyRound
|
||||
class={
|
||||
classStringFromStatusCode(taskData.status)
|
||||
+ (isBlockerHighlight ? ' blocker-highlight' : '')
|
||||
+ (isUnselected ? ' unselect' : '')
|
||||
}
|
||||
style="transform: rotate(-90deg) scale(-1, 1);"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if context.isTaskBlocked(taskId) && taskData.status !== StatusCode.DONE}
|
||||
{#if context.isTaskBlocked(taskId)}
|
||||
<div
|
||||
class="icon-container"
|
||||
style="
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
import Task from "./Task.svelte";
|
||||
import Panzoom, {type PanzoomObject} from '@panzoom/panzoom'
|
||||
import type {Context} from "../Context.svelte.js";
|
||||
import {MouseDown, type Vector2} from "../types";
|
||||
import {MouseDown, StatusCode, type Vector2} from "../types";
|
||||
import Connection from "./Connection.svelte";
|
||||
import {NoTaskId, RootTaskId} from "../NodePositionsCalculator";
|
||||
import {DraggingManager} from "../DraggingManager.svelte";
|
||||
|
|
@ -160,10 +160,34 @@
|
|||
isBlockerConnection={false}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<div
|
||||
class="task-layer"
|
||||
tabindex="-1"
|
||||
role="presentation"
|
||||
>
|
||||
{#each context.projectData.tasks.filter(t => !context.isTaskHidden(t.taskId)) as task (task.taskId)}
|
||||
<Task taskId={task.taskId} {context} coords={context.getCurrentTaskPosition(task.taskId)}/>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<svg class="svg-layer" overflow="visible">
|
||||
<defs>
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="5" markerHeight="10" refX="3" refY="3" orient="auto" markerUnits="strokeWidth">
|
||||
<path d="M-1,0 L-1,6 L4.5,3 z" fill="context-stroke" />
|
||||
</marker>
|
||||
</defs>
|
||||
</defs>
|
||||
<g class="svg-group" bind:this={svgGroupEl}>
|
||||
{#if context.chosenBlockerId !== NoTaskId || context.chosenBlockedId !== NoTaskId}
|
||||
{#each (context.projectData.blockerPairs.filter(
|
||||
p => p.blocker === context.chosenBlockerId || p.blocked === context.chosenBlockedId
|
||||
).filter(
|
||||
p => context.projectData.getTask(p.blocked).status !== StatusCode.DONE
|
||||
&& context.projectData.getTask(p.blocker).status !== StatusCode.DONE
|
||||
)) as pair}
|
||||
<Connection
|
||||
startTaskId={pair.blocker}
|
||||
|
|
@ -175,16 +199,7 @@
|
|||
{/if}
|
||||
</g>
|
||||
</svg>
|
||||
<div
|
||||
class="task-layer"
|
||||
tabindex="-1"
|
||||
role="presentation"
|
||||
>
|
||||
{#each context.projectData.tasks.filter(t => !context.isTaskHidden(t.taskId)) as task (task.taskId)}
|
||||
<Task taskId={task.taskId} {context} coords={context.getCurrentTaskPosition(task.taskId)}/>
|
||||
{/each}
|
||||
|
||||
</div>
|
||||
|
||||
{#if context.selectedTaskId !== -1}
|
||||
{#key context.selectedTaskId}
|
||||
<Toolbar context={context} taskId={context.selectedTaskId}/>
|
||||
|
|
|
|||
|
|
@ -33,16 +33,16 @@
|
|||
let toolbarButtons = $derived(taskId == RootTaskId ? [
|
||||
IconCode.CREATE_LINKED_NOTE,
|
||||
IconCode.FOCUS,
|
||||
IconCode.STATUS
|
||||
IconCode.STATUS_SUBMENU
|
||||
|
||||
] : [
|
||||
IconCode.CREATE_LINKED_NOTE,
|
||||
IconCode.REMOVE,
|
||||
IconCode.REMOVE_SUBMENU,
|
||||
IconCode.REPARENT,
|
||||
IconCode.KEY,
|
||||
IconCode.LOCK,
|
||||
IconCode.FOCUS,
|
||||
IconCode.STATUS
|
||||
IconCode.STATUS_SUBMENU
|
||||
]);
|
||||
|
||||
let removeButtons = [
|
||||
|
|
@ -86,13 +86,13 @@
|
|||
{/each}
|
||||
{/key}
|
||||
|
||||
{#if context.pressedButtonCode === IconCode.REMOVE}
|
||||
{#if context.pressedButtonCode === IconCode.REMOVE_SUBMENU}
|
||||
<div
|
||||
class="subtoolbar"
|
||||
transition:slideCustom={{ duration: 300, easing: quintOut, axis: '-y' }}
|
||||
style="
|
||||
top: {subtoolbarTopShift(removeButtons)}px;
|
||||
left: {toolbarButtons.indexOf(IconCode.REMOVE) * (BUTTON_SIZE + TOOLBAR_GAP) - 2}px;
|
||||
left: {toolbarButtons.indexOf(IconCode.REMOVE_SUBMENU) * (BUTTON_SIZE + TOOLBAR_GAP) - 2}px;
|
||||
"
|
||||
>
|
||||
{#key context.updateOnZoomCounter}
|
||||
|
|
@ -102,13 +102,13 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
{#if context.pressedButtonCode === IconCode.STATUS}
|
||||
{#if context.pressedButtonCode === IconCode.STATUS_SUBMENU}
|
||||
<div
|
||||
class="subtoolbar"
|
||||
transition:slideCustom={{ duration: 300, easing: quintOut, axis: '-y' }}
|
||||
style="
|
||||
top: {subtoolbarTopShift(statusButtons)}px;
|
||||
left: {toolbarButtons.indexOf(IconCode.STATUS) * (BUTTON_SIZE + TOOLBAR_GAP) - 2}px;
|
||||
left: {toolbarButtons.indexOf(IconCode.STATUS_SUBMENU) * (BUTTON_SIZE + TOOLBAR_GAP) - 2}px;
|
||||
"
|
||||
>
|
||||
{#key context.updateOnZoomCounter}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import type { EasingFunction } from "svelte/transition";
|
||||
|
||||
export enum IconCode {
|
||||
REMOVE,
|
||||
REMOVE_SUBMENU,
|
||||
KEY,
|
||||
LOCK,
|
||||
FOCUS,
|
||||
REPARENT,
|
||||
CREATE_LINKED_NOTE,
|
||||
STATUS,
|
||||
STATUS_SUBMENU,
|
||||
REMOVE_SINGLE,
|
||||
REMOVE_MULTIPLE,
|
||||
STATUS_DRAFT,
|
||||
|
|
|
|||
Loading…
Reference in a new issue