feat(topology): add square light canvas

Co-Authored-By: OpenAI Codex <codex@openai.com>
This commit is contained in:
2026-07-15 12:21:34 +08:00
co-authored by OpenAI Codex
parent 8d057dbfa3
commit c99c910aa3
8 changed files with 101 additions and 68 deletions
+29 -28
View File
@@ -3,20 +3,21 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="data:,">
<title>广寒基地拓扑结构</title>
<style>
:root {
color-scheme: dark;
--bg: #070d18; --panel: #0d1728; --panel-2: #101c30;
--text: #eaf2ff; --muted: #91a3bd; --border: #263750;
--structural: #8fa1b8; --pressurized: #51e89c; --utility: #b178e6;
--core: #ffad42; --habitat: #52baff; --power: #d5b642;
--vehicle: #c28cdf; --radiator: #f0d869;
color-scheme: light;
--bg: #f4f7fb; --panel: #ffffff; --panel-2: #eef3f8;
--text: #152033; --muted: #5e6f85; --border: #b8c5d4;
--structural: #66788e; --pressurized: #168a55; --utility: #7a4fb3;
--core: #c76b00; --habitat: #1677b8; --power: #9b7900;
--vehicle: #8755a4; --radiator: #9b7900;
}
* { box-sizing: border-box; }
body {
margin: 0; min-height: 100vh; padding: 30px;
background: radial-gradient(circle at 50% 0%, rgba(51,88,140,0.18), transparent 36rem), var(--bg);
background: radial-gradient(circle at 50% 0%, rgba(89,132,181,0.14), transparent 36rem), var(--bg);
color: var(--text);
font-family: "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
}
@@ -27,42 +28,42 @@
.toolbar { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 12px; margin: 16px 0; }
.toolbar label { color: var(--muted); font-size: 0.88rem; }
.toolbar select, .toolbar input { padding: 6px 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--panel); color: var(--text); font-size: 0.88rem; }
.toolbar button { padding: 6px 16px; border: 1px solid var(--pressurized); border-radius: 6px; background: #0a2e16; color: var(--pressurized); cursor: pointer; font-size: 0.88rem; font-weight: 600; }
.toolbar button:hover { background: #0f3d1f; }
.toolbar button { padding: 6px 16px; border: 1px solid var(--pressurized); border-radius: 6px; background: #e7f7ee; color: #0e6840; cursor: pointer; font-size: 0.88rem; font-weight: 600; }
.toolbar button:hover { background: #d6f0e1; }
.loading-msg { text-align: center; color: var(--muted); padding: 40px; }
.error-msg { text-align: center; color: #f66; padding: 40px; }
.legend { display: flex; flex-wrap: wrap; justify-content: center; gap: 13px 24px; margin: 20px 0; padding: 13px 18px; border: 1px solid var(--border); border-radius: 12px; background: rgba(13,23,40,0.84); }
.legend-item { display: inline-flex; align-items: center; gap: 9px; color: #c8d5e7; font-size: 0.86rem; }
.error-msg { text-align: center; color: #b42318; padding: 40px; }
.legend { display: flex; flex-wrap: wrap; justify-content: center; gap: 13px 24px; margin: 20px 0; padding: 13px 18px; border: 1px solid var(--border); border-radius: 12px; background: rgba(255,255,255,0.88); }
.legend-item { display: inline-flex; align-items: center; gap: 9px; color: var(--text); font-size: 0.86rem; }
.legend-line { display: inline-block; width: 46px; border-top: 4px solid; }
.legend-chip { width: 19px; height: 13px; border: 2px solid var(--radiator); background: #665511; border-radius: 3px; }
.map-shell { overflow: auto; border: 1px solid var(--border); border-radius: 18px; background: #08101e; box-shadow: 0 24px 70px rgba(0,0,0,0.34); }
.topology-map { display: block; width: 100%; min-width: 1080px; height: auto; background: linear-gradient(rgba(18,36,60,0.21) 1px, transparent 1px), linear-gradient(90deg, rgba(18,36,60,0.21) 1px, transparent 1px), #08101e; background-size: 48px 48px; }
.legend-chip { width: 19px; height: 13px; border: 2px solid var(--radiator); background: #fff0a8; border-radius: 3px; }
.map-shell { overflow: auto; border: 1px solid var(--border); border-radius: 18px; background: #f8fbff; box-shadow: 0 18px 45px rgba(50,72,96,0.16); }
.topology-map { display: block; width: 100%; min-width: 1080px; height: auto; background: linear-gradient(rgba(78,105,135,0.12) 1px, transparent 1px), linear-gradient(90deg, rgba(78,105,135,0.12) 1px, transparent 1px), #f8fbff; background-size: 48px 48px; }
.connection { fill: none; vector-effect: non-scaling-stroke; stroke-linecap: square; }
.topology-node { cursor: pointer; outline: none; }
.topology-node rect { vector-effect: non-scaling-stroke; transition: filter 150ms ease, stroke-width 150ms ease; }
.topology-node:hover rect, .topology-node:focus-visible rect { filter: brightness(1.25); stroke-width: 5; }
.topology-node:hover rect, .topology-node:focus-visible rect { filter: brightness(0.97) drop-shadow(0 6px 8px rgba(45,66,88,0.18)); stroke-width: 5; }
.node-title { fill: var(--text); font-size: 25px; font-weight: 700; text-anchor: middle; }
.node-meta { fill: #a6b5c9; font-size: 17px; text-anchor: middle; }
.node-hint { fill: #71849e; font-size: 14px; text-anchor: middle; }
.node-meta { fill: #435a72; font-size: 17px; text-anchor: middle; }
.node-hint { fill: #6f8296; font-size: 14px; text-anchor: middle; }
.radiator { pointer-events: none; }
.radiator rect { vector-effect: non-scaling-stroke; }
.radiator line { stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.radiator-label { font-size: 15px; font-weight: 650; text-anchor: middle; }
.click-note { margin: 13px 0 0; color: var(--muted); font-size: 0.84rem; text-align: center; }
body.modal-open { overflow: hidden; }
.modal-backdrop { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 24px; background: rgba(2,7,14,0.82); backdrop-filter: blur(8px); }
.modal-backdrop { position: fixed; inset: 0; z-index: 20; display: none; align-items: center; justify-content: center; padding: 24px; background: rgba(21,32,51,0.38); backdrop-filter: blur(8px); }
.modal-backdrop[aria-hidden="false"] { display: flex; }
.detail-dialog { position: relative; width: min(760px, 100%); max-height: min(820px, calc(100vh - 48px)); overflow: auto; padding: 30px; border: 1px solid #405572; border-radius: 18px; outline: none; background: linear-gradient(145deg, #13233a, #0b1424 72%); box-shadow: 0 30px 100px rgba(0,0,0,0.64); }
.detail-dialog:focus-visible { box-shadow: 0 0 0 3px var(--pressurized), 0 30px 100px rgba(0,0,0,0.64); }
.modal-close { position: absolute; top: 14px; right: 14px; width: 40px; height: 40px; border: 1px solid #4e627e; border-radius: 50%; background: #182a43; color: var(--text); font: 500 1.65rem/1 system-ui, sans-serif; cursor: pointer; }
.modal-close:hover, .modal-close:focus-visible { border-color: var(--pressurized); outline: none; background: #203754; }
.detail-dialog { position: relative; width: min(760px, 100%); max-height: min(820px, calc(100vh - 48px)); overflow: auto; padding: 30px; border: 1px solid #a8b7c8; border-radius: 18px; outline: none; background: linear-gradient(145deg, #ffffff, #f2f6fa 72%); box-shadow: 0 30px 80px rgba(38,55,74,0.28); }
.detail-dialog:focus-visible { box-shadow: 0 0 0 3px var(--pressurized), 0 30px 80px rgba(38,55,74,0.28); }
.modal-close { position: absolute; top: 14px; right: 14px; width: 40px; height: 40px; border: 1px solid #9aabbd; border-radius: 50%; background: #edf2f7; color: var(--text); font: 500 1.65rem/1 system-ui, sans-serif; cursor: pointer; }
.modal-close:hover, .modal-close:focus-visible { border-color: var(--pressurized); outline: none; background: #e2eaf2; }
.detail-kicker { margin: 0 46px 6px 0; color: var(--pressurized); font-size: 0.77rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; }
#detail-title { margin: 0 50px 10px 0; font-size: 1.85rem; }
#detail-role { margin: 0 0 22px; color: #c4d2e4; line-height: 1.7; }
#detail-role { margin: 0 0 22px; color: #42566e; line-height: 1.7; }
.detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 0; }
.detail-grid > div { min-width: 0; padding: 14px; border: 1px solid #293c57; border-radius: 10px; background: rgba(8,18,33,0.7); }
.detail-grid dt { margin-bottom: 7px; color: #7f94b1; font-size: 0.75rem; }
.detail-grid dd { margin: 0; color: #e1ebf8; line-height: 1.55; overflow-wrap: anywhere; }
.detail-grid > div { min-width: 0; padding: 14px; border: 1px solid #c7d2de; border-radius: 10px; background: rgba(247,249,252,0.9); }
.detail-grid dt { margin-bottom: 7px; color: #61758c; font-size: 0.75rem; }
.detail-grid dd { margin: 0; color: #1e2d40; line-height: 1.55; overflow-wrap: anywhere; }
.detail-grid dd span { display: block; }
.detail-grid dd span + span { margin-top: 4px; }
@media (max-width: 760px) {
@@ -96,7 +97,7 @@
<div id="error-msg" class="error-msg" style="display:none;"></div>
<div class="map-shell" id="map-shell" style="display:none;">
<svg class="topology-map" viewBox="0 0 1500 1900" role="img" aria-labelledby="topology-title" id="topology-svg">
<svg class="topology-map" viewBox="0 0 1900 1900" role="img" aria-labelledby="topology-title" id="topology-svg">
<title id="topology-title">广寒基地拓扑</title>
<desc id="topology-desc">根据所选任务或时间展示广寒基地当时的工程拓扑。</desc>
<!-- FUTURE_EXPANSION_ANCHOR:north -->