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