mirror of
https://github.com/immich-app/immich.git
synced 2025-06-04 14:14:23 -04:00
refactor: buttons (#18317)
* refactor: buttons * fix: woopsie --------- Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
This commit is contained in:
parent
c1150fe7e3
commit
86d64f3483
@ -1,20 +0,0 @@
|
|||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import { render, screen } from '@testing-library/svelte';
|
|
||||||
|
|
||||||
describe('Button component', () => {
|
|
||||||
it('should render as a button', () => {
|
|
||||||
render(Button);
|
|
||||||
const button = screen.getByRole('button');
|
|
||||||
expect(button).toBeInTheDocument();
|
|
||||||
expect(button).toHaveAttribute('type', 'button');
|
|
||||||
expect(button).not.toHaveAttribute('href');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render as a link if href prop is set', () => {
|
|
||||||
render(Button, { props: { href: '/test' } });
|
|
||||||
const link = screen.getByRole('link');
|
|
||||||
expect(link).toBeInTheDocument();
|
|
||||||
expect(link).toHaveAttribute('href', '/test');
|
|
||||||
expect(link).not.toHaveAttribute('type');
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,123 +0,0 @@
|
|||||||
<script lang="ts" module>
|
|
||||||
export type Color =
|
|
||||||
| 'primary'
|
|
||||||
| 'primary-inversed'
|
|
||||||
| 'secondary'
|
|
||||||
| 'transparent-primary'
|
|
||||||
| 'text-primary'
|
|
||||||
| 'light-red'
|
|
||||||
| 'red'
|
|
||||||
| 'green'
|
|
||||||
| 'gray'
|
|
||||||
| 'transparent-gray'
|
|
||||||
| 'dark-gray'
|
|
||||||
| 'overlay-primary';
|
|
||||||
export type Size = 'tiny' | 'icon' | 'link' | 'sm' | 'base' | 'lg';
|
|
||||||
export type Rounded = 'lg' | '3xl' | 'full' | 'none';
|
|
||||||
export type Shadow = 'md' | false;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import type { Snippet } from 'svelte';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
type?: string;
|
|
||||||
href?: string;
|
|
||||||
color?: Color;
|
|
||||||
size?: Size;
|
|
||||||
rounded?: Rounded;
|
|
||||||
shadow?: Shadow;
|
|
||||||
fullwidth?: boolean;
|
|
||||||
border?: boolean;
|
|
||||||
class?: string;
|
|
||||||
children?: Snippet;
|
|
||||||
onclick?: (event: MouseEvent) => void;
|
|
||||||
onfocus?: () => void;
|
|
||||||
onblur?: () => void;
|
|
||||||
form?: string;
|
|
||||||
disabled?: boolean;
|
|
||||||
title?: string;
|
|
||||||
'aria-current'?: 'page' | 'step' | 'location' | 'date' | 'time' | undefined | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let {
|
|
||||||
type = 'button',
|
|
||||||
href = undefined,
|
|
||||||
color = 'primary',
|
|
||||||
size = 'base',
|
|
||||||
rounded = '3xl',
|
|
||||||
shadow = 'md',
|
|
||||||
fullwidth = false,
|
|
||||||
border = false,
|
|
||||||
class: className = '',
|
|
||||||
children,
|
|
||||||
onclick,
|
|
||||||
onfocus,
|
|
||||||
onblur,
|
|
||||||
...rest
|
|
||||||
}: Props = $props();
|
|
||||||
|
|
||||||
const colorClasses: Record<Color, string> = {
|
|
||||||
primary:
|
|
||||||
'bg-immich-primary dark:bg-immich-dark-primary text-white dark:text-immich-dark-gray dark:hover:bg-immich-dark-primary/80 hover:bg-immich-primary/90',
|
|
||||||
secondary:
|
|
||||||
'bg-gray-500 dark:bg-gray-200 text-white dark:text-immich-dark-gray hover:bg-gray-500/90 dark:hover:bg-gray-200/90',
|
|
||||||
'transparent-primary': 'text-gray-500 dark:text-immich-dark-primary hover:bg-gray-100 dark:hover:bg-gray-700',
|
|
||||||
'text-primary':
|
|
||||||
'text-immich-primary dark:text-immich-dark-primary dark:hover:bg-immich-dark-primary/10 hover:bg-immich-primary/10',
|
|
||||||
'light-red': 'bg-[#F9DEDC] text-[#410E0B] hover:bg-red-50',
|
|
||||||
red: 'bg-red-500 text-white hover:bg-red-400',
|
|
||||||
green: 'bg-green-400 text-gray-800 hover:bg-green-400/90',
|
|
||||||
gray: 'bg-gray-500 dark:bg-gray-200 hover:bg-gray-500/75 dark:hover:bg-gray-200/80 text-white dark:text-immich-dark-gray',
|
|
||||||
'transparent-gray':
|
|
||||||
'dark:text-immich-dark-fg hover:bg-immich-primary/5 hover:text-gray-700 hover:dark:text-immich-dark-fg dark:hover:bg-immich-dark-primary/25',
|
|
||||||
'dark-gray':
|
|
||||||
'dark:border-immich-dark-gray dark:bg-gray-500 dark:hover:bg-immich-dark-primary/50 hover:bg-immich-primary/10 dark:text-white',
|
|
||||||
'overlay-primary': 'text-gray-500 hover:bg-gray-100',
|
|
||||||
'primary-inversed':
|
|
||||||
'bg-immich-dark-primary dark:bg-immich-primary text-black dark:text-white hover:bg-immich-dark-primary/80 dark:hover:bg-immich-primary/90',
|
|
||||||
};
|
|
||||||
|
|
||||||
const sizeClasses: Record<Size, string> = {
|
|
||||||
tiny: 'p-0 ms-2 me-0 align-top',
|
|
||||||
icon: 'p-2.5',
|
|
||||||
link: 'p-2 font-medium',
|
|
||||||
sm: 'px-4 py-2 text-sm font-medium',
|
|
||||||
base: 'px-6 py-3 font-medium',
|
|
||||||
lg: 'px-6 py-4 font-semibold',
|
|
||||||
};
|
|
||||||
|
|
||||||
const roundedClasses: Record<Rounded, string> = {
|
|
||||||
none: '',
|
|
||||||
lg: 'rounded-lg',
|
|
||||||
'3xl': 'rounded-3xl',
|
|
||||||
full: 'rounded-full',
|
|
||||||
};
|
|
||||||
|
|
||||||
let computedClass = $derived(
|
|
||||||
[
|
|
||||||
className,
|
|
||||||
colorClasses[color],
|
|
||||||
sizeClasses[size],
|
|
||||||
roundedClasses[rounded],
|
|
||||||
shadow === 'md' && 'shadow-md',
|
|
||||||
fullwidth && 'w-full',
|
|
||||||
border && 'border',
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.join(' '),
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:element
|
|
||||||
this={href ? 'a' : 'button'}
|
|
||||||
type={href ? undefined : type}
|
|
||||||
{href}
|
|
||||||
{onclick}
|
|
||||||
{onfocus}
|
|
||||||
{onblur}
|
|
||||||
class="inline-flex items-center justify-center transition-colors disabled:cursor-not-allowed disabled:opacity-60 disabled:pointer-events-none {computedClass}"
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{@render children?.()}
|
|
||||||
</svelte:element>
|
|
@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getTabbable } from '$lib/utils/focus-util';
|
import { getTabbable } from '$lib/utils/focus-util';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import Button from './button.svelte';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
@ -58,8 +58,7 @@
|
|||||||
|
|
||||||
<div class="absolute top-2 start-2 transition-transform {isFocused ? 'translate-y-0' : '-translate-y-10 sr-only'}">
|
<div class="absolute top-2 start-2 transition-transform {isFocused ? 'translate-y-0' : '-translate-y-10 sr-only'}">
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="small"
|
||||||
rounded="none"
|
|
||||||
onclick={moveFocus}
|
onclick={moveFocus}
|
||||||
class={getBreakpoint()}
|
class={getBreakpoint()}
|
||||||
onfocus={() => (isFocused = true)}
|
onfocus={() => (isFocused = true)}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type PersonResponseDto } from '@immich/sdk';
|
|
||||||
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
|
||||||
import SearchPeople from '$lib/components/faces-page/people-search.svelte';
|
import SearchPeople from '$lib/components/faces-page/people-search.svelte';
|
||||||
|
import { type PersonResponseDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
person: PersonResponseDto;
|
person: PersonResponseDto;
|
||||||
@ -44,6 +44,6 @@
|
|||||||
inputClass="w-full gap-2 bg-gray-100 dark:bg-gray-700 dark:text-white"
|
inputClass="w-full gap-2 bg-gray-100 dark:bg-gray-700 dark:text-white"
|
||||||
bind:showLoadingSpinner={isSearchingPeople}
|
bind:showLoadingSpinner={isSearchingPeople}
|
||||||
/>
|
/>
|
||||||
<Button size="sm" type="submit">{$t('done')}</Button>
|
<Button size="small" shape="round" type="submit">{$t('done')}</Button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { shortcut } from '$lib/actions/shortcut';
|
import { shortcut } from '$lib/actions/shortcut';
|
||||||
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import PeopleInfiniteScroll from '$lib/components/faces-page/people-infinite-scroll.svelte';
|
import PeopleInfiniteScroll from '$lib/components/faces-page/people-infinite-scroll.svelte';
|
||||||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
|
||||||
import {
|
import {
|
||||||
notificationController,
|
notificationController,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
@ -13,6 +11,7 @@
|
|||||||
import { getPeopleThumbnailUrl } from '$lib/utils';
|
import { getPeopleThumbnailUrl } from '$lib/utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { updatePeople, type PersonResponseDto } from '@immich/sdk';
|
import { updatePeople, type PersonResponseDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiClose, mdiEye, mdiEyeOff, mdiEyeSettings, mdiRestart } from '@mdi/js';
|
import { mdiClose, mdiEye, mdiEyeOff, mdiEyeSettings, mdiRestart } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
@ -126,11 +125,7 @@
|
|||||||
<CircleIconButton title={$t('reset_people_visibility')} icon={mdiRestart} onclick={handleResetVisibility} />
|
<CircleIconButton title={$t('reset_people_visibility')} icon={mdiRestart} onclick={handleResetVisibility} />
|
||||||
<CircleIconButton title={toggleButton.label} icon={toggleButton.icon} onclick={handleToggleVisibility} />
|
<CircleIconButton title={toggleButton.label} icon={toggleButton.icon} onclick={handleToggleVisibility} />
|
||||||
</div>
|
</div>
|
||||||
{#if !showLoadingSpinner}
|
<Button loading={showLoadingSpinner} onclick={handleSaveVisibility} size="small">{$t('done')}</Button>
|
||||||
<Button onclick={handleSaveVisibility} size="sm" rounded="lg">{$t('done')}</Button>
|
|
||||||
{:else}
|
|
||||||
<LoadingSpinner />
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { getAllPeople, getPerson, mergePerson, type PersonResponseDto } from '@immich/sdk';
|
import { getAllPeople, getPerson, mergePerson, type PersonResponseDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
|
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { flip } from 'svelte/animate';
|
import { flip } from 'svelte/animate';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
@ -108,10 +108,9 @@
|
|||||||
<div></div>
|
<div></div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet trailing()}
|
{#snippet trailing()}
|
||||||
<Button size="sm" disabled={!hasSelection} onclick={handleMerge}>
|
<Button leadingIcon={mdiMerge} size="small" shape="round" disabled={!hasSelection} onclick={handleMerge}>
|
||||||
<Icon path={mdiMerge} size={18} />
|
{$t('merge')}
|
||||||
<span class="ms-2">{$t('merge')}</span></Button
|
</Button>
|
||||||
>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</ControlAppBar>
|
</ControlAppBar>
|
||||||
<section class="px-[70px] pt-[100px]">
|
<section class="px-[70px] pt-[100px]">
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import { timeBeforeShowLoadingSpinner } from '$lib/constants';
|
import { timeBeforeShowLoadingSpinner } from '$lib/constants';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import {
|
import {
|
||||||
@ -9,14 +8,13 @@
|
|||||||
type AssetFaceUpdateItem,
|
type AssetFaceUpdateItem,
|
||||||
type PersonResponseDto,
|
type PersonResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiMerge, mdiPlus } from '@mdi/js';
|
import { mdiMerge, mdiPlus } from '@mdi/js';
|
||||||
import { onMount, type Snippet } from 'svelte';
|
import { onMount, type Snippet } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
|
|
||||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||||
import FaceThumbnail from './face-thumbnail.svelte';
|
import FaceThumbnail from './face-thumbnail.svelte';
|
||||||
import PeopleList from './people-list.svelte';
|
import PeopleList from './people-list.svelte';
|
||||||
@ -130,33 +128,27 @@
|
|||||||
{#snippet trailing()}
|
{#snippet trailing()}
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<Button
|
<Button
|
||||||
|
shape="round"
|
||||||
title={$t('create_new_person_hint')}
|
title={$t('create_new_person_hint')}
|
||||||
size="sm"
|
leadingIcon={mdiPlus}
|
||||||
|
loading={showLoadingSpinnerCreate}
|
||||||
|
size="small"
|
||||||
disabled={disableButtons || hasSelection}
|
disabled={disableButtons || hasSelection}
|
||||||
onclick={handleCreate}
|
onclick={handleCreate}
|
||||||
>
|
>
|
||||||
{#if !showLoadingSpinnerCreate}
|
{$t('create_new_person')}</Button
|
||||||
<Icon path={mdiPlus} size={18} />
|
|
||||||
{:else}
|
|
||||||
<LoadingSpinner />
|
|
||||||
{/if}
|
|
||||||
<span class="ms-2"> {$t('create_new_person')}</span></Button
|
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="small"
|
||||||
|
shape="round"
|
||||||
title={$t('reassing_hint')}
|
title={$t('reassing_hint')}
|
||||||
|
leadingIcon={mdiMerge}
|
||||||
|
loading={showLoadingSpinnerReassign}
|
||||||
disabled={disableButtons || !hasSelection}
|
disabled={disableButtons || !hasSelection}
|
||||||
onclick={handleReassign}
|
onclick={handleReassign}
|
||||||
>
|
>
|
||||||
{#if !showLoadingSpinnerReassign}
|
{$t('reassign')}
|
||||||
<div>
|
</Button>
|
||||||
<Icon path={mdiMerge} size={18} class="rotate-180" />
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<LoadingSpinner />
|
|
||||||
{/if}
|
|
||||||
<span class="ms-2"> {$t('reassign')}</span></Button
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</ControlAppBar>
|
</ControlAppBar>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import { type LibraryResponseDto } from '@immich/sdk';
|
import { type LibraryResponseDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiPencilOutline } from '@mdi/js';
|
import { mdiPencilOutline } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { handleError } from '../../utils/handle-error';
|
import { handleError } from '../../utils/handle-error';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
|
||||||
import LibraryExclusionPatternForm from './library-exclusion-pattern-form.svelte';
|
import LibraryExclusionPatternForm from './library-exclusion-pattern-form.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -152,20 +152,21 @@
|
|||||||
{$t('admin.no_pattern_added')}
|
{$t('admin.no_pattern_added')}
|
||||||
{/if}
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td class="w-1/4 text-ellipsis px-4 text-sm"
|
<td class="w-1/4 text-ellipsis px-4 text-sm flex justify-center">
|
||||||
><Button
|
<Button
|
||||||
size="sm"
|
size="small"
|
||||||
|
shape="round"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
addExclusionPattern = true;
|
addExclusionPattern = true;
|
||||||
}}>{$t('add_exclusion_pattern')}</Button
|
}}>{$t('add_exclusion_pattern')}</Button
|
||||||
></td
|
|
||||||
></tr
|
|
||||||
>
|
>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div class="flex w-full justify-end gap-4">
|
<div class="flex w-full justify-end gap-2">
|
||||||
<Button size="sm" color="gray" onclick={onCancel}>{$t('cancel')}</Button>
|
<Button size="small" shape="round" color="secondary" onclick={onCancel}>{$t('cancel')}</Button>
|
||||||
<Button size="sm" type="submit">{$t('save')}</Button>
|
<Button size="small" shape="round" type="submit">{$t('save')}</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
|
import { getAllTags, upsertTags, type TagResponseDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiClose, mdiTag } from '@mdi/js';
|
import { mdiClose, mdiTag } from '@mdi/js';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import { SvelteSet } from 'svelte/reactivity';
|
||||||
import Combobox, { type ComboBoxOption } from '../shared-components/combobox.svelte';
|
import Combobox, { type ComboBoxOption } from '../shared-components/combobox.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
import { onMount } from 'svelte';
|
|
||||||
import { getAllTags, upsertTags, type TagResponseDto } from '@immich/sdk';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import { SvelteSet } from 'svelte/reactivity';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onTag: (tagIds: string[]) => void;
|
onTag: (tagIds: string[]) => void;
|
||||||
@ -93,7 +93,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{#snippet stickyBottom()}
|
{#snippet stickyBottom()}
|
||||||
<Button color="gray" fullwidth onclick={onCancel}>{$t('cancel')}</Button>
|
<Button shape="round" fullWidth color="secondary" onclick={onCancel}>{$t('cancel')}</Button>
|
||||||
<Button type="submit" fullwidth form="create-tag-form" {disabled}>{$t('tag_assets')}</Button>
|
<Button type="submit" shape="round" fullWidth form="create-tag-form" {disabled}>{$t('tag_assets')}</Button>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import OnboardingCard from './onboarding-card.svelte';
|
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import { mdiArrowRight } from '@mdi/js';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
|
import { mdiArrowRight } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import OnboardingCard from './onboarding-card.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onDone: () => void;
|
onDone: () => void;
|
||||||
@ -22,9 +21,8 @@
|
|||||||
<p class="text-3xl pb-6 font-light">{$t('onboarding_welcome_description')}</p>
|
<p class="text-3xl pb-6 font-light">{$t('onboarding_welcome_description')}</p>
|
||||||
|
|
||||||
<div class="w-full flex place-content-end">
|
<div class="w-full flex place-content-end">
|
||||||
<Button class="flex gap-2 place-content-center" onclick={() => onDone()}>
|
<Button shape="round" trailingIcon={mdiArrowRight} class="flex gap-2 place-content-center" onclick={onDone}>
|
||||||
<p>{$t('theme')}</p>
|
<p>{$t('theme')}</p>
|
||||||
<Icon path={mdiArrowRight} size="18" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</OnboardingCard>
|
</OnboardingCard>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
||||||
|
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { getConfig, type SystemConfigDto } from '@immich/sdk';
|
import { getConfig, type SystemConfigDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiArrowLeft, mdiArrowRight, mdiIncognito } from '@mdi/js';
|
import { mdiArrowLeft, mdiArrowRight, mdiIncognito } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import OnboardingCard from './onboarding-card.svelte';
|
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
import OnboardingCard from './onboarding-card.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onDone: () => void;
|
onDone: () => void;
|
||||||
@ -45,13 +44,19 @@
|
|||||||
/>
|
/>
|
||||||
<div class="flex pt-4">
|
<div class="flex pt-4">
|
||||||
<div class="w-full flex place-content-start">
|
<div class="w-full flex place-content-start">
|
||||||
<Button class="flex gap-2 place-content-center" onclick={() => onPrevious()}>
|
<Button
|
||||||
<Icon path={mdiArrowLeft} size="18" />
|
shape="round"
|
||||||
|
leadingIcon={mdiArrowLeft}
|
||||||
|
class="flex gap-2 place-content-center"
|
||||||
|
onclick={() => onPrevious()}
|
||||||
|
>
|
||||||
<p>{$t('theme')}</p>
|
<p>{$t('theme')}</p>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex w-full place-content-end">
|
<div class="flex w-full place-content-end">
|
||||||
<Button
|
<Button
|
||||||
|
shape="round"
|
||||||
|
trailingIcon={mdiArrowRight}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
adminSettingsComponent?.handleSave({ map: config?.map, newVersionCheck: config?.newVersionCheck });
|
adminSettingsComponent?.handleSave({ map: config?.map, newVersionCheck: config?.newVersionCheck });
|
||||||
onDone();
|
onDone();
|
||||||
@ -59,7 +64,6 @@
|
|||||||
>
|
>
|
||||||
<span class="flex place-content-center place-items-center gap-2">
|
<span class="flex place-content-center place-items-center gap-2">
|
||||||
{$t('admin.storage_template_settings')}
|
{$t('admin.storage_template_settings')}
|
||||||
<Icon path={mdiArrowRight} size="18" />
|
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
||||||
|
import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
|
||||||
|
import FormatMessage from '$lib/components/i18n/format-message.svelte';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { getConfig, type SystemConfigDto } from '@immich/sdk';
|
import { getConfig, type SystemConfigDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiArrowLeft, mdiCheck, mdiHarddisk } from '@mdi/js';
|
import { mdiArrowLeft, mdiCheck, mdiHarddisk } from '@mdi/js';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import AdminSettings from '$lib/components/admin-page/settings/admin-settings.svelte';
|
|
||||||
import StorageTemplateSettings from '$lib/components/admin-page/settings/storage-template/storage-template-settings.svelte';
|
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import OnboardingCard from './onboarding-card.svelte';
|
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import FormatMessage from '$lib/components/i18n/format-message.svelte';
|
import OnboardingCard from './onboarding-card.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onDone: () => void;
|
onDone: () => void;
|
||||||
@ -52,13 +51,19 @@
|
|||||||
>
|
>
|
||||||
<div class="flex pt-4">
|
<div class="flex pt-4">
|
||||||
<div class="w-full flex place-content-start">
|
<div class="w-full flex place-content-start">
|
||||||
<Button class="flex gap-2 place-content-center" onclick={() => onPrevious()}>
|
<Button
|
||||||
<Icon path={mdiArrowLeft} size="18" />
|
shape="round"
|
||||||
|
leadingIcon={mdiArrowLeft}
|
||||||
|
class="flex gap-2 place-content-center"
|
||||||
|
onclick={() => onPrevious()}
|
||||||
|
>
|
||||||
<p>{$t('privacy')}</p>
|
<p>{$t('privacy')}</p>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex w-full place-content-end">
|
<div class="flex w-full place-content-end">
|
||||||
<Button
|
<Button
|
||||||
|
shape="round"
|
||||||
|
trailingIcon={mdiCheck}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
adminSettingsComponent?.handleSave({ storageTemplate: config?.storageTemplate });
|
adminSettingsComponent?.handleSave({ storageTemplate: config?.storageTemplate });
|
||||||
onDone();
|
onDone();
|
||||||
@ -66,7 +71,6 @@
|
|||||||
>
|
>
|
||||||
<span class="flex place-content-center place-items-center gap-2">
|
<span class="flex place-content-center place-items-center gap-2">
|
||||||
{$t('done')}
|
{$t('done')}
|
||||||
<Icon path={mdiCheck} size="18" />
|
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths';
|
import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { Theme } from '$lib/constants';
|
import { Theme } from '$lib/constants';
|
||||||
import { themeManager } from '$lib/managers/theme-manager.svelte';
|
import { themeManager } from '$lib/managers/theme-manager.svelte';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiArrowRight, mdiThemeLightDark } from '@mdi/js';
|
import { mdiArrowRight, mdiThemeLightDark } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import OnboardingCard from './onboarding-card.svelte';
|
import OnboardingCard from './onboarding-card.svelte';
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<div class="flex gap-4 mb-6">
|
<div class="flex gap-4 mb-6">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="light w-1/2 aspect-square bg-light rounded-3xl transition-all shadow-sm hover:shadow-xl border-[3px] border-immich-dark-primary/80 border-immich-primary dark:border dark:border-transparent"
|
class="w-1/2 aspect-square bg-light dark:bg-dark rounded-3xl transition-all shadow-sm hover:shadow-xl border-[3px] border-immich-dark-primary/80 border-immich-primary dark:border dark:border-transparent"
|
||||||
onclick={() => themeManager.setTheme(Theme.LIGHT)}
|
onclick={() => themeManager.setTheme(Theme.LIGHT)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@ -49,9 +49,13 @@
|
|||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="w-full flex place-content-end">
|
<div class="w-full flex place-content-end">
|
||||||
<Button class="flex gap-2 place-content-center" onclick={() => onDone()}>
|
<Button
|
||||||
|
trailingIcon={mdiArrowRight}
|
||||||
|
shape="round"
|
||||||
|
class="flex gap-2 place-content-center"
|
||||||
|
onclick={() => onDone()}
|
||||||
|
>
|
||||||
<p>{$t('privacy')}</p>
|
<p>{$t('privacy')}</p>
|
||||||
<Icon path={mdiArrowRight} size="18" />
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import { focusTrap } from '$lib/actions/focus-trap';
|
import { focusTrap } from '$lib/actions/focus-trap';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
import { modalManager } from '$lib/managers/modal-manager.svelte';
|
||||||
import AvatarEditModal from '$lib/modals/AvatarEditModal.svelte';
|
import AvatarEditModal from '$lib/modals/AvatarEditModal.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js';
|
import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
@ -53,7 +53,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<Button href={AppRoute.USER_SETTINGS} onclick={onClose} color="dark-gray" size="sm" shadow={false} border>
|
<Button
|
||||||
|
href={AppRoute.USER_SETTINGS}
|
||||||
|
onclick={onClose}
|
||||||
|
size="small"
|
||||||
|
color="secondary"
|
||||||
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
class="border dark:border-immich-dark-gray dark:bg-gray-500 dark:hover:bg-immich-dark-primary/50 hover:bg-immich-primary/10 dark:text-white"
|
||||||
|
>
|
||||||
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
||||||
<Icon path={mdiCog} size="18" ariaHidden />
|
<Icon path={mdiCog} size="18" ariaHidden />
|
||||||
{$t('account_settings')}
|
{$t('account_settings')}
|
||||||
@ -63,11 +71,12 @@
|
|||||||
<Button
|
<Button
|
||||||
href={AppRoute.ADMIN_USERS}
|
href={AppRoute.ADMIN_USERS}
|
||||||
onclick={onClose}
|
onclick={onClose}
|
||||||
color="dark-gray"
|
shape="round"
|
||||||
size="sm"
|
variant="ghost"
|
||||||
shadow={false}
|
size="small"
|
||||||
border
|
color="secondary"
|
||||||
aria-current={page.url.pathname.includes('/admin') ? 'page' : undefined}
|
aria-current={page.url.pathname.includes('/admin') ? 'page' : undefined}
|
||||||
|
class="border dark:border-immich-dark-gray dark:bg-gray-500 dark:hover:bg-immich-dark-primary/50 hover:bg-immich-primary/10 dark:text-white"
|
||||||
>
|
>
|
||||||
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
|
||||||
<Icon path={mdiWrench} size="18" ariaHidden />
|
<Icon path={mdiWrench} size="18" ariaHidden />
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { createProfileImage, type AssetResponseDto } from '@immich/sdk';
|
import { createProfileImage, type AssetResponseDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import domtoimage from 'dom-to-image';
|
import domtoimage from 'dom-to-image';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import PhotoViewer from '../asset-viewer/photo-viewer.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
|
||||||
import { NotificationType, notificationController } from './notification/notification';
|
|
||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
import PhotoViewer from '../asset-viewer/photo-viewer.svelte';
|
||||||
|
import { NotificationType, notificationController } from './notification/notification';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
asset: AssetResponseDto;
|
asset: AssetResponseDto;
|
||||||
@ -99,6 +99,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#snippet stickyBottom()}
|
{#snippet stickyBottom()}
|
||||||
<Button fullwidth onclick={handleSetProfilePicture}>{$t('set_as_profile_picture')}</Button>
|
<Button fullWidth shape="round" onclick={handleSetProfilePicture}>{$t('set_as_profile_picture')}</Button>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { ImmichProduct } from '$lib/constants';
|
import { ImmichProduct } from '$lib/constants';
|
||||||
import { getLicenseLink as getProductLink } from '$lib/utils/license-utils';
|
import { getLicenseLink as getProductLink } from '$lib/utils/license-utils';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiAccount, mdiCheckCircleOutline } from '@mdi/js';
|
import { mdiAccount, mdiCheckCircleOutline } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
</script>
|
</script>
|
||||||
@ -39,6 +39,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button href={getProductLink(ImmichProduct.Client)} fullwidth>{$t('purchase_button_select')}</Button>
|
<Button shape="round" href={getProductLink(ImmichProduct.Client)} fullWidth>{$t('purchase_button_select')}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||||
import { preferences } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import { setSupportBadgeVisibility } from '$lib/utils/purchase-utils';
|
import { setSupportBadgeVisibility } from '$lib/utils/purchase-utils';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiPartyPopper } from '@mdi/js';
|
import { mdiPartyPopper } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
|
|
||||||
@ -29,6 +29,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-6 w-full">
|
<div class="mt-6 w-full">
|
||||||
<Button fullwidth onclick={onDone}>{$t('ok')}</Button>
|
<Button fullWidth shape="round" onclick={onDone}>{$t('ok')}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||||
import { purchaseStore } from '$lib/stores/purchase.store';
|
import { purchaseStore } from '$lib/stores/purchase.store';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { activateProduct, getActivationKey } from '$lib/utils/license-utils';
|
import { activateProduct, getActivationKey } from '$lib/utils/license-utils';
|
||||||
import { Heading } from '@immich/ui';
|
import { Button, Heading } from '@immich/ui';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import UserPurchaseOptionCard from './individual-purchase-option-card.svelte';
|
import UserPurchaseOptionCard from './individual-purchase-option-card.svelte';
|
||||||
import ServerPurchaseOptionCard from './server-purchase-option-card.svelte';
|
import ServerPurchaseOptionCard from './server-purchase-option-card.svelte';
|
||||||
@ -74,7 +73,7 @@
|
|||||||
placeholder="IMCL-0KEY-0CAN-00BE-FOUD-FROM-YOUR-EMAIL-INBX"
|
placeholder="IMCL-0KEY-0CAN-00BE-FOUD-FROM-YOUR-EMAIL-INBX"
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
<Button type="submit" rounded="lg"
|
<Button type="submit"
|
||||||
>{#if isLoading}
|
>{#if isLoading}
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
{:else}
|
{:else}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import { ImmichProduct } from '$lib/constants';
|
import { ImmichProduct } from '$lib/constants';
|
||||||
import { getLicenseLink } from '$lib/utils/license-utils';
|
import { getLicenseLink } from '$lib/utils/license-utils';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiCheckCircleOutline, mdiServer } from '@mdi/js';
|
import { mdiCheckCircleOutline, mdiServer } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
</script>
|
</script>
|
||||||
@ -39,6 +39,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button href={getLicenseLink(ImmichProduct.Server)} fullwidth>{$t('purchase_button_select')}</Button>
|
<Button shape="round" href={getLicenseLink(ImmichProduct.Server)} fullWidth>{$t('purchase_button_select')}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
|
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
|
||||||
import SearchBar from '$lib/components/elements/search-bar.svelte';
|
import SearchBar from '$lib/components/elements/search-bar.svelte';
|
||||||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||||
import SingleGridRow from '$lib/components/shared-components/single-grid-row.svelte';
|
import SingleGridRow from '$lib/components/shared-components/single-grid-row.svelte';
|
||||||
import { getPeopleThumbnailUrl } from '$lib/utils';
|
import { getPeopleThumbnailUrl } from '$lib/utils';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { getAllPeople, type PersonResponseDto } from '@immich/sdk';
|
import { getAllPeople, type PersonResponseDto } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { mdiArrowRight, mdiClose } from '@mdi/js';
|
import { mdiArrowRight, mdiClose } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { SvelteSet } from 'svelte/reactivity';
|
import type { SvelteSet } from 'svelte/reactivity';
|
||||||
@ -92,18 +91,14 @@
|
|||||||
{#if showAllPeople || people.length > peopleList.length}
|
{#if showAllPeople || people.length > peopleList.length}
|
||||||
<div class="flex justify-center mt-2">
|
<div class="flex justify-center mt-2">
|
||||||
<Button
|
<Button
|
||||||
shadow={false}
|
color="primary"
|
||||||
color="text-primary"
|
variant="ghost"
|
||||||
|
shape="round"
|
||||||
|
leadingIcon={showAllPeople ? mdiClose : mdiArrowRight}
|
||||||
class="flex gap-2 place-items-center"
|
class="flex gap-2 place-items-center"
|
||||||
onclick={() => (showAllPeople = !showAllPeople)}
|
onclick={() => (showAllPeople = !showAllPeople)}
|
||||||
>
|
>
|
||||||
{#if showAllPeople}
|
{showAllPeople ? $t('collapse') : $t('see_all_people')}
|
||||||
<span><Icon path={mdiClose} ariaHidden /></span>
|
|
||||||
{$t('collapse')}
|
|
||||||
{:else}
|
|
||||||
<span><Icon path={mdiArrowRight} ariaHidden /></span>
|
|
||||||
{$t('see_all_people')}
|
|
||||||
{/if}
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import FormatMessage from '$lib/components/i18n/format-message.svelte';
|
||||||
import { websocketStore } from '$lib/stores/websocket';
|
import { websocketStore } from '$lib/stores/websocket';
|
||||||
import type { ServerVersionResponseDto } from '@immich/sdk';
|
import type { ServerVersionResponseDto } from '@immich/sdk';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import { Button } from '@immich/ui';
|
||||||
import FullScreenModal from './full-screen-modal.svelte';
|
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import FormatMessage from '$lib/components/i18n/format-message.svelte';
|
import FullScreenModal from './full-screen-modal.svelte';
|
||||||
|
|
||||||
let showModal = $state(false);
|
let showModal = $state(false);
|
||||||
|
|
||||||
@ -65,7 +65,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#snippet stickyBottom()}
|
{#snippet stickyBottom()}
|
||||||
<Button fullwidth onclick={onAcknowledge}>{$t('acknowledge')}</Button>
|
<Button fullWidth shape="round" onclick={onAcknowledge}>{$t('acknowledge')}</Button>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte';
|
import SettingInputField from '$lib/components/shared-components/settings/setting-input-field.svelte';
|
||||||
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
|
||||||
|
import { SettingInputFieldType } from '$lib/constants';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiArrowDownThin,
|
mdiArrowDownThin,
|
||||||
mdiArrowUpThin,
|
mdiArrowUpThin,
|
||||||
@ -10,12 +12,10 @@
|
|||||||
mdiPanorama,
|
mdiPanorama,
|
||||||
mdiShuffle,
|
mdiShuffle,
|
||||||
} from '@mdi/js';
|
} from '@mdi/js';
|
||||||
|
import { t } from 'svelte-i18n';
|
||||||
import { SlideshowLook, SlideshowNavigation, slideshowStore } from '../stores/slideshow.store';
|
import { SlideshowLook, SlideshowNavigation, slideshowStore } from '../stores/slideshow.store';
|
||||||
import Button from './elements/buttons/button.svelte';
|
|
||||||
import type { RenderedOption } from './elements/dropdown.svelte';
|
import type { RenderedOption } from './elements/dropdown.svelte';
|
||||||
import SettingDropdown from './shared-components/settings/setting-dropdown.svelte';
|
import SettingDropdown from './shared-components/settings/setting-dropdown.svelte';
|
||||||
import { t } from 'svelte-i18n';
|
|
||||||
import { SettingInputFieldType } from '$lib/constants';
|
|
||||||
|
|
||||||
const { slideshowDelay, showProgressBar, slideshowNavigation, slideshowLook, slideshowTransition } = slideshowStore;
|
const { slideshowDelay, showProgressBar, slideshowNavigation, slideshowLook, slideshowTransition } = slideshowStore;
|
||||||
|
|
||||||
@ -79,6 +79,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#snippet stickyBottom()}
|
{#snippet stickyBottom()}
|
||||||
<Button fullwidth color="primary" onclick={(_) => onClose()}>{$t('done')}</Button>
|
<Button fullWidth shape="round" color="primary" onclick={() => onClose()}>{$t('done')}</Button>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
</FullScreenModal>
|
</FullScreenModal>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
import { shortcuts } from '$lib/actions/shortcut';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import Portal from '$lib/components/shared-components/portal/portal.svelte';
|
import Portal from '$lib/components/shared-components/portal/portal.svelte';
|
||||||
import DuplicateAsset from '$lib/components/utilities-page/duplicates/duplicate-asset.svelte';
|
import DuplicateAsset from '$lib/components/utilities-page/duplicates/duplicate-asset.svelte';
|
||||||
@ -7,9 +7,9 @@
|
|||||||
import { handlePromiseError } from '$lib/utils';
|
import { handlePromiseError } from '$lib/utils';
|
||||||
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
|
import { suggestDuplicate } from '$lib/utils/duplicate-utils';
|
||||||
import { navigate } from '$lib/utils/navigation';
|
import { navigate } from '$lib/utils/navigation';
|
||||||
import { shortcuts } from '$lib/actions/shortcut';
|
|
||||||
import { type AssetResponseDto } from '@immich/sdk';
|
import { type AssetResponseDto } from '@immich/sdk';
|
||||||
import { mdiCheck, mdiTrashCanOutline, mdiImageMultipleOutline } from '@mdi/js';
|
import { Button } from '@immich/ui';
|
||||||
|
import { mdiCheck, mdiImageMultipleOutline, mdiTrashCanOutline } from '@mdi/js';
|
||||||
import { onDestroy, onMount } from 'svelte';
|
import { onDestroy, onMount } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { SvelteSet } from 'svelte/reactivity';
|
import { SvelteSet } from 'svelte/reactivity';
|
||||||
@ -132,18 +132,28 @@
|
|||||||
<!-- CONFIRM BUTTONS -->
|
<!-- CONFIRM BUTTONS -->
|
||||||
<div class="flex text-xs text-black">
|
<div class="flex text-xs text-black">
|
||||||
{#if trashCount === 0}
|
{#if trashCount === 0}
|
||||||
<Button size="sm" color="primary" class="flex place-items-center rounded-s-full gap-2" onclick={handleResolve}>
|
<Button
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
class="flex place-items-center rounded-s-full gap-2"
|
||||||
|
onclick={handleResolve}
|
||||||
|
>
|
||||||
<Icon path={mdiCheck} size="20" />{$t('keep_all')}
|
<Icon path={mdiCheck} size="20" />{$t('keep_all')}
|
||||||
</Button>
|
</Button>
|
||||||
{:else}
|
{:else}
|
||||||
<Button size="sm" color="red" class="flex place-items-center rounded-s-full gap-2 py-3" onclick={handleResolve}>
|
<Button
|
||||||
|
size="small"
|
||||||
|
color="danger"
|
||||||
|
class="flex place-items-center rounded-s-full gap-2 py-3"
|
||||||
|
onclick={handleResolve}
|
||||||
|
>
|
||||||
<Icon path={mdiTrashCanOutline} size="20" />{trashCount === assets.length
|
<Icon path={mdiTrashCanOutline} size="20" />{trashCount === assets.length
|
||||||
? $t('trash_all')
|
? $t('trash_all')
|
||||||
: $t('trash_count', { values: { count: trashCount } })}
|
: $t('trash_count', { values: { count: trashCount } })}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="small"
|
||||||
color="primary"
|
color="primary"
|
||||||
class="flex place-items-center rounded-e-full gap-2"
|
class="flex place-items-center rounded-e-full gap-2"
|
||||||
onclick={handleStack}
|
onclick={handleStack}
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { updatePerson, type PersonResponseDto } from '@immich/sdk';
|
import { updatePerson, type PersonResponseDto } from '@immich/sdk';
|
||||||
import { Modal, ModalBody, ModalFooter } from '@immich/ui';
|
import { Button, Modal, ModalBody, ModalFooter } from '@immich/ui';
|
||||||
import { mdiCake } from '@mdi/js';
|
import { mdiCake } from '@mdi/js';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import Button from '../components/elements/buttons/button.svelte';
|
|
||||||
import DateInput from '../components/elements/date-input.svelte';
|
import DateInput from '../components/elements/date-input.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -60,8 +59,12 @@
|
|||||||
|
|
||||||
<ModalFooter>
|
<ModalFooter>
|
||||||
<div class="flex gap-3 w-full">
|
<div class="flex gap-3 w-full">
|
||||||
<Button color="secondary" fullwidth onclick={() => onClose()}>{$t('cancel')}</Button>
|
<Button shape="round" color="secondary" fullWidth onclick={() => onClose()}>
|
||||||
<Button type="submit" fullwidth form="set-birth-date-form">{$t('set')}</Button>
|
{$t('cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" shape="round" color="primary" fullWidth>
|
||||||
|
{$t('set')}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
import AlbumTitle from '$lib/components/album-page/album-title.svelte';
|
import AlbumTitle from '$lib/components/album-page/album-title.svelte';
|
||||||
import ActivityStatus from '$lib/components/asset-viewer/activity-status.svelte';
|
import ActivityStatus from '$lib/components/asset-viewer/activity-status.svelte';
|
||||||
import ActivityViewer from '$lib/components/asset-viewer/activity-viewer.svelte';
|
import ActivityViewer from '$lib/components/asset-viewer/activity-viewer.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
|
import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte';
|
||||||
@ -67,6 +66,7 @@
|
|||||||
updateAlbumInfo,
|
updateAlbumInfo,
|
||||||
type AlbumUserAddDto,
|
type AlbumUserAddDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiArrowLeft,
|
mdiArrowLeft,
|
||||||
mdiCogOutline,
|
mdiCogOutline,
|
||||||
@ -552,7 +552,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isCreatingSharedAlbum && album.albumUsers.length === 0}
|
{#if isCreatingSharedAlbum && album.albumUsers.length === 0}
|
||||||
<Button size="sm" rounded="lg" disabled={album.assetCount === 0} onclick={handleShare}>
|
<Button size="small" disabled={album.assetCount === 0} onclick={handleShare}>
|
||||||
{$t('share')}
|
{$t('share')}
|
||||||
</Button>
|
</Button>
|
||||||
{/if}
|
{/if}
|
||||||
@ -580,7 +580,7 @@
|
|||||||
>
|
>
|
||||||
{$t('select_from_computer')}
|
{$t('select_from_computer')}
|
||||||
</button>
|
</button>
|
||||||
<Button size="sm" rounded="lg" disabled={!timelineInteraction.selectionActive} onclick={handleAddAssets}
|
<Button size="small" disabled={!timelineInteraction.selectionActive} onclick={handleAddAssets}
|
||||||
>{$t('done')}</Button
|
>{$t('done')}</Button
|
||||||
>
|
>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import AlbumViewer from '$lib/components/album-page/album-viewer.svelte';
|
import AlbumViewer from '$lib/components/album-page/album-viewer.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
|
||||||
import IndividualSharedViewer from '$lib/components/share-page/individual-shared-viewer.svelte';
|
import IndividualSharedViewer from '$lib/components/share-page/individual-shared-viewer.svelte';
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import ImmichLogoSmallLink from '$lib/components/shared-components/immich-logo-small-link.svelte';
|
import ImmichLogoSmallLink from '$lib/components/shared-components/immich-logo-small-link.svelte';
|
||||||
@ -12,6 +11,7 @@
|
|||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { navigate } from '$lib/utils/navigation';
|
import { navigate } from '$lib/utils/navigation';
|
||||||
import { getMySharedLink, SharedLinkType } from '@immich/sdk';
|
import { getMySharedLink, SharedLinkType } from '@immich/sdk';
|
||||||
|
import { Button } from '@immich/ui';
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user