this repo has no description
1<script lang="ts"> 2 import { navigate } from '../lib/router.svelte' 3 import { api, ApiError } from '../lib/api' 4 5 let identifier = $state('') 6 let submitting = $state(false) 7 let error = $state<string | null>(null) 8 let success = $state(false) 9 10 async function handleSubmit(e: Event) { 11 e.preventDefault() 12 submitting = true 13 error = null 14 15 try { 16 await api.requestPasskeyRecovery(identifier) 17 success = true 18 } catch (err) { 19 if (err instanceof ApiError) { 20 error = err.message || 'Failed to send recovery link' 21 } else if (err instanceof Error) { 22 error = err.message || 'Failed to send recovery link' 23 } else { 24 error = 'Failed to send recovery link' 25 } 26 } finally { 27 submitting = false 28 } 29 } 30</script> 31 32<div class="recovery-container"> 33 {#if success} 34 <div class="success-content"> 35 <h1>Recovery Link Sent</h1> 36 <p class="subtitle"> 37 If your account exists and is a passkey-only account, you'll receive a recovery link 38 at your preferred notification channel. 39 </p> 40 <p class="info"> 41 The link will expire in 1 hour. Check your email, Discord, Telegram, or Signal 42 depending on your account settings. 43 </p> 44 <button onclick={() => navigate('/login')}>Back to Sign In</button> 45 </div> 46 {:else} 47 <h1>Recover Passkey Account</h1> 48 <p class="subtitle"> 49 Lost access to your passkey? Enter your handle or email and we'll send you a recovery link. 50 </p> 51 52 {#if error} 53 <div class="error">{error}</div> 54 {/if} 55 56 <form onsubmit={handleSubmit}> 57 <div class="field"> 58 <label for="identifier">Handle or Email</label> 59 <input 60 id="identifier" 61 type="text" 62 bind:value={identifier} 63 placeholder="handle or you@example.com" 64 disabled={submitting} 65 required 66 /> 67 </div> 68 69 <div class="info-box"> 70 <strong>How it works</strong> 71 <p> 72 We'll send a secure link to your registered notification channel. 73 Click the link to set a temporary password. Then you can sign in 74 and add a new passkey. 75 </p> 76 </div> 77 78 <button type="submit" disabled={submitting || !identifier.trim()}> 79 {submitting ? 'Sending...' : 'Send Recovery Link'} 80 </button> 81 </form> 82 {/if} 83 84 <p class="back-link"> 85 <a href="#/login">Back to Sign In</a> 86 </p> 87</div> 88 89<style> 90 .recovery-container { 91 max-width: 400px; 92 margin: 4rem auto; 93 padding: 2rem; 94 } 95 96 h1 { 97 margin: 0 0 0.5rem 0; 98 } 99 100 .subtitle { 101 color: var(--text-secondary); 102 margin: 0 0 2rem 0; 103 } 104 105 form { 106 display: flex; 107 flex-direction: column; 108 gap: 1rem; 109 } 110 111 .field { 112 display: flex; 113 flex-direction: column; 114 gap: 0.25rem; 115 } 116 117 label { 118 font-size: 0.875rem; 119 font-weight: 500; 120 } 121 122 input { 123 padding: 0.75rem; 124 border: 1px solid var(--border-color-light); 125 border-radius: 4px; 126 font-size: 1rem; 127 background: var(--bg-input); 128 color: var(--text-primary); 129 } 130 131 input:focus { 132 outline: none; 133 border-color: var(--accent); 134 } 135 136 .info-box { 137 background: var(--bg-secondary); 138 border: 1px solid var(--border-color); 139 border-radius: 6px; 140 padding: 1rem; 141 font-size: 0.875rem; 142 } 143 144 .info-box strong { 145 display: block; 146 margin-bottom: 0.5rem; 147 } 148 149 .info-box p { 150 margin: 0; 151 color: var(--text-secondary); 152 } 153 154 button { 155 padding: 0.75rem; 156 background: var(--accent); 157 color: white; 158 border: none; 159 border-radius: 4px; 160 font-size: 1rem; 161 cursor: pointer; 162 } 163 164 button:hover:not(:disabled) { 165 background: var(--accent-hover); 166 } 167 168 button:disabled { 169 opacity: 0.6; 170 cursor: not-allowed; 171 } 172 173 .error { 174 padding: 0.75rem; 175 background: var(--error-bg); 176 border: 1px solid var(--error-border); 177 border-radius: 4px; 178 color: var(--error-text); 179 margin-bottom: 1rem; 180 } 181 182 .success-content { 183 text-align: center; 184 } 185 186 .info { 187 color: var(--text-secondary); 188 font-size: 0.875rem; 189 margin-bottom: 1.5rem; 190 } 191 192 .back-link { 193 text-align: center; 194 margin-top: 2rem; 195 } 196 197 .back-link a { 198 color: var(--accent); 199 text-decoration: none; 200 } 201 202 .back-link a:hover { 203 text-decoration: underline; 204 } 205</style>