mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	fix(web): multiple improvements for people page (1) (#4717)
* fix(web): multiple improvements for people page * feat: better responsive icons
This commit is contained in:
		| @@ -103,11 +103,7 @@ export class PersonRepository implements IPersonRepository { | ||||
|     return this.personRepository.findOne({ where: { id: personId } }); | ||||
|   } | ||||
|  | ||||
|   async getByName( | ||||
|     userId: string, | ||||
|     personName: string, | ||||
|     { withHidden }: PersonNameSearchOptions, | ||||
|   ): Promise<PersonEntity[]> { | ||||
|   getByName(userId: string, personName: string, { withHidden }: PersonNameSearchOptions): Promise<PersonEntity[]> { | ||||
|     const queryBuilder = this.personRepository | ||||
|       .createQueryBuilder('person') | ||||
|       .leftJoin('person.faces', 'face') | ||||
|   | ||||
| @@ -10,10 +10,11 @@ | ||||
|   import { NotificationType, notificationController } from '../shared-components/notification/notification'; | ||||
|   import ConfirmDialogue from '../shared-components/confirm-dialogue.svelte'; | ||||
|   import { handleError } from '$lib/utils/handle-error'; | ||||
|   import { goto, invalidateAll } from '$app/navigation'; | ||||
|   import { goto } from '$app/navigation'; | ||||
|   import { AppRoute } from '$lib/constants'; | ||||
|   import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js'; | ||||
|   import Icon from '$lib/components/elements/icon.svelte'; | ||||
|   import CircleIconButton from '../elements/buttons/circle-icon-button.svelte'; | ||||
|  | ||||
|   export let person: PersonResponseDto; | ||||
|   let people: PersonResponseDto[] = []; | ||||
| @@ -69,8 +70,6 @@ | ||||
|         message: `Merged ${count} ${count === 1 ? 'person' : 'people'}`, | ||||
|         type: NotificationType.Info, | ||||
|       }); | ||||
|       people = people.filter((person) => !results.some((result) => result.id === person.id && result.success === true)); | ||||
|       await invalidateAll(); | ||||
|       dispatch('merge'); | ||||
|     } catch (error) { | ||||
|       handleError(error, 'Cannot merge faces'); | ||||
| @@ -121,14 +120,18 @@ | ||||
|           {/each} | ||||
|  | ||||
|           {#if hasSelection} | ||||
|             <span class="grid grid-cols-1" | ||||
|               ><Icon path={mdiCallMerge} size={48} class="rotate-90 dark:text-white" /> | ||||
|             <div class="relative h-full"> | ||||
|               <div class="flex flex-col h-full justify-between"> | ||||
|                 <div class="flex h-full items-center justify-center"> | ||||
|                   <Icon path={mdiCallMerge} size={48} class="rotate-90 dark:text-white" /> | ||||
|                 </div> | ||||
|                 {#if selectedPeople.length === 1} | ||||
|                 <button class="flex justify-center" on:click={handleSwapPeople} | ||||
|                   ><Icon path={mdiSwapHorizontal} size={24} class="dark:text-white" /> | ||||
|                 </button> | ||||
|                   <div class="absolute bottom-2"> | ||||
|                     <CircleIconButton icon={mdiSwapHorizontal} size="24" on:click={handleSwapPeople} /> | ||||
|                   </div> | ||||
|                 {/if} | ||||
|             </span> | ||||
|               </div> | ||||
|             </div> | ||||
|           {/if} | ||||
|           <FaceThumbnail {person} border circle selectable={false} thumbnailSize={180} /> | ||||
|         </div> | ||||
|   | ||||
| @@ -22,7 +22,9 @@ | ||||
|     OBJECTS = 'smartInfo.objects', | ||||
|   } | ||||
|  | ||||
|   const MAX_ITEMS = 12; | ||||
|   let MAX_ITEMS: number; | ||||
|   let innerWidth: number; | ||||
|   let screenSize: number; | ||||
|   const getFieldItems = (items: SearchExploreResponseDto[], field: Field) => { | ||||
|     const targetField = items.find((item) => item.fieldName === field); | ||||
|     return targetField?.items || []; | ||||
| @@ -32,8 +34,16 @@ | ||||
|   $: places = getFieldItems(data.items, Field.CITY); | ||||
|   $: people = data.response.people.slice(0, MAX_ITEMS); | ||||
|   $: hasPeople = data.response.total > 0; | ||||
|   $: { | ||||
|     if (innerWidth && screenSize) { | ||||
|       // Set the number of faces according to the screen size and the div size | ||||
|       MAX_ITEMS = screenSize < 768 ? Math.floor(innerWidth / 96) : Math.floor(innerWidth / 112); | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <svelte:window bind:innerWidth={screenSize} /> | ||||
|  | ||||
| <UserPageLayout user={data.user} title={data.meta.title}> | ||||
|   {#if hasPeople} | ||||
|     <div class="mb-6 mt-2"> | ||||
| @@ -45,9 +55,10 @@ | ||||
|           draggable="false">View All</a | ||||
|         > | ||||
|       </div> | ||||
|       <div class="flex flex-row flex-wrap gap-4"> | ||||
|       <div class="flex flex-row {MAX_ITEMS < 5 ? 'justify-center' : ''} flex-wrap gap-4" bind:offsetWidth={innerWidth}> | ||||
|         {#if MAX_ITEMS} | ||||
|           {#each people as person (person.id)} | ||||
|           <a href="/people/{person.id}" class="w-24 text-center"> | ||||
|             <a href="/people/{person.id}" class="w-20 md:w-24 text-center"> | ||||
|               <ImageThumbnail | ||||
|                 circle | ||||
|                 shadow | ||||
| @@ -58,6 +69,7 @@ | ||||
|               <p class="mt-2 text-ellipsis text-sm font-medium dark:text-white">{person.name}</p> | ||||
|             </a> | ||||
|           {/each} | ||||
|         {/if} | ||||
|       </div> | ||||
|     </div> | ||||
|   {/if} | ||||
|   | ||||
| @@ -87,7 +87,7 @@ | ||||
|     if ((people.length < 20 && name.startsWith(searchWord)) || name === '') { | ||||
|       return; | ||||
|     } | ||||
|     const timeout = setTimeout(() => (isSearchingPeople = true), 300); | ||||
|     const timeout = setTimeout(() => (isSearchingPeople = true), 100); | ||||
|     try { | ||||
|       const { data } = await api.searchApi.searchPerson({ name }); | ||||
|       people = data; | ||||
| @@ -156,6 +156,7 @@ | ||||
|         personId: data.person.id, | ||||
|       }); | ||||
|       previousPersonId = data.person.id; | ||||
|       name = data.person.name; | ||||
|       refreshAssetGrid = !refreshAssetGrid; | ||||
|     } | ||||
|   }); | ||||
| @@ -265,7 +266,7 @@ | ||||
|     if (viewMode === ViewMode.SUGGEST_MERGE) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     isSearchingPeople = false; | ||||
|     isEditingName = false; | ||||
|   }; | ||||
|  | ||||
| @@ -463,7 +464,7 @@ | ||||
|             <div class="absolute z-[999] w-64 sm:w-96"> | ||||
|               {#if isSearchingPeople} | ||||
|                 <div | ||||
|                   class="flex rounded-b-lg dark:border-immich-dark-gray place-items-center bg-gray-100 p-2 dark:bg-gray-700" | ||||
|                   class="flex border h-14 rounded-b-lg border-gray-400 dark:border-immich-dark-gray place-items-center bg-gray-200 p-2 dark:bg-gray-700" | ||||
|                 > | ||||
|                   <div class="flex w-full place-items-center"> | ||||
|                     <LoadingSpinner /> | ||||
| @@ -472,8 +473,10 @@ | ||||
|               {:else} | ||||
|                 {#each suggestedPeople as person, index (person.id)} | ||||
|                   <div | ||||
|                     class="flex border-t dark:border-immich-dark-gray place-items-center bg-gray-100 p-2 dark:bg-gray-700 {index === | ||||
|                       suggestedPeople.length - 1 && 'rounded-b-lg'}" | ||||
|                     class="flex border-t border-x border-gray-400 dark:border-immich-dark-gray h-14 place-items-center bg-gray-200 p-2 dark:bg-gray-700 hover:bg-gray-300 hover:dark:bg-[#232932] {index === | ||||
|                     suggestedPeople.length - 1 | ||||
|                       ? 'rounded-b-lg border-b' | ||||
|                       : ''}" | ||||
|                   > | ||||
|                     <button class="flex w-full place-items-center" on:click={() => handleSuggestPeople(person)}> | ||||
|                       <ImageThumbnail | ||||
|   | ||||
		Reference in New Issue
	
	Block a user