Files
lit.ruv.wtf/website/index.html
Max Litruv Boonzaayer 40fd8e8e42 feat: Add blog post functionality with Markdown support
- Introduced BlogPostNode to render blog posts with metadata and content.
- Updated graph.json to include new blog post nodes.
- Enhanced MarkdownRenderer to support code block options for max height.
- Added CSS styles for improved code block scrolling and syntax highlighting.
- Created example blog posts: "Markdown Formatting Test", "Welcome to My Blog", and "Building Interactive Node Graphs".
- Implemented dynamic loading of blog data from blogs.json.
- Updated WorkspaceNavigator to allow smooth panning over blog nodes.
2026-04-19 09:09:53 +10:00

340 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Lit.ruv.wtf - Interactive Node Graph</title>
<meta name="description" content="Personal site of Lit.ruv.wtf. Graph editor edition">
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="16x16" href="logos/16px.png">
<link rel="icon" type="image/png" sizes="32x32" href="logos/32px.png">
<link rel="icon" type="image/png" sizes="48x48" href="logos/48px.png">
<link rel="icon" type="image/png" sizes="64x64" href="logos/64px.png">
<link rel="icon" type="image/png" sizes="128x128" href="logos/128px.png">
<link rel="icon" type="image/png" sizes="256x256" href="logos/256px.png">
<link rel="apple-touch-icon" sizes="180x180" href="logos/256px.png">
<!-- Open Graph / Social Media -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://lit.ruv.wtf/">
<meta property="og:title" content="Lit.ruv.wtf - Interactive Node Graph">
<meta property="og:description" content="Personal site of Lit.ruv.wtf. Graph editor edition">
<meta property="og:image" content="https://lit.ruv.wtf/banner.webp">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="https://lit.ruv.wtf/">
<meta name="twitter:title" content="Lit.ruv.wtf - Interactive Node Graph">
<meta name="twitter:description" content="Personal site of Lit.ruv.wtf. Graph editor edition">
<meta name="twitter:image" content="https://lit.ruv.wtf/banner.webp">
<link rel="stylesheet" href="styles/main.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-typescript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-jsx.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-json.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-bash.min.js"></script>
<script src="https://unpkg.com/@lottiefiles/lottie-player@latest/dist/lottie-player.js"></script>
</head>
<body>
<div id="workspaceCanvas" class="workspace-canvas">
<nav class="quick-links">
<a href="/docs/" class="quick-link">docs</a>
<a href="https://github.com/litruv" target="_blank" rel="noopener" class="quick-link">github</a>
<a href="https://bsky.app/profile/lit.mates.dev" target="_blank" rel="noopener" class="quick-link">bluesky</a>
<a href="/materials" class="quick-link">materials</a>
</nav>
<svg id="connectionLayer" class="connection-layer"></svg>
<div id="worldLayer" class="world-layer">
<div id="nodeLayer" class="node-layer"></div>
</div>
<div class="hud">
<button id="resetViewBtn" class="hud-btn" title="Reset View">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
<polyline points="9 22 9 12 15 12 15 22"></polyline>
</svg>
</button>
<button id="draggableToggle" class="hud-btn-drag" title="Toggle Dragging">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 19l7-7 3 3-7 7-3-3z"></path>
<path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"></path>
<path d="M2 2l7.586 7.586"></path>
<circle cx="11" cy="11" r="2"></circle>
</svg>
<div class="hud-tooltip">
alt+click - disconnect pin
</div>
</button>
</div>
<div id="debugPanel" class="debug-panel collapsed">
<div class="debug-header">
<div class="debug-title">Debug</div>
<button class="debug-toggle-btn" title="Toggle debug panel" aria-label="Toggle debug panel">
<svg class="debug-eye-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path class="eye-visible" d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle class="eye-visible" cx="12" cy="12" r="3"></circle>
<path class="eye-hidden" d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" style="display: none;"></path>
<line class="eye-hidden" x1="1" y1="1" x2="23" y2="23" style="display: none;"></line>
</svg>
</button>
</div>
<div class="debug-row">
<span class="debug-label">Zoom</span>
<span class="debug-value debug-zoom">1.000</span>
</div>
<div class="debug-row">
<span class="debug-label">DPR</span>
<span class="debug-value debug-dpr">1.0</span>
</div>
<div class="debug-row">
<span class="debug-label">Viewport</span>
<span class="debug-value debug-viewport">0 × 0</span>
</div>
<div class="debug-row">
<span class="debug-label">Center</span>
<span class="debug-value debug-center">0.0, 0.0</span>
</div>
<div class="debug-row">
<span class="debug-label">Viewbox</span>
<span class="debug-value debug-viewbox"></span>
</div>
<div class="debug-row">
<span class="debug-label">NodeAnchor</span>
<span class="debug-value debug-anchor"></span>
</div>
<div class="debug-divider"></div>
<label class="debug-row debug-check-row">
<span class="debug-label">Draggable</span>
<input class="debug-draggable-cb" type="checkbox" />
</label>
<label class="debug-row debug-check-row">
<span class="debug-label">WorldBoxes</span>
<input class="debug-worldbox-cb" type="checkbox" />
</label>
<label class="debug-row debug-check-row">
<span class="debug-label">Viewbox</span>
<input class="debug-viewbox-cb" type="checkbox" />
</label>
<div class="debug-divider"></div>
<button class="debug-copy-json-btn" title="Copy current graph as JSON">Copy JSON</button>
<button class="debug-show-properties-btn" title="Open properties panel">Show Properties</button>
<div class="debug-row debug-active-row" hidden>
<span class="debug-label debug-active-label"></span>
<span class="debug-value debug-active-pos">0.0, 0.0</span>
<button class="debug-copy-btn" title="Copy graph.json">Copy graph</button>
</div>
<div class="debug-divider" id="debugNodeEditorDivider" hidden></div>
<div id="debugNodeEditor" class="debug-node-editor" hidden>
<div class="debug-subtitle">Node Editor</div>
<div class="debug-row">
<span class="debug-label">ID</span>
<input class="debug-input debug-node-id" type="text" readonly />
</div>
<div class="debug-row">
<span class="debug-label">Type</span>
<input class="debug-input debug-node-type" type="text" readonly />
</div>
<div class="debug-row">
<span class="debug-label">Title</span>
<input class="debug-input debug-node-title" type="text" />
</div>
<div class="debug-row">
<span class="debug-label">X</span>
<input class="debug-input debug-node-x" type="number" step="1" />
</div>
<div class="debug-row">
<span class="debug-label">Y</span>
<input class="debug-input debug-node-y" type="number" step="1" />
</div>
<div class="debug-row">
<span class="debug-label">Width</span>
<input class="debug-input debug-node-width" type="number" step="1" />
</div>
<div class="debug-subtitle">Inputs</div>
<div id="debugInputsList" class="debug-pins-list"></div>
<button class="debug-add-btn debug-add-input-btn">+ Add Input</button>
<div class="debug-subtitle">Outputs</div>
<div id="debugOutputsList" class="debug-pins-list"></div>
<button class="debug-add-btn debug-add-output-btn">+ Add Output</button>
</div>
</div>
</div>
<!-- Properties Editor Panel (Right Side) -->
<div id="propertiesPanel" class="properties-panel collapsed">
<button class="properties-panel-tab" title="Open properties panel" aria-label="Open properties panel">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="7" height="7"></rect>
<rect x="14" y="3" width="7" height="7"></rect>
<rect x="14" y="14" width="7" height="7"></rect>
<rect x="3" y="14" width="7" height="7"></rect>
</svg>
</button>
<div class="properties-header">
<h2 class="properties-title">Properties</h2>
<button class="properties-toggle-btn" title="Close properties panel" aria-label="Close properties panel">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="15 18 9 12 15 6"></polyline>
</svg>
</button>
</div>
<div class="properties-content">
<!-- Node Properties Section -->
<div id="nodePropertiesSection" class="properties-section" style="display: none;">
<div class="section-header">
<h3>Node</h3>
</div>
<div class="section-content">
<div class="prop-row">
<label class="prop-label">ID</label>
<input type="text" class="prop-input" id="propNodeId" readonly />
</div>
<div class="prop-row">
<label class="prop-label">Type</label>
<input type="text" class="prop-input" id="propNodeType" readonly />
</div>
<div class="prop-row">
<label class="prop-label">Title</label>
<input type="text" class="prop-input" id="propNodeTitle" />
</div>
<div class="prop-row">
<label class="prop-label">Position X</label>
<input type="number" class="prop-input" id="propNodeX" step="20" />
</div>
<div class="prop-row">
<label class="prop-label">Position Y</label>
<input type="number" class="prop-input" id="propNodeY" step="20" />
</div>
<div class="prop-row">
<label class="prop-label">Width</label>
<input type="number" class="prop-input" id="propNodeWidth" placeholder="Auto" />
</div>
</div>
</div>
<!-- Focus Options Section -->
<div id="focusOptionsSection" class="properties-section" style="display: none;">
<div class="section-header collapsible">
<h3>Focus Options</h3>
<button class="section-toggle"></button>
</div>
<div class="section-content">
<div class="prop-row">
<label class="prop-label">Duration (ms)</label>
<input type="number" class="prop-input" id="propFocusDuration" placeholder="550" />
</div>
<div class="prop-row">
<label class="prop-label">Anchor X</label>
<input type="number" class="prop-input" id="propFocusAnchorX" step="0.1" min="0" max="1" placeholder="0.5" />
</div>
<div class="prop-row">
<label class="prop-label">Anchor Y</label>
<input type="number" class="prop-input" id="propFocusAnchorY" step="0.1" min="0" max="1" placeholder="0.5" />
</div>
<div class="prop-divider"></div>
<h4 class="prop-subtitle">Default WorldBox</h4>
<div class="prop-row">
<label class="prop-label">Width</label>
<input type="number" class="prop-input" id="propWorldBoxWidth" placeholder="Auto" />
</div>
<div class="prop-row">
<label class="prop-label">Height</label>
<input type="number" class="prop-input" id="propWorldBoxHeight" placeholder="Auto" />
</div>
<div class="prop-divider"></div>
<h4 class="prop-subtitle">Responsive Breakpoints</h4>
<div id="breakpointsList" class="breakpoints-list"></div>
<button class="prop-btn-add" id="addBreakpointBtn">+ Add Breakpoint</button>
</div>
</div>
<!-- Graph Settings Section -->
<div id="graphSettingsSection" class="properties-section">
<div class="section-header collapsible">
<h3>Graph Settings</h3>
<button class="section-toggle"></button>
</div>
<div class="section-content">
<div class="prop-row">
<label class="prop-label">Draggable</label>
<input type="checkbox" class="prop-checkbox" id="propGraphDraggable" />
</div>
<div class="prop-row">
<label class="prop-label">Intro Duration (ms)</label>
<input type="number" class="prop-input" id="propIntroDuration" placeholder="700" />
</div>
<div class="prop-divider"></div>
<h4 class="prop-subtitle">Initial Viewport</h4>
<div class="prop-row">
<label class="prop-label">X</label>
<input type="number" class="prop-input" id="propInitViewX" />
</div>
<div class="prop-row">
<label class="prop-label">Y</label>
<input type="number" class="prop-input" id="propInitViewY" />
</div>
<div class="prop-row">
<label class="prop-label">Width</label>
<input type="number" class="prop-input" id="propInitViewWidth" />
</div>
<div class="prop-row">
<label class="prop-label">Height</label>
<input type="number" class="prop-input" id="propInitViewHeight" />
</div>
<div class="prop-divider"></div>
<button class="prop-btn-primary" id="applySettingsBtn">Apply Settings</button>
</div>
</div>
<!-- No Selection Message -->
<div id="noSelectionMessage" class="no-selection">
<p>Select a node to edit its properties</p>
</div>
</div>
</div>
<template id="nodeTemplate">
<article class="blueprint-node" draggable="false">
<header class="node-header">
<div class="node-title"></div>
</header>
<section class="node-io node-inputs"></section>
<section class="node-io node-outputs"></section>
</article>
</template>
<template id="pinTemplate">
<div class="pin" draggable="false">
<span class="pin-label"></span>
<span class="pin-handle" tabindex="-1"></span>
</div>
</template>
<!-- WorldBox Overlay Layer -->
<svg id="worldBoxLayer" class="worldbox-layer" style="display: none;"></svg>
<!-- Viewbox Overlay Layer -->
<svg id="viewboxLayer" class="viewbox-layer" style="display: none;"></svg>
<!-- JSON Editor Modal -->
<script type="module" src="scripts/main.js"></script>
</body>
</html>