Fixed progress bar overflow with floating tooltip action
This commit is contained in:
+29
@@ -27,3 +27,32 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
min-height: 100svh;
|
min-height: 100svh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tooltip-floating {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9999;
|
||||||
|
background: var(--surface);
|
||||||
|
color: var(--text);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
||||||
|
font-family: var(--sans);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 400;
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0.45em 0.9em;
|
||||||
|
border-radius: 8px;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(4px);
|
||||||
|
transition: opacity 0.15s ease, transform 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-floating::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
border: 6px solid transparent;
|
||||||
|
border-top-color: var(--border);
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,44 @@
|
|||||||
import { enqueue } from '$lib/download-pool.js';
|
import { enqueue } from '$lib/download-pool.js';
|
||||||
import type { Station, Measurement } from '$lib/types.js';
|
import type { Station, Measurement } from '$lib/types.js';
|
||||||
|
|
||||||
|
function floatingTooltip(node: HTMLElement, text: string) {
|
||||||
|
let el: HTMLDivElement | null = null;
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
if (!text) return;
|
||||||
|
const rect = node.getBoundingClientRect();
|
||||||
|
el = document.createElement('div');
|
||||||
|
el.className = 'tooltip-floating';
|
||||||
|
el.textContent = text;
|
||||||
|
document.body.appendChild(el);
|
||||||
|
el.style.top = `${rect.top - el.offsetHeight - 10}px`;
|
||||||
|
el.style.left = `${rect.left + rect.width / 2 - el.offsetWidth / 2}px`;
|
||||||
|
void el.offsetHeight; // force reflow prima della transizione
|
||||||
|
el.style.opacity = '1';
|
||||||
|
el.style.transform = 'translateY(0)';
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
if (!el) return;
|
||||||
|
const target = el;
|
||||||
|
el = null;
|
||||||
|
target.style.opacity = '0';
|
||||||
|
target.style.transform = 'translateY(4px)';
|
||||||
|
target.addEventListener('transitionend', () => target.remove(), { once: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
node.addEventListener('mouseenter', show);
|
||||||
|
node.addEventListener('mouseleave', hide);
|
||||||
|
return {
|
||||||
|
update(t: string) { text = t; },
|
||||||
|
destroy() {
|
||||||
|
node.removeEventListener('mouseenter', show);
|
||||||
|
node.removeEventListener('mouseleave', hide);
|
||||||
|
hide();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let { station }: { station: Station } = $props();
|
let { station }: { station: Station } = $props();
|
||||||
|
|
||||||
const formatDate = (d: string) => new Intl.DateTimeFormat('it-IT', {
|
const formatDate = (d: string) => new Intl.DateTimeFormat('it-IT', {
|
||||||
@@ -99,12 +137,12 @@
|
|||||||
<div class="right">
|
<div class="right">
|
||||||
<span class="date">Attivata il {createdDate}</span>
|
<span class="date">Attivata il {createdDate}</span>
|
||||||
<span class="sep">·</span>
|
<span class="sep">·</span>
|
||||||
<span class="status" class:active={isActive} class:ended={!isActive}>
|
<span
|
||||||
{isActive ? 'Attiva' : 'Terminata'}
|
class="status"
|
||||||
{#if !isActive}
|
class:active={isActive}
|
||||||
<span class="tooltip">Terminata il {endDate}</span>
|
class:ended={!isActive}
|
||||||
{/if}
|
use:floatingTooltip={!isActive ? `Terminata il ${endDate}` : ''}
|
||||||
</span>
|
>{isActive ? 'Attiva' : 'Terminata'}</span>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -153,6 +191,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 1.25rem;
|
gap: 1.25rem;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
@@ -272,39 +311,6 @@
|
|||||||
color: var(--text-dim);
|
color: var(--text-dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
position: absolute;
|
|
||||||
bottom: calc(100% + 16px);
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
background: var(--surface);
|
|
||||||
color: var(--text);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
|
||||||
font-size: 0.85rem;
|
|
||||||
font-weight: 400;
|
|
||||||
white-space: nowrap;
|
|
||||||
padding: 0.45em 0.9em;
|
|
||||||
border-radius: 8px;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status:hover .tooltip {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
border: 6px solid transparent;
|
|
||||||
border-top-color: var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bar-wrap {
|
.bar-wrap {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
@@ -312,7 +318,6 @@
|
|||||||
right: 0;
|
right: 0;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
background: var(--border);
|
background: var(--border);
|
||||||
border-radius: 0 0 14px 14px;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user