239 lines
11 KiB
PHP
239 lines
11 KiB
PHP
<div class="max-w-full mx-auto p-6">
|
|
<!-- Header con contador y botón de agregar -->
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h2 class="text-2xl font-bold text-gray-800">
|
|
Codificación de los documentos del proyecto
|
|
</h2>
|
|
|
|
<button
|
|
type="button"
|
|
wire:click="addComponent"
|
|
class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700 transition-colors flex items-center space-x-2"
|
|
>
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
|
|
</svg>
|
|
<span>Agregar Componente</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Label con nombres de componentes -->
|
|
<div class="mb-6 p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
|
<div class="flex items-center space-x-2">
|
|
<span class="text-sm font-medium text-blue-800">Código:</span>
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
<span ><flux:badge color="green">SOGOS0001</flux:badge>-</span>
|
|
@foreach($components as $index => $component)
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-white text-blue-700 border border-blue-200">
|
|
{{ $component['headerLabel'] }}
|
|
@if(isset($component['data']['documentTypes']) && count($component['data']['documentTypes']) > 0)
|
|
<span class="ml-1 bg-blue-100 text-blue-800 px-1.5 py-0.5 rounded-full">
|
|
{{ count($component['data']['documentTypes']) }}
|
|
</span>
|
|
@endif
|
|
</span>
|
|
@if(!$loop->last)
|
|
<span class="text-blue-400">-</span>
|
|
@endif
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Contenedor horizontal para drag and drop -->
|
|
<div
|
|
x-data="{
|
|
draggedComponent: null,
|
|
init() {
|
|
const container = this.$refs.componentsContainer;
|
|
|
|
if (container.children.length > 0) {
|
|
// Inicializar Sortable para horizontal
|
|
new Sortable(container, {
|
|
animation: 150,
|
|
ghostClass: 'bg-blue-50',
|
|
chosenClass: 'bg-blue-100',
|
|
dragClass: 'bg-blue-200',
|
|
direction: 'horizontal',
|
|
onStart: (evt) => {
|
|
this.draggedComponent = evt.item.getAttribute('data-component-id');
|
|
},
|
|
onEnd: (evt) => {
|
|
const orderedIds = Array.from(container.children).map(child => {
|
|
return parseInt(child.getAttribute('data-component-id'));
|
|
});
|
|
|
|
// Enviar el nuevo orden a Livewire
|
|
this.$wire.updateComponentOrder(orderedIds);
|
|
this.draggedComponent = null;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}"
|
|
x-ref="componentsContainer"
|
|
class="flex space-x-4 overflow-x-auto pb-4 min-h-80"
|
|
>
|
|
<!-- Lista de componentes en horizontal -->
|
|
@foreach($components as $component)
|
|
<div
|
|
data-component-id="{{ $component['id'] }}"
|
|
class="component-item bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-shadow duration-200 flex-shrink-0 w-80"
|
|
wire:key="component-{{ $component['id'] }}"
|
|
>
|
|
<!-- Header del componente -->
|
|
<div class="flex justify-between items-center p-3 border-b border-gray-100 bg-gray-50 rounded-t-lg">
|
|
<div class="flex items-center space-x-2">
|
|
<!-- Handle para drag -->
|
|
<!--
|
|
<div class="cursor-move text-gray-400 hover:text-gray-600">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8h16M4 16h16"></path>
|
|
</svg>
|
|
</div>
|
|
-->
|
|
<span class="text-xs font-medium text-gray-700">
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-white text-blue-700 border border-blue-200">{{ $loop->iteration }}</span>
|
|
{{ $component['headerLabel'] }}
|
|
</span>
|
|
|
|
<!-- Contador de tipos en este componente -->
|
|
@if(isset($component['data']['documentTypes']) && count($component['data']['documentTypes']) > 0)
|
|
<span class="bg-blue-100 text-blue-800 text-xs px-1.5 py-0.5 rounded-full">
|
|
{{ count($component['data']['documentTypes']) }}
|
|
</span>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex items-center space-x-1">
|
|
<!-- Botones de orden -->
|
|
@if(!$loop->first)
|
|
<button
|
|
type="button"
|
|
wire:click="moveComponentUp({{ $component['id'] }})"
|
|
title="Mover hacia arriba"
|
|
class="p-1 text-blue-600 hover:text-blue-800 hover:bg-blue-100 rounded transition-colors"
|
|
>
|
|
<svg class="w-4 h-4" 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>
|
|
@else
|
|
<div class="w-6"></div> <!-- Espacio para mantener alineación -->
|
|
@endif
|
|
|
|
@if(!$loop->last)
|
|
<button
|
|
type="button"
|
|
wire:click="moveComponentDown({{ $component['id'] }})"
|
|
title="Mover hacia abajo"
|
|
class="p-1 text-blue-600 hover:text-blue-800 hover:bg-blue-100 rounded transition-colors"
|
|
>
|
|
<svg class="w-4 h-4" 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>
|
|
@else
|
|
<div class="w-6"></div> <!-- Espacio para mantener alineación -->
|
|
@endif
|
|
|
|
<!-- Botón eliminar -->
|
|
<button
|
|
type="button"
|
|
wire:click="removeComponent({{ $component['id'] }})"
|
|
title="Eliminar este componente"
|
|
class="p-1 text-red-600 hover:text-red-800 hover:bg-red-100 rounded transition-colors"
|
|
>
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Componente hijo -->
|
|
<div class="p-3">
|
|
<livewire:code-edit
|
|
:key="'document-manager-' . $component['id']"
|
|
:component-id="$component['id']"
|
|
:initial-name="$component['headerLabel']"
|
|
/>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
<!-- Mensaje cuando no hay componentes -->
|
|
@if($this->componentsCount === 0)
|
|
<div class="text-center py-12 bg-gray-50 rounded-lg border-2 border-dashed border-gray-300">
|
|
<svg class="w-12 h-12 text-gray-400 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
|
</svg>
|
|
<p class="text-gray-500 mb-4">No hay componentes de tipos de documento</p>
|
|
<button
|
|
type="button"
|
|
wire:click="addComponent"
|
|
class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors"
|
|
>
|
|
Agregar el primer componente
|
|
</button>
|
|
</div>
|
|
@endif
|
|
|
|
|
|
<!-- Incluir Sortable.js -->
|
|
|
|
|
|
<style>
|
|
.component-item {
|
|
cursor: default;
|
|
min-width: 320px;
|
|
}
|
|
|
|
.component-item .cursor-move {
|
|
cursor: grab;
|
|
}
|
|
|
|
.component-item .cursor-move:active {
|
|
cursor: grabbing;
|
|
}
|
|
|
|
.sortable-ghost {
|
|
opacity: 0.4;
|
|
background-color: #dbeafe;
|
|
}
|
|
|
|
.sortable-chosen {
|
|
background-color: #eff6ff;
|
|
transform: rotate(2deg);
|
|
}
|
|
|
|
.sortable-drag {
|
|
background-color: #dbeafe;
|
|
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.overflow-x-auto {
|
|
scrollbar-width: thin;
|
|
scrollbar-color: #cbd5e0 #f7fafc;
|
|
}
|
|
|
|
.overflow-x-auto::-webkit-scrollbar {
|
|
height: 8px;
|
|
}
|
|
|
|
.overflow-x-auto::-webkit-scrollbar-track {
|
|
background: #f7fafc;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.overflow-x-auto::-webkit-scrollbar-thumb {
|
|
background: #cbd5e0;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.overflow-x-auto::-webkit-scrollbar-thumb:hover {
|
|
background: #a0aec0;
|
|
}
|
|
</style>
|
|
</div> |