feat: añadir badge de responsables y popover con enlaces wa.me
Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>webui
parent
4039390ab0
commit
f4632859e0
@ -0,0 +1,111 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { tick, onDestroy } from 'svelte';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
export let open: boolean = false;
|
||||||
|
export let ariaLabel: string = 'Diálogo';
|
||||||
|
export let id: string | undefined;
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
let panelEl: HTMLElement | null = null;
|
||||||
|
let lastActive: Element | null = null;
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
open = false;
|
||||||
|
dispatch('closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeydown(e: KeyboardEvent) {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
e.preventDefault();
|
||||||
|
close();
|
||||||
|
} else if (e.key === 'Tab' && panelEl) {
|
||||||
|
const focusables = Array.from(
|
||||||
|
panelEl.querySelectorAll<HTMLElement>(
|
||||||
|
'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])'
|
||||||
|
)
|
||||||
|
).filter((el) => el.offsetParent !== null);
|
||||||
|
if (focusables.length === 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const first = focusables[0];
|
||||||
|
const last = focusables[focusables.length - 1];
|
||||||
|
const active = document.activeElement as HTMLElement | null;
|
||||||
|
if (e.shiftKey) {
|
||||||
|
if (active === first || !panelEl.contains(active)) {
|
||||||
|
e.preventDefault();
|
||||||
|
last.focus();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (active === last) {
|
||||||
|
e.preventDefault();
|
||||||
|
first.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (open) {
|
||||||
|
lastActive = document.activeElement;
|
||||||
|
tick().then(() => {
|
||||||
|
panelEl?.focus();
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
if (lastActive instanceof HTMLElement) {
|
||||||
|
tick().then(() => lastActive?.focus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if open}
|
||||||
|
<div class="popover-overlay" on:click={close} />
|
||||||
|
<div
|
||||||
|
class="popover-panel"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
{id}
|
||||||
|
aria-label={ariaLabel}
|
||||||
|
tabindex="-1"
|
||||||
|
bind:this={panelEl}
|
||||||
|
on:keydown={handleKeydown}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.popover-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.35);
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.popover-panel {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1001;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
max-width: min(420px, 92vw);
|
||||||
|
width: 92vw;
|
||||||
|
background: var(--color-surface);
|
||||||
|
color: var(--color-text);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
padding: 12px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
.popover-overlay {
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
export function normalizeDigits(input: string | null | undefined): string {
|
||||||
|
return String(input ?? '').replace(/\D+/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildWaMeUrl(input: string): string {
|
||||||
|
const digits = normalizeDigits(input);
|
||||||
|
return `https://wa.me/${digits}`;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue