feat(setup-wizard): improve E2EE dialog UX and password field

- Only show the passphrase and "Obfuscate Properties" controls once
  end-to-end encryption is enabled, instead of leaving them visible
  but disabled.
- Replace the password show/hide checkbox with an icon toggle button.
- Let translated labels wrap to their content instead of being
  clipped into a fixed-width column (this clipped longer translated
  labels, e.g. in German and Spanish).
- Scope the onboarding invitation link's 44px touch-target padding to
  mobile, so on desktop it renders as a normal inline link instead of
  a stray, oddly-padded button.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Zeedif
2026-08-23 20:23:50 -06:00
co-authored by Claude Sonnet 5
parent 694371898a
commit 6b37ea8778
9 changed files with 108 additions and 25 deletions
@@ -2530,6 +2530,10 @@ export const allMessages: Readonly<Record<string, Readonly<Record<string, string
ko: "해당 없는 항목 숨기기", ko: "해당 없는 항목 숨기기",
"zh-tw": "隱藏不適用的項目", "zh-tw": "隱藏不適用的項目",
}, },
"Hide password": {
def: "Hide password",
es: "Ocultar contraseña",
},
"Higher (${local} > ${remote})": { "Higher (${local} > ${remote})": {
def: "Higher (${local} > ${remote})", def: "Higher (${local} > ${remote})",
es: "Superior (${local} > ${remote})", es: "Superior (${local} > ${remote})",
@@ -9570,6 +9574,10 @@ export const allMessages: Readonly<Record<string, Readonly<Record<string, string
zh: "仅显示通知", zh: "仅显示通知",
"zh-tw": "僅顯示通知", "zh-tw": "僅顯示通知",
}, },
"Show password": {
def: "Show password",
es: "Mostrar contraseña",
},
"Show status as icons only": { "Show status as icons only": {
def: "Show status as icons only", def: "Show status as icons only",
es: "Mostrar estado solo con íconos", es: "Mostrar estado solo con íconos",
+2
View File
@@ -303,6 +303,7 @@
"Hidden Files": "Hidden Files", "Hidden Files": "Hidden Files",
"Hide completely": "Hide completely", "Hide completely": "Hide completely",
"Hide not applicable items": "Hide not applicable items", "Hide not applicable items": "Hide not applicable items",
"Hide password": "Hide password",
"Higher (${local} > ${remote})": "Higher (${local} > ${remote})", "Higher (${local} > ${remote})": "Higher (${local} > ${remote})",
"Highlight diff": "Highlight diff", "Highlight diff": "Highlight diff",
"How to display network errors when the sync server is unreachable.": "How to display network errors when the sync server is unreachable.", "How to display network errors when the sync server is unreachable.": "How to display network errors when the sync server is unreachable.",
@@ -1028,6 +1029,7 @@
"Show history": "Show history", "Show history": "Show history",
"Show icon only": "Show icon only", "Show icon only": "Show icon only",
"Show only notifications": "Show only notifications", "Show only notifications": "Show only notifications",
"Show password": "Show password",
"Show status as icons only": "Show status as icons only", "Show status as icons only": "Show status as icons only",
"Show status icon instead of file warnings banner": "Show status icon instead of file warnings banner", "Show status icon instead of file warnings banner": "Show status icon instead of file warnings banner",
"Show status inside the editor": "Show status inside the editor", "Show status inside the editor": "Show status inside the editor",
+2
View File
@@ -304,6 +304,7 @@
"Hidden Files": "Archivos ocultos", "Hidden Files": "Archivos ocultos",
"Hide completely": "Ocultar por completo", "Hide completely": "Ocultar por completo",
"Hide not applicable items": "Ocultar elementos no aplicables", "Hide not applicable items": "Ocultar elementos no aplicables",
"Hide password": "Ocultar contraseña",
"Higher (${local} > ${remote})": "Superior (${local} > ${remote})", "Higher (${local} > ${remote})": "Superior (${local} > ${remote})",
"Highlight diff": "Resaltar las diferencias", "Highlight diff": "Resaltar las diferencias",
"How to display network errors when the sync server is unreachable.": "Cómo mostrar los errores de red cuando el servidor de sincronización no está disponible.", "How to display network errors when the sync server is unreachable.": "Cómo mostrar los errores de red cuando el servidor de sincronización no está disponible.",
@@ -1069,6 +1070,7 @@
"Show history": "Mostrar el historial", "Show history": "Mostrar el historial",
"Show icon only": "Mostrar solo el icono", "Show icon only": "Mostrar solo el icono",
"Show only notifications": "Mostrar solo notificaciones", "Show only notifications": "Mostrar solo notificaciones",
"Show password": "Mostrar contraseña",
"Show status as icons only": "Mostrar estado solo con íconos", "Show status as icons only": "Mostrar estado solo con íconos",
"Show status icon instead of file warnings banner": "Mostrar icono de estado en lugar del banner de advertencia de archivos", "Show status icon instead of file warnings banner": "Mostrar icono de estado en lugar del banner de advertencia de archivos",
"Show status inside the editor": "Mostrar estado dentro del editor", "Show status inside the editor": "Mostrar estado dentro del editor",
+2
View File
@@ -401,6 +401,7 @@ Hidden file synchronization have been temporarily disabled. Please enable them a
Hidden Files: Hidden Files Hidden Files: Hidden Files
Hide completely: Hide completely Hide completely: Hide completely
Hide not applicable items: Hide not applicable items Hide not applicable items: Hide not applicable items
Hide password: Hide password
Higher (${local} > ${remote}): Higher (${local} > ${remote}) Higher (${local} > ${remote}): Higher (${local} > ${remote})
Highlight diff: Highlight diff Highlight diff: Highlight diff
How to display network errors when the sync server is unreachable.: How to display network errors when the sync server is unreachable. How to display network errors when the sync server is unreachable.: How to display network errors when the sync server is unreachable.
@@ -1830,6 +1831,7 @@ Show full banner: Show full banner
Show history: Show history Show history: Show history
Show icon only: Show icon only Show icon only: Show icon only
Show only notifications: Show only notifications Show only notifications: Show only notifications
Show password: Show password
Show status as icons only: Show status as icons only Show status as icons only: Show status as icons only
Show status icon instead of file warnings banner: Show status icon instead of file warnings banner Show status icon instead of file warnings banner: Show status icon instead of file warnings banner
Show status inside the editor: Show status inside the editor Show status inside the editor: Show status inside the editor
+2
View File
@@ -425,6 +425,7 @@ Hidden file synchronization have been temporarily disabled. Please enable them a
Hidden Files: Archivos ocultos Hidden Files: Archivos ocultos
Hide completely: Ocultar por completo Hide completely: Ocultar por completo
Hide not applicable items: Ocultar elementos no aplicables Hide not applicable items: Ocultar elementos no aplicables
Hide password: Ocultar contraseña
Higher (${local} > ${remote}): Superior (${local} > ${remote}) Higher (${local} > ${remote}): Superior (${local} > ${remote})
Highlight diff: Resaltar las diferencias Highlight diff: Resaltar las diferencias
How to display network errors when the sync server is unreachable.: How to display network errors when the sync server is unreachable.:
@@ -1950,6 +1951,7 @@ Show full banner: Mostrar banner completo
Show history: Mostrar el historial Show history: Mostrar el historial
Show icon only: Mostrar solo el icono Show icon only: Mostrar solo el icono
Show only notifications: Mostrar solo notificaciones Show only notifications: Mostrar solo notificaciones
Show password: Mostrar contraseña
Show status as icons only: Mostrar estado solo con íconos Show status as icons only: Mostrar estado solo con íconos
Show status icon instead of file warnings banner: Mostrar icono de estado en lugar del banner de advertencia de archivos Show status icon instead of file warnings banner: Mostrar icono de estado en lugar del banner de advertencia de archivos
Show status inside the editor: Mostrar estado dentro del editor Show status inside the editor: Mostrar estado dentro del editor
@@ -52,13 +52,6 @@
<Guidance>{translateMessage("Please configure your end-to-end encryption settings.")}</Guidance> <Guidance>{translateMessage("Please configure your end-to-end encryption settings.")}</Guidance>
<InputRow label={translateMessage("End-to-End Encryption")}> <InputRow label={translateMessage("End-to-End Encryption")}>
<input type="checkbox" bind:checked={encryptionSettings.encrypt} /> <input type="checkbox" bind:checked={encryptionSettings.encrypt} />
<Password
name="e2ee-passphrase"
placeholder={translateMessage("Enter your passphrase")}
bind:value={encryptionSettings.passphrase}
disabled={!encryptionSettings.encrypt}
required={encryptionSettings.encrypt}
/>
</InputRow> </InputRow>
<InfoNote title={translateMessage("Strongly Recommended")}> <InfoNote title={translateMessage("Strongly Recommended")}>
{translateMessage( {translateMessage(
@@ -69,22 +62,29 @@
"Also, please note that if you are using Peer-to-Peer synchronization, this configuration will be used when you switch to other methods and connect to a remote server in the future." "Also, please note that if you are using Peer-to-Peer synchronization, this configuration will be used when you switch to other methods and connect to a remote server in the future."
)} )}
</InfoNote> </InfoNote>
<InfoNote warning> {#if encryptionSettings.encrypt}
{translateMessage("This setting must be the same even when connecting to multiple synchronisation destinations.")} <InputRow label={translateMessage("Passphrase")}>
</InfoNote> <Password
<InputRow label={translateMessage("Obfuscate Properties")}> name="e2ee-passphrase"
<input placeholder={translateMessage("Enter your passphrase")}
type="checkbox" bind:value={encryptionSettings.passphrase}
bind:checked={encryptionSettings.usePathObfuscation} required
disabled={!encryptionSettings.encrypt} />
/> </InputRow>
</InputRow> <InfoNote warning>
{translateMessage(
<InfoNote> "This setting must be the same even when connecting to multiple synchronisation destinations."
{translateMessage( )}
"Obfuscating properties (e.g., path of file, size, creation and modification dates) adds an additional layer of security by making it harder to identify the structure and names of your files and folders on the remote server. This helps protect your privacy and makes it more difficult for unauthorized users to infer information about your data." </InfoNote>
)} <InputRow label={translateMessage("Obfuscate Properties")}>
</InfoNote> <input type="checkbox" bind:checked={encryptionSettings.usePathObfuscation} />
</InputRow>
<InfoNote>
{translateMessage(
"Obfuscating properties (e.g., path of file, size, creation and modification dates) adds an additional layer of security by making it harder to identify the structure and names of your files and folders on the remote server. This helps protect your privacy and makes it more difficult for unauthorized users to infer information about your data."
)}
</InfoNote>
{/if}
<ExtraItems title={translateMessage("Advanced")}> <ExtraItems title={translateMessage("Advanced")}>
<InputRow label={translateMessage("Encryption Algorithm")}> <InputRow label={translateMessage("Encryption Algorithm")}>
@@ -110,7 +110,7 @@
.dialog-host :global(label > span) { .dialog-host :global(label > span) {
display: block; display: block;
width: 8em; min-width: 8em;
} }
.dialog-host :global(.note), .dialog-host :global(.note),
@@ -18,6 +18,7 @@
let showPassword = $state(false); let showPassword = $state(false);
const type = $derived.by(() => (showPassword ? "text" : "password")); const type = $derived.by(() => (showPassword ? "text" : "password"));
const translatedPlaceholder = $derived.by(() => translate(placeholder)); const translatedPlaceholder = $derived.by(() => translate(placeholder));
const toggleLabel = $derived.by(() => translate(showPassword ? "Hide password" : "Show password"));
</script> </script>
<input <input
@@ -31,4 +32,64 @@
autocorrect="off" autocorrect="off"
autocapitalize="off" autocapitalize="off"
/> />
<input type="checkbox" bind:checked={showPassword} /> <button
type="button"
class="sls-password-toggle"
aria-label={toggleLabel}
title={toggleLabel}
aria-pressed={showPassword}
{disabled}
onclick={() => (showPassword = !showPassword)}
>
{#if showPassword}
<svg
viewBox="0 0 24 24"
width="16"
height="16"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9.88 9.88a3 3 0 1 0 4.24 4.24" />
<path d="M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68" />
<path d="M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61" />
<line x1="2" x2="22" y1="2" y2="22" />
</svg>
{:else}
<svg
viewBox="0 0 24 24"
width="16"
height="16"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z" />
<circle cx="12" cy="12" r="3" />
</svg>
{/if}
</button>
<style>
.sls-password-toggle {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
justify-content: center;
padding: 4px;
margin-left: 4px;
background: transparent;
border: none;
box-shadow: none;
color: var(--text-muted);
cursor: pointer;
}
.sls-password-toggle:hover {
color: var(--text-normal);
background: var(--background-modifier-hover);
}
</style>
+6
View File
@@ -353,6 +353,12 @@ body {
} }
.sls-onboarding-invitation-action { .sls-onboarding-invitation-action {
display: inline;
}
/* Touch devices need a larger tap target; on desktop this would just pad the
link with blank space and make it look like a misplaced button. */
body.is-mobile .sls-onboarding-invitation-action {
display: inline-flex; display: inline-flex;
min-width: 44px; min-width: 44px;
min-height: 44px; min-height: 44px;