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)]">
|
||||
<div class="mx-auto flex max-w-7xl items-center justify-between px-6 py-5 lg:px-8">
|
||||
|
||||
<header class="relative z-50 border-b border-[var(--border)]">
|
||||
<div
|
||||
class="mx-auto flex h-16 max-w-7xl items-center justify-between px-6 lg:px-8"
|
||||
>
|
||||
<!-- Logo -->
|
||||
<a
|
||||
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>
|
||||
|
||||
<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
|
||||
href="/projects"
|
||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
||||
href="/#projects"
|
||||
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
|
||||
href="#lab"
|
||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
||||
href="/#lab"
|
||||
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
|
||||
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
|
||||
href="#about"
|
||||
class="text-[var(--muted)] transition-colors hover:text-[var(--text)]"
|
||||
href="/#about"
|
||||
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>
|
||||
</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
|
||||
href="https://www.donationalerts.com/r/alastor3301"
|
||||
target="_blank"
|
||||
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>
|
||||
|
||||
<!-- TODO: заменить # на GitHub -->
|
||||
<a
|
||||
href="https://github.com/Trytonottry"
|
||||
target="_blank"
|
||||
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 ↗
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
|
||||
<button
|
||||
class="font-mono text-xs text-[var(--muted)] md:hidden"
|
||||
aria-label="Open menu"
|
||||
>
|
||||
MENU
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
```
|
||||
|
||||
</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
|
||||
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="mb-8 flex items-center gap-3 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]">
|
||||
<!-- Status -->
|
||||
<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="absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--accent)] opacity-40"></span>
|
||||
<span class="relative inline-flex h-2 w-2 rounded-full bg-[var(--accent)]"></span>
|
||||
<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>
|
||||
|
||||
SYSTEM ONLINE
|
||||
|
||||
<span class="text-[var(--border)]">/</span>
|
||||
|
||||
<span>ALASTOR.LOL</span>
|
||||
</div>
|
||||
|
||||
<div class="mb-6 font-mono text-[10px] uppercase tracking-[0.25em] text-[var(--muted)]">
|
||||
SYSTEMS / AUTOMATION / INFRASTRUCTURE
|
||||
</div>
|
||||
|
||||
<!-- Main title -->
|
||||
<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.
|
||||
<br />
|
||||
<span class="block">BUILD.</span>
|
||||
|
||||
<span class="block text-[var(--muted)]">
|
||||
BREAK.
|
||||
<br />
|
||||
<span class="text-[var(--accent)]">UNDERSTAND.</span>
|
||||
<br />
|
||||
REPEAT.
|
||||
</span>
|
||||
|
||||
<span class="block">
|
||||
<span class="text-[var(--accent)]">
|
||||
UNDERSTAND.
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<span class="block">REPEAT.</span>
|
||||
</h1>
|
||||
|
||||
<div class="mt-10 flex flex-col gap-8 sm:flex-row sm:items-end sm:justify-between">
|
||||
|
||||
<p class="max-w-xl text-base leading-7 text-[var(--muted)] sm:text-lg">
|
||||
<!-- Description -->
|
||||
<p
|
||||
class="mt-10 max-w-xl text-base leading-7 text-[var(--muted)] sm:text-lg"
|
||||
>
|
||||
Systems administrator and infrastructure engineer.
|
||||
I build infrastructure, automate systems and investigate
|
||||
things when they inevitably break.
|
||||
</p>
|
||||
|
||||
<div class="hidden font-mono text-right text-[10px] leading-5 text-[var(--muted)] sm:block">
|
||||
<div>ALASTOR.LOL</div>
|
||||
<div>SYS / 001</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="mt-10 flex flex-wrap gap-3">
|
||||
|
||||
<a
|
||||
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>
|
||||
</a>
|
||||
|
||||
<a
|
||||
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>
|
||||
|
||||
</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>
|
||||
|
||||
<!-- RIGHT -->
|
||||
<div class="flex items-end">
|
||||
|
||||
<div class="w-full border border-[var(--border)] bg-[var(--surface)] font-mono text-xs">
|
||||
|
||||
<div class="flex items-center justify-between border-b border-[var(--border)] px-4 py-3">
|
||||
|
||||
<div
|
||||
class="w-full border border-[var(--border)] bg-[var(--surface)] font-mono text-xs shadow-2xl shadow-black/20"
|
||||
>
|
||||
<!-- 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">
|
||||
<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)]">
|
||||
SYSTEM STATUS
|
||||
|
|
@ -85,102 +134,108 @@
|
|||
<span class="text-[var(--accent)]">
|
||||
OPERATIONAL
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="p-5">
|
||||
|
||||
<div class="mb-6 text-[10px] uppercase tracking-[0.2em] text-[var(--muted)]">
|
||||
CAPABILITIES
|
||||
<!-- Terminal prompt -->
|
||||
<div class="mb-7 text-[var(--muted)]">
|
||||
<span class="text-[var(--accent)]">$</span>
|
||||
./check-system.sh
|
||||
</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">
|
||||
<span class="text-[var(--muted)]">Linux</span>
|
||||
<span class="text-[var(--accent)]">●</span>
|
||||
</div>
|
||||
<span class="text-[var(--muted)]">
|
||||
Infrastructure
|
||||
</span>
|
||||
|
||||
<div class="h-px bg-[var(--border)]"></div>
|
||||
<span class="text-[var(--accent)]">
|
||||
● OK
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-[var(--muted)]">Infrastructure</span>
|
||||
<span class="text-[var(--accent)]">●</span>
|
||||
</div>
|
||||
<span class="text-[var(--muted)]">
|
||||
Networking
|
||||
</span>
|
||||
|
||||
<div class="h-px bg-[var(--border)]"></div>
|
||||
<span class="text-[var(--accent)]">
|
||||
● OK
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-[var(--muted)]">Networking</span>
|
||||
<span class="text-[var(--accent)]">●</span>
|
||||
<span class="text-[var(--muted)]">
|
||||
Automation
|
||||
</span>
|
||||
|
||||
<span class="text-[var(--accent)]">
|
||||
● OK
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-px bg-[var(--border)]"></div>
|
||||
|
||||
<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">
|
||||
|
||||
<!-- Homelab -->
|
||||
<div class="mt-8 border-t border-[var(--border)] pt-5">
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<span class="text-[var(--muted)]">HOMELAB</span>
|
||||
<span class="text-[var(--accent)]">87%</span>
|
||||
<span class="text-[var(--muted)]">
|
||||
HOMELAB
|
||||
</span>
|
||||
|
||||
<span class="text-[var(--accent)]">
|
||||
87%
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="h-1 bg-[var(--border)]">
|
||||
<div class="h-full w-[87%] bg-[var(--accent)]"></div>
|
||||
<div class="h-1 overflow-hidden bg-[var(--border)]">
|
||||
<div
|
||||
class="h-full w-[87%] bg-[var(--accent)]"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-8 grid grid-cols-2 gap-4 border-t border-[var(--border)] pt-6">
|
||||
|
||||
<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)]">
|
||||
|
||||
<!-- Footer -->
|
||||
<div
|
||||
class="mt-7 border-t border-[var(--border)] pt-5 text-[10px] text-[var(--muted)]"
|
||||
>
|
||||
<div class="flex justify-between">
|
||||
<span>UPTIME</span>
|
||||
<span class="text-[var(--text)]">99.9%</span>
|
||||
<span>HOSTS</span>
|
||||
<span>06</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 flex justify-between">
|
||||
<span>STATUS</span>
|
||||
<span class="text-[var(--accent)]">BUILDING</span>
|
||||
<span>SERVICES</span>
|
||||
<span>30+</span>
|
||||
</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>
|
||||
|
||||
<!-- 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 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="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="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
|
||||
</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
|
||||
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
|
||||
id="status-dot"
|
||||
|
|
@ -19,31 +29,53 @@
|
|||
</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">
|
||||
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]">
|
||||
<!-- Current state -->
|
||||
<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
|
||||
</div>
|
||||
|
||||
<div class="mt-3 text-sm leading-relaxed">
|
||||
Building things,<br />
|
||||
break fixing things.
|
||||
<div class="mt-4 flex items-start gap-3">
|
||||
<span class="mt-2 h-1 w-1 shrink-0 bg-[var(--accent)]"></span>
|
||||
|
||||
<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 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="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
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<div
|
||||
<span
|
||||
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
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||
01
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a
|
||||
|
|
@ -51,35 +83,63 @@
|
|||
href="#"
|
||||
target="_blank"
|
||||
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>
|
||||
</a>
|
||||
<div class="flex items-start gap-3">
|
||||
<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
|
||||
id="spotify-artist"
|
||||
class="mt-1 text-xs text-[var(--muted)]"
|
||||
class="mt-1 truncate text-xs text-[var(--muted)]"
|
||||
>
|
||||
Spotify
|
||||
</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
|
||||
</span>
|
||||
|
||||
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||
30s
|
||||
</span>
|
||||
</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="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
|
||||
</div>
|
||||
</span>
|
||||
|
||||
<div
|
||||
<span
|
||||
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
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||
02
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<a
|
||||
|
|
@ -87,80 +147,127 @@
|
|||
href="#"
|
||||
target="_blank"
|
||||
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>
|
||||
</a>
|
||||
<div class="flex items-start gap-3">
|
||||
<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
|
||||
</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
|
||||
</span>
|
||||
|
||||
<span class="font-mono text-[8px] text-[var(--muted)]">
|
||||
60s
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="py-7 md:pl-8">
|
||||
<div class="font-mono text-[10px] uppercase tracking-widest text-[var(--muted)]">
|
||||
<!-- Building -->
|
||||
<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
|
||||
</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
|
||||
</div>
|
||||
|
||||
<div class="mt-1 text-xs text-[var(--muted)]">
|
||||
This website
|
||||
</div>
|
||||
|
||||
<div class="mt-3 font-mono text-[9px] uppercase tracking-widest text-[var(--muted)]">
|
||||
ASTRO · TYPESCRIPT
|
||||
</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>
|
||||
|
||||
<!-- 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>
|
||||
SPOTIFY / STEAM / LOCAL
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const spotifyTitle =
|
||||
document.querySelector("#spotify-title");
|
||||
|
||||
const spotifyArtist =
|
||||
document.querySelector("#spotify-artist");
|
||||
|
||||
const spotifyTitle = document.querySelector("#spotify-title");
|
||||
const spotifyArtist = document.querySelector("#spotify-artist");
|
||||
const spotifyLink =
|
||||
document.querySelector("#spotify-link") as HTMLAnchorElement | null;
|
||||
const spotifyIndicator = document.querySelector("#spotify-indicator");
|
||||
|
||||
const spotifyIndicator =
|
||||
document.querySelector("#spotify-indicator");
|
||||
|
||||
const steamGame =
|
||||
document.querySelector("#steam-game");
|
||||
|
||||
const steamGame = document.querySelector("#steam-game");
|
||||
const steamLink =
|
||||
document.querySelector("#steam-link") as HTMLAnchorElement | null;
|
||||
const steamIndicator = document.querySelector("#steam-indicator");
|
||||
|
||||
const steamIndicator =
|
||||
document.querySelector("#steam-indicator");
|
||||
|
||||
const statusText =
|
||||
document.querySelector("#status-text");
|
||||
|
||||
const statusDot =
|
||||
document.querySelector("#status-dot");
|
||||
const statusText = document.querySelector("#status-text");
|
||||
const statusDot = document.querySelector("#status-dot");
|
||||
const lastUpdate = document.querySelector("#last-update");
|
||||
|
||||
function updateOverallStatus() {
|
||||
const spotifyLive =
|
||||
spotifyIndicator?.classList.contains("inline");
|
||||
|
||||
const steamLive =
|
||||
steamIndicator?.classList.contains("inline");
|
||||
|
||||
if (spotifyLive || steamLive) {
|
||||
statusText!.textContent = "LIVE";
|
||||
|
||||
statusDot!.classList.remove("bg-[var(--muted)]");
|
||||
statusDot!.classList.add(
|
||||
"bg-[var(--accent)]",
|
||||
|
|
@ -168,6 +275,7 @@
|
|||
);
|
||||
} else {
|
||||
statusText!.textContent = "IDLE";
|
||||
|
||||
statusDot!.classList.remove(
|
||||
"bg-[var(--accent)]",
|
||||
"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() {
|
||||
try {
|
||||
const response = await fetch("/api/spotify", {
|
||||
|
|
@ -197,6 +317,7 @@
|
|||
spotifyIndicator?.classList.add("hidden");
|
||||
|
||||
updateOverallStatus();
|
||||
updateTimestamp();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -211,6 +332,7 @@
|
|||
spotifyIndicator?.classList.add("inline");
|
||||
|
||||
updateOverallStatus();
|
||||
updateTimestamp();
|
||||
} catch {
|
||||
spotifyTitle!.textContent = "Unavailable";
|
||||
spotifyArtist!.textContent = "Spotify";
|
||||
|
|
@ -220,6 +342,7 @@
|
|||
spotifyIndicator?.classList.add("hidden");
|
||||
|
||||
updateOverallStatus();
|
||||
updateTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -243,6 +366,7 @@
|
|||
steamIndicator?.classList.add("hidden");
|
||||
|
||||
updateOverallStatus();
|
||||
updateTimestamp();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -256,6 +380,7 @@
|
|||
steamIndicator?.classList.add("inline");
|
||||
|
||||
updateOverallStatus();
|
||||
updateTimestamp();
|
||||
} catch {
|
||||
steamGame!.textContent = "Unavailable";
|
||||
steamLink?.removeAttribute("href");
|
||||
|
|
@ -264,6 +389,7 @@
|
|||
steamIndicator?.classList.add("hidden");
|
||||
|
||||
updateOverallStatus();
|
||||
updateTimestamp();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
---
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
|
|
@ -11,91 +10,65 @@ const projects = await getCollection("projects", ({ data }) => {
|
|||
id="projects"
|
||||
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 -->
|
||||
|
||||
<div class="flex flex-col gap-8 md:flex-row md:items-end md:justify-between">
|
||||
<div class="grid gap-10 lg:grid-cols-[1fr_360px] lg:items-end">
|
||||
|
||||
<div>
|
||||
<div class="font-mono text-[10px] tracking-[0.25em] text-[var(--muted)]">
|
||||
02 / PROJECTS
|
||||
<div class="flex items-center gap-3 font-mono text-[10px] tracking-[0.25em] text-[var(--muted)]">
|
||||
<span class="text-[var(--accent)]">02</span>
|
||||
<span>/</span>
|
||||
<span>PROJECTS</span>
|
||||
</div>
|
||||
|
||||
<h2 class="mt-6 text-4xl font-bold tracking-tight sm:text-6xl">
|
||||
Things I build.
|
||||
<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
|
||||
<span class="text-[var(--muted)]"> build.</span>
|
||||
</h2>
|
||||
</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.
|
||||
Some are production systems. Some are glorified
|
||||
learning exercises.
|
||||
Some are production systems. Some are glorified learning
|
||||
exercises.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Projects -->
|
||||
|
||||
<div class="mt-16 border-t border-[var(--border)]">
|
||||
<!-- Project grid -->
|
||||
<div class="mt-20 grid gap-px border border-[var(--border)] bg-[var(--border)] md:grid-cols-2">
|
||||
|
||||
{
|
||||
projects.map((project, index) => (
|
||||
<a
|
||||
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">
|
||||
|
||||
<!-- Number -->
|
||||
|
||||
<div class="font-mono text-[10px] text-[var(--muted)]">
|
||||
<!-- Background number -->
|
||||
<div
|
||||
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)]"
|
||||
>
|
||||
{String(index + 1).padStart(2, "0")}
|
||||
</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">
|
||||
|
||||
<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="flex items-center justify-between">
|
||||
|
||||
<div class="font-mono text-[10px] tracking-[0.2em] text-[var(--muted)]">
|
||||
PROJECT {String(index + 1).padStart(2, "0")}
|
||||
</div>
|
||||
|
||||
<p class="mt-3 max-w-2xl text-sm leading-6 text-[var(--muted)]">
|
||||
{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">
|
||||
<div class="flex items-center gap-2 font-mono text-[9px] uppercase tracking-[0.15em]">
|
||||
|
||||
<span
|
||||
class:list={[
|
||||
|
|
@ -121,13 +94,51 @@ const projects = await getCollection("projects", ({ data }) => {
|
|||
</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)]">
|
||||
VIEW →
|
||||
<p class="mt-5 max-w-lg text-sm leading-7 text-[var(--muted)]">
|
||||
{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>
|
||||
))
|
||||
}
|
||||
|
||||
</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>
|
||||
|
||||
|
|
@ -141,18 +152,22 @@ const projects = await getCollection("projects", ({ data }) => {
|
|||
|
||||
|
||||
<!-- 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">
|
||||
|
||||
<span>
|
||||
{projects.length} PROJECTS
|
||||
</span>
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="h-1.5 w-1.5 rounded-full bg-[var(--accent)]"></span>
|
||||
<span>{projects.length} PROJECTS</span>
|
||||
</div>
|
||||
|
||||
<a
|
||||
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>
|
||||
|
||||
</div>
|
||||
|
|
@ -161,3 +176,5 @@ const projects = await getCollection("projects", ({ data }) => {
|
|||
</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";
|
||||
|
||||
:root {
|
||||
|
|
@ -21,19 +22,7 @@ html {
|
|||
body {
|
||||
margin: 0;
|
||||
min-width: 320px;
|
||||
background:
|
||||
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;
|
||||
background: var(--bg);
|
||||
|
||||
font-family:
|
||||
Inter,
|
||||
|
|
@ -43,9 +32,6 @@ body {
|
|||
BlinkMacSystemFont,
|
||||
"Segoe UI",
|
||||
sans-serif;
|
||||
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
::selection {
|
||||
|
|
@ -58,16 +44,6 @@ a {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
button,
|
||||
a {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 1px solid var(--accent);
|
||||
outline-offset: 4px;
|
||||
}
|
||||
|
||||
.font-mono {
|
||||
font-family:
|
||||
"JetBrains Mono",
|
||||
|
|
@ -77,43 +53,591 @@ a {
|
|||
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 {
|
||||
background: var(--bg);
|
||||
.prose > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #292929;
|
||||
.prose > *:last-child {
|
||||
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-color: #292929 var(--bg);
|
||||
}
|
||||
|
||||
/* Motion */
|
||||
.prose pre code {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html {
|
||||
scroll-behavior: auto;
|
||||
color: var(--text);
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
|
||||
/* Horizontal rule */
|
||||
|
||||
.prose hr {
|
||||
margin: 3rem 0;
|
||||
|
||||
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