234 lines
8.4 KiB
PHP
234 lines
8.4 KiB
PHP
<?php
|
|
|
|
use App\Models\AdminLog;
|
|
use App\Models\Page;
|
|
use Livewire\Volt\Component;
|
|
|
|
new class extends Component
|
|
{
|
|
public Page $page;
|
|
|
|
public string $activeTab = 'ar';
|
|
public string $content_ar = '';
|
|
public string $content_en = '';
|
|
public bool $showPreview = false;
|
|
|
|
public function mount(string $slug): void
|
|
{
|
|
$this->page = Page::query()->where('slug', $slug)->firstOrFail();
|
|
$this->content_ar = $this->page->content_ar ?? '';
|
|
$this->content_en = $this->page->content_en ?? '';
|
|
}
|
|
|
|
public function setTab(string $tab): void
|
|
{
|
|
$this->activeTab = $tab;
|
|
}
|
|
|
|
public function save(): void
|
|
{
|
|
$oldValues = $this->page->toArray();
|
|
|
|
$this->page->update([
|
|
'content_ar' => clean($this->content_ar),
|
|
'content_en' => clean($this->content_en),
|
|
]);
|
|
|
|
AdminLog::create([
|
|
'admin_id' => auth()->id(),
|
|
'action' => 'update',
|
|
'target_type' => 'page',
|
|
'target_id' => $this->page->id,
|
|
'old_values' => $oldValues,
|
|
'new_values' => $this->page->fresh()->toArray(),
|
|
'ip_address' => request()->ip(),
|
|
'created_at' => now(),
|
|
]);
|
|
|
|
session()->flash('success', __('pages.page_saved'));
|
|
}
|
|
|
|
public function togglePreview(): void
|
|
{
|
|
$this->showPreview = ! $this->showPreview;
|
|
}
|
|
|
|
public function closePreview(): void
|
|
{
|
|
$this->showPreview = false;
|
|
}
|
|
}; ?>
|
|
|
|
<div>
|
|
<div class="mb-6">
|
|
<flux:button variant="outline" :href="route('admin.pages.index')" wire:navigate icon="arrow-left">
|
|
{{ __('pages.back_to_pages') }}
|
|
</flux:button>
|
|
</div>
|
|
|
|
<div class="mb-6 flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center">
|
|
<div>
|
|
<flux:heading size="xl">{{ __('pages.edit_page') }}: {{ $page->title_en }}</flux:heading>
|
|
<p class="mt-1 text-sm text-zinc-500">
|
|
{{ __('pages.last_updated') }}: {{ $page->updated_at->diffForHumans() }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
@if (session('success'))
|
|
<flux:callout variant="success" class="mb-6">
|
|
{{ session('success') }}
|
|
</flux:callout>
|
|
@endif
|
|
|
|
<div class="rounded-lg border border-zinc-200 bg-white p-6">
|
|
<!-- Language Tabs -->
|
|
<div class="mb-6 border-b border-zinc-200">
|
|
<nav class="-mb-px flex gap-4">
|
|
<button
|
|
wire:click="setTab('ar')"
|
|
class="{{ $activeTab === 'ar' ? 'border-blue-500 text-blue-600' : 'border-transparent text-zinc-500 hover:border-zinc-300 hover:text-zinc-700' }} border-b-2 px-1 pb-3 text-sm font-medium transition-colors"
|
|
>
|
|
{{ __('pages.arabic') }}
|
|
</button>
|
|
<button
|
|
wire:click="setTab('en')"
|
|
class="{{ $activeTab === 'en' ? 'border-blue-500 text-blue-600' : 'border-transparent text-zinc-500 hover:border-zinc-300 hover:text-zinc-700' }} border-b-2 px-1 pb-3 text-sm font-medium transition-colors"
|
|
>
|
|
{{ __('pages.english') }}
|
|
</button>
|
|
</nav>
|
|
</div>
|
|
|
|
<form wire:submit="save" class="space-y-6">
|
|
<!-- Arabic Content -->
|
|
<div x-show="$wire.activeTab === 'ar'" x-cloak>
|
|
<flux:field>
|
|
<flux:label>{{ __('pages.content') }} ({{ __('pages.arabic') }})</flux:label>
|
|
<div wire:ignore>
|
|
<div
|
|
id="editor-ar"
|
|
class="min-h-[300px] rounded-lg border border-zinc-200 bg-white"
|
|
dir="rtl"
|
|
></div>
|
|
<textarea id="content_ar" wire:model="content_ar" class="hidden">{{ $content_ar }}</textarea>
|
|
</div>
|
|
</flux:field>
|
|
</div>
|
|
|
|
<!-- English Content -->
|
|
<div x-show="$wire.activeTab === 'en'" x-cloak>
|
|
<flux:field>
|
|
<flux:label>{{ __('pages.content') }} ({{ __('pages.english') }})</flux:label>
|
|
<div wire:ignore>
|
|
<div
|
|
id="editor-en"
|
|
class="min-h-[300px] rounded-lg border border-zinc-200 bg-white"
|
|
></div>
|
|
<textarea id="content_en" wire:model="content_en" class="hidden">{{ $content_en }}</textarea>
|
|
</div>
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div class="flex items-center justify-end gap-4 border-t border-zinc-200 pt-6">
|
|
<flux:button variant="outline" :href="route('admin.pages.index')" wire:navigate>
|
|
{{ __('common.cancel') }}
|
|
</flux:button>
|
|
<flux:button type="button" wire:click="togglePreview">
|
|
{{ __('pages.preview') }}
|
|
</flux:button>
|
|
<flux:button variant="primary" type="submit">
|
|
{{ __('pages.save_publish') }}
|
|
</flux:button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
{{-- Preview Modal --}}
|
|
<flux:modal wire:model="showPreview" class="max-w-4xl">
|
|
<div class="p-6">
|
|
<flux:heading size="lg" class="mb-4">{{ __('pages.preview') }}</flux:heading>
|
|
|
|
<div class="space-y-6">
|
|
<div class="border-b border-zinc-200 pb-4">
|
|
<h3 class="mb-2 text-lg font-semibold text-zinc-600">{{ __('pages.arabic') }}</h3>
|
|
<h2 class="text-xl font-bold text-zinc-900" dir="rtl">{{ $page->title_ar }}</h2>
|
|
<div class="prose prose-sm mt-2 max-w-none" dir="rtl">{!! clean($content_ar) !!}</div>
|
|
</div>
|
|
|
|
<div>
|
|
<h3 class="mb-2 text-lg font-semibold text-zinc-600">{{ __('pages.english') }}</h3>
|
|
<h2 class="text-xl font-bold text-zinc-900">{{ $page->title_en }}</h2>
|
|
<div class="prose prose-sm mt-2 max-w-none">{!! clean($content_en) !!}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6 flex justify-end">
|
|
<flux:button wire:click="closePreview">{{ __('common.close') }}</flux:button>
|
|
</div>
|
|
</div>
|
|
</flux:modal>
|
|
</div>
|
|
|
|
@push('styles')
|
|
<link href="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.snow.css" rel="stylesheet" />
|
|
<style>
|
|
.ql-editor {
|
|
min-height: 250px;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.ql-container {
|
|
font-family: inherit;
|
|
}
|
|
</style>
|
|
@endpush
|
|
|
|
@push('scripts')
|
|
<script src="https://cdn.jsdelivr.net/npm/quill@2.0.3/dist/quill.js"></script>
|
|
<script>
|
|
document.addEventListener('livewire:navigated', initQuillEditors)
|
|
document.addEventListener('DOMContentLoaded', initQuillEditors)
|
|
|
|
function initQuillEditors() {
|
|
if (document.querySelector('#editor-ar') && !document.querySelector('#editor-ar .ql-editor')) {
|
|
const toolbarOptions = [
|
|
[{ header: [1, 2, 3, false] }],
|
|
['bold', 'italic', 'underline'],
|
|
[{ list: 'ordered' }, { list: 'bullet' }],
|
|
['link'],
|
|
['clean'],
|
|
]
|
|
|
|
// Arabic Editor
|
|
const quillAr = new Quill('#editor-ar', {
|
|
theme: 'snow',
|
|
modules: {
|
|
toolbar: toolbarOptions,
|
|
},
|
|
placeholder: '{{ __('pages.enter_content_ar') }}',
|
|
})
|
|
|
|
quillAr.root.innerHTML = document.getElementById('content_ar').value
|
|
quillAr.on('text-change', function () {
|
|
@this.set('content_ar', quillAr.root.innerHTML)
|
|
})
|
|
|
|
// English Editor
|
|
const quillEn = new Quill('#editor-en', {
|
|
theme: 'snow',
|
|
modules: {
|
|
toolbar: toolbarOptions,
|
|
},
|
|
placeholder: '{{ __('pages.enter_content_en') }}',
|
|
})
|
|
|
|
quillEn.root.innerHTML = document.getElementById('content_en').value
|
|
quillEn.on('text-change', function () {
|
|
@this.set('content_en', quillEn.root.innerHTML)
|
|
})
|
|
}
|
|
}
|
|
</script>
|
|
@endpush
|