feat: Reemplazar la página de selección de servidor con una interfaz de selección en línea y ajustar el diseño de la página de inicio de sesión
This commit is contained in:
@@ -1138,14 +1138,10 @@ export const server = createServer(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select guild page
|
// Keep /dashboard/select-guild for compatibility: redirect to /dashboard
|
||||||
if (url.pathname === "/dashboard/select-guild") {
|
if (url.pathname === "/dashboard/select-guild") {
|
||||||
await renderTemplate(req, res, "select_guild", {
|
res.writeHead(302, { Location: "/dashboard" });
|
||||||
appName: pkg.name ?? "Amayo Bot",
|
res.end();
|
||||||
user,
|
|
||||||
guilds,
|
|
||||||
hideNavbar: true,
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,85 @@
|
|||||||
<div class="max-w-3xl mx-auto p-6">
|
<div class="max-w-3xl mx-auto p-6">
|
||||||
<div class="relative flex justify-center">
|
<div class="relative flex justify-center">
|
||||||
<% if (!selectedGuild) { %>
|
<% if (!selectedGuild) { %>
|
||||||
<!-- Card principal (centered) -->
|
<!-- Show server selection UI inline (replaces /dashboard/select-guild) -->
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class="mx-auto backdrop-blur-md bg-white/10 border border-white/10 rounded-xl p-6 shadow-lg glass-card">
|
<div class="mx-auto backdrop-blur-md bg-white/6 border border-white/10 rounded-xl p-6 shadow-lg glass-card max-w-xl text-center">
|
||||||
<h1 class="text-3xl font-bold mb-2"><%= appName %></h1>
|
<h2 class="text-2xl font-bold mb-2"><%= appName %></h2>
|
||||||
<p class="text-sm text-slate-200/80 mb-4">Panel de administración</p>
|
<p class="text-sm text-slate-200/80 mb-4">Selecciona un servidor desde la lista abajo para administrar sus ajustes.</p>
|
||||||
<div class="mt-4">
|
|
||||||
<p class="text-sm text-slate-200/80">Selecciona un servidor desde la página principal para administrar sus ajustes.</p>
|
<div class="mt-4 text-left">
|
||||||
<a href="/dashboard/select-guild" class="inline-block mt-3 pixel-btn">Seleccionar servidor</a>
|
<label class="block text-xs text-slate-300 mb-2">Servidor</label>
|
||||||
|
<div class="relative">
|
||||||
|
<input id="guildInput" aria-controls="guildList" aria-expanded="false" aria-autocomplete="list" autocomplete="off" placeholder="Busca o selecciona un servidor..." class="w-full rounded-md p-3 bg-white/6 text-white placeholder:text-slate-400 focus:outline-none" />
|
||||||
|
<button id="clearBtn" aria-label="Limpiar" class="absolute right-2 top-2 text-slate-300 hover:text-white hidden">✕</button>
|
||||||
|
|
||||||
|
<div id="guildList" role="listbox" class="mt-2 max-h-64 overflow-auto rounded-md bg-white/4 backdrop-blur divide-y divide-white/6 hidden">
|
||||||
|
<% if (guilds && guilds.length) { %>
|
||||||
|
<% guilds.sort((a,b)=> a.name.localeCompare(b.name)).forEach(g => { %>
|
||||||
|
<div role="option" data-id="<%= g.id %>" class="p-3 cursor-pointer hover:bg-white/6 text-white flex items-center gap-3">
|
||||||
|
<div class="w-8 h-8 rounded-md bg-white/10 flex items-center justify-center text-sm text-white/80">#</div>
|
||||||
|
<div class="truncate">
|
||||||
|
<div class="font-medium"><%= g.name %></div>
|
||||||
|
<div class="text-xs text-slate-300"><%= g.id %></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% }) %>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="p-3 text-slate-300">No tienes servidores gestionados</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const input = document.getElementById('guildInput');
|
||||||
|
const list = document.getElementById('guildList');
|
||||||
|
const clearBtn = document.getElementById('clearBtn');
|
||||||
|
if (!input || !list) return;
|
||||||
|
|
||||||
|
const items = Array.from(list.querySelectorAll('[role="option"]'));
|
||||||
|
function showList() { list.classList.remove('hidden'); input.setAttribute('aria-expanded','true'); }
|
||||||
|
function hideList() { list.classList.add('hidden'); input.setAttribute('aria-expanded','false'); }
|
||||||
|
|
||||||
|
function filter(q) {
|
||||||
|
const v = String(q || '').toLowerCase().trim();
|
||||||
|
let any = 0;
|
||||||
|
items.forEach(it => {
|
||||||
|
const name = (it.querySelector('.font-medium')?.textContent || '').toLowerCase();
|
||||||
|
const id = (it.dataset.id || '');
|
||||||
|
if (!v || name.includes(v) || id.includes(v)) { it.style.display = ''; any++; } else { it.style.display = 'none'; }
|
||||||
|
});
|
||||||
|
return any;
|
||||||
|
}
|
||||||
|
|
||||||
|
let focused = -1;
|
||||||
|
function focusItem(idx) {
|
||||||
|
items.forEach((it,i)=> it.classList.toggle('ring-2 ring-white/20', i===idx));
|
||||||
|
focused = idx;
|
||||||
|
if (idx>=0) { const el = items[idx]; el.scrollIntoView({ block:'nearest' }); }
|
||||||
|
}
|
||||||
|
|
||||||
|
input.addEventListener('input', (e) => { const v = (e.target).value; filter(v); showList(); clearBtn.classList.toggle('hidden', !v); focused = -1; });
|
||||||
|
input.addEventListener('focus', () => { filter(input.value); showList(); });
|
||||||
|
input.addEventListener('blur', () => setTimeout(hideList, 150));
|
||||||
|
clearBtn?.addEventListener('click', (e)=>{ e.preventDefault(); input.value=''; filter(''); input.focus(); clearBtn.classList.add('hidden'); });
|
||||||
|
|
||||||
|
// click selection
|
||||||
|
items.forEach((it)=>{ it.addEventListener('click', ()=>{ const id = it.getAttribute('data-id'); if (id) window.location.href = `/dashboard/${id}/overview`; }); });
|
||||||
|
|
||||||
|
// keyboard navigation
|
||||||
|
input.addEventListener('keydown', (e)=>{
|
||||||
|
const visible = items.filter(it => it.style.display !== 'none');
|
||||||
|
if (e.key === 'ArrowDown') { e.preventDefault(); if (visible.length) { focused = Math.min(visible.length-1, (focused+1)); const idx = items.indexOf(visible[focused]); focusItem(idx); } }
|
||||||
|
else if (e.key === 'ArrowUp') { e.preventDefault(); if (visible.length) { focused = Math.max(0, (focused-1)); const idx = items.indexOf(visible[focused]); focusItem(idx); } }
|
||||||
|
else if (e.key === 'Enter') { e.preventDefault(); if (focused>=0) { const sel = items[focused]; const id = sel.getAttribute('data-id'); if (id) window.location.href = `/dashboard/${id}/overview`; } }
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% if (typeof selectedGuild !== 'undefined' && selectedGuild) { %>
|
<% if (typeof selectedGuild !== 'undefined' && selectedGuild) { %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="min-h-screen flex items-center justify-center pixel-grid-bg" style="background-image: url('/assets/images/background.svg'); background-size: cover;">
|
<div class="min-h-screen flex items-center justify-center pixel-grid-bg" style="background-image: url('/assets/images/background.svg'); background-size: cover;">
|
||||||
<div class="w-full max-w-3xl p-8">
|
<div class="w-full max-w-3xl p-8">
|
||||||
<div class="mx-auto max-w-lg text-center mb-8">
|
<div class="mx-auto max-w-lg text-center">
|
||||||
<!-- Animated inline logo -->
|
<!-- Animated inline logo -->
|
||||||
<div class="mx-auto mb-4 w-24 logo-anim" aria-hidden="true">
|
<div class="mx-auto mb-4 w-24 logo-anim" aria-hidden="true">
|
||||||
<img src="/assets/images/logo-amayo.svg" alt="logo" class="mx-auto mb-4 rounded-full" />
|
<img src="/assets/images/logo-amayo.svg" alt="logo" class="mx-auto mb-4 rounded-full" />
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<h1 class="text-2xl font-bold text-white">Amayo</h1>
|
<h1 class="text-2xl font-bold text-white">Amayo</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mx-auto max-w-md glass-card backdrop-blur-md rounded-xl p-8 entrance-card">
|
<div class="mx-auto max-w-md glass-card backdrop-blur-md rounded-xl p-4 entrance-card">
|
||||||
<p class="text-sm text-slate-300 mb-6">Log in with Discord to access the dashboard.</p>
|
<p class="text-sm text-slate-300 mb-6">Log in with Discord to access the dashboard.</p>
|
||||||
|
|
||||||
<a id="discordLoginBtn" href="/auth/discord" class="inline-flex items-center justify-center gap-3 w-full px-4 py-3 rounded-md bg-indigo-600 hover:bg-indigo-700 text-white font-medium transition-colors relative overflow-hidden">
|
<a id="discordLoginBtn" href="/auth/discord" class="inline-flex items-center justify-center gap-3 w-full px-4 py-3 rounded-md bg-indigo-600 hover:bg-indigo-700 text-white font-medium transition-colors relative overflow-hidden">
|
||||||
|
|||||||
Reference in New Issue
Block a user