forked from MapComplete/MapComplete
Chore: reformat all files with prettier
This commit is contained in:
parent
5757ae5dea
commit
d008dcb54d
214 changed files with 8926 additions and 8196 deletions
|
@ -1,17 +1,20 @@
|
|||
<script lang="ts">
|
||||
/**
|
||||
* Wrapper around 'subtleButton' with an arrow pointing to the right
|
||||
* See also: NextButton
|
||||
*/
|
||||
import SubtleButton from "./SubtleButton.svelte";
|
||||
import {ChevronLeftIcon} from "@rgossiaux/svelte-heroicons/solid";
|
||||
import {createEventDispatcher} from "svelte";
|
||||
/**
|
||||
* Wrapper around 'subtleButton' with an arrow pointing to the right
|
||||
* See also: NextButton
|
||||
*/
|
||||
import SubtleButton from "./SubtleButton.svelte"
|
||||
import { ChevronLeftIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
const dispatch = createEventDispatcher<{ click }>()
|
||||
export let clss = ""
|
||||
const dispatch = createEventDispatcher<{ click }>()
|
||||
export let clss = ""
|
||||
</script>
|
||||
|
||||
<SubtleButton on:click={() => dispatch("click")} options={{extraClasses:clss+ " flex items-center"}}>
|
||||
<ChevronLeftIcon class="w-12 h-12" slot="image"/>
|
||||
<slot slot="message"/>
|
||||
<SubtleButton
|
||||
on:click={() => dispatch("click")}
|
||||
options={{ extraClasses: clss + " flex items-center" }}
|
||||
>
|
||||
<ChevronLeftIcon class="w-12 h-12" slot="image" />
|
||||
<slot slot="message" />
|
||||
</SubtleButton>
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
<script lang="ts">
|
||||
import { UIEventSource } from "../../Logic/UIEventSource.js";
|
||||
import { UIEventSource } from "../../Logic/UIEventSource.js"
|
||||
|
||||
/**
|
||||
* For some stupid reason, it is very hard to bind inputs
|
||||
*/
|
||||
export let selected: UIEventSource<boolean>;
|
||||
let _c: boolean = selected.data ?? true;
|
||||
export let selected: UIEventSource<boolean>
|
||||
let _c: boolean = selected.data ?? true
|
||||
$: selected.setData(_c)
|
||||
|
||||
</script>
|
||||
|
||||
<input type="checkbox" bind:checked={_c} />
|
||||
|
|
|
@ -3,84 +3,82 @@
|
|||
* This overlay element will regularly show a hand that swipes over the underlying element.
|
||||
* This element will hide as soon as the Store 'hideSignal' receives a change (which is not undefined)
|
||||
*/
|
||||
import { Store } from "../../Logic/UIEventSource";
|
||||
import { onDestroy } from "svelte";
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import { onDestroy } from "svelte"
|
||||
|
||||
let mainElem: HTMLElement;
|
||||
export let hideSignal: Store<any>;
|
||||
function hide(){
|
||||
mainElem.style.visibility = "hidden";
|
||||
let mainElem: HTMLElement
|
||||
export let hideSignal: Store<any>
|
||||
function hide() {
|
||||
mainElem.style.visibility = "hidden"
|
||||
}
|
||||
if (hideSignal) {
|
||||
onDestroy(hideSignal.addCallbackD(() => {
|
||||
console.log("Received hide signal")
|
||||
hide()
|
||||
return true;
|
||||
}));
|
||||
onDestroy(
|
||||
hideSignal.addCallbackD(() => {
|
||||
console.log("Received hide signal")
|
||||
hide()
|
||||
return true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
$: {
|
||||
mainElem?.addEventListener("click",_ => hide())
|
||||
mainElem?.addEventListener("touchstart",_ => hide())
|
||||
}
|
||||
</script>
|
||||
|
||||
$: {
|
||||
mainElem?.addEventListener("click", (_) => hide())
|
||||
mainElem?.addEventListener("touchstart", (_) => hide())
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={mainElem} class="absolute bottom-0 right-0 w-full h-full">
|
||||
<div id="hand-container" class="pointer-events-none">
|
||||
<img src="./assets/svg/hand.svg"/>
|
||||
<img src="./assets/svg/hand.svg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
@keyframes hand-drag-animation {
|
||||
/* This is the animation on the little extra hand on the location input. If fades in, invites the user to interact/drag the map */
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
6% {
|
||||
opacity: 1;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
12% {
|
||||
opacity: 1;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
24% {
|
||||
opacity: 1;
|
||||
transform: rotate(-00deg);
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 1;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
36% {
|
||||
opacity: 0;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
@keyframes hand-drag-animation {
|
||||
/* This is the animation on the little extra hand on the location input. If fades in, invites the user to interact/drag the map */
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
6% {
|
||||
opacity: 1;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
#hand-container {
|
||||
position: absolute;
|
||||
width: 2rem;
|
||||
left: calc(50% + 4rem);
|
||||
top: calc(50%);
|
||||
opacity: 0.7;
|
||||
animation: hand-drag-animation 4s ease-in-out infinite;
|
||||
transform-origin: 50% 125%;
|
||||
12% {
|
||||
opacity: 1;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
24% {
|
||||
opacity: 1;
|
||||
transform: rotate(-00deg);
|
||||
}
|
||||
|
||||
30% {
|
||||
opacity: 1;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
36% {
|
||||
opacity: 0;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: rotate(-30deg);
|
||||
}
|
||||
}
|
||||
|
||||
#hand-container {
|
||||
position: absolute;
|
||||
width: 2rem;
|
||||
left: calc(50% + 4rem);
|
||||
top: calc(50%);
|
||||
opacity: 0.7;
|
||||
animation: hand-drag-animation 4s ease-in-out infinite;
|
||||
transform-origin: 50% 125%;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
<script lang="ts">
|
||||
import { UIEventSource } from "../../Logic/UIEventSource.js";
|
||||
import { UIEventSource } from "../../Logic/UIEventSource.js"
|
||||
|
||||
/**
|
||||
* For some stupid reason, it is very hard to bind inputs
|
||||
*/
|
||||
export let value: UIEventSource<number>;
|
||||
let i: number = value.data;
|
||||
export let value: UIEventSource<number>
|
||||
let i: number = value.data
|
||||
$: value.setData(i)
|
||||
|
||||
</script>
|
||||
|
||||
<select bind:value={i} >
|
||||
<slot></slot>
|
||||
<select bind:value={i}>
|
||||
<slot />
|
||||
</select>
|
||||
|
|
|
@ -1,31 +1,36 @@
|
|||
<script lang="ts">
|
||||
import {createEventDispatcher} from "svelte";
|
||||
import {XCircleIcon} from "@rgossiaux/svelte-heroicons/solid";
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
|
||||
/**
|
||||
* The slotted element will be shown on top, with a lower-opacity border
|
||||
*/
|
||||
const dispatch = createEventDispatcher<{ close }>();
|
||||
/**
|
||||
* The slotted element will be shown on top, with a lower-opacity border
|
||||
*/
|
||||
const dispatch = createEventDispatcher<{ close }>()
|
||||
</script>
|
||||
|
||||
<div class="absolute top-0 right-0 w-screen h-screen p-4 md:p-6" style="background-color: #00000088">
|
||||
<div class="content normal-background">
|
||||
<div class="rounded-xl h-full">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<slot name="close-button">
|
||||
<!-- The close button is placed _after_ the default slot in order to always paint it on top -->
|
||||
<div class="w-8 h-8 absolute right-10 top-10 cursor-pointer" on:click={() => dispatch("close")}>
|
||||
<XCircleIcon/>
|
||||
</div>
|
||||
</slot>
|
||||
<div
|
||||
class="absolute top-0 right-0 w-screen h-screen p-4 md:p-6"
|
||||
style="background-color: #00000088"
|
||||
>
|
||||
<div class="content normal-background">
|
||||
<div class="rounded-xl h-full">
|
||||
<slot />
|
||||
</div>
|
||||
<slot name="close-button">
|
||||
<!-- The close button is placed _after_ the default slot in order to always paint it on top -->
|
||||
<div
|
||||
class="w-8 h-8 absolute right-10 top-10 cursor-pointer"
|
||||
on:click={() => dispatch("close")}
|
||||
>
|
||||
<XCircleIcon />
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.content {
|
||||
height: calc( 100vh - 2rem );
|
||||
height: calc(100vh - 2rem);
|
||||
border-radius: 0.5rem;
|
||||
overflow-x: auto;
|
||||
box-shadow: 0 0 1rem #00000088;
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
* Given an HTML string, properly shows this
|
||||
*/
|
||||
|
||||
export let src: string;
|
||||
let htmlElem: HTMLElement;
|
||||
export let src: string
|
||||
let htmlElem: HTMLElement
|
||||
$: {
|
||||
if (htmlElem) {
|
||||
htmlElem.innerHTML = src;
|
||||
htmlElem.innerHTML = src
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,5 @@
|
|||
</script>
|
||||
|
||||
{#if src !== undefined}
|
||||
<span bind:this={htmlElem} class={clss}></span>
|
||||
<span bind:this={htmlElem} class={clss} />
|
||||
{/if}
|
||||
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
<script lang="ts">
|
||||
import { UIEventSource } from "../../Logic/UIEventSource";
|
||||
import { onDestroy } from "svelte";
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { onDestroy } from "svelte"
|
||||
|
||||
/**
|
||||
* For some stupid reason, it is very hard to let {#if} work together with UIEventSources, so we wrap then here
|
||||
*/
|
||||
export let condition: UIEventSource<boolean>;
|
||||
let _c = condition.data;
|
||||
onDestroy(condition.addCallback(c => {
|
||||
/* Do _not_ abbreviate this as `.addCallback(c => _c = c)`. This is the same as writing `.addCallback(c => {return _c = c})`,
|
||||
export let condition: UIEventSource<boolean>
|
||||
let _c = condition.data
|
||||
onDestroy(
|
||||
condition.addCallback((c) => {
|
||||
/* Do _not_ abbreviate this as `.addCallback(c => _c = c)`. This is the same as writing `.addCallback(c => {return _c = c})`,
|
||||
which will _unregister_ the callback if `c = true`! */
|
||||
_c = c;
|
||||
return false
|
||||
}))
|
||||
|
||||
_c = c
|
||||
return false
|
||||
})
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if _c}
|
||||
<slot></slot>
|
||||
{:else}
|
||||
<slot name="else"></slot>
|
||||
<slot />
|
||||
{:else}
|
||||
<slot name="else" />
|
||||
{/if}
|
||||
|
|
|
@ -1,33 +1,34 @@
|
|||
<script lang="ts">
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import {onDestroy} from "svelte";
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { onDestroy } from "svelte"
|
||||
|
||||
/**
|
||||
* Functions as 'If', but uses 'display:hidden' instead.
|
||||
*/
|
||||
export let condition: UIEventSource<boolean>;
|
||||
let _c = condition.data;
|
||||
let hasBeenShownPositive = false
|
||||
let hasBeenShownNegative = false
|
||||
onDestroy(condition.addCallbackAndRun(c => {
|
||||
/* Do _not_ abbreviate this as `.addCallback(c => _c = c)`. This is the same as writing `.addCallback(c => {return _c = c})`,
|
||||
/**
|
||||
* Functions as 'If', but uses 'display:hidden' instead.
|
||||
*/
|
||||
export let condition: UIEventSource<boolean>
|
||||
let _c = condition.data
|
||||
let hasBeenShownPositive = false
|
||||
let hasBeenShownNegative = false
|
||||
onDestroy(
|
||||
condition.addCallbackAndRun((c) => {
|
||||
/* Do _not_ abbreviate this as `.addCallback(c => _c = c)`. This is the same as writing `.addCallback(c => {return _c = c})`,
|
||||
which will _unregister_ the callback if `c = true`! */
|
||||
hasBeenShownPositive = hasBeenShownPositive || c
|
||||
hasBeenShownNegative = hasBeenShownNegative || !c
|
||||
_c = c;
|
||||
return false
|
||||
}))
|
||||
|
||||
hasBeenShownPositive = hasBeenShownPositive || c
|
||||
hasBeenShownNegative = hasBeenShownNegative || !c
|
||||
_c = c
|
||||
return false
|
||||
})
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if hasBeenShownPositive}
|
||||
<span class={_c ? "" : "hidden"}>
|
||||
<slot/>
|
||||
</span>
|
||||
<span class={_c ? "" : "hidden"}>
|
||||
<slot />
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
{#if hasBeenShownNegative}
|
||||
<span class={_c ? "hidden" : ""}>
|
||||
<slot name="else"/>
|
||||
</span>
|
||||
<span class={_c ? "hidden" : ""}>
|
||||
<slot name="else" />
|
||||
</span>
|
||||
{/if}
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
<script lang="ts">
|
||||
import { UIEventSource } from "../../Logic/UIEventSource";
|
||||
import { onDestroy } from "svelte";
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import { onDestroy } from "svelte"
|
||||
|
||||
/**
|
||||
* For some stupid reason, it is very hard to let {#if} work together with UIEventSources, so we wrap then here
|
||||
*/
|
||||
export let condition: UIEventSource<boolean>;
|
||||
let _c = !condition.data;
|
||||
onDestroy(condition.addCallback(c => {
|
||||
_c = !c;
|
||||
return false
|
||||
}))
|
||||
export let condition: UIEventSource<boolean>
|
||||
let _c = !condition.data
|
||||
onDestroy(
|
||||
condition.addCallback((c) => {
|
||||
_c = !c
|
||||
return false
|
||||
})
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if _c}
|
||||
<slot></slot>
|
||||
<slot />
|
||||
{/if}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<script>
|
||||
import ToSvelte from "./ToSvelte.svelte";
|
||||
import Svg from "../../Svg";
|
||||
import ToSvelte from "./ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
</script>
|
||||
|
||||
<div class="pl-2 p-1 flex">
|
||||
<div class="animate-spin self-center w-6 h-6 min-w-6">
|
||||
<ToSvelte construct={Svg.loading_svg()}></ToSvelte>
|
||||
<ToSvelte construct={Svg.loading_svg()} />
|
||||
</div>
|
||||
<div class="ml-2">
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<script lang="ts">
|
||||
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
|
||||
import Translations from "../i18n/Translations.js";
|
||||
import Tr from "./Tr.svelte";
|
||||
import ToSvelte from "./ToSvelte.svelte";
|
||||
import Svg from "../../Svg";
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import Translations from "../i18n/Translations.js"
|
||||
import Tr from "./Tr.svelte"
|
||||
import ToSvelte from "./ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
|
||||
export let osmConnection: OsmConnection
|
||||
export let clss = ""
|
||||
export let osmConnection: OsmConnection
|
||||
export let clss = ""
|
||||
</script>
|
||||
|
||||
<button class={clss} on:click={() => osmConnection.AttemptLogin()}>
|
||||
<ToSvelte construct={Svg.login_svg().SetClass("w-12 m-1")}/>
|
||||
<slot name="message">
|
||||
<Tr t={Translations.t.general.loginWithOpenStreetMap}/>
|
||||
</slot>
|
||||
<ToSvelte construct={Svg.login_svg().SetClass("w-12 m-1")} />
|
||||
<slot name="message">
|
||||
<Tr t={Translations.t.general.loginWithOpenStreetMap} />
|
||||
</slot>
|
||||
</button>
|
||||
|
|
|
@ -1,47 +1,45 @@
|
|||
<script lang="ts">
|
||||
import Loading from "./Loading.svelte";
|
||||
import type { OsmServiceState } from "../../Logic/Osm/OsmConnection";
|
||||
import { Translation } from "../i18n/Translation";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Tr from "./Tr.svelte";
|
||||
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
|
||||
import {ImmutableStore, UIEventSource} from "../../Logic/UIEventSource";
|
||||
import Loading from "./Loading.svelte"
|
||||
import type { OsmServiceState } from "../../Logic/Osm/OsmConnection"
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Tr from "./Tr.svelte"
|
||||
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||
import { ImmutableStore, UIEventSource } from "../../Logic/UIEventSource"
|
||||
|
||||
export let state: {osmConnection: OsmConnection, featureSwitches?: { featureSwitchUserbadge?: UIEventSource<boolean>}};
|
||||
export let state: {
|
||||
osmConnection: OsmConnection
|
||||
featureSwitches?: { featureSwitchUserbadge?: UIEventSource<boolean> }
|
||||
}
|
||||
/**
|
||||
* If set, 'loading' will act as if we are already logged in.
|
||||
*/
|
||||
export let ignoreLoading: boolean = false
|
||||
let loadingStatus = state.osmConnection.loadingStatus;
|
||||
let badge = state.featureSwitches?.featureSwitchUserbadge ?? new ImmutableStore(true);
|
||||
const t = Translations.t.general;
|
||||
let loadingStatus = state.osmConnection.loadingStatus
|
||||
let badge = state.featureSwitches?.featureSwitchUserbadge ?? new ImmutableStore(true)
|
||||
const t = Translations.t.general
|
||||
const offlineModes: Partial<Record<OsmServiceState, Translation>> = {
|
||||
offline: t.loginFailedOfflineMode,
|
||||
unreachable: t.loginFailedUnreachableMode,
|
||||
unknown: t.loginFailedUnreachableMode,
|
||||
readonly: t.loginFailedReadonlyMode
|
||||
};
|
||||
const apiState = state.osmConnection.apiIsOnline;
|
||||
|
||||
|
||||
readonly: t.loginFailedReadonlyMode,
|
||||
}
|
||||
const apiState = state.osmConnection.apiIsOnline
|
||||
</script>
|
||||
|
||||
{#if $badge}
|
||||
{#if !ignoreLoading && $loadingStatus === "loading"}
|
||||
<slot name="loading">
|
||||
<Loading></Loading>
|
||||
<Loading />
|
||||
</slot>
|
||||
{:else if $loadingStatus === "error"}
|
||||
<div class="flex items-center alert max-w-64">
|
||||
<img src="./assets/svg/invalid.svg" class="w-8 h-8 m-2 shrink-0">
|
||||
<img src="./assets/svg/invalid.svg" class="w-8 h-8 m-2 shrink-0" />
|
||||
<Tr t={offlineModes[$apiState]} />
|
||||
</div>
|
||||
|
||||
{:else if $loadingStatus === "logged-in"}
|
||||
<slot></slot>
|
||||
<slot />
|
||||
{:else if $loadingStatus === "not-attempted"}
|
||||
<slot name="not-logged-in">
|
||||
|
||||
</slot>
|
||||
<slot name="not-logged-in" />
|
||||
{/if}
|
||||
{/if}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
/**
|
||||
* A round button with an icon and possible a small text, which hovers above the map
|
||||
*/
|
||||
const dispatch = createEventDispatcher()
|
||||
const dispatch = createEventDispatcher()
|
||||
export let cls = ""
|
||||
</script>
|
||||
|
||||
|
||||
<button on:click={e => dispatch("click", e)} class={"rounded-full h-fit w-fit m-0.5 md:m-1 p-0.5 sm:p-1 pointer-events-auto "+cls} >
|
||||
<slot/>
|
||||
<button
|
||||
on:click={(e) => dispatch("click", e)}
|
||||
class={"rounded-full h-fit w-fit m-0.5 md:m-1 p-0.5 sm:p-1 pointer-events-auto " + cls}
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
|
|
|
@ -1,20 +1,26 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { XCircleIcon } from "@rgossiaux/svelte-heroicons/solid";
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import { XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
|
||||
/**
|
||||
* The slotted element will be shown on the right side
|
||||
*/
|
||||
const dispatch = createEventDispatcher<{ close }>();
|
||||
const dispatch = createEventDispatcher<{ close }>()
|
||||
</script>
|
||||
|
||||
<div class="absolute top-0 right-0 h-screen overflow-auto w-full md:w-6/12 lg:w-5/12 xl:w-4/12 drop-shadow-2xl" style="max-width: 100vw; max-height: 100vh">
|
||||
<div
|
||||
class="absolute top-0 right-0 h-screen overflow-auto w-full md:w-6/12 lg:w-5/12 xl:w-4/12 drop-shadow-2xl"
|
||||
style="max-width: 100vw; max-height: 100vh"
|
||||
>
|
||||
<div class="flex flex-col m-0 normal-background">
|
||||
<slot name="close-button">
|
||||
<div class="w-8 h-8 absolute right-10 top-10 cursor-pointer" on:click={() => dispatch("close")}>
|
||||
<div
|
||||
class="w-8 h-8 absolute right-10 top-10 cursor-pointer"
|
||||
on:click={() => dispatch("close")}
|
||||
>
|
||||
<XCircleIcon />
|
||||
</div>
|
||||
</slot>
|
||||
<slot></slot>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
<script lang="ts">
|
||||
/**
|
||||
* Wrapper around 'subtleButton' with an arrow pointing to the right
|
||||
* See also: BackButton
|
||||
*/
|
||||
import SubtleButton from "./SubtleButton.svelte";
|
||||
import {ChevronRightIcon} from "@rgossiaux/svelte-heroicons/solid";
|
||||
import {createEventDispatcher} from "svelte";
|
||||
/**
|
||||
* Wrapper around 'subtleButton' with an arrow pointing to the right
|
||||
* See also: BackButton
|
||||
*/
|
||||
import SubtleButton from "./SubtleButton.svelte"
|
||||
import { ChevronRightIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
const dispatch = createEventDispatcher<{ click }>()
|
||||
|
||||
export let clss : string= ""
|
||||
const dispatch = createEventDispatcher<{ click }>()
|
||||
|
||||
export let clss: string = ""
|
||||
</script>
|
||||
|
||||
<SubtleButton on:click={() => dispatch("click")} options={{extraClasses: clss+" flex items-center"}}>
|
||||
<slot name="image" slot="image"/>
|
||||
<div class="w-full flex justify-between items-center" slot="message">
|
||||
<slot/>
|
||||
<ChevronRightIcon class="w-12 h-12"/>
|
||||
</div>
|
||||
<SubtleButton
|
||||
on:click={() => dispatch("click")}
|
||||
options={{ extraClasses: clss + " flex items-center" }}
|
||||
>
|
||||
<slot name="image" slot="image" />
|
||||
<div class="w-full flex justify-between items-center" slot="message">
|
||||
<slot />
|
||||
<ChevronRightIcon class="w-12 h-12" />
|
||||
</div>
|
||||
</SubtleButton>
|
||||
|
|
|
@ -1,33 +1,30 @@
|
|||
<script lang="ts">
|
||||
|
||||
import ToSvelte from "./ToSvelte.svelte";
|
||||
import Svg from "../../Svg";
|
||||
import ToSvelte from "./ToSvelte.svelte"
|
||||
import Svg from "../../Svg"
|
||||
|
||||
export let generateShareData: () => {
|
||||
export let generateShareData: () => {
|
||||
text: string
|
||||
title: string
|
||||
url: string
|
||||
}
|
||||
function share(){
|
||||
}
|
||||
function share() {
|
||||
if (!navigator.share) {
|
||||
console.log("web share not supported")
|
||||
return;
|
||||
console.log("web share not supported")
|
||||
return
|
||||
}
|
||||
navigator
|
||||
.share(generateShareData())
|
||||
.then(() => {
|
||||
console.log("Thanks for sharing!")
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Couldn't share because of`, err.message)
|
||||
})
|
||||
}
|
||||
|
||||
.share(generateShareData())
|
||||
.then(() => {
|
||||
console.log("Thanks for sharing!")
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(`Couldn't share because of`, err.message)
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<button on:click={share} class="secondary w-8 h-8 m-0 p-0">
|
||||
<slot name="content">
|
||||
<ToSvelte construct={Svg.share_svg().SetClass("w-7 h-7 p-1")}/>
|
||||
</slot>
|
||||
<slot name="content">
|
||||
<ToSvelte construct={Svg.share_svg().SetClass("w-7 h-7 p-1")} />
|
||||
</slot>
|
||||
</button>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import {createEventDispatcher} from "svelte";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import Img from "./Img";
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import Img from "./Img"
|
||||
|
||||
export let imageUrl: string | BaseUIElement = undefined
|
||||
export let message: string | BaseUIElement = undefined
|
||||
|
@ -10,22 +10,22 @@
|
|||
extraClasses?: string
|
||||
} = {}
|
||||
|
||||
let imgClasses = "block justify-center shrink-0 mr-4 " + (options?.imgSize ?? "h-11 w-11");
|
||||
const dispatch = createEventDispatcher<{click}>()
|
||||
let imgClasses = "block justify-center shrink-0 mr-4 " + (options?.imgSize ?? "h-11 w-11")
|
||||
const dispatch = createEventDispatcher<{ click }>()
|
||||
</script>
|
||||
|
||||
<button
|
||||
class={(options.extraClasses??"") + ' secondary no-image-background'}
|
||||
class={(options.extraClasses ?? "") + " secondary no-image-background"}
|
||||
target={options?.newTab ? "_blank" : ""}
|
||||
on:click={(e) => dispatch("click", e)}
|
||||
>
|
||||
<slot name="image">
|
||||
{#if imageUrl !== undefined}
|
||||
{#if typeof imageUrl === "string"}
|
||||
<Img src={imageUrl} class={imgClasses}></Img>
|
||||
<Img src={imageUrl} class={imgClasses} />
|
||||
{/if}
|
||||
{/if}
|
||||
</slot>
|
||||
|
||||
<slot name="message"/>
|
||||
<slot name="message" />
|
||||
</button>
|
||||
|
|
|
@ -5,10 +5,10 @@ import { VariableUiElement } from "./VariableUIElement"
|
|||
import Lazy from "./Lazy"
|
||||
import Loading from "./Loading"
|
||||
import SvelteUIElement from "./SvelteUIElement"
|
||||
import SubtleLink from "./SubtleLink.svelte";
|
||||
import Translations from "../i18n/Translations";
|
||||
import Combine from "./Combine";
|
||||
import Img from "./Img";
|
||||
import SubtleLink from "./SubtleLink.svelte"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Combine from "./Combine"
|
||||
import Img from "./Img"
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
|
@ -40,26 +40,28 @@ export class SubtleButton extends UIElement {
|
|||
}
|
||||
|
||||
protected InnerRender(): string | BaseUIElement {
|
||||
if(this.options.url !== undefined){
|
||||
return new SvelteUIElement(SubtleLink, {href: this.options.url, newTab: this.options.newTab})
|
||||
if (this.options.url !== undefined) {
|
||||
return new SvelteUIElement(SubtleLink, {
|
||||
href: this.options.url,
|
||||
newTab: this.options.newTab,
|
||||
})
|
||||
}
|
||||
|
||||
const classes = "button";
|
||||
const message = Translations.W(this.message)?.SetClass("block overflow-ellipsis no-images flex-shrink");
|
||||
let img;
|
||||
const imgClasses = "block justify-center flex-none mr-4 " + (this.options?.imgSize ?? "h-11 w-11")
|
||||
const classes = "button"
|
||||
const message = Translations.W(this.message)?.SetClass(
|
||||
"block overflow-ellipsis no-images flex-shrink"
|
||||
)
|
||||
let img
|
||||
const imgClasses =
|
||||
"block justify-center flex-none mr-4 " + (this.options?.imgSize ?? "h-11 w-11")
|
||||
if ((this.imageUrl ?? "") === "") {
|
||||
img = undefined;
|
||||
} else if (typeof (this.imageUrl) === "string") {
|
||||
img = undefined
|
||||
} else if (typeof this.imageUrl === "string") {
|
||||
img = new Img(this.imageUrl)?.SetClass(imgClasses)
|
||||
} else {
|
||||
img = this.imageUrl?.SetClass(imgClasses);
|
||||
img = this.imageUrl?.SetClass(imgClasses)
|
||||
}
|
||||
const button = new Combine([
|
||||
img,
|
||||
message
|
||||
]).SetClass("flex items-center group w-full")
|
||||
|
||||
const button = new Combine([img, message]).SetClass("flex items-center group w-full")
|
||||
|
||||
this.SetClass(classes)
|
||||
return button
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import {onMount} from "svelte";
|
||||
import BaseUIElement from "../BaseUIElement";
|
||||
import Img from "./Img";
|
||||
import { onMount } from "svelte"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import Img from "./Img"
|
||||
|
||||
export let imageUrl: string | BaseUIElement = undefined
|
||||
export let href: string
|
||||
|
@ -10,10 +10,9 @@
|
|||
imgSize?: string
|
||||
// extraClasses?: string
|
||||
} = {}
|
||||
|
||||
|
||||
let imgElem: HTMLElement;
|
||||
let imgClasses = "block justify-center shrink-0 mr-4 " + (options?.imgSize ?? "h-11 w-11");
|
||||
let imgElem: HTMLElement
|
||||
let imgClasses = "block justify-center shrink-0 mr-4 " + (options?.imgSize ?? "h-11 w-11")
|
||||
|
||||
onMount(() => {
|
||||
// Image
|
||||
|
@ -27,24 +26,23 @@
|
|||
}
|
||||
if (img) imgElem.replaceWith(img.ConstructElement())
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
|
||||
<a
|
||||
class={(options.extraClasses??"") + ' button text-ellipsis'}
|
||||
class={(options.extraClasses ?? "") + " button text-ellipsis"}
|
||||
{href}
|
||||
target={(newTab ? "_blank" : undefined) }
|
||||
target={newTab ? "_blank" : undefined}
|
||||
>
|
||||
<slot name="image">
|
||||
{#if imageUrl !== undefined}
|
||||
{#if typeof imageUrl === "string"}
|
||||
<Img src={imageUrl} class={imgClasses}></Img>
|
||||
{:else }
|
||||
<Img src={imageUrl} class={imgClasses} />
|
||||
{:else}
|
||||
<template bind:this={imgElem} />
|
||||
{/if}
|
||||
{/if}
|
||||
</slot>
|
||||
|
||||
<slot/>
|
||||
<slot />
|
||||
</a>
|
||||
|
|
|
@ -1,121 +1,126 @@
|
|||
<script lang="ts">
|
||||
/**
|
||||
* Thin wrapper around 'TabGroup' which binds the state
|
||||
*/
|
||||
/**
|
||||
* Thin wrapper around 'TabGroup' which binds the state
|
||||
*/
|
||||
|
||||
import {Tab, TabGroup, TabList, TabPanel, TabPanels} from "@rgossiaux/svelte-headlessui";
|
||||
import {UIEventSource} from "../../Logic/UIEventSource";
|
||||
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
|
||||
export let tab: UIEventSource<number>;
|
||||
let tabElements: HTMLElement[] = [];
|
||||
$: tabElements[$tab]?.click();
|
||||
$: {
|
||||
if (tabElements[tab.data]) {
|
||||
window.setTimeout(() => tabElements[tab.data].click(), 50)
|
||||
}
|
||||
export let tab: UIEventSource<number>
|
||||
let tabElements: HTMLElement[] = []
|
||||
$: tabElements[$tab]?.click()
|
||||
$: {
|
||||
if (tabElements[tab.data]) {
|
||||
window.setTimeout(() => tabElements[tab.data].click(), 50)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="tabbedgroup w-full h-full">
|
||||
<TabGroup class="h-full w-full flex flex-col" defaultIndex={1}
|
||||
on:change={(e) =>{if(e.detail >= 0){tab.setData( e.detail); }} }>
|
||||
<div class="interactive flex items-center justify-between sticky top-0">
|
||||
<TabList class="flex flex-wrap">
|
||||
{#if $$slots.title1}
|
||||
<Tab class={({selected}) => "tab "+(selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[0]} class="flex">
|
||||
<slot name="title0">
|
||||
Tab 0
|
||||
</slot>
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title1}
|
||||
<Tab class={({selected}) => "tab "+(selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[1]} class="flex">
|
||||
<slot name="title1"/>
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title2}
|
||||
<Tab class={({selected}) => "tab "+(selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[2]} class="flex">
|
||||
<slot name="title2"/>
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title3}
|
||||
<Tab class={({selected}) => "tab "+(selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[3]} class="flex">
|
||||
<slot name="title3"/>
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title4}
|
||||
<Tab class={({selected}) => "tab "+(selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[4]} class="flex">
|
||||
<slot name="title4"/>
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
</TabList>
|
||||
<slot name="post-tablist"/>
|
||||
</div>
|
||||
<div class="overflow-y-auto normal-background">
|
||||
|
||||
<TabPanels defaultIndex={$tab}>
|
||||
<TabPanel>
|
||||
<slot name="content0">
|
||||
<div>Empty</div>
|
||||
</slot>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content1"/>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content2"/>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content3"/>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content4"/>
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</div>
|
||||
</TabGroup>
|
||||
<TabGroup
|
||||
class="h-full w-full flex flex-col"
|
||||
defaultIndex={1}
|
||||
on:change={(e) => {
|
||||
if (e.detail >= 0) {
|
||||
tab.setData(e.detail)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div class="interactive flex items-center justify-between sticky top-0">
|
||||
<TabList class="flex flex-wrap">
|
||||
{#if $$slots.title1}
|
||||
<Tab class={({ selected }) => "tab " + (selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[0]} class="flex">
|
||||
<slot name="title0">Tab 0</slot>
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title1}
|
||||
<Tab class={({ selected }) => "tab " + (selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[1]} class="flex">
|
||||
<slot name="title1" />
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title2}
|
||||
<Tab class={({ selected }) => "tab " + (selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[2]} class="flex">
|
||||
<slot name="title2" />
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title3}
|
||||
<Tab class={({ selected }) => "tab " + (selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[3]} class="flex">
|
||||
<slot name="title3" />
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
{#if $$slots.title4}
|
||||
<Tab class={({ selected }) => "tab " + (selected ? "primary" : "")}>
|
||||
<div bind:this={tabElements[4]} class="flex">
|
||||
<slot name="title4" />
|
||||
</div>
|
||||
</Tab>
|
||||
{/if}
|
||||
</TabList>
|
||||
<slot name="post-tablist" />
|
||||
</div>
|
||||
<div class="overflow-y-auto normal-background">
|
||||
<TabPanels defaultIndex={$tab}>
|
||||
<TabPanel>
|
||||
<slot name="content0">
|
||||
<div>Empty</div>
|
||||
</slot>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content1" />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content2" />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content3" />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<slot name="content4" />
|
||||
</TabPanel>
|
||||
</TabPanels>
|
||||
</div>
|
||||
</TabGroup>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tabbedgroup {
|
||||
max-height: 100vh;
|
||||
height: 100%;
|
||||
}
|
||||
.tabbedgroup {
|
||||
max-height: 100vh;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:global(.tab) {
|
||||
margin: 0.25rem;
|
||||
padding: 0.25rem;
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
:global(.tab) {
|
||||
margin: 0.25rem;
|
||||
padding: 0.25rem;
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
:global(.tab .flex) {
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
:global(.tab .flex) {
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
:global(.tab span|div) {
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
display: flex;
|
||||
}
|
||||
:global(.tab span|div) {
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
:global(.tab-selected svg) {
|
||||
fill: var(--catch-detail-color-contrast);
|
||||
}
|
||||
:global(.tab-selected svg) {
|
||||
fill: var(--catch-detail-color-contrast);
|
||||
}
|
||||
|
||||
:global(.tab-unselected) {
|
||||
background-color: var(--background-color) !important;
|
||||
color: var(--foreground-color) !important;
|
||||
}
|
||||
:global(.tab-unselected) {
|
||||
background-color: var(--background-color) !important;
|
||||
color: var(--foreground-color) !important;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -78,7 +78,7 @@ export default class Table extends BaseUIElement {
|
|||
for (let j = 0; j < row.length; j++) {
|
||||
try {
|
||||
let elem = row[j]
|
||||
if(elem?.ConstructElement === undefined){
|
||||
if (elem?.ConstructElement === undefined) {
|
||||
continue
|
||||
}
|
||||
const htmlElem = elem?.ConstructElement()
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
<script lang="ts">
|
||||
import BaseUIElement from "../BaseUIElement.js";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import BaseUIElement from "../BaseUIElement.js"
|
||||
import { onDestroy, onMount } from "svelte"
|
||||
|
||||
export let construct: BaseUIElement | (() => BaseUIElement);
|
||||
let elem: HTMLElement;
|
||||
let html: HTMLElement;
|
||||
export let construct: BaseUIElement | (() => BaseUIElement)
|
||||
let elem: HTMLElement
|
||||
let html: HTMLElement
|
||||
onMount(() => {
|
||||
const uiElem = typeof construct === "function"
|
||||
? construct() : construct;
|
||||
html =uiElem?.ConstructElement();
|
||||
const uiElem = typeof construct === "function" ? construct() : construct
|
||||
html = uiElem?.ConstructElement()
|
||||
if (html !== undefined) {
|
||||
elem.replaceWith(html);
|
||||
elem.replaceWith(html)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
html?.remove();
|
||||
});
|
||||
|
||||
html?.remove()
|
||||
})
|
||||
</script>
|
||||
|
||||
<span bind:this={elem} />
|
||||
|
|
|
@ -2,36 +2,37 @@
|
|||
/**
|
||||
* Properly renders a translation
|
||||
*/
|
||||
import { Translation } from "../i18n/Translation";
|
||||
import { onDestroy } from "svelte";
|
||||
import Locale from "../i18n/Locale";
|
||||
import { Utils } from "../../Utils";
|
||||
import FromHtml from "./FromHtml.svelte";
|
||||
import WeblateLink from "./WeblateLink.svelte";
|
||||
import { Translation } from "../i18n/Translation"
|
||||
import { onDestroy } from "svelte"
|
||||
import Locale from "../i18n/Locale"
|
||||
import { Utils } from "../../Utils"
|
||||
import FromHtml from "./FromHtml.svelte"
|
||||
import WeblateLink from "./WeblateLink.svelte"
|
||||
|
||||
export let t: Translation;
|
||||
export let t: Translation
|
||||
export let cls: string = ""
|
||||
export let tags: Record<string, string> | undefined = undefined;
|
||||
export let tags: Record<string, string> | undefined = undefined
|
||||
// Text for the current language
|
||||
let txt: string | undefined;
|
||||
|
||||
$: onDestroy(Locale.language.addCallbackAndRunD(l => {
|
||||
const translation = t?.textFor(l);
|
||||
if (translation === undefined) {
|
||||
return;
|
||||
}
|
||||
if (tags) {
|
||||
txt = Utils.SubstituteKeys(txt, tags);
|
||||
} else {
|
||||
txt = translation;
|
||||
}
|
||||
}));
|
||||
let txt: string | undefined
|
||||
|
||||
$: onDestroy(
|
||||
Locale.language.addCallbackAndRunD((l) => {
|
||||
const translation = t?.textFor(l)
|
||||
if (translation === undefined) {
|
||||
return
|
||||
}
|
||||
if (tags) {
|
||||
txt = Utils.SubstituteKeys(txt, tags)
|
||||
} else {
|
||||
txt = translation
|
||||
}
|
||||
})
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if t}
|
||||
<span class={cls}>
|
||||
<FromHtml src={txt}></FromHtml>
|
||||
<WeblateLink context={t.context}></WeblateLink>
|
||||
<FromHtml src={txt} />
|
||||
<WeblateLink context={t.context} />
|
||||
</span>
|
||||
{/if}
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
<script lang="ts">
|
||||
import Locale from "../i18n/Locale";
|
||||
import LinkToWeblate from "./LinkToWeblate";
|
||||
import Locale from "../i18n/Locale"
|
||||
import LinkToWeblate from "./LinkToWeblate"
|
||||
|
||||
/**
|
||||
* Shows a small icon which will open up weblate; a contributor can translate the item for 'context' there
|
||||
*/
|
||||
export let context : string
|
||||
export let context: string
|
||||
|
||||
let linkToWeblate = Locale.showLinkToWeblate;
|
||||
let linkOnMobile = Locale.showLinkOnMobile;
|
||||
let language = Locale.language;
|
||||
let linkToWeblate = Locale.showLinkToWeblate
|
||||
let linkOnMobile = Locale.showLinkOnMobile
|
||||
let language = Locale.language
|
||||
</script>
|
||||
|
||||
|
||||
{#if !!context && context.indexOf(":") > 0}
|
||||
{#if $linkOnMobile}
|
||||
<a href={LinkToWeblate.hrefToWeblate($language, context)} target="_blank" class="mx-1 weblate-link">
|
||||
<a
|
||||
href={LinkToWeblate.hrefToWeblate($language, context)}
|
||||
target="_blank"
|
||||
class="mx-1 weblate-link"
|
||||
>
|
||||
<img src="./assets/svg/translate.svg" class="font-gray" />
|
||||
</a>
|
||||
{:else if $linkToWeblate}
|
||||
<a href={LinkToWeblate.hrefToWeblate($language, context)} class="weblate-link hidden-on-mobile mx-1" target="_blank">
|
||||
<a
|
||||
href={LinkToWeblate.hrefToWeblate($language, context)}
|
||||
class="weblate-link hidden-on-mobile mx-1"
|
||||
target="_blank"
|
||||
>
|
||||
<img src="./assets/svg/translate.svg" class="font-gray inline-block" />
|
||||
</a>
|
||||
{/if}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue