fix embedding playground update

This commit is contained in:
vcoppe
2024-09-04 13:26:00 +02:00
parent 96836228db
commit 2996f047d3

View File

@@ -1,324 +1,330 @@
<script lang="ts"> <script lang="ts">
import * as Card from '$lib/components/ui/card'; import * as Card from '$lib/components/ui/card';
import { Label } from '$lib/components/ui/label'; import { Label } from '$lib/components/ui/label';
import { Input } from '$lib/components/ui/input'; import { Input } from '$lib/components/ui/input';
import * as Select from '$lib/components/ui/select'; import * as Select from '$lib/components/ui/select';
import { Checkbox } from '$lib/components/ui/checkbox'; import { Checkbox } from '$lib/components/ui/checkbox';
import * as RadioGroup from '$lib/components/ui/radio-group'; import * as RadioGroup from '$lib/components/ui/radio-group';
import { import {
Zap, Zap,
HeartPulse, HeartPulse,
Orbit, Orbit,
Thermometer, Thermometer,
SquareActivity, SquareActivity,
Coins, Coins,
Milestone, Milestone,
Video Video
} from 'lucide-svelte'; } from 'lucide-svelte';
import { _ } from 'svelte-i18n'; import { _ } from 'svelte-i18n';
import { import {
allowedEmbeddingBasemaps, allowedEmbeddingBasemaps,
getCleanedEmbeddingOptions, getCleanedEmbeddingOptions,
getDefaultEmbeddingOptions, getDefaultEmbeddingOptions,
getURLForGoogleDriveFile getURLForGoogleDriveFile
} from './Embedding'; } from './Embedding';
import { PUBLIC_MAPBOX_TOKEN } from '$env/static/public'; import { PUBLIC_MAPBOX_TOKEN } from '$env/static/public';
import Embedding from './Embedding.svelte'; import Embedding from './Embedding.svelte';
import { map } from '$lib/stores'; import { map } from '$lib/stores';
import { tick } from 'svelte'; import { tick } from 'svelte';
import { base } from '$app/paths'; import { base } from '$app/paths';
let options = getDefaultEmbeddingOptions(); let options = getDefaultEmbeddingOptions();
options.token = 'YOUR_MAPBOX_TOKEN'; options.token = 'YOUR_MAPBOX_TOKEN';
options.files = [ options.files = [
'https://raw.githubusercontent.com/gpxstudio/gpx.studio/main/gpx/test-data/simple.gpx' 'https://raw.githubusercontent.com/gpxstudio/gpx.studio/main/gpx/test-data/simple.gpx'
]; ];
let files = options.files[0]; let files = options.files[0];
let driveIds = ''; let driveIds = '';
$: if (files && driveIds) { $: if (files || driveIds) {
let urls = files.split(','); let urls = files.split(',');
urls = urls.filter((url) => url.length > 0); urls = urls.filter((url) => url.length > 0);
let ids = driveIds.split(','); let ids = driveIds.split(',');
ids = ids.filter((id) => id.length > 0); ids = ids.filter((id) => id.length > 0);
urls.push(...ids.map(getURLForGoogleDriveFile)); urls.push(...ids.map(getURLForGoogleDriveFile));
if (JSON.stringify(urls) !== JSON.stringify(options.files)) { if (JSON.stringify(urls) !== JSON.stringify(options.files)) {
options.files = urls; options.files = urls;
} }
} }
let manualCamera = false; let manualCamera = false;
let zoom = '0'; let zoom = '0';
let lat = '0'; let lat = '0';
let lon = '0'; let lon = '0';
let bearing = '0'; let bearing = '0';
let pitch = '0'; let pitch = '0';
$: hash = manualCamera ? `#${zoom}/${lat}/${lon}/${bearing}/${pitch}` : ''; $: hash = manualCamera ? `#${zoom}/${lat}/${lon}/${bearing}/${pitch}` : '';
$: iframeOptions = $: iframeOptions =
options.token.length === 0 || options.token === 'YOUR_MAPBOX_TOKEN' options.token.length === 0 || options.token === 'YOUR_MAPBOX_TOKEN'
? Object.assign({}, options, { token: PUBLIC_MAPBOX_TOKEN }) ? Object.assign({}, options, { token: PUBLIC_MAPBOX_TOKEN })
: options; : options;
async function resizeMap() { async function resizeMap() {
if ($map) { if ($map) {
await tick(); await tick();
$map.resize(); $map.resize();
} }
} }
$: if (options.elevation.height || options.elevation.show) { $: if (options.elevation.height || options.elevation.show) {
resizeMap(); resizeMap();
} }
function updateCamera() { function updateCamera() {
if ($map) { if ($map) {
let center = $map.getCenter(); let center = $map.getCenter();
lat = center.lat.toFixed(4); lat = center.lat.toFixed(4);
lon = center.lng.toFixed(4); lon = center.lng.toFixed(4);
zoom = $map.getZoom().toFixed(2); zoom = $map.getZoom().toFixed(2);
bearing = $map.getBearing().toFixed(1); bearing = $map.getBearing().toFixed(1);
pitch = $map.getPitch().toFixed(0); pitch = $map.getPitch().toFixed(0);
} }
} }
$: if ($map) { $: if ($map) {
$map.on('moveend', updateCamera); $map.on('moveend', updateCamera);
} }
</script> </script>
<Card.Root> <Card.Root>
<Card.Header> <Card.Header>
<Card.Title>{$_('embedding.title')}</Card.Title> <Card.Title>{$_('embedding.title')}</Card.Title>
</Card.Header> </Card.Header>
<Card.Content> <Card.Content>
<fieldset class="flex flex-col gap-3"> <fieldset class="flex flex-col gap-3">
<Label for="token">{$_('embedding.mapbox_token')}</Label> <Label for="token">{$_('embedding.mapbox_token')}</Label>
<Input id="token" type="text" class="h-8" bind:value={options.token} /> <Input id="token" type="text" class="h-8" bind:value={options.token} />
<Label for="file_urls">{$_('embedding.file_urls')}</Label> <Label for="file_urls">{$_('embedding.file_urls')}</Label>
<Input id="file_urls" type="text" class="h-8" bind:value={files} /> <Input id="file_urls" type="text" class="h-8" bind:value={files} />
<Label for="drive_ids">{$_('embedding.drive_ids')}</Label> <Label for="drive_ids">{$_('embedding.drive_ids')}</Label>
<Input id="drive_ids" type="text" class="h-8" bind:value={driveIds} /> <Input id="drive_ids" type="text" class="h-8" bind:value={driveIds} />
<Label for="basemap">{$_('embedding.basemap')}</Label> <Label for="basemap">{$_('embedding.basemap')}</Label>
<Select.Root <Select.Root
selected={{ value: options.basemap, label: $_(`layers.label.${options.basemap}`) }} selected={{ value: options.basemap, label: $_(`layers.label.${options.basemap}`) }}
onSelectedChange={(selected) => { onSelectedChange={(selected) => {
if (selected?.value) { if (selected?.value) {
options.basemap = selected?.value; options.basemap = selected?.value;
} }
}} }}
> >
<Select.Trigger id="basemap" class="w-full h-8"> <Select.Trigger id="basemap" class="w-full h-8">
<Select.Value /> <Select.Value />
</Select.Trigger> </Select.Trigger>
<Select.Content class="max-h-60 overflow-y-scroll"> <Select.Content class="max-h-60 overflow-y-scroll">
{#each allowedEmbeddingBasemaps as basemap} {#each allowedEmbeddingBasemaps as basemap}
<Select.Item value={basemap}>{$_(`layers.label.${basemap}`)}</Select.Item> <Select.Item value={basemap}>{$_(`layers.label.${basemap}`)}</Select.Item>
{/each} {/each}
</Select.Content> </Select.Content>
</Select.Root> </Select.Root>
<div class="flex flex-row items-center gap-2"> <div class="flex flex-row items-center gap-2">
<Label for="profile">{$_('menu.elevation_profile')}</Label> <Label for="profile">{$_('menu.elevation_profile')}</Label>
<Checkbox id="profile" bind:checked={options.elevation.show} /> <Checkbox id="profile" bind:checked={options.elevation.show} />
</div> </div>
{#if options.elevation.show} {#if options.elevation.show}
<div class="grid grid-cols-2 gap-x-6 gap-y-3 rounded-md border p-3 mt-1"> <div class="grid grid-cols-2 gap-x-6 gap-y-3 rounded-md border p-3 mt-1">
<Label class="flex flex-row items-center gap-2"> <Label class="flex flex-row items-center gap-2">
{$_('embedding.height')} {$_('embedding.height')}
<Input type="number" bind:value={options.elevation.height} class="h-8 w-20" /> <Input
</Label> type="number"
<div class="flex flex-row items-center gap-2"> bind:value={options.elevation.height}
<span class="shrink-0"> class="h-8 w-20"
{$_('embedding.fill_by')} />
</span> </Label>
<Select.Root <div class="flex flex-row items-center gap-2">
selected={{ value: 'none', label: $_('embedding.none') }} <span class="shrink-0">
onSelectedChange={(selected) => { {$_('embedding.fill_by')}
let value = selected?.value; </span>
if (value === 'none') { <Select.Root
options.elevation.fill = undefined; selected={{ value: 'none', label: $_('embedding.none') }}
} else if (value === 'slope' || value === 'surface') { onSelectedChange={(selected) => {
options.elevation.fill = value; let value = selected?.value;
} if (value === 'none') {
}} options.elevation.fill = undefined;
> } else if (value === 'slope' || value === 'surface') {
<Select.Trigger class="grow h-8"> options.elevation.fill = value;
<Select.Value /> }
</Select.Trigger> }}
<Select.Content> >
<Select.Item value="slope">{$_('quantities.slope')}</Select.Item> <Select.Trigger class="grow h-8">
<Select.Item value="surface">{$_('quantities.surface')}</Select.Item> <Select.Value />
<Select.Item value="none">{$_('embedding.none')}</Select.Item> </Select.Trigger>
</Select.Content> <Select.Content>
</Select.Root> <Select.Item value="slope">{$_('quantities.slope')}</Select.Item>
</div> <Select.Item value="surface">{$_('quantities.surface')}</Select.Item
<div class="flex flex-row items-center gap-2"> >
<Checkbox id="controls" bind:checked={options.elevation.controls} /> <Select.Item value="none">{$_('embedding.none')}</Select.Item>
<Label for="controls">{$_('embedding.show_controls')}</Label> </Select.Content>
</div> </Select.Root>
<div class="flex flex-row items-center gap-2"> </div>
<Checkbox id="show-speed" bind:checked={options.elevation.speed} /> <div class="flex flex-row items-center gap-2">
<Label for="show-speed" class="flex flex-row items-center gap-1"> <Checkbox id="controls" bind:checked={options.elevation.controls} />
<Zap size="16" /> <Label for="controls">{$_('embedding.show_controls')}</Label>
{$_('chart.show_speed')} </div>
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="show-speed" bind:checked={options.elevation.speed} />
<div class="flex flex-row items-center gap-2"> <Label for="show-speed" class="flex flex-row items-center gap-1">
<Checkbox id="show-hr" bind:checked={options.elevation.hr} /> <Zap size="16" />
<Label for="show-hr" class="flex flex-row items-center gap-1"> {$_('chart.show_speed')}
<HeartPulse size="16" /> </Label>
{$_('chart.show_heartrate')} </div>
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="show-hr" bind:checked={options.elevation.hr} />
<div class="flex flex-row items-center gap-2"> <Label for="show-hr" class="flex flex-row items-center gap-1">
<Checkbox id="show-cad" bind:checked={options.elevation.cad} /> <HeartPulse size="16" />
<Label for="show-cad" class="flex flex-row items-center gap-1"> {$_('chart.show_heartrate')}
<Orbit size="16" /> </Label>
{$_('chart.show_cadence')} </div>
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="show-cad" bind:checked={options.elevation.cad} />
<div class="flex flex-row items-center gap-2"> <Label for="show-cad" class="flex flex-row items-center gap-1">
<Checkbox id="show-temp" bind:checked={options.elevation.temp} /> <Orbit size="16" />
<Label for="show-temp" class="flex flex-row items-center gap-1"> {$_('chart.show_cadence')}
<Thermometer size="16" /> </Label>
{$_('chart.show_temperature')} </div>
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="show-temp" bind:checked={options.elevation.temp} />
<div class="flex flex-row items-center gap-2"> <Label for="show-temp" class="flex flex-row items-center gap-1">
<Checkbox id="show-power" bind:checked={options.elevation.power} /> <Thermometer size="16" />
<Label for="show-power" class="flex flex-row items-center gap-1"> {$_('chart.show_temperature')}
<SquareActivity size="16" /> </Label>
{$_('chart.show_power')} </div>
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="show-power" bind:checked={options.elevation.power} />
</div> <Label for="show-power" class="flex flex-row items-center gap-1">
{/if} <SquareActivity size="16" />
<div class="flex flex-row items-center gap-2"> {$_('chart.show_power')}
<Checkbox id="distance-markers" bind:checked={options.distanceMarkers} /> </Label>
<Label for="distance-markers" class="flex flex-row items-center gap-1"> </div>
<Coins size="16" /> </div>
{$_('menu.distance_markers')} {/if}
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="distance-markers" bind:checked={options.distanceMarkers} />
<div class="flex flex-row items-center gap-2"> <Label for="distance-markers" class="flex flex-row items-center gap-1">
<Checkbox id="direction-markers" bind:checked={options.directionMarkers} /> <Coins size="16" />
<Label for="direction-markers" class="flex flex-row items-center gap-1"> {$_('menu.distance_markers')}
<Milestone size="16" /> </Label>
{$_('menu.direction_markers')} </div>
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="direction-markers" bind:checked={options.directionMarkers} />
<div class="flex flex-row flex-wrap justify-between gap-3"> <Label for="direction-markers" class="flex flex-row items-center gap-1">
<Label class="flex flex-col items-start gap-2"> <Milestone size="16" />
{$_('menu.distance_units')} {$_('menu.direction_markers')}
<RadioGroup.Root bind:value={options.distanceUnits}> </Label>
<div class="flex items-center space-x-2"> </div>
<RadioGroup.Item value="metric" id="metric" /> <div class="flex flex-row flex-wrap justify-between gap-3">
<Label for="metric">{$_('menu.metric')}</Label> <Label class="flex flex-col items-start gap-2">
</div> {$_('menu.distance_units')}
<div class="flex items-center space-x-2"> <RadioGroup.Root bind:value={options.distanceUnits}>
<RadioGroup.Item value="imperial" id="imperial" /> <div class="flex items-center space-x-2">
<Label for="imperial">{$_('menu.imperial')}</Label> <RadioGroup.Item value="metric" id="metric" />
</div> <Label for="metric">{$_('menu.metric')}</Label>
<div class="flex items-center space-x-2"> </div>
<RadioGroup.Item value="nautical" id="nautical" /> <div class="flex items-center space-x-2">
<Label for="nautical">{$_('menu.nautical')}</Label> <RadioGroup.Item value="imperial" id="imperial" />
</div> <Label for="imperial">{$_('menu.imperial')}</Label>
</RadioGroup.Root> </div>
</Label> <div class="flex items-center space-x-2">
<Label class="flex flex-col items-start gap-2"> <RadioGroup.Item value="nautical" id="nautical" />
{$_('menu.velocity_units')} <Label for="nautical">{$_('menu.nautical')}</Label>
<RadioGroup.Root bind:value={options.velocityUnits}> </div>
<div class="flex items-center space-x-2"> </RadioGroup.Root>
<RadioGroup.Item value="speed" id="speed" /> </Label>
<Label for="speed">{$_('quantities.speed')}</Label> <Label class="flex flex-col items-start gap-2">
</div> {$_('menu.velocity_units')}
<div class="flex items-center space-x-2"> <RadioGroup.Root bind:value={options.velocityUnits}>
<RadioGroup.Item value="pace" id="pace" /> <div class="flex items-center space-x-2">
<Label for="pace">{$_('quantities.pace')}</Label> <RadioGroup.Item value="speed" id="speed" />
</div> <Label for="speed">{$_('quantities.speed')}</Label>
</RadioGroup.Root> </div>
</Label> <div class="flex items-center space-x-2">
<Label class="flex flex-col items-start gap-2"> <RadioGroup.Item value="pace" id="pace" />
{$_('menu.temperature_units')} <Label for="pace">{$_('quantities.pace')}</Label>
<RadioGroup.Root bind:value={options.temperatureUnits}> </div>
<div class="flex items-center space-x-2"> </RadioGroup.Root>
<RadioGroup.Item value="celsius" id="celsius" /> </Label>
<Label for="celsius">{$_('menu.celsius')}</Label> <Label class="flex flex-col items-start gap-2">
</div> {$_('menu.temperature_units')}
<div class="flex items-center space-x-2"> <RadioGroup.Root bind:value={options.temperatureUnits}>
<RadioGroup.Item value="fahrenheit" id="fahrenheit" /> <div class="flex items-center space-x-2">
<Label for="fahrenheit">{$_('menu.fahrenheit')}</Label> <RadioGroup.Item value="celsius" id="celsius" />
</div> <Label for="celsius">{$_('menu.celsius')}</Label>
</RadioGroup.Root> </div>
</Label> <div class="flex items-center space-x-2">
</div> <RadioGroup.Item value="fahrenheit" id="fahrenheit" />
<Label class="flex flex-col items-start gap-2"> <Label for="fahrenheit">{$_('menu.fahrenheit')}</Label>
{$_('menu.mode')} </div>
<RadioGroup.Root bind:value={options.theme} class="flex flex-row"> </RadioGroup.Root>
<div class="flex items-center space-x-2"> </Label>
<RadioGroup.Item value="system" id="system" /> </div>
<Label for="system">{$_('menu.system')}</Label> <Label class="flex flex-col items-start gap-2">
</div> {$_('menu.mode')}
<div class="flex items-center space-x-2"> <RadioGroup.Root bind:value={options.theme} class="flex flex-row">
<RadioGroup.Item value="light" id="light" /> <div class="flex items-center space-x-2">
<Label for="light">{$_('menu.light')}</Label> <RadioGroup.Item value="system" id="system" />
</div> <Label for="system">{$_('menu.system')}</Label>
<div class="flex items-center space-x-2"> </div>
<RadioGroup.Item value="dark" id="dark" /> <div class="flex items-center space-x-2">
<Label for="dark">{$_('menu.dark')}</Label> <RadioGroup.Item value="light" id="light" />
</div> <Label for="light">{$_('menu.light')}</Label>
</RadioGroup.Root> </div>
</Label> <div class="flex items-center space-x-2">
<div class="flex flex-col gap-3 p-3 border rounded-md"> <RadioGroup.Item value="dark" id="dark" />
<div class="flex flex-row items-center gap-2"> <Label for="dark">{$_('menu.dark')}</Label>
<Checkbox id="manual-camera" bind:checked={manualCamera} /> </div>
<Label for="manual-camera" class="flex flex-row items-center gap-1"> </RadioGroup.Root>
<Video size="16" /> </Label>
{$_('embedding.manual_camera')} <div class="flex flex-col gap-3 p-3 border rounded-md">
</Label> <div class="flex flex-row items-center gap-2">
</div> <Checkbox id="manual-camera" bind:checked={manualCamera} />
<p class="text-sm text-muted-foreground"> <Label for="manual-camera" class="flex flex-row items-center gap-1">
{$_('embedding.manual_camera_description')} <Video size="16" />
</p> {$_('embedding.manual_camera')}
<div class="flex flex-row flex-wrap items-center gap-6"> </Label>
<Label class="flex flex-col gap-1"> </div>
<span>{$_('embedding.latitude')}</span> <p class="text-sm text-muted-foreground">
<span>{lat}</span> {$_('embedding.manual_camera_description')}
</Label> </p>
<Label class="flex flex-col gap-1"> <div class="flex flex-row flex-wrap items-center gap-6">
<span>{$_('embedding.longitude')}</span> <Label class="flex flex-col gap-1">
<span>{lon}</span> <span>{$_('embedding.latitude')}</span>
</Label> <span>{lat}</span>
<Label class="flex flex-col gap-1"> </Label>
<span>{$_('embedding.zoom')}</span> <Label class="flex flex-col gap-1">
<span>{zoom}</span> <span>{$_('embedding.longitude')}</span>
</Label> <span>{lon}</span>
<Label class="flex flex-col gap-1"> </Label>
<span>{$_('embedding.bearing')}</span> <Label class="flex flex-col gap-1">
<span>{bearing}</span> <span>{$_('embedding.zoom')}</span>
</Label> <span>{zoom}</span>
<Label class="flex flex-col gap-1"> </Label>
<span>{$_('embedding.pitch')}</span> <Label class="flex flex-col gap-1">
<span>{pitch}</span> <span>{$_('embedding.bearing')}</span>
</Label> <span>{bearing}</span>
</div> </Label>
</div> <Label class="flex flex-col gap-1">
<Label> <span>{$_('embedding.pitch')}</span>
{$_('embedding.preview')} <span>{pitch}</span>
</Label> </Label>
<div class="relative h-[600px]"> </div>
<Embedding bind:options={iframeOptions} bind:hash useHash={false} /> </div>
</div> <Label>
<Label> {$_('embedding.preview')}
{$_('embedding.code')} </Label>
</Label> <div class="relative h-[600px]">
<pre class="bg-primary text-primary-foreground p-3 rounded-md whitespace-normal break-all"> <Embedding bind:options={iframeOptions} bind:hash useHash={false} />
</div>
<Label>
{$_('embedding.code')}
</Label>
<pre
class="bg-primary text-primary-foreground p-3 rounded-md whitespace-normal break-all">
<code class="language-html"> <code class="language-html">
{`<iframe src="https://gpx.studio${base}/embed?options=${encodeURIComponent(JSON.stringify(getCleanedEmbeddingOptions(options)))}${hash}" width="100%" height="600px" frameborder="0" style="outline: none;"/>`} {`<iframe src="https://gpx.studio${base}/embed?options=${encodeURIComponent(JSON.stringify(getCleanedEmbeddingOptions(options)))}${hash}" width="100%" height="600px" frameborder="0" style="outline: none;"/>`}
</code> </code>
</pre> </pre>
</fieldset> </fieldset>
</Card.Content> </Card.Content>
</Card.Root> </Card.Root>