♻️ refactor: migrate all web apps to Phosphor icons

Replace lucide-svelte with @manacore/shared-icons across all web apps
for consistent icon usage throughout the monorepo.

Apps migrated:
- calendar (12 files)
- contacts (1 file)
- matrix (16 files)
- nutriphi (7 files)
- presi (6 files)
- questions (9 files)
- skilltree (9 files)
- storage (16 files)
- todo (package.json only)

Key icon mappings:
- Trash2 → Trash
- ChevronLeft/Right/Up/Down → CaretLeft/Right/Up/Down
- Search → MagnifyingGlass
- Settings → Gear
- Loader2 → CircleNotch
- AlertCircle → WarningCircle
- ExternalLink → ArrowSquareOut
- LogOut → SignOut
This commit is contained in:
Till-JS 2026-01-29 13:15:13 +01:00
parent c21f780581
commit b89749deed
86 changed files with 1736 additions and 904 deletions

View file

@ -13,7 +13,7 @@ A minimal, privacy-focused Matrix client that connects to your self-hosted Synap
| Frontend | SvelteKit 2, Svelte 5 (runes), Tailwind CSS 4 |
| Matrix SDK | matrix-js-sdk |
| State Management | Svelte 5 runes ($state, $derived) |
| Icons | lucide-svelte |
| Icons | @manacore/shared-icons (Phosphor) |
| Date Handling | date-fns |
## Project Structure

View file

@ -39,7 +39,6 @@
"@manacore/shared-tailwind": "workspace:*",
"@manacore/shared-i18n": "workspace:*",
"@manacore/shared-icons": "workspace:*",
"lucide-svelte": "^0.509.0",
"date-fns": "^4.1.0",
"svelte-i18n": "^4.0.1"
}

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { matrixStore } from '$lib/matrix';
import { X, Users, MessageCircle, Lock, Globe, Loader2 } from 'lucide-svelte';
import { X, Users, ChatCircle, Lock, Globe, CircleNotch } from '@manacore/shared-icons';
interface Props {
open: boolean;
@ -102,7 +102,10 @@
{#if open}
<!-- Backdrop -->
<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/50" onclick={handleClose}>
<div
class="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
onclick={handleClose}
>
<!-- Dialog -->
<div
class="w-full max-w-md rounded-xl bg-base-100 shadow-xl"
@ -128,7 +131,7 @@
class:btn-ghost={!isDirect}
onclick={() => (isDirect = true)}
>
<MessageCircle class="h-4 w-4" />
<ChatCircle class="h-4 w-4" />
Direktnachricht
</button>
<button
@ -182,11 +185,7 @@
Öffentlicher Raum
{/if}
</span>
<input
type="checkbox"
class="toggle"
bind:checked={isPrivate}
/>
<input type="checkbox" class="toggle" bind:checked={isPrivate} />
</label>
<p class="text-xs text-base-content/60 ml-1">
{isPrivate
@ -213,7 +212,7 @@
placeholder="@benutzer:server.de oder Name"
/>
{#if searching}
<Loader2 class="absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin" />
<CircleNotch class="absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin" />
{/if}
</div>
@ -222,10 +221,7 @@
<ul class="menu mt-2 max-h-40 overflow-y-auto rounded-lg bg-base-200 p-2">
{#each searchResults as user}
<li>
<button
class="flex items-center gap-2"
onclick={() => selectUser(user)}
>
<button class="flex items-center gap-2" onclick={() => selectUser(user)}>
<div class="avatar placeholder">
<div class="w-8 rounded-full bg-neutral text-neutral-content">
{#if user.avatarUrl}
@ -275,7 +271,7 @@
<button class="btn btn-ghost" onclick={handleClose}>Abbrechen</button>
<button class="btn btn-primary" onclick={handleCreate} disabled={loading}>
{#if loading}
<Loader2 class="h-4 w-4 animate-spin" />
<CircleNotch class="h-4 w-4 animate-spin" />
{/if}
{isDirect ? 'Chat starten' : 'Raum erstellen'}
</button>

View file

@ -4,17 +4,17 @@
import { format, isToday, isYesterday } from 'date-fns';
import { de } from 'date-fns/locale';
import {
Reply,
Pencil,
Trash2,
MoreHorizontal,
Download,
FileIcon,
ArrowBendUpLeft,
PencilSimple,
Trash,
DotsThree,
DownloadSimple,
File as FileIcon,
Play,
Image as ImageIcon,
Lock,
AlertTriangle,
} from 'lucide-svelte';
Warning,
} from '@manacore/shared-icons';
interface Props {
message: SimpleMessage;
@ -141,7 +141,7 @@
<div
class="mb-1 flex items-center gap-2 rounded border-l-2 border-primary/50 bg-muted px-2 py-1 text-sm"
>
<Reply class="h-3 w-3 flex-shrink-0 text-muted-foreground" />
<ArrowBendUpLeft class="h-3 w-3 flex-shrink-0 text-muted-foreground" />
<span class="truncate text-muted-foreground">{message.replyToBody}</span>
</div>
{/if}
@ -153,7 +153,7 @@
{:else if isDecryptionError}
<!-- Decryption error -->
<div class="flex items-center gap-2 rounded-lg bg-warning/10 px-3 py-2 text-warning">
<AlertTriangle class="h-4 w-4 flex-shrink-0" />
<Warning class="h-4 w-4 flex-shrink-0" />
<span class="text-sm">
Nachricht kann nicht entschlüsselt werden. Möglicherweise fehlen Schlüssel.
</span>
@ -224,7 +224,7 @@
{/if}
</p>
</div>
<Download class="h-5 w-5 flex-shrink-0 text-muted-foreground" />
<DownloadSimple class="h-5 w-5 flex-shrink-0 text-muted-foreground" />
</a>
{:else if message.type === 'm.emote'}
<p class="italic text-muted-foreground">* {message.senderName} {message.body}</p>
@ -251,16 +251,16 @@
class="absolute -top-2 right-2 flex items-center gap-1 rounded-lg border border-border bg-surface p-1 shadow-sm"
>
<button class="btn-ghost rounded p-1" title="Antworten" onclick={() => onReply?.(message)}>
<Reply class="h-4 w-4" />
<ArrowBendUpLeft class="h-4 w-4" />
</button>
{#if message.isOwn && message.type === 'm.text'}
<button class="btn-ghost rounded p-1" title="Bearbeiten" onclick={() => onEdit?.(message)}>
<Pencil class="h-4 w-4" />
<PencilSimple class="h-4 w-4" />
</button>
{/if}
{#if message.isOwn}
<button class="btn-ghost rounded p-1 text-error" title="Löschen" onclick={handleDelete}>
<Trash2 class="h-4 w-4" />
<Trash class="h-4 w-4" />
</button>
{/if}
</div>

View file

@ -1,6 +1,14 @@
<script lang="ts">
import { matrixStore, type SimpleMessage } from '$lib/matrix';
import { Send, Paperclip, Smile, X, Image, File, Loader2 } from 'lucide-svelte';
import {
PaperPlaneTilt,
Paperclip,
Smiley,
X,
Image,
File,
CircleNotch,
} from '@manacore/shared-icons';
interface Props {
replyTo?: SimpleMessage | null;
@ -163,7 +171,7 @@
<!-- Upload Progress -->
{#if uploading}
<div class="flex items-center gap-3 px-4 py-2">
<Loader2 class="h-5 w-5 animate-spin text-primary" />
<CircleNotch class="h-5 w-5 animate-spin text-primary" />
<div class="flex-1">
<div class="h-2 overflow-hidden rounded-full bg-base-300">
<div
@ -242,7 +250,7 @@
title="Emoji hinzufügen"
disabled
>
<Smile class="h-5 w-5" />
<Smiley class="h-5 w-5" />
</button>
</div>
@ -253,7 +261,7 @@
disabled={!message.trim() || uploading}
title={editMessage ? 'Speichern' : 'Senden'}
>
<Send class="h-5 w-5" />
<PaperPlaneTilt class="h-5 w-5" />
</button>
</div>

View file

@ -1,15 +1,15 @@
<script lang="ts">
import { matrixStore } from '$lib/matrix';
import {
Menu,
List,
Phone,
Video,
VideoCamera,
Info,
LockOpen,
ShieldCheck,
ShieldAlert,
ShieldWarning,
Users,
} from 'lucide-svelte';
} from '@manacore/shared-icons';
interface Props {
onMenuClick?: () => void;
@ -44,7 +44,7 @@
<header class="flex items-center gap-3 border-b border-border bg-surface px-4 py-3">
<!-- Mobile menu button -->
<button class="btn-ghost rounded p-2 lg:hidden" onclick={onMenuClick}>
<Menu class="h-5 w-5" />
<List class="h-5 w-5" />
</button>
<!-- Room avatar -->
@ -72,7 +72,7 @@
class="flex-shrink-0"
title="Verschlüsselt - {encryptionStatus.unverifiedDevices} unverifizierte Geräte"
>
<ShieldAlert class="h-4 w-4 text-warning" />
<ShieldWarning class="h-4 w-4 text-warning" />
</div>
{/if}
{:else}
@ -99,7 +99,7 @@
<Phone class="h-5 w-5" />
</button>
<button class="btn-ghost rounded p-2" title="Videoanruf" disabled>
<Video class="h-5 w-5" />
<VideoCamera class="h-5 w-5" />
</button>
<button class="btn-ghost rounded p-2" title="Rauminfo" onclick={onInfoClick}>
<Info class="h-5 w-5" />

View file

@ -2,7 +2,7 @@
import type { SimpleRoom } from '$lib/matrix';
import { formatDistanceToNow } from 'date-fns';
import { de } from 'date-fns/locale';
import { Lock, Users } from 'lucide-svelte';
import { Lock, Users } from '@manacore/shared-icons';
interface Props {
room: SimpleRoom;

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { matrixStore } from '$lib/matrix';
import RoomItem from './RoomItem.svelte';
import { Search, Plus, Users, MessageCircle } from 'lucide-svelte';
import { MagnifyingGlass, Plus, Users, ChatCircle } from '@manacore/shared-icons';
interface Props {
onCreateRoom?: () => void;
@ -23,7 +23,9 @@
<!-- Search -->
<div class="p-3">
<div class="relative">
<Search class="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-base-content/50" />
<MagnifyingGlass
class="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-base-content/50"
/>
<input
type="text"
bind:value={search}
@ -36,7 +38,7 @@
<!-- Tabs -->
<div class="tabs tabs-boxed mx-3 mb-2">
<button class="tab flex-1" class:tab-active={showDMs} onclick={() => (showDMs = true)}>
<MessageCircle class="mr-1 h-4 w-4" />
<ChatCircle class="mr-1 h-4 w-4" />
Direct
{#if matrixStore.directRooms.length > 0}
<span class="badge badge-sm ml-1">{matrixStore.directRooms.length}</span>
@ -62,10 +64,10 @@
{:else}
<div class="flex flex-col items-center justify-center p-8 text-base-content/50">
{#if search}
<Search class="mb-2 h-8 w-8" />
<MagnifyingGlass class="mb-2 h-8 w-8" />
<p>No rooms match "{search}"</p>
{:else}
<MessageCircle class="mb-2 h-8 w-8" />
<ChatCircle class="mb-2 h-8 w-8" />
<p>No {showDMs ? 'direct messages' : 'rooms'} yet</p>
{/if}
</div>

View file

@ -3,15 +3,15 @@
import {
X,
Users,
Settings,
Gear,
UserPlus,
LogOut,
SignOut,
Crown,
Shield,
Bell,
BellOff,
Loader2,
} from 'lucide-svelte';
BellSlash,
CircleNotch,
} from '@manacore/shared-icons';
interface Props {
open: boolean;
@ -79,7 +79,9 @@
{#if open && room}
<!-- Slide-in Panel -->
<div class="fixed inset-y-0 right-0 z-40 flex w-80 flex-col border-l border-base-300 bg-base-100 shadow-xl">
<div
class="fixed inset-y-0 right-0 z-40 flex w-80 flex-col border-l border-base-300 bg-base-100 shadow-xl"
>
<!-- Header -->
<header class="flex items-center justify-between border-b border-base-300 px-4 py-3">
<h2 class="font-semibold">Raum-Details</h2>
@ -126,7 +128,7 @@
class:tab-active={activeTab === 'settings'}
onclick={() => (activeTab = 'settings')}
>
<Settings class="mr-1 h-4 w-4" />
<Gear class="mr-1 h-4 w-4" />
Einstellungen
</button>
</div>
@ -145,7 +147,7 @@
placeholder="Benutzer einladen..."
/>
{#if searching}
<Loader2 class="absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin" />
<CircleNotch class="absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin" />
{/if}
</div>
@ -215,7 +217,7 @@
<!-- Leave Room -->
<button class="btn btn-ghost w-full justify-start text-error" onclick={leaveRoom}>
<LogOut class="h-4 w-4" />
<SignOut class="h-4 w-4" />
Raum verlassen
</button>
</div>

View file

@ -3,7 +3,7 @@
import Message from './Message.svelte';
import TypingIndicator from './TypingIndicator.svelte';
import { onMount, tick } from 'svelte';
import { Loader2, ArrowDown } from 'lucide-svelte';
import { CircleNotch, ArrowDown } from '@manacore/shared-icons';
interface Props {
onReply?: (message: SimpleMessage) => void;
@ -87,7 +87,7 @@
<!-- Loading indicator at top -->
{#if loadingMore}
<div class="flex justify-center py-4">
<Loader2 class="h-6 w-6 animate-spin text-base-content/50" />
<CircleNotch class="h-6 w-6 animate-spin text-base-content/50" />
</div>
{/if}

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { matrixStore } from '$lib/matrix';
import type { VerificationRequest, SasVerification } from '$lib/matrix/types';
import { Check, X, Loader2, ShieldCheck } from 'lucide-svelte';
import { Check, X, CircleNotch, ShieldCheck } from '@manacore/shared-icons';
interface Props {
request: VerificationRequest;
@ -82,7 +82,7 @@
<div class="space-y-6">
{#if phase === 'waiting'}
<div class="flex flex-col items-center gap-4 py-8">
<Loader2 class="h-12 w-12 animate-spin text-primary" />
<CircleNotch class="h-12 w-12 animate-spin text-primary" />
<p class="text-center text-muted-foreground">Warte auf Antwort vom anderen Gerät...</p>
<p class="text-sm text-muted-foreground/70">
Öffne die Verifizierungsanfrage auf deinem anderen Gerät.
@ -128,7 +128,7 @@
</div>
{:else if phase === 'confirming'}
<div class="flex flex-col items-center gap-4 py-8">
<Loader2 class="h-12 w-12 animate-spin text-primary" />
<CircleNotch class="h-12 w-12 animate-spin text-primary" />
<p class="text-center text-muted-foreground">Bestätige Verifizierung...</p>
</div>
{:else if phase === 'done'}

View file

@ -4,13 +4,13 @@
import {
X,
Key,
Download,
DownloadSimple,
Copy,
Check,
Loader2,
AlertTriangle,
CircleNotch,
Warning,
ShieldCheck,
} from 'lucide-svelte';
} from '@manacore/shared-icons';
interface Props {
open: boolean;
@ -185,7 +185,7 @@
</p>
<div class="flex items-start gap-3 rounded-lg bg-warning/10 p-3 text-warning">
<AlertTriangle class="h-5 w-5 flex-shrink-0 mt-0.5" />
<Warning class="h-5 w-5 flex-shrink-0 mt-0.5" />
<span class="text-sm">
Ohne Recovery Key verlierst du den Zugriff auf deine verschlüsselten Nachrichten,
wenn du dich abmeldest.
@ -267,7 +267,7 @@
{:else if step === 'show-key'}
<div class="space-y-4">
<div class="flex items-start gap-3 rounded-lg bg-warning/10 p-3 text-warning">
<AlertTriangle class="h-5 w-5 flex-shrink-0 mt-0.5" />
<Warning class="h-5 w-5 flex-shrink-0 mt-0.5" />
<span class="text-sm">
Speichere diesen Schlüssel an einem sicheren Ort. Du benötigst ihn, um deine
Nachrichten wiederherzustellen.
@ -298,7 +298,7 @@
class="btn-secondary flex-1 flex items-center justify-center gap-2"
onclick={downloadKey}
>
<Download class="h-4 w-4" />
<DownloadSimple class="h-4 w-4" />
Herunterladen
</button>
</div>
@ -333,7 +333,7 @@
disabled={loading}
>
{#if loading}
<Loader2 class="h-4 w-4 animate-spin" />
<CircleNotch class="h-4 w-4 animate-spin" />
{/if}
Weiter
</button>
@ -344,7 +344,7 @@
disabled={loading || !inputRecoveryKey.trim()}
>
{#if loading}
<Loader2 class="h-4 w-4 animate-spin" />
<CircleNotch class="h-4 w-4 animate-spin" />
{/if}
Wiederherstellen
</button>
@ -357,7 +357,7 @@
disabled={loading || !passphrase || passphrase !== passphraseConfirm}
>
{#if loading}
<Loader2 class="h-4 w-4 animate-spin" />
<CircleNotch class="h-4 w-4 animate-spin" />
{/if}
Schlüssel erstellen
</button>

View file

@ -6,12 +6,12 @@
X,
Shield,
ShieldCheck,
ShieldAlert,
Smartphone,
ShieldWarning,
DeviceMobile,
Monitor,
Loader2,
RefreshCw,
} from 'lucide-svelte';
CircleNotch,
ArrowsClockwise,
} from '@manacore/shared-icons';
import EmojiVerification from './EmojiVerification.svelte';
interface Props {
@ -98,7 +98,7 @@
name.includes('android') ||
name.includes('ios')
) {
return Smartphone;
return DeviceMobile;
}
return Monitor;
}
@ -151,7 +151,7 @@
{#if loading}
<div class="flex justify-center py-8">
<Loader2 class="h-8 w-8 animate-spin text-primary" />
<CircleNotch class="h-8 w-8 animate-spin text-primary" />
</div>
{:else if devices.length === 0}
<div class="py-8 text-center text-muted-foreground">
@ -175,12 +175,12 @@
{:else if device.blocked}
<div class="relative">
<DeviceIcon class="h-10 w-10 text-muted-foreground" />
<ShieldAlert class="absolute -right-1 -bottom-1 h-5 w-5 text-error" />
<ShieldWarning class="absolute -right-1 -bottom-1 h-5 w-5 text-error" />
</div>
{:else}
<div class="relative">
<DeviceIcon class="h-10 w-10 text-muted-foreground" />
<ShieldAlert class="absolute -right-1 -bottom-1 h-5 w-5 text-warning" />
<ShieldWarning class="absolute -right-1 -bottom-1 h-5 w-5 text-warning" />
</div>
{/if}
</div>
@ -225,7 +225,7 @@
onclick={loadDevices}
disabled={loading}
>
<RefreshCw class={`h-4 w-4 ${loading ? 'animate-spin' : ''}`} />
<ArrowsClockwise class={`h-4 w-4 ${loading ? 'animate-spin' : ''}`} />
Aktualisieren
</button>
</div>

View file

@ -3,7 +3,7 @@
import { goto } from '$app/navigation';
import { onMount, onDestroy } from 'svelte';
import type { Snippet } from 'svelte';
import { Loader2, AlertCircle, RefreshCw } from 'lucide-svelte';
import { CircleNotch, WarningCircle, ArrowsClockwise } from '@manacore/shared-icons';
interface Props {
children: Snippet;
@ -60,7 +60,7 @@
{#if loading}
<!-- Loading State -->
<div class="flex h-screen flex-col items-center justify-center gap-4">
<Loader2 class="h-12 w-12 animate-spin text-primary" />
<CircleNotch class="h-12 w-12 animate-spin text-primary" />
<div class="text-center">
<p class="font-medium">Connecting to Matrix...</p>
<p class="text-sm text-base-content/60">
@ -80,7 +80,7 @@
<!-- Error State -->
<div class="flex h-screen flex-col items-center justify-center gap-4 p-4">
<div class="rounded-full bg-error/10 p-4">
<AlertCircle class="h-12 w-12 text-error" />
<WarningCircle class="h-12 w-12 text-error" />
</div>
<div class="text-center">
<h2 class="text-xl font-semibold">Connection Failed</h2>
@ -88,7 +88,7 @@
</div>
<div class="flex gap-2">
<button class="btn btn-primary" onclick={retry}>
<RefreshCw class="h-4 w-4" />
<ArrowsClockwise class="h-4 w-4" />
Retry
</button>
<button class="btn btn-ghost" onclick={logout}> Sign Out </button>

View file

@ -4,7 +4,7 @@
import CreateRoomDialog from '$lib/components/chat/CreateRoomDialog.svelte';
import RoomSettingsPanel from '$lib/components/chat/RoomSettingsPanel.svelte';
import { goto } from '$app/navigation';
import { Settings, LogOut, MessageSquare, Plus } from 'lucide-svelte';
import { Gear, SignOut, ChatCircle, Plus } from '@manacore/shared-icons';
let sidebarOpen = $state(true);
let showCreateRoom = $state(false);
@ -48,7 +48,7 @@
<!-- Sidebar Header -->
<header class="flex items-center justify-between border-b border-base-300 p-4">
<div class="flex items-center gap-2">
<MessageSquare class="h-6 w-6 text-primary" />
<ChatCircle class="h-6 w-6 text-primary" />
<h1 class="text-xl font-bold">Mana Matrix</h1>
</div>
<div class="flex items-center gap-1">
@ -61,7 +61,7 @@
</button>
<div class="dropdown dropdown-end">
<button tabindex="0" class="btn btn-ghost btn-sm btn-circle">
<Settings class="h-5 w-5" />
<Gear class="h-5 w-5" />
</button>
<ul
tabindex="0"
@ -69,13 +69,13 @@
>
<li>
<a href="/settings">
<Settings class="h-4 w-4" />
<Gear class="h-4 w-4" />
Einstellungen
</a>
</li>
<li>
<button onclick={handleLogout} class="text-error">
<LogOut class="h-4 w-4" />
<SignOut class="h-4 w-4" />
Abmelden
</button>
</li>
@ -121,7 +121,7 @@
{:else}
<!-- No Room Selected -->
<div class="flex flex-1 flex-col items-center justify-center gap-4 p-8 text-base-content/50">
<MessageSquare class="h-16 w-16" />
<ChatCircle class="h-16 w-16" />
<div class="text-center">
<h2 class="text-xl font-semibold text-base-content">Willkommen bei Mana Matrix</h2>
<p class="mt-2">

View file

@ -7,14 +7,14 @@
Bell,
Palette,
Shield,
LogOut,
Server,
SignOut,
HardDrive,
ShieldCheck,
ShieldAlert,
ShieldWarning,
Key,
Smartphone,
Loader2,
} from 'lucide-svelte';
DeviceMobile,
CircleNotch,
} from '@manacore/shared-icons';
import { VerificationDialog, RecoveryKeyDialog } from '$lib/components/crypto';
let verificationDialogOpen = $state(false);
@ -77,7 +77,7 @@
<section class="card">
<div class="space-y-4">
<h2 class="flex items-center gap-2 text-lg font-semibold">
<Server class="h-5 w-5" />
<HardDrive class="h-5 w-5" />
Server
</h2>
<div class="space-y-2 text-sm">
@ -109,7 +109,7 @@
{#if !cryptoReady}
<div class="flex items-center gap-3 text-warning">
<Loader2 class="h-5 w-5 animate-spin" />
<CircleNotch class="h-5 w-5 animate-spin" />
<span>Verschlüsselung wird initialisiert...</span>
</div>
{:else}
@ -120,7 +120,7 @@
{#if verificationStatus === 'verified'}
<ShieldCheck class="h-8 w-8 text-success" />
{:else}
<ShieldAlert class="h-8 w-8 text-warning" />
<ShieldWarning class="h-8 w-8 text-warning" />
{/if}
<div>
<p class="font-medium">
@ -137,7 +137,7 @@
class="btn-primary flex items-center gap-2 text-sm"
onclick={() => (verificationDialogOpen = true)}
>
<Smartphone class="h-4 w-4" />
<DeviceMobile class="h-4 w-4" />
Geräte
</button>
</div>
@ -208,7 +208,7 @@
class="flex w-full items-center justify-center gap-2 rounded-lg bg-error p-3 text-white hover:brightness-90"
onclick={handleLogout}
>
<LogOut class="h-5 w-5" />
<SignOut class="h-5 w-5" />
Abmelden
</button>
</section>

View file

@ -2,7 +2,16 @@
import { goto } from '$app/navigation';
import { browser } from '$app/environment';
import { loginWithPassword, discoverHomeserver, checkHomeserver, matrixStore } from '$lib/matrix';
import { Eye, EyeOff, Loader2, Server, User, Lock, AlertCircle, LogIn } from 'lucide-svelte';
import {
Eye,
EyeSlash,
CircleNotch,
HardDrive,
User,
Lock,
WarningCircle,
SignIn,
} from '@manacore/shared-icons';
// Form state
let homeserver = $state('matrix.mana.how');
@ -100,7 +109,7 @@
<!-- Error Alert -->
{#if error}
<div class="alert alert-error mb-4">
<AlertCircle class="h-5 w-5" />
<WarningCircle class="h-5 w-5" />
<span>{error}</span>
</div>
{/if}
@ -111,12 +120,12 @@
<div class="form-control">
<label class="label" for="homeserver">
<span class="label-text flex items-center gap-2">
<Server class="h-4 w-4" />
<HardDrive class="h-4 w-4" />
Homeserver
</span>
{#if checkingServer}
<span class="label-text-alt">
<Loader2 class="h-4 w-4 animate-spin" />
<CircleNotch class="h-4 w-4 animate-spin" />
</span>
{:else if serverValid === true}
<span class="label-text-alt text-success">Connected</span>
@ -182,7 +191,7 @@
tabindex={-1}
>
{#if showPassword}
<EyeOff class="h-5 w-5" />
<EyeSlash class="h-5 w-5" />
{:else}
<Eye class="h-5 w-5" />
{/if}
@ -193,7 +202,7 @@
<!-- Submit Button -->
<button type="submit" class="btn btn-primary w-full" disabled={loading}>
{#if loading}
<Loader2 class="h-5 w-5 animate-spin" />
<CircleNotch class="h-5 w-5 animate-spin" />
Signing in...
{:else}
Sign In
@ -212,10 +221,10 @@
disabled={loadingSSO}
>
{#if loadingSSO}
<Loader2 class="h-5 w-5 animate-spin" />
<CircleNotch class="h-5 w-5 animate-spin" />
Redirecting...
{:else}
<LogIn class="h-5 w-5" />
<SignIn class="h-5 w-5" />
Sign in with Mana Core
{/if}
</button>

View file

@ -3,7 +3,7 @@
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { matrixStore } from '$lib/matrix';
import { Loader2 } from 'lucide-svelte';
import { CircleNotch } from '@manacore/shared-icons';
let checking = $state(true);
@ -27,7 +27,7 @@
<div class="flex h-screen items-center justify-center">
<div class="text-center">
<Loader2 class="mx-auto h-8 w-8 animate-spin text-primary" />
<CircleNotch class="mx-auto h-8 w-8 animate-spin text-primary" />
<p class="mt-4 text-base-content/60">Loading...</p>
</div>
</div>