forge-server 0.1.0
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/.claude/hooks/worktree-create.sh +64 -0
- package/.claude/hooks/worktree-remove.sh +57 -0
- package/.claude/settings.local.json +29 -0
- package/.forge/knowledge/conventions.yaml +1 -0
- package/.forge/knowledge/decisions.yaml +1 -0
- package/.forge/knowledge/gotchas.yaml +1 -0
- package/.forge/knowledge/patterns.yaml +1 -0
- package/.forge/manifest.yaml +6 -0
- package/CLAUDE.md +144 -0
- package/bin/setup-forge.sh +132 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +553 -0
- package/dist/cli.js.map +1 -0
- package/dist/context/codebase.d.ts +57 -0
- package/dist/context/codebase.d.ts.map +1 -0
- package/dist/context/codebase.js +301 -0
- package/dist/context/codebase.js.map +1 -0
- package/dist/context/injector.d.ts +147 -0
- package/dist/context/injector.d.ts.map +1 -0
- package/dist/context/injector.js +533 -0
- package/dist/context/injector.js.map +1 -0
- package/dist/context/memory.d.ts +32 -0
- package/dist/context/memory.d.ts.map +1 -0
- package/dist/context/memory.js +140 -0
- package/dist/context/memory.js.map +1 -0
- package/dist/context/session-index.d.ts +54 -0
- package/dist/context/session-index.d.ts.map +1 -0
- package/dist/context/session-index.js +265 -0
- package/dist/context/session-index.js.map +1 -0
- package/dist/context/session.d.ts +42 -0
- package/dist/context/session.d.ts.map +1 -0
- package/dist/context/session.js +121 -0
- package/dist/context/session.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/ingestion/chunker.d.ts +19 -0
- package/dist/ingestion/chunker.d.ts.map +1 -0
- package/dist/ingestion/chunker.js +189 -0
- package/dist/ingestion/chunker.js.map +1 -0
- package/dist/ingestion/embedder.d.ts +45 -0
- package/dist/ingestion/embedder.d.ts.map +1 -0
- package/dist/ingestion/embedder.js +152 -0
- package/dist/ingestion/embedder.js.map +1 -0
- package/dist/ingestion/git-analyzer.d.ts +77 -0
- package/dist/ingestion/git-analyzer.d.ts.map +1 -0
- package/dist/ingestion/git-analyzer.js +437 -0
- package/dist/ingestion/git-analyzer.js.map +1 -0
- package/dist/ingestion/indexer.d.ts +79 -0
- package/dist/ingestion/indexer.d.ts.map +1 -0
- package/dist/ingestion/indexer.js +766 -0
- package/dist/ingestion/indexer.js.map +1 -0
- package/dist/ingestion/markdown-chunker.d.ts +19 -0
- package/dist/ingestion/markdown-chunker.d.ts.map +1 -0
- package/dist/ingestion/markdown-chunker.js +243 -0
- package/dist/ingestion/markdown-chunker.js.map +1 -0
- package/dist/ingestion/markdown-knowledge.d.ts +21 -0
- package/dist/ingestion/markdown-knowledge.d.ts.map +1 -0
- package/dist/ingestion/markdown-knowledge.js +129 -0
- package/dist/ingestion/markdown-knowledge.js.map +1 -0
- package/dist/ingestion/parser.d.ts +20 -0
- package/dist/ingestion/parser.d.ts.map +1 -0
- package/dist/ingestion/parser.js +429 -0
- package/dist/ingestion/parser.js.map +1 -0
- package/dist/ingestion/watcher.d.ts +28 -0
- package/dist/ingestion/watcher.d.ts.map +1 -0
- package/dist/ingestion/watcher.js +147 -0
- package/dist/ingestion/watcher.js.map +1 -0
- package/dist/knowledge/hydrator.d.ts +37 -0
- package/dist/knowledge/hydrator.d.ts.map +1 -0
- package/dist/knowledge/hydrator.js +220 -0
- package/dist/knowledge/hydrator.js.map +1 -0
- package/dist/knowledge/registry.d.ts +129 -0
- package/dist/knowledge/registry.d.ts.map +1 -0
- package/dist/knowledge/registry.js +361 -0
- package/dist/knowledge/registry.js.map +1 -0
- package/dist/knowledge/search.d.ts +114 -0
- package/dist/knowledge/search.d.ts.map +1 -0
- package/dist/knowledge/search.js +428 -0
- package/dist/knowledge/search.js.map +1 -0
- package/dist/knowledge/store.d.ts +76 -0
- package/dist/knowledge/store.d.ts.map +1 -0
- package/dist/knowledge/store.js +230 -0
- package/dist/knowledge/store.js.map +1 -0
- package/dist/learning/confidence.d.ts +30 -0
- package/dist/learning/confidence.d.ts.map +1 -0
- package/dist/learning/confidence.js +165 -0
- package/dist/learning/confidence.js.map +1 -0
- package/dist/learning/patterns.d.ts +52 -0
- package/dist/learning/patterns.d.ts.map +1 -0
- package/dist/learning/patterns.js +290 -0
- package/dist/learning/patterns.js.map +1 -0
- package/dist/learning/trajectory.d.ts +55 -0
- package/dist/learning/trajectory.d.ts.map +1 -0
- package/dist/learning/trajectory.js +200 -0
- package/dist/learning/trajectory.js.map +1 -0
- package/dist/memory/memory-compat.d.ts +100 -0
- package/dist/memory/memory-compat.d.ts.map +1 -0
- package/dist/memory/memory-compat.js +146 -0
- package/dist/memory/memory-compat.js.map +1 -0
- package/dist/memory/observation-store.d.ts +57 -0
- package/dist/memory/observation-store.d.ts.map +1 -0
- package/dist/memory/observation-store.js +154 -0
- package/dist/memory/observation-store.js.map +1 -0
- package/dist/memory/session-tracker.d.ts +81 -0
- package/dist/memory/session-tracker.d.ts.map +1 -0
- package/dist/memory/session-tracker.js +262 -0
- package/dist/memory/session-tracker.js.map +1 -0
- package/dist/pipeline/engine.d.ts +179 -0
- package/dist/pipeline/engine.d.ts.map +1 -0
- package/dist/pipeline/engine.js +691 -0
- package/dist/pipeline/engine.js.map +1 -0
- package/dist/pipeline/events.d.ts +54 -0
- package/dist/pipeline/events.d.ts.map +1 -0
- package/dist/pipeline/events.js +157 -0
- package/dist/pipeline/events.js.map +1 -0
- package/dist/pipeline/parallel.d.ts +83 -0
- package/dist/pipeline/parallel.d.ts.map +1 -0
- package/dist/pipeline/parallel.js +277 -0
- package/dist/pipeline/parallel.js.map +1 -0
- package/dist/pipeline/state-machine.d.ts +65 -0
- package/dist/pipeline/state-machine.d.ts.map +1 -0
- package/dist/pipeline/state-machine.js +176 -0
- package/dist/pipeline/state-machine.js.map +1 -0
- package/dist/query/graph-queries.d.ts +84 -0
- package/dist/query/graph-queries.d.ts.map +1 -0
- package/dist/query/graph-queries.js +216 -0
- package/dist/query/graph-queries.js.map +1 -0
- package/dist/query/hybrid-search.d.ts +34 -0
- package/dist/query/hybrid-search.d.ts.map +1 -0
- package/dist/query/hybrid-search.js +263 -0
- package/dist/query/hybrid-search.js.map +1 -0
- package/dist/query/intent-detector.d.ts +35 -0
- package/dist/query/intent-detector.d.ts.map +1 -0
- package/dist/query/intent-detector.js +115 -0
- package/dist/query/intent-detector.js.map +1 -0
- package/dist/query/ranking.d.ts +57 -0
- package/dist/query/ranking.d.ts.map +1 -0
- package/dist/query/ranking.js +109 -0
- package/dist/query/ranking.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +291 -0
- package/dist/server.js.map +1 -0
- package/dist/storage/falkordb-store.d.ts +73 -0
- package/dist/storage/falkordb-store.d.ts.map +1 -0
- package/dist/storage/falkordb-store.js +346 -0
- package/dist/storage/falkordb-store.js.map +1 -0
- package/dist/storage/file-cache.d.ts +32 -0
- package/dist/storage/file-cache.d.ts.map +1 -0
- package/dist/storage/file-cache.js +115 -0
- package/dist/storage/file-cache.js.map +1 -0
- package/dist/storage/interfaces.d.ts +151 -0
- package/dist/storage/interfaces.d.ts.map +1 -0
- package/dist/storage/interfaces.js +7 -0
- package/dist/storage/interfaces.js.map +1 -0
- package/dist/storage/qdrant-store.d.ts +110 -0
- package/dist/storage/qdrant-store.d.ts.map +1 -0
- package/dist/storage/qdrant-store.js +467 -0
- package/dist/storage/qdrant-store.js.map +1 -0
- package/dist/storage/schema.d.ts +4 -0
- package/dist/storage/schema.d.ts.map +1 -0
- package/dist/storage/schema.js +136 -0
- package/dist/storage/schema.js.map +1 -0
- package/dist/storage/sqlite.d.ts +35 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +132 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/tools/collaboration-tools.d.ts +111 -0
- package/dist/tools/collaboration-tools.d.ts.map +1 -0
- package/dist/tools/collaboration-tools.js +174 -0
- package/dist/tools/collaboration-tools.js.map +1 -0
- package/dist/tools/context-tools.d.ts +293 -0
- package/dist/tools/context-tools.d.ts.map +1 -0
- package/dist/tools/context-tools.js +437 -0
- package/dist/tools/context-tools.js.map +1 -0
- package/dist/tools/graph-tools.d.ts +129 -0
- package/dist/tools/graph-tools.d.ts.map +1 -0
- package/dist/tools/graph-tools.js +237 -0
- package/dist/tools/graph-tools.js.map +1 -0
- package/dist/tools/ingestion-tools.d.ts +96 -0
- package/dist/tools/ingestion-tools.d.ts.map +1 -0
- package/dist/tools/ingestion-tools.js +90 -0
- package/dist/tools/ingestion-tools.js.map +1 -0
- package/dist/tools/learning-tools.d.ts +168 -0
- package/dist/tools/learning-tools.d.ts.map +1 -0
- package/dist/tools/learning-tools.js +158 -0
- package/dist/tools/learning-tools.js.map +1 -0
- package/dist/tools/memory-tools.d.ts +183 -0
- package/dist/tools/memory-tools.d.ts.map +1 -0
- package/dist/tools/memory-tools.js +197 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/phase-tools.d.ts +954 -0
- package/dist/tools/phase-tools.d.ts.map +1 -0
- package/dist/tools/phase-tools.js +1215 -0
- package/dist/tools/phase-tools.js.map +1 -0
- package/dist/tools/pipeline-tools.d.ts +140 -0
- package/dist/tools/pipeline-tools.d.ts.map +1 -0
- package/dist/tools/pipeline-tools.js +162 -0
- package/dist/tools/pipeline-tools.js.map +1 -0
- package/dist/tools/registration-tools.d.ts +220 -0
- package/dist/tools/registration-tools.d.ts.map +1 -0
- package/dist/tools/registration-tools.js +391 -0
- package/dist/tools/registration-tools.js.map +1 -0
- package/dist/util/circuit-breaker.d.ts +75 -0
- package/dist/util/circuit-breaker.d.ts.map +1 -0
- package/dist/util/circuit-breaker.js +159 -0
- package/dist/util/circuit-breaker.js.map +1 -0
- package/dist/util/config.d.ts +23 -0
- package/dist/util/config.d.ts.map +1 -0
- package/dist/util/config.js +164 -0
- package/dist/util/config.js.map +1 -0
- package/dist/util/logger.d.ts +13 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +45 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/token-counter.d.ts +24 -0
- package/dist/util/token-counter.d.ts.map +1 -0
- package/dist/util/token-counter.js +48 -0
- package/dist/util/token-counter.js.map +1 -0
- package/dist/util/types.d.ts +525 -0
- package/dist/util/types.d.ts.map +1 -0
- package/dist/util/types.js +5 -0
- package/dist/util/types.js.map +1 -0
- package/docker-compose.yml +20 -0
- package/docs/plans/2026-02-27-swarm-coordination/architecture.md +203 -0
- package/docs/plans/2026-02-27-swarm-coordination/vision.md +57 -0
- package/docs/plans/completed/2026-02-26-forge-plugin-bundling/architecture.md +1 -0
- package/docs/plans/completed/2026-02-26-forge-plugin-bundling/vision.md +300 -0
- package/docs/plans/completed/2026-02-27-forge-swarm-learning/architecture.md +480 -0
- package/docs/plans/completed/2026-02-27-forge-swarm-learning/verification-checklist.md +462 -0
- package/docs/plans/completed/2026-02-27-git-history-atlassian/git-jira-plan.md +181 -0
- package/package.json +39 -0
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/.mcp.json +15 -0
- package/plugin/README.md +134 -0
- package/plugin/agents/architect.md +367 -0
- package/plugin/agents/backend-specialist.md +263 -0
- package/plugin/agents/brainstormer.md +122 -0
- package/plugin/agents/data-specialist.md +266 -0
- package/plugin/agents/designer.md +408 -0
- package/plugin/agents/frontend-specialist.md +241 -0
- package/plugin/agents/inspector.md +406 -0
- package/plugin/agents/knowledge-keeper.md +443 -0
- package/plugin/agents/platform-engineer.md +326 -0
- package/plugin/agents/product-manager.md +268 -0
- package/plugin/agents/product-owner.md +438 -0
- package/plugin/agents/pulse-checker.md +73 -0
- package/plugin/agents/qa-strategist.md +500 -0
- package/plugin/agents/self-improver.md +310 -0
- package/plugin/agents/strategist.md +360 -0
- package/plugin/agents/supervisor.md +380 -0
- package/plugin/commands/brainstorm.md +25 -0
- package/plugin/commands/forge.md +88 -0
- package/plugin/docs/atlassian-integration.md +110 -0
- package/plugin/docs/workflow.md +126 -0
- package/plugin/skills/agent-development/.skillfish.json +10 -0
- package/plugin/skills/agent-development/SKILL.md +415 -0
- package/plugin/skills/agent-development/examples/agent-creation-prompt.md +238 -0
- package/plugin/skills/agent-development/examples/complete-agent-examples.md +427 -0
- package/plugin/skills/agent-development/references/agent-creation-system-prompt.md +207 -0
- package/plugin/skills/agent-development/references/system-prompt-design.md +411 -0
- package/plugin/skills/agent-development/references/triggering-examples.md +491 -0
- package/plugin/skills/agent-development/scripts/validate-agent.sh +217 -0
- package/plugin/skills/agent-handoff/SKILL.md +335 -0
- package/plugin/skills/anti-stub/SKILL.md +317 -0
- package/plugin/skills/brainstorm/SKILL.md +31 -0
- package/plugin/skills/debugging/SKILL.md +276 -0
- package/plugin/skills/fix/SKILL.md +62 -0
- package/plugin/skills/frontend-design/.skillfish.json +10 -0
- package/plugin/skills/frontend-design/SKILL.md +42 -0
- package/plugin/skills/gotchas/SKILL.md +61 -0
- package/plugin/skills/graph-orchestrator/SKILL.md +38 -0
- package/plugin/skills/history/SKILL.md +58 -0
- package/plugin/skills/impact/SKILL.md +59 -0
- package/plugin/skills/implementation-execution/SKILL.md +291 -0
- package/plugin/skills/index-repo/SKILL.md +55 -0
- package/plugin/skills/interviewing/SKILL.md +225 -0
- package/plugin/skills/knowledge-curation/SKILL.md +393 -0
- package/plugin/skills/learn/SKILL.md +69 -0
- package/plugin/skills/mcp-integration/.skillfish.json +10 -0
- package/plugin/skills/mcp-integration/SKILL.md +554 -0
- package/plugin/skills/mcp-integration/examples/http-server.json +20 -0
- package/plugin/skills/mcp-integration/examples/sse-server.json +19 -0
- package/plugin/skills/mcp-integration/examples/stdio-server.json +26 -0
- package/plugin/skills/mcp-integration/references/authentication.md +549 -0
- package/plugin/skills/mcp-integration/references/server-types.md +536 -0
- package/plugin/skills/mcp-integration/references/tool-usage.md +538 -0
- package/plugin/skills/nestjs/.skillfish.json +10 -0
- package/plugin/skills/nestjs/SKILL.md +669 -0
- package/plugin/skills/nestjs/drizzle-reference.md +1894 -0
- package/plugin/skills/nestjs/reference.md +1447 -0
- package/plugin/skills/nestjs/workflow-optimization.md +229 -0
- package/plugin/skills/parallel-dispatch/SKILL.md +308 -0
- package/plugin/skills/project-discovery/SKILL.md +304 -0
- package/plugin/skills/search/SKILL.md +56 -0
- package/plugin/skills/security-audit/SKILL.md +362 -0
- package/plugin/skills/skill-development/.skillfish.json +10 -0
- package/plugin/skills/skill-development/SKILL.md +637 -0
- package/plugin/skills/skill-development/references/skill-creator-original.md +209 -0
- package/plugin/skills/tdd/SKILL.md +273 -0
- package/plugin/skills/terminal-presentation/SKILL.md +395 -0
- package/plugin/skills/test-strategy/SKILL.md +365 -0
- package/plugin/skills/verification-protocol/SKILL.md +256 -0
- package/plugin/skills/visual-explainer/CHANGELOG.md +97 -0
- package/plugin/skills/visual-explainer/LICENSE +21 -0
- package/plugin/skills/visual-explainer/README.md +137 -0
- package/plugin/skills/visual-explainer/SKILL.md +352 -0
- package/plugin/skills/visual-explainer/banner.png +0 -0
- package/plugin/skills/visual-explainer/package.json +11 -0
- package/plugin/skills/visual-explainer/prompts/diff-review.md +68 -0
- package/plugin/skills/visual-explainer/prompts/fact-check.md +63 -0
- package/plugin/skills/visual-explainer/prompts/generate-slides.md +18 -0
- package/plugin/skills/visual-explainer/prompts/generate-web-diagram.md +10 -0
- package/plugin/skills/visual-explainer/prompts/plan-review.md +86 -0
- package/plugin/skills/visual-explainer/prompts/project-recap.md +61 -0
- package/plugin/skills/visual-explainer/references/css-patterns.md +1188 -0
- package/plugin/skills/visual-explainer/references/libraries.md +470 -0
- package/plugin/skills/visual-explainer/references/responsive-nav.md +212 -0
- package/plugin/skills/visual-explainer/references/slide-patterns.md +1403 -0
- package/plugin/skills/visual-explainer/templates/architecture.html +596 -0
- package/plugin/skills/visual-explainer/templates/data-table.html +540 -0
- package/plugin/skills/visual-explainer/templates/mermaid-flowchart.html +435 -0
- package/plugin/skills/visual-explainer/templates/slide-deck.html +913 -0
- package/src/cli.ts +655 -0
- package/src/context/.gitkeep +0 -0
- package/src/context/codebase.ts +393 -0
- package/src/context/injector.ts +797 -0
- package/src/context/memory.ts +187 -0
- package/src/context/session-index.ts +327 -0
- package/src/context/session.ts +152 -0
- package/src/index.ts +47 -0
- package/src/ingestion/.gitkeep +0 -0
- package/src/ingestion/chunker.ts +277 -0
- package/src/ingestion/embedder.ts +167 -0
- package/src/ingestion/git-analyzer.ts +545 -0
- package/src/ingestion/indexer.ts +984 -0
- package/src/ingestion/markdown-chunker.ts +337 -0
- package/src/ingestion/markdown-knowledge.ts +175 -0
- package/src/ingestion/parser.ts +475 -0
- package/src/ingestion/watcher.ts +182 -0
- package/src/knowledge/.gitkeep +0 -0
- package/src/knowledge/hydrator.ts +246 -0
- package/src/knowledge/registry.ts +463 -0
- package/src/knowledge/search.ts +565 -0
- package/src/knowledge/store.ts +262 -0
- package/src/learning/.gitkeep +0 -0
- package/src/learning/confidence.ts +193 -0
- package/src/learning/patterns.ts +360 -0
- package/src/learning/trajectory.ts +268 -0
- package/src/memory/.gitkeep +0 -0
- package/src/memory/memory-compat.ts +233 -0
- package/src/memory/observation-store.ts +224 -0
- package/src/memory/session-tracker.ts +332 -0
- package/src/pipeline/.gitkeep +0 -0
- package/src/pipeline/engine.ts +1139 -0
- package/src/pipeline/events.ts +253 -0
- package/src/pipeline/parallel.ts +394 -0
- package/src/pipeline/state-machine.ts +199 -0
- package/src/query/.gitkeep +0 -0
- package/src/query/graph-queries.ts +262 -0
- package/src/query/hybrid-search.ts +337 -0
- package/src/query/intent-detector.ts +131 -0
- package/src/query/ranking.ts +161 -0
- package/src/server.ts +352 -0
- package/src/storage/.gitkeep +0 -0
- package/src/storage/falkordb-store.ts +388 -0
- package/src/storage/file-cache.ts +141 -0
- package/src/storage/interfaces.ts +201 -0
- package/src/storage/qdrant-store.ts +557 -0
- package/src/storage/schema.ts +139 -0
- package/src/storage/sqlite.ts +168 -0
- package/src/tools/.gitkeep +0 -0
- package/src/tools/collaboration-tools.ts +208 -0
- package/src/tools/context-tools.ts +493 -0
- package/src/tools/graph-tools.ts +295 -0
- package/src/tools/ingestion-tools.ts +122 -0
- package/src/tools/learning-tools.ts +181 -0
- package/src/tools/memory-tools.ts +234 -0
- package/src/tools/phase-tools.ts +1452 -0
- package/src/tools/pipeline-tools.ts +188 -0
- package/src/tools/registration-tools.ts +450 -0
- package/src/util/.gitkeep +0 -0
- package/src/util/circuit-breaker.ts +193 -0
- package/src/util/config.ts +177 -0
- package/src/util/logger.ts +53 -0
- package/src/util/token-counter.ts +52 -0
- package/src/util/types.ts +710 -0
- package/tests/context/.gitkeep +0 -0
- package/tests/integration/.gitkeep +0 -0
- package/tests/knowledge/.gitkeep +0 -0
- package/tests/learning/.gitkeep +0 -0
- package/tests/pipeline/.gitkeep +0 -0
- package/tests/tools/.gitkeep +0 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +10 -0
- package/vscode-extension/.vscodeignore +7 -0
- package/vscode-extension/README.md +43 -0
- package/vscode-extension/out/edge-collector.js +274 -0
- package/vscode-extension/out/edge-collector.js.map +1 -0
- package/vscode-extension/out/extension.js +264 -0
- package/vscode-extension/out/extension.js.map +1 -0
- package/vscode-extension/out/forge-client.js +318 -0
- package/vscode-extension/out/forge-client.js.map +1 -0
- package/vscode-extension/package-lock.json +59 -0
- package/vscode-extension/package.json +71 -0
- package/vscode-extension/src/edge-collector.ts +320 -0
- package/vscode-extension/src/extension.ts +269 -0
- package/vscode-extension/src/forge-client.ts +364 -0
- package/vscode-extension/tsconfig.json +19 -0
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
# External Libraries (CDN)
|
|
2
|
+
|
|
3
|
+
Optional CDN libraries for cases where pure CSS/HTML isn't enough. Only include what the diagram actually needs — most diagrams need zero external JS.
|
|
4
|
+
|
|
5
|
+
## Mermaid.js — Diagramming Engine
|
|
6
|
+
|
|
7
|
+
Use for flowcharts, sequence diagrams, ER diagrams, state machines, mind maps, class diagrams, and any diagram where automatic node positioning and edge routing saves effort. Mermaid handles layout — you handle theming.
|
|
8
|
+
|
|
9
|
+
Do NOT use for dashboards — CSS Grid card layouts with Chart.js look better for those. Data tables use `<table>` elements.
|
|
10
|
+
|
|
11
|
+
**CDN:**
|
|
12
|
+
```html
|
|
13
|
+
<script type="module">
|
|
14
|
+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
|
15
|
+
|
|
16
|
+
mermaid.initialize({ startOnLoad: true, /* ... */ });
|
|
17
|
+
</script>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**With ELK layout** (required for `layout: 'elk'` — it's a separate package, not bundled in core):
|
|
21
|
+
```html
|
|
22
|
+
<script type="module">
|
|
23
|
+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
|
24
|
+
import elkLayouts from 'https://cdn.jsdelivr.net/npm/@mermaid-js/layout-elk/dist/mermaid-layout-elk.esm.min.mjs';
|
|
25
|
+
|
|
26
|
+
mermaid.registerLayoutLoaders(elkLayouts);
|
|
27
|
+
mermaid.initialize({ startOnLoad: true, layout: 'elk', /* ... */ });
|
|
28
|
+
</script>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Without the ELK import and registration, `layout: 'elk'` silently falls back to dagre. Only import ELK when you actually need it — it adds significant bundle weight. Most simple diagrams render fine with dagre.
|
|
32
|
+
|
|
33
|
+
### Deep Theming
|
|
34
|
+
|
|
35
|
+
Always use `theme: 'base'` — it's the only theme where all `themeVariables` are fully customizable. The built-in themes (`default`, `dark`, `forest`, `neutral`) ignore most variable overrides.
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<script type="module">
|
|
39
|
+
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
|
40
|
+
|
|
41
|
+
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
42
|
+
mermaid.initialize({
|
|
43
|
+
startOnLoad: true,
|
|
44
|
+
theme: 'base',
|
|
45
|
+
look: 'classic',
|
|
46
|
+
themeVariables: {
|
|
47
|
+
// Background and surfaces — teal/slate palette (not violet/indigo!)
|
|
48
|
+
primaryColor: isDark ? '#134e4a' : '#ccfbf1',
|
|
49
|
+
primaryBorderColor: isDark ? '#14b8a6' : '#0d9488',
|
|
50
|
+
primaryTextColor: isDark ? '#f0fdfa' : '#134e4a',
|
|
51
|
+
secondaryColor: isDark ? '#1e293b' : '#f0fdf4',
|
|
52
|
+
secondaryBorderColor: isDark ? '#059669' : '#16a34a',
|
|
53
|
+
secondaryTextColor: isDark ? '#f1f5f9' : '#1e293b',
|
|
54
|
+
tertiaryColor: isDark ? '#27201a' : '#fef3c7',
|
|
55
|
+
tertiaryBorderColor: isDark ? '#d97706' : '#f59e0b',
|
|
56
|
+
tertiaryTextColor: isDark ? '#fef3c7' : '#27201a',
|
|
57
|
+
// Lines and edges
|
|
58
|
+
lineColor: isDark ? '#64748b' : '#94a3b8',
|
|
59
|
+
// Text
|
|
60
|
+
fontSize: '16px',
|
|
61
|
+
fontFamily: 'var(--font-body)',
|
|
62
|
+
// Notes and labels
|
|
63
|
+
noteBkgColor: isDark ? '#1e293b' : '#fefce8',
|
|
64
|
+
noteTextColor: isDark ? '#f1f5f9' : '#1e293b',
|
|
65
|
+
noteBorderColor: isDark ? '#fbbf24' : '#d97706',
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**FORBIDDEN in Mermaid themeVariables:** `#8b5cf6`, `#7c3aed`, `#a78bfa` (indigo/violet), `#d946ef` (fuchsia). Use teal, slate, amber, emerald, or colors from your page's palette.
|
|
72
|
+
|
|
73
|
+
### CSS Overrides on Mermaid SVG
|
|
74
|
+
|
|
75
|
+
Mermaid renders SVG. Override its classes for pixel-perfect control that `themeVariables` can't reach:
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
/* Container — see css-patterns.md "Mermaid Zoom Controls" for the full zoom pattern */
|
|
79
|
+
.mermaid-wrap {
|
|
80
|
+
position: relative;
|
|
81
|
+
background: var(--surface);
|
|
82
|
+
border: 1px solid var(--border);
|
|
83
|
+
border-radius: 12px;
|
|
84
|
+
padding: 24px;
|
|
85
|
+
overflow: auto;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* CRITICAL: Force node/edge text to follow the page's color scheme.
|
|
89
|
+
Without this, themeVariables.primaryTextColor works for DEFAULT nodes,
|
|
90
|
+
but any classDef that sets color: will hardcode a single value that
|
|
91
|
+
breaks in the opposite color scheme. Fix: never set color: in classDef,
|
|
92
|
+
and always include these CSS overrides. */
|
|
93
|
+
.mermaid .nodeLabel { color: var(--text) !important; }
|
|
94
|
+
.mermaid .edgeLabel { color: var(--text-dim) !important; background-color: var(--bg) !important; }
|
|
95
|
+
.mermaid .edgeLabel rect { fill: var(--bg) !important; }
|
|
96
|
+
|
|
97
|
+
/* Node shapes */
|
|
98
|
+
.mermaid .node rect,
|
|
99
|
+
.mermaid .node circle,
|
|
100
|
+
.mermaid .node polygon {
|
|
101
|
+
stroke-width: 1.5px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Edge paths */
|
|
105
|
+
.mermaid .edge-pattern-solid {
|
|
106
|
+
stroke-width: 1.5px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Edge labels — smaller than node labels for visual hierarchy */
|
|
110
|
+
.mermaid .edgeLabel {
|
|
111
|
+
font-family: var(--font-mono) !important;
|
|
112
|
+
font-size: 13px !important;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Node labels — 16px default; drop to 14px for complex diagrams (20+ nodes) */
|
|
116
|
+
.mermaid .nodeLabel {
|
|
117
|
+
font-family: var(--font-body) !important;
|
|
118
|
+
font-size: 16px !important;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* Sequence diagram actors */
|
|
122
|
+
.mermaid .actor {
|
|
123
|
+
stroke-width: 1.5px;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Sequence diagram messages */
|
|
127
|
+
.mermaid .messageText {
|
|
128
|
+
font-family: var(--font-mono) !important;
|
|
129
|
+
font-size: 12px !important;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* ER diagram entities */
|
|
133
|
+
.mermaid .er.entityBox {
|
|
134
|
+
stroke-width: 1.5px;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Mind map nodes */
|
|
138
|
+
.mermaid .mindmap-node rect {
|
|
139
|
+
stroke-width: 1.5px;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### classDef and style Gotchas
|
|
144
|
+
|
|
145
|
+
`classDef` values and per-node `style` directives are static text inside `<pre>` — they can't use CSS variables or JS ternaries. Two rules:
|
|
146
|
+
|
|
147
|
+
1. **Never set `color:` in classDef or per-node `style` directives.** It hardcodes a text color that breaks in the opposite color scheme. This applies to both `classDef highlight fill:...,color:#2c2a25` and `style I fill:...,color:#2c2a25`. Let the CSS overrides above handle text color via `var(--text)`.
|
|
148
|
+
|
|
149
|
+
2. **Use semi-transparent fills (8-digit hex) for node backgrounds.** They layer over whatever Mermaid's base theme background is, producing a tint that works in both light and dark modes. Use `20`–`44` alpha for subtle, `55`–`77` for prominent:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
classDef highlight fill:#b5761433,stroke:#b57614,stroke-width:2px
|
|
153
|
+
classDef muted fill:#7c6f6411,stroke:#7c6f6444,stroke-width:1px
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Avoid opaque light fills like `fill:#fefce8` — they render as bright boxes in dark mode.
|
|
157
|
+
|
|
158
|
+
### stateDiagram-v2 Label Limitations
|
|
159
|
+
|
|
160
|
+
State diagram transition labels have a strict parser. Avoid:
|
|
161
|
+
- `<br/>` — only works in flowcharts; causes a parse error in state diagrams
|
|
162
|
+
- Parentheses in labels — `cancel()` can confuse the parser
|
|
163
|
+
- Multiple colons — the first `:` is the label delimiter; extra colons in the label text may break parsing
|
|
164
|
+
|
|
165
|
+
If you need multi-line labels or special characters, use a `flowchart` instead of `stateDiagram-v2`. Flowcharts support quoted labels (`|"label with: special chars"|`) and `<br/>` for line breaks.
|
|
166
|
+
|
|
167
|
+
### Writing Valid Mermaid
|
|
168
|
+
|
|
169
|
+
Most Mermaid failures come from a few recurring issues. Follow these rules to avoid invalid diagrams:
|
|
170
|
+
|
|
171
|
+
**Quote labels with special characters.** Parentheses, colons, commas, brackets, and ampersands break the parser when unquoted. Wrap any label containing special characters in double quotes:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
A["handleRequest(ctx)"] --> B["DB: query users"]
|
|
175
|
+
A[handleRequest] --> B[query users]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Keep IDs simple.** Node IDs should be alphanumeric with no spaces or punctuation. Put the readable name in the label, not the ID:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
userSvc["User Service"] --> authSvc["Auth Service"]
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Max 15-20 nodes per diagram.** Beyond that, readability collapses even with ELK layout. Use `subgraph` blocks to group related nodes, or split into multiple diagrams:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
subgraph Auth
|
|
188
|
+
login --> validate --> token
|
|
189
|
+
end
|
|
190
|
+
subgraph API
|
|
191
|
+
gateway --> router --> handler
|
|
192
|
+
end
|
|
193
|
+
Auth --> API
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Arrow styles for semantic meaning:**
|
|
197
|
+
|
|
198
|
+
| Arrow | Meaning | Use for |
|
|
199
|
+
|-------|---------|---------|
|
|
200
|
+
| `-->` | Solid | Primary flow |
|
|
201
|
+
| `-.->` | Dotted | Optional, async, or fallback paths |
|
|
202
|
+
| `==>` | Thick | Critical or highlighted path |
|
|
203
|
+
| `--x` | Cross | Rejected or blocked |
|
|
204
|
+
| `-->\|label\|` | Labeled | Decision branches, data descriptions |
|
|
205
|
+
|
|
206
|
+
**Escape pipes in labels.** If a label contains a literal `|`, use `#124;` (HTML entity) or rephrase to avoid it — pipes delimit edge labels in flowcharts.
|
|
207
|
+
|
|
208
|
+
**Sequence diagram messages must be plain text.** Unlike flowchart labels, sequence diagram messages (the text after `:`) cannot be quoted or escaped. Curly braces `{}`, square brackets `[]`, angle brackets `<>`, and `&` will silently break the parser and the entire diagram renders as raw text. Write human-readable descriptions, not code:
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
%% WRONG — parser chokes on braces, brackets, ampersand
|
|
212
|
+
A->>B: web_search({ queries: [...] })
|
|
213
|
+
B->>B: User removes query 2, keeps 1 & 3
|
|
214
|
+
B->>S: POST /submit { selected: [0, 2] }
|
|
215
|
+
|
|
216
|
+
%% RIGHT — plain English, no special characters
|
|
217
|
+
A->>B: Call web_search with queries
|
|
218
|
+
B->>B: User removes query 2, keeps 1 and 3
|
|
219
|
+
B->>S: POST /submit with selected indices
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Don't mix diagram syntax.** Each diagram type has its own syntax. `-->` works in flowcharts but not in sequence diagrams (`->>` instead). `:::className` works in flowcharts but not in ER diagrams. When in doubt, check the examples below for correct syntax per type.
|
|
223
|
+
|
|
224
|
+
### Diagram Type Examples
|
|
225
|
+
|
|
226
|
+
**Flowchart with decisions:**
|
|
227
|
+
```html
|
|
228
|
+
<pre class="mermaid">
|
|
229
|
+
graph TD
|
|
230
|
+
A[Request] --> B{Authenticated?}
|
|
231
|
+
B -->|Yes| C[Load Dashboard]
|
|
232
|
+
B -->|No| D[Login Page]
|
|
233
|
+
D --> E[Submit Credentials]
|
|
234
|
+
E --> B
|
|
235
|
+
C --> F{Role?}
|
|
236
|
+
F -->|Admin| G[Admin Panel]
|
|
237
|
+
F -->|User| H[User Dashboard]
|
|
238
|
+
</pre>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Sequence diagram:**
|
|
242
|
+
```html
|
|
243
|
+
<pre class="mermaid">
|
|
244
|
+
sequenceDiagram
|
|
245
|
+
participant C as Client
|
|
246
|
+
participant G as Gateway
|
|
247
|
+
participant S as Service
|
|
248
|
+
participant D as Database
|
|
249
|
+
C->>G: POST /api/data
|
|
250
|
+
G->>G: Validate JWT
|
|
251
|
+
G->>S: Forward request
|
|
252
|
+
S->>D: Query
|
|
253
|
+
D-->>S: Results
|
|
254
|
+
S-->>G: Response
|
|
255
|
+
G-->>C: 200 OK
|
|
256
|
+
</pre>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**ER diagram:**
|
|
260
|
+
```html
|
|
261
|
+
<pre class="mermaid">
|
|
262
|
+
erDiagram
|
|
263
|
+
USERS ||--o{ ORDERS : places
|
|
264
|
+
ORDERS ||--|{ LINE_ITEMS : contains
|
|
265
|
+
LINE_ITEMS }o--|| PRODUCTS : references
|
|
266
|
+
USERS { string email PK }
|
|
267
|
+
ORDERS { int id PK }
|
|
268
|
+
LINE_ITEMS { int quantity }
|
|
269
|
+
PRODUCTS { string name }
|
|
270
|
+
</pre>
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**State diagram:**
|
|
274
|
+
```html
|
|
275
|
+
<pre class="mermaid">
|
|
276
|
+
stateDiagram-v2
|
|
277
|
+
[*] --> Draft
|
|
278
|
+
Draft --> Review : submit
|
|
279
|
+
Review --> Approved : approve
|
|
280
|
+
Review --> Draft : request_changes
|
|
281
|
+
Approved --> Published : publish
|
|
282
|
+
Published --> Archived : archive
|
|
283
|
+
Archived --> [*]
|
|
284
|
+
</pre>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Mind map:**
|
|
288
|
+
```html
|
|
289
|
+
<pre class="mermaid">
|
|
290
|
+
mindmap
|
|
291
|
+
root((Project))
|
|
292
|
+
Frontend
|
|
293
|
+
React
|
|
294
|
+
Next.js
|
|
295
|
+
Tailwind
|
|
296
|
+
Backend
|
|
297
|
+
Node.js
|
|
298
|
+
PostgreSQL
|
|
299
|
+
Redis
|
|
300
|
+
Infrastructure
|
|
301
|
+
AWS
|
|
302
|
+
Docker
|
|
303
|
+
Terraform
|
|
304
|
+
</pre>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### Dark Mode Handling
|
|
308
|
+
|
|
309
|
+
Mermaid initializes once — it can't reactively switch themes. Read the preference at load time inside your `<script type="module">`:
|
|
310
|
+
|
|
311
|
+
```javascript
|
|
312
|
+
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
313
|
+
// Use isDark to pick light or dark values in themeVariables
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The CSS overrides on the container (`.mermaid-wrap`) and page will still respond to `prefers-color-scheme` normally — only the Mermaid SVG internals are static.
|
|
317
|
+
|
|
318
|
+
## Chart.js — Data Visualizations
|
|
319
|
+
|
|
320
|
+
Use for bar charts, line charts, pie/doughnut charts, radar charts, and other data-driven visualizations in dashboard-type diagrams. Overkill for static numbers — use pure SVG/CSS for simple progress bars and sparklines.
|
|
321
|
+
|
|
322
|
+
```html
|
|
323
|
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
|
|
324
|
+
|
|
325
|
+
<canvas id="myChart" width="600" height="300"></canvas>
|
|
326
|
+
|
|
327
|
+
<script>
|
|
328
|
+
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
329
|
+
const textColor = isDark ? '#8b949e' : '#6b7280';
|
|
330
|
+
const gridColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)';
|
|
331
|
+
const fontFamily = getComputedStyle(document.documentElement)
|
|
332
|
+
.getPropertyValue('--font-body').trim() || 'system-ui, sans-serif';
|
|
333
|
+
|
|
334
|
+
new Chart(document.getElementById('myChart'), {
|
|
335
|
+
type: 'bar',
|
|
336
|
+
data: {
|
|
337
|
+
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
|
|
338
|
+
datasets: [{
|
|
339
|
+
label: 'Feedback Items',
|
|
340
|
+
data: [45, 62, 78, 91, 120],
|
|
341
|
+
backgroundColor: isDark ? 'rgba(129, 140, 248, 0.6)' : 'rgba(79, 70, 229, 0.6)',
|
|
342
|
+
borderColor: isDark ? '#818cf8' : '#4f46e5',
|
|
343
|
+
borderWidth: 1,
|
|
344
|
+
borderRadius: 4,
|
|
345
|
+
}]
|
|
346
|
+
},
|
|
347
|
+
options: {
|
|
348
|
+
responsive: true,
|
|
349
|
+
plugins: {
|
|
350
|
+
legend: { labels: { color: textColor, font: { family: fontFamily } } },
|
|
351
|
+
},
|
|
352
|
+
scales: {
|
|
353
|
+
x: { ticks: { color: textColor, font: { family: fontFamily } }, grid: { color: gridColor } },
|
|
354
|
+
y: { ticks: { color: textColor, font: { family: fontFamily } }, grid: { color: gridColor } },
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
</script>
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Wrap the canvas in a styled container:
|
|
362
|
+
```css
|
|
363
|
+
.chart-container {
|
|
364
|
+
background: var(--surface);
|
|
365
|
+
border: 1px solid var(--border);
|
|
366
|
+
border-radius: 10px;
|
|
367
|
+
padding: 20px;
|
|
368
|
+
position: relative;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.chart-container canvas {
|
|
372
|
+
max-height: 300px;
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## anime.js — Orchestrated Animations
|
|
377
|
+
|
|
378
|
+
Use when a diagram has 10+ elements and you want a choreographed entrance sequence (staggered reveals, path drawing, count-up numbers). For simpler diagrams, CSS `animation-delay` staggering is sufficient.
|
|
379
|
+
|
|
380
|
+
```html
|
|
381
|
+
<script src="https://cdn.jsdelivr.net/npm/animejs@3.2.2/lib/anime.min.js"></script>
|
|
382
|
+
|
|
383
|
+
<script>
|
|
384
|
+
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
385
|
+
|
|
386
|
+
if (!prefersReduced) {
|
|
387
|
+
anime({
|
|
388
|
+
targets: '.ve-card',
|
|
389
|
+
opacity: [0, 1],
|
|
390
|
+
translateY: [20, 0],
|
|
391
|
+
delay: anime.stagger(80, { start: 200 }),
|
|
392
|
+
easing: 'easeOutCubic',
|
|
393
|
+
duration: 500,
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
anime({
|
|
397
|
+
targets: '.connector path',
|
|
398
|
+
strokeDashoffset: [anime.setDashoffset, 0],
|
|
399
|
+
easing: 'easeInOutCubic',
|
|
400
|
+
duration: 800,
|
|
401
|
+
delay: anime.stagger(150, { start: 600 }),
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
document.querySelectorAll('[data-count]').forEach(el => {
|
|
405
|
+
anime({
|
|
406
|
+
targets: { val: 0 },
|
|
407
|
+
val: parseInt(el.dataset.count),
|
|
408
|
+
round: 1,
|
|
409
|
+
duration: 1200,
|
|
410
|
+
delay: 400,
|
|
411
|
+
easing: 'easeOutExpo',
|
|
412
|
+
update: (anim) => { el.textContent = anim.animations[0].currentValue; }
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
</script>
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
When using anime.js, set initial opacity to 0 in CSS so elements don't flash before the animation:
|
|
420
|
+
```css
|
|
421
|
+
.ve-card { opacity: 0; }
|
|
422
|
+
|
|
423
|
+
@media (prefers-reduced-motion: reduce) {
|
|
424
|
+
.ve-card { opacity: 1 !important; }
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## Google Fonts — Typography
|
|
429
|
+
|
|
430
|
+
Always load with `display=swap` for fast rendering. Pick a distinctive pairing — body + mono at minimum, optionally a display font for the title.
|
|
431
|
+
|
|
432
|
+
**FORBIDDEN as `--font-body` (AI slop signals):**
|
|
433
|
+
- Inter — the single most overused AI default font
|
|
434
|
+
- Roboto — generic Android/Google default
|
|
435
|
+
- Arial, Helvetica — system defaults with no character
|
|
436
|
+
- system-ui alone without a named font — signals zero design intent
|
|
437
|
+
|
|
438
|
+
```html
|
|
439
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
440
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
441
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Define as CSS variables for easy reference:
|
|
445
|
+
```css
|
|
446
|
+
:root {
|
|
447
|
+
--font-body: 'Outfit', system-ui, sans-serif;
|
|
448
|
+
--font-mono: 'Space Mono', 'SF Mono', Consolas, monospace;
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
**Font pairings** (rotate — never use the same pairing twice in a row):
|
|
453
|
+
|
|
454
|
+
| Body / Headings | Mono / Labels | Feel | Use for |
|
|
455
|
+
|---|---|---|---|
|
|
456
|
+
| DM Sans | Fira Code | Friendly, developer | Blueprint, technical docs |
|
|
457
|
+
| Instrument Serif | JetBrains Mono | Editorial, refined | Plan reviews, decision logs |
|
|
458
|
+
| IBM Plex Sans | IBM Plex Mono | Reliable, readable | Architecture diagrams |
|
|
459
|
+
| Bricolage Grotesque | Fragment Mono | Bold, characterful | Data tables, dashboards |
|
|
460
|
+
| Plus Jakarta Sans | Azeret Mono | Rounded, approachable | Status reports, audits |
|
|
461
|
+
| Outfit | Space Mono | Clean geometric, modern | Flowcharts, pipelines |
|
|
462
|
+
| Sora | IBM Plex Mono | Technical, precise | ER diagrams, schemas |
|
|
463
|
+
| Crimson Pro | Noto Sans Mono | Scholarly, serious | RFC reviews, specs |
|
|
464
|
+
| Fraunces | Source Code Pro | Warm, distinctive | Project recaps |
|
|
465
|
+
| Geist | Geist Mono | Vercel-inspired, sharp | Modern API docs |
|
|
466
|
+
| Red Hat Display | Red Hat Mono | Cohesive family | System overviews |
|
|
467
|
+
| Libre Franklin | Inconsolata | Classic, reliable | Data-dense tables |
|
|
468
|
+
| Playfair Display | Roboto Mono | Elegant contrast | Executive summaries |
|
|
469
|
+
|
|
470
|
+
The first 5 pairings are recommended for most use cases. Vary across consecutive diagrams.
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# Responsive Section Navigation
|
|
2
|
+
|
|
3
|
+
Navigation pattern for multi-section pages (reviews, recaps, dashboards). Provides a sticky sidebar TOC on desktop and a sticky horizontal scrollable bar on mobile.
|
|
4
|
+
|
|
5
|
+
## Layout Structure
|
|
6
|
+
|
|
7
|
+
The page uses a two-column CSS Grid: sidebar (TOC) + main content. On mobile it collapses to single-column with the TOC becoming a horizontal bar.
|
|
8
|
+
|
|
9
|
+
```html
|
|
10
|
+
<body>
|
|
11
|
+
<div class="wrap">
|
|
12
|
+
|
|
13
|
+
<nav class="toc" id="toc">
|
|
14
|
+
<div class="toc-title">Contents</div>
|
|
15
|
+
<a href="#s1">1. First Section</a>
|
|
16
|
+
<a href="#s2">2. Second Section</a>
|
|
17
|
+
<!-- one link per section -->
|
|
18
|
+
</nav>
|
|
19
|
+
|
|
20
|
+
<div class="main">
|
|
21
|
+
<h1>Page Title</h1>
|
|
22
|
+
<p class="subtitle">Subtitle text</p>
|
|
23
|
+
|
|
24
|
+
<div id="s1" class="sec-head ...">1 — First Section</div>
|
|
25
|
+
<!-- section content -->
|
|
26
|
+
|
|
27
|
+
<div id="s2" class="sec-head ...">2 — Second Section</div>
|
|
28
|
+
<!-- section content -->
|
|
29
|
+
</div><!-- /main -->
|
|
30
|
+
|
|
31
|
+
</div><!-- /wrap -->
|
|
32
|
+
</body>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Key structural rules:
|
|
36
|
+
- `<nav class="toc">` is the **first child** of `.wrap`
|
|
37
|
+
- All page content goes inside `<div class="main">`
|
|
38
|
+
- Every section heading gets an `id="s1"`, `id="s2"`, etc.
|
|
39
|
+
- TOC links use `href="#s1"` matching those IDs
|
|
40
|
+
- Keep TOC link text short (truncate long section names)
|
|
41
|
+
|
|
42
|
+
## CSS
|
|
43
|
+
|
|
44
|
+
### Wrap (grid layout)
|
|
45
|
+
|
|
46
|
+
```css
|
|
47
|
+
.wrap {
|
|
48
|
+
max-width: 1400px;
|
|
49
|
+
margin: 0 auto;
|
|
50
|
+
display: grid;
|
|
51
|
+
grid-template-columns: 170px 1fr;
|
|
52
|
+
gap: 0 40px;
|
|
53
|
+
}
|
|
54
|
+
.main { min-width: 0; }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### TOC — Desktop (sticky sidebar)
|
|
58
|
+
|
|
59
|
+
```css
|
|
60
|
+
.toc {
|
|
61
|
+
position: sticky;
|
|
62
|
+
top: 24px;
|
|
63
|
+
align-self: start;
|
|
64
|
+
padding: 14px 0;
|
|
65
|
+
grid-row: 1 / -1;
|
|
66
|
+
max-height: calc(100dvh - 48px);
|
|
67
|
+
overflow-y: auto;
|
|
68
|
+
}
|
|
69
|
+
.toc::-webkit-scrollbar { width: 3px; }
|
|
70
|
+
.toc::-webkit-scrollbar-thumb { background: var(--surface-elevated); border-radius: 2px; }
|
|
71
|
+
|
|
72
|
+
.toc-title {
|
|
73
|
+
font-family: var(--font-mono);
|
|
74
|
+
font-size: 9px;
|
|
75
|
+
font-weight: 700;
|
|
76
|
+
text-transform: uppercase;
|
|
77
|
+
letter-spacing: 2px;
|
|
78
|
+
color: var(--text-dim);
|
|
79
|
+
padding: 0 0 10px;
|
|
80
|
+
margin-bottom: 8px;
|
|
81
|
+
border-bottom: 1px solid var(--border);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.toc a {
|
|
85
|
+
display: block;
|
|
86
|
+
font-size: 11px;
|
|
87
|
+
color: var(--text-dim);
|
|
88
|
+
text-decoration: none;
|
|
89
|
+
padding: 4px 8px;
|
|
90
|
+
border-radius: 5px;
|
|
91
|
+
border-left: 2px solid transparent;
|
|
92
|
+
transition: all 0.15s;
|
|
93
|
+
line-height: 1.4;
|
|
94
|
+
margin-bottom: 1px;
|
|
95
|
+
}
|
|
96
|
+
.toc a:hover { color: var(--text); background: var(--surface2); }
|
|
97
|
+
.toc a.active { color: var(--text); border-left-color: var(--accent); }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Replace `var(--accent)` with your page's primary accent color variable (e.g., `var(--orange)`, `var(--blue)`).
|
|
101
|
+
|
|
102
|
+
### TOC — Mobile (sticky horizontal bar)
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
@media (max-width: 1000px) {
|
|
106
|
+
.wrap { grid-template-columns: 1fr; padding-top: 0; }
|
|
107
|
+
body { padding-top: 0; }
|
|
108
|
+
|
|
109
|
+
.toc {
|
|
110
|
+
position: sticky;
|
|
111
|
+
top: 0;
|
|
112
|
+
z-index: 200;
|
|
113
|
+
max-height: none;
|
|
114
|
+
display: flex;
|
|
115
|
+
gap: 4px;
|
|
116
|
+
align-items: center;
|
|
117
|
+
overflow-x: auto;
|
|
118
|
+
-webkit-overflow-scrolling: touch;
|
|
119
|
+
background: var(--bg);
|
|
120
|
+
border-bottom: 1px solid var(--border);
|
|
121
|
+
padding: 10px 0;
|
|
122
|
+
margin: 0 -40px;
|
|
123
|
+
padding-left: 40px;
|
|
124
|
+
padding-right: 40px;
|
|
125
|
+
grid-row: auto;
|
|
126
|
+
}
|
|
127
|
+
.toc::-webkit-scrollbar { display: none; }
|
|
128
|
+
.toc-title { display: none; }
|
|
129
|
+
|
|
130
|
+
.toc a {
|
|
131
|
+
white-space: nowrap;
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
border-left: none;
|
|
134
|
+
border-bottom: 2px solid transparent;
|
|
135
|
+
border-radius: 4px 4px 0 0;
|
|
136
|
+
padding: 6px 10px;
|
|
137
|
+
font-size: 10px;
|
|
138
|
+
}
|
|
139
|
+
.toc a.active {
|
|
140
|
+
border-left: none;
|
|
141
|
+
border-bottom-color: var(--accent);
|
|
142
|
+
background: var(--surface);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.main { padding-top: 20px; }
|
|
146
|
+
|
|
147
|
+
/* Offset scroll target so headings clear the sticky bar */
|
|
148
|
+
.sec-head { scroll-margin-top: 52px; }
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Adjust `margin: 0 -40px` and `padding-left/right: 40px` to match your `body` padding so the bar bleeds edge-to-edge.
|
|
153
|
+
|
|
154
|
+
## JavaScript — Scroll Spy
|
|
155
|
+
|
|
156
|
+
Place before `</body>`, after any Mermaid init:
|
|
157
|
+
|
|
158
|
+
```html
|
|
159
|
+
<script>
|
|
160
|
+
(function() {
|
|
161
|
+
const toc = document.getElementById('toc');
|
|
162
|
+
const links = toc.querySelectorAll('a');
|
|
163
|
+
const sections = [];
|
|
164
|
+
|
|
165
|
+
links.forEach(link => {
|
|
166
|
+
const id = link.getAttribute('href').slice(1);
|
|
167
|
+
const el = document.getElementById(id);
|
|
168
|
+
if (el) sections.push({ id, el, link });
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const observer = new IntersectionObserver(entries => {
|
|
172
|
+
entries.forEach(entry => {
|
|
173
|
+
if (entry.isIntersecting) {
|
|
174
|
+
links.forEach(l => l.classList.remove('active'));
|
|
175
|
+
const match = sections.find(s => s.el === entry.target);
|
|
176
|
+
if (match) {
|
|
177
|
+
match.link.classList.add('active');
|
|
178
|
+
// On mobile, auto-scroll the active tab into view
|
|
179
|
+
if (window.innerWidth <= 1000) {
|
|
180
|
+
match.link.scrollIntoView({
|
|
181
|
+
behavior: 'smooth', block: 'nearest', inline: 'center'
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}, { rootMargin: '-10% 0px -80% 0px' });
|
|
188
|
+
|
|
189
|
+
sections.forEach(s => observer.observe(s.el));
|
|
190
|
+
|
|
191
|
+
links.forEach(link => {
|
|
192
|
+
link.addEventListener('click', e => {
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
const id = link.getAttribute('href').slice(1);
|
|
195
|
+
const el = document.getElementById(id);
|
|
196
|
+
if (el) {
|
|
197
|
+
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
198
|
+
history.replaceState(null, '', '#' + id);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
})();
|
|
203
|
+
</script>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Adaptation Notes
|
|
207
|
+
|
|
208
|
+
- The `.toc-title` text, link labels, accent color, and section IDs change per page. Everything else is copy-paste.
|
|
209
|
+
- For pages with fewer than 4 sections, skip the TOC entirely — it adds clutter without value.
|
|
210
|
+
- The `grid-template-columns: 170px 1fr` width works for most TOCs. If section names are longer, go up to `200px`.
|
|
211
|
+
- The `rootMargin: '-10% 0px -80% 0px'` means a section is "active" when its heading enters the top 10-20% of the viewport. This works well with sticky headers.
|
|
212
|
+
- On mobile, the horizontal bar uses `overflow-x: auto` with hidden scrollbar. The active tab auto-scrolls into the center of the bar as the user scrolls the page.
|