mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
wip
This commit is contained in:
parent
2e8a286540
commit
9806e94f6f
@ -34,6 +34,9 @@
|
|||||||
--immich-ui-info: 14 165 233;
|
--immich-ui-info: 14 165 233;
|
||||||
--immich-ui-default-border: 209 213 219;
|
--immich-ui-default-border: 209 213 219;
|
||||||
}
|
}
|
||||||
|
* {
|
||||||
|
--tw-ring-offset-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
/* dark */
|
/* dark */
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
import { cancelImageUrl } from '$lib/utils/sw-messaging';
|
import { cancelImageUrl } from '$lib/utils/sw-messaging';
|
||||||
import { TUNABLES } from '$lib/utils/tunables';
|
import { TUNABLES } from '$lib/utils/tunables';
|
||||||
import { mdiEyeOffOutline } from '@mdi/js';
|
import { mdiEyeOffOutline } from '@mdi/js';
|
||||||
import type { ClassValue } from 'svelte/elements';
|
|
||||||
import type { ActionReturn } from 'svelte/action';
|
import type { ActionReturn } from 'svelte/action';
|
||||||
|
import type { ClassValue } from 'svelte/elements';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -77,7 +77,7 @@
|
|||||||
circle && 'rounded-full',
|
circle && 'rounded-full',
|
||||||
shadow && 'shadow-lg',
|
shadow && 'shadow-lg',
|
||||||
(circle || !heightStyle) && 'aspect-square',
|
(circle || !heightStyle) && 'aspect-square',
|
||||||
border && 'border-[3px] border-immich-dark-primary/80 hover:border-immich-primary',
|
border && 'border-[3px] border-immich-dark-primary/80 hocus:border-immich-primary',
|
||||||
brokenAssetClass,
|
brokenAssetClass,
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
|
@ -61,17 +61,17 @@
|
|||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
const colorClasses: Record<Color, string> = {
|
const colorClasses: Record<Color, string> = {
|
||||||
transparent: 'bg-transparent hover:bg-[#d3d3d3] dark:text-immich-dark-fg',
|
transparent: 'bg-transparent hocus:bg-[#d3d3d3] dark:text-immich-dark-fg',
|
||||||
opaque: 'bg-transparent hover:bg-immich-bg/30 text-white hover:dark:text-white',
|
opaque: 'bg-transparent hocus:bg-immich-bg/30 text-white hocus:dark:text-white',
|
||||||
light: 'bg-white hover:bg-[#d3d3d3]',
|
light: 'bg-white hocus:bg-[#d3d3d3]',
|
||||||
red: 'text-red-400 bg-red-100 hover:bg-[#d3d3d3]',
|
red: 'text-red-400 bg-red-100 hocus:bg-[#d3d3d3]',
|
||||||
dark: 'bg-[#202123] hover:bg-[#d3d3d3]',
|
dark: 'bg-[#202123] hocus:bg-[#d3d3d3]',
|
||||||
alert: 'text-[#ff0000] hover:text-white',
|
alert: 'text-[#ff0000] hocus:text-white',
|
||||||
gray: 'bg-[#d3d3d3] hover:bg-[#e2e7e9] text-immich-dark-gray hover:text-black',
|
gray: 'bg-[#d3d3d3] hocus:bg-[#e2e7e9] text-immich-dark-gray hocus:text-black',
|
||||||
neutral:
|
neutral:
|
||||||
'dark:bg-immich-dark-gray dark:text-gray-300 hover:dark:bg-immich-dark-gray/50 hover:dark:text-gray-300 bg-gray-200 text-gray-700 hover:bg-gray-300',
|
'dark:bg-immich-dark-gray dark:text-gray-300 hocus:dark:bg-immich-dark-gray/50 hocus:dark:text-gray-300 bg-gray-200 text-gray-700 hocus:bg-gray-300',
|
||||||
primary:
|
primary:
|
||||||
'bg-immich-primary dark:bg-immich-dark-primary hover:bg-immich-primary/75 hover:dark:bg-immich-dark-primary/80 text-white dark:text-immich-dark-gray',
|
'bg-immich-primary dark:bg-immich-dark-primary hocus:bg-immich-primary/75 hocus:dark:bg-immich-dark-primary/80 text-white dark:text-immich-dark-gray',
|
||||||
};
|
};
|
||||||
|
|
||||||
const paddingClasses: Record<Padding, string> = {
|
const paddingClasses: Record<Padding, string> = {
|
||||||
@ -92,9 +92,16 @@
|
|||||||
{href}
|
{href}
|
||||||
style:width={buttonSize ? buttonSize + 'px' : ''}
|
style:width={buttonSize ? buttonSize + 'px' : ''}
|
||||||
style:height={buttonSize ? buttonSize + 'px' : ''}
|
style:height={buttonSize ? buttonSize + 'px' : ''}
|
||||||
class="flex place-content-center place-items-center rounded-full {colorClass} {paddingClass} transition-all disabled:cursor-default hover:dark:text-immich-dark-gray {className} {mobileClass}"
|
class="flex place-content-center place-items-center rounded-full {colorClass} {paddingClass} transition-all disabled:cursor-default hover:dark:text-immich-dark-gray focus:dark:text-immich-dark-gray outline-none ring-offset-transparent focus:ring-4 {className} {mobileClass}"
|
||||||
{onclick}
|
{onclick}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
<Icon path={icon} {size} ariaLabel={title} {viewBox} color="currentColor" />
|
<Icon path={icon} {size} ariaLabel={title} {viewBox} color="currentColor" />
|
||||||
</svelte:element>
|
</svelte:element>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
button,
|
||||||
|
a {
|
||||||
|
--tw-ring-offset-width: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { focusOutside } from '$lib/actions/focus-outside';
|
|
||||||
import Icon from '$lib/components/elements/icon.svelte';
|
import Icon from '$lib/components/elements/icon.svelte';
|
||||||
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
|
||||||
import { AppRoute, QueryParameter } from '$lib/constants';
|
import { AppRoute, QueryParameter } from '$lib/constants';
|
||||||
@ -27,22 +26,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let { person, onSetBirthDate, onMergePeople, onHidePerson, onToggleFavorite }: Props = $props();
|
let { person, onSetBirthDate, onMergePeople, onHidePerson, onToggleFavorite }: Props = $props();
|
||||||
|
|
||||||
let showVerticalDots = $state(false);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div id="people-card" class="relative group" role="group">
|
||||||
id="people-card"
|
|
||||||
class="relative"
|
|
||||||
onmouseenter={() => (showVerticalDots = true)}
|
|
||||||
onmouseleave={() => (showVerticalDots = false)}
|
|
||||||
role="group"
|
|
||||||
use:focusOutside={{ onFocusOut: () => (showVerticalDots = false) }}
|
|
||||||
>
|
|
||||||
<a
|
<a
|
||||||
|
class="focus:outline-none"
|
||||||
href="{AppRoute.PEOPLE}/{person.id}?{QueryParameter.PREVIOUS_ROUTE}={AppRoute.PEOPLE}"
|
href="{AppRoute.PEOPLE}/{person.id}?{QueryParameter.PREVIOUS_ROUTE}={AppRoute.PEOPLE}"
|
||||||
draggable="false"
|
draggable="false"
|
||||||
onfocus={() => (showVerticalDots = true)}
|
|
||||||
>
|
>
|
||||||
<div class="w-full h-full rounded-xl brightness-95 filter">
|
<div class="w-full h-full rounded-xl brightness-95 filter">
|
||||||
<ImageThumbnail
|
<ImageThumbnail
|
||||||
@ -61,10 +51,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
{#if showVerticalDots}
|
|
||||||
<div class="absolute top-2 end-2">
|
<div class="absolute top-2 end-2">
|
||||||
<ButtonContextMenu
|
<ButtonContextMenu
|
||||||
buttonClass="icon-white-drop-shadow focus:opacity-100 {showVerticalDots ? 'opacity-100' : 'opacity-0'}"
|
buttonClass="icon-white-drop-shadow focus:opacity-100 group-hover:opacity-100 opacity-0"
|
||||||
color="opaque"
|
color="opaque"
|
||||||
padding="2"
|
padding="2"
|
||||||
size="20"
|
size="20"
|
||||||
@ -81,5 +70,4 @@
|
|||||||
/>
|
/>
|
||||||
</ButtonContextMenu>
|
</ButtonContextMenu>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
import { AppRoute } from '$lib/constants';
|
import { AppRoute } from '$lib/constants';
|
||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
|
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
|
||||||
|
import { notificationManager } from '$lib/stores/notification-manager.svelte';
|
||||||
import { featureFlags } from '$lib/stores/server-config.store';
|
import { featureFlags } from '$lib/stores/server-config.store';
|
||||||
import { sidebarStore } from '$lib/stores/sidebar.svelte';
|
import { sidebarStore } from '$lib/stores/sidebar.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
@ -26,7 +27,6 @@
|
|||||||
import ThemeButton from '../theme-button.svelte';
|
import ThemeButton from '../theme-button.svelte';
|
||||||
import UserAvatar from '../user-avatar.svelte';
|
import UserAvatar from '../user-avatar.svelte';
|
||||||
import AccountInfoPanel from './account-info-panel.svelte';
|
import AccountInfoPanel from './account-info-panel.svelte';
|
||||||
import { notificationManager } from '$lib/stores/notification-manager.svelte';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
showUploadButton?: boolean;
|
showUploadButton?: boolean;
|
||||||
@ -35,6 +35,8 @@
|
|||||||
|
|
||||||
let { showUploadButton = true, onUploadClick }: Props = $props();
|
let { showUploadButton = true, onUploadClick }: Props = $props();
|
||||||
|
|
||||||
|
let isHocus = $state(false);
|
||||||
|
|
||||||
let shouldShowAccountInfo = $state(false);
|
let shouldShowAccountInfo = $state(false);
|
||||||
let shouldShowAccountInfoPanel = $state(false);
|
let shouldShowAccountInfoPanel = $state(false);
|
||||||
let shouldShowHelpPanel = $state(false);
|
let shouldShowHelpPanel = $state(false);
|
||||||
@ -83,7 +85,11 @@
|
|||||||
}}
|
}}
|
||||||
class="sidebar:hidden"
|
class="sidebar:hidden"
|
||||||
/>
|
/>
|
||||||
<a data-sveltekit-preload-data="hover" href={AppRoute.PHOTOS}>
|
<a
|
||||||
|
class="outline-none rounded-xl ring-inset focus:ring-2"
|
||||||
|
data-sveltekit-preload-data="hover"
|
||||||
|
href={AppRoute.PHOTOS}
|
||||||
|
>
|
||||||
<ImmichLogo class="max-md:h-[48px] h-[50px]" noText={!mobileDevice.isFullSidebar} />
|
<ImmichLogo class="max-md:h-[48px] h-[50px]" noText={!mobileDevice.isFullSidebar} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -97,6 +103,7 @@
|
|||||||
<section class="flex place-items-center justify-end gap-1 md:gap-2 w-full sm:w-auto">
|
<section class="flex place-items-center justify-end gap-1 md:gap-2 w-full sm:w-auto">
|
||||||
{#if $featureFlags.search}
|
{#if $featureFlags.search}
|
||||||
<IconButton
|
<IconButton
|
||||||
|
class="sm:hidden focus:ring-2 ring-offset-transparent focus:bg-dark/10"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
shape="round"
|
shape="round"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@ -104,7 +111,6 @@
|
|||||||
icon={mdiMagnify}
|
icon={mdiMagnify}
|
||||||
href={AppRoute.SEARCH}
|
href={AppRoute.SEARCH}
|
||||||
id="search-button"
|
id="search-button"
|
||||||
class="sm:hidden"
|
|
||||||
aria-label={$t('go_to_search')}
|
aria-label={$t('go_to_search')}
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
@ -113,7 +119,7 @@
|
|||||||
<Button
|
<Button
|
||||||
leadingIcon={mdiTrayArrowUp}
|
leadingIcon={mdiTrayArrowUp}
|
||||||
onclick={onUploadClick}
|
onclick={onUploadClick}
|
||||||
class="hidden lg:flex"
|
class="hidden lg:flex focus:ring-2 ring-offset-transparent focus:bg-dark/10"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="medium"
|
size="medium"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@ -128,7 +134,7 @@
|
|||||||
title={$t('upload')}
|
title={$t('upload')}
|
||||||
aria-label={$t('upload')}
|
aria-label={$t('upload')}
|
||||||
icon={mdiTrayArrowUp}
|
icon={mdiTrayArrowUp}
|
||||||
class="lg:hidden"
|
class="lg:hidden focus:ring-2 ring-offset-transparent focus:bg-dark/10"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@ -140,6 +146,7 @@
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
class="focus:inset-ring-2 ring-offset-transparent focus:bg-dark/10"
|
||||||
shape="round"
|
shape="round"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@ -157,6 +164,7 @@
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
class="focus:ring-2 ring-offset-transparent focus:bg-dark/10"
|
||||||
shape="round"
|
shape="round"
|
||||||
color={hasUnreadNotifications ? 'primary' : 'secondary'}
|
color={hasUnreadNotifications ? 'primary' : 'secondary'}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@ -179,11 +187,11 @@
|
|||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="flex ps-2"
|
class="flex ps-2 outline-none group"
|
||||||
onmouseover={() => (shouldShowAccountInfo = true)}
|
onmouseover={() => ((shouldShowAccountInfo = true), (isHocus = true))}
|
||||||
onfocus={() => (shouldShowAccountInfo = true)}
|
onfocus={() => ((shouldShowAccountInfo = true), (isHocus = true))}
|
||||||
onblur={() => (shouldShowAccountInfo = false)}
|
onblur={() => ((shouldShowAccountInfo = false), (isHocus = false))}
|
||||||
onmouseleave={() => (shouldShowAccountInfo = false)}
|
onmouseleave={() => ((shouldShowAccountInfo = false), (isHocus = false))}
|
||||||
onclick={() => (shouldShowAccountInfoPanel = !shouldShowAccountInfoPanel)}
|
onclick={() => (shouldShowAccountInfoPanel = !shouldShowAccountInfoPanel)}
|
||||||
>
|
>
|
||||||
{#key $user}
|
{#key $user}
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
let title = $derived(label ?? `${user.name} (${user.email})`);
|
let title = $derived(label ?? `${user.name} (${user.email})`);
|
||||||
let interactiveClass = $derived(
|
let interactiveClass = $derived(
|
||||||
interactive
|
interactive
|
||||||
? 'border-2 border-immich-primary hover:border-immich-dark-primary dark:hover:border-immich-primary dark:border-immich-dark-primary transition-colors'
|
? 'group-focus:ring-4 ring-2 ring-immich-primary dark:ring-immich-dark-primary hocus:immich-dark-primary transition-colors'
|
||||||
: '',
|
: '',
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
@ -410,7 +410,7 @@
|
|||||||
<PeopleInfiniteScroll people={showPeople} hasNextPage={!!nextPage && !searchName} {loadNextPage}>
|
<PeopleInfiniteScroll people={showPeople} hasNextPage={!!nextPage && !searchName} {loadNextPage}>
|
||||||
{#snippet children({ person })}
|
{#snippet children({ person })}
|
||||||
<div
|
<div
|
||||||
class="p-2 rounded-xl hover:bg-gray-200 border-2 hover:border-immich-primary/50 hover:shadow-sm dark:hover:bg-immich-dark-primary/20 hover:dark:border-immich-dark-primary/25 border-transparent transition-all"
|
class="p-2 rounded-xl hocus:bg-gray-200 border-2 hocus-within:border-immich-primary/50 hocus-within:shadow-sm dark:hocus-within:bg-immich-dark-primary/20 dark:border-immich-dark-primary/25 border-transparent transition-all"
|
||||||
>
|
>
|
||||||
<PeopleCard
|
<PeopleCard
|
||||||
{person}
|
{person}
|
||||||
@ -423,7 +423,7 @@
|
|||||||
<form onsubmit={() => onNameChangeSubmit(newName, person)}>
|
<form onsubmit={() => onNameChangeSubmit(newName, person)}>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class=" bg-white dark:bg-immich-dark-gray border-gray-100 placeholder-gray-400 text-center dark:border-gray-900 w-full rounded-2xl mt-2 py-2 text-sm text-immich-primary dark:text-immich-dark-primary"
|
class="bg-immich-gray dark:bg-immich-dark-gray border-gray-100 placeholder-gray-400 text-center dark:border-gray-900 w-full rounded-2xl mt-2 py-2 text-sm text-immich-primary dark:text-immich-dark-primary"
|
||||||
value={person.name}
|
value={person.name}
|
||||||
placeholder={$t('add_a_name')}
|
placeholder={$t('add_a_name')}
|
||||||
onfocusin={() => onNameChangeInputFocus(person)}
|
onfocusin={() => onNameChangeInputFocus(person)}
|
||||||
|
@ -73,5 +73,10 @@ export default {
|
|||||||
{ values: theme('width') },
|
{ values: theme('width') },
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
plugin(({ addVariant }) => {
|
||||||
|
addVariant('hocus', ['&:hover', '&:focus']);
|
||||||
|
addVariant('hocus-within', ['&:hover', '&:focus-within']);
|
||||||
|
addVariant('hocus-visible', ['&:hover', '&:focus-visible']);
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user