refactor: 更新URL哈希处理逻辑 feat: 添加聊天消息存储支持 docs: 更新API控制器基类文档 chore: 删除无用脚本文件 fix: 修复分类模型返回类型问题 feat: 添加回执登录功能 build: 更新依赖项配置 style: 统一HTML模板中的哈希ID引用格式 ci: 添加部署和检查脚本
522 lines
13 KiB
HTML
522 lines
13 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>句子详情Sheet — 设计方案预览</title>
|
||
<style>
|
||
:root {
|
||
--bg-primary: #000000;
|
||
--bg-card: #1C1C1E;
|
||
--bg-secondary: #2C2C2E;
|
||
--bg-tertiary: #3A3A3C;
|
||
--text-primary: #FFFFFF;
|
||
--text-secondary: #8E8E93;
|
||
--text-hint: #636366;
|
||
--accent: #0A84FF;
|
||
--accent-green: #30D158;
|
||
--accent-orange: #FF9F0A;
|
||
--accent-pink: #FF375F;
|
||
--accent-purple: #BF5AF2;
|
||
--border: rgba(255,255,255,0.08);
|
||
--glass-bg: rgba(28,28,30,0.85);
|
||
--glass-border: rgba(255,255,255,0.12);
|
||
--radius-lg: 20px;
|
||
--radius-md: 14px;
|
||
--radius-sm: 10px;
|
||
--radius-pill: 100px;
|
||
}
|
||
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
||
body {
|
||
font-family: -apple-system, 'SF Pro Display', 'SF Pro Text', 'Helvetica Neue', sans-serif;
|
||
background: var(--bg-primary);
|
||
color: var(--text-primary);
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 20px;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
h1 {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 8px;
|
||
letter-spacing: -0.2px;
|
||
}
|
||
|
||
.subtitle {
|
||
font-size: 13px;
|
||
color: var(--text-hint);
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.phone-frame {
|
||
width: 390px;
|
||
max-width: 100%;
|
||
background: var(--bg-primary);
|
||
border-radius: 44px;
|
||
border: 1px solid var(--glass-border);
|
||
overflow: hidden;
|
||
position: relative;
|
||
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
|
||
}
|
||
|
||
.sheet-container {
|
||
padding: 0 0 34px 0;
|
||
max-height: 85vh;
|
||
overflow-y: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
scrollbar-width: none;
|
||
}
|
||
.sheet-container::-webkit-scrollbar { display: none; }
|
||
|
||
.drag-handle {
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 12px 0 8px;
|
||
}
|
||
.drag-handle span {
|
||
width: 36px;
|
||
height: 5px;
|
||
background: var(--text-hint);
|
||
border-radius: 100px;
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.content-area {
|
||
padding: 0 20px;
|
||
}
|
||
|
||
.source-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
margin-bottom: 16px;
|
||
}
|
||
.source-icon {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 8px;
|
||
background: linear-gradient(135deg, var(--accent-purple), var(--accent-pink));
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 16px;
|
||
}
|
||
.source-info {
|
||
flex: 1;
|
||
}
|
||
.source-name {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
}
|
||
.source-meta {
|
||
font-size: 11px;
|
||
color: var(--text-hint);
|
||
margin-top: 1px;
|
||
}
|
||
.views-badge {
|
||
font-size: 11px;
|
||
color: var(--text-hint);
|
||
background: var(--bg-secondary);
|
||
padding: 3px 8px;
|
||
border-radius: var(--radius-pill);
|
||
}
|
||
|
||
.stats-row {
|
||
display: flex;
|
||
gap: 12px;
|
||
margin-bottom: 16px;
|
||
}
|
||
.stat-chip {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
background: var(--bg-secondary);
|
||
padding: 4px 10px;
|
||
border-radius: var(--radius-pill);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
|
||
.sentence-card {
|
||
background: linear-gradient(135deg,
|
||
rgba(10,132,255,0.08) 0%,
|
||
rgba(191,90,242,0.05) 100%
|
||
);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 20px;
|
||
margin-bottom: 16px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.sentence-card::before {
|
||
content: '"';
|
||
position: absolute;
|
||
top: -8px;
|
||
left: 12px;
|
||
font-size: 72px;
|
||
font-weight: 700;
|
||
color: var(--accent);
|
||
opacity: 0.12;
|
||
line-height: 1;
|
||
}
|
||
.sentence-text {
|
||
font-size: 18px;
|
||
font-weight: 500;
|
||
line-height: 1.7;
|
||
color: var(--text-primary);
|
||
position: relative;
|
||
z-index: 1;
|
||
word-break: break-word;
|
||
user-select: text;
|
||
-webkit-user-select: text;
|
||
}
|
||
|
||
.selectable-hint {
|
||
font-size: 10px;
|
||
color: var(--text-hint);
|
||
text-align: right;
|
||
margin-top: 4px;
|
||
opacity: 0.6;
|
||
}
|
||
|
||
.author-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.author-avatar {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, var(--accent-orange), var(--accent-pink));
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 13px;
|
||
}
|
||
.author-name {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
font-weight: 500;
|
||
}
|
||
|
||
.summary-box {
|
||
background: var(--bg-secondary);
|
||
border-radius: var(--radius-md);
|
||
padding: 14px 16px;
|
||
margin-bottom: 16px;
|
||
display: flex;
|
||
gap: 10px;
|
||
align-items: flex-start;
|
||
}
|
||
.summary-box .icon {
|
||
font-size: 16px;
|
||
flex-shrink: 0;
|
||
margin-top: 1px;
|
||
}
|
||
.summary-box .text {
|
||
font-size: 13px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.5;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.html-content-box {
|
||
background: var(--bg-secondary);
|
||
border-radius: var(--radius-md);
|
||
padding: 14px 16px;
|
||
margin-bottom: 16px;
|
||
border-left: 3px solid var(--accent);
|
||
}
|
||
.html-content-box .label {
|
||
font-size: 11px;
|
||
color: var(--accent);
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
margin-bottom: 6px;
|
||
}
|
||
.html-content-box .text {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.6;
|
||
word-break: break-word;
|
||
}
|
||
|
||
.action-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 8px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.action-btn {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 12px 4px;
|
||
background: var(--bg-secondary);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
.action-btn:hover {
|
||
background: var(--bg-tertiary);
|
||
transform: scale(1.02);
|
||
}
|
||
.action-btn:active {
|
||
transform: scale(0.96);
|
||
}
|
||
.action-btn .emoji {
|
||
font-size: 22px;
|
||
}
|
||
.action-btn .label {
|
||
font-size: 10px;
|
||
color: var(--text-secondary);
|
||
font-weight: 500;
|
||
}
|
||
.action-btn.active .emoji { filter: none; }
|
||
.action-btn.active .label { color: var(--accent); }
|
||
|
||
.secondary-actions {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.secondary-btn {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
padding: 10px;
|
||
background: var(--bg-secondary);
|
||
border: 1px solid var(--border);
|
||
border-radius: var(--radius-md);
|
||
font-size: 13px;
|
||
color: var(--text-secondary);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
.secondary-btn:hover {
|
||
background: var(--bg-tertiary);
|
||
}
|
||
|
||
.primary-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
width: 100%;
|
||
padding: 14px;
|
||
background: var(--accent);
|
||
border: none;
|
||
border-radius: var(--radius-md);
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
color: #fff;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
.primary-btn:hover { opacity: 0.9; }
|
||
.primary-btn:active { transform: scale(0.98); }
|
||
|
||
.danger-row {
|
||
display: flex;
|
||
gap: 8px;
|
||
margin-top: 8px;
|
||
}
|
||
.danger-btn {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 4px;
|
||
padding: 8px;
|
||
background: transparent;
|
||
border: 1px solid rgba(255,55,95,0.2);
|
||
border-radius: var(--radius-sm);
|
||
font-size: 12px;
|
||
color: var(--accent-pink);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
.danger-btn:hover {
|
||
background: rgba(255,55,95,0.1);
|
||
}
|
||
|
||
.divider {
|
||
height: 1px;
|
||
background: var(--border);
|
||
margin: 16px 0;
|
||
}
|
||
|
||
.section-label {
|
||
font-size: 11px;
|
||
color: var(--text-hint);
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.note {
|
||
margin-top: 32px;
|
||
padding: 16px;
|
||
background: var(--bg-card);
|
||
border-radius: var(--radius-md);
|
||
border: 1px solid var(--border);
|
||
max-width: 390px;
|
||
width: 100%;
|
||
}
|
||
.note h3 {
|
||
font-size: 14px;
|
||
color: var(--accent);
|
||
margin-bottom: 8px;
|
||
}
|
||
.note ul {
|
||
list-style: none;
|
||
padding: 0;
|
||
}
|
||
.note li {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
padding: 4px 0;
|
||
padding-left: 16px;
|
||
position: relative;
|
||
line-height: 1.5;
|
||
}
|
||
.note li::before {
|
||
content: '•';
|
||
position: absolute;
|
||
left: 0;
|
||
color: var(--accent);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>📱 句子详情 Sheet 设计方案</h1>
|
||
<p class="subtitle">iOS 26 风格 · 暗色模式 · 可滚动 · HTML标签处理 · 布局不溢出</p>
|
||
|
||
<div class="phone-frame">
|
||
<div class="sheet-container">
|
||
<div class="drag-handle"><span></span></div>
|
||
|
||
<div class="content-area">
|
||
<!-- 来源信息 -->
|
||
<div class="source-row">
|
||
<div class="source-icon">📖</div>
|
||
<div class="source-info">
|
||
<div class="source-name">一言· Hitokoto</div>
|
||
<div class="source-meta">2026-04-30 · 文学</div>
|
||
</div>
|
||
<div class="views-badge">👁 1.2k</div>
|
||
</div>
|
||
|
||
<!-- 互动统计 -->
|
||
<div class="stats-row">
|
||
<div class="stat-chip">👍 328</div>
|
||
<div class="stat-chip">⭐ 156</div>
|
||
<div class="stat-chip">💬 42</div>
|
||
</div>
|
||
|
||
<!-- 句子卡片 -->
|
||
<div class="sentence-card">
|
||
<div class="sentence-text">
|
||
生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。每一次跌倒都是成长的开始,每一次泪水都浇灌着明天的花朵。
|
||
</div>
|
||
<div class="selectable-hint">长按可选择文字 · 支持全选/复制</div>
|
||
</div>
|
||
|
||
<!-- 作者 -->
|
||
<div class="author-row">
|
||
<div class="author-avatar">✍</div>
|
||
<div class="author-name">—— 维维安·格林</div>
|
||
</div>
|
||
|
||
<!-- 摘要 -->
|
||
<div class="summary-box">
|
||
<span class="icon">💡</span>
|
||
<span class="text">这句话告诉我们,面对困难时不要消极等待,而应积极应对,在逆境中寻找美好与成长的机会。</span>
|
||
</div>
|
||
|
||
<!-- HTML内容(处理<P>等标签) -->
|
||
<div class="html-content-box">
|
||
<div class="label">📝 原文内容</div>
|
||
<div class="text">
|
||
生活不是等待暴风雨过去,而是学会在雨中翩翩起舞。<br><br>每一次跌倒都是成长的开始,每一次泪水都浇灌着明天的花朵。<br><br>—— 出自《在雨中起舞》
|
||
</div>
|
||
</div>
|
||
|
||
<div class="divider"></div>
|
||
|
||
<!-- 主操作区 -->
|
||
<div class="section-label">快捷操作</div>
|
||
<div class="action-grid">
|
||
<div class="action-btn active">
|
||
<span class="emoji">❤️</span>
|
||
<span class="label">已点赞</span>
|
||
</div>
|
||
<div class="action-btn">
|
||
<span class="emoji">⭐</span>
|
||
<span class="label">收藏</span>
|
||
</div>
|
||
<div class="action-btn">
|
||
<span class="emoji">📖</span>
|
||
<span class="label">稍后读</span>
|
||
</div>
|
||
<div class="action-btn">
|
||
<span class="emoji">↗️</span>
|
||
<span class="label">分享</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 次要操作 -->
|
||
<div class="secondary-actions">
|
||
<div class="secondary-btn">🎨 创作卡片</div>
|
||
</div>
|
||
|
||
<!-- 主按钮 -->
|
||
<button class="primary-btn">✏️ 编辑此句</button>
|
||
|
||
<!-- 危险操作 -->
|
||
<div class="danger-row">
|
||
<div class="danger-btn">🚫 屏蔽</div>
|
||
<div class="danger-btn">🚨 举报</div>
|
||
<div class="danger-btn">🙈 不感兴趣</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="note">
|
||
<h3>📋 设计要点</h3>
|
||
<ul>
|
||
<li><strong>可滚动容器</strong> — sheet-container 设置 max-height + overflow-y: auto,文本再多也不会溢出</li>
|
||
<li><strong>HTML标签处理</strong> — <P> <br> 等标签解析为换行,<em> <strong> 解析为加粗/斜体,其他标签剥离</li>
|
||
<li><strong>长按选择</strong> — 句子文本支持长按选择,弹出系统菜单(全选/复制/分享等)</li>
|
||
<li><strong>保留半高Sheet</strong> — 使用原有 showHalf 半高弹窗</li>
|
||
<li><strong>去掉评论按钮</strong> — 操作区不再包含评论入口</li>
|
||
<li><strong>句子卡片</strong> — 渐变背景+引号装饰,视觉焦点突出</li>
|
||
<li><strong>操作分层</strong> — 快捷操作(4宫格) → 次要操作(双列) → 主按钮 → 危险操作(小字)</li>
|
||
<li><strong>来源信息</strong> — 图标+名称+日期+浏览量,信息密度高但不拥挤</li>
|
||
<li><strong>统计chips</strong> — 点赞/收藏/评论数,pill形状紧凑显示</li>
|
||
<li><strong>iOS 26风格</strong> — 大圆角、毛玻璃感、系统色、SF字体</li>
|
||
</ul>
|
||
</div>
|
||
|
||
</body>
|
||
</html>
|