🎨 refactor(shared-ui): improve LoginPage and InputBar components

This commit is contained in:
Till-JS 2026-02-13 23:29:56 +01:00
parent ceebb5dda6
commit 9bfc20b8d5
3 changed files with 37 additions and 4 deletions

View file

@ -119,11 +119,18 @@
const t = $derived({ ...defaultTranslations, ...translations }); const t = $derived({ ...defaultTranslations, ...translations });
// Check if we're in development mode (early for state init)
const isDevMode = typeof import.meta !== 'undefined' && import.meta.env?.DEV;
// Local dev credentials (run `pnpm db:seed:dev` in mana-core-auth to create this user)
const DEV_EMAIL = 'dev@manacore.local';
const DEV_PASSWORD = 'devpassword123';
let loading = $state(false); let loading = $state(false);
let error = $state<string | null>(null); let error = $state<string | null>(null);
let errorField = $state<'email' | 'password' | 'general' | null>(null); let errorField = $state<'email' | 'password' | 'general' | null>(null);
let email = $state(initialEmail); // In dev mode, pre-fill with test credentials
let password = $state(initialPassword); let email = $state(initialEmail || (isDevMode ? DEV_EMAIL : ''));
let password = $state(initialPassword || (isDevMode ? DEV_PASSWORD : ''));
let showPassword = $state(false); let showPassword = $state(false);
let rememberMe = $state(false); let rememberMe = $state(false);
let showSuccess = $state(false); let showSuccess = $state(false);
@ -278,8 +285,8 @@
} }
function fillDevCredentials() { function fillDevCredentials() {
email = 't@t.de'; email = DEV_EMAIL;
password = 'testtesttest'; password = DEV_PASSWORD;
} }
</script> </script>

View file

@ -57,6 +57,8 @@
User, User,
Scales, Scales,
Robot, Robot,
Key,
Shield,
} from '@manacore/shared-icons'; } from '@manacore/shared-icons';
// Map icon names to Phosphor components // Map icon names to Phosphor components
@ -109,6 +111,8 @@
building: Buildings, building: Buildings,
scale: Scales, scale: Scales,
robot: Robot, robot: Robot,
key: Key,
shield: Shield,
}; };
// Convert app items to dropdown items (will be computed as derived) // Convert app items to dropdown items (will be computed as derived)
@ -476,6 +480,9 @@
'M18 8a3 3 0 100-6 3 3 0 000 6zM6 15a3 3 0 100-6 3 3 0 000 6zM18 22a3 3 0 100-6 3 3 0 000 6zM8.59 13.51l6.83 3.98M15.41 6.51l-6.82 3.98', 'M18 8a3 3 0 100-6 3 3 0 000 6zM6 15a3 3 0 100-6 3 3 0 000 6zM18 22a3 3 0 100-6 3 3 0 000 6zM8.59 13.51l6.83 3.98M15.41 6.51l-6.82 3.98',
filter: filter:
'M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z', 'M3 4a1 1 0 011-1h16a1 1 0 011 1v2.586a1 1 0 01-.293.707l-6.414 6.414a1 1 0 00-.293.707V17l-4 4v-6.586a1 1 0 00-.293-.707L3.293 7.293A1 1 0 013 6.586V4z',
key: 'M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z',
shield:
'M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z',
}; };
function getIconPath(name: string): string { function getIconPath(name: string): string {

View file

@ -54,6 +54,8 @@
label: string; label: string;
} }
import type { Snippet } from 'svelte';
interface Props { interface Props {
onSearch: (query: string) => Promise<QuickInputItem[]>; onSearch: (query: string) => Promise<QuickInputItem[]>;
onSelect: (item: QuickInputItem) => void; onSelect: (item: QuickInputItem) => void;
@ -85,6 +87,8 @@
onShowShortcuts?: () => void; onShowShortcuts?: () => void;
/** Callback to show syntax help */ /** Callback to show syntax help */
onShowSyntaxHelp?: () => void; onShowSyntaxHelp?: () => void;
/** Snippet for left action button (e.g., voice input) - rendered inside the input bar on the left */
leftAction?: Snippet;
} }
let { let {
@ -108,6 +112,7 @@
onDefaultChange, onDefaultChange,
onShowShortcuts, onShowShortcuts,
onShowSyntaxHelp, onShowSyntaxHelp,
leftAction,
}: Props = $props(); }: Props = $props();
// Use settings for autoFocus // Use settings for autoFocus
@ -423,6 +428,13 @@
<!-- Input Bar (always visible) --> <!-- Input Bar (always visible) -->
<!-- svelte-ignore a11y_no_static_element_interactions --> <!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="input-container" oncontextmenu={handleContextMenu}> <div class="input-container" oncontextmenu={handleContextMenu}>
<!-- Left action slot (e.g., voice input button) -->
{#if leftAction}
<div class="left-action">
{@render leftAction()}
</div>
{/if}
<div class="app-icon"> <div class="app-icon">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"> <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
{#if appIcon === 'check-square' || appIcon === 'todo'} {#if appIcon === 'check-square' || appIcon === 'todo'}
@ -576,6 +588,13 @@
0 0 0 2px hsl(var(--color-primary) / 0.25); 0 0 0 2px hsl(var(--color-primary) / 0.25);
} }
.left-action {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.app-icon { .app-icon {
width: 1.25rem; width: 1.25rem;
height: 1.25rem; height: 1.25rem;