@@ -1634,6 +1634,19 @@ ${commonRules}`;
16341634 display: none; padding: 8px 12px;
16351635 border-top: 1px solid var(--input-border);
16361636 }
1637+ .sdrop-auth-tab-bar {
1638+ display: flex; margin-bottom: 8px; gap: 0;
1639+ border: 1px solid var(--input-border); border-radius: 4px; overflow: hidden;
1640+ }
1641+ .sdrop-tab-btn {
1642+ flex: 1; padding: 4px 0; font-size: 11px; font-weight: 600;
1643+ background: none; color: var(--muted);
1644+ border: none; cursor: pointer; transition: all 0.15s;
1645+ }
1646+ .sdrop-tab-btn.active {
1647+ background: var(--btn-bg); color: var(--btn-fg);
1648+ }
1649+ .sdrop-tab-btn:not(.active):hover { background: var(--input-border); }
16371650 .sdrop-auth-panel input {
16381651 width: 100%; box-sizing: border-box;
16391652 padding: 5px 7px; margin-bottom: 5px;
@@ -1642,18 +1655,25 @@ ${commonRules}`;
16421655 font-size: 11px; outline: none;
16431656 }
16441657 .sdrop-auth-panel input:focus { border-color: var(--btn-bg); }
1658+ .sdrop-pass-wrap {
1659+ position: relative; margin-bottom: 5px;
1660+ }
1661+ .sdrop-pass-wrap input {
1662+ width: 100%; box-sizing: border-box; padding-right: 28px; margin-bottom: 0;
1663+ }
1664+ .sdrop-eye-btn {
1665+ position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
1666+ background: none; border: none; cursor: pointer;
1667+ font-size: 13px; line-height: 1; padding: 2px; color: var(--muted);
1668+ opacity: 0.6; transition: opacity 0.1s;
1669+ }
1670+ .sdrop-eye-btn:hover { opacity: 1; }
16451671 .sdrop-login-btn {
1646- flex: 1 ; padding: 5px ; font-size: 11px; font-weight: 600;
1672+ width: 100% ; padding: 6px ; font-size: 11px; font-weight: 600;
16471673 background: var(--btn-bg); color: var(--btn-fg);
1648- border: none; border-radius: 3px; cursor: pointer;
1674+ border: none; border-radius: 3px; cursor: pointer; margin-top: 4px;
16491675 }
16501676 .sdrop-login-btn:hover { background: var(--btn-hover); }
1651- .sdrop-register-btn {
1652- padding: 5px 8px; font-size: 11px;
1653- background: none; color: var(--btn-bg);
1654- border: 1px solid var(--btn-bg); border-radius: 3px; cursor: pointer;
1655- }
1656- .sdrop-register-btn:hover { background: var(--btn-bg); color: var(--btn-fg); }
16571677 .auth-error {
16581678 color: var(--error); font-size: 11px; margin: 0 0 5px; display: none;
16591679 }
@@ -1696,23 +1716,49 @@ ${commonRules}`;
16961716 </div>
16971717 <div class="sdrop-divider"></div>
16981718 <div class="sdrop-item" id="settingsAuthRow">
1699- <span id="settingsAuthLabel">🔑 账户登录</span>
1700- <span id="settingsAuthArrow" style="font-size:10px;color:var(--muted)">▾</span>
1719+ <span id="settingsAuthLabel">🔑 账号</span>
1720+ <span style="display:flex;align-items:center;gap:4px">
1721+ <span id="authStatusDot" style="display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--muted);flex-shrink:0"></span>
1722+ <span id="settingsAuthArrow" style="font-size:10px;color:var(--muted)">▾</span>
1723+ </span>
17011724 </div>
17021725 <div id="settingsAuthPanel" class="sdrop-auth-panel">
1703- <div id="authError" class="auth-error"></div>
1704- <input id="authUser" type="text" placeholder="用户名或邮箱" autocomplete="username" />
1705- <input id="authPass" type="password" placeholder="密码" autocomplete="current-password" />
1706- <div style="display:flex;gap:6px;margin-top:4px">
1726+ <!-- 登录/注册切换 Tab -->
1727+ <div class="sdrop-auth-tab-bar">
1728+ <button class="sdrop-tab-btn active" id="tabAuthLogin">登录</button>
1729+ <button class="sdrop-tab-btn" id="tabAuthRegister">注册</button>
1730+ </div>
1731+ <!-- 登录表单 -->
1732+ <div id="loginForm">
1733+ <div id="authError" class="auth-error"></div>
1734+ <input id="authUser" type="text" placeholder="用户名或邮箱" autocomplete="username" />
1735+ <div class="sdrop-pass-wrap">
1736+ <input id="authPass" type="password" placeholder="密码" autocomplete="current-password" />
1737+ <button class="sdrop-eye-btn" id="authPassEye" title="显示/隐藏密码">👁</button>
1738+ </div>
17071739 <button class="sdrop-login-btn" id="authLoginBtn">登录</button>
1708- <button class="sdrop-register-btn" id="authRegisterBtn">前往注册 ↗</button>
1740+ </div>
1741+ <!-- 注册表单 -->
1742+ <div id="registerForm" style="display:none">
1743+ <div id="regError" class="auth-error"></div>
1744+ <input id="regEmail" type="email" placeholder="邮箱地址" autocomplete="email" />
1745+ <input id="regUser" type="text" placeholder="用户名" autocomplete="username" />
1746+ <div class="sdrop-pass-wrap">
1747+ <input id="regPass" type="password" placeholder="密码" autocomplete="new-password" />
1748+ <button class="sdrop-eye-btn" id="regPassEye" title="显示/隐藏密码">👁</button>
1749+ </div>
1750+ <div class="sdrop-pass-wrap">
1751+ <input id="regConfirm" type="password" placeholder="确认密码" autocomplete="new-password" />
1752+ <button class="sdrop-eye-btn" id="regConfirmEye" title="显示/隐藏密码">👁</button>
1753+ </div>
1754+ <button class="sdrop-login-btn" id="authRegisterSubmit">注册账号</button>
17091755 </div>
17101756 </div>
17111757 <div id="settingsUserRow" class="sdrop-user-row" style="display:none">
17121758 <div style="display:flex;align-items:center;justify-content:space-between">
17131759 <span style="color:var(--success);font-weight:600">👤 <span id="authUsername"></span>
17141760 <span style="color:var(--muted)" id="authPlan"></span></span>
1715- <button id="authLogoutBtn" style="background:none;border:none;color:var(--muted);cursor:pointer;font-size:11px;text-decoration:underline">退出 </button>
1761+ <button id="authLogoutBtn" style="background:none;border:none;color:var(--muted);cursor:pointer;font-size:11px;text-decoration:underline">退出登录 </button>
17161762 </div>
17171763 <div id="authCredits" style="font-size:11px;color:var(--muted);margin-top:2px"></div>
17181764 </div>
@@ -1920,7 +1966,7 @@ ${commonRules}`;
19201966 <script nonce="${ nonce } ">
19211967 const vscode = acquireVsCodeApi();
19221968
1923- // ── 认证逻辑(登录UI位于设置菜单内 ) ──────────────────────────────
1969+ // ── 认证逻辑(登录/注册UI位于设置菜单内 ) ──────────────────────────────
19241970 const authUser = document.getElementById('authUser');
19251971 const authPass = document.getElementById('authPass');
19261972 const authError = document.getElementById('authError');
@@ -1930,6 +1976,51 @@ ${commonRules}`;
19301976 function showAuthError(msg) {
19311977 if (authError) { authError.textContent = msg; authError.style.display = msg ? 'block' : 'none'; }
19321978 }
1979+ function showRegError(msg) {
1980+ const el = document.getElementById('regError');
1981+ if (el) { el.textContent = msg; el.style.display = msg ? 'block' : 'none'; }
1982+ }
1983+
1984+ // 眼睛切换
1985+ function bindEye(eyeId, inputId) {
1986+ const eye = document.getElementById(eyeId);
1987+ const inp = document.getElementById(inputId);
1988+ if (!eye || !inp) return;
1989+ eye.addEventListener('click', (e) => {
1990+ e.stopPropagation();
1991+ const show = inp.type === 'password';
1992+ inp.type = show ? 'text' : 'password';
1993+ eye.textContent = show ? '🙈' : '👁';
1994+ });
1995+ }
1996+ bindEye('authPassEye', 'authPass');
1997+ bindEye('regPassEye', 'regPass');
1998+ bindEye('regConfirmEye', 'regConfirm');
1999+
2000+ // 登录/注册 Tab 切换
2001+ function switchAuthTab(tab) {
2002+ const loginForm = document.getElementById('loginForm');
2003+ const regForm = document.getElementById('registerForm');
2004+ const tabL = document.getElementById('tabAuthLogin');
2005+ const tabR = document.getElementById('tabAuthRegister');
2006+ if (tab === 'login') {
2007+ if (loginForm) loginForm.style.display = '';
2008+ if (regForm) regForm.style.display = 'none';
2009+ if (tabL) { tabL.classList.add('active'); }
2010+ if (tabR) { tabR.classList.remove('active'); }
2011+ setTimeout(() => authUser && authUser.focus(), 50);
2012+ } else {
2013+ if (loginForm) loginForm.style.display = 'none';
2014+ if (regForm) regForm.style.display = '';
2015+ if (tabL) { tabL.classList.remove('active'); }
2016+ if (tabR) { tabR.classList.add('active'); }
2017+ setTimeout(() => { const el = document.getElementById('regEmail'); if (el) el.focus(); }, 50);
2018+ }
2019+ }
2020+ const tabAuthLogin = document.getElementById('tabAuthLogin');
2021+ const tabAuthRegister = document.getElementById('tabAuthRegister');
2022+ if (tabAuthLogin) tabAuthLogin.addEventListener('click', (e) => { e.stopPropagation(); switchAuthTab('login'); });
2023+ if (tabAuthRegister) tabAuthRegister.addEventListener('click', (e) => { e.stopPropagation(); switchAuthTab('register'); });
19332024
19342025 function toggleSettingsAuth() {
19352026 const panel = document.getElementById('settingsAuthPanel');
@@ -1940,18 +2031,26 @@ ${commonRules}`;
19402031 if (!open) setTimeout(() => authUser && authUser.focus(), 50);
19412032 }
19422033
1943- function openRegister() {
1944- vscode.postMessage({ command: 'openExternal', url: 'https://testpilotai.pages.dev/register' });
1945- }
1946-
19472034 function doAuth() {
19482035 showAuthError('');
1949- const u = authUser.value.trim();
1950- const p = authPass.value;
2036+ const u = authUser ? authUser .value.trim() : '' ;
2037+ const p = authPass ? authPass .value : '' ;
19512038 if (!u || !p) { showAuthError('请填写用户名和密码'); return; }
19522039 vscode.postMessage({ command: 'login', emailOrUsername: u, password: p });
19532040 }
19542041
2042+ function doRegister() {
2043+ showRegError('');
2044+ const email = (document.getElementById('regEmail')).value.trim();
2045+ const user = (document.getElementById('regUser')).value.trim();
2046+ const pass = (document.getElementById('regPass')).value;
2047+ const confirm = (document.getElementById('regConfirm')).value;
2048+ if (!email || !user || !pass) { showRegError('请填写所有字段'); return; }
2049+ if (pass !== confirm) { showRegError('两次密码不一致'); return; }
2050+ if (pass.length < 6) { showRegError('密码至少6位'); return; }
2051+ vscode.postMessage({ command: 'register', email, username: user, password: pass });
2052+ }
2053+
19552054 function doLogout() {
19562055 vscode.postMessage({ command: 'logout' });
19572056 }
@@ -1962,8 +2061,8 @@ ${commonRules}`;
19622061 if (authPass) authPass.addEventListener('keydown', (e) => { if (e.key === 'Enter') doAuth(); });
19632062 const authLoginBtn = document.getElementById('authLoginBtn');
19642063 if (authLoginBtn) authLoginBtn.addEventListener('click', doAuth);
1965- const authRegisterBtn = document.getElementById('authRegisterBtn ');
1966- if (authRegisterBtn) authRegisterBtn .addEventListener('click', openRegister );
2064+ const authRegisterSubmit = document.getElementById('authRegisterSubmit ');
2065+ if (authRegisterSubmit) authRegisterSubmit .addEventListener('click', doRegister );
19672066 const authLogoutBtn = document.getElementById('authLogoutBtn');
19682067 if (authLogoutBtn) authLogoutBtn.addEventListener('click', doLogout);
19692068 const themeToggleLabel = document.getElementById('themeToggleLabel');
@@ -1974,11 +2073,13 @@ ${commonRules}`;
19742073 const userRow = document.getElementById('settingsUserRow');
19752074 const authLabel = document.getElementById('settingsAuthLabel');
19762075 const authArrow = document.getElementById('settingsAuthArrow');
2076+ const statusDot = document.getElementById('authStatusDot');
19772077 if (loggedIn && user) {
19782078 if (authPanel) authPanel.style.display = 'none';
19792079 if (userRow) userRow.style.display = 'block';
19802080 if (authLabel) authLabel.textContent = '👤 ' + (user.username || '');
19812081 if (authArrow) authArrow.style.display = 'none';
2082+ if (statusDot) { statusDot.style.background = 'var(--success)'; statusDot.title = '已登录'; }
19822083 if (authUsername) authUsername.textContent = user.username || '';
19832084 if (authPlan) authPlan.textContent = user.plan ? '(' + user.plan + ')' : '';
19842085 const creditsEl = document.getElementById('authCredits');
@@ -1990,7 +2091,8 @@ ${commonRules}`;
19902091 } else {
19912092 if (authPanel) authPanel.style.display = 'none';
19922093 if (userRow) userRow.style.display = 'none';
1993- if (authLabel) authLabel.textContent = '🔑 账户登录';
2094+ if (authLabel) authLabel.textContent = '🔑 账号';
2095+ if (statusDot) { statusDot.style.background = 'var(--muted)'; statusDot.title = '未登录'; }
19942096 if (authArrow) { authArrow.textContent = '▾'; authArrow.style.display = ''; }
19952097 }
19962098 }
@@ -2377,9 +2479,15 @@ ${commonRules}`;
23772479 if (msg.success) {
23782480 setAuthState(true, msg.user);
23792481 showAuthError('');
2482+ showRegError('');
23802483 } else {
23812484 setAuthState(false, null);
2382- if (msg.error) { showAuthError(msg.error); }
2485+ const regFormEl = document.getElementById('registerForm');
2486+ const isRegTab = regFormEl && regFormEl.style.display !== 'none';
2487+ if (msg.error) {
2488+ if (isRegTab) showRegError(msg.error);
2489+ else showAuthError(msg.error);
2490+ }
23832491 }
23842492 break;
23852493 case "shareResult":
0 commit comments