First commit
This commit is contained in:
commit
7cf3558ba7
12933 changed files with 1180047 additions and 0 deletions
375
packages/flux-cms/components/src/Livewire/Backend/PageEditor.php
Normal file
375
packages/flux-cms/components/src/Livewire/Backend/PageEditor.php
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
<?php
|
||||
|
||||
namespace FluxCms\Components\Livewire\Backend;
|
||||
|
||||
use Livewire\Component;
|
||||
use Livewire\Attributes\On;
|
||||
use FluxCms\Core\Models\Page;
|
||||
use FluxCms\Core\Models\PageComponent;
|
||||
use FluxCms\Core\Services\ComponentRegistry;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class PageEditor extends Component
|
||||
{
|
||||
public Page $page;
|
||||
public Collection $components;
|
||||
public array $availableLanguages = [];
|
||||
public string $currentLocale = 'de';
|
||||
public bool $showComponentModal = false;
|
||||
public array $availableComponents = [];
|
||||
public string $selectedCategory = 'all';
|
||||
public bool $isLoading = false;
|
||||
|
||||
protected ComponentRegistry $componentRegistry;
|
||||
|
||||
public function boot(ComponentRegistry $componentRegistry)
|
||||
{
|
||||
$this->componentRegistry = $componentRegistry;
|
||||
}
|
||||
|
||||
public function mount(Page $page)
|
||||
{
|
||||
$this->page = $page;
|
||||
$this->availableLanguages = array_keys(config('flux-cms.locales', ['de' => 'Deutsch', 'en' => 'English']));
|
||||
$this->currentLocale = app()->getLocale();
|
||||
$this->loadComponents();
|
||||
$this->loadAvailableComponents();
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('flux-cms-components::livewire.backend.page-editor')
|
||||
->layout('flux-cms-components::layouts.admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Load page components
|
||||
*/
|
||||
public function loadComponents()
|
||||
{
|
||||
$this->components = $this->page->allComponents()->ordered()->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load available components from registry
|
||||
*/
|
||||
public function loadAvailableComponents()
|
||||
{
|
||||
$this->availableComponents = $this->componentRegistry->getComponentsByCategory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch locale
|
||||
*/
|
||||
public function switchLocale(string $locale)
|
||||
{
|
||||
if (in_array($locale, $this->availableLanguages)) {
|
||||
$this->currentLocale = $locale;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show add component modal
|
||||
*/
|
||||
public function showAddComponentModal()
|
||||
{
|
||||
$this->loadAvailableComponents(); // Refresh components
|
||||
$this->showComponentModal = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close add component modal
|
||||
*/
|
||||
public function closeAddComponentModal()
|
||||
{
|
||||
$this->showComponentModal = false;
|
||||
$this->selectedCategory = 'all';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set category filter
|
||||
*/
|
||||
public function setCategory(string $category)
|
||||
{
|
||||
$this->selectedCategory = $category;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new component
|
||||
*/
|
||||
public function addComponent(string $componentClass)
|
||||
{
|
||||
if (!$this->componentRegistry->isValidComponent($componentClass)) {
|
||||
$this->addError('component', 'Invalid component selected.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$maxOrder = $this->page->allComponents()->max('order') ?? 0;
|
||||
|
||||
$component = $this->page->allComponents()->create([
|
||||
'component_class' => $componentClass,
|
||||
'order' => $maxOrder + 1,
|
||||
'content' => $this->getDefaultContent($componentClass),
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$this->loadComponents();
|
||||
$this->closeAddComponentModal();
|
||||
|
||||
$this->dispatch('scroll-to-component', componentId: $component->id);
|
||||
session()->flash('success', 'Component added successfully.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('component', 'Error adding component: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete component
|
||||
*/
|
||||
public function deleteComponent(int $componentId)
|
||||
{
|
||||
try {
|
||||
$component = $this->components->firstWhere('id', $componentId);
|
||||
|
||||
if (!$component) {
|
||||
$this->addError('component', 'Component not found.');
|
||||
return;
|
||||
}
|
||||
|
||||
$component->delete();
|
||||
$this->loadComponents();
|
||||
$this->reorderComponents();
|
||||
|
||||
session()->flash('success', 'Component deleted successfully.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('component', 'Error deleting component: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate component
|
||||
*/
|
||||
public function duplicateComponent(int $componentId)
|
||||
{
|
||||
try {
|
||||
$component = $this->components->firstWhere('id', $componentId);
|
||||
|
||||
if (!$component) {
|
||||
$this->addError('component', 'Component not found.');
|
||||
return;
|
||||
}
|
||||
|
||||
$duplicate = $component->duplicate();
|
||||
$this->loadComponents();
|
||||
|
||||
$this->dispatch('scroll-to-component', componentId: $duplicate->id);
|
||||
session()->flash('success', 'Component duplicated successfully.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('component', 'Error duplicating component: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle component active state
|
||||
*/
|
||||
public function toggleComponent(int $componentId)
|
||||
{
|
||||
try {
|
||||
$component = $this->components->firstWhere('id', $componentId);
|
||||
|
||||
if (!$component) {
|
||||
return;
|
||||
}
|
||||
|
||||
$component->update(['is_active' => !$component->is_active]);
|
||||
$this->loadComponents();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('component', 'Error toggling component: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update component order
|
||||
*/
|
||||
#[On('components-reordered')]
|
||||
public function updateOrder(array $orderedIds)
|
||||
{
|
||||
try {
|
||||
foreach ($orderedIds as $index => $id) {
|
||||
PageComponent::where('id', $id)->update(['order' => $index + 1]);
|
||||
}
|
||||
|
||||
$this->loadComponents();
|
||||
session()->flash('success', 'Component order updated.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('order', 'Error updating order: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder components to close gaps
|
||||
*/
|
||||
protected function reorderComponents()
|
||||
{
|
||||
$components = $this->page->allComponents()->orderBy('order')->get();
|
||||
|
||||
foreach ($components as $index => $component) {
|
||||
$component->update(['order' => $index + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate default content for component
|
||||
*/
|
||||
protected function getDefaultContent(string $componentClass): array
|
||||
{
|
||||
$config = $this->componentRegistry->getComponentConfig($componentClass);
|
||||
$content = [];
|
||||
|
||||
if (empty($config['fields'])) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
foreach ($config['fields'] as $field) {
|
||||
if (!$field instanceof \FluxCms\Core\FieldTypes\BaseField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$defaultValue = $field->getDefault();
|
||||
|
||||
if ($field->isTranslatable()) {
|
||||
foreach ($this->availableLanguages as $locale) {
|
||||
$content[$field->getKey()][$locale] = $defaultValue;
|
||||
}
|
||||
} else {
|
||||
$content[$field->getKey()] = $defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update page data
|
||||
*/
|
||||
public function updatePageData()
|
||||
{
|
||||
try {
|
||||
$this->validate([
|
||||
'page.title' => 'required|array',
|
||||
'page.slug' => 'required|array',
|
||||
'page.meta_description' => 'nullable|array',
|
||||
]);
|
||||
|
||||
$this->page->save();
|
||||
session()->flash('success', 'Page data saved successfully.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('page', 'Error saving page: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle publish status
|
||||
*/
|
||||
public function togglePublish()
|
||||
{
|
||||
try {
|
||||
if ($this->page->is_published) {
|
||||
$this->page->unpublish();
|
||||
$message = 'Page unpublished successfully.';
|
||||
} else {
|
||||
$this->page->publish();
|
||||
$message = 'Page published successfully.';
|
||||
}
|
||||
|
||||
session()->flash('success', $message);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('publish', 'Error updating publish status: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create version
|
||||
*/
|
||||
public function createVersion(string $description = null)
|
||||
{
|
||||
try {
|
||||
$this->page->createVersion($description, auth()->id());
|
||||
session()->flash('success', 'Version created successfully.');
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$this->addError('version', 'Error creating version: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview page
|
||||
*/
|
||||
public function preview()
|
||||
{
|
||||
$locale = $this->currentLocale;
|
||||
$slug = $this->page->getTranslation('slug', $locale);
|
||||
|
||||
if (empty($slug)) {
|
||||
$this->addError('preview', 'No slug available for current language.');
|
||||
return;
|
||||
}
|
||||
|
||||
$url = $this->page->getUrl($locale) . '?preview=1';
|
||||
$this->dispatch('open-preview', url: $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available categories for filter
|
||||
*/
|
||||
public function getAvailableCategoriesProperty(): array
|
||||
{
|
||||
$categories = ['all' => 'All Categories'];
|
||||
|
||||
foreach ($this->availableComponents as $category => $components) {
|
||||
$categories[$category] = $category;
|
||||
}
|
||||
|
||||
return $categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filtered components for modal
|
||||
*/
|
||||
public function getFilteredComponentsProperty(): array
|
||||
{
|
||||
if ($this->selectedCategory === 'all') {
|
||||
$components = [];
|
||||
foreach ($this->availableComponents as $category => $categoryComponents) {
|
||||
$components = array_merge($components, $categoryComponents);
|
||||
}
|
||||
return $components;
|
||||
}
|
||||
|
||||
return $this->availableComponents[$this->selectedCategory] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page status
|
||||
*/
|
||||
public function getPageStatusProperty(): string
|
||||
{
|
||||
if (!$this->page->is_published) {
|
||||
return 'draft';
|
||||
}
|
||||
|
||||
if ($this->page->published_at && $this->page->published_at->isFuture()) {
|
||||
return 'scheduled';
|
||||
}
|
||||
|
||||
return 'published';
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue