Files
xianyan/docs/preview/experimental_features_preview.html
Developer adfa0af825 chore: 汇总2026-05-30全量更新
### 详细变更:
1.  **文档与配置**:更新AGENTS.md添加命令超时约束,升级Rive依赖至0.14.7并替换平台插件引用
2.  **UI优化**:重构AppInfo页面布局、移除图表冗余配置、锁定部分系统设置项
3.  **功能增强**:
    - 新增工具面板拖拽状态管理与介绍弹窗
    - 新增进度页面编辑/重排/清空用户进度功能
    - 新增摇一摇路由作用域拦截逻辑
4.  **体验优化**:
    - 统一外部链接跳转弹窗,添加文件打开确认逻辑
    - 修复设备卡片IP溢出、Android权限声明问题
    - 后台任务初始化增加协议校验
5.  **代码重构**:拆分工具面板配置、拖拽逻辑与动画参数,优化状态管理代码
6.  **工具脚本**:新增协议文件上传脚本
2026-05-30 05:29:50 +08:00

1382 lines
33 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" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>闲言 — 🧪 实验中的功能 预览</title>
<!--
@File: experimental_features_preview.html
@Created: 2026-05-30
@Updated: 2026-05-30
@Name: 实验中的功能预览页
@Desc: iOS 26风格实验功能与问题列表预览页面
@LastUpdate: 初始创建包含功能预览Tab和问题列表Tab
-->
<style>
:root {
--primary: #6C5CE7;
--primary-light: #A29BFE;
--primary-dark: #5A4BD1;
--primary-gradient: linear-gradient(135deg, #6C5CE7 0%, #A29BFE 100%);
--bg: #F2F2F7;
--bg-card: #FFFFFF;
--bg-elevated: rgba(255,255,255,0.85);
--text1: #1C1C1E;
--text2: #3C3C43;
--text3: #8E8E93;
--text-inverse: #FFFFFF;
--border: rgba(60,60,67,0.1);
--glass-bg: rgba(255,255,255,0.72);
--glass-border: rgba(255,255,255,0.35);
--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);
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 999px;
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 32px;
--font-xs: 11px;
--font-sm: 12px;
--font-md: 14px;
--font-lg: 17px;
--font-xl: 20px;
--font-xxl: 22px;
--font-display: 28px;
--blue: #007AFF;
--green: #34C759;
--orange: #FF9500;
--purple: #AF52DE;
--teal: #5AC8FA;
--red: #FF3B30;
--yellow: #FFCC00;
--status-dev: #FF9500;
--status-test: #007AFF;
--status-preview: #34C759;
--severity-high: #FF3B30;
--severity-mid: #FF9500;
--severity-low: #34C759;
--fix-pending: #FF3B30;
--fix-progress: #FF9500;
--fix-done: #34C759;
}
[data-theme="dark"] {
--bg: #000000;
--bg-card: #1C1C1E;
--bg-elevated: rgba(28,28,30,0.85);
--text1: #F5F5F7;
--text2: #EBEBF5;
--text3: #636366;
--border: rgba(84,84,88,0.36);
--glass-bg: rgba(28,28,30,0.72);
--glass-border: rgba(255,255,255,0.1);
--shadow-sm: 0 1px 3px rgba(0,0,0,0.2);
--shadow-md: 0 4px 12px rgba(0,0,0,0.3);
--shadow-lg: 0 8px 24px rgba(0,0,0,0.4);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif;
background: var(--bg);
color: var(--text1);
-webkit-font-smoothing: antialiased;
min-height: 100vh;
display: flex;
flex-direction: column;
}
/* ========== Header ========== */
.page-header {
background: var(--primary-gradient);
padding: var(--space-xl) var(--space-md) var(--space-lg);
position: relative;
overflow: hidden;
}
.page-header::before {
content: '';
position: absolute;
top: -40%;
right: -10%;
width: 300px;
height: 300px;
background: rgba(255,255,255,0.08);
border-radius: 50%;
pointer-events: none;
}
.page-header::after {
content: '';
position: absolute;
bottom: -30%;
left: -5%;
width: 200px;
height: 200px;
background: rgba(255,255,255,0.05);
border-radius: 50%;
pointer-events: none;
}
.header-content {
max-width: 1200px;
margin: 0 auto;
position: relative;
z-index: 1;
}
.header-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-md);
}
.header-title {
font-size: var(--font-display);
font-weight: 700;
color: var(--text-inverse);
letter-spacing: -0.5px;
}
.header-subtitle {
font-size: var(--font-md);
color: rgba(255,255,255,0.8);
margin-top: var(--space-xs);
}
/* ========== 工具栏按钮 ========== */
.toolbar-btn {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-full);
border: 1px solid rgba(255,255,255,0.3);
background: rgba(255,255,255,0.15);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
color: var(--text-inverse);
font-size: var(--font-sm);
font-weight: 500;
cursor: pointer;
transition: all 0.25s ease;
font-family: inherit;
}
.toolbar-btn:hover {
background: rgba(255,255,255,0.25);
transform: translateY(-1px);
}
.toolbar-btn:active {
transform: scale(0.96);
}
/* ========== Tab 切换 ========== */
.tab-container {
max-width: 1200px;
margin: 0 auto;
padding: var(--space-md) var(--space-md) 0;
width: 100%;
}
.tab-bar {
display: flex;
background: var(--glass-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-radius: var(--radius-xl);
padding: var(--space-xs);
gap: var(--space-xs);
box-shadow: var(--shadow-md);
border: 1px solid var(--glass-border);
position: relative;
}
.tab-item {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-sm);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-lg);
font-size: var(--font-md);
font-weight: 600;
color: var(--text3);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
position: relative;
z-index: 1;
user-select: none;
border: none;
background: none;
font-family: inherit;
}
.tab-item.active {
color: var(--text-inverse);
background: var(--primary);
box-shadow: 0 2px 8px rgba(108,92,231,0.35);
}
.tab-item:not(.active):hover {
color: var(--text1);
background: rgba(108,92,231,0.08);
}
.tab-badge {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 20px;
height: 20px;
padding: 0 6px;
border-radius: var(--radius-full);
font-size: var(--font-xs);
font-weight: 700;
line-height: 1;
}
.tab-item.active .tab-badge {
background: rgba(255,255,255,0.3);
color: var(--text-inverse);
}
.tab-item:not(.active) .tab-badge {
background: rgba(108,92,231,0.12);
color: var(--primary);
}
/* ========== 内容区 ========== */
.main-content {
flex: 1;
max-width: 1200px;
margin: 0 auto;
padding: var(--space-md);
width: 100%;
}
.tab-panel {
display: none;
animation: fadeSlideIn 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.tab-panel.active {
display: block;
}
@keyframes fadeSlideIn {
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ========== 筛选栏 ========== */
.filter-bar {
display: flex;
gap: var(--space-sm);
margin-bottom: var(--space-md);
flex-wrap: wrap;
}
.filter-chip {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
padding: var(--space-sm) var(--space-md);
border-radius: var(--radius-full);
font-size: var(--font-sm);
font-weight: 500;
cursor: pointer;
transition: all 0.25s ease;
border: 1.5px solid var(--border);
background: var(--bg-card);
color: var(--text2);
font-family: inherit;
}
.filter-chip:hover {
border-color: var(--primary-light);
color: var(--primary);
}
.filter-chip.active {
background: var(--primary);
color: var(--text-inverse);
border-color: var(--primary);
box-shadow: 0 2px 8px rgba(108,92,231,0.3);
}
.filter-chip:active {
transform: scale(0.95);
}
/* ========== 功能卡片网格 ========== */
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
gap: var(--space-md);
}
@media (max-width: 640px) {
.features-grid {
grid-template-columns: 1fr;
}
}
/* ========== 功能卡片 ========== */
.feature-card {
background: var(--bg-card);
border-radius: var(--radius-xl);
padding: var(--space-lg);
box-shadow: var(--shadow-sm);
border: 1px solid var(--border);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
position: relative;
overflow: hidden;
}
.feature-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: var(--primary-gradient);
opacity: 0;
transition: opacity 0.3s ease;
}
.feature-card:hover {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
.feature-card:hover::before {
opacity: 1;
}
.feature-card:active {
transform: scale(0.985);
}
.feature-card.expanded {
box-shadow: var(--shadow-lg);
}
.feature-card.expanded::before {
opacity: 1;
}
.card-header {
display: flex;
align-items: flex-start;
gap: var(--space-md);
margin-bottom: var(--space-md);
}
.card-icon {
width: 48px;
height: 48px;
border-radius: var(--radius-lg);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
flex-shrink: 0;
background: linear-gradient(135deg, rgba(108,92,231,0.1) 0%, rgba(162,155,254,0.15) 100%);
}
.card-info {
flex: 1;
min-width: 0;
}
.card-title {
font-size: var(--font-lg);
font-weight: 600;
color: var(--text1);
margin-bottom: var(--space-xs);
line-height: 1.3;
}
.card-desc {
font-size: var(--font-sm);
color: var(--text3);
line-height: 1.5;
}
/* ========== 状态标签 ========== */
.status-tag {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 3px 10px;
border-radius: var(--radius-full);
font-size: var(--font-xs);
font-weight: 600;
letter-spacing: 0.2px;
white-space: nowrap;
}
.status-tag.dev {
background: rgba(255,149,0,0.12);
color: var(--status-dev);
}
.status-tag.test {
background: rgba(0,122,255,0.12);
color: var(--status-test);
}
.status-tag.preview {
background: rgba(52,199,89,0.12);
color: var(--status-preview);
}
.status-dot {
width: 6px;
height: 6px;
border-radius: 50%;
display: inline-block;
}
.status-tag.dev .status-dot { background: var(--status-dev); }
.status-tag.test .status-dot { background: var(--status-test); }
.status-tag.preview .status-dot { background: var(--status-preview); }
/* ========== 进度条 ========== */
.progress-section {
margin-top: var(--space-md);
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-sm);
}
.progress-label {
font-size: var(--font-xs);
color: var(--text3);
font-weight: 500;
}
.progress-value {
font-size: var(--font-xs);
font-weight: 700;
color: var(--primary);
}
.progress-track {
width: 100%;
height: 6px;
background: rgba(108,92,231,0.1);
border-radius: var(--radius-full);
overflow: hidden;
position: relative;
}
.progress-fill {
height: 100%;
border-radius: var(--radius-full);
background: var(--primary-gradient);
transition: width 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94);
position: relative;
}
.progress-fill::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.3) 50%, transparent 100%);
animation: shimmer 2s infinite;
}
@keyframes shimmer {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
/* ========== 卡片展开详情 ========== */
.card-detail {
max-height: 0;
overflow: hidden;
transition: max-height 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94),
margin-top 0.3s ease,
opacity 0.3s ease;
opacity: 0;
}
.feature-card.expanded .card-detail {
max-height: 300px;
margin-top: var(--space-md);
opacity: 1;
}
.detail-divider {
height: 1px;
background: var(--border);
margin-bottom: var(--space-md);
}
.detail-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--space-sm) 0;
}
.detail-label {
font-size: var(--font-sm);
color: var(--text3);
}
.detail-value {
font-size: var(--font-sm);
font-weight: 500;
color: var(--text1);
}
.card-expand-hint {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-xs);
margin-top: var(--space-sm);
font-size: var(--font-xs);
color: var(--text3);
transition: color 0.2s ease;
}
.feature-card:hover .card-expand-hint {
color: var(--primary);
}
.expand-arrow {
display: inline-block;
transition: transform 0.3s ease;
font-size: 10px;
}
.feature-card.expanded .expand-arrow {
transform: rotate(180deg);
}
/* ========== 问题列表 ========== */
.issues-list {
display: flex;
flex-direction: column;
gap: var(--space-sm);
}
.issue-item {
display: flex;
align-items: center;
gap: var(--space-md);
padding: var(--space-md) var(--space-lg);
background: var(--bg-card);
border-radius: var(--radius-xl);
box-shadow: var(--shadow-sm);
border: 1px solid var(--border);
transition: all 0.25s ease;
cursor: pointer;
}
.issue-item:hover {
box-shadow: var(--shadow-md);
transform: translateX(4px);
}
.issue-item:active {
transform: scale(0.99);
}
.issue-severity-icon {
width: 36px;
height: 36px;
border-radius: var(--radius-lg);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
flex-shrink: 0;
}
.issue-severity-icon.high {
background: rgba(255,59,48,0.1);
}
.issue-severity-icon.mid {
background: rgba(255,149,0,0.1);
}
.issue-severity-icon.low {
background: rgba(52,199,89,0.1);
}
.issue-content {
flex: 1;
min-width: 0;
}
.issue-title {
font-size: var(--font-md);
font-weight: 500;
color: var(--text1);
line-height: 1.4;
margin-bottom: var(--space-xs);
}
.issue-meta {
display: flex;
align-items: center;
gap: var(--space-sm);
flex-wrap: wrap;
}
.severity-tag {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 2px 8px;
border-radius: var(--radius-full);
font-size: var(--font-xs);
font-weight: 600;
}
.severity-tag.high {
background: rgba(255,59,48,0.1);
color: var(--severity-high);
}
.severity-tag.mid {
background: rgba(255,149,0,0.1);
color: var(--severity-mid);
}
.severity-tag.low {
background: rgba(52,199,89,0.1);
color: var(--severity-low);
}
.fix-status {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 2px 8px;
border-radius: var(--radius-full);
font-size: var(--font-xs);
font-weight: 600;
}
.fix-status.pending {
background: rgba(255,59,48,0.08);
color: var(--fix-pending);
}
.fix-status.progress {
background: rgba(255,149,0,0.08);
color: var(--fix-progress);
}
.fix-status.done {
background: rgba(52,199,89,0.08);
color: var(--fix-done);
}
.fix-status-dot {
width: 5px;
height: 5px;
border-radius: 50%;
display: inline-block;
}
.fix-status.pending .fix-status-dot { background: var(--fix-pending); }
.fix-status.progress .fix-status-dot { background: var(--fix-progress); }
.fix-status.done .fix-status-dot { background: var(--fix-done); }
.issue-arrow {
color: var(--text3);
font-size: 14px;
flex-shrink: 0;
transition: transform 0.2s ease;
}
.issue-item:hover .issue-arrow {
transform: translateX(3px);
color: var(--primary);
}
/* ========== 统计卡片 ========== */
.stats-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: var(--space-sm);
margin-bottom: var(--space-md);
}
.stat-card {
background: var(--bg-card);
border-radius: var(--radius-xl);
padding: var(--space-md);
text-align: center;
box-shadow: var(--shadow-sm);
border: 1px solid var(--border);
transition: all 0.25s ease;
}
.stat-card:hover {
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.stat-number {
font-size: var(--font-xxl);
font-weight: 700;
color: var(--primary);
line-height: 1.2;
}
.stat-label {
font-size: var(--font-xs);
color: var(--text3);
margin-top: var(--space-xs);
font-weight: 500;
}
/* ========== 页脚 ========== */
.page-footer {
text-align: center;
padding: var(--space-xl) var(--space-md);
color: var(--text3);
font-size: var(--font-sm);
line-height: 1.8;
border-top: 1px solid var(--border);
margin-top: var(--space-xl);
}
.footer-link {
color: var(--primary);
text-decoration: none;
transition: opacity 0.2s ease;
}
.footer-link:hover {
opacity: 0.7;
}
/* ========== 语言切换按钮 ========== */
.lang-toggle {
position: relative;
display: inline-flex;
background: rgba(255,255,255,0.15);
border-radius: var(--radius-full);
padding: 2px;
border: 1px solid rgba(255,255,255,0.25);
}
.lang-option {
padding: var(--space-xs) var(--space-sm);
border-radius: var(--radius-full);
font-size: var(--font-xs);
font-weight: 600;
color: rgba(255,255,255,0.7);
cursor: pointer;
transition: all 0.25s ease;
border: none;
background: none;
font-family: inherit;
}
.lang-option.active {
background: rgba(255,255,255,0.25);
color: var(--text-inverse);
}
.lang-option:hover:not(.active) {
color: rgba(255,255,255,0.9);
}
/* ========== 空状态 ========== */
.empty-state {
text-align: center;
padding: var(--space-xl) var(--space-md);
color: var(--text3);
}
.empty-icon {
font-size: 48px;
margin-bottom: var(--space-md);
}
.empty-text {
font-size: var(--font-md);
font-weight: 500;
}
/* ========== 响应式 ========== */
@media (max-width: 640px) {
.page-header {
padding: var(--space-lg) var(--space-md) var(--space-md);
}
.header-title {
font-size: var(--font-xxl);
}
.header-subtitle {
font-size: var(--font-sm);
}
.features-grid {
grid-template-columns: 1fr;
}
.stats-row {
grid-template-columns: repeat(2, 1fr);
}
.issue-item {
padding: var(--space-md);
}
.tab-item {
font-size: var(--font-sm);
padding: var(--space-sm);
}
}
@media (min-width: 641px) and (max-width: 1024px) {
.features-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* ========== 动画 ========== */
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.status-tag.test .status-dot {
animation: pulse 2s infinite;
}
.fix-status.progress .fix-status-dot {
animation: pulse 1.5s infinite;
}
/* ========== 滚动条美化 ========== */
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(108,92,231,0.2);
border-radius: var(--radius-full);
}
::-webkit-scrollbar-thumb:hover {
background: rgba(108,92,231,0.4);
}
</style>
</head>
<body>
<!-- ==================== Header ==================== -->
<header class="page-header">
<div class="header-content">
<div class="header-top">
<div>
<h1 class="header-title" data-i18n="title">🧪 实验中的功能</h1>
<p class="header-subtitle" data-i18n="subtitle">探索正在开发的新功能与已知问题</p>
</div>
<div style="display:flex;gap:8px;align-items:center;">
<div class="lang-toggle">
<button class="lang-option active" data-lang="zh" onclick="switchLang('zh')"></button>
<button class="lang-option" data-lang="en" onclick="switchLang('en')">EN</button>
</div>
<button class="toolbar-btn" onclick="toggleTheme()" id="themeBtn">🌙</button>
</div>
</div>
</div>
</header>
<!-- ==================== Tab 切换 ==================== -->
<div class="tab-container">
<div class="tab-bar">
<button class="tab-item active" data-tab="features" onclick="switchTab('features')">
<span>🔬</span>
<span data-i18n="tab_features">预览中的功能</span>
<span class="tab-badge">6</span>
</button>
<button class="tab-item" data-tab="issues" onclick="switchTab('issues')">
<span>🐛</span>
<span data-i18n="tab_issues">问题列表</span>
<span class="tab-badge">5</span>
</button>
</div>
</div>
<!-- ==================== 主内容区 ==================== -->
<main class="main-content">
<!-- ===== 功能预览面板 ===== -->
<div class="tab-panel active" id="panel-features">
<div class="stats-row">
<div class="stat-card">
<div class="stat-number">6</div>
<div class="stat-label" data-i18n="stat_total">功能总数</div>
</div>
<div class="stat-card">
<div class="stat-number">2</div>
<div class="stat-label" data-i18n="stat_dev">开发中</div>
</div>
<div class="stat-card">
<div class="stat-number">2</div>
<div class="stat-label" data-i18n="stat_test">测试中</div>
</div>
<div class="stat-card">
<div class="stat-number">2</div>
<div class="stat-label" data-i18n="stat_preview">预览中</div>
</div>
</div>
<div class="features-grid" id="featuresGrid">
<!-- JS 动态渲染 -->
</div>
</div>
<!-- ===== 问题列表面板 ===== -->
<div class="tab-panel" id="panel-issues">
<div class="stats-row">
<div class="stat-card">
<div class="stat-number">5</div>
<div class="stat-label" data-i18n="issue_total">问题总数</div>
</div>
<div class="stat-card">
<div class="stat-number">2</div>
<div class="stat-label" data-i18n="issue_high">高严重度</div>
</div>
<div class="stat-card">
<div class="stat-number">2</div>
<div class="stat-label" data-i18n="issue_mid">中严重度</div>
</div>
<div class="stat-card">
<div class="stat-number">1</div>
<div class="stat-label" data-i18n="issue_done">已修复</div>
</div>
</div>
<div class="filter-bar" id="issueFilter">
<button class="filter-chip active" data-filter="all" onclick="filterIssues('all')">
<span>📋</span> <span data-i18n="filter_all">全部</span>
</button>
<button class="filter-chip" data-filter="pending" onclick="filterIssues('pending')">
<span>🔴</span> <span data-i18n="filter_pending">待修复</span>
</button>
<button class="filter-chip" data-filter="progress" onclick="filterIssues('progress')">
<span>🟡</span> <span data-i18n="filter_progress">修复中</span>
</button>
<button class="filter-chip" data-filter="done" onclick="filterIssues('done')">
<span>🟢</span> <span data-i18n="filter_done">已修复</span>
</button>
</div>
<div class="issues-list" id="issuesList">
<!-- JS 动态渲染 -->
</div>
</div>
</main>
<!-- ==================== 页脚 ==================== -->
<footer class="page-footer">
<div>
<a class="footer-link" href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">滇ICP备2022000863号-18A</a>
</div>
<div>
📧 <a class="footer-link" href="mailto:2821981550@qq.com">2821981550@qq.com</a>
</div>
<div style="margin-top:4px;font-size:11px;opacity:0.6;" data-i18n="footer_note">
闲言 — 让阅读更有温度
</div>
</footer>
<script>
/* ========== 数据定义 ========== */
const featuresData = [
{
icon: '🤖',
name: { zh: 'AI智能摘要', en: 'AI Smart Summary' },
desc: { zh: '自动为长文生成摘要摘要', en: 'Auto-generate summaries for long articles' },
status: 'test',
progress: 70,
detail: {
zh: { owner: 'AI团队', eta: '2026年Q3', tech: 'LLM + NLP' },
en: { owner: 'AI Team', eta: '2026 Q3', tech: 'LLM + NLP' }
}
},
{
icon: '🎨',
name: { zh: '主题商店', en: 'Theme Store' },
desc: { zh: '下载和分享自定义主题', en: 'Download and share custom themes' },
status: 'dev',
progress: 40,
detail: {
zh: { owner: 'UI团队', eta: '2026年Q4', tech: 'Flutter Theme' },
en: { owner: 'UI Team', eta: '2026 Q4', tech: 'Flutter Theme' }
}
},
{
icon: '📊',
name: { zh: '阅读报告', en: 'Reading Report' },
desc: { zh: '年度/月度阅读数据可视化', en: 'Annual/monthly reading data visualization' },
status: 'preview',
progress: 90,
detail: {
zh: { owner: '数据团队', eta: '2026年Q2', tech: 'Charts + Analytics' },
en: { owner: 'Data Team', eta: '2026 Q2', tech: 'Charts + Analytics' }
}
},
{
icon: '🔄',
name: { zh: '跨设备同步', en: 'Cross-device Sync' },
desc: { zh: '实时同步阅读进度和收藏', en: 'Real-time sync reading progress & bookmarks' },
status: 'dev',
progress: 30,
detail: {
zh: { owner: '基础架构组', eta: '2026年Q4', tech: 'WebSocket + CRDT' },
en: { owner: 'Infra Team', eta: '2026 Q4', tech: 'WebSocket + CRDT' }
}
},
{
icon: '🎵',
name: { zh: '语音朗读', en: 'Voice Reading' },
desc: { zh: 'AI语音朗读句子和文章', en: 'AI voice reading for sentences & articles' },
status: 'test',
progress: 60,
detail: {
zh: { owner: 'AI团队', eta: '2026年Q3', tech: 'TTS Engine' },
en: { owner: 'AI Team', eta: '2026 Q3', tech: 'TTS Engine' }
}
},
{
icon: '📱',
name: { zh: '桌面小组件', en: 'Desktop Widgets' },
desc: { zh: 'iOS/Android桌面Widget', en: 'iOS/Android home screen widgets' },
status: 'preview',
progress: 85,
detail: {
zh: { owner: '客户端组', eta: '2026年Q2', tech: 'WidgetKit + Glance' },
en: { owner: 'Client Team', eta: '2026 Q2', tech: 'WidgetKit + Glance' }
}
}
];
const issuesData = [
{
icon: '🔴',
title: { zh: '编辑器在暗色模式下光标不可见', en: 'Cursor invisible in dark mode editor' },
severity: 'high',
fixStatus: 'progress'
},
{
icon: '🟡',
title: { zh: '部分句子收藏后图片不显示', en: 'Images not showing after bookmarking sentences' },
severity: 'mid',
fixStatus: 'pending'
},
{
icon: '🟢',
title: { zh: '文件传输大文件偶尔中断', en: 'Large file transfer occasionally interrupted' },
severity: 'low',
fixStatus: 'done'
},
{
icon: '🔴',
title: { zh: '签到日历跨月显示异常', en: 'Check-in calendar display issue across months' },
severity: 'high',
fixStatus: 'pending'
},
{
icon: '🟡',
title: { zh: '搜索结果排序不够精准', en: 'Search result ranking not precise enough' },
severity: 'mid',
fixStatus: 'progress'
}
];
/* ========== 国际化文案 ========== */
const i18nMap = {
zh: {
title: '🧪 实验中的功能',
subtitle: '探索正在开发的新功能与已知问题',
tab_features: '预览中的功能',
tab_issues: '问题列表',
stat_total: '功能总数',
stat_dev: '开发中',
stat_test: '测试中',
stat_preview: '预览中',
issue_total: '问题总数',
issue_high: '高严重度',
issue_mid: '中严重度',
issue_done: '已修复',
filter_all: '全部',
filter_pending: '待修复',
filter_progress: '修复中',
filter_done: '已修复',
footer_note: '闲言 — 让阅读更有温度',
status_dev: '开发中',
status_test: '测试中',
status_preview: '预览中',
severity_high: '高',
severity_mid: '中',
severity_low: '低',
fix_pending: '待修复',
fix_progress: '修复中',
fix_done: '已修复',
progress_label: '开发进度',
detail_owner: '负责团队',
detail_eta: '预计上线',
detail_tech: '技术方案',
expand_hint: '点击查看详情',
no_result: '暂无匹配的问题'
},
en: {
title: '🧪 Experimental Features',
subtitle: 'Explore new features in development & known issues',
tab_features: 'Preview Features',
tab_issues: 'Issue List',
stat_total: 'Total',
stat_dev: 'In Dev',
stat_test: 'In Test',
stat_preview: 'Preview',
issue_total: 'Total Issues',
issue_high: 'High Severity',
issue_mid: 'Mid Severity',
issue_done: 'Fixed',
filter_all: 'All',
filter_pending: 'Pending',
filter_progress: 'In Progress',
filter_done: 'Fixed',
footer_note: 'XianYan — Make reading warmer',
status_dev: 'In Dev',
status_test: 'In Test',
status_preview: 'Preview',
severity_high: 'High',
severity_mid: 'Medium',
severity_low: 'Low',
fix_pending: 'Pending',
fix_progress: 'In Progress',
fix_done: 'Fixed',
progress_label: 'Progress',
detail_owner: 'Team',
detail_eta: 'ETA',
detail_tech: 'Tech Stack',
expand_hint: 'Tap for details',
no_result: 'No matching issues'
}
};
/* ========== 全局状态 ========== */
let currentLang = 'zh';
let currentFilter = 'all';
/* ========== Tab 切换 ========== */
function switchTab(tabName) {
document.querySelectorAll('.tab-item').forEach(function(t) {
t.classList.toggle('active', t.dataset.tab === tabName);
});
document.querySelectorAll('.tab-panel').forEach(function(p) {
p.classList.remove('active');
});
var panel = document.getElementById('panel-' + tabName);
if (panel) {
panel.classList.add('active');
}
}
/* ========== 主题切换 ========== */
function toggleTheme() {
var html = document.documentElement;
var isDark = html.getAttribute('data-theme') === 'dark';
html.setAttribute('data-theme', isDark ? 'light' : 'dark');
document.getElementById('themeBtn').textContent = isDark ? '🌙' : '☀️';
}
/* ========== 语言切换 ========== */
function switchLang(lang) {
currentLang = lang;
document.querySelectorAll('.lang-option').forEach(function(btn) {
btn.classList.toggle('active', btn.dataset.lang === lang);
});
applyI18n();
renderFeatures();
renderIssues();
}
function applyI18n() {
var texts = i18nMap[currentLang];
document.querySelectorAll('[data-i18n]').forEach(function(el) {
var key = el.getAttribute('data-i18n');
if (texts[key]) {
el.textContent = texts[key];
}
});
}
/* ========== 渲染功能卡片 ========== */
function renderFeatures() {
var grid = document.getElementById('featuresGrid');
var texts = i18nMap[currentLang];
var statusMap = {
dev: texts.status_dev,
test: texts.status_test,
preview: texts.status_preview
};
grid.innerHTML = featuresData.map(function(f, i) {
var detail = f.detail[currentLang];
return '<div class="feature-card" onclick="toggleCard(this)" data-index="' + i + '">' +
'<div class="card-header">' +
'<div class="card-icon">' + f.icon + '</div>' +
'<div class="card-info">' +
'<div class="card-title">' + f.name[currentLang] + '</div>' +
'<div class="card-desc">' + f.desc[currentLang] + '</div>' +
'</div>' +
'<span class="status-tag ' + f.status + '">' +
'<span class="status-dot"></span>' +
statusMap[f.status] +
'</span>' +
'</div>' +
'<div class="progress-section">' +
'<div class="progress-header">' +
'<span class="progress-label">' + texts.progress_label + '</span>' +
'<span class="progress-value">' + f.progress + '%</span>' +
'</div>' +
'<div class="progress-track">' +
'<div class="progress-fill" style="width:' + f.progress + '%"></div>' +
'</div>' +
'</div>' +
'<div class="card-expand-hint">' +
'<span data-i18n="expand_hint">' + texts.expand_hint + '</span>' +
'<span class="expand-arrow">▼</span>' +
'</div>' +
'<div class="card-detail">' +
'<div class="detail-divider"></div>' +
'<div class="detail-row">' +
'<span class="detail-label">' + texts.detail_owner + '</span>' +
'<span class="detail-value">' + detail.owner + '</span>' +
'</div>' +
'<div class="detail-row">' +
'<span class="detail-label">' + texts.detail_eta + '</span>' +
'<span class="detail-value">' + detail.eta + '</span>' +
'</div>' +
'<div class="detail-row">' +
'<span class="detail-label">' + texts.detail_tech + '</span>' +
'<span class="detail-value">' + detail.tech + '</span>' +
'</div>' +
'</div>' +
'</div>';
}).join('');
}
/* ========== 卡片展开/收起 ========== */
function toggleCard(card) {
card.classList.toggle('expanded');
}
/* ========== 渲染问题列表 ========== */
function renderIssues() {
var list = document.getElementById('issuesList');
var texts = i18nMap[currentLang];
var severityMap = {
high: texts.severity_high,
mid: texts.severity_mid,
low: texts.severity_low
};
var fixMap = {
pending: texts.fix_pending,
progress: texts.fix_progress,
done: texts.fix_done
};
var filtered = issuesData.filter(function(issue) {
if (currentFilter === 'all') return true;
return issue.fixStatus === currentFilter;
});
if (filtered.length === 0) {
list.innerHTML = '<div class="empty-state">' +
'<div class="empty-icon">🔍</div>' +
'<div class="empty-text">' + texts.no_result + '</div>' +
'</div>';
return;
}
list.innerHTML = filtered.map(function(issue) {
return '<div class="issue-item">' +
'<div class="issue-severity-icon ' + issue.severity + '">' + issue.icon + '</div>' +
'<div class="issue-content">' +
'<div class="issue-title">' + issue.title[currentLang] + '</div>' +
'<div class="issue-meta">' +
'<span class="severity-tag ' + issue.severity + '">' +
'<span class="fix-status-dot" style="background:var(--severity-' + issue.severity + ')"></span>' +
severityMap[issue.severity] +
'</span>' +
'<span class="fix-status ' + issue.fixStatus + '">' +
'<span class="fix-status-dot"></span>' +
fixMap[issue.fixStatus] +
'</span>' +
'</div>' +
'</div>' +
'<span class="issue-arrow"></span>' +
'</div>';
}).join('');
}
/* ========== 问题筛选 ========== */
function filterIssues(filter) {
currentFilter = filter;
document.querySelectorAll('#issueFilter .filter-chip').forEach(function(chip) {
chip.classList.toggle('active', chip.dataset.filter === filter);
});
renderIssues();
}
/* ========== 初始化 ========== */
document.addEventListener('DOMContentLoaded', function() {
renderFeatures();
renderIssues();
applyI18n();
});
</script>
</body>
</html>