feat: initial release

This commit is contained in:
2026-08-22 16:25:09 +05:00
commit 24bf56e8d1
9 changed files with 4642 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
---
import '../styles/global.css'
interface Props {
title: string
description: string
}
const { title, description } = Astro.props
---
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="description" content={description} />
<meta name="theme-color" content="#090a0a" />
<meta name="color-scheme" content="dark" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;1,400&family=IBM+Plex+Mono:wght@400;500;600&family=Inter&display=swap"
rel="stylesheet"
/>
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>
+187
View File
@@ -0,0 +1,187 @@
---
import Layout from "../layouts/Layout.astro";
const START_DATE = new Date("2026-07-09T20:00:00+05:00");
function getElapsedTime(): { days: number; hours: number; minutes: number; seconds: number } {
const totalSeconds = Math.max(0, Math.floor((Date.now() - START_DATE.getTime()) / 1000));
return {
days: Math.floor(totalSeconds / 86400),
hours: Math.floor((totalSeconds % 86400) / 3600),
minutes: Math.floor((totalSeconds % 3600) / 60),
seconds: totalSeconds % 60,
};
}
function pad(value: number): string {
return value.toString().padStart(2, "0");
}
const time = getElapsedTime();
const units = [
{ label: "Days", digits: pad(time.days), value: time.days, wide: true },
{ label: "Hours", digits: pad(time.hours), value: time.hours, wide: false },
{ label: "Minutes", digits: pad(time.minutes), value: time.minutes, wide: false },
{ label: "Seconds", digits: pad(time.seconds), value: time.seconds, wide: false },
];
const startLabel = START_DATE.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric",
timeZone: "Etc/GMT-5",
}).toUpperCase();
---
<Layout
title="Waiting for GitHub Support — Elapsed Time"
description="A live record of time elapsed since a GitHub support ticket was opened."
>
<main class="clock-page">
<div class="ambient-line ambient-line-left"></div>
<div class="ambient-line ambient-line-right"></div>
<header class="site-header">
<div class="brand-mark"><span class="brand-dot"></span> GITHUB TICKET ID: 4549142</div>
<div class="header-status"><span class="status-pulse"></span> STATUS: AWAITING RESPONSE</div>
</header>
<section class="hero-content" aria-labelledby="page-title">
<div class="eyebrow"><span></span> TIME IN LIMBO <span></span></div>
<h1 id="page-title">Waiting for GitHub<br /><em>Support</em></h1>
<p class="subtitle">Time elapsed since the ticket was opened without a response.</p>
<div class="clock-frame">
<div class="clock-frame-top"><span>ELAPSED TIME</span><span>SLA: NOT FOUND</span></div>
<div class="clock-display" role="timer" aria-live="polite">
{
units.map((unit, index) => (
<>
{index > 0 && (
<span class="unit-divider" aria-hidden="true">
:
</span>
)}
<div class:list={["clock-unit", { "clock-unit-wide": unit.wide }]}>
<div class="unit-digits" data-unit={unit.label} aria-label={`${unit.value} ${unit.label}`}>
{unit.digits.split("").map((digit) => (
<span class="flip-digit" data-displayed={digit} aria-hidden="true">
<span class="digit-face digit-top">{digit}</span>
<span class="digit-face digit-bottom">{digit}</span>
<span class="digit-flap digit-flap-top">{digit}</span>
<span class="digit-flap digit-flap-bottom">{digit}</span>
<span class="digit-seam" />
<span class="digit-notch digit-notch-left" />
<span class="digit-notch digit-notch-right" />
</span>
))}
</div>
<span class="unit-label">{unit.label}</span>
</div>
</>
))
}
</div>
<div class="clock-frame-bottom"><span>OPENED {startLabel}</span><span>NO RESOLUTION YET</span></div>
</div>
</section>
<footer class="site-footer">
<span>AN EXERCISE IN PATIENCE</span>
<span class="footer-rule"></span>
<span>THE CLOCK KEEPS MOVING</span>
</footer>
</main>
<script>
const START_TIME = new Date("2026-07-09T20:00:00+05:00").getTime();
const FLIP_MS = 640;
function getElapsedTime(): [number, number, number, number] {
const total = Math.max(0, Math.floor((Date.now() - START_TIME) / 1000));
return [
Math.floor(total / 86400),
Math.floor((total % 86400) / 3600),
Math.floor((total % 3600) / 60),
total % 60,
];
}
function pad(value: number): string {
return value.toString().padStart(2, "0");
}
function startFlip(digit: HTMLElement, value: string): void {
const displayed = digit.dataset.displayed ?? "0";
digit.querySelector(".digit-top")!.textContent = value;
digit.querySelector(".digit-flap-top")!.textContent = displayed;
digit.querySelector(".digit-flap-bottom")!.textContent = value;
digit.classList.add("is-flipping");
window.setTimeout(() => {
digit.dataset.displayed = value;
digit.classList.remove("is-flipping");
for (const face of digit.querySelectorAll(".digit-top, .digit-bottom, .digit-flap-top, .digit-flap-bottom")) {
face.textContent = value;
}
const pending = digit.dataset.pending;
delete digit.dataset.pending;
if (pending && pending !== value) startFlip(digit, pending);
}, FLIP_MS);
}
function setDigit(digit: HTMLElement, value: string): void {
if (digit.dataset.displayed === value) return;
if (digit.classList.contains("is-flipping")) {
digit.dataset.pending = value;
return;
}
startFlip(digit, value);
}
function updateUnit(container: HTMLElement, value: number): void {
container.setAttribute("aria-label", `${value} ${container.dataset.unit}`);
const target = pad(value).split("");
const existing = Array.from(container.querySelectorAll<HTMLElement>(".flip-digit"));
if (existing.length !== target.length) {
container.innerHTML = target
.map(
(d) =>
`<span class="flip-digit" data-displayed="${d}" aria-hidden="true">` +
'<span class="digit-face digit-top">' +
d +
"</span>" +
'<span class="digit-face digit-bottom">' +
d +
"</span>" +
'<span class="digit-flap digit-flap-top">' +
d +
"</span>" +
'<span class="digit-flap digit-flap-bottom">' +
d +
"</span>" +
'<span class="digit-seam"></span>' +
'<span class="digit-notch digit-notch-left"></span>' +
'<span class="digit-notch digit-notch-right"></span>' +
"</span>",
)
.join("");
return;
}
existing.forEach((digit, i) => setDigit(digit, target[i]!));
}
const containers = Array.from(document.querySelectorAll<HTMLElement>("[data-unit]"));
function tick(): void {
const [days, hours, minutes, seconds] = getElapsedTime();
const values = [days, hours, minutes, seconds];
containers.forEach((container, i) => updateUnit(container, values[i]!));
}
tick();
window.setInterval(tick, 1000);
</script>
</Layout>
+52
View File
@@ -0,0 +1,52 @@
:root {
color-scheme: dark;
--background: #090a0a;
--foreground: #e9e4d9;
--gold: #b99a62;
--font-inter: 'Inter', sans-serif;
--font-cormorant: 'Cormorant Garamond', Georgia, serif;
--font-mono-local: 'IBM Plex Mono', monospace;
}
* { box-sizing: border-box; }
html { background: var(--background); }
body { margin: 0; background: var(--background); color: var(--foreground); }
.clock-page {
position: relative; min-height: 100svh; overflow: hidden; display: flex; flex-direction: column;
padding: 28px clamp(20px, 5vw, 80px) 24px; background-color: #090a0a;
background-image: linear-gradient(135deg, rgba(255,255,255,.018) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.018) 50%, rgba(255,255,255,.018) 75%, transparent 75%);
background-size: 9px 9px;
}
.clock-page::before { content: ''; position: absolute; inset: 0; pointer-events: none; background: radial-gradient(ellipse at 50% 45%, transparent 22%, rgba(0,0,0,.55) 100%); }
.site-header, .site-footer { position: relative; z-index: 1; display: flex; align-items: center; justify-content: space-between; color: #77766f; font: 10px var(--font-mono-local); letter-spacing: .19em; }
.brand-mark { display: flex; align-items: center; gap: 9px; color: #b1aca1; }
.brand-dot, .status-pulse { width: 5px; height: 5px; display: inline-block; border-radius: 50%; background: var(--gold); box-shadow: 0 0 10px rgba(185,154,98,.6); }
.header-status { display: flex; gap: 9px; align-items: center; }
.ambient-line { position: absolute; z-index: 0; top: 47%; width: 17vw; height: 1px; background: linear-gradient(90deg, transparent, rgba(185,154,98,.25)); }
.ambient-line-left { left: 0; }.ambient-line-right { right: 0; transform: rotate(180deg); }
.hero-content { position: relative; z-index: 1; width: min(1360px, 100%); margin: auto; text-align: center; }
.eyebrow { display: flex; align-items: center; justify-content: center; gap: 14px; color: var(--gold); font: 10px var(--font-mono-local); letter-spacing: .28em; }
.eyebrow span { width: 32px; height: 1px; background: rgba(185,154,98,.5); }
h1 { margin: 22px 0 10px; color: #e8e1d3; font: 400 clamp(42px, 6.2vw, 92px)/.88 var(--font-cormorant), Georgia, serif; letter-spacing: -.035em; }
h1 em { color: var(--gold); font-style: italic; }
.subtitle { margin: 0 auto 44px; color: #88877f; font: 12px/1.5 var(--font-inter), sans-serif; letter-spacing: .05em; }
.clock-frame { border-top: 1px solid rgba(185,154,98,.5); border-bottom: 1px solid rgba(185,154,98,.5); padding: 17px 0 16px; }
.clock-frame-top, .clock-frame-bottom { display: flex; justify-content: space-between; color: #77766f; font: 9px var(--font-mono-local); letter-spacing: .16em; }
.clock-frame-bottom { margin-top: 22px; color: #9b8357; }
.clock-display { display: flex; align-items: center; justify-content: center; gap: clamp(7px, 1vw, 18px); margin-top: 13px; }
.clock-unit { min-width: 0; flex: 1; }.unit-digits { display: flex; gap: clamp(4px, .7vw, 11px); justify-content: center; }.unit-label { display: block; margin-top: 13px; color: #aba79c; font: 9px var(--font-mono-local); letter-spacing: .22em; text-transform: uppercase; }
.unit-divider { margin-top: -16px; color: #a98d5a; font: 600 clamp(28px, 4vw, 72px)/1 var(--font-mono-local); opacity: .8; }
.flip-digit { position: relative; display: block; width: clamp(38px, 7vw, 118px); height: clamp(54px, 11vw, 158px); perspective: 600px; color: #eee9dd; font: 500 clamp(43px, 8.8vw, 126px)/1 var(--font-mono-local); letter-spacing: -.14em; text-indent: -.12em; text-align: center; filter: drop-shadow(0 15px 15px rgba(0,0,0,.5)); }
.digit-face, .digit-flap { position: absolute; inset: 0; height: 100%; display: flex; align-items: center; justify-content: center; overflow: hidden; border: 1px solid #393934; text-shadow: 0 2px 2px #000; }
.digit-top { clip-path: inset(0 0 50% 0); border-radius: 4px; background: linear-gradient(145deg, #343633, #171918 48%, #252724); }.digit-bottom { clip-path: inset(50% 0 0 0); border-radius: 4px; background: linear-gradient(145deg, #282b29, #111313 60%, #202220); }
.digit-face::after, .digit-flap::after { content: ''; position: absolute; inset: 0; background: repeating-linear-gradient(115deg, transparent 0 3px, rgba(255,255,255,.018) 3px 4px); pointer-events: none; }
.digit-seam { position: absolute; top: calc(50% - 1px); left: 0; right: 0; height: 2px; background: #0b0c0c; box-shadow: 0 1px 2px rgba(255,255,255,.13); z-index: 3; }
.digit-notch { position: absolute; z-index: 5; top: calc(50% - 4px); width: 7px; height: 8px; background: #090a0a; border-radius: 50%; }.digit-notch-left { left: -4px; }.digit-notch-right { right: -4px; }
.digit-flap { z-index: 4; backface-visibility: hidden; transform-style: preserve-3d; }.digit-flap-top { clip-path: inset(0 0 50% 0); transform-origin: 50% 50%; border-radius: 4px; background: linear-gradient(145deg, #343633, #171918 48%, #252724); }.digit-flap-bottom { clip-path: inset(50% 0 0 0); transform-origin: 50% 50%; border-radius: 4px; background: linear-gradient(145deg, #282b29, #111313 60%, #202220); transform: rotateX(90deg); }
.is-flipping .digit-flap-top { animation: flip-top .42s cubic-bezier(.37,.01,.2,1) forwards; }.is-flipping .digit-flap-bottom { animation: flip-bottom .42s cubic-bezier(.37,.01,.2,1) .2s forwards; }
@keyframes flip-top { 0% { transform: rotateX(0); } 100% { transform: rotateX(-90deg); } }
@keyframes flip-bottom { 0% { transform: rotateX(90deg); } 100% { transform: rotateX(0); } }
.site-footer { margin-top: auto; padding-top: 22px; color: #65655f; }.footer-rule { flex: 1; height: 1px; margin: 0 22px; background: #292a27; }
@media (max-width: 640px) { .clock-page { padding: 20px 14px 18px; }.site-header { font-size: 8px; }.header-status { max-width: 150px; text-align: right; line-height: 1.6; }.subtitle { margin-bottom: 30px; font-size: 11px; }.clock-frame-top, .clock-frame-bottom { font-size: 7px; letter-spacing: .1em; }.clock-frame-bottom { margin-top: 16px; }.clock-display { gap: 4px; }.unit-divider { font-size: 23px; }.unit-label { font-size: 7px; letter-spacing: .12em; margin-top: 9px; }.flip-digit { width: clamp(35px, 17vw, 64px); height: clamp(50px, 24vw, 88px); font-size: clamp(39px, 20vw, 70px); } }
@media (prefers-reduced-motion: reduce) { .is-flipping .digit-flap { animation: none; } }