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
15
README.md
15
README.md
|
|
@ -7,9 +7,9 @@ from the saved theme, all from the same content:
|
|||
|
||||
- **`web`** (default) — a light, frosted-glass **website**: a sticky full-height sidebar
|
||||
(section nav, light/dark switch, desktop switch) beside a column of glass cards — hero with
|
||||
a socials row, quick tiles, the Revival Inc. / RustyWolf feature panels (drawn as little
|
||||
CSS windows, not screenshots), live services,
|
||||
activity heatmap, projects and hardware (a masonry gallery), and friends. Dark by default
|
||||
a socials row, quick tiles, the Freezmo feature panel (a real app screenshot) above the
|
||||
Revival Inc. / RustyWolf CSS mock windows, live services,
|
||||
activity heatmap, projects and hardware (grouped index lists), and friends. Dark by default
|
||||
with a persisted light mode, and fully responsive, so phones and desktops get the same shell.
|
||||
- **`skeuo`** — an alternate KDE Plasma / Windows-style **desktop simulation** (desktop
|
||||
only): draggable snap-to-grid icons, resizable/floating windows, a Start menu, taskbar and
|
||||
|
|
@ -36,11 +36,12 @@ more.
|
|||
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
|
||||
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
|
||||
- **Asset-free index & wallpaper** — Projects and Hardware are grouped repo-style index lists
|
||||
(category headers, status/language chips, language-tinted dots on project rows, years — no emoji, 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.
|
||||
only real images left are the logo, the social SVGs, the Freezmo screenshot, the Joker
|
||||
easter egg and the Gentoo mark.
|
||||
- **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
|
||||
collide.
|
||||
|
|
|
|||
39
agents.md
39
agents.md
|
|
@ -157,15 +157,25 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
|||
rectangle/square and never ends in an orphan "L" row (a 4th friend made the old
|
||||
3-column grid do that). The same `friend.emoji` drives the desktop friend icon
|
||||
(Josef is 🧌 goblin, the rest 🧙 — the old per-friend SVGs are gone).
|
||||
Projects/hardware use a CSS multi-column
|
||||
**masonry** gallery (`.project-grid`) so short cards don't leave half-empty
|
||||
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
|
||||
Projects/hardware render as a grouped repo-listing-style
|
||||
**index** (`ProjectIndex.tsx`, `.index-*` classes): group headers
|
||||
(Games & game jams / Linux & desktop / Bots, servers & plugins / Apps &
|
||||
experiments; Desktops & servers / Laptops / Phones / Consoles & handhelds),
|
||||
then rows: coding rows lead with a language-coloured dot, title and a
|
||||
status pill over the description, with the language/host tag right-aligned;
|
||||
hardware rows are plain (no dot) with the year right-aligned. Coding rows are
|
||||
external links with a hover highlight + arrow; hardware rows are static. The
|
||||
rows are **asset-free** (no emoji, no screenshots). `codingProjects` in
|
||||
`data.ts` carries `slug` / `group` / `status?` / `tag` / `accent`;
|
||||
`techProjects` carries `slug` / `group` / `year?`
|
||||
(no `img`/`image`/`emoji`/`accent`). Status pill colors come from the `--status-*`
|
||||
tokens in `web.css`, overridden for the dark desktop windows in `skeuo.css`
|
||||
along with the row hairlines (`--index-line`). Above the split, the full-width
|
||||
**Freezmo** feature panel (`.web-feature` + `.web-feature-shot`) is the one
|
||||
place a **real screenshot** is used (`public/freezmo-app.webp`, the live
|
||||
study app). The two remaining feature panels (`.web-split`) stretch
|
||||
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) — decorative, **asset-free CSS mock-ups** rather than screenshots:
|
||||
Revival Inc. is a little necromancy game scene (night sky, moon, tombstones,
|
||||
blinking "PRESS START") and RustyWolf is a little browser window (tabs in the
|
||||
title bar, toolbar, address bar, start page). The browser window is `aria-hidden`
|
||||
|
|
@ -178,11 +188,13 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
|||
Revival Inc. → game, RustyWolf → browser), so there are no app-preview
|
||||
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,
|
||||
- **No raster UI assets.** Every list, feature panel mock, app preview and the
|
||||
desktop wallpaper is drawn in CSS: project/hardware entries are `.index-row`
|
||||
list rows (accent dot, status pill, tag/year, hairline separators), 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
|
||||
`wallpaper.jpg`). Only the social SVGs, the site logo (`src/app/icon.png`),
|
||||
the Freezmo screenshot (`public/freezmo-app.webp`), 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
|
||||
|
|
@ -207,7 +219,8 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
|||
alphas makes dark look far more gradient-heavy. Tune the two schemes
|
||||
separately, not by eye against each other.
|
||||
- Interactive surfaces (`.web-ctl`, `.service-button`, `.social-button`,
|
||||
`.project-card`, `.gym-item`, `.contribution-entry`, `.heatmap-container`) read
|
||||
`.index-list`, `a.index-row:hover`, `.gym-item`, `.contribution-entry`,
|
||||
`.heatmap-container`) read
|
||||
the `--btn-bg` / `--btn-bg-hi` / `--btn-border` / `--btn-shadow` tokens with
|
||||
the glass tokens as **fallbacks** (`var(--btn-bg, var(--glass-lo))`). The
|
||||
tokens are only defined under `html[data-theme="web"]`, so the desktop theme
|
||||
|
|
|
|||
243
package-lock.json
generated
243
package-lock.json
generated
|
|
@ -1901,9 +1901,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-arm64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.4.tgz",
|
||||
"integrity": "sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz",
|
||||
"integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1919,13 +1919,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-arm64": "1.3.3"
|
||||
"@img/sharp-libvips-darwin-arm64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-darwin-x64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.4.tgz",
|
||||
"integrity": "sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz",
|
||||
"integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1941,20 +1941,20 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-darwin-x64": "1.3.3"
|
||||
"@img/sharp-libvips-darwin-x64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-freebsd-wasm32": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.4.tgz",
|
||||
"integrity": "sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz",
|
||||
"integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"dependencies": {
|
||||
"@img/sharp-wasm32": "0.35.4"
|
||||
"@img/sharp-wasm32": "0.35.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.9.0"
|
||||
|
|
@ -1964,9 +1964,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-arm64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.3.tgz",
|
||||
"integrity": "sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz",
|
||||
"integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -1980,9 +1980,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-darwin-x64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.3.tgz",
|
||||
"integrity": "sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz",
|
||||
"integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -1996,9 +1996,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.3.tgz",
|
||||
"integrity": "sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz",
|
||||
"integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
|
@ -2015,9 +2015,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-arm64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.3.tgz",
|
||||
"integrity": "sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz",
|
||||
"integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2034,9 +2034,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-ppc64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.3.tgz",
|
||||
"integrity": "sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz",
|
||||
"integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
|
@ -2053,9 +2053,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-riscv64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.3.tgz",
|
||||
"integrity": "sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz",
|
||||
"integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
|
@ -2072,9 +2072,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-s390x": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.3.tgz",
|
||||
"integrity": "sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz",
|
||||
"integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
|
@ -2091,9 +2091,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linux-x64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.3.tgz",
|
||||
"integrity": "sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz",
|
||||
"integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2110,9 +2110,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.3.tgz",
|
||||
"integrity": "sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz",
|
||||
"integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2129,9 +2129,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.3.tgz",
|
||||
"integrity": "sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==",
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz",
|
||||
"integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2148,9 +2148,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.4.tgz",
|
||||
"integrity": "sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz",
|
||||
"integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
|
|
@ -2169,13 +2169,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm": "1.3.3"
|
||||
"@img/sharp-libvips-linux-arm": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-arm64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.4.tgz",
|
||||
"integrity": "sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz",
|
||||
"integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2194,13 +2194,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-arm64": "1.3.3"
|
||||
"@img/sharp-libvips-linux-arm64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-ppc64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.4.tgz",
|
||||
"integrity": "sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz",
|
||||
"integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
|
|
@ -2219,13 +2219,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-ppc64": "1.3.3"
|
||||
"@img/sharp-libvips-linux-ppc64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-riscv64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.4.tgz",
|
||||
"integrity": "sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz",
|
||||
"integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
|
|
@ -2244,13 +2244,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-riscv64": "1.3.3"
|
||||
"@img/sharp-libvips-linux-riscv64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-s390x": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.4.tgz",
|
||||
"integrity": "sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz",
|
||||
"integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
|
|
@ -2269,13 +2269,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-s390x": "1.3.3"
|
||||
"@img/sharp-libvips-linux-s390x": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linux-x64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.4.tgz",
|
||||
"integrity": "sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz",
|
||||
"integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2294,13 +2294,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linux-x64": "1.3.3"
|
||||
"@img/sharp-libvips-linux-x64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-arm64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.4.tgz",
|
||||
"integrity": "sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz",
|
||||
"integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2319,13 +2319,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.3"
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-linuxmusl-x64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.4.tgz",
|
||||
"integrity": "sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz",
|
||||
"integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2344,13 +2344,13 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.3"
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@img/sharp-wasm32": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.4.tgz",
|
||||
"integrity": "sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz",
|
||||
"integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==",
|
||||
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
|
|
@ -2364,16 +2364,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-webcontainers-wasm32": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.4.tgz",
|
||||
"integrity": "sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz",
|
||||
"integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@img/sharp-wasm32": "0.35.4"
|
||||
"@img/sharp-wasm32": "0.35.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.9.0"
|
||||
|
|
@ -2383,9 +2383,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-arm64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.4.tgz",
|
||||
"integrity": "sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz",
|
||||
"integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2402,9 +2402,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-ia32": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.4.tgz",
|
||||
"integrity": "sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz",
|
||||
"integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
|
|
@ -2421,9 +2421,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@img/sharp-win32-x64": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.4.tgz",
|
||||
"integrity": "sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz",
|
||||
"integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -8052,9 +8052,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/sharp": {
|
||||
"version": "0.35.4",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.4.tgz",
|
||||
"integrity": "sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==",
|
||||
"version": "0.35.5",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz",
|
||||
"integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
|
|
@ -8069,31 +8069,31 @@
|
|||
"url": "https://opencollective.com/libvips"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@img/sharp-darwin-arm64": "0.35.4",
|
||||
"@img/sharp-darwin-x64": "0.35.4",
|
||||
"@img/sharp-freebsd-wasm32": "0.35.4",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.3.3",
|
||||
"@img/sharp-libvips-darwin-x64": "1.3.3",
|
||||
"@img/sharp-libvips-linux-arm": "1.3.3",
|
||||
"@img/sharp-libvips-linux-arm64": "1.3.3",
|
||||
"@img/sharp-libvips-linux-ppc64": "1.3.3",
|
||||
"@img/sharp-libvips-linux-riscv64": "1.3.3",
|
||||
"@img/sharp-libvips-linux-s390x": "1.3.3",
|
||||
"@img/sharp-libvips-linux-x64": "1.3.3",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.3",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.3",
|
||||
"@img/sharp-linux-arm": "0.35.4",
|
||||
"@img/sharp-linux-arm64": "0.35.4",
|
||||
"@img/sharp-linux-ppc64": "0.35.4",
|
||||
"@img/sharp-linux-riscv64": "0.35.4",
|
||||
"@img/sharp-linux-s390x": "0.35.4",
|
||||
"@img/sharp-linux-x64": "0.35.4",
|
||||
"@img/sharp-linuxmusl-arm64": "0.35.4",
|
||||
"@img/sharp-linuxmusl-x64": "0.35.4",
|
||||
"@img/sharp-webcontainers-wasm32": "0.35.4",
|
||||
"@img/sharp-win32-arm64": "0.35.4",
|
||||
"@img/sharp-win32-ia32": "0.35.4",
|
||||
"@img/sharp-win32-x64": "0.35.4"
|
||||
"@img/sharp-darwin-arm64": "0.35.5",
|
||||
"@img/sharp-darwin-x64": "0.35.5",
|
||||
"@img/sharp-freebsd-wasm32": "0.35.5",
|
||||
"@img/sharp-libvips-darwin-arm64": "1.3.4",
|
||||
"@img/sharp-libvips-darwin-x64": "1.3.4",
|
||||
"@img/sharp-libvips-linux-arm": "1.3.4",
|
||||
"@img/sharp-libvips-linux-arm64": "1.3.4",
|
||||
"@img/sharp-libvips-linux-ppc64": "1.3.4",
|
||||
"@img/sharp-libvips-linux-riscv64": "1.3.4",
|
||||
"@img/sharp-libvips-linux-s390x": "1.3.4",
|
||||
"@img/sharp-libvips-linux-x64": "1.3.4",
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "1.3.4",
|
||||
"@img/sharp-libvips-linuxmusl-x64": "1.3.4",
|
||||
"@img/sharp-linux-arm": "0.35.5",
|
||||
"@img/sharp-linux-arm64": "0.35.5",
|
||||
"@img/sharp-linux-ppc64": "0.35.5",
|
||||
"@img/sharp-linux-riscv64": "0.35.5",
|
||||
"@img/sharp-linux-s390x": "0.35.5",
|
||||
"@img/sharp-linux-x64": "0.35.5",
|
||||
"@img/sharp-linuxmusl-arm64": "0.35.5",
|
||||
"@img/sharp-linuxmusl-x64": "0.35.5",
|
||||
"@img/sharp-webcontainers-wasm32": "0.35.5",
|
||||
"@img/sharp-win32-arm64": "0.35.5",
|
||||
"@img/sharp-win32-ia32": "0.35.5",
|
||||
"@img/sharp-win32-x64": "0.35.5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
|
|
@ -8220,9 +8220,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
|
||||
"integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
|
|||
BIN
public/freezmo-app.webp
Normal file
BIN
public/freezmo-app.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
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