finale 2.0.0

This commit is contained in:
2026-06-09 11:09:00 +02:00
parent d82b123bfd
commit 06387568cb
7 changed files with 500 additions and 0 deletions
@@ -0,0 +1,34 @@
@php
$filterTags = $filterTags ?? (\App\Models\Tag::orderBy('name')->get());
$activeTags = (array) request('tag', []);
@endphp
@if($filterTags->isNotEmpty())
<div class="tag-filter-bar px-3 py-2 bg-light border-bottom" style="display:flex;flex-wrap:wrap;gap:4px;align-items:center;">
<span class="small font-weight-bold text-muted mr-1"><i class="fas fa-tags mr-1"></i>Tag:</span>
@foreach($filterTags as $tag)
@php
$isActive = in_array($tag->slug, $activeTags);
$query = request()->query();
if ($isActive) {
$newTags = array_values(array_diff($activeTags, [$tag->slug]));
if (empty($newTags)) {
unset($query['tag']);
} else {
$query['tag'] = $newTags;
}
} else {
$query['tag'] = array_merge($activeTags, [$tag->slug]);
}
$url = request()->url() . '?' . http_build_query($query);
@endphp
<a href="{{ $url }}" class="badge tag-filter-badge" style="background-color:{{ $tag->color ?? '#6c757d' }};color:#fff;{{ $isActive ? '' : 'opacity:0.45;' }}font-size:0.8rem;padding:4px 10px;border-radius:12px;text-decoration:none;">
{{ $tag->name }}
</a>
@endforeach
@if(!empty($activeTags))
<a href="{{ request()->url() }}" class="badge badge-light" style="font-size:0.8rem;padding:4px 10px;border-radius:12px;text-decoration:none;">
<i class="fas fa-times mr-1"></i>Cancella filtri
</a>
@endif
</div>
@endif
@@ -0,0 +1,123 @@
@php
$allTags = $allTags ?? \App\Models\Tag::orderBy('name')->get();
$selectedTags = old('tags', $selectedTags ?? []);
$tagFieldName = $tagFieldName ?? 'tags';
$selectorId = 'tag-selector-' . md5($tagFieldName);
$selectedTagObjects = $allTags->whereIn('id', $selectedTags);
@endphp
<div class="form-group" id="{{ $selectorId }}">
<label>{{ $label ?? 'Tag' }}</label>
<div class="tag-selector-container" style="border:1px solid #ced4da;border-radius:.25rem;padding:8px;background:#fff;">
<div class="tag-selected d-flex flex-wrap mb-1" style="gap:4px;">
@foreach($selectedTagObjects as $tag)
<span class="tag-pill badge d-inline-flex align-items-center" data-tag-id="{{ $tag->id }}" style="background-color:{{ $tag->color ?? '#6c757d' }};color:#fff;padding:4px 10px;border-radius:12px;font-size:0.85rem;">
{{ $tag->name }}
<button type="button" class="tag-remove btn btn-xs p-0 ml-1 text-white" style="line-height:1;font-size:14px;background:none;border:none;" onclick="removeTag(event, '{{ $selectorId }}', {{ $tag->id }})">&times;</button>
</span>
@endforeach
</div>
<div class="tag-search-input">
<input type="text" class="form-control form-control-sm" placeholder="Cerca tag..." oninput="filterTags(event, '{{ $selectorId }}')" autocomplete="off">
</div>
<div class="tag-available mt-1" style="max-height:140px;overflow-y:auto;display:flex;flex-wrap:wrap;gap:4px;">
@foreach($allTags as $tag)
<button type="button" class="tag-btn btn btn-sm {{ in_array($tag->id, $selectedTags) ? 'tag-selected' : '' }}" data-tag-id="{{ $tag->id }}" data-tag-name="{{ $tag->name }}" data-tag-color="{{ $tag->color ?? '#6c757d' }}" style="background-color:{{ $tag->color ?? '#6c757d' }};color:#fff;border-radius:12px;cursor:pointer;{{ in_array($tag->id, $selectedTags) ? '' : 'opacity:0.5;' }}" onclick="toggleTag(event, '{{ $selectorId }}', {{ $tag->id }})">
{{ $tag->name }}
</button>
@endforeach
@if($allTags->isEmpty())
<p class="text-muted small mb-0 w-100">Nessun tag disponibile. <a href="{{ route('impostazioni.index') }}#tag">Crea i tag</a> nelle Impostazioni.</p>
@endif
<p class="tag-no-match text-muted small mb-0 w-100" style="display:none;">Nessun tag corrisponde alla ricerca.</p>
</div>
</div>
<div class="tag-hidden-inputs">
@foreach($selectedTags as $selectedId)
<input type="hidden" name="{{ $tagFieldName }}[]" value="{{ $selectedId }}">
@endforeach
</div>
</div>
@once
@push('scripts')
<script>
function toggleTag(e, selId, tagId) {
e.preventDefault();
var container = document.getElementById(selId);
var btn = container.querySelector('.tag-btn[data-tag-id="' + tagId + '"]');
if (!btn) return;
var isSelected = btn.classList.contains('tag-selected');
var selectedBox = container.querySelector('.tag-selected');
var hiddenContainer = container.querySelector('.tag-hidden-inputs');
if (isSelected) {
btn.classList.remove('tag-selected');
btn.style.opacity = '0.5';
var pill = container.querySelector('.tag-pill[data-tag-id="' + tagId + '"]');
if (pill) pill.remove();
var hidden = hiddenContainer.querySelector('input[value="' + tagId + '"]');
if (hidden) hidden.remove();
} else {
btn.classList.add('tag-selected');
btn.style.opacity = '1';
var name = btn.dataset.tagName;
var color = btn.dataset.tagColor || '#6c757d';
var pill = document.createElement('span');
pill.className = 'tag-pill badge d-inline-flex align-items-center';
pill.style.cssText = 'background-color:' + color + ';color:#fff;padding:4px 10px;border-radius:12px;font-size:0.85rem;';
pill.dataset.tagId = tagId;
pill.innerHTML = name + '<button type="button" class="tag-remove btn btn-xs p-0 ml-1 text-white" style="line-height:1;font-size:14px;background:none;border:none;" onclick="removeTag(event, \'' + selId + '\', ' + tagId + ')">&times;</button>';
selectedBox.appendChild(pill);
if (hiddenContainer.querySelector('input[value="' + tagId + '"]')) return;
var hidden = document.createElement('input');
hidden.type = 'hidden';
hidden.name = '{{ $tagFieldName }}[]';
hidden.value = tagId;
hiddenContainer.appendChild(hidden);
}
}
function removeTag(e, selId, tagId) {
e.preventDefault();
var container = document.getElementById(selId);
var btn = container.querySelector('.tag-btn[data-tag-id="' + tagId + '"]');
if (btn) {
btn.classList.remove('tag-selected');
btn.style.opacity = '0.5';
}
var pill = container.querySelector('.tag-pill[data-tag-id="' + tagId + '"]');
if (pill) pill.remove();
var hiddenContainer = container.querySelector('.tag-hidden-inputs');
var hidden = hiddenContainer.querySelector('input[value="' + tagId + '"]');
if (hidden) hidden.remove();
}
function filterTags(e, selId) {
var container = document.getElementById(selId);
var q = e.target.value.toLowerCase();
var btns = container.querySelectorAll('.tag-btn');
var visibleCount = 0;
btns.forEach(function(btn) {
var name = btn.dataset.tagName.toLowerCase();
if (name.includes(q)) {
btn.style.display = '';
visibleCount++;
} else {
btn.style.display = 'none';
}
});
var noMatch = container.querySelector('.tag-no-match');
if (noMatch) {
noMatch.style.display = visibleCount === 0 ? 'block' : 'none';
}
}
</script>
@endpush
@endonce