Crippled version of task display
This commit is contained in:
		
							parent
							
								
									5298dae17f
								
							
						
					
					
						commit
						6ec2234ef9
					
				
					 5 changed files with 100 additions and 20 deletions
				
			
		|  | @ -2,10 +2,19 @@ | |||
|   import Graph from "./Graph.svelte"; | ||||
|   import GraphNode from "./GraphNode.svelte"; | ||||
|   import { loadTasks } from "./task-loader"; | ||||
|   import type { TasksFile } from "./task-loader"; | ||||
|   import type { TasksFile, TaskDescriptor } from "./task-loader"; | ||||
|   import TasksLoader from "./TasksLoader.svelte"; | ||||
|   import TaskPanel from "./TaskPanel.svelte"; | ||||
| 
 | ||||
|   const tasksPromise: Promise<TasksFile> = loadTasks(); | ||||
| 
 | ||||
|   let selectedTask: string | null = null | ||||
|   let finalSelect: boolean = false | ||||
| 
 | ||||
|   function clickTask(e: CustomEvent<TaskDescriptor>) { | ||||
|     finalSelect = true | ||||
|   } | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
|  | @ -37,6 +46,7 @@ | |||
| </svg> | ||||
| --> | ||||
|   <TasksLoader promise={tasksPromise} let:data={t}> | ||||
|     <Graph tasks={t} /> | ||||
|     <TaskPanel bind:finalSelect={finalSelect} selectedTask={selectedTask} /> | ||||
|     <Graph tasks={t} bind:selectedTask={selectedTask} on:selectTask={clickTask} /> | ||||
|   </TasksLoader> | ||||
| </main> | ||||
|  |  | |||
|  | @ -1,15 +1,32 @@ | |||
| <script type="ts"> | ||||
|   import GraphNode from "./GraphNode.svelte"; | ||||
|   import GraphEdge from "./GraphEdge.svelte"; | ||||
|   import { onMount } from "svelte"; | ||||
|   import { createEventDispatcher, onMount } from "svelte"; | ||||
|   import * as d3 from "d3"; | ||||
|   import { createLinksFromTaskMap } from "./task-loader"; | ||||
|   import type { TasksFile } from "./task-loader"; | ||||
|   import type { TasksFile, TaskDescriptor } from "./task-loader"; | ||||
| 
 | ||||
|   const eventDispatcher = createEventDispatcher() | ||||
| 
 | ||||
|   export let tasks: TasksFile; | ||||
|   let nodes = tasks.tasks; | ||||
|   let edges = createLinksFromTaskMap(tasks); | ||||
| 
 | ||||
|   export let selectedTask: null | string = null | ||||
|   const nodeClick = (task: TaskDescriptor) => (e: CustomEvent<MouseEvent>) => { | ||||
|     selectedTask = task.id | ||||
|     eventDispatcher("selectTask", task) | ||||
|   } | ||||
| 
 | ||||
|   const nodeHover = (task: TaskDescriptor) => (hovering: CustomEvent<boolean>) => { | ||||
|     if (hovering.detail) { | ||||
|       selectedTask = task.id | ||||
|     } else { | ||||
|       if (selectedTask == task.id) | ||||
|         selectedTask = null | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Svelte automatically fills this with a reference | ||||
|   let container: HTMLElement; | ||||
| 
 | ||||
|  | @ -69,7 +86,7 @@ | |||
|          <GraphEdge {edge} /> | ||||
|       {/each} | ||||
|       {#each nodes as task} | ||||
|         <GraphNode {task} /> | ||||
|         <GraphNode {task} on:click={nodeClick(task)} on:hoveringChange={nodeHover(task)} /> | ||||
|       {/each} | ||||
|     </g> | ||||
|   </svg> | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| <script lang="ts"> | ||||
|   import { onMount } from "svelte"; | ||||
|   import { createEventDispatcher, onMount } from "svelte"; | ||||
| 
 | ||||
|   import type { TaskDescriptor } from "./task-loader"; | ||||
| 
 | ||||
|  | @ -7,15 +7,23 @@ | |||
|   let hovering: boolean = false; | ||||
|   let text_element: SVGTextElement; | ||||
| 
 | ||||
|   const eventDispatcher = createEventDispatcher() | ||||
| 
 | ||||
|   $: cx = task === undefined || task.x === undefined ? 0 : task.x; | ||||
|   $: cy = task === undefined || task.y === undefined ? 0 : task.y; | ||||
| 
 | ||||
|   function enter() { | ||||
|     hovering = true; | ||||
|     eventDispatcher("hoveringChange", hovering) | ||||
|   } | ||||
| 
 | ||||
|   function leave() { | ||||
|     hovering = false; | ||||
|     eventDispatcher("hoveringChange", hovering) | ||||
|   } | ||||
| 
 | ||||
|   function click(e: MouseEvent) { | ||||
|     eventDispatcher("click", e) | ||||
|   } | ||||
| 
 | ||||
|   let ellipse_rx = 20; | ||||
|  | @ -36,7 +44,7 @@ | |||
|   } | ||||
| </style> | ||||
| 
 | ||||
| <g on:mouseenter={enter} on:mouseleave={leave}> | ||||
| <g on:mouseenter={enter} on:mouseleave={leave} on:click={click}> | ||||
|   <ellipse rx={ellipse_rx} ry={ellipse_ry} {cx} {cy} /> | ||||
|   <text | ||||
|     bind:this={text_element} | ||||
|  |  | |||
							
								
								
									
										42
									
								
								frontend/src/TaskPanel.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								frontend/src/TaskPanel.svelte
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| <script lang="ts"> | ||||
|     import { grabAssignment } from "./ksp-task-grabber"; | ||||
|     import type { TasksFile, TaskDescriptor } from "./task-loader"; | ||||
| 
 | ||||
|     // export let tasks: TasksFile; | ||||
|     export let selectedTask: string | null = null | ||||
|     export let finalSelect: boolean = false | ||||
|     let mouse: boolean = false | ||||
| 
 | ||||
|     let height: string; | ||||
|     $: height = selectedTask == null && !mouse ? "0" : | ||||
|                 finalSelect ? "100%" : | ||||
|                 "100px" | ||||
| 
 | ||||
|     let taskPromise: Promise<string | null> | ||||
|     $: { | ||||
|         if (selectedTask != null) | ||||
|             taskPromise = grabAssignment(selectedTask) | ||||
|     } | ||||
| </script> | ||||
| 
 | ||||
| <style> | ||||
|     .panel { | ||||
|         position: absolute; | ||||
|         width: 100%; | ||||
|         background-color: #222; | ||||
|         overflow: hidden; | ||||
|     } | ||||
| </style> | ||||
| 
 | ||||
| <div class="panel" style="height: {height}" on:mouseover={() => mouse = false} on:mouseout={() => mouse = false}> | ||||
|     {#if selectedTask != null} | ||||
|     {#await taskPromise} | ||||
|         Načítám úložku {selectedTask} ;) | ||||
|     {:then task} | ||||
|         {@html task} | ||||
|     {/await} | ||||
|     <button type=button on:click={() => finalSelect = false}> | ||||
|         Zavřít | ||||
|     </button> | ||||
|     {/if} | ||||
| </div> | ||||
|  | @ -12,28 +12,28 @@ type TaskLocation = { | |||
|     startElement: string | ||||
| } | ||||
| 
 | ||||
| function getLocation(id: string, solution: boolean): TaskLocation { | ||||
| function getLocation(id: string, solution: boolean): TaskLocation | null { | ||||
|     const m = /^(\d+)-(Z?)(\d)-(\d)$/.exec(id) | ||||
|     if (!m) throw new Error(`Invalid task id: ${m}`) | ||||
|     const [_, rocnik, z, serie, uloha] = m[1] | ||||
|     if (!m) return null | ||||
|     const [_, rocnik, z, serie, uloha] = m | ||||
|     if (z == 'Z') { | ||||
|         const urlX = solution ? "reseni" : "zadani" | ||||
|         return { | ||||
|             url: `z/ulohy/${rocnik}/${urlX}${serie}.html`, | ||||
|             startElement: `task${uloha}` | ||||
|             startElement: `task-${id}` | ||||
|         } | ||||
|     } else { | ||||
|         const urlX = solution ? "solution" : "tasks" | ||||
|         return { | ||||
|             url: `tasks/${rocnik}/${urlX}${serie}.html`, | ||||
|             startElement: `task${uloha}` | ||||
|             startElement: `task-${id}` | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function parseTask(startElementId: string, html: string, contentType: string): string { | ||||
| function parseTask(startElementId: string, html: string): string { | ||||
|     const parser = new DOMParser() | ||||
|     const doc = parser.parseFromString(html, contentType as any) | ||||
|     const doc = parser.parseFromString(html, "text/html") | ||||
| 
 | ||||
|     const titleElement = doc.getElementById(startElementId) | ||||
|     if (!titleElement) | ||||
|  | @ -69,14 +69,17 @@ async function loadTask({ url, startElement }: TaskLocation) { | |||
|         throw Error("Bad request") | ||||
|     } | ||||
|     const rText = await r.text() | ||||
|     const contentType = r.headers.get("Content-Type") || "text/html" | ||||
|     return parseTask(startElement, rText, contentType) | ||||
|     return parseTask(startElement, rText) | ||||
| } | ||||
| 
 | ||||
| export function loadAssignment(id: string) { | ||||
|     return loadTask(getLocation(id, false)) | ||||
| export async function grabAssignment(id: string) { | ||||
|     const l = getLocation(id, false) | ||||
|     if (!l) return "úloha je virtuální a neexistuje" | ||||
|     return await loadTask(l) | ||||
| } | ||||
| 
 | ||||
| export function loadSolution(id: string) { | ||||
|     return loadTask(getLocation(id, true)) | ||||
| export async function grabSolution(id: string) { | ||||
|     const l = getLocation(id, true) | ||||
|     if (!l) return "úloha je virtuální a neexistuje" | ||||
|     return await loadTask(l) | ||||
| } | ||||
|  |  | |||
		Reference in a new issue