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'; } }