Files
hermes-wiki-static/docs/CUSTOMIZATIONS.md
T
agentandClaude 677a8dde4f Initial commit: hermes-wiki-viewer v0.2.0
Fork of DanielCheer/obsidian-web-viewer (MIT, 2026-04) with Lukas' first
additions for the Hermes Wiki workflow.

Additive customization layer (vault-custom.js) — keeps upstream-merge
trivial via a one-line script tag in vault.html.

Features added:
1. Current-page highlighting in 3D Graph — current node gold+glow,
   connected nodes light-blue, others dim to 20% opacity
2. Click-to-navigate on graph — Three.js raycaster triggers file load
3. Responsive layout — graph collapses below 1024px, tree below 768px
4. URL-based deep-linking via ?file=<path> query param
5. Server-side ?file= support in /api/vault/file/ endpoint

Modified files:
- server.py: +7 lines (Lukas-add: ?file= query param parsing)
- vault.html: +1 line (script tag for vault-custom.js)

New files:
- vault-custom.js: 11KB, all customizations in one place under HermesCustom namespace
- README.md: fork intro, quick start, customization guide
- CHANGELOG.md: Lukas-additions tracking
- docs/ARCHITECTURE.md: design rationale
- docs/CUSTOMIZATIONS.md: feature spec
- .gitignore: standard

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-16 15:17:16 +00:00

121 lines
5.5 KiB
Markdown
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.
# Customizations — Feature Spec
Each section describes one Lukas-feature: what it does, how it works, where the code lives, and known limitations.
## 1. Current-page highlighting in 3D Graph
**What:** When you open a file, the corresponding node in the 3D Graph becomes brighter and larger. Nodes that the open file links to (via `[[wikilinks]]`) also brighten. All other nodes dim.
**How:**
1. `HermesCustom.getCurrentFile()` reads the file path from `?file=` URL param (preferred) or tracks via the `loadFile()` hook
2. `HermesCustom.getConnectedFiles(currentFile)` looks up outgoing edges in the global graph data
3. `HermesCustom.highlightCurrentNode()` iterates `window.graphNodeObjects` (obv's Three.js node meshes) and adjusts `material.color`, `emissive`, `scale`, `opacity`
**Code:** `vault-custom.js`, methods under namespace `HermesCustom.*`.
**Materials used (Catppuccin palette, matches theme):**
- Current: `#FFD700` (gold) + emissive glow + 1.5x scale
- Connected: `#89b4fa` (light blue) + faint emissive + 1.1x scale
- Other: `#313244` (muted) + 20% opacity (transparent)
**Known limitation:**
- Uses `window.graphNodeObjects` global from obv — if obv renames this, we need to update. Mitigation: detection in `highlightCurrentNode` waits up to 500ms for obv's graph to be ready.
- Highlight doesn't preserve selection across page reload — fresh fetch on every load.
## 2. Click-to-navigate on 3D Graph
**What:** Clicking a node in the 3D Graph navigates to that file's page.
**How:**
1. `HermesCustom.setupGraphClickHandler()` sets up a Three.js Raycaster on the canvas DOM element
2. On click, computes normalized mouse coords, raycasts into scene
3. First intersection's `userData.nodeId` is the file path
4. Calls `window.loadFile(nodeId)` (obv's existing loader)
5. Updates URL with `window.history.pushState({}, '', '?file=<path>')`
**Code:** `vault-custom.js`, ~25 lines.
**Known limitation:**
- Three.js raycasting requires nodes to have `userData.nodeId` set — verified in obv's `addNodeToScene` function (line ~310 in obv's graph render). If obv removes this, our handler silently does nothing.
- No keyboard navigation in graph (yet). Roadmap item.
## 3. Responsive Layout
**What:** The 3-panel desktop layout collapses gracefully on smaller screens.
**Breakpoints:**
- **Desktop (≥1024px):** Full 3-panel layout — Tree 240px | Content 1fr | Graph 240px
- **Tablet (768px1023px):** Tree 240px | Content 1fr | Graph 200px (bottom panel)
- **Mobile (<768px):** Tree as hamburger menu (off-canvas, slides in from left) | Content full-width | Graph hidden
**How:**
- `HermesCustom.injectResponsiveCSS()` adds `<style>` tag with media queries
- `HermesCustom.responsiveLayout()` adds `.mobile-mode` / `.tablet-mode` classes to `.vault-app` based on `window.innerWidth`
- Resize handler is throttled (150ms) to avoid jank
- Hamburger toggle button is appended to header in mobile mode
**Code:** `vault-custom.js`, ~80 lines (including CSS string).
**Known limitation:**
- The injected CSS uses `!important` to override obv's `grid-template-columns`. If obv restructures the layout, we may need to adjust selectors.
- Hamburger menu doesn't auto-close on file selection — minor UX nit. Roadmap.
## 4. URL-based navigation (?file=)
**What:** The URL contains the currently-open file as a `?file=<path>` query param. This makes pages deep-linkable and back-button friendly.
**How:**
- `HermesCustom.getCurrentFile()` reads `?file=` from `URLSearchParams`
- `vault-custom.js` updates URL via `history.pushState()` on file load
- Server.py patch accepts `?file=` in API calls
**Server-side patch (server.py):**
```python
# Lukas-add: also support ?file=<path> query for clean URL navigation
if "?" in rel:
rel, _, query = rel.partition("?")
from urllib.parse import parse_qs
file_param = parse_qs(query).get("file", [None])[0]
if file_param:
rel = file_param
```
**Known limitation:**
- Server-side patch assumes `?file=` is the only query parameter obv might add. If obv adds another (e.g. `?theme=`), the simple `partition("?")` still works but is naive. Acceptable for current state.
## 5. Tracking current file via loadFile hook
**What:** `vault-custom.js` patches obv's `window.loadFile` to remember the last loaded path. Used as a fallback when the URL doesn't have `?file=` (e.g., when obv opens a file from search without updating URL).
**How:**
```js
const originalLoadFile = window.loadFile;
window.loadFile = function(path) {
HermesCustom._lastLoadedFile = path;
const result = originalLoadFile.apply(this, arguments);
setTimeout(HermesCustom.highlightCurrentNode, 300);
return result;
};
```
**Known limitation:**
- The 300ms delay assumes the render finishes within that time. Slow devices may need a longer delay. Could be improved by hooking into a render-completion signal if obv provides one.
---
## Testing
Manual testing only for now. Test cases:
| Scenario | Expected |
|----------|----------|
| Open `concepts/agent-reference-model.md` | Graph: that node gold + glow, connected nodes light blue, others dim |
| Open file via search (not via tree click) | Same highlighting (URL gets `?file=`) |
| Click graph node | File loads, URL updates |
| Resize browser to <1024px | Graph moves to bottom panel |
| Resize browser to <768px | Tree becomes hamburger, graph hidden |
| Hard reload on file URL | File loads directly (server.py parses `?file=`) |
| Upstream obv update (theoretical) | Only 1 line of conflict in vault.html, easy merge |
Planned: Playwright-based automated test for the 5 visual features.