229 lines
No EOL
9.7 KiB
PHP
229 lines
No EOL
9.7 KiB
PHP
<div class="space-y-6">
|
|
{{-- Header --}}
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-semibold text-gray-900">Navigation Manager</h1>
|
|
<p class="text-sm text-gray-500 mt-1">
|
|
Manage site navigation and menu structures
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex items-center space-x-3">
|
|
<flux:button wire:click="createNavigation" variant="primary">
|
|
Create Navigation
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Navigation Selector --}}
|
|
<flux:card>
|
|
<div class="flex items-center space-x-4">
|
|
<div class="flex-1">
|
|
<flux:select wire:model.live="selectedNavigationId" placeholder="Select Navigation">
|
|
@foreach($navigations as $nav)
|
|
<flux:option value="{{ $nav->id }}">{{ $nav->display_name }}</flux:option>
|
|
@endforeach
|
|
</flux:select>
|
|
</div>
|
|
|
|
@if($selectedNavigationId)
|
|
<flux:button wire:click="editNavigation({{ $selectedNavigationId }})" size="sm">
|
|
Edit Navigation
|
|
</flux:button>
|
|
<flux:button wire:click="deleteNavigation({{ $selectedNavigationId }})"
|
|
variant="danger" size="sm">
|
|
Delete
|
|
</flux:button>
|
|
@endif
|
|
</div>
|
|
</flux:card>
|
|
|
|
{{-- Navigation Items --}}
|
|
@if($selectedNavigationId && $navigationItems)
|
|
<flux:card>
|
|
<flux:card.header>
|
|
<div class="flex items-center justify-between">
|
|
<flux:heading size="lg">Navigation Items</flux:heading>
|
|
<flux:button wire:click="addNavigationItem" size="sm">
|
|
Add Item
|
|
</flux:button>
|
|
</div>
|
|
</flux:card.header>
|
|
|
|
<div class="space-y-2" wire:sortable="updateItemOrder">
|
|
@forelse($navigationItems as $item)
|
|
<div wire:sortable.item="{{ $item->id }}"
|
|
wire:key="nav-item-{{ $item->id }}"
|
|
class="nested-sortable-item">
|
|
@include('flux-cms-components::partials.navigation-item', ['item' => $item, 'level' => 0])
|
|
</div>
|
|
@empty
|
|
<div class="text-center py-8 text-gray-500">
|
|
<flux:icon.bars-3 class="w-12 h-12 mx-auto mb-3 text-gray-300" />
|
|
<p>No navigation items yet.</p>
|
|
<p class="text-sm">Click "Add Item" to create your first navigation item.</p>
|
|
</div>
|
|
@endforelse
|
|
</div>
|
|
</flux:card>
|
|
@endif
|
|
|
|
{{-- Navigation Form Modal --}}
|
|
<flux:modal name="navigation-form" class="md:w-2xl">
|
|
<div class="space-y-6">
|
|
<flux:heading size="lg">
|
|
{{ $editingNavigation ? 'Edit Navigation' : 'Create Navigation' }}
|
|
</flux:heading>
|
|
|
|
<div class="space-y-4">
|
|
<flux:field>
|
|
<flux:label>Name</flux:label>
|
|
<flux:input wire:model.live="navigationForm.name"
|
|
placeholder="main-menu" />
|
|
<flux:description>Unique identifier for this navigation (lowercase, no spaces)</flux:description>
|
|
<flux:error name="navigationForm.name" />
|
|
</flux:field>
|
|
|
|
<flux:field>
|
|
<flux:label>Display Name</flux:label>
|
|
<flux:input wire:model.live="navigationForm.display_name"
|
|
placeholder="Main Menu" />
|
|
<flux:description>Human-readable name for this navigation</flux:description>
|
|
<flux:error name="navigationForm.display_name" />
|
|
</flux:field>
|
|
|
|
<flux:field>
|
|
<flux:checkbox wire:model.live="navigationForm.is_active">
|
|
Active
|
|
</flux:checkbox>
|
|
<flux:description>Inactive navigations will not be displayed</flux:description>
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div class="flex justify-end space-x-3">
|
|
<flux:button wire:click="$dispatch('close-modal')" variant="ghost">
|
|
Cancel
|
|
</flux:button>
|
|
<flux:button wire:click="saveNavigation" variant="primary">
|
|
{{ $editingNavigation ? 'Update' : 'Create' }}
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</flux:modal>
|
|
|
|
{{-- Navigation Item Form Modal --}}
|
|
<flux:modal name="navigation-item-form" class="md:w-2xl">
|
|
<div class="space-y-6">
|
|
<flux:heading size="lg">
|
|
{{ $editingItem ? 'Edit Navigation Item' : 'Add Navigation Item' }}
|
|
</flux:heading>
|
|
|
|
{{-- Language Tabs --}}
|
|
<div class="border-b border-gray-200">
|
|
<nav class="-mb-px flex space-x-8">
|
|
@foreach($availableLocales as $locale)
|
|
<button wire:click="setActiveLocale('{{ $locale }}')"
|
|
class="py-2 px-1 border-b-2 font-medium text-sm {{ $activeLocale === $locale ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' }}">
|
|
{{ strtoupper($locale) }}
|
|
</button>
|
|
@endforeach
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
{{-- Title (Translatable) --}}
|
|
<flux:field>
|
|
<flux:label>Title ({{ strtoupper($activeLocale) }})</flux:label>
|
|
<flux:input wire:model.live="itemForm.title.{{ $activeLocale }}"
|
|
placeholder="Navigation item title" />
|
|
<flux:error name="itemForm.title.{{ $activeLocale }}" />
|
|
</flux:field>
|
|
|
|
{{-- Link Type --}}
|
|
<flux:field>
|
|
<flux:label>Link Type</flux:label>
|
|
<flux:select wire:model.live="itemForm.link_type">
|
|
<flux:option value="page">Page</flux:option>
|
|
<flux:option value="url">Custom URL</flux:option>
|
|
<flux:option value="none">No Link</flux:option>
|
|
</flux:select>
|
|
</flux:field>
|
|
|
|
{{-- Page Selection --}}
|
|
@if($itemForm['link_type'] === 'page')
|
|
<flux:field>
|
|
<flux:label>Select Page</flux:label>
|
|
<flux:select wire:model.live="itemForm.page_id" placeholder="Choose a page">
|
|
@foreach($availablePages as $page)
|
|
<flux:option value="{{ $page->id }}">{{ $page->title }}</flux:option>
|
|
@endforeach
|
|
</flux:select>
|
|
<flux:error name="itemForm.page_id" />
|
|
</flux:field>
|
|
@endif
|
|
|
|
{{-- Custom URL --}}
|
|
@if($itemForm['link_type'] === 'url')
|
|
<flux:field>
|
|
<flux:label>URL</flux:label>
|
|
<flux:input wire:model.live="itemForm.url"
|
|
placeholder="https://example.com" />
|
|
<flux:error name="itemForm.url" />
|
|
</flux:field>
|
|
|
|
<flux:field>
|
|
<flux:label>Target</flux:label>
|
|
<flux:select wire:model.live="itemForm.target">
|
|
<flux:option value="_self">Same Window</flux:option>
|
|
<flux:option value="_blank">New Window</flux:option>
|
|
</flux:select>
|
|
</flux:field>
|
|
@endif
|
|
|
|
{{-- Parent Item --}}
|
|
<flux:field>
|
|
<flux:label>Parent Item</flux:label>
|
|
<flux:select wire:model.live="itemForm.parent_id" placeholder="No parent (top level)">
|
|
@foreach($this->getParentOptions() as $option)
|
|
<flux:option value="{{ $option['id'] }}">
|
|
{{ str_repeat('— ', $option['level']) }}{{ $option['title'] }}
|
|
</flux:option>
|
|
@endforeach
|
|
</flux:select>
|
|
<flux:description>Choose a parent to create a sub-menu item</flux:description>
|
|
</flux:field>
|
|
|
|
{{-- Settings --}}
|
|
<flux:field>
|
|
<flux:checkbox wire:model.live="itemForm.is_active">
|
|
Active
|
|
</flux:checkbox>
|
|
<flux:description>Inactive items will not be displayed</flux:description>
|
|
</flux:field>
|
|
</div>
|
|
|
|
<div class="flex justify-end space-x-3">
|
|
<flux:button wire:click="$dispatch('close-modal')" variant="ghost">
|
|
Cancel
|
|
</flux:button>
|
|
<flux:button wire:click="saveNavigationItem" variant="primary">
|
|
{{ $editingItem ? 'Update' : 'Add' }}
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</flux:modal>
|
|
</div>
|
|
|
|
@push('scripts')
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Initialize nested sortable
|
|
const initializeNestedSortable = () => {
|
|
// Implementation for nested drag & drop would go here
|
|
// You might want to use a library like SortableJS with nested support
|
|
};
|
|
|
|
initializeNestedSortable();
|
|
});
|
|
</script>
|
|
@endpush |