ui update!
This commit is contained in:
parent
cadbe8caa9
commit
d2f99c87b9
16 changed files with 3085 additions and 592 deletions
4
next-env.d.ts
vendored
4
next-env.d.ts
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/dev/types/routes.d.ts";
|
import "./.next/types/routes.d.ts";
|
||||||
import "./.next/dev/types/root-params.d.ts";
|
import "./.next/types/root-params.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|
|
||||||
BIN
public/wallpaper.jpg
Normal file
BIN
public/wallpaper.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
43
src/app/components/Clock.tsx
Normal file
43
src/app/components/Clock.tsx
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
function format(date: Date) {
|
||||||
|
return date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Clock({
|
||||||
|
className,
|
||||||
|
withSeconds = false,
|
||||||
|
}: {
|
||||||
|
className?: string;
|
||||||
|
withSeconds?: boolean;
|
||||||
|
}) {
|
||||||
|
const [now, setNow] = useState<Date | null>(() =>
|
||||||
|
typeof window === "undefined" ? null : new Date()
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const id = window.setInterval(
|
||||||
|
() => setNow(new Date()),
|
||||||
|
withSeconds ? 1000 : 10000
|
||||||
|
);
|
||||||
|
return () => window.clearInterval(id);
|
||||||
|
}, [withSeconds]);
|
||||||
|
|
||||||
|
const text = now
|
||||||
|
? withSeconds
|
||||||
|
? now.toLocaleTimeString([], {
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
})
|
||||||
|
: format(now)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={className} suppressHydrationWarning>
|
||||||
|
{text}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
77
src/app/components/IosHome.tsx
Normal file
77
src/app/components/IosHome.tsx
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { APPS, APP_BY_ID } from "./apps";
|
||||||
|
import Clock from "./Clock";
|
||||||
|
import { useTheme } from "./useTheme";
|
||||||
|
import { WALLPAPER } from "../data";
|
||||||
|
|
||||||
|
export default function IosHome() {
|
||||||
|
const { theme, toggle } = useTheme();
|
||||||
|
const [openId, setOpenId] = useState<string | null>(null);
|
||||||
|
const openApp = openId ? APP_BY_ID[openId] : null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="ios-root">
|
||||||
|
{/* iOS app view */}
|
||||||
|
{openApp ? (
|
||||||
|
<div className="ios-app-view">
|
||||||
|
<div className="ios-navbar">
|
||||||
|
<button type="button" className="ios-back" onClick={() => setOpenId(null)}>
|
||||||
|
‹ Home
|
||||||
|
</button>
|
||||||
|
<span className="ios-navbar-title">{openApp.title}</span>
|
||||||
|
<span className="ios-navbar-spacer" />
|
||||||
|
</div>
|
||||||
|
<div className="ios-app-body app-surface">{openApp.content}</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="ios-home"
|
||||||
|
style={{ backgroundImage: `url('${WALLPAPER}')` }}
|
||||||
|
>
|
||||||
|
<div className="ios-statusbar">
|
||||||
|
<span className="ios-status-time">
|
||||||
|
<Clock />
|
||||||
|
</span>
|
||||||
|
<span className="ios-status-icons" aria-hidden="true">
|
||||||
|
●●● ᯤ ▮
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="ios-theme-app"
|
||||||
|
onClick={toggle}
|
||||||
|
aria-label={`Switch to ${theme === "skeuo" ? "terminal" : "Aero"} theme`}
|
||||||
|
>
|
||||||
|
<span className="ios-theme-app-icon" aria-hidden="true">
|
||||||
|
{theme === "skeuo" ? "▚" : "❖"}
|
||||||
|
</span>
|
||||||
|
<span className="ios-theme-app-label">{theme === "skeuo" ? "Terminal" : "Aero"}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="ios-grid">
|
||||||
|
{APPS.map((app) => (
|
||||||
|
<button
|
||||||
|
key={app.id}
|
||||||
|
type="button"
|
||||||
|
className="ios-app"
|
||||||
|
onClick={() => setOpenId(app.id)}
|
||||||
|
>
|
||||||
|
<span className="ios-app-icon" style={{ background: app.color }}>
|
||||||
|
{app.icon}
|
||||||
|
</span>
|
||||||
|
<span className="ios-app-label">{app.title}</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="ios-dock">
|
||||||
|
<span className="ios-dock-slots" aria-hidden="true" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -51,6 +51,7 @@ export default function SlBackground() {
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
<div
|
<div
|
||||||
|
className="sl-background"
|
||||||
style={{
|
style={{
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
top: 0,
|
top: 0,
|
||||||
|
|
|
||||||
726
src/app/components/TerminalLayout.tsx
Normal file
726
src/app/components/TerminalLayout.tsx
Normal file
|
|
@ -0,0 +1,726 @@
|
||||||
|
import Image from "next/image";
|
||||||
|
import type { CSSProperties } from "react";
|
||||||
|
import SlBackground from "./SlBackground";
|
||||||
|
import JokerLogo from "./JokerLogo";
|
||||||
|
import ServiceButton from "./ServiceButton";
|
||||||
|
import ContributionHeatmap from "./ContributionHeatmap";
|
||||||
|
import Clock from "./Clock";
|
||||||
|
import { useTheme } from "./useTheme";
|
||||||
|
import { socials, codingProjects, techProjects, friends } from "../data";
|
||||||
|
|
||||||
|
type PanelStyle = CSSProperties & { "--panel-color"?: string };
|
||||||
|
|
||||||
|
const panelStyle = (color: string, style: CSSProperties = {}): PanelStyle => ({
|
||||||
|
...style,
|
||||||
|
"--panel-color": color,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function TerminalLayout() {
|
||||||
|
const { theme, toggle } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SlBackground />
|
||||||
|
<div className="container">
|
||||||
|
<header className="header">
|
||||||
|
<div className="header-center">
|
||||||
|
<JokerLogo />
|
||||||
|
<h1 className="site-name">dvorakmortonxd.dev</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main className="hero">
|
||||||
|
<div className="hero-panel" style={panelStyle("var(--accent)")}>
|
||||||
|
<span
|
||||||
|
className="hero-panel-label"
|
||||||
|
style={{ color: "var(--accent)", borderColor: "var(--accent)" }}
|
||||||
|
>
|
||||||
|
README.MD
|
||||||
|
</span>
|
||||||
|
<h2 className="hero-title">$ whoami</h2>
|
||||||
|
<p className="hero-subtitle">
|
||||||
|
Welcome my personal website! Here I show off my projects and hardware I own,
|
||||||
|
aswell as my self-hosted services :)<span className="cursor-blink"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="search-section">
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--white)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
SEARXNG.C
|
||||||
|
</span>
|
||||||
|
<form
|
||||||
|
action="https://search.dvorakmortonxd.dev/search"
|
||||||
|
method="GET"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="search-form"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="q"
|
||||||
|
placeholder="Search... (only works for those who are whitelisted)"
|
||||||
|
className="search-bar"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="social-section">
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--accent)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--accent)", borderColor: "var(--accent)" }}
|
||||||
|
>
|
||||||
|
SOCIALS.JS
|
||||||
|
</span>
|
||||||
|
<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>
|
||||||
|
<div className="mail-contact">
|
||||||
|
mail if u ever wanna contact me:{" "}
|
||||||
|
<a href="mailto:dvorak@dvorakmortonxd.dev">dvorak@dvorakmortonxd.dev</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="gym-section">
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--white)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
GYM_SBD_AT_73KG_BW.DB
|
||||||
|
</span>
|
||||||
|
<div className="gym-grid">
|
||||||
|
<div className="gym-item">
|
||||||
|
<Image src="/squat.svg" alt="Squat" width={48} height={48} className="gym-icon" />
|
||||||
|
<div className="gym-label">SQUAT</div>
|
||||||
|
<div className="gym-weight">125kg</div>
|
||||||
|
<div className="gym-date">5.1.2025</div>
|
||||||
|
</div>
|
||||||
|
<div className="gym-item">
|
||||||
|
<Image src="/bench.svg" alt="Bench" width={48} height={48} className="gym-icon" />
|
||||||
|
<div className="gym-label">BENCH</div>
|
||||||
|
<div className="gym-weight">111kg</div>
|
||||||
|
<div className="gym-date">29.5.2026</div>
|
||||||
|
</div>
|
||||||
|
<div className="gym-item">
|
||||||
|
<Image
|
||||||
|
src="/deadlift.svg"
|
||||||
|
alt="Deadlift"
|
||||||
|
width={48}
|
||||||
|
height={48}
|
||||||
|
className="gym-icon"
|
||||||
|
/>
|
||||||
|
<div className="gym-label">DEADLIFT</div>
|
||||||
|
<div className="gym-weight">165kg</div>
|
||||||
|
<div className="gym-date">17.12.2024</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="about-section">
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--white)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
NOW.TXT
|
||||||
|
</span>
|
||||||
|
<div className="about-content">
|
||||||
|
<p>
|
||||||
|
<span style={{ color: "var(--green)" }}>martin@dvorakmortonxd</span>:
|
||||||
|
<span className="text-blue">~</span>$ cat now.txt
|
||||||
|
</p>
|
||||||
|
<div style={{ color: "#a3a3a3" }}>
|
||||||
|
<p>
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="about-section">
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--accent)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--accent)", borderColor: "var(--accent)" }}
|
||||||
|
>
|
||||||
|
README.MD
|
||||||
|
</span>
|
||||||
|
<div className="about-content">
|
||||||
|
<p>
|
||||||
|
<span className="text-green">martin@dvorakmortonxd</span>:
|
||||||
|
<span className="text-blue">~</span>$ cat about_me.md
|
||||||
|
</p>
|
||||||
|
<div style={{ color: "#a3a3a3" }}>
|
||||||
|
<p>
|
||||||
|
Hey, I'm Martin Dvořák — a 17(soon to be 18)-year-old IT student based
|
||||||
|
in the Czech Republic, specializing in network management and
|
||||||
|
administration at <a href="https://sssvt.cz">sssvt.cz</a>. I'm a
|
||||||
|
sophomore and I have wanted to go to this school since 7th grade (2022) so
|
||||||
|
I'm happy I got in in 2025, the school is pretty cool so if you are in
|
||||||
|
middle school and interested in IT, make sure to check it out. I'm a
|
||||||
|
homelabber and developer heavily focused on self-hosting{" "}
|
||||||
|
<i>literally everything</i>, writing code (for example games for gamejams),
|
||||||
|
tinkering with GNU/Linux or Musl/Linux systems and retro hardware. I own a
|
||||||
|
small collection of laptops ranging from 2009 to 2014 (and ofcourse my 2025
|
||||||
|
macbook), most of these found in ewaste. In my free time I mostly spend
|
||||||
|
time with my gf {"<"}3, I also spend a bit of time setting up my self
|
||||||
|
hosted stuff (like jellyfin or gitdxd), and also when I'm in my gaming
|
||||||
|
mood I play terraria (around 1300hr playtime btw) and minecraft modpacks
|
||||||
|
with mekanism and/or create. I also go to the gym around 3-5 times a week,
|
||||||
|
running a PPL split focused on strength/powerlifting and especially SBD. I
|
||||||
|
take a big focus on my health and physique.
|
||||||
|
<span className="cursor-blink"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="services-section">
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--accent)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--accent)", borderColor: "var(--accent)" }}
|
||||||
|
>
|
||||||
|
SERVICES.HTML
|
||||||
|
</span>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="gitdxd-section" style={{ marginTop: "20px" }}>
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--white)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
GITDXD.GIT
|
||||||
|
</span>
|
||||||
|
<div style={{ padding: "24px 16px 16px" }}>
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: "2.4rem",
|
||||||
|
fontWeight: "bold",
|
||||||
|
color: "var(--white)",
|
||||||
|
marginBottom: "16px",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
GitDXD
|
||||||
|
</h2>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
fontSize: "1.8rem",
|
||||||
|
color: "var(--white)",
|
||||||
|
fontWeight: "500",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
My Self-hosted Git Instance
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: "16px",
|
||||||
|
marginBottom: "16px",
|
||||||
|
borderRadius: "8px",
|
||||||
|
overflow: "hidden",
|
||||||
|
border: "1px solid rgba(255, 255, 255, 0.4)",
|
||||||
|
boxShadow: "0 0 30px rgba(180, 255, 125, 0.15)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/gitdxd.webp"
|
||||||
|
alt="GitDXD Preview"
|
||||||
|
width={1280}
|
||||||
|
height={720}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
color: "var(--gray)",
|
||||||
|
marginTop: "12px",
|
||||||
|
lineHeight: "1.6",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
My very own forgejo git instance, originally started as a private git
|
||||||
|
instance for me and my friends to boycott GitHub but I've made it
|
||||||
|
public now so. Join at{" "}
|
||||||
|
<span className="text-purple-500">
|
||||||
|
<a href="https://git.dvorakmortonxd.dev">git.dvorakmortonxd.dev</a>
|
||||||
|
</span>
|
||||||
|
.<span className="cursor-blink"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="commits-section" style={{ marginTop: "20px" }}>
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--accent)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--accent)", borderColor: "var(--accent)" }}
|
||||||
|
>
|
||||||
|
CONTRIBUTIONS@GITDXD.GIT
|
||||||
|
</span>
|
||||||
|
<div className="commits-content" style={{ padding: "24px 12px 16px" }}>
|
||||||
|
<ContributionHeatmap />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="revival-section" style={{ marginTop: "20px" }}>
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--white)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
REVIVAL.INC
|
||||||
|
</span>
|
||||||
|
<div style={{ padding: "24px 16px 16px" }}>
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: "2.4rem",
|
||||||
|
fontWeight: "bold",
|
||||||
|
color: "var(--white)",
|
||||||
|
marginBottom: "32px",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Revival inc.
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: "12px",
|
||||||
|
marginBottom: "12px",
|
||||||
|
borderRadius: "8px",
|
||||||
|
overflow: "hidden",
|
||||||
|
border: "1px solid rgba(0, 0, 0, 0.4)",
|
||||||
|
boxShadow: "0 0 30px rgba(255, 255, 255, 0.35)",
|
||||||
|
width: "80%",
|
||||||
|
margin: "12px auto",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/revivalinc.webp"
|
||||||
|
alt="revival inc thumbnail"
|
||||||
|
width={768}
|
||||||
|
height={576}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
fontSize: "1.8rem",
|
||||||
|
color: "var(--white)",
|
||||||
|
fontWeight: "500",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
What is it?
|
||||||
|
</p>
|
||||||
|
<div style={{ color: "var(--gray)", marginTop: "12px", lineHeight: "1.6" }}>
|
||||||
|
<p>
|
||||||
|
It's 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{" "}
|
||||||
|
<span className="text-purple-500">
|
||||||
|
<a href="https://martin-dv.itch.io/revival-inc">itch.io</a>
|
||||||
|
</span>{" "}
|
||||||
|
or play{" "}
|
||||||
|
<span className="text-purple-500">
|
||||||
|
<a href="https://dvorakmortonxd.dev/revival-inc">here</a>
|
||||||
|
</span>
|
||||||
|
.<span className="cursor-blink"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="rustywolf-section" style={{ marginTop: "20px" }}>
|
||||||
|
<div className="tui-panel" style={panelStyle("var(--white)")}>
|
||||||
|
<span
|
||||||
|
className="tui-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
RUSTYWOLF.RS
|
||||||
|
</span>
|
||||||
|
<div style={{ padding: "24px 16px 16px" }}>
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: "2.4rem",
|
||||||
|
fontWeight: "bold",
|
||||||
|
color: "var(--white)",
|
||||||
|
marginBottom: "32px",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Introducing RustyWolf
|
||||||
|
</h2>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: "12px",
|
||||||
|
marginBottom: "12px",
|
||||||
|
borderRadius: "8px",
|
||||||
|
overflow: "hidden",
|
||||||
|
border: "1px solid rgba(255, 255, 255, 0.4)",
|
||||||
|
boxShadow: "0 0 30px rgba(255, 255, 255, 0.2)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/RustyWolfPreview.webp"
|
||||||
|
alt="RustyWolf Browser Preview"
|
||||||
|
width={1280}
|
||||||
|
height={720}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p
|
||||||
|
style={{
|
||||||
|
fontSize: "1.8rem",
|
||||||
|
color: "var(--white)",
|
||||||
|
fontWeight: "500",
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
What makes it so cool???
|
||||||
|
</p>
|
||||||
|
<div style={{ color: "var(--gray)", marginTop: "12px", lineHeight: "1.6" }}>
|
||||||
|
<p>
|
||||||
|
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. It's a perfect browser for old machines that
|
||||||
|
struggle with modern browsers. Check it out at{" "}
|
||||||
|
<span style={{ color: "var(--accent2)" }}>
|
||||||
|
<a href="https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf">
|
||||||
|
GitDXD
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
.<span className="cursor-blink"></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<section className="projects">
|
||||||
|
<div className="subsection-wrapper">
|
||||||
|
<div className="subsection-panel" style={panelStyle("var(--white)")}>
|
||||||
|
<span
|
||||||
|
className="subsection-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
TECH_LIST.JSON
|
||||||
|
</span>
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: "2rem",
|
||||||
|
fontWeight: "bold",
|
||||||
|
textAlign: "center",
|
||||||
|
margin: "4px 0 20px",
|
||||||
|
color: "var(--white)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
All my hardware equipment :)
|
||||||
|
</h2>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="subsection-wrapper">
|
||||||
|
<div className="subsection-panel coding-panel" style={panelStyle("var(--accent)")}>
|
||||||
|
<span
|
||||||
|
className="subsection-panel-label"
|
||||||
|
style={{ color: "var(--accent)", borderColor: "var(--accent)" }}
|
||||||
|
>
|
||||||
|
PROJECTS.DOCX
|
||||||
|
</span>
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: "2rem",
|
||||||
|
fontWeight: "bold",
|
||||||
|
textAlign: "center",
|
||||||
|
margin: "4px 0 20px",
|
||||||
|
color: "var(--accent)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
All the stuff I've worked on :))
|
||||||
|
</h2>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="subsection-wrapper">
|
||||||
|
<div
|
||||||
|
className="subsection-panel friends-panel"
|
||||||
|
style={panelStyle("var(--white)", { backgroundColor: "rgba(255, 255, 255, 0.02)" })}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="subsection-panel-label"
|
||||||
|
style={{ color: "var(--white)", borderColor: "var(--white)" }}
|
||||||
|
>
|
||||||
|
FRIENDS.TSX
|
||||||
|
</span>
|
||||||
|
<h2
|
||||||
|
style={{
|
||||||
|
fontSize: "2rem",
|
||||||
|
fontWeight: "bold",
|
||||||
|
textAlign: "center",
|
||||||
|
margin: "4px 0 20px",
|
||||||
|
color: "var(--white)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Friend's websites and projects
|
||||||
|
</h2>
|
||||||
|
<div className="services-buttons" style={{ gap: "1rem" }}>
|
||||||
|
{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%",
|
||||||
|
filter:
|
||||||
|
"brightness(0) invert(65%) hue-rotate(70deg) saturate(100%)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
name={friend.name}
|
||||||
|
desc={friend.desc}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: "12px",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: "16px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<h3 style={{ fontSize: "1.5rem", color: "var(--accent)", fontWeight: "600" }}>
|
||||||
|
Quipee by Bukovina Filip & Vlk Tomáš
|
||||||
|
</h3>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: "8px",
|
||||||
|
overflow: "hidden",
|
||||||
|
border: "1px solid rgba(255, 255, 0, 0.3)",
|
||||||
|
boxShadow: "0 0 20px rgba(255, 255, 0, 0.1)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/quipee.webp"
|
||||||
|
alt="Quipee Thumbnail"
|
||||||
|
width={1280}
|
||||||
|
height={720}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
gap: "12px",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://quipee.me"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "rgba(255, 255, 255, 0.04)",
|
||||||
|
color: "var(--white)",
|
||||||
|
padding: "6px 16px",
|
||||||
|
borderRadius: "6px",
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: "500",
|
||||||
|
textDecoration: "none",
|
||||||
|
border: "1px solid rgba(255, 255, 0, 0.3)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Web
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://drive.google.com/drive/folders/1oi76JyWs6J84MUmCGV7GvtLUexXI8Jel?usp=share_link"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "rgba(255, 255, 255, 0.04)",
|
||||||
|
color: "var(--white)",
|
||||||
|
padding: "6px 16px",
|
||||||
|
borderRadius: "6px",
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: "500",
|
||||||
|
textDecoration: "none",
|
||||||
|
border: "1px solid rgba(255, 255, 0, 0.3)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Android
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://testflight.apple.com/join/hP2a1E5x"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "rgba(255, 255, 255, 0.04)",
|
||||||
|
color: "var(--white)",
|
||||||
|
padding: "6px 16px",
|
||||||
|
borderRadius: "6px",
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: "500",
|
||||||
|
textDecoration: "none",
|
||||||
|
border: "1px solid rgba(255, 255, 0, 0.3)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
IOS
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer className="footer">
|
||||||
|
<span className="footer-label">v1.2.1</span>
|
||||||
|
© 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just follow
|
||||||
|
the GPL3.0 License)
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="tui-statusbar">
|
||||||
|
<span className="tui-statusbar-item">theme: terminal</span>
|
||||||
|
<button type="button" className="tui-statusbar-btn" onClick={toggle}>
|
||||||
|
[ switch to {theme === "skeuo" ? "terminal" : "Aero"} ]
|
||||||
|
</button>
|
||||||
|
<span className="tui-statusbar-spacer" />
|
||||||
|
<Clock className="tui-statusbar-clock" />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
25
src/app/components/ThemeRoot.tsx
Normal file
25
src/app/components/ThemeRoot.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useTheme } from "./useTheme";
|
||||||
|
import TerminalLayout from "./TerminalLayout";
|
||||||
|
import WindowsDesktop from "./WindowsDesktop";
|
||||||
|
import IosHome from "./IosHome";
|
||||||
|
|
||||||
|
export default function ThemeRoot() {
|
||||||
|
const { theme } = useTheme();
|
||||||
|
|
||||||
|
if (theme === "terminal") {
|
||||||
|
return <TerminalLayout />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="skeuo-desktop-root">
|
||||||
|
<WindowsDesktop />
|
||||||
|
</div>
|
||||||
|
<div className="skeuo-ios-root">
|
||||||
|
<IosHome />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
109
src/app/components/WinWindow.tsx
Normal file
109
src/app/components/WinWindow.tsx
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useRef, type CSSProperties } from "react";
|
||||||
|
import type { AppDef } from "./apps";
|
||||||
|
|
||||||
|
export interface WinState {
|
||||||
|
id: number;
|
||||||
|
appId: string;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
z: number;
|
||||||
|
minimized: boolean;
|
||||||
|
maximized: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
win: WinState;
|
||||||
|
app: AppDef;
|
||||||
|
active: boolean;
|
||||||
|
onFocus: () => void;
|
||||||
|
onClose: () => void;
|
||||||
|
onMinimize: () => void;
|
||||||
|
onToggleMaximize: () => void;
|
||||||
|
onMove: (x: number, y: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function WinWindow({
|
||||||
|
win,
|
||||||
|
app,
|
||||||
|
active,
|
||||||
|
onFocus,
|
||||||
|
onClose,
|
||||||
|
onMinimize,
|
||||||
|
onToggleMaximize,
|
||||||
|
onMove,
|
||||||
|
}: Props) {
|
||||||
|
const drag = useRef<{ sx: number; sy: number; ox: number; oy: number } | null>(null);
|
||||||
|
|
||||||
|
const style: CSSProperties = win.maximized
|
||||||
|
? { left: 0, top: 0, width: "100%", height: "100%", zIndex: win.z }
|
||||||
|
: { left: win.x, top: win.y, width: win.w, height: win.h, zIndex: win.z };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className={
|
||||||
|
"win-window" +
|
||||||
|
(active ? " active" : "") +
|
||||||
|
(win.minimized ? " minimized" : "") +
|
||||||
|
(win.maximized ? " maximized" : "")
|
||||||
|
}
|
||||||
|
style={style}
|
||||||
|
onPointerDown={onFocus}
|
||||||
|
role="dialog"
|
||||||
|
aria-label={app.title}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="win-titlebar"
|
||||||
|
onPointerDown={(e) => {
|
||||||
|
onFocus();
|
||||||
|
if (win.maximized) return;
|
||||||
|
if ((e.target as HTMLElement).closest(".win-controls")) return;
|
||||||
|
drag.current = { sx: e.clientX, sy: e.clientY, ox: win.x, oy: win.y };
|
||||||
|
e.currentTarget.setPointerCapture(e.pointerId);
|
||||||
|
}}
|
||||||
|
onPointerMove={(e) => {
|
||||||
|
const d = drag.current;
|
||||||
|
if (!d) return;
|
||||||
|
onMove(d.ox + (e.clientX - d.sx), d.oy + (e.clientY - d.sy));
|
||||||
|
}}
|
||||||
|
onPointerUp={(e) => {
|
||||||
|
drag.current = null;
|
||||||
|
try {
|
||||||
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="win-titlebar-icon" style={{ background: app.color }} aria-hidden="true">
|
||||||
|
{app.icon}
|
||||||
|
</span>
|
||||||
|
<span className="win-titlebar-text">{app.title}</span>
|
||||||
|
<div className="win-controls">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="win-ctl win-ctl-min"
|
||||||
|
onClick={onMinimize}
|
||||||
|
aria-label="Minimize"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="win-ctl win-ctl-max"
|
||||||
|
onClick={onToggleMaximize}
|
||||||
|
aria-label={win.maximized ? "Restore" : "Maximize"}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="win-ctl win-ctl-close"
|
||||||
|
onClick={onClose}
|
||||||
|
aria-label="Close"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="win-body app-surface">{app.content}</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
274
src/app/components/WindowsDesktop.tsx
Normal file
274
src/app/components/WindowsDesktop.tsx
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { APPS, APP_BY_ID } from "./apps";
|
||||||
|
import WinWindow, { type WinState } from "./WinWindow";
|
||||||
|
import Clock from "./Clock";
|
||||||
|
import { useTheme } from "./useTheme";
|
||||||
|
import { WALLPAPER } from "../data";
|
||||||
|
|
||||||
|
const TASKBAR_HEIGHT = 40;
|
||||||
|
|
||||||
|
export default function WindowsDesktop() {
|
||||||
|
const { theme, toggle } = useTheme();
|
||||||
|
|
||||||
|
const [wins, setWins] = useState<WinState[]>(() => [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
appId: "welcome",
|
||||||
|
x: 110,
|
||||||
|
y: 64,
|
||||||
|
w: 620,
|
||||||
|
h: 430,
|
||||||
|
z: 10,
|
||||||
|
minimized: false,
|
||||||
|
maximized: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const [activeId, setActiveId] = useState<number | null>(1);
|
||||||
|
const [startOpen, setStartOpen] = useState(false);
|
||||||
|
const [selectedIcon, setSelectedIcon] = useState<string | null>(null);
|
||||||
|
|
||||||
|
const idRef = useRef(2);
|
||||||
|
const zRef = useRef(11);
|
||||||
|
const spawnRef = useRef(1);
|
||||||
|
|
||||||
|
const focus = (id: number) => {
|
||||||
|
setActiveId(id);
|
||||||
|
setWins((prev) =>
|
||||||
|
prev.map((w) => (w.id === id ? { ...w, z: ++zRef.current } : w))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const openApp = (appId: string) => {
|
||||||
|
setStartOpen(false);
|
||||||
|
const existing = wins.find((w) => w.appId === appId);
|
||||||
|
if (existing) {
|
||||||
|
setWins((prev) =>
|
||||||
|
prev.map((w) =>
|
||||||
|
w.id === existing.id ? { ...w, minimized: false, z: ++zRef.current } : w
|
||||||
|
)
|
||||||
|
);
|
||||||
|
setActiveId(existing.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const app = APP_BY_ID[appId];
|
||||||
|
if (!app) return;
|
||||||
|
const n = spawnRef.current++;
|
||||||
|
const id = idRef.current++;
|
||||||
|
const maxX = Math.max(20, (typeof window !== "undefined" ? window.innerWidth : 1280) - app.width - 20);
|
||||||
|
const maxY = Math.max(20, (typeof window !== "undefined" ? window.innerHeight : 800) - TASKBAR_HEIGHT - app.height - 20);
|
||||||
|
const x = Math.min(maxX, 90 + (n % 8) * 30);
|
||||||
|
const y = Math.min(maxY, 56 + (n % 8) * 28);
|
||||||
|
setWins((prev) => [
|
||||||
|
...prev,
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
appId,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
w: app.width,
|
||||||
|
h: app.height,
|
||||||
|
z: ++zRef.current,
|
||||||
|
minimized: false,
|
||||||
|
maximized: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
setActiveId(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeWin = (id: number) =>
|
||||||
|
setWins((prev) => prev.filter((w) => w.id !== id));
|
||||||
|
const minimizeWin = (id: number) =>
|
||||||
|
setWins((prev) => prev.map((w) => (w.id === id ? { ...w, minimized: true } : w)));
|
||||||
|
const toggleMax = (id: number) =>
|
||||||
|
setWins((prev) =>
|
||||||
|
prev.map((w) => (w.id === id ? { ...w, maximized: !w.maximized } : w))
|
||||||
|
);
|
||||||
|
const moveWin = (id: number, x: number, y: number) => {
|
||||||
|
const maxX =
|
||||||
|
(typeof window !== "undefined" ? window.innerWidth : 1280) - 120;
|
||||||
|
const maxY =
|
||||||
|
(typeof window !== "undefined" ? window.innerHeight : 800) - TASKBAR_HEIGHT - 20;
|
||||||
|
setWins((prev) =>
|
||||||
|
prev.map((w) =>
|
||||||
|
w.id === id
|
||||||
|
? { ...w, x: Math.max(-w.w + 120, Math.min(maxX, x)), y: Math.max(0, Math.min(maxY, y)) }
|
||||||
|
: w
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const taskbarClick = (w: WinState) => {
|
||||||
|
if (w.minimized) {
|
||||||
|
setWins((prev) =>
|
||||||
|
prev.map((x) => (x.id === w.id ? { ...x, minimized: false, z: ++zRef.current } : x))
|
||||||
|
);
|
||||||
|
setActiveId(w.id);
|
||||||
|
} else if (activeId === w.id) {
|
||||||
|
minimizeWin(w.id);
|
||||||
|
} else {
|
||||||
|
focus(w.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const wallpaper = `url('${WALLPAPER}')`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="win-desktop"
|
||||||
|
style={{ backgroundImage: wallpaper }}
|
||||||
|
onPointerDown={(e) => {
|
||||||
|
if (e.target === e.currentTarget) {
|
||||||
|
setStartOpen(false);
|
||||||
|
setSelectedIcon(null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="win-wallpaper-tint" aria-hidden="true" />
|
||||||
|
|
||||||
|
{/* Desktop icons */}
|
||||||
|
<div className="win-icons" onPointerDown={(e) => e.stopPropagation()}>
|
||||||
|
{APPS.map((app) => (
|
||||||
|
<button
|
||||||
|
key={app.id}
|
||||||
|
type="button"
|
||||||
|
className={"win-icon" + (selectedIcon === app.id ? " selected" : "")}
|
||||||
|
onClick={() => setSelectedIcon(app.id)}
|
||||||
|
onDoubleClick={() => openApp(app.id)}
|
||||||
|
title={`Open ${app.title}`}
|
||||||
|
>
|
||||||
|
<span className="win-icon-glyph" style={{ background: app.color }}>
|
||||||
|
{app.icon}
|
||||||
|
</span>
|
||||||
|
<span className="win-icon-label">{app.title}</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Windows */}
|
||||||
|
<div className="win-layer">
|
||||||
|
{wins.map((w) => (
|
||||||
|
<WinWindow
|
||||||
|
key={w.id}
|
||||||
|
win={w}
|
||||||
|
app={APP_BY_ID[w.appId]}
|
||||||
|
active={activeId === w.id}
|
||||||
|
onFocus={() => focus(w.id)}
|
||||||
|
onClose={() => closeWin(w.id)}
|
||||||
|
onMinimize={() => minimizeWin(w.id)}
|
||||||
|
onToggleMaximize={() => toggleMax(w.id)}
|
||||||
|
onMove={(x, y) => moveWin(w.id, x, y)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Start menu */}
|
||||||
|
{startOpen && (
|
||||||
|
<div className="win-startmenu" onPointerDown={(e) => e.stopPropagation()}>
|
||||||
|
<div className="win-startmenu-user">
|
||||||
|
<span className="win-startmenu-avatar">🧑💻</span>
|
||||||
|
<span>Martin Dvořák</span>
|
||||||
|
</div>
|
||||||
|
<div className="win-startmenu-list">
|
||||||
|
{APPS.map((app) => (
|
||||||
|
<button
|
||||||
|
key={app.id}
|
||||||
|
type="button"
|
||||||
|
className="win-startmenu-item"
|
||||||
|
onClick={() => openApp(app.id)}
|
||||||
|
>
|
||||||
|
<span className="win-startmenu-icon" style={{ background: app.color }}>
|
||||||
|
{app.icon}
|
||||||
|
</span>
|
||||||
|
{app.title}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="win-startmenu-foot">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="win-startmenu-power"
|
||||||
|
onClick={() => {
|
||||||
|
toggle();
|
||||||
|
setStartOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
⏻ Switch to {theme === "skeuo" ? "Terminal" : "Aero"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Taskbar */}
|
||||||
|
<div className="win-taskbar" onPointerDown={(e) => e.stopPropagation()}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={"win-start" + (startOpen ? " open" : "")}
|
||||||
|
onClick={() => setStartOpen((v) => !v)}
|
||||||
|
aria-label="Start"
|
||||||
|
>
|
||||||
|
<span className="win-start-orb">⊞</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="win-tb-buttons">
|
||||||
|
{wins.map((w) => {
|
||||||
|
const app = APP_BY_ID[w.appId];
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={w.id}
|
||||||
|
type="button"
|
||||||
|
className={
|
||||||
|
"win-tb-btn" +
|
||||||
|
(activeId === w.id && !w.minimized ? " active" : "") +
|
||||||
|
(w.minimized ? " minimized" : "")
|
||||||
|
}
|
||||||
|
onClick={() => taskbarClick(w)}
|
||||||
|
title={app.title}
|
||||||
|
>
|
||||||
|
<span className="win-tb-btn-icon" style={{ background: app.color }}>
|
||||||
|
{app.icon}
|
||||||
|
</span>
|
||||||
|
<span className="win-tb-btn-label">{app.title}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="win-tray">
|
||||||
|
<form
|
||||||
|
className="win-search"
|
||||||
|
action="https://search.dvorakmortonxd.dev/search"
|
||||||
|
method="GET"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<span className="win-search-glyph" aria-hidden="true">
|
||||||
|
⌕
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="q"
|
||||||
|
placeholder="Search the web..."
|
||||||
|
aria-label="Search the web"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="win-theme-toggle"
|
||||||
|
onClick={toggle}
|
||||||
|
title={`Switch to ${theme === "skeuo" ? "terminal" : "Aero"} theme`}
|
||||||
|
>
|
||||||
|
<span aria-hidden="true">{theme === "skeuo" ? "▚" : "❖"}</span>
|
||||||
|
<span>{theme === "skeuo" ? "Terminal" : "Aero"}</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Clock className="win-clock" />
|
||||||
|
|
||||||
|
<button type="button" className="win-showdesktop" aria-label="Show desktop" onClick={() => setWins((prev) => prev.map((w) => ({ ...w, minimized: true })))} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
426
src/app/components/apps.tsx
Normal file
426
src/app/components/apps.tsx
Normal file
|
|
@ -0,0 +1,426 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import Image from "next/image";
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
import {
|
||||||
|
socials,
|
||||||
|
codingProjects,
|
||||||
|
techProjects,
|
||||||
|
friends,
|
||||||
|
WALLPAPER_CREDIT,
|
||||||
|
} from "../data";
|
||||||
|
import ServiceButton from "./ServiceButton";
|
||||||
|
import ContributionHeatmap from "./ContributionHeatmap";
|
||||||
|
import JokerLogo from "./JokerLogo";
|
||||||
|
|
||||||
|
export interface AppDef {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
icon: string;
|
||||||
|
color: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
content: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
function WelcomeApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad app-welcome">
|
||||||
|
<div className="app-welcome-head">
|
||||||
|
<JokerLogo />
|
||||||
|
<div>
|
||||||
|
<h2>Welcome to dvorakmortonxd.dev</h2>
|
||||||
|
<p className="app-muted">A Windows 7 desktop edition of my personal website.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Double-click an icon on the desktop (or open the
|
||||||
|
<strong> Start </strong> menu) to launch an application. Everything you used to
|
||||||
|
scroll through now lives inside its own little window.
|
||||||
|
</p>
|
||||||
|
<ul className="app-list">
|
||||||
|
<li>Drag windows around by their title bar.</li>
|
||||||
|
<li>Use the buttons at the top-right to minimize, maximize or close.</li>
|
||||||
|
<li>Search the web from the taskbar at the bottom.</li>
|
||||||
|
<li>Switch back to the terminal theme from the tray, bottom-right.</li>
|
||||||
|
</ul>
|
||||||
|
<p className="app-muted app-fineprint">
|
||||||
|
Wallpaper from{" "}
|
||||||
|
<a href={WALLPAPER_CREDIT} target="_blank" rel="noopener noreferrer">
|
||||||
|
wallpaperaccess.com/open-source
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function AboutApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<p className="app-cmd">
|
||||||
|
<span className="app-user">martin@dvorakmortonxd</span>:<span className="app-path">~</span>$
|
||||||
|
cat about_me.md
|
||||||
|
</p>
|
||||||
|
<div className="app-text">
|
||||||
|
<p>
|
||||||
|
Hey, I'm Martin Dvořák — a 17(soon to be 18)-year-old IT student based in the
|
||||||
|
Czech Republic, specializing in network management and administration at{" "}
|
||||||
|
<a href="https://sssvt.cz">sssvt.cz</a>. I'm a sophomore and I have wanted to
|
||||||
|
go to this school since 7th grade (2022) so I'm happy I got in in 2025, the
|
||||||
|
school is pretty cool so if you are in middle school and interested in IT, make
|
||||||
|
sure to check it out. I'm a homelabber and developer heavily focused on
|
||||||
|
self-hosting <i>literally everything</i>, writing code (for example games for
|
||||||
|
gamejams), tinkering with GNU/Linux or Musl/Linux systems and retro hardware. I
|
||||||
|
own a small collection of laptops ranging from 2009 to 2014 (and ofcourse my 2025
|
||||||
|
macbook), most of these found in ewaste. In my free time I mostly spend time with
|
||||||
|
my gf {'<'}3, I also spend a bit of time setting up my self hosted stuff (like
|
||||||
|
jellyfin or gitdxd), and also when I'm in my gaming mood I play terraria
|
||||||
|
(around 1300hr playtime btw) and minecraft modpacks with mekanism and/or create. I
|
||||||
|
also go to the gym around 3-5 times a week, running a PPL split focused on
|
||||||
|
strength/powerlifting and especially SBD. I take a big focus on my health and
|
||||||
|
physique.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function NowApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<p className="app-cmd">
|
||||||
|
<span className="app-user">martin@dvorakmortonxd</span>:<span className="app-path">~</span>$
|
||||||
|
cat now.txt
|
||||||
|
</p>
|
||||||
|
<div className="app-text">
|
||||||
|
<p>
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SocialsApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<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>
|
||||||
|
<div className="mail-contact">
|
||||||
|
mail if u ever wanna contact me:{" "}
|
||||||
|
<a href="mailto:dvorak@dvorakmortonxd.dev">dvorak@dvorakmortonxd.dev</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ServicesApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ProjectsApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HardwareApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function FriendsApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<div className="services-buttons" style={{ gap: "1rem" }}>
|
||||||
|
{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>
|
||||||
|
|
||||||
|
<div className="friends-extra">
|
||||||
|
<h3>Quipee by Bukovina Filip & Vlk Tomáš</h3>
|
||||||
|
<div className="app-shot">
|
||||||
|
<Image
|
||||||
|
src="/quipee.webp"
|
||||||
|
alt="Quipee Thumbnail"
|
||||||
|
width={1280}
|
||||||
|
height={720}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="app-linkrow">
|
||||||
|
<a href="https://quipee.me" target="_blank" rel="noopener noreferrer">
|
||||||
|
Web
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://drive.google.com/drive/folders/1oi76JyWs6J84MUmCGV7GvtLUexXI8Jel?usp=share_link"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Android
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
href="https://testflight.apple.com/join/hP2a1E5x"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
IOS
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function GitdxdApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad app-center">
|
||||||
|
<h2 className="app-h1">GitDXD</h2>
|
||||||
|
<p className="app-h2">My Self-hosted Git Instance</p>
|
||||||
|
<div className="app-shot app-shot-glow">
|
||||||
|
<Image
|
||||||
|
src="/gitdxd.webp"
|
||||||
|
alt="GitDXD Preview"
|
||||||
|
width={1280}
|
||||||
|
height={720}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="app-text">
|
||||||
|
My very own forgejo git instance, originally started as a private git instance for
|
||||||
|
me and my friends to boycott GitHub but I've made it public now so. Join at{" "}
|
||||||
|
<a href="https://git.dvorakmortonxd.dev">git.dvorakmortonxd.dev</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ContributionsApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<ContributionHeatmap />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function GymApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad">
|
||||||
|
<div className="gym-grid">
|
||||||
|
<div className="gym-item">
|
||||||
|
<Image src="/squat.svg" alt="Squat" width={48} height={48} className="gym-icon" />
|
||||||
|
<div className="gym-label">SQUAT</div>
|
||||||
|
<div className="gym-weight">125kg</div>
|
||||||
|
<div className="gym-date">5.1.2025</div>
|
||||||
|
</div>
|
||||||
|
<div className="gym-item">
|
||||||
|
<Image src="/bench.svg" alt="Bench" width={48} height={48} className="gym-icon" />
|
||||||
|
<div className="gym-label">BENCH</div>
|
||||||
|
<div className="gym-weight">111kg</div>
|
||||||
|
<div className="gym-date">29.5.2026</div>
|
||||||
|
</div>
|
||||||
|
<div className="gym-item">
|
||||||
|
<Image
|
||||||
|
src="/deadlift.svg"
|
||||||
|
alt="Deadlift"
|
||||||
|
width={48}
|
||||||
|
height={48}
|
||||||
|
className="gym-icon"
|
||||||
|
/>
|
||||||
|
<div className="gym-label">DEADLIFT</div>
|
||||||
|
<div className="gym-weight">165kg</div>
|
||||||
|
<div className="gym-date">17.12.2024</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RevivalApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad app-center">
|
||||||
|
<h2 className="app-h1">Revival Inc.</h2>
|
||||||
|
<div className="app-shot app-shot-light">
|
||||||
|
<Image
|
||||||
|
src="/revivalinc.webp"
|
||||||
|
alt="revival inc thumbnail"
|
||||||
|
width={768}
|
||||||
|
height={576}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="app-h2">What is it?</p>
|
||||||
|
<p className="app-text">
|
||||||
|
It's 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>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function RustyWolfApp() {
|
||||||
|
return (
|
||||||
|
<div className="app-pad app-center">
|
||||||
|
<h2 className="app-h1">Introducing RustyWolf</h2>
|
||||||
|
<div className="app-shot app-shot-glow">
|
||||||
|
<Image
|
||||||
|
src="/RustyWolfPreview.webp"
|
||||||
|
alt="RustyWolf Browser Preview"
|
||||||
|
width={1280}
|
||||||
|
height={720}
|
||||||
|
style={{ width: "100%", height: "auto", display: "block" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="app-h2">What makes it so cool???</p>
|
||||||
|
<p className="app-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. It's a perfect browser for old machines that struggle with modern
|
||||||
|
browsers. Check it out at{" "}
|
||||||
|
<a href="https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf">GitDXD</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const APPS: AppDef[] = [
|
||||||
|
{ id: "welcome", title: "Welcome", icon: "👋", color: "#2f7fc4", width: 620, height: 430, content: <WelcomeApp /> },
|
||||||
|
{ id: "about", title: "About Me", icon: "🧑💻", color: "#0d5aa7", width: 720, height: 470, content: <AboutApp /> },
|
||||||
|
{ id: "now", title: "now.txt", icon: "📝", color: "#6a4fb3", width: 560, height: 320, content: <NowApp /> },
|
||||||
|
{ id: "socials", title: "Socials", icon: "🔗", color: "#0a7cc1", width: 700, height: 460, content: <SocialsApp /> },
|
||||||
|
{ id: "services", title: "Services", icon: "🖥️", color: "#157347", width: 760, height: 480, content: <ServicesApp /> },
|
||||||
|
{ id: "projects", title: "Projects", icon: "🎮", color: "#b3005f", width: 860, height: 560, content: <ProjectsApp /> },
|
||||||
|
{ id: "hardware", title: "Hardware", icon: "💻", color: "#1257a0", width: 860, height: 560, content: <HardwareApp /> },
|
||||||
|
{ id: "friends", title: "Friends", icon: "🫂", color: "#c0392b", width: 780, height: 560, content: <FriendsApp /> },
|
||||||
|
{ id: "gitdxd", title: "GitDXD", icon: "🐙", color: "#333333", width: 780, height: 560, content: <GitdxdApp /> },
|
||||||
|
{ id: "contributions", title: "Contributions", icon: "📊", color: "#157347", width: 900, height: 470, content: <ContributionsApp /> },
|
||||||
|
{ id: "gym", title: "Gym SBD", icon: "🏋️", color: "#c0392b", width: 620, height: 380, content: <GymApp /> },
|
||||||
|
{ id: "revival", title: "Revival Inc.", icon: "🧟", color: "#6a4fb3", width: 740, height: 560, content: <RevivalApp /> },
|
||||||
|
{ id: "rustywolf", title: "RustyWolf", icon: "🐺", color: "#0a7cc1", width: 780, height: 560, content: <RustyWolfApp /> },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const APP_BY_ID: Record<string, AppDef> = Object.fromEntries(
|
||||||
|
APPS.map((a) => [a.id, a])
|
||||||
|
);
|
||||||
45
src/app/components/useTheme.ts
Normal file
45
src/app/components/useTheme.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useSyncExternalStore } from "react";
|
||||||
|
|
||||||
|
export type Theme = "skeuo" | "terminal";
|
||||||
|
|
||||||
|
const EVENT = "theme-change";
|
||||||
|
|
||||||
|
function subscribe(callback: () => void) {
|
||||||
|
window.addEventListener(EVENT, callback);
|
||||||
|
window.addEventListener("storage", callback);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener(EVENT, callback);
|
||||||
|
window.removeEventListener("storage", callback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSnapshot(): Theme {
|
||||||
|
return document.documentElement.getAttribute("data-theme") === "terminal"
|
||||||
|
? "terminal"
|
||||||
|
: "skeuo";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getServerSnapshot(): Theme {
|
||||||
|
return "skeuo";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setTheme(theme: Theme) {
|
||||||
|
if (typeof document === "undefined") return;
|
||||||
|
document.documentElement.setAttribute("data-theme", theme);
|
||||||
|
try {
|
||||||
|
localStorage.setItem("theme", theme);
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
window.dispatchEvent(new Event(EVENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useTheme() {
|
||||||
|
const theme = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
||||||
|
return {
|
||||||
|
theme,
|
||||||
|
toggle: () => setTheme(theme === "skeuo" ? "terminal" : "skeuo"),
|
||||||
|
};
|
||||||
|
}
|
||||||
261
src/app/data.ts
Normal file
261
src/app/data.ts
Normal file
|
|
@ -0,0 +1,261 @@
|
||||||
|
export interface Social {
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CodingProject {
|
||||||
|
title: string;
|
||||||
|
desc: string;
|
||||||
|
img: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TechProject {
|
||||||
|
title: string;
|
||||||
|
desc: string;
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Friend {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
realUrl: string;
|
||||||
|
img: string;
|
||||||
|
desc: string;
|
||||||
|
iframe: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const socials: Social[] = [
|
||||||
|
{ name: "Instagram (main)", icon: "/instagram.svg", url: "https://www.instagram.com/dvorakmortonxd/" },
|
||||||
|
{ name: "Instagram (gym)", icon: "/instagram.svg", url: "https://www.instagram.com/dvorakmortonxd2/" },
|
||||||
|
{ name: "SoundCloud", icon: "/soundcloud.svg", url: "https://soundcloud.com/martin-dvorak-185636305" },
|
||||||
|
{ name: "TikTok", icon: "/tiktok.svg", url: "https://www.tiktok.com/@dvorakmortonxd" },
|
||||||
|
{ name: "Snapchat", icon: "/snapchat.svg", url: "https://www.snapchat.com/add/dvorakmortonxd" },
|
||||||
|
{ name: "GitDXD", icon: "/github.svg", url: "https://git.dvorakmortonxd.dev/dvorakmortonxd" },
|
||||||
|
{ name: "LinkedIn", icon: "/linkedin.svg", url: "https://www.linkedin.com/in/martin-dvorak-32012a394/" },
|
||||||
|
{ name: "Itch.io", icon: "/itchio.svg", url: "https://martin-dv.itch.io" },
|
||||||
|
{ name: "Discord", icon: "/discord.svg", url: "https://discord.com/users/555745543763001364" },
|
||||||
|
{ name: "Reddit", icon: "/reddit.svg", url: "https://www.reddit.com/user/M4RT1NYT/" },
|
||||||
|
{ name: "Twitter", icon: "/twitter.svg", url: "https://x.com/pepicskopcecek" },
|
||||||
|
{ name: "Quipee", icon: "/quip.svg", url: "https://quipee.me/dvorakmortonxd" },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const codingProjects: CodingProject[] = [
|
||||||
|
{
|
||||||
|
title: "Hospital Execution (Unfinished)",
|
||||||
|
desc: "the first ever real game I made, in pygame. I've abandoned it.",
|
||||||
|
img: "/coding-1.webp",
|
||||||
|
url: "https://martin-dv.itch.io/hospital-execution-demo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Underbaranoia (Finished)",
|
||||||
|
desc: "basically a undertale like infinite fight simulator that gets progressively harder, made in pygame.",
|
||||||
|
img: "/coding-2.webp",
|
||||||
|
url: "https://martin-dv.itch.io/underbaranoia",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Offline memer (Finished)",
|
||||||
|
desc: "parody of the discord bot \"Dank Memer\" made in batch. (this was technically my first ever game I published).",
|
||||||
|
img: "/coding-3.webp",
|
||||||
|
url: "https://martin-dv.itch.io/offline-memer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "4y (Forgotten)",
|
||||||
|
desc: "just a renamed fork of the ly login manager (based login manager btw I love it), no extra features, just a rename, its actually outdated so dont use it.",
|
||||||
|
img: "/coding-4.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4y",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "4rch linux (Forgotten)",
|
||||||
|
desc: "same as above, basically just a renamed fork of arch linux with calamares installer, also outdated and not maintained at all so no use please.",
|
||||||
|
img: "/coding-5.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4rch-linux",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "You_Are_An_Idiot_Virus.py (Finished)",
|
||||||
|
desc: "this is just a python script that just spams blinking \"you are an idiot\" windows, made it as a prank I think, not really sure rn.",
|
||||||
|
img: "/coding-6.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/uranidiot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Venturesome (Discontinued)",
|
||||||
|
desc: "a browser I wrote in python using PyQtWebEngine with PyQt5, actually pretty cool and modular but I couldnt get past the stage of adding a tab system, basically surpassed by my other project: RustyWolf.",
|
||||||
|
img: "/coding-7.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/Venturesome",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Mandelbrot set in Pygame (Finished)",
|
||||||
|
desc: "a python pygame script that renders the mandelbrot set, made it when I was fascinated by how it looks and ngl it still looks cool af.",
|
||||||
|
img: "/coding-8.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/mandelbrot",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Underpygametale (Unfinished)",
|
||||||
|
desc: "a remake of undertale written in pygame, got it to about the flowey part (at the beginning) and didnt touch it in a long time.",
|
||||||
|
img: "/coding-9.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/underpygametale",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Many discord bots...",
|
||||||
|
desc: "so many of them, once I (allegedly, pls discord dont ban me) even wrote a \"self-bot\" which auto-advertised a minecraft server on minecraft discord server in lfg-hosting every two hours, around 800 people joined in total.",
|
||||||
|
img: "/coding-10.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/PYGETEX",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "MMO minecraft plugin (Unfinished)",
|
||||||
|
desc: "a minceraft plugin with custom bosses, items, and functions. pretty barebones and basic but I did it all manually before vibecoding was even a thing so what.",
|
||||||
|
img: "/coding-11.webp",
|
||||||
|
url: "https://www.youtube.com/watch?v=cSAX5Ds61ac",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Many many failed minecraft servers..",
|
||||||
|
desc: "creative games, softcraft, frostville, eusmp, eurthsmp, softsmp and many other SMPs that died later on. I cant even count how many mc servers I had in total.",
|
||||||
|
img: "/coding-12.webp",
|
||||||
|
url: "https://discord.gg/KtHRm9kRmy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Swords and Sandals 2 pygame remake (Unfinished)",
|
||||||
|
desc: "an unfinished remake of swords and sandals 2 in pygame, I got bored of it and never finished it but ill finish it one day for sure lol.",
|
||||||
|
img: "/coding-13.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/sas2py",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Llama.cpp server",
|
||||||
|
desc: "my llama.cpp vm running on my proxmox with a gpu passthroughed RTX 3070, dm me if u wanna test it lol.",
|
||||||
|
img: "/coding-14.webp",
|
||||||
|
url: "https://ai.dvorakmortonxd.dev/",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Batch MSDOS Simulator (Finished)",
|
||||||
|
desc: "a freshman school project on making games in batch, it was like an OS simulator with a web browser, games, photos, even a video suprise (youll have to try it to figure that one out lol).",
|
||||||
|
img: "/coding-15.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/DvorakMSDOS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "RustyWolf (WIP, Available now!)",
|
||||||
|
desc: "a browser I made in rust with webkitgtk, I made it to be lightweight and to be able to be ran on macbook unibody 2010 before I realised I got scammed.. It's the successor to my previous project Venturesome :)",
|
||||||
|
img: "/coding-16.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "dxdwm (Discontinued)",
|
||||||
|
desc: "a small x11 window manager written in rust.",
|
||||||
|
img: "/coding-17.webp",
|
||||||
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/dxdwm",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Revival Inc. (Finished)",
|
||||||
|
desc: "My game written in pygame and packaged with pygbag made for the Mini Jame Gam #55! tho I only made it in 6 hours lmao",
|
||||||
|
img: "/revivalinc.webp",
|
||||||
|
url: "https://dvorakmortonxd.dev/revival-inc",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const techProjects: TechProject[] = [
|
||||||
|
{
|
||||||
|
title: "Gentoo Setup",
|
||||||
|
desc: "my main computer with gentoo and SwayFX. specs: Ryzen 5 3600 (6c/12t), RX 580 8GB ASUS ROG, 16gb of ram and a 240gb sata ssd.",
|
||||||
|
image: "/gentoo-setup.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Proxmox Server",
|
||||||
|
desc: "my personal proxmox server (dm me on ig if u need a VPS/hosting), specs: Xeon E5 2680 v4 (14c/28t), RTX 3070 (llama.cpp), 68gb ddr4 rdimm ram (2*16gb, 1*32gb, 1*4gb), 256gb of sata m2 space + 1tb hdd + 750gb hdd.",
|
||||||
|
image: "/proxmox-server.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Xbox 360 S (badupdate)",
|
||||||
|
desc: "xbox 360 slim (trinity) with badupdate exploit, allowing to boot custom software. (not my photo), the specs are XCGPU (3c/6t), 0.5GB of gddr3 ram and a 500gb hdd.",
|
||||||
|
image: "/xbox360.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Lenovo Legion Go S",
|
||||||
|
desc: "my gaming handheld which I sometimes use as a computer, it has 32gb of unified lpddr5x memory and 1tb of nvme storage, I dualboot artix linux (openrc) with SwayFX and stock SteamOS on it.",
|
||||||
|
image: "/legiongos.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Macbook Air M4 13\"",
|
||||||
|
desc: "my main device for basically everything on the go except gaming. specs are Apple M4 (cpu:10c,gpu:8c), 16gb of unified ram (lpddr5x), 256gb Storage.",
|
||||||
|
image: "/macbook-air.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Macbook Air 2013 11\"",
|
||||||
|
desc: "bought this for tinkering lol, specs are intel core i5 (2c/4t), 8gb of ddr3 ram and 250gb ssd, installed arch linux on it with i3wm.",
|
||||||
|
image: "/macbook-air-11.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "iPhone 7 128gb",
|
||||||
|
desc: "somehow found a listing for 4 bucks (refurbed.cz) for it so I got it lol, it has a little dent I marked it on the photo (which isnt mine btw), except cosmetic damage its pretty much fully functional, specs are Apple A10 (4c/4t), 2gb of ram and 128gb of storage",
|
||||||
|
image: "/iphone-7.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Macbook Unibody 2010",
|
||||||
|
desc: "found random listing on bazos for 15 bucks but after I bought a power adapter it turned out to be non functioning so I got scammed :(",
|
||||||
|
image: "/macbook2010.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "ThinkPad T400s 14\"",
|
||||||
|
desc: "got it from a random guy for 20 bucks, its an old laptop from 2009. I put void linux on it and i3wm on it, specs are intel core 2 duo (2c/2t), 8gb ddr3 ram and 800gb hdd.",
|
||||||
|
image: "/thinkpadt400s.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Asus N56JR 15.6\"",
|
||||||
|
desc: "one of my first laptops my dad got for me when I was like 12, still works but the battery is KO, specs are intel core i7 4700HQ (4c/8t), 8gb ddr3 ram and 240gb ssd, it currently runs ubuntu linux 24.04LTS and my mom uses it for movies and shows.",
|
||||||
|
image: "/asuslaptop.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Small Unknown XP Acer Laptop",
|
||||||
|
desc: "found that one in ewaste, I think it has like 2gb of ram and an intel atom, not sure what to do with it yet",
|
||||||
|
image: "/acerlaptop.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Dell Latitude E6320",
|
||||||
|
desc: "also from ewaste, put mint on it but didnt do anything yet, lowk kinda capable for its time in 2011 so I might put it to use later but the battery is KO.",
|
||||||
|
image: "/latitude.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "iPhone 11 128gb",
|
||||||
|
desc: "my first iphone I got from my parents at 13, rn my dad has it because I switched over to the iphone 16 pro in 2025, specs are Apple A13 (6c/6t), 4gb of ram and 128gb of storage. (NOT MY IMAGE)",
|
||||||
|
image: "/iphone11.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "iPhone 16 Pro 128gb",
|
||||||
|
desc: "originally wanted iphone 13 mini (because of the size) but I somehow decided to get 16 pro, which is a bit smaller than my older iphone 11, specs are Apple A18 pro (6c/6t), (btw this chip is the same chip used in the macbook neo so thats cool) and 8gb of ram and 128gb of storage, my main phone.",
|
||||||
|
image: "/iphone16pro.webp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Xbox one S 2TB",
|
||||||
|
desc: "my dad bought it for me also in like 2018 or 2019 and I sometimes play the console edition of minecraft because I like to play the gliding minigame on it when someone comes over.",
|
||||||
|
image: "/xboxones.webp",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const friends: Friend[] = [
|
||||||
|
{
|
||||||
|
name: "Josef Skopec",
|
||||||
|
url: "/skopec.html",
|
||||||
|
realUrl: "https://skopec.dev/",
|
||||||
|
img: "/skopec.svg",
|
||||||
|
desc: "skopec.dev",
|
||||||
|
iframe: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Filip Bukovina",
|
||||||
|
url: "https://bukovinafilip.com/",
|
||||||
|
realUrl: "https://bukovinafilip.com/",
|
||||||
|
img: "/bukovina.svg",
|
||||||
|
desc: "bukovinafilip.com",
|
||||||
|
iframe: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Tomáš Vlk",
|
||||||
|
url: "https://vlcak.me",
|
||||||
|
realUrl: "https://vlcak.me",
|
||||||
|
img: "/vlcak.svg",
|
||||||
|
desc: "vlcak.me",
|
||||||
|
iframe: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const WALLPAPER = "/wallpaper.jpg";
|
||||||
|
export const WALLPAPER_CREDIT = "https://wallpaperaccess.com/open-source";
|
||||||
|
|
@ -24,7 +24,14 @@ export default function RootLayout({
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en" data-theme="skeuo" suppressHydrationWarning>
|
||||||
|
<head>
|
||||||
|
<script
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `(function(){try{var t=localStorage.getItem('theme');if(t==='terminal'||t==='skeuo'){document.documentElement.setAttribute('data-theme',t);}}catch(e){}})();`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</head>
|
||||||
<body className="antialiased">
|
<body className="antialiased">
|
||||||
{children}
|
{children}
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -1268,3 +1268,58 @@ body {
|
||||||
overflow-wrap: anywhere;
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
TUI STATUS BAR (terminal theme)
|
||||||
|
============================================ */
|
||||||
|
body {
|
||||||
|
padding-bottom: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-statusbar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 5000;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: rgba(29, 32, 33, 0.92);
|
||||||
|
border-top: 1px solid var(--tui-border);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
-webkit-backdrop-filter: blur(12px);
|
||||||
|
font-family: var(--font-custom-mono), 'JetBrains Mono', monospace;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-statusbar-item {
|
||||||
|
color: var(--gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-statusbar-btn {
|
||||||
|
padding: 3px 8px;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--gray);
|
||||||
|
color: var(--fg);
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-statusbar-btn:hover {
|
||||||
|
border-color: var(--accent);
|
||||||
|
color: var(--accent);
|
||||||
|
box-shadow: 0 0 8px rgba(250, 189, 47, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-statusbar-spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-statusbar-clock {
|
||||||
|
color: var(--gray);
|
||||||
|
}
|
||||||
|
|
|
||||||
593
src/app/page.tsx
593
src/app/page.tsx
|
|
@ -1,11 +1,7 @@
|
||||||
import Image from "next/image";
|
|
||||||
import "./page.css";
|
|
||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import type { CSSProperties } from 'react';
|
import './page.css';
|
||||||
import JokerLogo from "./components/JokerLogo";
|
import './skeuo.css';
|
||||||
import ServiceButton from "./components/ServiceButton";
|
import ThemeRoot from './components/ThemeRoot';
|
||||||
import SlBackground from "./components/SlBackground";
|
|
||||||
import ContributionHeatmap from "./components/ContributionHeatmap";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: 'dvorakmortonxd.dev',
|
title: 'dvorakmortonxd.dev',
|
||||||
|
|
@ -19,587 +15,6 @@ export const metadata: Metadata = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
type PanelStyle = CSSProperties & { '--panel-color'?: string };
|
|
||||||
|
|
||||||
const panelStyle = (color: string, style: CSSProperties = {}): PanelStyle => ({
|
|
||||||
...style,
|
|
||||||
'--panel-color': color,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Example projects array (you can edit this)
|
|
||||||
const codingProjects = [
|
|
||||||
{
|
|
||||||
title: "Hospital Execution (Unfinished)",
|
|
||||||
desc: "the first ever real game I made, in pygame. I've abandoned it.",
|
|
||||||
img: "/coding-1.webp",
|
|
||||||
url: "https://martin-dv.itch.io/hospital-execution-demo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Underbaranoia (Finished)",
|
|
||||||
desc: "basically a undertale like infinite fight simulator that gets progressively harder, made in pygame.",
|
|
||||||
img: "/coding-2.webp",
|
|
||||||
url: "https://martin-dv.itch.io/underbaranoia",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Offline memer (Finished)",
|
|
||||||
desc: "parody of the discord bot \"Dank Memer\" made in batch. (this was technically my first ever game I published).",
|
|
||||||
img: "/coding-3.webp",
|
|
||||||
url: "https://martin-dv.itch.io/offline-memer",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "4y (Forgotten)",
|
|
||||||
desc: "just a renamed fork of the ly login manager (based login manager btw I love it), no extra features, just a rename, its actually outdated so dont use it.",
|
|
||||||
img: "/coding-4.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4y",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "4rch linux (Forgotten)",
|
|
||||||
desc: "same as above, basically just a renamed fork of arch linux with calamares installer, also outdated and not maintained at all so no use please.",
|
|
||||||
img: "/coding-5.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4rch-linux",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "You_Are_An_Idiot_Virus.py (Finished)",
|
|
||||||
desc: "this is just a python script that just spams blinking \"you are an idiot\" windows, made it as a prank I think, not really sure rn.",
|
|
||||||
img: "/coding-6.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/uranidiot",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Venturesome (Discontinued)",
|
|
||||||
desc: "a browser I wrote in python using PyQtWebEngine with PyQt5, actually pretty cool and modular but I couldnt get past the stage of adding a tab system, basically surpassed by my other project: RustyWolf.",
|
|
||||||
img: "/coding-7.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/Venturesome",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Mandelbrot set in Pygame (Finished)",
|
|
||||||
desc: "a python pygame script that renders the mandelbrot set, made it when I was fascinated by how it looks and ngl it still looks cool af.",
|
|
||||||
img: "/coding-8.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/mandelbrot",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Underpygametale (Unfinished)",
|
|
||||||
desc: "a remake of undertale written in pygame, got it to about the flowey part (at the beginning) and didnt touch it in a long time.",
|
|
||||||
img: "/coding-9.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/underpygametale",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Many discord bots...",
|
|
||||||
desc: "so many of them, once I (allegedly, pls discord dont ban me) even wrote a \"self-bot\" which auto-advertised a minecraft server on minecraft discord server in lfg-hosting every two hours, around 800 people joined in total.",
|
|
||||||
img: "/coding-10.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/PYGETEX",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "MMO minecraft plugin (Unfinished)",
|
|
||||||
desc: "a minceraft plugin with custom bosses, items, and functions. pretty barebones and basic but I did it all manually before vibecoding was even a thing so what.",
|
|
||||||
img: "/coding-11.webp",
|
|
||||||
url: "https://www.youtube.com/watch?v=cSAX5Ds61ac",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Many many failed minecraft servers..",
|
|
||||||
desc: "creative games, softcraft, frostville, eusmp, eurthsmp, softsmp and many other SMPs that died later on. I cant even count how many mc servers I had in total.",
|
|
||||||
img: "/coding-12.webp",
|
|
||||||
url: "https://discord.gg/KtHRm9kRmy",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Swords and Sandals 2 pygame remake (Unfinished)",
|
|
||||||
desc: "an unfinished remake of swords and sandals 2 in pygame, I got bored of it and never finished it but ill finish it one day for sure lol.",
|
|
||||||
img: "/coding-13.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/sas2py",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Llama.cpp server",
|
|
||||||
desc: "my llama.cpp vm running on my proxmox with a gpu passthroughed RTX 3070, dm me if u wanna test it lol.",
|
|
||||||
img: "/coding-14.webp",
|
|
||||||
url: "https://ai.dvorakmortonxd.dev/",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Batch MSDOS Simulator (Finished)",
|
|
||||||
desc: "a freshman school project on making games in batch, it was like an OS simulator with a web browser, games, photos, even a video suprise (youll have to try it to figure that one out lol).",
|
|
||||||
img: "/coding-15.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/DvorakMSDOS",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "RustyWolf (WIP, Available now!)",
|
|
||||||
desc: "a browser I made in rust with webkitgtk, I made it to be lightweight and to be able to be ran on macbook unibody 2010 before I realised I got scammed.. It's the successor to my previous project Venturesome :)",
|
|
||||||
img: "/coding-16.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "dxdwm (Discontinued)",
|
|
||||||
desc: "a small x11 window manager written in rust.",
|
|
||||||
img: "/coding-17.webp",
|
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/dxdwm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Revival Inc. (Finished)",
|
|
||||||
desc: "My game written in pygame and packaged with pygbag made for the Mini Jame Gam #55! tho I only made it in 6 hours lmao",
|
|
||||||
img: "/revivalinc.webp",
|
|
||||||
url: "https://dvorakmortonxd.dev/revival-inc",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const socials = [
|
return <ThemeRoot />;
|
||||||
{ name: "Instagram (main)", icon: "/instagram.svg", url: "https://www.instagram.com/dvorakmortonxd/" },
|
|
||||||
{ name: "Instagram (gym)", icon: "/instagram.svg", url: "https://www.instagram.com/dvorakmortonxd2/" },
|
|
||||||
{ name: "SoundCloud", icon: "/soundcloud.svg", url: "https://soundcloud.com/martin-dvorak-185636305" },
|
|
||||||
{ name: "TikTok", icon: "/tiktok.svg", url: "https://www.tiktok.com/@dvorakmortonxd" },
|
|
||||||
{ name: "Snapchat", icon: "/snapchat.svg", url: "https://www.snapchat.com/add/dvorakmortonxd" },
|
|
||||||
{ name: "GitDXD", icon: "/github.svg", url: "https://git.dvorakmortonxd.dev/dvorakmortonxd" },
|
|
||||||
{ name: "LinkedIn", icon: "/linkedin.svg", url: "https://www.linkedin.com/in/martin-dvorak-32012a394/" },
|
|
||||||
{ name: "Itch.io", icon: "/itchio.svg", url: "https://martin-dv.itch.io" },
|
|
||||||
{ name: "Discord", icon: "/discord.svg", url: "https://discord.com/users/555745543763001364" },
|
|
||||||
{ name: "Reddit", icon: "/reddit.svg", url: "https://www.reddit.com/user/M4RT1NYT/" },
|
|
||||||
{ name: "Twitter", icon: "/twitter.svg", url: "https://x.com/pepicskopcecek" },
|
|
||||||
{ name: "Quipee", icon: "/quip.svg", url: "https://quipee.me/dvorakmortonxd" },
|
|
||||||
];
|
|
||||||
|
|
||||||
const techProjects = [
|
|
||||||
{
|
|
||||||
title: "Gentoo Setup",
|
|
||||||
desc: "my main computer with gentoo and SwayFX. specs: Ryzen 5 3600 (6c/12t), RX 580 8GB ASUS ROG, 16gb of ram and a 240gb sata ssd.",
|
|
||||||
image: "/gentoo-setup.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Proxmox Server",
|
|
||||||
desc: "my personal proxmox server (dm me on ig if u need a VPS/hosting), specs: Xeon E5 2680 v4 (14c/28t), RTX 3070 (llama.cpp), 68gb ddr4 rdimm ram (2*16gb, 1*32gb, 1*4gb), 256gb of sata m2 space + 1tb hdd + 750gb hdd.",
|
|
||||||
image: "/proxmox-server.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Xbox 360 S (badupdate)",
|
|
||||||
desc: "xbox 360 slim (trinity) with badupdate exploit, allowing to boot custom software. (not my photo), the specs are XCGPU (3c/6t), 0.5GB of gddr3 ram and a 500gb hdd.",
|
|
||||||
image: "/xbox360.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Lenovo Legion Go S",
|
|
||||||
desc: "my gaming handheld which I sometimes use as a computer, it has 32gb of unified lpddr5x memory and 1tb of nvme storage, I dualboot artix linux (openrc) with SwayFX and stock SteamOS on it.",
|
|
||||||
image: "/legiongos.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Macbook Air M4 13\"",
|
|
||||||
desc: "my main device for basically everything on the go except gaming. specs are Apple M4 (cpu:10c,gpu:8c), 16gb of unified ram (lpddr5x), 256gb Storage.",
|
|
||||||
image: "/macbook-air.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Macbook Air 2013 11\"",
|
|
||||||
desc: "bought this for tinkering lol, specs are intel core i5 (2c/4t), 8gb of ddr3 ram and 250gb ssd, installed arch linux on it with i3wm.",
|
|
||||||
image: "/macbook-air-11.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "iPhone 7 128gb",
|
|
||||||
desc: "somehow found a listing for 4 bucks (refurbed.cz) for it so I got it lol, it has a little dent I marked it on the photo (which isnt mine btw), except cosmetic damage its pretty much fully functional, specs are Apple A10 (4c/4t), 2gb of ram and 128gb of storage",
|
|
||||||
image: "/iphone-7.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Macbook Unibody 2010",
|
|
||||||
desc: "found random listing on bazos for 15 bucks but after I bought a power adapter it turned out to be non functioning so I got scammed :(",
|
|
||||||
image: "/macbook2010.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "ThinkPad T400s 14\"",
|
|
||||||
desc: "got it from a random guy for 20 bucks, its an old laptop from 2009. I put void linux on it and i3wm on it, specs are intel core 2 duo (2c/2t), 8gb ddr3 ram and 800gb hdd.",
|
|
||||||
image: "/thinkpadt400s.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Asus N56JR 15.6\"",
|
|
||||||
desc: "one of my first laptops my dad got for me when I was like 12, still works but the battery is KO, specs are intel core i7 4700HQ (4c/8t), 8gb ddr3 ram and 240gb ssd, it currently runs ubuntu linux 24.04LTS and my mom uses it for movies and shows.",
|
|
||||||
image: "/asuslaptop.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Small Unknown XP Acer Laptop",
|
|
||||||
desc: "found that one in ewaste, I think it has like 2gb of ram and an intel atom, not sure what to do with it yet",
|
|
||||||
image: "/acerlaptop.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Dell Latitude E6320",
|
|
||||||
desc: "also from ewaste, put mint on it but didnt do anything yet, lowk kinda capable for its time in 2011 so I might put it to use later but the battery is KO.",
|
|
||||||
image: "/latitude.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "iPhone 11 128gb",
|
|
||||||
desc: "my first iphone I got from my parents at 13, rn my dad has it because I switched over to the iphone 16 pro in 2025, specs are Apple A13 (6c/6t), 4gb of ram and 128gb of storage. (NOT MY IMAGE)",
|
|
||||||
image: "/iphone11.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "iPhone 16 Pro 128gb",
|
|
||||||
desc: "originally wanted iphone 13 mini (because of the size) but I somehow decided to get 16 pro, which is a bit smaller than my older iphone 11, specs are Apple A18 pro (6c/6t), (btw this chip is the same chip used in the macbook neo so thats cool) and 8gb of ram and 128gb of storage, my main phone.",
|
|
||||||
image: "/iphone16pro.webp",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Xbox one S 2TB",
|
|
||||||
desc: "my dad bought it for me also in like 2018 or 2019 and I sometimes play the console edition of minecraft because I like to play the gliding minigame on it when someone comes over.",
|
|
||||||
image: "/xboxones.webp",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const friends = [
|
|
||||||
{
|
|
||||||
name: "Josef Skopec",
|
|
||||||
url: "/skopec.html",
|
|
||||||
realUrl: "https://skopec.dev/",
|
|
||||||
img: "/skopec.svg",
|
|
||||||
desc: "skopec.dev",
|
|
||||||
iframe: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Filip Bukovina",
|
|
||||||
url: "https://bukovinafilip.com/",
|
|
||||||
realUrl: "https://bukovinafilip.com/",
|
|
||||||
img: "/bukovina.svg",
|
|
||||||
desc: "bukovinafilip.com",
|
|
||||||
iframe: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Tomáš Vlk",
|
|
||||||
url: "https://vlcak.me",
|
|
||||||
realUrl: "https://vlcak.me",
|
|
||||||
img: "/vlcak.svg",
|
|
||||||
desc: "vlcak.me",
|
|
||||||
iframe: true
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return <>
|
|
||||||
<SlBackground />
|
|
||||||
<div className="container">
|
|
||||||
|
|
||||||
{/* Header - TUI top bar */}
|
|
||||||
<header className="header">
|
|
||||||
<div className="header-center">
|
|
||||||
<JokerLogo />
|
|
||||||
<h1 className="site-name">dvorakmortonxd.dev</h1>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* Hero - TUI welcome panel */}
|
|
||||||
<main className="hero">
|
|
||||||
<div className="hero-panel" style={panelStyle('var(--accent)')}>
|
|
||||||
<span className="hero-panel-label" style={{ color: 'var(--accent)', borderColor: 'var(--accent)' }}>README.MD</span>
|
|
||||||
<h2 className="hero-title">$ whoami</h2>
|
|
||||||
<p className="hero-subtitle">
|
|
||||||
Welcome my personal website! Here I show off my projects and hardware I own, aswell as my self-hosted services :)<span className="cursor-blink"></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Search Panel */}
|
|
||||||
<div className="search-section">
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--white)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>SEARXNG.C</span>
|
|
||||||
<form action="https://search.dvorakmortonxd.dev/search" method="GET" target="_blank" rel="noopener noreferrer" className="search-form">
|
|
||||||
<input type="text" name="q" placeholder="Search... (only works for those who are whitelisted)" className="search-bar" />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Social Links Panel */}
|
|
||||||
<div className="social-section">
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--accent)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--accent)', borderColor: 'var(--accent)' }}>SOCIALS.JS</span>
|
|
||||||
<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>
|
|
||||||
<div className="mail-contact">
|
|
||||||
mail if u ever wanna contact me: <a href="mailto:dvorak@dvorakmortonxd.dev">dvorak@dvorakmortonxd.dev</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Gym SBD Panel */}
|
|
||||||
<div className="gym-section">
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--white)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>GYM_SBD_AT_73KG_BW.DB</span>
|
|
||||||
<div className="gym-grid">
|
|
||||||
<div className="gym-item">
|
|
||||||
<Image src="/squat.svg" alt="Squat" width={48} height={48} className="gym-icon" />
|
|
||||||
<div className="gym-label">SQUAT</div>
|
|
||||||
<div className="gym-weight">125kg</div>
|
|
||||||
<div className="gym-date" style={{ fontSize: '0.65rem', color: 'var(--gray)' }}>5.1.2025</div>
|
|
||||||
</div>
|
|
||||||
<div className="gym-item">
|
|
||||||
<Image src="/bench.svg" alt="Bench" width={48} height={48} className="gym-icon" />
|
|
||||||
<div className="gym-label">BENCH</div>
|
|
||||||
<div className="gym-weight">111kg</div>
|
|
||||||
<div className="gym-date" style={{ fontSize: '0.65rem', color: 'var(--gray)' }}>29.5.2026</div>
|
|
||||||
</div>
|
|
||||||
<div className="gym-item">
|
|
||||||
<Image src="/deadlift.svg" alt="Deadlift" width={48} height={48} className="gym-icon" />
|
|
||||||
<div className="gym-label">DEADLIFT</div>
|
|
||||||
<div className="gym-weight">165kg</div>
|
|
||||||
<div className="gym-date" style={{ fontSize: '0.65rem', color: 'var(--gray)' }}>17.12.2024</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Now Panel */}
|
|
||||||
<div className="about-section">
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--white)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>NOW.TXT</span>
|
|
||||||
<div className="about-content">
|
|
||||||
<p>
|
|
||||||
<span style={{ color: 'var(--green)' }}>martin@dvorakmortonxd</span>:<span className="text-blue">~</span>$ cat now.txt
|
|
||||||
</p>
|
|
||||||
<div style={{ color: '#a3a3a3' }}>
|
|
||||||
<p>
|
|
||||||
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 <span className="text-purple-500"><a href="https://skopec.dev">Pepa</a></span> are working on an education app so we can study more efficiently, It's called <span className="text-purple-500"><a href="https://git.dvorakmortonxd.dev/edu/maturita.c">maturita.c</a></span>!
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* About Me Panel */}
|
|
||||||
<div className="about-section">
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--accent)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--accent)', borderColor: 'var(--accent)' }}>README.MD</span>
|
|
||||||
<div className="about-content">
|
|
||||||
<p>
|
|
||||||
<span className="text-green">martin@dvorakmortonxd</span>:<span className="text-blue">~</span>$ cat about_me.md
|
|
||||||
</p>
|
|
||||||
<div style={{ color: '#a3a3a3' }}>
|
|
||||||
<p>
|
|
||||||
Hey, I'm Martin Dvořák — a 17(soon to be 18)-year-old IT student based in the Czech Republic, specializing in network management and administration at <span className="text-purple-500"><a href="https://sssvt.cz">sssvt.cz</a></span>. I'm a sophomore and I have wanted to go to this school since 7th grade (2022) so I'm happy I got in in 2025, the school is pretty cool so if you are in middle school and interested in IT, make sure to check it out. I'm a homelabber and developer heavily focused on self-hosting <i>literally everything</i>, writing code (for example games for gamejams), tinkering with GNU/Linux or Musl/Linux systems and retro hardware. I own a small collection of laptops ranging from 2009 to 2014 (and ofcourse my 2025 macbook), most of these found in ewaste. In my free time I mostly spend time with my gf {'<'}3, I also spend a bit of time setting up my self hosted stuff (like jellyfin or gitdxd), and also when I'm in my gaming mood I play terraria (around 1300hr playtime btw) and minecraft modpacks with mekanism and/or create. I also go to the gym around 3-5 times a week, running a PPL split focused on strength/powerlifting and especially SBD. I take a big focus on my health and physique.<span className="cursor-blink"></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Services Panel */}
|
|
||||||
<div className="services-section">
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--accent)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--accent)', borderColor: 'var(--accent)' }}>SERVICES.HTML</span>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* GitDXD Panel */}
|
|
||||||
<div className="gitdxd-section" style={{ marginTop: '20px' }}>
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--white)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>GITDXD.GIT</span>
|
|
||||||
<div style={{ padding: '24px 16px 16px' }}>
|
|
||||||
<h2 style={{ fontSize: '2.4rem', fontWeight: 'bold', color: 'var(--white)', marginBottom: '16px', textAlign: 'center' }}>GitDXD</h2>
|
|
||||||
<p style={{ fontSize: '1.8rem', color: 'var(--white)', fontWeight: '500', textAlign: 'center' }}>My Self-hosted Git Instance</p>
|
|
||||||
<div style={{ marginTop: '16px', marginBottom: '16px', borderRadius: '8px', overflow: 'hidden', border: '1px solid rgba(255, 255, 255, 0.4)', boxShadow: '0 0 30px rgba(180, 255, 125, 0.15)' }}>
|
|
||||||
<Image
|
|
||||||
src="/gitdxd.webp"
|
|
||||||
alt="GitDXD Preview"
|
|
||||||
width={1280}
|
|
||||||
height={720}
|
|
||||||
style={{ width: '100%', height: 'auto', display: 'block' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style={{ color: 'var(--gray)', marginTop: '12px', lineHeight: '1.6', textAlign: 'center' }}>
|
|
||||||
<p>My very own forgejo git instance, originally started as a private git instance for me and my friends to boycott GitHub but I've made it public now so. Join at <span className="text-purple-500"><a href="https://git.dvorakmortonxd.dev">git.dvorakmortonxd.dev</a></span>.<span className="cursor-blink"></span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Commits Panel */}
|
|
||||||
<div className="commits-section" style={{ marginTop: '20px' }}>
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--accent)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--accent)', borderColor: 'var(--accent)' }}>CONTRIBUTIONS@GITDXD.GIT</span>
|
|
||||||
<div className="commits-content" style={{ padding: '24px 12px 16px' }}>
|
|
||||||
<ContributionHeatmap />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* REVIVAL INC Panel */}
|
|
||||||
<div className="revival-section" style={{ marginTop: '20px' }}>
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--white)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>REVIVAL.INC</span>
|
|
||||||
<div style={{ padding: '24px 16px 16px' }}>
|
|
||||||
<h2 style={{ fontSize: '2.4rem', fontWeight: 'bold', color: 'var(--white)', marginBottom: '32px', textAlign: 'center' }}>Revival inc.</h2>
|
|
||||||
<div style={{ marginTop: '12px', marginBottom: '12px', borderRadius: '8px', overflow: 'hidden', border: '1px solid rgba(0, 0, 0, 0.4)', boxShadow: '0 0 30px rgba(255, 255, 255, 0.35)', width: '80%', margin: '12px auto' }}>
|
|
||||||
<Image
|
|
||||||
src="/revivalinc.webp"
|
|
||||||
alt="revival inc thumbnail"
|
|
||||||
width={768}
|
|
||||||
height={576}
|
|
||||||
style={{ width: '100%', height: 'auto', display: 'block' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p style={{ fontSize: '1.8rem', color: 'var(--white)', fontWeight: '500', textAlign: 'center' }}>What is it?</p>
|
|
||||||
<div style={{ color: 'var(--gray)', marginTop: '12px', lineHeight: '1.6' }}>
|
|
||||||
<p>It's 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 <span className="text-purple-500"><a href="https://martin-dv.itch.io/revival-inc">itch.io</a></span> or play <span className="text-purple-500"><a href="https://dvorakmortonxd.dev/revival-inc">here</a></span>.<span className="cursor-blink"></span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* RustyWolf Panel */}
|
|
||||||
<div className="rustywolf-section" style={{ marginTop: '20px' }}>
|
|
||||||
<div className="tui-panel" style={panelStyle('var(--white)')}>
|
|
||||||
<span className="tui-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>RUSTYWOLF.RS</span>
|
|
||||||
<div style={{ padding: '24px 16px 16px' }}>
|
|
||||||
<h2 style={{ fontSize: '2.4rem', fontWeight: 'bold', color: 'var(--white)', marginBottom: '32px', textAlign: 'center' }}>Introducing RustyWolf</h2>
|
|
||||||
<div style={{ marginTop: '12px', marginBottom: '12px', borderRadius: '8px', overflow: 'hidden', border: '1px solid rgba(255, 255, 255, 0.4)', boxShadow: '0 0 30px rgba(255, 255, 255, 0.2)' }}>
|
|
||||||
<Image
|
|
||||||
src="/RustyWolfPreview.webp"
|
|
||||||
alt="RustyWolf Browser Preview"
|
|
||||||
width={1280}
|
|
||||||
height={720}
|
|
||||||
style={{ width: '100%', height: 'auto', display: 'block' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p style={{ fontSize: '1.8rem', color: 'var(--white)', fontWeight: '500', textAlign: 'center' }}>What makes it so cool???</p>
|
|
||||||
<div style={{ color: 'var(--gray)', marginTop: '12px', lineHeight: '1.6' }}>
|
|
||||||
<p>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. It's a perfect browser for old machines that struggle with modern browsers. Check it out at <span style={{ color: 'var(--accent2)' }}><a href="https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf">GitDXD</a></span>.<span className="cursor-blink"></span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
{/* Projects */}
|
|
||||||
<section className="projects">
|
|
||||||
{/* Tech Section */}
|
|
||||||
<div className="subsection-wrapper">
|
|
||||||
<div className="subsection-panel" style={panelStyle('var(--white)')}>
|
|
||||||
<span className="subsection-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>TECH_LIST.JSON</span>
|
|
||||||
<h2 style={{ fontSize: '2rem', fontWeight: 'bold', textAlign: 'center', margin: '4px 0 20px', color: 'var(--white)' }}>All my hardware equipment :)</h2>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Coding Section */}
|
|
||||||
<div className="subsection-wrapper">
|
|
||||||
<div className="subsection-panel coding-panel" style={panelStyle('var(--accent)')}>
|
|
||||||
<span className="subsection-panel-label" style={{ color: 'var(--accent)', borderColor: 'var(--accent)' }}>PROJECTS.DOCX</span>
|
|
||||||
<h2 style={{ fontSize: '2rem', fontWeight: 'bold', textAlign: 'center', margin: '4px 0 20px', color: 'var(--accent)' }}>All the stuff I've worked on :))</h2>
|
|
||||||
<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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Friends Section */}
|
|
||||||
<div className="subsection-wrapper">
|
|
||||||
<div className="subsection-panel friends-panel" style={panelStyle('var(--white)', { backgroundColor: 'rgba(255, 255, 255, 0.02)' })}>
|
|
||||||
<span className="subsection-panel-label" style={{ color: 'var(--white)', borderColor: 'var(--white)' }}>FRIENDS.TSX</span>
|
|
||||||
<h2 style={{ fontSize: '2rem', fontWeight: 'bold', textAlign: 'center', margin: '4px 0 20px', color: 'var(--white)' }}>Friend's websites and projects</h2>
|
|
||||||
<div className="services-buttons" style={{ gap: '1rem' }}>
|
|
||||||
{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%', filter: 'brightness(0) invert(65%) hue-rotate(70deg) saturate(100%)' }} />}
|
|
||||||
name={friend.name}
|
|
||||||
desc={friend.desc}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={{ marginTop: '12px', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '16px' }}>
|
|
||||||
<h3 style={{ fontSize: '1.5rem', color: 'var(--accent)', fontWeight: '600' }}>Quipee by Bukovina Filip & Vlk Tomáš</h3>
|
|
||||||
<div style={{ width: '100%', borderRadius: '8px', overflow: 'hidden', border: '1px solid rgba(255, 255, 0, 0.3)', boxShadow: '0 0 20px rgba(255, 255, 0, 0.1)' }}>
|
|
||||||
<Image src="/quipee.webp" alt="Quipee Thumbnail" width={1280} height={720} style={{ width: '100%', height: 'auto', display: 'block' }} />
|
|
||||||
</div>
|
|
||||||
<div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap', justifyContent: 'center' }}>
|
|
||||||
<a href="https://quipee.me" target="_blank" rel="noopener noreferrer" style={{ backgroundColor: 'rgba(255, 255, 255, 0.04)', color: 'var(--white)', padding: '6px 16px', borderRadius: '6px', fontSize: '1rem', fontWeight: '500', textDecoration: 'none', border: '1px solid rgba(255, 255, 0, 0.3)' }}>Web</a>
|
|
||||||
<a href="https://drive.google.com/drive/folders/1oi76JyWs6J84MUmCGV7GvtLUexXI8Jel?usp=share_link" target="_blank" rel="noopener noreferrer" style={{ backgroundColor: 'rgba(255, 255, 255, 0.04)', color: 'var(--white)', padding: '6px 16px', borderRadius: '6px', fontSize: '1rem', fontWeight: '500', textDecoration: 'none', border: '1px solid rgba(255, 255, 0, 0.3)' }}>Android</a>
|
|
||||||
<a href="https://testflight.apple.com/join/hP2a1E5x" target="_blank" rel="noopener noreferrer" style={{ backgroundColor: 'rgba(255, 255, 255, 0.04)', color: 'var(--white)', padding: '6px 16px', borderRadius: '6px', fontSize: '1rem', fontWeight: '500', textDecoration: 'none', border: '1px solid rgba(255, 255, 0, 0.3)' }}>IOS</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<footer className="footer">
|
|
||||||
<span className="footer-label">v1.2.1</span>
|
|
||||||
© 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just follow the GPL3.0 License)
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1029
src/app/skeuo.css
Normal file
1029
src/app/skeuo.css
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue