From e2a7013ee036e0893e119fef576efc1e82076432 Mon Sep 17 00:00:00 2001 From: Shni Date: Wed, 15 Oct 2025 10:10:41 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20Actualizar=20la=20tipograf=C3=ADa=20y?= =?UTF-8?q?=20mejorar=20la=20selecci=C3=B3n=20de=20roles=20en=20el=20panel?= =?UTF-8?q?=20de=20configuraci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/public/assets/css/modern-pixel.css | 2 +- .../partials/dashboard/dashboard_settings.ejs | 168 +++++++++++++++--- 2 files changed, 145 insertions(+), 25 deletions(-) diff --git a/src/server/public/assets/css/modern-pixel.css b/src/server/public/assets/css/modern-pixel.css index 9f2134d..35b4cae 100644 --- a/src/server/public/assets/css/modern-pixel.css +++ b/src/server/public/assets/css/modern-pixel.css @@ -76,7 +76,7 @@ body::before { /* Tipografía Moderna */ h1 { - font-family: 'Press Start 2P', monospace; + font-family: 'BoldPixels', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial; font-size: clamp(2rem, 5vw, 4rem); font-weight: 400; line-height: 1.3; diff --git a/src/server/views/partials/dashboard/dashboard_settings.ejs b/src/server/views/partials/dashboard/dashboard_settings.ejs index 5cd13b3..e003d95 100644 --- a/src/server/views/partials/dashboard/dashboard_settings.ejs +++ b/src/server/views/partials/dashboard/dashboard_settings.ejs @@ -13,35 +13,25 @@ -
- - <% if (typeof guildRoles !== 'undefined' && guildRoles && guildRoles.length) { %> -
- -
- - <% } else { %> - <% const fallbackStaff = (guildConfig && Array.isArray(guildConfig.staff) ? guildConfig.staff.map(String) : (guildConfig && guildConfig.staff ? String(guildConfig.staff).split(',') : [])) || []; %> - <% if (fallbackStaff.length) { %> + +
+ + <% const selectedStaff = (guildConfig && Array.isArray(guildConfig.staff) ? guildConfig.staff.map(String) : (guildConfig && guildConfig.staff ? String(guildConfig.staff).split(',') : [])) || []; %> + <% if (typeof guildRoles !== 'undefined' && guildRoles && guildRoles.length) { %>
- +
+
+ +
+ + +
Selecciona roles del servidor. Escribe para filtrar, pulsa Enter para elegir.
- <% } else { %> -
No se pudo obtener roles desde la API ni hay roles guardados. Introduce IDs manualmente separadas por coma.
+
No se pudo obtener roles desde la API. Introduce IDs manualmente separadas por coma.
<% } %> - <% } %> -
+
@@ -98,4 +88,134 @@ } }); })(); + (function(){ + const form = document.getElementById('guildSettingsForm'); + const status = document.getElementById('saveStatus'); + + // Multi-select tag/autocomplete for roles + const staffTagInput = document.getElementById('staffTagInput'); + const staffSuggestions = document.getElementById('staffSuggestions'); + const staffChips = document.getElementById('staffChips'); + const staffHidden = document.getElementById('staffHidden'); + + // Prepare role options (id, name, color) from server-side `guildRoles` + <% const ROLE_JSON = JSON.stringify((guildRoles||[]).map(r=>{ var c; if (typeof r.color !== 'undefined' && r.color !== null) { if (typeof r.color === 'number') { c = '#'+('000000'+r.color.toString(16)).slice(-6); } else { c = (''+r.color).replace(/^#?/, '#'); } } else { c = (r.colorHex||r.hex||'#8b95a0'); } return { id: String(r.id), name: r.name, color: c }; })); %> + const ROLE_OPTIONS = <%- ROLE_JSON %>; + // Initial selected staff IDs (strings) + const INITIAL_STAFF = <%- JSON.stringify(selectedStaff || []) %>; + + let selectedIds = Array.isArray(INITIAL_STAFF) ? INITIAL_STAFF.slice() : []; + + function renderChips(){ + staffChips.innerHTML = ''; + for(const id of selectedIds){ + const role = ROLE_OPTIONS.find(r=>r.id===String(id)); + const label = role ? role.name : String(id); + const chip = document.createElement('div'); + chip.className = 'px-2 py-1 bg-white/6 rounded-full text-sm flex items-center gap-2'; + const swatch = role && role.color ? `` : ''; + chip.innerHTML = `${swatch}${label}`; + staffChips.appendChild(chip); + } + // update hidden input + if(staffHidden) staffHidden.value = selectedIds.join(','); + } + + function showSuggestions(query){ + if(!staffSuggestions) return; + const q = (query||'').trim().toLowerCase(); + const filtered = ROLE_OPTIONS.filter(r=> !selectedIds.includes(String(r.id)) && (!q || r.name.toLowerCase().includes(q) || String(r.id).includes(q)) ).slice(0,50); + if(!filtered.length){ staffSuggestions.classList.add('hidden'); staffSuggestions.innerHTML=''; return; } + staffSuggestions.classList.remove('hidden'); + staffSuggestions.innerHTML = filtered.map(r=>`
  • ${r.name}
  • `).join(''); + } + + function addId(id){ + id = String(id); + if(!id) return; + if(selectedIds.includes(id)) return; + selectedIds.push(id); + renderChips(); + } + + function removeId(id){ + id = String(id); + selectedIds = selectedIds.filter(i=>String(i)!==id); + renderChips(); + } + + if(staffTagInput){ + // initial render + renderChips(); + + staffTagInput.addEventListener('input', (e)=>{ + showSuggestions(e.target.value); + }); + + staffTagInput.addEventListener('keydown', (e)=>{ + if(e.key === 'Enter'){ + e.preventDefault(); + // pick first suggestion if any, otherwise ignore + const first = staffSuggestions.querySelector('li'); + if(first){ addId(first.dataset.id); staffTagInput.value=''; staffSuggestions.classList.add('hidden'); } + } else if (e.key === 'Backspace' && !staffTagInput.value){ + // remove last + selectedIds.pop(); renderChips(); + } + }); + + document.addEventListener('click', (ev)=>{ + if(!staffSuggestions) return; + if(ev.target.closest && ev.target.closest('#staffSuggestions')) return; + if(ev.target === staffTagInput) return; + staffSuggestions.classList.add('hidden'); + }); + + staffSuggestions.addEventListener('click', (ev)=>{ + const li = ev.target.closest('li'); + if(!li) return; + addId(li.dataset.id); + staffTagInput.value=''; + staffSuggestions.classList.add('hidden'); + staffTagInput.focus(); + }); + + staffChips.addEventListener('click', (ev)=>{ + const btn = ev.target.closest('.remove-chip'); + if(!btn) return; + removeId(btn.dataset.id); + }); + } + + form.addEventListener('submit', async (e)=>{ + e.preventDefault(); + status.textContent = 'Guardando...'; + const prefix = document.getElementById('prefixInput').value.trim(); + const aiRolePrompt = document.getElementById('aiRoleInput').value.trim(); + let staffArr = []; + if(typeof selectedIds !== 'undefined' && selectedIds && selectedIds.length){ + staffArr = selectedIds.slice(); + } else if (document.getElementById('staffInput')){ + const staffRaw = document.getElementById('staffInput').value.trim(); + staffArr = staffRaw ? staffRaw.split(',').map(s=>s.trim()).filter(Boolean) : []; + } + const payload = { prefix: prefix, aiRolePrompt: aiRolePrompt.length ? aiRolePrompt : null, staff: staffArr }; + try { + const res = await fetch(`/api/dashboard/${encodeURIComponent('<%= selectedGuild %>')}/settings`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload), + }); + const json = await res.json(); + if (res.ok && json.ok) { + status.textContent = 'Guardado'; + setTimeout(()=> status.textContent = '', 2500); + } else { + status.textContent = json.error || 'Error'; + } + } catch (err) { + status.textContent = 'Error de red'; + } + }); + })();