my own indieAuth provider! indiko.dunkirk.sh/docs
indieauth oauth2-server
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: use toasts more often

+47 -13
+14 -11
src/client/index.ts
··· 3 3 const welcome = document.getElementById('welcome') as HTMLElement; 4 4 const subtitle = document.getElementById('subtitle') as HTMLElement; 5 5 const recentApps = document.getElementById('recentApps') as HTMLElement; 6 - const message = document.getElementById('message') as HTMLElement; 6 + const toast = document.getElementById('toast') as HTMLElement; 7 7 8 8 // Profile form elements 9 9 const profileForm = document.getElementById('profileForm') as HTMLFormElement; ··· 40 40 isAdmin?: boolean; 41 41 } 42 42 43 - function showMessage(text: string, type: 'error' | 'success' = 'error') { 44 - message.textContent = text; 45 - message.className = `message show ${type}`; 46 - setTimeout(() => message.classList.remove('show'), 5000); 43 + function showToast(message: string, type: 'success' | 'error' = 'success') { 44 + toast.textContent = message; 45 + toast.className = `toast ${type} show`; 46 + 47 + setTimeout(() => { 48 + toast.classList.remove('show'); 49 + }, 3000); 47 50 } 48 51 49 52 function updateAvatarPreview(photo: string | null, username: string) { ··· 146 149 }); 147 150 } catch (error) { 148 151 console.error('Failed to load profile:', error); 149 - showMessage('Failed to load profile'); 152 + showToast('Failed to load profile', 'error'); 150 153 } 151 154 } 152 155 ··· 220 223 throw new Error(error.error || 'Failed to update profile'); 221 224 } 222 225 223 - showMessage('Profile updated successfully!', 'success'); 226 + showToast('Profile updated successfully!', 'success'); 224 227 } catch (error) { 225 - showMessage((error as Error).message || 'Failed to update profile'); 228 + showToast((error as Error).message || 'Failed to update profile', 'error'); 226 229 } finally { 227 230 saveBtn.disabled = false; 228 231 saveBtn.textContent = 'save changes'; ··· 243 246 244 247 if (confirmation !== 'DELETE') { 245 248 if (confirmation !== null) { 246 - showMessage('Account deletion cancelled. You must type "DELETE" exactly.'); 249 + showToast('Account deletion cancelled. You must type "DELETE" exactly.', 'error'); 247 250 } 248 251 return; 249 252 } ··· 266 269 267 270 // Clear session and redirect 268 271 localStorage.removeItem('indiko_session'); 269 - showMessage('Account deleted successfully. Redirecting...', 'success'); 272 + showToast('Account deleted successfully. Redirecting...', 'success'); 270 273 setTimeout(() => { 271 274 window.location.href = '/login'; 272 275 }, 2000); 273 276 } catch (error) { 274 - showMessage((error as Error).message || 'Failed to delete account'); 277 + showToast((error as Error).message || 'Failed to delete account', 'error'); 275 278 deleteAccountBtn.disabled = false; 276 279 deleteAccountBtn.textContent = 'delete my account'; 277 280 }
+33 -2
src/html/index.html
··· 165 165 .view-all:hover { 166 166 text-decoration: underline; 167 167 } 168 + 169 + .toast { 170 + position: fixed; 171 + bottom: 2rem; 172 + right: 2rem; 173 + background: var(--mahogany); 174 + border: 2px solid var(--berry-crush); 175 + padding: 1rem 1.5rem; 176 + color: var(--lavender); 177 + font-size: 0.875rem; 178 + font-weight: 500; 179 + z-index: 2000; 180 + opacity: 0; 181 + transform: translateY(1rem); 182 + transition: opacity 0.3s, transform 0.3s; 183 + max-width: 25rem; 184 + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.5); 185 + } 186 + 187 + .toast.show { 188 + opacity: 1; 189 + transform: translateY(0); 190 + } 191 + 192 + .toast.error { 193 + border-color: var(--rosewood); 194 + } 195 + 196 + .toast.success { 197 + border-color: var(--berry-crush); 198 + } 168 199 </style> 169 200 </head> 170 201 ··· 175 206 </header> 176 207 177 208 <main> 178 - <div id="message" class="message"></div> 179 - 180 209 <div class="profile-section"> 181 210 <h2 class="section-title">recent apps</h2> 182 211 <div id="recentApps" class="apps-preview"> ··· 229 258 <footer id="footer"> 230 259 loading... 231 260 </footer> 261 + 262 + <div id="toast" class="toast"></div> 232 263 233 264 <script type="module" src="../client/index.ts"></script> 234 265 </body>