mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-09 21:07:46 +00:00
update
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils/classnames';
|
||||
import { slugify } from '$lib/utils/slugify';
|
||||
import { Tooltip } from 'bits-ui';
|
||||
import { latLongToSvgPosition } from './utils/projections';
|
||||
import { tooltipData } from './map-tooltip.svelte';
|
||||
|
||||
interface Props {
|
||||
city: string;
|
||||
@@ -16,7 +16,7 @@
|
||||
west: number;
|
||||
east: number;
|
||||
};
|
||||
available?: boolean;
|
||||
available: boolean;
|
||||
class?: string;
|
||||
animate?: boolean;
|
||||
isOpen: boolean;
|
||||
@@ -28,22 +28,32 @@
|
||||
index = 0,
|
||||
lat,
|
||||
lng,
|
||||
available = false,
|
||||
class: className = '',
|
||||
available,
|
||||
animate = false,
|
||||
isOpen = false
|
||||
}: Props = $props();
|
||||
|
||||
const position = $derived(latLongToSvgPosition({ latitude: lat, longitude: lng }));
|
||||
|
||||
let open = $state(isOpen);
|
||||
|
||||
$effect(() => {
|
||||
open = isOpen;
|
||||
const handleSetActiveMarker = () => {
|
||||
tooltipData.set({
|
||||
city,
|
||||
code,
|
||||
available
|
||||
});
|
||||
};
|
||||
|
||||
const handleResetActiveMarker = () => {
|
||||
console.log('reset');
|
||||
// tooltipData.set({
|
||||
// city: null,
|
||||
// code: null,
|
||||
// available: null
|
||||
// });
|
||||
};
|
||||
</script>
|
||||
|
||||
<div
|
||||
<button
|
||||
class={classNames(
|
||||
'group absolute z-10 flex size-2 cursor-pointer items-center justify-center opacity-0 [animation-delay:var(--delay)]',
|
||||
{ 'animate-fade-in': animate }
|
||||
@@ -51,6 +61,11 @@
|
||||
style="left: {position.x}%; top: {position.y}%;--delay: {index * 10}ms;"
|
||||
data-region={slugify(city)}
|
||||
data-active={isOpen}
|
||||
onmouseenter={handleSetActiveMarker}
|
||||
onfocus={handleSetActiveMarker}
|
||||
onmouseout={handleResetActiveMarker}
|
||||
onblur={handleResetActiveMarker}
|
||||
aria-label={city}
|
||||
>
|
||||
<span
|
||||
class="from-accent/20 to-accent/10 border-gradient ease-spring absolute inline-flex h-5 w-5 rounded-full bg-gradient-to-b opacity-0 transition-opacity group-hover:animate-ping group-hover:opacity-75 before:rounded-full"
|
||||
@@ -58,30 +73,4 @@
|
||||
></span>
|
||||
<span class="bg-accent absolute inline-flex h-full w-full rounded-full"></span>
|
||||
<span class="absolute size-1/2 rounded-full bg-white/80 transition-all"></span>
|
||||
</div>
|
||||
|
||||
<!-- <div
|
||||
class={classNames(
|
||||
'bg-card/90 border-gradient relative z-100 flex w-[190px] flex-col gap-2 rounded-[10px] p-2 backdrop-blur-lg before:rounded-[10px] after:rounded-[10px]',
|
||||
'data-[state="closed"]:animate-menu-out data-[state="instant-open"]:animate-menu-in data-[state="delayed-open"]:animate-menu-in',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<span class="text-primary text-caption w-fit">
|
||||
{city}
|
||||
({code})
|
||||
</span>
|
||||
{#if available}
|
||||
<div
|
||||
class="text-caption flex h-5 items-center justify-center place-self-start rounded-md bg-[#10B981]/24 p-1 text-center text-[#B4F8E2]"
|
||||
>
|
||||
<span class="text-micro -tracking-tight">Available now</span>
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="text-caption flex h-5 items-center justify-center place-self-start rounded-md bg-white/6 p-1 text-center text-white/60"
|
||||
>
|
||||
<span class="text-micro -tracking-tight">Planned</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div> -->
|
||||
</button>
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
<script lang="ts" module>
|
||||
import { classNames } from '$lib/utils/classnames';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const tooltipData = writable<{
|
||||
city: string | null;
|
||||
code: string | null;
|
||||
available: boolean | null;
|
||||
}>({
|
||||
city: null,
|
||||
code: null,
|
||||
available: null
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
type Props = {
|
||||
coords: {
|
||||
@@ -6,7 +21,38 @@
|
||||
};
|
||||
};
|
||||
|
||||
const { coords } = $props();
|
||||
const { coords }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div style:left="{coords.x}px" style:top="{coords.y}px">Tooltip</div>
|
||||
{#if $tooltipData.city}
|
||||
<div
|
||||
class="pointer-events-none absolute"
|
||||
style:left="{coords.x + 10}px"
|
||||
style:top="{coords.y - 25}px"
|
||||
>
|
||||
<div
|
||||
class={classNames(
|
||||
'bg-card/90 border-gradient relative z-100 flex w-[190px] flex-col gap-2 rounded-[10px] p-2 backdrop-blur-lg before:rounded-[10px] after:rounded-[10px]',
|
||||
'data-[state="closed"]:animate-menu-out data-[state="instant-open"]:animate-menu-in data-[state="delayed-open"]:animate-menu-in'
|
||||
)}
|
||||
>
|
||||
<span class="text-primary text-caption w-fit">
|
||||
{$tooltipData.city}
|
||||
({$tooltipData.code})
|
||||
</span>
|
||||
{#if $tooltipData.available}
|
||||
<div
|
||||
class="text-caption flex h-5 items-center justify-center place-self-start rounded-md bg-[#10B981]/24 p-1 text-center text-[#B4F8E2]"
|
||||
>
|
||||
<span class="text-micro -tracking-tight">Available now</span>
|
||||
</div>
|
||||
{:else}
|
||||
<div
|
||||
class="text-caption flex h-5 items-center justify-center place-self-start rounded-md bg-white/6 p-1 text-center text-white/60"
|
||||
>
|
||||
<span class="text-micro -tracking-tight">Planned</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -11,12 +11,10 @@
|
||||
import MapMarker from './map-marker.svelte';
|
||||
import { slugify } from '$lib/utils/slugify';
|
||||
import { classNames } from '$lib/utils/classnames';
|
||||
import { Tooltip } from 'bits-ui';
|
||||
import MapNav from './map-nav.svelte';
|
||||
import { useMousePosition } from '$lib/actions/mouse-position';
|
||||
import { useAnimateInView } from '$lib/actions/animate-in-view';
|
||||
import { pins, type PinSegment } from './data/pins';
|
||||
import { latLongToSvgPosition } from './utils/projections';
|
||||
import MapTooltip from './map-tooltip.svelte';
|
||||
|
||||
let dimensions = $state({
|
||||
@@ -123,15 +121,13 @@
|
||||
alt="Map of the world"
|
||||
/>
|
||||
|
||||
{#each pins[activeSegment as PinSegment].map( (pin) => ({ ...pin, isOpen: activeRegion === slugify(pin.city), position: latLongToSvgPosition( { latitude: pin.lat, longitude: pin.lng, ...dimensions } ) }) ) as pin, index}
|
||||
{#each pins[activeSegment as PinSegment].map( (pin) => ({ ...pin, isOpen: activeRegion === slugify(pin.city) }) ) as pin, index}
|
||||
<MapMarker {...pin} animate={$animate} {index} bounds={MAP_BOUNDS} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MapTooltip coords={$position} />
|
||||
|
||||
<MapNav onValueChange={(value) => (activeSegment = value)} />
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user