feat: styles

This commit is contained in:
2026-04-02 12:42:21 +02:00
parent 462d6bf289
commit fcf3dc74a8
14 changed files with 336 additions and 275 deletions

View File

@@ -1,11 +1,26 @@
import { useEffect, useState, type ReactNode } from "react";
import NavBar from "./NavBar";
import { useNavigate } from "react-router-dom";
import { TooltipProvider } from "@/components/ui/tooltip";
import { Toaster } from "@/components/ui/sonner";
import frameSvg from "@/assets/frame.themed.svg";
const TITLE = `
▄▄▄▄███▄▄▄▄ ▄█ ▄████████ ▄████████ ▄██████▄ ███▄▄▄▄ ▄██████▄ ▄▄▄▄███▄▄▄▄ ▄█ ▄████████ ▄██████▄ ███▄▄▄▄
▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ███ ███ ███ ███ ███▀▀▀██▄ ███ ███ ▄██▀▀▀███▀▀▀██▄ ███ ███ ███ ███ ███ ███▀▀▀██▄
███ ███ ███ ███▌ ███ █▀ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███▌ ███ █▀ ███ ███ ███ ███
███ ███ ███ ███▌ ███ ▄███▄▄▄▄██▀ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███▌ ███ ███ ███ ███ ███
███ ███ ███ ███▌ ███ ▀▀███▀▀▀▀▀ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███▌ ███ ███ ███ ███ ███
███ ███ ███ ███ ███ █▄ ▀███████████ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ █▄ ███ ███ ███ ███
███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███ ███
▀█ ███ █▀ █▀ ████████▀ ███ ███ ▀██████▀ ▀█ █▀ ▀██████▀ ▀█ ███ █▀ █▀ ████████▀ ▀██████▀ ▀█ █▀
███ ███
`;
function toRoman(n: number): string {
const vals = [1000,900,500,400,100,90,50,40,10,9,5,4,1];
const syms = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"];
const vals = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
const syms = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"];
let r = "";
for (let i = 0; i < vals.length; i++) {
while (n >= vals[i]) { r += syms[i]; n -= vals[i]; }
@@ -28,15 +43,48 @@ function RomanClock() {
}
export default function AppShell({ children }: { children: ReactNode }) {
const navigate = useNavigate();
return (
<TooltipProvider>
<div className="flex flex-col h-screen bg-background text-foreground">
<NavBar />
<main className="flex-1 overflow-auto">{children}</main>
<main className="flex-1 overflow-auto">
<div className="relative max-w-5xl min-w-5xl mx-auto min-h-full">
{/* Frame SVG — background */}
<img
src={frameSvg}
alt=""
aria-hidden
className="absolute inset-0 w-full min-w-full pointer-events-none select-none"
style={{ zIndex: 0, objectFit: "fill" }}
/>
{/* Top hole — ASCII title */}
<div
className="relative z-10 flex flex-col cursor-pointer overflow-hidden"
style={{ paddingTop: 65, height: 185, paddingLeft: 60, paddingRight: 500, paddingBottom: 25 }}
onClick={() => navigate("/")}
>
<pre
className="select-none text-primary/70 hover:text-primary transition-colors whitespace-pre origin-center"
style={{ height: 60, fontSize: 6, lineHeight: 1.05, transform: "scale(0.50)", transformOrigin: "left center", alignContent: "center" }}
>
{TITLE}
</pre>
<span className="font-mono text-[10px] text-muted-foreground"><RomanClock /></span>
</div>
{/* Bottom hole — main content */}
<div
className="relative z-10 overflow-auto"
style={{ marginLeft: 12, marginRight: 68, width: 843, height: 1030, paddingTop: 8, paddingBottom: 20 }}
>
{children}
</div>
</div>
</main>
<footer className="flex items-center justify-center gap-3 text-[10px] text-muted-foreground py-4 shrink-0 tracking-widest uppercase">
<span>Built with hubris by the demiurge · MMXXVI</span>
<span className="text-muted-foreground/50"></span>
<span className="font-mono"><RomanClock /></span>
<span>Becoming with hubris · MMXXVI</span>
</footer>
</div>
<Toaster />

View File

@@ -1,46 +1,4 @@
import { useNavigate } from "react-router-dom";
import baldothSvg from "@/assets/baldoth.min.svg";
const TITLE = ` █████ ██ ██
██████ █████ █████ █
██ █ █ █████ █████ ███
█ █ █ █ ██ █ ██ █
█ █ █ █ ███ ████ ████ ████
██ ██ █ █ ███ ████ ████ ████ █ █ ███ ████ ████ █ ███ ████ ████ ████ ███ ████ █ ███ ████ ████
██ ██ █ █ ███ █ ███ █ ██ ████ █ ████ ████ ████ █ █ ████ ███ ████ ███ █ ███ █ ███ █ █ ████ ████ ████ █
██ ██ █ █ ██ █ ████ ██ ██ ██ ██ ████ ██ ██ ██ ████ ████ ██ █ ████ ██ ██ ██ ████
██ ██ █ █ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
██ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
█ ██ █ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
█ █ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
████ █ ██ ██ ███ █ ███ ██████ ██ ██ ██████ ██ ██ ██ ██ ███ █ ██████ ██ ██
█ █████ ██ ███ █ ███████ ███ ████ ███ ███ ████ ███ ███ ███ ███ █ ███████ ████ ███ ███
█ ██ ███ █████ ███ ███ ███ ███ ███ ███ █████ ███ ███
██`;
// NavBar removed — frame.svg is the visual wrapper now
export default function NavBar() {
const navigate = useNavigate();
return (
<div className="flex flex-col items-center pt-6 pb-3 shrink-0 gap-2">
<button
onClick={() => navigate("/")}
className="hover:opacity-80 transition-opacity cursor-pointer flex flex-col items-center gap-2"
title="Go to Dashboard"
>
<div
className="h-28 w-28"
style={{
backgroundColor: "var(--primary)",
opacity: 0.5,
mask: `url(${baldothSvg}) center/contain no-repeat`,
WebkitMask: `url(${baldothSvg}) center/contain no-repeat`,
}}
/>
<pre className="text-[4px] leading-[1] tracking-tighter select-none text-primary/40">{TITLE}</pre>
</button>
</div>
);
return null;
}