mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-31 15:43:25 +00:00
fix layout shift
This commit is contained in:
26
website/src/lib/components/ButtonWithTooltip.svelte
Normal file
26
website/src/lib/components/ButtonWithTooltip.svelte
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Button } from '$lib/components/ui/button/index.js';
|
||||||
|
import * as Tooltip from '$lib/components/ui/tooltip/index.js';
|
||||||
|
|
||||||
|
export let variant:
|
||||||
|
| 'default'
|
||||||
|
| 'secondary'
|
||||||
|
| 'link'
|
||||||
|
| 'destructive'
|
||||||
|
| 'outline'
|
||||||
|
| 'ghost'
|
||||||
|
| undefined = 'default';
|
||||||
|
export let label: string;
|
||||||
|
export let side: 'top' | 'right' | 'bottom' | 'left' = 'top';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Tooltip.Root>
|
||||||
|
<Tooltip.Trigger asChild let:builder>
|
||||||
|
<Button builders={[builder]} {variant} {...$$restProps}>
|
||||||
|
<slot />
|
||||||
|
</Button>
|
||||||
|
</Tooltip.Trigger>
|
||||||
|
<Tooltip.Content {side}>
|
||||||
|
<span>{label}</span>
|
||||||
|
</Tooltip.Content>
|
||||||
|
</Tooltip.Root>
|
@@ -4,6 +4,7 @@
|
|||||||
import { Label } from '$lib/components/ui/label/index.js';
|
import { Label } from '$lib/components/ui/label/index.js';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import Help from '$lib/components/Help.svelte';
|
import Help from '$lib/components/Help.svelte';
|
||||||
|
import ButtonWithTooltip from '$lib/components/ButtonWithTooltip.svelte';
|
||||||
import Tooltip from '$lib/components/Tooltip.svelte';
|
import Tooltip from '$lib/components/Tooltip.svelte';
|
||||||
import Shortcut from '$lib/components/Shortcut.svelte';
|
import Shortcut from '$lib/components/Shortcut.svelte';
|
||||||
import {
|
import {
|
||||||
@@ -105,7 +106,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if minimized}
|
{#if minimizable && minimized}
|
||||||
<div class="-m-1.5 -mb-2">
|
<div class="-m-1.5 -mb-2">
|
||||||
<Button variant="ghost" class="px-1 h-[26px]" on:click={() => (minimized = false)}>
|
<Button variant="ghost" class="px-1 h-[26px]" on:click={() => (minimized = false)}>
|
||||||
<SquareArrowOutDownRight size="18" />
|
<SquareArrowOutDownRight size="18" />
|
||||||
@@ -116,24 +117,24 @@
|
|||||||
class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}"
|
class="flex flex-col gap-3 w-full max-w-80 {$$props.class ?? ''}"
|
||||||
in:flyAndScale={{ x: -2, y: 0, duration: 50 }}
|
in:flyAndScale={{ x: -2, y: 0, duration: 50 }}
|
||||||
>
|
>
|
||||||
<div class="grow flex flex-col gap-3">
|
<div class="flex flex-col gap-3">
|
||||||
<Tooltip label={$_('toolbar.routing.use_routing_tooltip')}>
|
<Label class="flex flex-row justify-between items-center gap-2">
|
||||||
<Label class="w-full flex flex-row justify-between items-center gap-2">
|
<span class="flex flex-row items-center gap-1">
|
||||||
<span class="flex flex-row gap-1">
|
{#if $routing}
|
||||||
{#if $routing}
|
<Route size="16" />
|
||||||
<Route size="16" />
|
{:else}
|
||||||
{:else}
|
<RouteOff size="16" />
|
||||||
<RouteOff size="16" />
|
{/if}
|
||||||
{/if}
|
{$_('toolbar.routing.use_routing')}
|
||||||
{$_('toolbar.routing.use_routing')}
|
</span>
|
||||||
</span>
|
<Tooltip label={$_('toolbar.routing.use_routing_tooltip')}>
|
||||||
<Switch class="scale-90" bind:checked={$routing} />
|
<Switch class="scale-90" bind:checked={$routing} />
|
||||||
</Label>
|
<Shortcut slot="extra" key="F5" />
|
||||||
<Shortcut slot="extra" key="F5" />
|
</Tooltip>
|
||||||
</Tooltip>
|
</Label>
|
||||||
{#if $routing}
|
{#if $routing}
|
||||||
<div class="flex flex-col gap-3" in:slide>
|
<div class="flex flex-col gap-3" in:slide>
|
||||||
<Label class="w-full flex flex-row justify-between items-center gap-2">
|
<Label class="flex flex-row justify-between items-center gap-2">
|
||||||
<span class="shrink-0 flex flex-row items-center gap-1">
|
<span class="shrink-0 flex flex-row items-center gap-1">
|
||||||
{#if $routingProfileSelectItem.value.includes('bike') || $routingProfileSelectItem.value.includes('motorcycle')}
|
{#if $routingProfileSelectItem.value.includes('bike') || $routingProfileSelectItem.value.includes('motorcycle')}
|
||||||
<Bike size="16" />
|
<Bike size="16" />
|
||||||
@@ -159,72 +160,70 @@
|
|||||||
</Select.Content>
|
</Select.Content>
|
||||||
</Select.Root>
|
</Select.Root>
|
||||||
</Label>
|
</Label>
|
||||||
<Label class="w-full flex flex-row justify-between items-center gap-2">
|
<Label class="flex flex-row justify-between items-center gap-2">
|
||||||
<span class="flex flex-row gap-1"
|
<span class="flex flex-row gap-1">
|
||||||
><TriangleAlert size="16" />{$_('toolbar.routing.allow_private')}</span
|
<TriangleAlert size="16" />
|
||||||
>
|
{$_('toolbar.routing.allow_private')}
|
||||||
|
</span>
|
||||||
<Switch class="scale-90" bind:checked={$privateRoads} />
|
<Switch class="scale-90" bind:checked={$privateRoads} />
|
||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row flex-wrap justify-center gap-1">
|
<div class="flex flex-row flex-wrap justify-center gap-1">
|
||||||
<Tooltip label={$_('toolbar.routing.reverse.tooltip')}>
|
<ButtonWithTooltip
|
||||||
<Button
|
label={$_('toolbar.routing.reverse.tooltip')}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="flex flex-row gap-1 text-xs px-2"
|
class="flex flex-row gap-1 text-xs px-2"
|
||||||
disabled={!validSelection}
|
disabled={!validSelection}
|
||||||
on:click={dbUtils.reverseSelection}
|
on:click={dbUtils.reverseSelection}
|
||||||
>
|
>
|
||||||
<ArrowRightLeft size="12" />{$_('toolbar.routing.reverse.button')}
|
<ArrowRightLeft size="12" />{$_('toolbar.routing.reverse.button')}
|
||||||
</Button>
|
</ButtonWithTooltip>
|
||||||
</Tooltip>
|
<ButtonWithTooltip
|
||||||
<Tooltip label={$_('toolbar.routing.route_back_to_start.tooltip')}>
|
label={$_('toolbar.routing.route_back_to_start.tooltip')}
|
||||||
<Button
|
variant="outline"
|
||||||
variant="outline"
|
class="flex flex-row gap-1 text-xs px-2"
|
||||||
class="flex flex-row gap-1 text-xs px-2"
|
disabled={!validSelection}
|
||||||
disabled={!validSelection}
|
on:click={() => {
|
||||||
on:click={() => {
|
const selected = getOrderedSelection();
|
||||||
const selected = getOrderedSelection();
|
if (selected.length > 0) {
|
||||||
if (selected.length > 0) {
|
const firstFileId = selected[0].getFileId();
|
||||||
const firstFileId = selected[0].getFileId();
|
const firstFile = getFile(firstFileId);
|
||||||
const firstFile = getFile(firstFileId);
|
if (firstFile) {
|
||||||
if (firstFile) {
|
let start = (() => {
|
||||||
let start = (() => {
|
if (selected[0] instanceof ListFileItem) {
|
||||||
if (selected[0] instanceof ListFileItem) {
|
return firstFile.trk[0]?.trkseg[0]?.trkpt[0];
|
||||||
return firstFile.trk[0]?.trkseg[0]?.trkpt[0];
|
} else if (selected[0] instanceof ListTrackItem) {
|
||||||
} else if (selected[0] instanceof ListTrackItem) {
|
return firstFile.trk[selected[0].getTrackIndex()]?.trkseg[0]?.trkpt[0];
|
||||||
return firstFile.trk[selected[0].getTrackIndex()]?.trkseg[0]?.trkpt[0];
|
} else if (selected[0] instanceof ListTrackSegmentItem) {
|
||||||
} else if (selected[0] instanceof ListTrackSegmentItem) {
|
return firstFile.trk[selected[0].getTrackIndex()]?.trkseg[
|
||||||
return firstFile.trk[selected[0].getTrackIndex()]?.trkseg[
|
selected[0].getSegmentIndex()
|
||||||
selected[0].getSegmentIndex()
|
]?.trkpt[0];
|
||||||
]?.trkpt[0];
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (start !== undefined) {
|
|
||||||
const lastFileId = selected[selected.length - 1].getFileId();
|
|
||||||
routingControls
|
|
||||||
.get(lastFileId)
|
|
||||||
?.appendAnchorWithCoordinates(start.getCoordinates());
|
|
||||||
}
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (start !== undefined) {
|
||||||
|
const lastFileId = selected[selected.length - 1].getFileId();
|
||||||
|
routingControls
|
||||||
|
.get(lastFileId)
|
||||||
|
?.appendAnchorWithCoordinates(start.getCoordinates());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}}
|
}
|
||||||
>
|
}}
|
||||||
<Home size="12" />{$_('toolbar.routing.route_back_to_start.button')}
|
>
|
||||||
</Button>
|
<Home size="12" />{$_('toolbar.routing.route_back_to_start.button')}
|
||||||
</Tooltip>
|
</ButtonWithTooltip>
|
||||||
<Tooltip label={$_('toolbar.routing.round_trip.tooltip')}>
|
<ButtonWithTooltip
|
||||||
<Button
|
label={$_('toolbar.routing.round_trip.tooltip')}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="flex flex-row gap-1 text-xs px-2"
|
class="flex flex-row gap-1 text-xs px-2"
|
||||||
disabled={!validSelection}
|
disabled={!validSelection}
|
||||||
on:click={dbUtils.createRoundTripForSelection}
|
on:click={dbUtils.createRoundTripForSelection}
|
||||||
>
|
>
|
||||||
<Repeat size="12" />{$_('toolbar.routing.round_trip.button')}
|
<Repeat size="12" />{$_('toolbar.routing.round_trip.button')}
|
||||||
</Button>
|
</ButtonWithTooltip>
|
||||||
</Tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex flex-row gap-2 items-end justify-between">
|
<div class="w-full flex flex-row gap-2 items-end justify-between">
|
||||||
<Help link={getURLForLanguage($locale, '/help/toolbar/routing')}>
|
<Help link={getURLForLanguage($locale, '/help/toolbar/routing')}>
|
||||||
|
Reference in New Issue
Block a user