revamp projects/hardware as grouped index lists, drop emoji tiles, add Freezmo feature section
This commit is contained in:
parent
dae4f1c414
commit
95dd0128b8
10 changed files with 730 additions and 398 deletions
140
src/app/components/ProjectIndex.tsx
Normal file
140
src/app/components/ProjectIndex.tsx
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import type { CSSProperties, ReactNode } from "react";
|
||||
import {
|
||||
codingProjects,
|
||||
techProjects,
|
||||
type CodingProject,
|
||||
type CodingProjectGroup,
|
||||
type ProjectStatus,
|
||||
type TechProject,
|
||||
type TechProjectGroup,
|
||||
} from "../data";
|
||||
|
||||
const STATUS_LABEL: Record<ProjectStatus, string> = {
|
||||
finished: "Finished",
|
||||
live: "Live",
|
||||
wip: "WIP",
|
||||
unfinished: "Unfinished",
|
||||
discontinued: "Discontinued",
|
||||
forgotten: "Forgotten",
|
||||
};
|
||||
|
||||
const PROJECT_GROUPS: { id: CodingProjectGroup; title: string }[] = [
|
||||
{ id: "games", title: "Games & game jams" },
|
||||
{ id: "linux", title: "Linux & desktop" },
|
||||
{ id: "bots", title: "Bots, servers & plugins" },
|
||||
{ id: "apps", title: "Apps & experiments" },
|
||||
];
|
||||
|
||||
const HARDWARE_GROUPS: { id: TechProjectGroup; title: string }[] = [
|
||||
{ id: "desktops", title: "Desktops & servers" },
|
||||
{ id: "laptops", title: "Laptops" },
|
||||
{ id: "phones", title: "Phones" },
|
||||
{ id: "consoles", title: "Consoles & handhelds" },
|
||||
];
|
||||
|
||||
/**
|
||||
* Grouped, repo-listing-style index that replaced the old card gallery.
|
||||
* Coding rows: language-coloured dot — title (+ status pill) over the
|
||||
* description — host/language tag. Hardware rows: plain rows with the year
|
||||
* on the right. Coding rows are links; hardware rows are static.
|
||||
*/
|
||||
function Group({
|
||||
title,
|
||||
count,
|
||||
children,
|
||||
}: {
|
||||
title: string;
|
||||
count: number;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<section className="index-group">
|
||||
<h3 className="index-group-head">
|
||||
<span>{title}</span>
|
||||
<span className="index-group-count">{count}</span>
|
||||
</h3>
|
||||
<div className="index-list">{children}</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function CodingRow({ project }: { project: CodingProject }) {
|
||||
return (
|
||||
<a
|
||||
href={project.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="index-row"
|
||||
style={{ "--index-accent": project.accent } as CSSProperties}
|
||||
>
|
||||
<span className="index-dot" aria-hidden="true" />
|
||||
<span className="index-body">
|
||||
<span className="index-line1">
|
||||
<span className="index-title">{project.title}</span>
|
||||
{project.status && (
|
||||
<span className={`index-status index-status-${project.status}`}>
|
||||
{STATUS_LABEL[project.status]}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
<span className="index-desc">{project.desc}</span>
|
||||
</span>
|
||||
<span className="index-meta">
|
||||
<span>{project.tag}</span>
|
||||
<span className="index-arrow" aria-hidden="true">
|
||||
↗
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
function HardwareRow({ project }: { project: TechProject }) {
|
||||
return (
|
||||
<div className="index-row index-row-plain">
|
||||
<span className="index-body">
|
||||
<span className="index-line1">
|
||||
<span className="index-title">{project.title}</span>
|
||||
</span>
|
||||
<span className="index-desc">{project.desc}</span>
|
||||
</span>
|
||||
<span className="index-meta">{project.year ?? ""}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function CodingProjectIndex() {
|
||||
return (
|
||||
<div className="index-groups">
|
||||
{PROJECT_GROUPS.map((group) => {
|
||||
const items = codingProjects.filter((p) => p.group === group.id);
|
||||
if (!items.length) return null;
|
||||
return (
|
||||
<Group key={group.id} title={group.title} count={items.length}>
|
||||
{items.map((project) => (
|
||||
<CodingRow key={project.slug} project={project} />
|
||||
))}
|
||||
</Group>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function HardwareProjectIndex() {
|
||||
return (
|
||||
<div className="index-groups">
|
||||
{HARDWARE_GROUPS.map((group) => {
|
||||
const items = techProjects.filter((p) => p.group === group.id);
|
||||
if (!items.length) return null;
|
||||
return (
|
||||
<Group key={group.id} title={group.title} count={items.length}>
|
||||
{items.map((project) => (
|
||||
<HardwareRow key={project.slug} project={project} />
|
||||
))}
|
||||
</Group>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -6,10 +6,11 @@ import JokerLogo from "./JokerLogo";
|
|||
import ServiceButton from "./ServiceButton";
|
||||
import ContributionHeatmap from "./ContributionHeatmap";
|
||||
import FeatureWindow from "./FeatureWindow";
|
||||
import { CodingProjectIndex, HardwareProjectIndex } from "./ProjectIndex";
|
||||
import Clock from "./Clock";
|
||||
import { useTheme } from "./useTheme";
|
||||
import { useColorScheme } from "./useColorScheme";
|
||||
import { socials, codingProjects, techProjects, friends } from "../data";
|
||||
import { socials, friends } from "../data";
|
||||
|
||||
const NAV = [
|
||||
{ id: "overview", label: "Overview" },
|
||||
|
|
@ -234,6 +235,23 @@ export default function WebLayout() {
|
|||
</article>
|
||||
</div>
|
||||
|
||||
<Section eyebrow="FREEZMO" title="Introducing Freezmo" className="web-feature">
|
||||
<Image
|
||||
src="/freezmo-app.webp"
|
||||
alt="Freezmo quiz screen — a history question about the Schuman plan with AI grading feedback"
|
||||
width={1941}
|
||||
height={942}
|
||||
sizes="(max-width: 900px) 100vw, 1100px"
|
||||
className="web-feature-shot"
|
||||
/>
|
||||
<p className="web-feature-text">
|
||||
Started working on a new project Freezmo — basically a free version of the
|
||||
famous Gizmo app, but instead of paying for AI you use your ollama free cloud
|
||||
API key. Notes in, flashcards and quizzes out. Try it at{" "}
|
||||
<a href="https://freezmo.dvorakmortonxd.dev">freezmo.dvorakmortonxd.dev</a>.
|
||||
</p>
|
||||
</Section>
|
||||
|
||||
<div className="web-split">
|
||||
<Section eyebrow="REVIVAL.INC" title="Revival Inc." className="web-feature">
|
||||
<FeatureWindow variant="game" />
|
||||
|
|
@ -246,7 +264,7 @@ export default function WebLayout() {
|
|||
</p>
|
||||
</Section>
|
||||
|
||||
<Section eyebrow="RustyWolf" title="Introducing RustyWolf" className="web-feature">
|
||||
<Section eyebrow="BROWSER" title="RustyWolf" className="web-feature">
|
||||
<FeatureWindow variant="browser" />
|
||||
<p className="web-feature-text">
|
||||
A lightweight browser made in Rust with WebKitGTK. It's the successor to my
|
||||
|
|
@ -267,37 +285,11 @@ export default function WebLayout() {
|
|||
</Section>
|
||||
|
||||
<Section id="projects" eyebrow="Portfolio" title="Things I've worked on">
|
||||
<div className="project-grid">
|
||||
{codingProjects.map((project, idx) => (
|
||||
<a
|
||||
key={idx}
|
||||
href={project.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="project-card"
|
||||
>
|
||||
<div className={`project-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||
{project.emoji}
|
||||
</div>
|
||||
<h4 className="project-title">{project.title}</h4>
|
||||
<p className="project-desc">{project.desc}</p>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<CodingProjectIndex />
|
||||
</Section>
|
||||
|
||||
<Section id="hardware" eyebrow="My gear" title="Hardware I own">
|
||||
<div className="project-grid">
|
||||
{techProjects.map((project, idx) => (
|
||||
<div key={project.title} className="project-card">
|
||||
<div className={`project-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||
{project.emoji}
|
||||
</div>
|
||||
<h4 className="project-title">{project.title}</h4>
|
||||
<p className="project-desc">{project.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<HardwareProjectIndex />
|
||||
</Section>
|
||||
|
||||
<Section id="friends" eyebrow="Links" title="Friend's websites and projects">
|
||||
|
|
|
|||
|
|
@ -2,15 +2,11 @@
|
|||
|
||||
import Image from "next/image";
|
||||
import { useEffect, useRef, useState, type KeyboardEvent as ReactKeyboardEvent, type ReactNode } from "react";
|
||||
import {
|
||||
socials,
|
||||
codingProjects,
|
||||
techProjects,
|
||||
friends,
|
||||
} from "../data";
|
||||
import { socials, friends } from "../data";
|
||||
import ServiceButton from "./ServiceButton";
|
||||
import ContributionHeatmap from "./ContributionHeatmap";
|
||||
import FeatureWindow from "./FeatureWindow";
|
||||
import { CodingProjectIndex, HardwareProjectIndex } from "./ProjectIndex";
|
||||
import JokerLogo from "./JokerLogo";
|
||||
import { setTheme } from "./useTheme";
|
||||
|
||||
|
|
@ -107,10 +103,14 @@ function NowApp() {
|
|||
<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>!
|
||||
cooking daily, because im bulking through out the non-summer seasons. I started
|
||||
working on a new project{" "}
|
||||
<a href="https://freezmo.dvorakmortonxd.dev">Freezmo</a>, basically a free
|
||||
version of the famous Gizmo app but instead of paying for AI you use your ollama
|
||||
free cloud api key. The education app I started with my pal{" "}
|
||||
<a href="https://skopec.dev">Pepa</a>, maturita.c, now lives on as{" "}
|
||||
<a href="https://github.com/pepaskopec-blip/Graduately">Graduately</a> under his
|
||||
wing.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -204,23 +204,7 @@ function ServicesApp() {
|
|||
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-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||
{project.emoji}
|
||||
</div>
|
||||
<h4 className="project-title">{project.title}</h4>
|
||||
<p className="project-desc">{project.desc}</p>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<CodingProjectIndex />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -228,17 +212,7 @@ function ProjectsApp() {
|
|||
function HardwareApp() {
|
||||
return (
|
||||
<div className="app-pad">
|
||||
<div className="project-grid">
|
||||
{techProjects.map((project, idx) => (
|
||||
<div key={project.title} className="project-card">
|
||||
<div className={`project-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||
{project.emoji}
|
||||
</div>
|
||||
<h4 className="project-title">{project.title}</h4>
|
||||
<p className="project-desc">{project.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<HardwareProjectIndex />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -480,7 +454,7 @@ function RevivalApp() {
|
|||
function RustyWolfApp() {
|
||||
return (
|
||||
<div className="app-pad app-center">
|
||||
<h2 className="app-h1">Introducing RustyWolf</h2>
|
||||
<h2 className="app-h1">RustyWolf</h2>
|
||||
<FeatureWindow variant="browser" />
|
||||
<p className="app-h2">What makes it so cool???</p>
|
||||
<p className="app-text">
|
||||
|
|
@ -513,7 +487,7 @@ const TERMINAL_FILES: Record<string, string> = {
|
|||
"about_me.md":
|
||||
"Hey, I'm Martin Dvorak, a 17 year old IT student from the Czech Republic.\nI self-host way too many things and tinker with GNU/Linux.",
|
||||
"now.txt":
|
||||
"Currently hosting an SMP and building an education app with Pepa.",
|
||||
"Currently hosting an SMP. Started working on a new project Freezmo, basically a free version of the famous Gizmo app but instead of paying for AI you use your ollama free cloud api key.",
|
||||
"resume.txt":
|
||||
"sssvt.cz - network management & administration (2025-)\nGentoo, SwayFX, RustyWolf, dxdwm, Revival Inc.",
|
||||
};
|
||||
|
|
|
|||
266
src/app/data.ts
266
src/app/data.ts
|
|
@ -4,19 +4,46 @@ export interface Social {
|
|||
url: string;
|
||||
}
|
||||
|
||||
/** Lifecycle state of a coding project, shown as a chip on its index row. */
|
||||
export type ProjectStatus =
|
||||
| "finished"
|
||||
| "live"
|
||||
| "wip"
|
||||
| "unfinished"
|
||||
| "discontinued"
|
||||
| "forgotten";
|
||||
|
||||
/** Section a coding project is filed under in the Projects index. */
|
||||
export type CodingProjectGroup = "games" | "linux" | "bots" | "apps";
|
||||
|
||||
export interface CodingProject {
|
||||
title: string;
|
||||
desc: string;
|
||||
/** Emoji glyph shown on the card's CSS gradient tile (no image assets). */
|
||||
emoji: string;
|
||||
/** Stable key for the index row (also the React key), e.g. `rustywolf`. */
|
||||
slug: string;
|
||||
/** Index group the project is listed under. */
|
||||
group: CodingProjectGroup;
|
||||
/** Status chip on the row; omitted for grab-bag entries. */
|
||||
status?: ProjectStatus;
|
||||
/** Language or host badge on the row. */
|
||||
tag: string;
|
||||
/** Hex accent for the row dot + hover tint. */
|
||||
accent: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
/** Section a device is filed under in the Hardware index. */
|
||||
export type TechProjectGroup = "desktops" | "laptops" | "phones" | "consoles";
|
||||
|
||||
export interface TechProject {
|
||||
title: string;
|
||||
desc: string;
|
||||
/** Emoji glyph shown on the card's CSS gradient tile (no image assets). */
|
||||
emoji: string;
|
||||
/** Stable key for the index row (also the React key), e.g. `macbook-air-m4`. */
|
||||
slug: string;
|
||||
/** Index group the device is listed under. */
|
||||
group: TechProjectGroup;
|
||||
/** Model / build year, shown on the right when known. */
|
||||
year?: string;
|
||||
}
|
||||
|
||||
export interface Friend {
|
||||
|
|
@ -54,190 +81,317 @@ export const socials: Social[] = [
|
|||
|
||||
export const codingProjects: CodingProject[] = [
|
||||
{
|
||||
title: "Hospital Execution (Unfinished)",
|
||||
title: "Hospital Execution",
|
||||
desc: "the first ever real game I made, in pygame. I've abandoned it.",
|
||||
emoji: "🏥",
|
||||
slug: "hospital-execution",
|
||||
group: "games",
|
||||
status: "unfinished",
|
||||
tag: "itch.io",
|
||||
accent: "#fa5c5c",
|
||||
url: "https://martin-dv.itch.io/hospital-execution-demo",
|
||||
},
|
||||
{
|
||||
title: "Underbaranoia (Finished)",
|
||||
title: "Underbaranoia",
|
||||
desc: "basically a undertale like infinite fight simulator that gets progressively harder, made in pygame.",
|
||||
emoji: "⚔️",
|
||||
slug: "underbaranoia",
|
||||
group: "games",
|
||||
status: "finished",
|
||||
tag: "itch.io",
|
||||
accent: "#fa5c5c",
|
||||
url: "https://martin-dv.itch.io/underbaranoia",
|
||||
},
|
||||
{
|
||||
title: "Offline memer (Finished)",
|
||||
title: "Offline memer",
|
||||
desc: "parody of the discord bot \"Dank Memer\" made in batch. (this was technically my first ever game I published).",
|
||||
emoji: "🤖",
|
||||
slug: "offline-memer",
|
||||
group: "games",
|
||||
status: "finished",
|
||||
tag: "itch.io",
|
||||
accent: "#fa5c5c",
|
||||
url: "https://martin-dv.itch.io/offline-memer",
|
||||
},
|
||||
{
|
||||
title: "4y (Forgotten)",
|
||||
title: "The Larvae",
|
||||
desc: "my entry for Mini Jam 212 (theme: Control), made in pygame. you spawn in a well developed city and parasite on people with your manipulative powers until you get so rich you destroy it.",
|
||||
slug: "the-larvae",
|
||||
group: "games",
|
||||
status: "unfinished",
|
||||
tag: "Python",
|
||||
accent: "#cf6bd6",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/the-larvae",
|
||||
},
|
||||
{
|
||||
title: "4y",
|
||||
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.",
|
||||
emoji: "🔐",
|
||||
slug: "4y",
|
||||
group: "linux",
|
||||
status: "forgotten",
|
||||
tag: "C",
|
||||
accent: "#7d8590",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4y",
|
||||
},
|
||||
{
|
||||
title: "4rch linux (Forgotten)",
|
||||
title: "4rch linux",
|
||||
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.",
|
||||
emoji: "🐧",
|
||||
slug: "4rch-linux",
|
||||
group: "linux",
|
||||
status: "forgotten",
|
||||
tag: "Shell",
|
||||
accent: "#89e051",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4rch-linux",
|
||||
},
|
||||
{
|
||||
title: "You_Are_An_Idiot_Virus.py (Finished)",
|
||||
title: "You_Are_An_Idiot_Virus.py",
|
||||
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.",
|
||||
emoji: "🪟",
|
||||
slug: "uranidiot",
|
||||
group: "apps",
|
||||
status: "finished",
|
||||
tag: "Python",
|
||||
accent: "#3572A5",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/uranidiot",
|
||||
},
|
||||
{
|
||||
title: "Venturesome (Discontinued)",
|
||||
title: "Venturesome",
|
||||
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.",
|
||||
emoji: "🌐",
|
||||
slug: "venturesome",
|
||||
group: "linux",
|
||||
status: "discontinued",
|
||||
tag: "Python",
|
||||
accent: "#3572A5",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/Venturesome",
|
||||
},
|
||||
{
|
||||
title: "Mandelbrot set in Pygame (Finished)",
|
||||
title: "Mandelbrot set in Pygame",
|
||||
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.",
|
||||
emoji: "🌀",
|
||||
slug: "mandelbrot",
|
||||
group: "apps",
|
||||
status: "finished",
|
||||
tag: "Python",
|
||||
accent: "#8b5cf6",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/mandelbrot",
|
||||
},
|
||||
{
|
||||
title: "Underpygametale (Unfinished)",
|
||||
title: "Underpygametale",
|
||||
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.",
|
||||
emoji: "💀",
|
||||
slug: "underpygametale",
|
||||
group: "games",
|
||||
status: "unfinished",
|
||||
tag: "Python",
|
||||
accent: "#ef476f",
|
||||
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.",
|
||||
emoji: "💬",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/PYGETEX",
|
||||
desc: "so many of them, once I (allegedly, pls discord dont ban me) even wrote a \"self-bot\" (lfg-bot) which auto-advertised a minecraft server on minecraft discord server in lfg-hosting every two hours, around 800 people joined in total.",
|
||||
slug: "lfg-bot",
|
||||
group: "bots",
|
||||
tag: "Python",
|
||||
accent: "#5865F2",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/lfg-bot",
|
||||
},
|
||||
{
|
||||
title: "MMO minecraft plugin (Unfinished)",
|
||||
title: "MMO minecraft plugin",
|
||||
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.",
|
||||
emoji: "⛏️",
|
||||
slug: "mmo-plugin",
|
||||
group: "bots",
|
||||
status: "unfinished",
|
||||
tag: "YouTube",
|
||||
accent: "#ff3d3d",
|
||||
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.",
|
||||
emoji: "🧱",
|
||||
slug: "smp-graveyard",
|
||||
group: "bots",
|
||||
tag: "Discord",
|
||||
accent: "#62b47a",
|
||||
url: "https://discord.gg/KtHRm9kRmy",
|
||||
},
|
||||
{
|
||||
title: "Swords and Sandals 2 pygame remake (Unfinished)",
|
||||
title: "Swords and Sandals 2 pygame remake",
|
||||
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.",
|
||||
emoji: "🗡️",
|
||||
slug: "sas2py",
|
||||
group: "games",
|
||||
status: "unfinished",
|
||||
tag: "Python",
|
||||
accent: "#d97706",
|
||||
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.",
|
||||
emoji: "🦾",
|
||||
slug: "llama-cpp",
|
||||
group: "bots",
|
||||
status: "live",
|
||||
tag: "self-hosted",
|
||||
accent: "#76b900",
|
||||
url: "https://ai.dvorakmortonxd.dev/",
|
||||
},
|
||||
{
|
||||
title: "Batch MSDOS Simulator (Finished)",
|
||||
title: "Batch MSDOS Simulator",
|
||||
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).",
|
||||
emoji: "💾",
|
||||
slug: "dvorakmsdos",
|
||||
group: "linux",
|
||||
status: "finished",
|
||||
tag: "Batchfile",
|
||||
accent: "#b6d94c",
|
||||
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 :)",
|
||||
emoji: "🐺",
|
||||
title: "RustyWolf",
|
||||
desc: "my privacy focused browser made in rust with webkitgtk, made lightweight so it can run on a macbook unibody 2010 before I realised I got scammed.. It's the successor to my previous project Venturesome :)",
|
||||
slug: "rustywolf",
|
||||
group: "linux",
|
||||
status: "wip",
|
||||
tag: "Rust",
|
||||
accent: "#dea584",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf",
|
||||
},
|
||||
{
|
||||
title: "dxdwm (Discontinued)",
|
||||
desc: "a small x11 window manager written in rust.",
|
||||
emoji: "🪟",
|
||||
title: "dxdwm",
|
||||
desc: "a small x11 window manager. originally written in rust (dxdwm-rs), now continued in C.",
|
||||
slug: "dxdwm",
|
||||
group: "linux",
|
||||
status: "discontinued",
|
||||
tag: "C",
|
||||
accent: "#94a3b8",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/dxdwm",
|
||||
},
|
||||
{
|
||||
title: "Revival Inc. (Finished)",
|
||||
title: "Revival Inc.",
|
||||
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",
|
||||
emoji: "🧟",
|
||||
slug: "revival-inc",
|
||||
group: "games",
|
||||
status: "finished",
|
||||
tag: "Python",
|
||||
accent: "#10b981",
|
||||
url: "https://dvorakmortonxd.dev/revival-inc",
|
||||
},
|
||||
{
|
||||
title: "freezmo",
|
||||
desc: "a free version of the famous Gizmo app: notes in, flashcards and quizzes out — instead of paying for AI you use your own ollama free cloud api key.",
|
||||
slug: "freezmo",
|
||||
group: "apps",
|
||||
status: "wip",
|
||||
tag: "TypeScript",
|
||||
accent: "#3178c6",
|
||||
url: "https://freezmo.dvorakmortonxd.dev",
|
||||
},
|
||||
{
|
||||
title: "qol-tweaks",
|
||||
desc: "my quality of life plugin for the dvorakmortonxd SMP.",
|
||||
slug: "qol-tweaks",
|
||||
group: "bots",
|
||||
status: "live",
|
||||
tag: "Java",
|
||||
accent: "#b07219",
|
||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/qol-tweaks",
|
||||
},
|
||||
];
|
||||
|
||||
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.",
|
||||
emoji: "🐧",
|
||||
slug: "gentoo-swayfx",
|
||||
group: "desktops",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "🖥️",
|
||||
slug: "proxmox-server",
|
||||
group: "desktops",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "🎮",
|
||||
slug: "xbox-360-s",
|
||||
group: "consoles",
|
||||
year: "2010",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "🕹️",
|
||||
slug: "legion-go-s",
|
||||
group: "consoles",
|
||||
year: "2025",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "💻",
|
||||
slug: "macbook-air-m4",
|
||||
group: "laptops",
|
||||
year: "2025",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "💻",
|
||||
slug: "macbook-air-2013",
|
||||
group: "laptops",
|
||||
year: "2013",
|
||||
},
|
||||
{
|
||||
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",
|
||||
emoji: "📱",
|
||||
slug: "iphone-7",
|
||||
group: "phones",
|
||||
year: "2016",
|
||||
},
|
||||
{
|
||||
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 :(",
|
||||
emoji: "💻",
|
||||
slug: "macbook-unibody-2010",
|
||||
group: "laptops",
|
||||
year: "2010",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "💻",
|
||||
slug: "thinkpad-t400s",
|
||||
group: "laptops",
|
||||
year: "2009",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "💻",
|
||||
slug: "asus-n56jr",
|
||||
group: "laptops",
|
||||
year: "2013",
|
||||
},
|
||||
{
|
||||
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",
|
||||
emoji: "📟",
|
||||
slug: "unknown-acer-xp",
|
||||
group: "laptops",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "💻",
|
||||
slug: "latitude-e6320",
|
||||
group: "laptops",
|
||||
year: "2011",
|
||||
},
|
||||
{
|
||||
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)",
|
||||
emoji: "📱",
|
||||
slug: "iphone-11",
|
||||
group: "phones",
|
||||
year: "2019",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "📱",
|
||||
slug: "iphone-16-pro",
|
||||
group: "phones",
|
||||
year: "2025",
|
||||
},
|
||||
{
|
||||
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.",
|
||||
emoji: "🎮",
|
||||
slug: "xbox-one-s",
|
||||
group: "consoles",
|
||||
year: "2016",
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -852,41 +852,6 @@ a.win-icon {
|
|||
color: #9a9a9a;
|
||||
}
|
||||
|
||||
.app-surface .project-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
.app-surface .project-card {
|
||||
padding: 10px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
border-radius: 6px;
|
||||
background: linear-gradient(to bottom, #ffffff, #f0f4fa);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
|
||||
}
|
||||
.app-surface .project-card:hover {
|
||||
border-color: #7db9e8;
|
||||
background: #ffffff;
|
||||
box-shadow: 0 0 0 1px #7db9e8, 0 0 14px rgba(110, 185, 255, 0.5),
|
||||
0 8px 18px rgba(0, 25, 55, 0.2);
|
||||
}
|
||||
.app-surface .project-thumb {
|
||||
height: 150px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
.app-surface .project-title {
|
||||
color: #0e3355;
|
||||
}
|
||||
.app-surface .project-card:hover .project-title {
|
||||
color: #0d5aa7;
|
||||
}
|
||||
.app-surface .project-desc {
|
||||
color: #43607c;
|
||||
}
|
||||
.app-surface .project-card:hover .project-desc {
|
||||
color: #1d3e5c;
|
||||
}
|
||||
|
||||
.app-surface .gym-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
|
|
@ -1151,29 +1116,29 @@ a.win-icon {
|
|||
.win-body .service-button:hover .service-desc {
|
||||
color: #d3dae3;
|
||||
}
|
||||
.win-body .project-card {
|
||||
border-color: #1b1e20;
|
||||
background: linear-gradient(to bottom, #31363b, #2a2e32);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
||||
/* Project/Hardware index inside the dark KDE windows. */
|
||||
.win-body {
|
||||
--index-line: rgba(255, 255, 255, 0.07);
|
||||
--status-finished: #4ade80;
|
||||
--status-live: #60a5fa;
|
||||
--status-wip: #fbbf24;
|
||||
--status-unfinished: #fb923c;
|
||||
--status-discontinued: #f87171;
|
||||
--status-forgotten: #94a3b8;
|
||||
}
|
||||
.win-body .project-card:hover {
|
||||
border-color: #3daee9;
|
||||
background: #353b40;
|
||||
box-shadow: 0 0 0 1px #3daee9, 0 0 14px rgba(61, 174, 233, 0.45);
|
||||
.win-body .index-list {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
.win-body .project-thumb {
|
||||
border-color: #1b1e20;
|
||||
}
|
||||
.win-body .project-title {
|
||||
.win-body .index-title {
|
||||
color: #eff0f1;
|
||||
}
|
||||
.win-body .project-card:hover .project-title {
|
||||
color: #3daee9;
|
||||
}
|
||||
.win-body .project-desc {
|
||||
.win-body .index-desc {
|
||||
color: #b0b6bc;
|
||||
}
|
||||
.win-body .project-card:hover .project-desc {
|
||||
.win-body a.index-row:hover {
|
||||
background: rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
.win-body a.index-row:hover .index-desc {
|
||||
color: #d3dae3;
|
||||
}
|
||||
|
||||
|
|
@ -1600,9 +1565,6 @@ html[data-theme="skeuo"] .fw {
|
|||
.app-pad {
|
||||
padding: 14px;
|
||||
}
|
||||
.app-surface .project-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.app-surface .social-buttons {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
|
@ -1613,8 +1575,14 @@ html[data-theme="skeuo"] .fw {
|
|||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
}
|
||||
.app-surface .project-thumb {
|
||||
height: 140px;
|
||||
.app-surface .index-group-head {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
.app-surface .index-row {
|
||||
padding: 10px 11px;
|
||||
}
|
||||
.app-surface .index-desc {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
243
src/app/web.css
243
src/app/web.css
|
|
@ -44,6 +44,15 @@
|
|||
--red: #e11d48;
|
||||
--darkpink: #db2777;
|
||||
|
||||
/* Project/Hardware index tokens */
|
||||
--index-line: rgba(16, 24, 43, 0.1);
|
||||
--status-finished: #15803d;
|
||||
--status-live: #1d4ed8;
|
||||
--status-wip: #b45309;
|
||||
--status-unfinished: #c2410c;
|
||||
--status-discontinued: #b91c1c;
|
||||
--status-forgotten: #64748b;
|
||||
|
||||
--web-font: "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
--font-custom-mono: ui-monospace, "JetBrains Mono", "SFMono-Regular", Menlo, Consolas,
|
||||
|
|
@ -84,6 +93,15 @@ html[data-theme="web"][data-scheme="dark"] {
|
|||
--purple: #c084fc;
|
||||
--red: #fb7185;
|
||||
--darkpink: #f472b6;
|
||||
|
||||
/* Project/Hardware index tokens */
|
||||
--index-line: rgba(255, 255, 255, 0.09);
|
||||
--status-finished: #4ade80;
|
||||
--status-live: #60a5fa;
|
||||
--status-wip: #fbbf24;
|
||||
--status-unfinished: #fb923c;
|
||||
--status-discontinued: #f87171;
|
||||
--status-forgotten: #94a3b8;
|
||||
}
|
||||
|
||||
html[data-theme="web"] {
|
||||
|
|
@ -430,6 +448,17 @@ html[data-theme="web"] body {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
/* Real app screenshot inside a feature panel (Freezmo) — framed like the CSS
|
||||
mock windows so it sits in the same visual language. */
|
||||
.web-feature-shot {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
margin-bottom: 14px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid var(--glass-border);
|
||||
box-shadow: 0 18px 36px -22px rgba(23, 32, 60, 0.5);
|
||||
}
|
||||
/* ============================================================
|
||||
FEATURE WINDOWS
|
||||
Asset-free decorative mock windows that replace the old
|
||||
|
|
@ -1161,78 +1190,145 @@ html[data-theme="web"] body {
|
|||
}
|
||||
|
||||
/* ============================================================
|
||||
PROJECTS / HARDWARE
|
||||
============================================================ */
|
||||
.project-grid {
|
||||
/* Masonry-ish gallery: multi-column packs the cards tightly, so a short card
|
||||
never leaves a half-empty slot under a tall neighbour. */
|
||||
columns: 3 250px;
|
||||
column-gap: 14px;
|
||||
PROJECTS / HARDWARE INDEX
|
||||
------------------------------------------------------------
|
||||
Grouped repo-listing layout: per-section group headers, then
|
||||
rows of accent dot – title (+ status) over description – tag /
|
||||
year. Replaced the old card gallery. */
|
||||
.index-groups {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 22px;
|
||||
}
|
||||
.project-card {
|
||||
display: block;
|
||||
break-inside: avoid;
|
||||
-webkit-column-break-inside: avoid;
|
||||
margin-bottom: 14px;
|
||||
padding: 12px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid var(--btn-border, var(--glass-border));
|
||||
.index-group-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin: 0 0 8px;
|
||||
font-family: var(--font-custom-mono);
|
||||
font-size: 0.66rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.16em;
|
||||
text-transform: uppercase;
|
||||
color: var(--gray);
|
||||
}
|
||||
.index-group-count {
|
||||
font-weight: 600;
|
||||
color: color-mix(in srgb, var(--gray) 55%, transparent);
|
||||
}
|
||||
.index-group-head::after {
|
||||
content: "";
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--index-line);
|
||||
}
|
||||
.index-list {
|
||||
border: 1px solid var(--index-line);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: var(--btn-bg, var(--glass-lo));
|
||||
box-shadow: var(--btn-shadow, none);
|
||||
}
|
||||
.index-list > * + * {
|
||||
border-top: 1px solid var(--index-line);
|
||||
}
|
||||
.index-row {
|
||||
display: grid;
|
||||
grid-template-columns: 10px minmax(0, 1fr) auto;
|
||||
gap: 14px;
|
||||
align-items: start;
|
||||
padding: 11px 14px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease,
|
||||
background-color 0.22s ease;
|
||||
}
|
||||
.project-card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: var(--accent-line);
|
||||
/* Hardware rows: no accent dot (it carried no meaning there), so the body
|
||||
takes the full first track. */
|
||||
.index-row-plain {
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
}
|
||||
a.index-row {
|
||||
transition: background-color 0.16s ease;
|
||||
}
|
||||
a.index-row:hover {
|
||||
background: var(--btn-bg-hi, var(--glass-hi));
|
||||
box-shadow: 0 20px 38px -20px rgba(23, 32, 60, 0.55);
|
||||
}
|
||||
.project-thumb {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
height: 150px;
|
||||
width: 100%;
|
||||
margin-bottom: 12px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid var(--glass-border);
|
||||
font-size: 2.6rem;
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
text-shadow: 0 3px 10px rgba(0, 0, 0, 0.35);
|
||||
.index-dot {
|
||||
width: 9px;
|
||||
height: 9px;
|
||||
margin-top: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--index-accent, var(--accent));
|
||||
box-shadow: 0 0 9px color-mix(in srgb, var(--index-accent, var(--accent)) 55%, transparent);
|
||||
}
|
||||
/* Shared gradient palette for the card tiles (no image assets). */
|
||||
.thumb-0 {
|
||||
background: linear-gradient(150deg, #6d5efc, #2f8bff);
|
||||
.index-line1 {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.thumb-1 {
|
||||
background: linear-gradient(150deg, #ec4899, #db2777);
|
||||
}
|
||||
.thumb-2 {
|
||||
background: linear-gradient(150deg, #f59e0b, #d97757);
|
||||
}
|
||||
.thumb-3 {
|
||||
background: linear-gradient(150deg, #10b981, #0d9488);
|
||||
}
|
||||
.thumb-4 {
|
||||
background: linear-gradient(150deg, #8b5cf6, #6366f1);
|
||||
}
|
||||
.thumb-5 {
|
||||
background: linear-gradient(150deg, #06b6d4, #3b82f6);
|
||||
}
|
||||
.project-title {
|
||||
font-size: 0.95rem;
|
||||
.index-title {
|
||||
font-size: 0.92rem;
|
||||
font-weight: 700;
|
||||
color: var(--fg);
|
||||
}
|
||||
.project-card:hover .project-title {
|
||||
color: var(--accent);
|
||||
a.index-row:hover .index-title {
|
||||
color: color-mix(in srgb, var(--index-accent, var(--accent)) 72%, var(--fg));
|
||||
}
|
||||
.project-desc {
|
||||
margin-top: 4px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--web-muted);
|
||||
.index-status {
|
||||
padding: 1px 7px 2px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid color-mix(in srgb, currentColor 32%, transparent);
|
||||
background: color-mix(in srgb, currentColor 10%, transparent);
|
||||
font-family: var(--font-custom-mono);
|
||||
font-size: 0.56rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--status-forgotten);
|
||||
}
|
||||
.index-status-finished {
|
||||
color: var(--status-finished);
|
||||
}
|
||||
.index-status-live {
|
||||
color: var(--status-live);
|
||||
}
|
||||
.index-status-wip {
|
||||
color: var(--status-wip);
|
||||
}
|
||||
.index-status-unfinished {
|
||||
color: var(--status-unfinished);
|
||||
}
|
||||
.index-status-discontinued {
|
||||
color: var(--status-discontinued);
|
||||
}
|
||||
.index-status-forgotten {
|
||||
color: var(--status-forgotten);
|
||||
}
|
||||
.index-desc {
|
||||
display: block;
|
||||
margin-top: 3px;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.5;
|
||||
color: var(--gray);
|
||||
}
|
||||
.index-meta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding-top: 3px;
|
||||
font-family: var(--font-custom-mono);
|
||||
font-size: 0.62rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--gray);
|
||||
white-space: nowrap;
|
||||
}
|
||||
.index-arrow {
|
||||
transition: transform 0.16s ease, color 0.16s ease;
|
||||
}
|
||||
a.index-row:hover .index-arrow {
|
||||
transform: translate(2px, -2px);
|
||||
color: color-mix(in srgb, var(--index-accent, var(--accent)) 72%, var(--fg));
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
|
|
@ -1750,27 +1846,20 @@ html[data-theme="web"][data-scheme="dark"] .heatmap-legend-cell[data-level="4"]
|
|||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
/* Projects/hardware gallery: 2-up on phones instead of one full-width card
|
||||
per row, with a shorter image + tighter card so a row is compact. */
|
||||
.project-grid {
|
||||
columns: 2;
|
||||
column-gap: 10px;
|
||||
/* Projects/hardware index: tighter rows on phones. */
|
||||
.index-groups {
|
||||
gap: 18px;
|
||||
}
|
||||
.project-card {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
.index-row {
|
||||
gap: 10px;
|
||||
padding: 10px 11px;
|
||||
}
|
||||
.project-thumb {
|
||||
height: 90px;
|
||||
margin-bottom: 8px;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
.project-title {
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
.project-desc {
|
||||
.index-desc {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.index-meta {
|
||||
font-size: 0.58rem;
|
||||
}
|
||||
.services-buttons,
|
||||
.services-buttons.services-main {
|
||||
grid-template-columns: 1fr;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue