fix(portal): fix card layout ejection bug & sync top-right status dot with live service state

This commit is contained in:
2026-10-08 21:56:42 +11:00
parent 24227c527a
commit a639824fd0
2 changed files with 62 additions and 16 deletions

View File

@@ -196,6 +196,7 @@ button.button, input[type="submit"].button { font-family: inherit; }
@media (max-width: 600px) { .tool-grid { grid-template-columns: 1fr; } }
.tool-card {
position: relative;
display: flex;
flex-direction: column;
gap: var(--space-sm);
@@ -212,6 +213,20 @@ button.button, input[type="submit"].button { font-family: inherit; }
transform: translateY(-1px);
text-decoration: none;
}
.tool-card-link {
position: absolute;
inset: 0;
z-index: 1;
border-radius: inherit;
}
.tool-card-top,
.tool-card .tool-name,
.tool-card .tool-desc,
.tool-card-bottom {
position: relative;
z-index: 1;
pointer-events: none;
}
.tool-card-top { display: flex; align-items: flex-start; justify-content: space-between; }
.tool-icon {
width: 40px; height: 40px;
@@ -251,6 +266,8 @@ button.button, input[type="submit"].button { font-family: inherit; }
.status-online { background: var(--sticker-green); }
.status-starting { background: var(--sticker-orange); }
.status-offline { background: var(--ink-faint); }
.status-failed { background: #d33a2b; }
[data-theme="dark"] .status-failed { background: #ff6b5e; }
/* loading pulse for polling */
.tool-grid.htmx-request .tool-card { opacity: .6; transition: opacity .2s; }
@@ -388,22 +405,37 @@ button.button, input[type="submit"].button { font-family: inherit; }
/* ---------- ON/OFF service strip (ON_OFF.md) ---------- */
.svc-strip {
position: relative;
z-index: 2;
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 4px;
padding: 8px 12px;
background: var(--surface-2, #f6f5f4);
border: 1px solid var(--hairline);
border-radius: var(--rounded-md);
pointer-events: auto;
}
[data-theme="dark"] .svc-strip {
background: rgba(255, 255, 255, 0.04);
}
.svc-strip-left,
.svc-strip-right {
display: flex;
align-items: center;
gap: 8px;
margin-top: 2px;
padding-top: 10px;
border-top: 1px dashed var(--hairline);
}
.svc-state { display: inline-flex; align-items: center; gap: 6px; font: var(--type-caption); color: var(--ink-muted); }
.svc-dot { width: 8px; height: 8px; border-radius: var(--rounded-full); }
.svc-state { display: inline-flex; align-items: center; gap: 6px; font: var(--type-caption); color: var(--ink-muted); font-weight: 500; }
.svc-dot { width: 8px; height: 8px; border-radius: var(--rounded-full); flex-shrink: 0; }
.svc-dot.svc-on { background: var(--accent-green, #1aae39); }
.svc-dot.svc-off { background: var(--ink-faint, #a39e98); }
.svc-dot.svc-trans { background: var(--accent-orange, #dd5b00); animation: pulse 1.2s ease-in-out infinite; }
.svc-dot.svc-fail { background: #d33a2b; }
.svc-dot.svc-part { background: var(--accent-orange, #dd5b00); } /* partial: some group members running */
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
.svc-ram { margin-left: auto; font: var(--type-caption); color: var(--ink-faint); white-space: nowrap; }
.button-sm { padding: 4px 10px; font-size: 12px; }
.svc-ram { font: var(--type-caption); color: var(--ink-faint); white-space: nowrap; font-size: 11px; }
.button-sm { padding: 4px 10px; font-size: 12px; height: 26px; line-height: 1; }
[data-theme="dark"] .svc-dot.svc-fail { background: #ff6b5e; }
.svc-logs { font: var(--type-caption); color: var(--sticker-orange, #dd5b00); text-decoration: underline; }