711f218622
Comprehensive pre-production sweep across the Aurora redesign — drives svelte-check to 0 errors / 0 warnings (was 61) without changing visual intent. Highlights: - Mobile: hero title shrinks at 480px, signal-list stacks timestamp under sentence below 640px, sidebar icon buttons bumped to 40x40 - Light theme: muted-foreground darkened to #3a3560 to clear WCAG AA on glass surfaces and the modal close button - Perf: topbar backdrop-filter 28→14px, mobile-more sheet 28→12px to cut concurrent blur layers on mid-tier mobile - a11y: prefers-reduced-motion mute for aurora drift / pulses / shimmer / stagger; aria-label on every icon-only button; aria-describedby on Hint; combobox/listbox/aria-activedescendant on SearchPalette; modal dialog tabindex; 47 label-without-control warnings across 14 form pages cleaned up via for=/id= or label→div - Dashboard derived state split into topology- vs status-bound layers so polling no longer re-runs the full provider/wires computation - Mobile bottom nav derived from baseNavEntries by key lookup so adding a top-level nav entry keeps the two trees in sync - Bug: template-configs page now respects the global provider filter for both the count meter and the type pill (was reading the unfiltered cache) - Misc: portal EventChart tooltip and switch its swatches to Aurora tokens; CollapsibleSlot warning state uses warning-fg/-bg tokens instead of #d97706; Hint z-index 99999→9999; element refs across Modal/EntitySelect/MultiEntitySelect/SearchPalette/IconGridSelect/ Hint/targets converted to \$state for reactivity; 4 dead .topbar-cta selectors removed
73 lines
2.2 KiB
Svelte
73 lines
2.2 KiB
Svelte
<script lang="ts">
|
|
import { portal } from '$lib/portal';
|
|
|
|
let { text = '' } = $props<{ text: string }>();
|
|
let visible = $state(false);
|
|
let tooltipStyle = $state('');
|
|
let btnEl = $state<HTMLButtonElement | undefined>();
|
|
const tooltipId = `hint-${Math.random().toString(36).slice(2, 9)}`;
|
|
|
|
function show() {
|
|
if (!btnEl) return;
|
|
visible = true;
|
|
const rect = btnEl.getBoundingClientRect();
|
|
const tooltipWidth = 272;
|
|
let left = rect.left + rect.width / 2 - tooltipWidth / 2;
|
|
if (left < 8) left = 8;
|
|
if (left + tooltipWidth > window.innerWidth - 8) left = window.innerWidth - tooltipWidth - 8;
|
|
tooltipStyle = `position:fixed; z-index:9999; bottom:${window.innerHeight - rect.top + 8}px; left:${left}px; width:${tooltipWidth}px;`;
|
|
}
|
|
|
|
function hide() {
|
|
visible = false;
|
|
}
|
|
</script>
|
|
|
|
<button type="button" bind:this={btnEl}
|
|
class="hint-btn inline-flex items-center justify-center w-4 h-4 rounded-full text-[11px] font-bold leading-none
|
|
focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--color-primary)]
|
|
transition-colors cursor-help align-middle ml-2 flex-shrink-0"
|
|
onmouseenter={show}
|
|
onmouseleave={hide}
|
|
onfocus={show}
|
|
onblur={hide}
|
|
aria-label={text}
|
|
aria-describedby={visible ? tooltipId : undefined}
|
|
title={text}
|
|
tabindex="0"
|
|
>?</button>
|
|
|
|
{#if visible}
|
|
<div use:portal>
|
|
<div id={tooltipId} role="tooltip" style={tooltipStyle} class="hint-tooltip">
|
|
{text}
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
|
|
<style>
|
|
.hint-btn {
|
|
border: 1px solid var(--color-border);
|
|
background: var(--color-glass-strong);
|
|
color: var(--color-muted-foreground);
|
|
}
|
|
.hint-btn:hover {
|
|
background: var(--color-glass-elev);
|
|
color: var(--color-foreground);
|
|
border-color: var(--color-rule-strong);
|
|
}
|
|
.hint-tooltip {
|
|
background: var(--hint-solid-bg, #131520);
|
|
color: var(--color-foreground);
|
|
border: 1px solid var(--color-rule-strong);
|
|
box-shadow: var(--shadow-card), 0 12px 30px -10px rgba(0, 0, 0, 0.5);
|
|
padding: 0.7rem 0.85rem;
|
|
border-radius: 12px;
|
|
font-size: 0.8125rem;
|
|
white-space: normal;
|
|
line-height: 1.55;
|
|
pointer-events: none;
|
|
}
|
|
:global([data-theme="light"]) .hint-tooltip { --hint-solid-bg: #fafafe; }
|
|
</style>
|