Files
xianyan/plugin_preview.html
Developer d2bd53f3bc refactor: 完成v6.5.28版本迭代,修复多项体验问题
主要变更:
1. 重构多处Provider初始化逻辑,使用Future.microtask避免build阶段修改state
2. 重命名"灵感"模块为"工作流","天气诗词"改为"情景诗词"
3. 新增插件系统页面与路由,添加speech_to_text_windows插件支持
4. 优化玻璃容器性能,添加性能节流与模糊值适配
5. 新增离线横幅、阅读体验控制器、手势控制器等组件
6. 完善头像审核状态展示与缓存管理
7. 修复键盘弹出与页面路由问题
8. 更新依赖与项目配置,优化widget默认数据
2026-05-26 01:47:47 +08:00

1891 lines
74 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">
<title>闲言APP — 插件系统方案预览</title>
<style>
:root {
--primary: #007AFF;
--primary-light: rgba(0,122,255,0.1);
--bg: #F2F2F7;
--card-bg: #FFFFFF;
--text: #1C1C1E;
--text-secondary: #8E8E93;
--text-hint: #AEAEB2;
--separator: rgba(60,60,67,0.12);
--green: #34C759;
--orange: #FF9500;
--red: #FF3B30;
--purple: #AF52DE;
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--shadow-sm: 0 1px 3px rgba(0,0,0,0.06);
--shadow-md: 0 4px 12px rgba(0,0,0,0.08);
--shadow-lg: 0 8px 24px rgba(0,0,0,0.12);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
.preview-header {
background: linear-gradient(135deg, #007AFF, #5856D6);
color: white;
padding: 40px 20px 30px;
text-align: center;
}
.preview-header h1 { font-size: 28px; font-weight: 700; margin-bottom: 8px; }
.preview-header p { font-size: 15px; opacity: 0.85; }
.section-nav {
position: sticky;
top: 0;
z-index: 100;
background: rgba(255,255,255,0.85);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 0.5px solid var(--separator);
padding: 12px 16px;
display: flex;
gap: 8px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.section-nav::-webkit-scrollbar { display: none; }
.nav-chip {
flex-shrink: 0;
padding: 6px 14px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
background: var(--primary-light);
color: var(--primary);
cursor: pointer;
transition: all 0.2s;
border: none;
}
.nav-chip:hover, .nav-chip.active {
background: var(--primary);
color: white;
}
.container { max-width: 860px; margin: 0 auto; padding: 20px 16px 60px; }
.section-title {
font-size: 22px;
font-weight: 700;
margin: 32px 0 16px;
display: flex;
align-items: center;
gap: 8px;
}
.section-title .emoji { font-size: 26px; }
.section-desc {
font-size: 14px;
color: var(--text-secondary);
margin-bottom: 16px;
line-height: 1.6;
}
/* ===== Phone Frame ===== */
.phone-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
gap: 24px;
margin-bottom: 32px;
}
.phone-frame {
background: #000;
border-radius: 40px;
padding: 12px;
box-shadow: var(--shadow-lg);
position: relative;
}
.phone-screen {
background: var(--bg);
border-radius: 30px;
overflow: hidden;
min-height: 640px;
position: relative;
}
.phone-label {
text-align: center;
font-size: 13px;
color: var(--text-secondary);
margin-top: 12px;
font-weight: 500;
}
/* ===== iOS Nav Bar ===== */
.ios-navbar {
display: flex;
align-items: center;
padding: 12px 16px;
background: rgba(242,242,247,0.85);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 0.5px solid var(--separator);
position: sticky;
top: 0;
z-index: 10;
}
.ios-navbar .back { color: var(--primary); font-size: 17px; cursor: pointer; }
.ios-navbar .title { flex: 1; text-align: center; font-size: 17px; font-weight: 600; }
.ios-navbar .action { color: var(--primary); font-size: 17px; }
/* ===== Plugin List Page ===== */
.plugin-list { padding: 0 16px; }
.plugin-item {
display: flex;
flex-direction: column;
padding: 0;
border-bottom: 0.5px solid var(--separator);
cursor: pointer;
transition: background 0.15s;
background: var(--card-bg);
}
.plugin-item:active { background: rgba(0,0,0,0.04); }
.plugin-item-top {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px 0;
}
.plugin-icon {
width: 52px;
height: 52px;
border-radius: var(--radius-md);
display: flex;
align-items: center;
justify-content: center;
font-size: 26px;
flex-shrink: 0;
}
.plugin-icon.translate { background: linear-gradient(135deg, #007AFF, #5AC8FA); }
.plugin-icon.tts { background: linear-gradient(135deg, #AF52DE, #FF9500); }
.plugin-info { flex: 1; min-width: 0; }
.plugin-name-row { display: flex; align-items: center; gap: 6px; }
.plugin-name { font-size: 16px; font-weight: 600; }
.plugin-badge {
font-size: 10px;
padding: 1px 6px;
border-radius: 4px;
font-weight: 600;
letter-spacing: 0.3px;
}
.plugin-badge.official { background: rgba(0,122,255,0.1); color: var(--primary); }
.plugin-badge.new { background: rgba(255,59,48,0.1); color: var(--red); }
.plugin-desc { font-size: 13px; color: var(--text-secondary); margin-top: 2px; }
.plugin-status {
font-size: 12px;
padding: 3px 8px;
border-radius: 10px;
font-weight: 500;
}
.plugin-status.on { background: rgba(52,199,89,0.12); color: var(--green); }
.plugin-status.off { background: rgba(142,142,147,0.12); color: var(--text-secondary); }
.plugin-chevron { color: var(--text-hint); font-size: 14px; }
.plugin-preview {
margin: 10px 16px 12px;
border-radius: var(--radius-sm);
overflow: hidden;
height: 100px;
position: relative;
}
.plugin-preview.translate-preview {
background: linear-gradient(135deg, #007AFF 0%, #5AC8FA 50%, #64D2FF 100%);
}
.plugin-preview.tts-preview {
background: linear-gradient(135deg, #AF52DE 0%, #FF9500 50%, #FF6B6B 100%);
}
.plugin-preview-content {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
color: white;
padding: 12px;
gap: 12px;
}
.plugin-preview-mock {
background: rgba(255,255,255,0.2);
border-radius: 8px;
padding: 8px 12px;
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
font-size: 12px;
line-height: 1.5;
max-width: 45%;
}
.plugin-preview-mock .mock-label {
font-size: 10px;
opacity: 0.8;
margin-bottom: 2px;
}
.plugin-preview-mock .mock-text {
font-weight: 500;
}
.plugin-item-bottom {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px 14px;
}
.plugin-meta {
font-size: 12px;
color: var(--text-hint);
display: flex;
align-items: center;
gap: 8px;
}
/* ===== Plugin Detail Page ===== */
.plugin-detail-header {
padding: 20px 16px;
text-align: center;
background: var(--card-bg);
border-bottom: 0.5px solid var(--separator);
}
.plugin-detail-icon {
width: 72px;
height: 72px;
border-radius: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 36px;
margin-bottom: 12px;
}
.plugin-detail-name { font-size: 22px; font-weight: 700; }
.plugin-detail-version { font-size: 13px; color: var(--text-secondary); margin-top: 4px; }
.plugin-enable-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
background: var(--card-bg);
margin-top: 8px;
border-bottom: 0.5px solid var(--separator);
}
.plugin-enable-label { font-size: 16px; font-weight: 500; }
/* iOS Toggle */
.ios-toggle {
width: 51px;
height: 31px;
border-radius: 16px;
background: #E5E5EA;
position: relative;
cursor: pointer;
transition: background 0.3s;
}
.ios-toggle.on { background: var(--green); }
.ios-toggle .knob {
width: 27px;
height: 27px;
border-radius: 50%;
background: white;
position: absolute;
top: 2px;
left: 2px;
box-shadow: 0 2px 4px rgba(0,0,0,0.15);
transition: transform 0.3s;
}
.ios-toggle.on .knob { transform: translateX(20px); }
/* Preview Banner */
.preview-banner {
margin: 12px 16px;
border-radius: var(--radius-md);
overflow: hidden;
position: relative;
height: 160px;
}
.preview-banner.translate-banner {
background: linear-gradient(135deg, #007AFF 0%, #5AC8FA 50%, #64D2FF 100%);
}
.preview-banner.tts-banner {
background: linear-gradient(135deg, #AF52DE 0%, #FF9500 50%, #FF6B6B 100%);
}
.preview-banner-content {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: white;
text-align: center;
padding: 16px;
}
.preview-banner-emoji { font-size: 40px; margin-bottom: 8px; }
.preview-banner-title { font-size: 18px; font-weight: 700; }
.preview-banner-subtitle { font-size: 13px; opacity: 0.85; margin-top: 4px; }
/* Plugin Config Section */
.config-section {
margin-top: 8px;
background: var(--card-bg);
}
.config-section-title {
font-size: 13px;
color: var(--text-secondary);
padding: 8px 16px 4px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.config-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-bottom: 0.5px solid var(--separator);
}
.config-item:last-child { border-bottom: none; }
.config-item-left { display: flex; align-items: center; gap: 10px; }
.config-item-icon { font-size: 20px; width: 28px; text-align: center; }
.config-item-label { font-size: 16px; }
.config-item-value { font-size: 15px; color: var(--text-secondary); display: flex; align-items: center; gap: 4px; }
/* ===== Card Preview ===== */
.card-preview-area { padding: 16px; }
.daily-card {
background: linear-gradient(135deg, rgba(0,122,255,0.08), rgba(88,86,214,0.06));
border-radius: var(--radius-lg);
padding: 20px;
margin-bottom: 16px;
position: relative;
overflow: hidden;
}
.daily-card::before {
content: '';
position: absolute;
top: -30px;
right: -30px;
width: 100px;
height: 100px;
border-radius: 50%;
background: rgba(0,122,255,0.06);
}
.daily-card-header {
display: flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--text-secondary);
margin-bottom: 12px;
}
.daily-card-text {
font-size: 17px;
font-weight: 500;
line-height: 1.7;
margin-bottom: 16px;
}
.daily-card-footer {
display: flex;
align-items: center;
gap: 8px;
}
.daily-card-author {
flex: 1;
font-size: 14px;
color: var(--text-secondary);
}
.card-action-btn {
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
cursor: pointer;
transition: all 0.2s;
border: none;
background: transparent;
position: relative;
}
.card-action-btn:active { transform: scale(0.9); }
.card-action-btn.translate-btn { color: var(--primary); }
.card-action-btn.tts-btn { color: var(--purple); }
.card-action-btn.fav-btn { color: var(--orange); }
.card-action-btn.like-btn { color: var(--red); }
.card-action-btn.active { background: rgba(0,122,255,0.1); }
/* Sentence Card */
.sentence-card {
background: var(--card-bg);
border-radius: var(--radius-md);
overflow: hidden;
margin-bottom: 12px;
box-shadow: var(--shadow-sm);
}
.sentence-card-inner {
display: flex;
}
.sentence-card-accent {
width: 3px;
background: var(--primary);
margin: 12px 0;
border-radius: 2px;
flex-shrink: 0;
}
.sentence-card-content {
flex: 1;
padding: 12px 14px;
}
.sentence-card-feed {
display: flex;
align-items: center;
gap: 4px;
font-size: 11px;
color: var(--text-secondary);
margin-bottom: 6px;
}
.sentence-card-text {
font-size: 15px;
line-height: 1.6;
margin-bottom: 8px;
}
.sentence-card-stats {
display: flex;
gap: 12px;
font-size: 12px;
color: var(--text-hint);
margin-bottom: 8px;
}
.sentence-card-actions {
display: flex;
align-items: center;
gap: 6px;
}
.sentence-card-author {
flex: 1;
font-size: 13px;
color: var(--text-secondary);
}
/* ===== Popup / Sheet ===== */
.popup-overlay {
position: absolute;
inset: 0;
background: rgba(0,0,0,0.3);
display: flex;
align-items: flex-end;
z-index: 50;
border-radius: 30px;
overflow: hidden;
}
.popup-sheet {
width: 100%;
background: var(--card-bg);
border-radius: 16px 16px 0 0;
padding: 0 0 20px;
max-height: 70%;
overflow-y: auto;
}
.popup-handle {
width: 36px;
height: 5px;
border-radius: 3px;
background: rgba(0,0,0,0.15);
margin: 8px auto 12px;
}
.popup-title {
font-size: 17px;
font-weight: 600;
text-align: center;
padding: 4px 16px 12px;
border-bottom: 0.5px solid var(--separator);
}
.popup-body { padding: 16px; }
.translate-result {
background: var(--primary-light);
border-radius: var(--radius-md);
padding: 16px;
margin-bottom: 12px;
}
.translate-result-label {
font-size: 12px;
color: var(--primary);
font-weight: 600;
margin-bottom: 6px;
display: flex;
align-items: center;
gap: 4px;
}
.translate-result-text {
font-size: 16px;
line-height: 1.6;
}
.translate-original {
background: rgba(142,142,147,0.08);
border-radius: var(--radius-md);
padding: 12px;
}
.translate-original-label {
font-size: 12px;
color: var(--text-secondary);
margin-bottom: 4px;
}
.translate-original-text {
font-size: 14px;
color: var(--text-secondary);
line-height: 1.5;
}
/* TTS Player */
.tts-player {
background: linear-gradient(135deg, rgba(175,82,222,0.08), rgba(255,149,0,0.06));
border-radius: var(--radius-md);
padding: 16px;
}
.tts-player-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
}
.tts-player-title { font-size: 15px; font-weight: 600; }
.tts-player-text {
font-size: 14px;
color: var(--text-secondary);
line-height: 1.5;
margin-bottom: 12px;
max-height: 60px;
overflow: hidden;
}
.tts-controls {
display: flex;
align-items: center;
gap: 12px;
}
.tts-btn {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
cursor: pointer;
border: none;
transition: all 0.2s;
}
.tts-btn:active { transform: scale(0.9); }
.tts-btn.play {
background: var(--purple);
color: white;
width: 48px;
height: 48px;
font-size: 22px;
}
.tts-btn.secondary {
background: rgba(175,82,222,0.1);
color: var(--purple);
}
.tts-progress {
flex: 1;
height: 4px;
background: rgba(175,82,222,0.15);
border-radius: 2px;
overflow: hidden;
}
.tts-progress-fill {
height: 100%;
width: 35%;
background: var(--purple);
border-radius: 2px;
transition: width 0.3s;
}
.tts-speed-label {
font-size: 12px;
color: var(--purple);
font-weight: 600;
padding: 4px 10px;
background: rgba(175,82,222,0.1);
border-radius: 10px;
}
/* ===== Settings Entry ===== */
.settings-entry {
background: var(--card-bg);
border-radius: var(--radius-md);
overflow: hidden;
margin-bottom: 16px;
}
.settings-group-title {
font-size: 13px;
color: var(--text-secondary);
padding: 8px 16px 4px;
}
.settings-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
border-bottom: 0.5px solid var(--separator);
cursor: pointer;
}
.settings-item:last-child { border-bottom: none; }
.settings-item:active { background: rgba(0,0,0,0.04); }
.settings-item-icon {
width: 30px;
height: 30px;
border-radius: 7px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color: white;
}
.settings-item-label { flex: 1; font-size: 16px; }
.settings-item-arrow { color: var(--text-hint); font-size: 14px; }
/* ===== Flow Diagram ===== */
.flow-diagram {
background: var(--card-bg);
border-radius: var(--radius-md);
padding: 24px;
margin-bottom: 24px;
box-shadow: var(--shadow-sm);
}
.flow-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 16px;
text-align: center;
}
.flow-steps {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
gap: 8px;
}
.flow-step {
padding: 8px 16px;
border-radius: var(--radius-sm);
font-size: 13px;
font-weight: 500;
text-align: center;
}
.flow-step.page { background: var(--primary-light); color: var(--primary); }
.flow-step.action { background: rgba(52,199,89,0.1); color: var(--green); }
.flow-step.data { background: rgba(175,82,222,0.1); color: var(--purple); }
.flow-arrow { color: var(--text-hint); font-size: 18px; }
/* ===== Feature Tags ===== */
.feature-tags {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 16px;
}
.feature-tag {
padding: 6px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 500;
}
.feature-tag.blue { background: var(--primary-light); color: var(--primary); }
.feature-tag.green { background: rgba(52,199,89,0.1); color: var(--green); }
.feature-tag.purple { background: rgba(175,82,222,0.1); color: var(--purple); }
.feature-tag.orange { background: rgba(255,149,0,0.1); color: var(--orange); }
/* ===== Comparison Table ===== */
.comparison-table {
width: 100%;
border-collapse: collapse;
background: var(--card-bg);
border-radius: var(--radius-md);
overflow: hidden;
margin-bottom: 24px;
box-shadow: var(--shadow-sm);
}
.comparison-table th {
background: rgba(0,122,255,0.06);
padding: 10px 14px;
font-size: 13px;
font-weight: 600;
text-align: left;
color: var(--primary);
}
.comparison-table td {
padding: 10px 14px;
font-size: 14px;
border-bottom: 0.5px solid var(--separator);
}
.comparison-table tr:last-child td { border-bottom: none; }
/* ===== Annotation ===== */
.annotation {
background: rgba(255,149,0,0.08);
border-left: 3px solid var(--orange);
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
padding: 12px 16px;
margin-bottom: 16px;
font-size: 14px;
line-height: 1.6;
}
.annotation strong { color: var(--orange); }
/* ===== Responsive ===== */
@media (max-width: 640px) {
.phone-grid { grid-template-columns: 1fr; }
.phone-frame { max-width: 380px; margin: 0 auto; }
}
</style>
</head>
<body>
<!-- ===== Header ===== -->
<div class="preview-header">
<h1>🧩 闲言插件系统</h1>
<p>翻译守护 · 文本朗读 — 方案预览与交互设计</p>
</div>
<!-- ===== Nav ===== -->
<div class="section-nav">
<button class="nav-chip active" onclick="scrollToSection('overview')">📋 总览</button>
<button class="nav-chip" onclick="scrollToSection('plugin-list')">🧩 插件列表</button>
<button class="nav-chip" onclick="scrollToSection('translate-detail')">🌐 翻译守护</button>
<button class="nav-chip" onclick="scrollToSection('tts-detail')">🔊 文本朗读</button>
<button class="nav-chip" onclick="scrollToSection('card-integration')">🃏 卡片集成</button>
<button class="nav-chip" onclick="scrollToSection('popup-demo')">💬 弹窗交互</button>
<button class="nav-chip" onclick="scrollToSection('architecture')">🏗️ 架构设计</button>
<button class="nav-chip" onclick="scrollToSection('api-test')">🔌 接口方案</button>
</div>
<div class="container">
<!-- ===== Section 1: Overview ===== -->
<div id="overview">
<div class="section-title"><span class="emoji">📋</span> 方案总览</div>
<div class="section-desc">
在通用设置页新增「插件」入口,点击进入插件管理页面。插件页面参考微信小程序/插件列表风格,每个插件卡片包含预览图、启用开关、功能说明和配置项。启用后的插件会在主页句子卡片和句子广场中注入功能按钮。
</div>
<div class="feature-tags">
<span class="feature-tag blue">🌐 翻译守护</span>
<span class="feature-tag purple">🔊 文本朗读</span>
<span class="feature-tag green">⚡ 插件化架构</span>
<span class="feature-tag orange">🔄 跨平台兼容</span>
<span class="feature-tag blue">📱 iOS风格</span>
<span class="feature-tag purple">🧩 可扩展</span>
</div>
<div class="flow-diagram">
<div class="flow-title">用户操作流程</div>
<div class="flow-steps">
<span class="flow-step page">通用设置</span>
<span class="flow-arrow"></span>
<span class="flow-step page">插件管理</span>
<span class="flow-arrow"></span>
<span class="flow-step action">启用插件</span>
<span class="flow-arrow"></span>
<span class="flow-step data">配置参数</span>
<span class="flow-arrow"></span>
<span class="flow-step page">主页/广场</span>
<span class="flow-arrow"></span>
<span class="flow-step action">使用功能</span>
</div>
</div>
<div class="annotation">
<strong>设计原则:</strong>插件启用前,主页卡片不显示任何插件按钮(零侵入);启用后,按钮以动画方式淡入,保持界面简洁。插件状态通过 Riverpod 持久化到 KvStorage跨平台统一。
</div>
</div>
<!-- ===== Section 2: Plugin List Page ===== -->
<div id="plugin-list">
<div class="section-title"><span class="emoji">🧩</span> 插件列表页</div>
<div class="section-desc">参考微信「设置 → 插件」页面风格iOS 原生列表布局,每个插件显示图标、名称、简介和启用状态。</div>
<div class="phone-grid">
<!-- Phone 1: 通用设置入口 -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"> 返回</span>
<span class="title">通用设置</span>
<span class="action"></span>
</div>
<div style="padding: 0 16px;">
<div class="settings-group-title">功能扩展</div>
<div class="settings-entry">
<div class="settings-item" style="border-bottom: none;">
<div class="settings-item-icon" style="background: linear-gradient(135deg, #007AFF, #AF52DE);">🧩</div>
<span class="settings-item-label">插件</span>
<span style="font-size:13px;color:var(--text-secondary);margin-right:4px;">2个可用</span>
<span class="settings-item-arrow"></span>
</div>
</div>
<div class="settings-group-title" style="margin-top:16px;">交互设置</div>
<div class="settings-entry">
<div class="settings-item">
<div class="settings-item-icon" style="background:#007AFF;">🔊</div>
<span class="settings-item-label">声音</span>
<div class="ios-toggle on"><div class="knob"></div></div>
</div>
<div class="settings-item">
<div class="settings-item-icon" style="background:#5856D6;">📳</div>
<span class="settings-item-label">震动</span>
<span class="settings-item-arrow"></span>
</div>
<div class="settings-item" style="border-bottom: none;">
<div class="settings-item-icon" style="background:#34C759;">🎵</div>
<span class="settings-item-label">音效反馈</span>
<div class="ios-toggle"><div class="knob"></div></div>
</div>
</div>
</div>
</div>
</div>
<div class="phone-label">通用设置 — 新增「插件」入口</div>
</div>
<!-- Phone 2: 插件列表 -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"> 通用设置</span>
<span class="title">插件</span>
<span class="action"></span>
</div>
<div class="plugin-list">
<div style="padding:12px 0 6px;font-size:13px;color:var(--text-secondary);">可用插件</div>
<div class="plugin-item" style="border-radius:var(--radius-md);margin-bottom:12px;overflow:hidden;">
<div class="plugin-item-top">
<div class="plugin-icon translate">🌐</div>
<div class="plugin-info">
<div class="plugin-name-row">
<span class="plugin-name">翻译守护</span>
<span class="plugin-badge official">官方</span>
</div>
<div class="plugin-desc">实时翻译句子内容,支持多语言</div>
</div>
<span class="plugin-status on">已启用</span>
</div>
<div class="plugin-preview translate-preview">
<div class="plugin-preview-content">
<div class="plugin-preview-mock">
<div class="mock-label">原文</div>
<div class="mock-text">山有木兮木有枝</div>
</div>
<div style="font-size:20px;"></div>
<div class="plugin-preview-mock">
<div class="mock-label">English</div>
<div class="mock-text">The mountains have trees...</div>
</div>
</div>
</div>
<div class="plugin-item-bottom">
<div class="plugin-meta">
<span>v1.0.0</span>
<span>·</span>
<span>翻译 128 次</span>
</div>
<span class="plugin-chevron"></span>
</div>
</div>
<div class="plugin-item" style="border-radius:var(--radius-md);margin-bottom:12px;overflow:hidden;">
<div class="plugin-item-top">
<div class="plugin-icon tts">🔊</div>
<div class="plugin-info">
<div class="plugin-name-row">
<span class="plugin-name">文本朗读</span>
<span class="plugin-badge official">官方</span>
<span class="plugin-badge new">NEW</span>
</div>
<div class="plugin-desc">语音朗读句子TTS + 在线双引擎</div>
</div>
<span class="plugin-status off">未启用</span>
</div>
<div class="plugin-preview tts-preview">
<div class="plugin-preview-content">
<div class="plugin-preview-mock">
<div class="mock-label">正在朗读</div>
<div class="mock-text">🎙️ 人生如逆旅...</div>
</div>
<div style="display:flex;flex-direction:column;align-items:center;gap:4px;">
<div style="width:36px;height:36px;background:rgba(255,255,255,0.3);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:16px;"></div>
<div style="font-size:10px;opacity:0.8;">0:03 / 0:08</div>
</div>
</div>
</div>
<div class="plugin-item-bottom">
<div class="plugin-meta">
<span>v1.0.0</span>
<span>·</span>
<span>朗读 0 次</span>
</div>
<span class="plugin-chevron"></span>
</div>
</div>
<div style="padding:20px 0 6px;font-size:13px;color:var(--text-secondary);">关于插件</div>
<div style="padding:12px 16px;background:var(--card-bg);border-radius:var(--radius-md);font-size:14px;color:var(--text-secondary);line-height:1.6;">
插件为闲言提供可选的增强功能。启用后,相关功能按钮会出现在句子卡片上。你可以随时关闭插件,关闭后按钮会自动隐藏。<br><br>⚠️ 部分插件需要网络连接,无网络时将显示暂无可用插件。
</div>
</div>
</div>
</div>
<div class="phone-label">插件列表页(有网络)</div>
</div>
<!-- Phone: 无网络状态 -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"> 通用设置</span>
<span class="title">插件</span>
<span class="action"></span>
</div>
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:400px;padding:40px;">
<div style="font-size:56px;margin-bottom:16px;">📡</div>
<div style="font-size:17px;font-weight:600;color:var(--text);margin-bottom:6px;">暂无可用插件</div>
<div style="font-size:14px;color:var(--text-secondary);text-align:center;line-height:1.5;">当前无网络连接,插件功能需要网络支持。请检查网络设置后重试。</div>
<button style="margin-top:20px;padding:10px 24px;background:var(--primary);color:white;border:none;border-radius:20px;font-size:15px;font-weight:500;cursor:pointer;">重新加载</button>
</div>
</div>
</div>
<div class="phone-label">插件列表页(无网络)</div>
</div>
</div>
</div>
<!-- ===== Section 3: Translate Plugin Detail ===== -->
<div id="translate-detail">
<div class="section-title"><span class="emoji">🌐</span> 翻译守护 — 插件详情</div>
<div class="section-desc">点击翻译守护进入详情页,展示预览图、启用开关、翻译引擎选择、目标语言配置等。</div>
<div class="phone-grid">
<!-- Phone 3: 翻译守护详情 -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"> 插件</span>
<span class="title">翻译守护</span>
<span class="action"></span>
</div>
<div class="plugin-detail-header">
<div class="plugin-detail-icon translate-banner" style="border-radius:18px;">🌐</div>
<div class="plugin-detail-name">翻译守护</div>
<div class="plugin-detail-version">v1.0.0 · 翻译增强插件</div>
</div>
<div class="preview-banner translate-banner">
<div class="preview-banner-content">
<div class="preview-banner-emoji">🌍</div>
<div class="preview-banner-title">一键翻译,跨越语言</div>
<div class="preview-banner-subtitle">支持 30+ 语言 · 自动检测 · 多引擎降级</div>
</div>
</div>
<div class="plugin-enable-row">
<span class="plugin-enable-label">启用翻译守护</span>
<div class="ios-toggle on" onclick="this.classList.toggle('on')"><div class="knob"></div></div>
</div>
<div class="config-section">
<div class="config-section-title">使用预览</div>
<div style="padding:12px 16px;">
<div style="background:linear-gradient(135deg, rgba(0,122,255,0.08), rgba(88,86,214,0.06));border-radius:var(--radius-md);padding:16px;">
<div style="font-size:15px;line-height:1.7;margin-bottom:12px;">山有木兮木有枝,心悦君兮君不知。</div>
<div style="display:flex;align-items:center;gap:6px;">
<span style="flex:1;font-size:13px;color:var(--text-secondary);">—— 越人歌</span>
<span style="width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:var(--primary);font-size:16px;">🌐</span>
<span style="width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:var(--purple);font-size:16px;">🔊</span>
<span style="font-size:16px;"></span>
<span style="font-size:16px;">❤️</span>
</div>
<div style="margin-top:12px;padding:10px;background:rgba(0,122,255,0.08);border-radius:8px;">
<div style="font-size:11px;color:var(--primary);font-weight:600;margin-bottom:4px;">🌐 英文翻译 · Bing</div>
<div style="font-size:14px;line-height:1.5;">The mountains have trees and the trees have branches, my heart delights in you but you do not know.</div>
</div>
</div>
</div>
</div>
<div class="config-section">
<div class="config-section-title">翻译设置</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🔧</span>
<span class="config-item-label">翻译引擎</span>
</div>
<span class="config-item-value">Bing </span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🎯</span>
<span class="config-item-label">目标语言</span>
</div>
<span class="config-item-value">简体中文 </span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon"></span>
<span class="config-item-label">自动检测源语言</span>
</div>
<div class="ios-toggle on" onclick="this.classList.toggle('on')" style="transform:scale(0.8);"><div class="knob"></div></div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🔄</span>
<span class="config-item-label">降级策略</span>
</div>
<span class="config-item-value">Bing→MyMemory→Google </span>
</div>
</div>
<div class="config-section">
<div class="config-section-title">显示设置</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">📍</span>
<span class="config-item-label">按钮位置</span>
</div>
<span class="config-item-value">爱心左侧 </span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon"></span>
<span class="config-item-label">自动翻译</span>
</div>
<div class="ios-toggle" onclick="this.classList.toggle('on')" style="transform:scale(0.8);"><div class="knob"></div></div>
</div>
</div>
<div class="config-section">
<div class="config-section-title">翻译记录</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">📊</span>
<span class="config-item-label">累计翻译</span>
</div>
<span class="config-item-value">128 次</span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🕐</span>
<div>
<span class="config-item-label" style="font-size:14px;">山有木兮木有枝...</span>
<div style="font-size:11px;color:var(--text-hint);">→ The mountains have trees... · 3分钟前</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🕐</span>
<div>
<span class="config-item-label" style="font-size:14px;">人生如逆旅...</span>
<div style="font-size:11px;color:var(--text-hint);">→ Life is like a journey... · 1小时前</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🗑️</span>
<span class="config-item-label" style="color:var(--red);">清除翻译记录</span>
</div>
</div>
</div>
<div class="config-section">
<div class="config-section-title">使用场景</div>
<div style="padding:8px 16px 12px;">
<div style="display:flex;flex-wrap:wrap;gap:8px;">
<span style="padding:6px 12px;background:var(--primary-light);color:var(--primary);border-radius:16px;font-size:13px;font-weight:500;">🃏 每日推荐卡片</span>
<span style="padding:6px 12px;background:var(--primary-light);color:var(--primary);border-radius:16px;font-size:13px;font-weight:500;">📖 句子广场列表</span>
<span style="padding:6px 12px;background:rgba(142,142,147,0.08);color:var(--text-secondary);border-radius:16px;font-size:13px;font-weight:500;">📝 笔记编辑 (即将支持)</span>
<span style="padding:6px 12px;background:rgba(142,142,147,0.08);color:var(--text-secondary);border-radius:16px;font-size:13px;font-weight:500;">🔍 搜索结果 (即将支持)</span>
</div>
</div>
</div>
<div class="config-section">
<div class="config-section-title">反馈与建议</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">💬</span>
<span class="config-item-label">提交意见</span>
</div>
<span class="config-item-value">帮助我们改进 </span>
</div>
</div>
</div>
</div>
<div class="phone-label">翻译守护 — 插件详情页</div>
</div>
<!-- Phone 4: 翻译引擎选择 -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"> 翻译守护</span>
<span class="title">翻译引擎</span>
<span class="action"></span>
</div>
<div style="padding:16px;">
<div style="font-size:13px;color:var(--text-secondary);margin-bottom:12px;">选择首选翻译引擎,失败时自动降级</div>
<div style="background:var(--card-bg);border-radius:var(--radius-md);overflow:hidden;">
<div class="config-item" style="background:var(--primary-light);">
<div class="config-item-left">
<span class="config-item-icon">🔷</span>
<div>
<div class="config-item-label">Bing Translator</div>
<div style="font-size:12px;color:var(--text-secondary);">免费 · 自动检测 · 70+语言</div>
</div>
</div>
<span style="color:var(--primary);font-size:18px;"></span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🟢</span>
<div>
<div class="config-item-label">Google Translate</div>
<div style="font-size:12px;color:var(--text-secondary);">免费 · 自动检测 · 100+语言</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🟡</span>
<div>
<div class="config-item-label">MyMemory</div>
<div style="font-size:12px;color:var(--text-secondary);">免费 · 无需Key · 不支持自动检测</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🟠</span>
<div>
<div class="config-item-label">AppWorlds</div>
<div style="font-size:12px;color:var(--text-secondary);">国内直连 · 免费 · 2秒频率限制</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🟣</span>
<div>
<div class="config-item-label">LibreTranslate</div>
<div style="font-size:12px;color:var(--text-secondary);">开源免费 · 自动检测 · 较慢</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">⚙️</span>
<div>
<div class="config-item-label">自定义 API</div>
<div style="font-size:12px;color:var(--text-secondary);">配置自己的翻译接口</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="phone-label">翻译引擎选择</div>
</div>
</div>
</div>
<!-- ===== Section 4: TTS Plugin Detail ===== -->
<div id="tts-detail">
<div class="section-title"><span class="emoji">🔊</span> 文本朗读 — 插件详情</div>
<div class="section-desc">文本朗读插件提供两种引擎:系统 TTS离线和在线语音合成需网络用户可自由切换。</div>
<div class="phone-grid">
<!-- Phone 5: 文本朗读详情 -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"> 插件</span>
<span class="title">文本朗读</span>
<span class="action"></span>
</div>
<div class="plugin-detail-header">
<div class="plugin-detail-icon tts-banner" style="border-radius:18px;">🔊</div>
<div class="plugin-detail-name">文本朗读</div>
<div class="plugin-detail-version">v1.0.0 · 语音增强插件</div>
</div>
<div class="preview-banner tts-banner">
<div class="preview-banner-content">
<div class="preview-banner-emoji">🎙️</div>
<div class="preview-banner-title">让文字被听见</div>
<div class="preview-banner-subtitle">TTS离线引擎 + 在线语音合成 · 双引擎切换</div>
</div>
</div>
<div class="plugin-enable-row">
<span class="plugin-enable-label">启用文本朗读</span>
<div class="ios-toggle on" onclick="this.classList.toggle('on')"><div class="knob"></div></div>
</div>
<div class="config-section">
<div class="config-section-title">朗读引擎</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">📱</span>
<div>
<span class="config-item-label">系统 TTS</span>
<div style="font-size:11px;color:var(--green);">推荐 · 离线可用</div>
</div>
</div>
<span style="color:var(--primary);font-size:18px;"></span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">☁️</span>
<div>
<span class="config-item-label">在线语音合成</span>
<div style="font-size:11px;color:var(--text-secondary);">需网络 · 音质更佳</div>
</div>
</div>
<span class="config-item-value"></span>
</div>
</div>
<div class="config-section">
<div class="config-section-title">朗读设置</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🗣️</span>
<span class="config-item-label">语速</span>
</div>
<span class="config-item-value">正常 </span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🎵</span>
<span class="config-item-label">音调</span>
</div>
<span class="config-item-value">标准 </span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🔉</span>
<span class="config-item-label">音量</span>
</div>
<span class="config-item-value">80% </span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🇨🇳</span>
<span class="config-item-label">朗读语言</span>
</div>
<span class="config-item-value">中文 </span>
</div>
</div>
<div class="config-section">
<div class="config-section-title">使用预览</div>
<div style="padding:12px 16px;">
<div style="background:linear-gradient(135deg, rgba(175,82,222,0.08), rgba(255,149,0,0.06));border-radius:var(--radius-md);padding:16px;">
<div style="font-size:15px;line-height:1.7;margin-bottom:12px;">人生如逆旅,我亦是行人。</div>
<div style="display:flex;align-items:center;gap:6px;">
<span style="flex:1;font-size:13px;color:var(--text-secondary);">—— 苏轼</span>
<span style="width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:var(--primary);font-size:16px;">🌐</span>
<span style="width:28px;height:28px;display:flex;align-items:center;justify-content:center;color:var(--purple);font-size:16px;">🔊</span>
<span style="font-size:16px;"></span>
<span style="font-size:16px;">❤️</span>
</div>
<div style="margin-top:12px;background:rgba(175,82,222,0.08);border-radius:8px;padding:12px;">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
<span style="font-size:16px;">🎙️</span>
<span style="font-size:13px;font-weight:600;">正在朗读</span>
<span style="font-size:11px;padding:2px 8px;background:rgba(175,82,222,0.12);color:var(--purple);border-radius:8px;">1.0x</span>
</div>
<div style="height:4px;background:rgba(175,82,222,0.15);border-radius:2px;">
<div style="width:35%;height:100%;background:var(--purple);border-radius:2px;"></div>
</div>
<div style="display:flex;justify-content:space-between;font-size:10px;color:var(--text-hint);margin-top:4px;">
<span>0:03</span><span>0:08</span>
</div>
</div>
</div>
</div>
</div>
<div class="config-section">
<div class="config-section-title">朗读记录</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">📊</span>
<span class="config-item-label">累计朗读</span>
</div>
<span class="config-item-value">56 次</span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🕐</span>
<div>
<span class="config-item-label" style="font-size:14px;">人生如逆旅,我亦是行人。</span>
<div style="font-size:11px;color:var(--text-hint);">系统TTS · 5分钟前</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🕐</span>
<div>
<span class="config-item-label" style="font-size:14px;">山有木兮木有枝...</span>
<div style="font-size:11px;color:var(--text-hint);">Edge TTS · 30分钟前</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🗑️</span>
<span class="config-item-label" style="color:var(--red);">清除朗读记录</span>
</div>
</div>
</div>
<div class="config-section">
<div class="config-section-title">使用场景</div>
<div style="padding:8px 16px 12px;">
<div style="display:flex;flex-wrap:wrap;gap:8px;">
<span style="padding:6px 12px;background:rgba(175,82,222,0.1);color:var(--purple);border-radius:16px;font-size:13px;font-weight:500;">🃏 每日推荐卡片</span>
<span style="padding:6px 12px;background:rgba(175,82,222,0.1);color:var(--purple);border-radius:16px;font-size:13px;font-weight:500;">📖 句子广场列表</span>
<span style="padding:6px 12px;background:rgba(142,142,147,0.08);color:var(--text-secondary);border-radius:16px;font-size:13px;font-weight:500;">📝 笔记编辑 (即将支持)</span>
<span style="padding:6px 12px;background:rgba(142,142,147,0.08);color:var(--text-secondary);border-radius:16px;font-size:13px;font-weight:500;">🌐 翻译结果朗读 (即将支持)</span>
</div>
</div>
</div>
<div class="config-section">
<div class="config-section-title">反馈与建议</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">💬</span>
<span class="config-item-label">提交意见</span>
</div>
<span class="config-item-value">帮助我们改进 </span>
</div>
</div>
</div>
</div>
<div class="phone-label">文本朗读 — 插件详情页</div>
</div>
<!-- Phone 6: 在线引擎选择 -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"> 文本朗读</span>
<span class="title">在线语音合成</span>
<span class="action"></span>
</div>
<div style="padding:16px;">
<div style="font-size:13px;color:var(--text-secondary);margin-bottom:12px;">选择在线语音合成服务(需网络连接)</div>
<div style="background:var(--card-bg);border-radius:var(--radius-md);overflow:hidden;">
<div class="config-item" style="background:rgba(175,82,222,0.06);">
<div class="config-item-left">
<span class="config-item-icon">🤖</span>
<div>
<div class="config-item-label">Edge TTS</div>
<div style="font-size:12px;color:var(--text-secondary);">微软Edge在线语音 · 高音质 · 免费</div>
</div>
</div>
<span style="color:var(--purple);font-size:18px;"></span>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🇨🇳</span>
<div>
<div class="config-item-label">百度语音合成</div>
<div style="font-size:12px;color:var(--text-secondary);">国内直连 · 需申请Key · 高音质</div>
</div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">⚙️</span>
<div>
<div class="config-item-label">自定义 API</div>
<div style="font-size:12px;color:var(--text-secondary);">配置自己的语音合成接口</div>
</div>
</div>
</div>
</div>
<div style="margin-top:16px;padding:12px;background:rgba(255,149,0,0.08);border-radius:var(--radius-sm);font-size:13px;color:var(--orange);line-height:1.5;">
💡 推荐使用系统TTS作为默认引擎在线引擎作为备选。系统TTS无需网络响应更快在线引擎音质更好但需要网络连接。
</div>
</div>
</div>
</div>
<div class="phone-label">在线语音合成引擎选择</div>
</div>
</div>
<!-- TTS Engine Comparison -->
<table class="comparison-table">
<thead>
<tr>
<th>特性</th>
<th>📱 系统 TTS</th>
<th>☁️ 在线语音合成</th>
</tr>
</thead>
<tbody>
<tr><td>网络要求</td><td>❌ 无需网络</td><td>✅ 需要网络</td></tr>
<tr><td>音质</td><td>⭐⭐⭐ 标准</td><td>⭐⭐⭐⭐⭐ 高品质</td></tr>
<tr><td>响应速度</td><td>⚡ 极快</td><td>🔄 需加载</td></tr>
<tr><td>跨平台</td><td>✅ 全平台</td><td>✅ 全平台</td></tr>
<tr><td>语音选择</td><td>系统内置</td><td>丰富多样</td></tr>
<tr><td>成本</td><td>免费</td><td>免费/需Key</td></tr>
<tr><td>实现方式</td><td>flutter_tts</td><td>HTTP API / WebSocket</td></tr>
</tbody>
</table>
</div>
<!-- ===== Section 5: Card Integration ===== -->
<div id="card-integration">
<div class="section-title"><span class="emoji">🃏</span> 卡片集成效果</div>
<div class="section-desc">插件启用后,在主页每日推荐卡片和句子广场列表卡片的操作区域注入功能按钮。</div>
<div class="phone-grid">
<!-- Phone 7: Daily Card with buttons -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"></span>
<span class="title">闲言</span>
<span class="action"></span>
</div>
<div class="card-preview-area">
<div style="font-size:13px;color:var(--text-secondary);margin-bottom:8px;">✨ 每日推荐</div>
<div class="daily-card">
<div class="daily-card-header">
<span>📖 一言</span>
<span style="margin-left:auto;">1/5</span>
</div>
<div class="daily-card-text">
生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。
</div>
<div class="daily-card-footer">
<span class="daily-card-author">—— 维维安·格林</span>
<!-- NEW: Plugin buttons -->
<button class="card-action-btn translate-btn" title="翻译">🌐</button>
<button class="card-action-btn tts-btn" title="朗读">🔊</button>
<!-- Existing buttons -->
<button class="card-action-btn fav-btn" title="收藏"></button>
<button class="card-action-btn like-btn" title="点赞">❤️</button>
</div>
</div>
<div style="font-size:13px;color:var(--text-secondary);margin:16px 0 8px;">📖 句子广场</div>
<div class="sentence-card">
<div class="sentence-card-inner">
<div class="sentence-card-accent"></div>
<div class="sentence-card-content">
<div class="sentence-card-feed">
<span>💬 一言</span>
<span style="margin-left:auto;">👁 1.2k</span>
</div>
<div class="sentence-card-text">山有木兮木有枝,心悦君兮君不知。</div>
<div class="sentence-card-stats">
<span>👍 328</span>
<span>⭐ 156</span>
</div>
<div class="sentence-card-actions">
<span class="sentence-card-author">—— 越人歌</span>
<!-- NEW: Plugin buttons -->
<button class="card-action-btn translate-btn" style="width:28px;height:28px;font-size:14px;" title="翻译">🌐</button>
<button class="card-action-btn tts-btn" style="width:28px;height:28px;font-size:14px;" title="朗读">🔊</button>
<!-- Existing buttons -->
<button class="card-action-btn fav-btn" style="width:28px;height:28px;font-size:14px;"></button>
<button class="card-action-btn like-btn" style="width:28px;height:28px;font-size:14px;">❤️</button>
</div>
</div>
</div>
</div>
<div class="sentence-card">
<div class="sentence-card-inner">
<div class="sentence-card-accent" style="background:#AF52DE;"></div>
<div class="sentence-card-content">
<div class="sentence-card-feed">
<span>📜 诗词</span>
<span style="margin-left:auto;">👁 856</span>
</div>
<div class="sentence-card-text">人生如逆旅,我亦是行人。</div>
<div class="sentence-card-stats">
<span>👍 512</span>
<span>⭐ 289</span>
</div>
<div class="sentence-card-actions">
<span class="sentence-card-author">—— 苏轼</span>
<button class="card-action-btn translate-btn" style="width:28px;height:28px;font-size:14px;">🌐</button>
<button class="card-action-btn tts-btn" style="width:28px;height:28px;font-size:14px;">🔊</button>
<button class="card-action-btn fav-btn" style="width:28px;height:28px;font-size:14px;"></button>
<button class="card-action-btn like-btn" style="width:28px;height:28px;font-size:14px;">🤍</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="phone-label">主页 — 插件按钮注入效果</div>
</div>
<!-- Phone 8: Before/After comparison -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"></span>
<span class="title">对比效果</span>
<span class="action"></span>
</div>
<div class="card-preview-area">
<div style="font-size:13px;color:var(--red);margin-bottom:8px;font-weight:600;">❌ 插件未启用</div>
<div class="daily-card" style="opacity:0.6;">
<div class="daily-card-text" style="font-size:15px;">生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。</div>
<div class="daily-card-footer">
<span class="daily-card-author" style="font-size:13px;">—— 维维安·格林</span>
<button class="card-action-btn fav-btn" style="width:28px;height:28px;font-size:14px;"></button>
<button class="card-action-btn like-btn" style="width:28px;height:28px;font-size:14px;">❤️</button>
</div>
</div>
<div style="font-size:13px;color:var(--green);margin:16px 0 8px;font-weight:600;">✅ 仅翻译守护启用</div>
<div class="daily-card">
<div class="daily-card-text" style="font-size:15px;">生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。</div>
<div class="daily-card-footer">
<span class="daily-card-author" style="font-size:13px;">—— 维维安·格林</span>
<button class="card-action-btn translate-btn active" style="width:28px;height:28px;font-size:14px;">🌐</button>
<button class="card-action-btn fav-btn" style="width:28px;height:28px;font-size:14px;"></button>
<button class="card-action-btn like-btn" style="width:28px;height:28px;font-size:14px;">❤️</button>
</div>
</div>
<div style="font-size:13px;color:var(--purple);margin:16px 0 8px;font-weight:600;">✅ 两个插件都启用</div>
<div class="daily-card">
<div class="daily-card-text" style="font-size:15px;">生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。</div>
<div class="daily-card-footer">
<span class="daily-card-author" style="font-size:13px;">—— 维维安·格林</span>
<button class="card-action-btn translate-btn active" style="width:28px;height:28px;font-size:14px;">🌐</button>
<button class="card-action-btn tts-btn active" style="width:28px;height:28px;font-size:14px;">🔊</button>
<button class="card-action-btn fav-btn" style="width:28px;height:28px;font-size:14px;"></button>
<button class="card-action-btn like-btn" style="width:28px;height:28px;font-size:14px;">❤️</button>
</div>
</div>
</div>
</div>
</div>
<div class="phone-label">插件启用前后对比</div>
</div>
</div>
</div>
<!-- ===== Section 6: Popup Demo ===== -->
<div id="popup-demo">
<div class="section-title"><span class="emoji">💬</span> 弹窗交互效果</div>
<div class="section-desc">点击翻译按钮弹出翻译结果 Sheet点击朗读按钮弹出朗读控制 Sheet。均采用 iOS 风格底部弹出面板。</div>
<div class="phone-grid">
<!-- Phone 9: Translate Popup -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"></span>
<span class="title">闲言</span>
<span class="action"></span>
</div>
<div class="card-preview-area" style="opacity:0.5;">
<div class="daily-card">
<div class="daily-card-text" style="font-size:15px;">生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。</div>
<div class="daily-card-footer">
<span class="daily-card-author" style="font-size:13px;">—— 维维安·格林</span>
<button class="card-action-btn translate-btn active" style="width:28px;height:28px;font-size:14px;">🌐</button>
<button class="card-action-btn tts-btn" style="width:28px;height:28px;font-size:14px;">🔊</button>
<button class="card-action-btn fav-btn" style="width:28px;height:28px;font-size:14px;"></button>
<button class="card-action-btn like-btn" style="width:28px;height:28px;font-size:14px;">❤️</button>
</div>
</div>
</div>
<!-- Translate Popup -->
<div class="popup-overlay">
<div class="popup-sheet">
<div class="popup-handle"></div>
<div class="popup-title">🌐 翻译结果</div>
<div class="popup-body">
<div class="translate-result">
<div class="translate-result-label">🌐 英文翻译 · Bing</div>
<div class="translate-result-text">Life isn't about waiting for the storm to pass, it's about learning to dance in the rain.</div>
</div>
<div class="translate-original">
<div class="translate-original-label">📝 原文 · 自动检测: 中文</div>
<div class="translate-original-text">生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。</div>
</div>
<div style="display:flex;gap:8px;margin-top:12px;">
<button style="flex:1;padding:10px;border-radius:var(--radius-sm);background:var(--primary-light);color:var(--primary);font-size:14px;font-weight:500;border:none;cursor:pointer;">📋 复制翻译</button>
<button style="flex:1;padding:10px;border-radius:var(--radius-sm);background:rgba(175,82,222,0.1);color:var(--purple);font-size:14px;font-weight:500;border:none;cursor:pointer;">🔊 朗读翻译</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="phone-label">翻译弹窗 — 底部Sheet</div>
</div>
<!-- Phone 10: TTS Popup -->
<div>
<div class="phone-frame">
<div class="phone-screen">
<div class="ios-navbar">
<span class="back"></span>
<span class="title">闲言</span>
<span class="action"></span>
</div>
<div class="card-preview-area" style="opacity:0.5;">
<div class="daily-card">
<div class="daily-card-text" style="font-size:15px;">山有木兮木有枝,心悦君兮君不知。</div>
<div class="daily-card-footer">
<span class="daily-card-author" style="font-size:13px;">—— 越人歌</span>
<button class="card-action-btn translate-btn" style="width:28px;height:28px;font-size:14px;">🌐</button>
<button class="card-action-btn tts-btn active" style="width:28px;height:28px;font-size:14px;">🔊</button>
<button class="card-action-btn fav-btn" style="width:28px;height:28px;font-size:14px;"></button>
<button class="card-action-btn like-btn" style="width:28px;height:28px;font-size:14px;">❤️</button>
</div>
</div>
</div>
<!-- TTS Popup -->
<div class="popup-overlay">
<div class="popup-sheet">
<div class="popup-handle"></div>
<div class="popup-title">🔊 文本朗读</div>
<div class="popup-body">
<div class="tts-player">
<div class="tts-player-header">
<span style="font-size:20px;">🎙️</span>
<span class="tts-player-title">正在朗读</span>
<span class="tts-speed-label">1.0x</span>
</div>
<div class="tts-player-text">山有木兮木有枝,心悦君兮君不知。</div>
<div class="tts-controls">
<button class="tts-btn secondary"></button>
<button class="tts-btn play"></button>
<button class="tts-btn secondary"></button>
<div style="flex:1;display:flex;flex-direction:column;gap:4px;">
<div class="tts-progress">
<div class="tts-progress-fill"></div>
</div>
<div style="display:flex;justify-content:space-between;font-size:11px;color:var(--text-hint);">
<span>0:03</span>
<span>0:08</span>
</div>
</div>
</div>
</div>
<div style="margin-top:12px;background:var(--card-bg);border-radius:var(--radius-md);overflow:hidden;">
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">🗣️</span>
<span class="config-item-label">语速</span>
</div>
<div style="flex:1;margin:0 12px;height:4px;background:rgba(175,82,222,0.15);border-radius:2px;position:relative;">
<div style="position:absolute;left:0;top:0;width:50%;height:100%;background:var(--purple);border-radius:2px;"></div>
<div style="position:absolute;left:50%;top:-4px;width:12px;height:12px;background:var(--purple);border-radius:50%;transform:translateX(-50%);"></div>
</div>
</div>
<div class="config-item">
<div class="config-item-left">
<span class="config-item-icon">📱</span>
<span class="config-item-label">引擎</span>
</div>
<span class="config-item-value">系统TTS </span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="phone-label">朗读弹窗 — 底部Sheet</div>
</div>
</div>
</div>
<!-- ===== Section 7: Architecture ===== -->
<div id="architecture">
<div class="section-title"><span class="emoji">🏗️</span> 架构设计</div>
<div class="section-desc">插件系统采用 Riverpod 状态管理 + KvStorage 持久化,与现有翻译/TTS服务复用零侵入式注入卡片按钮。</div>
<div class="flow-diagram">
<div class="flow-title">插件系统架构图</div>
<div style="text-align:center;font-size:13px;line-height:2.2;">
<div style="margin-bottom:12px;">
<span style="padding:6px 16px;background:var(--primary-light);color:var(--primary);border-radius:8px;font-weight:600;">PluginProvider (Riverpod)</span>
</div>
<div style="color:var(--text-hint);">↓ 管理插件状态</div>
<div style="display:flex;justify-content:center;gap:16px;margin:8px 0;flex-wrap:wrap;">
<span style="padding:6px 12px;background:rgba(52,199,89,0.1);color:var(--green);border-radius:8px;">TranslatePlugin</span>
<span style="padding:6px 12px;background:rgba(175,82,222,0.1);color:var(--purple);border-radius:8px;">TtsPlugin</span>
</div>
<div style="color:var(--text-hint);">↓ 复用现有服务</div>
<div style="display:flex;justify-content:center;gap:16px;margin:8px 0;flex-wrap:wrap;">
<span style="padding:6px 12px;background:rgba(255,149,0,0.1);color:var(--orange);border-radius:8px;">TranslateApiService</span>
<span style="padding:6px 12px;background:rgba(255,149,0,0.1);color:var(--orange);border-radius:8px;">TtsService</span>
<span style="padding:6px 12px;background:rgba(255,149,0,0.1);color:var(--orange);border-radius:8px;">OnlineTtsService (新)</span>
</div>
<div style="color:var(--text-hint);">↓ 注入UI组件</div>
<div style="display:flex;justify-content:center;gap:16px;margin:8px 0;flex-wrap:wrap;">
<span style="padding:6px 12px;background:rgba(0,122,255,0.1);color:var(--primary);border-radius:8px;">DailyCard</span>
<span style="padding:6px 12px;background:rgba(0,122,255,0.1);color:var(--primary);border-radius:8px;">SentenceCard</span>
</div>
</div>
</div>
<div class="annotation">
<strong>关键设计决策:</strong>
<br>1. 插件状态独立于通用设置,通过 <code>PluginProvider</code> 统一管理,避免耦合
<br>2. 翻译功能复用现有 <code>TranslateApiService</code> 体系Bing/Google/MyMemory/AppWorlds/Libre/自定义),不重复造轮子
<br>3. TTS 在现有 <code>TtsService</code> 基础上新增 <code>OnlineTtsService</code>,支持 Edge TTS 等在线引擎
<br>4. 卡片按钮通过 <code>ref.watch(pluginProvider)</code> 条件渲染,未启用时完全不构建 Widget
<br>5. 弹窗使用 <code>StupidSimpleSheet</code>(项目已有依赖),保持 iOS 风格一致性
</div>
<table class="comparison-table">
<thead>
<tr>
<th>文件</th>
<th>类型</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr><td><code>plugin_provider.dart</code></td><td>状态管理</td><td>插件启用状态 + 配置持久化</td></tr>
<tr><td><code>plugin_page.dart</code></td><td>页面</td><td>插件列表页</td></tr>
<tr><td><code>plugin_detail_page.dart</code></td><td>页面</td><td>插件详情/配置页</td></tr>
<tr><td><code>translate_plugin.dart</code></td><td>服务</td><td>翻译插件逻辑复用TranslateApiService</td></tr>
<tr><td><code>online_tts_service.dart</code></td><td>服务</td><td>在线语音合成Edge TTS等</td></tr>
<tr><td><code>translate_sheet.dart</code></td><td>组件</td><td>翻译结果底部弹窗</td></tr>
<tr><td><code>tts_player_sheet.dart</code></td><td>组件</td><td>朗读控制底部弹窗</td></tr>
</tbody>
</table>
</div>
<!-- ===== Section 8: API Test ===== -->
<div id="api-test">
<div class="section-title"><span class="emoji">🔌</span> 接口方案</div>
<div class="section-desc">翻译接口复用现有翻译助手的服务体系在线TTS新增 Edge TTS 免费接口。</div>
<table class="comparison-table">
<thead>
<tr>
<th>接口</th>
<th>类型</th>
<th>端点</th>
<th>费用</th>
<th>跨平台</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Bing Translator</strong></td>
<td>翻译</td>
<td><code>api.cognitive.microsofttranslator.com</code></td>
<td>免费</td>
<td></td>
</tr>
<tr>
<td><strong>Google Translate</strong></td>
<td>翻译</td>
<td><code>translate.googleapis.com</code></td>
<td>免费</td>
<td></td>
</tr>
<tr>
<td><strong>Edge TTS</strong></td>
<td>在线朗读</td>
<td><code>speech.platform.bing.com/consumer/speech/synthesize</code></td>
<td>免费</td>
<td></td>
</tr>
<tr>
<td><strong>系统 TTS</strong></td>
<td>离线朗读</td>
<td>flutter_tts (原生)</td>
<td>免费</td>
<td></td>
</tr>
</tbody>
</table>
<div class="annotation">
<strong>Edge TTS 方案说明:</strong>
<br>Edge TTS 是微软为 Edge 浏览器提供的免费在线语音合成服务,通过 WebSocket 连接 <code>speech.platform.bing.com</code>,支持 100+ 语音(含中文晓晓、云扬等),音质接近真人。无需 API Key通过模拟 Edge 浏览器的 WebSocket 握手即可使用。该方案已被多个开源项目验证(如 edge-tts Python 库),稳定可靠。
<br><br>
<strong>降级策略:</strong>系统 TTS离线→ Edge TTS在线→ 静默失败提示
</div>
</div>
</div>
<script>
function scrollToSection(id) {
document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
document.querySelectorAll('.nav-chip').forEach(c => c.classList.remove('active'));
event.target.classList.add('active');
}
document.querySelectorAll('.ios-toggle').forEach(toggle => {
toggle.addEventListener('click', function() {
this.classList.toggle('on');
});
});
</script>
</body>
</html>