forked from Cutlery/immich
		
	feat(web): previous button for on-boarding steps (#6178)
* feat: previous on the onboarding * fix: storage full screen * feat: transition * use svelte files for svg * fix: use icon component * fix: additional check * styling' --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
		
							parent
							
								
									8c784defa0
								
							
						
					
					
						commit
						2cc5149d0b
					
				
							
								
								
									
										6
									
								
								web/src/lib/assets/svg-paths.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								web/src/lib/assets/svg-paths.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| export const moonPath = 'M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z'; | ||||
| export const sunPath = | ||||
|   'M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z'; | ||||
| 
 | ||||
| export const moonViewBox = '0 0 20 20'; | ||||
| export const sunViewBox = '0 0 20 20'; | ||||
| @ -19,7 +19,7 @@ | ||||
|   import Button from '$lib/components/elements/buttons/button.svelte'; | ||||
|   import { createEventDispatcher } from 'svelte'; | ||||
|   import Icon from '$lib/components/elements/icon.svelte'; | ||||
|   import { mdiCheck } from '@mdi/js'; | ||||
|   import { mdiArrowLeft, mdiCheck } from '@mdi/js'; | ||||
| 
 | ||||
|   export let storageConfig: SystemConfigStorageTemplateDto; | ||||
|   export let disabled = false; | ||||
| @ -30,7 +30,10 @@ | ||||
|   let templateOptions: SystemConfigTemplateStorageOptionDto; | ||||
|   let selectedPreset = ''; | ||||
| 
 | ||||
|   const dispatch = createEventDispatcher<{ save: void }>(); | ||||
|   const dispatch = createEventDispatcher<{ | ||||
|     save: void; | ||||
|     previous: void; | ||||
|   }>(); | ||||
| 
 | ||||
|   const handleReset = (detail: ResetOptions) => { | ||||
|     if (detail.default) { | ||||
| @ -283,13 +286,21 @@ | ||||
|       {/if} | ||||
| 
 | ||||
|       {#if minified} | ||||
|         <div class="flex w-full place-content-end"> | ||||
|           <Button on:click={saveSetting}> | ||||
|             <span class="flex place-content-center place-items-center gap-2"> | ||||
|               Done | ||||
|               <Icon path={mdiCheck} size="18" /> | ||||
|             </span> | ||||
|           </Button> | ||||
|         <div class="flex pt-4"> | ||||
|           <div class="w-full flex place-content-start"> | ||||
|             <Button class="flex gap-2 place-content-center" on:click={() => dispatch('previous')}> | ||||
|               <Icon path={mdiArrowLeft} size="18" /> | ||||
|               <p>Theme</p> | ||||
|             </Button> | ||||
|           </div> | ||||
|           <div class="flex w-full place-content-end"> | ||||
|             <Button on:click={saveSetting}> | ||||
|               <span class="flex place-content-center place-items-center gap-2"> | ||||
|                 Done | ||||
|                 <Icon path={mdiCheck} size="18" /> | ||||
|               </span> | ||||
|             </Button> | ||||
|           </div> | ||||
|         </div> | ||||
|       {:else} | ||||
|         <SettingButtonsRow | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
|   width={size} | ||||
|   height={size} | ||||
|   {viewBox} | ||||
|   class="{className} {flipped && '-scale-x-100'}" | ||||
|   class="{className} {flipped ? '-scale-x-100' : ''}" | ||||
|   {role} | ||||
|   aria-label={ariaLabel} | ||||
|   aria-hidden={ariaHidden} | ||||
|  | ||||
| @ -8,6 +8,7 @@ | ||||
| 
 | ||||
|   const dispatch = createEventDispatcher<{ | ||||
|     done: void; | ||||
|     previous: void; | ||||
|   }>(); | ||||
| 
 | ||||
|   let configs: SystemConfigDto | null = null; | ||||
| @ -32,6 +33,7 @@ | ||||
|       disabled={$featureFlags.configFile} | ||||
|       storageConfig={configs.storageTemplate} | ||||
|       on:save={() => dispatch('done')} | ||||
|       on:previous={() => dispatch('previous')} | ||||
|     /> | ||||
|   {/if} | ||||
| </OnboardingCard> | ||||
|  | ||||
| @ -1,13 +1,15 @@ | ||||
| <script lang="ts"> | ||||
|   import { mdiArrowRight, mdiWhiteBalanceSunny, mdiMoonWaningCrescent } from '@mdi/js'; | ||||
|   import { mdiArrowRight } from '@mdi/js'; | ||||
|   import Button from '../elements/buttons/button.svelte'; | ||||
|   import Icon from '../elements/icon.svelte'; | ||||
|   import OnboardingCard from './onboarding-card.svelte'; | ||||
|   import { createEventDispatcher } from 'svelte'; | ||||
|   import { colorTheme } from '$lib/stores/preferences.store'; | ||||
|   import { moonPath, moonViewBox, sunPath, sunViewBox } from '$lib/assets/svg-paths'; | ||||
| 
 | ||||
|   const dispatch = createEventDispatcher<{ | ||||
|     done: void; | ||||
|     previous: void; | ||||
|   }>(); | ||||
| 
 | ||||
|   const toggleLightTheme = () => { | ||||
| @ -28,38 +30,35 @@ | ||||
| 
 | ||||
|   <div class="flex gap-4 mb-6"> | ||||
|     <button | ||||
|       class="w-1/2 aspect-square bg-immich-bg rounded-3xl transition-all shadow-sm hover:shadow-xl {$colorTheme == | ||||
|       'light' | ||||
|         ? 'border-[3px] border-immich-dark-primary/80 border-immich-primary' | ||||
|         : 'border border-transparent'}" | ||||
|       class="w-1/2 aspect-square bg-immich-bg rounded-3xl transition-all shadow-sm hover:shadow-xl border-[3px] border-immich-dark-primary/80 border-immich-primary dark:border dark:border-transparent" | ||||
|       on:click={toggleLightTheme} | ||||
|     > | ||||
|       <div | ||||
|         class="flex flex-col place-items-center place-content-center justify-around h-full w-full text-immich-primary" | ||||
|       > | ||||
|         <Icon path={mdiWhiteBalanceSunny} size="96" /> | ||||
|         <Icon path={sunPath} viewBox={sunViewBox} size="96" /> | ||||
|         <p class="font-semibold text-4xl">LIGHT</p> | ||||
|       </div> | ||||
|     </button> | ||||
|     <button | ||||
|       class="w-1/2 aspect-square bg-immich-dark-bg rounded-3xl {$colorTheme == 'dark' | ||||
|         ? 'border-[3px] border-immich-dark-primary/80 border-immich-primary' | ||||
|         : 'border border-transparent'}" | ||||
|       class="w-1/2 aspect-square bg-immich-dark-bg rounded-3xl dark:border-[3px] dark:border-immich-dark-primary/80 dark:border-immich-dark-primary border border-transparent" | ||||
|       on:click={toggleDarkTheme} | ||||
|     > | ||||
|       <div | ||||
|         class="flex flex-col place-items-center place-content-center justify-around h-full w-full text-immich-dark-primary" | ||||
|       > | ||||
|         <Icon path={mdiMoonWaningCrescent} size="96" /> | ||||
|         <Icon path={moonPath} viewBox={moonViewBox} size="96" /> | ||||
|         <p class="font-semibold text-4xl">DARK</p> | ||||
|       </div> | ||||
|     </button> | ||||
|   </div> | ||||
| 
 | ||||
|   <div class="w-full flex place-content-end"> | ||||
|     <Button class="flex gap-2 place-content-center" on:click={() => dispatch('done')}> | ||||
|       <p>Storage Template</p> | ||||
|       <Icon path={mdiArrowRight} size="18" /> | ||||
|     </Button> | ||||
|   <div class="flex"> | ||||
|     <div class="w-full flex place-content-end"> | ||||
|       <Button class="flex gap-2 place-content-center" on:click={() => dispatch('done')}> | ||||
|         <p>Storage Template</p> | ||||
|         <Icon path={mdiArrowRight} size="18" /> | ||||
|       </Button> | ||||
|     </div> | ||||
|   </div> | ||||
| </OnboardingCard> | ||||
|  | ||||
| @ -1,7 +1,9 @@ | ||||
| <script lang="ts"> | ||||
|   import { browser } from '$app/environment'; | ||||
|   import { moonPath, sunPath, sunViewBox } from '$lib/assets/svg-paths'; | ||||
|   import { colorTheme } from '$lib/stores/preferences.store'; | ||||
|   import IconButton from '../elements/buttons/icon-button.svelte'; | ||||
|   import Icon from '../elements/icon.svelte'; | ||||
| 
 | ||||
|   const toggleTheme = () => { | ||||
|     $colorTheme = $colorTheme === 'dark' ? 'light' : 'dark'; | ||||
| @ -20,16 +22,8 @@ | ||||
| 
 | ||||
| <IconButton on:click={toggleTheme} title="Toggle theme"> | ||||
|   {#if $colorTheme === 'light'} | ||||
|     <svg class="h-6 w-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" | ||||
|       ><path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" /></svg | ||||
|     > | ||||
|     <Icon path={moonPath} viewBox={sunViewBox} class="h-6 w-6" /> | ||||
|   {:else} | ||||
|     <svg class="h-6 w-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" | ||||
|       ><path | ||||
|         d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" | ||||
|         fill-rule="evenodd" | ||||
|         clip-rule="evenodd" | ||||
|       /></svg | ||||
|     > | ||||
|     <Icon path={sunPath} viewBox={sunViewBox} class="h-6 w-6" /> | ||||
|   {/if} | ||||
| </IconButton> | ||||
|  | ||||
| @ -14,7 +14,7 @@ | ||||
|     component: typeof OnboardingHello | typeof OnboardingTheme | typeof OnboadingStorageTemplate; | ||||
|   } | ||||
| 
 | ||||
|   let onboardingSteps: OnboardingStep[] = [ | ||||
|   const onboardingSteps: OnboardingStep[] = [ | ||||
|     { name: 'hello', component: OnboardingHello }, | ||||
|     { name: 'theme', component: OnboardingTheme }, | ||||
|     { name: 'storage', component: OnboadingStorageTemplate }, | ||||
| @ -35,8 +35,29 @@ | ||||
|       goto(`${AppRoute.AUTH_ONBOARDING}?step=${onboardingSteps[index].name}`); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   const handlePrevious = () => { | ||||
|     if (index >= 1) { | ||||
|       index--; | ||||
|       goto(`${AppRoute.AUTH_ONBOARDING}?step=${onboardingSteps[index].name}`); | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| 
 | ||||
| <section id="onboarding-page" class="min-w-screen flex min-h-screen place-content-center place-items-center p-4"> | ||||
|   <svelte:component this={onboardingSteps[index].component} on:done={handleDoneClicked} /> | ||||
| <section id="onboarding-page" class="min-w-screen flex min-h-screen p-4"> | ||||
|   <div class="flex flex-col w-full"> | ||||
|     <div class="w-full bg-gray-300 dark:bg-gray-600 rounded-md h-2"> | ||||
|       <div | ||||
|         class="progress-bar bg-immich-primary dark:bg-immich-dark-primary h-2 rounded-md transition-all duration-200 ease-out" | ||||
|         style="width: {(index / (onboardingSteps.length - 1)) * 100}%" | ||||
|       ></div> | ||||
|     </div> | ||||
|     <div class="w-full min-w-screen py-8 flex h-full place-content-center place-items-center"> | ||||
|       <svelte:component | ||||
|         this={onboardingSteps[index].component} | ||||
|         on:done={handleDoneClicked} | ||||
|         on:previous={handlePrevious} | ||||
|       /> | ||||
|     </div> | ||||
|   </div> | ||||
| </section> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user