jsgui3-server 0.0.140 → 0.0.142
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/agents/jsgui3-server.agent.md +699 -0
- package/.github/instructions/copilot.instructions.md +180 -0
- package/.playwright-mcp/page-2025-11-29T23-39-18-629Z.png +0 -0
- package/.playwright-mcp/page-2025-11-29T23-39-31-903Z.png +0 -0
- package/.playwright-mcp/page-2025-11-30T00-33-56-265Z.png +0 -0
- package/.playwright-mcp/page-2025-11-30T00-34-06-619Z.png +0 -0
- package/docs/agent-development-guide.md +108 -4
- package/docs/api-reference.md +116 -0
- package/docs/controls-development.md +127 -0
- package/docs/css/luxuryObsidianCss.js +1203 -0
- package/docs/css/obsidian-scrollbars.css +370 -0
- package/docs/diagrams/jsgui3-stack.svg +568 -0
- package/docs/guides/JSGUI3_UI_ARCHITECTURE_GUIDE.md +2527 -0
- package/docs/guides/OBSIDIAN_LUXURY_DESIGN_GUIDE.md +847 -0
- package/docs/jsgui3-vs-express-comparison.svg +542 -0
- package/docs/jsgui3-vs-nestjs-comparison.svg +550 -0
- package/docs/publishers-guide.md +76 -0
- package/docs/troubleshooting.md +51 -0
- package/examples/controls/15) window, observable SSE/README.md +125 -0
- package/examples/controls/15) window, observable SSE/check.js +144 -0
- package/examples/controls/15) window, observable SSE/client.js +395 -0
- package/examples/controls/15) window, observable SSE/server.js +111 -0
- package/http/responders/static/Static_Route_HTTP_Responder.js +16 -16
- package/module.js +7 -0
- package/package.json +9 -8
- package/port-utils.js +112 -0
- package/serve-factory.js +27 -5
- package/tests/README.md +40 -26
- package/tests/examples-controls.e2e.test.js +164 -0
- package/tests/observable-sse.test.js +363 -0
- package/tests/port-utils.test.js +114 -0
- package/tests/test-runner.js +13 -12
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
# Obsidian Luxury Design Guide
|
|
2
|
+
|
|
3
|
+
## Architecture Diagrams for Software Stack Visualization
|
|
4
|
+
|
|
5
|
+
This guide establishes the visual language for creating premium architectural diagrams that illustrate software stacks, platform compositions, and system hierarchies. The "Obsidian Luxury" aesthetic combines dark sophistication with jewel-toned accents to create diagrams that are both beautiful and technically precise.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Design Philosophy
|
|
10
|
+
|
|
11
|
+
### Core Principles
|
|
12
|
+
|
|
13
|
+
1. **Layered Clarity** - Software stacks should read like geological cross-sections, with clear stratification showing how platforms build upon each other
|
|
14
|
+
2. **Jeweled Hierarchy** - Use gemstone colors to encode architectural significance and data flow direction
|
|
15
|
+
3. **Dimensional Depth** - Employ gradients, shadows, and perspective to convey the "weight" of foundational layers
|
|
16
|
+
4. **Elegant Density** - Pack information richly while maintaining visual breathing room
|
|
17
|
+
|
|
18
|
+
### When to Use This Style
|
|
19
|
+
|
|
20
|
+
- System architecture overviews
|
|
21
|
+
- Platform composition diagrams
|
|
22
|
+
- Technology stack illustrations
|
|
23
|
+
- Infrastructure layer visualizations
|
|
24
|
+
- Service mesh and microservice topologies
|
|
25
|
+
- Data flow through multi-tier systems
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Color Palette
|
|
30
|
+
|
|
31
|
+
### Foundation Colors (Dark Theme Base)
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Obsidian Background
|
|
35
|
+
├── Deep Black: #0d1117 (primary background)
|
|
36
|
+
├── Slate Dark: #161b22 (card backgrounds)
|
|
37
|
+
├── Slate Medium: #21262d (elevated surfaces)
|
|
38
|
+
└── Slate Light: #30363d (borders, dividers)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Jewel Accent Colors (Architectural Significance)
|
|
42
|
+
|
|
43
|
+
Each gemstone color encodes a specific architectural role:
|
|
44
|
+
|
|
45
|
+
| Gem | Hex | RGB | Architectural Meaning |
|
|
46
|
+
|-----|-----|-----|----------------------|
|
|
47
|
+
| **Gold** | `#c9a227` | 201, 162, 39 | Core/Foundation, APIs, Primary Data Flow |
|
|
48
|
+
| **Sapphire** | `#3b82f6` | 59, 130, 246 | Services, Business Logic, Processing |
|
|
49
|
+
| **Emerald** | `#10b981` | 16, 185, 129 | Success States, Health, Active Connections |
|
|
50
|
+
| **Ruby** | `#ef4444` | 239, 68, 68 | Errors, Critical Paths, Breaking Changes |
|
|
51
|
+
| **Amethyst** | `#a855f7` | 168, 85, 247 | External Systems, Integrations, Plugins |
|
|
52
|
+
| **Topaz** | `#f59e0b` | 245, 158, 11 | Warnings, Pending States, Async Operations |
|
|
53
|
+
| **Pearl** | `#e2e8f0` | 226, 232, 240 | Text, Labels, Secondary Information |
|
|
54
|
+
|
|
55
|
+
### Gradient Definitions
|
|
56
|
+
|
|
57
|
+
```xml
|
|
58
|
+
<!-- Gold Accent (horizontal) - for headers, key elements -->
|
|
59
|
+
<linearGradient id="goldAccent" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
60
|
+
<stop offset="0%" stop-color="#d4af37"/>
|
|
61
|
+
<stop offset="25%" stop-color="#c9a227"/>
|
|
62
|
+
<stop offset="50%" stop-color="#b8960f"/>
|
|
63
|
+
<stop offset="75%" stop-color="#c9a227"/>
|
|
64
|
+
<stop offset="100%" stop-color="#d4af37"/>
|
|
65
|
+
</linearGradient>
|
|
66
|
+
|
|
67
|
+
<!-- Gold Shine (text effect) -->
|
|
68
|
+
<linearGradient id="goldShine" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
69
|
+
<stop offset="0%" stop-color="#f4e4bc"/>
|
|
70
|
+
<stop offset="50%" stop-color="#c9a227"/>
|
|
71
|
+
<stop offset="100%" stop-color="#f4e4bc"/>
|
|
72
|
+
</linearGradient>
|
|
73
|
+
|
|
74
|
+
<!-- Obsidian Background (vertical depth) -->
|
|
75
|
+
<linearGradient id="obsidianBg" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
76
|
+
<stop offset="0%" stop-color="#1a1f2e"/>
|
|
77
|
+
<stop offset="50%" stop-color="#0d1117"/>
|
|
78
|
+
<stop offset="100%" stop-color="#080b10"/>
|
|
79
|
+
</linearGradient>
|
|
80
|
+
|
|
81
|
+
<!-- Sapphire Glow (services) -->
|
|
82
|
+
<radialGradient id="sapphireGlow" cx="50%" cy="50%" r="50%">
|
|
83
|
+
<stop offset="0%" stop-color="#60a5fa"/>
|
|
84
|
+
<stop offset="100%" stop-color="#3b82f6"/>
|
|
85
|
+
</radialGradient>
|
|
86
|
+
|
|
87
|
+
<!-- Emerald Glow (success/active) -->
|
|
88
|
+
<radialGradient id="emeraldGlow" cx="50%" cy="50%" r="50%">
|
|
89
|
+
<stop offset="0%" stop-color="#34d399"/>
|
|
90
|
+
<stop offset="100%" stop-color="#10b981"/>
|
|
91
|
+
</radialGradient>
|
|
92
|
+
|
|
93
|
+
<!-- Ruby Glow (errors/critical) -->
|
|
94
|
+
<radialGradient id="rubyGlow" cx="50%" cy="50%" r="50%">
|
|
95
|
+
<stop offset="0%" stop-color="#f87171"/>
|
|
96
|
+
<stop offset="100%" stop-color="#ef4444"/>
|
|
97
|
+
</radialGradient>
|
|
98
|
+
|
|
99
|
+
<!-- Amethyst Glow (external/integrations) -->
|
|
100
|
+
<radialGradient id="amethystGlow" cx="50%" cy="50%" r="50%">
|
|
101
|
+
<stop offset="0%" stop-color="#c084fc"/>
|
|
102
|
+
<stop offset="100%" stop-color="#a855f7"/>
|
|
103
|
+
</radialGradient>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Architecture Diagram Patterns
|
|
109
|
+
|
|
110
|
+
### Pattern 1: Vertical Stack (Platform Layers)
|
|
111
|
+
|
|
112
|
+
Use for showing how technologies build upon each other:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
┌─────────────────────────────────────────────────────────┐
|
|
116
|
+
│ APPLICATION LAYER │ ← Gold border
|
|
117
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|
118
|
+
│ │ Web UI │ │ API │ │ Admin │ │ CLI │ │
|
|
119
|
+
│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │
|
|
120
|
+
├───────┼────────────┼────────────┼────────────┼──────────┤
|
|
121
|
+
│ └────────────┴─────┬──────┴────────────┘ │
|
|
122
|
+
│ SERVICE LAYER │ ← Sapphire
|
|
123
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
124
|
+
│ │ Business Logic Services │ │
|
|
125
|
+
│ └──────────────────────┬───────────────────────────┘ │
|
|
126
|
+
├─────────────────────────┼───────────────────────────────┤
|
|
127
|
+
│ DATA LAYER │ ← Emerald
|
|
128
|
+
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
|
129
|
+
│ │ SQLite │ │ Cache │ │ Files │ │
|
|
130
|
+
│ └─────────┘ └─────────┘ └─────────┘ │
|
|
131
|
+
├─────────────────────────────────────────────────────────┤
|
|
132
|
+
│ INFRASTRUCTURE LAYER │ ← Slate
|
|
133
|
+
│ ┌─────────────────────────────────────────────────┐ │
|
|
134
|
+
│ │ Node.js │ │
|
|
135
|
+
│ └─────────────────────────────────────────────────┘ │
|
|
136
|
+
└─────────────────────────────────────────────────────────┘
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**SVG Implementation Notes:**
|
|
140
|
+
- Each layer is a `<g>` group with consistent padding
|
|
141
|
+
- Layer backgrounds use subtle gradients (darker at bottom = "heavier")
|
|
142
|
+
- Gold accent on top layer indicates entry points
|
|
143
|
+
- Connector lines use `stroke-dasharray` for optional paths
|
|
144
|
+
|
|
145
|
+
### Pattern 2: Horizontal Flow (Data Pipeline)
|
|
146
|
+
|
|
147
|
+
Use for showing data transformation through stages:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
151
|
+
│ INGEST │───▶│ PROCESS │───▶│ STORE │───▶│ SERVE │
|
|
152
|
+
│ │ │ │ │ │ │ │
|
|
153
|
+
│ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │
|
|
154
|
+
│ │Source│ │ │ │Parse │ │ │ │ DB │ │ │ │ API │ │
|
|
155
|
+
│ │ URLs │ │ │ │& Norm│ │ │ │Write │ │ │ │Query │ │
|
|
156
|
+
│ └──────┘ │ │ └──────┘ │ │ └──────┘ │ │ └──────┘ │
|
|
157
|
+
└──────────┘ └──────────┘ └──────────┘ └──────────┘
|
|
158
|
+
Topaz Sapphire Emerald Gold
|
|
159
|
+
(pending) (process) (storage) (output)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**SVG Implementation Notes:**
|
|
163
|
+
- Arrows use `<marker>` elements with gold fill
|
|
164
|
+
- Stage boxes have rounded corners (`rx="8"`)
|
|
165
|
+
- Inner boxes show specific operations
|
|
166
|
+
- Color encodes stage type, not status
|
|
167
|
+
|
|
168
|
+
### Pattern 3: Nested Composition (System of Systems)
|
|
169
|
+
|
|
170
|
+
Use for showing how subsystems compose into larger wholes:
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
174
|
+
│ NEWS AGGREGATOR │
|
|
175
|
+
│ ┌───────────────────────────┐ ┌───────────────────────────┐ │
|
|
176
|
+
│ │ CRAWLER SYSTEM │ │ ANALYSIS SYSTEM │ │
|
|
177
|
+
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
|
|
178
|
+
│ │ │Queue│ │Fetch│ │Parse│ │ │ │ NLP │ │ Geo │ │Score│ │ │
|
|
179
|
+
│ │ └──┬──┘ └──┬──┘ └──┬──┘ │ │ └──┬──┘ └──┬──┘ └──┬──┘ │ │
|
|
180
|
+
│ │ └───────┴───────┘ │ │ └───────┴───────┘ │ │
|
|
181
|
+
│ │ Orchestrator │ │ Orchestrator │ │
|
|
182
|
+
│ └─────────────┬─────────────┘ └─────────────┬─────────────┘ │
|
|
183
|
+
│ │ │ │
|
|
184
|
+
│ └──────────────┬───────────────┘ │
|
|
185
|
+
│ │ │
|
|
186
|
+
│ ┌────────────────────────────┴─────────────────────────────┐ │
|
|
187
|
+
│ │ SHARED DATA LAYER │ │
|
|
188
|
+
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
|
|
189
|
+
│ │ │ URLs │ │ Articles │ │ Places │ │ Scores │ │ │
|
|
190
|
+
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
|
|
191
|
+
│ └───────────────────────────────────────────────────────────┘ │
|
|
192
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**SVG Implementation Notes:**
|
|
196
|
+
- Outer container has gold accent border
|
|
197
|
+
- Subsystems use sapphire tint backgrounds
|
|
198
|
+
- Shared layer uses emerald to show connectivity
|
|
199
|
+
- Depth conveyed through nested rounded rectangles
|
|
200
|
+
|
|
201
|
+
### Pattern 4: Radial Architecture (Hub and Spoke)
|
|
202
|
+
|
|
203
|
+
Use for showing central services with satellite dependencies:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
┌─────────┐
|
|
207
|
+
│ External│
|
|
208
|
+
│ API │
|
|
209
|
+
└────┬────┘
|
|
210
|
+
│
|
|
211
|
+
┌────────┐ ┌────┴────┐ ┌────────┐
|
|
212
|
+
│ Cache │──│ CORE │──│ Search │
|
|
213
|
+
│ Layer │ │ SERVICE │ │ Index │
|
|
214
|
+
└────────┘ └────┬────┘ └────────┘
|
|
215
|
+
│
|
|
216
|
+
┌────────┐ ┌────┴────┐ ┌────────┐
|
|
217
|
+
│ Queue │──│Database │──│ Files │
|
|
218
|
+
│Service │ │ Cluster │ │ Store │
|
|
219
|
+
└────────┘ └─────────┘ └────────┘
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**SVG Implementation Notes:**
|
|
223
|
+
- Central node uses radial gradient with gold center
|
|
224
|
+
- Spokes use straight lines with subtle glow
|
|
225
|
+
- Satellite nodes sized by importance
|
|
226
|
+
- Optional: animate pulse on central node
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Visual Elements
|
|
231
|
+
|
|
232
|
+
### Box Styles
|
|
233
|
+
|
|
234
|
+
#### Primary Container (System Boundary)
|
|
235
|
+
```xml
|
|
236
|
+
<rect x="0" y="0" width="400" height="300"
|
|
237
|
+
rx="12" ry="12"
|
|
238
|
+
fill="url(#obsidianBg)"
|
|
239
|
+
stroke="url(#goldAccent)"
|
|
240
|
+
stroke-width="2"
|
|
241
|
+
filter="url(#dropShadow)"/>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Secondary Container (Subsystem)
|
|
245
|
+
```xml
|
|
246
|
+
<rect x="20" y="20" width="360" height="260"
|
|
247
|
+
rx="8" ry="8"
|
|
248
|
+
fill="#161b22"
|
|
249
|
+
stroke="#30363d"
|
|
250
|
+
stroke-width="1"/>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
#### Component Box (Individual Service)
|
|
254
|
+
```xml
|
|
255
|
+
<rect x="40" y="40" width="120" height="80"
|
|
256
|
+
rx="6" ry="6"
|
|
257
|
+
fill="#21262d"
|
|
258
|
+
stroke="#3b82f6"
|
|
259
|
+
stroke-width="1.5"
|
|
260
|
+
opacity="0.9"/>
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Connector Styles
|
|
264
|
+
|
|
265
|
+
#### Primary Data Flow
|
|
266
|
+
```xml
|
|
267
|
+
<line x1="100" y1="100" x2="200" y2="100"
|
|
268
|
+
stroke="url(#goldAccent)"
|
|
269
|
+
stroke-width="2"
|
|
270
|
+
marker-end="url(#arrowGold)"/>
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### Secondary/Optional Flow
|
|
274
|
+
```xml
|
|
275
|
+
<line x1="100" y1="120" x2="200" y2="120"
|
|
276
|
+
stroke="#64748b"
|
|
277
|
+
stroke-width="1"
|
|
278
|
+
stroke-dasharray="4 2"
|
|
279
|
+
marker-end="url(#arrowGray)"/>
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### Bidirectional Flow
|
|
283
|
+
```xml
|
|
284
|
+
<line x1="100" y1="140" x2="200" y2="140"
|
|
285
|
+
stroke="#3b82f6"
|
|
286
|
+
stroke-width="1.5"
|
|
287
|
+
marker-start="url(#arrowBlue)"
|
|
288
|
+
marker-end="url(#arrowBlue)"/>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### Arrow Markers
|
|
292
|
+
|
|
293
|
+
```xml
|
|
294
|
+
<defs>
|
|
295
|
+
<!-- Gold arrow for primary flows -->
|
|
296
|
+
<marker id="arrowGold" viewBox="0 0 10 10" refX="9" refY="5"
|
|
297
|
+
markerWidth="6" markerHeight="6" orient="auto-start-reverse">
|
|
298
|
+
<path d="M 0 0 L 10 5 L 0 10 z" fill="#c9a227"/>
|
|
299
|
+
</marker>
|
|
300
|
+
|
|
301
|
+
<!-- Blue arrow for service connections -->
|
|
302
|
+
<marker id="arrowBlue" viewBox="0 0 10 10" refX="9" refY="5"
|
|
303
|
+
markerWidth="5" markerHeight="5" orient="auto-start-reverse">
|
|
304
|
+
<path d="M 0 0 L 10 5 L 0 10 z" fill="#3b82f6"/>
|
|
305
|
+
</marker>
|
|
306
|
+
|
|
307
|
+
<!-- Gray arrow for optional paths -->
|
|
308
|
+
<marker id="arrowGray" viewBox="0 0 10 10" refX="9" refY="5"
|
|
309
|
+
markerWidth="4" markerHeight="4" orient="auto-start-reverse">
|
|
310
|
+
<path d="M 0 0 L 10 5 L 0 10 z" fill="#64748b"/>
|
|
311
|
+
</marker>
|
|
312
|
+
</defs>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Filter Effects
|
|
316
|
+
|
|
317
|
+
```xml
|
|
318
|
+
<defs>
|
|
319
|
+
<!-- Drop shadow for elevated elements -->
|
|
320
|
+
<filter id="dropShadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
321
|
+
<feDropShadow dx="0" dy="4" stdDeviation="8" flood-color="#000" flood-opacity="0.5"/>
|
|
322
|
+
</filter>
|
|
323
|
+
|
|
324
|
+
<!-- Glow effect for active/highlighted elements -->
|
|
325
|
+
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
|
|
326
|
+
<feGaussianBlur stdDeviation="4" result="coloredBlur"/>
|
|
327
|
+
<feMerge>
|
|
328
|
+
<feMergeNode in="coloredBlur"/>
|
|
329
|
+
<feMergeNode in="SourceGraphic"/>
|
|
330
|
+
</feMerge>
|
|
331
|
+
</filter>
|
|
332
|
+
|
|
333
|
+
<!-- Text glow for titles -->
|
|
334
|
+
<filter id="textGlow" x="-20%" y="-20%" width="140%" height="140%">
|
|
335
|
+
<feGaussianBlur in="SourceAlpha" stdDeviation="2" result="blur"/>
|
|
336
|
+
<feFlood flood-color="#c9a227" flood-opacity="0.5"/>
|
|
337
|
+
<feComposite in2="blur" operator="in"/>
|
|
338
|
+
<feMerge>
|
|
339
|
+
<feMergeNode/>
|
|
340
|
+
<feMergeNode in="SourceGraphic"/>
|
|
341
|
+
</feMerge>
|
|
342
|
+
</filter>
|
|
343
|
+
</defs>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Typography
|
|
349
|
+
|
|
350
|
+
### Font Stack
|
|
351
|
+
```css
|
|
352
|
+
/* Primary: Technical content */
|
|
353
|
+
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
|
|
354
|
+
|
|
355
|
+
/* Display: Titles and headers */
|
|
356
|
+
font-family: 'Georgia', 'Times New Roman', serif;
|
|
357
|
+
|
|
358
|
+
/* UI: Labels and annotations */
|
|
359
|
+
font-family: 'Inter', 'SF Pro Display', 'Segoe UI', sans-serif;
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Text Hierarchy
|
|
363
|
+
|
|
364
|
+
| Level | Font | Size | Color | Usage |
|
|
365
|
+
|-------|------|------|-------|-------|
|
|
366
|
+
| **Title** | Georgia Bold | 32-48px | `url(#goldShine)` | Diagram title |
|
|
367
|
+
| **Section** | Inter SemiBold | 18-24px | `#e2e8f0` | Layer/section names |
|
|
368
|
+
| **Label** | Inter Medium | 12-14px | `#94a3b8` | Component labels |
|
|
369
|
+
| **Code** | JetBrains Mono | 11-13px | `#a5b4fc` | Technical names |
|
|
370
|
+
| **Annotation** | Inter Regular | 10-11px | `#64748b` | Explanatory notes |
|
|
371
|
+
|
|
372
|
+
### Text Examples
|
|
373
|
+
|
|
374
|
+
```xml
|
|
375
|
+
<!-- Diagram Title -->
|
|
376
|
+
<text x="700" y="50" text-anchor="middle"
|
|
377
|
+
font-family="Georgia, serif" font-size="38" font-weight="bold"
|
|
378
|
+
fill="url(#goldShine)" filter="url(#textGlow)">
|
|
379
|
+
System Architecture
|
|
380
|
+
</text>
|
|
381
|
+
|
|
382
|
+
<!-- Section Header -->
|
|
383
|
+
<text x="100" y="120"
|
|
384
|
+
font-family="Inter, sans-serif" font-size="20" font-weight="600"
|
|
385
|
+
fill="#e2e8f0" letter-spacing="2">
|
|
386
|
+
APPLICATION LAYER
|
|
387
|
+
</text>
|
|
388
|
+
|
|
389
|
+
<!-- Component Label -->
|
|
390
|
+
<text x="150" y="180" text-anchor="middle"
|
|
391
|
+
font-family="Inter, sans-serif" font-size="13" font-weight="500"
|
|
392
|
+
fill="#94a3b8">
|
|
393
|
+
API Gateway
|
|
394
|
+
</text>
|
|
395
|
+
|
|
396
|
+
<!-- Technical Name -->
|
|
397
|
+
<text x="150" y="200" text-anchor="middle"
|
|
398
|
+
font-family="JetBrains Mono, monospace" font-size="11"
|
|
399
|
+
fill="#a5b4fc">
|
|
400
|
+
express.Router()
|
|
401
|
+
</text>
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Layout Guidelines
|
|
407
|
+
|
|
408
|
+
### Spacing Scale
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
4px - Minimal gap (text kerning adjustments)
|
|
412
|
+
8px - Tight spacing (inline elements)
|
|
413
|
+
16px - Standard padding (component internals)
|
|
414
|
+
24px - Comfortable margin (between components)
|
|
415
|
+
32px - Section spacing (between logical groups)
|
|
416
|
+
48px - Layer separation (major architectural boundaries)
|
|
417
|
+
64px - Canvas margins (diagram edges)
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
### Alignment Rules
|
|
421
|
+
|
|
422
|
+
1. **Vertical stacks**: Align centers, maintain consistent width
|
|
423
|
+
2. **Horizontal flows**: Align baselines, maintain consistent height
|
|
424
|
+
3. **Nested containers**: Indent by 24px per nesting level
|
|
425
|
+
4. **Connectors**: Use orthogonal routing (90° angles only)
|
|
426
|
+
|
|
427
|
+
### Responsive Considerations
|
|
428
|
+
|
|
429
|
+
For large diagrams (>1200px wide):
|
|
430
|
+
- Use `viewBox` for scalability
|
|
431
|
+
- Minimum text size: 10px at 100% zoom
|
|
432
|
+
- Ensure 4:3 or 16:9 aspect ratios for presentation compatibility
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Icon Vocabulary
|
|
437
|
+
|
|
438
|
+
### Standard Symbols
|
|
439
|
+
|
|
440
|
+
```xml
|
|
441
|
+
<!-- Database (cylinder) -->
|
|
442
|
+
<symbol id="iconDatabase" viewBox="0 0 32 32">
|
|
443
|
+
<ellipse cx="16" cy="6" rx="12" ry="4" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
444
|
+
<path d="M4 6 v20 a12,4 0 0,0 24,0 v-20" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
445
|
+
<ellipse cx="16" cy="26" rx="12" ry="4" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
446
|
+
</symbol>
|
|
447
|
+
|
|
448
|
+
<!-- Server/Service (rectangle with status) -->
|
|
449
|
+
<symbol id="iconServer" viewBox="0 0 32 32">
|
|
450
|
+
<rect x="2" y="4" width="28" height="24" rx="3" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
451
|
+
<line x1="2" y1="12" x2="30" y2="12" stroke="currentColor" stroke-width="2"/>
|
|
452
|
+
<circle cx="8" cy="8" r="2" fill="currentColor"/>
|
|
453
|
+
<line x1="8" y1="18" x2="24" y2="18" stroke="currentColor" stroke-width="2"/>
|
|
454
|
+
<line x1="8" y1="22" x2="20" y2="22" stroke="currentColor" stroke-width="2"/>
|
|
455
|
+
</symbol>
|
|
456
|
+
|
|
457
|
+
<!-- API (connected nodes) -->
|
|
458
|
+
<symbol id="iconAPI" viewBox="0 0 32 32">
|
|
459
|
+
<circle cx="8" cy="16" r="5" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
460
|
+
<circle cx="24" cy="16" r="5" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
461
|
+
<line x1="13" y1="16" x2="19" y2="16" stroke="currentColor" stroke-width="2"/>
|
|
462
|
+
<circle cx="16" cy="6" r="4" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
463
|
+
<line x1="16" y1="10" x2="16" y2="14" stroke="currentColor" stroke-width="2"/>
|
|
464
|
+
</symbol>
|
|
465
|
+
|
|
466
|
+
<!-- Queue (stacked items) -->
|
|
467
|
+
<symbol id="iconQueue" viewBox="0 0 32 32">
|
|
468
|
+
<rect x="4" y="4" width="24" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
469
|
+
<rect x="4" y="13" width="24" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
470
|
+
<rect x="4" y="22" width="24" height="6" rx="2" fill="none" stroke="currentColor" stroke-width="2"/>
|
|
471
|
+
</symbol>
|
|
472
|
+
|
|
473
|
+
<!-- External System (cloud) -->
|
|
474
|
+
<symbol id="iconCloud" viewBox="0 0 32 32">
|
|
475
|
+
<path d="M8 24 a6,6 0 0,1 0-12 a8,8 0 0,1 16,0 a5,5 0 0,1 0,12 z"
|
|
476
|
+
fill="none" stroke="currentColor" stroke-width="2"/>
|
|
477
|
+
</symbol>
|
|
478
|
+
|
|
479
|
+
<!-- Gem/Accent (decorative) -->
|
|
480
|
+
<symbol id="iconGem" viewBox="0 0 32 32">
|
|
481
|
+
<polygon points="16,2 28,12 16,30 4,12"
|
|
482
|
+
fill="none" stroke="currentColor" stroke-width="2"/>
|
|
483
|
+
<line x1="4" y1="12" x2="28" y2="12" stroke="currentColor" stroke-width="1"/>
|
|
484
|
+
<line x1="16" y1="2" x2="10" y2="12" stroke="currentColor" stroke-width="1"/>
|
|
485
|
+
<line x1="16" y1="2" x2="22" y2="12" stroke="currentColor" stroke-width="1"/>
|
|
486
|
+
<line x1="10" y1="12" x2="16" y2="30" stroke="currentColor" stroke-width="1"/>
|
|
487
|
+
<line x1="22" y1="12" x2="16" y2="30" stroke="currentColor" stroke-width="1"/>
|
|
488
|
+
</symbol>
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Icon Usage
|
|
492
|
+
|
|
493
|
+
```xml
|
|
494
|
+
<!-- Place icon with color -->
|
|
495
|
+
<use href="#iconDatabase" x="100" y="100" width="32" height="32"
|
|
496
|
+
style="color: #10b981"/>
|
|
497
|
+
|
|
498
|
+
<!-- Icon with label -->
|
|
499
|
+
<g transform="translate(200, 150)">
|
|
500
|
+
<use href="#iconServer" x="0" y="0" width="32" height="32" style="color: #3b82f6"/>
|
|
501
|
+
<text x="16" y="45" text-anchor="middle"
|
|
502
|
+
font-family="Inter, sans-serif" font-size="11" fill="#94a3b8">
|
|
503
|
+
API Server
|
|
504
|
+
</text>
|
|
505
|
+
</g>
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Complete Example: Three-Tier Architecture
|
|
511
|
+
|
|
512
|
+
```xml
|
|
513
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
514
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">
|
|
515
|
+
<defs>
|
|
516
|
+
<!-- Include all gradients, markers, filters from above -->
|
|
517
|
+
<linearGradient id="obsidianBg" x1="0%" y1="0%" x2="0%" y2="100%">
|
|
518
|
+
<stop offset="0%" stop-color="#1a1f2e"/>
|
|
519
|
+
<stop offset="100%" stop-color="#0d1117"/>
|
|
520
|
+
</linearGradient>
|
|
521
|
+
<linearGradient id="goldAccent" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
522
|
+
<stop offset="0%" stop-color="#d4af37"/>
|
|
523
|
+
<stop offset="50%" stop-color="#c9a227"/>
|
|
524
|
+
<stop offset="100%" stop-color="#d4af37"/>
|
|
525
|
+
</linearGradient>
|
|
526
|
+
<filter id="dropShadow">
|
|
527
|
+
<feDropShadow dx="0" dy="4" stdDeviation="8" flood-opacity="0.4"/>
|
|
528
|
+
</filter>
|
|
529
|
+
</defs>
|
|
530
|
+
|
|
531
|
+
<!-- Background -->
|
|
532
|
+
<rect width="800" height="600" fill="url(#obsidianBg)"/>
|
|
533
|
+
|
|
534
|
+
<!-- Title -->
|
|
535
|
+
<text x="400" y="45" text-anchor="middle"
|
|
536
|
+
font-family="Georgia, serif" font-size="28" font-weight="bold"
|
|
537
|
+
fill="url(#goldAccent)">
|
|
538
|
+
Three-Tier Architecture
|
|
539
|
+
</text>
|
|
540
|
+
|
|
541
|
+
<!-- Presentation Layer -->
|
|
542
|
+
<g transform="translate(50, 80)">
|
|
543
|
+
<rect width="700" height="120" rx="8" fill="#161b22"
|
|
544
|
+
stroke="#c9a227" stroke-width="2" filter="url(#dropShadow)"/>
|
|
545
|
+
<text x="20" y="25" font-family="Inter, sans-serif" font-size="14"
|
|
546
|
+
fill="#c9a227" font-weight="600">PRESENTATION LAYER</text>
|
|
547
|
+
|
|
548
|
+
<g transform="translate(50, 45)">
|
|
549
|
+
<rect width="140" height="60" rx="6" fill="#21262d" stroke="#64748b"/>
|
|
550
|
+
<text x="70" y="35" text-anchor="middle" font-family="Inter"
|
|
551
|
+
font-size="13" fill="#e2e8f0">Web Browser</text>
|
|
552
|
+
</g>
|
|
553
|
+
<g transform="translate(230, 45)">
|
|
554
|
+
<rect width="140" height="60" rx="6" fill="#21262d" stroke="#64748b"/>
|
|
555
|
+
<text x="70" y="35" text-anchor="middle" font-family="Inter"
|
|
556
|
+
font-size="13" fill="#e2e8f0">Mobile App</text>
|
|
557
|
+
</g>
|
|
558
|
+
<g transform="translate(410, 45)">
|
|
559
|
+
<rect width="140" height="60" rx="6" fill="#21262d" stroke="#64748b"/>
|
|
560
|
+
<text x="70" y="35" text-anchor="middle" font-family="Inter"
|
|
561
|
+
font-size="13" fill="#e2e8f0">CLI Tool</text>
|
|
562
|
+
</g>
|
|
563
|
+
</g>
|
|
564
|
+
|
|
565
|
+
<!-- Connectors: Presentation → Business -->
|
|
566
|
+
<g stroke="#c9a227" stroke-width="2">
|
|
567
|
+
<line x1="400" y1="200" x2="400" y2="230"/>
|
|
568
|
+
<polygon points="395,225 400,235 405,225" fill="#c9a227"/>
|
|
569
|
+
</g>
|
|
570
|
+
|
|
571
|
+
<!-- Business Layer -->
|
|
572
|
+
<g transform="translate(50, 240)">
|
|
573
|
+
<rect width="700" height="120" rx="8" fill="#161b22"
|
|
574
|
+
stroke="#3b82f6" stroke-width="2" filter="url(#dropShadow)"/>
|
|
575
|
+
<text x="20" y="25" font-family="Inter, sans-serif" font-size="14"
|
|
576
|
+
fill="#3b82f6" font-weight="600">BUSINESS LAYER</text>
|
|
577
|
+
|
|
578
|
+
<g transform="translate(50, 45)">
|
|
579
|
+
<rect width="180" height="60" rx="6" fill="#21262d" stroke="#3b82f6"/>
|
|
580
|
+
<text x="90" y="35" text-anchor="middle" font-family="Inter"
|
|
581
|
+
font-size="13" fill="#e2e8f0">API Gateway</text>
|
|
582
|
+
</g>
|
|
583
|
+
<g transform="translate(260, 45)">
|
|
584
|
+
<rect width="180" height="60" rx="6" fill="#21262d" stroke="#3b82f6"/>
|
|
585
|
+
<text x="90" y="35" text-anchor="middle" font-family="Inter"
|
|
586
|
+
font-size="13" fill="#e2e8f0">Service Layer</text>
|
|
587
|
+
</g>
|
|
588
|
+
<g transform="translate(470, 45)">
|
|
589
|
+
<rect width="180" height="60" rx="6" fill="#21262d" stroke="#3b82f6"/>
|
|
590
|
+
<text x="90" y="35" text-anchor="middle" font-family="Inter"
|
|
591
|
+
font-size="13" fill="#e2e8f0">Auth Service</text>
|
|
592
|
+
</g>
|
|
593
|
+
</g>
|
|
594
|
+
|
|
595
|
+
<!-- Connectors: Business → Data -->
|
|
596
|
+
<g stroke="#3b82f6" stroke-width="2">
|
|
597
|
+
<line x1="400" y1="360" x2="400" y2="390"/>
|
|
598
|
+
<polygon points="395,385 400,395 405,385" fill="#3b82f6"/>
|
|
599
|
+
</g>
|
|
600
|
+
|
|
601
|
+
<!-- Data Layer -->
|
|
602
|
+
<g transform="translate(50, 400)">
|
|
603
|
+
<rect width="700" height="120" rx="8" fill="#161b22"
|
|
604
|
+
stroke="#10b981" stroke-width="2" filter="url(#dropShadow)"/>
|
|
605
|
+
<text x="20" y="25" font-family="Inter, sans-serif" font-size="14"
|
|
606
|
+
fill="#10b981" font-weight="600">DATA LAYER</text>
|
|
607
|
+
|
|
608
|
+
<g transform="translate(50, 45)">
|
|
609
|
+
<rect width="180" height="60" rx="6" fill="#21262d" stroke="#10b981"/>
|
|
610
|
+
<text x="90" y="35" text-anchor="middle" font-family="Inter"
|
|
611
|
+
font-size="13" fill="#e2e8f0">Primary Database</text>
|
|
612
|
+
</g>
|
|
613
|
+
<g transform="translate(260, 45)">
|
|
614
|
+
<rect width="180" height="60" rx="6" fill="#21262d" stroke="#10b981"/>
|
|
615
|
+
<text x="90" y="35" text-anchor="middle" font-family="Inter"
|
|
616
|
+
font-size="13" fill="#e2e8f0">Cache Layer</text>
|
|
617
|
+
</g>
|
|
618
|
+
<g transform="translate(470, 45)">
|
|
619
|
+
<rect width="180" height="60" rx="6" fill="#21262d" stroke="#10b981"/>
|
|
620
|
+
<text x="90" y="35" text-anchor="middle" font-family="Inter"
|
|
621
|
+
font-size="13" fill="#e2e8f0">File Storage</text>
|
|
622
|
+
</g>
|
|
623
|
+
</g>
|
|
624
|
+
|
|
625
|
+
<!-- Legend -->
|
|
626
|
+
<g transform="translate(50, 550)">
|
|
627
|
+
<text x="0" y="0" font-family="Inter" font-size="10" fill="#64748b">
|
|
628
|
+
<tspan fill="#c9a227">■</tspan> Entry Points
|
|
629
|
+
<tspan dx="20" fill="#3b82f6">■</tspan> Services
|
|
630
|
+
<tspan dx="20" fill="#10b981">■</tspan> Storage
|
|
631
|
+
</text>
|
|
632
|
+
</g>
|
|
633
|
+
</svg>
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
---
|
|
637
|
+
|
|
638
|
+
## Validation & Tooling
|
|
639
|
+
|
|
640
|
+
Use the SVG validation tools to ensure diagram quality:
|
|
641
|
+
|
|
642
|
+
```bash
|
|
643
|
+
# Validate XML and check for issues
|
|
644
|
+
node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg
|
|
645
|
+
|
|
646
|
+
# Check for visual overlaps
|
|
647
|
+
node tools/dev/svg-collisions.js docs/diagrams/my-architecture.svg
|
|
648
|
+
|
|
649
|
+
# Index elements for reference
|
|
650
|
+
node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg --index
|
|
651
|
+
|
|
652
|
+
# Find specific elements
|
|
653
|
+
node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg --find "@rect"
|
|
654
|
+
node tools/dev/svg-validate.js docs/diagrams/my-architecture.svg --find "L:50-100"
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
659
|
+
## Checklist for Architecture Diagrams
|
|
660
|
+
|
|
661
|
+
- [ ] **Clear hierarchy**: Layers read top-to-bottom or left-to-right
|
|
662
|
+
- [ ] **Consistent colors**: Each color encodes the same meaning throughout
|
|
663
|
+
- [ ] **Readable text**: Minimum 10px at 100% zoom
|
|
664
|
+
- [ ] **Labeled connections**: Data flows have directional arrows
|
|
665
|
+
- [ ] **Legend included**: Color/symbol meanings explained
|
|
666
|
+
- [ ] **Valid SVG**: Passes `svg-validate.js` checks
|
|
667
|
+
- [ ] **No overlaps**: Passes `svg-collisions.js` checks
|
|
668
|
+
- [ ] **Proper viewBox**: Scalable without distortion
|
|
669
|
+
- [ ] **Accessible names**: Groups have meaningful structure
|
|
670
|
+
|
|
671
|
+
---
|
|
672
|
+
|
|
673
|
+
## Scrollbar Styling (Obsidian Theme)
|
|
674
|
+
|
|
675
|
+
Custom scrollbars are essential for maintaining visual consistency in dark-themed dashboards. The Obsidian theme uses subtle, elegant scrollbars that complement the jewel-toned aesthetic.
|
|
676
|
+
|
|
677
|
+
### ⚠️ CRITICAL: Preventing Layout Jiggle
|
|
678
|
+
|
|
679
|
+
**Layout jiggle** occurs when scrollbar appearance/disappearance causes content to shift horizontally. This is the most common scrollbar UX problem and MUST be addressed.
|
|
680
|
+
|
|
681
|
+
**Solution: Use Overlay Scrollbars**
|
|
682
|
+
|
|
683
|
+
```css
|
|
684
|
+
/* RECOMMENDED: Overlay scrollbars - no layout jiggle */
|
|
685
|
+
.my-scrollable-container {
|
|
686
|
+
/* Primary: overlay scrollbars (Chromium-based browsers) */
|
|
687
|
+
overflow-y: overlay;
|
|
688
|
+
/* Reserve space on browsers that support it */
|
|
689
|
+
scrollbar-gutter: stable;
|
|
690
|
+
/* Firefox styling */
|
|
691
|
+
scrollbar-width: thin;
|
|
692
|
+
scrollbar-color: var(--obsidian-border) transparent;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/* Fallback for browsers without overlay support */
|
|
696
|
+
@supports not (overflow: overlay) {
|
|
697
|
+
.my-scrollable-container {
|
|
698
|
+
overflow-y: auto;
|
|
699
|
+
/* scrollbar-gutter: stable still helps in modern Firefox */
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
**Key CSS Properties:**
|
|
705
|
+
|
|
706
|
+
| Property | Purpose |
|
|
707
|
+
|----------|---------|
|
|
708
|
+
| `overflow: overlay` | Scrollbar floats over content (Chromium) |
|
|
709
|
+
| `scrollbar-gutter: stable` | Reserves scrollbar space to prevent jiggle |
|
|
710
|
+
| `background: transparent` on track | Makes overlay scrollbar less intrusive |
|
|
711
|
+
|
|
712
|
+
**Available Utility Classes** (from `src/ui/css/obsidian-scrollbars.css`):
|
|
713
|
+
|
|
714
|
+
| Class | Description |
|
|
715
|
+
|-------|-------------|
|
|
716
|
+
| `.obsidian-scroll-overlay` | **RECOMMENDED** - No layout jiggle, gold theme |
|
|
717
|
+
| `.obsidian-scroll-overlay-glow` | Overlay + gold glow on hover |
|
|
718
|
+
| `.obsidian-scroll` | Standard scrollbar (may jiggle) |
|
|
719
|
+
| `.obsidian-scroll-thin` | 6px width scrollbar |
|
|
720
|
+
| `.obsidian-scroll-hidden` | Hidden scrollbar (still scrollable) |
|
|
721
|
+
|
|
722
|
+
### CSS Variables for Scrollbars
|
|
723
|
+
|
|
724
|
+
Use these CSS variables (defined in `:root`) for consistent scrollbar theming:
|
|
725
|
+
|
|
726
|
+
```css
|
|
727
|
+
:root {
|
|
728
|
+
/* Core backgrounds */
|
|
729
|
+
--obsidian-bg-deep: rgba(10, 13, 20, 0.99);
|
|
730
|
+
--obsidian-bg-surface: rgba(20, 24, 36, 0.98);
|
|
731
|
+
--obsidian-bg-elevated: rgba(30, 35, 50, 0.95);
|
|
732
|
+
|
|
733
|
+
/* Gold accents */
|
|
734
|
+
--obsidian-gold: #c9a227;
|
|
735
|
+
--obsidian-gold-dim: rgba(201, 162, 39, 0.6);
|
|
736
|
+
--obsidian-gold-glow: rgba(201, 162, 39, 0.4);
|
|
737
|
+
|
|
738
|
+
/* Borders */
|
|
739
|
+
--obsidian-border: rgba(201, 162, 39, 0.3);
|
|
740
|
+
--obsidian-border-dim: rgba(201, 162, 39, 0.15);
|
|
741
|
+
}
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### Standard Scrollbar Implementation
|
|
745
|
+
|
|
746
|
+
Apply to any scrollable container:
|
|
747
|
+
|
|
748
|
+
```css
|
|
749
|
+
/* Scrollbar - Obsidian Luxury */
|
|
750
|
+
.your-scrollable-container {
|
|
751
|
+
overflow-y: auto;
|
|
752
|
+
scrollbar-width: thin; /* Firefox */
|
|
753
|
+
scrollbar-color: var(--obsidian-border) var(--obsidian-bg-deep); /* Firefox */
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/* WebKit Browsers (Chrome, Safari, Edge) */
|
|
757
|
+
.your-scrollable-container::-webkit-scrollbar {
|
|
758
|
+
width: 8px;
|
|
759
|
+
height: 8px;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
.your-scrollable-container::-webkit-scrollbar-track {
|
|
763
|
+
background: var(--obsidian-bg-deep);
|
|
764
|
+
border-radius: 4px;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.your-scrollable-container::-webkit-scrollbar-thumb {
|
|
768
|
+
background: var(--obsidian-border);
|
|
769
|
+
border-radius: 4px;
|
|
770
|
+
border: 1px solid transparent;
|
|
771
|
+
background-clip: content-box;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.your-scrollable-container::-webkit-scrollbar-thumb:hover {
|
|
775
|
+
background: var(--obsidian-gold-dim);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.your-scrollable-container::-webkit-scrollbar-corner {
|
|
779
|
+
background: var(--obsidian-bg-deep);
|
|
780
|
+
}
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### Size Variants
|
|
784
|
+
|
|
785
|
+
| Variant | Width | Use Case |
|
|
786
|
+
|---------|-------|----------|
|
|
787
|
+
| **Thin** | 6px | Compact lists, sidebars |
|
|
788
|
+
| **Standard** | 8px | Default for most containers |
|
|
789
|
+
| **Wide** | 12px | Main content areas, data tables |
|
|
790
|
+
|
|
791
|
+
```css
|
|
792
|
+
/* Thin variant */
|
|
793
|
+
.scrollbar-thin::-webkit-scrollbar { width: 6px; }
|
|
794
|
+
|
|
795
|
+
/* Wide variant */
|
|
796
|
+
.scrollbar-wide::-webkit-scrollbar { width: 12px; }
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
### Scrollbar Hover Glow Effect
|
|
800
|
+
|
|
801
|
+
For premium interactive feel, add a gold glow on hover:
|
|
802
|
+
|
|
803
|
+
```css
|
|
804
|
+
.premium-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
805
|
+
background: var(--obsidian-gold-dim);
|
|
806
|
+
box-shadow:
|
|
807
|
+
0 0 4px var(--obsidian-gold-glow),
|
|
808
|
+
inset 0 0 2px var(--obsidian-gold-glow);
|
|
809
|
+
}
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
### jsgui3 Integration
|
|
813
|
+
|
|
814
|
+
When building jsgui3 controls with scrollable areas, add scrollbar CSS in the control's factory:
|
|
815
|
+
|
|
816
|
+
```javascript
|
|
817
|
+
// In your control factory
|
|
818
|
+
class ScrollableListControl extends jsgui.Control {
|
|
819
|
+
constructor(spec = {}) {
|
|
820
|
+
super({ ...spec, tagName: 'div' });
|
|
821
|
+
this.dom.attributes.set('class', 'scrollable-list obsidian-scroll');
|
|
822
|
+
// ...
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
Reference CSS file:
|
|
828
|
+
- `src/ui/controls/DatabaseSelector.css` - Full implementation example
|
|
829
|
+
- `src/ui/css/obsidian-scrollbars.css` - Shared scrollbar utilities (create if needed)
|
|
830
|
+
|
|
831
|
+
### Best Practices
|
|
832
|
+
|
|
833
|
+
1. **Always include Firefox fallback** - `scrollbar-width: thin; scrollbar-color: ...`
|
|
834
|
+
2. **Use CSS variables** - Never hardcode colors
|
|
835
|
+
3. **Respect container borders** - Add `padding-right` to prevent content touching scrollbar
|
|
836
|
+
4. **Test dark mode** - Scrollbars should be subtle but visible
|
|
837
|
+
5. **Consider touch devices** - Scrollbar styles may be ignored on mobile
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## Related Resources
|
|
842
|
+
|
|
843
|
+
- `docs/diagrams/decision-tree-engine-deep-dive.svg` - Reference implementation
|
|
844
|
+
- `tools/dev/svg-validate.js` - Validation tool with hash indexing
|
|
845
|
+
- `tools/dev/svg-collisions.js` - Visual collision detection
|
|
846
|
+
- `tools/dev/svg-shared/hashUtils.js` - Element referencing utilities
|
|
847
|
+
- `src/ui/controls/DatabaseSelector.css` - Scrollbar implementation reference
|