This commit is contained in:
Min Idzelis 2025-04-30 03:50:13 +00:00
parent 2e8a286540
commit 9806e94f6f
8 changed files with 69 additions and 58 deletions

View File

@ -34,6 +34,9 @@
--immich-ui-info: 14 165 233;
--immich-ui-default-border: 209 213 219;
}
* {
--tw-ring-offset-width: 0px;
}
.dark {
/* dark */

View File

@ -5,8 +5,8 @@
import { cancelImageUrl } from '$lib/utils/sw-messaging';
import { TUNABLES } from '$lib/utils/tunables';
import { mdiEyeOffOutline } from '@mdi/js';
import type { ClassValue } from 'svelte/elements';
import type { ActionReturn } from 'svelte/action';
import type { ClassValue } from 'svelte/elements';
import { fade } from 'svelte/transition';
interface Props {
@ -77,7 +77,7 @@
circle && 'rounded-full',
shadow && 'shadow-lg',
(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,
]
.filter(Boolean)

View File

@ -61,17 +61,17 @@
}: Props = $props();
const colorClasses: Record<Color, string> = {
transparent: 'bg-transparent hover:bg-[#d3d3d3] dark:text-immich-dark-fg',
opaque: 'bg-transparent hover:bg-immich-bg/30 text-white hover:dark:text-white',
light: 'bg-white hover:bg-[#d3d3d3]',
red: 'text-red-400 bg-red-100 hover:bg-[#d3d3d3]',
dark: 'bg-[#202123] hover:bg-[#d3d3d3]',
alert: 'text-[#ff0000] hover:text-white',
gray: 'bg-[#d3d3d3] hover:bg-[#e2e7e9] text-immich-dark-gray hover:text-black',
transparent: 'bg-transparent hocus:bg-[#d3d3d3] dark:text-immich-dark-fg',
opaque: 'bg-transparent hocus:bg-immich-bg/30 text-white hocus:dark:text-white',
light: 'bg-white hocus:bg-[#d3d3d3]',
red: 'text-red-400 bg-red-100 hocus:bg-[#d3d3d3]',
dark: 'bg-[#202123] hocus:bg-[#d3d3d3]',
alert: 'text-[#ff0000] hocus:text-white',
gray: 'bg-[#d3d3d3] hocus:bg-[#e2e7e9] text-immich-dark-gray hocus:text-black',
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:
'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> = {
@ -92,9 +92,16 @@
{href}
style:width={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}
{...rest}
>
<Icon path={icon} {size} ariaLabel={title} {viewBox} color="currentColor" />
</svelte:element>
<style>
button,
a {
--tw-ring-offset-width: 0px;
}
</style>

View File

@ -1,5 +1,4 @@
<script lang="ts">
import { focusOutside } from '$lib/actions/focus-outside';
import Icon from '$lib/components/elements/icon.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import { AppRoute, QueryParameter } from '$lib/constants';
@ -27,22 +26,13 @@
}
let { person, onSetBirthDate, onMergePeople, onHidePerson, onToggleFavorite }: Props = $props();
let showVerticalDots = $state(false);
</script>
<div
id="people-card"
class="relative"
onmouseenter={() => (showVerticalDots = true)}
onmouseleave={() => (showVerticalDots = false)}
role="group"
use:focusOutside={{ onFocusOut: () => (showVerticalDots = false) }}
>
<div id="people-card" class="relative group" role="group">
<a
class="focus:outline-none"
href="{AppRoute.PEOPLE}/{person.id}?{QueryParameter.PREVIOUS_ROUTE}={AppRoute.PEOPLE}"
draggable="false"
onfocus={() => (showVerticalDots = true)}
>
<div class="w-full h-full rounded-xl brightness-95 filter">
<ImageThumbnail
@ -61,25 +51,23 @@
</div>
</a>
{#if showVerticalDots}
<div class="absolute top-2 end-2">
<ButtonContextMenu
buttonClass="icon-white-drop-shadow focus:opacity-100 {showVerticalDots ? 'opacity-100' : 'opacity-0'}"
color="opaque"
padding="2"
size="20"
icon={mdiDotsVertical}
title={$t('show_person_options')}
>
<MenuOption onClick={onHidePerson} icon={mdiEyeOffOutline} text={$t('hide_person')} />
<MenuOption onClick={onSetBirthDate} icon={mdiCalendarEditOutline} text={$t('set_date_of_birth')} />
<MenuOption onClick={onMergePeople} icon={mdiAccountMultipleCheckOutline} text={$t('merge_people')} />
<MenuOption
onClick={onToggleFavorite}
icon={person.isFavorite ? mdiHeartMinusOutline : mdiHeartOutline}
text={person.isFavorite ? $t('unfavorite') : $t('to_favorite')}
/>
</ButtonContextMenu>
</div>
{/if}
<div class="absolute top-2 end-2">
<ButtonContextMenu
buttonClass="icon-white-drop-shadow focus:opacity-100 group-hover:opacity-100 opacity-0"
color="opaque"
padding="2"
size="20"
icon={mdiDotsVertical}
title={$t('show_person_options')}
>
<MenuOption onClick={onHidePerson} icon={mdiEyeOffOutline} text={$t('hide_person')} />
<MenuOption onClick={onSetBirthDate} icon={mdiCalendarEditOutline} text={$t('set_date_of_birth')} />
<MenuOption onClick={onMergePeople} icon={mdiAccountMultipleCheckOutline} text={$t('merge_people')} />
<MenuOption
onClick={onToggleFavorite}
icon={person.isFavorite ? mdiHeartMinusOutline : mdiHeartOutline}
text={person.isFavorite ? $t('unfavorite') : $t('to_favorite')}
/>
</ButtonContextMenu>
</div>
</div>

View File

@ -13,6 +13,7 @@
import { AppRoute } from '$lib/constants';
import { authManager } from '$lib/managers/auth-manager.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 { sidebarStore } from '$lib/stores/sidebar.svelte';
import { user } from '$lib/stores/user.store';
@ -26,7 +27,6 @@
import ThemeButton from '../theme-button.svelte';
import UserAvatar from '../user-avatar.svelte';
import AccountInfoPanel from './account-info-panel.svelte';
import { notificationManager } from '$lib/stores/notification-manager.svelte';
interface Props {
showUploadButton?: boolean;
@ -35,6 +35,8 @@
let { showUploadButton = true, onUploadClick }: Props = $props();
let isHocus = $state(false);
let shouldShowAccountInfo = $state(false);
let shouldShowAccountInfoPanel = $state(false);
let shouldShowHelpPanel = $state(false);
@ -83,7 +85,11 @@
}}
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} />
</a>
</div>
@ -97,6 +103,7 @@
<section class="flex place-items-center justify-end gap-1 md:gap-2 w-full sm:w-auto">
{#if $featureFlags.search}
<IconButton
class="sm:hidden focus:ring-2 ring-offset-transparent focus:bg-dark/10"
color="secondary"
shape="round"
variant="ghost"
@ -104,7 +111,6 @@
icon={mdiMagnify}
href={AppRoute.SEARCH}
id="search-button"
class="sm:hidden"
aria-label={$t('go_to_search')}
/>
{/if}
@ -113,7 +119,7 @@
<Button
leadingIcon={mdiTrayArrowUp}
onclick={onUploadClick}
class="hidden lg:flex"
class="hidden lg:flex focus:ring-2 ring-offset-transparent focus:bg-dark/10"
variant="ghost"
size="medium"
color="secondary"
@ -128,7 +134,7 @@
title={$t('upload')}
aria-label={$t('upload')}
icon={mdiTrayArrowUp}
class="lg:hidden"
class="lg:hidden focus:ring-2 ring-offset-transparent focus:bg-dark/10"
/>
{/if}
@ -140,6 +146,7 @@
}}
>
<IconButton
class="focus:inset-ring-2 ring-offset-transparent focus:bg-dark/10"
shape="round"
color="secondary"
variant="ghost"
@ -157,6 +164,7 @@
}}
>
<IconButton
class="focus:ring-2 ring-offset-transparent focus:bg-dark/10"
shape="round"
color={hasUnreadNotifications ? 'primary' : 'secondary'}
variant="ghost"
@ -179,11 +187,11 @@
>
<button
type="button"
class="flex ps-2"
onmouseover={() => (shouldShowAccountInfo = true)}
onfocus={() => (shouldShowAccountInfo = true)}
onblur={() => (shouldShowAccountInfo = false)}
onmouseleave={() => (shouldShowAccountInfo = false)}
class="flex ps-2 outline-none group"
onmouseover={() => ((shouldShowAccountInfo = true), (isHocus = true))}
onfocus={() => ((shouldShowAccountInfo = true), (isHocus = true))}
onblur={() => ((shouldShowAccountInfo = false), (isHocus = false))}
onmouseleave={() => ((shouldShowAccountInfo = false), (isHocus = false))}
onclick={() => (shouldShowAccountInfoPanel = !shouldShowAccountInfoPanel)}
>
{#key $user}

View File

@ -84,7 +84,7 @@
let title = $derived(label ?? `${user.name} (${user.email})`);
let interactiveClass = $derived(
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>

View File

@ -410,7 +410,7 @@
<PeopleInfiniteScroll people={showPeople} hasNextPage={!!nextPage && !searchName} {loadNextPage}>
{#snippet children({ person })}
<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
{person}
@ -423,7 +423,7 @@
<form onsubmit={() => onNameChangeSubmit(newName, person)}>
<input
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}
placeholder={$t('add_a_name')}
onfocusin={() => onNameChangeInputFocus(person)}

View File

@ -73,5 +73,10 @@ export default {
{ values: theme('width') },
);
}),
plugin(({ addVariant }) => {
addVariant('hocus', ['&:hover', '&:focus']);
addVariant('hocus-within', ['&:hover', '&:focus-within']);
addVariant('hocus-visible', ['&:hover', '&:focus-visible']);
}),
],
};