From: Javier Sagredo Date: Sun, 3 May 2026 22:00:13 +0000 (+0200) Subject: Side panel: subclass index, pin/mute buttons; search now locates rather than drills in X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=da1d95dfb2568b66c6ee1d532211c60fa25ef7e3;p=classgraph.git Side panel: subclass index, pin/mute buttons; search now locates rather than drills in --- diff --git a/data/viewer.css b/data/viewer.css index 1bfaf41..005ce9b 100644 --- a/data/viewer.css +++ b/data/viewer.css @@ -7,8 +7,161 @@ body { display: flex; } flex-direction: column; height: 100vh; min-width: 0; + position: relative; /* anchor for #canvas-controls */ } +#canvas-controls { + position: absolute; + bottom: 12px; + right: 12px; + display: flex; + flex-direction: column; + align-items: flex-end; + gap: 6px; + z-index: 10; +} + +#fit-btn { + appearance: none; + background: #fff; + border: 1px solid #cbd5e1; + border-radius: 4px; + padding: 5px 12px; + font-size: 12px; + cursor: pointer; + color: #1f2937; + box-shadow: 0 1px 3px rgba(15, 23, 42, 0.1); +} +#fit-btn:hover { background: #f1f5f9; } +#fit-btn:active { background: #e2e8f0; } + +#help-panel { + background: #fff; + border: 1px solid #cbd5e1; + border-radius: 4px; + font-size: 11px; + position: relative; + box-shadow: 0 1px 3px rgba(15, 23, 42, 0.1); +} +#help-panel summary { + cursor: pointer; + padding: 5px 12px; + font-size: 12px; + font-weight: 600; + color: #1f2937; + user-select: none; + list-style: none; +} +#help-panel summary::-webkit-details-marker { display: none; } +#help-panel summary::before { + content: '?'; + display: inline-block; + width: 14px; + height: 14px; + background: #6366f1; + color: #fff; + border-radius: 50%; + text-align: center; + font-size: 10px; + font-weight: 700; + line-height: 14px; + margin-right: 6px; +} +#help-panel[open] summary::before { background: #1f2937; } + +/* Help content opens upward, away from the bottom edge of the canvas. */ +.help-content { + position: absolute; + bottom: calc(100% + 6px); + right: 0; + width: 360px; + max-height: 70vh; + overflow-y: auto; + background: #fff; + border: 1px solid #cbd5e1; + border-radius: 4px; + padding: 10px 14px; + box-shadow: 0 6px 16px rgba(15, 23, 42, 0.18); +} +.help-content h4 { + margin: 12px 0 4px; + font-size: 11px; + color: #475569; + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 700; +} +.help-content h4:first-child { margin-top: 0; } +.help-content code { + background: #f1f5f9; + padding: 0 4px; + border-radius: 3px; + font-size: 10.5px; +} +.help-content kbd { + background: #e5e7eb; + border: 1px solid #cbd5e1; + border-radius: 3px; + padding: 0 5px; + font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; + font-size: 10px; +} +.help-tip { + margin: 3px 0; + color: #475569; +} + +.legend-row { + display: flex; + align-items: center; + gap: 10px; + margin: 4px 0; + line-height: 1.4; +} +.legend-row > .swatch { + flex-shrink: 0; + display: inline-flex; + align-items: center; + justify-content: flex-start; + width: 56px; +} +.swatch-edge-wrap { padding-left: 6px; } +.swatch-node { + display: inline-block; + padding: 2px 6px; + font-size: 10px; + border-radius: 4px; + border: 1px solid; + font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; + white-space: nowrap; +} +.swatch-class { background: #3b82f6; color: #fff; border-color: #1d4ed8; } +.swatch-family { background: #fbbf24; color: #3f2d05; border-color: #b45309; } +.swatch-instance { background: #ecfdf5; color: #065f46; border-color: #10b981; } +.swatch-faminst { background: #f5f3ff; color: #5b21b6; border-color: #a78bfa; font-style: italic; } +.swatch-external { background: #e5e7eb; color: #374151; border-color: #9ca3af; border-style: dashed; } +.swatch-ghost { background: #dbeafe; color: #1e3a8a; border-color: #1d4ed8; border-style: dashed; opacity: 0.85; } +.swatch-orphan { background: #ecfdf5; color: #065f46; border: 1px dashed #dc2626; } + +.swatch-edge { + display: inline-block; + height: 0; + width: 36px; + border-top: 2px solid; + vertical-align: middle; +} +.swatch-edge.solid { border-top-style: solid; } +.swatch-edge.dashed { border-top-style: dashed; } +.swatch-edge.dotted { border-top-style: dotted; border-top-width: 3px; } +.swatch-edge.gray { border-top-color: #94a3b8; } +.swatch-edge.amber { border-top-color: #f59e0b; } +.swatch-edge.light-gray { border-top-color: #cbd5e1; } +.swatch-edge.green { border-top-color: #10b981; } +.swatch-edge.purple { border-top-color: #6366f1; } +.swatch-edge.violet-light { border-top-color: #c084fc; } +.swatch-edge.violet { border-top-color: #a78bfa; } +.swatch-edge.teal { border-top-color: #0d9488; } + #topbar { flex: 0 0 auto; display: flex; @@ -285,6 +438,45 @@ body { display: flex; } #panel h1 { margin: 0 0 4px; font-size: 16px; letter-spacing: 0.04em; text-transform: uppercase; color: #444; } #panel .hint { margin: 0 0 16px; font-size: 12px; color: #888; line-height: 1.5; } +.panel-actions { + display: flex; + gap: 8px; + margin: 8px 0 16px; +} +.panel-btn { + appearance: none; + border: 1px solid #d1d5db; + background: #fff; + font-size: 12px; + padding: 4px 10px; + border-radius: 4px; + cursor: pointer; + color: #374151; + display: inline-flex; + align-items: center; + gap: 4px; +} +.panel-btn:hover { background: #f3f4f6; } +.panel-btn.pin.active { + background: #dbeafe; + color: #1e40af; + border-color: #93c5fd; +} +.panel-btn.mute.active { + background: #fed7aa; + color: #7c2d12; + border-color: #fdba74; +} + +#selected dd a[data-action="navigate-class"] { + color: #1d4ed8; + text-decoration: none; + cursor: pointer; +} +#selected dd a[data-action="navigate-class"]:hover { + text-decoration: underline; +} + #selected h2 { margin: 0 0 4px; font-size: 18px; } #selected .pkgmod { margin: 0 0 12px; color: #888; font-size: 12px; word-break: break-all; } #selected .empty { color: #aaa; font-style: italic; } diff --git a/data/viewer.html b/data/viewer.html index 289ea4c..df2ead4 100644 --- a/data/viewer.html +++ b/data/viewer.html @@ -22,12 +22,49 @@
+
+ +
+ Help / legend +
+

Nodes

+
ClsClass defined in this program
+
FamType family (open / closed / associated)
+
InstClass instance
+
f a=btype instance F … = … row
+
ExtExternal class (referenced but not defined here)
+
ClsGhost — one-hop neighbour in focus mode (click to pin)
+
InstOrphan instance (red dashed border)
+ +

Classes-view edges

+
Plain superclass
+
Superclass mediated by a type family (Foo (F a) => …)
+
Class → associated type family
+ +

Instance-view edges

+
Class defines this instance
+
Context constraint required by this instance
+
Instance needs a superclass instance (matched locally)
+
Needs a superclass instance (no local match)
+
Instance references this type family
+
Family → its type-instance row
+
Instance's associated type instance RHS
+
Type-instance row resolves to a class instance (chain)
+ +

Controls

+
Click → highlight + side panel
+
Double-click a class → instances; a family → type instances
+
/ focuses search · F fits the graph
+
Pin / mute via the right-side buttons (chips appear in the topbar)
+
+
+