dvorakmortonxd.dev/src/app/components/WebLayout.tsx

376 lines
12 KiB
TypeScript

"use client";
import Image from "next/image";
import type { ReactNode } from "react";
import JokerLogo from "./JokerLogo";
import ServiceButton from "./ServiceButton";
import ContributionHeatmap from "./ContributionHeatmap";
import Clock from "./Clock";
import { useTheme } from "./useTheme";
import { useColorScheme } from "./useColorScheme";
import { socials, codingProjects, techProjects, friends } from "../data";
const NAV = [
{ id: "overview", label: "Overview" },
{ id: "services", label: "Services" },
{ id: "activity", label: "Activity" },
{ id: "projects", label: "Projects" },
{ id: "hardware", label: "Hardware" },
{ id: "friends", label: "Friends" },
];
function Section({
id,
eyebrow,
title,
children,
className,
}: {
id?: string;
eyebrow: string;
title: string;
children: ReactNode;
className?: string;
}) {
return (
<section id={id} className={"web-section glass" + (className ? ` ${className}` : "")}>
<header className="web-section-head">
<span className="web-eyebrow">{eyebrow}</span>
<h2 className="web-section-title">{title}</h2>
</header>
{children}
</section>
);
}
function Socials() {
return (
<div className="social-buttons">
{socials.map((s) => (
<a
key={s.name}
href={s.url}
target="_blank"
rel="noopener noreferrer"
className="social-button"
>
<Image src={s.icon} alt={s.name} width={16} height={16} className="social-icon" />
<span className="social-label">{s.name}</span>
</a>
))}
</div>
);
}
function Services() {
return (
<div className="services-buttons services-main">
<ServiceButton
url="https://proxmox.dvorakmortonxd.dev/"
className="proxmox"
icon="🖥️"
name="Proxmox"
desc="Server Management"
access="private"
disabled
/>
<ServiceButton
url="https://ai.dvorakmortonxd.dev/"
className="ai"
icon="🦾"
name="Llama.cpp"
desc="Local AI Server"
access="on_request"
/>
<ServiceButton
url="https://jelly.dvorakmortonxd.dev/"
className="jellyfin"
icon="🎬"
name="Jellyfin"
desc="Local Media Server"
access="on_request"
/>
<ServiceButton
url="https://discord.gg/vyvhk7d8bX"
checkUrl="minecraft://mc.dvorakmortonxd.dev:25565"
className="pterodactyl"
icon="🎮"
name="SMP"
desc="My Survival Minecraft Server"
access="on_request"
/>
<ServiceButton
url="https://navidrome.dvorakmortonxd.dev/"
className="funkwhale"
icon="🎸"
name="Navidrome"
desc="Music Streaming"
access="private"
/>
<ServiceButton
url="https://git.dvorakmortonxd.dev"
className="gitdxd"
icon="🐙"
name="GitDXD"
desc="Best Git Hosting OAT"
access="public"
/>
</div>
);
}
function Gym() {
const lifts = [
{ icon: "/squat.svg", label: "SQUAT", weight: "125kg", date: "5.1.2025" },
{ icon: "/bench.svg", label: "BENCH", weight: "111kg", date: "29.5.2026" },
{ icon: "/deadlift.svg", label: "DEADLIFT", weight: "165kg", date: "17.12.2024" },
];
return (
<div className="gym-grid">
{lifts.map((l) => (
<div key={l.label} className="gym-item">
<Image src={l.icon} alt={l.label} width={48} height={48} className="gym-icon" />
<div className="gym-label">{l.label}</div>
<div className="gym-weight">{l.weight}</div>
<div className="gym-date">{l.date}</div>
</div>
))}
</div>
);
}
function FeatureShot({
src,
alt,
width,
height,
}: {
src: string;
alt: string;
width: number;
height: number;
}) {
return (
<div className="web-shot">
<Image src={src} alt={alt} width={width} height={height} />
</div>
);
}
export default function WebLayout() {
const { toggle } = useTheme();
const { scheme, toggle: toggleScheme } = useColorScheme();
const dark = scheme === "dark";
return (
<>
<div className="web-bg" aria-hidden="true" />
<div className="web-root">
<aside className="web-sidebar glass">
<div className="web-brand">
<JokerLogo />
<div className="web-brand-text">
<span className="web-brand-name">dvorakmortonxd.dev</span>
<span className="web-brand-tag">I use gentoo btw</span>
</div>
</div>
<nav className="web-nav" aria-label="Sections">
{NAV.map((n) => (
<a key={n.id} href={`#${n.id}`}>
{n.label}
</a>
))}
</nav>
<div className="web-controls">
<button
type="button"
className="web-ctl"
onClick={toggleScheme}
aria-pressed={dark}
title="Toggle light / dark mode"
>
<span className="web-ctl-icon" aria-hidden="true">
{dark ? "☾" : "☀"}
</span>
<span className="web-ctl-label">{dark ? "Dark" : "Light"}</span>
<span className={"web-switch" + (dark ? " on" : "")} aria-hidden="true">
<span className="web-switch-knob" />
</span>
</button>
<button
type="button"
className="web-ctl web-ctl-desktop"
onClick={toggle}
title="Switch to the desktop theme"
>
<span className="web-ctl-icon" aria-hidden="true">
❖
</span>
<span className="web-ctl-label">Desktop</span>
</button>
</div>
<div className="web-side-foot">
<Clock className="web-clock" />
<a href="mailto:dvorak@dvorakmortonxd.dev">dvorak@dvorakmortonxd.dev</a>
</div>
</aside>
<main className="web-main">
<header id="overview" className="web-hero glass">
<span className="web-eyebrow">About me</span>
<h1 className="web-title">Martin Dvořák</h1>
<p className="web-lead">
Welcome to my personal website! Here I show off my projects and the hardware I
own, as well as my self-hosted services.
</p>
<div className="web-hero-actions">
<a className="web-pill" href="#projects">
View projects
</a>
<a className="web-pill ghost" href="#services">
Self-hosted services
</a>
</div>
<div className="web-social-strip">
<span className="web-eyebrow">Find me</span>
<Socials />
</div>
</header>
<div className="web-quick">
<article id="now" className="web-tile glass">
<h3 className="web-tile-title">Right now</h3>
<p className="web-tile-text">
I&#39;m currently hosting an SMP (dm me on discord). Also I&#39;m pretty much
cooking daily, because im bulking through out the non-summer seasons. And me
and my pal <a href="https://skopec.dev">Pepa</a> are working on an education
app so we can study more efficiently, It&#39;s called{" "}
<a href="https://git.dvorakmortonxd.dev/edu/maturita.c">maturita.c</a>!
</p>
</article>
<article className="web-tile glass">
<h3 className="web-tile-title">Gym PRs</h3>
<Gym />
<p className="web-tile-note">Current squat / bench / deadlift PRs at ~73kg BW.</p>
</article>
</div>
<Section id="services" eyebrow="SELF-HOSTED" title="Services">
<Services />
</Section>
<Section id="activity" eyebrow="GitDXD" title="Contribution activity">
<ContributionHeatmap variant="web" />
</Section>
<Section id="projects" eyebrow="Portfolio" title="Things I've worked on">
<div className="project-grid">
{codingProjects.map((project, idx) => (
<a
key={idx}
href={project.url}
target="_blank"
rel="noopener noreferrer"
className="project-card"
>
<div
className="project-image"
style={{ backgroundImage: `url(${project.img})` }}
/>
<h4 className="project-title">{project.title}</h4>
<p className="project-desc">{project.desc}</p>
</a>
))}
</div>
</Section>
<Section id="hardware" eyebrow="My gear" title="Hardware I own">
<div className="project-grid">
{techProjects.map((project) => (
<div key={project.title} className="project-card">
<div
className="project-image"
style={{ backgroundImage: `url(${project.image})` }}
/>
<h4 className="project-title">{project.title}</h4>
<p className="project-desc">{project.desc}</p>
</div>
))}
</div>
</Section>
<div className="web-split">
<Section eyebrow="REVIVAL.INC" title="Revival Inc." className="web-feature">
<FeatureShot
src="/revivalinc.webp"
alt="Revival Inc. thumbnail"
width={768}
height={576}
/>
<p className="web-feature-text">
A game I made for the game jam &#34;Mini Jame Gam #55&#34;, the theme was
Necromancy and the special item was Milk, the game also includes a tutorial so
if you wanna try it do it. Check it out at{" "}
<a href="https://martin-dv.itch.io/revival-inc">itch.io</a> or play{" "}
<a href="https://dvorakmortonxd.dev/revival-inc">here</a>.
</p>
</Section>
<Section eyebrow="RustyWolf" title="Introducing RustyWolf" className="web-feature">
<FeatureShot
src="/RustyWolfPreview.webp"
alt="RustyWolf Browser Preview"
width={1280}
height={720}
/>
<p className="web-feature-text">
A lightweight browser made in Rust with WebKitGTK. It&#39;s the successor to my
previous project Venturesome, aiming to provide a fast and minimalist browsing
experience — perfect for old machines that struggle with modern browsers.
Check it out on{" "}
<a href="https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf">GitDXD</a>.
</p>
</Section>
</div>
<Section id="friends" eyebrow="Links" title="Friend's websites and projects">
<div className="services-buttons">
{friends.map((friend, idx) => (
<ServiceButton
key={idx}
url={friend.realUrl || friend.url}
className="friend"
icon={
<Image
src={friend.img}
alt={friend.name}
width={68}
height={68}
className="friend-icon"
style={{ borderRadius: "50%" }}
/>
}
name={friend.name}
desc={friend.desc}
/>
))}
</div>
</Section>
<footer className="web-footer glass">
<span className="web-footer-label">v2.2.2</span>
© 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just
follow the GPL3.0 License)
</footer>
</main>
</div>
</>
);
}