feat(web): Modul-Identitaet mit App-Kacheln und deutschen Kategorienamen
Jedes Modul bekommt Farbe und Symbol (tender-radar Ocker, dkv-fleet Petrol, cert-manager Violett, domaincheck Blau, proxmox Rotorange, unbekannte stabil per Hash). Kategorien in Alltagssprache; dazu die Texte fuer die neue Anmeldeseite. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Modul-Identitaet (Design „Mosaik“): jedes Modul bekommt eine feste Farbe
|
||||
* und ein Symbol — wie die App-Kacheln bei Microsoft 365. Die Kachel wird in
|
||||
* der Seitenleiste (20 px), auf den Marktplatz-Karten (40 px) und im Kopf der
|
||||
* Modulseiten (36 px) gezeigt, immer mit weissem Symbol.
|
||||
*
|
||||
* Kontrast weisses Symbol gegen Kachel (WCAG, gemessen): tender-radar 3,8:1
|
||||
* (Ockerton gegenueber dem Entwurf oklch(0.68 0.14 70) = 2,96:1 abgedunkelt),
|
||||
* dkv-fleet 4,5:1, cert-manager 5,1:1, domaincheck 4,3:1, proxmox 4,6:1,
|
||||
* Reserve gruen 4,1:1, Reserve pink 4,3:1 — alle ueber den geforderten 3:1
|
||||
* fuer grafische Elemente.
|
||||
*/
|
||||
|
||||
export type ModuleIconId =
|
||||
| 'radar'
|
||||
| 'fuel'
|
||||
| 'certificate'
|
||||
| 'globe'
|
||||
| 'server'
|
||||
| 'tile';
|
||||
|
||||
export interface ModuleIdentity {
|
||||
/** Kachelfarbe als OKLCH-Farbwert. */
|
||||
color: string;
|
||||
/** Symbol auf der Kachel. */
|
||||
icon: ModuleIconId;
|
||||
}
|
||||
|
||||
const KNOWN: Record<string, ModuleIdentity> = {
|
||||
'tender-radar': { color: 'oklch(0.62 0.135 68)', icon: 'radar' },
|
||||
'dkv-fleet': { color: 'oklch(0.56 0.09 195)', icon: 'fuel' },
|
||||
'cert-manager': { color: 'oklch(0.55 0.14 292)', icon: 'certificate' },
|
||||
domaincheck: { color: 'oklch(0.58 0.14 250)', icon: 'globe' },
|
||||
proxmox: { color: 'oklch(0.58 0.16 35)', icon: 'server' },
|
||||
};
|
||||
|
||||
/** Reservefarben fuer unbekannte Module (stabil per Kennungs-Hash). */
|
||||
const RESERVE = ['oklch(0.58 0.12 150)', 'oklch(0.60 0.15 350)'] as const;
|
||||
|
||||
function stableHash(value: string): number {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
hash = (hash * 31 + value.charCodeAt(i)) >>> 0;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/** Farbe und Symbol eines Moduls; unbekannte Kennungen bekommen stabil eine Reservefarbe. */
|
||||
export function getModuleIdentity(slug: string): ModuleIdentity {
|
||||
const known = KNOWN[slug];
|
||||
if (known) return known;
|
||||
return { color: RESERVE[stableHash(slug) % RESERVE.length], icon: 'tile' };
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
'use client';
|
||||
|
||||
import { useTranslations } from 'next-intl';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
/**
|
||||
* Liefert den Anzeigenamen einer Modulkategorie in Alltagssprache
|
||||
* (`domain-tools` → „Domains“). Unbekannte Kategorien behalten ihre Kennung.
|
||||
*/
|
||||
export function useCategoryLabel(): (slug: string) => string {
|
||||
const t = useTranslations('moduleCategories');
|
||||
return useCallback(
|
||||
// `t.has` fehlt in einfachen Test-Attrappen von next-intl — dann Kennung.
|
||||
(slug: string) => (typeof t.has === 'function' && t.has(slug) ? t(slug) : slug),
|
||||
[t],
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user