Server updates from the web panel with progress screen
- Updater checks git.mbm.wtf every 6 h (and on demand) for a newer <Version> on main, shows the new commits and the required mod version - Install: download the source, build it with dotnet publish into data/app/current, warn players and restart (exit code 75 for Docker/systemd, self-relaunch on Windows). At startup a newer installed update is loaded in its own AssemblyLoadContext; after 3 failed starts the built-in version runs - Panel: Update page, sidebar badge, full-screen progress overlay (download, build, install, restart) that survives the restart and reloads the panel - Panel sessions survive restarts (hashed tokens in data/panel_sessions.json) - Docker image is based on the .NET SDK so it can build updates - Version 2.9.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -231,3 +231,64 @@ input[type=file]::file-selector-button { background: var(--panel); color: var(--
|
||||
th, td { padding: 10px 12px; }
|
||||
.console { height: 55vh; }
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- Updates */
|
||||
.nav-badge { margin-left: auto; font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; padding: 2px 7px;
|
||||
border-radius: 999px; background: var(--accent); color: #fff; box-shadow: 0 0 0 3px rgba(242, 107, 29, .18); }
|
||||
.card.accent { border-color: rgba(242, 107, 29, .45); background: linear-gradient(180deg, rgba(242, 107, 29, .10), transparent 70%), var(--panel); }
|
||||
.notice.ok { background: rgba(61, 214, 140, .07); border-color: rgba(61, 214, 140, .3); }
|
||||
.notice.update-notice { background: rgba(242, 107, 29, .08); border-color: rgba(242, 107, 29, .35); }
|
||||
.warn-text { color: var(--pending); margin-top: 4px; }
|
||||
.update-body > * + * { margin-top: 14px; }
|
||||
.small-print { font-size: 12.5px; margin-bottom: 0; }
|
||||
.changes { list-style: none; margin: 0; padding: 0; display: grid; }
|
||||
.changes li { display: grid; grid-template-columns: auto 1fr auto; gap: 12px; align-items: baseline; padding: 8px 4px; border-bottom: 1px solid var(--border); }
|
||||
.changes li:last-child { border-bottom: 0; }
|
||||
.change-sha { color: var(--accent); font-size: 12px; font-family: var(--mono); }
|
||||
.change-title { overflow-wrap: anywhere; }
|
||||
@media (max-width: 560px) { .changes li { grid-template-columns: auto 1fr; } .changes li small { grid-column: 2; } }
|
||||
|
||||
.update-overlay { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center; padding: 16px;
|
||||
background: radial-gradient(1200px 600px at 50% 0%, rgba(242, 107, 29, .14), transparent 60%), rgba(10, 10, 13, .92);
|
||||
backdrop-filter: blur(6px); animation: us-in .2s ease-out; }
|
||||
@keyframes us-in { from { opacity: 0; } to { opacity: 1; } }
|
||||
.update-card { width: min(640px, 100%); max-height: calc(100vh - 32px); overflow: auto; background: var(--panel); border: 1px solid var(--border);
|
||||
border-radius: 16px; padding: 24px; box-shadow: 0 30px 80px rgba(0, 0, 0, .5); display: grid; gap: 16px; }
|
||||
.update-card.success { border-color: rgba(61, 214, 140, .45); }
|
||||
.us-head { display: flex; align-items: center; gap: 14px; }
|
||||
.us-head img { width: 44px; height: 44px; border-radius: 10px; }
|
||||
.us-versions { color: var(--muted); margin-top: 2px; }
|
||||
.us-versions .mono { color: var(--text); font-family: var(--mono); }
|
||||
.us-steps { list-style: none; margin: 4px 0 0; padding: 0; display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
|
||||
.us-steps li { display: grid; justify-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); text-align: center; position: relative; }
|
||||
.us-steps li::before { content: ""; position: absolute; top: 11px; left: calc(-50% + 16px); right: calc(50% + 16px); height: 2px; background: var(--border); }
|
||||
.us-steps li:first-child::before { display: none; }
|
||||
.us-dot { width: 24px; height: 24px; border-radius: 50%; border: 2px solid var(--border); background: var(--panel-2); display: grid; place-items: center;
|
||||
font-size: 12px; font-weight: 800; color: #fff; position: relative; z-index: 1; }
|
||||
.us-steps li.done { color: var(--text); }
|
||||
.us-steps li.done .us-dot { background: var(--online); border-color: var(--online); }
|
||||
.us-steps li.done .us-dot::after { content: "✓"; }
|
||||
.us-steps li.done::before, .us-steps li.active::before, .us-steps li.failed::before { background: var(--online); }
|
||||
.us-steps li.active { color: #fff; font-weight: 700; }
|
||||
.us-steps li.active .us-dot { border-color: var(--accent); box-shadow: 0 0 0 4px rgba(242, 107, 29, .2); animation: us-pulse 1.4s ease-in-out infinite; }
|
||||
.us-steps li.active .us-dot::after { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
|
||||
.us-steps li.failed { color: #ff8a8d; font-weight: 700; }
|
||||
.us-steps li.failed .us-dot { background: var(--danger); border-color: var(--danger); }
|
||||
.us-steps li.failed .us-dot::after { content: "!"; }
|
||||
@keyframes us-pulse { 50% { box-shadow: 0 0 0 7px rgba(242, 107, 29, .08); } }
|
||||
.us-bar { height: 10px; border-radius: 999px; background: var(--panel-2); overflow: hidden; border: 1px solid var(--border); }
|
||||
.us-fill { height: 100%; width: 0; border-radius: 999px; transition: width .6s ease;
|
||||
background: linear-gradient(90deg, #e5561a, #ffa24d, #e5561a); background-size: 200% 100%; animation: us-flow 2s linear infinite; }
|
||||
.update-card.success .us-fill { background: var(--online); animation: none; }
|
||||
@keyframes us-flow { to { background-position: -200% 0; } }
|
||||
.us-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||||
.us-msg { min-width: 0; overflow-wrap: anywhere; }
|
||||
.us-pct, .us-clock { font-variant-numeric: tabular-nums; }
|
||||
.us-log { height: 240px; min-height: 0; }
|
||||
.update-card .buttons { display: flex; justify-content: flex-end; gap: 10px; }
|
||||
.update-card .buttons:empty { display: none; }
|
||||
@media (max-width: 560px) {
|
||||
.update-card { padding: 18px; }
|
||||
.us-steps li { font-size: 11px; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) { .us-fill, .us-steps li.active .us-dot, .update-overlay { animation: none; } }
|
||||
|
||||
Reference in New Issue
Block a user