- Implementada nueva funcion para crear productos destacados por etiquetas, mostrando carrusel con los mismos en la pagina welcome.
This commit is contained in:
Bryam105
2026-06-02 09:46:53 -03:00
parent 63f91bdd6d
commit 902b8433d9
17 changed files with 480 additions and 33 deletions
+29 -1
View File
@@ -82,7 +82,7 @@
<button type="submit" class="px-5 py-3 text-sm font-bold text-neutral-900 bg-neon-lime rounded-lg hover:bg-[#b3e600] transition-colors">
Filtrar
</button>
@if(request('search') || request('type'))
@if(request('search') || request('type') || request('tag'))
<a href="{{ route('catalogo.index') }}" title="Limpiar Filtros" class="flex items-center justify-center p-3 text-sm font-bold text-red-600 bg-red-100 dark:bg-red-900/30 rounded-lg hover:bg-red-200 transition-colors">
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18 17.94 6M18 18 6.06 6"/>
@@ -90,8 +90,25 @@
</a>
@endif
</div>
<input type="hidden" name="tag" value="{{ request('tag') }}">
</form>
<!-- Filtro de Etiquetas -->
@if($allTags->count() > 0)
<div class="mb-8 flex flex-wrap gap-2">
@foreach($allTags as $t)
<a href="{{ route('catalogo.index', array_merge(request()->query(), ['tag' => $t->name])) }}"
class="px-3 py-1.5 text-xs font-bold uppercase rounded-full border transition-colors
{{ request('tag') == $t->name
? 'bg-neon-lime border-neon-lime text-black dark:text-black'
: 'bg-transparent border-neutral-400 dark:border-neutral-600 text-gray-700 dark:text-gray-300 hover:border-neon-lime hover:text-neon-lime dark:hover:border-neon-lime dark:hover:text-neon-lime' }}">
#{{ $t->name }}
</a>
@endforeach
</div>
@endif
<!-- GRILLA DE PRODUCTOS -->
<!-- GRILLA DE PRODUCTOS -->
@if ($products->count() > 0)
@@ -113,6 +130,17 @@
<!-- ACÁ ESTÁ EL SEGUNDO CAMBIO: Agregamos "flex-1" al título -->
<h2 class="text-lg font-semibold text-black dark:text-white flex-1">{{ $product->name }}</h2>
{{-- Etiquetas --}}
@if($product->tags->count() > 0)
<div class="flex flex-wrap gap-1 mt-2">
@foreach($product->tags as $t)
<span class="text-[10px] font-bold uppercase tracking-wider px-2 py-0.5 rounded-full border border-neon-lime text-neon-lime bg-neon-lime/10">
#{{ $t->name }}
</span>
@endforeach
</div>
@endif
{{-- Precio --}}
@if (!empty($product->price))
<p class="text-neutral-900 dark:text-white group-hover:text-lime-700 group-hover:dark:text-neon-lime font-bold mt-3 transition-colors">${{ number_format($product->price, 2, ',', '.') }}</p>
+11
View File
@@ -50,6 +50,17 @@
<p class="text-stone-500 dark:text-neon-lime text-sm font-bold uppercase tracking-widest mb-2">SKU: {{ $product->sku ?? 'N/A' }}</p>
<h1 class="text-4xl font-black text-black dark:text-white italic mb-2 leading-tight">{{ $product->name }}</h1>
{{-- Etiquetas --}}
@if($product->tags->count() > 0)
<div class="flex flex-wrap gap-2 mt-2 mb-4">
@foreach($product->tags as $t)
<span class="text-xs font-bold uppercase tracking-wider px-3 py-1 rounded-full border border-neon-lime text-neon-lime bg-neon-lime/10">
#{{ $t->name }}
</span>
@endforeach
</div>
@endif
<!-- Stock Status -->
<div class="flex items-center gap-2 mt-4">
@if($product->stock_quantity > 5)
@@ -41,6 +41,12 @@
Stock
</a>
</li>
<li>
<a href="{{ route('tags.index') }}"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('tags*') ? 'text-lime-600 dark:text-neon-lime border-b-2 border-lime-600 dark:border-neon-lime' : 'dark:text-white hover:text-lime-600 hover:dark:text-neon-lime' }}">
Etiquetas
</a>
</li>
<li>
<a href="{{ route('taller.index') }}"
class="block py-2 px-3 md:p-0 transition-colors {{ request()->is('taller*') ? 'text-lime-600 dark:text-neon-lime border-b-2 border-lime-600 dark:border-neon-lime' : 'dark:text-white hover:text-lime-600 hover:dark:text-neon-lime' }}">
@@ -1,14 +1,18 @@
@props(['items'])
@props(['items', 'title' => 'Destacados'])
<div class="relative w-full overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-800 bg-slate-50 dark:bg-panel-bg shadow-xl group" id="lauck-carousel">
@php
$id = Str::random(8);
@endphp
<div class="relative w-full overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-800 bg-slate-50 dark:bg-panel-bg shadow-xl group carousel-container" id="carousel-{{ $id }}">
<!-- Título Flotante (Opcional) -->
<div class="absolute top-4 left-6 z-10 bg-neon-lime/50 dark:bg-black/50 backdrop-blur-sm px-3 py-1 rounded border border-black/30 dark:border-neon-lime/30">
<span class="text-xs font-bold text-black dark:text-neon-lime uppercase tracking-widest">Destacados</span>
<span class="text-xs font-bold text-black dark:text-neon-lime uppercase tracking-widest">{{ $title }}</span>
</div>
<!-- Contenedor de Slides (Track) -->
<div class="flex transition-transform duration-500 ease-in-out h-[400px]" id="carousel-track">
<div class="flex transition-transform duration-500 ease-in-out h-[400px] carousel-track">
@forelse($items as $item)
<div class="w-full flex-shrink-0 flex flex-col md:flex-row h-full relative">
@@ -61,11 +65,11 @@
</div>
<!-- Controles (Flechas) -->
<button id="prevBtn" class="absolute top-1/2 left-4 -translate-y-1/2 bg-black/30 hover:bg-neon-lime hover:text-neutral-900 text-white p-3 rounded-full backdrop-blur-sm transition-all border border-white/10 z-20">
<button class="prevBtn absolute top-1/2 left-4 -translate-y-1/2 bg-black/30 hover:bg-neon-lime hover:text-neutral-900 text-white p-3 rounded-full backdrop-blur-sm transition-all border border-white/10 z-20">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path></svg>
</button>
<button id="nextBtn" class="absolute top-1/2 right-4 -translate-y-1/2 bg-black/30 hover:bg-neon-lime hover:text-neutral-900 text-white p-3 rounded-full backdrop-blur-sm transition-all border border-white/10 z-20">
<button class="nextBtn absolute top-1/2 right-4 -translate-y-1/2 bg-black/30 hover:bg-neon-lime hover:text-neutral-900 text-white p-3 rounded-full backdrop-blur-sm transition-all border border-white/10 z-20">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path></svg>
</button>
@@ -80,7 +84,8 @@
<script type="module">
$(document).ready(function() {
const $track = $('#carousel-track');
const $container = $('#carousel-{{ $id }}');
const $track = $container.find('.carousel-track');
const $slides = $track.children();
const slideCount = $slides.length;
let currentIndex = 0;
@@ -91,8 +96,8 @@
$track.css('transform', `translateX(${translateX}%)`);
// Actualizar puntos
$('.carousel-dot').removeClass('bg-lime-500 dark:bg-neon-lime scale-125').addClass('bg-black/20 dark:bg-white/20');
$(`.carousel-dot[data-index="${currentIndex}"]`).addClass('bg-lime-500 dark:bg-neon-lime scale-125').removeClass('bg-black/20 dark:bg-white/20');
$container.find('.carousel-dot').removeClass('bg-lime-500 dark:bg-neon-lime scale-125').addClass('bg-black/20 dark:bg-white/20');
$container.find(`.carousel-dot[data-index="${currentIndex}"]`).addClass('bg-lime-500 dark:bg-neon-lime scale-125').removeClass('bg-black/20 dark:bg-white/20');
}
function nextSlide() {
@@ -106,17 +111,17 @@
}
// Event Listeners
$('#nextBtn').click(function() {
$container.find('.nextBtn').click(function() {
nextSlide();
resetAutoPlay();
});
$('#prevBtn').click(function() {
$container.find('.prevBtn').click(function() {
prevSlide();
resetAutoPlay();
});
$('.carousel-dot').click(function() {
$container.find('.carousel-dot').click(function() {
currentIndex = $(this).data('index');
updateCarousel();
resetAutoPlay();
@@ -35,6 +35,17 @@
<option value="spare" {{ old('type') == 'spare' ? 'selected' : '' }}>Repuesto</option>
</select>
</div>
<!-- Etiquetas -->
<div class="md:col-span-4">
<x-forms.label for="tags" value="Etiquetas" />
<select id="tags" name="tags[]" multiple="multiple" class="select2-tags w-full">
@foreach($tags as $tag)
<option value="{{ $tag->id }}" {{ in_array($tag->id, old('tags', [])) ? 'selected' : '' }}>
{{ $tag->name }}
</option>
@endforeach
</select>
</div>
<!-- Precios -->
<div class="">
<x-forms.label for="price" value="Precio Venta ($)" />
@@ -72,4 +83,83 @@
</div>
</form>
</div>
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
/* Dark Theme & Neon Lime overrides for Select2 */
.select2-container--default .select2-selection--multiple {
background-color: rgb(38 38 38); /* neutral-800 */
border-color: rgb(64 64 64); /* neutral-700 */
border-radius: 0.5rem;
min-height: 42px;
}
.select2-container--default.select2-container--focus .select2-selection--multiple {
border-color: #b3e600; /* neon-lime */
outline: 0;
box-shadow: 0 0 0 1px #b3e600;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
background-color: #b3e600;
border-color: #99c200;
color: #171717; /* neutral-900 */
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
color: #171717;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
background-color: #99c200;
color: #171717;
}
.select2-dropdown {
background-color: rgb(38 38 38);
border-color: rgb(64 64 64);
color: white;
}
.select2-search--dropdown .select2-search__field {
background-color: rgb(23 23 23);
border-color: rgb(64 64 64);
color: white;
}
.select2-container--default .select2-results__option--selected {
background-color: rgb(64 64 64);
}
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
background-color: #b3e600;
color: #171717;
}
.select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
color: white;
}
html:not(.dark) .select2-container--default .select2-selection--multiple {
background-color: rgb(209 213 219); /* gray-300 */
border-color: rgb(156 163 175); /* neutral-400 */
}
html:not(.dark) .select2-dropdown {
background-color: rgb(209 213 219);
border-color: rgb(156 163 175);
color: black;
}
html:not(.dark) .select2-search--dropdown .select2-search__field {
background-color: white;
color: black;
}
html:not(.dark) .select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
color: black;
}
</style>
@endpush
@push('scripts')
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('.select2-tags').select2({
placeholder: "Buscar y seleccionar etiquetas...",
allowClear: true
});
});
</script>
@endpush
</x-layout>
+90
View File
@@ -34,6 +34,17 @@
<option value="spare" {{ old('type', $product->type) == 'spare' ? 'selected' : '' }}>Repuesto</option>
</select>
</div>
<!-- Etiquetas -->
<div class="md:col-span-4">
<x-forms.label for="tags" value="Etiquetas" />
<select id="tags" name="tags[]" multiple="multiple" class="select2-tags w-full">
@foreach($tags as $tag)
<option value="{{ $tag->id }}" {{ in_array($tag->id, old('tags', $product->tags->pluck('id')->toArray())) ? 'selected' : '' }}>
{{ $tag->name }}
</option>
@endforeach
</select>
</div>
<!-- Precios -->
<div class="">
<x-forms.label for="price" value="Precio Venta ($)" />
@@ -68,4 +79,83 @@
</div>
</form>
</div>
@push('styles')
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<style>
/* Dark Theme & Neon Lime overrides for Select2 */
.select2-container--default .select2-selection--multiple {
background-color: rgb(38 38 38); /* neutral-800 */
border-color: rgb(64 64 64); /* neutral-700 */
border-radius: 0.5rem;
min-height: 42px;
}
.select2-container--default.select2-container--focus .select2-selection--multiple {
border-color: #b3e600; /* neon-lime */
outline: 0;
box-shadow: 0 0 0 1px #b3e600;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
background-color: #b3e600;
border-color: #99c200;
color: #171717; /* neutral-900 */
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
color: #171717;
}
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
background-color: #99c200;
color: #171717;
}
.select2-dropdown {
background-color: rgb(38 38 38);
border-color: rgb(64 64 64);
color: white;
}
.select2-search--dropdown .select2-search__field {
background-color: rgb(23 23 23);
border-color: rgb(64 64 64);
color: white;
}
.select2-container--default .select2-results__option--selected {
background-color: rgb(64 64 64);
}
.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
background-color: #b3e600;
color: #171717;
}
.select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
color: white;
}
html:not(.dark) .select2-container--default .select2-selection--multiple {
background-color: rgb(209 213 219); /* gray-300 */
border-color: rgb(156 163 175); /* neutral-400 */
}
html:not(.dark) .select2-dropdown {
background-color: rgb(209 213 219);
border-color: rgb(156 163 175);
color: black;
}
html:not(.dark) .select2-search--dropdown .select2-search__field {
background-color: white;
color: black;
}
html:not(.dark) .select2-container--default .select2-selection--multiple .select2-search--inline .select2-search__field {
color: black;
}
</style>
@endpush
@push('scripts')
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script>
$(document).ready(function() {
$('.select2-tags').select2({
placeholder: "Buscar y seleccionar etiquetas...",
allowClear: true
});
});
</script>
@endpush
</x-layout>
+61
View File
@@ -0,0 +1,61 @@
<x-layout title="Lauck - Etiquetas">
<x-section-header subtitle="Administración" title="Gestión de " highlight="Etiquetas" />
<div class="w-full max-w-4xl mx-auto space-y-6">
<!-- Create Form -->
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-4">Nueva Etiqueta</h3>
<form action="{{ route('tags.store') }}" method="POST" class="flex flex-col md:flex-row gap-4 items-end">
@csrf
<div class="w-full md:flex-1">
<x-forms.label for="name" value="Nombre de la Etiqueta" />
<x-forms.input id="name" name="name" type="text" required placeholder="Ej: Oferta, Temporada Verano" :error="$errors->first('name')" />
</div>
<button type="submit" class="w-full md:w-auto px-6 py-2.5 h-[42px] bg-neutral-900 dark:bg-neon-lime text-neon-lime dark:text-neutral-900 font-bold rounded-lg hover:bg-neutral-800 hover:dark:bg-[#b3e600] transition-colors shadow-lg">
Guardar
</button>
</form>
</div>
<!-- Tags List -->
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl shadow-lg overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead class="text-xs text-gray-700 uppercase bg-gray-300 dark:bg-neutral-800/50 dark:text-gray-400">
<tr>
<th scope="col" class="px-6 py-3">Nombre</th>
<th scope="col" class="px-6 py-3 text-right">Acciones</th>
</tr>
</thead>
<tbody>
@forelse($tags as $tag)
<tr class="bg-gray-200 dark:bg-neutral-900/50 border-b border-gray-300 dark:border-neutral-800 hover:bg-gray-300 dark:hover:bg-neutral-800/80 transition-colors">
<td class="px-6 py-4 font-medium text-gray-900 dark:text-white">
<form action="{{ route('tags.update', $tag) }}" method="POST" class="flex gap-2 items-center" id="form-edit-{{ $tag->id }}">
@csrf
@method('PUT')
<input type="text" name="name" value="{{ $tag->name }}" class="bg-transparent border-b border-transparent focus:border-neon-lime focus:ring-0 text-sm p-1 rounded-sm text-gray-900 dark:text-white w-full max-w-xs transition-colors" required>
</form>
</td>
<td class="px-6 py-4 text-right space-x-2 whitespace-nowrap">
<button type="button" onclick="document.getElementById('form-edit-{{ $tag->id }}').submit()" class="font-medium text-blue-600 dark:text-blue-500 hover:underline">Guardar</button>
<form action="{{ route('tags.destroy', $tag) }}" method="POST" class="inline-block">
@csrf
@method('DELETE')
<button type="submit" class="font-medium text-red-600 dark:text-red-500 hover:underline" onclick="return confirm('¿Seguro que deseas eliminar esta etiqueta?')">Eliminar</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="2" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">
No hay etiquetas creadas.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</x-layout>
+11 -4
View File
@@ -1,10 +1,17 @@
<x-layout title="Home - Lauck">
<x-section-header subtitle="Inicio" title="Bicicleteria " highlight="Lauck"/>
<!-- CARROUSEL DESTACADO -->
<div class="w-full mb-12">
<!-- datos del controlador -->
<x-ui.carrousel :items="$destacados" />
<!-- CARROUSELES POR ETIQUETA -->
<div class="w-full mb-12 space-y-16">
@forelse($tagsConProductos as $tag)
<div>
<x-ui.carrousel :items="$tag->products" title="{{ $tag->name }}" />
</div>
@empty
<div class="text-center py-12 bg-slate-100 dark:bg-panel-bg rounded-xl border border-neutral-200 dark:border-neutral-800">
<p class="text-gray-500 dark:text-gray-400 font-medium">Aún no hay productos etiquetados para mostrar.</p>
</div>
@endforelse
</div>
</x-layout>