Files
haos-hacs-immich-album-watcher/frontend/src/routes/login/+page.svelte
alexei.dolgolyov b708b14f32
Some checks failed
Validate / Hassfest (push) Has been cancelled
Add frontend for TrackingConfig + TemplateConfig, fix locale, simplify trackers
New pages:
- /tracking-configs: Full CRUD with event tracking, asset display,
  periodic summary, scheduled assets, and memory mode sections.
  Collapsible sub-sections that show/hide based on enabled state.
- /template-configs: Full CRUD with all 21 template slots organized
  into 5 fieldsets (event messages, asset formatting, date/location,
  scheduled messages, telegram). Preview support per slot.

Updated pages:
- Targets: added tracking_config_id + template_config_id selectors
  (dropdowns populated from configs). Configs are reusable.
- Trackers: simplified to album selection + scan interval + targets.
  Added Test, Test Periodic, Test Memory buttons per tracker.
- Nav: replaced Templates with Tracking + Templates config links

Other fixes:
- Language button: now triggers window.location.reload() to force
  all child pages to re-evaluate t() calls
- Dark theme buttons: changed primary color to dark gray in dark mode
- Removed old /templates page (replaced by /template-configs)
- Added .gitignore for __pycache__ in server package

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 17:10:34 +03:00

77 lines
3.1 KiB
Svelte

<script lang="ts">
import { goto } from '$app/navigation';
import { onMount } from 'svelte';
import { api } from '$lib/api';
import { login } from '$lib/auth.svelte';
import { t, initLocale, getLocale, setLocale } from '$lib/i18n';
import { initTheme, getTheme, setTheme, type Theme } from '$lib/theme.svelte';
const theme = getTheme();
let username = $state('');
let password = $state('');
let error = $state('');
let submitting = $state(false);
onMount(async () => {
initLocale();
initTheme();
try {
const res = await api<{ needs_setup: boolean }>('/auth/needs-setup');
if (res.needs_setup) goto('/setup');
} catch { /* ignore */ }
});
async function handleSubmit(e: SubmitEvent) {
e.preventDefault();
error = '';
submitting = true;
try {
await login(username, password);
goto('/');
} catch (err: any) {
error = err.message || 'Login failed';
}
submitting = false;
}
</script>
<div class="min-h-screen flex items-center justify-center bg-[var(--color-background)]">
<div class="w-full max-w-sm">
<div class="bg-[var(--color-card)] border border-[var(--color-border)] rounded-lg p-6 shadow-sm">
<div class="flex justify-end gap-1 mb-4">
<button onclick={() => { setLocale(getLocale() === 'en' ? 'ru' : 'en'); window.location.reload(); }}
class="text-xs px-1.5 py-0.5 rounded bg-[var(--color-muted)] text-[var(--color-muted-foreground)]">
{getLocale().toUpperCase()}
</button>
<button onclick={() => { const o: Theme[] = ['light','dark','system']; setTheme(o[(o.indexOf(theme.current)+1)%3]); }}
class="text-xs px-1.5 py-0.5 rounded bg-[var(--color-muted)] text-[var(--color-muted-foreground)]">
{theme.resolved === 'dark' ? '🌙' : '☀️'}
</button>
</div>
<h1 class="text-xl font-semibold text-center mb-1">{t('app.name')}</h1>
<p class="text-sm text-[var(--color-muted-foreground)] text-center mb-6">{t('auth.signInTitle')}</p>
{#if error}
<div class="bg-[var(--color-error-bg)] text-[var(--color-error-fg)] text-sm rounded-md p-3 mb-4">{error}</div>
{/if}
<form onsubmit={handleSubmit} class="space-y-4">
<div>
<label for="username" class="block text-sm font-medium mb-1.5">{t('auth.username')}</label>
<input id="username" type="text" bind:value={username} required
class="w-full px-3 py-2 border border-[var(--color-border)] rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--color-background)]" />
</div>
<div>
<label for="password" class="block text-sm font-medium mb-1.5">{t('auth.password')}</label>
<input id="password" type="password" bind:value={password} required
class="w-full px-3 py-2 border border-[var(--color-border)] rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--color-background)]" />
</div>
<button type="submit" disabled={submitting}
class="w-full py-2 px-4 bg-[var(--color-primary)] text-[var(--color-primary-foreground)] rounded-md text-sm font-medium hover:opacity-90 transition-opacity disabled:opacity-50">
{submitting ? t('auth.signingIn') : t('auth.signIn')}
</button>
</form>
</div>
</div>
</div>