feat: add internal alpha frontend shell
This commit is contained in:
1 parent
eeb3c7634e
commit
b741fd799b
10 files changed
+1982
-15
No files matched your search
@@ -0,0 +1,755 @@
|
||||
:root {
|
||||
color-scheme: light;
|
||||
font-family: Inter, "Segoe UI", Arial, sans-serif;
|
||||
font-synthesis: none;
|
||||
--ink: #17202a;
|
||||
--muted: #5a6773;
|
||||
--line: #ccd4dc;
|
||||
--surface: #ffffff;
|
||||
--canvas: #f3f5f7;
|
||||
--nav: #0f172a;
|
||||
--accent: #f97316;
|
||||
--focus: #1677b8;
|
||||
--good: #177245;
|
||||
--warn: #9a5b00;
|
||||
--danger: #b42318;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
min-width: 320px;
|
||||
background: var(--canvas);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
color: var(--ink);
|
||||
background: var(--canvas);
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.skip-link {
|
||||
position: fixed;
|
||||
left: 12px;
|
||||
top: -60px;
|
||||
z-index: 100;
|
||||
padding: 10px 14px;
|
||||
background: var(--surface);
|
||||
border: 2px solid var(--focus);
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
top: 12px;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 3px solid var(--focus);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
.app-shell {
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
grid-template-columns: 224px minmax(0, 1fr);
|
||||
grid-template-rows: 68px minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.topbar {
|
||||
grid-column: 1 / -1;
|
||||
display: grid;
|
||||
grid-template-columns: 224px minmax(240px, 620px) 1fr;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
min-height: 68px;
|
||||
padding: 10px 18px;
|
||||
color: #ffffff;
|
||||
background: var(--nav);
|
||||
border-bottom: 3px solid var(--accent);
|
||||
}
|
||||
|
||||
.brand-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.brand-tagline {
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
color: #d3dae2;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.global-search {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.global-search label {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.global-search input {
|
||||
width: 100%;
|
||||
min-height: 42px;
|
||||
padding: 9px 14px;
|
||||
border: 1px solid #647385;
|
||||
border-radius: 5px;
|
||||
color: var(--ink);
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.session-tools {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.session-copy {
|
||||
min-width: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.session-user,
|
||||
.session-role {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.session-user {
|
||||
font-size: 13px;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.session-role {
|
||||
color: #d3dae2;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.quiet-button,
|
||||
.menu-button {
|
||||
min-height: 40px;
|
||||
border: 1px solid #8390a0;
|
||||
border-radius: 5px;
|
||||
padding: 8px 11px;
|
||||
color: #ffffff;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.primary-nav {
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
padding: 20px 12px;
|
||||
color: #eef2f6;
|
||||
background: #17212d;
|
||||
}
|
||||
|
||||
.primary-nav ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.primary-nav a {
|
||||
display: block;
|
||||
min-height: 42px;
|
||||
padding: 11px 12px;
|
||||
border-left: 3px solid transparent;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.primary-nav a:hover {
|
||||
background: #263343;
|
||||
}
|
||||
|
||||
.primary-nav a[aria-current="page"] {
|
||||
border-color: var(--accent);
|
||||
background: #2c3948;
|
||||
}
|
||||
|
||||
.nav-note {
|
||||
margin: 22px 12px 0;
|
||||
color: #aeb9c5;
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
min-width: 0;
|
||||
padding: 26px clamp(16px, 3vw, 42px) 48px;
|
||||
}
|
||||
|
||||
.page-head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 5px;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 750;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 32px;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.page-summary {
|
||||
max-width: 760px;
|
||||
margin: 8px 0 0;
|
||||
color: var(--muted);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.freshness {
|
||||
margin: 4px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, minmax(130px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.metric,
|
||||
.panel,
|
||||
.map-inspector {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.metric {
|
||||
min-height: 122px;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
display: block;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
display: block;
|
||||
margin: 14px 0 6px;
|
||||
font-size: 25px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.metric-state {
|
||||
display: block;
|
||||
color: var(--warn);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1.7fr) minmax(260px, .7fr);
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
padding: 18px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.panel h2 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.panel-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.panel-copy {
|
||||
margin: 7px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.state-message {
|
||||
padding: 26px 16px;
|
||||
border: 1px dashed #aeb8c2;
|
||||
text-align: center;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.state-message strong {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.state-message[data-kind="error"] {
|
||||
border-color: #d4a09b;
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.state-message[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 11px 12px;
|
||||
border-bottom: 1px solid #e3e8ed;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
th {
|
||||
color: #40505f;
|
||||
background: #f7f8fa;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
tbody tr:last-child td {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.object-link {
|
||||
color: #075b91;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.secondary {
|
||||
display: block;
|
||||
margin-top: 3px;
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.status-text::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-right: 7px;
|
||||
border-radius: 50%;
|
||||
background: #758493;
|
||||
}
|
||||
|
||||
.status-text[data-status="active"]::before,
|
||||
.status-text[data-status="online"]::before {
|
||||
background: var(--good);
|
||||
}
|
||||
|
||||
.status-text[data-status="in_repair"]::before,
|
||||
.status-text[data-status="repair"]::before {
|
||||
background: var(--warn);
|
||||
}
|
||||
|
||||
.status-text[data-status="critical"]::before {
|
||||
background: var(--danger);
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
display: flex;
|
||||
align-items: end;
|
||||
gap: 10px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.field {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
min-width: min(100%, 320px);
|
||||
}
|
||||
|
||||
.field label {
|
||||
color: #40505f;
|
||||
font-size: 12px;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.field input,
|
||||
.field select {
|
||||
min-height: 42px;
|
||||
border: 1px solid #9da9b5;
|
||||
border-radius: 5px;
|
||||
padding: 8px 10px;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.command-button {
|
||||
min-height: 42px;
|
||||
border: 1px solid #1b5f89;
|
||||
border-radius: 5px;
|
||||
padding: 8px 15px;
|
||||
color: #ffffff;
|
||||
background: #176b9a;
|
||||
font-weight: 750;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.command-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: .58;
|
||||
}
|
||||
|
||||
.map-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 210px minmax(340px, 1fr) 280px;
|
||||
min-height: 520px;
|
||||
border: 1px solid var(--line);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.map-controls,
|
||||
.map-inspector {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.map-controls {
|
||||
border-right: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.map-controls h2,
|
||||
.map-inspector h2 {
|
||||
margin: 0 0 14px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.hierarchy {
|
||||
margin: 0 0 20px;
|
||||
padding-left: 18px;
|
||||
color: #40505f;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.control-stack {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.map-viewport {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-height: 420px;
|
||||
padding: 28px;
|
||||
background: #e8edf1;
|
||||
box-shadow: inset 0 0 0 10px #dde4ea;
|
||||
}
|
||||
|
||||
.map-empty {
|
||||
max-width: 460px;
|
||||
padding: 22px;
|
||||
border: 1px solid #9da9b5;
|
||||
background: #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.map-empty strong {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.map-inspector {
|
||||
border: 0;
|
||||
border-left: 1px solid var(--line);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.definition-list {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 10px 14px;
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.definition-list dt {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.definition-list dd {
|
||||
margin: 0;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.notice {
|
||||
padding: 12px 14px;
|
||||
border-left: 4px solid var(--warn);
|
||||
background: #fff8e8;
|
||||
color: #694100;
|
||||
font-size: 13px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
@media (max-width: 1120px) {
|
||||
.metrics {
|
||||
grid-template-columns: repeat(3, minmax(140px, 1fr));
|
||||
}
|
||||
|
||||
.map-layout {
|
||||
grid-template-columns: 190px minmax(320px, 1fr);
|
||||
}
|
||||
|
||||
.map-inspector {
|
||||
grid-column: 1 / -1;
|
||||
border-top: 1px solid var(--line);
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 820px) {
|
||||
.app-shell {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto auto minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.topbar {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 30;
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.brand-tagline,
|
||||
.session-copy {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu-button {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.global-search {
|
||||
grid-column: 1 / -1;
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
.primary-nav {
|
||||
display: none;
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.primary-nav[data-open="true"] {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.primary-nav ul {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.primary-nav a {
|
||||
min-height: 46px;
|
||||
padding: 12px 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nav-note {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
grid-column: 1;
|
||||
grid-row: 3;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.metrics {
|
||||
grid-template-columns: repeat(2, minmax(130px, 1fr));
|
||||
}
|
||||
|
||||
.content-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.map-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.map-controls,
|
||||
.map-inspector {
|
||||
border: 0;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
.topbar {
|
||||
padding: 9px 10px;
|
||||
}
|
||||
|
||||
.brand-name {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.quiet-button {
|
||||
padding: 7px 9px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 18px 12px 36px;
|
||||
}
|
||||
|
||||
.page-head {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.freshness {
|
||||
margin-top: 10px;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.metrics {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.metric {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.primary-nav ul {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.field {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.command-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.table-wrap {
|
||||
border: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
table,
|
||||
thead,
|
||||
tbody,
|
||||
tr,
|
||||
th,
|
||||
td {
|
||||
display: block;
|
||||
}
|
||||
|
||||
thead {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
tbody {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
tr {
|
||||
border: 1px solid var(--line);
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
td {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(90px, .45fr) 1fr;
|
||||
gap: 10px;
|
||||
border-bottom: 1px solid #e3e8ed;
|
||||
}
|
||||
|
||||
td::before {
|
||||
content: attr(data-label);
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
font-weight: 750;
|
||||
}
|
||||
|
||||
.map-viewport {
|
||||
min-height: 340px;
|
||||
padding: 14px;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user