Files
xianyan/prototype_translate.html
Developer 6f5400ec4b feat: 5.4.0版本大更新,新增多端桌面小组件与多项功能优化
- 重构「灵感」模块为「发现」模块,统一页面命名与文案
- 新增flutter_tts语音朗读依赖与鸿蒙Nearby配对方式
- 添加Android/iOS/鸿蒙全平台桌面小组件支持(7种类型)
- 完善文件传输模块,新增画布邀请消息与删除会话功能
- 优化协作画布光标广播节流逻辑,修复已知bug
- 更新应用英文名与隐私政策入口,新增翻译API抽象层
- 移除用户中心多余的加号按钮,完善空状态组件类型
2026-05-19 05:39:50 +08:00

1179 lines
46 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>闲言APP — 翻译助手 原型预览 v2</title>
<style>
:root {
--primary: #6C63FF;
--secondary: #FF6B6B;
--accent: #4ECDC4;
--bgPrimary: #FAFAFA;
--bgSecondary: #F5F5F5;
--bgCard: #FFFFFF;
--bgElevated: #FFFFFF;
--textPrimary: #1A1A2E;
--textSecondary: #6B7280;
--textHint: #9CA3AF;
--textInverse: #FFFFFF;
--iconPrimary: #1A1A2E;
--iconSecondary: #6B7280;
--overlaySubtle: rgba(0,0,0,0.04);
--overlayMedium: rgba(0,0,0,0.12);
--overlayStrong: rgba(0,0,0,0.5);
--successColor: #34C759;
--errorColor: #FF3B30;
--warningColor: #FF9500;
--infoColor: #007AFF;
--destructiveColor: #FF3B30;
--glassBg: rgba(255,255,255,0.72);
--glassBorder: rgba(255,255,255,0.35);
--glassBlur: 20px;
--space-1: 4px;
--space-2: 8px;
--space-3: 16px;
--space-4: 24px;
--space-5: 32px;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 999px;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', system-ui, sans-serif;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: var(--font-family);
background: #E5E5EA;
display: flex;
justify-content: center;
align-items: flex-start;
min-height: 100vh;
padding: 20px;
gap: 24px;
flex-wrap: wrap;
}
.phone-frame {
width: 390px;
height: 844px;
background: var(--bgPrimary);
border-radius: 44px;
overflow: hidden;
box-shadow: 0 25px 60px rgba(0,0,0,0.3), 0 0 0 1px rgba(0,0,0,0.08);
position: relative;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.phone-frame.dark {
--bgPrimary: #1A1A2E;
--bgSecondary: #16213E;
--bgCard: #2D2D44;
--bgElevated: #333355;
--textPrimary: #E5E5E5;
--textSecondary: #9CA3AF;
--textHint: #6B7280;
--iconPrimary: #E5E5E5;
--iconSecondary: #9CA3AF;
--overlaySubtle: rgba(255,255,255,0.04);
--overlayMedium: rgba(255,255,255,0.12);
--glassBg: rgba(45,45,68,0.72);
--glassBorder: rgba(255,255,255,0.12);
}
.status-bar {
height: 54px;
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 0 32px 8px;
font-size: 15px;
font-weight: 600;
color: var(--textPrimary);
flex-shrink: 0;
}
.status-bar .time { font-weight: 700; }
.status-bar .icons { display: flex; gap: 6px; align-items: center; font-size: 13px; }
.nav-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 4px var(--space-3) 8px;
background: var(--bgPrimary);
flex-shrink: 0;
position: relative;
z-index: 10;
}
.nav-bar .back-btn {
display: flex;
align-items: center;
gap: 4px;
color: var(--primary);
font-size: 17px;
cursor: pointer;
background: none;
border: none;
font-family: inherit;
}
.nav-bar .title {
position: absolute;
left: 50%;
transform: translateX(-50%);
font-size: 17px;
font-weight: 600;
color: var(--textPrimary);
white-space: nowrap;
}
.nav-bar .actions {
display: flex;
gap: var(--space-2);
align-items: center;
}
.nav-icon-btn {
width: 36px;
height: 36px;
border-radius: var(--radius-md);
border: none;
background: var(--bgSecondary);
color: var(--textSecondary);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
transition: all 0.2s;
}
.nav-icon-btn:hover { background: var(--primary); color: white; }
.lang-bar {
display: flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-2) var(--space-3);
background: var(--bgSecondary);
flex-shrink: 0;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
}
.lang-bar::-webkit-scrollbar { display: none; }
.lang-chip {
display: flex;
align-items: center;
gap: 4px;
padding: 6px 14px;
border-radius: var(--radius-full);
border: 1.5px solid transparent;
background: var(--bgCard);
color: var(--textSecondary);
font-size: 13px;
font-weight: 500;
cursor: pointer;
white-space: nowrap;
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
font-family: inherit;
box-shadow: var(--shadow-sm);
}
.lang-chip:hover { border-color: var(--primary); color: var(--primary); }
.lang-chip.selected {
background: var(--primary);
color: white;
border-color: var(--primary);
box-shadow: 0 2px 8px rgba(108,99,255,0.35);
}
.lang-chip .flag { font-size: 16px; }
.lang-pair-bar {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-3);
padding: var(--space-2) var(--space-3);
flex-shrink: 0;
}
.lang-pair-item {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 16px;
border-radius: var(--radius-lg);
background: var(--bgCard);
box-shadow: var(--shadow-sm);
font-size: 14px;
font-weight: 600;
color: var(--textPrimary);
cursor: pointer;
transition: all 0.2s;
}
.lang-pair-item:hover { box-shadow: var(--shadow-md); }
.lang-pair-item .flag { font-size: 18px; }
.lang-pair-item .detect-badge {
font-size: 10px;
padding: 2px 6px;
border-radius: var(--radius-full);
background: var(--accent);
color: white;
font-weight: 600;
}
.lang-pair-arrow { font-size: 18px; color: var(--textHint); }
.message-area {
flex: 1;
overflow-y: auto;
padding: var(--space-3);
display: flex;
flex-direction: column;
gap: var(--space-2);
-webkit-overflow-scrolling: touch;
}
.message-area::-webkit-scrollbar { width: 0; }
.empty-state {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-3);
padding: var(--space-5);
}
.empty-state .icon { font-size: 64px; }
.empty-state .title { font-size: 20px; font-weight: 700; color: var(--textPrimary); }
.empty-state .subtitle { font-size: 14px; color: var(--textHint); text-align: center; line-height: 1.5; max-width: 260px; }
.msg-row {
display: flex;
gap: var(--space-2);
max-width: 85%;
animation: msgIn 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes msgIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.msg-row.user { align-self: flex-end; flex-direction: row-reverse; }
.msg-row.assistant { align-self: flex-start; }
.msg-avatar {
width: 32px;
height: 32px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
margin-top: 2px;
}
.msg-row.user .msg-avatar { background: var(--primary); color: white; }
.msg-row.assistant .msg-avatar { background: var(--accent); color: white; }
.msg-bubble {
padding: 10px 14px;
border-radius: 18px;
font-size: 15px;
line-height: 1.5;
position: relative;
word-break: break-word;
}
.msg-row.user .msg-bubble { background: var(--primary); color: white; border-bottom-right-radius: 4px; }
.msg-row.assistant .msg-bubble { background: var(--bgCard); color: var(--textPrimary); border-bottom-left-radius: 4px; box-shadow: var(--shadow-sm); }
.msg-meta {
display: flex;
align-items: center;
gap: 6px;
margin-top: 4px;
font-size: 11px;
color: var(--textHint);
}
.msg-row.user .msg-meta { justify-content: flex-end; }
.msg-lang-badge {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 2px 8px;
border-radius: var(--radius-full);
background: rgba(108,99,255,0.12);
color: var(--primary);
font-size: 11px;
font-weight: 600;
}
.msg-row.assistant .msg-lang-badge { background: rgba(78,205,196,0.12); color: var(--accent); }
.msg-copy-btn {
background: none;
border: none;
color: var(--textHint);
cursor: pointer;
font-size: 13px;
padding: 2px 4px;
border-radius: 4px;
transition: all 0.2s;
}
.msg-copy-btn:hover { background: var(--overlaySubtle); color: var(--primary); }
.typing-indicator { display: flex; gap: 4px; padding: 4px 0; }
.typing-indicator span {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--textHint);
animation: typing 1.4s infinite;
}
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing {
0%, 60%, 100% { opacity: 0.3; transform: scale(0.8); }
30% { opacity: 1; transform: scale(1); }
}
.input-bar {
display: flex;
align-items: flex-end;
gap: var(--space-2);
padding: var(--space-2) var(--space-3);
padding-bottom: calc(var(--space-2) + 20px);
background: var(--bgPrimary);
border-top: 0.5px solid var(--overlayMedium);
flex-shrink: 0;
}
.input-wrapper {
flex: 1;
display: flex;
align-items: flex-end;
background: var(--bgSecondary);
border-radius: 22px;
padding: 6px 6px 6px 16px;
min-height: 44px;
max-height: 120px;
transition: box-shadow 0.2s;
}
.input-wrapper:focus-within { box-shadow: 0 0 0 2px var(--primary); }
.input-wrapper textarea {
flex: 1;
border: none;
background: none;
font-size: 16px;
font-family: inherit;
color: var(--textPrimary);
resize: none;
outline: none;
line-height: 1.4;
max-height: 100px;
padding: 6px 0;
}
.input-wrapper textarea::placeholder { color: var(--textHint); }
.send-btn {
width: 36px;
height: 36px;
border-radius: var(--radius-full);
border: none;
background: var(--primary);
color: white;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
transition: all 0.2s;
box-shadow: 0 2px 8px rgba(108,99,255,0.3);
}
.send-btn:hover { transform: scale(1.08); }
.send-btn:active { transform: scale(0.95); }
.send-btn:disabled { background: var(--bgSecondary); color: var(--textHint); box-shadow: none; cursor: default; transform: none; }
.sheet-overlay {
position: absolute;
inset: 0;
background: rgba(0,0,0,0.4);
z-index: 100;
display: none;
animation: fadeIn 0.25s;
}
.sheet-overlay.show { display: flex; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.settings-sheet {
position: absolute;
bottom: 0;
left: 0;
right: 0;
max-height: 85%;
background: var(--bgPrimary);
border-radius: 16px 16px 0 0;
overflow: hidden;
display: none;
flex-direction: column;
animation: slideUp 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}
.settings-sheet.show { display: flex; }
@keyframes slideUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
.sheet-handle { width: 36px; height: 5px; border-radius: 3px; background: var(--overlayMedium); margin: 8px auto 4px; flex-shrink: 0; }
.sheet-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-2) var(--space-3) var(--space-3);
border-bottom: 0.5px solid var(--overlayMedium);
flex-shrink: 0;
}
.sheet-header .title { font-size: 17px; font-weight: 700; color: var(--textPrimary); }
.sheet-header .close-btn {
width: 30px;
height: 30px;
border-radius: var(--radius-full);
border: none;
background: var(--bgSecondary);
color: var(--textSecondary);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
}
.sheet-content { flex: 1; overflow-y: auto; padding: var(--space-3); }
.settings-group { margin-bottom: var(--space-4); }
.settings-group-title {
font-size: 13px;
font-weight: 600;
color: var(--textHint);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: var(--space-2);
padding-left: var(--space-2);
}
.settings-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px var(--space-3);
background: var(--bgCard);
border-radius: var(--radius-lg);
margin-bottom: 2px;
cursor: pointer;
transition: background 0.15s;
}
.settings-item:first-of-type { border-radius: var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-sm); }
.settings-item:last-of-type { border-radius: var(--radius-sm) var(--radius-sm) var(--radius-lg) var(--radius-lg); }
.settings-item:only-of-type { border-radius: var(--radius-lg); }
.settings-item:hover { background: var(--bgSecondary); }
.settings-item .left { display: flex; align-items: center; gap: var(--space-3); }
.settings-item .icon-wrap {
width: 32px;
height: 32px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.settings-item .label { font-size: 15px; font-weight: 500; color: var(--textPrimary); }
.settings-item .sublabel { font-size: 12px; color: var(--textHint); margin-top: 2px; }
.settings-item .right { display: flex; align-items: center; gap: 6px; color: var(--textHint); font-size: 14px; }
.ios-toggle {
width: 51px;
height: 31px;
border-radius: 16px;
background: #E5E5EA;
position: relative;
cursor: pointer;
transition: background 0.3s;
flex-shrink: 0;
}
.ios-toggle.on { background: var(--successColor); }
.ios-toggle .knob {
width: 27px;
height: 27px;
border-radius: 50%;
background: white;
position: absolute;
top: 2px;
left: 2px;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.ios-toggle.on .knob { transform: translateX(20px); }
.api-list { display: flex; flex-direction: column; gap: 2px; }
.api-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: 12px var(--space-3);
background: var(--bgCard);
cursor: pointer;
transition: background 0.15s;
}
.api-item:first-of-type { border-radius: var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-sm); }
.api-item:last-of-type { border-radius: var(--radius-sm) var(--radius-sm) var(--radius-lg) var(--radius-lg); }
.api-item:hover { background: var(--bgSecondary); }
.api-item .api-icon {
width: 36px;
height: 36px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
.api-item .api-info { flex: 1; }
.api-item .api-name { font-size: 15px; font-weight: 500; color: var(--textPrimary); }
.api-item .api-desc { font-size: 12px; color: var(--textHint); margin-top: 2px; }
.api-item .api-check {
width: 22px;
height: 22px;
border-radius: 50%;
border: 2px solid var(--overlayMedium);
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: transparent;
transition: all 0.2s;
}
.api-item.selected .api-check { background: var(--primary); border-color: var(--primary); color: white; }
.api-item .api-status { font-size: 10px; padding: 2px 8px; border-radius: var(--radius-full); font-weight: 600; }
.api-status.active { background: rgba(52,199,89,0.12); color: var(--successColor); }
.api-status.slow { background: rgba(255,149,0,0.12); color: var(--warningColor); }
.discover-card {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3);
background: var(--bgCard);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-sm);
cursor: pointer;
transition: all 0.2s;
margin: 0 var(--space-3) var(--space-2);
}
.discover-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.discover-card .card-icon {
width: 52px;
height: 52px;
border-radius: var(--radius-lg);
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
flex-shrink: 0;
}
.discover-card .card-info { flex: 1; }
.discover-card .card-title { font-size: 16px; font-weight: 600; color: var(--textPrimary); }
.discover-card .card-desc { font-size: 13px; color: var(--textHint); margin-top: 2px; }
.discover-card .card-arrow { color: var(--textHint); font-size: 18px; }
.page-label {
text-align: center;
padding: 12px;
font-size: 13px;
font-weight: 600;
color: var(--textHint);
background: var(--bgSecondary);
border-radius: 0 0 20px 20px;
}
.conversation-list-item {
display: flex;
align-items: center;
gap: var(--space-2);
padding: 10px var(--space-3);
background: var(--bgCard);
margin-bottom: 2px;
cursor: pointer;
transition: background 0.15s;
}
.conversation-list-item:first-of-type { border-radius: var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-sm); }
.conversation-list-item:last-of-type { border-radius: var(--radius-sm) var(--radius-sm) var(--radius-lg) var(--radius-lg); }
.conversation-list-item:hover { background: var(--bgSecondary); }
.conv-avatar {
width: 36px;
height: 36px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.conv-info { flex: 1; }
.conv-name { font-size: 14px; font-weight: 500; color: var(--textPrimary); }
.conv-preview { font-size: 12px; color: var(--textHint); margin-top: 1px; }
.history-count {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 20px;
height: 20px;
border-radius: 10px;
background: var(--primary);
color: white;
font-size: 11px;
font-weight: 700;
padding: 0 6px;
}
.toast {
position: absolute;
top: 80px;
left: 50%;
transform: translateX(-50%) translateY(-20px);
background: var(--bgCard);
color: var(--textPrimary);
padding: 10px 20px;
border-radius: var(--radius-full);
box-shadow: var(--shadow-lg);
font-size: 14px;
font-weight: 500;
z-index: 200;
opacity: 0;
transition: all 0.3s;
pointer-events: none;
white-space: nowrap;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.detect-result {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 10px;
border-radius: var(--radius-full);
background: rgba(78,205,196,0.1);
color: var(--accent);
font-size: 12px;
font-weight: 600;
margin-top: 6px;
}
.tab-bar {
display: flex;
justify-content: space-around;
padding: 8px 0 24px;
background: var(--bgPrimary);
border-top: 0.5px solid var(--overlayMedium);
flex-shrink: 0;
}
.tab-item {
text-align: center;
color: var(--textHint);
font-size: 10px;
cursor: pointer;
transition: color 0.2s;
}
.tab-item.active { color: var(--primary); font-weight: 600; }
.tab-item .tab-icon { font-size: 22px; }
.session-row {
display: flex;
align-items: center;
gap: var(--space-2);
padding: 12px var(--space-3);
background: var(--bgCard);
margin: 0 var(--space-3) 2px;
border-radius: var(--radius-lg);
cursor: pointer;
transition: all 0.15s;
}
.session-row:hover { background: var(--bgSecondary); }
.session-row .session-avatar {
width: 44px;
height: 44px;
border-radius: var(--radius-full);
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
flex-shrink: 0;
}
.session-row .session-info { flex: 1; }
.session-row .session-name { font-size: 15px; font-weight: 600; color: var(--textPrimary); }
.session-row .session-preview { font-size: 13px; color: var(--textHint); margin-top: 2px; }
.session-row .session-time { font-size: 11px; color: var(--textHint); }
.session-row .unread-badge {
min-width: 20px;
height: 20px;
border-radius: 10px;
background: var(--primary);
color: white;
font-size: 11px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
padding: 0 6px;
}
@media (max-width: 860px) {
body { padding: 10px; }
.phone-frame { width: 100%; max-width: 390px; height: 85vh; border-radius: 24px; }
}
</style>
</head>
<body>
<!-- ==================== Phone 1: 发现页 — 主页面3Tab ==================== -->
<div class="phone-frame" id="phone-discover">
<div class="status-bar">
<span class="time">9:41</span>
<span class="icons">📶 📡 🔋</span>
</div>
<div style="flex:1; overflow-y:auto;">
<div style="padding: var(--space-3) var(--space-4) var(--space-2);">
<div style="display:flex; align-items:center; gap:var(--space-2);">
<span style="font-size:28px;">⚙️</span>
<span style="font-size:28px; font-weight:700; color:var(--textPrimary);">工作流</span>
<div style="flex:1;"></div>
<div style="width:36px; height:36px; border-radius:10px; background:var(--bgSecondary); display:flex; align-items:center; justify-content:center; font-size:16px; color:var(--textSecondary);">🔧</div>
</div>
</div>
<!-- 搜索栏 -->
<div style="padding: var(--space-1) var(--space-3) var(--space-2);">
<div style="display:flex; align-items:center; gap:var(--space-2); padding:8px 14px; background:var(--bgSecondary); border-radius:var(--radius-lg);">
<span style="color:var(--textHint); font-size:14px;">🔍</span>
<span style="color:var(--textHint); font-size:14px;">搜索</span>
</div>
</div>
<!-- 置顶会话 -->
<div style="padding: var(--space-2) var(--space-3) var(--space-1);">
<div style="display:flex; align-items:center; gap:4px;">
<span style="font-size:13px; font-weight:600; color:var(--textSecondary);">📌 置顶</span>
<span style="font-size:12px; color:var(--textHint);">1</span>
</div>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(78,205,196,0.12);">📖</div>
<div class="session-info">
<div class="session-name">稍后读 <span style="font-size:10px; padding:1px 6px; border-radius:var(--radius-full); background:var(--secondary); color:white; font-weight:600; vertical-align:middle;">HOT</span></div>
<div class="session-preview">收藏内容,稍后阅读</div>
</div>
<span class="session-time">18:30</span>
</div>
<div style="padding: 0 var(--space-3);"><div style="height:0.5px; background:var(--overlayMedium); margin:var(--space-2) 0;"></div></div>
<!-- 对话会话 -->
<div style="padding: var(--space-2) var(--space-3) var(--space-1);">
<div style="display:flex; align-items:center; gap:4px;">
<span style="font-size:13px; font-weight:600; color:var(--textSecondary);">💬 对话</span>
<span style="font-size:12px; color:var(--textHint);">15</span>
</div>
</div>
<div class="session-row" onclick="switchToTranslate()">
<div class="session-avatar" style="background:linear-gradient(135deg, rgba(108,99,255,0.15), rgba(78,205,196,0.15));">🌐</div>
<div class="session-info">
<div class="session-name">翻译助手 <span style="font-size:10px; padding:1px 6px; border-radius:var(--radius-full); background:var(--accent); color:white; font-weight:600; vertical-align:middle;">NEW</span></div>
<div class="session-preview">多语言智能翻译 · 自动识别语言</div>
</div>
<div class="unread-badge" id="translateBadge" style="background:var(--errorColor);">1</div>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(108,99,255,0.12);">🌤️</div>
<div class="session-info">
<div class="session-name">天气诗词</div>
<div class="session-preview">实时天气 · 天气关联诗词 · 心情推荐</div>
</div>
<span class="session-time">30分钟前</span>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(108,99,255,0.12);">📜</div>
<div class="session-info">
<div class="session-name">今日诗词</div>
<div class="session-preview">每日推荐 · 完整诗词 · 译文赏析</div>
</div>
<span class="session-time">1小时前</span>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(255,149,0,0.12);">📅</div>
<div class="session-info">
<div class="session-name">日签卡片</div>
<div class="session-preview">每日一句 · 样式切换 · 一键分享</div>
</div>
<span class="session-time">6小时前</span>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(255,107,107,0.12);">🎨</div>
<div class="session-info">
<div class="session-name">壁纸模板</div>
<div class="session-preview">预设模板 · 分类浏览 · 一键应用</div>
</div>
<span class="session-time">12小时前</span>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(78,205,196,0.12);">🔍</div>
<div class="session-info">
<div class="session-name">发现</div>
<div class="session-preview">热门句子 · 分类浏览 · 每日推荐</div>
</div>
<span class="session-time">18小时前</span>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(255,149,0,0.12);">👣</div>
<div class="session-info">
<div class="session-name">足迹</div>
<div class="session-preview">浏览 · 点赞 · 收藏 · 稍后读 · 笔记</div>
</div>
<span class="session-time">3天前</span>
</div>
<div class="session-row">
<div class="session-avatar" style="background:rgba(108,99,255,0.12);">📁</div>
<div class="session-info">
<div class="session-name">文件传输助手</div>
<div class="session-preview">局域网 · 蓝牙 · NFC · WebRTC · USB</div>
</div>
<span class="session-time">昨天</span>
</div>
<div style="padding:var(--space-4) 0; text-align:center;">
<span style="font-size:12px; color:var(--textHint);">⬆️ 下拉打开工具中心</span>
</div>
</div>
<!-- 3 Tab Bar -->
<div class="tab-bar">
<div class="tab-item">
<div class="tab-icon">🏠</div>闲言
</div>
<div class="tab-item active">
<div class="tab-icon">🧭</div>发现
</div>
<div class="tab-item">
<div class="tab-icon">👤</div>我的
</div>
</div>
<div class="page-label">📱 工作流页 — 会话流列表 · 翻译助手置顶</div>
</div>
<!-- ==================== Phone 2: 翻译助手主页面 ==================== -->
<div class="phone-frame" id="phone-translate">
<div class="status-bar">
<span class="time">9:41</span>
<span class="icons">📶 📡 🔋</span>
</div>
<div class="nav-bar">
<button class="back-btn"> 发现</button>
<span class="title">🌐 翻译助手</span>
<div class="actions">
<button class="nav-icon-btn" title="历史记录" onclick="showToast('📜 历史记录')">📋</button>
<button class="nav-icon-btn" title="设置" onclick="toggleSettings()">⚙️</button>
</div>
</div>
<div class="lang-pair-bar">
<div class="lang-pair-item" id="sourceLang">
<span class="flag">🔍</span>
<span>自动检测</span>
<span class="detect-badge">AUTO</span>
</div>
<span class="lang-pair-arrow"></span>
<div class="lang-pair-item" id="targetLang" onclick="showToast('🌍 选择目标语言')">
<span class="flag">🇨🇳</span>
<span>中文</span>
</div>
</div>
<div class="lang-bar">
<button class="lang-chip selected" onclick="selectTargetLang(this, '🇨🇳', '中文')"><span class="flag">🇨🇳</span>中文</button>
<button class="lang-chip" onclick="selectTargetLang(this, '🇺🇸', '英语')"><span class="flag">🇺🇸</span>英语</button>
<button class="lang-chip" onclick="selectTargetLang(this, '🇯🇵', '日语')"><span class="flag">🇯🇵</span>日语</button>
<button class="lang-chip" onclick="selectTargetLang(this, '🇰🇷', '韩语')"><span class="flag">🇰🇷</span>韩语</button>
<button class="lang-chip" onclick="selectTargetLang(this, '🇫🇷', '法语')"><span class="flag">🇫🇷</span>法语</button>
<button class="lang-chip" onclick="selectTargetLang(this, '🇩🇪', '德语')"><span class="flag">🇩🇪</span>德语</button>
<button class="lang-chip" onclick="selectTargetLang(this, '🇪🇸', '西语')"><span class="flag">🇪🇸</span>西语</button>
<button class="lang-chip" onclick="selectTargetLang(this, '🇷🇺', '俄语')"><span class="flag">🇷🇺</span>俄语</button>
<button class="lang-chip" onclick="showToast('🌍 更多语言')"><span class="flag">🌍</span>更多</button>
</div>
<div class="message-area" id="messageArea">
<div class="empty-state" id="emptyState">
<div class="icon">🌐</div>
<div class="title">翻译助手</div>
<div class="subtitle">输入需要翻译的文本,选择目标语言,即可获得翻译结果。支持自动识别源语言。</div>
<div style="display:flex; flex-wrap:wrap; gap:8px; justify-content:center; margin-top:8px;">
<button class="lang-chip" onclick="quickTranslate('Hello, how are you today?')" style="font-size:12px; padding:6px 12px;">🇺🇸 Hello, how are you today?</button>
<button class="lang-chip" onclick="quickTranslate('こんにちは、元気ですか?')" style="font-size:12px; padding:6px 12px;">🇯🇵 こんにちは、元気ですか?</button>
<button class="lang-chip" onclick="quickTranslate('Bonjour le monde')" style="font-size:12px; padding:6px 12px;">🇫🇷 Bonjour le monde</button>
</div>
</div>
</div>
<div class="input-bar">
<div class="input-wrapper">
<textarea id="inputField" rows="1" placeholder="输入需要翻译的文本..." oninput="autoResize(this)" onkeydown="handleKeyDown(event)"></textarea>
<button class="send-btn" id="sendBtn" onclick="sendMessage()" disabled></button>
</div>
</div>
<div class="toast" id="toast"></div>
<!-- Settings Sheet -->
<div class="sheet-overlay" id="settingsOverlay" onclick="toggleSettings()"></div>
<div class="settings-sheet" id="settingsSheet">
<div class="sheet-handle"></div>
<div class="sheet-header">
<span class="title">⚙️ 翻译设置</span>
<button class="close-btn" onclick="toggleSettings()"></button>
</div>
<div class="sheet-content">
<div class="settings-group">
<div class="settings-group-title">翻译接口</div>
<div class="api-list">
<div class="api-item selected" onclick="selectApi(this)">
<div class="api-icon" style="background:rgba(66,133,244,0.12);">🔍</div>
<div class="api-info"><div class="api-name">Google Translate</div><div class="api-desc">免费 · 自动检测 · 100+语言</div></div>
<span class="api-status active">正常</span>
<div class="api-check"></div>
</div>
<div class="api-item" onclick="selectApi(this)">
<div class="api-icon" style="background:rgba(0,120,212,0.12);">🅱️</div>
<div class="api-info"><div class="api-name">Bing Translator</div><div class="api-desc">免费 · 自动检测 · 70+语言</div></div>
<span class="api-status active">正常</span>
<div class="api-check"></div>
</div>
<div class="api-item" onclick="selectApi(this)">
<div class="api-icon" style="background:rgba(78,205,196,0.12);">📖</div>
<div class="api-info"><div class="api-name">LibreTranslate</div><div class="api-desc">开源免费 · 自托管 · 30+语言</div></div>
<span class="api-status slow">较慢</span>
<div class="api-check"></div>
</div>
<div class="api-item" onclick="selectApi(this)">
<div class="api-icon" style="background:rgba(255,107,107,0.12);">💾</div>
<div class="api-info"><div class="api-name">MyMemory API</div><div class="api-desc">免费 · 无需Key · 逐句翻译</div></div>
<span class="api-status active">正常</span>
<div class="api-check"></div>
</div>
<div class="api-item" onclick="selectApi(this)">
<div class="api-icon" style="background:rgba(108,99,255,0.12);">🌐</div>
<div class="api-info"><div class="api-name">AppWorlds 翻译</div><div class="api-desc">免费 · 国内直连 · 100+语言</div></div>
<span class="api-status active">正常</span>
<div class="api-check"></div>
</div>
</div>
</div>
<div class="settings-group">
<div class="settings-group-title">翻译设置</div>
<div class="settings-item">
<div class="left"><div class="icon-wrap" style="background:rgba(78,205,196,0.12);">🔍</div><div><div class="label">自动检测语言</div><div class="sublabel">自动识别输入文本的源语言</div></div></div>
<div class="ios-toggle on" onclick="this.classList.toggle('on')"><div class="knob"></div></div>
</div>
<div class="settings-item">
<div class="left"><div class="icon-wrap" style="background:rgba(108,99,255,0.12);">🔄</div><div><div class="label">自动翻译</div><div class="sublabel">输入后自动发送翻译请求</div></div></div>
<div class="ios-toggle" onclick="this.classList.toggle('on')"><div class="knob"></div></div>
</div>
<div class="settings-item">
<div class="left"><div class="icon-wrap" style="background:rgba(255,149,0,0.12);">📋</div><div><div class="label">翻译后自动复制</div><div class="sublabel">翻译结果自动复制到剪贴板</div></div></div>
<div class="ios-toggle" onclick="this.classList.toggle('on')"><div class="knob"></div></div>
</div>
<div class="settings-item">
<div class="left"><div class="icon-wrap" style="background:rgba(52,199,89,0.12);">🔊</div><div><div class="label">发音朗读</div><div class="sublabel">翻译结果自动朗读发音</div></div></div>
<div class="ios-toggle" onclick="this.classList.toggle('on')"><div class="knob"></div></div>
</div>
</div>
<div class="settings-group">
<div class="settings-group-title">会话管理</div>
<div class="conversation-list-item" style="border-radius:var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-sm);">
<div class="conv-avatar" style="background:rgba(108,99,255,0.12);">🌐</div>
<div class="conv-info"><div class="conv-name">默认翻译会话</div><div class="conv-preview">上次: Hello → 你好</div></div>
<span class="history-count">12</span>
</div>
<div class="conversation-list-item" style="border-radius:var(--radius-sm) var(--radius-sm) var(--radius-lg) var(--radius-lg);">
<div class="conv-avatar" style="background:rgba(78,205,196,0.12);">📚</div>
<div class="conv-info"><div class="conv-name">英语学习</div><div class="conv-preview">上次: 翻译了一段英文文章</div></div>
<span class="history-count">8</span>
</div>
<div style="padding:var(--space-3);">
<button style="width:100%; padding:12px; border-radius:var(--radius-lg); border:1.5px dashed var(--primary); background:none; color:var(--primary); font-size:14px; font-weight:600; cursor:pointer; font-family:inherit;"> 新建翻译会话</button>
</div>
</div>
<div class="settings-group">
<div class="settings-group-title">数据管理</div>
<div class="settings-item" style="border-radius:var(--radius-lg);">
<div class="left"><div class="icon-wrap" style="background:rgba(108,99,255,0.12);">📤</div><div class="label">导出翻译记录</div></div>
<div class="right"></div>
</div>
<div class="settings-item" style="border-radius:var(--radius-lg);">
<div class="left"><div class="icon-wrap" style="background:rgba(255,59,48,0.12);">🗑️</div><div class="label" style="color:var(--errorColor);">清空所有翻译记录</div></div>
<div class="right"></div>
</div>
</div>
<div class="settings-group">
<div class="settings-group-title">调试</div>
<div class="settings-item" style="border-radius:var(--radius-lg);">
<div class="left"><div class="icon-wrap" style="background:rgba(255,149,0,0.12);">🐛</div><div><div class="label">接口测试</div><div class="sublabel">测试各翻译API的连通性和响应速度</div></div></div>
<div class="right"></div>
</div>
</div>
</div>
</div>
</div>
<!-- ==================== Phone 3: 深色模式翻译效果 ==================== -->
<div class="phone-frame dark" id="phone-dark">
<div class="status-bar">
<span class="time">9:41</span>
<span class="icons">📶 📡 🔋</span>
</div>
<div class="nav-bar">
<button class="back-btn" style="color:var(--primary);"> 发现</button>
<span class="title" style="color:var(--textPrimary);">🌐 翻译助手</span>
<div class="actions">
<button class="nav-icon-btn" style="background:var(--bgSecondary); color:var(--textSecondary);">📋</button>
<button class="nav-icon-btn" style="background:var(--bgSecondary); color:var(--textSecondary);">⚙️</button>
</div>
</div>
<div class="lang-pair-bar">
<div class="lang-pair-item" style="background:var(--bgCard);">
<span class="flag">🇨🇳</span>
<span style="color:var(--textPrimary);">中文</span>
<span class="detect-badge" style="background:var(--accent);">已检测</span>
</div>
<span class="lang-pair-arrow" style="color:var(--textHint);"></span>
<div class="lang-pair-item" style="background:var(--bgCard);">
<span class="flag">🇺🇸</span>
<span style="color:var(--textPrimary);">英语</span>
</div>
</div>
<div class="lang-bar" style="background:var(--bgSecondary);">
<button class="lang-chip" style="background:var(--bgCard); color:var(--textSecondary);"><span class="flag">🇨🇳</span>中文</button>
<button class="lang-chip selected"><span class="flag">🇺🇸</span>英语</button>
<button class="lang-chip" style="background:var(--bgCard); color:var(--textSecondary);"><span class="flag">🇯🇵</span>日语</button>
<button class="lang-chip" style="background:var(--bgCard); color:var(--textSecondary);"><span class="flag">🇰🇷</span>韩语</button>
<button class="lang-chip" style="background:var(--bgCard); color:var(--textSecondary);"><span class="flag">🇫🇷</span>法语</button>
</div>
<div class="message-area" style="background:var(--bgPrimary);">
<div class="msg-row user">
<div class="msg-avatar">👤</div>
<div>
<div class="msg-bubble">生活不是等待风暴过去,而是学会在雨中翩翩起舞。</div>
<div class="msg-meta"><span class="msg-lang-badge" style="background:rgba(108,99,255,0.2); color:var(--primary);">🇨🇳 中文</span><span>9:40</span></div>
</div>
</div>
<div class="msg-row assistant">
<div class="msg-avatar" style="background:var(--accent);">🌐</div>
<div>
<div class="msg-bubble" style="background:var(--bgCard); color:var(--textPrimary);">Life isn't about waiting for the storm to pass, it's about learning to dance in the rain.</div>
<div class="msg-meta">
<span class="msg-lang-badge" style="background:rgba(78,205,196,0.15); color:var(--accent);">🇺🇸 英语</span>
<button class="msg-copy-btn" onclick="showToast('✅ 已复制')">📋</button>
<button class="msg-copy-btn" onclick="showToast('🔊 朗读中...')">🔊</button>
<span>9:40</span>
</div>
<div class="detect-result" style="background:rgba(78,205,196,0.1); color:var(--accent);">🔍 检测: 中文 → 英语 · Google Translate</div>
</div>
</div>
<div class="msg-row user">
<div class="msg-avatar">👤</div>
<div>
<div class="msg-bubble">你好世界</div>
<div class="msg-meta"><span class="msg-lang-badge" style="background:rgba(108,99,255,0.2); color:var(--primary);">🇨🇳 中文</span><span>9:41</span></div>
</div>
</div>
<div class="msg-row assistant">
<div class="msg-avatar" style="background:var(--accent);">🌐</div>
<div>
<div class="msg-bubble" style="background:var(--bgCard); color:var(--textPrimary);">Hello World</div>
<div class="msg-meta">
<span class="msg-lang-badge" style="background:rgba(78,205,196,0.15); color:var(--accent);">🇺🇸 英语</span>
<button class="msg-copy-btn" onclick="showToast('✅ 已复制')">📋</button>
<button class="msg-copy-btn" onclick="showToast('🔊 朗读中...')">🔊</button>
<span>9:41</span>
</div>
<div class="detect-result" style="background:rgba(78,205,196,0.1); color:var(--accent);">🔍 检测: 中文 → 英语 · Google Translate</div>
</div>
</div>
</div>
<div class="input-bar" style="background:var(--bgPrimary); border-color:var(--overlayMedium);">
<div class="input-wrapper" style="background:var(--bgSecondary);">
<textarea rows="1" placeholder="输入需要翻译的文本..." style="color:var(--textPrimary);" readonly></textarea>
<button class="send-btn" style="background:var(--primary);"></button>
</div>
</div>
<div class="page-label" style="background:var(--bgSecondary); color:var(--textHint);">🌙 深色模式 — 翻译对话效果</div>
</div>
<script>
const inputField = document.getElementById('inputField');
const sendBtn = document.getElementById('sendBtn');
const messageArea = document.getElementById('messageArea');
const emptyState = document.getElementById('emptyState');
let currentTarget = { flag: '🇨🇳', name: '中文', code: 'zh-CN' };
const translations = {
'Hello, how are you today?': { text: '你好,你今天怎么样?', lang: '中文', flag: '🇨🇳', detected: '英语', detectedFlag: '🇺🇸' },
'こんにちは、元気ですか?': { text: '你好,你还好吗?', lang: '中文', flag: '🇨🇳', detected: '日语', detectedFlag: '🇯🇵' },
'Bonjour le monde': { text: '你好世界', lang: '中文', flag: '🇨🇳', detected: '法语', detectedFlag: '🇫🇷' },
};
inputField.addEventListener('input', () => { sendBtn.disabled = inputField.value.trim() === ''; });
function autoResize(el) { el.style.height = 'auto'; el.style.height = Math.min(el.scrollHeight, 100) + 'px'; }
function handleKeyDown(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(); } }
function sendMessage() {
const text = inputField.value.trim();
if (!text) return;
if (emptyState) emptyState.style.display = 'none';
addUserMessage(text);
inputField.value = '';
inputField.style.height = 'auto';
sendBtn.disabled = true;
setTimeout(() => {
addTypingIndicator();
setTimeout(() => {
removeTypingIndicator();
const translation = translations[text] || { text: '[翻译] ' + text, lang: currentTarget.name, flag: currentTarget.flag, detected: '自动', detectedFlag: '🔍' };
addAssistantMessage(translation);
}, 800 + Math.random() * 600);
}, 300);
}
function quickTranslate(text) { inputField.value = text; sendBtn.disabled = false; sendMessage(); }
function addUserMessage(text) {
const div = document.createElement('div');
div.className = 'msg-row user';
div.innerHTML = `<div class="msg-avatar">👤</div><div><div class="msg-bubble">${escapeHtml(text)}</div><div class="msg-meta"><span class="msg-lang-badge">🔍 ${currentTarget.name}</span><span>${new Date().toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit'})}</span></div></div>`;
messageArea.appendChild(div);
scrollToBottom();
}
function addAssistantMessage(translation) {
const div = document.createElement('div');
div.className = 'msg-row assistant';
div.innerHTML = `<div class="msg-avatar">🌐</div><div><div class="msg-bubble">${escapeHtml(translation.text)}</div><div class="msg-meta"><span class="msg-lang-badge">${translation.flag} ${translation.lang}</span><button class="msg-copy-btn" onclick="copyText('${escapeHtml(translation.text)}')">📋</button><button class="msg-copy-btn" onclick="showToast('🔊 朗读中...')">🔊</button><span>${new Date().toLocaleTimeString('zh-CN',{hour:'2-digit',minute:'2-digit'})}</span></div><div class="detect-result">🔍 检测: ${translation.detectedFlag} ${translation.detected}${translation.flag} ${translation.lang} · Google Translate</div></div>`;
messageArea.appendChild(div);
scrollToBottom();
}
function addTypingIndicator() {
const div = document.createElement('div');
div.className = 'msg-row assistant';
div.id = 'typingIndicator';
div.innerHTML = `<div class="msg-avatar">🌐</div><div><div class="msg-bubble"><div class="typing-indicator"><span></span><span></span><span></span></div></div></div>`;
messageArea.appendChild(div);
scrollToBottom();
}
function removeTypingIndicator() { const el = document.getElementById('typingIndicator'); if (el) el.remove(); }
function scrollToBottom() { messageArea.scrollTop = messageArea.scrollHeight; }
function selectTargetLang(btn, flag, name) {
document.querySelectorAll('.lang-bar .lang-chip').forEach(c => c.classList.remove('selected'));
btn.classList.add('selected');
currentTarget = { flag, name, code: 'zh-CN' };
document.getElementById('targetLang').innerHTML = `<span class="flag">${flag}</span><span>${name}</span>`;
showToast(`🎯 目标语言: ${flag} ${name}`);
}
function toggleSettings() {
const overlay = document.getElementById('settingsOverlay');
const sheet = document.getElementById('settingsSheet');
const isOpen = sheet.classList.contains('show');
if (isOpen) { overlay.classList.remove('show'); sheet.classList.remove('show'); }
else { overlay.classList.add('show'); sheet.classList.add('show'); }
}
function selectApi(el) {
document.querySelectorAll('.api-item').forEach(i => i.classList.remove('selected'));
el.classList.add('selected');
showToast(`✅ 已选择: ${el.querySelector('.api-name').textContent}`);
}
function copyText(text) { navigator.clipboard?.writeText(text).then(() => showToast('✅ 已复制到剪贴板')).catch(() => showToast('✅ 已复制')); }
function showToast(msg) { const toast = document.getElementById('toast'); toast.textContent = msg; toast.classList.add('show'); setTimeout(() => toast.classList.remove('show'), 2000); }
function switchToTranslate() {
const badge = document.getElementById('translateBadge');
if (badge) badge.style.display = 'none';
document.getElementById('phone-translate').scrollIntoView({ behavior: 'smooth', inline: 'center' });
showToast('📱 切换到翻译助手');
}
function escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }
</script>
</body>
</html>