Implement simple routing for TaskPanel #17
2 changed files with 38 additions and 18 deletions
|
@ -15,8 +15,9 @@ import type { detach } from "svelte/internal";
|
||||||
// react to hash changes
|
// react to hash changes
|
||||||
let hash = window.location.hash.substr(1);
|
let hash = window.location.hash.substr(1);
|
||||||
window.onhashchange = () => {
|
window.onhashchange = () => {
|
||||||
hash = window.location.hash.substr(1);
|
hash = window.location.hash.substr(1);
|
||||||
}
|
}
|
||||||
|
$: selectedTaskId = (/^task\/([^\/]*)/.exec(hash) || [null, null])[1]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -34,10 +35,10 @@ import type { detach } from "svelte/internal";
|
||||||
</TasksLoader>
|
</TasksLoader>
|
||||||
{:else}
|
{:else}
|
||||||
<TasksLoader promise={tasksPromise} let:data={t}>
|
<TasksLoader promise={tasksPromise} let:data={t}>
|
||||||
<TaskPanel bind:this={taskPanel} />
|
<TaskPanel tasks={t} bind:this={taskPanel} {selectedTaskId} />
|
||||||
<div style="height: 100%">
|
<div style="height: 100%">
|
||||||
<Graph tasks={t}
|
<Graph tasks={t}
|
||||||
on:selectTask={e => taskPanel.select(e.detail)}
|
on:selectTask={e => location.hash=`#task/${e.detail.id}`}
|
||||||
on:preSelectTask={e => taskPanel.preSelect(e.detail)}
|
on:preSelectTask={e => taskPanel.preSelect(e.detail)}
|
||||||
on:unPreSelectTask={e => taskPanel.unPreselect(e.detail)} />
|
on:unPreSelectTask={e => taskPanel.unPreselect(e.detail)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
import type { TasksFile, TaskDescriptor } from "./task-loader";
|
import type { TasksFile, TaskDescriptor } from "./task-loader";
|
||||||
import TaskDisplay from "./TaskDisplay.svelte";
|
import TaskDisplay from "./TaskDisplay.svelte";
|
||||||
|
|
||||||
// export let tasks: TasksFile;
|
export let tasks: TasksFile;
|
||||||
let selectedTask: TaskDescriptor | null = null
|
let selectedTask: TaskDescriptor | null = null
|
||||||
|
export let selectedTaskId: string | null = null
|
||||||
|
|
||||||
let heightClass: "collapsed" | "full" | "preview" = "collapsed"
|
let heightClass: "closed" | "collapsed" | "full" | "preview" = "collapsed"
|
||||||
|
|
||||||
export function preSelect(task: TaskDescriptor) {
|
export function preSelect(task: TaskDescriptor) {
|
||||||
if (heightClass != "full") {
|
if (heightClass != "full") {
|
||||||
|
@ -24,19 +25,30 @@ import TaskDisplay from "./TaskDisplay.svelte";
|
||||||
}, 10);
|
}, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function select(task: TaskDescriptor) {
|
$: {
|
||||||
selectedTask = task
|
if (selectedTaskId) {
|
||||||
heightClass = "full"
|
heightClass = "full"
|
||||||
|
selectedTask = tasks.tasks.find(t => t.id == selectedTaskId) ?? null
|
||||||
|
} else {
|
||||||
|
heightClass = "collapsed"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
heightClass = "collapsed"
|
location.hash = ""
|
||||||
|
heightClass = "closed"
|
||||||
window.setTimeout(() => window.scrollTo({
|
window.setTimeout(() => window.scrollTo({
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
}), 100)
|
}), 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleKeydown(e: KeyboardEvent) {
|
||||||
|
if (e.key === "Escape") {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -54,10 +66,15 @@ import TaskDisplay from "./TaskDisplay.svelte";
|
||||||
padding: 0 10px 10px 10px;
|
padding: 0 10px 10px 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Used when the panel is explicitly closed - collapsed would still show the hover preview */
|
||||||
|
.panel.closed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
/* Used when the panel is implicitly closed - it does not disappear when there is mouse over it */
|
||||||
.panel.collapsed:not(:hover) {
|
.panel.collapsed:not(:hover) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
/* Used when the user hovers over a node and we want to show that there is something - a small expandable preview */
|
||||||
.panel.preview, .panel:not(.full):hover {
|
.panel.preview, .panel:not(.full):hover {
|
||||||
height: 100px;
|
height: 100px;
|
||||||
}
|
}
|
||||||
|
@ -66,13 +83,13 @@ import TaskDisplay from "./TaskDisplay.svelte";
|
||||||
}
|
}
|
||||||
.closeButton {
|
.closeButton {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
color: white;
|
color: white;
|
||||||
background-color: red;
|
background-color: red;
|
||||||
border: 0;
|
border: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.closeButton::before {
|
.closeButton::before {
|
||||||
content: "X";
|
content: "X";
|
||||||
|
@ -80,8 +97,10 @@ import TaskDisplay from "./TaskDisplay.svelte";
|
||||||
.panel.full .closeButton { display: inherit }
|
.panel.full .closeButton { display: inherit }
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<svelte:window on:keydown={handleKeydown} />
|
||||||
|
|
||||||
<div class="panel {heightClass}"
|
<div class="panel {heightClass}"
|
||||||
on:click={() => selectedTask && select(selectedTask)}>
|
on:click={() => location.hash = `#task/${selectedTask?.id}`}>
|
||||||
<TaskDisplay taskId={selectedTask?.id} />
|
<TaskDisplay taskId={selectedTask?.id} />
|
||||||
<button type=button class="closeButton" on:click|stopPropagation={close}></button>
|
<button type=button class="closeButton" on:click|stopPropagation={close}></button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Reference in a new issue