Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 40 additions & 28 deletions src/lib/components/Tooltip.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,8 @@
break;
}

// Clamp horizontal position to keep tooltip within viewport
if (finalPosition === 'bottom' || finalPosition === 'top') {
const halfWidth = tooltipMaxWidth / 2;
if (x - halfWidth < padding) {
x = padding + halfWidth;
} else if (x + halfWidth > window.innerWidth - padding) {
x = window.innerWidth - padding - halfWidth;
}
}

// Clamp vertical position for left/right tooltips
if (finalPosition === 'left' || finalPosition === 'right') {
const halfHeight = tooltipHeight / 2;
if (y - halfHeight < padding) {
y = padding + halfHeight;
} else if (y + halfHeight > window.innerHeight - padding) {
y = window.innerHeight - padding - halfHeight;
}
}

// Viewport clamping happens in the component after render,
// where the actual tooltip dimensions can be measured.
tooltipStore.set({ text, shortcut, maxWidth, x, y, visible: true, position: finalPosition });
}, 50);
}
Expand Down Expand Up @@ -152,21 +134,51 @@
</script>

<script lang="ts">
let state = $state<TooltipState>({ text: '', x: 0, y: 0, visible: false, position: 'bottom' });
let tip = $state<TooltipState>({ text: '', x: 0, y: 0, visible: false, position: 'bottom' });
let tooltipEl = $state<HTMLDivElement>();

tooltipStore.subscribe((s) => {
state = s;
tip = s;
});

// Clamp the rendered tooltip to the viewport using its measured size,
// so narrow tooltips sit flush at the edges instead of being pushed
// inward by a max-width estimate.
$effect(() => {
if (!tip.visible || !tooltipEl) return;
void tip.text; void tip.shortcut; void tip.position;
const padding = 8; // Minimum distance from viewport edge
// Measure from the unclamped anchor position — a previous run may
// have shifted the element while Svelte skipped the style attribute.
tooltipEl.style.left = `${tip.x}px`;
tooltipEl.style.top = `${tip.y}px`;
const rect = tooltipEl.getBoundingClientRect();
let dx = 0;
let dy = 0;
if (rect.left < padding) {
dx = padding - rect.left;
} else if (rect.right > window.innerWidth - padding) {
dx = window.innerWidth - padding - rect.right;
}
if (rect.top < padding) {
dy = padding - rect.top;
} else if (rect.bottom > window.innerHeight - padding) {
dy = window.innerHeight - padding - rect.bottom;
}
if (dx !== 0) tooltipEl.style.left = `${tip.x + dx}px`;
if (dy !== 0) tooltipEl.style.top = `${tip.y + dy}px`;
});
</script>

{#if state.visible}
{#if tip.visible}
<div
class="tooltip tooltip-{state.position}"
style="left: {state.x}px; top: {state.y}px;{state.maxWidth ? ` max-width: ${state.maxWidth}px;` : ''}"
bind:this={tooltipEl}
class="tooltip tooltip-{tip.position}"
style="left: {tip.x}px; top: {tip.y}px;{tip.maxWidth ? ` max-width: ${tip.maxWidth}px;` : ''}"
>
<span class="text">{state.text}</span>
{#if state.shortcut}
<span class="shortcut">{state.shortcut}</span>
<span class="text">{tip.text}</span>
{#if tip.shortcut}
<span class="shortcut">{tip.shortcut}</span>
{/if}
</div>
{/if}
Expand Down
27 changes: 0 additions & 27 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -1366,11 +1366,6 @@
</div>
</header>

<!-- Logo overlay: stays over the canvas, below the fixed nav. -->
<button class="logo-overlay" onclick={() => showWelcomeModal = true} use:tooltip={"Welcome"} aria-label="Welcome">
<img src="{base}/{BRAND.logo}" alt="{BRAND.name}" />
</button>

<!-- Canvas takes full screen -->
<div class="canvas-layer">
<FlowCanvas />
Expand Down Expand Up @@ -1840,27 +1835,6 @@
.editor-nav .brand { margin-right: var(--space-xs); }
/* Push the top-anchored floating overlays below the fixed nav. */
.app.has-nav .subsystem-breadcrumb { top: calc(var(--space-md) + var(--header-height)); }
.app.has-nav .logo-overlay { top: calc(var(--space-md) + var(--header-height)); }

/* Logo overlay — stays over the canvas, below the fixed nav. */
.logo-overlay {
position: fixed;
top: var(--space-md);
left: var(--space-md);
z-index: 100;
background: none;
border: none;
padding: 0;
cursor: pointer;
}
.logo-overlay img {
height: 44px;
width: auto;
transition: opacity var(--transition-fast);
}
.logo-overlay:hover img {
opacity: 0.8;
}

.toolbar-btn {
width: var(--header-height);
Expand Down Expand Up @@ -2064,7 +2038,6 @@
pointer-events: none;
}

/* Logo overlay */
/* Subsystem breadcrumb navigation */
.subsystem-breadcrumb {
position: fixed;
Expand Down