165 lines
5.6 KiB
HTML
165 lines
5.6 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="robots" content="noindex">
|
||
<meta name="color-scheme" content="dark">
|
||
<meta name="theme-color" content="#0c100f">
|
||
<title>Maintenance · xcce.cc</title>
|
||
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%230c100f'/%3E%3Cpath d='M9 11l5 5-5 5' fill='none' stroke='%236ee7b7' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Crect x='16' y='19.5' width='8' height='2.5' rx='1' fill='%236ee7b7'/%3E%3C/svg%3E">
|
||
<style>
|
||
:root {
|
||
color-scheme: dark;
|
||
--bg: #0c100f;
|
||
--fg: #e8eeec;
|
||
--muted: #74807c;
|
||
--faint: #2c3533;
|
||
--accent: #6ee7b7;
|
||
}
|
||
|
||
* { margin: 0; box-sizing: border-box; }
|
||
html, body { height: 100%; }
|
||
|
||
body {
|
||
background: var(--bg);
|
||
color: var(--muted);
|
||
font: 400 clamp(13px, 3.6vw, 15px)/1.75 ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
||
-webkit-font-smoothing: antialiased;
|
||
display: grid;
|
||
place-items: center;
|
||
padding: 24px 16px;
|
||
}
|
||
|
||
::selection { background: var(--accent); color: var(--bg); }
|
||
|
||
/* terminal window: a plain frame with the site name set into its top border */
|
||
.wrap {
|
||
position: relative;
|
||
width: min(640px, 100%);
|
||
border: 1px solid #2f3a37;
|
||
border-radius: 12px;
|
||
padding: clamp(40px, 8vw, 56px) clamp(20px, 5vw, 40px) clamp(24px, 5vw, 36px);
|
||
}
|
||
|
||
.host {
|
||
position: absolute;
|
||
top: 0;
|
||
left: clamp(14px, 4vw, 28px);
|
||
transform: translateY(-52%);
|
||
padding: 0 12px;
|
||
background: var(--bg);
|
||
color: var(--fg);
|
||
font-size: clamp(24px, 6.5vw, 36px);
|
||
font-weight: 700;
|
||
line-height: 1;
|
||
letter-spacing: -.03em;
|
||
text-decoration: none;
|
||
transition: color .2s ease;
|
||
}
|
||
.host b { color: var(--accent); font-weight: inherit; }
|
||
.host:hover, .host:focus-visible { color: var(--accent); outline: none; }
|
||
|
||
.cmd { color: var(--fg); }
|
||
.cmd + .out { margin-top: 2px; }
|
||
.out + .cmd { margin-top: 24px; }
|
||
.ps { color: var(--accent); margin-right: .6em; }
|
||
|
||
.hi { color: var(--fg); }
|
||
.ok { color: var(--accent); }
|
||
|
||
.bar { color: var(--faint); letter-spacing: -.02em; }
|
||
.bar i { color: var(--accent); font-style: normal; }
|
||
|
||
.cursor, .typing .t::after {
|
||
content: "";
|
||
display: inline-block;
|
||
width: .6em;
|
||
height: 1.2em;
|
||
vertical-align: -.25em;
|
||
background: var(--accent);
|
||
}
|
||
.cursor { animation: blink 1.1s steps(1) infinite; }
|
||
@keyframes blink { 50% { opacity: 0; } }
|
||
|
||
/* lines keep their space while hidden, so nothing shifts as they appear */
|
||
.off { visibility: hidden; }
|
||
.in { animation: fade .35s ease-out both; }
|
||
@keyframes fade { from { opacity: 0; } }
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.cursor { animation: none; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<a class="host" href="https://xcce.cc"><span>xcce<b>.</b>cc</span></a>
|
||
<main id="term">
|
||
<p class="cmd"><span class="ps">~ ❯</span><span class="t">status</span></p>
|
||
<div class="out">
|
||
<p><span class="ok">●</span> <span class="hi">Under maintenance.</span></p>
|
||
<p>We’re upgrading a few things. Back soon.</p>
|
||
<p>scheduled maintenance · in progress</p>
|
||
</div>
|
||
<p class="cmd"><span class="ps">~ ❯</span><span class="t">retry --auto</span></p>
|
||
<div class="out">
|
||
<p><span class="bar" id="bar" aria-hidden="true"></span> <span id="sec">60s</span></p>
|
||
</div>
|
||
<p class="cmd"><span class="ps">~ ❯</span><span class="cursor"></span></p>
|
||
</main>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
var TOTAL = 60, W = 24, start = Date.now();
|
||
var bar = document.getElementById('bar'), sec = document.getElementById('sec');
|
||
|
||
// retry countdown, drawn as a text progress bar
|
||
(function tick() {
|
||
var t = Math.min((Date.now() - start) / 1000, TOTAL);
|
||
var n = Math.round(t / TOTAL * W);
|
||
bar.innerHTML = '<i>' + '█'.repeat(n) + '</i>' + '░'.repeat(W - n);
|
||
if (t >= TOTAL) { sec.textContent = 'reconnecting…'; location.reload(); return; }
|
||
sec.textContent = Math.ceil(TOTAL - t) + 's';
|
||
setTimeout(tick, 250);
|
||
})();
|
||
|
||
// play the session: type each command, pause as if it runs, then print output line by line
|
||
if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
||
var steps = [];
|
||
[].forEach.call(document.getElementById('term').children, function (c) {
|
||
if (c.classList.contains('out')) [].push.apply(steps, c.children);
|
||
else steps.push(c);
|
||
});
|
||
steps.forEach(function (n) {
|
||
var t = n.querySelector('.t');
|
||
if (t) { t.dataset.s = t.textContent; t.textContent = ''; }
|
||
n.classList.add('off');
|
||
});
|
||
var i = 0;
|
||
function next() {
|
||
if (i >= steps.length) return;
|
||
var n = steps[i], prev = steps[i - 1];
|
||
i++;
|
||
var wait = n.classList.contains('cmd')
|
||
? (prev ? 900 : 300) // gap before the next prompt
|
||
: (prev && prev.classList.contains('cmd') ? 750 : 280); // command "runs", then lines stream
|
||
setTimeout(function () {
|
||
n.classList.remove('off');
|
||
n.classList.add('in');
|
||
var t = n.querySelector('.t');
|
||
if (!t) return next();
|
||
var s = t.dataset.s, k = 0;
|
||
n.classList.add('typing');
|
||
setTimeout(function type() {
|
||
if (k < s.length) { t.textContent += s[k++]; setTimeout(type, 60 + Math.random() * 80); }
|
||
else { n.classList.remove('typing'); next(); }
|
||
}, 550);
|
||
}, wait);
|
||
}
|
||
next();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html> |