feat/voice #4
|
|
@ -329,7 +329,6 @@ export function App(){
|
||||||
<div className="account-wrap" onClick={event=>event.stopPropagation()}>
|
<div className="account-wrap" onClick={event=>event.stopPropagation()}>
|
||||||
{accountOpen&&<div className="account-menu" role="menu">
|
{accountOpen&&<div className="account-menu" role="menu">
|
||||||
<button type="button" role="menuitem" onClick={()=>openAccount("phone")}><Smartphone/>{t("openOnPhone")}</button>
|
<button type="button" role="menuitem" onClick={()=>openAccount("phone")}><Smartphone/>{t("openOnPhone")}</button>
|
||||||
<button type="button" role="menuitem" onClick={()=>setLocale(getLocale()==="zh-TW"?"en":"zh-TW")}>{t("language")}: {getLocale()==="zh-TW"?t("languageEn"):t("languageZh")}</button>
|
|
||||||
<button type="button" role="menuitem" onClick={()=>openAccount("settings")}><Settings/>{t("settings")}</button>
|
<button type="button" role="menuitem" onClick={()=>openAccount("settings")}><Settings/>{t("settings")}</button>
|
||||||
<button type="button" role="menuitem" onClick={()=>openAccount("model")}><BotIcon/>{t("modelSettings")}</button>
|
<button type="button" role="menuitem" onClick={()=>openAccount("model")}><BotIcon/>{t("modelSettings")}</button>
|
||||||
<button type="button" role="menuitem" onClick={()=>openAccount("voice")}><PhoneIcon/>{t("voiceSettings")}</button>
|
<button type="button" role="menuitem" onClick={()=>openAccount("voice")}><PhoneIcon/>{t("voiceSettings")}</button>
|
||||||
|
|
@ -854,11 +853,12 @@ function FeedbackDialog({close}:{close:()=>void}){
|
||||||
function LoginScreen({authenticated}:{authenticated:()=>void}){
|
function LoginScreen({authenticated}:{authenticated:()=>void}){
|
||||||
useLocale();
|
useLocale();
|
||||||
const[token,setToken]=useState("");const[busy,setBusy]=useState(false);const[error,setError]=useState("");
|
const[token,setToken]=useState("");const[busy,setBusy]=useState(false);const[error,setError]=useState("");
|
||||||
return <main className="login-screen"><form className="dialog compact login-dialog" onSubmit={async e=>{e.preventDefault();if(!token)return;setBusy(true);setError("");try{await api("/api/session",{method:"POST",body:JSON.stringify({token})});authenticated()}catch(err){setError(err instanceof Error?localizeError(err.message):t("loginFailed"))}finally{setBusy(false)}}}>
|
return <main className="login-screen">
|
||||||
<div className="login-lang">
|
<div className="login-lang" role="group" aria-label={t("language")}>
|
||||||
<button type="button" className={getLocale()==="zh-TW"?"picked":""} onClick={()=>setLocale("zh-TW")}>{t("languageZh")}</button>
|
<button type="button" aria-pressed={getLocale()==="zh-TW"} className={getLocale()==="zh-TW"?"picked":""} onClick={()=>setLocale("zh-TW")}>{t("languageZh")}</button>
|
||||||
<button type="button" className={getLocale()==="en"?"picked":""} onClick={()=>setLocale("en")}>{t("languageEn")}</button>
|
<button type="button" aria-pressed={getLocale()==="en"} className={getLocale()==="en"?"picked":""} onClick={()=>setLocale("en")}>{t("languageEn")}</button>
|
||||||
</div>
|
</div>
|
||||||
|
<form className="dialog compact login-dialog" onSubmit={async e=>{e.preventDefault();if(!token)return;setBusy(true);setError("");try{await api("/api/session",{method:"POST",body:JSON.stringify({token})});authenticated()}catch(err){setError(err instanceof Error?localizeError(err.message):t("loginFailed"))}finally{setBusy(false)}}}>
|
||||||
<Avatar name="L" size={58}/><h1>{t("loginTitle")}</h1><p>{t("loginDescription")}</p><label>{t("accessToken")}<input type="password" autoFocus autoComplete="current-password" value={token} onChange={e=>setToken(e.target.value)}/></label>{error&&<div className="login-error">{error}</div>}<button className="primary" disabled={busy||!token}>{busy?t("verifying"):t("login")}</button>
|
<Avatar name="L" size={58}/><h1>{t("loginTitle")}</h1><p>{t("loginDescription")}</p><label>{t("accessToken")}<input type="password" autoFocus autoComplete="current-password" value={token} onChange={e=>setToken(e.target.value)}/></label>{error&&<div className="login-error">{error}</div>}<button className="primary" disabled={busy||!token}>{busy?t("verifying"):t("login")}</button>
|
||||||
</form></main>;
|
</form></main>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -415,12 +415,12 @@ export const en: { [K in keyof typeof zhTW]: string } = {
|
||||||
schedHours: "hours",
|
schedHours: "hours",
|
||||||
schedDays: "days",
|
schedDays: "days",
|
||||||
computerLoginHint: "Sign in inside this bot’s own browser. The session stays on its computer — don’t type passwords in chat.",
|
computerLoginHint: "Sign in inside this bot’s own browser. The session stays on its computer — don’t type passwords in chat.",
|
||||||
language: "Language",
|
language: "Interface language",
|
||||||
languageZh: "中文",
|
languageZh: "繁體中文",
|
||||||
languageEn: "English",
|
languageEn: "English",
|
||||||
languageHint: "Interface language. Chat history and agent replies are not translated.",
|
languageHint: "Interface language. Chat history and agent replies are not translated.",
|
||||||
helpLanguageTitle: "Language",
|
helpLanguageTitle: "Language",
|
||||||
helpLanguage: "Switch Chinese and English from the workspace menu or Settings.",
|
helpLanguage: "Switch between Traditional Chinese and English in Settings, accessible from the workspace menu.",
|
||||||
clipboardSynced: "Clipboard synced",
|
clipboardSynced: "Clipboard synced",
|
||||||
clipboardSyncBlocked: "The browser blocked sync. Use the copy button.",
|
clipboardSyncBlocked: "The browser blocked sync. Use the copy button.",
|
||||||
clipboardPasted: "Pasted",
|
clipboardPasted: "Pasted",
|
||||||
|
|
|
||||||
|
|
@ -126,9 +126,9 @@ export const zhTW = {
|
||||||
schedEveryWeek: "每週一", schedEveryMonth: "每月", schedInterval: "間隔", schedAdvanced: "進階 cron",
|
schedEveryWeek: "每週一", schedEveryMonth: "每月", schedInterval: "間隔", schedAdvanced: "進階 cron",
|
||||||
schedMinutes: "分鐘", schedHours: "小時", schedDays: "天",
|
schedMinutes: "分鐘", schedHours: "小時", schedDays: "天",
|
||||||
computerLoginHint: "在這台機器人自己的瀏覽器登入。Session 留在它的電腦,不要把密碼打在聊天裡。",
|
computerLoginHint: "在這台機器人自己的瀏覽器登入。Session 留在它的電腦,不要把密碼打在聊天裡。",
|
||||||
language: "語言", languageZh: "中文", languageEn: "English",
|
language: "介面語言", languageZh: "繁體中文", languageEn: "English",
|
||||||
languageHint: "介面語言。對話內容與 Agent 回覆不會自動翻譯。",
|
languageHint: "介面語言。對話內容與 Agent 回覆不會自動翻譯。",
|
||||||
helpLanguageTitle: "語言", helpLanguage: "工作區選單或設定裡可切換中文與英文。",
|
helpLanguageTitle: "語言", helpLanguage: "在左下角工作區選單的設定裡,可切換繁體中文與英文。",
|
||||||
clipboardSynced: "剪貼簿已同步", clipboardSyncBlocked: "瀏覽器未允許同步,請按複製按鈕",
|
clipboardSynced: "剪貼簿已同步", clipboardSyncBlocked: "瀏覽器未允許同步,請按複製按鈕",
|
||||||
clipboardPasted: "已貼上文字", clipboardPasteFailed: "貼上失敗,請確認已接管電腦後重試",
|
clipboardPasted: "已貼上文字", clipboardPasteFailed: "貼上失敗,請確認已接管電腦後重試",
|
||||||
clipboardCopiedSelection: "已複製選取文字", clipboardCopyFailed: "複製未同步;請按複製按鈕,或在遠端使用 Ctrl+Shift+C",
|
clipboardCopiedSelection: "已複製選取文字", clipboardCopyFailed: "複製未同步;請按複製按鈕,或在遠端使用 Ctrl+Shift+C",
|
||||||
|
|
|
||||||
|
|
@ -587,7 +587,7 @@
|
||||||
.memory-clear-confirm{display:flex;align-items:center;gap:8px;margin-right:auto;color:var(--muted);font-size:13px}
|
.memory-clear-confirm{display:flex;align-items:center;gap:8px;margin-right:auto;color:var(--muted);font-size:13px}
|
||||||
|
|
||||||
|
|
||||||
.login-screen{display:grid;min-height:100%;place-items:center;padding:20px;background:radial-gradient(circle at 50% 20%,#18201e 0,#080809 55%)}
|
.login-screen{position:relative;display:grid;min-height:100%;place-items:center;padding:88px 20px;background:radial-gradient(circle at 50% 20%,#18201e 0,#080809 55%)}
|
||||||
|
|
||||||
.login-dialog{display:grid;justify-items:stretch}
|
.login-dialog{display:grid;justify-items:stretch}
|
||||||
|
|
||||||
|
|
@ -599,7 +599,7 @@
|
||||||
|
|
||||||
.login-error{color:var(--danger-soft);font-size:13px}
|
.login-error{color:var(--danger-soft);font-size:13px}
|
||||||
|
|
||||||
.login-lang{display:flex;justify-content:center;gap:6px;margin-bottom:4px}
|
.login-lang{position:absolute;top:24px;right:24px;display:flex;align-items:center;gap:6px}
|
||||||
|
|
||||||
.login-lang button{height:32px;padding:0 12px;border:1px solid var(--border);border-radius:9px;background:transparent;color:var(--muted);cursor:pointer}
|
.login-lang button{height:32px;padding:0 12px;border:1px solid var(--border);border-radius:9px;background:transparent;color:var(--muted);cursor:pointer}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue