@tienne/gestalt 0.87.0 → 0.89.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.md +12 -4
- package/README.ko.md +2 -1
- package/README.md +3 -1
- package/dist/bin/gestalt-hook.d.ts +5 -0
- package/dist/bin/gestalt-hook.d.ts.map +1 -0
- package/dist/bin/gestalt-hook.js +51 -0
- package/dist/bin/gestalt-hook.js.map +1 -0
- package/dist/package.json +5 -3
- package/dist/plugin/skills/_shared/proactive-routing.md +1 -0
- package/dist/plugin/skills/architecture/SKILL.md +913 -0
- package/dist/plugin/skills/blast-radius/SKILL.md +11 -1
- package/dist/plugin/skills/diff-radius/SKILL.md +11 -0
- package/dist/schemas/architecture-ir.schema.json +596 -0
- package/dist/schemas/gestalt.schema.json +19 -0
- package/dist/src/architecture/canvas-geometry.d.ts +40 -0
- package/dist/src/architecture/canvas-geometry.d.ts.map +1 -0
- package/dist/src/architecture/canvas-geometry.js +212 -0
- package/dist/src/architecture/canvas-geometry.js.map +1 -0
- package/dist/src/architecture/codeowners.d.ts +16 -0
- package/dist/src/architecture/codeowners.d.ts.map +1 -0
- package/dist/src/architecture/codeowners.js +58 -0
- package/dist/src/architecture/codeowners.js.map +1 -0
- package/dist/src/architecture/compare-layout.d.ts +27 -0
- package/dist/src/architecture/compare-layout.d.ts.map +1 -0
- package/dist/src/architecture/compare-layout.js +72 -0
- package/dist/src/architecture/compare-layout.js.map +1 -0
- package/dist/src/architecture/dataflow-layout.d.ts +29 -0
- package/dist/src/architecture/dataflow-layout.d.ts.map +1 -0
- package/dist/src/architecture/dataflow-layout.js +229 -0
- package/dist/src/architecture/dataflow-layout.js.map +1 -0
- package/dist/src/architecture/doc-fresh.d.ts +31 -0
- package/dist/src/architecture/doc-fresh.d.ts.map +1 -0
- package/dist/src/architecture/doc-fresh.js +84 -0
- package/dist/src/architecture/doc-fresh.js.map +1 -0
- package/dist/src/architecture/doc-link.d.ts +84 -0
- package/dist/src/architecture/doc-link.d.ts.map +1 -0
- package/dist/src/architecture/doc-link.js +396 -0
- package/dist/src/architecture/doc-link.js.map +1 -0
- package/dist/src/architecture/doc-routes.d.ts +39 -0
- package/dist/src/architecture/doc-routes.d.ts.map +1 -0
- package/dist/src/architecture/doc-routes.js +123 -0
- package/dist/src/architecture/doc-routes.js.map +1 -0
- package/dist/src/architecture/doc-scan.d.ts +107 -0
- package/dist/src/architecture/doc-scan.d.ts.map +1 -0
- package/dist/src/architecture/doc-scan.js +617 -0
- package/dist/src/architecture/doc-scan.js.map +1 -0
- package/dist/src/architecture/doc-stale.d.ts +32 -0
- package/dist/src/architecture/doc-stale.d.ts.map +1 -0
- package/dist/src/architecture/doc-stale.js +60 -0
- package/dist/src/architecture/doc-stale.js.map +1 -0
- package/dist/src/architecture/drilldown.d.ts +51 -0
- package/dist/src/architecture/drilldown.d.ts.map +1 -0
- package/dist/src/architecture/drilldown.js +1160 -0
- package/dist/src/architecture/drilldown.js.map +1 -0
- package/dist/src/architecture/endpoint-match.d.ts +43 -0
- package/dist/src/architecture/endpoint-match.d.ts.map +1 -0
- package/dist/src/architecture/endpoint-match.js +133 -0
- package/dist/src/architecture/endpoint-match.js.map +1 -0
- package/dist/src/architecture/flow-layout.d.ts +79 -0
- package/dist/src/architecture/flow-layout.d.ts.map +1 -0
- package/dist/src/architecture/flow-layout.js +519 -0
- package/dist/src/architecture/flow-layout.js.map +1 -0
- package/dist/src/architecture/focus.d.ts +14 -0
- package/dist/src/architecture/focus.d.ts.map +1 -0
- package/dist/src/architecture/focus.js +107 -0
- package/dist/src/architecture/focus.js.map +1 -0
- package/dist/src/architecture/global-context.d.ts +23 -0
- package/dist/src/architecture/global-context.d.ts.map +1 -0
- package/dist/src/architecture/global-context.js +67 -0
- package/dist/src/architecture/global-context.js.map +1 -0
- package/dist/src/architecture/html-client.d.ts +35 -0
- package/dist/src/architecture/html-client.d.ts.map +1 -0
- package/dist/src/architecture/html-client.js +1852 -0
- package/dist/src/architecture/html-client.js.map +1 -0
- package/dist/src/architecture/html-renderer.d.ts +22 -0
- package/dist/src/architecture/html-renderer.d.ts.map +1 -0
- package/dist/src/architecture/html-renderer.js +1290 -0
- package/dist/src/architecture/html-renderer.js.map +1 -0
- package/dist/src/architecture/html-theme.d.ts +25 -0
- package/dist/src/architecture/html-theme.d.ts.map +1 -0
- package/dist/src/architecture/html-theme.js +681 -0
- package/dist/src/architecture/html-theme.js.map +1 -0
- package/dist/src/architecture/index.d.ts +9 -0
- package/dist/src/architecture/index.d.ts.map +1 -0
- package/dist/src/architecture/index.js +9 -0
- package/dist/src/architecture/index.js.map +1 -0
- package/dist/src/architecture/ir-schema.d.ts +1832 -0
- package/dist/src/architecture/ir-schema.d.ts.map +1 -0
- package/dist/src/architecture/ir-schema.js +343 -0
- package/dist/src/architecture/ir-schema.js.map +1 -0
- package/dist/src/architecture/kind-text.d.ts +21 -0
- package/dist/src/architecture/kind-text.d.ts.map +1 -0
- package/dist/src/architecture/kind-text.js +42 -0
- package/dist/src/architecture/kind-text.js.map +1 -0
- package/dist/src/architecture/layout.d.ts +227 -0
- package/dist/src/architecture/layout.d.ts.map +1 -0
- package/dist/src/architecture/layout.js +627 -0
- package/dist/src/architecture/layout.js.map +1 -0
- package/dist/src/architecture/mcp-tool-match.d.ts +49 -0
- package/dist/src/architecture/mcp-tool-match.d.ts.map +1 -0
- package/dist/src/architecture/mcp-tool-match.js +53 -0
- package/dist/src/architecture/mcp-tool-match.js.map +1 -0
- package/dist/src/architecture/merge.d.ts +54 -0
- package/dist/src/architecture/merge.d.ts.map +1 -0
- package/dist/src/architecture/merge.js +681 -0
- package/dist/src/architecture/merge.js.map +1 -0
- package/dist/src/architecture/micro-app.d.ts +20 -0
- package/dist/src/architecture/micro-app.d.ts.map +1 -0
- package/dist/src/architecture/micro-app.js +41 -0
- package/dist/src/architecture/micro-app.js.map +1 -0
- package/dist/src/architecture/name-ref-match.d.ts +43 -0
- package/dist/src/architecture/name-ref-match.d.ts.map +1 -0
- package/dist/src/architecture/name-ref-match.js +127 -0
- package/dist/src/architecture/name-ref-match.js.map +1 -0
- package/dist/src/architecture/packs/data.d.ts +109 -0
- package/dist/src/architecture/packs/data.d.ts.map +1 -0
- package/dist/src/architecture/packs/data.js +64 -0
- package/dist/src/architecture/packs/data.js.map +1 -0
- package/dist/src/architecture/packs/generic.d.ts +47 -0
- package/dist/src/architecture/packs/generic.d.ts.map +1 -0
- package/dist/src/architecture/packs/generic.js +35 -0
- package/dist/src/architecture/packs/generic.js.map +1 -0
- package/dist/src/architecture/packs/harness.d.ts +96 -0
- package/dist/src/architecture/packs/harness.d.ts.map +1 -0
- package/dist/src/architecture/packs/harness.js +66 -0
- package/dist/src/architecture/packs/harness.js.map +1 -0
- package/dist/src/architecture/packs/index.d.ts +840 -0
- package/dist/src/architecture/packs/index.d.ts.map +1 -0
- package/dist/src/architecture/packs/index.js +87 -0
- package/dist/src/architecture/packs/index.js.map +1 -0
- package/dist/src/architecture/packs/infra.d.ts +91 -0
- package/dist/src/architecture/packs/infra.d.ts.map +1 -0
- package/dist/src/architecture/packs/infra.js +57 -0
- package/dist/src/architecture/packs/infra.js.map +1 -0
- package/dist/src/architecture/packs/knowledge.d.ts +72 -0
- package/dist/src/architecture/packs/knowledge.d.ts.map +1 -0
- package/dist/src/architecture/packs/knowledge.js +58 -0
- package/dist/src/architecture/packs/knowledge.js.map +1 -0
- package/dist/src/architecture/packs/process.d.ts +87 -0
- package/dist/src/architecture/packs/process.d.ts.map +1 -0
- package/dist/src/architecture/packs/process.js +52 -0
- package/dist/src/architecture/packs/process.js.map +1 -0
- package/dist/src/architecture/packs/render-classes.d.ts +11 -0
- package/dist/src/architecture/packs/render-classes.d.ts.map +1 -0
- package/dist/src/architecture/packs/render-classes.js +92 -0
- package/dist/src/architecture/packs/render-classes.js.map +1 -0
- package/dist/src/architecture/packs/types.d.ts +66 -0
- package/dist/src/architecture/packs/types.d.ts.map +1 -0
- package/dist/src/architecture/packs/types.js +18 -0
- package/dist/src/architecture/packs/types.js.map +1 -0
- package/dist/src/architecture/packs/web-product.d.ts +348 -0
- package/dist/src/architecture/packs/web-product.d.ts.map +1 -0
- package/dist/src/architecture/packs/web-product.js +226 -0
- package/dist/src/architecture/packs/web-product.js.map +1 -0
- package/dist/src/architecture/sequence-layout.d.ts +50 -0
- package/dist/src/architecture/sequence-layout.d.ts.map +1 -0
- package/dist/src/architecture/sequence-layout.js +140 -0
- package/dist/src/architecture/sequence-layout.js.map +1 -0
- package/dist/src/architecture/service-facts.d.ts +30 -0
- package/dist/src/architecture/service-facts.d.ts.map +1 -0
- package/dist/src/architecture/service-facts.js +88 -0
- package/dist/src/architecture/service-facts.js.map +1 -0
- package/dist/src/architecture/store.d.ts +50 -0
- package/dist/src/architecture/store.d.ts.map +1 -0
- package/dist/src/architecture/store.js +320 -0
- package/dist/src/architecture/store.js.map +1 -0
- package/dist/src/architecture/types.d.ts +400 -0
- package/dist/src/architecture/types.d.ts.map +1 -0
- package/dist/src/architecture/types.js +75 -0
- package/dist/src/architecture/types.js.map +1 -0
- package/dist/src/architecture/validator.d.ts +65 -0
- package/dist/src/architecture/validator.d.ts.map +1 -0
- package/dist/src/architecture/validator.js +1249 -0
- package/dist/src/architecture/validator.js.map +1 -0
- package/dist/src/code-graph/cochange.d.ts +40 -0
- package/dist/src/code-graph/cochange.d.ts.map +1 -1
- package/dist/src/code-graph/cochange.js +88 -3
- package/dist/src/code-graph/cochange.js.map +1 -1
- package/dist/src/code-graph/engine.d.ts +35 -1
- package/dist/src/code-graph/engine.d.ts.map +1 -1
- package/dist/src/code-graph/engine.js +300 -55
- package/dist/src/code-graph/engine.js.map +1 -1
- package/dist/src/code-graph/freshness.d.ts +39 -0
- package/dist/src/code-graph/freshness.d.ts.map +1 -0
- package/dist/src/code-graph/freshness.js +93 -0
- package/dist/src/code-graph/freshness.js.map +1 -0
- package/dist/src/code-graph/hooks/background.d.ts +18 -0
- package/dist/src/code-graph/hooks/background.d.ts.map +1 -0
- package/dist/src/code-graph/hooks/background.js +55 -0
- package/dist/src/code-graph/hooks/background.js.map +1 -0
- package/dist/src/code-graph/hooks/pointers.d.ts +66 -0
- package/dist/src/code-graph/hooks/pointers.d.ts.map +1 -0
- package/dist/src/code-graph/hooks/pointers.js +292 -0
- package/dist/src/code-graph/hooks/pointers.js.map +1 -0
- package/dist/src/code-graph/hooks/rank.d.ts +36 -0
- package/dist/src/code-graph/hooks/rank.d.ts.map +1 -0
- package/dist/src/code-graph/hooks/rank.js +212 -0
- package/dist/src/code-graph/hooks/rank.js.map +1 -0
- package/dist/src/code-graph/hooks/run.d.ts +37 -0
- package/dist/src/code-graph/hooks/run.d.ts.map +1 -0
- package/dist/src/code-graph/hooks/run.js +324 -0
- package/dist/src/code-graph/hooks/run.js.map +1 -0
- package/dist/src/code-graph/hooks/settings.d.ts +11 -0
- package/dist/src/code-graph/hooks/settings.d.ts.map +1 -0
- package/dist/src/code-graph/hooks/settings.js +25 -0
- package/dist/src/code-graph/hooks/settings.js.map +1 -0
- package/dist/src/code-graph/hooks/state.d.ts +20 -0
- package/dist/src/code-graph/hooks/state.d.ts.map +1 -0
- package/dist/src/code-graph/hooks/state.js +73 -0
- package/dist/src/code-graph/hooks/state.js.map +1 -0
- package/dist/src/code-graph/index.d.ts +6 -2
- package/dist/src/code-graph/index.d.ts.map +1 -1
- package/dist/src/code-graph/index.js +3 -1
- package/dist/src/code-graph/index.js.map +1 -1
- package/dist/src/code-graph/ko-text.d.ts +39 -0
- package/dist/src/code-graph/ko-text.d.ts.map +1 -0
- package/dist/src/code-graph/ko-text.js +223 -0
- package/dist/src/code-graph/ko-text.js.map +1 -0
- package/dist/src/code-graph/lock.d.ts +30 -0
- package/dist/src/code-graph/lock.d.ts.map +1 -0
- package/dist/src/code-graph/lock.js +140 -0
- package/dist/src/code-graph/lock.js.map +1 -0
- package/dist/src/code-graph/plugins/typescript-skeleton.d.ts +7 -0
- package/dist/src/code-graph/plugins/typescript-skeleton.d.ts.map +1 -0
- package/dist/src/code-graph/plugins/typescript-skeleton.js +157 -0
- package/dist/src/code-graph/plugins/typescript-skeleton.js.map +1 -0
- package/dist/src/code-graph/plugins/typescript.d.ts.map +1 -1
- package/dist/src/code-graph/plugins/typescript.js +58 -0
- package/dist/src/code-graph/plugins/typescript.js.map +1 -1
- package/dist/src/code-graph/storage.d.ts +85 -0
- package/dist/src/code-graph/storage.d.ts.map +1 -1
- package/dist/src/code-graph/storage.js +318 -3
- package/dist/src/code-graph/storage.js.map +1 -1
- package/dist/src/code-graph/types.d.ts +66 -0
- package/dist/src/code-graph/types.d.ts.map +1 -1
- package/dist/src/core/config.d.ts +33 -0
- package/dist/src/core/config.d.ts.map +1 -1
- package/dist/src/core/config.js +14 -0
- package/dist/src/core/config.js.map +1 -1
- package/dist/src/core/errors.d.ts +4 -0
- package/dist/src/core/errors.d.ts.map +1 -1
- package/dist/src/core/errors.js +8 -0
- package/dist/src/core/errors.js.map +1 -1
- package/dist/src/core/hooks-env.d.ts +9 -0
- package/dist/src/core/hooks-env.d.ts.map +1 -0
- package/dist/src/core/hooks-env.js +16 -0
- package/dist/src/core/hooks-env.js.map +1 -0
- package/dist/src/mcp/schemas.d.ts +326 -3
- package/dist/src/mcp/schemas.d.ts.map +1 -1
- package/dist/src/mcp/schemas.js +170 -2
- package/dist/src/mcp/schemas.js.map +1 -1
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +28 -4
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/mcp/tools/architecture-passthrough.d.ts +9 -0
- package/dist/src/mcp/tools/architecture-passthrough.d.ts.map +1 -0
- package/dist/src/mcp/tools/architecture-passthrough.js +587 -0
- package/dist/src/mcp/tools/architecture-passthrough.js.map +1 -0
- package/dist/src/mcp/tools/code-graph-passthrough.d.ts +6 -1
- package/dist/src/mcp/tools/code-graph-passthrough.d.ts.map +1 -1
- package/dist/src/mcp/tools/code-graph-passthrough.js +95 -6
- package/dist/src/mcp/tools/code-graph-passthrough.js.map +1 -1
- package/dist/src/utils/claude-projects.d.ts +19 -0
- package/dist/src/utils/claude-projects.d.ts.map +1 -0
- package/dist/src/utils/claude-projects.js +157 -0
- package/dist/src/utils/claude-projects.js.map +1 -0
- package/dist/src/utils/read-only-tools.d.ts +19 -0
- package/dist/src/utils/read-only-tools.d.ts.map +1 -0
- package/dist/src/utils/read-only-tools.js +132 -0
- package/dist/src/utils/read-only-tools.js.map +1 -0
- package/package.json +5 -3
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/.mcp.json +1 -1
- package/plugin/mcp.json +1 -1
- package/plugin/skills/_shared/proactive-routing.md +1 -0
- package/plugin/skills/architecture/SKILL.md +913 -0
- package/plugin/skills/blast-radius/SKILL.md +11 -1
- package/plugin/skills/diff-radius/SKILL.md +11 -0
- package/schemas/architecture-ir.schema.json +596 -0
- package/schemas/gestalt.schema.json +19 -0
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
import { LEGACY_PACK_IDS, vocabularyOf } from './packs/index.js';
|
|
2
|
+
// 색과 아이콘은 팩의 nodeKinds와 displayKinds에 있다. 아이콘은 24 격자 선 그림이다.
|
|
3
|
+
// 이모지는 플랫폼마다 모양이 달라서 path로 직접 그린다.
|
|
4
|
+
// 페이지에는 IR이 쓰는 팩 것만 싣는다. 팩을 더해도 그 팩을 안 쓰는 그림의 바이트가 그대로다
|
|
5
|
+
const LEGACY_VOCABULARY = vocabularyOf(LEGACY_PACK_IDS);
|
|
6
|
+
// 플랫폼 칩 아이콘. 앱 둘은 칩만 보고 바로 알아보게 공식 로고를 브랜드 색으로 채워 그린다. 모양은 simple-icons에서 가져왔다
|
|
7
|
+
const PLATFORM_ICONS = {
|
|
8
|
+
web: '<rect x="3" y="4.5" width="18" height="15" rx="2"/><path d="M3 9h18"/>',
|
|
9
|
+
android: `<path fill="currentColor" stroke="none" d="M18.4395 5.5586c-.675 1.1664-1.352 2.3318-2.0274 3.498-.0366-.0155-.0742-.0286-.1113-.043-1.8249-.6957-3.484-.8-4.42-.787-1.8551.0185-3.3544.4643-4.2597.8203-.084-.1494-1.7526-3.021-2.0215-3.4864a1.1451 1.1451 0 0 0-.1406-.1914c-.3312-.364-.9054-.4859-1.379-.203-.475.282-.7136.9361-.3886 1.5019 1.9466 3.3696-.0966-.2158 1.9473 3.3593.0172.031-.4946.2642-1.3926 1.0177C2.8987 12.176.452 14.772 0 18.9902h24c-.119-1.1108-.3686-2.099-.7461-3.0683-.7438-1.9118-1.8435-3.2928-2.7402-4.1836a12.1048 12.1048 0 0 0-2.1309-1.6875c.6594-1.122 1.312-2.2559 1.9649-3.3848.2077-.3615.1886-.7956-.0079-1.1191a1.1001 1.1001 0 0 0-.8515-.5332c-.5225-.0536-.9392.3128-1.0488.5449zm-.0391 8.461c.3944.5926.324 1.3306-.1563 1.6503-.4799.3197-1.188.0985-1.582-.4941-.3944-.5927-.324-1.3307.1563-1.6504.4727-.315 1.1812-.1086 1.582.4941zM7.207 13.5273c.4803.3197.5506 1.0577.1563 1.6504-.394.5926-1.1038.8138-1.584.4941-.48-.3197-.5503-1.0577-.1563-1.6504.4008-.6021 1.1087-.8106 1.584-.4941z"/>`,
|
|
10
|
+
ios: `<path fill="currentColor" stroke="none" d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"/>`,
|
|
11
|
+
};
|
|
12
|
+
// 데이터 저장소 엔진 로고. 카드만 보고 어떤 DB인지 알아보게 브랜드 모양을 채워 그린다. 모양은 simple-icons에서 가져왔다
|
|
13
|
+
const ENGINE_ICONS = {
|
|
14
|
+
documentdb: {
|
|
15
|
+
body: '<path d="m16.5053 21.0947.7158.4632C16.2526 23.0316 13.0947 24 9.3895 24c-4.6316 0-8.1263-1.4737-8.1263-3.4105V3.3685C1.2632 1.7262 4.1263 0 9.4737 0c5.3474 0 8.2105 1.7263 8.2105 3.3684v2.9053h-.8421V4.8842c-1.221 1.0105-3.7053 1.8105-7.3684 1.8105-3.6632 0-6.1474-.8-7.3684-1.8105v4.8c.3368 1.179 3.2 2.3579 7.242 2.3579q1.0948 0 2.1053-.1263l.1263.842q-1.0947.1264-2.2315.1264c-3.2421 0-5.9369-.7158-7.2421-1.8105v4.5052c.3368 1.1369 3.2 2.3158 7.242 2.3158q1.0527 0 2.1053-.0842l.1263.8q-1.1368.1263-2.2315.1263c-3.2421 0-5.9369-.7157-7.2421-1.8105v3.6632c0 1.221 2.9894 2.5684 7.2842 2.5684 3.7894 0 6.442-1.0526 7.1158-2.0632zm-14.4-17.7263c0 1.179 3.0315 2.4842 7.3684 2.4842 4.3368 0 7.3684-1.3052 7.3684-2.4842 0-1.221-3.0316-2.5263-7.3684-2.5263-4.3369 0-7.3684 1.3053-7.3684 2.5263zm20.6315 7.6632v9.0947c0 .2526-.1684.421-.421.421h-8c-.2526 0-.421-.1684-.421-.421V9.2211c0-.2106.1684-.4211.421-.4211h4.6316l-.7158-.8421h-5.179V18.021h.421v.842h-.842c-.2527 0-.421-.1684-.421-.421V7.5368c0-.2105.1683-.421.421-.421h5.8105c.1263 0 .2526.0842.2947.1684L20.0421 8.8h.4632q.1684 0 .2947.1263l1.8105 1.8105q.1263.1264.1263.2948zm-.842.7158h-2.1053c-.2527 0-.421-.1685-.421-.421V9.642h-4.6317v10.0632h7.158zm-2.4422.9684c.2527 0 .4632.0842.5895.2526.2526.3369.2105.8.2105.9684 0 .8843.5053 1.0527.5474 1.0948.1684.042.2947.2105.2947.421 0 .1685-.1263.3369-.2947.379-.0421 0-.5474.2105-.5474 1.0947 0 .5053-.2526 1.0526-.8 1.0526h-.2947v-.842h.2105c0-.0422.0421-.1264.0421-.2106 0-.7579.2527-1.221.5053-1.5158-.2526-.2526-.5053-.7579-.5053-1.5158v-.3368h-.2526v-.8421zm.758-1.8105h1.3473L20.2947 9.642h-.0842zm-2.737 1.8105h.337v.842h-.2527v.2106c0 .758-.2526 1.221-.5474 1.5158.2948.2947.5474.7579.5474 1.5158q0 .0421-.0421.0842v.2947h.2947v.8422h-.3368c-.2105 0-.421-.1264-.5895-.2948-.2526-.2947-.2105-.8-.1684-.9684-.0421-.8842-.5053-1.0526-.5895-1.0526-.1684-.0421-.2947-.2527-.2947-.421 0-.1685.1263-.337.3368-.379.0421-.0421.5474-.2106.5474-1.1369-.0421-.4631.2105-1.0526.7579-1.0526z"/>',
|
|
16
|
+
},
|
|
17
|
+
dynamodb: {
|
|
18
|
+
body: '<path d="M16.606 20.705v-2.371c-1.263 1.082-3.884 1.795-7.066 1.795-3.184 0-5.805-.714-7.068-1.797v2.369c0 1.168 2.903 2.47 7.068 2.47 4.16 0 7.06-1.3 7.066-2.466zm.001-6.765l.817-.005v.005c0 .517-.258.998-.75 1.441.601.54.75 1.071.75 1.449a1661.7 1661.7 0 0 0 0 3.87c0 1.881-3.389 3.3-7.884 3.3-4.471 0-7.846-1.404-7.88-3.27a583.119 583.119 0 0 1-.003-3.909c.001-.375.15-.9.745-1.437-.592-.538-.743-1.062-.746-1.435v-3.892c.002-.377.153-.903.747-1.438-.593-.54-.744-1.062-.747-1.435 0-1.357-.002-2.735.002-3.897C1.674 1.412 5.056 0 9.54 0c2.159 0 4.233.356 5.689.974l-.315.766c-1.36-.58-3.319-.91-5.374-.91-4.165 0-7.067 1.3-7.067 2.47 0 1.168 2.902 2.47 7.067 2.47.115 0 .222 0 .334-.005l.033.828c-.122.006-.245.006-.367.006-3.184 0-5.805-.714-7.068-1.798v2.38c.005.45.45.843.821 1.093 1.116.736 3.114 1.239 5.34 1.342l-.037.829c-2.254-.105-4.23-.59-5.5-1.332-.318.245-.623.573-.623.952 0 1.168 2.902 2.47 7.067 2.47.411 0 .812-.014 1.203-.042l.06.826c-.41.03-.833.045-1.263.045-3.184 0-5.805-.713-7.068-1.797v2.368c.005.462.449.855.821 1.104 1.275.842 3.67 1.366 6.247 1.366h.182v.83H9.54c-2.62 0-4.99-.507-6.444-1.359-.317.245-.623.574-.623.954 0 1.168 2.902 2.47 7.067 2.47 4.159 0 7.058-1.298 7.066-2.465v-.007c0-.377-.303-.705-.62-.948a5.732 5.732 0 0 1-.662.336l-.316-.764c.3-.128.56-.266.776-.412.376-.254.823-.651.823-1.1zm4.377-6.915h-2.717a.406.406 0 0 1-.332-.173.42.42 0 0 1-.055-.375l1.204-3.597h-5.403l-2.583 4.974h2.623c.128 0 .248.06.325.164a.418.418 0 0 1 .069.36l-2.249 8.365zm1.249-.128l-10.89 11.608a.408.408 0 0 1-.498.075.418.418 0 0 1-.192-.471l2.534-9.426h-2.766a.407.407 0 0 1-.349-.2.418.418 0 0 1-.012-.407l3.014-5.804a.408.408 0 0 1 .36-.222h6.22c.132 0 .256.065.332.174a.422.422 0 0 1 .055.374l-1.204 3.598h3.1c.164 0 .31.099.375.251a.422.422 0 0 1-.08.45zM3.085 20.723a8.107 8.107 0 0 0 1.72.72l.233-.794a7.32 7.32 0 0 1-1.546-.645zm1.72-5.984l.233-.795a7.262 7.262 0 0 1-1.546-.646l-.407.72a8.051 8.051 0 0 0 1.72.72zm-1.72-7.427l.407-.719c.418.244.939.462 1.546.646l-.232.794a8.046 8.046 0 0 1-1.72-.72Z"/>',
|
|
19
|
+
},
|
|
20
|
+
elasticsearch: {
|
|
21
|
+
body: '<path d="M13.394 0C8.683 0 4.609 2.716 2.644 6.667h15.641a4.77 4.77 0 0 0 3.073-1.11c.446-.375.864-.785 1.247-1.243l.001-.002A11.974 11.974 0 0 0 13.394 0zM1.804 8.889a12.009 12.009 0 0 0 0 6.222h14.7a3.111 3.111 0 1 0 0-6.222zm.84 8.444C4.61 21.283 8.684 24 13.395 24c3.701 0 7.011-1.677 9.212-4.312l-.001-.002a9.958 9.958 0 0 0-1.247-1.243 4.77 4.77 0 0 0-3.073-1.11z"/>',
|
|
22
|
+
},
|
|
23
|
+
mariadb: {
|
|
24
|
+
body: '<path d="M23.157 4.412c-.676.284-.79.31-1.673.372-.65.045-.757.057-1.212.209-.75.246-1.395.75-2.02 1.59-.296.398-1.249 1.913-1.249 1.988 0 .057-.65.998-.915 1.32-.574.713-1.08 1.079-2.14 1.59-.77.36-1.224.524-4.102 1.477-1.073.353-2.133.738-2.367.864-.852.449-1.515 1.036-2.203 1.938-1.003 1.32-.972 1.313-3.042.947a12.264 12.264 0 00-.675-.063c-.644-.05-1.023.044-1.332.334L0 17.193l.177.088c.094.05.353.234.561.398.215.17.461.347.55.391.088.044.17.088.183.101.012.013-.089.17-.228.353-.435.581-.593.871-.574 1.048.019.164.032.17.43.17.517-.006.826-.056 1.261-.208.65-.233 2.058-.94 2.784-1.4.776-.5 1.717-.998 1.956-1.042.082-.02.354-.07.594-.114.58-.107 1.464-.095 2.587.05.108.013.373.045.6.064.227.025.43.057.454.076.026.012.474.037.998.056.934.026 1.104.007 1.3-.189.126-.133.385-.631.498-.985.209-.643.417-.921.366-.492-.113.966-.322 1.692-.713 2.411-.259.499-.663 1.092-.934 1.395-.322.347-.315.36.088.315.619-.063 1.471-.397 2.096-.82.827-.562 1.647-1.691 2.19-3.03.107-.27.22-.22.183.083-.013.094-.038.315-.057.498l-.031.328.353-.202c.833-.48 1.414-1.262 2.127-2.884.227-.518.877-2.922 1.073-3.976a9.64 9.64 0 01.271-1.042c.127-.429.196-.555.48-.858.183-.19.625-.555.978-.808.72-.505.953-.75 1.187-1.205.208-.417.284-1.13.132-1.357-.132-.202-.284-.196-.763.006Z"/>',
|
|
25
|
+
},
|
|
26
|
+
mongodb: {
|
|
27
|
+
body: '<path d="M17.193 9.555c-1.264-5.58-4.252-7.414-4.573-8.115-.28-.394-.53-.954-.735-1.44-.036.495-.055.685-.523 1.184-.723.566-4.438 3.682-4.74 10.02-.282 5.912 4.27 9.435 4.888 9.884l.07.05A73.49 73.49 0 0111.91 24h.481c.114-1.032.284-2.056.51-3.07.417-.296.604-.463.85-.693a11.342 11.342 0 003.639-8.464c.01-.814-.103-1.662-.197-2.218zm-5.336 8.195s0-8.291.275-8.29c.213 0 .49 10.695.49 10.695-.381-.045-.765-1.76-.765-2.405z"/>',
|
|
28
|
+
},
|
|
29
|
+
// 원래 로고는 돌고래 아래에 MySQL 글자가 붙어 있어 12px에선 글자가 뭉개진다. 돌고래만 남기고 그 둘레로 viewBox를 좁혔다
|
|
30
|
+
mysql: {
|
|
31
|
+
viewBox: '14.17 3.76 9.83 9.83',
|
|
32
|
+
body: '<path stroke="currentColor" stroke-width=".25" d="M16.405 5.501c-.115 0 -.193 .014 -.274 .033v.013h.014c.054 .104 .146 .18 .214 .273c.054 .107 .1 .214 .154 .32l.014 -.015c.094 -.066 .14 -.172 .14 -.333c-.04 -.047 -.046 -.094 -.08 -.14c-.04 -.067 -.126 -.1 -.18 -.153zM23.224 11.311c-.535 -.014 -.95 .04 -1.297 .188c-.1 .04 -.26 .04 -.274 .167c.055 .053 .063 .14 .11 .214c.08 .134 .218 .313 .346 .407c.14 .11 .28 .216 .427 .31c.26 .16 .555 .255 .81 .416c.145 .094 .293 .213 .44 .313c.073 .05 .12 .14 .214 .172v-.02c-.046 -.06 -.06 -.147 -.105 -.214c-.067 -.067 -.134 -.127 -.2 -.193a3.223 3.223 0 0 0 -.695 -.675c-.214 -.146 -.682 -.35 -.77 -.595l-.013 -.014c.146 -.013 .32 -.066 .46 -.106c.227 -.06 .435 -.047 .67 -.106c.106 -.027 .213 -.06 .32 -.094v-.06c-.12 -.12 -.21 -.283 -.334 -.395a8.867 8.867 0 0 0 -1.104 -.823c-.21 -.134 -.476 -.22 -.697 -.334c-.08 -.04 -.214 -.06 -.26 -.127c-.12 -.146 -.19 -.34 -.275 -.514a17.69 17.69 0 0 1 -.547 -1.163c-.12 -.262 -.193 -.523 -.34 -.763c-.69 -1.137 -1.437 -1.826 -2.586 -2.5c-.247 -.14 -.543 -.2 -.856 -.274c-.167 -.008 -.334 -.02 -.5 -.027c-.11 -.047 -.216 -.174 -.31 -.235c-.38 -.24 -1.364 -.76 -1.644 -.072c-.18 .434 .267 .862 .422 1.082c.115 .153 .26 .328 .34 .5c.047 .116 .06 .235 .107 .356c.106 .294 .207 .622 .347 .897c.073 .14 .153 .287 .247 .413c.054 .073 .146 .107 .167 .227c-.094 .136 -.1 .334 -.154 .5c-.24 .757 -.146 1.693 .194 2.25c.107 .166 .362 .534 .703 .393c.3 -.12 .234 -.5 .32 -.835c.02 -.08 .007 -.133 .048 -.187v.015c.094 .188 .188 .367 .274 .555c.206 .328 .566 .668 .867 .895c.16 .12 .287 .328 .487 .402v-.02h-.015c-.043 -.058 -.1 -.086 -.154 -.133a3.445 3.445 0 0 1 -.35 -.4a8.76 8.76 0 0 1 -.747 -1.218c-.11 -.21 -.202 -.436 -.29 -.643c-.04 -.08 -.04 -.2 -.107 -.24c-.1 .146 -.247 .273 -.32 .453c-.127 .288 -.14 .642 -.188 1.01c-.027 .007 -.014 0 -.027 .014c-.214 -.052 -.287 -.274 -.367 -.46c-.2 -.475 -.233 -1.238 -.06 -1.785c.047 -.14 .247 -.582 .167 -.716c-.042 -.127 -.174 -.2 -.247 -.303a2.478 2.478 0 0 1 -.24 -.427c-.16 -.374 -.24 -.788 -.414 -1.162c-.08 -.173 -.22 -.354 -.334 -.513c-.127 -.18 -.267 -.307 -.368 -.52c-.033 -.073 -.08 -.194 -.027 -.274c.014 -.054 .042 -.075 .094 -.09c.088 -.072 .335 .022 .422 .062c.247 .1 .455 .194 .662 .334c.094 .066 .195 .193 .315 .226h.14c.214 .047 .455 .014 .655 .073c.355 .114 .675 .28 .962 .46a5.953 5.953 0 0 1 2.085 2.286c.08 .154 .115 .295 .188 .455c.14 .33 .313 .663 .455 .982c.14 .315 .275 .636 .476 .897c.1 .14 .502 .213 .682 .286c.133 .06 .34 .115 .46 .188c.23 .14 .454 .3 .67 .454c.11 .076 .443 .243 .463 .378z"/>',
|
|
33
|
+
},
|
|
34
|
+
postgresql: {
|
|
35
|
+
body: '<path d="M23.5594 14.7228a.5269.5269 0 0 0-.0563-.1191c-.139-.2632-.4768-.3418-1.0074-.2321-1.6533.3411-2.2935.1312-2.5256-.0191 1.342-2.0482 2.445-4.522 3.0411-6.8297.2714-1.0507.7982-3.5237.1222-4.7316a1.5641 1.5641 0 0 0-.1509-.235C21.6931.9086 19.8007.0248 17.5099.0005c-1.4947-.0158-2.7705.3461-3.1161.4794a9.449 9.449 0 0 0-.5159-.0816 8.044 8.044 0 0 0-1.3114-.1278c-1.1822-.0184-2.2038.2642-3.0498.8406-.8573-.3211-4.7888-1.645-7.2219.0788C.9359 2.1526.3086 3.8733.4302 6.3043c.0409.818.5069 3.334 1.2423 5.7436.4598 1.5065.9387 2.7019 1.4334 3.582.553.9942 1.1259 1.5933 1.7143 1.7895.4474.1491 1.1327.1441 1.8581-.7279.8012-.9635 1.5903-1.8258 1.9446-2.2069.4351.2355.9064.3625 1.39.3772a.0569.0569 0 0 0 .0004.0041 11.0312 11.0312 0 0 0-.2472.3054c-.3389.4302-.4094.5197-1.5002.7443-.3102.064-1.1344.2339-1.1464.8115-.0025.1224.0329.2309.0919.3268.2269.4231.9216.6097 1.015.6331 1.3345.3335 2.5044.092 3.3714-.6787-.017 2.231.0775 4.4174.3454 5.0874.2212.5529.7618 1.9045 2.4692 1.9043.2505 0 .5263-.0291.8296-.0941 1.7819-.3821 2.5557-1.1696 2.855-2.9059.1503-.8707.4016-2.8753.5388-4.1012.0169-.0703.0357-.1207.057-.1362.0007-.0005.0697-.0471.4272.0307a.3673.3673 0 0 0 .0443.0068l.2539.0223.0149.001c.8468.0384 1.9114-.1426 2.5312-.4308.6438-.2988 1.8057-1.0323 1.5951-1.6698zM2.371 11.8765c-.7435-2.4358-1.1779-4.8851-1.2123-5.5719-.1086-2.1714.4171-3.6829 1.5623-4.4927 1.8367-1.2986 4.8398-.5408 6.108-.13-.0032.0032-.0066.0061-.0098.0094-2.0238 2.044-1.9758 5.536-1.9708 5.7495-.0002.0823.0066.1989.0162.3593.0348.5873.0996 1.6804-.0735 2.9184-.1609 1.1504.1937 2.2764.9728 3.0892.0806.0841.1648.1631.2518.2374-.3468.3714-1.1004 1.1926-1.9025 2.1576-.5677.6825-.9597.5517-1.0886.5087-.3919-.1307-.813-.5871-1.2381-1.3223-.4796-.839-.9635-2.0317-1.4155-3.5126zm6.0072 5.0871c-.1711-.0428-.3271-.1132-.4322-.1772.0889-.0394.2374-.0902.4833-.1409 1.2833-.2641 1.4815-.4506 1.9143-1.0002.0992-.126.2116-.2687.3673-.4426a.3549.3549 0 0 0 .0737-.1298c.1708-.1513.2724-.1099.4369-.0417.156.0646.3078.26.3695.4752.0291.1016.0619.2945-.0452.4444-.9043 1.2658-2.2216 1.2494-3.1676 1.0128zm2.094-3.988-.0525.141c-.133.3566-.2567.6881-.3334 1.003-.6674-.0021-1.3168-.2872-1.8105-.8024-.6279-.6551-.9131-1.5664-.7825-2.5004.1828-1.3079.1153-2.4468.079-3.0586-.005-.0857-.0095-.1607-.0122-.2199.2957-.2621 1.6659-.9962 2.6429-.7724.4459.1022.7176.4057.8305.928.5846 2.7038.0774 3.8307-.3302 4.7363-.084.1866-.1633.3629-.2311.5454zm7.3637 4.5725c-.0169.1768-.0358.376-.0618.5959l-.146.4383a.3547.3547 0 0 0-.0182.1077c-.0059.4747-.054.6489-.115.8693-.0634.2292-.1353.4891-.1794 1.0575-.11 1.4143-.8782 2.2267-2.4172 2.5565-1.5155.3251-1.7843-.4968-2.0212-1.2217a6.5824 6.5824 0 0 0-.0769-.2266c-.2154-.5858-.1911-1.4119-.1574-2.5551.0165-.5612-.0249-1.9013-.3302-2.6462.0044-.2932.0106-.5909.019-.8918a.3529.3529 0 0 0-.0153-.1126 1.4927 1.4927 0 0 0-.0439-.208c-.1226-.4283-.4213-.7866-.7797-.9351-.1424-.059-.4038-.1672-.7178-.0869.067-.276.1831-.5875.309-.9249l.0529-.142c.0595-.16.134-.3257.213-.5012.4265-.9476 1.0106-2.2453.3766-5.1772-.2374-1.0981-1.0304-1.6343-2.2324-1.5098-.7207.0746-1.3799.3654-1.7088.5321a5.6716 5.6716 0 0 0-.1958.1041c.0918-1.1064.4386-3.1741 1.7357-4.4823a4.0306 4.0306 0 0 1 .3033-.276.3532.3532 0 0 0 .1447-.0644c.7524-.5706 1.6945-.8506 2.802-.8325.4091.0067.8017.0339 1.1742.081 1.939.3544 3.2439 1.4468 4.0359 2.3827.8143.9623 1.2552 1.9315 1.4312 2.4543-1.3232-.1346-2.2234.1268-2.6797.779-.9926 1.4189.543 4.1729 1.2811 5.4964.1353.2426.2522.4522.2889.5413.2403.5825.5515.9713.7787 1.2552.0696.087.1372.1714.1885.245-.4008.1155-1.1208.3825-1.0552 1.717-.0123.1563-.0423.4469-.0834.8148-.0461.2077-.0702.4603-.0994.7662zm.8905-1.6211c-.0405-.8316.2691-.9185.5967-1.0105a2.8566 2.8566 0 0 0 .135-.0406 1.202 1.202 0 0 0 .1342.103c.5703.3765 1.5823.4213 3.0068.1344-.2016.1769-.5189.3994-.9533.6011-.4098.1903-1.0957.333-1.7473.3636-.7197.0336-1.0859-.0807-1.1721-.151zm.5695-9.2712c-.0059.3508-.0542.6692-.1054 1.0017-.055.3576-.112.7274-.1264 1.1762-.0142.4368.0404.8909.0932 1.3301.1066.887.216 1.8003-.2075 2.7014a3.5272 3.5272 0 0 1-.1876-.3856c-.0527-.1276-.1669-.3326-.3251-.6162-.6156-1.1041-2.0574-3.6896-1.3193-4.7446.3795-.5427 1.3408-.5661 2.1781-.463zm.2284 7.0137a12.3762 12.3762 0 0 0-.0853-.1074l-.0355-.0444c.7262-1.1995.5842-2.3862.4578-3.4385-.0519-.4318-.1009-.8396-.0885-1.2226.0129-.4061.0666-.7543.1185-1.0911.0639-.415.1288-.8443.1109-1.3505.0134-.0531.0188-.1158.0118-.1902-.0457-.4855-.5999-1.938-1.7294-3.253-.6076-.7073-1.4896-1.4972-2.6889-2.0395.5251-.1066 1.2328-.2035 2.0244-.1859 2.0515.0456 3.6746.8135 4.8242 2.2824a.908.908 0 0 1 .0667.1002c.7231 1.3556-.2762 6.2751-2.9867 10.5405zm-8.8166-6.1162c-.025.1794-.3089.4225-.6211.4225a.5821.5821 0 0 1-.0809-.0056c-.1873-.026-.3765-.144-.5059-.3156-.0458-.0605-.1203-.178-.1055-.2844.0055-.0401.0261-.0985.0925-.1488.1182-.0894.3518-.1226.6096-.0867.3163.0441.6426.1938.6113.4186zm7.9305-.4114c.0111.0792-.049.201-.1531.3102-.0683.0717-.212.1961-.4079.2232a.5456.5456 0 0 1-.075.0052c-.2935 0-.5414-.2344-.5607-.3717-.024-.1765.2641-.3106.5611-.352.297-.0414.6111.0088.6356.1851z"/>',
|
|
36
|
+
},
|
|
37
|
+
redis: {
|
|
38
|
+
body: '<path d="M22.71 13.145c-1.66 2.092-3.452 4.483-7.038 4.483-3.203 0-4.397-2.825-4.48-5.12.701 1.484 2.073 2.685 4.214 2.63 4.117-.133 6.94-3.852 6.94-7.239 0-4.05-3.022-6.972-8.268-6.972-3.752 0-8.4 1.428-11.455 3.685C2.59 6.937 3.885 9.958 4.35 9.626c2.648-1.904 4.748-3.13 6.784-3.744C8.12 9.244.886 17.05 0 18.425c.1 1.261 1.66 4.648 2.424 4.648.232 0 .431-.133.664-.365a100.49 100.49 0 0 0 5.54-6.765c.222 3.104 1.748 6.898 6.014 6.898 3.819 0 7.604-2.756 9.33-8.965.2-.764-.73-1.361-1.261-.73zm-4.349-5.013c0 1.959-1.926 2.922-3.685 2.922-.941 0-1.664-.247-2.235-.568 1.051-1.592 2.092-3.225 3.21-4.973 1.972.334 2.71 1.43 2.71 2.619z"/>',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
// 브랜드 색. 어두운 화면에서 묻히는 짙은 색만 같은 색상을 밝혀 쓴다. 애플 로고는 브랜드 색이 검정이라 어두운 화면에선 흰색이다
|
|
42
|
+
const BRAND_COLORS = {
|
|
43
|
+
android: { light: '#3ddc84', dark: '#3ddc84' },
|
|
44
|
+
documentdb: { light: '#c925d1', dark: '#e06ae6' },
|
|
45
|
+
dynamodb: { light: '#4053d6', dark: '#7b8af0' },
|
|
46
|
+
elasticsearch: { light: '#005571', dark: '#00bfb3' },
|
|
47
|
+
ios: { light: '#000000', dark: '#ffffff' },
|
|
48
|
+
mariadb: { light: '#003545', dark: '#5fa8bd' },
|
|
49
|
+
mongodb: { light: '#47a248', dark: '#5fbf60' },
|
|
50
|
+
mysql: { light: '#4479a1', dark: '#6b9bd1' },
|
|
51
|
+
postgresql: { light: '#4169e1', dark: '#7b98ee' },
|
|
52
|
+
redis: { light: '#ff4438', dark: '#ff6b61' },
|
|
53
|
+
};
|
|
54
|
+
// 이름 안에 이 글자가 있으면 그 엔진이다. aurora-mysql처럼 관리형 서비스 이름이 앞에 붙어도 잡는다. mariadb가 mysql보다 먼저다
|
|
55
|
+
const ENGINE_MATCH = [
|
|
56
|
+
['mariadb', 'mariadb'],
|
|
57
|
+
['mysql', 'mysql'],
|
|
58
|
+
['postgres', 'postgresql'],
|
|
59
|
+
['redis', 'redis'],
|
|
60
|
+
['elasticsearch', 'elasticsearch'],
|
|
61
|
+
['documentdb', 'documentdb'],
|
|
62
|
+
['docdb', 'documentdb'],
|
|
63
|
+
['mongo', 'mongodb'],
|
|
64
|
+
['dynamo', 'dynamodb'],
|
|
65
|
+
];
|
|
66
|
+
/** datastore 노드의 엔진. engine 필드가 없으면 label에서 찾고 모르는 엔진이면 undefined다 */
|
|
67
|
+
export function datastoreEngine(node) {
|
|
68
|
+
if (node.kind !== 'datastore')
|
|
69
|
+
return undefined;
|
|
70
|
+
const name = (node.engine ?? node.label).toLowerCase();
|
|
71
|
+
return ENGINE_MATCH.find(([needle]) => name.includes(needle))?.[1];
|
|
72
|
+
}
|
|
73
|
+
const UI_ICONS = {
|
|
74
|
+
search: '<circle cx="11" cy="11" r="6.5"/><path d="M20 20l-4.2-4.2"/>',
|
|
75
|
+
plus: '<path d="M12 5v14M5 12h14"/>',
|
|
76
|
+
minus: '<path d="M5 12h14"/>',
|
|
77
|
+
fit: '<path d="M4 9V5.5A1.5 1.5 0 0 1 5.5 4H9M15 4h3.5A1.5 1.5 0 0 1 20 5.5V9M20 15v3.5a1.5 1.5 0 0 1-1.5 1.5H15M9 20H5.5A1.5 1.5 0 0 1 4 18.5V15"/>',
|
|
78
|
+
sun: '<circle cx="12" cy="12" r="4"/><path d="M12 2.5v2M12 19.5v2M2.5 12h2M19.5 12h2M5.3 5.3l1.4 1.4M17.3 17.3l1.4 1.4M5.3 18.7l1.4-1.4M17.3 6.7l1.4-1.4"/>',
|
|
79
|
+
moon: '<path d="M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z"/>',
|
|
80
|
+
close: '<path d="M6 6l12 12M18 6L6 18"/>',
|
|
81
|
+
focus: '<circle cx="12" cy="12" r="3"/><path d="M4 8.5V6a2 2 0 0 1 2-2h2.5M15.5 4H18a2 2 0 0 1 2 2v2.5M20 15.5V18a2 2 0 0 1-2 2h-2.5M8.5 20H6a2 2 0 0 1-2-2v-2.5"/>',
|
|
82
|
+
legend: '<path d="M4 6h3M4 12h3M4 18h3M10 6h10M10 12h10M10 18h10"/>',
|
|
83
|
+
question: '<circle cx="12" cy="12" r="8.5"/><path d="M9.6 9.5a2.5 2.5 0 0 1 4.8 1c0 1.7-2.4 2.2-2.4 3.6M12 17h.01"/>',
|
|
84
|
+
person: '<circle cx="12" cy="8" r="3.8"/><path d="M4.5 20.5a7.5 7.5 0 0 1 15 0"/>',
|
|
85
|
+
system: '<rect x="4" y="4" width="16" height="16" rx="3"/><path d="M9 9h6v6H9zM9 2v2M15 2v2M9 20v2M15 20v2M2 9h2M2 15h2M20 9h2M20 15h2"/>',
|
|
86
|
+
link: '<path d="M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1"/>',
|
|
87
|
+
flow: '<path d="M3.5 7h9M3.5 17h5M12.5 7l3 3-3 3M8.5 17l3-3"/><circle cx="18.5" cy="10" r="2"/>',
|
|
88
|
+
};
|
|
89
|
+
function symbol(id, body) {
|
|
90
|
+
return (`<symbol id="${id}" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.9" ` +
|
|
91
|
+
`stroke-linecap="round" stroke-linejoin="round">${body}</g></symbol>`);
|
|
92
|
+
}
|
|
93
|
+
function filledSymbol(id, body, viewBox = '0 0 24 24') {
|
|
94
|
+
return `<symbol id="${id}" viewBox="${viewBox}"><g fill="currentColor">${body}</g></symbol>`;
|
|
95
|
+
}
|
|
96
|
+
/** 페이지에 한 번만 싣는 아이콘 묶음. 카드와 단추는 use로 가져다 쓴다 */
|
|
97
|
+
export function renderIconSprite(vocab = LEGACY_VOCABULARY) {
|
|
98
|
+
const kinds = Object.keys(vocab.looks)
|
|
99
|
+
.sort()
|
|
100
|
+
.map((k) => symbol(`i-${k}`, vocab.looks[k].icon));
|
|
101
|
+
const ui = Object.keys(UI_ICONS)
|
|
102
|
+
.sort()
|
|
103
|
+
.map((k) => symbol(`u-${k}`, UI_ICONS[k]));
|
|
104
|
+
const platforms = Object.keys(PLATFORM_ICONS)
|
|
105
|
+
.sort()
|
|
106
|
+
.map((k) => symbol(`p-${k}`, PLATFORM_ICONS[k]));
|
|
107
|
+
const engines = Object.keys(ENGINE_ICONS)
|
|
108
|
+
.sort()
|
|
109
|
+
.map((k) => filledSymbol(`e-${k}`, ENGINE_ICONS[k].body, ENGINE_ICONS[k].viewBox));
|
|
110
|
+
return `<svg class="sprite" aria-hidden="true" focusable="false"><defs>${[...kinds, ...ui, ...platforms, ...engines].join('')}</defs></svg>`;
|
|
111
|
+
}
|
|
112
|
+
export function iconUse(id, cls = '') {
|
|
113
|
+
const c = cls ? ` class="${cls}"` : '';
|
|
114
|
+
return `<svg${c} viewBox="0 0 24 24" aria-hidden="true" focusable="false"><use href="#${id}"/></svg>`;
|
|
115
|
+
}
|
|
116
|
+
// 제품 브릭 색. 흰 글자를 올리므로 두 테마 다 같은 진한 색을 쓴다. 제품이 이보다 많으면 처음 색부터 다시 돈다
|
|
117
|
+
const PRODUCT_PALETTE = [
|
|
118
|
+
'#0f766e',
|
|
119
|
+
'#c2410c',
|
|
120
|
+
'#be185d',
|
|
121
|
+
'#0369a1',
|
|
122
|
+
'#4d7c0f',
|
|
123
|
+
'#92400e',
|
|
124
|
+
'#6d28d9',
|
|
125
|
+
'#475569',
|
|
126
|
+
];
|
|
127
|
+
export const PRODUCT_COLORS = PRODUCT_PALETTE.length;
|
|
128
|
+
function productRules() {
|
|
129
|
+
return PRODUCT_PALETTE.map((c, i) => `.p-${i}{--p:${c};}`).join('');
|
|
130
|
+
}
|
|
131
|
+
function kindRules(vocab, theme) {
|
|
132
|
+
return Object.keys(vocab.looks)
|
|
133
|
+
.sort()
|
|
134
|
+
.map((k) => `.k-${k}{--kind:${vocab.looks[k].color[theme]};}`)
|
|
135
|
+
.join('');
|
|
136
|
+
}
|
|
137
|
+
// 종류 칩의 로고는 흰 바탕 위에 서서 어두운 화면에서도 밝은 화면 색을 그대로 쓴다
|
|
138
|
+
function brandRules(theme) {
|
|
139
|
+
return Object.keys(BRAND_COLORS)
|
|
140
|
+
.sort()
|
|
141
|
+
.map((k) => {
|
|
142
|
+
const c = BRAND_COLORS[k];
|
|
143
|
+
return theme === 'light'
|
|
144
|
+
? `.b-${k}{--brand:${c.light};--brand-on-white:${c.light};}`
|
|
145
|
+
: `.b-${k}{--brand:${c.dark};}`;
|
|
146
|
+
})
|
|
147
|
+
.join('');
|
|
148
|
+
}
|
|
149
|
+
const LIGHT_TOKENS = `
|
|
150
|
+
color-scheme: light;
|
|
151
|
+
--bg: #f7f8fa;
|
|
152
|
+
--surface: #ffffff;
|
|
153
|
+
--surface-2: #f1f3f6;
|
|
154
|
+
--border: #e3e6ea;
|
|
155
|
+
--border-strong: #cdd2d9;
|
|
156
|
+
--text: #1b1f24;
|
|
157
|
+
--muted: #6b7280;
|
|
158
|
+
--accent: #2563eb;
|
|
159
|
+
--accent-soft: rgba(37, 99, 235, 0.14);
|
|
160
|
+
--on-accent: #ffffff;
|
|
161
|
+
--edge: #7b8494;
|
|
162
|
+
--edge-alpha: 0.55;
|
|
163
|
+
--edge-strong: #3f4753;
|
|
164
|
+
--lane: rgba(100, 116, 139, 0.085);
|
|
165
|
+
--lane-line: rgba(100, 116, 139, 0.16);
|
|
166
|
+
--warn: #b45309;
|
|
167
|
+
--warn-soft: #fef3c7;
|
|
168
|
+
--ok: #15803d;
|
|
169
|
+
--ok-soft: #dcfce7;
|
|
170
|
+
--live: #0369a1;
|
|
171
|
+
--live-soft: #e0f2fe;
|
|
172
|
+
--x-account: #c026d3;
|
|
173
|
+
--frame: rgba(3, 105, 161, 0.05);
|
|
174
|
+
--frame-line: #0369a1;
|
|
175
|
+
--loads: #0369a1;
|
|
176
|
+
--hit: #f59e0b;
|
|
177
|
+
--brick-base: #ffffff;
|
|
178
|
+
--brick-tint: 24%;
|
|
179
|
+
--shadow: 0 1px 2px rgba(16, 24, 40, 0.05), 0 1px 3px rgba(16, 24, 40, 0.04);
|
|
180
|
+
--shadow-hover: 0 6px 16px rgba(16, 24, 40, 0.1);
|
|
181
|
+
--shadow-pop: 0 12px 32px rgba(16, 24, 40, 0.14), 0 2px 6px rgba(16, 24, 40, 0.06);
|
|
182
|
+
`;
|
|
183
|
+
const DARK_TOKENS = `
|
|
184
|
+
color-scheme: dark;
|
|
185
|
+
--bg: #0f1115;
|
|
186
|
+
--surface: #171a21;
|
|
187
|
+
--surface-2: #1e222b;
|
|
188
|
+
--border: #2a2f3a;
|
|
189
|
+
--border-strong: #3b4250;
|
|
190
|
+
--text: #e6e8ec;
|
|
191
|
+
--muted: #8b93a1;
|
|
192
|
+
--accent: #60a5fa;
|
|
193
|
+
--accent-soft: rgba(96, 165, 250, 0.2);
|
|
194
|
+
--on-accent: #0b1220;
|
|
195
|
+
--edge: #8d96a8;
|
|
196
|
+
--edge-alpha: 0.5;
|
|
197
|
+
--edge-strong: #dde1e8;
|
|
198
|
+
--lane: rgba(148, 163, 184, 0.06);
|
|
199
|
+
--lane-line: rgba(148, 163, 184, 0.13);
|
|
200
|
+
--warn: #fbbf24;
|
|
201
|
+
--warn-soft: rgba(251, 191, 36, 0.14);
|
|
202
|
+
--ok: #4ade80;
|
|
203
|
+
--ok-soft: rgba(74, 222, 128, 0.12);
|
|
204
|
+
--live: #38bdf8;
|
|
205
|
+
--live-soft: rgba(56, 189, 248, 0.14);
|
|
206
|
+
--x-account: #e879f9;
|
|
207
|
+
--frame: rgba(125, 211, 252, 0.06);
|
|
208
|
+
--frame-line: #7dd3fc;
|
|
209
|
+
--loads: #7dd3fc;
|
|
210
|
+
--hit: #fbbf24;
|
|
211
|
+
--brick-base: #171a21;
|
|
212
|
+
--brick-tint: 44%;
|
|
213
|
+
--shadow: none;
|
|
214
|
+
--shadow-hover: 0 6px 18px rgba(0, 0, 0, 0.4);
|
|
215
|
+
--shadow-pop: 0 16px 40px rgba(0, 0, 0, 0.55);
|
|
216
|
+
`;
|
|
217
|
+
const LAYOUT_CSS = `
|
|
218
|
+
* { box-sizing: border-box; }
|
|
219
|
+
html, body { height: 100%; }
|
|
220
|
+
body {
|
|
221
|
+
margin: 0; display: flex; flex-direction: column; height: 100vh; overflow: hidden;
|
|
222
|
+
background: var(--bg); color: var(--text);
|
|
223
|
+
font: 14px/1.45 var(--font); -webkit-font-smoothing: antialiased;
|
|
224
|
+
}
|
|
225
|
+
button { font: inherit; color: inherit; }
|
|
226
|
+
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
227
|
+
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
|
|
228
|
+
.bar {
|
|
229
|
+
flex: none; height: 48px; display: flex; align-items: center; gap: 8px; padding: 0 12px 0 16px;
|
|
230
|
+
background: var(--surface); border-bottom: 1px solid var(--border); position: relative; z-index: 20;
|
|
231
|
+
}
|
|
232
|
+
.bar h1 { margin: 0; font-size: 14px; font-weight: 650; white-space: nowrap; }
|
|
233
|
+
.crumbs { display: flex; align-items: center; gap: 2px; min-width: 0; overflow: hidden; font-size: 13px; color: var(--muted); }
|
|
234
|
+
.crumbs::before { content: ''; width: 1px; height: 16px; background: var(--border); margin: 0 8px 0 4px; flex: none; }
|
|
235
|
+
.crumbs[hidden] { display: none; }
|
|
236
|
+
.crumbs button { border: 0; background: none; padding: 4px 6px; border-radius: 6px; cursor: pointer; color: var(--muted); white-space: nowrap; }
|
|
237
|
+
.crumbs button:hover { background: var(--surface-2); color: var(--text); }
|
|
238
|
+
.crumbs .sep { opacity: 0.6; padding: 0 1px; }
|
|
239
|
+
.crumbs .here { color: var(--text); font-weight: 600; padding: 4px 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
240
|
+
.spacer { flex: 1; }
|
|
241
|
+
.focus-chip {
|
|
242
|
+
display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 4px 0 10px; margin-left: 6px; flex: none; max-width: 320px;
|
|
243
|
+
border-radius: 14px; font-size: 12px; color: var(--accent); background: var(--accent-soft); white-space: nowrap;
|
|
244
|
+
}
|
|
245
|
+
.focus-chip[hidden] { display: none; }
|
|
246
|
+
.focus-chip svg { width: 14px; height: 14px; flex: none; }
|
|
247
|
+
.focus-chip b { overflow: hidden; text-overflow: ellipsis; color: var(--text); font-weight: 650; }
|
|
248
|
+
.focus-chip button { flex: none; width: 22px; height: 22px; padding: 3px; border: 0; border-radius: 11px; background: none; color: var(--accent); cursor: pointer; }
|
|
249
|
+
.focus-chip button:hover { background: var(--accent-soft); }
|
|
250
|
+
.btn[hidden] { display: none; }
|
|
251
|
+
.search {
|
|
252
|
+
display: flex; align-items: center; gap: 6px; height: 32px; width: 240px; padding: 0 10px;
|
|
253
|
+
border: 1px solid var(--border); border-radius: 8px; background: var(--bg); color: var(--muted);
|
|
254
|
+
}
|
|
255
|
+
.search:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
|
|
256
|
+
.search svg { width: 15px; height: 15px; flex: none; }
|
|
257
|
+
.search input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; color: var(--text); font: inherit; font-size: 13px; }
|
|
258
|
+
.search input::-webkit-search-cancel-button { display: none; }
|
|
259
|
+
.search .count { font-size: 11px; font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
260
|
+
.btn {
|
|
261
|
+
height: 32px; display: inline-flex; align-items: center; gap: 6px; padding: 0 10px; flex: none;
|
|
262
|
+
border: 1px solid var(--border); border-radius: 8px; background: var(--surface); font-size: 13px; cursor: pointer; white-space: nowrap;
|
|
263
|
+
}
|
|
264
|
+
.btn:hover { background: var(--surface-2); }
|
|
265
|
+
.btn svg { width: 16px; height: 16px; color: var(--muted); }
|
|
266
|
+
.btn.icon { width: 32px; padding: 0; justify-content: center; }
|
|
267
|
+
.btn[aria-expanded="true"] { background: var(--surface-2); border-color: var(--border-strong); }
|
|
268
|
+
.btn .n {
|
|
269
|
+
min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; display: inline-flex; align-items: center; justify-content: center;
|
|
270
|
+
font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; background: var(--surface-2); color: var(--muted);
|
|
271
|
+
}
|
|
272
|
+
.btn .n.warn { background: var(--warn-soft); color: var(--warn); }
|
|
273
|
+
.seg { display: inline-flex; align-items: center; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); flex: none; }
|
|
274
|
+
.seg .btn { border: 0; height: 30px; }
|
|
275
|
+
.env-picker .btn { padding: 0 9px; color: var(--muted); font-variant-numeric: tabular-nums; }
|
|
276
|
+
.env-picker .btn[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); font-weight: 650; }
|
|
277
|
+
.env-off { display: none !important; }
|
|
278
|
+
.zoom-level { min-width: 44px; text-align: center; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
|
|
279
|
+
#theme-btn .sun { display: none; }
|
|
280
|
+
#theme-btn[data-mode="dark"] .sun { display: block; }
|
|
281
|
+
#theme-btn[data-mode="dark"] .moon { display: none; }
|
|
282
|
+
#theme-btn[data-mode="light"] .moon { display: block; }
|
|
283
|
+
#theme-btn[data-mode="light"] .sun { display: none; }
|
|
284
|
+
.meta { display: flex; gap: 10px; padding-left: 4px; font-size: 11px; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
285
|
+
.main { position: relative; flex: 1; min-height: 0; overflow: hidden; }
|
|
286
|
+
.stage { position: absolute; inset: 0; overflow: hidden; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
|
|
287
|
+
.stage.panning { cursor: grabbing; }
|
|
288
|
+
.viewport { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
|
|
289
|
+
.viewport.glide { transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.2, 1); }
|
|
290
|
+
.level { position: relative; }
|
|
291
|
+
.level[hidden] { display: none; }
|
|
292
|
+
.links { position: absolute; left: 0; top: 0; overflow: visible; pointer-events: none; }
|
|
293
|
+
.lane { fill: var(--lane); stroke: var(--lane-line); stroke-width: 1; }
|
|
294
|
+
.frame { fill: var(--frame); stroke: var(--frame-line); stroke-width: 1.25; stroke-opacity: 0.6; }
|
|
295
|
+
.band-line { stroke: var(--border-strong); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
296
|
+
.band-title {
|
|
297
|
+
position: absolute; height: 20px; padding: 0 6px; display: flex; align-items: center; gap: 6px; border-radius: 4px;
|
|
298
|
+
font-size: 12px; font-weight: 700; color: var(--text); background: var(--bg); white-space: nowrap; pointer-events: none;
|
|
299
|
+
}
|
|
300
|
+
.band-title .sw { width: 10px; height: 10px; border-radius: 2px; background: var(--p); }
|
|
301
|
+
.lane-title {
|
|
302
|
+
position: absolute; display: flex; align-items: center; gap: 8px; padding: 0 14px; height: 22px;
|
|
303
|
+
font-size: 14px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden;
|
|
304
|
+
}
|
|
305
|
+
.lane-title .n {
|
|
306
|
+
min-width: 20px; height: 18px; padding: 0 6px; border-radius: 9px; display: inline-flex; align-items: center; justify-content: center;
|
|
307
|
+
font-size: 11px; font-weight: 600; color: var(--muted); background: var(--surface); border: 1px solid var(--border); font-variant-numeric: tabular-nums;
|
|
308
|
+
}
|
|
309
|
+
.node {
|
|
310
|
+
--brick: color-mix(in srgb, var(--kind) var(--brick-tint), var(--brick-base));
|
|
311
|
+
--brick-edge: color-mix(in srgb, var(--kind) 42%, var(--brick));
|
|
312
|
+
--thick: 0 3px 0 var(--brick-edge);
|
|
313
|
+
position: absolute; display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: 8px; row-gap: 2px; align-content: center;
|
|
314
|
+
padding: 0 20px 0 10px; cursor: pointer;
|
|
315
|
+
background: var(--brick); border: 1px solid var(--brick-edge); border-radius: 4px; box-shadow: var(--thick);
|
|
316
|
+
transition: box-shadow 0.15s, border-color 0.15s, opacity 0.15s;
|
|
317
|
+
}
|
|
318
|
+
/* 카드 위 돌기. 하나를 그리고 box-shadow로 셋을 더 찍는다. 그림자 사본도 모서리 둥글기를 따라간다 */
|
|
319
|
+
.node::before {
|
|
320
|
+
content: ''; position: absolute; left: 12px; top: -6px; width: 14px; height: 5px; border-radius: 3px 3px 0 0;
|
|
321
|
+
background: var(--brick-edge); box-shadow: 20px 0 var(--brick-edge), 40px 0 var(--brick-edge), 60px 0 var(--brick-edge);
|
|
322
|
+
}
|
|
323
|
+
/* 같이 쓰는 카드는 돌기 자리에 제품 브릭을 꽂는다 */
|
|
324
|
+
.node.shared::before { display: none; }
|
|
325
|
+
.pbricks { position: absolute; left: 8px; right: 8px; bottom: calc(100% + 1px); display: flex; gap: 2px; }
|
|
326
|
+
.pb {
|
|
327
|
+
flex: none; height: 17px; padding: 0 6px; border-radius: 3px 3px 0 0;
|
|
328
|
+
font: 700 10.5px/17px var(--font); color: #fff; background: var(--p); white-space: nowrap;
|
|
329
|
+
box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--p) 70%, #000);
|
|
330
|
+
}
|
|
331
|
+
.pb.more {
|
|
332
|
+
border: 1px solid var(--border-strong); border-bottom: 0; line-height: 15px; cursor: pointer;
|
|
333
|
+
color: var(--text); background: var(--surface); box-shadow: none;
|
|
334
|
+
}
|
|
335
|
+
.pb.more:hover, .pb.more[aria-expanded="true"] { color: var(--bg); background: var(--text); border-color: var(--text); }
|
|
336
|
+
.pb.more:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
337
|
+
/* +N 드롭다운. 캔버스는 확대와 스크롤 상자 안이라 그 안에 두면 잘린다. 화면 기준으로 띄운다 */
|
|
338
|
+
.pmenu {
|
|
339
|
+
position: fixed; z-index: 40; min-width: 168px; padding: 6px;
|
|
340
|
+
background: var(--surface); border: 1px solid var(--border-strong); border-radius: 6px; box-shadow: 0 3px 0 var(--border-strong);
|
|
341
|
+
}
|
|
342
|
+
.pmenu[hidden] { display: none; }
|
|
343
|
+
.pmenu h3 { margin: 2px 6px 6px; font-size: 11px; font-weight: 600; color: var(--muted); }
|
|
344
|
+
.pmenu ul { margin: 0; padding: 0; list-style: none; }
|
|
345
|
+
.pmenu li { display: flex; align-items: center; gap: 8px; padding: 4px 6px; font-size: 13px; font-weight: 600; color: var(--text); }
|
|
346
|
+
.pmenu .pb { height: 15px; padding: 0 5px; font-size: 10px; line-height: 15px; }
|
|
347
|
+
.pmenu small { margin-left: auto; font-weight: 500; color: var(--muted); }
|
|
348
|
+
.node:hover { box-shadow: var(--thick), var(--shadow-hover); }
|
|
349
|
+
.node:focus { outline: none; }
|
|
350
|
+
.node:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
|
|
351
|
+
.node.is-focus { border-color: var(--kind); }
|
|
352
|
+
.node.focus-root:not(.selected) { border-color: var(--accent); box-shadow: var(--thick), 0 0 0 3px var(--accent-soft); }
|
|
353
|
+
.node.selected { border-color: var(--accent); box-shadow: var(--thick), 0 0 0 4px var(--accent-soft), var(--shadow-hover); }
|
|
354
|
+
.node.anchor:not(.selected) { outline: 2px dashed var(--accent); outline-offset: 3px; }
|
|
355
|
+
.node.hit { box-shadow: var(--thick), 0 0 0 3px var(--hit); }
|
|
356
|
+
.node.hit.current { box-shadow: var(--thick), 0 0 0 4px var(--hit), var(--shadow-hover); }
|
|
357
|
+
.kc {
|
|
358
|
+
grid-row: 1; display: inline-flex; align-items: center; gap: 3px; height: 18px; padding: 0 6px 0 4px; border-radius: 5px; align-self: center;
|
|
359
|
+
font-size: 10.5px; font-weight: 650; line-height: 1; white-space: nowrap;
|
|
360
|
+
color: color-mix(in srgb, var(--kind) 72%, var(--text)); background: color-mix(in srgb, var(--kind) 13%, transparent);
|
|
361
|
+
}
|
|
362
|
+
.kc svg { width: 12px; height: 12px; flex: none; color: var(--kind); }
|
|
363
|
+
.kc svg.brand, .pf svg.brand { color: var(--brand); }
|
|
364
|
+
/* 붉은 저장소 칩 위에서 파란 로고가 흐려져서 흰 바탕을 깐다 */
|
|
365
|
+
.kc svg.brand {
|
|
366
|
+
width: 16px; height: 16px; padding: 2px; margin-left: -2px; border-radius: 4px;
|
|
367
|
+
color: var(--brand-on-white); background: #fff;
|
|
368
|
+
}
|
|
369
|
+
.nm { grid-row: 1; grid-column: 2; display: flex; align-items: center; min-width: 0; font-size: 13px; font-weight: 600; line-height: 18px; }
|
|
370
|
+
.nm .t { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
371
|
+
.tc {
|
|
372
|
+
grid-row: 2; grid-column: 1 / -1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
373
|
+
font: 11px/16px var(--mono); color: var(--muted);
|
|
374
|
+
}
|
|
375
|
+
.guess {
|
|
376
|
+
flex: none; margin-left: 6px; padding: 0 5px; border-radius: 8px; font-size: 10px; font-weight: 600; line-height: 16px;
|
|
377
|
+
color: var(--warn); background: var(--warn-soft);
|
|
378
|
+
}
|
|
379
|
+
.flow-badge {
|
|
380
|
+
flex: none; display: inline-flex; align-items: center; gap: 3px; margin-left: 6px; padding: 0 6px; border-radius: 8px;
|
|
381
|
+
font-size: 10.5px; font-weight: 700; line-height: 16px; color: var(--on-accent);
|
|
382
|
+
background: var(--accent); box-shadow: 0 2px 0 color-mix(in srgb, var(--accent) 60%, #000);
|
|
383
|
+
}
|
|
384
|
+
.flow-badge svg { width: 12px; height: 12px; flex: none; }
|
|
385
|
+
.flow-badge:hover { background: color-mix(in srgb, var(--accent) 85%, var(--text)); }
|
|
386
|
+
/* 파스텔 브릭 위에서 연한 배지는 묻힌다. 카드 안 추정 배지는 꽉 채운다 */
|
|
387
|
+
.node .guess { color: var(--bg); background: var(--warn); }
|
|
388
|
+
.go { position: absolute; right: 8px; bottom: 4px; font-size: 14px; line-height: 1; color: var(--muted); }
|
|
389
|
+
.pf {
|
|
390
|
+
flex: none; display: inline-flex; align-items: center; gap: 3px; height: 16px; margin-left: 4px; padding: 0 4px;
|
|
391
|
+
border: 1px solid color-mix(in srgb, var(--muted) 45%, transparent); border-radius: 4px;
|
|
392
|
+
font-size: 10px; font-weight: 650; line-height: 1; color: var(--muted);
|
|
393
|
+
}
|
|
394
|
+
.pf svg { width: 11px; height: 11px; flex: none; }
|
|
395
|
+
.tc.dom { font-family: var(--font); color: var(--text); }
|
|
396
|
+
.l2 { grid-row: 2; grid-column: 1 / -1; display: flex; align-items: center; min-width: 0; }
|
|
397
|
+
.l2 .pf:first-child { margin-left: 0; }
|
|
398
|
+
/* 도메인 흐름. 행위자 줄은 번갈아 옅게 칠해 줄 경계를 읽히게 하고, 옆 흐름은 정상 흐름과 색으로 가른다 */
|
|
399
|
+
.flane { fill: var(--lane); stroke: var(--lane-line); stroke-width: 1; }
|
|
400
|
+
.flane.alt { fill: color-mix(in srgb, var(--lane) 55%, var(--bg)); }
|
|
401
|
+
.fstage {
|
|
402
|
+
position: absolute; height: 26px; display: flex; align-items: center; justify-content: center; padding: 0 10px;
|
|
403
|
+
border-radius: 999px; background: var(--lane); border: 1px solid var(--lane-line);
|
|
404
|
+
font: 600 12px/1 var(--mono); color: var(--text); pointer-events: none; box-sizing: border-box;
|
|
405
|
+
}
|
|
406
|
+
.fstage span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
407
|
+
.fstage.side { font-family: inherit; color: var(--muted); border-style: dashed; }
|
|
408
|
+
.fstage.named { font-family: inherit; }
|
|
409
|
+
.fstage-line { stroke: var(--lane-line); stroke-width: 1; stroke-dasharray: 4 4; }
|
|
410
|
+
.fstage-line.side { stroke-width: 1.5; stroke-dasharray: none; }
|
|
411
|
+
.flane-title {
|
|
412
|
+
position: absolute; display: flex; align-items: flex-start; gap: 6px; max-width: 112px;
|
|
413
|
+
font-size: 13px; font-weight: 700; line-height: 18px; color: var(--text); pointer-events: none;
|
|
414
|
+
}
|
|
415
|
+
.flane-title span { overflow: hidden; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; word-break: keep-all; }
|
|
416
|
+
.flane-title svg { width: 15px; height: 15px; flex: none; margin-top: 1.5px; color: var(--muted); }
|
|
417
|
+
.flow-step { --kind: var(--accent); padding: 0 12px 0 12px; }
|
|
418
|
+
.flow-step.p-side { --kind: var(--warn); }
|
|
419
|
+
.flow-step.doc-only { border-style: dashed; }
|
|
420
|
+
.flow-step .nm { grid-column: 1 / -1; white-space: normal; }
|
|
421
|
+
.flow-step .nm .t { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 17px; }
|
|
422
|
+
.flow-step .l2 { gap: 6px; }
|
|
423
|
+
.flow-step .st {
|
|
424
|
+
min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
|
|
425
|
+
font: 10.5px/16px var(--mono); padding: 0 5px; border-radius: 4px; color: var(--muted); background: var(--lane);
|
|
426
|
+
}
|
|
427
|
+
.flow-step .st.named { font-family: inherit; font-weight: 600; }
|
|
428
|
+
.flow-step .refs, .flow-step .qb {
|
|
429
|
+
flex: none; display: inline-flex; align-items: center; gap: 2px; font-size: 10.5px; font-weight: 650; color: var(--muted);
|
|
430
|
+
}
|
|
431
|
+
.flow-step .qb { color: var(--warn); }
|
|
432
|
+
.flow-step .end {
|
|
433
|
+
flex: none; font-size: 10.5px; line-height: 16px; font-weight: 700; padding: 0 5px; border-radius: 4px;
|
|
434
|
+
color: var(--surface); background: var(--text);
|
|
435
|
+
}
|
|
436
|
+
.flow-step .refs svg, .flow-step .qb svg { width: 11px; height: 11px; }
|
|
437
|
+
.node .l2 { overflow: hidden; }
|
|
438
|
+
.link.flow-t { cursor: pointer; }
|
|
439
|
+
.legend-lines line.side-line { stroke: var(--warn); }
|
|
440
|
+
.swatch-step { display: inline-block; width: 30px; height: 14px; margin-right: 8px; border: 1.5px dashed var(--border-strong); border-radius: 4px; vertical-align: middle; }
|
|
441
|
+
.link.flow-t.p-side .edge { stroke: var(--warn); }
|
|
442
|
+
.link.flow-t.p-side .tip { fill: var(--warn); }
|
|
443
|
+
.link.flow-t .t-label {
|
|
444
|
+
font-size: 11px; font-weight: 600; text-anchor: middle; fill: var(--muted);
|
|
445
|
+
paint-order: stroke; stroke: var(--bg); stroke-width: 4px; stroke-linejoin: round;
|
|
446
|
+
}
|
|
447
|
+
.link.flow-t .t-who { fill: var(--text); font-weight: 700; }
|
|
448
|
+
.link.flow-t .t-back { fill: var(--accent); font-weight: 700; }
|
|
449
|
+
.dr-body .refs-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; padding: 0; list-style: none; }
|
|
450
|
+
.dr-body .refs-list button {
|
|
451
|
+
display: inline-flex; align-items: center; gap: 4px; max-width: 100%; padding: 3px 8px; border-radius: 6px; cursor: pointer;
|
|
452
|
+
font: inherit; font-size: 12px; color: var(--text); background: var(--surface); border: 1px solid var(--border);
|
|
453
|
+
}
|
|
454
|
+
.dr-body .refs-list button:hover { border-color: var(--accent); }
|
|
455
|
+
.dr-body .refs-list button svg { width: 12px; height: 12px; flex: none; color: var(--kind, var(--muted)); }
|
|
456
|
+
.flow-list { margin: 8px 0 0; padding: 0; list-style: none; }
|
|
457
|
+
.flow-list button {
|
|
458
|
+
display: block; width: 100%; padding: 8px 10px; border: 0; border-radius: 6px; text-align: left; cursor: pointer;
|
|
459
|
+
font: inherit; font-size: 13px; color: var(--text); background: none;
|
|
460
|
+
}
|
|
461
|
+
.flow-list button:hover { background: var(--lane); }
|
|
462
|
+
.link.x-account .edge { stroke: var(--x-account); stroke-opacity: 0.85; }
|
|
463
|
+
.link.x-account .tip { fill: var(--x-account); fill-opacity: 0.85; }
|
|
464
|
+
.link.e-contains .edge { stroke-opacity: 0.35; }
|
|
465
|
+
.link.e-loads .edge { stroke: var(--loads); stroke-opacity: 0.75; }
|
|
466
|
+
.link.e-loads .tip { fill: var(--loads); fill-opacity: 0.8; }
|
|
467
|
+
/* 근거가 확인된 로드 선은 점선으로 요청 흐름과 구분한다. 근거가 약한 선은 기존 파선이 그대로 이긴다 */
|
|
468
|
+
.link.e-loads .edge:not([stroke-dasharray]) { stroke-dasharray: 1 6; stroke-width: 2.5; }
|
|
469
|
+
.link .edge { fill: none; stroke: var(--edge); stroke-opacity: var(--edge-alpha); stroke-linecap: round; transition: stroke 0.15s, stroke-opacity 0.15s; }
|
|
470
|
+
.link .tip { fill: var(--edge); fill-opacity: 0.6; transition: fill 0.15s; }
|
|
471
|
+
.link .hit { fill: none; stroke: transparent; pointer-events: stroke; }
|
|
472
|
+
.link.bundle { cursor: pointer; }
|
|
473
|
+
.link:focus { outline: none; }
|
|
474
|
+
.link.lit .edge, .link:hover .edge { stroke: var(--edge-strong); stroke-opacity: 0.9; }
|
|
475
|
+
.link.lit .tip, .link:hover .tip { fill: var(--edge-strong); fill-opacity: 1; }
|
|
476
|
+
.link:focus-visible .edge { stroke: var(--accent); stroke-opacity: 1; }
|
|
477
|
+
.pill { opacity: 0; transition: opacity 0.15s; }
|
|
478
|
+
.link.lit .pill, .link:hover .pill, .link:focus-visible .pill { opacity: 1; }
|
|
479
|
+
.pill rect { fill: var(--surface); stroke: var(--border-strong); }
|
|
480
|
+
.pill text { fill: var(--text); font: 600 11px var(--font); text-anchor: middle; dominant-baseline: central; font-variant-numeric: tabular-nums; }
|
|
481
|
+
.level .node, .level .link { transition: opacity 0.15s, box-shadow 0.15s, border-color 0.15s; }
|
|
482
|
+
.dimmed .node:not(.lit), .dimmed .link:not(.lit) { opacity: 0.15; }
|
|
483
|
+
.searching .node:not(.hit) { opacity: 0.35; }
|
|
484
|
+
.empty-state { position: absolute; inset: 0; display: grid; place-items: center; margin: 0; color: var(--muted); }
|
|
485
|
+
.hint {
|
|
486
|
+
position: absolute; left: 16px; bottom: 16px; z-index: 5; max-width: min(560px, calc(100% - 32px));
|
|
487
|
+
display: flex; align-items: flex-start; gap: 8px; margin: 0; padding: 8px 8px 8px 12px;
|
|
488
|
+
font-size: 12px; color: var(--muted); background: var(--surface); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow);
|
|
489
|
+
}
|
|
490
|
+
.hint[hidden] { display: none; }
|
|
491
|
+
.hint button { flex: none; border: 0; background: none; width: 20px; height: 20px; padding: 2px; border-radius: 5px; cursor: pointer; color: var(--muted); }
|
|
492
|
+
.hint button:hover { background: var(--surface-2); }
|
|
493
|
+
.hint svg { width: 16px; height: 16px; display: block; }
|
|
494
|
+
.drawer {
|
|
495
|
+
position: absolute; top: 0; right: 0; bottom: 0; width: 380px; max-width: 100%; z-index: 15;
|
|
496
|
+
display: flex; flex-direction: column; background: var(--surface); border-left: 1px solid var(--border); box-shadow: var(--shadow-pop);
|
|
497
|
+
transform: translateX(100%); visibility: hidden; transition: transform 0.2s ease, visibility 0s linear 0.2s;
|
|
498
|
+
}
|
|
499
|
+
.drawer.open { transform: none; visibility: visible; transition: transform 0.2s ease; }
|
|
500
|
+
.dr-close { position: absolute; top: 12px; right: 12px; }
|
|
501
|
+
.dr-head { padding: 18px 56px 14px 20px; border-bottom: 1px solid var(--border); }
|
|
502
|
+
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 10px; }
|
|
503
|
+
.chip {
|
|
504
|
+
display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 8px; border-radius: 11px;
|
|
505
|
+
font-size: 12px; font-weight: 600; color: var(--kind); background: color-mix(in srgb, var(--kind) 13%, transparent);
|
|
506
|
+
}
|
|
507
|
+
.chip svg { width: 12px; height: 12px; }
|
|
508
|
+
.chip.flow { --kind: var(--accent); }
|
|
509
|
+
.chip.flow.side { --kind: var(--warn); }
|
|
510
|
+
.repo { font: 11px var(--mono); color: var(--muted); word-break: break-all; }
|
|
511
|
+
.dr-head h2 { margin: 0; font-size: 17px; line-height: 1.4; word-break: break-word; outline: none; }
|
|
512
|
+
.dr-head h2 .guess { vertical-align: 2px; }
|
|
513
|
+
.tech { margin-top: 2px; font: 12px/1.5 var(--mono); color: var(--muted); word-break: break-all; }
|
|
514
|
+
.guess-note { margin: 10px 0 0; padding: 8px 10px; border-radius: 8px; font-size: 12px; line-height: 1.5; color: var(--warn); background: var(--warn-soft); }
|
|
515
|
+
.dr-body { flex: 1; overflow-y: auto; padding: 16px 20px 28px; }
|
|
516
|
+
.actions { display: flex; gap: 8px; margin-bottom: 16px; }
|
|
517
|
+
.actions button { flex: 1; height: 36px; border-radius: 8px; cursor: pointer; font-weight: 600; display: inline-flex; align-items: center; justify-content: center; gap: 6px; }
|
|
518
|
+
.actions svg { width: 15px; height: 15px; }
|
|
519
|
+
.enter { border: 0; background: var(--accent); color: var(--on-accent); }
|
|
520
|
+
.enter:hover { filter: brightness(1.06); }
|
|
521
|
+
.actions .focus { border: 1px solid var(--border-strong); background: var(--surface); color: var(--text); }
|
|
522
|
+
.actions .focus:hover { background: var(--surface-2); }
|
|
523
|
+
.desc { margin: 0 0 18px; line-height: 1.6; word-break: break-word; }
|
|
524
|
+
.dr-body h3, .pop h3 { margin: 0 0 8px; font-size: 12px; font-weight: 650; color: var(--muted); }
|
|
525
|
+
.evidence { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
|
|
526
|
+
.evidence li { padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); }
|
|
527
|
+
.badge { display: inline-flex; align-items: center; height: 20px; padding: 0 7px; margin: 0 6px 4px 0; border-radius: 10px; font-size: 11px; font-weight: 600; vertical-align: middle; }
|
|
528
|
+
.badge.t-code, .badge.t-spec { color: var(--ok); background: var(--ok-soft); }
|
|
529
|
+
.badge.t-doc, .badge.t-user, .badge.guess { color: var(--warn); background: var(--warn-soft); }
|
|
530
|
+
.badge.t-live { color: var(--live); background: var(--live-soft); }
|
|
531
|
+
.cmd { display: block; margin-top: 4px; font: 12px/1.5 var(--mono); word-break: break-all; color: var(--text); }
|
|
532
|
+
.facts { list-style: none; margin: 0 0 18px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
533
|
+
.facts li { display: flex; gap: 8px; align-items: baseline; font-size: 12.5px; }
|
|
534
|
+
.facts .env { flex: none; min-width: 44px; font-weight: 650; color: var(--muted); }
|
|
535
|
+
.facts .val { min-width: 0; word-break: break-all; }
|
|
536
|
+
.evidence.plat { margin-bottom: 18px; }
|
|
537
|
+
.evidence .evidence { margin-top: 8px; }
|
|
538
|
+
.loc { display: block; font: 12px/1.5 var(--mono); word-break: break-all; }
|
|
539
|
+
a.loc { color: var(--accent); text-decoration: none; }
|
|
540
|
+
a.loc:hover { text-decoration: underline; }
|
|
541
|
+
.ev-meta { margin-top: 4px; font-size: 11px; color: var(--muted); }
|
|
542
|
+
.evidence pre {
|
|
543
|
+
margin: 8px 0 0; padding: 8px 10px; max-height: 220px; overflow: auto; border-radius: 6px;
|
|
544
|
+
font: 11.5px/1.55 var(--mono); white-space: pre-wrap; word-break: break-word; background: var(--surface-2);
|
|
545
|
+
}
|
|
546
|
+
.empty { margin: 0; color: var(--muted); }
|
|
547
|
+
.pop {
|
|
548
|
+
position: fixed; z-index: 40; width: 360px; max-width: calc(100vw - 16px); max-height: min(70vh, 560px); overflow-x: hidden; overflow-y: auto;
|
|
549
|
+
padding: 14px 16px; background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow-pop);
|
|
550
|
+
}
|
|
551
|
+
.pop[hidden] { display: none; }
|
|
552
|
+
.pop:focus { outline: none; }
|
|
553
|
+
.pop ul { list-style: none; margin: 0 0 14px; padding: 0; display: grid; gap: 8px; }
|
|
554
|
+
.pop li { display: flex; align-items: center; gap: 10px; font-size: 13px; }
|
|
555
|
+
.legend-kinds { grid-template-columns: 1fr 1fr; }
|
|
556
|
+
.legend-lines svg { flex: none; }
|
|
557
|
+
.legend-lines line { stroke: var(--edge-strong); stroke-linecap: round; }
|
|
558
|
+
.legend-lines line.x-account-line { stroke: var(--x-account); }
|
|
559
|
+
.swatch { flex: none; width: 22px; height: 22px; border-radius: 6px; display: grid; place-items: center; color: var(--kind); background: color-mix(in srgb, var(--kind) 14%, transparent); }
|
|
560
|
+
.swatch svg { width: 14px; height: 14px; }
|
|
561
|
+
.legend-kinds { grid-template-columns: 1fr !important; }
|
|
562
|
+
.legend-kinds .kc { flex: none; }
|
|
563
|
+
.pop .foot { margin: 0; padding-top: 10px; border-top: 1px solid var(--border); font-size: 11px; line-height: 1.6; color: var(--muted); }
|
|
564
|
+
.q-list { gap: 2px !important; }
|
|
565
|
+
.q-list li { display: block; }
|
|
566
|
+
.q {
|
|
567
|
+
display: block; width: 100%; padding: 8px 10px; text-align: left; border: 0; border-radius: 8px; background: none; cursor: pointer;
|
|
568
|
+
}
|
|
569
|
+
.q:hover:not(:disabled) { background: var(--surface-2); }
|
|
570
|
+
.q:disabled { cursor: default; }
|
|
571
|
+
.q-subj { display: block; font-size: 12px; font-weight: 600; color: var(--accent); word-break: break-all; }
|
|
572
|
+
.q:disabled .q-subj { color: var(--muted); }
|
|
573
|
+
.qlist { list-style: none; margin: 0 0 12px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
574
|
+
.q-text { display: block; margin-top: 2px; font-size: 13px; line-height: 1.5; overflow-wrap: anywhere; }
|
|
575
|
+
.sheet {
|
|
576
|
+
position: absolute; left: 16px; right: 16px; bottom: 16px; z-index: 10; max-height: 45%; display: flex; flex-direction: column;
|
|
577
|
+
background: var(--surface); border: 1px solid var(--border); border-radius: 12px; box-shadow: var(--shadow-pop);
|
|
578
|
+
}
|
|
579
|
+
.sheet[hidden] { display: none; }
|
|
580
|
+
.sheet summary { padding: 10px 14px; font-size: 13px; font-weight: 600; cursor: pointer; }
|
|
581
|
+
.sheet .scroll { overflow: auto; padding: 0 14px 12px; }
|
|
582
|
+
.sheet table { width: 100%; border-collapse: collapse; font-size: 12px; }
|
|
583
|
+
.sheet th { position: sticky; top: 0; background: var(--surface); color: var(--muted); font-weight: 600; text-align: left; }
|
|
584
|
+
.sheet th, .sheet td { padding: 6px 8px; border-bottom: 1px solid var(--border); vertical-align: top; text-align: left; }
|
|
585
|
+
.sheet td .loc { font-size: 11px; }
|
|
586
|
+
.sheet th:first-child, .sheet td:first-child { white-space: nowrap; }
|
|
587
|
+
@media (max-width: 900px) {
|
|
588
|
+
.meta, .bar h1 { display: none; }
|
|
589
|
+
.crumbs::before { display: none; }
|
|
590
|
+
.search { width: 160px; }
|
|
591
|
+
.btn .label { display: none; }
|
|
592
|
+
}
|
|
593
|
+
@media (max-width: 560px) {
|
|
594
|
+
.bar { gap: 6px; padding: 0 8px 0 12px; }
|
|
595
|
+
.seg, #zoom-fit, .spacer { display: none; }
|
|
596
|
+
.search { width: auto; flex: 1; min-width: 0; }
|
|
597
|
+
.search input { width: 100%; }
|
|
598
|
+
.drawer { width: 100%; }
|
|
599
|
+
.hint { display: none; }
|
|
600
|
+
}
|
|
601
|
+
`;
|
|
602
|
+
/** 질문별 그림이 있을 때만 붙이는 스타일. 공용 CSS에 넣으면 투영 없는 그림의 바이트가 바뀐다 */
|
|
603
|
+
export const VIEW_CSS = `.view-q { position: absolute; top: 18px; margin: 0; font-size: 13px; color: var(--muted); }
|
|
604
|
+
.lifeline { stroke: var(--border-strong); stroke-width: 1.5; stroke-dasharray: 4 5; }
|
|
605
|
+
.seq-block rect { fill: var(--lane); stroke: var(--border-strong); stroke-width: 1; }
|
|
606
|
+
.seq-block .b-tab { fill: var(--surface); stroke: var(--border-strong); stroke-width: 1; }
|
|
607
|
+
.seq-block .b-kind { font-size: 11px; font-weight: 700; fill: var(--text); }
|
|
608
|
+
.seq-block .b-label { font-size: 11px; fill: var(--muted); }
|
|
609
|
+
.seq-block .b-branch { stroke: var(--border-strong); stroke-dasharray: 5 4; }
|
|
610
|
+
.link.seq-m { cursor: pointer; }
|
|
611
|
+
.link.seq-m .tip.open { fill: none; stroke: var(--edge); stroke-width: 1.6; }
|
|
612
|
+
.link.seq-m.lit .tip.open, .link.seq-m:hover .tip.open { fill: none; stroke: var(--edge-strong); }
|
|
613
|
+
.link.seq-m .m-label {
|
|
614
|
+
font-size: 11.5px; font-weight: 600; fill: var(--text);
|
|
615
|
+
paint-order: stroke; stroke: var(--bg); stroke-width: 4px; stroke-linejoin: round;
|
|
616
|
+
}
|
|
617
|
+
.link.seq-m .m-n { fill: var(--muted); }
|
|
618
|
+
.view-list a { display: block; padding: 8px 10px; border-radius: 6px; color: var(--text); text-decoration: none; font-size: 13px; }
|
|
619
|
+
.view-list a:hover { background: var(--lane); }
|
|
620
|
+
.view-list a span { display: block; margin-top: 2px; font-size: 12px; color: var(--muted); }
|
|
621
|
+
.cmp-col rect { fill: var(--lane); stroke: var(--border); stroke-width: 1; }
|
|
622
|
+
.cmp-col.cmp-both rect { stroke: var(--border-strong); stroke-width: 1.5; }
|
|
623
|
+
.cmp-head { font-size: 12.5px; font-weight: 700; fill: var(--text); }
|
|
624
|
+
.cmp-n, .cmp-empty { font-size: 12px; font-weight: 400; fill: var(--muted); }
|
|
625
|
+
.seq-sticky { position: absolute; left: 0; background: var(--bg); }
|
|
626
|
+
.seq-sticky.stuck { box-shadow: 0 1px 0 var(--border-strong); }
|
|
627
|
+
.viewport.glide .seq-sticky, .viewport.glide .view-level .node {
|
|
628
|
+
transition: transform 0.28s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.15s, box-shadow 0.15s, border-color 0.15s;
|
|
629
|
+
}
|
|
630
|
+
.view-strip { position: absolute; }
|
|
631
|
+
.view-strip h3 { margin: 0 0 8px; font-size: 13px; font-weight: 700; color: var(--text); }
|
|
632
|
+
.view-strip h3 .n { margin-left: 4px; color: var(--muted); font-weight: 600; }
|
|
633
|
+
.view-strip .vs-row { position: relative; height: 92px; }
|
|
634
|
+
.view-card {
|
|
635
|
+
position: absolute; top: 0; box-sizing: border-box; height: 92px; padding: 10px 12px;
|
|
636
|
+
display: flex; flex-direction: column; gap: 2px; overflow: hidden;
|
|
637
|
+
background: var(--surface); border: 1px solid var(--border-strong); border-radius: 10px;
|
|
638
|
+
color: var(--text); text-decoration: none; font-size: 13px;
|
|
639
|
+
}
|
|
640
|
+
.view-card:hover, .view-card:focus-visible { border-color: var(--accent); }
|
|
641
|
+
.view-card .vc-shape { font-size: 11px; font-weight: 700; color: var(--accent); }
|
|
642
|
+
.view-card .vc-q { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
643
|
+
.view-card .vc-n { margin-top: auto; font-size: 11.5px; color: var(--muted); }`;
|
|
644
|
+
/** 지식 문서 팩을 쓰는 그림에만 붙이는 스타일. 카드 배지와 서랍의 근거 구성 막대 */
|
|
645
|
+
export const DOC_CSS = `.doc-badge {
|
|
646
|
+
flex: none; margin-left: 6px; padding: 0 5px; border-radius: 8px; font-size: 10px; font-weight: 700; line-height: 16px;
|
|
647
|
+
color: var(--bg); background: var(--warn);
|
|
648
|
+
}
|
|
649
|
+
.doc-badge.broken { background: var(--text); }
|
|
650
|
+
.doc-badge.cover { color: var(--accent); background: var(--accent-soft); }
|
|
651
|
+
.doc-badge.none { color: var(--muted); background: var(--lane); }
|
|
652
|
+
.doc-badge.stale { background: var(--warn); }
|
|
653
|
+
.badge.doc-gap, .badge.doc-unverified { color: var(--warn); background: var(--warn-soft); }
|
|
654
|
+
.doc-mix { display: flex; height: 10px; margin: 4px 0 8px; border-radius: 5px; overflow: hidden; background: var(--lane); }
|
|
655
|
+
.doc-mix span { display: block; height: 100%; }
|
|
656
|
+
.doc-mix .mix-0 { background: var(--accent); }
|
|
657
|
+
.doc-mix .mix-1 { background: var(--ok); }
|
|
658
|
+
.doc-mix .mix-2 { background: var(--warn); }
|
|
659
|
+
.doc-mix .mix-3 { background: var(--live); }
|
|
660
|
+
.doc-mix .mix-4 { background: var(--muted); }
|
|
661
|
+
.doc-mix .mix-5 { background: var(--border-strong); }
|
|
662
|
+
.doc-thumb { display: block; max-width: 100%; margin: 8px 0; border: 1px solid var(--border); border-radius: 6px; }
|
|
663
|
+
.doc-routes .loc { font-size: 12px; color: var(--muted); }`;
|
|
664
|
+
/** 테마 토큰과 레이아웃 CSS. 시스템 설정을 기본으로 따르고 html의 data-theme가 있으면 그걸 따른다 */
|
|
665
|
+
export function renderCss(vocab = LEGACY_VOCABULARY) {
|
|
666
|
+
return [
|
|
667
|
+
`:root {${LIGHT_TOKENS} --font: "Pretendard", -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Noto Sans KR", "Segoe UI", sans-serif;\n --mono: ui-monospace, SFMono-Regular, Menlo, monospace;\n}`,
|
|
668
|
+
`@media (prefers-color-scheme: dark) {\n:root:not([data-theme="light"]) {${DARK_TOKENS}}\n${scoped(vocab, ':root:not([data-theme="light"])', 'dark')}\n}`,
|
|
669
|
+
`:root[data-theme="dark"] {${DARK_TOKENS}}`,
|
|
670
|
+
kindRules(vocab, 'light'),
|
|
671
|
+
brandRules('light'),
|
|
672
|
+
productRules(),
|
|
673
|
+
scoped(vocab, ':root[data-theme="dark"]', 'dark'),
|
|
674
|
+
LAYOUT_CSS,
|
|
675
|
+
].join('\n');
|
|
676
|
+
}
|
|
677
|
+
function scoped(vocab, prefix, theme) {
|
|
678
|
+
return (kindRules(vocab, theme).replace(/\.k-/g, `${prefix} .k-`) +
|
|
679
|
+
brandRules(theme).replace(/\.b-/g, `${prefix} .b-`));
|
|
680
|
+
}
|
|
681
|
+
//# sourceMappingURL=html-theme.js.map
|