Skip to content
Navigation

Logo

The Ströer wordmark. Inline SVG, so it stays sharp at any size and takes its colour from the surrounding text.

Added 14 October 2026

React

Codecomponents/react/logo-demo.tsx
import {LOGO_ASPECT, LOGO_SIZE_PX, Header, HeaderActions, HeaderLogo, Logo} from '@stroeer-labs/design-library/react';

// Every row answers one question a consumer actually has: how big, what colour, what about an exact box, what
// about a11y. Captions carry the numbers because the point is that the width is derived — and they are computed
// from the shared ladder, since hand-typed ones would be the first thing to go stale.
const sizes = (['sm', 'md', 'lg', 'xl'] as const).map((size) => ({
    size,
    caption: `${size} · ${LOGO_SIZE_PX[size]}px${size === 'md' ? ' (default)' : ''}`,
}));

const colours = [
    {className: 'text-foreground', caption: 'inherits — the default'},
    {className: 'text-muted-foreground', caption: 'text-muted-foreground · de-emphasised (light)'},
];

export function LogoDemo() {
    return (
        <div className="space-y-6">
            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">Sizes — height is set, width follows the artwork</p>
                <div className="flex flex-wrap items-end gap-6">
                    {sizes.map(({size, caption}) => (
                        <div key={size} className="space-y-1.5">
                            <Logo size={size} />
                            <p className="font-mono text-xs tabular-nums text-muted-foreground">{caption}</p>
                        </div>
                    ))}
                </div>
            </div>

            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">
                    Colour — the mark paints with <code className="font-mono">currentColor</code>
                </p>
                <div className="flex flex-wrap items-end gap-6">
                    {colours.map(({className, caption}) => (
                        <div key={className} className="space-y-1.5">
                            <Logo className={className} />
                            <p className="font-mono text-xs text-muted-foreground">{caption}</p>
                        </div>
                    ))}
                </div>
                <div className="flex flex-wrap items-end gap-4 pt-1">
                    <div className="space-y-1.5">
                        <div className="flex w-fit items-center rounded-lg bg-brand-fixed p-4">
                            <Logo className="text-brand-fixed-foreground" />
                        </div>
                        <p className="font-mono text-xs text-muted-foreground">✓ brand-fixed-foreground on bg-brand-fixed</p>
                    </div>
                    {/* `brand-fixed` is navy in BOTH themes (fixed identity, no `.dark` override), so this tile
                        pins a light surface instead of following the theme — otherwise the dark render is a
                        1.22:1 smudge, and the demo would be teaching the "Never" case as a specimen. */}
                    <div className="space-y-1.5">
                        <div className="flex w-fit items-center rounded-lg bg-brand-fixed-foreground p-4 ring-1 ring-border">
                            <Logo className="text-brand-fixed" />
                        </div>
                        <p className="font-mono text-xs text-muted-foreground">✓ brand-fixed on a light surface</p>
                    </div>
                    <div className="space-y-1.5">
                        <div className="flex w-fit items-center rounded-lg bg-brand-fixed p-4 ring-2 ring-destructive">
                            <Logo className="text-brand-fixed" />
                        </div>
                        <p className="font-mono text-xs text-destructive">✗ brand-fixed on a dark surface — 1.2:1</p>
                    </div>
                </div>
            </div>

            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">An exact box, when a layout needs one</p>
                <div className="flex flex-wrap items-end gap-6">
                    <div className="space-y-1.5">
                        <Logo height={28} />
                        <p className="font-mono text-xs tabular-nums text-muted-foreground">height=28 → {Math.round(28 * LOGO_ASPECT)}×28</p>
                    </div>
                    <div className="space-y-1.5">
                        {/* Outlined, not filled: a tinted slab behind the mark reads as a backing plate, which is
                            exactly the treatment the mark must never get. */}
                        <div className="w-fit rounded-md outline-1 outline-dashed outline-border">
                            <Logo width={160} height={64} />
                        </div>
                        <p className="font-mono text-xs tabular-nums text-muted-foreground">
                            your 160×64 box · mark fits to 160×{Math.round(160 / LOGO_ASPECT)}, centred
                        </p>
                    </div>
                </div>
            </div>

            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">
                    Accessibility — named on its own, <code className="font-mono">decorative</code> beside a product name
                </p>
                <div className="flex flex-wrap items-end gap-6">
                    <div className="space-y-1.5">
                        <Logo size="sm" />
                        <p className="font-mono text-xs text-muted-foreground">role=img · aria-label="Ströer"</p>
                    </div>
                    <div className="space-y-1.5">
                        <span className="flex items-baseline gap-2">
                            <Logo size="sm" decorative />
                            <span className="text-sm text-muted-foreground">design library</span>
                        </span>
                        <p className="font-mono text-xs text-muted-foreground">decorative · aria-hidden</p>
                    </div>
                </div>
            </div>

            <div className="space-y-2">
                <p className="text-xs font-medium text-muted-foreground">
                    In a header — <code className="font-mono">HeaderLogo</code> is the slot, the mark goes inside it
                </p>
                <Header className="static rounded-lg border">
                    <HeaderLogo>
                        <Logo size="sm" />
                    </HeaderLogo>
                    <HeaderActions>
                        <span className="text-xs text-muted-foreground">actions</span>
                    </HeaderActions>
                </Header>
            </div>
        </div>
    );
}

Angular

Codecomponents/angular/logo-demo.ts
import {Component} from '@angular/core';
import {LOGO_ASPECT, LOGO_SIZE_PX, HeaderImports, LogoImports} from '@stroeer-labs/design-library/angular';

// Mirrors react/logo-demo.tsx row for row, captions included — this pair is also the parity check for the two
// implementations, and a caption that differs would hide a box that differs.
@Component({
    selector: 'dl-logo-demo',
    standalone: true,
    imports: [LogoImports, HeaderImports],
    template: `
        <div class="space-y-6">
            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">Sizes — height is set, width follows the artwork</p>
                <div class="flex flex-wrap items-end gap-6">
                    @for (item of sizes; track item.size) {
                        <div class="space-y-1.5">
                            <dl-logo [size]="item.size" />
                            <p class="font-mono text-xs tabular-nums text-muted-foreground">{{ item.caption }}</p>
                        </div>
                    }
                </div>
            </div>

            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">
                    Colour — the mark paints with <code class="font-mono">currentColor</code>
                </p>
                <div class="flex flex-wrap items-end gap-6">
                    <!-- Static classes on purpose: a dynamic [class] on the host is the one pattern classes()
                         warns about, since it reconciles the host's static class attribute. -->
                    <div class="space-y-1.5">
                        <dl-logo class="text-foreground" />
                        <p class="font-mono text-xs text-muted-foreground">inherits — the default</p>
                    </div>
                    <div class="space-y-1.5">
                        <dl-logo class="text-muted-foreground" />
                        <p class="font-mono text-xs text-muted-foreground">text-muted-foreground · de-emphasised (light)</p>
                    </div>
                </div>
                <div class="flex flex-wrap items-end gap-4 pt-1">
                    <div class="space-y-1.5">
                        <div class="flex w-fit items-center rounded-lg bg-brand-fixed p-4">
                            <dl-logo class="text-brand-fixed-foreground" />
                        </div>
                        <p class="font-mono text-xs text-muted-foreground">✓ brand-fixed-foreground on bg-brand-fixed</p>
                    </div>
                    <!-- brand-fixed is navy in BOTH themes (fixed identity, no .dark override), so this tile pins
                         a light surface instead of following the theme — otherwise the dark render is a 1.22:1
                         smudge and the demo would teach the "Never" case as a specimen. -->
                    <div class="space-y-1.5">
                        <div class="flex w-fit items-center rounded-lg bg-brand-fixed-foreground p-4 ring-1 ring-border">
                            <dl-logo class="text-brand-fixed" />
                        </div>
                        <p class="font-mono text-xs text-muted-foreground">✓ brand-fixed on a light surface</p>
                    </div>
                    <div class="space-y-1.5">
                        <div class="flex w-fit items-center rounded-lg bg-brand-fixed p-4 ring-2 ring-destructive">
                            <dl-logo class="text-brand-fixed" />
                        </div>
                        <p class="font-mono text-xs text-destructive">✗ brand-fixed on a dark surface — 1.2:1</p>
                    </div>
                </div>
            </div>

            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">An exact box, when a layout needs one</p>
                <div class="flex flex-wrap items-end gap-6">
                    <div class="space-y-1.5">
                        <dl-logo [height]="28" />
                        <p class="font-mono text-xs tabular-nums text-muted-foreground">height=28 → {{ presetHeight }}×28</p>
                    </div>
                    <div class="space-y-1.5">
                        <!-- Outlined, not filled: a tinted slab behind the mark reads as a backing plate, which is
                             exactly the treatment the mark must never get. -->
                        <div class="w-fit rounded-md outline-1 outline-dashed outline-border">
                            <dl-logo [width]="160" [height]="64" />
                        </div>
                        <p class="font-mono text-xs tabular-nums text-muted-foreground">
                            your 160×64 box · mark fits to 160×{{ letterboxHeight }}, centred
                        </p>
                    </div>
                </div>
            </div>

            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">
                    Accessibility — named on its own, <code class="font-mono">decorative</code> beside a product name
                </p>
                <div class="flex flex-wrap items-end gap-6">
                    <div class="space-y-1.5">
                        <dl-logo size="sm" />
                        <p class="font-mono text-xs text-muted-foreground">role=img · aria-label="Ströer"</p>
                    </div>
                    <div class="space-y-1.5">
                        <span class="flex items-baseline gap-2">
                            <dl-logo size="sm" decorative />
                            <span class="text-sm text-muted-foreground">design library</span>
                        </span>
                        <p class="font-mono text-xs text-muted-foreground">decorative · aria-hidden</p>
                    </div>
                </div>
            </div>

            <div class="space-y-2">
                <p class="text-xs font-medium text-muted-foreground">
                    In a header — <code class="font-mono">dl-header-logo</code> is the slot, the mark goes inside it
                </p>
                <dl-header class="static rounded-lg border">
                    <dl-header-logo>
                        <dl-logo size="sm" />
                    </dl-header-logo>
                    <dl-header-actions>
                        <span class="text-xs text-muted-foreground">actions</span>
                    </dl-header-actions>
                </dl-header>
            </div>
        </div>
    `,
})
export class LogoDemoComponent {
    protected readonly sizes = (['sm', 'md', 'lg', 'xl'] as const).map((size) => ({
        size,
        caption: `${size} · ${LOGO_SIZE_PX[size]}px${size === 'md' ? ' (default)' : ''}`,
    }));

    protected readonly letterboxHeight = Math.round(160 / LOGO_ASPECT);
    protected readonly presetHeight = Math.round(28 * LOGO_ASPECT);
}