e.key === 'Escape' && closeUserDetail()} role="presentation">
+
e.key === 'Escape' && closeUserDetail()} role="presentation">
e.stopPropagation()} onkeydown={(e) => e.stopPropagation()} role="dialog" aria-modal="true" tabindex="-1">
- {$_('delegation.did')}
- {account.did}
+ {$_('delegation.did')}
+ {account.did}
- {$_('delegation.granted')}
- {formatDateTime(account.grantedAt)}
+ {$_('delegation.granted')}
+ {formatDateTime(account.grantedAt)}
@@ -601,19 +601,19 @@
- {$_('delegation.actor')}
- {entry.actorDid}
+ {$_('delegation.actor')}
+ {entry.actorDid}
{#if entry.delegatedDid}
- {$_('delegation.target')}
- {entry.delegatedDid}
+ {$_('delegation.target')}
+ {entry.delegatedDid}
{/if}
{#if entry.actionDetails}
- {$_('delegation.details')}
- {formatActionDetails(entry.actionDetails)}
+ {$_('delegation.details')}
+ {formatActionDetails(entry.actionDetails)}
{/if}
diff --git a/frontend/src/components/dashboard/MigrationContent.svelte b/frontend/src/components/dashboard/MigrationContent.svelte
deleted file mode 100644
index 44f76f3..0000000
--- a/frontend/src/components/dashboard/MigrationContent.svelte
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
- {$_('migration.migrateHere')}
- {$_('migration.migrateHereDesc')}
-
- - {$_('migration.bringDid')}
- - {$_('migration.transferData')}
- - {$_('migration.keepFollowers')}
-
-
-
-
-
- {$_('migration.offlineRestore')}
- {$_('migration.offlineRestoreDesc')}
-
- - {$_('migration.offlineFeature1')}
- - {$_('migration.offlineFeature2')}
- - {$_('migration.offlineFeature3')}
-
-
-
-
- {#if session.accountKind === 'migrated'}
-
- {$_('dashboard.migratedTitle')}
- {$_('dashboard.migratedMessage', { values: { pds: session.migratedToPds || 'another PDS' } })}
-
- {/if}
-
diff --git a/frontend/src/components/dashboard/PasskeySection.svelte b/frontend/src/components/dashboard/PasskeySection.svelte
new file mode 100644
index 0000000..1cde80d
--- /dev/null
+++ b/frontend/src/components/dashboard/PasskeySection.svelte
@@ -0,0 +1,166 @@
+
+
+
diff --git a/frontend/src/components/dashboard/PasswordSection.svelte b/frontend/src/components/dashboard/PasswordSection.svelte
new file mode 100644
index 0000000..ee27a54
--- /dev/null
+++ b/frontend/src/components/dashboard/PasswordSection.svelte
@@ -0,0 +1,265 @@
+
+
+
+ {$_('security.password')}
+ {#if !loading}
+ {#if hasPassword}
+ {$_('security.passwordStatus')}
+
+ {#if !showChangePasswordForm && !showRemovePasswordForm}
+
+
+ {#if passkeyCount > 0}
+
+ {/if}
+
+ {/if}
+
+ {#if showChangePasswordForm}
+
+ {/if}
+
+ {#if showRemovePasswordForm}
+
+ {/if}
+ {:else}
+ {$_('security.noPassword')}
+
+ {#if !showSetPasswordForm}
+
+ {:else}
+
+ {/if}
+ {/if}
+ {/if}
+
diff --git a/frontend/src/components/dashboard/SessionsContent.svelte b/frontend/src/components/dashboard/SessionsContent.svelte
index 82691ba..617126e 100644
--- a/frontend/src/components/dashboard/SessionsContent.svelte
+++ b/frontend/src/components/dashboard/SessionsContent.svelte
@@ -116,12 +116,12 @@
- {$_('sessions.created')}
- {timeAgo(s.createdAt)}
+ {$_('sessions.created')}
+ {timeAgo(s.createdAt)}
- {$_('sessions.expires')}
- {formatDate(s.expiresAt)}
+ {$_('sessions.expires')}
+ {formatDate(s.expiresAt)}
diff --git a/frontend/src/components/dashboard/TotpSection.svelte b/frontend/src/components/dashboard/TotpSection.svelte
new file mode 100644
index 0000000..7bf9036
--- /dev/null
+++ b/frontend/src/components/dashboard/TotpSection.svelte
@@ -0,0 +1,279 @@
+
+
+
+ {$_('security.totp')}
+
+ {#if totpSetup.step === 'idle'}
+ {#if totpEnabled}
+ {$_('security.totpEnabled')}
+
+ {#if !showDisableForm && !showRegenForm}
+
+
+
+
+ {/if}
+
+ {#if showRegenForm}
+
+ {/if}
+
+ {#if showDisableForm}
+
+ {/if}
+ {:else}
+ {$_('security.totpDisabled')}
+
+ {/if}
+ {:else if totpSetup.step === 'qr'}
+ {@const qrData = totpSetup as TotpQr}
+
+
{$_('security.totpSetupInstructions')}
+
+

+
+
+ {$_('security.cantScan')}
+ {qrData.totpUri.split('secret=')[1]?.split('&')[0] || ''}
+
+
+
+ {:else if totpSetup.step === 'verify'}
+ {@const verifyData = totpSetup}
+
+
{$_('security.totpCodePlaceholder')}
+
+
+ {:else if totpSetup.step === 'backup'}
+
+
{$_('security.backupCodes')}
+
{$_('security.backupCodesDescription')}
+
+ {#each totpSetup.backupCodes as code}
+ {code}
+ {/each}
+
+
+
+
+
+
+ {/if}
+
diff --git a/frontend/src/styles/dashboard.css b/frontend/src/styles/dashboard.css
index 0370584..c4eb8cc 100644
--- a/frontend/src/styles/dashboard.css
+++ b/frontend/src/styles/dashboard.css
@@ -279,13 +279,19 @@ button.dropdown-item.logout-item {
display: flex;
align-items: center;
gap: var(--space-1);
- padding: 0;
+ padding: var(--space-2) var(--space-3);
background: transparent;
border: none;
- color: var(--secondary);
+ color: var(--text-secondary);
font-size: var(--text-base);
cursor: pointer;
margin-bottom: var(--space-2);
+ min-height: 44px;
+}
+
+.back-button:hover:not(:disabled) {
+ background: var(--bg-secondary);
+ color: var(--text-primary);
}
.back-arrow {
@@ -376,11 +382,6 @@ button.dropdown-item.logout-item {
}
}
-.overview {
- background: var(--bg-secondary);
- padding: var(--space-6);
-}
-
.overview dl {
display: grid;
grid-template-columns: auto 1fr;
@@ -429,7 +430,6 @@ button.dropdown-item.logout-item {
}
}
-
.current {
color: var(--text-secondary);
font-size: var(--text-sm);
@@ -607,7 +607,10 @@ code.record {
}
.password-actions,
-.totp-actions,
+.totp-actions {
+ display: flex;
+ gap: var(--space-3);
+}
.remove-password-form {
background: var(--error-bg);
@@ -949,12 +952,12 @@ code.record {
font-size: var(--text-sm);
}
-.sessions .detail .label {
+.detail-label {
color: var(--text-secondary);
margin-right: var(--space-2);
}
-.sessions .detail .value {
+.detail-value {
color: var(--text-primary);
}
@@ -1688,16 +1691,7 @@ button.record-item:hover {
font-size: var(--text-sm);
}
-.controllers .detail .label {
- color: var(--text-secondary);
- margin-right: var(--space-2);
-}
-
-.controllers .detail .value {
- color: var(--text-primary);
-}
-
-.controllers .detail .value.did {
+.detail-value-did {
font-family: var(--font-mono);
font-size: var(--text-xs);
word-break: break-all;
@@ -2092,8 +2086,6 @@ button.typeahead-item:hover {
gap: var(--space-3);
}
-
-
.item-id {
font-weight: var(--font-medium);
font-family: var(--font-mono);
@@ -2174,12 +2166,6 @@ button.typeahead-item:hover {
font-size: var(--text-base);
}
-.feature-list {
- list-style: none;
- padding: 0;
- margin: 0 0 var(--space-4) 0;
-}
-
.feature-list li {
padding: var(--space-2) 0;
padding-left: var(--space-4);
@@ -2263,6 +2249,7 @@ button.typeahead-item:hover {
}
button.user-item-btn:hover {
+ background: var(--bg-secondary);
border-color: var(--secondary);
}
@@ -2406,7 +2393,7 @@ button.remove-logo:hover {
margin-bottom: var(--space-5);
}
-.admin .definition-list .mono {
+.definition-mono {
font-family: var(--font-mono);
font-size: var(--text-xs);
word-break: break-all;