Browse Source

Changed the styles of the visualization page, moved the settings

master
Nuša Pukšič 11 months ago
parent
commit
1df1da95ce
  1. 10
      src/app.css
  2. 6
      src/lib/components/EventLimitControl.svelte
  3. 6
      src/lib/components/EventRenderLevelLimit.svelte
  4. 119
      src/lib/navigator/EventNetwork/Legend.svelte
  5. 52
      src/lib/navigator/EventNetwork/Settings.svelte
  6. 38
      src/lib/navigator/EventNetwork/index.svelte
  7. 55
      src/routes/visualize/+page.svelte
  8. 13
      src/styles/visualize.css

10
src/app.css

@ -206,8 +206,9 @@ @@ -206,8 +206,9 @@
@layer components {
/* Legend */
.leather-legend {
@apply flex-shrink-0 p-4 bg-primary-0 dark:bg-primary-1000 rounded-lg shadow
border border-gray-200 dark:border-gray-800;
@apply relative m-4 sm:m-0 sm:absolute sm:top-1 sm:left-1 flex-shrink-0 p-2 rounded;
@apply shadow-none text-primary-1000 border border-s-4 bg-highlight border-primary-200 has-[:hover]:border-primary-700;
@apply dark:bg-primary-1000 dark:border-primary-800 dark:has-[:hover]:bg-primary-950 dark:has-[:hover]:border-primary-500;
}
/* Tooltip */
@ -219,8 +220,7 @@ @@ -219,8 +220,7 @@
z-index: 1000;
}
/* Heading for leather components */
h3.h-leather {
@apply text-gray-800 dark:text-gray-200 text-lg font-bold mb-2;
.leather-legend button {
@apply dark:text-white;
}
}

6
src/lib/components/EventLimitControl.svelte

@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
</script>
<div class="flex items-center gap-2 mb-4">
<label for="event-limit" class="text-sm font-medium"
<label for="event-limit" class="leather bg-transparent text-sm font-medium"
>Number of root events:
</label>
<input
@ -38,14 +38,14 @@ @@ -38,14 +38,14 @@
id="event-limit"
min="1"
max="50"
class="w-20 bg-primary-0 dark:bg-primary-1000 border border-gray-300 dark:border-gray-700 rounded-md px-2 py-1"
class="w-20 bg-primary-0 dark:bg-primary-1000 border border-gray-300 dark:border-gray-700 rounded-md px-2 py-1 dark:text-white"
bind:value={inputValue}
on:input={handleInput}
on:keydown={handleKeyDown}
/>
<button
on:click={handleUpdate}
class="px-3 py-1 bg-primary-0 dark:bg-primary-1000 border border-gray-300 dark:border-gray-700 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
class="btn-leather px-3 py-1 bg-primary-0 dark:bg-primary-1000 border border-gray-300 dark:border-gray-700 rounded-md hover:bg-gray-100 dark:hover:bg-gray-800"
>
Update
</button>

6
src/lib/components/EventRenderLevelLimit.svelte

@ -29,16 +29,16 @@ @@ -29,16 +29,16 @@
</script>
<div class="flex items-center gap-2 mb-4">
<label for="levels-to-render" class="text-sm font-medium"
<label for="levels-to-render" class="leather bg-transparent text-sm font-medium"
>Levels to render:
</label>
<label for="event-limit" class="text-sm font-medium">Limit: </label>
<label for="event-limit" class="leather bg-transparent text-sm font-medium">Limit: </label>
<input
type="number"
id="levels-to-render"
min="1"
max="50"
class="w-20 bg-primary-0 dark:bg-primary-1000 border border-gray-300 dark:border-gray-700 rounded-md px-2 py-1"
class="w-20 bg-primary-0 dark:bg-primary-1000 border border-gray-300 dark:border-gray-700 rounded-md px-2 py-1 dark:text-white"
bind:value={inputValue}
oninput={handleInput}
onkeydown={handleKeyDown}

119
src/lib/navigator/EventNetwork/Legend.svelte

@ -1,52 +1,75 @@ @@ -1,52 +1,75 @@
<!--
Legend Component
Displays a legend explaining the different node and link types in the
event network visualization.
-->
<!-- Legend Component (Svelte 5, Runes Mode) -->
<script lang="ts">
// Optional class name to apply to the legend container
export let className: string = "";
import {Button} from 'flowbite-svelte';
import { CaretDownOutline, CaretUpOutline } from "flowbite-svelte-icons";
let {
collapsedOnInteraction = false,
className = ""
} = $props<{collapsedOnInteraction: boolean, className: string}>();
let expanded = $state(true);
$effect(() => {
if (collapsedOnInteraction) {
expanded = false;
}
});
function toggle() {
expanded = !expanded;
}
</script>
<div class="leather-legend {className}">
<h3 class="h-leather">Legend</h3>
<ul class="legend-list">
<!-- Index event node -->
<li class="legend-item">
<div class="legend-icon">
<span
class="legend-circle"
style="background-color: hsl(200, 70%, 75%)"
>
<span class="legend-letter">I</span>
</span>
</div>
<span class="legend-text">Index events (kind 30040) - Each with a unique pastel color</span>
</li>
<!-- Content event node -->
<li class="legend-item">
<div class="legend-icon">
<span class="legend-circle content">
<span class="legend-letter">C</span>
</span>
</div>
<span class="legend-text">Content events (kinds 30041, 30818) - Publication sections</span>
</li>
<!-- Link arrow -->
<li class="legend-item">
<svg class="w-6 h-6 mr-2" viewBox="0 0 24 24">
<path
d="M4 12h16M16 6l6 6-6 6"
class="network-link-leather"
stroke-width="2"
fill="none"
/>
</svg>
<span class="legend-text">Arrows indicate reading/sequence order</span>
</li>
</ul>
</div>
<div class={`leather-legend ${className}`}>
<div class="flex items-center justify-between space-x-3">
<h3 class="h-leather">Legend</h3>
<Button color='none' outline size='xs' onclick={toggle} class="rounded-full" >
{#if expanded}
<CaretUpOutline />
{:else}
<CaretDownOutline />
{/if}
</Button>
</div>
{#if expanded}
<ul class="legend-list">
<!-- Index event node -->
<li class="legend-item">
<div class="legend-icon">
<span
class="legend-circle"
style="background-color: hsl(200, 70%, 75%)"
>
<span class="legend-letter">I</span>
</span>
</div>
<span class="legend-text">Index events (kind 30040) - Each with a unique pastel color</span>
</li>
<!-- Content event node -->
<li class="legend-item">
<div class="legend-icon">
<span class="legend-circle content">
<span class="legend-letter">C</span>
</span>
</div>
<span class="legend-text">Content events (kinds 30041, 30818) - Publication sections</span>
</li>
<!-- Link arrow -->
<li class="legend-item">
<svg class="w-6 h-6 mr-2" viewBox="0 0 24 24">
<path
d="M4 12h16M16 6l6 6-6 6"
class="network-link-leather"
stroke-width="2"
fill="none"
/>
</svg>
<span class="legend-text">Arrows indicate reading/sequence order</span>
</li>
</ul>
{/if}
</div>

52
src/lib/navigator/EventNetwork/Settings.svelte

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
<!--
Settings Component
-->
<script lang="ts">
import {Button} from 'flowbite-svelte';
import { CaretDownOutline, CaretUpOutline } from "flowbite-svelte-icons";
import { fly } from "svelte/transition";
import { quintOut } from "svelte/easing";
import EventLimitControl from "$lib/components/EventLimitControl.svelte";
import EventRenderLevelLimit from "$lib/components/EventRenderLevelLimit.svelte";
import { networkFetchLimit } from "$lib/state";
let {
count = 0,
onupdate
} = $props<{count: number, onupdate: () => void}>();
let expanded = $state(false);
function toggle() {
expanded = !expanded;
}
/**
* Handles updates to visualization settings
*/
function handleLimitUpdate() {
onupdate();
}
</script>
<div class="leather-legend sm:!right-1 sm:!left-auto" >
<div class="flex items-center justify-between space-x-3">
<h3 class="h-leather">Settings</h3>
<Button color='none' outline size='xs' onclick={toggle} class="rounded-full" >
{#if expanded}
<CaretUpOutline />
{:else}
<CaretDownOutline />
{/if}
</Button>
</div>
{#if expanded}
<div class="space-y-4">
<span class="leather bg-transparent legend-text">
Showing {count} events from {$networkFetchLimit} headers
</span>
<EventLimitControl on:update={handleLimitUpdate} />
<EventRenderLevelLimit on:update={handleLimitUpdate} />
</div>
{/if}
</div>

38
src/lib/navigator/EventNetwork/index.svelte

@ -21,6 +21,8 @@ @@ -21,6 +21,8 @@
import Legend from "./Legend.svelte";
import NodeTooltip from "./NodeTooltip.svelte";
import type { NetworkNode, NetworkLink } from "./types";
import Settings from "./Settings.svelte";
import {Button} from 'flowbite-svelte';
// Type alias for D3 selections
type Selection = any;
@ -43,7 +45,7 @@ @@ -43,7 +45,7 @@
}
// Component props
let { events = [] } = $props<{ events?: NDKEvent[] }>();
let { events = [], onupdate } = $props<{ events?: NDKEvent[], onupdate: () => void }>();
// Error state
let errorMessage = $state<string | null>(null);
@ -498,6 +500,17 @@ @@ -498,6 +500,17 @@
);
}
}
/**
* Legend interactions
*/
let graphInteracted = $state(false);
function handleGraphClick() {
if (!graphInteracted) {
graphInteracted = true;
}
}
</script>
<div class="network-container">
@ -514,15 +527,23 @@ @@ -514,15 +527,23 @@
</div>
{/if}
<div class="network-svg-container" bind:this={container}>
<div class="network-svg-container" bind:this={container} role="figure">
<Legend collapsedOnInteraction={graphInteracted} className='' />
<!-- Settings Panel (shown when settings button is clicked) -->
<Settings count={events.length} onupdate={onupdate} />
<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<svg
bind:this={svg}
class="network-svg"
onclick={handleGraphClick}
/>
<!-- Zoom controls -->
<div class="network-controls">
<button
<Button outline size="lg"
class="network-control-button btn-leather rounded-lg p-2"
onclick={zoomIn}
aria-label="Zoom in"
@ -533,8 +554,8 @@ @@ -533,8 +554,8 @@
<line x1="11" y1="8" x2="11" y2="14"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
</svg>
</button>
<button
</Button>
<Button outline size="lg"
class="network-control-button btn-leather rounded-lg p-2"
onclick={zoomOut}
aria-label="Zoom out"
@ -544,8 +565,8 @@ @@ -544,8 +565,8 @@
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
<line x1="8" y1="11" x2="14" y2="11"></line>
</svg>
</button>
<button
</Button>
<Button outline size="lg"
class="network-control-button btn-leather rounded-lg p-2"
onclick={centerGraph}
aria-label="Center graph"
@ -554,7 +575,7 @@ @@ -554,7 +575,7 @@
<circle cx="12" cy="12" r="10"></circle>
<circle cx="12" cy="12" r="3"></circle>
</svg>
</button>
</Button>
</div>
</div>
@ -568,5 +589,4 @@ @@ -568,5 +589,4 @@
/>
{/if}
<Legend />
</div>

55
src/routes/visualize/+page.svelte

@ -10,13 +10,10 @@ @@ -10,13 +10,10 @@
import { ndkInstance } from "$lib/ndk";
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { filterValidIndexEvents } from "$lib/utils";
import EventLimitControl from "$lib/components/EventLimitControl.svelte";
import EventRenderLevelLimit from "$lib/components/EventRenderLevelLimit.svelte";
import { networkFetchLimit } from "$lib/state";
import { fly } from "svelte/transition";
import { quintOut } from "svelte/easing";
import { CogSolid } from "flowbite-svelte-icons";
import { Button } from "flowbite-svelte";
import Settings from "$lib/navigator/EventNetwork/Settings.svelte";
// Configuration
const DEBUG = false; // Set to true to enable debug logging
@ -110,12 +107,6 @@ @@ -110,12 +107,6 @@
}
}
/**
* Handles updates to visualization settings
*/
function handleLimitUpdate() {
fetchEvents();
}
// Fetch events when component mounts
onMount(() => {
@ -127,44 +118,8 @@ @@ -127,44 +118,8 @@
<div class="leather w-full p-4 relative">
<!-- Header with title and settings button -->
<div class="flex items-center mb-4">
<h1 class="h-leather text-2xl font-bold">Publication Network</h1>
<!-- Settings Button -->
{#if !loading && !error}
<Button
class="btn-leather z-10 rounded-lg min-w-[120px] ml-3"
on:click={() => (showSettings = !showSettings)}
>
<CogSolid class="mr-2 h-5 w-5" />
Settings
</Button>
{/if}
<h1 class="h-leather">Publication Network</h1>
</div>
<!-- Settings Panel (shown when settings button is clicked) -->
{#if !loading && !error && showSettings}
<div
class="absolute left-0 top-14 h-auto w-80 bg-white dark:bg-gray-800 p-4 shadow-lg z-10
overflow-y-auto max-h-[calc(100vh-96px)] rounded-lg border
border-gray-200 dark:border-gray-700"
transition:fly={{ duration: 300, y: -10, opacity: 1, easing: quintOut }}
>
<div class="card space-y-4">
<h2 class="text-xl font-bold mb-4 h-leather">
Visualization Settings
</h2>
<div class="space-y-4">
<span class="text-sm text-gray-600 dark:text-gray-400">
Showing {events.length} events from {$networkFetchLimit} headers
</span>
<EventLimitControl on:update={handleLimitUpdate} />
<EventRenderLevelLimit on:update={handleLimitUpdate} />
</div>
</div>
</div>
{/if}
<!-- Loading spinner -->
{#if loading}
<div class="flex justify-center items-center h-64">
@ -206,9 +161,7 @@ @@ -206,9 +161,7 @@
</div>
<!-- Network visualization -->
{:else}
<div class="relative">
<!-- Event network visualization -->
<EventNetwork {events} />
</div>
<!-- Event network visualization -->
<EventNetwork {events} onupdate={fetchEvents} />
{/if}
</div>

13
src/styles/visualize.css

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
@layer components {
/* Legend styles - specific to visualization */
.legend-list {
@apply list-disc pl-5 space-y-2 text-gray-800 dark:text-gray-300;
@apply list-disc mt-2 space-y-2 text-gray-800 dark:text-gray-300;
}
.legend-item {
@ -39,15 +39,16 @@ @@ -39,15 +39,16 @@
/* Network visualization styles - specific to visualization */
.network-container {
@apply flex flex-col w-full h-[calc(100vh-120px)] min-h-[400px] max-h-[900px] p-4 gap-4;
@apply flex flex-col w-full h-[calc(100vh-138px)] min-h-[400px] max-h-[900px];
}
.network-svg-container {
@apply relative;
@apply relative sm:h-[100%];
}
.network-svg {
@apply w-full h-full border border-gray-300 dark:border-gray-700 rounded;
@apply w-full sm:h-[100%] border;
@apply border border-primary-200 has-[:hover]:border-primary-700 dark:bg-primary-1000 dark:border-primary-800 dark:has-[:hover]:bg-primary-950 dark:has-[:hover]:border-primary-500 rounded;
}
.network-error {
@ -72,9 +73,7 @@ @@ -72,9 +73,7 @@
}
.network-control-button {
@apply bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-300
shadow-md hover:shadow-lg transition-shadow duration-200
border border-gray-300 dark:border-gray-700;
@apply bg-white;
}
/* Tooltip styles - specific to visualization tooltips */

Loading…
Cancel
Save