Fix share-link serialization and tooltip positioning
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
let val2 = '';
|
||||
let val3 = '';
|
||||
let activeField: 1 | 2 | 3 = 1;
|
||||
let swapState: { originalField: 1 | 2; originalValue: string } | null = null;
|
||||
let swapState: { originalField: 1 | 2; originalValue: string | number | null } | null = null;
|
||||
let copyStatus: 'idle' | 'copied' | 'failed' = 'idle';
|
||||
let statusTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
let tooltipFadeTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
@@ -23,6 +23,8 @@
|
||||
let showCopyTooltip = false;
|
||||
let isTooltipFading = false;
|
||||
let showHoverTooltip = false;
|
||||
let footerControlsEl: HTMLDivElement | null = null;
|
||||
let tooltipX = 20;
|
||||
let copyStatusMessage = '';
|
||||
|
||||
$: has3 = ['3col', '3col-mul'].includes(config.type) || !!config.labels.in3;
|
||||
@@ -75,21 +77,27 @@
|
||||
|
||||
function buildShareUrl() {
|
||||
const params = new URLSearchParams();
|
||||
if (val1.trim()) {
|
||||
params.set('v1', val1);
|
||||
}
|
||||
if (val2.trim()) {
|
||||
params.set('v2', val2);
|
||||
}
|
||||
if (val3.trim() && has3) {
|
||||
params.set('v3', val3);
|
||||
}
|
||||
const v1 = toQueryValue(val1);
|
||||
const v2 = toQueryValue(val2);
|
||||
const v3 = toQueryValue(val3);
|
||||
|
||||
if (v1 !== null) params.set('v1', v1);
|
||||
if (v2 !== null) params.set('v2', v2);
|
||||
if (has3 && v3 !== null) params.set('v3', v3);
|
||||
|
||||
const shareUrl = new URL($page.url);
|
||||
shareUrl.search = params.toString();
|
||||
return shareUrl.toString();
|
||||
}
|
||||
|
||||
function toQueryValue(value: unknown): string | null {
|
||||
if (value === null || value === undefined) {
|
||||
return null;
|
||||
}
|
||||
const stringValue = String(value);
|
||||
return stringValue.trim() ? stringValue : null;
|
||||
}
|
||||
|
||||
async function copyText(text: string) {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
@@ -125,6 +133,21 @@
|
||||
}, 1300);
|
||||
}
|
||||
|
||||
function updateTooltipPosition(event: MouseEvent) {
|
||||
if (!footerControlsEl) return;
|
||||
const rect = footerControlsEl.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
tooltipX = Math.max(12, Math.min(rect.width - 12, x));
|
||||
}
|
||||
|
||||
function positionTooltipFromButton(button: HTMLButtonElement) {
|
||||
if (!footerControlsEl) return;
|
||||
const controlsRect = footerControlsEl.getBoundingClientRect();
|
||||
const buttonRect = button.getBoundingClientRect();
|
||||
const centerX = buttonRect.left - controlsRect.left + buttonRect.width / 2;
|
||||
tooltipX = Math.max(12, Math.min(controlsRect.width - 12, centerX));
|
||||
}
|
||||
|
||||
async function copyLink() {
|
||||
if (!browser) return;
|
||||
const url = buildShareUrl();
|
||||
@@ -237,17 +260,27 @@
|
||||
</div>
|
||||
|
||||
<div class="calc-footer">
|
||||
<div class="footer-controls">
|
||||
<div class="footer-controls" bind:this={footerControlsEl}>
|
||||
<button type="button" class="clear-btn" on:click={clear} aria-label="Clear calculator inputs">
|
||||
Clear
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="icon-btn"
|
||||
on:click={copyLink}
|
||||
on:mouseenter={() => (showHoverTooltip = true)}
|
||||
on:click={(event) => {
|
||||
positionTooltipFromButton(event.currentTarget as HTMLButtonElement);
|
||||
copyLink();
|
||||
}}
|
||||
on:mouseenter={(event) => {
|
||||
showHoverTooltip = true;
|
||||
updateTooltipPosition(event);
|
||||
}}
|
||||
on:mousemove={updateTooltipPosition}
|
||||
on:mouseleave={() => (showHoverTooltip = false)}
|
||||
on:focus={() => (showHoverTooltip = true)}
|
||||
on:focus={(event) => {
|
||||
showHoverTooltip = true;
|
||||
positionTooltipFromButton(event.currentTarget as HTMLButtonElement);
|
||||
}}
|
||||
on:blur={() => (showHoverTooltip = false)}
|
||||
aria-label="Copy calculator link"
|
||||
>
|
||||
@@ -263,10 +296,10 @@
|
||||
</svg>
|
||||
</button>
|
||||
{#if showHoverTooltip && !showCopyTooltip}
|
||||
<span class="copy-tooltip hover">Copy link</span>
|
||||
<span class="copy-tooltip hover" style={`left: ${tooltipX}px;`}>Copy link</span>
|
||||
{/if}
|
||||
{#if showCopyTooltip && copyStatus === 'copied'}
|
||||
<span class="copy-tooltip" class:fading={isTooltipFading}>Link copied!</span>
|
||||
<span class="copy-tooltip" class:fading={isTooltipFading} style={`left: ${tooltipX}px;`}>Link copied!</span>
|
||||
{/if}
|
||||
<span class="sr-only" aria-live="polite">
|
||||
{copyStatusMessage}
|
||||
@@ -465,8 +498,7 @@
|
||||
}
|
||||
.copy-tooltip {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.4rem);
|
||||
right: 0;
|
||||
bottom: calc(100% + 0.4rem);
|
||||
background: color-mix(in srgb, var(--accent) 90%, black 10%);
|
||||
color: #fff;
|
||||
border-radius: 6px;
|
||||
@@ -476,7 +508,7 @@
|
||||
letter-spacing: 0.02em;
|
||||
pointer-events: none;
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transform: translate(-50%, 0);
|
||||
transition: opacity 0.35s ease, transform 0.35s ease;
|
||||
white-space: nowrap;
|
||||
z-index: 2;
|
||||
@@ -488,7 +520,7 @@
|
||||
}
|
||||
.copy-tooltip.fading {
|
||||
opacity: 0;
|
||||
transform: translateY(-0.2rem);
|
||||
transform: translate(-50%, -0.2rem);
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
|
||||
Reference in New Issue
Block a user