Auth fertig erstellt. Aktuell läuft review durch KI
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
import { useEffect, useRef, useState, type ReactNode, type CSSProperties } from 'react';
|
||||
|
||||
interface CrosshairProps {
|
||||
children: ReactNode;
|
||||
/** Optionales Label, das vor den Dimensionen angezeigt wird, z. B. "Header" */
|
||||
label?: string;
|
||||
/** Beliebige CSS-Farbe für Rahmen/Kreuz, überschreibt --crosshair-color */
|
||||
color?: string;
|
||||
/** Schraffur-Hintergrund aktivieren (.hatch Utility) */
|
||||
hatch?: boolean;
|
||||
/** Größe der Schraffur in px, überschreibt --hatch-size */
|
||||
hatchSize?: number;
|
||||
/** Live-Breite/Höhe oben links einblenden (per ResizeObserver) */
|
||||
showDimensions?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function Crosshair({
|
||||
children,
|
||||
label,
|
||||
color,
|
||||
hatch = false,
|
||||
hatchSize,
|
||||
showDimensions = true,
|
||||
className = '',
|
||||
}: CrosshairProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [size, setSize] = useState({ w: 0, h: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el || !showDimensions) return;
|
||||
|
||||
const ro = new ResizeObserver(([entry]) => {
|
||||
const { width, height } = entry.contentRect;
|
||||
setSize({ w: Math.round(width), h: Math.round(height) });
|
||||
});
|
||||
ro.observe(el);
|
||||
return () => ro.disconnect();
|
||||
}, [showDimensions]);
|
||||
|
||||
const style: CSSProperties = {
|
||||
...(color ? { ['--crosshair-color' as string]: color } : {}),
|
||||
...(hatchSize ? { ['--hatch-size' as string]: `${hatchSize}px` } : {}),
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={`crosshair ${hatch ? 'hatch' : ''} ${className}`.trim()}
|
||||
style={style}
|
||||
>
|
||||
{showDimensions && (
|
||||
<span className="pointer-events-none absolute left-1 top-1 z-50 rounded bg-black/70 px-1.5 py-0.5 font-mono text-[10px] leading-none text-white">
|
||||
{label ? `${label} · ` : ''}
|
||||
{size.w}×{size.h}
|
||||
</span>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/** Zeigt den berechneten z-index eines Elements als Badge oben rechts an. */
|
||||
export function ZIndexBadge({
|
||||
children,
|
||||
className = '',
|
||||
}: {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [z, setZ] = useState('auto');
|
||||
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
setZ(getComputedStyle(el).zIndex);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={`relative ${className}`.trim()}>
|
||||
<span className="pointer-events-none absolute right-1 top-1 z-[9999] rounded bg-black/70 px-1.5 py-0.5 font-mono text-[10px] leading-none text-white">
|
||||
z: {z}
|
||||
</span>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Definiert die SVG-Filter für die colorblind-* Utilities aus dev-utilities.css.
|
||||
* Einmal im App-Root rendern (z. B. direkt unter <body>/<App>) — erzeugt selbst
|
||||
* kein sichtbares Element, nur die <filter>-Definitionen im DOM.
|
||||
*/
|
||||
export function ColorblindFilters() {
|
||||
return (
|
||||
<svg aria-hidden="true" className="absolute h-0 w-0 overflow-hidden">
|
||||
<defs>
|
||||
<filter id="protanopia">
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0.567 0.433 0 0 0
|
||||
0.558 0.442 0 0 0
|
||||
0 0.242 0.758 0 0
|
||||
0 0 0 1 0"
|
||||
/>
|
||||
</filter>
|
||||
<filter id="deuteranopia">
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0.625 0.375 0 0 0
|
||||
0.7 0.3 0 0 0
|
||||
0 0.3 0.7 0 0
|
||||
0 0 0 1 0"
|
||||
/>
|
||||
</filter>
|
||||
<filter id="tritanopia">
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0.95 0.05 0 0 0
|
||||
0 0.433 0.567 0 0
|
||||
0 0.475 0.525 0 0
|
||||
0 0 0 1 0"
|
||||
/>
|
||||
</filter>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user