forked from Cutlery/immich
		
	feat(web): UI/UX improvement for date time edit form (#5505)
This commit is contained in:
		
							parent
							
								
									7e8488694d
								
							
						
					
					
						commit
						84c5b08c25
					
				@ -15,8 +15,12 @@
 | 
				
			|||||||
  import { fly } from 'svelte/transition';
 | 
					  import { fly } from 'svelte/transition';
 | 
				
			||||||
  import { createEventDispatcher } from 'svelte';
 | 
					  import { createEventDispatcher } from 'svelte';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let className = '';
 | 
				
			||||||
 | 
					  export { className as class };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const dispatch = createEventDispatcher<{
 | 
					  const dispatch = createEventDispatcher<{
 | 
				
			||||||
    select: T;
 | 
					    select: T;
 | 
				
			||||||
 | 
					    'click-outside': void;
 | 
				
			||||||
  }>();
 | 
					  }>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  export let options: T[];
 | 
					  export let options: T[];
 | 
				
			||||||
@ -36,6 +40,8 @@
 | 
				
			|||||||
    if (!controlable) {
 | 
					    if (!controlable) {
 | 
				
			||||||
      showMenu = false;
 | 
					      showMenu = false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dispatch('click-outside');
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleSelectOption = (option: T) => {
 | 
					  const handleSelectOption = (option: T) => {
 | 
				
			||||||
@ -76,7 +82,7 @@
 | 
				
			|||||||
  {#if showMenu}
 | 
					  {#if showMenu}
 | 
				
			||||||
    <div
 | 
					    <div
 | 
				
			||||||
      transition:fly={{ y: -30, x: 30, duration: 100 }}
 | 
					      transition:fly={{ y: -30, x: 30, duration: 100 }}
 | 
				
			||||||
      class="text-md fixed z-50 flex min-w-[250px] max-h-[70vh] overflow-y-scroll immich-scrollbar flex-col rounded-2xl bg-gray-100 py-2 text-black shadow-lg dark:bg-gray-700 dark:text-white"
 | 
					      class="text-md fixed z-50 flex min-w-[250px] max-h-[70vh] overflow-y-scroll immich-scrollbar flex-col rounded-2xl bg-gray-100 py-2 text-black shadow-lg dark:bg-gray-700 dark:text-white {className}"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {#each options as option (option)}
 | 
					      {#each options as option (option)}
 | 
				
			||||||
        {@const renderedOption = renderOption(option)}
 | 
					        {@const renderedOption = renderOption(option)}
 | 
				
			||||||
 | 
				
			|||||||
@ -59,12 +59,27 @@
 | 
				
			|||||||
      dispatch('confirm', value);
 | 
					      dispatch('confirm', value);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const handleKeydown = (event: KeyboardEvent) => {
 | 
					  const handleKeydown = (event: KeyboardEvent) => {
 | 
				
			||||||
    if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
 | 
					    if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
 | 
				
			||||||
      event.stopPropagation();
 | 
					      event.stopPropagation();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let isDropdownOpen = false;
 | 
					  let isDropdownOpen = false;
 | 
				
			||||||
 | 
					  let isSearching = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSearchFocused = () => {
 | 
				
			||||||
 | 
					    isSearching = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    openDropdown();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSearchBlurred = () => {
 | 
				
			||||||
 | 
					    isSearching = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    closeDropdown();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const openDropdown = () => {
 | 
					  const openDropdown = () => {
 | 
				
			||||||
    isDropdownOpen = true;
 | 
					    isDropdownOpen = true;
 | 
				
			||||||
@ -84,42 +99,46 @@
 | 
				
			|||||||
  <ConfirmDialogue
 | 
					  <ConfirmDialogue
 | 
				
			||||||
    confirmColor="primary"
 | 
					    confirmColor="primary"
 | 
				
			||||||
    cancelColor="secondary"
 | 
					    cancelColor="secondary"
 | 
				
			||||||
    title="Change Date"
 | 
					    title="Edit date & time"
 | 
				
			||||||
    prompt="Please select a new date:"
 | 
					    prompt="Please select a new date:"
 | 
				
			||||||
    {disabled}
 | 
					    {disabled}
 | 
				
			||||||
    on:confirm={handleConfirm}
 | 
					    on:confirm={handleConfirm}
 | 
				
			||||||
    on:cancel={handleCancel}
 | 
					    on:cancel={handleCancel}
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <div class="flex flex-col text-md px-4 py-5 text-center gap-2" slot="prompt">
 | 
					    <div class="flex flex-col text-md px-4 text-center gap-2" slot="prompt">
 | 
				
			||||||
      <div class="mt-2" />
 | 
					      <div class="mt-2" />
 | 
				
			||||||
      <div class="flex flex-col">
 | 
					      <div class="flex flex-col">
 | 
				
			||||||
        <label for="datetime">Date and Time</label>
 | 
					        <label for="datetime">Date and Time</label>
 | 
				
			||||||
        <input
 | 
					        <input
 | 
				
			||||||
          class="immich-form-label text-sm mt-2 w-full text-black"
 | 
					          class="text-sm my-4 w-full bg-gray-200 p-4 rounded-lg dark:text-white dark:bg-gray-600"
 | 
				
			||||||
          id="datetime"
 | 
					          id="datetime"
 | 
				
			||||||
          type="datetime-local"
 | 
					          type="datetime-local"
 | 
				
			||||||
          bind:value={selectedDate}
 | 
					          bind:value={selectedDate}
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="flex flex-col w-full">
 | 
					      <div class="flex flex-col w-full mt-2">
 | 
				
			||||||
        <label for="timezone">Timezone</label>
 | 
					        <label for="timezone">Timezone</label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div class="relative">
 | 
					        <div class="relative">
 | 
				
			||||||
          <input
 | 
					          <input
 | 
				
			||||||
            class="immich-form-label text-sm mt-2 w-full text-black"
 | 
					            class="text-sm my-4 w-full bg-gray-200 p-3 rounded-lg dark:text-white dark:bg-gray-600"
 | 
				
			||||||
            id="timezoneSearch"
 | 
					            id="timezoneSearch"
 | 
				
			||||||
            type="text"
 | 
					            type="text"
 | 
				
			||||||
            placeholder="Search timezone..."
 | 
					            placeholder="Search timezone..."
 | 
				
			||||||
            bind:value={searchQuery}
 | 
					            bind:value={searchQuery}
 | 
				
			||||||
            on:input={updateSearchQuery}
 | 
					            on:input={updateSearchQuery}
 | 
				
			||||||
            on:focus={openDropdown}
 | 
					            on:focus={onSearchFocused}
 | 
				
			||||||
 | 
					            on:blur={onSearchBlurred}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          <Dropdown
 | 
					          <Dropdown
 | 
				
			||||||
 | 
					            class="h-[400px]"
 | 
				
			||||||
            selectedOption={initialOption}
 | 
					            selectedOption={initialOption}
 | 
				
			||||||
            options={filteredTimezones}
 | 
					            options={filteredTimezones}
 | 
				
			||||||
            render={(item) => (item ? `${item.zone} (${item.offset})` : '(not selected)')}
 | 
					            render={(item) => (item ? `${item.zone} (${item.offset})` : '(not selected)')}
 | 
				
			||||||
            on:select={({ detail: item }) => handleSelectTz(item)}
 | 
					            on:select={({ detail: item }) => handleSelectTz(item)}
 | 
				
			||||||
            controlable={true}
 | 
					            controlable={true}
 | 
				
			||||||
            bind:showMenu={isDropdownOpen}
 | 
					            bind:showMenu={isDropdownOpen}
 | 
				
			||||||
 | 
					            on:click-outside={isSearching ? null : closeDropdown}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@
 | 
				
			|||||||
  export let hideCancelButton = false;
 | 
					  export let hideCancelButton = false;
 | 
				
			||||||
  export let disabled = false;
 | 
					  export let disabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const dispatch = createEventDispatcher<{ cancel: void; confirm: void }>();
 | 
					  const dispatch = createEventDispatcher<{ cancel: void; confirm: void; 'click-outside': void }>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let isConfirmButtonDisabled = false;
 | 
					  let isConfirmButtonDisabled = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -28,9 +28,13 @@
 | 
				
			|||||||
    isConfirmButtonDisabled = true;
 | 
					    isConfirmButtonDisabled = true;
 | 
				
			||||||
    dispatch('confirm');
 | 
					    dispatch('confirm');
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleClickOutside = () => {
 | 
				
			||||||
 | 
					    dispatch('click-outside');
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<FullScreenModal on:clickOutside={handleCancel} on:escape={() => handleEscape()}>
 | 
					<FullScreenModal on:clickOutside={handleClickOutside} on:escape={() => handleEscape()}>
 | 
				
			||||||
  <div
 | 
					  <div
 | 
				
			||||||
    class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
 | 
					    class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user