diff --git a/frontend/index.html b/frontend/index.html
index cc11671..cfc5ecf 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -144,7 +144,18 @@
-
+
@@ -258,8 +269,24 @@
主机密钥--
-
-
+
+
@@ -295,9 +322,12 @@
aria-controls="file-manager-panel"
aria-expanded="false"
tabindex="0"
+ aria-label="文件管理"
+ data-i18n-aria-label-zh="文件管理"
+ data-i18n-aria-label-en="Files"
>
-
文件管理
+
文件管理
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index e515a9d..ec759e5 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -7,6 +7,7 @@ import { decryptPasswordResult, encryptPassword, isEncryptedPassword } from './p
import { resolveConnectionControl, resolveConnectionPanel } from './ui-state';
import { classifyHostKey, SSH_FINGERPRINT_RE, type HostKeyPrompt } from './host-key';
import { FileManager, collectFileManagerElements } from './file-manager';
+import { resetTerminalForConnection } from './terminal-session';
import './style.css';
type AuthMethod = 'password' | 'publickey';
@@ -312,7 +313,7 @@ const ui = {
function updateRevealPasswordButton(): void {
const revealed = ui.password.type === 'text';
- ui.revealPassword.textContent = revealed ? bilingual('隐藏', 'Hide') : bilingual('显示', 'Show');
+ ui.revealPassword.setAttribute('aria-pressed', revealed ? 'true' : 'false');
ui.revealPassword.setAttribute('aria-label', revealed
? bilingual('隐藏密码', 'Hide password')
: bilingual('显示密码', 'Show password'));
@@ -1467,7 +1468,7 @@ async function connect(): Promise {
authorizationAbort = abortController;
setState('connecting');
ui.terminalEmpty.hidden = true;
- terminal.clear();
+ resetTerminalForConnection(terminal);
fitTerminal(false);
const host = normalizeHost(ui.host.value);
diff --git a/frontend/src/style.css b/frontend/src/style.css
index ca49110..6e2721d 100644
--- a/frontend/src/style.css
+++ b/frontend/src/style.css
@@ -715,7 +715,7 @@ button:disabled {
}
.input-action-wrap input {
- padding-right: 82px;
+ padding-right: 44px;
}
.input-action {
@@ -723,6 +723,9 @@ button:disabled {
top: 5px;
right: 5px;
bottom: 5px;
+ display: grid;
+ width: 34px;
+ place-items: center;
border: 0;
border-radius: 5px;
background: var(--surface-2);
@@ -732,6 +735,32 @@ button:disabled {
text-transform: uppercase;
}
+.input-action:hover {
+ color: var(--text);
+}
+
+.reveal-icon {
+ width: 16px;
+ height: 16px;
+ fill: none;
+ stroke: currentColor;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-width: 1.8;
+}
+
+.reveal-icon-eye-off {
+ display: none;
+}
+
+.input-action[aria-pressed='true'] .reveal-icon-eye {
+ display: none;
+}
+
+.input-action[aria-pressed='true'] .reveal-icon-eye-off {
+ display: block;
+}
+
.key-field {
display: grid;
gap: 9px;
@@ -1014,6 +1043,10 @@ button:disabled {
}
.terminal-actions .toolbar-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: 5px;
padding: 5px 7px;
border-color: #263642;
background: #151f28;
@@ -1168,6 +1201,17 @@ button:disabled {
stroke-width: 1.7;
}
+.toolbar-button-icon {
+ width: 13px;
+ height: 13px;
+ flex: 0 0 auto;
+ fill: none;
+ stroke: currentColor;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-width: 1.8;
+}
+
.dock-tab:hover {
background: var(--surface-3);
color: var(--text);
@@ -1816,6 +1860,15 @@ button:disabled {
.file-table th:nth-child(2) { width: 16%; }
.file-table th:nth-child(3) { width: 16%; }
.file-table th:nth-child(4) { width: 28%; }
+
+ .button-label {
+ display: none;
+ }
+
+ .dock-tab {
+ min-width: 0;
+ padding: 0 13px;
+ }
}
@media (max-width: 480px) {
diff --git a/frontend/src/terminal-session.ts b/frontend/src/terminal-session.ts
new file mode 100644
index 0000000..71b8a39
--- /dev/null
+++ b/frontend/src/terminal-session.ts
@@ -0,0 +1,10 @@
+const TERMINAL_RESET_SEQUENCE = '\x1bc';
+
+interface WritableTerminal {
+ write(data: string): void;
+}
+
+export function resetTerminalForConnection(terminal: WritableTerminal): void {
+ // Queue RIS behind pending SSH output so stale writes cannot land after the reset.
+ terminal.write(TERMINAL_RESET_SEQUENCE);
+}