Skip to content

Commit

Permalink
Add marquee to handle localized text overflowing
Browse files Browse the repository at this point in the history
  • Loading branch information
mircearoata committed Sep 29, 2024
1 parent b4791da commit 6f1404d
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 77 deletions.
64 changes: 64 additions & 0 deletions frontend/src/lib/components/Marquee.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import { cubicInOut } from 'svelte/easing';
import { tweened } from 'svelte/motion';
let running = false;
export let animationSpeed = 8;
let clazz = '';
export { clazz as class };
let element: HTMLElement | null = null;
$: totalWidth = element?.scrollWidth ?? 0;
$: visibleWidth = element?.clientWidth || totalWidth;
$: scrollableWidth = totalWidth - visibleWidth;
$: animationDuration = scrollableWidth / animationSpeed * 1000;
$: hoverTranslation = tweened(0, { duration: animationDuration, easing: cubicInOut });
let interval: ReturnType<typeof setInterval> | null = null;
function stop() {
if (interval) {
clearInterval(interval);
interval = null;
}
$hoverTranslation = 0;
}
function start() {
stop();
if (animationDuration > 0) {
$hoverTranslation = 1;
interval = setInterval(() => {
$hoverTranslation = 1 - $hoverTranslation;
}, animationDuration);
}
}
onDestroy(stop);
$: {
animationDuration;
if (running) {
start();
} else {
stop();
}
}
</script>

<span
bind:this={element}
class="max-w-full overflow-hidden {clazz}"
role="marquee"
on:mouseover={() => running = true}
on:mouseout={() => running = false}
on:focus={() => running = true}
on:blur={() => running = false}
>
<span style="transform: translateX(-{$hoverTranslation * scrollableWidth}px);" class="relative inline-block">
<slot />
</span>
</span>
2 changes: 1 addition & 1 deletion frontend/src/lib/components/SVGIcon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
export { clazz as class };
</script>

<svg class="{clazz}" viewBox="0 0 24 24">
<svg class="shrink-0 {clazz}" viewBox="0 0 24 24">
<path d={icon} fill="currentColor" />
</svg>
2 changes: 1 addition & 1 deletion frontend/src/lib/components/Select.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
Wrap button in a div so that the trigger node location does not change.
-->
<button class="btn w-full h-full {buttonClass}" {disabled}>
<div class="grow flex justify-start min-w-0">
<div class="flex-auto text-start justify-start flex min-w-0 space-x-1 overflow-hidden">
{#if $$slots.selected}
<slot name="selected" item={value} />
{:else}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/lib/components/T.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
export let language: string | undefined = undefined;
export let parts: (TranslationComponentPart<SvelteComponent> | TranslationElementPart<keyof SvelteHTMLElements>)[] = [];
const { t } = getTranslate();
function split(content: string) {
Expand Down Expand Up @@ -85,10 +85,10 @@

{#each contentParts as part}
{#if typeof part === 'string'}
{part}
<span>{part}</span>
{:else if 'element' in part.component}
<svelte:element this={part.component.element} {...part.component.props}>{part.content}</svelte:element>
{:else}
<svelte:component this={part.component.component} {...part.component.props}>{part.content}</svelte:component>
{/if}
{/each}
{/each}
16 changes: 7 additions & 9 deletions frontend/src/lib/components/left-bar/LaunchButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { mdiOpenInNew, mdiTrayFull } from '@mdi/js';
import { getContextClient } from '@urql/svelte';
import Marquee from '$lib/components/Marquee.svelte';
import SvgIcon from '$lib/components/SVGIcon.svelte';
import T from '$lib/components/T.svelte';
import Tooltip from '$lib/components/Tooltip.svelte';
Expand Down Expand Up @@ -135,10 +136,9 @@
disabled={!$canInstallMods || !!$progress}
on:click={() => startQueue()}
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue={'Apply {queued, plural, one {one change} other {# changes}}'} keyName="launch-button.apply-queued" params={{ queued: $queuedMods.length }}/>
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiTrayFull}/>
Expand All @@ -162,10 +162,9 @@
class="btn h-8 w-full text-sm bg-surface-200-700-token"
disabled
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="SMM can't launch this install" keyName="launch-button.cant-launch"/>
</span>
<div class="grow" />
</Marquee>
</button>
{:else if $launchButton === 'normal' || $isGameRunning || $isLaunchingGame}
<button
Expand All @@ -176,10 +175,9 @@
disabled={!!$progress || $isGameRunning || $isLaunchingGame}
on:click={() => launchGame()}
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Play Satisfactory" keyName="launch-button.play"/>
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiOpenInNew}/>
Expand Down
61 changes: 25 additions & 36 deletions frontend/src/lib/components/left-bar/LeftBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import Settings from './Settings.svelte';
import Updates from './Updates.svelte';
import Marquee from '$lib/components/Marquee.svelte';
import SvgIcon from '$lib/components/SVGIcon.svelte';
import Select from '$lib/components/Select.svelte';
import T from '$lib/components/T.svelte';
Expand Down Expand Up @@ -240,10 +241,9 @@
disabled={!$canModify}
on:click={() => setModsEnabled(false)}
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Mods off" keyName="left-bar.mods-off"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiCloseCircle} />
Expand All @@ -253,10 +253,9 @@
class:!bg-primary-900={$modsEnabled}
disabled={!$canModify}
on:click={() => setModsEnabled(true)}>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Mods on" keyName="left-bar.mods-on"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiCheckCircle} />
Expand Down Expand Up @@ -301,10 +300,9 @@
class="btn w-1/3 bg-surface-200-700-token px-4 h-8 text-sm"
disabled={!$canModify}
on:click={() => modalStore.trigger({ type:'component', component: 'addProfile' })}>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Add" keyName="common.add"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5 text-primary-600"
icon={mdiPlusCircle} />
Expand All @@ -313,10 +311,9 @@
class="btn w-1/3 bg-surface-200-700-token px-2 h-8 text-sm"
disabled={!$canModify}
on:click={() => modalStore.trigger({ type:'component', component: { ref: RenameProfile, props: { profile: $selectedProfile } } })}>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Rename" keyName="common.rename"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5 text-warning-500"
icon={mdiPencil} />
Expand All @@ -325,10 +322,9 @@
class="btn w-1/3 bg-surface-200-700-token px-3 h-8 text-sm"
disabled={!$canModify || $profiles.length === 1}
on:click={() => modalStore.trigger({ type:'component', component: { ref: DeleteProfile, props: { profile: $selectedProfile } } })}>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Delete" keyName="common.delete"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5 text-error-700"
icon={mdiTrashCan} />
Expand All @@ -340,10 +336,9 @@
disabled={!$canModify}
on:click={() => modalStore.trigger({ type: 'component', component: 'importProfile' })}
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Import" keyName="common.import"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiDownload} />
Expand All @@ -353,10 +348,9 @@
disabled={!$canModify}
on:click={() => exportCurrentProfile()}
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Export" keyName="left-bar.export"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiUpload} />
Expand Down Expand Up @@ -384,10 +378,9 @@
<button
class="btn px-4 h-8 w-full text-sm bg-surface-200-700-token"
on:click={() => modalStore.trigger({ type: 'component', component: 'serverManager' })}>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Manage Servers" keyName="left-bar.manage-servers"/>
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiServerNetwork} />
Expand All @@ -397,10 +390,9 @@
class="btn w-full bg-surface-200-700-token px-4 h-8 text-sm"
on:click={() => BrowserOpenURL('https://docs.ficsit.app/satisfactory-modding/latest/ForUsers/SatisfactoryModManager.html')}
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Help" keyName="left-bar.help"/>
</span>
<div class="grow"/>
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiHelpCircle} />
Expand All @@ -413,32 +405,29 @@
<button
class="btn w-full bg-surface-200-700-token px-4 h-8 text-sm"
on:click={() => BrowserOpenURL($siteURL)}>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="ficsit.app (Mod Repository)" keyName="left-bar.ficsit-app"/>
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiWeb} />
</button>
<button
class="btn w-full bg-surface-200-700-token px-4 h-8 text-sm"
on:click={() => BrowserOpenURL('https://discord.ficsit.app/')}>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Satisfactory Modding Discord" keyName="left-bar.satisfactory-modding-discord"/>
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={siDiscord.path} />
</button>
<button
class="btn w-full bg-surface-200-700-token px-4 h-8 text-sm"
on:click={() => BrowserOpenURL('https://github.com/satisfactorymodding/SatisfactoryModManager')} >
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="SMM GitHub" keyName="left-bar.smm-github"/>
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={siGithub.path} />
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/lib/components/left-bar/Settings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { getTranslate } from '@tolgee/svelte';
import { getContextClient } from '@urql/svelte';
import Marquee from '$lib/components/Marquee.svelte';
import SvgIcon from '$lib/components/SVGIcon.svelte';
import T from '$lib/components/T.svelte';
import { GetModNameDocument } from '$lib/generated';
Expand Down Expand Up @@ -190,10 +191,9 @@
<div class="w-full h-8" use:popup={settingsMenu}>
<button class="btn px-4 h-full w-full text-sm bg-surface-200-700-token"
>
<span>
<Marquee class="flex-auto text-start">
<T defaultValue="Mod Manager Settings" keyName="settings.title"/>
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiTune} />
Expand Down
11 changes: 5 additions & 6 deletions frontend/src/lib/components/left-bar/Updates.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { mdiCheckCircle, mdiSync } from '@mdi/js';
import Marquee from '$lib/components/Marquee.svelte';
import SvgIcon from '$lib/components/SVGIcon.svelte';
import T from '$lib/components/T.svelte';
import { getModalStore } from '$lib/skeletonExtensions';
Expand Down Expand Up @@ -43,16 +44,15 @@
class="btn w-full bg-surface-200-700-token px-4 h-8 text-sm"
class:!bg-primary-600={$smmUpdate || $unignoredUpdates.length > 0}
on:click={() => showUpdateDialog()}>
<span>
<Marquee class="flex-auto text-start">
{#if $smmUpdate}
<T defaultValue="SMM update available" keyName="updates.smm-update-available"/>
{:else if $unignoredUpdates.length > 0}
<T defaultValue={'{updates} mod {updates, plural, one {update} other {updates}} available'} keyName="updates.mod-update-available" params={{ updates: $unignoredUpdates.length }}/>
{:else}
<T defaultValue="No mod/SMM updates right now" keyName="updates.no-updates"/>
{/if}
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5"
icon={mdiCheckCircle} />
Expand All @@ -62,14 +62,13 @@
class="btn w-full bg-surface-200-700-token px-4 h-8 text-sm"
disabled={!!$progress || $updateCheckInProgress}
on:click={checkForAllUpdates}>
<span>
<Marquee class="flex-auto text-start">
{#if $updateCheckInProgress}
<T defaultValue="Checking for updates..." keyName="updates.checking-for-updates"/>
{:else}
<T defaultValue="Check for updates" keyName="updates.check-for-updates"/>
{/if}
</span>
<div class="grow" />
</Marquee>
<SvgIcon
class="h-5 w-5 {$updateCheckInProgress ? 'update-check' : ''}"
icon={mdiSync} />
Expand Down
Loading

0 comments on commit 6f1404d

Please sign in to comment.