Files
WitShop/resources/views/admin/pages/form.blade.php
T
marcoandClaude Sonnet 4.6 41078fdc08 Initial commit: WitShop Laravel Online-Shop
- Laravel 11, Blade, Alpine.js, Tailwind CSS
- Produkt- & Kategorieverwaltung mit Varianten
- Checkout (Vorkasse + Rechnung), Session-Warenkorb
- Admin-Backend (Dashboard, Bestellungen, Kunden, CMS)
- DSGVO-konform: Cookie-Consent, Impressum, Widerruf, AGB
- PDF-Rechnung via dompdf, SMTP-Mailversand
- Kundenverwaltung mit manueller Freischaltung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-20 00:34:09 +02:00

253 lines
12 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@extends('layouts.admin')
@section('title', isset($page) ? 'Seite bearbeiten' : 'Neue Seite')
@push('head')
{{-- Quill WYSIWYG --}}
<link href="https://cdn.quilljs.com/1.3.7/quill.snow.css" rel="stylesheet">
<style>
.ql-container { font-size: 14px; min-height: 320px; border-bottom-left-radius: 6px; border-bottom-right-radius: 6px; }
.ql-toolbar { border-top-left-radius: 6px; border-top-right-radius: 6px; background: #f9fafb; }
.ql-editor { min-height: 320px; line-height: 1.7; }
.ql-editor h1 { font-size: 1.8em; font-weight: 700; margin-bottom: .5em; }
.ql-editor h2 { font-size: 1.4em; font-weight: 600; margin-bottom: .4em; }
.ql-editor h3 { font-size: 1.15em; font-weight: 600; margin-bottom: .3em; }
.ql-editor a { color: #2563eb; text-decoration: underline; }
.ql-editor blockquote { border-left: 4px solid #d1d5db; padding-left: 1em; color: #6b7280; font-style: italic; }
.ql-editor pre { background: #1e293b; color: #e2e8f0; padding: 1em; border-radius: 6px; font-family: monospace; overflow-x: auto; }
.ql-editor ul, .ql-editor ol { padding-left: 1.5em; }
.ql-editor img { max-width: 100%; border-radius: 4px; }
</style>
@endpush
@section('content')
<div class="max-w-4xl">
<form id="page-form"
method="POST"
action="{{ isset($page) ? route('admin.pages.update', $page) : route('admin.pages.store') }}"
enctype="multipart/form-data"
class="space-y-4">
@csrf @if(isset($page)) @method('PUT') @endif
{{-- Metadaten --}}
<div class="bg-white rounded shadow p-6 space-y-4">
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium mb-1">Titel *</label>
<input type="text" name="title" id="title-input"
value="{{ old('title', $page->title ?? '') }}"
class="w-full border rounded px-3 py-2 text-sm" required>
</div>
<div>
<label class="block text-sm font-medium mb-1">
Slug (URL)
<span class="text-xs text-gray-400 font-normal">– automatisch aus Titel</span>
</label>
<div class="flex items-center border rounded overflow-hidden">
<span class="px-2 py-2 bg-gray-50 text-gray-400 text-xs border-r select-none">/seite/</span>
<input type="text" name="slug" id="slug-input"
value="{{ old('slug', $page->slug ?? '') }}"
class="flex-1 px-3 py-2 text-sm font-mono focus:outline-none"
placeholder="wird-automatisch-generiert">
</div>
</div>
<div>
<label class="block text-sm font-medium mb-1">Typ</label>
<select name="type" class="w-full border rounded px-3 py-2 text-sm">
<option value="static" {{ old('type', $page->type ?? 'static') === 'static' ? 'selected' : '' }}>Statische Seite (Impressum, AGB, …)</option>
<option value="blog" {{ old('type', $page->type ?? '') === 'blog' ? 'selected' : '' }}>Blog-Beitrag</option>
</select>
</div>
<div>
<label class="block text-sm font-medium mb-1">Titelbild</label>
@if(isset($page) && $page->image)
<img src="{{ asset('storage/'.$page->image) }}" class="h-10 mb-1 rounded">
@endif
<input type="file" name="image" accept="image/*" class="text-sm">
</div>
</div>
</div>
{{-- WYSIWYG Editor --}}
<div class="bg-white rounded shadow overflow-hidden">
<div class="px-5 py-3 border-b flex items-center justify-between">
<span class="text-sm font-semibold text-gray-700">Inhalt</span>
<button type="button" id="toggle-source"
class="text-xs px-3 py-1 border rounded hover:bg-gray-50 text-gray-500">
HTML-Quellcode
</button>
</div>
{{-- Quill Editor --}}
<div id="quill-editor" class="border-0">
{!! old('content', $page->content ?? '') !!}
</div>
{{-- Roher HTML-Quellcode (Toggle) --}}
<textarea id="source-editor" name="_content_source" rows="16"
class="hidden w-full px-4 py-3 text-sm font-mono border-0 focus:outline-none resize-none"
style="min-height: 320px">{{ old('content', $page->content ?? '') }}</textarea>
{{-- Verstecktes Feld das beim Submit gefüllt wird --}}
<input type="hidden" name="content" id="content-hidden"
value="{{ old('content', $page->content ?? '') }}">
</div>
{{-- SEO & Optionen --}}
<div class="bg-white rounded shadow p-6 space-y-4">
<h3 class="text-sm font-semibold text-gray-700">SEO & Einstellungen</h3>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium mb-1">Meta-Titel <span class="text-xs text-gray-400 font-normal">(Browser-Tab)</span></label>
<input type="text" name="meta_title"
value="{{ old('meta_title', $page->meta_title ?? '') }}"
class="w-full border rounded px-3 py-2 text-sm">
</div>
<div>
<label class="block text-sm font-medium mb-1">Meta-Beschreibung <span class="text-xs text-gray-400 font-normal">(Suchergebnisse)</span></label>
<input type="text" name="meta_description"
value="{{ old('meta_description', $page->meta_description ?? '') }}"
class="w-full border rounded px-3 py-2 text-sm"
maxlength="160">
</div>
<div>
<label class="block text-sm font-medium mb-1">Veröffentlichungsdatum</label>
<input type="date" name="published_at"
value="{{ old('published_at', isset($page->published_at) ? $page->published_at->format('Y-m-d') : '') }}"
class="w-full border rounded px-3 py-2 text-sm">
</div>
<div class="flex items-end pb-2">
<label class="flex items-center gap-2 text-sm cursor-pointer">
<input type="checkbox" name="published" value="1"
{{ old('published', $page->published ?? true) ? 'checked' : '' }}
class="w-4 h-4 accent-blue-600">
<span>Veröffentlicht</span>
</label>
</div>
</div>
<hr class="border-gray-100">
<h3 class="text-sm font-semibold text-gray-700">Navigation</h3>
<div class="grid grid-cols-3 gap-4">
<label class="flex items-start gap-2 text-sm cursor-pointer p-3 border rounded-lg hover:bg-gray-50">
<input type="checkbox" name="show_in_footer" value="1"
{{ old('show_in_footer', $page->show_in_footer ?? true) ? 'checked' : '' }}
class="mt-0.5 accent-blue-600">
<div>
<span class="font-medium">Footer</span>
<p class="text-xs text-gray-400 mt-0.5">Link in der Fußzeile des Shops</p>
</div>
</label>
<label class="flex items-start gap-2 text-sm cursor-pointer p-3 border rounded-lg hover:bg-gray-50">
<input type="checkbox" name="show_in_nav" value="1"
{{ old('show_in_nav', $page->show_in_nav ?? false) ? 'checked' : '' }}
class="mt-0.5 accent-blue-600">
<div>
<span class="font-medium">Hauptmenü</span>
<p class="text-xs text-gray-400 mt-0.5">Link in der Top-Navigation</p>
</div>
</label>
<div>
<label class="block text-sm font-medium mb-1">Reihenfolge im Menü</label>
<input type="number" name="nav_sort" value="{{ old('nav_sort', $page->nav_sort ?? 0) }}"
class="w-full border rounded px-3 py-2 text-sm" min="0">
<p class="text-xs text-gray-400 mt-1">Niedrigere Zahl = weiter links</p>
</div>
</div>
</div>
@if($errors->any())
<div class="bg-red-50 border border-red-200 rounded px-4 py-3 text-sm text-red-700">
@foreach($errors->all() as $e)<p>• {{ $e }}</p>@endforeach
</div>
@endif
<div class="flex gap-3 pb-8">
<button type="submit" class="bg-blue-600 text-white px-6 py-2.5 rounded-lg hover:bg-blue-700 text-sm font-medium">
Speichern
</button>
<a href="{{ route('admin.pages.index') }}"
class="px-6 py-2.5 rounded-lg border text-sm hover:bg-gray-50">
Abbrechen
</a>
</div>
</form>
</div>
<script src="https://cdn.quilljs.com/1.3.7/quill.js"></script>
<script>
// ── Quill initialisieren ────────────────────────────────────────────────────
const quill = new Quill('#quill-editor', {
theme: 'snow',
modules: {
toolbar: [
[{ header: [1, 2, 3, false] }],
['bold', 'italic', 'underline', 'strike'],
[{ color: [] }, { background: [] }],
[{ align: [] }],
[{ list: 'ordered' }, { list: 'bullet' }],
[{ indent: '-1' }, { indent: '+1' }],
['blockquote', 'code-block'],
['link', 'image'],
['clean']
]
},
placeholder: 'Seiteninhalt hier eingeben …',
});
// ── Slug automatisch aus Titel generieren ───────────────────────────────────
const titleInput = document.getElementById('title-input');
const slugInput = document.getElementById('slug-input');
let slugManuallyEdited = slugInput.value.length > 0;
titleInput.addEventListener('input', () => {
if (slugManuallyEdited) return;
slugInput.value = titleInput.value
.toLowerCase()
.replace(/ä/g,'ae').replace(/ö/g,'oe').replace(/ü/g,'ue').replace(/ß/g,'ss')
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
});
slugInput.addEventListener('input', () => { slugManuallyEdited = true; });
// ── HTML-Quellcode-Toggle ───────────────────────────────────────────────────
const toggleBtn = document.getElementById('toggle-source');
const sourceEditor = document.getElementById('source-editor');
const quillWrapper = document.getElementById('quill-editor');
let sourceMode = false;
toggleBtn.addEventListener('click', () => {
sourceMode = !sourceMode;
if (sourceMode) {
// Quill → HTML
sourceEditor.value = quill.root.innerHTML === '<p><br></p>' ? '' : quill.root.innerHTML;
quillWrapper.style.display = 'none';
sourceEditor.classList.remove('hidden');
toggleBtn.textContent = 'WYSIWYG';
toggleBtn.classList.add('bg-yellow-50', 'text-yellow-700', 'border-yellow-300');
} else {
// HTML → Quill
quill.root.innerHTML = sourceEditor.value;
sourceEditor.classList.add('hidden');
quillWrapper.style.display = '';
toggleBtn.textContent = 'HTML-Quellcode';
toggleBtn.classList.remove('bg-yellow-50', 'text-yellow-700', 'border-yellow-300');
}
});
// ── Beim Absenden: Quill-HTML in hidden field schreiben ─────────────────────
document.getElementById('page-form').addEventListener('submit', () => {
const html = sourceMode
? sourceEditor.value
: (quill.root.innerHTML === '<p><br></p>' ? '' : quill.root.innerHTML);
document.getElementById('content-hidden').value = html;
});
</script>
@push('styles')
<style>
/* Quill-Bilder klickbar im Editor */
.ql-editor img { cursor: pointer; }
</style>
@endpush
@endsection