'Desktop', 'tablet' => 'Tablet', 'mobile' => 'Mobil']; /** A colour is a hex value or "@name", a reference into the site palette. */ public const COLOR = '/^(#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?|@[a-z][a-z0-9-]{0,31})$/D'; /** A length is a number with a unit, plus the two keywords that behave like one. */ public const LENGTH = '/^(0|-?\d{1,5}(\.\d{1,3})?(px|rem|em|%|vw|vh|ch))$/D'; public const LENGTH_AUTO = '/^(auto|none|0|-?\d{1,5}(\.\d{1,3})?(px|rem|em|%|vw|vh|ch))$/D'; /** * group – where the property appears in the editor * type – length | length-auto | color | number | choice | text * css – the CSS property it becomes; sides/corners expand to four * label – German label for the editor. * * @return array, min?: float, max?: float, step?: float, sides?: bool, hover?: bool}> */ public static function properties(): array { return [ // ---- Typografie ------------------------------------------------------------- 'fontFamily' => ['group' => 'text', 'type' => 'font', 'css' => 'font-family', 'label' => 'Schriftart'], 'fontSize' => ['group' => 'text', 'type' => 'length', 'css' => 'font-size', 'label' => 'Schriftgröße'], 'fontWeight' => ['group' => 'text', 'type' => 'choice', 'css' => 'font-weight', 'label' => 'Schriftstärke', 'values' => [ '100' => '100 · Thin', '200' => '200 · Extra Light', '300' => '300 · Light', '400' => '400 · Regular', '500' => '500 · Medium', '600' => '600 · Semibold', '700' => '700 · Bold', '800' => '800 · Extra Bold', '900' => '900 · Black', ]], 'fontStyle' => ['group' => 'text', 'type' => 'choice', 'css' => 'font-style', 'label' => 'Schriftlage', 'values' => ['normal' => 'Normal', 'italic' => 'Kursiv']], 'lineHeight' => ['group' => 'text', 'type' => 'number', 'css' => 'line-height', 'label' => 'Zeilenhöhe', 'min' => 0.7, 'max' => 4, 'step' => 0.05], 'letterSpacing' => ['group' => 'text', 'type' => 'length', 'css' => 'letter-spacing', 'label' => 'Buchstabenabstand'], 'wordSpacing' => ['group' => 'text', 'type' => 'length', 'css' => 'word-spacing', 'label' => 'Wortabstand'], 'textAlign' => ['group' => 'text', 'type' => 'choice', 'css' => 'text-align', 'label' => 'Ausrichtung', 'values' => [ 'left' => 'Links', 'center' => 'Mittig', 'right' => 'Rechts', 'justify' => 'Blocksatz', ]], 'textTransform' => ['group' => 'text', 'type' => 'choice', 'css' => 'text-transform', 'label' => 'Schreibweise', 'values' => [ 'none' => 'Wie eingegeben', 'uppercase' => 'GROSSBUCHSTABEN', 'lowercase' => 'kleinbuchstaben', 'capitalize' => 'Erster Buchstabe Groß', ]], 'textDecoration' => ['group' => 'text', 'type' => 'choice', 'css' => 'text-decoration-line', 'label' => 'Textlinie', 'values' => [ 'none' => 'Keine', 'underline' => 'Unterstrichen', 'line-through' => 'Durchgestrichen', ]], 'color' => ['group' => 'text', 'type' => 'color', 'css' => 'color', 'label' => 'Textfarbe', 'hover' => true], // ---- Hintergrund ------------------------------------------------------------ 'backgroundColor' => ['group' => 'background', 'type' => 'color', 'css' => 'background-color', 'label' => 'Hintergrundfarbe', 'hover' => true], 'gradientFrom' => ['group' => 'background', 'type' => 'color', 'css' => null, 'label' => 'Verlauf von'], 'gradientTo' => ['group' => 'background', 'type' => 'color', 'css' => null, 'label' => 'Verlauf bis'], 'gradientAngle' => ['group' => 'background', 'type' => 'number', 'css' => null, 'label' => 'Verlaufswinkel', 'min' => 0, 'max' => 360, 'step' => 1], 'backgroundImage' => ['group' => 'background', 'type' => 'media', 'css' => null, 'label' => 'Hintergrundbild'], 'backgroundSize' => ['group' => 'background', 'type' => 'choice', 'css' => 'background-size', 'label' => 'Bildgröße', 'values' => [ 'cover' => 'Füllend', 'contain' => 'Vollständig sichtbar', 'auto' => 'Originalgröße', ]], 'backgroundPosition' => ['group' => 'background', 'type' => 'choice', 'css' => 'background-position', 'label' => 'Bildausschnitt', 'values' => [ 'center' => 'Mittig', 'top' => 'Oben', 'bottom' => 'Unten', 'left' => 'Links', 'right' => 'Rechts', 'top left' => 'Oben links', 'top right' => 'Oben rechts', 'bottom left' => 'Unten links', 'bottom right' => 'Unten rechts', ]], 'backgroundRepeat' => ['group' => 'background', 'type' => 'choice', 'css' => 'background-repeat', 'label' => 'Wiederholung', 'values' => [ 'no-repeat' => 'Nicht wiederholen', 'repeat' => 'Kacheln', 'repeat-x' => 'Waagerecht kacheln', 'repeat-y' => 'Senkrecht kacheln', ]], 'backgroundAttachment' => ['group' => 'background', 'type' => 'choice', 'css' => 'background-attachment', 'label' => 'Scrollverhalten', 'values' => [ 'scroll' => 'Mitscrollen', 'fixed' => 'Feststehend (Parallax)', ]], 'overlayColor' => ['group' => 'background', 'type' => 'color', 'css' => null, 'label' => 'Überlagerung'], 'overlayOpacity' => ['group' => 'background', 'type' => 'number', 'css' => null, 'label' => 'Deckkraft der Überlagerung', 'min' => 0, 'max' => 1, 'step' => 0.05], // ---- Abstand ---------------------------------------------------------------- 'padding' => ['group' => 'spacing', 'type' => 'length', 'css' => 'padding', 'label' => 'Innenabstand', 'sides' => true], 'margin' => ['group' => 'spacing', 'type' => 'length-auto', 'css' => 'margin', 'label' => 'Außenabstand', 'sides' => true], // ---- Größe ------------------------------------------------------------------ 'width' => ['group' => 'size', 'type' => 'length-auto', 'css' => 'width', 'label' => 'Breite'], 'maxWidth' => ['group' => 'size', 'type' => 'length-auto', 'css' => 'max-width', 'label' => 'Maximale Breite'], 'minWidth' => ['group' => 'size', 'type' => 'length-auto', 'css' => 'min-width', 'label' => 'Mindestbreite'], 'height' => ['group' => 'size', 'type' => 'length-auto', 'css' => 'height', 'label' => 'Höhe'], 'minHeight' => ['group' => 'size', 'type' => 'length-auto', 'css' => 'min-height', 'label' => 'Mindesthöhe'], 'maxHeight' => ['group' => 'size', 'type' => 'length-auto', 'css' => 'max-height', 'label' => 'Maximale Höhe'], 'overflow' => ['group' => 'size', 'type' => 'choice', 'css' => 'overflow', 'label' => 'Überlauf', 'values' => [ 'visible' => 'Sichtbar', 'hidden' => 'Abschneiden', 'auto' => 'Scrollen bei Bedarf', ]], // ---- Rahmen ----------------------------------------------------------------- 'borderWidth' => ['group' => 'border', 'type' => 'length', 'css' => 'border-width', 'label' => 'Rahmenstärke', 'sides' => true], 'borderStyle' => ['group' => 'border', 'type' => 'choice', 'css' => 'border-style', 'label' => 'Rahmenart', 'values' => [ 'solid' => 'Durchgezogen', 'dashed' => 'Gestrichelt', 'dotted' => 'Gepunktet', 'double' => 'Doppelt', 'none' => 'Keiner', ]], 'borderColor' => ['group' => 'border', 'type' => 'color', 'css' => 'border-color', 'label' => 'Rahmenfarbe', 'hover' => true], 'borderRadius' => ['group' => 'border', 'type' => 'length', 'css' => 'border-radius', 'label' => 'Ecken', 'corners' => true], // ---- Layout ----------------------------------------------------------------- 'display' => ['group' => 'layout', 'type' => 'choice', 'css' => 'display', 'label' => 'Anzeige', 'values' => [ 'block' => 'Block', 'flex' => 'Flex', 'inline-flex' => 'Inline-Flex', 'grid' => 'Raster', 'inline-block' => 'Inline-Block', 'none' => 'Ausgeblendet', ]], 'flexDirection' => ['group' => 'layout', 'type' => 'choice', 'css' => 'flex-direction', 'label' => 'Flexrichtung', 'values' => [ 'row' => 'Nebeneinander', 'row-reverse' => 'Nebeneinander, umgekehrt', 'column' => 'Untereinander', 'column-reverse' => 'Untereinander, umgekehrt', ]], 'flexWrap' => ['group' => 'layout', 'type' => 'choice', 'css' => 'flex-wrap', 'label' => 'Umbruch', 'values' => ['wrap' => 'Umbrechen', 'nowrap' => 'Nicht umbrechen']], 'justifyContent' => ['group' => 'layout', 'type' => 'choice', 'css' => 'justify-content', 'label' => 'Verteilung', 'values' => [ 'flex-start' => 'Anfang', 'center' => 'Mitte', 'flex-end' => 'Ende', 'space-between' => 'Außen verteilt', 'space-around' => 'Gleichmäßig', 'space-evenly' => 'Exakt gleich', ]], 'alignItems' => ['group' => 'layout', 'type' => 'choice', 'css' => 'align-items', 'label' => 'Ausrichtung quer', 'values' => [ 'stretch' => 'Dehnen', 'flex-start' => 'Anfang', 'center' => 'Mitte', 'flex-end' => 'Ende', 'baseline' => 'Grundlinie', ]], 'gridColumns' => ['group' => 'layout', 'type' => 'number', 'css' => null, 'label' => 'Spalten', 'min' => 1, 'max' => 12, 'step' => 1], 'gap' => ['group' => 'layout', 'type' => 'length', 'css' => 'gap', 'label' => 'Abstand zwischen Elementen'], 'order' => ['group' => 'layout', 'type' => 'number', 'css' => 'order', 'label' => 'Reihenfolge', 'min' => -20, 'max' => 20, 'step' => 1], // ---- Wirkung ---------------------------------------------------------------- 'opacity' => ['group' => 'effect', 'type' => 'number', 'css' => 'opacity', 'label' => 'Deckkraft', 'min' => 0, 'max' => 1, 'step' => 0.05, 'hover' => true], 'shadowX' => ['group' => 'effect', 'type' => 'length', 'css' => null, 'label' => 'Schatten waagerecht'], 'shadowY' => ['group' => 'effect', 'type' => 'length', 'css' => null, 'label' => 'Schatten senkrecht'], 'shadowBlur' => ['group' => 'effect', 'type' => 'length', 'css' => null, 'label' => 'Schatten weich'], 'shadowSpread' => ['group' => 'effect', 'type' => 'length', 'css' => null, 'label' => 'Schatten größer'], 'shadowColor' => ['group' => 'effect', 'type' => 'color', 'css' => null, 'label' => 'Schattenfarbe', 'hover' => true], 'translateX' => ['group' => 'effect', 'type' => 'length', 'css' => null, 'label' => 'Verschieben waagerecht', 'hover' => true], 'translateY' => ['group' => 'effect', 'type' => 'length', 'css' => null, 'label' => 'Verschieben senkrecht', 'hover' => true], 'scale' => ['group' => 'effect', 'type' => 'number', 'css' => null, 'label' => 'Skalierung', 'min' => 0.1, 'max' => 3, 'step' => 0.01, 'hover' => true], 'rotate' => ['group' => 'effect', 'type' => 'number', 'css' => null, 'label' => 'Drehung', 'min' => -360, 'max' => 360, 'step' => 1, 'hover' => true], 'transition' => ['group' => 'effect', 'type' => 'number', 'css' => null, 'label' => 'Übergangsdauer (ms)', 'min' => 0, 'max' => 2000, 'step' => 25], ]; } /** Properties that may also be given a hover value. */ public static function hoverable(): array { return array_keys(array_filter(self::properties(), static fn (array $p): bool => $p['hover'] ?? false)); } public static function sides(): array { return ['top' => 'Oben', 'right' => 'Rechts', 'bottom' => 'Unten', 'left' => 'Links']; } /** Corners round a box; they are not sides, and their CSS property is spelled differently. */ public static function corners(): array { return ['topLeft' => 'Oben links', 'topRight' => 'Oben rechts', 'bottomRight' => 'Unten rechts', 'bottomLeft' => 'Unten links']; } /** "topLeft" becomes the CSS fragment "top-left". */ public static function cornerCss(string $corner): string { return strtolower(preg_replace('/([A-Z])/', '-$1', $corner) ?? $corner); } }