mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-08-30 15:20:01 +00:00
about page progress
This commit is contained in:
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 vcoppe
|
Copyright (c) 2024 gpx.studio
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@@ -1,17 +1,103 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
|
import LanguageSelect from '$lib/components/LanguageSelect.svelte';
|
||||||
|
import Logo from '$lib/components/Logo.svelte';
|
||||||
|
import { AtSign, BookOpenText, Heart, Info, Map } from 'lucide-svelte';
|
||||||
|
import { _ } from 'svelte-i18n';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<footer class="w-full">
|
<footer class="w-full">
|
||||||
<div class="mx-6 py-2 flex flex-row flex-wrap border-t">
|
<div class="mx-6 border-t">
|
||||||
<div class="flex flex-row" id="contact">
|
<div class="mx-12 py-10 flex flex-row flex-wrap justify-between gap-x-10 gap-y-6">
|
||||||
<Button variant="link" href="https://github.com/gpxstudio/gpx.studio" target="_blank"
|
<div class="grow flex flex-col items-start">
|
||||||
>GitHub</Button
|
<Logo class="h-8" />
|
||||||
>
|
<Button
|
||||||
<Button variant="link" href="https://facebook.com/gpx.studio" target="_blank">Facebook</Button
|
variant="link"
|
||||||
>
|
class="h-6 px-0 text-muted-foreground"
|
||||||
<Button variant="link" href="https://twitter.com/gpxstudio" target="_blank">Twitter</Button>
|
href="https://github.com/gpxstudio/gpx.studio/blob/main/LICENSE"
|
||||||
<Button variant="link" href="mailto:hello@gpx.studio" target="_blank">Mail</Button>
|
target="_blank"
|
||||||
|
>
|
||||||
|
MIT © 2024 gpx.studio
|
||||||
|
</Button>
|
||||||
|
<LanguageSelect class="w-40 mt-3" />
|
||||||
|
</div>
|
||||||
|
<div class="grow max-w-2xl flex flex-row flex-wrap justify-between gap-x-10 gap-y-6">
|
||||||
|
<div class="flex flex-col items-start gap-1">
|
||||||
|
<span class="font-semibold">{$_('homepage.website')}</span>
|
||||||
|
<Button variant="link" class="h-6 px-0 text-muted-foreground" href="./">
|
||||||
|
<Map size="16" class="mr-1" />
|
||||||
|
{$_('homepage.app')}
|
||||||
|
</Button>
|
||||||
|
<Button variant="link" class="h-6 px-0 text-muted-foreground" href="./about">
|
||||||
|
<Info size="16" class="mr-1" />
|
||||||
|
{$_('menu.about')}
|
||||||
|
</Button>
|
||||||
|
<Button variant="link" class="h-6 px-0 text-muted-foreground" href="./documentation">
|
||||||
|
<BookOpenText size="16" class="mr-1" />
|
||||||
|
{$_('homepage.documentation')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-start gap-1" id="contact">
|
||||||
|
<span class="font-semibold">{$_('homepage.contact')}</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="h-6 px-0 text-muted-foreground"
|
||||||
|
href="https://facebook.com/gpx.studio"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Logo company="facebook" class="h-4 mr-1 fill-muted-foreground" />
|
||||||
|
{$_('homepage.facebook')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="h-6 px-0 text-muted-foreground"
|
||||||
|
href="https://x.com/gpxstudio"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Logo company="x" class="h-4 mr-1 fill-muted-foreground" />
|
||||||
|
{$_('homepage.x')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="h-6 px-0 text-muted-foreground"
|
||||||
|
href="mailto:hello@gpx.studio"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<AtSign size="16" class="mr-1" />
|
||||||
|
{$_('homepage.email')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-start gap-1">
|
||||||
|
<span class="font-semibold">{$_('homepage.contribute')}</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="h-6 px-0 text-muted-foreground"
|
||||||
|
href="https://ko-fi.com/gpxstudio"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Heart size="16" class="mr-1" />
|
||||||
|
{$_('menu.donate')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="h-6 px-0 text-muted-foreground"
|
||||||
|
href="https://crowdin.com/project/gpxstudio"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Logo company="crowdin" class="h-4 mr-1 fill-muted-foreground" />
|
||||||
|
{$_('homepage.crowdin')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
class="h-6 px-0 text-muted-foreground"
|
||||||
|
href="https://github.com/gpxstudio/gpx.studio"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<Logo company="github" class="h-4 mr-1 fill-muted-foreground" />
|
||||||
|
{$_('homepage.github')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
46
website/src/lib/components/LanguageSelect.svelte
Normal file
46
website/src/lib/components/LanguageSelect.svelte
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import * as Select from '$lib/components/ui/select';
|
||||||
|
import { languages } from '$lib/languages';
|
||||||
|
import { Languages } from 'lucide-svelte';
|
||||||
|
import { _, locale } from 'svelte-i18n';
|
||||||
|
|
||||||
|
let selected = {
|
||||||
|
value: '',
|
||||||
|
label: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
$: if ($locale) {
|
||||||
|
selected = {
|
||||||
|
value: $locale,
|
||||||
|
label: languages[$locale]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getURLForLanguage(lang?: string): string {
|
||||||
|
let currentPath = window.location.pathname;
|
||||||
|
let currentPathArray = currentPath.split('/');
|
||||||
|
|
||||||
|
if (currentPathArray.length > 1 && languages.hasOwnProperty(currentPathArray[1])) {
|
||||||
|
currentPathArray.splice(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lang !== undefined && lang !== 'en') {
|
||||||
|
currentPathArray.splice(1, 0, lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPathArray.join('/');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Select.Root bind:selected onSelectedChange={(s) => goto(getURLForLanguage(s?.value))}>
|
||||||
|
<Select.Trigger class="w-[180px] {$$props.class ?? ''}">
|
||||||
|
<Languages size="16" />
|
||||||
|
<Select.Value class="ml-2 mr-auto" />
|
||||||
|
</Select.Trigger>
|
||||||
|
<Select.Content>
|
||||||
|
{#each Object.entries(languages) as [key, value]}
|
||||||
|
<Select.Item value={key}>{value}</Select.Item>
|
||||||
|
{/each}
|
||||||
|
</Select.Content>
|
||||||
|
</Select.Root>
|
@@ -3,10 +3,59 @@
|
|||||||
import { mode } from 'mode-watcher';
|
import { mode } from 'mode-watcher';
|
||||||
|
|
||||||
export let iconOnly = false;
|
export let iconOnly = false;
|
||||||
|
export let company = 'gpx.studio';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<img
|
{#if company === 'gpx.studio'}
|
||||||
src="{base}/{iconOnly ? 'icon' : 'logo'}{$mode === 'dark' ? '-dark' : ''}.svg"
|
<img
|
||||||
alt="Logo of gpx.studio."
|
src="{base}/{iconOnly ? 'icon' : 'logo'}{$mode === 'dark' ? '-dark' : ''}.svg"
|
||||||
{...$$restProps}
|
alt="Logo of gpx.studio."
|
||||||
/>
|
{...$$restProps}
|
||||||
|
/>
|
||||||
|
{:else if company === 'mapbox'}
|
||||||
|
<img
|
||||||
|
src="{base}/mapbox-logo-{$mode === 'dark' ? 'white' : 'black'}.svg"
|
||||||
|
alt="Logo of Mapbox."
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
||||||
|
{:else if company === 'github'}
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="fill-foreground {$$restProps.class ?? ''}"
|
||||||
|
><title>GitHub</title><path
|
||||||
|
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
{:else if company === 'crowdin'}
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="fill-foreground {$$restProps.class ?? ''}"
|
||||||
|
><title>Crowdin</title><path
|
||||||
|
d="M16.119 17.793a2.619 2.619 0 0 1-1.667-.562c-.546-.436-1.004-1.09-1.018-1.858-.008-.388.414-.388.414-.388l1.018-.008c.332.008.43.47.445.586.128 1.04.717 1.495 1.168 1.702.273.123.204.513-.362.528zm-5.695-5.287L8.5 12.252c-.867-.214-.844-.982-.807-1.247a5.119 5.119 0 0 1 .814-2.125c.545-.804 1.303-1.508 2.29-2.073 1.856-1.074 4.45-1.673 7.31-1.673 2.09 0 4.256.27 4.29.27.197.025.328.213.333.437a.377.377 0 0 1-.355.393l-.92-.01c-2.902 0-4.968.394-6.506 1.248-1.527.837-2.57 2.117-3.287 4.012-.076.163-.335 1.12-1.24 1.022zm2.533 7.823c-1.44 0-2.797-.622-3.825-1.746-.87-.96-1.397-1.931-1.493-3.164-.06-.813.3-1.094.788-1.044l1.988.218c.45.092.75.34.825.854.397 2.736 2.122 3.814 3.15 4.046.18.042.292.157.283.365a.412.412 0 0 1-.322.398c-.458.074-.936.073-1.394.073zm-4.101 2.418a14.216 14.216 0 0 1-2.307-.214c-1.202-.214-2.208-.582-3.072-1.13C1.41 20.095.163 17.786.014 15.048c-.037-.65-.11-1.89 1.427-1.797.638.033 1.653.343 2.368.548.887.247 1.314.933 1.314 1.608 0 3.858 3.494 6.408 5.02 6.408.654 0 .414.701.127.779-.502.136-1.15.153-1.413.153zM3.525 11.419c-.605-.109-1.194-.358-1.768-.5C-.018 10.479.284 8.688.45 8.196c1.617-4.757 6.746-6.35 10.887-6.773 3.898-.4 7.978-.092 11.778.967.31.083 1.269.327.718.891-.35.358-1.7-.016-2.073-.041-2.23-.167-4.434-.192-6.656.15-2.349.357-4.768 1.099-6.71 2.665-.938.758-1.76 1.723-2.313 2.866-.144.3-.256.6-.354.9-.11.327-.47 1.91-2.215 1.6zm9.94.917c.332-1.488 1.81-3.848 6.385-3.686 1.05.033.57.749.052.731-2.586-.09-3.815 1.578-4.457 3.27-.219.546-.68.626-1.271.53-.415-.074-.866-.123-.71-.846Z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
{:else if company === 'facebook'}
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="fill-foreground {$$restProps.class ?? ''}"
|
||||||
|
><title>Facebook</title><path
|
||||||
|
d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
{:else if company === 'x'}
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="fill-foreground {$$restProps.class ?? ''}"
|
||||||
|
><title>X</title><path
|
||||||
|
d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
@@ -40,6 +40,7 @@
|
|||||||
});
|
});
|
||||||
newMap.on('load', () => {
|
newMap.on('load', () => {
|
||||||
$map = newMap; // only set the store after the map has loaded
|
$map = newMap; // only set the store after the map has loaded
|
||||||
|
scaleControl.setUnit($distanceUnits);
|
||||||
});
|
});
|
||||||
|
|
||||||
newMap.addControl(
|
newMap.addControl(
|
||||||
@@ -114,10 +115,6 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$: if ($map) {
|
|
||||||
scaleControl.setUnit($distanceUnits);
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if (
|
$: if (
|
||||||
$map &&
|
$map &&
|
||||||
(!$verticalFileView || !$elevationProfile || $bottomPanelSize || $rightPanelSize)
|
(!$verticalFileView || !$elevationProfile || $bottomPanelSize || $rightPanelSize)
|
||||||
|
@@ -1,12 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { base } from '$app/paths';
|
|
||||||
import { mode } from 'mode-watcher';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<a href="https://mapbox.com" target="_blank">
|
|
||||||
<img
|
|
||||||
src="{base}/mapbox-logo-{$mode === 'dark' ? 'white' : 'black'}.svg"
|
|
||||||
alt="Logo of Mapbox."
|
|
||||||
{...$$restProps}
|
|
||||||
/>
|
|
||||||
</a>
|
|
49
website/src/lib/components/ModeSwitch.svelte
Normal file
49
website/src/lib/components/ModeSwitch.svelte
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import * as Popover from '$lib/components/ui/popover';
|
||||||
|
import { Button } from '$lib/components/ui/button';
|
||||||
|
import { Moon, Sun } from 'lucide-svelte';
|
||||||
|
import { resetMode, setMode, systemPrefersMode } from 'mode-watcher';
|
||||||
|
import { settings } from '$lib/db';
|
||||||
|
import { _ } from 'svelte-i18n';
|
||||||
|
|
||||||
|
const { mode } = settings;
|
||||||
|
|
||||||
|
$: if ($mode === 'system') {
|
||||||
|
resetMode();
|
||||||
|
} else {
|
||||||
|
setMode($mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
export let size = '20';
|
||||||
|
let open = false;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Popover.Root bind:open>
|
||||||
|
<Popover.Trigger {...$$restProps}>
|
||||||
|
{#if $mode === 'system'}
|
||||||
|
{#if $systemPrefersMode === 'light'}
|
||||||
|
<Sun {size} class="mr-1" />
|
||||||
|
{:else if $systemPrefersMode === 'dark'}
|
||||||
|
<Moon {size} class="mr-1" />
|
||||||
|
{:else}
|
||||||
|
<Sun {size} class="mr-1" />
|
||||||
|
{/if}
|
||||||
|
{:else if $mode === 'light'}
|
||||||
|
<Sun {size} class="mr-1" />
|
||||||
|
{:else if $mode === 'dark'}
|
||||||
|
<Moon {size} class="mr-1" />
|
||||||
|
{/if}
|
||||||
|
</Popover.Trigger>
|
||||||
|
<Popover.Content class=" w-fit flex flex-col p-2">
|
||||||
|
{#each ['light', 'dark', 'system'] as m}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
class="h-8 justify-start"
|
||||||
|
on:click={() => {
|
||||||
|
$mode = m;
|
||||||
|
open = false;
|
||||||
|
}}>{$_(`menu.${m}`)}</Button
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
@@ -1,67 +1,29 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { goto } from '$app/navigation';
|
|
||||||
import Logo from '$lib/components/Logo.svelte';
|
import Logo from '$lib/components/Logo.svelte';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
import * as Select from '$lib/components/ui/select';
|
import ModeSwitch from '$lib/components/ModeSwitch.svelte';
|
||||||
import { languages } from '$lib/languages';
|
import { BookOpenText, Info, Map } from 'lucide-svelte';
|
||||||
import { BookOpenText, Info, Languages, Map } from 'lucide-svelte';
|
import { _ } from 'svelte-i18n';
|
||||||
import { _, locale } from 'svelte-i18n';
|
|
||||||
|
|
||||||
let selected = {
|
|
||||||
value: '',
|
|
||||||
label: ''
|
|
||||||
};
|
|
||||||
|
|
||||||
$: if ($locale) {
|
|
||||||
selected = {
|
|
||||||
value: $locale,
|
|
||||||
label: languages[$locale]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getURLForLanguage(lang?: string): string {
|
|
||||||
let currentPath = window.location.pathname;
|
|
||||||
let currentPathArray = currentPath.split('/');
|
|
||||||
|
|
||||||
if (currentPathArray.length > 1 && languages.hasOwnProperty(currentPathArray[1])) {
|
|
||||||
currentPathArray.splice(1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lang !== undefined && lang !== 'en') {
|
|
||||||
currentPathArray.splice(1, 0, lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentPathArray.join('/');
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav class="w-full sticky top-0 bg-background">
|
<nav class="w-full sticky top-0 bg-background z-10">
|
||||||
<div class="mx-6 py-2 flex flex-row items-center border-b">
|
<div class="mx-6 py-2 flex flex-row items-center border-b gap-4 md:gap-8">
|
||||||
<a href="./">
|
<a href="./" class="shrink-0">
|
||||||
<Logo class="h-6" />
|
<Logo class="h-8 sm:hidden" iconOnly={true} />
|
||||||
|
<Logo class="h-7 hidden sm:block" />
|
||||||
</a>
|
</a>
|
||||||
<Button variant="link" class="text-base" href="./">
|
<Button variant="link" class="text-base px-0" href="./">
|
||||||
<Map size="18" class="mr-1.5" />
|
<Map size="18" class="mr-1.5" />
|
||||||
{$_('menu.app')}
|
{$_('homepage.app')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="link" class="text-base" href="./about">
|
<Button variant="link" class="text-base px-0" href="./about">
|
||||||
<Info size="18" class="mr-1.5" />
|
<Info size="18" class="mr-1.5" />
|
||||||
{$_('menu.about')}
|
{$_('menu.about')}
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="link" class="text-base" href="./documentation">
|
<Button variant="link" class="text-base px-0" href="./documentation">
|
||||||
<BookOpenText size="18" class="mr-1.5" />
|
<BookOpenText size="18" class="mr-1.5" />
|
||||||
{$_('menu.documentation')}
|
{$_('homepage.documentation')}
|
||||||
</Button>
|
</Button>
|
||||||
<Select.Root bind:selected onSelectedChange={(s) => goto(getURLForLanguage(s?.value))}>
|
<ModeSwitch class="ml-auto" />
|
||||||
<Select.Trigger class="w-[180px] ml-auto">
|
|
||||||
<Languages size="16" />
|
|
||||||
<Select.Value class="ml-2 mr-auto" />
|
|
||||||
</Select.Trigger>
|
|
||||||
<Select.Content>
|
|
||||||
{#each Object.entries(languages) as [key, value]}
|
|
||||||
<Select.Item value={key}>{value}</Select.Item>
|
|
||||||
{/each}
|
|
||||||
</Select.Content>
|
|
||||||
</Select.Root>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
11
website/src/lib/components/docs/Docs.svelte
Normal file
11
website/src/lib/components/docs/Docs.svelte
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import Test, { metadata } from '$lib/docs/en/introduction/test.md';
|
||||||
|
|
||||||
|
const toc = {
|
||||||
|
introduction: ['test']
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{metadata.title}
|
||||||
|
|
||||||
|
<Test />
|
@@ -1,9 +0,0 @@
|
|||||||
<script>
|
|
||||||
import Test from '$lib/docs/en/introduction/test.md';
|
|
||||||
|
|
||||||
const toc = {
|
|
||||||
introduction: ['test']
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Test />
|
|
@@ -15,5 +15,38 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if module !== undefined}
|
{#if module !== undefined}
|
||||||
<svelte:component this={module} />
|
<div class="markdown">
|
||||||
|
<svelte:component this={module} />
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
:global(.markdown) {
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.markdown h1) {
|
||||||
|
@apply text-3xl;
|
||||||
|
@apply font-bold;
|
||||||
|
@apply mb-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.markdown h2) {
|
||||||
|
@apply text-2xl;
|
||||||
|
@apply font-bold;
|
||||||
|
@apply mb-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.markdown p > a) {
|
||||||
|
@apply text-blue-500;
|
||||||
|
@apply hover:underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.markdown ul) {
|
||||||
|
@apply list-disc;
|
||||||
|
@apply pl-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.markdown hr) {
|
||||||
|
@apply my-5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
<script>
|
|
||||||
import MapboxLogo from '$lib/components/MapboxLogo.svelte';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
**gpx.studio** is a *free* and *open-source* online GPX viewer and editor which allows to:
|
|
||||||
- visualize multiple traces in different colors and aided by many different maps (cycling, hiking, satellite, etc.)
|
|
||||||
- edit traces by adding, inserting, moving or deleting track points
|
|
||||||
- reverse traces
|
|
||||||
- add or change the timestamps of a trace
|
|
||||||
- view, add, edit and remove waypoints
|
|
||||||
- reduce the number of track points
|
|
||||||
- view and rework the structure of the file
|
|
||||||
- automatically add elevation data to traces if missing
|
|
||||||
- merge multiple traces, extending time, heart rate, cadence, power and temperature data where needed
|
|
||||||
- extract segments from traces and perform any other action while maintaining the segments' structure within files
|
|
||||||
- save the result on your computer or to your Google Drive™ to get a shareable link and embedding code
|
|
||||||
|
|
||||||
## Mapbox Community 🤝
|
|
||||||
|
|
||||||
[Mapbox](https://mapbox.com) is the company providing some of the beautiful maps on this website. They created a program called [Mapbox Community](https://www.mapbox.com/community) to support non-profits, educational institutions, and positive-impact organizations. We are very lucky and grateful to have joined this program and to benefit from a great discount on all API rates.
|
|
||||||
|
|
||||||
<MapboxLogo class="h-10" />
|
|
||||||
|
|
||||||
## Help keep the website free (and ad-free) 🙏
|
|
||||||
|
|
||||||
Each time you add or move a track point, we make a request to our servers to retrieve a route on the road network. We also rely on APIs from Mapbox to load beautiful maps, retrieve elevation data and process geocoding requests (looking for a place in the search bar).
|
|
||||||
|
|
||||||
Unfortunately this is very costly so if you like the tool and use it frequently, please consider making even a small donation so that this website can stay free to use and ad-free. Thanks for your support!
|
|
||||||
|
|
||||||
## Translating 🗣
|
|
||||||
|
|
||||||
The website is translated by volunteers on a collaborative translation platform. You can help complete and improve the translations by joining the [Crowdin project](https://crowdin.com/project/gpxstudio). [Get in touch](#contact) if you would like to start the translation in a new language. Any help is greatly appreciated!
|
|
7
website/src/lib/docs/en/about/funding.md
Normal file
7
website/src/lib/docs/en/about/funding.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Help keep the website free (and ad-free) 🙏
|
||||||
|
|
||||||
|
Each time you add or move a track point, we make a request to our servers to retrieve a route on the road network.
|
||||||
|
We also rely on APIs from [Mapbox](https://mapbox.com) to load beautiful maps, retrieve elevation data and process geocoding requests (looking for a place in the search bar).
|
||||||
|
Unfortunately this is very costly so if you like the tool and use it frequently, please consider making even a small donation so that this website can stay **free** and **ad-free**.
|
||||||
|
|
||||||
|
Thank you very much for your support! ❤️
|
4
website/src/lib/docs/en/about/mapbox.md
Normal file
4
website/src/lib/docs/en/about/mapbox.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[Mapbox](https://mapbox.com) is the company that provides some of the beautiful maps on this website.
|
||||||
|
They also develop the [map engine](https://github.com/mapbox/mapbox-gl-js) which powers *gpx.studio*.
|
||||||
|
We are incredibly lucky and grateful to have joined their [Community](https://www.mapbox.com/community) program, which supports nonprofits, educational institutions, and positive impact organizations.
|
||||||
|
This means that *gpx.studio* can benefit from Mapbox tools at discounted prices, which greatly contributes to the financial viability of the project and to offering the best possible user experience.
|
6
website/src/lib/docs/en/about/translation.md
Normal file
6
website/src/lib/docs/en/about/translation.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# Translation 🗣
|
||||||
|
|
||||||
|
The website is translated by volunteers on a collaborative translation platform.
|
||||||
|
You can help complete and improve the translations by joining the [Crowdin project](https://crowdin.com/project/gpxstudio).
|
||||||
|
[Get in touch](#contact) if you would like to start the translation in a new language.
|
||||||
|
Any help is greatly appreciated!
|
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
title: Test
|
||||||
|
---
|
||||||
|
|
||||||
|
test
|
@@ -52,10 +52,8 @@
|
|||||||
"layers": "Map layers...",
|
"layers": "Map layers...",
|
||||||
"distance_markers": "Distance markers",
|
"distance_markers": "Distance markers",
|
||||||
"direction_markers": "Direction markers",
|
"direction_markers": "Direction markers",
|
||||||
"app": "App",
|
|
||||||
"about": "About",
|
"about": "About",
|
||||||
"donate": "Donate",
|
"donate": "Donate",
|
||||||
"documentation": "Documentation",
|
|
||||||
"ctrl": "Ctrl",
|
"ctrl": "Ctrl",
|
||||||
"click": "Click",
|
"click": "Click",
|
||||||
"drag": "Drag",
|
"drag": "Drag",
|
||||||
@@ -346,5 +344,19 @@
|
|||||||
"segments": "Segments",
|
"segments": "Segments",
|
||||||
"waypoint": "Point of interest",
|
"waypoint": "Point of interest",
|
||||||
"waypoints": "Points of interest"
|
"waypoints": "Points of interest"
|
||||||
|
},
|
||||||
|
"homepage": {
|
||||||
|
"website": "Website",
|
||||||
|
"app": "App",
|
||||||
|
"documentation": "Documentation",
|
||||||
|
"contact": "Contact",
|
||||||
|
"x": "X",
|
||||||
|
"facebook": "Facebook",
|
||||||
|
"github": "GitHub",
|
||||||
|
"crowdin": "Crowdin",
|
||||||
|
"email": "Email",
|
||||||
|
"contribute": "Contribute",
|
||||||
|
"supported_by": "supported by",
|
||||||
|
"support_button": "Support gpx.studio on Ko-fi"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -27,30 +27,3 @@
|
|||||||
<Footer />
|
<Footer />
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="postcss">
|
|
||||||
:global(.markdown) {
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.markdown h1) {
|
|
||||||
@apply text-3xl;
|
|
||||||
@apply font-bold;
|
|
||||||
@apply mt-4 mb-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.markdown h2) {
|
|
||||||
@apply text-2xl;
|
|
||||||
@apply font-bold;
|
|
||||||
@apply mt-4 mb-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.markdown a) {
|
|
||||||
@apply text-blue-500;
|
|
||||||
@apply hover:underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
:global(.markdown ul) {
|
|
||||||
@apply list-disc;
|
|
||||||
@apply pl-4;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@@ -1,7 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { base } from '$app/paths';
|
import { base } from '$app/paths';
|
||||||
|
import { Button } from '$lib/components/ui/button';
|
||||||
import DocsLoader from '$lib/components/docs/DocsLoader.svelte';
|
import DocsLoader from '$lib/components/docs/DocsLoader.svelte';
|
||||||
|
import Logo from '$lib/components/Logo.svelte';
|
||||||
import { languages } from '$lib/languages';
|
import { languages } from '$lib/languages';
|
||||||
|
import { Heart } from 'lucide-svelte';
|
||||||
|
import { mode } from 'mode-watcher';
|
||||||
import { _ } from 'svelte-i18n';
|
import { _ } from 'svelte-i18n';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -23,6 +27,55 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<div class="px-10 py-6 markdown">
|
<div>
|
||||||
<DocsLoader path="about.svx" />
|
<div class="p-12">TODO hero section</div>
|
||||||
|
<div class="p-12">
|
||||||
|
<div>TODO show toolbar, advanced route planning and file editing tools</div>
|
||||||
|
</div>
|
||||||
|
<div class="relative">
|
||||||
|
<img src="{base}/map.png" alt="Screenshot of the gpx.studio app." class="w-full" />
|
||||||
|
<div
|
||||||
|
class="absolute top-0 left-0 w-full h-full bg-gradient-to-b from-background via-transparent to-background"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="p-12">
|
||||||
|
<div>TODO elevation profile (use component?)</div>
|
||||||
|
<img
|
||||||
|
src="{base}/profile-{$mode ?? 'light'}.png"
|
||||||
|
alt="Screenshot of an elevation profile in the gpx.studio app."
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="p-12">
|
||||||
|
<div>TODO show several squares with different basemaps of the same place</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-12 flex flex-col gap-12">
|
||||||
|
<div class="flex flex-col items-center gap-6">
|
||||||
|
<DocsLoader path="about/funding.md" />
|
||||||
|
<Button
|
||||||
|
href="https://ko-fi.com/gpxstudio"
|
||||||
|
target="_blank"
|
||||||
|
class="w-1/3 min-w-fit bg-support text-base"
|
||||||
|
>
|
||||||
|
<Heart size="16" class="ml-1 mr-1" fill="rgb(var(--support))" />
|
||||||
|
<span>{$_('homepage.support_button')}</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col items-center gap-6">
|
||||||
|
<DocsLoader path="about/translation.md" />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex flex-col md:flex-row items-center justify-center gap-x-12 gap-y-6 p-6 mx-6 border rounded-md shadow-lg"
|
||||||
|
>
|
||||||
|
<div class="shrink-0 flex flex-col sm:flex-row md:flex-col items-center gap-x-4 gap-y-2">
|
||||||
|
<div class="text-lg font-semibold text-muted-foreground">
|
||||||
|
❤️ {$_('homepage.supported_by')}
|
||||||
|
</div>
|
||||||
|
<a href="https://www.mapbox.com/" target="_blank">
|
||||||
|
<Logo company="mapbox" class="w-60" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<DocsLoader path="about/mapbox.md" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<script>
|
<script>
|
||||||
import Docs from '$lib/components/docs/Docs.svx';
|
import Docs from '$lib/components/docs/Docs.svelte';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Docs />
|
<Docs />
|
||||||
|
BIN
website/static/map.png
Normal file
BIN
website/static/map.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 MiB |
BIN
website/static/profile-dark.png
Normal file
BIN
website/static/profile-dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 313 KiB |
BIN
website/static/profile-light.png
Normal file
BIN
website/static/profile-light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 299 KiB |
Reference in New Issue
Block a user