fix(auth): surface rate-limit error on login and remove dropped background patterns

Show a clear too-many-attempts message on the login page when the server
throttles the request. Remove the nova and golden-ratio background options,
whose CSS definitions were already deleted.
This commit is contained in:
neon
2026-05-11 10:12:28 -06:00
parent 681f684dff
commit 3fd439289d
4 changed files with 17 additions and 33 deletions
-26
View File
@@ -153,32 +153,6 @@
filter: contrast(150%) brightness(110%);
}
.pattern-nova::before {
content: '';
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image:
radial-gradient(at 50% 50%, oklch(0.7 0.15 var(--tint-h) / 0.12) 0%, transparent 60%),
linear-gradient(to bottom, oklch(0.7 0.15 calc(var(--tint-h) + 150) / 0.08) 0%, transparent 40%),
linear-gradient(to top, oklch(0.7 0.15 calc(var(--tint-h) + 210) / 0.08) 0%, transparent 40%);
filter: contrast(150%) brightness(110%);
}
.pattern-golden-ratio::before {
content: '';
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background-image:
radial-gradient(at 38.2% 38.2%, oklch(0.7 0.15 var(--tint-h) / 0.1) 0%, transparent 55%),
radial-gradient(at 61.8% 61.8%, oklch(0.7 0.15 calc(var(--tint-h) + 137.5) / 0.1) 0%, transparent 55%),
radial-gradient(at 80% 20%, oklch(0.7 0.15 calc(var(--tint-h) + 275) / 0.08) 0%, transparent 50%);
filter: contrast(150%) brightness(110%);
}
.pattern-millimeter::before {
content: '';
position: fixed;
+16 -2
View File
@@ -59,6 +59,20 @@ const loading = ref(false)
const oidcProviders = ref<OidcProviderPublic[]>([])
const oidcLoadingSlug = ref<string | null>(null)
function resolveLoginError(err: unknown): string {
if (!(err instanceof Error)) return 'Invalid username or password'
const normalizedMessage = err.message.trim().toLowerCase()
if (normalizedMessage.includes('too many requests') || normalizedMessage.includes('throttler')) {
return 'Too many login attempts. Please wait a minute and try again.'
}
if (normalizedMessage.includes('invalid credentials')) {
return 'Invalid username or password'
}
return err.message || 'Invalid username or password'
}
onMounted(async () => {
oidcProviders.value = await getPublicProviders()
})
@@ -68,8 +82,8 @@ async function handleSubmit() {
loading.value = true
try {
await login(username.value, password.value)
} catch {
error.value = 'Invalid username or password'
} catch (err) {
error.value = resolveLoginError(err)
} finally {
loading.value = false
}
@@ -41,7 +41,7 @@ const BACKGROUND_GROUPS: { label: string; ids: string[] }[] = [
{ label: 'Fundamental', ids: ['none', 'dots', 'cross', 'terminal', 'millimeter'] },
{ label: 'Structural', ids: ['blueprint', 'brushed', 'scanlines', 'vinyl', 'carbon', 'perforated'] },
{ label: 'Ambient', ids: ['aurora', 'horizon', 'glow', 'mesh', 'elevation'] },
{ label: 'Refractive', ids: ['prism', 'spectrum', 'spectrum-x', 'spectrum-plus', 'eclipse', 'nova', 'golden-ratio'] },
{ label: 'Refractive', ids: ['prism', 'spectrum', 'spectrum-x', 'spectrum-plus', 'eclipse'] },
]
const accentLabel = computed(() => [...ACCENT_VIVID, ...ACCENT_PASTEL].find((opt) => opt.id === themeStore.accent)?.label ?? themeStore.accent)
-4
View File
@@ -61,8 +61,6 @@ export type Background =
| 'spectrum-x'
| 'spectrum-plus'
| 'eclipse'
| 'nova'
| 'golden-ratio'
export const ACCENT_VIVID: { id: Accent; label: string; color: string }[] = [
{ id: 'white', label: 'White', color: '#fafafa' },
@@ -140,8 +138,6 @@ export const BACKGROUND_OPTIONS: { id: Background; label: string; cssClass: stri
{ id: 'spectrum-x', label: 'Spectrum X', cssClass: 'pattern-spectrum-x' },
{ id: 'spectrum-plus', label: 'Spectrum Plus', cssClass: 'pattern-spectrum-plus' },
{ id: 'eclipse', label: 'Eclipse', cssClass: 'pattern-eclipse' },
{ id: 'nova', label: 'Nova', cssClass: 'pattern-nova' },
{ id: 'golden-ratio', label: 'Golden Ratio', cssClass: 'pattern-golden-ratio' },
]
const ACCENT_IDS = ACCENT_OPTIONS.map((a) => a.id)