/ src / components / notes / GraphModal.svelte
GraphModal.svelte
 1  <script lang="ts">
 2  import { onMount } from "svelte";
 3  
 4  interface Node {
 5  	id: string;
 6  	title: string;
 7  	category: string;
 8  	val: number;
 9  }
10  
11  interface Link {
12  	source: string;
13  	target: string;
14  }
15  
16  interface Props {
17  	nodes: Node[];
18  	links: Link[];
19  }
20  
21  let { nodes, links }: Props = $props();
22  
23  let isOpen = $state(false);
24  let modalRef: HTMLDivElement | undefined = $state(undefined);
25  
26  export function open() {
27  	isOpen = true;
28  	document.body.style.overflow = "hidden";
29  }
30  
31  export function close() {
32  	isOpen = false;
33  	document.body.style.overflow = "";
34  }
35  
36  function handleBackdropClick(e: MouseEvent) {
37  	if (e.target === modalRef) {
38  		close();
39  	}
40  }
41  
42  function handleKeydown(e: KeyboardEvent) {
43  	if (e.key === "Escape" && isOpen) {
44  		close();
45  	}
46  }
47  
48  onMount(() => {
49  	document.addEventListener("keydown", handleKeydown);
50  	return () => {
51  		document.removeEventListener("keydown", handleKeydown);
52  	};
53  });
54  </script>
55  
56  {#if isOpen}
57  	<!-- svelte-ignore a11y_click_events_have_key_events -->
58  	<!-- svelte-ignore a11y_no_static_element_interactions -->
59  	<div
60  		bind:this={modalRef}
61  		onclick={handleBackdropClick}
62  		class="fixed inset-0 z-50 bg-pink-950/30 backdrop-blur-sm flex items-center justify-center p-4"
63  	>
64  		<div
65  			class="w-full max-w-5xl h-[80vh] bg-white/95 rounded-2xl border border-dashed border-pink-200 shadow-2xl flex flex-col overflow-hidden"
66  			role="dialog"
67  			aria-modal="true"
68  			aria-labelledby="graph-modal-title"
69  		>
70  			<!-- Header -->
71  			<div class="flex items-center justify-between px-6 py-4 border-b border-dashed border-pink-200">
72  				<h2 id="graph-modal-title" class="font-display text-xl font-bold text-pink-950">
73  					Notes Graph
74  				</h2>
75  				<button
76  					onclick={close}
77  					class="p-2 rounded-lg text-pink-950/60 hover:text-pink-950 hover:bg-pink-100/50 transition-colors"
78  					aria-label="Close graph"
79  				>
80  					<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
81  						<path
82  							stroke-linecap="round"
83  							stroke-linejoin="round"
84  							stroke-width="2"
85  							d="M6 18L18 6M6 6l12 12"
86  						/>
87  					</svg>
88  				</button>
89  			</div>
90  
91  			<!-- Graph Container -->
92  			<div class="flex-1 relative">
93  				{#await import('./GraphView.svelte') then { default: GraphView }}
94  					<GraphView {nodes} {links} client:visible />
95  				{/await}
96  			</div>
97  		</div>
98  	</div>
99  {/if}