feat(ui): Marke und Grundkomponenten (#002)
Bildmarke als Inline-SVG und Wortmarke, dazu Karte, Button, Badge, Statuspunkt, Tabelle, Kennzahl, Diff-Box, Breadcrumb, Seitenkopf, Leerzustand und MonoKopieren. Die Bausteine kapseln die Designregeln (44 px Klickflaeche, Status nie nur ueber Farbe, Tabellen scrollen im eigenen Container), damit spaetere Seiten sie nicht neu erfinden. Nur MonoKopieren ist Client-Komponente, weil sie die Zwischenablage braucht. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Bildmarke (Tresortür mit Schlüsselloch) als Inline-SVG (#002).
|
||||
*
|
||||
* Inline statt <img src="/brand/logo.svg">, damit die Marke ohne zusätzliche Anfrage
|
||||
* sofort steht und die Farben aus den CSS-Tokens kommen. Geometrie identisch mit
|
||||
* public/brand/logo.svg – Änderungen bitte an beiden Stellen und `pnpm icons` laufen lassen.
|
||||
*/
|
||||
export function Bildmarke({
|
||||
groesse = 34,
|
||||
titel,
|
||||
className,
|
||||
}: {
|
||||
/** Kantenlänge in px. */
|
||||
groesse?: number;
|
||||
/** Zugänglicher Name; ohne Titel gilt die Marke als Schmuck (neben der Wortmarke). */
|
||||
titel?: string;
|
||||
className?: string;
|
||||
}) {
|
||||
const linie = "var(--text)";
|
||||
const messing = "var(--accent)";
|
||||
return (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 64 64"
|
||||
width={groesse}
|
||||
height={groesse}
|
||||
className={className}
|
||||
{...(titel ? { role: "img", "aria-label": titel } : { "aria-hidden": true, focusable: false })}
|
||||
>
|
||||
<rect x="4" y="4" width="56" height="56" rx="14" fill="none" stroke={linie} strokeWidth="3.5" />
|
||||
<circle
|
||||
cx="32"
|
||||
cy="32"
|
||||
r="19"
|
||||
fill="none"
|
||||
stroke={linie}
|
||||
strokeOpacity="0.28"
|
||||
strokeWidth="2"
|
||||
strokeDasharray="3 3.2"
|
||||
/>
|
||||
<circle cx="13.5" cy="13.5" r="2.2" fill={linie} />
|
||||
<circle cx="50.5" cy="13.5" r="2.2" fill={linie} />
|
||||
<circle cx="13.5" cy="50.5" r="2.2" fill={linie} />
|
||||
<circle cx="50.5" cy="50.5" r="2.2" fill={linie} />
|
||||
<circle cx="32" cy="27" r="7.5" fill={messing} />
|
||||
<path d="M28.6 30.5 L25.5 45 H38.5 L35.4 30.5 Z" fill={messing} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { clsx } from "clsx";
|
||||
import { Bildmarke } from "./Bildmarke";
|
||||
|
||||
/** „SSHKey“ in Textfarbe, „Vault“ in Messing – Space Grotesk 700 (#002). */
|
||||
export function Wortmarke({ groesse = 22, className }: { groesse?: number; className?: string }) {
|
||||
return (
|
||||
<span
|
||||
className={clsx("font-display leading-none font-bold whitespace-nowrap", className)}
|
||||
style={{ fontSize: groesse, letterSpacing: "-0.02em" }}
|
||||
>
|
||||
<span className="text-text">SSHKey</span>
|
||||
<span className="text-accent">Vault</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
/** Kurzname immer kleingeschrieben in JetBrains Mono. */
|
||||
export function Kurzname({ className }: { className?: string }) {
|
||||
return <span className={clsx("font-mono lowercase", className)}>sshkv</span>;
|
||||
}
|
||||
|
||||
/** Bildmarke + Wortmarke nebeneinander, Standardgrößen wie in der Seitenleiste (34/22 px). */
|
||||
export function Marke({
|
||||
bildGroesse = 34,
|
||||
textGroesse = 22,
|
||||
className,
|
||||
}: {
|
||||
bildGroesse?: number;
|
||||
textGroesse?: number;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<span className={clsx("inline-flex items-center gap-2.5", className)}>
|
||||
<Bildmarke groesse={bildGroesse} />
|
||||
<Wortmarke groesse={textGroesse} />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export { Bildmarke } from "./Bildmarke";
|
||||
export { Kurzname, Marke, Wortmarke } from "./Wortmarke";
|
||||
Reference in New Issue
Block a user