Skip to content
Hey AlbertBrand and design system
As MarkdownDeutschDE

Foundations

Shape

Five radius steps, lines that carry meaning, and depth without shadows – from a veil, an outline and a tilt. Plus sticky notes, playful shapes and the anatomy of a card.

Hey Albert’s shapes are soft and flat. Everything is paper on paper. Nothing shines, nothing casts a shadow.

Radii

Five radii, each with a job. Without a token there is no radius.

--radius-karte16pxKarten und Menüs
--radius-klein12pxTagesreiter, kleine Karten
--radius-leiste24pxiPhone-Leiste
--radius-block22pxMac-Block
--radius-pille999pxPillen, Kreise, Knöpfe

No free radius. Without a token there is no radius.

  • --radius-karte for cards, menus, dialogs.
  • --radius-klein for day tabs and small cards.
  • --radius-leiste for the iPhone tab bar, --radius-block for the black block of the Mac sidebar.
  • --radius-pille for pills, circles and every button. Our buttons are always round.

Lines mean something

A line is never decoration here. The kind of outline says what state a thing is in.

calm field
Hairline 1 px--strich-haar · --linie
on hover, instead of a shadow
Outline 1.5 px--strich-stark
suggestion from Albert
Dashed grey--strich-gestrichelt · --muster-gestrichelt
no one responsible
Dashed open-pink--offen
2 px, 2 px offset, :focus-visible only
Focus ring--fokus-ring · --fokus-abstand
lies: −0.3°
Tilt--kippung-zettel
OutlineMeansTokens
solid hairlinecalm field, everything settled--strich-haar, --linie-haar
solid, stronger outlinethe pointer is on it--strich-stark, --linie-stark
dashed greysuggestion from Albert, not yet accepted--strich-gestrichelt, --muster-gestrichelt, --rand-vorschlag
dashed open-pinkno one responsible--rand-offen
thin dashedarea chip in the surface header--strich-haar
ring with offsetkeyboard focus--fokus-ring, --fokus-abstand, --rand-fokus

Hairlines are always --strich-haar. The dash pattern is the same everywhere: --muster-gestrichelt.

No shadows

There are no shadows. Not under cards, not under menus, not under buttons. The token --schatten is none and not negotiable.

Depth comes from three means:

  1. The veil. --flaeche-schleier dims what lies behind a dialog, a menu or the scanner.
  2. The outline. What the pointer touches gets a stronger line: --strich-haar becomes --strich-stark. The surface stays the same.
  3. The tilt. What lies is tilted slightly (--kippung-zettel). What floats stands straight (--kippung-null). Sticky notes lie, menus float.

Sticky notes

Every person has their note in their person colour. Avatars, per-person lanes and the notes on the Today surface (Heute) are sticky notes.

  • Surface --person-1 to --person-8, text --person-text.
  • Tilted slightly, alternating left and right: --kippung-zettel.
  • Always with an initial or a name. Colour alone is never enough.

Playful shapes

Star, heart, blob, circle and puzzle piece (component DekoForm) bring joy to a surface. They are not decoration for everything.

  • Only on yellow and pink surfaces.
  • Always in the darker step of the same colour: --gelb-dunkel on yellow.
  • Cropped at the edge of the surface, never in the middle of text.
  • Never on cards with controls, never in the safe, never in finances, never in the clerk register (Sachbearbeiter).

DekoForm

components/bausteine/DekoForm.jsx
Auf Gelb · dunklere Stufe
Auf Blau

Die spielerische Form auf einer gelben oder rosa Fläche – Freude, kein Schmuck.

<DekoForm form="stern" groesse={110} farbe="var(--gelb-dunkel)" style={{ right: -18, bottom: -22 }} />

Die Elternfläche braucht position: relative und overflow: hidden. Nie auf Karten mit Bedienelementen, nie im Safe, nie bei Finanzen.

Types (.d.ts)
/** Spielerische Form als Deko auf gelben und rosa Flaechen - Stern, Herz, Kleks, Puzzleteil. */
export interface DekoFormProps {
  form?: "stern" | "herz" | "kleks" | "kreis" | "puzzle";
  groesse?: number;
  /** Immer die dunklere Stufe derselben Flaechenfarbe: var(--gelb-dunkel), var(--blau-dunkel). */
  farbe?: string;
  drehung?: number;
  style?: React.CSSProperties;
}
export function DekoForm(props: DekoFormProps): JSX.Element;

The anatomy of a card

The card is what Today, Week and the calendar are made of. It always has the same structure.

  • Surface by kind: appointment --flaeche-karte, drive --flaeche-karte-fahrt, family --flaeche-karte-familie, suggestion --flaeche-karte-vorschlag with a dashed grey outline, open with a dashed open-pink outline.
  • Radius --radius-karte, padding --karte-innen, gap to the next card --karte-abstand.
  • Outline: a hairline as a placeholder for the stronger outline. No shadow.
  • Header: on the left the symbol of the thing in a light circle, on the right the dots of the people. Nothing in between: no menu, no chevron.
  • Title in --grad-karten-titel, below it time and place in --grad-zweit.
  • Pills for states, for example “Kein Fahrer” (no driver).
  • Buttons at the bottom, in a Knopfreihe. A suggestion always has two: “Übernehmen” (accept) and “Rückgängig” (undo), or a question with two answers.

Three carriers in three places: the card colour tells the kind. The symbol tells the thing. The dots tell the people.

Karte

components/karten/Karte.jsx
AL
Kieferorthopädin
Praxis Dr. Voss
16:00 – 17:00
TF
Handball, Halle Süd
Schule → Halle Süd
Fr 16:40
Tobias fährt 16:40 · Kombi
ATFL
Mittagessen bei Oma Grete
So 12:30 · alle
Bei Tobias steht ab 13:00 nichts. Fragen?
Vorschlag von Albert
Abholen Halle Süd
19:00
Ohne Zuständigen
Mathe mit Felix17:30F

Die Karte – das Ding, aus dem Heute, Woche und Kalender bestehen. Ein Datenmodell, viele Ansichten.

<Karte art="fahrt" titel="Rückfahrt Auswärtsspiel" ort="Sportplatz Nord → Zuhause"
  zeit="14:00 – 14:30" leute={["felix"]} hoehe="hoch"
  pillen={<ZustandsPille>Kein Fahrer</ZustandsPille>}
  knoepfe={<Knopf>Ich fahre</Knopf>} />

<Karte art="vorschlag" titel="Bei Tobias steht ab 13:00 nichts. Fragen?"
  unterzeile="Vorschlag von Albert"
  knoepfe={<KarteVorschlagKnoepfe onUebernehmen={…} onZurueck={…} />} />

Register Family Manager, kurz und ruhig. Die Bedeutungen werden nicht getauscht: blau ist Fahrt, gelb ist Familie, gestrichelt rosa heisst "ohne Zuständigen". Ein Vorschlag hat immer zwei Knöpfe – Albert erledigt nie still.

Types (.d.ts)
/**
 * Die Karte in fuenf Arten. Die Farbe sagt die Art, das Symbol die Sache, die Punkte die Leute.
 */
export interface KarteProps {
  /** "termin" beige | "fahrt" blau | "familie" gelb | "vorschlag" gestrichelt grau | "offen" gestrichelt rosa. */
  art?: "termin" | "fahrt" | "familie" | "vorschlag" | "offen";
  /** Kartentitel, ein Gegenstand: "Rückfahrt Auswärtsspiel". */
  titel: string;
  /** Zweitzeile: Ort oder Bündel-Teile, mit " · " getrennt. */
  ort?: React.ReactNode;
  /** Zeitspanne als "16:00 – 17:00" (Halbgeviertstrich mit Leerzeichen). */
  zeit?: string;
  /** Wer dabei ist; der Zustaendige zuerst. */
  leute?: string[];
  /** Sach-Symbol, wenn es nicht aus der Art folgt: "schule", "sport", "arzt", "musik". */
  symbol?: string;
  /** "kurz" (78 px) oder "hoch" (132 px) - fuer das Stundenraster. */
  hoehe?: "kurz" | "hoch";
  /** Zustands- und Fahrt-Pillen. */
  pillen?: React.ReactNode;
  /** Handlungsknoepfe; bei Vorschlaegen immer zwei. */
  knoepfe?: React.ReactNode;
  /** Kleine Zeile unter dem Inhalt, z. B. "Vorschlag von Albert". */
  unterzeile?: React.ReactNode;
  /** Einzeiler fuer Listen: Symbol, Titel, Zeit, Punkt. */
  kompakt?: boolean;
  klickbar?: boolean;
  /** Leicht gekippt, wie ein liegender Klebezettel. */
  gekippt?: boolean;
  children?: React.ReactNode;
  style?: React.CSSProperties;
}
export function Karte(props: KarteProps): JSX.Element;
export function KarteVorschlagKnoepfe(props: { uebernehmen?: string; zurueck?: string; onUebernehmen?: () => void; onZurueck?: () => void }): JSX.Element;