schema([ Section::make('Grunddaten') ->columns(2) ->schema([ TextInput::make('name') ->label('Name') ->required() ->maxLength(255) ->afterStateUpdated(fn (callable $set, $state) => $set('slug', Str::slug((string) $state ?? ''))) ->reactive(), TextInput::make('slug') ->label('Slug') ->required() ->maxLength(191) ->unique(ignoreRecord: true), TextInput::make('subtitle') ->label('Unterzeile') ->maxLength(255) ->columnSpanFull(), Textarea::make('description') ->label('Beschreibung') ->rows(4) ->columnSpanFull(), Toggle::make('is_active') ->label('Aktiv') ->default(true), ]), Section::make('Papier & Format') ->columns(3) ->schema([ Select::make('paper') ->label('Papierformat') ->options([ 'a4' => 'A4 (210 × 297 mm)', 'a5' => 'A5 (148 × 210 mm)', 'a3' => 'A3 (297 × 420 mm)', 'custom' => 'Benutzerdefiniert', ]) ->default('a4'), Select::make('orientation') ->label('Ausrichtung') ->options([ 'portrait' => 'Hochformat', 'landscape' => 'Querformat', ]) ->default('portrait'), TextInput::make('layout_options.formats') ->label('Formate (Komma getrennt)') ->default('pdf,svg') ->helperText('Bestimmt, welche Downloads angeboten werden.') ->dehydrateStateUsing(fn ($state) => collect(explode(',', (string) $state)) ->map(fn ($value) => trim((string) $value)) ->filter() ->values() ->all()) ->afterStateHydrated(function (TextInput $component, $state) { if (is_array($state)) { $component->state(implode(',', $state)); } }), ]), Section::make('Farben') ->columns(5) ->schema([ ColorPicker::make('preview.background') ->label('Hintergrund') ->default('#F9FAFB'), ColorPicker::make('preview.accent') ->label('Akzent') ->default('#6366F1'), ColorPicker::make('preview.text') ->label('Text') ->default('#0F172A'), ColorPicker::make('preview.secondary') ->label('Sekundär') ->default('#CBD5F5'), ColorPicker::make('preview.badge') ->label('Badge') ->default('#2563EB'), TextInput::make('preview.qr.size_px') ->label('QR-Größe (px)') ->numeric() ->default(320) ->columnSpan(2), TextInput::make('preview.svg.width') ->label('SVG Breite') ->numeric() ->default(1080), TextInput::make('preview.svg.height') ->label('SVG Höhe') ->numeric() ->default(1520), ]), Section::make('Texte & Hinweise') ->columns(2) ->schema([ TextInput::make('layout_options.badge_label') ->label('Badge-Label') ->default('Digitale Gästebox'), TextInput::make('layout_options.instructions_heading') ->label('Anleitungstitel') ->default("So funktioniert's"), TextInput::make('layout_options.link_heading') ->label('Link-Titel') ->default('Alternative zum Einscannen'), TextInput::make('layout_options.cta_label') ->label('CTA Label') ->default('Scan mich & starte direkt'), TextInput::make('layout_options.cta_caption') ->label('CTA Untertitel') ->default('Scan mich & starte direkt'), TextInput::make('layout_options.link_label') ->label('Link Text (optional)') ->helperText('Überschreibt den standardmäßigen Einladungslink.'), TextInput::make('layout_options.logo_url') ->label('Logo URL') ->columnSpanFull(), Repeater::make('instructions') ->label('Hinweise') ->maxItems(6) ->schema([ Textarea::make('value') ->label('Hinweistext') ->rows(2) ->required() ->maxLength(180), ]) ->afterStateHydrated(function (Repeater $component, $state): void { if (is_array($state) && ! empty($state) && ! is_array(current($state))) { $component->state(array_map(fn ($value) => ['value' => $value], $state)); } }) ->dehydrateStateUsing(fn ($state) => collect($state)->pluck('value')->filter()->values()->all()), ]), ]); } }