Implement simple routing for TaskPanel #17

Manually merged
exyi merged 2 commits from exyi/task-url-routing into master 2020-09-29 21:31:26 +02:00
2 changed files with 38 additions and 18 deletions

View file

@ -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>

View file

@ -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>