mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
chore(web): migration svelte 5 syntax (#13883)
This commit is contained in:
parent
9203a61709
commit
0b3742cf13
310 changed files with 6435 additions and 4176 deletions
|
|
@ -3,7 +3,11 @@
|
|||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let albumType: keyof AlbumStatisticsResponseDto;
|
||||
interface Props {
|
||||
albumType: keyof AlbumStatisticsResponseDto;
|
||||
}
|
||||
|
||||
let { albumType }: Props = $props();
|
||||
|
||||
const handleAlbumCount = async () => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,11 @@
|
|||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
export let assetStats: NonNullable<Parameters<typeof getAssetStatistics>[0]>;
|
||||
interface Props {
|
||||
assetStats: NonNullable<Parameters<typeof getAssetStatistics>[0]>;
|
||||
}
|
||||
|
||||
let { assetStats }: Props = $props();
|
||||
</script>
|
||||
|
||||
{#await getAssetStatistics(assetStats)}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@
|
|||
import { getButtonVisibility } from '$lib/utils/purchase-utils';
|
||||
import SupporterBadge from '$lib/components/shared-components/side-bar/supporter-badge.svelte';
|
||||
|
||||
let showMessage = false;
|
||||
let isOpen = false;
|
||||
let hoverMessage = false;
|
||||
let hoverButton = false;
|
||||
let showMessage = $state(false);
|
||||
let isOpen = $state(false);
|
||||
let hoverMessage = $state(false);
|
||||
let hoverButton = $state(false);
|
||||
|
||||
let showBuyButton = getButtonVisibility();
|
||||
let showBuyButton = $state(getButtonVisibility());
|
||||
|
||||
const { isPurchased } = purchaseStore;
|
||||
|
||||
|
|
@ -63,13 +63,15 @@
|
|||
}
|
||||
};
|
||||
|
||||
$: if (showMessage && !hoverMessage && !hoverButton) {
|
||||
setTimeout(() => {
|
||||
if (!hoverMessage && !hoverButton) {
|
||||
showMessage = false;
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
$effect(() => {
|
||||
if (showMessage && !hoverMessage && !hoverButton) {
|
||||
setTimeout(() => {
|
||||
if (!hoverMessage && !hoverButton) {
|
||||
showMessage = false;
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if isOpen}
|
||||
|
|
@ -79,7 +81,7 @@
|
|||
<div class="hidden md:block license-status pl-4 text-sm">
|
||||
{#if $isPurchased && $preferences.purchase.showSupportBadge}
|
||||
<button
|
||||
on:click={() => goto(`${AppRoute.USER_SETTINGS}?isOpen=user-purchase-settings`)}
|
||||
onclick={() => goto(`${AppRoute.USER_SETTINGS}?isOpen=user-purchase-settings`)}
|
||||
class="w-full"
|
||||
type="button"
|
||||
>
|
||||
|
|
@ -88,11 +90,11 @@
|
|||
{:else if !$isPurchased && showBuyButton && getAccountAge() > 14}
|
||||
<button
|
||||
type="button"
|
||||
on:click={openPurchaseModal}
|
||||
on:mouseover={onButtonHover}
|
||||
on:mouseleave={() => (hoverButton = false)}
|
||||
on:focus={onButtonHover}
|
||||
on:blur={() => (hoverButton = false)}
|
||||
onclick={openPurchaseModal}
|
||||
onmouseover={onButtonHover}
|
||||
onmouseleave={() => (hoverButton = false)}
|
||||
onfocus={onButtonHover}
|
||||
onblur={() => (hoverButton = false)}
|
||||
class="p-2 flex justify-between place-items-center place-content-center border border-immich-primary/20 dark:border-immich-dark-primary/10 mt-2 rounded-lg shadow-md dark:bg-immich-dark-primary/10 w-full"
|
||||
>
|
||||
<div class="flex justify-between w-full place-items-center place-content-center">
|
||||
|
|
@ -122,10 +124,10 @@
|
|||
<div
|
||||
class="w-[500px] absolute bottom-[75px] left-[255px] bg-gray-50 dark:border-gray-800 border border-gray-200 dark:bg-immich-dark-gray dark:text-white text-black rounded-3xl z-10 shadow-2xl px-8 py-6"
|
||||
transition:fade={{ duration: 150 }}
|
||||
on:mouseover={() => (hoverMessage = true)}
|
||||
on:mouseleave={() => (hoverMessage = false)}
|
||||
on:focus={() => (hoverMessage = true)}
|
||||
on:blur={() => (hoverMessage = false)}
|
||||
onmouseover={() => (hoverMessage = true)}
|
||||
onmouseleave={() => (hoverMessage = false)}
|
||||
onfocus={() => (hoverMessage = true)}
|
||||
onblur={() => (hoverMessage = false)}
|
||||
role="dialog"
|
||||
>
|
||||
<div class="flex justify-between place-items-center">
|
||||
|
|
@ -134,7 +136,7 @@
|
|||
</div>
|
||||
<CircleIconButton
|
||||
icon={mdiClose}
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
showMessage = false;
|
||||
}}
|
||||
title={$t('close')}
|
||||
|
|
@ -157,12 +159,12 @@
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<Button class="mt-2" fullwidth on:click={openPurchaseModal}>{$t('purchase_button_buy_immich')}</Button>
|
||||
<Button class="mt-2" fullwidth onclick={openPurchaseModal}>{$t('purchase_button_buy_immich')}</Button>
|
||||
<div class="mt-3 flex gap-4">
|
||||
<Button size="sm" fullwidth shadow={false} color="transparent-gray" on:click={() => hideButton(true)}>
|
||||
<Button size="sm" fullwidth shadow={false} color="transparent-gray" onclick={() => hideButton(true)}>
|
||||
{$t('purchase_button_never_show_again')}
|
||||
</Button>
|
||||
<Button size="sm" fullwidth shadow={false} color="transparent-gray" on:click={() => hideButton(false)}>
|
||||
<Button size="sm" fullwidth shadow={false} color="transparent-gray" onclick={() => hideButton(false)}>
|
||||
{$t('purchase_button_reminder')}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,21 +15,22 @@
|
|||
|
||||
const { serverVersion, connected } = websocketStore;
|
||||
|
||||
let isOpen = false;
|
||||
let isOpen = $state(false);
|
||||
|
||||
$: isMain = info?.sourceRef === 'main' && info.repository === 'immich-app/immich';
|
||||
$: version = $serverVersion ? `v${$serverVersion.major}.${$serverVersion.minor}.${$serverVersion.patch}` : null;
|
||||
|
||||
let info: ServerAboutResponseDto;
|
||||
let versions: ServerVersionHistoryResponseDto[] = [];
|
||||
let info: ServerAboutResponseDto | undefined = $state();
|
||||
let versions: ServerVersionHistoryResponseDto[] = $state([]);
|
||||
|
||||
onMount(async () => {
|
||||
await requestServerInfo();
|
||||
[info, versions] = await Promise.all([getAboutInfo(), getVersionHistory()]);
|
||||
});
|
||||
let isMain = $derived(info?.sourceRef === 'main' && info.repository === 'immich-app/immich');
|
||||
let version = $derived(
|
||||
$serverVersion ? `v${$serverVersion.major}.${$serverVersion.minor}.${$serverVersion.patch}` : null,
|
||||
);
|
||||
</script>
|
||||
|
||||
{#if isOpen}
|
||||
{#if isOpen && info}
|
||||
<ServerAboutModal onClose={() => (isOpen = false)} {info} {versions} />
|
||||
{/if}
|
||||
|
||||
|
|
@ -50,9 +51,9 @@
|
|||
|
||||
<div class="flex justify-between justify-items-center">
|
||||
{#if $connected && version}
|
||||
<button type="button" on:click={() => (isOpen = true)} class="dark:text-immich-gray flex gap-1">
|
||||
<button type="button" onclick={() => (isOpen = true)} class="dark:text-immich-gray flex gap-1">
|
||||
{#if isMain}
|
||||
<Icon path={mdiAlert} size="1.5em" color="#ffcc4d" /> {info.sourceRef}
|
||||
<Icon path={mdiAlert} size="1.5em" color="#ffcc4d" /> {info?.sourceRef}
|
||||
{:else}
|
||||
{version}
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -4,17 +4,34 @@
|
|||
import { mdiInformationOutline } from '@mdi/js';
|
||||
import { resolveRoute } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
export let title: string;
|
||||
export let routeId: string;
|
||||
export let icon: string;
|
||||
export let flippedLogo = false;
|
||||
export let isSelected = false;
|
||||
export let preloadData = true;
|
||||
interface Props {
|
||||
title: string;
|
||||
routeId: string;
|
||||
icon: string;
|
||||
flippedLogo?: boolean;
|
||||
isSelected?: boolean;
|
||||
preloadData?: boolean;
|
||||
moreInformation?: Snippet;
|
||||
}
|
||||
|
||||
let showMoreInformation = false;
|
||||
$: routePath = resolveRoute(routeId, {});
|
||||
$: isSelected = ($page.route.id?.match(/^\/(admin|\(user\))\/[^/]*/) || [])[0] === routeId;
|
||||
let {
|
||||
title,
|
||||
routeId,
|
||||
icon,
|
||||
flippedLogo = false,
|
||||
isSelected = $bindable(false),
|
||||
preloadData = true,
|
||||
moreInformation,
|
||||
}: Props = $props();
|
||||
|
||||
let showMoreInformation = $state(false);
|
||||
let routePath = $derived(resolveRoute(routeId, {}));
|
||||
|
||||
$effect(() => {
|
||||
isSelected = ($page.route.id?.match(/^\/(admin|\(user\))\/[^/]*/) || [])[0] === routeId;
|
||||
});
|
||||
</script>
|
||||
|
||||
<a
|
||||
|
|
@ -37,12 +54,12 @@
|
|||
<div
|
||||
class="h-0 overflow-hidden transition-[height] delay-1000 duration-100 sm:group-hover:h-auto group-hover:sm:overflow-visible md:h-auto md:overflow-visible"
|
||||
>
|
||||
{#if $$slots.moreInformation}
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
{#if moreInformation}
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
class="relative flex cursor-default select-none justify-center"
|
||||
on:mouseenter={() => (showMoreInformation = true)}
|
||||
on:mouseleave={() => (showMoreInformation = false)}
|
||||
onmouseenter={() => (showMoreInformation = true)}
|
||||
onmouseleave={() => (showMoreInformation = false)}
|
||||
>
|
||||
<div class="p-1 text-gray-600 hover:cursor-help dark:text-gray-400">
|
||||
<Icon path={mdiInformationOutline} />
|
||||
|
|
@ -55,7 +72,7 @@
|
|||
class:hidden={!showMoreInformation}
|
||||
transition:fade={{ duration: 200 }}
|
||||
>
|
||||
<slot name="moreInformation" />
|
||||
{@render moreInformation?.()}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
children?: Snippet;
|
||||
}
|
||||
|
||||
let { children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<section
|
||||
|
|
@ -6,5 +13,5 @@
|
|||
tabindex="-1"
|
||||
class="immich-scrollbar group relative z-10 flex w-18 flex-col gap-1 overflow-y-auto bg-immich-bg pt-8 transition-all duration-200 dark:bg-immich-dark-bg hover:sm:w-64 hover:sm:border-r hover:sm:pr-6 hover:sm:shadow-2xl hover:sm:dark:border-r-immich-dark-gray md:w-64 md:pr-6 hover:md:border-none hover:md:shadow-none"
|
||||
>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@
|
|||
import BottomInfo from '$lib/components/shared-components/side-bar/bottom-info.svelte';
|
||||
import { preferences } from '$lib/stores/user.store';
|
||||
|
||||
let isArchiveSelected: boolean;
|
||||
let isFavoritesSelected: boolean;
|
||||
let isMapSelected: boolean;
|
||||
let isPeopleSelected: boolean;
|
||||
let isPhotosSelected: boolean;
|
||||
let isSharingSelected: boolean;
|
||||
let isTrashSelected: boolean;
|
||||
let isUtilitiesSelected: boolean;
|
||||
let isArchiveSelected: boolean = $state(false);
|
||||
let isFavoritesSelected: boolean = $state(false);
|
||||
let isMapSelected: boolean = $state(false);
|
||||
let isPeopleSelected: boolean = $state(false);
|
||||
let isPhotosSelected: boolean = $state(false);
|
||||
let isSharingSelected: boolean = $state(false);
|
||||
let isTrashSelected: boolean = $state(false);
|
||||
let isUtilitiesSelected: boolean = $state(false);
|
||||
</script>
|
||||
|
||||
<SideBarSection>
|
||||
|
|
@ -48,9 +48,9 @@
|
|||
bind:isSelected={isPhotosSelected}
|
||||
icon={isPhotosSelected ? mdiImageMultiple : mdiImageMultipleOutline}
|
||||
>
|
||||
<svelte:fragment slot="moreInformation">
|
||||
{#snippet moreInformation()}
|
||||
<MoreInformationAssets assetStats={{ isArchived: false }} />
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</SideBarLink>
|
||||
|
||||
{#if $featureFlags.search}
|
||||
|
|
@ -81,9 +81,9 @@
|
|||
icon={isSharingSelected ? mdiAccountMultiple : mdiAccountMultipleOutline}
|
||||
bind:isSelected={isSharingSelected}
|
||||
>
|
||||
<svelte:fragment slot="moreInformation">
|
||||
{#snippet moreInformation()}
|
||||
<MoreInformationAlbums albumType="shared" />
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</SideBarLink>
|
||||
|
||||
<div class="text-xs transition-all duration-200 dark:text-immich-dark-fg">
|
||||
|
|
@ -97,15 +97,15 @@
|
|||
icon={isFavoritesSelected ? mdiHeart : mdiHeartOutline}
|
||||
bind:isSelected={isFavoritesSelected}
|
||||
>
|
||||
<svelte:fragment slot="moreInformation">
|
||||
{#snippet moreInformation()}
|
||||
<MoreInformationAssets assetStats={{ isFavorite: true }} />
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</SideBarLink>
|
||||
|
||||
<SideBarLink title={$t('albums')} routeId="/(user)/albums" icon={mdiImageAlbum} flippedLogo>
|
||||
<svelte:fragment slot="moreInformation">
|
||||
{#snippet moreInformation()}
|
||||
<MoreInformationAlbums albumType="owned" />
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</SideBarLink>
|
||||
|
||||
{#if $preferences.tags.enabled && $preferences.tags.sidebarWeb}
|
||||
|
|
@ -129,9 +129,9 @@
|
|||
bind:isSelected={isArchiveSelected}
|
||||
icon={isArchiveSelected ? mdiArchiveArrowDown : mdiArchiveArrowDownOutline}
|
||||
>
|
||||
<svelte:fragment slot="moreInformation">
|
||||
{#snippet moreInformation()}
|
||||
<MoreInformationAssets assetStats={{ isArchived: true }} />
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</SideBarLink>
|
||||
|
||||
{#if $featureFlags.trash}
|
||||
|
|
@ -141,9 +141,9 @@
|
|||
bind:isSelected={isTrashSelected}
|
||||
icon={isTrashSelected ? mdiTrashCan : mdiTrashCanOutline}
|
||||
>
|
||||
<svelte:fragment slot="moreInformation">
|
||||
{#snippet moreInformation()}
|
||||
<MoreInformationAssets assetStats={{ isTrashed: true }} />
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</SideBarLink>
|
||||
{/if}
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@
|
|||
import { getByteUnitString } from '../../../utils/byte-units';
|
||||
import LoadingSpinner from '../loading-spinner.svelte';
|
||||
|
||||
let usageClasses = '';
|
||||
let usageClasses = $state('');
|
||||
|
||||
$: hasQuota = $user?.quotaSizeInBytes !== null;
|
||||
$: availableBytes = (hasQuota ? $user?.quotaSizeInBytes : $serverInfo?.diskSizeRaw) || 0;
|
||||
$: usedBytes = (hasQuota ? $user?.quotaUsageInBytes : $serverInfo?.diskUseRaw) || 0;
|
||||
$: usedPercentage = Math.min(Math.round((usedBytes / availableBytes) * 100), 100);
|
||||
let hasQuota = $derived($user?.quotaSizeInBytes !== null);
|
||||
let availableBytes = $derived((hasQuota ? $user?.quotaSizeInBytes : $serverInfo?.diskSizeRaw) || 0);
|
||||
let usedBytes = $derived((hasQuota ? $user?.quotaUsageInBytes : $serverInfo?.diskUseRaw) || 0);
|
||||
let usedPercentage = $derived(Math.min(Math.round((usedBytes / availableBytes) * 100), 100));
|
||||
|
||||
const onUpdate = () => {
|
||||
usageClasses = getUsageClass();
|
||||
|
|
@ -31,9 +31,11 @@
|
|||
return 'bg-immich-primary dark:bg-immich-dark-primary';
|
||||
};
|
||||
|
||||
$: if ($user) {
|
||||
onUpdate();
|
||||
}
|
||||
$effect(() => {
|
||||
if ($user) {
|
||||
onUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
await requestServerInfo();
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@
|
|||
import { t } from 'svelte-i18n';
|
||||
import ImmichLogo from '../immich-logo.svelte';
|
||||
|
||||
export let centered = false;
|
||||
export let logoSize: 'sm' | 'lg' = 'sm';
|
||||
interface Props {
|
||||
centered?: boolean;
|
||||
logoSize?: 'sm' | 'lg';
|
||||
}
|
||||
|
||||
let { centered = false, logoSize = 'sm' }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue