@futo-org/backups-orchestrator-ui 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/backends/BackendItem.svelte +28 -24
- package/dist/components/backends/BackendsList.svelte +33 -34
- package/dist/components/backends/BackendsList.svelte.d.ts +1 -0
- package/dist/components/backends/dialogs/SelectBackendModal.svelte +44 -55
- package/dist/components/backups/BackupItem.svelte +33 -26
- package/dist/components/backups/BackupStatus.svelte +200 -0
- package/dist/components/backups/BackupStatus.svelte.d.ts +19 -0
- package/dist/components/backups/BackupsList.svelte +17 -11
- package/dist/components/backups/dialogs/RestoreSnapshotModal.svelte +2 -2
- package/dist/components/backups/dialogs/SelectRepositoryModal.svelte +26 -36
- package/dist/components/backups/dialogs/ViewStatusModal.svelte +175 -0
- package/dist/components/backups/dialogs/ViewStatusModal.svelte.d.ts +8 -0
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte +22 -10
- package/dist/components/backups/run-history/RepositoryRunHistory.svelte.d.ts +2 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryItem.svelte +46 -20
- package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte +135 -0
- package/dist/components/backups/run-history/RepositoryRunHistoryPage.svelte.d.ts +8 -0
- package/dist/components/backups/run-history/RunHistoryModal.svelte +2 -2
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte +22 -10
- package/dist/components/backups/snapshots-list/RepositorySnapshotsList.svelte.d.ts +2 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsListItem.svelte +23 -21
- package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte +115 -0
- package/dist/components/backups/snapshots-list/RepositorySnapshotsPage.svelte.d.ts +9 -0
- package/dist/components/backups/snapshots-list/SnapshotsListModal.svelte +2 -2
- package/dist/components/dashboard/Dashboard.svelte +14 -7
- package/dist/components/dashboard/Dashboard.svelte.d.ts +1 -1
- package/dist/components/dashboard/DashboardAvgBackupTime.svelte +1 -1
- package/dist/components/dashboard/DashboardBackupHealth.svelte +5 -9
- package/dist/components/dashboard/DashboardBackupHealth.svelte.d.ts +1 -1
- package/dist/components/dashboard/DashboardCurrentUsage.svelte +1 -1
- package/dist/components/dashboard/DashboardDailyBackupTime.svelte +1 -1
- package/dist/components/dashboard/DashboardInstall.svelte +1 -1
- package/dist/components/dashboard/DashboardRecentBackups.svelte +47 -78
- package/dist/components/dashboard/DashboardTotalStored.svelte +1 -1
- package/dist/components/integrations/immich/ImmichBackupSettings.svelte +12 -0
- package/dist/components/integrations/immich/ImmichBackupSettings.svelte.d.ts +18 -0
- package/dist/components/integrations/immich/ImmichBackupsCard.svelte +73 -0
- package/dist/components/integrations/immich/ImmichBackupsCard.svelte.d.ts +12 -0
- package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte +55 -0
- package/dist/components/integrations/immich/ImmichBackupsNavButton.svelte.d.ts +10 -0
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte +15 -3
- package/dist/components/integrations/immich/ImmichBackupsPage.svelte.d.ts +7 -1
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte +66 -0
- package/dist/components/integrations/immich/ImmichBackupsSidebarItem.svelte.d.ts +8 -0
- package/dist/components/integrations/immich/ImmichManageBackup.svelte +53 -14
- package/dist/components/integrations/immich/ImmichManageBackupOverview.svelte +45 -71
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte +123 -82
- package/dist/components/integrations/immich/ImmichOnboardingSetupFlow.svelte.d.ts +1 -1
- package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte +313 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsBackupContents.svelte.d.ts +3 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte +218 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsSchedule.svelte.d.ts +3 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte +207 -0
- package/dist/components/integrations/immich/settings/ImmichSettingsStorage.svelte.d.ts +3 -0
- package/dist/components/onboarding/RecoveryKeyDisplay.svelte +34 -20
- package/dist/components/onboarding/SampleOnboarding.svelte +57 -38
- package/dist/components/onboarding/stages/OnboardingStageBackupServices.svelte +10 -24
- package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte +44 -0
- package/dist/components/onboarding/steps/OnboardingStep1FinishSetup.svelte.d.ts +7 -0
- package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte +50 -0
- package/dist/components/onboarding/steps/OnboardingStep2ConnectAccount.svelte.d.ts +7 -0
- package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte +45 -0
- package/dist/components/onboarding/steps/OnboardingStep3SaveRecoveryKey.svelte.d.ts +8 -0
- package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte +67 -0
- package/dist/components/onboarding/steps/OnboardingStep4FirstBackup.svelte.d.ts +9 -0
- package/dist/components/onboarding/steps/OnboardingStepLayout.svelte +58 -0
- package/dist/components/onboarding/steps/OnboardingStepLayout.svelte.d.ts +19 -0
- package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte +52 -0
- package/dist/components/onboarding/upsell/UpsellBackupFeaturesGrid.svelte.d.ts +18 -0
- package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte +33 -0
- package/dist/components/onboarding/upsell/UpsellExplainFutoBackups.svelte.d.ts +8 -0
- package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte +27 -0
- package/dist/components/onboarding/upsell/UpsellFrequentlyAskedQuestions.svelte.d.ts +10 -0
- package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte +7 -0
- package/dist/components/onboarding/upsell/UpsellFutoBackupsBadge.svelte.d.ts +18 -0
- package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte +46 -0
- package/dist/components/onboarding/upsell/UpsellHowItWorks.svelte.d.ts +6 -0
- package/dist/components/onboarding/upsell/UpsellModal.svelte +43 -0
- package/dist/components/onboarding/upsell/UpsellModal.svelte.d.ts +9 -0
- package/dist/components/onboarding/upsell/UpsellPage.svelte +39 -0
- package/dist/components/onboarding/upsell/UpsellPage.svelte.d.ts +13 -0
- package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte +58 -0
- package/dist/components/onboarding/upsell/UpsellProtectYourImmichLibrary.svelte.d.ts +8 -0
- package/dist/components/schedules/RepositoryPicker.svelte +45 -38
- package/dist/components/schedules/ScheduleItem.svelte +32 -26
- package/dist/components/schedules/ScheduleList.svelte +16 -10
- package/dist/components/settings/GlobalSettings.svelte +8 -0
- package/dist/components/settings/GlobalSettings.svelte.d.ts +18 -0
- package/dist/components/settings/SettingsBackends.svelte +16 -0
- package/dist/components/settings/SettingsBackends.svelte.d.ts +18 -0
- package/dist/components/settings/SettingsBilling.svelte +69 -0
- package/dist/components/settings/SettingsBilling.svelte.d.ts +6 -0
- package/dist/components/settings/SettingsNotifications.svelte +47 -0
- package/dist/components/settings/SettingsNotifications.svelte.d.ts +6 -0
- package/dist/components/test/ImmichTestUi.svelte +129 -27
- package/dist/components/test/TestUi.svelte +4 -4
- package/dist/components/test/dashboard/ActiveJobs.svelte +2 -2
- package/dist/components/test/immich/MockImmichPhotos.svelte +36 -0
- package/dist/components/test/immich/MockImmichPhotos.svelte.d.ts +18 -0
- package/dist/components/test/immich/MockImmichPurchaseInfo.svelte +29 -0
- package/dist/components/test/immich/MockImmichPurchaseInfo.svelte.d.ts +18 -0
- package/dist/components/test/immich/MockImmichStorageSpace.svelte +37 -0
- package/dist/components/test/immich/MockImmichStorageSpace.svelte.d.ts +6 -0
- package/dist/components/ui/Accordion.svelte +67 -0
- package/dist/components/ui/Accordion.svelte.d.ts +11 -0
- package/dist/components/ui/ListToolbar.svelte +60 -0
- package/dist/components/ui/ListToolbar.svelte.d.ts +16 -0
- package/dist/components/ui/PageLayout.svelte +21 -9
- package/dist/components/ui/PageLayout.svelte.d.ts +1 -0
- package/dist/components/ui/Pagination.svelte +80 -0
- package/dist/components/ui/Pagination.svelte.d.ts +8 -0
- package/dist/components/ui/PathListField.svelte +17 -14
- package/dist/components/ui/StackList.svelte +18 -18
- package/dist/components/ui/StackList.svelte.d.ts +6 -27
- package/dist/components/ui/StackListItem.svelte +47 -25
- package/dist/components/ui/StackListItem.svelte.d.ts +5 -2
- package/dist/components/ui/StackListOption.svelte +33 -0
- package/dist/components/ui/StackListOption.svelte.d.ts +11 -0
- package/dist/components/ui/StackListPlaceholder.svelte +12 -0
- package/dist/components/ui/StackListPlaceholder.svelte.d.ts +7 -0
- package/dist/components/ui/StepNumber.svelte +20 -0
- package/dist/components/ui/StepNumber.svelte.d.ts +7 -0
- package/dist/components/util/Suspense.svelte +7 -3
- package/dist/components/util/YuccaContext.svelte +1 -1
- package/dist/events.js +1 -1
- package/dist/fetch-client.d.ts +2 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +6 -1
- package/dist/services/backend.service.js +3 -0
- package/dist/services/immich.integration.service.d.ts +1 -1
- package/dist/services/immich.integration.service.js +2 -3
- package/dist/services/integrations.service.d.ts +1 -0
- package/dist/services/integrations.service.js +2 -1
- package/dist/services/log.service.svelte.d.ts +12 -0
- package/dist/services/log.service.svelte.js +15 -1
- package/dist/services/repository.service.js +9 -3
- package/dist/services/runHistory.service.js +2 -2
- package/dist/utils/format.d.ts +1 -1
- package/dist/utils/format.js +2 -2
- package/package.json +3 -3
- package/dist/components/backups/dialogs/ViewLogModal.svelte +0 -208
- package/dist/components/backups/dialogs/ViewLogModal.svelte.d.ts +0 -7
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte +0 -403
- package/dist/components/integrations/immich/ImmichConfigureBackup.svelte.d.ts +0 -9
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte +0 -80
- package/dist/components/integrations/immich/ImmichConfirmDefaultBackup.svelte.d.ts +0 -8
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte +0 -56
- package/dist/components/onboarding/stages/OnboardingStageKeyConfirm.svelte.d.ts +0 -9
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte +0 -50
- package/dist/components/onboarding/stages/OnboardingStageKeyIntro.svelte.d.ts +0 -7
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte +0 -44
- package/dist/components/onboarding/stages/OnboardingStageKeySave.svelte.d.ts +0 -8
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte +0 -56
- package/dist/components/onboarding/stages/OnboardingStageWelcome.svelte.d.ts +0 -9
- package/dist/components/util/TimedButton.svelte +0 -37
- package/dist/components/util/TimedButton.svelte.d.ts +0 -7
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
mdiCog,
|
|
20
20
|
mdiViewDashboard,
|
|
21
21
|
} from "@mdi/js";
|
|
22
|
-
import
|
|
22
|
+
import GlobalSettings from "../settings/GlobalSettings.svelte";
|
|
23
23
|
import BackupsList from "../backups/BackupsList.svelte";
|
|
24
24
|
import Dashboard from "../dashboard/Dashboard.svelte";
|
|
25
25
|
import ScheduleList from "../schedules/ScheduleList.svelte";
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
let route = $state("dashboard");
|
|
38
38
|
</script>
|
|
39
39
|
|
|
40
|
-
<AppShell>
|
|
40
|
+
<AppShell class="h-full">
|
|
41
41
|
<AppShellHeader>
|
|
42
42
|
<div class="flex items-center justify-between w-full px-4 py-2">
|
|
43
43
|
<Heading>
|
|
@@ -118,12 +118,12 @@
|
|
|
118
118
|
|
|
119
119
|
<div class="p-4 flex flex-col gap-2 max-w-6xl m-auto">
|
|
120
120
|
{#if route === "dashboard"}
|
|
121
|
-
<Dashboard local
|
|
121
|
+
<Dashboard local onViewBackups={() => (route = "backups")} />
|
|
122
122
|
{:else if route === "backups"}
|
|
123
123
|
<BackupsList local />
|
|
124
124
|
{:else if route === "config"}
|
|
125
125
|
{#if !mock}
|
|
126
|
-
<
|
|
126
|
+
<GlobalSettings />
|
|
127
127
|
{/if}
|
|
128
128
|
{:else if route === "schedules"}
|
|
129
129
|
{#if !mock}
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
import { SvelteMap } from "svelte/reactivity";
|
|
35
35
|
import OnEvents from "../../util/OnEvents.svelte";
|
|
36
36
|
import RelativeTime from "../../util/RelativeTime.svelte";
|
|
37
|
-
import
|
|
37
|
+
import ViewStatusModal from "../../backups/dialogs/ViewStatusModal.svelte";
|
|
38
38
|
|
|
39
39
|
const LINGER_MS = 3000;
|
|
40
40
|
const FADE_MS = 600;
|
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
};
|
|
172
172
|
|
|
173
173
|
const openLog = (logId: string) => {
|
|
174
|
-
modalManager.open(
|
|
174
|
+
modalManager.open(ViewStatusModal, { logId });
|
|
175
175
|
};
|
|
176
176
|
|
|
177
177
|
const onCancel = (parentId: string) => handleCancelTask(parentId);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Stack, Text } from "@immich/ui";
|
|
3
|
+
|
|
4
|
+
const groups = [
|
|
5
|
+
{ title: "Friday, 31 July 2026", count: 13 },
|
|
6
|
+
{ title: "Thursday, 30 July 2026", count: 8 },
|
|
7
|
+
{ title: "Sunday, 26 July 2026", count: 17 },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
const aspects = [1.5, 0.75, 1.33, 1, 0.7, 1.78, 1.2, 0.8, 1.4, 1];
|
|
11
|
+
const greys = [88, 82, 91, 78, 85, 93, 80, 87];
|
|
12
|
+
|
|
13
|
+
const seedOf = (group: number, index: number) => group * 7 + index * 3;
|
|
14
|
+
const aspect = (seed: number) => aspects[seed % aspects.length];
|
|
15
|
+
const grey = (seed: number) => greys[seed % greys.length];
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<Stack gap={8} class="p-4">
|
|
19
|
+
{#each groups as group, groupIndex (group.title)}
|
|
20
|
+
<Stack gap={2}>
|
|
21
|
+
<Text size="small" fontWeight="medium" color="muted">{group.title}</Text>
|
|
22
|
+
|
|
23
|
+
<div class="flex flex-wrap gap-1">
|
|
24
|
+
{#each Array.from({ length: group.count }, (_, index) => index) as index (index)}
|
|
25
|
+
{@const seed = seedOf(groupIndex, index)}
|
|
26
|
+
<div
|
|
27
|
+
class="h-36 grow rounded-sm"
|
|
28
|
+
style="background-color: hsl(0 0% {grey(seed)}%); flex-basis: {aspect(
|
|
29
|
+
seed,
|
|
30
|
+
) * 9}rem"
|
|
31
|
+
></div>
|
|
32
|
+
{/each}
|
|
33
|
+
</div>
|
|
34
|
+
</Stack>
|
|
35
|
+
{/each}
|
|
36
|
+
</Stack>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const MockImmichPhotos: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type MockImmichPhotos = InstanceType<typeof MockImmichPhotos>;
|
|
18
|
+
export default MockImmichPhotos;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Icon, Logo } from "@immich/ui";
|
|
3
|
+
import { mdiInformationOutline } from "@mdi/js";
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<div class="license-status text-sm">
|
|
7
|
+
<button
|
|
8
|
+
type="button"
|
|
9
|
+
onclick={() => {}}
|
|
10
|
+
class="flex w-full cursor-pointer place-content-center place-items-center justify-between rounded-lg border border-primary/20 p-2 shadow-md dark:border-primary/10 dark:bg-primary/10"
|
|
11
|
+
>
|
|
12
|
+
<div
|
|
13
|
+
class="flex w-full place-content-center place-items-center justify-between"
|
|
14
|
+
>
|
|
15
|
+
<div class="flex place-content-center place-items-center gap-1">
|
|
16
|
+
<Logo variant="icon" size="tiny" />
|
|
17
|
+
<p class="flex font-medium text-primary">Buy Immich</p>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<div>
|
|
21
|
+
<Icon
|
|
22
|
+
icon={mdiInformationOutline}
|
|
23
|
+
class="flex font-medium text-primary"
|
|
24
|
+
size="18"
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</button>
|
|
29
|
+
</div>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const MockImmichPurchaseInfo: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type MockImmichPurchaseInfo = InstanceType<typeof MockImmichPurchaseInfo>;
|
|
18
|
+
export default MockImmichPurchaseInfo;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Icon, Meter, Text } from "@immich/ui";
|
|
3
|
+
import { mdiChevronRight, mdiCloudCheckOutline } from "@mdi/js";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
onBackups: () => void;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const { onBackups }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<div class="bg-light-100 overflow-hidden rounded-lg text-sm">
|
|
13
|
+
<div class="p-4">
|
|
14
|
+
<Meter
|
|
15
|
+
size="tiny"
|
|
16
|
+
class="bg-light-200"
|
|
17
|
+
containerClass="gap-2 leading-6"
|
|
18
|
+
label="Storage"
|
|
19
|
+
valueLabel="22.1 GiB of 100 GiB used"
|
|
20
|
+
value={0.221}
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<button
|
|
25
|
+
type="button"
|
|
26
|
+
onclick={onBackups}
|
|
27
|
+
class="bg-success-50 text-success-700 flex w-full cursor-pointer items-center gap-2 px-3 py-3 text-start"
|
|
28
|
+
>
|
|
29
|
+
<Icon icon={mdiCloudCheckOutline} size="1em" class="shrink-0" />
|
|
30
|
+
|
|
31
|
+
<Text size="small" color="success" class="flex-1 truncate">
|
|
32
|
+
Backed up 2 hours ago
|
|
33
|
+
</Text>
|
|
34
|
+
|
|
35
|
+
<Icon icon={mdiChevronRight} size="1em" class="shrink-0" />
|
|
36
|
+
</button>
|
|
37
|
+
</div>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Icon, Text } from "@immich/ui";
|
|
3
|
+
import { mdiChevronDown } from "@mdi/js";
|
|
4
|
+
import type { Snippet } from "svelte";
|
|
5
|
+
import { slide } from "svelte/transition";
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
title: string;
|
|
9
|
+
subtitle?: string;
|
|
10
|
+
icon?: string;
|
|
11
|
+
isOpen?: boolean;
|
|
12
|
+
children?: Snippet;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
title,
|
|
17
|
+
subtitle,
|
|
18
|
+
icon,
|
|
19
|
+
isOpen = $bindable(false),
|
|
20
|
+
children,
|
|
21
|
+
}: Props = $props();
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div
|
|
25
|
+
class="border-primary/20 mt-4 rounded-2xl border-2 px-6 py-4 transition-all"
|
|
26
|
+
class:border-primary={isOpen}
|
|
27
|
+
class:shadow-md={isOpen}
|
|
28
|
+
>
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
aria-expanded={isOpen}
|
|
32
|
+
onclick={() => (isOpen = !isOpen)}
|
|
33
|
+
class="flex w-full place-items-center justify-between gap-4 text-start"
|
|
34
|
+
>
|
|
35
|
+
<div>
|
|
36
|
+
<div class="flex place-items-center gap-2">
|
|
37
|
+
{#if icon}
|
|
38
|
+
<Icon {icon} class="text-primary" size="1.5rem" aria-hidden="true" />
|
|
39
|
+
{/if}
|
|
40
|
+
<Text fontWeight="medium" color="primary">{title}</Text>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
{#if subtitle}
|
|
44
|
+
<Text size="small" color="muted" class="mt-1">{subtitle}</Text>
|
|
45
|
+
{/if}
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div
|
|
49
|
+
class="hover:bg-primary/10 flex shrink-0 place-content-center place-items-center rounded-full p-3 transition-all"
|
|
50
|
+
>
|
|
51
|
+
<Icon
|
|
52
|
+
icon={mdiChevronDown}
|
|
53
|
+
size="1.25rem"
|
|
54
|
+
class="transition-transform duration-200 ease-in {isOpen
|
|
55
|
+
? 'rotate-180'
|
|
56
|
+
: ''}"
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
</button>
|
|
61
|
+
|
|
62
|
+
{#if isOpen}
|
|
63
|
+
<div transition:slide={{ duration: 150 }} class="mb-2 ms-4">
|
|
64
|
+
{@render children?.()}
|
|
65
|
+
</div>
|
|
66
|
+
{/if}
|
|
67
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type Props = {
|
|
3
|
+
title: string;
|
|
4
|
+
subtitle?: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
isOpen?: boolean;
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
};
|
|
9
|
+
declare const Accordion: import("svelte").Component<Props, {}, "isOpen">;
|
|
10
|
+
type Accordion = ReturnType<typeof Accordion>;
|
|
11
|
+
export default Accordion;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
HStack,
|
|
5
|
+
Input,
|
|
6
|
+
menuManager,
|
|
7
|
+
type ActionItem,
|
|
8
|
+
} from "@immich/ui";
|
|
9
|
+
import { mdiFilterVariant, mdiMagnify, mdiSortVariant } from "@mdi/js";
|
|
10
|
+
|
|
11
|
+
type Menu = {
|
|
12
|
+
label: string;
|
|
13
|
+
items: ActionItem[];
|
|
14
|
+
active?: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
placeholder: string;
|
|
19
|
+
search: string;
|
|
20
|
+
onSearch: (value: string) => void;
|
|
21
|
+
sort?: Menu;
|
|
22
|
+
filters?: Menu;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const { placeholder, search, onSearch, sort, filters }: Props = $props();
|
|
26
|
+
|
|
27
|
+
const openMenu = (items: ActionItem[]) => (event: Event) =>
|
|
28
|
+
void menuManager.show({
|
|
29
|
+
target: event.currentTarget as HTMLElement,
|
|
30
|
+
position: "bottom-left",
|
|
31
|
+
items,
|
|
32
|
+
});
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<HStack class="items-center justify-between">
|
|
36
|
+
<Input
|
|
37
|
+
class="max-w-72"
|
|
38
|
+
leadingIcon={mdiMagnify}
|
|
39
|
+
{placeholder}
|
|
40
|
+
value={search}
|
|
41
|
+
oninput={(event) => onSearch(event.currentTarget.value)}
|
|
42
|
+
/>
|
|
43
|
+
|
|
44
|
+
<HStack gap={2}>
|
|
45
|
+
{#each [{ menu: sort, icon: mdiSortVariant }, { menu: filters, icon: mdiFilterVariant }] as { menu, icon } (icon)}
|
|
46
|
+
{#if menu}
|
|
47
|
+
<Button
|
|
48
|
+
variant="outline"
|
|
49
|
+
size="small"
|
|
50
|
+
color={menu.active ? "primary" : "secondary"}
|
|
51
|
+
class="whitespace-nowrap"
|
|
52
|
+
leadingIcon={icon}
|
|
53
|
+
onclick={openMenu(menu.items)}
|
|
54
|
+
>
|
|
55
|
+
{menu.label}
|
|
56
|
+
</Button>
|
|
57
|
+
{/if}
|
|
58
|
+
{/each}
|
|
59
|
+
</HStack>
|
|
60
|
+
</HStack>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ActionItem } from "@immich/ui";
|
|
2
|
+
type Menu = {
|
|
3
|
+
label: string;
|
|
4
|
+
items: ActionItem[];
|
|
5
|
+
active?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type Props = {
|
|
8
|
+
placeholder: string;
|
|
9
|
+
search: string;
|
|
10
|
+
onSearch: (value: string) => void;
|
|
11
|
+
sort?: Menu;
|
|
12
|
+
filters?: Menu;
|
|
13
|
+
};
|
|
14
|
+
declare const ListToolbar: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type ListToolbar = ReturnType<typeof ListToolbar>;
|
|
16
|
+
export default ListToolbar;
|
|
@@ -4,26 +4,42 @@
|
|
|
4
4
|
Button,
|
|
5
5
|
ContextMenuButton,
|
|
6
6
|
HStack,
|
|
7
|
+
IconButton,
|
|
7
8
|
type ActionItem,
|
|
8
9
|
} from "@immich/ui";
|
|
10
|
+
import { mdiArrowLeft } from "@mdi/js";
|
|
9
11
|
import type { Snippet } from "svelte";
|
|
10
12
|
|
|
11
13
|
type Props = {
|
|
12
14
|
title?: string;
|
|
13
15
|
actions?: ActionItem[];
|
|
16
|
+
onBack?: () => void;
|
|
14
17
|
children?: Snippet;
|
|
15
18
|
};
|
|
16
19
|
|
|
17
|
-
const { title, actions = [], children }: Props = $props();
|
|
20
|
+
const { title, actions = [], onBack, children }: Props = $props();
|
|
18
21
|
const { demoPadding } = options;
|
|
22
|
+
|
|
23
|
+
const hasHeader = $derived(Boolean(title) || actions.length > 0 || Boolean(onBack));
|
|
19
24
|
</script>
|
|
20
25
|
|
|
21
|
-
<main class="
|
|
22
|
-
{#if
|
|
26
|
+
<main class="flex h-full w-full flex-col">
|
|
27
|
+
{#if hasHeader}
|
|
23
28
|
<div
|
|
24
|
-
class="
|
|
29
|
+
class="flex h-16 shrink-0 place-items-center justify-between border-b p-2 text-dark"
|
|
25
30
|
>
|
|
26
31
|
<div class="flex gap-2 items-center">
|
|
32
|
+
{#if onBack}
|
|
33
|
+
<IconButton
|
|
34
|
+
icon={mdiArrowLeft}
|
|
35
|
+
aria-label="Back"
|
|
36
|
+
variant="ghost"
|
|
37
|
+
color="secondary"
|
|
38
|
+
shape="round"
|
|
39
|
+
onclick={onBack}
|
|
40
|
+
/>
|
|
41
|
+
{/if}
|
|
42
|
+
|
|
27
43
|
{#if title}
|
|
28
44
|
<div class="outline-none pe-8">{title}</div>
|
|
29
45
|
{/if}
|
|
@@ -57,11 +73,7 @@
|
|
|
57
73
|
</div>
|
|
58
74
|
{/if}
|
|
59
75
|
|
|
60
|
-
<div
|
|
61
|
-
class="absolute left-0 w-full overflow-y-auto {title || actions.length > 0
|
|
62
|
-
? 'top-16 h-[calc(100%-4rem)]'
|
|
63
|
-
: 'top-0 h-full'} {$demoPadding ? 'p-4' : ''}"
|
|
64
|
-
>
|
|
76
|
+
<div class="min-h-0 grow overflow-y-auto {$demoPadding ? 'p-4' : ''}">
|
|
65
77
|
{@render children?.()}
|
|
66
78
|
</div>
|
|
67
79
|
</main>
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button, HStack, IconButton, Text } from "@immich/ui";
|
|
3
|
+
import { mdiChevronLeft, mdiChevronRight } from "@mdi/js";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
page: number;
|
|
7
|
+
pageCount: number;
|
|
8
|
+
onChange: (page: number) => void;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const { page, pageCount, onChange }: Props = $props();
|
|
12
|
+
|
|
13
|
+
const boundaryCount = 2;
|
|
14
|
+
const siblingCount = 0;
|
|
15
|
+
|
|
16
|
+
const range = (from: number, to: number) =>
|
|
17
|
+
Array.from({ length: Math.max(to - from + 1, 0) }, (_, index) => from + index);
|
|
18
|
+
|
|
19
|
+
const pages = $derived.by(() => {
|
|
20
|
+
const shown = new Set([
|
|
21
|
+
...range(1, Math.min(boundaryCount, pageCount)),
|
|
22
|
+
...range(Math.max(pageCount - boundaryCount + 1, 1), pageCount),
|
|
23
|
+
...range(
|
|
24
|
+
Math.max(page - siblingCount, 1),
|
|
25
|
+
Math.min(page + siblingCount, pageCount),
|
|
26
|
+
),
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
const items: (number | "ellipsis")[] = [];
|
|
30
|
+
for (const candidate of range(1, pageCount)) {
|
|
31
|
+
if (shown.has(candidate)) {
|
|
32
|
+
items.push(candidate);
|
|
33
|
+
} else if (items.at(-1) !== "ellipsis") {
|
|
34
|
+
items.push("ellipsis");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return items;
|
|
39
|
+
});
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<HStack class="items-center justify-between">
|
|
43
|
+
<IconButton
|
|
44
|
+
icon={mdiChevronLeft}
|
|
45
|
+
aria-label="Previous page"
|
|
46
|
+
variant="ghost"
|
|
47
|
+
color="secondary"
|
|
48
|
+
disabled={page <= 1}
|
|
49
|
+
onclick={() => onChange(page - 1)}
|
|
50
|
+
/>
|
|
51
|
+
|
|
52
|
+
<HStack gap={1} class="items-center">
|
|
53
|
+
{#each pages as item, index (index)}
|
|
54
|
+
{#if item === "ellipsis"}
|
|
55
|
+
<Text class="w-8 text-center" color="muted">…</Text>
|
|
56
|
+
{:else}
|
|
57
|
+
<Button
|
|
58
|
+
size="small"
|
|
59
|
+
variant="ghost"
|
|
60
|
+
color="secondary"
|
|
61
|
+
class={item === page ? "bg-subtle" : undefined}
|
|
62
|
+
aria-label={`Page ${item}`}
|
|
63
|
+
aria-current={item === page ? "page" : undefined}
|
|
64
|
+
onclick={() => onChange(item)}
|
|
65
|
+
>
|
|
66
|
+
{item}
|
|
67
|
+
</Button>
|
|
68
|
+
{/if}
|
|
69
|
+
{/each}
|
|
70
|
+
</HStack>
|
|
71
|
+
|
|
72
|
+
<IconButton
|
|
73
|
+
icon={mdiChevronRight}
|
|
74
|
+
aria-label="Next page"
|
|
75
|
+
variant="ghost"
|
|
76
|
+
color="secondary"
|
|
77
|
+
disabled={page >= pageCount}
|
|
78
|
+
onclick={() => onChange(page + 1)}
|
|
79
|
+
/>
|
|
80
|
+
</HStack>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import StackList from "./StackList.svelte";
|
|
3
|
+
import StackListItem from "./StackListItem.svelte";
|
|
3
4
|
import type { FilesystemListingResponseDto } from "../../fetch-client";
|
|
4
5
|
import {
|
|
5
6
|
Button,
|
|
6
|
-
HStack,
|
|
7
7
|
IconButton,
|
|
8
8
|
modalManager,
|
|
9
9
|
Text,
|
|
@@ -58,26 +58,29 @@
|
|
|
58
58
|
|
|
59
59
|
{#if paths.size > 0}
|
|
60
60
|
{#each [...paths] as path (path)}
|
|
61
|
-
<
|
|
61
|
+
<StackListItem>
|
|
62
62
|
<Text class="grow truncate" title={path}>{path}</Text>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
|
|
64
|
+
{#snippet trailing()}
|
|
65
|
+
<IconButton
|
|
66
|
+
icon={mdiClose}
|
|
67
|
+
aria-label="Remove"
|
|
68
|
+
size="tiny"
|
|
69
|
+
variant="ghost"
|
|
70
|
+
onclick={() => paths.delete(path)}
|
|
71
|
+
/>
|
|
72
|
+
{/snippet}
|
|
73
|
+
</StackListItem>
|
|
71
74
|
{/each}
|
|
72
75
|
{:else if empty}
|
|
73
|
-
<
|
|
76
|
+
<StackListItem>
|
|
74
77
|
<Text color="secondary">{@render empty()}</Text>
|
|
75
|
-
</
|
|
78
|
+
</StackListItem>
|
|
76
79
|
{/if}
|
|
77
80
|
|
|
78
|
-
<
|
|
81
|
+
<StackListItem>
|
|
79
82
|
<Button size="small" variant="ghost" onclick={openPicker}>
|
|
80
83
|
{paths.size > 0 ? addLabel : manageLabel}
|
|
81
84
|
</Button>
|
|
82
|
-
</
|
|
85
|
+
</StackListItem>
|
|
83
86
|
</StackList>
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
<script lang="ts"
|
|
2
|
-
import {
|
|
3
|
-
import { Alert, Heading, LoadingSpinner, Stack } from "@immich/ui";
|
|
4
|
-
import type { CreateQueryResult } from "@tanstack/svelte-query";
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Card, CardBody, Heading, HStack, Stack } from "@immich/ui";
|
|
5
3
|
import type { Snippet } from "svelte";
|
|
6
4
|
|
|
7
5
|
type Props = {
|
|
8
6
|
title?: Snippet;
|
|
9
|
-
|
|
10
|
-
children
|
|
7
|
+
action?: Snippet;
|
|
8
|
+
children?: Snippet;
|
|
11
9
|
};
|
|
12
10
|
|
|
13
|
-
const { title,
|
|
11
|
+
const { title, action, children }: Props = $props();
|
|
14
12
|
</script>
|
|
15
13
|
|
|
16
14
|
<Stack gap={2}>
|
|
17
|
-
{#if title}
|
|
18
|
-
<
|
|
19
|
-
|
|
15
|
+
{#if title || action}
|
|
16
|
+
<HStack class="items-center justify-between px-1">
|
|
17
|
+
{#if title}
|
|
18
|
+
<Heading size="tiny">{@render title()}</Heading>
|
|
19
|
+
{/if}
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
{:else if query?.isError}
|
|
24
|
-
<Alert color="danger">{getReadableErrorMessage(query.error)}</Alert>
|
|
25
|
-
{:else}
|
|
26
|
-
<Stack gap={0} class="divide-y rounded-2xl border overflow-hidden">
|
|
27
|
-
{@render children(query?.data as T)}
|
|
28
|
-
</Stack>
|
|
21
|
+
{@render action?.()}
|
|
22
|
+
</HStack>
|
|
29
23
|
{/if}
|
|
24
|
+
|
|
25
|
+
<Card class="border-primary-100 shadow-none">
|
|
26
|
+
<CardBody class="divide-y p-0">
|
|
27
|
+
{@render children?.()}
|
|
28
|
+
</CardBody>
|
|
29
|
+
</Card>
|
|
30
30
|
</Stack>
|
|
@@ -1,30 +1,9 @@
|
|
|
1
|
-
import type { CreateQueryResult } from "@tanstack/svelte-query";
|
|
2
1
|
import type { Snippet } from "svelte";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
children: Snippet<[T]>;
|
|
8
|
-
};
|
|
9
|
-
exports: {};
|
|
10
|
-
bindings: "";
|
|
11
|
-
slots: {};
|
|
12
|
-
events: {};
|
|
2
|
+
type Props = {
|
|
3
|
+
title?: Snippet;
|
|
4
|
+
action?: Snippet;
|
|
5
|
+
children?: Snippet;
|
|
13
6
|
};
|
|
14
|
-
declare
|
|
15
|
-
|
|
16
|
-
events(): ReturnType<typeof $$render<T>>['events'];
|
|
17
|
-
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
18
|
-
bindings(): "";
|
|
19
|
-
exports(): {};
|
|
20
|
-
}
|
|
21
|
-
interface $$IsomorphicComponent {
|
|
22
|
-
new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
23
|
-
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
24
|
-
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
25
|
-
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
26
|
-
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
27
|
-
}
|
|
28
|
-
declare const StackList: $$IsomorphicComponent;
|
|
29
|
-
type StackList<T> = InstanceType<typeof StackList<T>>;
|
|
7
|
+
declare const StackList: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type StackList = ReturnType<typeof StackList>;
|
|
30
9
|
export default StackList;
|