Replaces "PhotoPrism" in UI strings (empty states, tooltips, toasts, log header, login screen) with neutral terms like "the indexer", "the library", "the server" — accurate regardless of backend. The login header becomes "Mulimage" and drops the explicit PhotoPrism mention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
118 lines
3.5 KiB
Svelte
118 lines
3.5 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { goto } from '$app/navigation';
|
|
import { toast } from 'svelte-sonner';
|
|
import { getConfig, login } from '$lib/services/photoprism';
|
|
import { isAuthenticated } from '$lib/stores/session.svelte';
|
|
|
|
let username = $state('');
|
|
let password = $state('');
|
|
let submitting = $state(false);
|
|
// OIDC config probed lazily from /api/v1/config (no auth required).
|
|
// Empty when OIDC is dormant; populated triggers the SSO button.
|
|
let oidc = $state<{ provider: string; loginUri: string } | null>(null);
|
|
|
|
$effect(() => {
|
|
if (isAuthenticated()) {
|
|
void goto('/', { replaceState: true });
|
|
}
|
|
});
|
|
|
|
onMount(async () => {
|
|
try {
|
|
const cfg = await getConfig();
|
|
const ext = cfg.ext?.oidc;
|
|
if (ext?.enabled && ext.loginUri) {
|
|
oidc = { provider: ext.provider || 'OIDC', loginUri: ext.loginUri };
|
|
}
|
|
} catch {
|
|
// /config is best-effort — SSO button just stays hidden.
|
|
}
|
|
});
|
|
|
|
async function onSubmit(e: SubmitEvent) {
|
|
e.preventDefault();
|
|
if (submitting) return;
|
|
submitting = true;
|
|
try {
|
|
await login(username, password);
|
|
toast.success('Signed in');
|
|
await goto('/', { replaceState: true });
|
|
} catch (err) {
|
|
const msg = err instanceof Error ? err.message : 'Login failed';
|
|
toast.error(msg);
|
|
} finally {
|
|
submitting = false;
|
|
}
|
|
}
|
|
|
|
function onOidcClick() {
|
|
if (!oidc) return;
|
|
// Full reload so PhotoPrism handles the redirect + cookie set on
|
|
// its own; the SPA picks up the resulting session on return via
|
|
// bootstrapSessionFromCookies in the root layout.
|
|
window.location.href = oidc.loginUri;
|
|
}
|
|
</script>
|
|
|
|
<div class="flex min-h-screen items-center justify-center bg-background p-6">
|
|
<form
|
|
onsubmit={onSubmit}
|
|
class="w-full max-w-sm space-y-5 rounded-lg border border-border bg-card p-8 shadow-sm"
|
|
>
|
|
<header class="space-y-1">
|
|
<h1 class="text-2xl font-semibold tracking-tight text-foreground">Mulimage</h1>
|
|
<p class="text-sm text-muted-foreground">Sign in to your account.</p>
|
|
</header>
|
|
|
|
<label class="block space-y-1.5">
|
|
<span class="text-sm font-medium text-foreground">Username</span>
|
|
<input
|
|
type="text"
|
|
autocomplete="username"
|
|
required
|
|
bind:value={username}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring"
|
|
/>
|
|
</label>
|
|
|
|
<label class="block space-y-1.5">
|
|
<span class="text-sm font-medium text-foreground">Password</span>
|
|
<input
|
|
type="password"
|
|
autocomplete="current-password"
|
|
required
|
|
bind:value={password}
|
|
class="w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring"
|
|
/>
|
|
</label>
|
|
|
|
<button
|
|
type="submit"
|
|
disabled={submitting}
|
|
class="w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow-sm hover:opacity-90 disabled:opacity-50"
|
|
>
|
|
{submitting ? 'Signing in…' : 'Sign in'}
|
|
</button>
|
|
|
|
{#if oidc}
|
|
<div class="relative py-1">
|
|
<div class="absolute inset-0 flex items-center" aria-hidden="true">
|
|
<div class="w-full border-t border-border"></div>
|
|
</div>
|
|
<div class="relative flex justify-center">
|
|
<span class="bg-card px-2 text-xs text-muted-foreground">or</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
onclick={onOidcClick}
|
|
class="w-full rounded-md border border-input bg-background px-4 py-2 text-sm font-medium text-foreground shadow-sm hover:bg-muted"
|
|
>
|
|
Sign in with {oidc.provider}
|
|
</button>
|
|
{/if}
|
|
</form>
|
|
</div>
|