IMPROVED - Add custom macOS-style squircle app icons to the dock

This commit is contained in:
moh
2026-09-20 19:05:29 +02:00
parent 6543ccada3
commit 6e7cc4dbc6
3 changed files with 142 additions and 32 deletions
+119
View File
@@ -0,0 +1,119 @@
"use client";
import { useId } from "react";
export type DockSymbol = "home" | "about" | "portfolio" | "products" | "contact";
/**
* macOS Big Surstyle squircle app icon, drawn entirely in SVG so it stays
* crisp at every magnification step. Inactive icons use a neutral graphite
* gradient; the active icon lights up in the brand coral.
*/
export function DockAppIcon({
symbol,
active = false,
disabled = false,
}: {
symbol: DockSymbol;
active?: boolean;
disabled?: boolean;
}) {
const uid = useId().replace(/[:]/g, "");
const bg = `bg-${uid}`;
const gloss = `gloss-${uid}`;
return (
<svg
viewBox="0 0 100 100"
className="h-full w-full"
role="presentation"
style={disabled ? { opacity: 0.55 } : undefined}
>
<defs>
<linearGradient id={bg} x1="0" y1="0" x2="0" y2="1">
{active ? (
<>
<stop offset="0" stopColor="#ff8a5f" />
<stop offset="1" stopColor="#e5431f" />
</>
) : (
<>
<stop offset="0" stopColor="#454b57" />
<stop offset="1" stopColor="#1c2027" />
</>
)}
</linearGradient>
<linearGradient id={gloss} x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stopColor="#ffffff" stopOpacity="0.28" />
<stop offset="0.5" stopColor="#ffffff" stopOpacity="0" />
</linearGradient>
</defs>
{/* tile */}
<rect x="4" y="4" width="92" height="92" rx="26" fill={`url(#${bg})`} />
<rect x="4" y="4" width="92" height="92" rx="26" fill={`url(#${gloss})`} />
<rect
x="4.75"
y="4.75"
width="90.5"
height="90.5"
rx="25.25"
fill="none"
stroke="#ffffff"
strokeOpacity="0.14"
strokeWidth="1.5"
/>
{/* symbol */}
<g
fill="none"
stroke="#ffffff"
strokeWidth="6"
strokeLinecap="round"
strokeLinejoin="round"
>
{symbol === "home" && (
<>
<path d="M29 49 L50 30 L71 49" />
<path d="M34 46 V70 H66 V46" />
</>
)}
{symbol === "about" && (
<>
<circle cx="50" cy="41" r="11" />
<path d="M30 72 C30 57, 70 57, 70 72" />
</>
)}
{symbol === "contact" && (
<>
<rect x="27" y="35" width="46" height="30" rx="6" />
<path d="M30 40 L50 54 L70 40" />
</>
)}
</g>
{/* filled symbols */}
{symbol === "portfolio" && (
<g fill="#ffffff">
<rect x="32" y="32" width="15" height="15" rx="4" />
<rect x="53" y="32" width="15" height="15" rx="4" />
<rect x="32" y="53" width="15" height="15" rx="4" />
<rect x="53" y="53" width="15" height="15" rx="4" />
</g>
)}
{symbol === "products" && (
<g
fill="none"
stroke="#ffffff"
strokeWidth="6"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M50 28 L71 40 L71 60 L50 72 L29 60 L29 40 Z" />
<path d="M29 40 L50 52 L71 40" />
<path d="M50 52 L50 72" />
</g>
)}
</svg>
);
}