This commit is contained in:
2025-09-26 17:23:30 -06:00
3 changed files with 76 additions and 0 deletions

View File

@@ -55,10 +55,24 @@
</div>
</div>
<div class="scroll">
<<<<<<< HEAD
<div v-if="loading.users" class="muted">Cargando usuarios</div>
<div v-else class="grid">
<UserCard v-for="u in filteredUsers" :key="u.username" :item="u" :mode="layoutMode"
@toggleDisable="toggleDisable" @remove="removeUser" @edit="openEditUser" />
=======
<form @submit.prevent="createUser" class="row" style="margin-bottom:10px;">
<input v-model="form.username" placeholder="usuario" required class="toggle"/>
<input v-model="form.password" placeholder="contraseña" required class="toggle"/>
<input v-model="form.vlan" placeholder="VLAN" class="toggle"/>
<label class="row toggle" style="gap:6px;"><input type="checkbox" v-model="form.disabled"/> deshabilitado</label>
<button type="submit" class="icon-btn">Crear / Actualizar</button>
</form>
<div v-if="loading.users" class="muted">Cargando usuarios</div>
<div v-else class="grid">
<UserCard v-for="u in filteredUsers" :key="u.username" :item="u" :mode="layoutMode"
@toggleDisable="toggleDisable" @remove="removeUser" />
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
</div>
</div>
</main>
@@ -89,11 +103,14 @@
</select>
</div>
</Modal>
<<<<<<< HEAD
<Modal :open="showUserForm" :title="userFormMode==='edit' ? 'Editar usuario' : (userFormMode==='guest' ? 'Agregar invitado' : 'Agregar usuario')"
@close="showUserForm=false">
<UserForm :model-value="userFormModel" :mode="userFormMode" @submit="handleUserFormSubmit" @cancel="showUserForm=false" />
</Modal>
=======
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
</template>
<script setup>
@@ -101,12 +118,19 @@ import { onMounted, reactive, ref, computed } from 'vue';
import EventCard from './components/EventCard.js';
import UserCard from './components/UserCard.js';
import Modal from './components/Modal.vue';
<<<<<<< HEAD
import UserForm from './components/UserForm.vue';
=======
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
const users = ref([]);
const requests = ref([]);
const loading = reactive({ users: false, requests: false });
<<<<<<< HEAD
// formulario inline removido: se usa modal con UserForm
=======
const form = reactive({ username: '', password: '', vlan: '', disabled: false });
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
const showEventFilters = ref(false);
const showUserFilters = ref(false);
@@ -136,6 +160,20 @@ async function fetchRequests() {
} finally { loading.requests = false; }
}
<<<<<<< HEAD
=======
async function createUser() {
const payload = { ...form };
if (!payload.vlan) delete payload.vlan;
await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
form.username = '';
form.password = '';
form.vlan = '';
form.disabled = false;
await fetchUsers();
}
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
async function toggleDisable(u) {
await fetch(`/api/users/${encodeURIComponent(u.username)}`, {
method: 'PATCH',
@@ -215,6 +253,7 @@ function applyTheme() {
document.documentElement.classList.toggle('light', theme.value === 'light');
}
<<<<<<< HEAD
const showUserForm = ref(false);
const userFormMode = ref('create'); // 'create' | 'edit' | 'guest'
const userFormModel = ref({ username:'', password:'', vlan:'', disabled:false });
@@ -247,4 +286,9 @@ async function handleUserFormSubmit(data) {
await fetchUsers();
showUserForm.value = false;
}
=======
function openAddUser() { /* placeholder for advanced modal */ }
function openAddGuest() { /* placeholder for advanced modal */ }
function openSettings() { /* placeholder for advanced modal */ }
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
</script>

View File

@@ -5,18 +5,28 @@ const html = htm.bind(h);
export default defineComponent({
name: 'UserCard',
props: { item: { type: Object, required: true }, mode: { type: String, default: 'user' } },
<<<<<<< HEAD
emits: ['toggleDisable', 'remove', 'edit'],
setup(props, { emit }) {
function toggle() { emit('toggleDisable', props.item); }
function remove() { emit('remove', props.item); }
function edit() { emit('edit', props.item); }
=======
emits: ['toggleDisable', 'remove'],
setup(props, { emit }) {
function toggle() { emit('toggleDisable', props.item); }
function remove() { emit('remove', props.item); }
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
return () => html`<div class="card">
<div class="row">
<b>${props.mode === 'user' ? props.item.username : (props.item.device || props.item.username)}</b>
<span class="chip">VLAN ${props.item.vlan}</span>
${props.item.disabled ? html`<span class="chip" style="color:#b33">deshabilitado</span>` : html`<span class="chip">activo</span>`}
<span class="spacer"></span>
<<<<<<< HEAD
<button class="icon-btn" onClick=${edit}>Editar</button>
=======
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
<button class="icon-btn" onClick=${toggle}>${props.item.disabled ? 'Habilitar' : 'Deshabilitar'}</button>
<button class="icon-btn" onClick=${remove}>Eliminar</button>
</div>
@@ -24,3 +34,7 @@ export default defineComponent({
</div>`;
}
});
<<<<<<< HEAD
=======
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722

View File

@@ -7,12 +7,15 @@
--border: 255 255 255 / 0.12;
--glass-blur: 14px;
--radius: 14px;
<<<<<<< HEAD
/* Scrollbar */
--sb-size: 10px;
--sb-thumb: rgba(255, 159, 203, 0.55);
--sb-thumb-hover: rgba(255, 159, 203, 0.75);
--sb-thumb-active: rgba(255, 127, 187, 0.9);
--sb-track: rgba(255,255,255,0.05);
=======
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
}
:root.light {
--bg: 245 245 248;
@@ -21,10 +24,13 @@
--accent: 18 108 242;
--card: 255 255 255 / 0.6;
--border: 0 0 0 / 0.08;
<<<<<<< HEAD
--sb-thumb: rgba(255, 127, 187, 0.65);
--sb-thumb-hover: rgba(255, 127, 187, 0.82);
--sb-thumb-active: rgba(255, 110, 178, 0.95);
--sb-track: rgba(0,0,0,0.06);
=======
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
}
* { box-sizing: border-box; }
html, body, #app { height: 100%; }
@@ -38,6 +44,7 @@ a { color: inherit; }
position: sticky; top: 0; z-index: 10;
display: flex; flex-wrap: wrap; align-items: center;
gap: 10px; padding: 10px 14px; backdrop-filter: blur(var(--glass-blur));
<<<<<<< HEAD
border: 1px solid transparent;
background:
linear-gradient(rgba(var(--card)), rgba(var(--card))) padding-box,
@@ -62,6 +69,10 @@ a { color: inherit; }
rgba(0, 0, 0, 0.00) 70%
) border-box;
border-width: 0.5px; /* borde más delgado en dark */
=======
background: linear-gradient(180deg, rgba(var(--card)), rgba(var(--card)) 60%, rgba(0,0,0,0));
border-bottom: 1px solid rgba(var(--border));
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
}
.title { font-size: 16px; font-weight: 700; letter-spacing: .2px; flex: 1 1 auto; }
.actions { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
@@ -72,6 +83,7 @@ a { color: inherit; }
/* Layout */
.shell { height: calc(100vh - 54px); display: grid; grid-template-columns: 360px 1fr; gap: 12px; padding: 12px; }
<<<<<<< HEAD
.panel {
border: 1px solid #ffcfe4; /* light más claro */
background: linear-gradient(rgba(var(--card)), rgba(var(--card))) padding-box;
@@ -80,6 +92,9 @@ a { color: inherit; }
overflow: hidden; display: flex; flex-direction: column; min-height: 0;
}
:root:not(.light) .panel { border-color: #ff2e86; border-width: 0.5px; /* borde más delgado en dark */ }
=======
.panel { border: 1px solid rgba(var(--border)); background: rgba(var(--card)); border-radius: var(--radius); backdrop-filter: blur(var(--glass-blur)); overflow: hidden; display: flex; flex-direction: column; min-height: 0; }
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722
.panel-header { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; padding: 10px 12px; border-bottom: 1px solid rgba(var(--border)); }
.panel-title { font-weight: 600; }
.panel-actions { display: inline-flex; flex-wrap: wrap; gap: 6px; }
@@ -112,6 +127,7 @@ a { color: inherit; }
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.spacer { flex: 1; }
.toggle { padding: 6px 10px; border-radius: 8px; border: 1px solid rgba(var(--border)); background: rgba(var(--card)); }
<<<<<<< HEAD
/* Scrollbars */
/* Firefox */
@@ -142,3 +158,5 @@ html::-webkit-scrollbar-thumb:active, body::-webkit-scrollbar-thumb:active, .scr
background: var(--sb-thumb-active);
background-clip: content-box;
}
=======
>>>>>>> c92df7bb9a1b22aee21d2c083ea163d21ab1a722