mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:49:11 -04:00 
			
		
		
		
	feat(web): Duplicate-Page shortcut changes (#11183)
* duplicate page assign other shortcut keys, add 'open image' shortcut * add shortcut info page to duplicates with own list of keys * edit translations, add translationkeys * format fix * remove typo --------- Co-authored-by: Zack Pollard <zackpollard@ymail.com> Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
		
							parent
							
								
									a78eeb9b9c
								
							
						
					
					
						commit
						e1ac73718c
					
				| @ -16,7 +16,7 @@ | ||||
|     info?: string; | ||||
|   } | ||||
| 
 | ||||
|   const shortcuts: Shortcuts = { | ||||
|   export let shortcuts: Shortcuts = { | ||||
|     general: [ | ||||
|       { key: ['←', '→'], action: $t('previous_or_next_photo') }, | ||||
|       { key: ['Esc'], action: $t('back_close_deselect') }, | ||||
| @ -40,45 +40,48 @@ | ||||
| 
 | ||||
| <FullScreenModal title={$t('keyboard_shortcuts')} width="auto" onClose={() => dispatch('close')}> | ||||
|   <div class="grid grid-cols-1 gap-4 px-4 pb-4 md:grid-cols-2"> | ||||
|     <div class="p-4"> | ||||
|       <h2>{$t('general')}</h2> | ||||
|       <div class="text-sm"> | ||||
|         {#each shortcuts.general as shortcut} | ||||
|           <div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm"> | ||||
|             <div class="flex justify-self-end"> | ||||
|               {#each shortcut.key as key} | ||||
|                 <p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"> | ||||
|                   {key} | ||||
|                 </p> | ||||
|               {/each} | ||||
|             </div> | ||||
|             <p class="mb-1 mt-1 flex">{shortcut.action}</p> | ||||
|           </div> | ||||
|         {/each} | ||||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="p-4"> | ||||
|       <h2>{$t('actions')}</h2> | ||||
|       <div class="text-sm"> | ||||
|         {#each shortcuts.actions as shortcut} | ||||
|           <div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm"> | ||||
|             <div class="flex justify-self-end"> | ||||
|               {#each shortcut.key as key} | ||||
|                 <p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"> | ||||
|                   {key} | ||||
|                 </p> | ||||
|               {/each} | ||||
|             </div> | ||||
|             <div class="flex items-center gap-2"> | ||||
|     {#if shortcuts.general.length > 0} | ||||
|       <div class="p-4"> | ||||
|         <h2>{$t('general')}</h2> | ||||
|         <div class="text-sm"> | ||||
|           {#each shortcuts.general as shortcut} | ||||
|             <div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm"> | ||||
|               <div class="flex justify-self-end"> | ||||
|                 {#each shortcut.key as key} | ||||
|                   <p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"> | ||||
|                     {key} | ||||
|                   </p> | ||||
|                 {/each} | ||||
|               </div> | ||||
|               <p class="mb-1 mt-1 flex">{shortcut.action}</p> | ||||
|               {#if shortcut.info} | ||||
|                 <Icon path={mdiInformationOutline} title={shortcut.info} /> | ||||
|               {/if} | ||||
|             </div> | ||||
|           </div> | ||||
|         {/each} | ||||
|           {/each} | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|     {/if} | ||||
|     {#if shortcuts.actions.length > 0} | ||||
|       <div class="p-4"> | ||||
|         <h2>{$t('actions')}</h2> | ||||
|         <div class="text-sm"> | ||||
|           {#each shortcuts.actions as shortcut} | ||||
|             <div class="grid grid-cols-[30%_70%] items-center gap-4 pt-4 text-sm"> | ||||
|               <div class="flex justify-self-end"> | ||||
|                 {#each shortcut.key as key} | ||||
|                   <p class="mr-1 flex items-center justify-center justify-self-end rounded-lg bg-immich-primary/25 p-2"> | ||||
|                     {key} | ||||
|                   </p> | ||||
|                 {/each} | ||||
|               </div> | ||||
|               <div class="flex items-center gap-2"> | ||||
|                 <p class="mb-1 mt-1 flex">{shortcut.action}</p> | ||||
|                 {#if shortcut.info} | ||||
|                   <Icon path={mdiInformationOutline} title={shortcut.info} /> | ||||
|                 {/if} | ||||
|               </div> | ||||
|             </div> | ||||
|           {/each} | ||||
|         </div> | ||||
|       </div> | ||||
|     {/if} | ||||
|   </div> | ||||
| </FullScreenModal> | ||||
|  | ||||
| @ -64,8 +64,14 @@ | ||||
| 
 | ||||
| <svelte:window | ||||
|   use:shortcuts={[ | ||||
|     { shortcut: { key: 'k', shift: true }, onShortcut: onSelectAll }, | ||||
|     { shortcut: { key: 't', shift: true }, onShortcut: onSelectNone }, | ||||
|     { shortcut: { key: 'a' }, onShortcut: onSelectAll }, | ||||
|     { | ||||
|       shortcut: { key: 's' }, | ||||
|       onShortcut: () => { | ||||
|         setAsset(assets[0]); | ||||
|       }, | ||||
|     }, | ||||
|     { shortcut: { key: 'd' }, onShortcut: onSelectNone }, | ||||
|     { shortcut: { key: 'c', shift: true }, onShortcut: handleResolve }, | ||||
|   ]} | ||||
| /> | ||||
|  | ||||
| @ -997,6 +997,7 @@ | ||||
|   "reset_password": "Reset password", | ||||
|   "reset_people_visibility": "Reset people visibility", | ||||
|   "reset_to_default": "Reset to default", | ||||
|   "resolve_duplicates": "Resolve duplicates", | ||||
|   "resolved_all_duplicates": "Resolved all duplicates", | ||||
|   "restore": "Restore", | ||||
|   "restore_all": "Restore all", | ||||
| @ -1041,6 +1042,7 @@ | ||||
|   "see_all_people": "See all people", | ||||
|   "select_album_cover": "Select album cover", | ||||
|   "select_all": "Select all", | ||||
|   "select_all_duplicates": "Select all duplicates", | ||||
|   "select_avatar_color": "Select avatar color", | ||||
|   "select_face": "Select face", | ||||
|   "select_featured_photo": "Select featured photo", | ||||
| @ -1166,6 +1168,7 @@ | ||||
|   "unnamed_share": "Unnamed Share", | ||||
|   "unsaved_change": "Unsaved change", | ||||
|   "unselect_all": "Unselect all", | ||||
|   "unselect_all_duplicates": "Unselect all duplicates", | ||||
|   "unstack": "Un-stack", | ||||
|   "unstacked_assets_count": "Un-stacked {count, plural, one {# asset} other {# assets}}", | ||||
|   "untracked_files": "Untracked files", | ||||
|  | ||||
| @ -13,10 +13,34 @@ | ||||
|   import type { PageData } from './$types'; | ||||
|   import { suggestDuplicateByFileSize } from '$lib/utils'; | ||||
|   import LinkButton from '$lib/components/elements/buttons/link-button.svelte'; | ||||
|   import ShowShortcuts from '$lib/components/shared-components/show-shortcuts.svelte'; | ||||
|   import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; | ||||
|   import { mdiKeyboard } from '@mdi/js'; | ||||
|   import { mdiCheckOutline, mdiTrashCanOutline } from '@mdi/js'; | ||||
|   import Icon from '$lib/components/elements/icon.svelte'; | ||||
| 
 | ||||
|   export let data: PageData; | ||||
|   export let isShowKeyboardShortcut = false; | ||||
| 
 | ||||
|   interface Shortcuts { | ||||
|     general: ExplainedShortcut[]; | ||||
|     actions: ExplainedShortcut[]; | ||||
|   } | ||||
|   interface ExplainedShortcut { | ||||
|     key: string[]; | ||||
|     action: string; | ||||
|     info?: string; | ||||
|   } | ||||
| 
 | ||||
|   const duplicateShortcuts: Shortcuts = { | ||||
|     general: [], | ||||
|     actions: [ | ||||
|       { key: ['a'], action: $t('select_all_duplicates') }, | ||||
|       { key: ['s'], action: $t('view') }, | ||||
|       { key: ['d'], action: $t('unselect_all_duplicates') }, | ||||
|       { key: ['⇧', 'c'], action: $t('resolve_duplicates') }, | ||||
|     ], | ||||
|   }; | ||||
| 
 | ||||
|   $: hasDuplicates = data.duplicates.length > 0; | ||||
| 
 | ||||
| @ -132,6 +156,11 @@ | ||||
|         {$t('keep_all')} | ||||
|       </div> | ||||
|     </LinkButton> | ||||
|     <CircleIconButton | ||||
|       icon={mdiKeyboard} | ||||
|       title={$t('show_keyboard_shortcuts')} | ||||
|       on:click={() => (isShowKeyboardShortcut = !isShowKeyboardShortcut)} | ||||
|     /> | ||||
|   </div> | ||||
| 
 | ||||
|   <div class="mt-4"> | ||||
| @ -153,3 +182,7 @@ | ||||
|     {/if} | ||||
|   </div> | ||||
| </UserPageLayout> | ||||
| 
 | ||||
| {#if isShowKeyboardShortcut} | ||||
|   <ShowShortcuts shortcuts={duplicateShortcuts} on:close={() => (isShowKeyboardShortcut = false)} /> | ||||
| {/if} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user