···11<script lang="ts">
22 import { listen } from '@tauri-apps/api/event';
33 import { onMount } from 'svelte';
44+ import ModeSelectScreen from '$lib/components/onboarding/ModeSelectScreen.svelte';
45 import RelayConfigScreen from '$lib/components/onboarding/RelayConfigScreen.svelte';
56 import WelcomeScreen from '$lib/components/onboarding/WelcomeScreen.svelte';
67 import ClaimCodeScreen from '$lib/components/onboarding/ClaimCodeScreen.svelte';
···1617 import HomeScreen from '$lib/components/home/HomeScreen.svelte';
1718 import DIDDocumentScreen from '$lib/components/home/DIDDocumentScreen.svelte';
1819 import RecoveryInfoScreen from '$lib/components/home/RecoveryInfoScreen.svelte';
1919- import { createAccount, getRelayUrl, type CreateAccountError, type OAuthError, type HomeData } from '$lib/ipc';
2020+ import { createAccount, getRelayUrl, listIdentities, type CreateAccountError, type OAuthError, type HomeData } from '$lib/ipc';
20212122 // ── Onboarding step type ─────────────────────────────────────────────────
2223 //
···2930 // instead of navigating through an extra modal. No 'error' step is needed.
30313132 type OnboardingStep =
3333+ | 'mode_select'
3234 | 'relay_config'
3335 | 'welcome'
3436 | 'claim_code'
···4547 | 'home'
4648 | 'did_document'
4749 | 'recovery_info'
4848- | 'auth_failed';
5050+ | 'auth_failed'
5151+ | 'identity_input'
5252+ | 'pds_auth'
5353+ | 'email_verification'
5454+ | 'review_operation'
5555+ | 'claim_success';
49565057 // ── State ────────────────────────────────────────────────────────────────
51585252- let step = $state<OnboardingStep>('relay_config');
5959+ let step = $state<OnboardingStep>('mode_select');
5360 let form = $state({ claimCode: '', email: '', handle: '', password: '', did: '', share3: '', registeredHandle: '' });
54615562 /**
···7481 // ── Relay configuration and OAuth event listener ──────────────────────
75827683 onMount(async () => {
7777- // If the user has already configured a relay URL, skip the config screen.
7878- const savedUrl = await getRelayUrl();
7979- if (savedUrl) {
8080- step = 'welcome';
8484+ // If the user has claimed identities, skip to home.
8585+ try {
8686+ const identities = await listIdentities();
8787+ if (identities.length > 0) {
8888+ step = 'home';
8989+ return;
9090+ }
9191+ } catch {
9292+ // listIdentities failed (e.g. empty Keychain on first launch) — continue to mode_select
8193 }
82948383- // Existing: listen for auth_ready deep-link callback from the OAuth flow.
9595+ // Legacy user fallback: if a relay URL is already configured (from the old
9696+ // single-identity flow before multi-identity), the user has used the app before
9797+ // but has no managed-dids entry. Skip relay_config but still show mode_select
9898+ // so they can choose create vs. import. Without this, legacy users would see
9999+ // mode_select and then relay_config (asking them to configure a relay they
100100+ // already configured).
101101+ // Note: mode_select is already the default step, so this is a no-op for
102102+ // mode_select itself, but it prevents the "Create new identity" path from
103103+ // redundantly showing relay_config when the relay is already configured.
104104+ // The relay_config screen itself already checks getRelayUrl() internally.
105105+106106+ // Listen for auth_ready from relay OAuth (existing onboarding flow).
84107 listen('auth_ready', () => {
85108 goTo('home');
86109 });
···159182</script>
160183161184<div class="app">
162162- {#if step === 'relay_config'}
185185+ {#if step === 'mode_select'}
186186+ <ModeSelectScreen
187187+ oncreate={() => goTo('relay_config')}
188188+ onimport={() => goTo('identity_input')}
189189+ />
190190+ {:else if step === 'relay_config'}
163191 <RelayConfigScreen onnext={() => goTo('welcome')} />
164192 {:else if step === 'welcome'}
165193 <WelcomeScreen onstart={() => goTo('claim_code')} />