swap friend SVGs for wizard emoji, 2-up shorter project cards on phones
This commit is contained in:
parent
dbf193fde9
commit
6827ca6ed1
9 changed files with 41 additions and 19815 deletions
27
agents.md
27
agents.md
|
|
@ -129,11 +129,11 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
||||||
content column of `.glass` panels: hero (with a compact "Find me" socials row),
|
content column of `.glass` panels: hero (with a compact "Find me" socials row),
|
||||||
a `.web-quick` 2-up ("Right now" + "Gym PRs"), then services, activity,
|
a `.web-quick` 2-up ("Right now" + "Gym PRs"), then services, activity,
|
||||||
projects, hardware, features (Revival/RustyWolf) and friends. Friend cards are
|
projects, hardware, features (Revival/RustyWolf) and friends. Friend cards are
|
||||||
**text-only** (name + domain — the web theme does not render `Friend.img`
|
**text-only** (name + domain) in a `.friends-grid` that collapses to a 2×2
|
||||||
avatars) in a `.friends-grid` that collapses to a 2×2 grid on phones.
|
grid on phones; the desktop friend icons use a 🧙 emoji glyph (the old
|
||||||
Projects/hardware
|
per-friend SVGs are gone). Projects/hardware use a CSS multi-column
|
||||||
use a CSS multi-column **masonry** gallery (`.project-grid`) so short cards
|
**masonry** gallery (`.project-grid`) so short cards don't leave half-empty
|
||||||
don't leave half-empty grid slots. The two feature panels (`.web-split`) stretch
|
grid slots; on phones it drops to 2 columns with a shorter card image. The two feature panels (`.web-split`) stretch
|
||||||
to equal height and share a fixed `16 / 10` `.web-shot` frame with
|
to equal height and share a fixed `16 / 10` `.web-shot` frame with
|
||||||
`object-fit: cover` (+ `object-position: center top`), so source images with
|
`object-fit: cover` (+ `object-position: center top`), so source images with
|
||||||
different aspect ratios still line up. The old stacked TUI panel layout and the
|
different aspect ratios still line up. The old stacked TUI panel layout and the
|
||||||
|
|
@ -245,12 +245,11 @@ with icons, it's almost certainly here.
|
||||||
exceeded" (this bug has already happened once — see history below).
|
exceeded" (this bug has already happened once — see history below).
|
||||||
|
|
||||||
### Gotcha: native drag hijacks the pointer gesture
|
### Gotcha: native drag hijacks the pointer gesture
|
||||||
Icons whose glyph is an `<img>` (the friend shortcuts that carry `Friend.img`,
|
Icons whose glyph is an `<img>` can start the browser's **native image drag**,
|
||||||
e.g. `/skopec.svg`, `/bukovina.svg`, `/vlcak.svg`) can start the browser's
|
which fires `pointercancel` and kills the custom drag, while emoji-based icons
|
||||||
**native image drag**, which fires `pointercancel` and kills the custom drag.
|
are unaffected (looks like "only some icons don't drag"). No desktop icon uses
|
||||||
Emoji-based icons are unaffected — including a friend with no `img` (`Friend.img`
|
an `<img>` glyph now — the friends are 🧙 emoji like the rest — but the guard
|
||||||
is optional now; it falls back to the 🫂 glyph), which makes this look like
|
below is kept in case an image glyph is reintroduced.
|
||||||
"only some icons don't drag".
|
|
||||||
|
|
||||||
Guard (already in place, keep it that way):
|
Guard (already in place, keep it that way):
|
||||||
- `draggable={false}` on the `<Image>` in `renderIcon`.
|
- `draggable={false}` on the `<Image>` in `renderIcon`.
|
||||||
|
|
@ -381,8 +380,8 @@ knows about icon ids, via `APP_BY_ID`.
|
||||||
two differ. `bukovinafilip.com`, `vlcak.me` and `k0t4tkos-portfolio.com` send
|
two differ. `bukovinafilip.com`, `vlcak.me` and `k0t4tkos-portfolio.com` send
|
||||||
no framing headers, so they frame the live site. `skopec.dev` sends
|
no framing headers, so they frame the live site. `skopec.dev` sends
|
||||||
`X-Frame-Options: SAMEORIGIN` on every path, so `friend.proxy` routes it
|
`X-Frame-Options: SAMEORIGIN` on every path, so `friend.proxy` routes it
|
||||||
through `/api/frame`. `Friend.img` is optional and only feeds the desktop icon
|
through `/api/frame`. Friend icons are a 🧙 emoji everywhere (no per-friend
|
||||||
/ FriendsApp avatar — the web theme's friends section is text-only.
|
images); the web theme's friends section is text-only.
|
||||||
- `/api/frame` is a **host-allowlisted** header-stripping proxy for sites that
|
- `/api/frame` is a **host-allowlisted** header-stripping proxy for sites that
|
||||||
refuse framing. It fetches the HTML server-side (so the upstream
|
refuse framing. It fetches the HTML server-side (so the upstream
|
||||||
`X-Frame-Options` never reaches the browser), injects `<base href="origin/">`
|
`X-Frame-Options` never reaches the browser), injects `<base href="origin/">`
|
||||||
|
|
@ -412,7 +411,7 @@ knows about icon ids, via `APP_BY_ID`.
|
||||||
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
|
- `next/image` is lazy by default, so a headless full-page screenshot shows the
|
||||||
below-the-fold feature shots and friend avatars as blank boxes. Scroll the page
|
below-the-fold feature shots as blank boxes. Scroll the page
|
||||||
slowly first and they load; this is a capture artifact, not a bug. Headless
|
slowly first and they load; this is a capture artifact, not a bug. 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).
|
||||||
|
|
|
||||||
4626
public/bukovina.svg
4626
public/bukovina.svg
File diff suppressed because it is too large
Load diff
|
Before Width: | Height: | Size: 285 KiB |
9125
public/skopec.svg
9125
public/skopec.svg
File diff suppressed because it is too large
Load diff
|
Before Width: | Height: | Size: 566 KiB |
5992
public/vlcak.svg
5992
public/vlcak.svg
File diff suppressed because it is too large
Load diff
|
Before Width: | Height: | Size: 351 KiB |
|
|
@ -76,8 +76,7 @@ const FRIEND_SHORTCUTS: Shortcut[] = friends.map((f, i) => ({
|
||||||
: f.url,
|
: f.url,
|
||||||
embed: f.iframe,
|
embed: f.iframe,
|
||||||
color: "#c0392b",
|
color: "#c0392b",
|
||||||
icon: "🫂",
|
icon: "🧙",
|
||||||
image: f.img,
|
|
||||||
desc: f.desc,
|
desc: f.desc,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -363,8 +362,7 @@ export default function WindowsDesktop() {
|
||||||
id: f.id,
|
id: f.id,
|
||||||
label: f.label,
|
label: f.label,
|
||||||
title: f.label,
|
title: f.label,
|
||||||
glyph: "🫂",
|
glyph: "🧙",
|
||||||
image: f.image,
|
|
||||||
onOpen: () => openShortcut(f),
|
onOpen: () => openShortcut(f),
|
||||||
}));
|
}));
|
||||||
const allEntries = [...leftEntries, ...serviceEntries, ...friendEntries];
|
const allEntries = [...leftEntries, ...serviceEntries, ...friendEntries];
|
||||||
|
|
@ -505,17 +503,7 @@ export default function WindowsDesktop() {
|
||||||
className="kickoff-item"
|
className="kickoff-item"
|
||||||
onClick={() => openShortcut(f)}
|
onClick={() => openShortcut(f)}
|
||||||
>
|
>
|
||||||
<span className="kickoff-icon">
|
<span className="kickoff-icon">{f.icon}</span>
|
||||||
{f.image && (
|
|
||||||
<Image
|
|
||||||
src={f.image}
|
|
||||||
alt={f.label}
|
|
||||||
width={20}
|
|
||||||
height={20}
|
|
||||||
className="kickoff-icon-img"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span className="kickoff-label">{f.label}</span>
|
<span className="kickoff-label">{f.label}</span>
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -255,20 +255,7 @@ function FriendsApp() {
|
||||||
key={idx}
|
key={idx}
|
||||||
url={friend.realUrl || friend.url}
|
url={friend.realUrl || friend.url}
|
||||||
className="friend"
|
className="friend"
|
||||||
icon={
|
icon="🧙"
|
||||||
friend.img ? (
|
|
||||||
<Image
|
|
||||||
src={friend.img}
|
|
||||||
alt={friend.name}
|
|
||||||
width={68}
|
|
||||||
height={68}
|
|
||||||
className="friend-icon"
|
|
||||||
style={{ borderRadius: "50%" }}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
"🫂"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
name={friend.name}
|
name={friend.name}
|
||||||
desc={friend.desc}
|
desc={friend.desc}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,6 @@ export interface Friend {
|
||||||
url: string;
|
url: string;
|
||||||
/** The live site: the window's `www` button and the status check use this. */
|
/** The live site: the window's `www` button and the status check use this. */
|
||||||
realUrl: string;
|
realUrl: string;
|
||||||
/**
|
|
||||||
* Desktop-icon avatar. Optional: the web theme's friends section is
|
|
||||||
* text-only (no SVG avatars), and a friend without one falls back to the
|
|
||||||
* generic glyph on the desktop.
|
|
||||||
*/
|
|
||||||
img?: string;
|
|
||||||
desc: string;
|
desc: string;
|
||||||
/** Render in an iframe in a desktop window. */
|
/** Render in an iframe in a desktop window. */
|
||||||
iframe: boolean;
|
iframe: boolean;
|
||||||
|
|
@ -250,7 +244,6 @@ export const friends: Friend[] = [
|
||||||
// window loads the live site through /api/frame (see `proxy` below).
|
// window loads the live site through /api/frame (see `proxy` below).
|
||||||
url: "https://skopec.dev/",
|
url: "https://skopec.dev/",
|
||||||
realUrl: "https://skopec.dev/",
|
realUrl: "https://skopec.dev/",
|
||||||
img: "/skopec.svg",
|
|
||||||
desc: "skopec.dev",
|
desc: "skopec.dev",
|
||||||
iframe: true,
|
iframe: true,
|
||||||
proxy: true,
|
proxy: true,
|
||||||
|
|
@ -259,7 +252,6 @@ export const friends: Friend[] = [
|
||||||
name: "Filip Bukovina",
|
name: "Filip Bukovina",
|
||||||
url: "https://bukovinafilip.com/",
|
url: "https://bukovinafilip.com/",
|
||||||
realUrl: "https://bukovinafilip.com/",
|
realUrl: "https://bukovinafilip.com/",
|
||||||
img: "/bukovina.svg",
|
|
||||||
desc: "bukovinafilip.com",
|
desc: "bukovinafilip.com",
|
||||||
iframe: true,
|
iframe: true,
|
||||||
},
|
},
|
||||||
|
|
@ -267,7 +259,6 @@ export const friends: Friend[] = [
|
||||||
name: "Tomáš Vlk",
|
name: "Tomáš Vlk",
|
||||||
url: "https://vlcak.me",
|
url: "https://vlcak.me",
|
||||||
realUrl: "https://vlcak.me",
|
realUrl: "https://vlcak.me",
|
||||||
img: "/vlcak.svg",
|
|
||||||
desc: "vlcak.me",
|
desc: "vlcak.me",
|
||||||
iframe: true,
|
iframe: true,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ html[data-theme="skeuo"] body {
|
||||||
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.95);
|
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.95);
|
||||||
transition: background-color 0.12s ease, border-color 0.12s ease;
|
transition: background-color 0.12s ease, border-color 0.12s ease;
|
||||||
/* Icons are dragged by our own pointer handlers. Without this, the browser's
|
/* Icons are dragged by our own pointer handlers. Without this, the browser's
|
||||||
native image/link drag hijacks the gesture (it fires pointercancel), which
|
native image/link drag hijacks the gesture (it fires pointercancel) for any
|
||||||
broke dragging for icons whose glyph is an <img> - the friend shortcuts. */
|
icon whose glyph is an <img>; kept in case one is reintroduced. */
|
||||||
-webkit-user-drag: none;
|
-webkit-user-drag: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
@ -1182,10 +1182,6 @@ a.win-icon {
|
||||||
.win-body .service-button:hover .service-desc {
|
.win-body .service-button:hover .service-desc {
|
||||||
color: #d3dae3;
|
color: #d3dae3;
|
||||||
}
|
}
|
||||||
.win-body .friend-icon {
|
|
||||||
filter: invert(1) brightness(1.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.win-body .project-card {
|
.win-body .project-card {
|
||||||
border-color: #1b1e20;
|
border-color: #1b1e20;
|
||||||
background: linear-gradient(to bottom, #31363b, #2a2e32);
|
background: linear-gradient(to bottom, #31363b, #2a2e32);
|
||||||
|
|
|
||||||
|
|
@ -562,7 +562,8 @@ html[data-theme="web"] body {
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Friend cards stack their round avatar above the name. */
|
/* Friend cards centre their text (the web theme has no icon; the desktop
|
||||||
|
Friends app shows the wizard emoji above the name). */
|
||||||
.service-button.friend {
|
.service-button.friend {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -592,23 +593,13 @@ html[data-theme="web"] body {
|
||||||
transform: none;
|
transform: none;
|
||||||
filter: none;
|
filter: none;
|
||||||
}
|
}
|
||||||
|
/* The desktop Friends app shows a big wizard emoji in place of the old avatars. */
|
||||||
.service-button.friend .service-icon {
|
.service-button.friend .service-icon {
|
||||||
width: 64px;
|
width: 64px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
border-radius: 50%;
|
font-size: 2.6rem;
|
||||||
overflow: hidden;
|
|
||||||
filter: none;
|
filter: none;
|
||||||
}
|
}
|
||||||
.friend-icon {
|
|
||||||
display: block;
|
|
||||||
width: 64px;
|
|
||||||
height: 64px;
|
|
||||||
border-radius: 50%;
|
|
||||||
object-fit: cover;
|
|
||||||
}
|
|
||||||
html[data-theme="web"][data-scheme="dark"] .friend-icon {
|
|
||||||
filter: invert(1) brightness(1.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
PROJECTS / HARDWARE
|
PROJECTS / HARDWARE
|
||||||
|
|
@ -1129,8 +1120,25 @@ html[data-theme="web"][data-scheme="dark"] .heatmap-legend-cell[data-level="4"]
|
||||||
font-size: 0.82rem;
|
font-size: 0.82rem;
|
||||||
font-weight: 600;
|
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 {
|
.project-grid {
|
||||||
columns: 1;
|
columns: 2;
|
||||||
|
column-gap: 10px;
|
||||||
|
}
|
||||||
|
.project-card {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.project-image {
|
||||||
|
height: 90px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.project-title {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
}
|
||||||
|
.project-desc {
|
||||||
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
.services-buttons,
|
.services-buttons,
|
||||||
.services-buttons.services-main {
|
.services-buttons.services-main {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue