Karten im hellen Modus lesbar: Kartenfarbe nach Theme
Die BorderGlow-Karten in Values, Kontaktabschnitt und Über uns hatten dunkle Hintergründe fest verdrahtet, ihr Text nutzt aber Theme-Farben (Kontrast 1,07:1 im hellen Modus). BorderGlow kennt jetzt lightBackgroundColor und wählt die Kartenfarbe per CSS nach Theme (--card-bg-dark / --card-bg-light, html:not(.dark)), ohne Flackern beim Laden. Dunkel behält exakt die bisherigen Farben (hsl(0 0% 6%), #120F17, hsl(0 0% 4%)); hell nutzt hsl(0 0% 96%) mit sichtbarem Rand. Der Kantenschein wird im hellen Modus normal statt mit plus-lighter gemischt und in Violett gezeichnet, sonst wäre er auf Weiß unsichtbar. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
194301c6af
commit
897d594dde
6 files changed
+83
-1
No files matched your search
@@ -6,6 +6,8 @@
|
|||||||
--border-radius: 28px;
|
--border-radius: 28px;
|
||||||
--glow-padding: 40px;
|
--glow-padding: 40px;
|
||||||
--cone-spread: 25;
|
--cone-spread: 25;
|
||||||
|
/* Kartenfarbe nach Theme: --card-bg-dark / --card-bg-light kommen aus BorderGlow.tsx */
|
||||||
|
--card-bg: var(--card-bg-dark, #000);
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
isolation: isolate;
|
isolation: isolate;
|
||||||
@@ -25,6 +27,12 @@
|
|||||||
rgba(0, 0, 0, 0.1) 0px 32px 64px;
|
rgba(0, 0, 0, 0.1) 0px 32px 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Heller Modus: helle Kartenfarbe und ein sichtbarer Rand (weiß mit 8 % Deckkraft wäre auf Weiß unsichtbar) */
|
||||||
|
html:not(.dark) .border-glow-card {
|
||||||
|
--card-bg: var(--card-bg-light, var(--card-bg-dark, #000));
|
||||||
|
border-color: hsl(var(--border));
|
||||||
|
}
|
||||||
|
|
||||||
.border-glow-card::before,
|
.border-glow-card::before,
|
||||||
.border-glow-card::after,
|
.border-glow-card::after,
|
||||||
.border-glow-card > .edge-light {
|
.border-glow-card > .edge-light {
|
||||||
@@ -147,6 +155,20 @@
|
|||||||
0 0 50px 2px var(--glow-color-10, hsl(40deg 80% 80% / 10%));
|
0 0 50px 2px var(--glow-color-10, hsl(40deg 80% 80% / 10%));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Heller Modus: "plus-lighter" ginge auf einer hellen Karte im Weiß unter, und die blasse Glow-Farbe wäre kaum sichtbar.
|
||||||
|
Der Kantenschein wird deshalb normal gemischt und in einem kräftigeren Violett gezeichnet. */
|
||||||
|
html:not(.dark) .border-glow-card > .edge-light {
|
||||||
|
mix-blend-mode: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
html:not(.dark) .border-glow-card > .edge-light::before {
|
||||||
|
box-shadow:
|
||||||
|
inset 0 0 0 1px hsl(268deg 83% 62% / 70%),
|
||||||
|
inset 0 0 3px 0 hsl(268deg 83% 62% / 45%),
|
||||||
|
inset 0 0 12px 0 hsl(268deg 83% 62% / 30%),
|
||||||
|
inset 0 0 25px 2px hsl(268deg 83% 62% / 15%);
|
||||||
|
}
|
||||||
|
|
||||||
.border-glow-inner {
|
.border-glow-inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -56,7 +56,10 @@ interface BorderGlowProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
edgeSensitivity?: number;
|
edgeSensitivity?: number;
|
||||||
glowColor?: string;
|
glowColor?: string;
|
||||||
|
/** Kartenfarbe im dunklen Modus (und Standard, wenn lightBackgroundColor fehlt). */
|
||||||
backgroundColor?: string;
|
backgroundColor?: string;
|
||||||
|
/** Kartenfarbe im hellen Modus; ohne Angabe gilt backgroundColor in beiden Themes. */
|
||||||
|
lightBackgroundColor?: string;
|
||||||
borderRadius?: number;
|
borderRadius?: number;
|
||||||
glowRadius?: number;
|
glowRadius?: number;
|
||||||
glowIntensity?: number;
|
glowIntensity?: number;
|
||||||
@@ -72,6 +75,7 @@ const BorderGlow = ({
|
|||||||
edgeSensitivity = 30,
|
edgeSensitivity = 30,
|
||||||
glowColor = '40 80 80',
|
glowColor = '40 80 80',
|
||||||
backgroundColor = '#120F17',
|
backgroundColor = '#120F17',
|
||||||
|
lightBackgroundColor,
|
||||||
borderRadius = 28,
|
borderRadius = 28,
|
||||||
glowRadius = 40,
|
glowRadius = 40,
|
||||||
glowIntensity = 1.0,
|
glowIntensity = 1.0,
|
||||||
@@ -183,7 +187,8 @@ const BorderGlow = ({
|
|||||||
onPointerMove={animated ? undefined : handlePointerMove}
|
onPointerMove={animated ? undefined : handlePointerMove}
|
||||||
className={`border-glow-card ${className}`}
|
className={`border-glow-card ${className}`}
|
||||||
style={{
|
style={{
|
||||||
'--card-bg': backgroundColor,
|
'--card-bg-dark': backgroundColor,
|
||||||
|
'--card-bg-light': lightBackgroundColor ?? backgroundColor,
|
||||||
'--edge-sensitivity': edgeSensitivity,
|
'--edge-sensitivity': edgeSensitivity,
|
||||||
'--border-radius': `${borderRadius}px`,
|
'--border-radius': `${borderRadius}px`,
|
||||||
'--glow-padding': `${glowRadius}px`,
|
'--glow-padding': `${glowRadius}px`,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const Contact = () => {
|
|||||||
edgeSensitivity={30}
|
edgeSensitivity={30}
|
||||||
glowColor="40 80 80"
|
glowColor="40 80 80"
|
||||||
backgroundColor="#120F17"
|
backgroundColor="#120F17"
|
||||||
|
lightBackgroundColor="hsl(0 0% 96%)"
|
||||||
borderRadius={28}
|
borderRadius={28}
|
||||||
glowRadius={40}
|
glowRadius={40}
|
||||||
glowIntensity={1}
|
glowIntensity={1}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ const Values = () => {
|
|||||||
edgeSensitivity={30}
|
edgeSensitivity={30}
|
||||||
glowColor="40 80 80"
|
glowColor="40 80 80"
|
||||||
backgroundColor="hsl(0 0% 6%)"
|
backgroundColor="hsl(0 0% 6%)"
|
||||||
|
lightBackgroundColor="hsl(0 0% 96%)"
|
||||||
borderRadius={8}
|
borderRadius={8}
|
||||||
glowRadius={30}
|
glowRadius={30}
|
||||||
glowIntensity={0.8}
|
glowIntensity={0.8}
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ const About = () => {
|
|||||||
edgeSensitivity={30}
|
edgeSensitivity={30}
|
||||||
glowColor="40 80 80"
|
glowColor="40 80 80"
|
||||||
backgroundColor="hsl(0 0% 4%)"
|
backgroundColor="hsl(0 0% 4%)"
|
||||||
|
lightBackgroundColor="hsl(0 0% 96%)"
|
||||||
borderRadius={8}
|
borderRadius={8}
|
||||||
glowRadius={30}
|
glowRadius={30}
|
||||||
glowIntensity={0.8}
|
glowIntensity={0.8}
|
||||||
@@ -128,6 +129,7 @@ const About = () => {
|
|||||||
edgeSensitivity={30}
|
edgeSensitivity={30}
|
||||||
glowColor="40 80 80"
|
glowColor="40 80 80"
|
||||||
backgroundColor="hsl(0 0% 4%)"
|
backgroundColor="hsl(0 0% 4%)"
|
||||||
|
lightBackgroundColor="hsl(0 0% 96%)"
|
||||||
borderRadius={8}
|
borderRadius={8}
|
||||||
glowRadius={30}
|
glowRadius={30}
|
||||||
glowIntensity={0.8}
|
glowIntensity={0.8}
|
||||||
@@ -151,6 +153,7 @@ const About = () => {
|
|||||||
edgeSensitivity={30}
|
edgeSensitivity={30}
|
||||||
glowColor="40 80 80"
|
glowColor="40 80 80"
|
||||||
backgroundColor="hsl(0 0% 4%)"
|
backgroundColor="hsl(0 0% 4%)"
|
||||||
|
lightBackgroundColor="hsl(0 0% 96%)"
|
||||||
borderRadius={8}
|
borderRadius={8}
|
||||||
glowRadius={30}
|
glowRadius={30}
|
||||||
glowIntensity={0.8}
|
glowIntensity={0.8}
|
||||||
|
|||||||
@@ -600,3 +600,53 @@ describe("A4 Glow-Überschrift (Fix A)", () => {
|
|||||||
expect(weg.mock.calls.map(([typ]) => typ)).toEqual(expect.arrayContaining(["pointermove", "scroll"]));
|
expect(weg.mock.calls.map(([typ]) => typ)).toEqual(expect.arrayContaining(["pointermove", "scroll"]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("A1 Karten (BorderGlow) im hellen Modus lesbar", () => {
|
||||||
|
// Dunkel bleibt exakt wie vorher; hell bekommt eine helle Kartenfarbe.
|
||||||
|
const KARTEN: { name: string; ui: React.ReactElement; anzahl: number; dunkel: string }[] = [
|
||||||
|
{ name: "Values (Was Sie bekommen)", ui: <Values />, anzahl: 6, dunkel: "hsl(0 0% 6%)" },
|
||||||
|
{ name: "Kontaktabschnitt (Der nächste Schritt)", ui: <KontaktAbschnitt />, anzahl: 1, dunkel: "#120F17" },
|
||||||
|
{ name: "Über uns (Der Unterschied)", ui: <About />, anzahl: 3, dunkel: "hsl(0 0% 4%)" },
|
||||||
|
];
|
||||||
|
|
||||||
|
it.each(KARTEN)("$name: dunkle Kartenfarbe unverändert, helle Variante vorhanden", ({ ui, anzahl, dunkel }) => {
|
||||||
|
const { container } = zeige(ui);
|
||||||
|
const karten = [...container.querySelectorAll<HTMLElement>(".border-glow-card")];
|
||||||
|
expect(karten).toHaveLength(anzahl);
|
||||||
|
for (const karte of karten) {
|
||||||
|
expect(karte.style.getPropertyValue("--card-bg-dark")).toBe(dunkel);
|
||||||
|
const hell = karte.style.getPropertyValue("--card-bg-light");
|
||||||
|
expect(hell).not.toBe("");
|
||||||
|
expect(hell).not.toBe(dunkel);
|
||||||
|
expect(leuchtdichte(farbe(hell))).toBeGreaterThan(0.85);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each(KARTEN)("$name: Text und Icons erreichen in beiden Themes mindestens 4,5:1", ({ ui }) => {
|
||||||
|
const { container } = zeige(ui);
|
||||||
|
const karte = container.querySelector<HTMLElement>(".border-glow-card") as HTMLElement;
|
||||||
|
const hintergrund = { hell: farbe(karte.style.getPropertyValue("--card-bg-light")), dunkel: farbe(karte.style.getPropertyValue("--card-bg-dark")) };
|
||||||
|
for (const thema of THEMEN) {
|
||||||
|
// text-foreground (Titel, Hover-Zustand der Icons) und text-muted-foreground (Fließtext, Icons).
|
||||||
|
// Der blaue CTA-Button im Kontaktabschnitt hat eigene Farben (Weiß auf #0793CF, 3,45:1, in beiden Themes gleich)
|
||||||
|
// und gehört nicht zu den Theme-Farben; siehe Bericht.
|
||||||
|
for (const name of ["foreground", "muted-foreground"]) {
|
||||||
|
expect(kontrast(tokenFarbe(thema, name), hintergrund[thema === "hell" ? "hell" : "dunkel"])).toBeGreaterThanOrEqual(4.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("BorderGlow wählt die Kartenfarbe per CSS nach Theme und zeigt im hellen Modus einen sichtbaren Rand", () => {
|
||||||
|
const css = lies("src/components/BorderGlow.css");
|
||||||
|
expect(css).toMatch(/--card-bg:\s*var\(--card-bg-dark/);
|
||||||
|
expect(css).toMatch(/html:not\(\.dark\)\s+\.border-glow-card\s*\{[^}]*--card-bg:\s*var\(--card-bg-light/);
|
||||||
|
expect(css).toMatch(/html:not\(\.dark\)\s+\.border-glow-card\s*\{[^}]*border-color:/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("der Kantenschein der Karten wird im hellen Modus normal statt mit plus-lighter gemischt (sonst unsichtbar auf Weiß)", () => {
|
||||||
|
const css = lies("src/components/BorderGlow.css");
|
||||||
|
expect(css).toMatch(/html:not\(\.dark\)\s+\.border-glow-card\s*>\s*\.edge-light\s*\{[^}]*mix-blend-mode:\s*normal/);
|
||||||
|
// dunkel bleibt wie vorher
|
||||||
|
expect(css).toMatch(/\.border-glow-card\s*>\s*\.edge-light\s*\{[^}]*mix-blend-mode:\s*plus-lighter/);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user