replace raster assets with CSS: emoji gradient cards, mock windows (add forge), gradient wallpaper
14
README.md
|
|
@ -36,6 +36,11 @@ more.
|
||||||
hand-built CSS mock windows instead of screenshots: a little necromancy game scene whose
|
hand-built CSS mock windows instead of screenshots: a little necromancy game scene whose
|
||||||
blinking "PRESS START" launches the game, and a little browser window with tabs in the
|
blinking "PRESS START" launches the game, and a little browser window with tabs in the
|
||||||
title bar, a toolbar and a start page.
|
title bar, a toolbar and a start page.
|
||||||
|
- **Asset-free cards & wallpaper** — every project/hardware card is a CSS gradient tile with
|
||||||
|
an emoji glyph (no screenshots), the desktop shell's app previews are the same CSS mock
|
||||||
|
windows (a git-forge page for GitDXD), and its wallpaper is a layered CSS gradient. The
|
||||||
|
only real images left are the logo, the social SVGs, the Joker easter egg and the Gentoo
|
||||||
|
mark.
|
||||||
- **Draggable desktop icons** — free placement that snaps to a measured grid, one icon per
|
- **Draggable desktop icons** — free placement that snaps to a measured grid, one icon per
|
||||||
cell, with a follow-the-cursor drag ghost. Icons shrink on cramped viewports so they never
|
cell, with a follow-the-cursor drag ghost. Icons shrink on cramped viewports so they never
|
||||||
collide.
|
collide.
|
||||||
|
|
@ -76,8 +81,9 @@ more.
|
||||||
imported for the base layer but the UI is custom CSS.
|
imported for the base layer but the UI is custom CSS.
|
||||||
- **Fonts:** the web theme uses the system sans stack; Monocraft (self-hosted in `public/`) is
|
- **Fonts:** the web theme uses the system sans stack; Monocraft (self-hosted in `public/`) is
|
||||||
used by the desktop theme's SMP menu and the in-desktop terminal.
|
used by the desktop theme's SMP menu and the in-desktop terminal.
|
||||||
- **Images:** `next/image`
|
- **Images:** `next/image` — only the logo (`src/app/icon.png`), the social SVGs, the Joker
|
||||||
- **Version:** `2.2.13` (see `package.json`)
|
easter egg and the Gentoo mark; all cards, feature/app previews and the wallpaper are CSS.
|
||||||
|
- **Version:** `2.2.14` (see `package.json`)
|
||||||
- **Dependencies:** `npm audit` reports **0 vulnerabilities**. `next` is kept at a patched
|
- **Dependencies:** `npm audit` reports **0 vulnerabilities**. `next` is kept at a patched
|
||||||
release (`>=16.3.6`) for the `next/og` RCE, and `brace-expansion` is force-upgraded via
|
release (`>=16.3.6`) for the `next/og` RCE, and `brace-expansion` is force-upgraded via
|
||||||
`overrides`. `braces` (a transitive ESLint/`fast-glob` dependency) has **no upstream fix**,
|
`overrides`. `braces` (a transitive ESLint/`fast-glob` dependency) has **no upstream fix**,
|
||||||
|
|
@ -187,7 +193,7 @@ src/app/
|
||||||
globals.css → base/reset styles + Tailwind import
|
globals.css → base/reset styles + Tailwind import
|
||||||
web.css → web theme styles (frosted glass, light + dark)
|
web.css → web theme styles (frosted glass, light + dark)
|
||||||
skeuo.css → desktop theme styles (KDE/Plasma shell)
|
skeuo.css → desktop theme styles (KDE/Plasma shell)
|
||||||
data.ts → socials, codingProjects, techProjects, friends, wallpapers
|
data.ts → socials, codingProjects, techProjects, friends
|
||||||
revival-inc/page.tsx → embeds the bundled game at /public/revival-inc/index.html
|
revival-inc/page.tsx → embeds the bundled game at /public/revival-inc/index.html
|
||||||
api/
|
api/
|
||||||
heatmap/route.ts → contribution heatmap proxy
|
heatmap/route.ts → contribution heatmap proxy
|
||||||
|
|
@ -216,7 +222,7 @@ deploy/
|
||||||
install-system-service.sh → installs the system unit (run with sudo/doas)
|
install-system-service.sh → installs the system unit (run with sudo/doas)
|
||||||
vendor/
|
vendor/
|
||||||
braces/ → locally patched braces@3.0.4 (depth guards for CVE-2026-93687; no upstream fix)
|
braces/ → locally patched braces@3.0.4 (depth guards for CVE-2026-93687; no upstream fix)
|
||||||
public/ → fonts, wallpapers, icons, /revival-inc game, llms.txt, robots.txt, sitemap.xml
|
public/ → fonts, social SVGs, /revival-inc game, llms.txt, robots.txt, sitemap.xml
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🌍 Deploying?
|
## 🌍 Deploying?
|
||||||
|
|
|
||||||
37
agents.md
|
|
@ -34,7 +34,7 @@ When in doubt, prefer updating. A stale README **or** agents.md is treated as a
|
||||||
## Bump the version on EVERY prompt — also do this every time
|
## Bump the version on EVERY prompt — also do this every time
|
||||||
|
|
||||||
Another standing requirement: increment the **patch** version (`x.x.+1`, so
|
Another standing requirement: increment the **patch** version (`x.x.+1`, so
|
||||||
`2.2.12` → `2.2.13` → …) as part of every task, even the small ones. Keep all of
|
`2.2.13` → `2.2.14` → …) as part of every task, even the small ones. Keep all of
|
||||||
these in sync:
|
these in sync:
|
||||||
|
|
||||||
- `package.json` → `"version"`
|
- `package.json` → `"version"`
|
||||||
|
|
@ -56,7 +56,7 @@ frosted-glass **web** site, and an alternate KDE/Plasma **desktop simulation**
|
||||||
utilities in the components (Tailwind is present via PostCSS but the look is
|
utilities in the components (Tailwind is present via PostCSS but the look is
|
||||||
hand-written CSS).
|
hand-written CSS).
|
||||||
- Path alias: `@/*` → `src/*`.
|
- Path alias: `@/*` → `src/*`.
|
||||||
- Version: `2.2.13` (see `package.json`).
|
- Version: `2.2.14` (see `package.json`).
|
||||||
|
|
||||||
### Scripts
|
### Scripts
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -90,7 +90,7 @@ src/app/
|
||||||
page.tsx → renders <ThemeRoot/>, imports web.css + skeuo.css
|
page.tsx → renders <ThemeRoot/>, imports web.css + skeuo.css
|
||||||
layout.tsx → html shell, metadata, ThemeScript
|
layout.tsx → html shell, metadata, ThemeScript
|
||||||
globals.css → base/reset styles + Tailwind import
|
globals.css → base/reset styles + Tailwind import
|
||||||
data.ts → socials, codingProjects, techProjects, friends, wallpapers
|
data.ts → socials, codingProjects, techProjects, friends
|
||||||
web.css → web theme: frosted glass, light + dark tokens
|
web.css → web theme: frosted glass, light + dark tokens
|
||||||
skeuo.css → Windows/Plasma desktop styles (desktop theme only)
|
skeuo.css → Windows/Plasma desktop styles (desktop theme only)
|
||||||
revival-inc/page.tsx → fullscreen iframe embedding /public/revival-inc/index.html
|
revival-inc/page.tsx → fullscreen iframe embedding /public/revival-inc/index.html
|
||||||
|
|
@ -103,7 +103,8 @@ src/app/
|
||||||
components/
|
components/
|
||||||
ThemeRoot.tsx → picks which shell to mount (the router of the UI)
|
ThemeRoot.tsx → picks which shell to mount (the router of the UI)
|
||||||
WebLayout.tsx → "web" theme (default): sticky sidebar + glass content
|
WebLayout.tsx → "web" theme (default): sticky sidebar + glass content
|
||||||
FeatureWindow.tsx → decorative CSS "windows" for the two feature panels (game / browser)
|
FeatureWindow.tsx → decorative CSS "windows" (game / browser / forge); used in the
|
||||||
|
web feature panels and the desktop app windows
|
||||||
WindowsDesktop.tsx → "skeuo" theme, desktop: icons, windows, taskbar
|
WindowsDesktop.tsx → "skeuo" theme, desktop: icons, windows, taskbar
|
||||||
WinWindow.tsx → a single draggable/resizable window
|
WinWindow.tsx → a single draggable/resizable window
|
||||||
apps.tsx → APPS registry + the content of each app + in-app terminal
|
apps.tsx → APPS registry + the content of each app + in-app terminal
|
||||||
|
|
@ -158,7 +159,11 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
||||||
(Josef is 🧌 goblin, the rest 🧙 — the old per-friend SVGs are gone).
|
(Josef is 🧌 goblin, the rest 🧙 — the old per-friend SVGs are gone).
|
||||||
Projects/hardware use a CSS multi-column
|
Projects/hardware use a CSS multi-column
|
||||||
**masonry** gallery (`.project-grid`) so short cards don't leave half-empty
|
**masonry** gallery (`.project-grid`) so short cards don't leave half-empty
|
||||||
grid slots; on phones it drops to 2 columns with a shorter card image. The two feature panels (`.web-split`) stretch
|
grid slots; on phones it drops to 2 columns with a shorter tile. Cards are
|
||||||
|
**asset-free**: each renders a `.project-thumb` — a `.thumb-N` gradient
|
||||||
|
(N = index % 6) with the item's `emoji` glyph centred — instead of a
|
||||||
|
screenshot. `codingProjects` / `techProjects` in `data.ts` carry `emoji`
|
||||||
|
(no `img`/`image`). The two feature panels (`.web-split`) stretch
|
||||||
to equal height and share a fixed `16 / 10` `.fw` window (the `FeatureWindow`
|
to equal height and share a fixed `16 / 10` `.fw` window (the `FeatureWindow`
|
||||||
component) — a decorative, **asset-free CSS mock-up** rather than a screenshot:
|
component) — a decorative, **asset-free CSS mock-up** rather than a screenshot:
|
||||||
Revival Inc. is a little necromancy game scene (night sky, moon, tombstones,
|
Revival Inc. is a little necromancy game scene (night sky, moon, tombstones,
|
||||||
|
|
@ -168,10 +173,18 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
||||||
`aria-hidden` but "PRESS START" is a **real link** to the game
|
`aria-hidden` but "PRESS START" is a **real link** to the game
|
||||||
(`https://dvorakmortonxd.dev/revival-inc`). The real copy stays in the
|
(`https://dvorakmortonxd.dev/revival-inc`). The real copy stays in the
|
||||||
`.web-feature-text` paragraph below.
|
`.web-feature-text` paragraph below.
|
||||||
The old raster feature shots (`.web-shot` + `next/image`) were removed from the
|
`FeatureWindow` also has a **`forge`** variant (a little git-forge repo page)
|
||||||
web theme only — `revivalinc.webp` / `RustyWolfPreview.webp` are still used by
|
and all three are reused inside the desktop app windows (GitDXD → forge,
|
||||||
the desktop theme and the projects gallery, so the files stay. The old stacked
|
Revival Inc. → game, RustyWolf → browser), so there are no app-preview
|
||||||
TUI panel layout and the `SlBackground` ASCII train were removed earlier.
|
screenshots. The old stacked TUI panel layout and the `SlBackground` ASCII
|
||||||
|
train were removed earlier.
|
||||||
|
- **No raster UI assets.** Every card, feature panel, app preview and the desktop
|
||||||
|
wallpaper is drawn in CSS: project/hardware cards are `.project-thumb` gradient
|
||||||
|
tiles with an `emoji`, the feature/app previews are `FeatureWindow` mock windows,
|
||||||
|
and `.win-desktop` carries a layered gradient "wallpaper" (there is no
|
||||||
|
`wallpaper.jpg`). Only the social SVGs, the site logo (`src/app/icon.png`), the
|
||||||
|
Joker easter egg (`joker.webp`) and the Gentoo mark (`gentoo.svg`) remain as
|
||||||
|
real image files.
|
||||||
- **Not a terminal.** The web theme deliberately has no TUI chrome: the hero is
|
- **Not a terminal.** The web theme deliberately has no TUI chrome: the hero is
|
||||||
a name + blurb (no `$ whoami` prompt, no blinking cursor), section eyebrows are
|
a name + blurb (no `$ whoami` prompt, no blinking cursor), section eyebrows are
|
||||||
plain words (not `README.MD` / `TECH_LIST.JSON` filenames), and the activity
|
plain words (not `README.MD` / `TECH_LIST.JSON` filenames), and the activity
|
||||||
|
|
@ -473,9 +486,9 @@ knows about icon ids, via `APP_BY_ID`.
|
||||||
contain `data-theme="web"` / `data-scheme="dark"` and the `.web-root` markup.
|
contain `data-theme="web"` / `data-scheme="dark"` and the `.web-root` markup.
|
||||||
Theme + scheme are read pre-paint from `localStorage.theme` / `.scheme`, so a
|
Theme + scheme are read pre-paint from `localStorage.theme` / `.scheme`, so a
|
||||||
quick check is to set those in devtools and reload.
|
quick check is to set those in devtools and reload.
|
||||||
- `next/image` is lazy by default, so a headless full-page screenshot shows the
|
- There are almost no raster images left (only the logo, the social SVGs, the
|
||||||
below-the-fold feature shots as blank boxes. Scroll the page
|
Joker easter egg and the Gentoo mark), so a headless full-page screenshot no
|
||||||
slowly first and they load; this is a capture artifact, not a bug. Headless
|
longer shows blank lazy-image boxes below the fold. Headless
|
||||||
Chromium lives at `~/.cache/ms-playwright/chromium-*/chrome-linux64/chrome`
|
Chromium lives at `~/.cache/ms-playwright/chromium-*/chrome-linux64/chrome`
|
||||||
(drive it with `--headless=new --remote-debugging-port=…` and CDP).
|
(drive it with `--headless=new --remote-debugging-port=…` and CDP).
|
||||||
- A dev server may already be running on port 3000 — on this host it is normally
|
- A dev server may already be running on port 3000 — on this host it is normally
|
||||||
|
|
|
||||||
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "dvorakmortonxd",
|
"name": "dvorakmortonxd",
|
||||||
"version": "2.2.13",
|
"version": "2.2.14",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "dvorakmortonxd",
|
"name": "dvorakmortonxd",
|
||||||
"version": "2.2.13",
|
"version": "2.2.14",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"next": "^16.3.8",
|
"next": "^16.3.8",
|
||||||
"react": "^19.3.0",
|
"react": "^19.3.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "dvorakmortonxd",
|
"name": "dvorakmortonxd",
|
||||||
"version": "2.2.13",
|
"version": "2.2.14",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node scripts/dev-server.mjs",
|
"dev": "node scripts/dev-server.mjs",
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 954 B |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 876 B |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 1 MiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
|
@ -93,7 +93,45 @@ function BrowserBody() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function FeatureWindow({ variant }: { variant: "game" | "browser" }) {
|
function ForgeBody() {
|
||||||
|
const files = ["src/", "public/", "package.json", "README.md", "LICENSE"];
|
||||||
|
return (
|
||||||
|
<div className="fw-forge">
|
||||||
|
<div className="fw-forge-head">
|
||||||
|
<span className="fw-forge-repo">
|
||||||
|
dvorakmortonxd / <b>dvorakmortonxd.dev</b>
|
||||||
|
</span>
|
||||||
|
<span className="fw-forge-tabs">
|
||||||
|
<span className="fw-forge-tab fw-forge-tab-active">Code</span>
|
||||||
|
<span className="fw-forge-tab">Issues</span>
|
||||||
|
<span className="fw-forge-tab">Pull requests</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="fw-forge-body">
|
||||||
|
<ul className="fw-forge-files">
|
||||||
|
{files.map((f) => (
|
||||||
|
<li key={f}>
|
||||||
|
<span className="fw-forge-file-icon" />
|
||||||
|
{f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<div className="fw-forge-code">
|
||||||
|
{Array.from({ length: 8 }).map((_, i) => (
|
||||||
|
<span key={i} className="fw-code-line" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="fw-forge-lang">
|
||||||
|
<span className="fw-lang-seg fw-lang-ts" />
|
||||||
|
<span className="fw-lang-seg fw-lang-css" />
|
||||||
|
<span className="fw-lang-seg fw-lang-md" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FeatureWindow({ variant }: { variant: "game" | "browser" | "forge" }) {
|
||||||
if (variant === "game") {
|
if (variant === "game") {
|
||||||
return (
|
return (
|
||||||
<Chrome title="revival-inc — mini jame gam #55" decorative={false}>
|
<Chrome title="revival-inc — mini jame gam #55" decorative={false}>
|
||||||
|
|
@ -101,6 +139,13 @@ export default function FeatureWindow({ variant }: { variant: "game" | "browser"
|
||||||
</Chrome>
|
</Chrome>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (variant === "forge") {
|
||||||
|
return (
|
||||||
|
<Chrome title="GitDXD — dvorakmortonxd/dvorakmortonxd.dev">
|
||||||
|
<ForgeBody />
|
||||||
|
</Chrome>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Chrome
|
<Chrome
|
||||||
tabs={
|
tabs={
|
||||||
|
|
|
||||||
|
|
@ -276,10 +276,9 @@ export default function WebLayout() {
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="project-card"
|
className="project-card"
|
||||||
>
|
>
|
||||||
<div
|
<div className={`project-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||||
className="project-image"
|
{project.emoji}
|
||||||
style={{ backgroundImage: `url(${project.img})` }}
|
</div>
|
||||||
/>
|
|
||||||
<h4 className="project-title">{project.title}</h4>
|
<h4 className="project-title">{project.title}</h4>
|
||||||
<p className="project-desc">{project.desc}</p>
|
<p className="project-desc">{project.desc}</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -289,12 +288,11 @@ export default function WebLayout() {
|
||||||
|
|
||||||
<Section id="hardware" eyebrow="My gear" title="Hardware I own">
|
<Section id="hardware" eyebrow="My gear" title="Hardware I own">
|
||||||
<div className="project-grid">
|
<div className="project-grid">
|
||||||
{techProjects.map((project) => (
|
{techProjects.map((project, idx) => (
|
||||||
<div key={project.title} className="project-card">
|
<div key={project.title} className="project-card">
|
||||||
<div
|
<div className={`project-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||||
className="project-image"
|
{project.emoji}
|
||||||
style={{ backgroundImage: `url(${project.image})` }}
|
</div>
|
||||||
/>
|
|
||||||
<h4 className="project-title">{project.title}</h4>
|
<h4 className="project-title">{project.title}</h4>
|
||||||
<p className="project-desc">{project.desc}</p>
|
<p className="project-desc">{project.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -318,7 +316,7 @@ export default function WebLayout() {
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<footer className="web-footer glass">
|
<footer className="web-footer glass">
|
||||||
<span className="web-footer-label">v2.2.13</span>
|
<span className="web-footer-label">v2.2.14</span>
|
||||||
© 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just
|
© 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just
|
||||||
follow the GPL3.0 License)
|
follow the GPL3.0 License)
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import WinWindow, { type WinState } from "./WinWindow";
|
||||||
import Clock from "./Clock";
|
import Clock from "./Clock";
|
||||||
import { useTheme } from "./useTheme";
|
import { useTheme } from "./useTheme";
|
||||||
import { useDesktopIcons } from "./useDesktopIcons";
|
import { useDesktopIcons } from "./useDesktopIcons";
|
||||||
import { WALLPAPER, friends } from "../data";
|
import { friends } from "../data";
|
||||||
|
|
||||||
// The panel sits at `bottom: 10px` with a height of 44px, so its top edge is
|
// The panel sits at `bottom: 10px` with a height of 44px, so its top edge is
|
||||||
// 54px above the viewport bottom. Windows clamp 5px above that (59), so a
|
// 54px above the viewport bottom. Windows clamp 5px above that (59), so a
|
||||||
|
|
@ -24,7 +24,6 @@ interface Shortcut {
|
||||||
url?: string;
|
url?: string;
|
||||||
appId?: string;
|
appId?: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
image?: string;
|
|
||||||
/** Show the real site in an iframe. Only for sites that allow framing. */
|
/** Show the real site in an iframe. Only for sites that allow framing. */
|
||||||
embed?: boolean;
|
embed?: boolean;
|
||||||
/** Frame src when it differs from `url` (e.g. a local mirror of a blocking site). */
|
/** Frame src when it differs from `url` (e.g. a local mirror of a blocking site). */
|
||||||
|
|
@ -37,7 +36,6 @@ interface IconEntry {
|
||||||
title: string;
|
title: string;
|
||||||
glyph: ReactNode;
|
glyph: ReactNode;
|
||||||
color?: string;
|
color?: string;
|
||||||
image?: string;
|
|
||||||
onOpen: () => void;
|
onOpen: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -224,7 +222,6 @@ export default function WindowsDesktop() {
|
||||||
url: s.url,
|
url: s.url,
|
||||||
desc: s.desc,
|
desc: s.desc,
|
||||||
icon: s.icon,
|
icon: s.icon,
|
||||||
image: s.image,
|
|
||||||
embed: s.embed,
|
embed: s.embed,
|
||||||
embedUrl: s.embedUrl,
|
embedUrl: s.embedUrl,
|
||||||
});
|
});
|
||||||
|
|
@ -336,8 +333,6 @@ export default function WindowsDesktop() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const wallpaper = `url('${WALLPAPER}')`;
|
|
||||||
|
|
||||||
const iconClick = (id: string, action: () => void) => {
|
const iconClick = (id: string, action: () => void) => {
|
||||||
if (consumeDrag()) return;
|
if (consumeDrag()) return;
|
||||||
activateIcon(id, action);
|
activateIcon(id, action);
|
||||||
|
|
@ -389,18 +384,7 @@ export default function WindowsDesktop() {
|
||||||
className="win-icon-glyph"
|
className="win-icon-glyph"
|
||||||
style={entry.color ? { background: entry.color } : undefined}
|
style={entry.color ? { background: entry.color } : undefined}
|
||||||
>
|
>
|
||||||
{entry.image ? (
|
{entry.glyph}
|
||||||
<Image
|
|
||||||
src={entry.image}
|
|
||||||
alt={entry.label}
|
|
||||||
width={38}
|
|
||||||
height={38}
|
|
||||||
className="win-icon-img"
|
|
||||||
draggable={false}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
entry.glyph
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
<span className="win-icon-label">{entry.label}</span>
|
<span className="win-icon-label">{entry.label}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -411,7 +395,6 @@ export default function WindowsDesktop() {
|
||||||
<div
|
<div
|
||||||
ref={desktopRef}
|
ref={desktopRef}
|
||||||
className="win-desktop"
|
className="win-desktop"
|
||||||
style={{ backgroundImage: wallpaper }}
|
|
||||||
onPointerDown={(e) => {
|
onPointerDown={(e) => {
|
||||||
if (e.target === e.currentTarget) {
|
if (e.target === e.currentTarget) {
|
||||||
closeStart();
|
closeStart();
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import {
|
||||||
codingProjects,
|
codingProjects,
|
||||||
techProjects,
|
techProjects,
|
||||||
friends,
|
friends,
|
||||||
WALLPAPER_CREDIT,
|
|
||||||
} from "../data";
|
} from "../data";
|
||||||
import ServiceButton from "./ServiceButton";
|
import ServiceButton from "./ServiceButton";
|
||||||
import ContributionHeatmap from "./ContributionHeatmap";
|
import ContributionHeatmap from "./ContributionHeatmap";
|
||||||
|
import FeatureWindow from "./FeatureWindow";
|
||||||
import JokerLogo from "./JokerLogo";
|
import JokerLogo from "./JokerLogo";
|
||||||
import { setTheme } from "./useTheme";
|
import { setTheme } from "./useTheme";
|
||||||
|
|
||||||
|
|
@ -59,11 +59,7 @@ function WelcomeApp() {
|
||||||
.
|
.
|
||||||
</p>
|
</p>
|
||||||
<p className="app-muted app-fineprint">
|
<p className="app-muted app-fineprint">
|
||||||
Wallpaper from{" "}
|
Gentoo logo by Matteo 'Peach' Pescarin (CC BY-SA 2.5), via Wikimedia
|
||||||
<a href={WALLPAPER_CREDIT} target="_blank" rel="noopener noreferrer">
|
|
||||||
wallpapercave.com/kde-plasma-wallpapers
|
|
||||||
</a>
|
|
||||||
. Gentoo logo by Matteo 'Peach' Pescarin (CC BY-SA 2.5), via Wikimedia
|
|
||||||
Commons.
|
Commons.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -217,7 +213,9 @@ function ProjectsApp() {
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="project-card"
|
className="project-card"
|
||||||
>
|
>
|
||||||
<div className="project-image" style={{ backgroundImage: `url(${project.img})` }} />
|
<div className={`project-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||||
|
{project.emoji}
|
||||||
|
</div>
|
||||||
<h4 className="project-title">{project.title}</h4>
|
<h4 className="project-title">{project.title}</h4>
|
||||||
<p className="project-desc">{project.desc}</p>
|
<p className="project-desc">{project.desc}</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -231,12 +229,11 @@ function HardwareApp() {
|
||||||
return (
|
return (
|
||||||
<div className="app-pad">
|
<div className="app-pad">
|
||||||
<div className="project-grid">
|
<div className="project-grid">
|
||||||
{techProjects.map((project) => (
|
{techProjects.map((project, idx) => (
|
||||||
<div key={project.title} className="project-card">
|
<div key={project.title} className="project-card">
|
||||||
<div
|
<div className={`project-thumb thumb-${idx % 6}`} aria-hidden="true">
|
||||||
className="project-image"
|
{project.emoji}
|
||||||
style={{ backgroundImage: `url(${project.image})` }}
|
</div>
|
||||||
/>
|
|
||||||
<h4 className="project-title">{project.title}</h4>
|
<h4 className="project-title">{project.title}</h4>
|
||||||
<p className="project-desc">{project.desc}</p>
|
<p className="project-desc">{project.desc}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -270,15 +267,7 @@ function GitdxdApp() {
|
||||||
<div className="app-pad app-center">
|
<div className="app-pad app-center">
|
||||||
<h2 className="app-h1">GitDXD</h2>
|
<h2 className="app-h1">GitDXD</h2>
|
||||||
<p className="app-h2">My Self-hosted Git Instance</p>
|
<p className="app-h2">My Self-hosted Git Instance</p>
|
||||||
<div className="app-shot app-shot-glow">
|
<FeatureWindow variant="forge" />
|
||||||
<Image
|
|
||||||
src="/gitdxd.webp"
|
|
||||||
alt="GitDXD Preview"
|
|
||||||
width={1280}
|
|
||||||
height={720}
|
|
||||||
style={{ width: "100%", height: "auto", display: "block" }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p className="app-text">
|
<p className="app-text">
|
||||||
My very own forgejo git instance, originally started as a private git instance for
|
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{" "}
|
me and my friends to boycott GitHub but I've made it public now so. Join at{" "}
|
||||||
|
|
@ -475,15 +464,7 @@ function RevivalApp() {
|
||||||
return (
|
return (
|
||||||
<div className="app-pad app-center">
|
<div className="app-pad app-center">
|
||||||
<h2 className="app-h1">Revival Inc.</h2>
|
<h2 className="app-h1">Revival Inc.</h2>
|
||||||
<div className="app-shot app-shot-light">
|
<FeatureWindow variant="game" />
|
||||||
<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-h2">What is it?</p>
|
||||||
<p className="app-text">
|
<p className="app-text">
|
||||||
It's a game I made for the game jam "Mini Jame Gam #55", the theme was
|
It's a game I made for the game jam "Mini Jame Gam #55", the theme was
|
||||||
|
|
@ -500,15 +481,7 @@ function RustyWolfApp() {
|
||||||
return (
|
return (
|
||||||
<div className="app-pad app-center">
|
<div className="app-pad app-center">
|
||||||
<h2 className="app-h1">Introducing RustyWolf</h2>
|
<h2 className="app-h1">Introducing RustyWolf</h2>
|
||||||
<div className="app-shot app-shot-glow">
|
<FeatureWindow variant="browser" />
|
||||||
<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-h2">What makes it so cool???</p>
|
||||||
<p className="app-text">
|
<p className="app-text">
|
||||||
A lightweight browser made in Rust with WebKitGTK. It's the successor to my
|
A lightweight browser made in Rust with WebKitGTK. It's the successor to my
|
||||||
|
|
@ -766,22 +739,16 @@ function WebsiteApp({
|
||||||
url,
|
url,
|
||||||
desc,
|
desc,
|
||||||
icon,
|
icon,
|
||||||
image,
|
|
||||||
}: {
|
}: {
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
image?: string;
|
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="app-pad app-center website-app">
|
<div className="app-pad app-center website-app">
|
||||||
<div className="website-app-icon">
|
<div className="website-app-icon">
|
||||||
{image ? (
|
<span className="website-app-emoji">{icon ?? "🌐"}</span>
|
||||||
<Image src={image} alt={title} width={84} height={84} className="website-app-img" />
|
|
||||||
) : (
|
|
||||||
<span className="website-app-emoji">{icon ?? "🌐"}</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<h2 className="app-h1">{title}</h2>
|
<h2 className="app-h1">{title}</h2>
|
||||||
{desc && <p className="app-h2">{desc}</p>}
|
{desc && <p className="app-h2">{desc}</p>}
|
||||||
|
|
@ -825,7 +792,6 @@ export function createWebsiteApp(opts: {
|
||||||
url: string;
|
url: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
image?: string;
|
|
||||||
/**
|
/**
|
||||||
* Render the real site in an iframe instead of the link card. Only works for
|
* Render the real site in an iframe instead of the link card. Only works for
|
||||||
* sites that do not send `X-Frame-Options` / a `frame-ancestors` CSP.
|
* sites that do not send `X-Frame-Options` / a `frame-ancestors` CSP.
|
||||||
|
|
@ -854,7 +820,6 @@ export function createWebsiteApp(opts: {
|
||||||
url={opts.url}
|
url={opts.url}
|
||||||
desc={opts.desc}
|
desc={opts.desc}
|
||||||
icon={opts.icon}
|
icon={opts.icon}
|
||||||
image={opts.image}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,16 @@ export interface Social {
|
||||||
export interface CodingProject {
|
export interface CodingProject {
|
||||||
title: string;
|
title: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
img: string;
|
/** Emoji glyph shown on the card's CSS gradient tile (no image assets). */
|
||||||
|
emoji: string;
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TechProject {
|
export interface TechProject {
|
||||||
title: string;
|
title: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
image: string;
|
/** Emoji glyph shown on the card's CSS gradient tile (no image assets). */
|
||||||
|
emoji: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Friend {
|
export interface Friend {
|
||||||
|
|
@ -54,109 +56,109 @@ export const codingProjects: CodingProject[] = [
|
||||||
{
|
{
|
||||||
title: "Hospital Execution (Unfinished)",
|
title: "Hospital Execution (Unfinished)",
|
||||||
desc: "the first ever real game I made, in pygame. I've abandoned it.",
|
desc: "the first ever real game I made, in pygame. I've abandoned it.",
|
||||||
img: "/coding-1.webp",
|
emoji: "🏥",
|
||||||
url: "https://martin-dv.itch.io/hospital-execution-demo",
|
url: "https://martin-dv.itch.io/hospital-execution-demo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Underbaranoia (Finished)",
|
title: "Underbaranoia (Finished)",
|
||||||
desc: "basically a undertale like infinite fight simulator that gets progressively harder, made in pygame.",
|
desc: "basically a undertale like infinite fight simulator that gets progressively harder, made in pygame.",
|
||||||
img: "/coding-2.webp",
|
emoji: "⚔️",
|
||||||
url: "https://martin-dv.itch.io/underbaranoia",
|
url: "https://martin-dv.itch.io/underbaranoia",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Offline memer (Finished)",
|
title: "Offline memer (Finished)",
|
||||||
desc: "parody of the discord bot \"Dank Memer\" made in batch. (this was technically my first ever game I published).",
|
desc: "parody of the discord bot \"Dank Memer\" made in batch. (this was technically my first ever game I published).",
|
||||||
img: "/coding-3.webp",
|
emoji: "🤖",
|
||||||
url: "https://martin-dv.itch.io/offline-memer",
|
url: "https://martin-dv.itch.io/offline-memer",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "4y (Forgotten)",
|
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.",
|
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",
|
emoji: "🔐",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4y",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4y",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "4rch linux (Forgotten)",
|
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.",
|
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",
|
emoji: "🐧",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4rch-linux",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/4rch-linux",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "You_Are_An_Idiot_Virus.py (Finished)",
|
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.",
|
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",
|
emoji: "🪟",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/uranidiot",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/uranidiot",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Venturesome (Discontinued)",
|
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.",
|
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",
|
emoji: "🌐",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/Venturesome",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/Venturesome",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Mandelbrot set in Pygame (Finished)",
|
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.",
|
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",
|
emoji: "🌀",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/mandelbrot",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/mandelbrot",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Underpygametale (Unfinished)",
|
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.",
|
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",
|
emoji: "💀",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/underpygametale",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/underpygametale",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Many discord bots...",
|
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.",
|
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",
|
emoji: "💬",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/PYGETEX",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/PYGETEX",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "MMO minecraft plugin (Unfinished)",
|
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.",
|
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",
|
emoji: "⛏️",
|
||||||
url: "https://www.youtube.com/watch?v=cSAX5Ds61ac",
|
url: "https://www.youtube.com/watch?v=cSAX5Ds61ac",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Many many failed minecraft servers..",
|
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.",
|
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",
|
emoji: "🧱",
|
||||||
url: "https://discord.gg/KtHRm9kRmy",
|
url: "https://discord.gg/KtHRm9kRmy",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Swords and Sandals 2 pygame remake (Unfinished)",
|
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.",
|
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",
|
emoji: "🗡️",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/sas2py",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/sas2py",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Llama.cpp server",
|
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.",
|
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",
|
emoji: "🦾",
|
||||||
url: "https://ai.dvorakmortonxd.dev/",
|
url: "https://ai.dvorakmortonxd.dev/",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Batch MSDOS Simulator (Finished)",
|
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).",
|
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",
|
emoji: "💾",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/DvorakMSDOS",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/DvorakMSDOS",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "RustyWolf (WIP, Available now!)",
|
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 :)",
|
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",
|
emoji: "🐺",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/RustyWolf",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "dxdwm (Discontinued)",
|
title: "dxdwm (Discontinued)",
|
||||||
desc: "a small x11 window manager written in rust.",
|
desc: "a small x11 window manager written in rust.",
|
||||||
img: "/coding-17.webp",
|
emoji: "🪟",
|
||||||
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/dxdwm",
|
url: "https://git.dvorakmortonxd.dev/dvorakmortonxd/dxdwm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Revival Inc. (Finished)",
|
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",
|
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",
|
emoji: "🧟",
|
||||||
url: "https://dvorakmortonxd.dev/revival-inc",
|
url: "https://dvorakmortonxd.dev/revival-inc",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -165,77 +167,77 @@ export const techProjects: TechProject[] = [
|
||||||
{
|
{
|
||||||
title: "Gentoo Setup",
|
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.",
|
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",
|
emoji: "🐧",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Proxmox Server",
|
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.",
|
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",
|
emoji: "🖥️",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Xbox 360 S (badupdate)",
|
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.",
|
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",
|
emoji: "🎮",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Lenovo Legion Go S",
|
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.",
|
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",
|
emoji: "🕹️",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Macbook Air M4 13\"",
|
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.",
|
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",
|
emoji: "💻",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Macbook Air 2013 11\"",
|
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.",
|
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",
|
emoji: "💻",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "iPhone 7 128gb",
|
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",
|
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",
|
emoji: "📱",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Macbook Unibody 2010",
|
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 :(",
|
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",
|
emoji: "💻",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "ThinkPad T400s 14\"",
|
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.",
|
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",
|
emoji: "💻",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Asus N56JR 15.6\"",
|
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.",
|
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",
|
emoji: "💻",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Small Unknown XP Acer Laptop",
|
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",
|
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",
|
emoji: "📟",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Dell Latitude E6320",
|
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.",
|
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",
|
emoji: "💻",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "iPhone 11 128gb",
|
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)",
|
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",
|
emoji: "📱",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "iPhone 16 Pro 128gb",
|
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.",
|
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",
|
emoji: "📱",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Xbox one S 2TB",
|
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.",
|
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",
|
emoji: "🎮",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -277,6 +279,3 @@ export const friends: Friend[] = [
|
||||||
iframe: true,
|
iframe: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const WALLPAPER = "/wallpaper.jpg";
|
|
||||||
export const WALLPAPER_CREDIT = "https://wallpapercave.com/kde-plasma-wallpapers";
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,13 @@ html[data-theme="skeuo"] body {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background-color: #1b1e20;
|
background-color: #0b1a2b;
|
||||||
|
/* Asset-free "wallpaper": layered KDE-ish blue/purple gradients. */
|
||||||
|
background-image:
|
||||||
|
radial-gradient(60rem 40rem at 15% 10%, rgba(61, 174, 233, 0.28), transparent 65%),
|
||||||
|
radial-gradient(55rem 42rem at 85% 18%, rgba(155, 89, 182, 0.22), transparent 65%),
|
||||||
|
radial-gradient(72rem 52rem at 68% 100%, rgba(41, 128, 185, 0.3), transparent 70%),
|
||||||
|
linear-gradient(160deg, #0a1524 0%, #10233b 45%, #0b1a2b 100%);
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
@ -143,13 +149,6 @@ a.win-icon {
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
max-height: none;
|
max-height: none;
|
||||||
}
|
}
|
||||||
.win-icon-img {
|
|
||||||
width: 38px;
|
|
||||||
height: 38px;
|
|
||||||
object-fit: contain;
|
|
||||||
filter: brightness(0) invert(1);
|
|
||||||
opacity: 0.92;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cramped desktops: shrink the icons so the grid always has a cell for every
|
/* Cramped desktops: shrink the icons so the grid always has a cell for every
|
||||||
icon (so they can never collide) and the launcher stacks stay on screen. The
|
icon (so they can never collide) and the launcher stacks stay on screen. The
|
||||||
|
|
@ -168,10 +167,6 @@ a.win-icon {
|
||||||
.win-icon-label {
|
.win-icon-label {
|
||||||
font-size: 0.68rem;
|
font-size: 0.68rem;
|
||||||
}
|
}
|
||||||
.win-icon-img {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@media (max-width: 720px), (max-height: 440px) {
|
@media (max-width: 720px), (max-height: 440px) {
|
||||||
.win-icon {
|
.win-icon {
|
||||||
|
|
@ -191,10 +186,6 @@ a.win-icon {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.win-icon-img {
|
|
||||||
width: 26px;
|
|
||||||
height: 26px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@media (max-height: 380px) {
|
@media (max-height: 380px) {
|
||||||
.win-icon {
|
.win-icon {
|
||||||
|
|
@ -214,10 +205,6 @@ a.win-icon {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.win-icon-img {
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The three default stacks are laid out once so the grid columns can be read
|
/* The three default stacks are laid out once so the grid columns can be read
|
||||||
|
|
@ -650,12 +637,6 @@ a.win-icon {
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
.website-app-img {
|
|
||||||
width: 84px;
|
|
||||||
height: 84px;
|
|
||||||
object-fit: contain;
|
|
||||||
filter: brightness(0);
|
|
||||||
}
|
|
||||||
.website-app-link {
|
.website-app-link {
|
||||||
margin-top: 14px;
|
margin-top: 14px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
|
|
@ -889,7 +870,7 @@ a.win-icon {
|
||||||
box-shadow: 0 0 0 1px #7db9e8, 0 0 14px rgba(110, 185, 255, 0.5),
|
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);
|
0 8px 18px rgba(0, 25, 55, 0.2);
|
||||||
}
|
}
|
||||||
.app-surface .project-image {
|
.app-surface .project-thumb {
|
||||||
height: 150px;
|
height: 150px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12);
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
|
@ -1022,18 +1003,6 @@ a.win-icon {
|
||||||
color: #0e3355;
|
color: #0e3355;
|
||||||
margin: 14px 0 8px;
|
margin: 14px 0 8px;
|
||||||
}
|
}
|
||||||
.app-surface .app-shot {
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
margin: 12px 0;
|
|
||||||
}
|
|
||||||
.app-surface .app-shot-glow {
|
|
||||||
box-shadow: 0 0 26px rgba(120, 190, 255, 0.35);
|
|
||||||
}
|
|
||||||
.app-surface .app-shot-light {
|
|
||||||
box-shadow: 0 0 26px rgba(0, 0, 0, 0.22);
|
|
||||||
}
|
|
||||||
.app-surface .app-list {
|
.app-surface .app-list {
|
||||||
margin: 10px 0 10px 20px;
|
margin: 10px 0 10px 20px;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
|
|
@ -1192,7 +1161,7 @@ a.win-icon {
|
||||||
background: #353b40;
|
background: #353b40;
|
||||||
box-shadow: 0 0 0 1px #3daee9, 0 0 14px rgba(61, 174, 233, 0.45);
|
box-shadow: 0 0 0 1px #3daee9, 0 0 14px rgba(61, 174, 233, 0.45);
|
||||||
}
|
}
|
||||||
.win-body .project-image {
|
.win-body .project-thumb {
|
||||||
border-color: #1b1e20;
|
border-color: #1b1e20;
|
||||||
}
|
}
|
||||||
.win-body .project-title {
|
.win-body .project-title {
|
||||||
|
|
@ -1250,9 +1219,6 @@ a.win-icon {
|
||||||
color: #27ae60;
|
color: #27ae60;
|
||||||
}
|
}
|
||||||
|
|
||||||
.win-body .app-shot {
|
|
||||||
border-color: #1b1e20;
|
|
||||||
}
|
|
||||||
.win-body .app-linkrow a {
|
.win-body .app-linkrow a {
|
||||||
border-color: #1b1e20;
|
border-color: #1b1e20;
|
||||||
background: linear-gradient(to bottom, #3b4147, #31363b);
|
background: linear-gradient(to bottom, #3b4147, #31363b);
|
||||||
|
|
@ -1262,6 +1228,22 @@ a.win-icon {
|
||||||
color: #3daee9;
|
color: #3daee9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Feature mock windows (FeatureWindow) inside the desktop app windows: swap the
|
||||||
|
web glass tokens for the KDE dark surface so they fit the rest of the shell. */
|
||||||
|
html[data-theme="skeuo"] .fw {
|
||||||
|
--fw-chrome: rgba(255, 255, 255, 0.05);
|
||||||
|
--glass-hi: rgba(255, 255, 255, 0.06);
|
||||||
|
--glass-lo: rgba(255, 255, 255, 0.03);
|
||||||
|
--glass-border: rgba(255, 255, 255, 0.12);
|
||||||
|
--btn-bg: rgba(255, 255, 255, 0.06);
|
||||||
|
--btn-border: rgba(255, 255, 255, 0.14);
|
||||||
|
--btn-shadow: none;
|
||||||
|
--web-muted: #9aa0a6;
|
||||||
|
--fg: #eff0f1;
|
||||||
|
background: #232629;
|
||||||
|
box-shadow: 0 10px 30px -16px rgba(0, 0, 0, 0.85);
|
||||||
|
}
|
||||||
|
|
||||||
/* Alacritty easter egg */
|
/* Alacritty easter egg */
|
||||||
.alacritty {
|
.alacritty {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
|
@ -1631,7 +1613,7 @@ a.win-icon {
|
||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
.app-surface .project-image {
|
.app-surface .project-thumb {
|
||||||
height: 140px;
|
height: 140px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
168
src/app/web.css
|
|
@ -845,6 +845,141 @@ html[data-theme="web"] body {
|
||||||
background: linear-gradient(150deg, #8b5cf6, #6366f1);
|
background: linear-gradient(150deg, #8b5cf6, #6366f1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------- GitDXD: a little git-forge repo page ---------- */
|
||||||
|
.fw-forge {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: linear-gradient(180deg, var(--glass-hi), var(--glass-lo));
|
||||||
|
}
|
||||||
|
.fw-forge-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 14px;
|
||||||
|
padding: 10px 14px 0;
|
||||||
|
border-bottom: 1px solid var(--glass-border);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.fw-forge-repo {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
font-size: 0.72rem;
|
||||||
|
color: var(--web-muted);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.fw-forge-repo b {
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
.fw-forge-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 13px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.fw-forge-tab {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
font-size: 0.66rem;
|
||||||
|
color: var(--web-muted);
|
||||||
|
}
|
||||||
|
.fw-forge-tab-active {
|
||||||
|
color: var(--fg);
|
||||||
|
box-shadow: inset 0 -2px 0 var(--accent);
|
||||||
|
}
|
||||||
|
.fw-forge-body {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(84px, 34%) 1fr;
|
||||||
|
}
|
||||||
|
.fw-forge-files {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 10px;
|
||||||
|
border-right: 1px solid var(--glass-border);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 7px;
|
||||||
|
font-size: 0.62rem;
|
||||||
|
color: var(--web-muted);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.fw-forge-files li {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.fw-forge-file-icon {
|
||||||
|
flex: none;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--accent);
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.fw-forge-code {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 9px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
}
|
||||||
|
.fw-code-line {
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: var(--glass-border);
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(1) {
|
||||||
|
width: 70%;
|
||||||
|
background: var(--accent);
|
||||||
|
opacity: 0.55;
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(2) {
|
||||||
|
width: 88%;
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(3) {
|
||||||
|
width: 54%;
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(4) {
|
||||||
|
width: 78%;
|
||||||
|
background: var(--accent2);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(5) {
|
||||||
|
width: 62%;
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(6) {
|
||||||
|
width: 84%;
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(7) {
|
||||||
|
width: 46%;
|
||||||
|
background: var(--accent);
|
||||||
|
opacity: 0.45;
|
||||||
|
}
|
||||||
|
.fw-code-line:nth-child(8) {
|
||||||
|
width: 66%;
|
||||||
|
}
|
||||||
|
.fw-forge-lang {
|
||||||
|
display: flex;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
.fw-lang-seg {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.fw-lang-ts {
|
||||||
|
width: 58%;
|
||||||
|
background: #3178c6;
|
||||||
|
}
|
||||||
|
.fw-lang-css {
|
||||||
|
width: 26%;
|
||||||
|
background: #e34c26;
|
||||||
|
}
|
||||||
|
.fw-lang-md {
|
||||||
|
width: 16%;
|
||||||
|
background: #563d7c;
|
||||||
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
.fw-stars,
|
.fw-stars,
|
||||||
.fw-start {
|
.fw-start {
|
||||||
|
|
@ -1055,15 +1190,37 @@ html[data-theme="web"] body {
|
||||||
background: var(--btn-bg-hi, var(--glass-hi));
|
background: var(--btn-bg-hi, var(--glass-hi));
|
||||||
box-shadow: 0 20px 38px -20px rgba(23, 32, 60, 0.55);
|
box-shadow: 0 20px 38px -20px rgba(23, 32, 60, 0.55);
|
||||||
}
|
}
|
||||||
.project-image {
|
.project-thumb {
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
height: 150px;
|
height: 150px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
border: 1px solid var(--glass-border);
|
border: 1px solid var(--glass-border);
|
||||||
background-size: cover;
|
font-size: 2.6rem;
|
||||||
background-position: center;
|
line-height: 1;
|
||||||
background-repeat: no-repeat;
|
user-select: none;
|
||||||
|
text-shadow: 0 3px 10px rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
/* Shared gradient palette for the card tiles (no image assets). */
|
||||||
|
.thumb-0 {
|
||||||
|
background: linear-gradient(150deg, #6d5efc, #2f8bff);
|
||||||
|
}
|
||||||
|
.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 {
|
.project-title {
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
|
|
@ -1603,9 +1760,10 @@ html[data-theme="web"][data-scheme="dark"] .heatmap-legend-cell[data-level="4"]
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
.project-image {
|
.project-thumb {
|
||||||
height: 90px;
|
height: 90px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
font-size: 1.8rem;
|
||||||
}
|
}
|
||||||
.project-title {
|
.project-title {
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
|
|
|
||||||