feat(web): toggle Frutiger Aero mode on Freezmo icon click (v2.2.17)
This commit is contained in:
parent
20f67910c4
commit
12e717448b
13 changed files with 454 additions and 64 deletions
13
AGENTS.md
13
AGENTS.md
|
|
@ -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
|
||||
hand-written CSS).
|
||||
- Path alias: `@/*` → `src/*`.
|
||||
- Version: `2.2.16` (see `package.json`).
|
||||
- Version: `2.2.17` (see `package.json`).
|
||||
|
||||
### Scripts
|
||||
```bash
|
||||
|
|
@ -174,7 +174,13 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
|||
**Freezmo** launch panel (`.web-freezmo` — app-tinted glow, floating orbs,
|
||||
gradient wordmark + "new" badge, feature bullets, Try/Source CTAs) is the one
|
||||
place the **real app icon** is used (`public/freezmo.png`, the live
|
||||
study app), floated beside the copy with a soft glow. The two remaining feature panels (`.web-split`) stretch
|
||||
study app), floated beside the copy with a soft glow. Clicking the Freezmo icon
|
||||
toggles **Frutiger Aero mode** (`data-aero="true"` on `<html>`, web shell only;
|
||||
desktop mode is untouched): the icon swaps to `public/freezmo_aero.png`, the
|
||||
website background switches to `public/frutigerbackground.png`, floating glossy
|
||||
bubbles (`.web-aero-bubbles` / `.web-aero-bubble`) rise across the backdrop, and
|
||||
all `.glass` panels and interactive controls become refractive liquid glass /
|
||||
gel buttons. The two remaining feature panels (`.web-split`) stretch
|
||||
to equal height and share a fixed `16 / 10` `.fw` window (the `FeatureWindow`
|
||||
component) — decorative, **asset-free CSS mock-ups** rather than screenshots:
|
||||
Revival Inc. is a little necromancy game scene (night sky, moon, tombstones,
|
||||
|
|
@ -195,7 +201,8 @@ Themes: `web` = default frosted-glass website (sidebar + content, light/dark),
|
|||
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 Freezmo app icon (`public/freezmo.png`), the
|
||||
the Freezmo app icons (`public/freezmo.png`, `public/freezmo_aero.png`), the
|
||||
Frutiger Aero wallpaper (`public/frutigerbackground.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
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -40,8 +40,14 @@ more.
|
|||
(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 Freezmo app icon, the Joker
|
||||
only real images left are the logo, the social SVGs, the Freezmo app icons (`freezmo.png` /
|
||||
`freezmo_aero.png`), the Frutiger Aero background (`frutigerbackground.png`), the Joker
|
||||
easter egg and the Gentoo mark.
|
||||
- **Frutiger Aero easter egg (web shell)** — clicking the Freezmo app icon swaps it to
|
||||
`freezmo_aero.png` and transforms the web shell into a Frutiger Aero theme:
|
||||
`frutigerbackground.png` as the full-screen backdrop, floating glossy water/soap bubbles
|
||||
across the viewport, and refractive liquid-glass panels and gel buttons (leaving the
|
||||
desktop mode untouched).
|
||||
- **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.
|
||||
|
|
@ -82,9 +88,11 @@ more.
|
|||
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
|
||||
used by the desktop theme's SMP menu and the in-desktop terminal.
|
||||
- **Images:** `next/image` — only the logo (`src/app/icon.png`), the social SVGs, the Joker
|
||||
easter egg and the Gentoo mark; all cards, feature/app previews and the wallpaper are CSS.
|
||||
- **Version:** `2.2.16` (see `package.json`)
|
||||
- **Images:** `next/image` — only the logo (`src/app/icon.png`), the social SVGs, the Freezmo
|
||||
icons (`public/freezmo.png`, `public/freezmo_aero.png`), the Frutiger Aero wallpaper
|
||||
(`public/frutigerbackground.png`), the Joker easter egg and the Gentoo mark; all cards,
|
||||
feature/app previews and the desktop wallpaper are CSS.
|
||||
- **Version:** `2.2.17` (see `package.json`)
|
||||
- **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
|
||||
`overrides`. `braces` (a transitive ESLint/`fast-glob` dependency) has **no upstream fix**,
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@
|
|||
"1": "Deployment & Ops Docs",
|
||||
"2": "braces Package Metadata",
|
||||
"4": "braces Parsing Engine",
|
||||
"5": "Project Index Data",
|
||||
"6": "braces Character Constants",
|
||||
"7": "Next Config & API Routes",
|
||||
"8": "TypeScript Compiler Config",
|
||||
"9": "Root Package Dependencies",
|
||||
"10": "Root Dev Dependencies",
|
||||
"11": "Custom Dev Server",
|
||||
"12": "Debian Dependency Installer",
|
||||
"13": "brace-expansion Overrides",
|
||||
"14": "npm Scripts",
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
# Graph Report - dvorakmortonxd.dev (2026-10-15)
|
||||
|
||||
## Corpus Check
|
||||
- 43 files · ~105,962 words
|
||||
- 43 files · ~319,246 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
- Unclassified: 19 file(s) not represented in the graph (top: (none) 6, .ttf 3, .css 3)
|
||||
|
||||
## Summary
|
||||
- 423 nodes · 591 edges · 42 communities (27 shown, 15 thin omitted)
|
||||
- 424 nodes · 592 edges · 40 communities (25 shown, 15 thin omitted)
|
||||
- Extraction: 93% EXTRACTED · 7% INFERRED · 0% AMBIGUOUS · INFERRED: 44 edges (avg confidence: 0.89)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `6702ca8d`
|
||||
- Built from commit: `20f67910`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
|
|
@ -21,13 +21,12 @@
|
|||
- braces Package Metadata
|
||||
- WindowsDesktop.tsx
|
||||
- braces Parsing Engine
|
||||
- Project Index Data
|
||||
- apps.tsx
|
||||
- braces Character Constants
|
||||
- Next Config & API Routes
|
||||
- TypeScript Compiler Config
|
||||
- Root Package Dependencies
|
||||
- Root Dev Dependencies
|
||||
- Custom Dev Server
|
||||
- Debian Dependency Installer
|
||||
- brace-expansion Overrides
|
||||
- npm Scripts
|
||||
|
|
@ -54,7 +53,6 @@
|
|||
- Snapchat Icon Asset
|
||||
- SoundCloud Icon Asset
|
||||
- Twitter/X Icon Asset
|
||||
- useColorScheme.ts
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
1. `WebLayout()` - 18 edges
|
||||
|
|
@ -69,6 +67,8 @@
|
|||
10. `ServiceButton()` - 8 edges
|
||||
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `Web theme + light/dark (v2.2 rework)` --references--> `FeatureWindow()` [INFERRED]
|
||||
AGENTS.md → src/app/components/FeatureWindow.tsx
|
||||
- `How UI selection works` --references--> `ThemeScript()` [INFERRED]
|
||||
AGENTS.md → src/app/components/ThemeScript.tsx
|
||||
- `How UI selection works` --references--> `WebLayout()` [INFERRED]
|
||||
|
|
@ -77,8 +77,6 @@
|
|||
AGENTS.md → src/app/components/useColorScheme.ts
|
||||
- `Conventions & things that will bite you` --references--> `braces()` [INFERRED]
|
||||
AGENTS.md → vendor/braces/index.js
|
||||
- `Web theme + light/dark (v2.2 rework)` --references--> `ContributionHeatmap()` [INFERRED]
|
||||
AGENTS.md → src/app/components/ContributionHeatmap.tsx
|
||||
|
||||
## Import Cycles
|
||||
- None detected.
|
||||
|
|
@ -88,11 +86,11 @@
|
|||
- **** — public_revival_inc_favicon_png_image, public_revival_inc_favicon_png_revival_inc_game, public_revival_inc_favicon_png_game_controller_mark [INFERRED 0.75]
|
||||
- **Site identity: eye logo used as app icon and in-page logo** — src_app_icon_png_image, src_app_icon_png_eye_logo, src_app_icon_png_favicon, src_app_components_jokerlogo_tsx_logo [INFERRED 0.85]
|
||||
|
||||
## Communities (42 total, 15 thin omitted)
|
||||
## Communities (40 total, 15 thin omitted)
|
||||
|
||||
### Community 0 - "Desktop App Catalog"
|
||||
Cohesion: 0.08
|
||||
Nodes (33): Web theme + light/dark (v2.2 rework), react, ALACRITTY_APP, ContributionsApp(), FriendsApp(), GitdxdApp(), NEOFETCH, RevivalApp() (+25 more)
|
||||
Cohesion: 0.11
|
||||
Nodes (26): Web theme + light/dark (v2.2 rework), react, ContributionsApp(), Clock(), getTime(), subscribe(), Activity, ActivityPayload (+18 more)
|
||||
|
||||
### Community 1 - "Deployment & Ops Docs"
|
||||
Cohesion: 0.09
|
||||
|
|
@ -104,15 +102,15 @@ Nodes (37): ansi-colors, bash-path, gulp-format-md, mocha, author, bugs, url, co
|
|||
|
||||
### Community 3 - "WindowsDesktop.tsx"
|
||||
Cohesion: 0.08
|
||||
Nodes (34): Conventions & things that will bite you, How UI selection works, APP_BY_ID, AppDef, APPS, createWebsiteApp(), EmbeddedSite(), WebsiteApp() (+26 more)
|
||||
Nodes (33): Conventions & things that will bite you, How UI selection works, APP_BY_ID, AppDef, APPS, createWebsiteApp(), EmbeddedSite(), WebsiteApp() (+25 more)
|
||||
|
||||
### Community 4 - "braces Parsing Engine"
|
||||
Cohesion: 0.10
|
||||
Nodes (17): compile, expand, parse, stringify, compile(), fill, utils, append() (+9 more)
|
||||
|
||||
### Community 5 - "Project Index Data"
|
||||
Cohesion: 0.14
|
||||
Nodes (20): HardwareApp(), ProjectsApp(), CodingProjectIndex(), CodingRow(), Group(), HARDWARE_GROUPS, HardwareProjectIndex(), HardwareRow() (+12 more)
|
||||
### Community 5 - "apps.tsx"
|
||||
Cohesion: 0.07
|
||||
Nodes (36): ALACRITTY_APP, FriendsApp(), GitdxdApp(), HardwareApp(), NEOFETCH, ProjectsApp(), RevivalApp(), RustyWolfApp() (+28 more)
|
||||
|
||||
### Community 6 - "braces Character Constants"
|
||||
Cohesion: 0.11
|
||||
|
|
@ -135,8 +133,8 @@ Nodes (3): {
|
|||
}, parse(), stringify
|
||||
|
||||
### Community 7 - "Next Config & API Routes"
|
||||
Cohesion: 0.15
|
||||
Nodes (13): nextConfig, next, ALLOWED_HOSTS, clickShim(), fail(), GET(), isAllowedHost(), ALLOWED_HOSTS (+5 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (20): nextConfig, next, app, hasForwardedHeaders(), isDevDebugRequest(), isLocalDebugRequest(), isLoopback(), port (+12 more)
|
||||
|
||||
### Community 8 - "TypeScript Compiler Config"
|
||||
Cohesion: 0.11
|
||||
|
|
@ -150,10 +148,6 @@ Nodes (14): fill-range, name, private, version, autoprefixer, postcss, react-dom
|
|||
Cohesion: 0.15
|
||||
Nodes (13): devDependencies, autoprefixer, eslint, eslint-config-next, fill-range, postcss, @svgr/webpack, tailwindcss (+5 more)
|
||||
|
||||
### Community 11 - "Custom Dev Server"
|
||||
Cohesion: 0.29
|
||||
Nodes (7): app, hasForwardedHeaders(), isDevDebugRequest(), isLocalDebugRequest(), isLoopback(), port, server
|
||||
|
||||
### Community 12 - "Debian Dependency Installer"
|
||||
Cohesion: 0.43
|
||||
Nodes (6): die(), log(), node_ok(), install-dependencies-deb.sh script, usage(), warn()
|
||||
|
|
@ -210,13 +204,9 @@ Nodes (3): Game Controller Logo Mark, Revival Inc. Favicon (yellow character wit
|
|||
Cohesion: 0.67
|
||||
Nodes (3): TikTok, TikTok Logo Icon, SVG Repo
|
||||
|
||||
### Community 41 - "useColorScheme.ts"
|
||||
Cohesion: 0.39
|
||||
Nodes (7): ColorScheme, DEFAULT_SCHEME, getServerSnapshot(), getSnapshot(), setColorScheme(), subscribe(), useColorScheme()
|
||||
|
||||
## Knowledge Gaps
|
||||
- **54 isolated node(s):** `react-dom`, `@svgr/webpack`, `@tailwindcss/postcss`, `@types/node`, `@types/react` (+49 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 226 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
|
||||
These have ≤1 connection - possible missing edges or undocumented components. (Counts symbols only; 227 node(s) total have ≤1 connection when file, concept and rationale nodes are included.)
|
||||
- **15 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
|
|
@ -229,10 +219,10 @@ _Questions this graph is uniquely positioned to answer:_
|
|||
- **What connects `react-dom`, `@svgr/webpack`, `@tailwindcss/postcss` to the rest of the system?**
|
||||
_54 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `Desktop App Catalog` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.0797872340425532 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.10873440285204991 - nodes in this community are weakly interconnected._
|
||||
- **Why does `braces()` connect `braces Public API Methods` to `WindowsDesktop.tsx`, `braces Parsing Engine`?**
|
||||
_High betweenness centrality (0.150) - this node is a cross-community bridge._
|
||||
- **Should `Deployment & Ops Docs` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.08735632183908046 - nodes in this community are weakly interconnected._
|
||||
- **Why does `next` connect `Next Config & API Routes` to `Desktop App Catalog`, `Root Package Dependencies`, `Custom Dev Server`, `WindowsDesktop.tsx`?**
|
||||
- **Why does `next` connect `Next Config & API Routes` to `Desktop App Catalog`, `Root Package Dependencies`, `WindowsDesktop.tsx`, `apps.tsx`?**
|
||||
_High betweenness centrality (0.126) - this node is a cross-community bridge._
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -24,9 +24,9 @@
|
|||
"semantic_hash": "03388a201be8750ddcddb14dfbc34411"
|
||||
},
|
||||
"package.json": {
|
||||
"mtime": 1792097800.6502452,
|
||||
"seen": 1792097851.621277,
|
||||
"ast_hash": "52b55982a20e4621bbf5c3d5b71cce72",
|
||||
"mtime": 1792099231.5153382,
|
||||
"seen": 1792099263.7669873,
|
||||
"ast_hash": "bb5daf478e875b6c5d5d2ec7def9b34b",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"postcss.config.mjs": {
|
||||
|
|
@ -114,9 +114,9 @@
|
|||
"semantic_hash": "20e25c727b4bb982e5a22d65efece143"
|
||||
},
|
||||
"src/app/components/WebLayout.tsx": {
|
||||
"mtime": 1792097800.6502452,
|
||||
"seen": 1792097851.62133,
|
||||
"ast_hash": "052b55c79df46ba5b1e8448149d4fd64",
|
||||
"mtime": 1792099104.6213684,
|
||||
"seen": 1792099263.767026,
|
||||
"ast_hash": "50f87afc8c92b67d8e83deaf0db4f4a6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"src/app/components/WinWindow.tsx": {
|
||||
|
|
@ -240,9 +240,9 @@
|
|||
"semantic_hash": "b81dea2175efa2b0b6c38451ab5a4bbd"
|
||||
},
|
||||
"README.md": {
|
||||
"mtime": 1792097800.6502452,
|
||||
"seen": 1792097851.6214051,
|
||||
"ast_hash": "4bb82eae835a1f9fb3bd13b54e9adeaa",
|
||||
"mtime": 1792099238.3164437,
|
||||
"seen": 1792099263.7670863,
|
||||
"ast_hash": "3109d3679249509421774e43bea54df6",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"public/llms.txt": {
|
||||
|
|
@ -366,9 +366,21 @@
|
|||
"semantic_hash": "6f69e16823f10d9c7af1625eff2b32e8"
|
||||
},
|
||||
"AGENTS.md": {
|
||||
"mtime": 1792097800.6502452,
|
||||
"seen": 1792097851.621398,
|
||||
"ast_hash": "c2418856058d91e442c35b5237ef54de",
|
||||
"mtime": 1792099254.9847023,
|
||||
"seen": 1792099263.7670813,
|
||||
"ast_hash": "401ce39abe80415b6a57cc5e55684160",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"public/freezmo_aero.png": {
|
||||
"mtime": 1792098428.3329225,
|
||||
"seen": 1792099263.7671037,
|
||||
"ast_hash": "603684d2e73038426c66896749c0c00d",
|
||||
"semantic_hash": ""
|
||||
},
|
||||
"public/frutigerbackground.png": {
|
||||
"mtime": 1792098606.0566647,
|
||||
"seen": 1792099263.7671065,
|
||||
"ast_hash": "78344ac481fd50f9366c30f041c8e135",
|
||||
"semantic_hash": ""
|
||||
}
|
||||
}
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "dvorakmortonxd",
|
||||
"version": "2.2.16",
|
||||
"version": "2.2.17",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "dvorakmortonxd",
|
||||
"version": "2.2.16",
|
||||
"version": "2.2.17",
|
||||
"dependencies": {
|
||||
"next": "^16.3.8",
|
||||
"react": "^19.3.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "dvorakmortonxd",
|
||||
"version": "2.2.16",
|
||||
"version": "2.2.17",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "node scripts/dev-server.mjs",
|
||||
|
|
|
|||
BIN
public/freezmo_aero.png
Normal file
BIN
public/freezmo_aero.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
BIN
public/frutigerbackground.png
Normal file
BIN
public/frutigerbackground.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2 MiB |
|
|
@ -1,7 +1,7 @@
|
|||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import type { ReactNode } from "react";
|
||||
import { useEffect, useState, type CSSProperties, type ReactNode } from "react";
|
||||
import JokerLogo from "./JokerLogo";
|
||||
import ServiceButton from "./ServiceButton";
|
||||
import ContributionHeatmap from "./ContributionHeatmap";
|
||||
|
|
@ -21,6 +21,42 @@ const NAV = [
|
|||
{ id: "friends", label: "Friends" },
|
||||
];
|
||||
|
||||
const AERO_BUBBLES: Array<{
|
||||
left: string;
|
||||
size: number;
|
||||
duration: number;
|
||||
delay: number;
|
||||
drift: number;
|
||||
opacity: number;
|
||||
}> = [
|
||||
{ left: "2%", size: 44, duration: 14, delay: -2, drift: 28, opacity: 0.78 },
|
||||
{ left: "6%", size: 18, duration: 9, delay: -6, drift: -18, opacity: 0.65 },
|
||||
{ left: "9%", size: 86, duration: 19, delay: -11, drift: 42, opacity: 0.72 },
|
||||
{ left: "13%", size: 28, duration: 11, delay: -4, drift: -24, opacity: 0.8 },
|
||||
{ left: "17%", size: 58, duration: 16, delay: -14, drift: 30, opacity: 0.75 },
|
||||
{ left: "21%", size: 14, duration: 8, delay: -1, drift: 16, opacity: 0.6 },
|
||||
{ left: "25%", size: 110, duration: 22, delay: -9, drift: -46, opacity: 0.68 },
|
||||
{ left: "29%", size: 34, duration: 12, delay: -7, drift: 22, opacity: 0.82 },
|
||||
{ left: "33%", size: 22, duration: 10, delay: -3, drift: -20, opacity: 0.7 },
|
||||
{ left: "37%", size: 68, duration: 17, delay: -12, drift: 36, opacity: 0.76 },
|
||||
{ left: "41%", size: 16, duration: 8.5, delay: -5, drift: -14, opacity: 0.62 },
|
||||
{ left: "45%", size: 48, duration: 15, delay: -10, drift: 26, opacity: 0.8 },
|
||||
{ left: "49%", size: 94, duration: 21, delay: -16, drift: -38, opacity: 0.7 },
|
||||
{ left: "53%", size: 26, duration: 11.5, delay: -2.5, drift: 20, opacity: 0.75 },
|
||||
{ left: "57%", size: 38, duration: 13, delay: -8, drift: -30, opacity: 0.78 },
|
||||
{ left: "61%", size: 124, duration: 24, delay: -18, drift: 48, opacity: 0.64 },
|
||||
{ left: "65%", size: 20, duration: 9.5, delay: -4.5, drift: -16, opacity: 0.68 },
|
||||
{ left: "69%", size: 54, duration: 15.5, delay: -13, drift: 32, opacity: 0.76 },
|
||||
{ left: "73%", size: 30, duration: 12.5, delay: -6.5, drift: -22, opacity: 0.8 },
|
||||
{ left: "77%", size: 76, duration: 18, delay: -15, drift: 34, opacity: 0.72 },
|
||||
{ left: "81%", size: 15, duration: 8, delay: -3.5, drift: 14, opacity: 0.6 },
|
||||
{ left: "84%", size: 62, duration: 16.5, delay: -11.5, drift: -28, opacity: 0.74 },
|
||||
{ left: "88%", size: 32, duration: 11, delay: -7.5, drift: 24, opacity: 0.82 },
|
||||
{ left: "91%", size: 102, duration: 20, delay: -17, drift: -40, opacity: 0.68 },
|
||||
{ left: "94%", size: 24, duration: 10.5, delay: -1.5, drift: 18, opacity: 0.72 },
|
||||
{ left: "97%", size: 46, duration: 14.5, delay: -9.5, drift: -26, opacity: 0.76 },
|
||||
];
|
||||
|
||||
function Section({
|
||||
id,
|
||||
eyebrow,
|
||||
|
|
@ -145,10 +181,45 @@ export default function WebLayout() {
|
|||
const { toggle } = useTheme();
|
||||
const { scheme, toggle: toggleScheme } = useColorScheme();
|
||||
const dark = scheme === "dark";
|
||||
const [aero, setAero] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (aero) {
|
||||
root.setAttribute("data-aero", "true");
|
||||
} else {
|
||||
root.removeAttribute("data-aero");
|
||||
}
|
||||
return () => {
|
||||
root.removeAttribute("data-aero");
|
||||
};
|
||||
}, [aero]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="web-bg" aria-hidden="true" />
|
||||
<div className="web-bg" aria-hidden="true">
|
||||
{aero && (
|
||||
<div className="web-aero-bubbles">
|
||||
{AERO_BUBBLES.map((b, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className="web-aero-bubble"
|
||||
style={
|
||||
{
|
||||
left: b.left,
|
||||
width: `${b.size}px`,
|
||||
height: `${b.size}px`,
|
||||
animationDuration: `${b.duration}s`,
|
||||
animationDelay: `${b.delay}s`,
|
||||
opacity: b.opacity,
|
||||
"--bubble-drift": `${b.drift}px`,
|
||||
} as CSSProperties
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="web-root">
|
||||
<aside className="web-sidebar glass">
|
||||
|
|
@ -271,16 +342,26 @@ export default function WebLayout() {
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className="web-freezmo-icon">
|
||||
<button
|
||||
type="button"
|
||||
className="web-freezmo-icon"
|
||||
onClick={() => setAero((a) => !a)}
|
||||
aria-pressed={aero}
|
||||
title={aero ? "Switch back from Frutiger Aero" : "Toggle Frutiger Aero mode"}
|
||||
>
|
||||
<Image
|
||||
src="/freezmo.png"
|
||||
alt="Freezmo app icon — a blue snowflake over a stack of cards on a navy squircle"
|
||||
src={aero ? "/freezmo_aero.png" : "/freezmo.png"}
|
||||
alt={
|
||||
aero
|
||||
? "Freezmo Frutiger Aero app icon — glossy cards with a snowflake over a bubbly sky and ocean scene"
|
||||
: "Freezmo app icon — a blue snowflake over a stack of cards on a navy squircle"
|
||||
}
|
||||
width={512}
|
||||
height={512}
|
||||
sizes="(max-width: 900px) 45vw, 200px"
|
||||
className="web-freezmo-img"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -340,7 +421,7 @@ export default function WebLayout() {
|
|||
</Section>
|
||||
|
||||
<footer className="web-footer glass">
|
||||
<span className="web-footer-label">v2.2.16</span>
|
||||
<span className="web-footer-label">v2.2.17</span>
|
||||
© 2025-2026 Martin Dvořák. All rights reserved (not really I dont care, just
|
||||
follow the GPL3.0 License)
|
||||
</footer>
|
||||
|
|
|
|||
294
src/app/web.css
294
src/app/web.css
|
|
@ -611,6 +611,10 @@ html[data-theme="web"] body {
|
|||
place-items: center;
|
||||
min-height: 100%;
|
||||
padding: clamp(10px, 2.5vw, 26px) 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
animation: freezmo-float 7s ease-in-out infinite;
|
||||
}
|
||||
.web-freezmo-icon::before {
|
||||
|
|
@ -1940,6 +1944,296 @@ html[data-theme="web"][data-scheme="dark"] .heatmap-legend-cell[data-level="4"]
|
|||
color: var(--fg);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
FRUTIGER AERO MODE (web shell only, toggled by Freezmo icon)
|
||||
------------------------------------------------------------
|
||||
Activated via `<html data-theme="web" data-aero="true">`.
|
||||
Sets `frutigerbackground.png` as the full-viewport backdrop,
|
||||
floats glossy water/soap bubbles across the screen, and turns
|
||||
every panel and button into refractive liquid glass.
|
||||
============================================================ */
|
||||
html[data-theme="web"][data-aero="true"],
|
||||
html[data-theme="web"][data-scheme="dark"][data-aero="true"] {
|
||||
--web-accent: #0078e8;
|
||||
--web-accent-2: #00c49a;
|
||||
--web-page: #0a74cc;
|
||||
--web-ink: #03223a;
|
||||
--web-muted: #0d456c;
|
||||
|
||||
--glass-hi: rgba(255, 255, 255, 0.72);
|
||||
--glass-lo: rgba(185, 238, 255, 0.34);
|
||||
--glass-border: rgba(255, 255, 255, 0.9);
|
||||
--glass-inset: rgba(255, 255, 255, 0.98);
|
||||
--pill-bg: rgba(230, 250, 255, 0.9);
|
||||
--glass-shadow:
|
||||
0 24px 50px -18px rgba(0, 42, 92, 0.58),
|
||||
0 4px 16px rgba(0, 170, 255, 0.28);
|
||||
--hover: rgba(0, 168, 255, 0.22);
|
||||
--accent-soft: rgba(0, 168, 255, 0.45);
|
||||
--accent-line: rgba(255, 255, 255, 0.95);
|
||||
|
||||
--btn-bg: rgba(255, 255, 255, 0.68);
|
||||
--btn-bg-hi: rgba(255, 255, 255, 0.92);
|
||||
--btn-border: rgba(255, 255, 255, 0.92);
|
||||
--btn-shadow:
|
||||
0 10px 22px -10px rgba(0, 55, 110, 0.45),
|
||||
inset 0 1.5px 0 rgba(255, 255, 255, 0.98),
|
||||
inset 0 -2px 6px rgba(0, 165, 245, 0.28);
|
||||
|
||||
--fg: var(--web-ink);
|
||||
--white: var(--web-ink);
|
||||
--gray: var(--web-muted);
|
||||
--bg: var(--web-page);
|
||||
--bg-hard: rgba(255, 255, 255, 0.42);
|
||||
--accent: var(--web-accent);
|
||||
--accent2: var(--web-accent-2);
|
||||
--accent3: var(--web-accent);
|
||||
--green: #0ea54a;
|
||||
--aqua: #009eb8;
|
||||
--blue: #006ee6;
|
||||
--purple: #6d4aff;
|
||||
--red: #e11d48;
|
||||
--darkpink: #d92682;
|
||||
|
||||
--index-line: rgba(255, 255, 255, 0.55);
|
||||
--status-finished: #0b7a38;
|
||||
--status-live: #005ec4;
|
||||
--status-wip: #9a4700;
|
||||
--status-unfinished: #a83205;
|
||||
--status-discontinued: #a81313;
|
||||
--status-forgotten: #2f516c;
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] body {
|
||||
background: #0a74cc url("/frutigerbackground.png") center / cover fixed no-repeat;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .web-bg {
|
||||
background:
|
||||
radial-gradient(56rem 38rem at 86% 6%, rgba(255, 255, 255, 0.42), transparent 65%),
|
||||
radial-gradient(50rem 40rem at 14% 92%, rgba(80, 255, 190, 0.24), transparent 68%),
|
||||
url("/frutigerbackground.png") center / cover no-repeat;
|
||||
}
|
||||
|
||||
/* ---------- Floating Frutiger Aero water/soap bubbles ---------- */
|
||||
.web-aero-bubbles {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.web-aero-bubble {
|
||||
position: absolute;
|
||||
bottom: -150px;
|
||||
border-radius: 50%;
|
||||
border: 1.2px solid rgba(255, 255, 255, 0.86);
|
||||
background:
|
||||
radial-gradient(
|
||||
circle at 28% 24%,
|
||||
rgba(255, 255, 255, 0.95) 0%,
|
||||
rgba(255, 255, 255, 0.45) 12%,
|
||||
rgba(160, 240, 255, 0.1) 44%,
|
||||
rgba(0, 195, 255, 0.28) 76%,
|
||||
rgba(130, 255, 210, 0.62) 92%,
|
||||
rgba(255, 255, 255, 0.92) 100%
|
||||
);
|
||||
box-shadow:
|
||||
inset 0 -8px 16px rgba(0, 175, 255, 0.36),
|
||||
inset 0 6px 12px rgba(255, 255, 255, 0.9),
|
||||
0 6px 22px rgba(0, 120, 215, 0.32),
|
||||
0 0 14px rgba(175, 250, 255, 0.55);
|
||||
-webkit-backdrop-filter: blur(2px) saturate(160%);
|
||||
backdrop-filter: blur(2px) saturate(160%);
|
||||
animation: aero-bubble-rise linear infinite;
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.web-aero-bubble::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 13%;
|
||||
left: 17%;
|
||||
width: 30%;
|
||||
height: 18%;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(
|
||||
ellipse at center,
|
||||
rgba(255, 255, 255, 0.98) 0%,
|
||||
rgba(255, 255, 255, 0.45) 65%,
|
||||
transparent 100%
|
||||
);
|
||||
transform: rotate(-32deg);
|
||||
}
|
||||
|
||||
.web-aero-bubble::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 12%;
|
||||
right: 15%;
|
||||
width: 22%;
|
||||
height: 12%;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(
|
||||
ellipse at center,
|
||||
rgba(200, 255, 235, 0.85) 0%,
|
||||
transparent 100%
|
||||
);
|
||||
transform: rotate(-28deg);
|
||||
}
|
||||
|
||||
@keyframes aero-bubble-rise {
|
||||
0% {
|
||||
transform: translate3d(0, 0, 0) scale(0.88);
|
||||
}
|
||||
25% {
|
||||
transform: translate3d(var(--bubble-drift, 24px), -28vh, 0) scale(0.96);
|
||||
}
|
||||
50% {
|
||||
transform: translate3d(calc(var(--bubble-drift, 24px) * -0.6), -58vh, 0) scale(1.03);
|
||||
}
|
||||
75% {
|
||||
transform: translate3d(var(--bubble-drift, 24px), -88vh, 0) scale(0.98);
|
||||
}
|
||||
100% {
|
||||
transform: translate3d(0, -122vh, 0) scale(1.06);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Liquid glass panels & glossy gel surfaces ---------- */
|
||||
html[data-theme="web"][data-aero="true"] .glass {
|
||||
background-color: rgba(210, 245, 255, 0.36);
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.82) 0%,
|
||||
rgba(240, 252, 255, 0.52) 44%,
|
||||
rgba(170, 232, 255, 0.34) 46%,
|
||||
rgba(130, 220, 255, 0.46) 86%,
|
||||
rgba(180, 255, 235, 0.56) 100%
|
||||
);
|
||||
border: 1.5px solid rgba(255, 255, 255, 0.92);
|
||||
box-shadow:
|
||||
0 24px 50px -18px rgba(0, 42, 92, 0.58),
|
||||
0 3px 14px rgba(0, 175, 255, 0.3),
|
||||
inset 0 2px 1px rgba(255, 255, 255, 1),
|
||||
inset 0 18px 28px rgba(255, 255, 255, 0.45),
|
||||
inset 0 -4px 12px rgba(0, 175, 255, 0.34);
|
||||
-webkit-backdrop-filter: blur(16px) saturate(200%) brightness(1.06);
|
||||
backdrop-filter: blur(16px) saturate(200%) brightness(1.06);
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .web-freezmo {
|
||||
background:
|
||||
radial-gradient(60% 90% at 12% 0%, rgba(255, 255, 255, 0.65), transparent 62%),
|
||||
radial-gradient(52% 82% at 94% 14%, rgba(0, 215, 255, 0.42), transparent 60%),
|
||||
radial-gradient(48% 72% at 76% 100%, rgba(70, 255, 180, 0.38), transparent 64%),
|
||||
linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.85) 0%,
|
||||
rgba(220, 248, 255, 0.52) 48%,
|
||||
rgba(145, 225, 255, 0.44) 50%,
|
||||
rgba(175, 255, 230, 0.58) 100%
|
||||
);
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .web-freezmo-orb {
|
||||
border: 1.2px solid rgba(255, 255, 255, 0.9);
|
||||
background: radial-gradient(
|
||||
circle at 30% 26%,
|
||||
rgba(255, 255, 255, 0.98) 0%,
|
||||
rgba(255, 255, 255, 0.45) 16%,
|
||||
rgba(130, 235, 255, 0.2) 52%,
|
||||
rgba(0, 195, 255, 0.42) 82%,
|
||||
rgba(160, 255, 220, 0.78) 100%
|
||||
);
|
||||
box-shadow:
|
||||
inset 0 -8px 16px rgba(0, 180, 255, 0.4),
|
||||
inset 0 6px 12px rgba(255, 255, 255, 0.95),
|
||||
0 0 36px rgba(100, 230, 255, 0.6);
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .web-ctl,
|
||||
html[data-theme="web"][data-aero="true"] .service-button,
|
||||
html[data-theme="web"][data-aero="true"] .social-button,
|
||||
html[data-theme="web"][data-aero="true"] .gym-item,
|
||||
html[data-theme="web"][data-aero="true"] .contribution-entry,
|
||||
html[data-theme="web"][data-aero="true"] .index-list,
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-container,
|
||||
html[data-theme="web"][data-aero="true"] .web-freezmo-ghost {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.92) 0%,
|
||||
rgba(230, 250, 255, 0.68) 49%,
|
||||
rgba(168, 230, 255, 0.52) 51%,
|
||||
rgba(215, 250, 255, 0.82) 100%
|
||||
);
|
||||
border-color: rgba(255, 255, 255, 0.94);
|
||||
box-shadow:
|
||||
0 10px 22px -12px rgba(0, 52, 105, 0.48),
|
||||
inset 0 1.5px 0 rgba(255, 255, 255, 1),
|
||||
inset 0 -2px 6px rgba(0, 170, 255, 0.28);
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .web-ctl:hover,
|
||||
html[data-theme="web"][data-aero="true"] .service-button:hover,
|
||||
html[data-theme="web"][data-aero="true"] .social-button:hover,
|
||||
html[data-theme="web"][data-aero="true"] .gym-item:hover,
|
||||
html[data-theme="web"][data-aero="true"] .web-freezmo-ghost:hover {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.98) 0%,
|
||||
rgba(235, 252, 255, 0.82) 49%,
|
||||
rgba(175, 238, 255, 0.68) 51%,
|
||||
rgba(210, 255, 242, 0.92) 100%
|
||||
);
|
||||
border-color: #ffffff;
|
||||
box-shadow:
|
||||
0 14px 28px -12px rgba(0, 95, 175, 0.55),
|
||||
0 0 14px rgba(80, 225, 255, 0.65),
|
||||
inset 0 2px 0 #ffffff;
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .web-freezmo-cta,
|
||||
html[data-theme="web"][data-aero="true"] .web-freezmo-badge,
|
||||
html[data-theme="web"][data-aero="true"] .web-switch.on {
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
#9df8ff 0%,
|
||||
#28c8ff 48%,
|
||||
#0088eb 52%,
|
||||
#00dc9e 100%
|
||||
);
|
||||
border: 1px solid rgba(255, 255, 255, 0.95);
|
||||
box-shadow:
|
||||
0 12px 26px -10px rgba(0, 95, 175, 0.65),
|
||||
0 0 12px rgba(0, 210, 255, 0.45),
|
||||
inset 0 1.5px 0 rgba(255, 255, 255, 0.98);
|
||||
text-shadow: 0 1px 2px rgba(0, 55, 105, 0.65);
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .social-icon {
|
||||
filter: none;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-cell[data-level="1"],
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-legend-cell[data-level="1"] {
|
||||
background-color: rgba(0, 168, 240, 0.28);
|
||||
}
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-cell[data-level="2"],
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-legend-cell[data-level="2"] {
|
||||
background-color: rgba(0, 155, 235, 0.5);
|
||||
}
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-cell[data-level="3"],
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-legend-cell[data-level="3"] {
|
||||
background-color: rgba(0, 140, 225, 0.76);
|
||||
}
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-cell[data-level="4"],
|
||||
html[data-theme="web"][data-aero="true"] .heatmap-legend-cell[data-level="4"] {
|
||||
background-color: #0078e8;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
RESPONSIVE — sidebar collapses to a header on phones/tablets
|
||||
============================================================ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue