this repo has no description
at main 5.8 kB view raw
1<script lang="ts"> 2 import type { AuthMethod, ServerDescription } from '../../lib/migration/types' 3 import { _ } from '../../lib/i18n' 4 5 interface Props { 6 handleInput: string 7 selectedDomain: string 8 handleAvailable: boolean | null 9 checkingHandle: boolean 10 email: string 11 password: string 12 authMethod: AuthMethod 13 inviteCode: string 14 serverInfo: ServerDescription | null 15 migratingFromLabel: string 16 migratingFromValue: string 17 loading?: boolean 18 onHandleChange: (handle: string) => void 19 onDomainChange: (domain: string) => void 20 onCheckHandle: () => void 21 onEmailChange: (email: string) => void 22 onPasswordChange: (password: string) => void 23 onAuthMethodChange: (method: AuthMethod) => void 24 onInviteCodeChange: (code: string) => void 25 onBack: () => void 26 onContinue: () => void 27 } 28 29 let { 30 handleInput, 31 selectedDomain, 32 handleAvailable, 33 checkingHandle, 34 email, 35 password, 36 authMethod, 37 inviteCode, 38 serverInfo, 39 migratingFromLabel, 40 migratingFromValue, 41 loading = false, 42 onHandleChange, 43 onDomainChange, 44 onCheckHandle, 45 onEmailChange, 46 onPasswordChange, 47 onAuthMethodChange, 48 onInviteCodeChange, 49 onBack, 50 onContinue, 51 }: Props = $props() 52 53 const canContinue = $derived( 54 handleInput.trim() && 55 email && 56 (authMethod === 'passkey' || password) && 57 handleAvailable !== false 58 ) 59</script> 60 61<div class="step-content"> 62 <h2>{$_('migration.inbound.chooseHandle.title')}</h2> 63 <p>{$_('migration.inbound.chooseHandle.desc')}</p> 64 65 <div class="current-info"> 66 <span class="label">{migratingFromLabel}:</span> 67 <span class="value">{migratingFromValue}</span> 68 </div> 69 70 <div class="field"> 71 <label for="new-handle">{$_('migration.inbound.chooseHandle.newHandle')}</label> 72 <div class="handle-input-group"> 73 <input 74 id="new-handle" 75 type="text" 76 placeholder="username" 77 value={handleInput} 78 oninput={(e) => onHandleChange((e.target as HTMLInputElement).value)} 79 onblur={onCheckHandle} 80 /> 81 {#if serverInfo && serverInfo.availableUserDomains.length > 0 && !handleInput.includes('.')} 82 <select value={selectedDomain} onchange={(e) => onDomainChange((e.target as HTMLSelectElement).value)}> 83 {#each serverInfo.availableUserDomains as domain} 84 <option value={domain}>.{domain}</option> 85 {/each} 86 </select> 87 {/if} 88 </div> 89 90 {#if checkingHandle} 91 <p class="hint">{$_('migration.inbound.chooseHandle.checkingAvailability')}</p> 92 {:else if handleAvailable === true} 93 <p class="hint" style="color: var(--success-text)">{$_('migration.inbound.chooseHandle.handleAvailable')}</p> 94 {:else if handleAvailable === false} 95 <p class="hint error">{$_('migration.inbound.chooseHandle.handleTaken')}</p> 96 {:else} 97 <p class="hint">{$_('migration.inbound.chooseHandle.handleHint')}</p> 98 {/if} 99 </div> 100 101 <div class="field"> 102 <label for="email">{$_('migration.inbound.chooseHandle.email')}</label> 103 <input 104 id="email" 105 type="email" 106 placeholder="you@example.com" 107 value={email} 108 oninput={(e) => onEmailChange((e.target as HTMLInputElement).value)} 109 required 110 /> 111 </div> 112 113 <div class="field"> 114 <span class="field-label">{$_('migration.inbound.chooseHandle.authMethod')}</span> 115 <div class="auth-method-options"> 116 <label class="auth-option" class:selected={authMethod === 'password'}> 117 <input 118 type="radio" 119 name="auth-method" 120 value="password" 121 checked={authMethod === 'password'} 122 onchange={() => onAuthMethodChange('password')} 123 /> 124 <div class="auth-option-content"> 125 <strong>{$_('migration.inbound.chooseHandle.authPassword')}</strong> 126 <span>{$_('migration.inbound.chooseHandle.authPasswordDesc')}</span> 127 </div> 128 </label> 129 <label class="auth-option" class:selected={authMethod === 'passkey'}> 130 <input 131 type="radio" 132 name="auth-method" 133 value="passkey" 134 checked={authMethod === 'passkey'} 135 onchange={() => onAuthMethodChange('passkey')} 136 /> 137 <div class="auth-option-content"> 138 <strong>{$_('migration.inbound.chooseHandle.authPasskey')}</strong> 139 <span>{$_('migration.inbound.chooseHandle.authPasskeyDesc')}</span> 140 </div> 141 </label> 142 </div> 143 </div> 144 145 {#if authMethod === 'password'} 146 <div class="field"> 147 <label for="new-password">{$_('migration.inbound.chooseHandle.password')}</label> 148 <input 149 id="new-password" 150 type="password" 151 placeholder="Password for your new account" 152 value={password} 153 oninput={(e) => onPasswordChange((e.target as HTMLInputElement).value)} 154 required 155 minlength={8} 156 /> 157 <p class="hint">{$_('migration.inbound.chooseHandle.passwordHint')}</p> 158 </div> 159 {:else} 160 <div class="info-box"> 161 <p>{$_('migration.inbound.chooseHandle.passkeyInfo')}</p> 162 </div> 163 {/if} 164 165 {#if serverInfo?.inviteCodeRequired} 166 <div class="field"> 167 <label for="invite">{$_('migration.inbound.chooseHandle.inviteCode')}</label> 168 <input 169 id="invite" 170 type="text" 171 placeholder="Enter invite code" 172 value={inviteCode} 173 oninput={(e) => onInviteCodeChange((e.target as HTMLInputElement).value)} 174 required 175 /> 176 </div> 177 {/if} 178 179 <div class="button-row"> 180 <button class="ghost" onclick={onBack} disabled={loading}>{$_('migration.inbound.common.back')}</button> 181 <button disabled={!canContinue || loading} onclick={onContinue}> 182 {$_('migration.inbound.common.continue')} 183 </button> 184 </div> 185</div>