feat(brand): gedrehte Kachel der Bildmarke übernimmt die Akzentfarbe
- LogoMark: gedrehte Signalkachel per Inline-Style fill: var(--primary, BRAND_YELLOW) statt festem fill-Attribut - folgt damit der persoenlichen Akzentfarbe (applyAccentColor in auth-store.ts) in Kopfzeile, Seitenleiste und leerem Dashboard; ohne Nutzer (Anmeldeseite) gilt der CSS-Standard Markengelb - brand.ts: Kommentar zu BRAND_YELLOW als Rueckfallwert ergaenzt - tessera-logo.test.tsx: Kacheltest auf Inline-Style-Fuellung umgeschrieben (jsdom haelt var() in style.fill) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,12 @@
|
|||||||
* mandantenspezifische Gestaltung setzt an dieser Datei an.
|
* mandantenspezifische Gestaltung setzt an dieser Datei an.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Gelbwert der gedrehten Signalkachel. */
|
/**
|
||||||
|
* Standard-Gelb der gedrehten Signalkachel und Rueckfall, wenn keine
|
||||||
|
* persoenliche Akzentfarbe (`--primary`) gesetzt ist. Die Kachel selbst wird
|
||||||
|
* in tessera-logo.tsx per `style={{ fill: var(--primary, BRAND_YELLOW) }}`
|
||||||
|
* gefuellt -- nicht mehr per festem `fill`-Praesentationsattribut.
|
||||||
|
*/
|
||||||
export const BRAND_YELLOW = '#ffed00';
|
export const BRAND_YELLOW = '#ffed00';
|
||||||
|
|
||||||
/** Olivton der vier achsenparallelen Kacheln. */
|
/** Olivton der vier achsenparallelen Kacheln. */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { cleanup, render, screen } from '@testing-library/react';
|
import { cleanup, render, screen } from '@testing-library/react';
|
||||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { BRAND_YELLOW } from './brand';
|
import { BRAND_OLIVE, BRAND_YELLOW } from './brand';
|
||||||
import { TesseraLogo } from './tessera-logo';
|
import { TesseraLogo } from './tessera-logo';
|
||||||
import de from '@/messages/de.json';
|
import de from '@/messages/de.json';
|
||||||
import en from '@/messages/en.json';
|
import en from '@/messages/en.json';
|
||||||
@@ -94,18 +94,28 @@ describe('TesseraLogo', () => {
|
|||||||
expect(plate?.getAttribute('class')).not.toContain('dark:stroke-white/25');
|
expect(plate?.getAttribute('class')).not.toContain('dark:stroke-white/25');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders exactly five tiles, exactly one in the brand yellow and exactly one rotated', () => {
|
it('renders exactly five tiles; only the rotated one is filled from the accent token with the brand yellow as fallback', () => {
|
||||||
render(<TesseraLogo variant="mark" />);
|
render(<TesseraLogo variant="mark" />);
|
||||||
|
|
||||||
const mark = screen.getByRole('img', { name: 'Tessera Logo' });
|
const mark = screen.getByRole('img', { name: 'Tessera Logo' });
|
||||||
const tiles = Array.from(mark.querySelectorAll('g rect'));
|
const tiles = Array.from(mark.querySelectorAll('g rect')) as SVGRectElement[];
|
||||||
expect(tiles).toHaveLength(5);
|
expect(tiles).toHaveLength(5);
|
||||||
|
|
||||||
const yellowTiles = tiles.filter((tile) => tile.getAttribute('fill') === BRAND_YELLOW);
|
const accentTiles = tiles.filter((tile) => tile.style.fill === `var(--primary, ${BRAND_YELLOW})`);
|
||||||
expect(yellowTiles).toHaveLength(1);
|
expect(accentTiles).toHaveLength(1);
|
||||||
|
expect(accentTiles[0].hasAttribute('transform')).toBe(true);
|
||||||
|
|
||||||
const rotatedTiles = tiles.filter((tile) => tile.hasAttribute('transform'));
|
const rotatedTiles = tiles.filter((tile) => tile.hasAttribute('transform'));
|
||||||
expect(rotatedTiles).toHaveLength(1);
|
expect(rotatedTiles).toHaveLength(1);
|
||||||
|
|
||||||
|
const presentationYellowTiles = tiles.filter((tile) => tile.getAttribute('fill') === BRAND_YELLOW);
|
||||||
|
expect(presentationYellowTiles).toHaveLength(0);
|
||||||
|
|
||||||
|
const oliveTiles = tiles.filter((tile) => tile.getAttribute('fill') === BRAND_OLIVE);
|
||||||
|
expect(oliveTiles).toHaveLength(4);
|
||||||
|
for (const tile of oliveTiles) {
|
||||||
|
expect(tile.getAttribute('style')).toBeNull();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,13 @@ function LogoMark({
|
|||||||
<g>
|
<g>
|
||||||
<rect x="16" y="16" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
<rect x="16" y="16" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
||||||
<rect x="30" y="16" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
<rect x="30" y="16" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
||||||
|
{/*
|
||||||
|
`var()` ist in SVG-Praesentationsattributen (fill="...") nicht
|
||||||
|
zuverlaessig, im Inline-Style schon — deshalb hier style statt fill.
|
||||||
|
`--primary` wird von applyAccentColor() in auth-store.ts gesetzt;
|
||||||
|
ohne angemeldeten Nutzer (z. B. Anmeldeseite) ist der Token nicht
|
||||||
|
definiert und der Rueckfall in var() greift: BRAND_YELLOW.
|
||||||
|
*/}
|
||||||
<rect
|
<rect
|
||||||
x="45"
|
x="45"
|
||||||
y="15"
|
y="15"
|
||||||
@@ -76,7 +83,7 @@ function LogoMark({
|
|||||||
height="12"
|
height="12"
|
||||||
rx="2.5"
|
rx="2.5"
|
||||||
transform="rotate(12 51 21)"
|
transform="rotate(12 51 21)"
|
||||||
fill={BRAND_YELLOW}
|
style={{ fill: `var(--primary, ${BRAND_YELLOW})` }}
|
||||||
/>
|
/>
|
||||||
<rect x="30" y="30" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
<rect x="30" y="30" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
||||||
<rect x="30" y="44" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
<rect x="30" y="44" width="12" height="12" rx="2.5" fill={BRAND_OLIVE} />
|
||||||
@@ -90,6 +97,9 @@ function LogoMark({
|
|||||||
* Schriftzug und deren Anordnung an einer einzigen Stelle -- eine spaetere
|
* Schriftzug und deren Anordnung an einer einzigen Stelle -- eine spaetere
|
||||||
* mandantenspezifische Gestaltung setzt hier an, nicht an den einzelnen
|
* mandantenspezifische Gestaltung setzt hier an, nicht an den einzelnen
|
||||||
* Verwendungsstellen.
|
* Verwendungsstellen.
|
||||||
|
*
|
||||||
|
* Die gedrehte Signalkachel der Bildmarke folgt der persoenlichen
|
||||||
|
* Akzentfarbe (CSS-Token `--primary`, siehe LogoMark).
|
||||||
*/
|
*/
|
||||||
export function TesseraLogo({
|
export function TesseraLogo({
|
||||||
variant = 'horizontal',
|
variant = 'horizontal',
|
||||||
|
|||||||
Reference in New Issue
Block a user