Refactor: Migrar UI completa a Tailwind CSS v4 + shadcn-vue
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 58s

- Reemplazar CSS nativo con Tailwind CSS v4 y utilidades custom
- Crear librería de componentes UI basada en shadcn-vue (Radix Vue)
- Componentes UI: Button, Card, Input, Textarea, Badge, Dialog, Avatar, DropdownMenu
- Migrar todos los componentes existentes a Tailwind utilities
- Convertir EventCard.js (htm) a EventCard.vue (SFC)
- Implementar sistema de temas dark/light con clase .dark
- Mantener efectos glassmorphism via @utility custom
- Eliminar styles.css legacy
This commit is contained in:
2025-11-24 18:12:24 -06:00
parent 003fdf18a7
commit 96a8f95f9e
52 changed files with 2580 additions and 1418 deletions

View File

@@ -1,29 +1,6 @@
<template>
<div class="card">
<div class="row">
<b>{{ device.nombre || device.mac }}</b>
<span class="chip">MAC: {{ device.mac }}</span>
<span class="chip">ID: {{ device.id }}</span>
<span v-if="connectedCount>0 || connected" class="chip" style="background: rgba(255,127,187,.2); border-color: rgba(255,127,187,.5);">Conectado</span>
<span class="spacer"></span>
<button class="icon-btn" @click="$emit('edit', device)">Editar</button>
<button class="icon-btn" @click="$emit('disconnect', device)">Desconectar</button>
<button v-if="!simple" class="icon-btn" @click="$emit('toggleExpand')">{{ expanded ? 'Contraer' : 'Expandir' }}</button>
</div>
<div class="muted" style="font-size:12px; margin-top:6px;" v-if="device.nombre || device.descripcion">
<div v-if="device.nombre">Nombre: {{ device.nombre }}</div>
<div v-if="device.descripcion">Descripción: {{ device.descripcion }}</div>
</div>
<div v-if="expanded && users && users.length" style="margin-top:8px;">
<div class="grid">
<UserCard v-for="u in users" :key="u.username" :item="u" :devicesById="devicesById" :expandable="false" />
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue';
import { Card, Badge, Button } from '@/components/ui';
import UserCard from './UserCard.vue';
const props = defineProps({
@@ -34,9 +11,48 @@ const props = defineProps({
connected: { type: Boolean, default: false },
expanded: { type: Boolean, default: false }
});
const emit = defineEmits(['edit', 'disconnect', 'toggleExpand']);
const connectedCount = computed(() => {
if (!props.users || !props.users.length) return props.connected ? 1 : 0;
const id = props.device.id;
return props.users.filter(u => Array.isArray(u.dispositivos_conectados) && u.dispositivos_conectados.includes(id)).length;
});
</script>
<template>
<Card class="p-3">
<div class="flex flex-wrap items-center gap-2">
<b>{{ device.nombre || device.mac }}</b>
<Badge>MAC: {{ device.mac }}</Badge>
<Badge variant="secondary">ID: {{ device.id }}</Badge>
<Badge v-if="connectedCount > 0 || connected" variant="pink">
Conectado
</Badge>
<span class="flex-1"></span>
<Button size="sm" @click="emit('edit', device)">Editar</Button>
<Button size="sm" variant="danger" @click="emit('disconnect', device)">Desconectar</Button>
<Button v-if="!simple" size="sm" variant="ghost" @click="emit('toggleExpand')">
{{ expanded ? 'Contraer' : 'Expandir' }}
</Button>
</div>
<div v-if="device.nombre || device.descripcion" class="text-muted text-xs mt-1.5">
<div v-if="device.nombre">Nombre: {{ device.nombre }}</div>
<div v-if="device.descripcion">Descripción: {{ device.descripcion }}</div>
</div>
<div v-if="expanded && users && users.length" class="mt-2">
<div class="grid grid-cols-[repeat(auto-fill,minmax(280px,1fr))] gap-2.5">
<UserCard
v-for="u in users"
:key="u.username"
:item="u"
:devicesById="devicesById"
:expandable="false"
/>
</div>
</div>
</Card>
</template>