From 53904350ec1cfc3c1e4c23e646c1a17519afec91 Mon Sep 17 00:00:00 2001 From: yanhenrique-dev Date: Wed, 30 Sep 2026 01:26:36 -0300 Subject: [PATCH 1/3] feat(experimental): morph icons flag, wrapper, and Tier 1 pairs morphicons 1.7.1 animates the two state toggles that already swap icons in one slot: pin/pin-off in the project rail and maximize/restore in the window controls. Off renders the same HugeiconsIcon markup as before. The flag is monocode.morphIconsEnabled, default off, persisted through the boot mirror like experimentalAnimations. The Experimental page gains a Morph icons row after the skills catalog. --- package-lock.json | 31 +++++++ package.json | 1 + src/chrome/ProjectRail.tsx | 20 +++-- src/chrome/WindowControls.tsx | 19 +++-- src/chrome/icons.tsx | 85 ++++++++++++++++++- src/lib/appearance.ts | 20 +++++ src/lib/locale.ts | 6 ++ src/lib/settings.ts | 7 ++ src/lib/settings/bootMirror.ts | 8 ++ src/lib/settings/schema.ts | 3 + .../settings/pages/ExperimentalPage.tsx | 21 +++++ 11 files changed, 209 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index aa8d8efe..4a8176a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "cuelume": "^0.2.2", "diff": "^9.0.0", "mermaid": "^12.0.0", + "morphicons": "^1.7.1", "prettier": "^3.9.6", "react": "^19.1.0", "react-dom": "^19.1.0", @@ -7700,6 +7701,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/morphicons": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/morphicons/-/morphicons-1.7.1.tgz", + "integrity": "sha512-q5ylxy5/d7vBg0OAzanlooXf05PekovMYDuuQVpr6vAQZxl99lrJbaIi+jJ32PXQf9WEEaDO2pbNBsx1ZhEnFQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=18", + "react-native": ">=0.71", + "react-native-svg": ">=14", + "svelte": ">=5", + "vue": ">=3.3" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-native": { + "optional": true + }, + "react-native-svg": { + "optional": true + }, + "svelte": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/package.json b/package.json index add185a9..43a7c0d7 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "cuelume": "^0.2.2", "diff": "^9.0.0", "mermaid": "^12.0.0", + "morphicons": "^1.7.1", "prettier": "^3.9.6", "react": "^19.1.0", "react-dom": "^19.1.0", diff --git a/src/chrome/ProjectRail.tsx b/src/chrome/ProjectRail.tsx index cb799c00..4f8dcfaa 100644 --- a/src/chrome/ProjectRail.tsx +++ b/src/chrome/ProjectRail.tsx @@ -16,6 +16,9 @@ import { Search, Settings, Trash2, + PinGlyph, + PinOffGlyph, + MorphIcon, } from "./icons"; import { useEffect, useMemo, useRef, useState, type MouseEvent } from "react"; import { useLocale, type Translate } from "../lib/locale"; @@ -1442,11 +1445,18 @@ function ProjectCard({ }} className="absolute left-2 top-1/2 grid size-4 -translate-y-1/2 place-items-center rounded-sm text-content/75 opacity-0 pointer-events-none transition-opacity hover:text-content group-hover:pointer-events-auto group-hover:opacity-100" > - {pinned ? ( - - ) : ( - - )} + {/* + Same slot either way: the pin state only swaps which endpoint the + morph shows. + Nota: docs/notes/morph-icons.md#same-slot-tier1 + */} + ); diff --git a/src/chrome/WindowControls.tsx b/src/chrome/WindowControls.tsx index 8a3edd4a..eb660a35 100644 --- a/src/chrome/WindowControls.tsx +++ b/src/chrome/WindowControls.tsx @@ -1,5 +1,5 @@ import { getCurrentWindow } from "@tauri-apps/api/window"; -import { Copy, Minus, Square, X } from "./icons"; +import { CopyGlyph, Minus, MorphIcon, SquareGlyph, X } from "./icons"; import { useEffect, useState } from "react"; export function WindowControls() { @@ -74,11 +74,18 @@ export function WindowControls() { onClick={handleToggleMaximize} className="flex w-10 items-center justify-center text-content/80 transition-colors hover:bg-content/10 hover:text-content" > - {isMaximized ? ( - - ) : ( - - )} + {/* + The restore glyph stays `Copy`: odd, but inherited, and swapping the + glyph would change the visual identity. Only the transition is new. + Nota: docs/notes/morph-icons.md#same-slot-tier1 + */} +