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