Initial commit

This commit is contained in:
Ronald Huynen
2026-03-23 21:37:59 +01:00
commit 2547717edb
2193 changed files with 972171 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
<div x-data="{ previewName: @entangle('previewName') }"
x-on:updatePreviewName.window="previewName = $event.detail || '{{ __('Category name') }}'">
<label class="block text-sm font-medium text-gray-700 mb-1">
{{ $label }}
</label>
<div class="relative">
<select
class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 pr-10 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500"
wire:model.live="selectedColor">
@foreach ($this->availableColors as $color)
<option value="{{ $color['value'] }}">{{ $color['label'] }}</option>
@endforeach
</select>
<!-- Color swatch preview -->
<div class="pointer-events-none absolute inset-y-0 right-10 flex items-center pr-2">
<span class="inline-block h-6 w-6 rounded border border-gray-300 bg-{{ $selectedColor }}-400"></span>
</div>
</div>
<!-- Large color preview -->
<div class="mt-2">
<div class="text-sm text-gray-600 mb-1">{{ __('Preview') }}:</div>
<span class="bg-{{ $selectedColor }}-400 inline-flex items-center rounded-md px-3 py-1.5 text-sm font-normal text-black" x-text="previewName"></span>
</div>
</div>

View File

@@ -0,0 +1,3 @@
<div>
{{-- Care about people's approval and you will be their prisoner. --}}
</div>

View File

@@ -0,0 +1,796 @@
<div class="mt-12">
<!-- Action buttons -->
<div class="mb-6 flex items-center justify-between">
<x-jetstream.button wire:click="openCreateCategoryModal" class="bg-theme-brand hover:bg-opacity-80">
{{ __('New Category') }}
</x-jetstream.button>
</div>
<!-- Search box -->
<div class="mb-4 flex items-center">
<!-- Input and Reset Button Container -->
<div class="relative w-2/3">
<input class="w-full rounded-md border border-theme-primary px-3 py-1 pr-10 text-theme-primary shadow-sm focus:border-theme-accent focus:outline-none focus:ring-1 focus:ring-theme-accent sm:text-sm"
placeholder="{{ __('Search keywords') . '...' }}" type="text"
wire:keydown.enter="handleSearchEnter" wire:model="search">
<!-- Reset Button -->
@if ($search)
<button class="absolute inset-y-0 right-0 flex items-center pr-3 text-theme-secondary hover:text-theme-primary focus:outline-none"
wire:click.prevent="resetSearch">
<x-icon mini name="backspace" solid />
</button>
@endif
</div>
<!-- Search Button -->
<x-jetstream.secondary-button class="ml-3 w-32 justify-center" wire:click.prevent="searchCategories">
{{ __('Search') }}
</x-jetstream.secondary-button>
</div>
<!-- Filter dropdowns -->
<div class="mb-4 flex flex-wrap items-center gap-3">
<!-- Parent Filter Dropdown -->
<div>
<x-select :clearable="true" :searchable="true" class="!w-40" style="width: 24rem !important; min-width: 24rem !important;"
placeholder="{{ __('Parent') }}" wire:model.live="parentFilter">
@foreach ($this->parents as $parent)
<x-select.option label="{{ $parent['name'] }}" value="{{ $parent['id'] }}" />
@endforeach
</x-select>
</div>
<!-- Language Filter Dropdown -->
<div>
<x-select :clearable="true" :searchable="true" class="!w-40" style="width: 24rem !important; min-width: 24rem !important;"
placeholder="{{ __('Language') }}" wire:model.live="languageFilter">
@foreach ($this->languages as $lang)
<x-select.option label="{{ $lang['name'] }}" value="{{ $lang['id'] }}" />
@endforeach
</x-select>
</div>
</div>
<!-- Bulk action buttons -->
<div class="mb-6 flex items-center justify-end space-x-4">
<x-jetstream.danger-button
:disabled="$this->bulkDisabled"
title="{{ __('Delete') . ' ' . __('selection') }}"
wire:click.prevent="openBulkDeleteTranslationsModal()">
<x-icon class="mr-3 h-5 w-5" name="trash" />
{{ __('Delete') }} {{ __('selection') }}
</x-jetstream.danger-button>
@if (!$this->bulkDisabled)
<x-jetstream.secondary-button wire:click="resetBulkSelection">
{{ __('Clear Selection') }}
</x-jetstream.secondary-button>
@endif
</div>
<!-- Table -->
<div class="bg-white shadow-sm rounded-lg" x-data="{
initScrollSync() {
if (this.$refs.topScroll && this.$refs.bottomScroll && this.$refs.table && this.$refs.topScrollContent) {
const topScroll = this.$refs.topScroll;
const bottomScroll = this.$refs.bottomScroll;
const table = this.$refs.table;
// Set the width of the dummy div to match table width
this.$refs.topScrollContent.style.width = table.scrollWidth + 'px';
}
}
}" x-init="setTimeout(() => initScrollSync(), 100)">
<!-- Top scrollbar -->
<div class="overflow-x-auto border-b border-gray-200" x-ref="topScroll" @scroll="$refs.bottomScroll.scrollLeft = $event.target.scrollLeft">
<div x-ref="topScrollContent" style="height: 20px;"></div>
</div>
<!-- Table with bottom scrollbar -->
<div class="overflow-x-auto" x-ref="bottomScroll" @scroll="$refs.topScroll.scrollLeft = $event.target.scrollLeft">
<table class="min-w-full divide-y divide-gray-200" x-ref="table">
<thead class="bg-gray-50">
<tr>
{{-- Checkbox column --}}
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"></th>
{{-- Sortable Id column --}}
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer"
wire:click="sortBy('id')">
<div class="flex items-center">
{{ __('Id') }}
@if ($sortField === 'id')
<x-icon :name="$sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'" class="ml-1 h-4 w-4" micro />
@endif
</div>
</th>
{{-- Sortable Name column --}}
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer"
wire:click="sortBy('name')">
<div class="flex items-center">
{{ __('Name') }}
@if ($sortField === 'name')
<x-icon :name="$sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'" class="ml-1 h-4 w-4" micro />
@endif
</div>
</th>
{{-- Sortable Language column --}}
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer"
wire:click="sortBy('locale')">
<div class="flex items-center">
{{ __('Lang.') }}
@if ($sortField === 'locale')
<x-icon :name="$sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'" class="ml-1 h-4 w-4" micro />
@endif
</div>
</th>
{{-- Sortable Tags column --}}
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer"
wire:click="sortBy('tags_count')">
<div class="flex items-center">
{{ __('Tags') }}
@if ($sortField === 'tags_count')
<x-icon :name="$sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'" class="ml-1 h-4 w-4" micro />
@endif
</div>
</th>
{{-- Sortable Parent column --}}
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer"
wire:click="sortBy('parent')">
<div class="flex items-center">
{{ __('Parent') }}
@if ($sortField === 'parent')
<x-icon :name="$sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'" class="ml-1 h-4 w-4" micro />
@endif
</div>
</th>
{{-- Sortable Updated column --}}
<th class="px-3 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider cursor-pointer"
wire:click="sortBy('updated_at')">
<div class="flex items-center">
{{ __('Updated') }}
@if ($sortField === 'updated_at')
<x-icon :name="$sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'" class="ml-1 h-4 w-4" micro />
@endif
</div>
</th>
{{-- Non-sortable Action column --}}
<th class="px-3 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider w-32">{{ __('Actions') }}</th>
</tr>
</thead>
<tbody class="bg-white">
@forelse ($categories as $category)
@php
// When sorting by translation fields, we have joined data instead of eager loaded translations
$sortingByTranslation = in_array($sortField, ['name', 'locale', 'updated_at']);
if ($sortingByTranslation && isset($category->joined_translation_id)) {
// Use joined translation data
$translations = [
(object)[
'id' => $category->joined_translation_id,
'locale' => $category->joined_locale,
'name' => $category->joined_name,
'updated_at' => $category->joined_updated_at ? \Carbon\Carbon::parse($category->joined_updated_at) : null,
]
];
} else {
// Use regular eager loaded translations
$translations = $category->translations;
}
@endphp
@if (count($translations) === 0)
{{-- Skip categories without translations --}}
@else
@foreach ($translations as $loop_index => $translation)
<tr class="@if($loop_index === 0) border-t border-gray-200 @endif">
<td class="px-3 py-4 whitespace-nowrap">
<input
type="checkbox"
value="{{ $category->id }}"
wire:model.live="bulkSelected"
class="rounded border-gray-300 text-theme-brand focus:border-theme-accent focus:ring-1 focus:ring-theme-accent">
</td>
<td class="px-3 py-4 whitespace-nowrap text-sm text-gray-500">
{{ $category->id }}
</td>
<td class="px-3 py-4 text-sm">
@php
// Use parent's color if it has a parent, otherwise use category's own color
$nameColor = $category->parent_id && $category->parent
? ($category->parent->color ?? 'gray')
: ($category->color ?? 'gray');
@endphp
<span class="bg-{{ $nameColor }}-400 inline-flex items-center rounded-md px-2 py-1 text-sm font-normal text-black">
{{ $translation->name }}
</span>
</td>
<td class="px-3 py-4 whitespace-nowrap text-sm text-gray-500">
{{ $translation->locale }}
</td>
<td class="px-3 py-4 whitespace-nowrap text-sm text-gray-500">
{{ $category->tags_count }}
</td>
<td class="px-3 py-4 text-sm">
@if ($category->parent && $category->parent->translation)
@php
$parentColor = $category->parent->color ?? 'gray';
@endphp
<span class="bg-{{ $parentColor }}-400 inline-flex items-center rounded-md px-2 py-1 text-sm font-normal text-black">
{{ $category->parent->translation->name }}
</span>
@else
<span class="text-gray-400">-</span>
@endif
</td>
<td class="px-3 py-4">
@if ($translation->updated_at)
<div class="text-sm text-gray-500 leading-tight">
<div>{{ $translation->updated_at->translatedFormat('M j') }}</div>
<div>{{ $translation->updated_at->translatedFormat('Y') }}</div>
<div class="text-xs">{{ $translation->updated_at->translatedFormat('H:i') }}</div>
</div>
@else
<span class="text-gray-400">-</span>
@endif
</td>
{{-- Action Buttons --}}
<td class="px-3 py-4 whitespace-nowrap text-center text-sm font-medium">
<div class="flex items-center justify-center space-x-1">
<x-jetstream.secondary-button
title="{{ __('Edit') }}"
wire:click="openEditCategoryModal({{ $translation->id }})">
<x-icon class="h-5 w-5" name="pencil-square" />
</x-jetstream.secondary-button>
<x-jetstream.danger-button
title="{{ __('Delete') }}"
wire:click="openDeleteCategoryModal({{ $translation->id }})">
<x-icon class="h-5 w-5" name="trash" />
</x-jetstream.danger-button>
</div>
</td>
</tr>
@endforeach
@endif
@empty
<tr>
<td colspan="8" class="px-6 py-12 text-center text-gray-500">
{{ __('No results found') }}
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
<!-- Pagination -->
@if($categories->hasPages())
<div class="bg-white shadow-sm rounded-lg mt-4">
<div class="py-3 border-t border-gray-200 flex items-center justify-between">
<!-- Left Side: perPage Dropdown -->
<div class="flex items-center">
<select class="w-20 rounded-md border border-theme-primary bg-theme-background px-3 py-2 text-theme-primary shadow-sm focus:border-theme-accent focus:outline-none focus:ring-1 focus:ring-theme-accent sm:text-sm"
wire:model.live="perPage">
<option value="10"> 10 </option>
<option value="50"> 50 </option>
<option value="100"> 100 </option>
</select>
<span class="ml-2 text-sm text-theme-secondary">{{ __('per page') }}</span>
</div>
<!-- Right Side: Paginator -->
{{ $categories->links('livewire.long-paginator') }}
</div>
</div>
@endif
<!-- Delete single translation modal -->
@if ($modalDeleteTranslation)
<x-jetstream.dialog-modal wire:key="modalDeleteTranslation" wire:model.live="modalDeleteTranslation" maxWidth="2xl">
<x-slot name="title">
{{ __('Are you sure?') }}
</x-slot>
<x-slot name="content">
{{ __('Do you want to permanently delete this category and all its translations?') }}
<table class="mt-6 table min-w-full border-t-white">
<thead>
<tr>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Id') }}</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Category ID') }}</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Language') }}</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Name') }}</th>
</tr>
</thead>
<tbody>
@foreach ($selectedTranslations as $translation)
<tr class="border-theme-background" wire:key="delete-translation-{{ $translation->id }}">
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->id }}
</td>
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->category_id }}
</td>
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->locale }}
</td>
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->name }}
</td>
</tr>
@endforeach
</tbody>
</table>
@if ($affectedTagsCount > 0)
<div class="mt-6 rounded-md border border-gray-200 p-4">
<div class="flex">
<div class="w-1/3 font-medium">{{ __('Affected Tags') }}:</div>
<div class="flex-1 text-red-600 font-semibold">{{ $affectedTagsCount }}</div>
</div>
</div>
@endif
@if ($needsCategoryReassignment)
<div class="mt-6 rounded-md border border-gray-300 bg-gray-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<x-icon class="h-5 w-5 text-gray-400" name="exclamation-triangle" />
</div>
<div class="ml-3">
<p class="text-sm text-gray-800">
<strong>{{ __('Important') }}:</strong>
{{ __('This category has') }} {{ $affectedTagsCount }} {{ __('associated tags') }}.
{{ __('Please select a category to reassign these tags to') }}.
</p>
</div>
</div>
</div>
<div class="mt-4">
<x-select
:clearable="false"
:searchable="true"
label="{{ __('Reassign tags to category') }}"
placeholder="{{ __('Select a category') }}"
:options="$availableCategories"
option-label="name"
option-value="id"
wire:model="targetCategoryId" />
</div>
@endif
<div class="mt-6 rounded-md border-l-4 border-red-400 bg-red-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<x-icon class="h-5 w-5 text-red-400" name="exclamation-triangle" />
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
<strong>{{ __('Warning') }}:</strong>
{{ __('This can not be undone!') }}
</p>
</div>
</div>
</div>
<div class="mt-3 w-1/3">
<x-input label="{!! __('messages.confirm_input') !!}" placeholder="{{ __('Confirmation keyword') }}"
autocomplete="off"
wire:model="confirmString" />
</div>
</x-slot>
<x-slot name="footer">
<x-jetstream.secondary-button wire:click="$set('modalDeleteTranslation', false)" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jetstream.secondary-button>
<x-jetstream.danger-button class="ml-3" wire:click.prevent="deleteCategory"
wire:loading.attr="disabled">
{{ __('Delete') }}
</x-jetstream.danger-button>
</x-slot>
</x-jetstream.dialog-modal>
@endif
<!-- Bulk delete modal -->
@if ($modalBulkDeleteTranslations)
<x-jetstream.dialog-modal wire:key="modalBulkDeleteTranslations" wire:model.live="modalBulkDeleteTranslations" maxWidth="2xl">
<x-slot name="title">
{{ __('Are you sure?') }}
</x-slot>
<x-slot name="content">
{{ __('Do you want to permanently delete these translations?') }}
<table class="mt-6 table min-w-full border-t-white">
<thead>
<tr>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Id') }}</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Category ID') }}</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Language') }}</th>
<th class="px-6 py-3 text-left text-sm leading-4 tracking-wider">{{ __('Name') }}</th>
</tr>
</thead>
<tbody>
@foreach ($selectedTranslations as $translation)
<tr class="border-theme-background" wire:key="bulk-delete-translation-{{ $translation->id }}">
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->id }}
</td>
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->category_id }}
</td>
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->locale }}
</td>
<td class="whitespace-no-wrap border-theme-background px-6 text-sm leading-5">
{{ $translation->name }}
</td>
</tr>
@endforeach
</tbody>
</table>
@if ($affectedTagsCount > 0)
<div class="mt-6 rounded-md border border-gray-200 p-4">
<div class="flex">
<div class="w-1/3 font-medium">{{ __('Total Affected Tags') }}:</div>
<div class="flex-1 text-red-600 font-semibold">{{ $affectedTagsCount }}</div>
</div>
</div>
@endif
@if (count($categoriesWithTags) > 0)
<div class="mt-6 rounded-md border border-gray-300 bg-gray-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<x-icon class="h-5 w-5 text-gray-400" name="exclamation-triangle" />
</div>
<div class="ml-3">
<p class="text-sm text-gray-800">
<strong>{{ __('Important') }}:</strong>
{{ __('The following categories have associated tags. Please select a target category for each to reassign their tags') }}.
</p>
</div>
</div>
</div>
<div class="mt-4 space-y-4">
@foreach ($categoriesWithTags as $categoryData)
<div class="rounded-md border border-gray-300 p-4">
<div class="mb-2 flex items-center justify-between">
<div class="font-medium text-gray-700">
{{ $categoryData['name'] }}
</div>
<div class="text-sm text-red-600">
{{ $categoryData['tags_count'] }} {{ __('tags') }}
</div>
</div>
<x-select
:clearable="false"
:searchable="true"
label="{{ __('Reassign tags to category') }}"
placeholder="{{ __('Select a category') }}"
:options="$availableCategories"
option-label="name"
option-value="id"
wire:model="categoryReassignments.{{ $categoryData['category_id'] }}" />
</div>
@endforeach
</div>
@endif
<div class="mt-6 rounded-md border-l-4 border-red-400 bg-red-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<x-icon class="h-5 w-5 text-red-400" name="exclamation-triangle" />
</div>
<div class="ml-3">
<p class="text-sm text-red-700">
<strong>{{ __('Warning') }}:</strong>
{{ __('This can not be undone!') }}
</p>
</div>
</div>
</div>
<div class="mt-3 w-1/3">
<x-input label="{!! __('messages.confirm_input') !!}" placeholder="{{ __('Confirmation keyword') }}"
autocomplete="off"
wire:model="confirmString" />
</div>
</x-slot>
<x-slot name="footer">
<x-jetstream.secondary-button wire:click="$set('modalBulkDeleteTranslations', false)" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jetstream.secondary-button>
<x-jetstream.danger-button class="ml-3" wire:click.prevent="deleteSelected"
wire:loading.attr="disabled">
{{ __('Delete') }}
</x-jetstream.danger-button>
</x-slot>
</x-jetstream.dialog-modal>
@endif
<!-- Edit category modal -->
@if ($modalEditCategory)
<x-jetstream.dialog-modal wire:key="modalEditCategory" wire:model.live="modalEditCategory" maxWidth="2xl">
<x-slot name="title">
{{ __('Edit Category') }}
</x-slot>
<x-slot name="content">
<div class="space-y-4">
<!-- Translation info -->
<div class="rounded-md border border-gray-200 bg-gray-50 p-4">
<div class="grid grid-cols-2 gap-4 text-sm">
<div>
<span class="font-medium">{{ __('Category ID') }}:</span>
<span class="ml-2">{{ $editCategoryId }}</span>
</div>
<div>
<span class="font-medium">{{ __('Language') }}:</span>
<span class="ml-2">{{ $editLocale }}</span>
</div>
</div>
</div>
<!-- Name field (translation-specific) -->
<div>
<x-input
label="{{ __('Name') }}"
placeholder="{{ __('Category name') }}"
wire:model="editName" />
</div>
<!-- Parent field (category-level - affects all translations) -->
<div>
<x-select
:clearable="true"
:searchable="true"
label="{{ __('Parent Category') }} ({{ __('affects all translations') }})"
placeholder="{{ __('Select parent category') }}"
:options="$this->parents"
option-label="name"
option-value="id"
wire:model.live="editParentId" />
</div>
<!-- Color field (category-level - affects all translations) -->
@if (!$editParentId || $editParentId === 'none')
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
{{ __('Color') }} ({{ __('affects all translations') }})
</label>
<div class="relative">
<select
class="w-full rounded-md border border-gray-300 bg-white px-3 py-2 pr-10 text-sm shadow-sm focus:border-primary-500 focus:outline-none focus:ring-1 focus:ring-primary-500"
wire:model.live="editColor">
@foreach ($availableColors as $color)
<option value="{{ $color['value'] }}">{{ $color['label'] }}</option>
@endforeach
</select>
<!-- Color swatch preview -->
<div class="pointer-events-none absolute inset-y-0 right-10 flex items-center pr-2">
<span class="inline-block h-6 w-6 rounded border border-gray-300 bg-{{ $editColor }}-400"></span>
</div>
</div>
</div>
@else
<div class="rounded-md border border-gray-200 bg-theme-surface p-4">
<p class="text-sm text-theme-primary">
{{ __('Color will be inherited from parent category') }}
</p>
</div>
@endif
<!-- Large color preview (always visible) -->
<div class="mt-2">
<div class="text-sm text-gray-600 mb-1">{{ __('Preview') }}:</div>
<span class="bg-{{ $this->editPreviewColor }}-400 inline-flex items-center rounded-md px-3 py-1.5 text-sm font-normal text-black">
{{ $editName ?: __('Category name') }}
</span>
</div>
<!-- Affected tags warning -->
@if ($editAffectedTagsCount > 0)
<div class="rounded-md border border-red-200 bg-red-50 p-4">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-2">
<x-icon class="h-5 w-5 text-red-500" name="information-circle" />
<span class="font-medium text-red-700">{{ __('Affected Tags') }}:</span>
</div>
<div class="text-red-600 font-semibold">{{ $editAffectedTagsCount }}</div>
</div>
<p class="mt-2 text-sm text-red-600">
{{ __('Changes to parent or color will affect how tags in this category are displayed') }}.
</p>
</div>
@endif
<!-- Warning box -->
<div class="rounded-md border border-gray-300 bg-gray-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<x-icon class="h-5 w-5 text-gray-400" name="exclamation-triangle" />
</div>
<div class="ml-3">
<p class="text-sm text-gray-800">
<strong>{{ __('Important') }}:</strong>
{{ __('Name changes only affect this translation') }}.
{{ __('Parent and color changes affect all translations of this category') }}.
</p>
</div>
</div>
</div>
<!-- Confirmation input -->
<div class="w-1/2">
<x-input
label="{!! __('messages.confirm_input') !!}"
placeholder="{{ __('Confirmation keyword') }}"
autocomplete="off"
wire:model="confirmString" />
</div>
</div>
</x-slot>
<x-slot name="footer">
<x-jetstream.secondary-button wire:click="$set('modalEditCategory', false)" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jetstream.secondary-button>
<x-jetstream.button class="ml-3" wire:click.prevent="updateCategory" wire:loading.attr="disabled">
{{ __('Update') }}
</x-jetstream.button>
</x-slot>
</x-jetstream.dialog-modal>
@endif
<!-- Create category modal -->
@if ($modalCreateCategory)
<x-jetstream.dialog-modal wire:key="modalCreateCategory" wire:model.live="modalCreateCategory" maxWidth="3xl">
<x-slot name="title">
{{ __('Create New Category') }}
</x-slot>
<x-slot name="content">
<div class="space-y-6">
<!-- Info box -->
<div class="rounded-md border border-gray-200 bg-theme-surface p-4">
<div class="flex">
<div class="flex-shrink-0">
<x-icon class="h-5 w-5 text-gray-500" name="information-circle" />
</div>
<div class="ml-3">
<p class="text-sm text-theme-primary">
{{ __('Please provide category names in all supported languages') }}.
{{ __('All fields are required') }}.
</p>
</div>
</div>
</div>
<!-- Translation fields -->
<div class="space-y-4">
<h3 class="text-sm font-medium text-gray-700">{{ __('Category Names') }}</h3>
@php
$appLocale = app()->getLocale();
@endphp
@foreach ($this->supportedLocales as $index => $locale)
@if($locale === $appLocale)
<div x-data="{}"
x-on:input.debounce.300ms="$dispatch('updatePreviewName', $event.target.value)"
x-on:change="$dispatch('updatePreviewName', $event.target.value)">
<x-input
label="{{ __('messages.' . $locale) }}"
placeholder="{{ __('Category name in') }} {{ __('messages.' . $locale) }}"
wire:model.defer="createTranslations.{{ $locale }}" />
</div>
@else
<div>
<x-input
label="{{ __('messages.' . $locale) }}"
placeholder="{{ __('Category name in') }} {{ __('messages.' . $locale) }}"
wire:model.defer="createTranslations.{{ $locale }}" />
</div>
@endif
@endforeach
</div>
<!-- Parent category selection -->
<div>
<x-select
:clearable="true"
:searchable="true"
label="{{ __('Parent Category') }} ({{ __('optional') }})"
placeholder="{{ __('Select parent category') }}"
:options="$this->parents"
option-label="name"
option-value="id"
wire:model.live="createParentId" />
</div>
<!-- Color picker - only shown if no parent selected -->
@if (!$createParentId || $createParentId === 'none')
<div>
@livewire('categories.color-picker', [
'color' => $createColor,
'label' => __('Color'),
'required' => true
])
</div>
@else
<div class="rounded-md border border-gray-200 bg-theme-surface p-4">
<p class="text-sm text-theme-primary">
{{ __('Color will be inherited from parent category') }}
</p>
</div>
@endif
<!-- Large color preview (always visible) -->
<div class="mt-2">
<div class="text-sm text-gray-600 mb-1">{{ __('Preview') }}:</div>
@php $appLocale = app()->getLocale(); @endphp
<span class="bg-{{ $this->createPreviewColor }}-400 inline-flex items-center rounded-md px-3 py-1.5 text-sm font-normal text-black">
{{ $createTranslations[$appLocale] ?? __('Category name') }}
</span>
</div>
<!-- Confirmation input -->
<div>
<x-input
label="{!! __('messages.confirm_input') !!}"
placeholder="{{ __('Confirmation keyword') }}"
autocomplete="off"
wire:model="confirmString" />
</div>
</div>
</x-slot>
<x-slot name="footer">
<x-jetstream.secondary-button wire:click="$set('modalCreateCategory', false)" wire:loading.attr="disabled">
{{ __('Cancel') }}
</x-jetstream.secondary-button>
<x-jetstream.button class="ml-3 bg-theme-brand" wire:click.prevent="storeCategory" wire:loading.attr="disabled">
{{ __('Create Category') }}
</x-jetstream.button>
</x-slot>
</x-jetstream.dialog-modal>
@endif
@push('scripts')
<script>
document.addEventListener('scroll-to-top', event => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
</script>
@endpush
</div>