376 lines
12 KiB
TypeScript
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'm currently hosting an SMP (dm me on discord). Also I'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'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 "Mini Jame Gam #55", 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'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>
|
|
</>
|
|
);
|
|
}
|