add rickroll
This commit is contained in:
parent
13a67bbf8d
commit
d07dbeb61f
6 changed files with 1350 additions and 407 deletions
|
|
@ -1,73 +1,206 @@
|
||||||
<header class="border-b border-[var(--border)]">
|
<header class="relative z-50 border-b border-[var(--border)]">
|
||||||
<div class="mx-auto flex max-w-7xl items-center justify-between px-6 py-5 lg:px-8">
|
<div
|
||||||
|
class="mx-auto flex h-16 max-w-7xl items-center justify-between px-6 lg:px-8"
|
||||||
|
>
|
||||||
|
<!-- Logo -->
|
||||||
<a
|
<a
|
||||||
href="/"
|
href="/"
|
||||||
class="font-mono text-sm font-bold tracking-tight"
|
class="group flex items-center gap-3 font-mono text-sm font-bold tracking-tight"
|
||||||
>
|
>
|
||||||
SEMYON<span class="text-[var(--accent)]">.</span>DEV
|
<span
|
||||||
|
class="flex h-7 w-7 items-center justify-center border border-[var(--border)] text-[10px] text-[var(--accent)] transition-colors group-hover:border-[var(--accent)]"
|
||||||
|
>
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
```
|
||||||
|
<span>
|
||||||
|
ALASTOR<span class="text-[var(--accent)]">.</span>LOL
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<nav class="hidden items-center gap-7 font-mono text-[11px] md:flex">
|
<!-- Desktop navigation -->
|
||||||
|
<nav class="hidden items-center md:flex">
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
<a
|
<a
|
||||||
href="/projects"
|
href="/#projects"
|
||||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
||||||
>
|
>
|
||||||
WORK
|
<span>PROJECTS</span>
|
||||||
|
<span
|
||||||
|
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
|
||||||
|
></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="#lab"
|
href="/#lab"
|
||||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
||||||
>
|
>
|
||||||
LAB
|
<span>LAB</span>
|
||||||
|
<span
|
||||||
|
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
|
||||||
|
></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="/blog"
|
href="/blog"
|
||||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
||||||
>
|
>
|
||||||
BLOG
|
<span>BLOG</span>
|
||||||
|
<span
|
||||||
|
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
|
||||||
|
></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="#about"
|
href="/#about"
|
||||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
class="group relative px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
||||||
>
|
>
|
||||||
ABOUT
|
<span>ABOUT</span>
|
||||||
|
<span
|
||||||
|
class="absolute bottom-0 left-3 right-3 h-px origin-left scale-x-0 bg-[var(--accent)] transition-transform duration-200 group-hover:scale-x-100"
|
||||||
|
></span>
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<span class="h-4 w-px bg-[var(--border)]"></span>
|
<div class="mx-4 h-5 w-px bg-[var(--border)]"></div>
|
||||||
|
|
||||||
<!-- TODO: заменить # на реальную ссылку DonationAlerts -->
|
<div class="flex items-center gap-2">
|
||||||
<a
|
<a
|
||||||
href="https://www.donationalerts.com/r/alastor3301"
|
href="https://www.donationalerts.com/r/alastor3301"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="text-[var(--accent)] transition-opacity hover:opacity-70"
|
class="group flex items-center gap-2 border border-[var(--border)] px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--accent)] transition-all duration-200 hover:border-[var(--accent)] hover:bg-[var(--accent)] hover:text-black"
|
||||||
>
|
>
|
||||||
SUPPORT ↗
|
<span>SUPPORT</span>
|
||||||
|
<span
|
||||||
|
class="transition-transform duration-200 group-hover:translate-x-0.5 group-hover:-translate-y-0.5"
|
||||||
|
>
|
||||||
|
↗
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- TODO: заменить # на GitHub -->
|
|
||||||
<a
|
<a
|
||||||
href="https://github.com/Trytonottry"
|
href="https://github.com/Trytonottry"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
aria-label="GitHub"
|
||||||
|
class="group flex h-8 w-8 items-center justify-center border border-[var(--border)] font-mono text-[10px] text-[var(--muted)] transition-colors hover:border-[var(--text)] hover:text-[var(--text)]"
|
||||||
|
>
|
||||||
|
<span class="transition-transform duration-200 group-hover:translate-x-0.5 group-hover:-translate-y-0.5">
|
||||||
|
↗
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Mobile menu button -->
|
||||||
|
<button
|
||||||
|
id="mobile-menu-button"
|
||||||
|
type="button"
|
||||||
|
class="flex items-center gap-3 border border-[var(--border)] px-3 py-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] transition-colors hover:border-[var(--text)] hover:text-[var(--text)] md:hidden"
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls="mobile-menu"
|
||||||
|
>
|
||||||
|
<span id="mobile-menu-label">MENU</span>
|
||||||
|
|
||||||
|
<span class="flex flex-col gap-1">
|
||||||
|
<span
|
||||||
|
id="menu-line-1"
|
||||||
|
class="block h-px w-3 bg-current transition-transform duration-200"
|
||||||
|
></span>
|
||||||
|
<span
|
||||||
|
id="menu-line-2"
|
||||||
|
class="block h-px w-3 bg-current transition-transform duration-200"
|
||||||
|
></span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Mobile navigation -->
|
||||||
|
<div
|
||||||
|
id="mobile-menu"
|
||||||
|
class="hidden border-t border-[var(--border)] bg-[var(--bg)] md:hidden"
|
||||||
|
>
|
||||||
|
<nav class="mx-auto max-w-7xl px-6 py-4 lg:px-8">
|
||||||
|
<div class="grid border border-[var(--border)]">
|
||||||
|
<a
|
||||||
|
href="/#projects"
|
||||||
|
class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
|
||||||
|
>
|
||||||
|
01 / PROJECTS
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/#lab"
|
||||||
|
class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
|
||||||
|
>
|
||||||
|
02 / LAB
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/blog"
|
||||||
|
class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
|
||||||
|
>
|
||||||
|
03 / BLOG
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/#about"
|
||||||
|
class="border-b border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
|
||||||
|
>
|
||||||
|
04 / ABOUT
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2">
|
||||||
|
<a
|
||||||
|
href="https://www.donationalerts.com/r/alastor3301"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="border-r border-[var(--border)] px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--accent)] transition-colors hover:bg-[var(--accent)] hover:text-black"
|
||||||
|
>
|
||||||
|
SUPPORT ↗
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="https://github.com/Trytonottry"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="px-4 py-4 font-mono text-xs uppercase tracking-widest text-[var(--muted)] transition-colors hover:bg-[var(--surface)] hover:text-[var(--text)]"
|
||||||
>
|
>
|
||||||
GITHUB ↗
|
GITHUB ↗
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="font-mono text-xs text-[var(--muted)] md:hidden"
|
|
||||||
aria-label="Open menu"
|
|
||||||
>
|
|
||||||
MENU
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const button = document.querySelector("#mobile-menu-button");
|
||||||
|
const menu = document.querySelector("#mobile-menu");
|
||||||
|
const label = document.querySelector("#mobile-menu-label");
|
||||||
|
const line1 = document.querySelector("#menu-line-1");
|
||||||
|
const line2 = document.querySelector("#menu-line-2");
|
||||||
|
|
||||||
|
button?.addEventListener("click", () => {
|
||||||
|
const isOpen = button.getAttribute("aria-expanded") === "true";
|
||||||
|
|
||||||
|
button.setAttribute("aria-expanded", String(!isOpen));
|
||||||
|
menu?.classList.toggle("hidden", isOpen);
|
||||||
|
|
||||||
|
if (label) {
|
||||||
|
label.textContent = isOpen ? "MENU" : "CLOSE";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOpen) {
|
||||||
|
line1?.classList.add("translate-y-[3px]", "rotate-45");
|
||||||
|
line2?.classList.add("-translate-y-[3px]", "-rotate-45");
|
||||||
|
} else {
|
||||||
|
line1?.classList.remove("translate-y-[3px]", "rotate-45");
|
||||||
|
line2?.classList.remove("-translate-y-[3px]", "-rotate-45");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,130 @@
|
||||||
<section class="relative overflow-hidden">
|
|
||||||
<div
|
<div
|
||||||
class="mx-auto grid min-h-[calc(100vh-73px)] max-w-7xl gap-16 px-6 py-20 lg:grid-cols-[minmax(0,1fr)_380px] lg:px-8 lg:py-24"
|
class="relative overflow-hidden border-b border-[var(--border)]"
|
||||||
>
|
>
|
||||||
|
<!-- Background grid -->
|
||||||
|
<div
|
||||||
|
class="pointer-events-none absolute inset-0 opacity-40"
|
||||||
|
style="
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(255,255,255,.025) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255,255,255,.025) 1px, transparent 1px);
|
||||||
|
background-size: 48px 48px;
|
||||||
|
mask-image: linear-gradient(to bottom, black, transparent);
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<!-- Accent glow -->
|
||||||
|
<div
|
||||||
|
class="pointer-events-none absolute -right-40 -top-40 h-[500px] w-[500px] rounded-full bg-[var(--accent)] opacity-[0.035] blur-3xl"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="relative mx-auto grid max-w-7xl gap-16 px-6 py-24 lg:grid-cols-[minmax(0,1fr)_360px] lg:px-8 lg:py-36"
|
||||||
|
>
|
||||||
|
<!-- LEFT -->
|
||||||
<div class="flex flex-col justify-center">
|
<div class="flex flex-col justify-center">
|
||||||
|
<!-- Status -->
|
||||||
<div class="mb-8 flex items-center gap-3 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]">
|
<div
|
||||||
|
class="mb-8 flex items-center gap-3 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]"
|
||||||
|
>
|
||||||
<span class="relative flex h-2 w-2">
|
<span class="relative flex h-2 w-2">
|
||||||
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--accent)] opacity-40"></span>
|
<span
|
||||||
<span class="relative inline-flex h-2 w-2 rounded-full bg-[var(--accent)]"></span>
|
class="absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--accent)] opacity-50"
|
||||||
|
></span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="relative inline-flex h-2 w-2 rounded-full bg-[var(--accent)]"
|
||||||
|
></span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
SYSTEM ONLINE
|
SYSTEM ONLINE
|
||||||
|
|
||||||
|
<span class="text-[var(--border)]">/</span>
|
||||||
|
|
||||||
|
<span>ALASTOR.LOL</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-6 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]">
|
<!-- Main title -->
|
||||||
SYSTEMS / AUTOMATION / INFRASTRUCTURE
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h1
|
<h1
|
||||||
class="max-w-5xl text-[4rem] font-bold leading-[0.88] tracking-[-0.065em] sm:text-[5.5rem] lg:text-[7.5rem]"
|
class="max-w-5xl text-5xl font-black uppercase leading-[0.88] tracking-[-0.065em] sm:text-7xl lg:text-[6.8rem]"
|
||||||
>
|
>
|
||||||
BUILD.
|
<span class="block">BUILD.</span>
|
||||||
<br />
|
|
||||||
|
<span class="block text-[var(--muted)]">
|
||||||
BREAK.
|
BREAK.
|
||||||
<br />
|
</span>
|
||||||
<span class="text-[var(--accent)]">UNDERSTAND.</span>
|
|
||||||
<br />
|
<span class="block">
|
||||||
REPEAT.
|
<span class="text-[var(--accent)]">
|
||||||
|
UNDERSTAND.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="block">REPEAT.</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="mt-10 flex flex-col gap-8 sm:flex-row sm:items-end sm:justify-between">
|
<!-- Description -->
|
||||||
|
<p
|
||||||
<p class="max-w-xl text-base leading-7 text-[var(--muted)] sm:text-lg">
|
class="mt-10 max-w-xl text-base leading-7 text-[var(--muted)] sm:text-lg"
|
||||||
|
>
|
||||||
Systems administrator and infrastructure engineer.
|
Systems administrator and infrastructure engineer.
|
||||||
I build infrastructure, automate systems and investigate
|
I build infrastructure, automate systems and investigate
|
||||||
things when they inevitably break.
|
things when they inevitably break.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="hidden font-mono text-right text-[10px] leading-5 text-[var(--muted)] sm:block">
|
<!-- Actions -->
|
||||||
<div>ALASTOR.LOL</div>
|
|
||||||
<div>SYS / 001</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-10 flex flex-wrap gap-3">
|
<div class="mt-10 flex flex-wrap gap-3">
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="#projects"
|
href="#projects"
|
||||||
class="group border border-[var(--text)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider transition-all duration-200 hover:bg-[var(--text)] hover:text-black"
|
class="group relative overflow-hidden border border-[var(--text)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider transition-colors duration-200 hover:bg-[var(--text)] hover:text-black"
|
||||||
|
>
|
||||||
|
<span class="relative z-10">
|
||||||
|
VIEW PROJECTS
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="ml-2 inline-block transition-transform duration-200 group-hover:translate-x-1"
|
||||||
>
|
>
|
||||||
<span>View projects</span>
|
|
||||||
<span class="ml-3 transition-transform duration-200 group-hover:translate-x-1">
|
|
||||||
→
|
→
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="/blog"
|
href="/blog"
|
||||||
class="border border-[var(--border)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider text-[var(--muted)] transition-all duration-200 hover:border-[var(--text)] hover:text-[var(--text)]"
|
class="group border border-[var(--border)] px-5 py-3 font-mono text-[11px] uppercase tracking-wider text-[var(--muted)] transition-colors duration-200 hover:border-[var(--text)] hover:text-[var(--text)]"
|
||||||
>
|
>
|
||||||
Read blog →
|
READ BLOG
|
||||||
|
|
||||||
|
<span
|
||||||
|
class="ml-2 inline-block transition-transform duration-200 group-hover:translate-x-1"
|
||||||
|
>
|
||||||
|
→
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Small metadata -->
|
||||||
|
<div
|
||||||
|
class="mt-14 flex flex-wrap gap-x-6 gap-y-2 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]"
|
||||||
|
>
|
||||||
|
<span>LINUX</span>
|
||||||
|
<span>NETWORKING</span>
|
||||||
|
<span>AUTOMATION</span>
|
||||||
|
<span>HOMELAB</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- RIGHT -->
|
||||||
<div class="flex items-end">
|
<div class="flex items-end">
|
||||||
|
<div
|
||||||
<div class="w-full border border-[var(--border)] bg-[var(--surface)] font-mono text-xs">
|
class="w-full border border-[var(--border)] bg-[var(--surface)] font-mono text-xs shadow-2xl shadow-black/20"
|
||||||
|
>
|
||||||
<div class="flex items-center justify-between border-b border-[var(--border)] px-4 py-3">
|
<!-- Terminal header -->
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between border-b border-[var(--border)] px-4 py-3"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<span class="h-1.5 w-1.5 rounded-full bg-[var(--accent)]"></span>
|
<span class="h-2 w-2 rounded-full bg-[var(--accent)]"></span>
|
||||||
|
|
||||||
<span class="text-[var(--muted)]">
|
<span class="text-[var(--muted)]">
|
||||||
SYSTEM STATUS
|
SYSTEM STATUS
|
||||||
|
|
@ -85,102 +134,108 @@
|
||||||
<span class="text-[var(--accent)]">
|
<span class="text-[var(--accent)]">
|
||||||
OPERATIONAL
|
OPERATIONAL
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="p-5">
|
<div class="p-5">
|
||||||
|
<!-- Terminal prompt -->
|
||||||
<div class="mb-6 text-[10px] uppercase tracking-[0.2em] text-[var(--muted)]">
|
<div class="mb-7 text-[var(--muted)]">
|
||||||
CAPABILITIES
|
<span class="text-[var(--accent)]">$</span>
|
||||||
|
./check-system.sh
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="space-y-4">
|
<!-- Systems -->
|
||||||
|
<div class="space-y-5">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-[var(--muted)]">
|
||||||
|
Linux
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="text-[var(--accent)]">
|
||||||
|
● OK
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span class="text-[var(--muted)]">Linux</span>
|
<span class="text-[var(--muted)]">
|
||||||
<span class="text-[var(--accent)]">●</span>
|
Infrastructure
|
||||||
</div>
|
</span>
|
||||||
|
|
||||||
<div class="h-px bg-[var(--border)]"></div>
|
<span class="text-[var(--accent)]">
|
||||||
|
● OK
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span class="text-[var(--muted)]">Infrastructure</span>
|
<span class="text-[var(--muted)]">
|
||||||
<span class="text-[var(--accent)]">●</span>
|
Networking
|
||||||
</div>
|
</span>
|
||||||
|
|
||||||
<div class="h-px bg-[var(--border)]"></div>
|
<span class="text-[var(--accent)]">
|
||||||
|
● OK
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<span class="text-[var(--muted)]">Networking</span>
|
<span class="text-[var(--muted)]">
|
||||||
<span class="text-[var(--accent)]">●</span>
|
Automation
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="text-[var(--accent)]">
|
||||||
|
● OK
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="h-px bg-[var(--border)]"></div>
|
<!-- Homelab -->
|
||||||
|
<div class="mt-8 border-t border-[var(--border)] pt-5">
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<span class="text-[var(--muted)]">Automation</span>
|
|
||||||
<span class="text-[var(--accent)]">●</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-8 border-t border-[var(--border)] pt-6">
|
|
||||||
|
|
||||||
<div class="mb-3 flex items-center justify-between">
|
<div class="mb-3 flex items-center justify-between">
|
||||||
<span class="text-[var(--muted)]">HOMELAB</span>
|
<span class="text-[var(--muted)]">
|
||||||
<span class="text-[var(--accent)]">87%</span>
|
HOMELAB
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="text-[var(--accent)]">
|
||||||
|
87%
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="h-1 bg-[var(--border)]">
|
<div class="h-1 overflow-hidden bg-[var(--border)]">
|
||||||
<div class="h-full w-[87%] bg-[var(--accent)]"></div>
|
<div
|
||||||
|
class="h-full w-[87%] bg-[var(--accent)]"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<!-- Footer -->
|
||||||
|
<div
|
||||||
<div class="mt-8 grid grid-cols-2 gap-4 border-t border-[var(--border)] pt-6">
|
class="mt-7 border-t border-[var(--border)] pt-5 text-[10px] text-[var(--muted)]"
|
||||||
|
>
|
||||||
<div>
|
|
||||||
<div class="text-[10px] text-[var(--muted)]">HOSTS</div>
|
|
||||||
<div class="mt-2 text-xl">06</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class="text-[10px] text-[var(--muted)]">SERVICES</div>
|
|
||||||
<div class="mt-2 text-xl">30+</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-8 border-t border-[var(--border)] pt-5 text-[10px] text-[var(--muted)]">
|
|
||||||
|
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<span>UPTIME</span>
|
<span>HOSTS</span>
|
||||||
<span class="text-[var(--text)]">99.9%</span>
|
<span>06</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-2 flex justify-between">
|
<div class="mt-2 flex justify-between">
|
||||||
<span>STATUS</span>
|
<span>SERVICES</span>
|
||||||
<span class="text-[var(--accent)]">BUILDING</span>
|
<span>30+</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2 flex justify-between">
|
||||||
|
<span>UPTIME</span>
|
||||||
|
<span class="text-[var(--accent)]">
|
||||||
|
99.9%
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottom coordinate -->
|
||||||
|
<div
|
||||||
|
class="pointer-events-none absolute bottom-5 left-1/2 hidden -translate-x-1/2 font-mono text-[9px] uppercase tracking-[0.3em] text-[var(--muted)] opacity-50 md:block"
|
||||||
|
>
|
||||||
|
SCROLL TO EXPLORE
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mx-auto hidden max-w-7xl px-6 pb-6 lg:block lg:px-8">
|
|
||||||
|
|
||||||
<div class="flex items-center justify-between font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
|
|
||||||
<span>SCROLL TO EXPLORE</span>
|
|
||||||
<span>ALASTOR.LOL / 2026</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,24 @@
|
||||||
<div class="border-y border-[var(--border)]">
|
<div class="border-y border-[var(--border)]">
|
||||||
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
<div class="mx-auto max-w-7xl px-6 lg:px-8">
|
||||||
|
|
||||||
|
```
|
||||||
|
<!-- Header -->
|
||||||
<div class="flex items-center justify-between border-b border-[var(--border)] py-4">
|
<div class="flex items-center justify-between border-b border-[var(--border)] py-4">
|
||||||
<div class="font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]">
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]">
|
||||||
01 / NOW
|
01 / NOW
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="hidden h-px w-8 bg-[var(--border)] sm:block"></span>
|
||||||
|
|
||||||
|
<span class="hidden font-mono text-[9px] uppercase tracking-widest text-[var(--muted)] sm:block">
|
||||||
|
LIVE ACTIVITY
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="now-status"
|
id="now-status"
|
||||||
class="flex items-center gap-2 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]"
|
class="flex items-center gap-2 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
id="status-dot"
|
id="status-dot"
|
||||||
|
|
@ -19,31 +29,53 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid divide-y divide-[var(--border)] md:grid-cols-4 md:divide-x md:divide-y-0">
|
<!-- Activity grid -->
|
||||||
|
<div class="grid md:grid-cols-4">
|
||||||
|
|
||||||
<div class="py-7 md:pr-8">
|
<!-- Current state -->
|
||||||
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]">
|
<div class="border-b border-[var(--border)] py-7 md:border-b-0 md:pr-8">
|
||||||
|
<div class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
|
||||||
CURRENT STATE
|
CURRENT STATE
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 text-sm leading-relaxed">
|
<div class="mt-4 flex items-start gap-3">
|
||||||
Building things,<br />
|
<span class="mt-2 h-1 w-1 shrink-0 bg-[var(--accent)]"></span>
|
||||||
break fixing things.
|
|
||||||
|
<div>
|
||||||
|
<div class="text-sm leading-6">
|
||||||
|
Building things,
|
||||||
|
<br />
|
||||||
|
breaking things,
|
||||||
|
<br />
|
||||||
|
understanding why.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]">
|
||||||
|
ALASTOR.LOL
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-7 md:px-8">
|
<!-- Spotify -->
|
||||||
|
<div class="border-b border-[var(--border)] py-7 md:border-b-0 md:border-l md:px-8">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]">
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
|
||||||
♪ LISTENING
|
♪ LISTENING
|
||||||
</div>
|
</span>
|
||||||
|
|
||||||
<div
|
<span
|
||||||
id="spotify-indicator"
|
id="spotify-indicator"
|
||||||
class="hidden font-mono text-[9px] uppercase tracking-widest text-[var(--accent)]"
|
class="hidden font-mono text-[8px] uppercase tracking-widest text-[var(--accent)]"
|
||||||
>
|
>
|
||||||
LIVE
|
LIVE
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||||
|
01
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
|
|
@ -51,35 +83,63 @@
|
||||||
href="#"
|
href="#"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="mt-3 block text-sm font-medium transition-colors hover:text-[var(--accent)]"
|
class="group mt-5 block"
|
||||||
>
|
>
|
||||||
<span id="spotify-title">Loading...</span>
|
<div class="flex items-start gap-3">
|
||||||
</a>
|
<div
|
||||||
|
class="mt-1 flex h-8 w-8 shrink-0 items-center justify-center border border-[var(--border)] text-[11px] text-[var(--accent)] transition-colors group-hover:border-[var(--accent)]"
|
||||||
|
>
|
||||||
|
♪
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="min-w-0">
|
||||||
|
<div
|
||||||
|
id="spotify-title"
|
||||||
|
class="truncate text-sm font-medium transition-colors group-hover:text-[var(--accent)]"
|
||||||
|
>
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="spotify-artist"
|
id="spotify-artist"
|
||||||
class="mt-1 text-xs text-[var(--muted)]"
|
class="mt-1 truncate text-xs text-[var(--muted)]"
|
||||||
>
|
>
|
||||||
Spotify
|
Spotify
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
<div class="mt-3 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]">
|
<div class="mt-5 flex items-center justify-between border-t border-[var(--border)] pt-3">
|
||||||
|
<span class="font-mono text-[8px] uppercase tracking-widest text-[var(--muted)]">
|
||||||
SPOTIFY
|
SPOTIFY
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||||
|
30s
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-7 md:px-8">
|
<!-- Steam -->
|
||||||
|
<div class="border-b border-[var(--border)] py-7 md:border-b-0 md:border-l md:px-8">
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]">
|
<div class="flex items-center gap-2">
|
||||||
|
<span class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
|
||||||
PLAYING
|
PLAYING
|
||||||
</div>
|
</span>
|
||||||
|
|
||||||
<div
|
<span
|
||||||
id="steam-indicator"
|
id="steam-indicator"
|
||||||
class="hidden font-mono text-[9px] uppercase tracking-widest text-[var(--accent)]"
|
class="hidden font-mono text-[8px] uppercase tracking-widest text-[var(--accent)]"
|
||||||
>
|
>
|
||||||
LIVE
|
LIVE
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||||
|
02
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
|
|
@ -87,80 +147,127 @@
|
||||||
href="#"
|
href="#"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
class="mt-3 block text-sm font-medium transition-colors hover:text-[var(--accent)]"
|
class="group mt-5 block"
|
||||||
>
|
>
|
||||||
<span id="steam-game">Loading...</span>
|
<div class="flex items-start gap-3">
|
||||||
</a>
|
<div
|
||||||
|
class="mt-1 flex h-8 w-8 shrink-0 items-center justify-center border border-[var(--border)] text-[10px] text-[var(--accent)] transition-colors group-hover:border-[var(--accent)]"
|
||||||
|
>
|
||||||
|
▶
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-1 text-xs text-[var(--muted)]">
|
<div class="min-w-0">
|
||||||
|
<div
|
||||||
|
id="steam-game"
|
||||||
|
class="truncate text-sm font-medium transition-colors group-hover:text-[var(--accent)]"
|
||||||
|
>
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-1 truncate text-xs text-[var(--muted)]">
|
||||||
Steam
|
Steam
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
<div class="mt-3 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]">
|
<div class="mt-5 flex items-center justify-between border-t border-[var(--border)] pt-3">
|
||||||
|
<span class="font-mono text-[8px] uppercase tracking-widest text-[var(--muted)]">
|
||||||
STEAM
|
STEAM
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||||
|
60s
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-7 md:pl-8">
|
<!-- Building -->
|
||||||
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]">
|
<div class="py-7 md:border-l md:pl-8">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="font-mono text-[9px] uppercase tracking-[0.2em] text-[var(--muted)]">
|
||||||
BUILDING
|
BUILDING
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-3 text-sm font-medium">
|
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||||
|
03
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-5">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<div class="relative flex h-8 w-8 items-center justify-center border border-[var(--border)]">
|
||||||
|
<span class="h-1.5 w-1.5 bg-[var(--accent)]"></span>
|
||||||
|
|
||||||
|
<span class="absolute inset-1 border border-[var(--border)]"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="text-sm font-medium">
|
||||||
alastor.lol
|
alastor.lol
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-1 text-xs text-[var(--muted)]">
|
<div class="mt-1 text-xs text-[var(--muted)]">
|
||||||
This website
|
This website
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="mt-3 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]">
|
|
||||||
ASTRO · TYPESCRIPT
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-5 flex items-center justify-between border-t border-[var(--border)] pt-3">
|
||||||
|
<span class="font-mono text-[8px] uppercase tracking-widest text-[var(--muted)]">
|
||||||
|
ASTRO · TS
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="font-mono text-[8px] text-[var(--accent)]">
|
||||||
|
ACTIVE
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Bottom telemetry -->
|
||||||
|
<div class="flex flex-col gap-2 border-t border-[var(--border)] py-3 font-mono text-[8px] uppercase tracking-widest text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between">
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span>ACTIVITY FEED</span>
|
||||||
|
<span class="h-px w-6 bg-[var(--border)]"></span>
|
||||||
|
<span id="last-update">WAITING FOR SYNC</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
SPOTIFY / STEAM / LOCAL
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const spotifyTitle =
|
const spotifyTitle = document.querySelector("#spotify-title");
|
||||||
document.querySelector("#spotify-title");
|
const spotifyArtist = document.querySelector("#spotify-artist");
|
||||||
|
|
||||||
const spotifyArtist =
|
|
||||||
document.querySelector("#spotify-artist");
|
|
||||||
|
|
||||||
const spotifyLink =
|
const spotifyLink =
|
||||||
document.querySelector("#spotify-link") as HTMLAnchorElement | null;
|
document.querySelector("#spotify-link") as HTMLAnchorElement | null;
|
||||||
|
const spotifyIndicator = document.querySelector("#spotify-indicator");
|
||||||
|
|
||||||
const spotifyIndicator =
|
const steamGame = document.querySelector("#steam-game");
|
||||||
document.querySelector("#spotify-indicator");
|
|
||||||
|
|
||||||
const steamGame =
|
|
||||||
document.querySelector("#steam-game");
|
|
||||||
|
|
||||||
const steamLink =
|
const steamLink =
|
||||||
document.querySelector("#steam-link") as HTMLAnchorElement | null;
|
document.querySelector("#steam-link") as HTMLAnchorElement | null;
|
||||||
|
const steamIndicator = document.querySelector("#steam-indicator");
|
||||||
|
|
||||||
const steamIndicator =
|
const statusText = document.querySelector("#status-text");
|
||||||
document.querySelector("#steam-indicator");
|
const statusDot = document.querySelector("#status-dot");
|
||||||
|
const lastUpdate = document.querySelector("#last-update");
|
||||||
const statusText =
|
|
||||||
document.querySelector("#status-text");
|
|
||||||
|
|
||||||
const statusDot =
|
|
||||||
document.querySelector("#status-dot");
|
|
||||||
|
|
||||||
function updateOverallStatus() {
|
function updateOverallStatus() {
|
||||||
const spotifyLive =
|
const spotifyLive =
|
||||||
spotifyIndicator?.classList.contains("inline");
|
spotifyIndicator?.classList.contains("inline");
|
||||||
|
|
||||||
const steamLive =
|
const steamLive =
|
||||||
steamIndicator?.classList.contains("inline");
|
steamIndicator?.classList.contains("inline");
|
||||||
|
|
||||||
if (spotifyLive || steamLive) {
|
if (spotifyLive || steamLive) {
|
||||||
statusText!.textContent = "LIVE";
|
statusText!.textContent = "LIVE";
|
||||||
|
|
||||||
statusDot!.classList.remove("bg-[var(--muted)]");
|
statusDot!.classList.remove("bg-[var(--muted)]");
|
||||||
statusDot!.classList.add(
|
statusDot!.classList.add(
|
||||||
"bg-[var(--accent)]",
|
"bg-[var(--accent)]",
|
||||||
|
|
@ -168,6 +275,7 @@
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
statusText!.textContent = "IDLE";
|
statusText!.textContent = "IDLE";
|
||||||
|
|
||||||
statusDot!.classList.remove(
|
statusDot!.classList.remove(
|
||||||
"bg-[var(--accent)]",
|
"bg-[var(--accent)]",
|
||||||
"animate-pulse",
|
"animate-pulse",
|
||||||
|
|
@ -176,6 +284,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTimestamp() {
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
lastUpdate!.textContent =
|
||||||
|
"LAST SYNC " +
|
||||||
|
now.toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function updateSpotify() {
|
async function updateSpotify() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("/api/spotify", {
|
const response = await fetch("/api/spotify", {
|
||||||
|
|
@ -197,6 +317,7 @@
|
||||||
spotifyIndicator?.classList.add("hidden");
|
spotifyIndicator?.classList.add("hidden");
|
||||||
|
|
||||||
updateOverallStatus();
|
updateOverallStatus();
|
||||||
|
updateTimestamp();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,6 +332,7 @@
|
||||||
spotifyIndicator?.classList.add("inline");
|
spotifyIndicator?.classList.add("inline");
|
||||||
|
|
||||||
updateOverallStatus();
|
updateOverallStatus();
|
||||||
|
updateTimestamp();
|
||||||
} catch {
|
} catch {
|
||||||
spotifyTitle!.textContent = "Unavailable";
|
spotifyTitle!.textContent = "Unavailable";
|
||||||
spotifyArtist!.textContent = "Spotify";
|
spotifyArtist!.textContent = "Spotify";
|
||||||
|
|
@ -220,6 +342,7 @@
|
||||||
spotifyIndicator?.classList.add("hidden");
|
spotifyIndicator?.classList.add("hidden");
|
||||||
|
|
||||||
updateOverallStatus();
|
updateOverallStatus();
|
||||||
|
updateTimestamp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,6 +366,7 @@
|
||||||
steamIndicator?.classList.add("hidden");
|
steamIndicator?.classList.add("hidden");
|
||||||
|
|
||||||
updateOverallStatus();
|
updateOverallStatus();
|
||||||
|
updateTimestamp();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,6 +380,7 @@
|
||||||
steamIndicator?.classList.add("inline");
|
steamIndicator?.classList.add("inline");
|
||||||
|
|
||||||
updateOverallStatus();
|
updateOverallStatus();
|
||||||
|
updateTimestamp();
|
||||||
} catch {
|
} catch {
|
||||||
steamGame!.textContent = "Unavailable";
|
steamGame!.textContent = "Unavailable";
|
||||||
steamLink?.removeAttribute("href");
|
steamLink?.removeAttribute("href");
|
||||||
|
|
@ -264,6 +389,7 @@
|
||||||
steamIndicator?.classList.add("hidden");
|
steamIndicator?.classList.add("hidden");
|
||||||
|
|
||||||
updateOverallStatus();
|
updateOverallStatus();
|
||||||
|
updateTimestamp();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
|
|
@ -11,91 +10,65 @@ const projects = await getCollection("projects", ({ data }) => {
|
||||||
id="projects"
|
id="projects"
|
||||||
class="border-t border-[var(--border)]"
|
class="border-t border-[var(--border)]"
|
||||||
>
|
>
|
||||||
<div class="mx-auto max-w-7xl px-6 py-28 lg:px-8">
|
<div class="mx-auto max-w-7xl px-6 py-28 lg:px-8 lg:py-36">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
|
<div class="grid gap-10 lg:grid-cols-[1fr_360px] lg:items-end">
|
||||||
<div class="flex flex-col gap-8 md:flex-row md:items-end md:justify-between">
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="font-mono text-[10px] tracking-[0.25em] text-[var(--muted)]">
|
<div class="flex items-center gap-3 font-mono text-[10px] tracking-[0.25em] text-[var(--muted)]">
|
||||||
02 / PROJECTS
|
<span class="text-[var(--accent)]">02</span>
|
||||||
|
<span>/</span>
|
||||||
|
<span>PROJECTS</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="mt-6 text-4xl font-bold tracking-tight sm:text-6xl">
|
<h2 class="mt-6 max-w-3xl text-5xl font-bold leading-[0.95] tracking-[-0.045em] sm:text-6xl lg:text-7xl">
|
||||||
Things I build.
|
Things I
|
||||||
|
<span class="text-[var(--muted)]"> build.</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="max-w-md text-sm leading-7 text-[var(--muted)]">
|
<div class="lg:pb-1">
|
||||||
|
<p class="text-sm leading-7 text-[var(--muted)]">
|
||||||
Infrastructure, automation, networking and experiments.
|
Infrastructure, automation, networking and experiments.
|
||||||
Some are production systems. Some are glorified
|
Some are production systems. Some are glorified learning
|
||||||
learning exercises.
|
exercises.
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Projects -->
|
<!-- Project grid -->
|
||||||
|
<div class="mt-20 grid gap-px border border-[var(--border)] bg-[var(--border)] md:grid-cols-2">
|
||||||
<div class="mt-16 border-t border-[var(--border)]">
|
|
||||||
|
|
||||||
{
|
{
|
||||||
projects.map((project, index) => (
|
projects.map((project, index) => (
|
||||||
<a
|
<a
|
||||||
href={`/projects/${project.id}`}
|
href={`/projects/${project.id}`}
|
||||||
class="group block border-b border-[var(--border)] transition-colors duration-200 hover:bg-[var(--surface)]"
|
class="group relative min-h-[320px] overflow-hidden bg-[var(--bg)] transition-colors duration-300 hover:bg-[var(--surface)]"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div class="grid gap-6 px-0 py-8 md:grid-cols-[64px_minmax(0,1fr)_220px_110px] md:items-center">
|
<!-- Background number -->
|
||||||
|
<div
|
||||||
<!-- Number -->
|
class="pointer-events-none absolute -right-3 -top-8 select-none font-mono text-[9rem] font-bold leading-none tracking-[-0.08em] text-[var(--surface-hover)] transition-colors duration-300 group-hover:text-[var(--border)]"
|
||||||
|
>
|
||||||
<div class="font-mono text-[10px] text-[var(--muted)]">
|
|
||||||
{String(index + 1).padStart(2, "0")}
|
{String(index + 1).padStart(2, "0")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Project -->
|
<div class="relative flex h-full flex-col justify-between p-7 sm:p-9">
|
||||||
|
|
||||||
<div class="min-w-0">
|
<!-- Top -->
|
||||||
|
<div>
|
||||||
|
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center justify-between">
|
||||||
|
|
||||||
<h3 class="truncate text-2xl font-semibold tracking-tight transition-colors duration-200 group-hover:text-[var(--accent)]">
|
|
||||||
{project.data.title}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<span class="font-mono text-xs text-[var(--muted)] transition-transform duration-200 group-hover:translate-x-1">
|
|
||||||
→
|
|
||||||
</span>
|
|
||||||
|
|
||||||
|
<div class="font-mono text-[10px] tracking-[0.2em] text-[var(--muted)]">
|
||||||
|
PROJECT {String(index + 1).padStart(2, "0")}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="mt-3 max-w-2xl text-sm leading-6 text-[var(--muted)]">
|
<div class="flex items-center gap-2 font-mono text-[9px] uppercase tracking-[0.15em]">
|
||||||
{project.data.description}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Stack + status -->
|
|
||||||
|
|
||||||
<div class="flex flex-col gap-3">
|
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-1.5">
|
|
||||||
|
|
||||||
{
|
|
||||||
project.data.stack.map((item) => (
|
|
||||||
<span class="border border-[var(--border)] px-2 py-1 font-mono text-[9px] uppercase tracking-wider text-[var(--muted)]">
|
|
||||||
{item}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center gap-2 font-mono text-[9px] uppercase tracking-widest">
|
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class:list={[
|
class:list={[
|
||||||
|
|
@ -121,13 +94,51 @@ const projects = await getCollection("projects", ({ data }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- View -->
|
<!-- Title -->
|
||||||
|
<div class="mt-12 max-w-xl">
|
||||||
|
|
||||||
<div class="hidden text-right font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] md:block">
|
<h3 class="text-3xl font-semibold leading-tight tracking-[-0.025em] transition-colors duration-200 group-hover:text-[var(--accent)] sm:text-4xl">
|
||||||
|
{project.data.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<span class="transition-colors group-hover:text-[var(--text)]">
|
<p class="mt-5 max-w-lg text-sm leading-7 text-[var(--muted)]">
|
||||||
VIEW →
|
{project.data.description}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Bottom -->
|
||||||
|
<div class="mt-12">
|
||||||
|
|
||||||
|
<div class="flex flex-wrap gap-1.5">
|
||||||
|
|
||||||
|
{
|
||||||
|
project.data.stack.map((item) => (
|
||||||
|
<span
|
||||||
|
class="border border-[var(--border)] px-2.5 py-1.5 font-mono text-[9px] uppercase tracking-wider text-[var(--muted)] transition-colors duration-200 group-hover:border-[var(--muted)] group-hover:text-[var(--text)]"
|
||||||
|
>
|
||||||
|
{item}
|
||||||
</span>
|
</span>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="mt-7 flex items-center justify-between border-t border-[var(--border)] pt-4">
|
||||||
|
|
||||||
|
<span class="font-mono text-[9px] uppercase tracking-[0.18em] text-[var(--muted)]">
|
||||||
|
EXPLORE PROJECT
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="font-mono text-sm text-[var(--muted)] transition-all duration-200 group-hover:translate-x-1 group-hover:text-[var(--accent)]">
|
||||||
|
→
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -141,18 +152,22 @@ const projects = await getCollection("projects", ({ data }) => {
|
||||||
|
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
|
<div class="mt-7 flex flex-col gap-4 font-mono text-[10px] uppercase tracking-[0.18em] text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between">
|
||||||
|
|
||||||
<div class="mt-8 flex flex-col gap-4 font-mono text-[10px] uppercase tracking-widest text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between">
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="h-1.5 w-1.5 rounded-full bg-[var(--accent)]"></span>
|
||||||
<span>
|
<span>{projects.length} PROJECTS</span>
|
||||||
{projects.length} PROJECTS
|
</div>
|
||||||
</span>
|
|
||||||
|
|
||||||
<a
|
<a
|
||||||
href="/projects"
|
href="/projects"
|
||||||
class="transition-colors hover:text-[var(--accent)]"
|
class="group flex items-center gap-2 transition-colors hover:text-[var(--accent)]"
|
||||||
>
|
>
|
||||||
VIEW ALL PROJECTS →
|
VIEW ALL PROJECTS
|
||||||
|
|
||||||
|
<span class="transition-transform duration-200 group-hover:translate-x-1">
|
||||||
|
→
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -161,3 +176,5 @@ const projects = await getCollection("projects", ({ data }) => {
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
88
src/pages/rickroll.astro
Normal file
88
src/pages/rickroll.astro
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
---
|
||||||
|
import Layout from "../layouts/Layout.astro";
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout>
|
||||||
|
<main
|
||||||
|
class="relative flex min-h-screen items-center justify-center overflow-hidden bg-black px-6"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="absolute inset-0 opacity-20"
|
||||||
|
style="
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(184,255,0,.08) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(184,255,0,.08) 1px, transparent 1px);
|
||||||
|
background-size: 40px 40px;
|
||||||
|
"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div class="relative z-10 w-full max-w-5xl">
|
||||||
|
<div
|
||||||
|
class="overflow-hidden border border-[var(--border)] bg-[var(--surface)]"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between border-b border-[var(--border)] px-4 py-3 font-mono text-[10px] uppercase tracking-widest"
|
||||||
|
>
|
||||||
|
<span class="text-[var(--muted)]">
|
||||||
|
SECURITY INCIDENT
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span class="flex items-center gap-2 text-[var(--accent)]">
|
||||||
|
<span class="h-1.5 w-1.5 animate-pulse rounded-full bg-[var(--accent)]"></span>
|
||||||
|
CRITICAL
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-6 sm:p-10 lg:p-14">
|
||||||
|
<div
|
||||||
|
class="mb-8 font-mono text-[10px] uppercase tracking-[0.3em] text-[var(--muted)]"
|
||||||
|
>
|
||||||
|
ERR / 0x1337 / ALASTOR.LOL
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1
|
||||||
|
class="max-w-4xl text-5xl font-black uppercase leading-[0.9] tracking-[-0.06em] sm:text-7xl lg:text-8xl"
|
||||||
|
>
|
||||||
|
Внимание!
|
||||||
|
<br />
|
||||||
|
<span class="text-[var(--accent)]">
|
||||||
|
Вас зарикроллили!
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="mt-10 aspect-video w-full overflow-hidden border border-[var(--border)] bg-black">
|
||||||
|
<iframe
|
||||||
|
class="h-full w-full"
|
||||||
|
src="https://www.youtube.com/embed/dQw4w9WgXcQ?autoplay=1&rel=0"
|
||||||
|
title="Never Gonna Give You Up"
|
||||||
|
frameborder="0"
|
||||||
|
allow="autoplay; encrypted-media"
|
||||||
|
allowfullscreen
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="mt-8 flex flex-col gap-4 border-t border-[var(--border)] pt-6 font-mono text-xs text-[var(--muted)] sm:flex-row sm:items-center sm:justify-between"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
STATUS: YOU SHOULD HAVE KNOWN BETTER
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
class="text-[var(--text)] transition-colors hover:text-[var(--accent)]"
|
||||||
|
>
|
||||||
|
← RETURN TO SAFETY
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="mt-4 text-center font-mono text-[9px] uppercase tracking-[0.25em] text-[var(--muted)]"
|
||||||
|
>
|
||||||
|
No systems were harmed during this incident.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</Layout>
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
|
@ -21,19 +22,7 @@ html {
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
background:
|
background: var(--bg);
|
||||||
linear-gradient(
|
|
||||||
rgba(255, 255, 255, 0.012) 1px,
|
|
||||||
transparent 1px
|
|
||||||
),
|
|
||||||
linear-gradient(
|
|
||||||
90deg,
|
|
||||||
rgba(255, 255, 255, 0.012) 1px,
|
|
||||||
transparent 1px
|
|
||||||
),
|
|
||||||
var(--bg);
|
|
||||||
|
|
||||||
background-size: 48px 48px;
|
|
||||||
|
|
||||||
font-family:
|
font-family:
|
||||||
Inter,
|
Inter,
|
||||||
|
|
@ -43,9 +32,6 @@ body {
|
||||||
BlinkMacSystemFont,
|
BlinkMacSystemFont,
|
||||||
"Segoe UI",
|
"Segoe UI",
|
||||||
sans-serif;
|
sans-serif;
|
||||||
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
::selection {
|
::selection {
|
||||||
|
|
@ -58,16 +44,6 @@ a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
button,
|
|
||||||
a {
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
:focus-visible {
|
|
||||||
outline: 1px solid var(--accent);
|
|
||||||
outline-offset: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-mono {
|
.font-mono {
|
||||||
font-family:
|
font-family:
|
||||||
"JetBrains Mono",
|
"JetBrains Mono",
|
||||||
|
|
@ -77,43 +53,591 @@ a {
|
||||||
monospace;
|
monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scrollbar */
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
/* ─────────────────────────────────────────
|
||||||
width: 8px;
|
Markdown / Article typography
|
||||||
|
───────────────────────────────────────── */
|
||||||
|
|
||||||
|
.prose {
|
||||||
|
max-width: 760px;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.85;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
.prose > *:first-child {
|
||||||
background: var(--bg);
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
.prose > *:last-child {
|
||||||
background: #292929;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #3a3a3a;
|
/* Headings */
|
||||||
|
|
||||||
|
.prose h1 {
|
||||||
|
margin-top: 3rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
|
||||||
|
font-size: 2.25rem;
|
||||||
|
line-height: 1.15;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.035em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Firefox */
|
.prose h2 {
|
||||||
|
margin-top: 3rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
|
||||||
|
font-size: 1.65rem;
|
||||||
|
line-height: 1.25;
|
||||||
|
font-weight: 650;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose h3 {
|
||||||
|
margin-top: 2.25rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1.35;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose h4 {
|
||||||
|
margin-top: 1.75rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Paragraphs */
|
||||||
|
|
||||||
|
.prose p {
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
|
||||||
|
.prose a {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--accent) 40%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
|
||||||
|
transition:
|
||||||
|
color 150ms ease,
|
||||||
|
text-decoration-color 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose a:hover {
|
||||||
|
color: var(--text);
|
||||||
|
text-decoration-color: var(--text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Lists */
|
||||||
|
|
||||||
|
.prose ul,
|
||||||
|
.prose ol {
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose li {
|
||||||
|
margin-top: 0.45rem;
|
||||||
|
padding-left: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose li::marker {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose li > ul,
|
||||||
|
.prose li > ol {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Blockquotes */
|
||||||
|
|
||||||
|
.prose blockquote {
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 0.75rem 0 0.75rem 1.25rem;
|
||||||
|
|
||||||
|
border-left: 2px solid var(--accent);
|
||||||
|
|
||||||
|
color: var(--muted);
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose blockquote p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
|
||||||
|
.prose :not(pre) > code {
|
||||||
|
padding: 0.15rem 0.4rem;
|
||||||
|
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: var(--surface);
|
||||||
|
|
||||||
|
color: var(--accent);
|
||||||
|
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"SFMono-Regular",
|
||||||
|
Consolas,
|
||||||
|
monospace;
|
||||||
|
|
||||||
|
font-size: 0.82em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
|
||||||
|
.prose pre {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 1.25rem 1.5rem;
|
||||||
|
|
||||||
|
overflow-x: auto;
|
||||||
|
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: #070707;
|
||||||
|
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"SFMono-Regular",
|
||||||
|
Consolas,
|
||||||
|
monospace;
|
||||||
|
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
|
||||||
* {
|
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: #292929 var(--bg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Motion */
|
.prose pre code {
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
color: var(--text);
|
||||||
html {
|
font-size: inherit;
|
||||||
scroll-behavior: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*,
|
|
||||||
*::before,
|
/* Horizontal rule */
|
||||||
*::after {
|
|
||||||
animation-duration: 0.01ms !important;
|
.prose hr {
|
||||||
animation-iteration-count: 1 !important;
|
margin: 3rem 0;
|
||||||
transition-duration: 0.01ms !important;
|
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Images */
|
||||||
|
|
||||||
|
.prose img {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
margin: 2rem 0;
|
||||||
|
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
|
||||||
|
.prose table {
|
||||||
|
width: 100%;
|
||||||
|
margin: 2rem 0;
|
||||||
|
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose th,
|
||||||
|
.prose td {
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose th {
|
||||||
|
background: var(--surface);
|
||||||
|
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"SFMono-Regular",
|
||||||
|
Consolas,
|
||||||
|
monospace;
|
||||||
|
|
||||||
|
font-size: 0.7rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose td {
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Strong / emphasis */
|
||||||
|
|
||||||
|
.prose strong {
|
||||||
|
color: var(--text);
|
||||||
|
font-weight: 650;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose em {
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Definition-style spacing */
|
||||||
|
|
||||||
|
.prose dl {
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose dt {
|
||||||
|
margin-top: 1rem;
|
||||||
|
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose dd {
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Mobile */
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.prose {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose h1 {
|
||||||
|
font-size: 1.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose h2 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose pre {
|
||||||
|
margin-left: -0.5rem;
|
||||||
|
margin-right: -0.5rem;
|
||||||
|
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose table {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ─────────────────────────────────────────────
|
||||||
|
Markdown / Article typography
|
||||||
|
───────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.markdown {
|
||||||
|
max-width: none;
|
||||||
|
color: var(--text);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown > *:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown > *:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Headings */
|
||||||
|
|
||||||
|
.markdown h1,
|
||||||
|
.markdown h2,
|
||||||
|
.markdown h3,
|
||||||
|
.markdown h4 {
|
||||||
|
color: var(--text);
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.025em;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1 {
|
||||||
|
margin-top: 3rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
font-size: 2.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h2 {
|
||||||
|
margin-top: 3rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding-bottom: 0.65rem;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
font-size: 1.65rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h3 {
|
||||||
|
margin-top: 2.25rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h4 {
|
||||||
|
margin-top: 1.75rem;
|
||||||
|
margin-bottom: 0.65rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Paragraphs */
|
||||||
|
|
||||||
|
.markdown p {
|
||||||
|
margin: 1.15rem 0;
|
||||||
|
color: #c4c4c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strong / emphasis */
|
||||||
|
|
||||||
|
.markdown strong {
|
||||||
|
color: var(--text);
|
||||||
|
font-weight: 650;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown em {
|
||||||
|
color: #d0d0d0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Links */
|
||||||
|
|
||||||
|
.markdown a {
|
||||||
|
color: var(--accent);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: color-mix(
|
||||||
|
in srgb,
|
||||||
|
var(--accent) 35%,
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
text-underline-offset: 3px;
|
||||||
|
transition:
|
||||||
|
text-decoration-color 150ms ease,
|
||||||
|
opacity 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown a:hover {
|
||||||
|
text-decoration-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lists */
|
||||||
|
|
||||||
|
.markdown ul,
|
||||||
|
.markdown ol {
|
||||||
|
margin: 1.25rem 0;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
color: #c4c4c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown ul {
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown ol {
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown li {
|
||||||
|
margin: 0.45rem 0;
|
||||||
|
padding-left: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown li::marker {
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown li > ul,
|
||||||
|
.markdown li > ol {
|
||||||
|
margin-top: 0.45rem;
|
||||||
|
margin-bottom: 0.45rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inline code */
|
||||||
|
|
||||||
|
.markdown :not(pre) > code {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: var(--surface);
|
||||||
|
padding: 0.15rem 0.4rem;
|
||||||
|
color: var(--accent);
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"SFMono-Regular",
|
||||||
|
Consolas,
|
||||||
|
"Liberation Mono",
|
||||||
|
monospace;
|
||||||
|
font-size: 0.82em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code blocks */
|
||||||
|
|
||||||
|
.markdown pre {
|
||||||
|
position: relative;
|
||||||
|
overflow-x: auto;
|
||||||
|
margin: 1.75rem 0;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
background: #050505;
|
||||||
|
padding: 1.25rem 1.35rem;
|
||||||
|
color: #d8d8d8;
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"SFMono-Regular",
|
||||||
|
Consolas,
|
||||||
|
"Liberation Mono",
|
||||||
|
monospace;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown pre code {
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Blockquotes */
|
||||||
|
|
||||||
|
.markdown blockquote {
|
||||||
|
margin: 1.75rem 0;
|
||||||
|
border-left: 2px solid var(--accent);
|
||||||
|
background: var(--surface);
|
||||||
|
padding: 1rem 1.25rem;
|
||||||
|
color: #bdbdbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown blockquote p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Horizontal rule */
|
||||||
|
|
||||||
|
.markdown hr {
|
||||||
|
margin: 3rem 0;
|
||||||
|
border: 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
|
||||||
|
.markdown table {
|
||||||
|
width: 100%;
|
||||||
|
margin: 1.75rem 0;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown thead {
|
||||||
|
background: var(--surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown th,
|
||||||
|
.markdown td {
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 0.7rem 0.8rem;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown th {
|
||||||
|
color: var(--text);
|
||||||
|
font-family:
|
||||||
|
"JetBrains Mono",
|
||||||
|
"SFMono-Regular",
|
||||||
|
Consolas,
|
||||||
|
monospace;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown td {
|
||||||
|
color: #bdbdbd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Images */
|
||||||
|
|
||||||
|
.markdown img {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
margin: 2rem auto;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small screens */
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.markdown {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h1 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown h2 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown pre {
|
||||||
|
margin-left: -1rem;
|
||||||
|
margin-right: -1rem;
|
||||||
|
border-left: 0;
|
||||||
|
border-right: 0;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.markdown table {
|
||||||
|
display: block;
|
||||||
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue