Basis: Certvia dev@a48c5fb als Fundament für Craftvia
Unveränderter Stand von certvia/dev (a48c5fb) plus Craftvia-Spezifikation und Brandbook unter docs/craftvia/. ISMS-Module werden im Folgecommit entfernt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { BRAND, BRAND_COLORS } from "@/lib/brand";
|
||||
|
||||
/**
|
||||
* Certvia-Logo als Inline-SVG.
|
||||
*
|
||||
* Bewusst inline statt <Image src="…svg">: die Wortmarke setzt „Cert" in Poppins
|
||||
* Light und „via" in Poppins Bold. Ein extern geladenes SVG hat keinen Zugriff auf
|
||||
* die per next/font/local eingebundene Schrift (gehashter Family-Name) und würde
|
||||
* auf eine System-Schrift zurückfallen. Inline greift `var(--font-poppins)`.
|
||||
*
|
||||
* Zeichen-Konstruktion (unverändert aus dem Design-Paket, viewBox 64×64):
|
||||
* „C" nach rechts offen, der Haken liegt bündig in der Öffnung. Kein Verlauf.
|
||||
*
|
||||
* theme="light" → heller Grund (C Violett, Haken/„via" Magenta, „Cert" Anthrazit)
|
||||
* theme="dark" → dunkler Grund (C #7d6fd6, Haken #d17bcf, „Cert" weiß)
|
||||
*/
|
||||
|
||||
type LogoTheme = "light" | "dark";
|
||||
|
||||
const PALETTE: Record<LogoTheme, { arc: string; hook: string; word: string; accent: string }> = {
|
||||
light: {
|
||||
arc: BRAND_COLORS.violet,
|
||||
hook: BRAND_COLORS.magenta,
|
||||
word: BRAND_COLORS.anthracite,
|
||||
accent: BRAND_COLORS.magenta,
|
||||
},
|
||||
dark: {
|
||||
arc: BRAND_COLORS.violetOnDark,
|
||||
hook: BRAND_COLORS.magentaOnDark,
|
||||
word: BRAND_COLORS.white,
|
||||
accent: BRAND_COLORS.magentaOnDark,
|
||||
},
|
||||
};
|
||||
|
||||
/** Das Monogramm allein — Pfade aus `certvia-mark-*.svg`. */
|
||||
function Monogram({ arc, hook }: { arc: string; hook: string }) {
|
||||
return (
|
||||
<>
|
||||
<path
|
||||
d="M46 20 A17 17 0 1 0 46 44"
|
||||
fill="none"
|
||||
stroke={arc}
|
||||
strokeWidth={6}
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<path
|
||||
d="M27 32 l6 6 l12 -15"
|
||||
fill="none"
|
||||
stroke={hook}
|
||||
strokeWidth={5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function CertviaLogo({
|
||||
variant = "lockup",
|
||||
theme = "dark",
|
||||
height = 40,
|
||||
className,
|
||||
title = BRAND.name,
|
||||
}: {
|
||||
variant?: "lockup" | "mark";
|
||||
theme?: LogoTheme;
|
||||
/** Renderhöhe in px; die Breite ergibt sich aus dem Seitenverhältnis. */
|
||||
height?: number;
|
||||
className?: string;
|
||||
title?: string;
|
||||
}) {
|
||||
const c = PALETTE[theme];
|
||||
|
||||
if (variant === "mark") {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 64 64"
|
||||
width={height}
|
||||
height={height}
|
||||
role="img"
|
||||
aria-label={title}
|
||||
className={className}
|
||||
>
|
||||
<title>{title}</title>
|
||||
<Monogram arc={c.arc} hook={c.hook} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 380 96"
|
||||
width={(height * 380) / 96}
|
||||
height={height}
|
||||
role="img"
|
||||
aria-label={title}
|
||||
className={className}
|
||||
>
|
||||
<title>{title}</title>
|
||||
<g transform="translate(6,8) scale(1.25)">
|
||||
<Monogram arc={c.arc} hook={c.hook} />
|
||||
</g>
|
||||
<text
|
||||
x={112}
|
||||
y={62}
|
||||
fontSize={52}
|
||||
letterSpacing={-1}
|
||||
style={{ fontFamily: "var(--font-poppins), Poppins, 'Segoe UI', sans-serif" }}
|
||||
>
|
||||
<tspan fontWeight={300} fill={c.word}>
|
||||
Cert
|
||||
</tspan>
|
||||
<tspan fontWeight={700} fill={c.accent}>
|
||||
via
|
||||
</tspan>
|
||||
</text>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import Image from "next/image";
|
||||
import { BRAND, BRAND_ASSETS } from "@/lib/brand";
|
||||
|
||||
/**
|
||||
* Dachmarken-Hinweis „Ein Produkt von GEFIM".
|
||||
*
|
||||
* Bewusste Leitplanke der Branding-Umstellung: Certvia ist die Produktmarke,
|
||||
* GEFIM bleibt Dachmarke und erscheint weiterhin in Fußzeilen, auf den
|
||||
* Anmeldeseiten sowie später in Export- und Mail-Fußzeilen.
|
||||
* Siehe docs/BRANDING-CERTVIA.md.
|
||||
*/
|
||||
export function PoweredByGefim({
|
||||
withLogo = true,
|
||||
className,
|
||||
}: {
|
||||
withLogo?: boolean;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<p
|
||||
className={`flex items-center justify-center gap-2 text-[11px] text-muted-foreground ${className ?? ""}`}
|
||||
>
|
||||
<span>{BRAND.byline}</span>
|
||||
{withLogo && (
|
||||
<Image
|
||||
src={BRAND_ASSETS.parentLogo}
|
||||
alt={BRAND.parentBrand}
|
||||
// Seitenverhältnis der Quelldatei (1000×353)
|
||||
width={76}
|
||||
height={27}
|
||||
// Negativdarstellung auf dunklem Grund
|
||||
className="opacity-80 brightness-0 invert"
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { CertviaLogo } from "@/components/brand/certvia-logo";
|
||||
import type { TenantBranding } from "@/lib/brand";
|
||||
|
||||
/**
|
||||
* Kopfbereichs-Marke eines Mandanten (Story S8).
|
||||
*
|
||||
* Default ist **Certvia**; ein mandanteneigenes Logo überschreibt nur, wenn es
|
||||
* gesetzt ist. Der Upload je Mandant kommt mit Admin Phase 2 (Objektspeicher) —
|
||||
* bis dahin liefert `resolveTenantBranding` konstant `logoUrl: null`, die
|
||||
* Verzweigung ist aber bereits vorhanden und muss dann nicht nachgezogen werden.
|
||||
*/
|
||||
export function TenantBrand({
|
||||
branding,
|
||||
height = 34,
|
||||
className,
|
||||
}: {
|
||||
branding: TenantBranding;
|
||||
height?: number;
|
||||
className?: string;
|
||||
}) {
|
||||
if (branding.logoUrl) {
|
||||
return (
|
||||
// Mandanten-Logos liegen später im Objektspeicher (beliebige Domain) —
|
||||
// daher bewusst <img> statt next/image ohne Remote-Pattern-Konfiguration.
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={branding.logoUrl}
|
||||
alt={branding.productName}
|
||||
style={{ height, width: "auto" }}
|
||||
className={className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <CertviaLogo variant="lockup" theme="dark" height={height} className={className} />;
|
||||
}
|
||||
Reference in New Issue
Block a user