- 新增壁纸图库相关组件(WallpaperGalleryView/WallpaperSearchBar等) - 优化编辑器主题服务和系统UI管理 - 新增虚线边框和拖拽描边风格支持 - 完善今日诗词服务和阅读报告功能 - 修复多个UI问题和空指针异常 - 更新依赖库版本和SVG资源 - 优化交互动画和状态管理 - 补充文档和API测试脚本
1263 lines
49 KiB
HTML
1263 lines
49 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>闲言APP — 壁纸公共组件设计方案</title>
|
||
<style>
|
||
:root {
|
||
--primary: #007AFF;
|
||
--primary-light: #4CD964;
|
||
--bg: #000000;
|
||
--bg-card: #1C1C1E;
|
||
--bg-elevated: #2C2C2E;
|
||
--bg-glass: rgba(28,28,30,0.72);
|
||
--text: #FFFFFF;
|
||
--text-secondary: rgba(255,255,255,0.6);
|
||
--text-hint: rgba(255,255,255,0.35);
|
||
--border: rgba(255,255,255,0.08);
|
||
--border-active: rgba(0,122,255,0.5);
|
||
--radius-sm: 8px;
|
||
--radius-md: 12px;
|
||
--radius-lg: 16px;
|
||
--radius-xl: 20px;
|
||
--shadow: 0 8px 32px rgba(0,0,0,0.4);
|
||
--font: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro Text', system-ui, sans-serif;
|
||
}
|
||
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
||
body {
|
||
font-family: var(--font);
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
min-height: 100vh;
|
||
overflow-x: hidden;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 24px 16px;
|
||
}
|
||
|
||
/* ─── Header ─── */
|
||
.page-header {
|
||
text-align: center;
|
||
padding: 40px 0 32px;
|
||
}
|
||
.page-header h1 {
|
||
font-size: 28px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.5px;
|
||
background: linear-gradient(135deg, #007AFF, #5AC8FA, #4CD964);
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
}
|
||
.page-header p {
|
||
color: var(--text-secondary);
|
||
font-size: 14px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
/* ─── Section ─── */
|
||
.section {
|
||
margin-bottom: 48px;
|
||
}
|
||
.section-title {
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
margin-bottom: 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
.section-desc {
|
||
color: var(--text-secondary);
|
||
font-size: 13px;
|
||
margin-bottom: 20px;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
/* ─── Approach Cards ─── */
|
||
.approach-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||
gap: 16px;
|
||
}
|
||
.approach-card {
|
||
background: var(--bg-card);
|
||
border-radius: var(--radius-lg);
|
||
border: 1px solid var(--border);
|
||
padding: 20px;
|
||
transition: all 0.3s;
|
||
position: relative;
|
||
}
|
||
.approach-card.recommended {
|
||
border-color: var(--primary);
|
||
box-shadow: 0 0 20px rgba(0,122,255,0.15);
|
||
}
|
||
.approach-card .badge {
|
||
position: absolute;
|
||
top: -8px;
|
||
right: 16px;
|
||
background: var(--primary);
|
||
color: white;
|
||
font-size: 11px;
|
||
font-weight: 600;
|
||
padding: 2px 10px;
|
||
border-radius: 10px;
|
||
}
|
||
.approach-card h3 {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
margin-bottom: 8px;
|
||
}
|
||
.approach-card .pros, .approach-card .cons {
|
||
font-size: 12px;
|
||
line-height: 1.8;
|
||
margin-top: 8px;
|
||
}
|
||
.approach-card .pros span { color: #4CD964; }
|
||
.approach-card .cons span { color: #FF9500; }
|
||
|
||
/* ─── Phone Mockup ─── */
|
||
.phone-frame {
|
||
width: 375px;
|
||
max-width: 100%;
|
||
margin: 0 auto;
|
||
background: var(--bg);
|
||
border-radius: 40px;
|
||
border: 3px solid #333;
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow), 0 0 0 1px rgba(255,255,255,0.05);
|
||
position: relative;
|
||
}
|
||
.phone-notch {
|
||
width: 120px;
|
||
height: 28px;
|
||
background: #000;
|
||
border-radius: 0 0 16px 16px;
|
||
margin: 0 auto;
|
||
position: relative;
|
||
z-index: 10;
|
||
}
|
||
.phone-content {
|
||
height: 680px;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
scrollbar-width: none;
|
||
}
|
||
.phone-content::-webkit-scrollbar { display: none; }
|
||
|
||
/* ─── Wallpaper Gallery Component ─── */
|
||
.gallery-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 8px 16px 4px;
|
||
}
|
||
.gallery-header h2 {
|
||
font-size: 17px;
|
||
font-weight: 700;
|
||
}
|
||
.gallery-close {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 14px;
|
||
background: rgba(255,255,255,0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 12px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Source Tabs */
|
||
.source-tabs {
|
||
display: flex;
|
||
gap: 6px;
|
||
padding: 8px 16px;
|
||
overflow-x: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
.source-tabs::-webkit-scrollbar { display: none; }
|
||
.source-tab {
|
||
flex-shrink: 0;
|
||
padding: 6px 12px;
|
||
border-radius: 999px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
background: rgba(255,255,255,0.06);
|
||
border: 1px solid transparent;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
white-space: nowrap;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
}
|
||
.source-tab.active {
|
||
background: rgba(0,122,255,0.15);
|
||
border-color: rgba(0,122,255,0.4);
|
||
color: #4DA3FF;
|
||
}
|
||
.source-tab .speed {
|
||
font-size: 9px;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
/* Category Tabs */
|
||
.category-tabs {
|
||
display: flex;
|
||
gap: 6px;
|
||
padding: 4px 16px 8px;
|
||
overflow-x: auto;
|
||
scrollbar-width: none;
|
||
}
|
||
.category-tabs::-webkit-scrollbar { display: none; }
|
||
.category-tab {
|
||
flex-shrink: 0;
|
||
padding: 4px 10px;
|
||
border-radius: 999px;
|
||
font-size: 11px;
|
||
font-weight: 500;
|
||
background: transparent;
|
||
border: 1px solid rgba(255,255,255,0.06);
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
white-space: nowrap;
|
||
}
|
||
.category-tab.active {
|
||
background: rgba(0,122,255,0.08);
|
||
border-color: rgba(0,122,255,0.3);
|
||
color: #4DA3FF;
|
||
}
|
||
|
||
/* Search Bar */
|
||
.search-bar {
|
||
margin: 4px 16px 10px;
|
||
padding: 8px 12px;
|
||
background: rgba(255,255,255,0.06);
|
||
border-radius: 10px;
|
||
font-size: 13px;
|
||
color: var(--text-hint);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
/* Masonry Grid */
|
||
.masonry {
|
||
columns: 2;
|
||
column-gap: 8px;
|
||
padding: 0 12px 16px;
|
||
}
|
||
.masonry-item {
|
||
break-inside: avoid;
|
||
margin-bottom: 8px;
|
||
border-radius: var(--radius-md);
|
||
overflow: hidden;
|
||
position: relative;
|
||
cursor: pointer;
|
||
transition: transform 0.2s;
|
||
}
|
||
.masonry-item:hover { transform: scale(1.02); }
|
||
.masonry-item img {
|
||
width: 100%;
|
||
display: block;
|
||
border-radius: var(--radius-md);
|
||
}
|
||
.masonry-item .overlay {
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
padding: 8px;
|
||
background: linear-gradient(transparent, rgba(0,0,0,0.7));
|
||
border-radius: 0 0 var(--radius-md) var(--radius-md);
|
||
}
|
||
.masonry-item .overlay .title {
|
||
font-size: 10px;
|
||
font-weight: 500;
|
||
color: rgba(255,255,255,0.85);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
.masonry-item .overlay .meta {
|
||
font-size: 8px;
|
||
color: rgba(255,255,255,0.5);
|
||
margin-top: 2px;
|
||
display: flex;
|
||
gap: 6px;
|
||
}
|
||
.masonry-item .select-check {
|
||
position: absolute;
|
||
top: 6px;
|
||
right: 6px;
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 10px;
|
||
background: var(--primary);
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 10px;
|
||
}
|
||
.masonry-item.selected .select-check { display: flex; }
|
||
.masonry-item.selected { outline: 2px solid var(--primary); outline-offset: -2px; }
|
||
|
||
/* Apply Button */
|
||
.apply-bar {
|
||
padding: 10px 16px;
|
||
background: rgba(28,28,30,0.9);
|
||
backdrop-filter: blur(20px);
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
.apply-btn {
|
||
width: 100%;
|
||
padding: 12px;
|
||
border-radius: var(--radius-md);
|
||
background: var(--primary);
|
||
color: white;
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
border: none;
|
||
cursor: pointer;
|
||
text-align: center;
|
||
}
|
||
.apply-btn:disabled {
|
||
opacity: 0.4;
|
||
cursor: default;
|
||
}
|
||
|
||
/* ─── Drag Border Demo ─── */
|
||
.drag-demo-area {
|
||
display: flex;
|
||
gap: 32px;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
.drag-demo-box {
|
||
width: 200px;
|
||
height: 260px;
|
||
background: var(--bg-card);
|
||
border-radius: var(--radius-lg);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.drag-demo-box .content {
|
||
width: 120px;
|
||
height: 80px;
|
||
background: linear-gradient(135deg, #667eea, #764ba2);
|
||
border-radius: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: white;
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
position: relative;
|
||
}
|
||
|
||
/* Dashed border style */
|
||
.drag-demo-box.dashed .content {
|
||
outline: 2px dashed rgba(0,122,255,0.8);
|
||
outline-offset: 4px;
|
||
}
|
||
.drag-demo-box.dashed .content::before,
|
||
.drag-demo-box.dashed .content::after {
|
||
content: '';
|
||
position: absolute;
|
||
width: 10px;
|
||
height: 10px;
|
||
background: white;
|
||
border: 2px solid var(--primary);
|
||
border-radius: 2px;
|
||
}
|
||
.drag-demo-box.dashed .content::before { top: -9px; left: -9px; }
|
||
.drag-demo-box.dashed .content::after { top: -9px; right: -9px; }
|
||
.drag-demo-box.dashed .corner-bl,
|
||
.drag-demo-box.dashed .corner-br {
|
||
position: absolute;
|
||
width: 10px;
|
||
height: 10px;
|
||
background: white;
|
||
border: 2px solid var(--primary);
|
||
border-radius: 2px;
|
||
}
|
||
.drag-demo-box.dashed .corner-bl { bottom: -9px; left: -9px; }
|
||
.drag-demo-box.dashed .corner-br { bottom: -9px; right: -9px; }
|
||
|
||
/* Glow border style */
|
||
.drag-demo-box.glow .content {
|
||
outline: 2px solid rgba(0,122,255,0.6);
|
||
outline-offset: 4px;
|
||
box-shadow: 0 0 12px rgba(0,122,255,0.4), 0 0 24px rgba(0,122,255,0.2), inset 0 0 8px rgba(0,122,255,0.1);
|
||
animation: glow-pulse 2s ease-in-out infinite;
|
||
}
|
||
@keyframes glow-pulse {
|
||
0%, 100% { box-shadow: 0 0 12px rgba(0,122,255,0.4), 0 0 24px rgba(0,122,255,0.2); }
|
||
50% { box-shadow: 0 0 18px rgba(0,122,255,0.6), 0 0 36px rgba(0,122,255,0.3); }
|
||
}
|
||
|
||
.drag-label {
|
||
text-align: center;
|
||
margin-top: 12px;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* ─── Rich Text Demo ─── */
|
||
.richtext-demo {
|
||
background: var(--bg-card);
|
||
border-radius: var(--radius-lg);
|
||
border: 1px solid var(--border);
|
||
overflow: hidden;
|
||
max-width: 600px;
|
||
margin: 0 auto;
|
||
}
|
||
.richtext-toolbar {
|
||
display: flex;
|
||
gap: 2px;
|
||
padding: 8px 12px;
|
||
background: rgba(255,255,255,0.03);
|
||
border-bottom: 1px solid var(--border);
|
||
flex-wrap: wrap;
|
||
}
|
||
.richtext-toolbar .tool-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
border-radius: 6px;
|
||
background: transparent;
|
||
border: none;
|
||
color: var(--text-secondary);
|
||
font-size: 14px;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.15s;
|
||
}
|
||
.richtext-toolbar .tool-btn:hover { background: rgba(255,255,255,0.08); }
|
||
.richtext-toolbar .tool-btn.active { background: rgba(0,122,255,0.2); color: #4DA3FF; }
|
||
.richtext-toolbar .divider {
|
||
width: 1px;
|
||
height: 20px;
|
||
background: var(--border);
|
||
margin: 6px 4px;
|
||
}
|
||
.richtext-canvas {
|
||
padding: 20px;
|
||
min-height: 200px;
|
||
}
|
||
.richtext-canvas h2 {
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
margin-bottom: 8px;
|
||
}
|
||
.richtext-canvas p {
|
||
font-size: 14px;
|
||
line-height: 1.7;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 8px;
|
||
}
|
||
.richtext-canvas .bold { font-weight: 700; color: var(--text); }
|
||
.richtext-canvas .italic { font-style: italic; }
|
||
.richtext-canvas .underline { text-decoration: underline; }
|
||
.richtext-canvas .strikethrough { text-decoration: line-through; }
|
||
.richtext-canvas blockquote {
|
||
border-left: 3px solid var(--primary);
|
||
padding-left: 12px;
|
||
margin: 8px 0;
|
||
color: var(--text-secondary);
|
||
font-style: italic;
|
||
}
|
||
.richtext-canvas ul {
|
||
padding-left: 20px;
|
||
margin: 8px 0;
|
||
}
|
||
.richtext-canvas li {
|
||
font-size: 14px;
|
||
line-height: 1.7;
|
||
color: var(--text-secondary);
|
||
}
|
||
.richtext-canvas code {
|
||
background: rgba(255,255,255,0.06);
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
font-family: 'SF Mono', Menlo, monospace;
|
||
font-size: 12px;
|
||
color: #FF9500;
|
||
}
|
||
|
||
/* ─── Icon Mapping Table ─── */
|
||
.icon-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 13px;
|
||
}
|
||
.icon-table th {
|
||
text-align: left;
|
||
padding: 10px 12px;
|
||
background: rgba(255,255,255,0.03);
|
||
border-bottom: 1px solid var(--border);
|
||
font-weight: 600;
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
}
|
||
.icon-table td {
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
vertical-align: middle;
|
||
}
|
||
.icon-table tr:hover td { background: rgba(255,255,255,0.02); }
|
||
.icon-table .icon-preview {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
.icon-table .icon-preview .cupertino {
|
||
color: var(--primary);
|
||
font-size: 16px;
|
||
}
|
||
.icon-table .icon-preview .fallback {
|
||
font-size: 12px;
|
||
color: var(--text-hint);
|
||
}
|
||
.icon-table .tag {
|
||
display: inline-block;
|
||
padding: 1px 6px;
|
||
border-radius: 4px;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
}
|
||
.icon-table .tag.cupertino { background: rgba(0,122,255,0.15); color: #4DA3FF; }
|
||
.icon-table .tag.svg { background: rgba(255,149,0,0.15); color: #FF9500; }
|
||
.icon-table .tag.emoji { background: rgba(255,59,48,0.15); color: #FF3B30; }
|
||
|
||
/* ─── Library Table ─── */
|
||
.lib-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 13px;
|
||
}
|
||
.lib-table th {
|
||
text-align: left;
|
||
padding: 10px 12px;
|
||
background: rgba(255,255,255,0.03);
|
||
border-bottom: 1px solid var(--border);
|
||
font-weight: 600;
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
}
|
||
.lib-table td {
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
.lib-table .priority {
|
||
display: inline-block;
|
||
padding: 1px 8px;
|
||
border-radius: 4px;
|
||
font-size: 10px;
|
||
font-weight: 600;
|
||
}
|
||
.lib-table .priority.p1 { background: rgba(255,59,48,0.15); color: #FF3B30; }
|
||
.lib-table .priority.p2 { background: rgba(255,149,0,0.15); color: #FF9500; }
|
||
.lib-table .priority.p3 { background: rgba(52,199,89,0.15); color: #34C759; }
|
||
|
||
/* ─── Two-column layout for comparison ─── */
|
||
.two-col {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 24px;
|
||
}
|
||
@media (max-width: 768px) {
|
||
.two-col { grid-template-columns: 1fr; }
|
||
.approach-grid { grid-template-columns: 1fr; }
|
||
.drag-demo-area { flex-direction: column; align-items: center; }
|
||
}
|
||
|
||
/* ─── Tab Switch ─── */
|
||
.tab-switch {
|
||
display: flex;
|
||
background: var(--bg-card);
|
||
border-radius: 10px;
|
||
padding: 3px;
|
||
margin-bottom: 20px;
|
||
max-width: 400px;
|
||
}
|
||
.tab-switch .tab {
|
||
flex: 1;
|
||
padding: 8px 16px;
|
||
border-radius: 8px;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
color: var(--text-secondary);
|
||
}
|
||
.tab-switch .tab.active {
|
||
background: var(--primary);
|
||
color: white;
|
||
}
|
||
|
||
/* ─── Loaded indicator ─── */
|
||
.loaded-badge {
|
||
position: absolute;
|
||
top: 6px;
|
||
left: 6px;
|
||
background: rgba(52,199,89,0.9);
|
||
color: white;
|
||
font-size: 8px;
|
||
font-weight: 600;
|
||
padding: 1px 5px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* ─── Skeleton ─── */
|
||
.skeleton {
|
||
background: linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.08) 50%, rgba(255,255,255,0.04) 75%);
|
||
background-size: 200% 100%;
|
||
animation: shimmer 1.5s infinite;
|
||
border-radius: var(--radius-md);
|
||
}
|
||
@keyframes shimmer {
|
||
0% { background-position: 200% 0; }
|
||
100% { background-position: -200% 0; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="container">
|
||
|
||
<!-- Header -->
|
||
<div class="page-header">
|
||
<h1>🎨 壁纸公共组件 + 编辑器增强 设计方案</h1>
|
||
<p>闲言APP v3.8.0 · 2026-05-04 · 5项需求整合设计</p>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<!-- Section 1: 方案对比 -->
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">📐 壁纸组件提取 — 三种方案对比</div>
|
||
<div class="section-desc">
|
||
当前问题:编辑器 WallpaperPanel 和灵感页 TemplateGalleryPage 代码重复、风格不一致、图片不显示。<br>
|
||
目标:提取公共组件,统一风格,修复 bug,两个场景复用。
|
||
</div>
|
||
|
||
<div class="approach-grid">
|
||
<!-- Approach 1 -->
|
||
<div class="approach-card">
|
||
<h3>🔧 方案A: 渐进增强</h3>
|
||
<p style="font-size:12px;color:var(--text-secondary);">保留现有两个组件,逐步抽取公共方法到 Service/Provider 层</p>
|
||
<div class="pros"><span>✅</span> 风险最低,改动最小</div>
|
||
<div class="cons"><span>⚠️</span> UI风格仍不统一,两套维护成本</div>
|
||
<div class="cons"><span>⚠️</span> 没有根本解决设计不一致问题</div>
|
||
</div>
|
||
|
||
<!-- Approach 2 (Recommended) -->
|
||
<div class="approach-card recommended">
|
||
<span class="badge">推荐</span>
|
||
<h3>🏗️ 方案B: 全量提取公共组件</h3>
|
||
<p style="font-size:12px;color:var(--text-secondary);">新建 WallpaperGalleryView 公共组件,替换两处旧代码,统一设计</p>
|
||
<div class="pros"><span>✅</span> 单一数据源,风格统一</div>
|
||
<div class="pros"><span>✅</span> 瀑布流+已加载优先+分类"全部"</div>
|
||
<div class="pros"><span>✅</span> 编辑器抽屉/全屏页面两种模式</div>
|
||
<div class="cons"><span>⚠️</span> 工作量稍大,需同时改两处调用</div>
|
||
</div>
|
||
|
||
<!-- Approach 3 -->
|
||
<div class="approach-card">
|
||
<h3>🧩 方案C: 组合式小组件</h3>
|
||
<p style="font-size:12px;color:var(--text-secondary);">拆分为 SourceBar/CategoryBar/MasonryGrid 等原子组件,按需组合</p>
|
||
<div class="pros"><span>✅</span> 最大灵活性,可自由组合</div>
|
||
<div class="cons"><span>⚠️</span> 组件数量多,复杂度高</div>
|
||
<div class="cons"><span>⚠️</span> 过度设计,当前只有2个场景</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<!-- Section 2: 壁纸公共组件 UI 原型 -->
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">🖼️ 壁纸公共组件 — UI原型</div>
|
||
<div class="section-desc">
|
||
方案B详细设计:顶栏横向滑动(源+分类+搜索)+ 全局瀑布流 + 已加载优先 + 分类"全部"<br>
|
||
两种使用模式:①编辑器抽屉面板(选择后应用为图层)②灵感页全屏页面(浏览+预览+下载)
|
||
</div>
|
||
|
||
<div class="tab-switch" id="modeSwitch">
|
||
<div class="tab active" onclick="switchMode('drawer')">📱 编辑器抽屉模式</div>
|
||
<div class="tab" onclick="switchMode('fullscreen')">🖥️ 灵感页全屏模式</div>
|
||
</div>
|
||
|
||
<div class="two-col">
|
||
<!-- Phone Mockup -->
|
||
<div>
|
||
<div class="phone-frame" id="phoneFrame">
|
||
<div class="phone-notch"></div>
|
||
<div class="phone-content" id="phoneContent">
|
||
<!-- Drawer Mode -->
|
||
<div id="drawerMode">
|
||
<div class="gallery-header">
|
||
<h2>🖼 在线壁纸</h2>
|
||
<div class="gallery-close">✕</div>
|
||
</div>
|
||
|
||
<!-- Source Tabs -->
|
||
<div class="source-tabs">
|
||
<div class="source-tab active">📷 Unsplash <span class="speed">138ms</span></div>
|
||
<div class="source-tab">🎞 Pexels <span class="speed">136ms</span></div>
|
||
<div class="source-tab">🌍 必应 <span class="speed">245ms</span></div>
|
||
<div class="source-tab">🚀 NASA <span class="speed">133ms</span></div>
|
||
<div class="source-tab">🔍 Pixabay <span class="speed">140ms</span></div>
|
||
<div class="source-tab">🏙 WallSt <span class="speed">140ms</span></div>
|
||
<div class="source-tab">🎨 动漫 <span class="speed">2.4s</span></div>
|
||
<div class="source-tab">🌸 二次元 <span class="speed">2.8s</span></div>
|
||
</div>
|
||
|
||
<!-- Category Tabs -->
|
||
<div class="category-tabs">
|
||
<div class="category-tab active">🌐 全部</div>
|
||
<div class="category-tab">🌿 自然</div>
|
||
<div class="category-tab">🐾 动物</div>
|
||
<div class="category-tab">🏛 建筑</div>
|
||
<div class="category-tab">💻 科技</div>
|
||
<div class="category-tab">🎨 抽象</div>
|
||
<div class="category-tab">👤 人物</div>
|
||
<div class="category-tab">✈️ 旅行</div>
|
||
<div class="category-tab">🍜 美食</div>
|
||
<div class="category-tab">🌸 动漫</div>
|
||
</div>
|
||
|
||
<!-- Search -->
|
||
<div class="search-bar">🔍 搜索壁纸…</div>
|
||
|
||
<!-- Masonry Grid -->
|
||
<div class="masonry">
|
||
<div class="masonry-item selected">
|
||
<div class="loaded-badge">已缓存</div>
|
||
<img src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=300&h=400&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Mountain Lake</div>
|
||
<div class="meta"><span>3840×2160</span><span>👁 12.3k</span></div>
|
||
</div>
|
||
<div class="select-check">✓</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300&h=200&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Foggy Forest</div>
|
||
<div class="meta"><span>2560×1440</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<div class="loaded-badge">已缓存</div>
|
||
<img src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=300&h=350&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Sunlight Forest</div>
|
||
<div class="meta"><span>1920×1080</span><span>👁 8.5k</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=300&h=250&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Tropical Beach</div>
|
||
<div class="meta"><span>4096×2160</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1519681393784-d120267933ba?w=300&h=450&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Starry Mountain</div>
|
||
<div class="meta"><span>3840×2160</span><span>👁 25.1k</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<div class="loaded-badge">已缓存</div>
|
||
<img src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=300&h=280&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Golden Sunset</div>
|
||
<div class="meta"><span>2560×1440</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<div class="skeleton" style="height:180px;"></div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<div class="skeleton" style="height:220px;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Apply Button -->
|
||
<div class="apply-bar">
|
||
<button class="apply-btn">🖼 设为背景图层</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Fullscreen Mode (hidden by default) -->
|
||
<div id="fullscreenMode" style="display:none;">
|
||
<div class="gallery-header" style="padding-top:4px;">
|
||
<h2>🎨 壁纸模板</h2>
|
||
<div style="display:flex;gap:8px;align-items:center;">
|
||
<div class="gallery-close" style="background:rgba(255,255,255,0.06);">🔍</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Source Tabs -->
|
||
<div class="source-tabs">
|
||
<div class="source-tab active">📷 Unsplash <span class="speed">138ms</span></div>
|
||
<div class="source-tab">🎞 Pexels <span class="speed">136ms</span></div>
|
||
<div class="source-tab">🌍 必应 <span class="speed">245ms</span></div>
|
||
<div class="source-tab">🚀 NASA <span class="speed">133ms</span></div>
|
||
<div class="source-tab">🔍 Pixabay <span class="speed">140ms</span></div>
|
||
<div class="source-tab">🏙 WallSt <span class="speed">140ms</span></div>
|
||
<div class="source-tab">🖼 360 <span class="speed">264ms</span></div>
|
||
<div class="source-tab">🏔 精选 <span class="speed">345ms</span></div>
|
||
<div class="source-tab">🎲 多多 <span class="speed">2.1s</span></div>
|
||
<div class="source-tab">🔮 增强必应 <span class="speed">371ms</span></div>
|
||
<div class="source-tab">🎨 动漫 <span class="speed">2.4s</span></div>
|
||
<div class="source-tab">🌸 二次元 <span class="speed">2.8s</span></div>
|
||
</div>
|
||
|
||
<!-- Category Tabs -->
|
||
<div class="category-tabs">
|
||
<div class="category-tab active">🌐 全部</div>
|
||
<div class="category-tab">🌿 自然</div>
|
||
<div class="category-tab">🐾 动物</div>
|
||
<div class="category-tab">🏛 建筑</div>
|
||
<div class="category-tab">💻 科技</div>
|
||
<div class="category-tab">🎨 抽象</div>
|
||
<div class="category-tab">👤 人物</div>
|
||
<div class="category-tab">✈️ 旅行</div>
|
||
<div class="category-tab">🍜 美食</div>
|
||
<div class="category-tab">🌸 动漫</div>
|
||
</div>
|
||
|
||
<!-- Masonry Grid (fullscreen has more items) -->
|
||
<div class="masonry">
|
||
<div class="masonry-item">
|
||
<div class="loaded-badge">已缓存</div>
|
||
<img src="https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=300&h=400&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Mountain Lake</div>
|
||
<div class="meta"><span>3840×2160</span><span>👁 12.3k</span><span>❤ 892</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=300&h=200&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Foggy Forest</div>
|
||
<div class="meta"><span>2560×1440</span><span>❤ 456</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<div class="loaded-badge">已缓存</div>
|
||
<img src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=300&h=350&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Sunlight Forest</div>
|
||
<div class="meta"><span>1920×1080</span><span>👁 8.5k</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=300&h=250&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Tropical Beach</div>
|
||
<div class="meta"><span>4096×2160</span><span>❤ 1.2k</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1519681393784-d120267933ba?w=300&h=450&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Starry Mountain</div>
|
||
<div class="meta"><span>3840×2160</span><span>👁 25.1k</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<div class="loaded-badge">已缓存</div>
|
||
<img src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=300&h=280&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Golden Sunset</div>
|
||
<div class="meta"><span>2560×1440</span><span>❤ 723</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=300&h=220&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Green Hills</div>
|
||
<div class="meta"><span>1920×1200</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="masonry-item">
|
||
<img src="https://images.unsplash.com/photo-1505144808419-1957a94ca61e?w=300&h=380&fit=crop" alt="" loading="lazy">
|
||
<div class="overlay">
|
||
<div class="title">Ocean Waves</div>
|
||
<div class="meta"><span>3840×2160</span><span>👁 15.7k</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p style="text-align:center;color:var(--text-hint);font-size:11px;margin-top:12px;">👆 点击顶部标签切换 编辑器抽屉 / 灵感页全屏 两种模式</p>
|
||
</div>
|
||
|
||
<!-- Design Spec -->
|
||
<div>
|
||
<h3 style="font-size:16px;font-weight:600;margin-bottom:16px;">📋 公共组件设计规格</h3>
|
||
|
||
<div style="background:var(--bg-card);border-radius:var(--radius-lg);border:1px solid var(--border);padding:16px;margin-bottom:16px;">
|
||
<h4 style="font-size:13px;font-weight:600;margin-bottom:8px;">🏗️ 组件架构</h4>
|
||
<pre style="font-size:11px;line-height:1.8;color:var(--text-secondary);font-family:'SF Mono',Menlo,monospace;">
|
||
WallpaperGalleryView (公共组件)
|
||
├── WallpaperGalleryMode enum
|
||
│ ├── drawer → 编辑器抽屉面板
|
||
│ └── fullscreen → 灵感页全屏
|
||
├── WallpaperSourceBar → 源切换横滑
|
||
├── WallpaperCategoryBar → 分类横滑(含"全部")
|
||
├── WallpaperSearchBar → 搜索栏
|
||
├── WallpaperMasonryGrid → 瀑布流网格
|
||
│ ├── 已加载优先排序
|
||
│ ├── CachedNetworkImage
|
||
│ └── 选择态/预览态
|
||
├── WallpaperApplyBar → 应用按钮(仅drawer)
|
||
└── WallpaperPreviewSheet → 大图预览(仅fullscreen)</pre>
|
||
</div>
|
||
|
||
<div style="background:var(--bg-card);border-radius:var(--radius-lg);border:1px solid var(--border);padding:16px;margin-bottom:16px;">
|
||
<h4 style="font-size:13px;font-weight:600;margin-bottom:8px;">🐛 图片不显示 Bug 修复</h4>
|
||
<div style="font-size:12px;line-height:1.8;color:var(--text-secondary);">
|
||
<p><span style="color:#FF3B30;">根因:</span> API返回的 <code>thumbnail_url</code> / <code>preview_url</code> 可能为空字符串</p>
|
||
<p><span style="color:#4CD964;">修复:</span> 三级回退策略 thumbnailUrl → previewUrl → imageUrl</p>
|
||
<p><span style="color:#4CD964;">修复:</span> 空URL时显示渐变占位+重试按钮</p>
|
||
<p><span style="color:#4CD964;">修复:</span> CachedNetworkImage 添加 http headers (User-Agent)</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--bg-card);border-radius:var(--radius-lg);border:1px solid var(--border);padding:16px;margin-bottom:16px;">
|
||
<h4 style="font-size:13px;font-weight:600;margin-bottom:8px;">⚡ 已加载优先策略</h4>
|
||
<div style="font-size:12px;line-height:1.8;color:var(--text-secondary);">
|
||
<p>1. 切换源/分类时,已缓存的图片排到前面</p>
|
||
<p>2. 使用 <code>CachedNetworkImage</code> 的缓存管理器检测本地缓存</p>
|
||
<p>3. 已缓存项显示绿色"已缓存"标记</p>
|
||
<p>4. 未缓存项显示骨架屏 shimmer 动画</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--bg-card);border-radius:var(--radius-lg);border:1px solid var(--border);padding:16px;">
|
||
<h4 style="font-size:13px;font-weight:600;margin-bottom:8px;">🌐 分类增加"全部"</h4>
|
||
<div style="font-size:12px;line-height:1.8;color:var(--text-secondary);">
|
||
<p>WallpaperCategory 枚举首位增加 <code>all('all', '🌐', '全部')</code></p>
|
||
<p>默认选中"全部",不传 category 参数给 API</p>
|
||
<p>⚠️ 已有 all 枚举值,需确认 API 传参逻辑</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<!-- Section 3: 拖拽描边效果 -->
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">✏️ 拖拽描边效果 — 两种风格</div>
|
||
<div class="section-desc">
|
||
拖拽可编辑视图组件(文本/贴纸/表情包等)时显示描边,松手后取消。<br>
|
||
编辑器顶部工具栏增加设置按钮,点击弹出 Sheet 切换风格。
|
||
</div>
|
||
|
||
<div class="drag-demo-area">
|
||
<div>
|
||
<div class="drag-demo-box dashed">
|
||
<div class="content">
|
||
文本层
|
||
<div class="corner-bl"></div>
|
||
<div class="corner-br"></div>
|
||
</div>
|
||
</div>
|
||
<div class="drag-label">虚线 + 控制点</div>
|
||
</div>
|
||
<div>
|
||
<div class="drag-demo-box glow">
|
||
<div class="content">贴纸层</div>
|
||
</div>
|
||
<div class="drag-label">发光边框</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--bg-card);border-radius:var(--radius-lg);border:1px solid var(--border);padding:16px;margin-top:24px;max-width:600px;margin-left:auto;margin-right:auto;">
|
||
<h4 style="font-size:13px;font-weight:600;margin-bottom:8px;">⚙️ 设置入口</h4>
|
||
<div style="font-size:12px;line-height:1.8;color:var(--text-secondary);">
|
||
<p>📍 位置:编辑器顶部导航栏,导出按钮左侧</p>
|
||
<p>🔘 图标:CupertinoIcons.settings (齿轮)</p>
|
||
<p>📋 弹出:StupidSimpleGlassSheet 设置面板</p>
|
||
<p>🔄 选项:描边风格切换 (虚线+控制点 / 发光边框)</p>
|
||
<p>💾 持久化:SharedPreferences 存储用户偏好</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<!-- Section 4: 富文本编辑器 -->
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">📝 富文本编辑器 — 中级排版</div>
|
||
<div class="section-desc">
|
||
点击底部"文字"按钮时,显示富文本编辑面板,实时渲染到编辑区画布。<br>
|
||
不与编辑器已有功能重复(已有:颜色/对齐/字号),新增:粗体/斜体/下划线/删除线/列表/引用/代码块。
|
||
</div>
|
||
|
||
<div class="richtext-demo">
|
||
<div class="richtext-toolbar">
|
||
<button class="tool-btn active" title="粗体"><b>B</b></button>
|
||
<button class="tool-btn" title="斜体"><i>I</i></button>
|
||
<button class="tool-btn" title="下划线"><u>U</u></button>
|
||
<button class="tool-btn" title="删除线"><s>S</s></button>
|
||
<div class="divider"></div>
|
||
<button class="tool-btn" title="有序列表">1.</button>
|
||
<button class="tool-btn" title="无序列表">•</button>
|
||
<button class="tool-btn" title="引用">❝</button>
|
||
<button class="tool-btn" title="代码块"></></button>
|
||
<div class="divider"></div>
|
||
<button class="tool-btn" title="字号">Aa</button>
|
||
<button class="tool-btn" title="颜色">🎨</button>
|
||
<button class="tool-btn" title="对齐">≡</button>
|
||
</div>
|
||
<div class="richtext-canvas">
|
||
<h2>示例标题</h2>
|
||
<p>这是一段<span class="bold">粗体文字</span>,包含<span class="italic">斜体</span>、<span class="underline">下划线</span>和<span class="strikethrough">删除线</span>效果。</p>
|
||
<blockquote>引用块:生活不止眼前的苟且,还有诗和远方。</blockquote>
|
||
<ul>
|
||
<li>列表项一:晨光熹微</li>
|
||
<li>列表项二:暮色苍茫</li>
|
||
<li>列表项三:<code>代码片段</code> 也可以嵌入</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--bg-card);border-radius:var(--radius-lg);border:1px solid var(--border);padding:16px;margin-top:20px;max-width:600px;margin-left:auto;margin-right:auto;">
|
||
<h4 style="font-size:13px;font-weight:600;margin-bottom:8px;">📚 推荐库选择</h4>
|
||
<div style="font-size:12px;line-height:2;color:var(--text-secondary);">
|
||
<p><span style="color:#4CD964;">✅ 推荐:</span> <code>flutter_quill</code> (^11.0) — 最成熟的Flutter富文本库</p>
|
||
<p>· 支持粗体/斜体/下划线/删除线/列表/引用/代码块</p>
|
||
<p>· 自定义工具栏,可与编辑器UI融合</p>
|
||
<p>· Delta格式,可序列化为JSON</p>
|
||
<p>· 导出为HTML/Markdown</p>
|
||
<p><span style="color:#FF9500;">备选:</span> <code>appflowy_editor</code> — 功能更全但更重,适合文档编辑</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<!-- Section 5: Emoji → Icon 映射表 -->
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">🔄 Emoji → Icon 全量替换映射</div>
|
||
<div class="section-desc">
|
||
优先级:CupertinoIcons → SVG → 自绘 → Emoji(兜底) · 每按钮仅一个icon
|
||
</div>
|
||
|
||
<div style="overflow-x:auto;">
|
||
<table class="icon-table">
|
||
<thead>
|
||
<tr>
|
||
<th>原始Emoji</th>
|
||
<th>原标签</th>
|
||
<th>替换方案</th>
|
||
<th>来源</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr><td>🖌️</td><td>编辑Tab</td><td><div class="icon-preview"><span class="cupertino">🖌</span> paintbrush</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>✨</td><td>效果Tab</td><td><div class="icon-preview"><span class="cupertino">✦</span> sparkles</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>📦</td><td>内容Tab</td><td><div class="icon-preview"><span class="cupertino">☐</span> square_grid_2x2</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>📐</td><td>画布Tab</td><td><div class="icon-preview"><span class="cupertino">△</span> triangle_ruler</div></td><td><span class="tag svg">SVG</span></td></tr>
|
||
<tr><td>🖌️</td><td>画笔</td><td><div class="icon-preview"><span class="cupertino">🖌</span> paintbrush</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>📝</td><td>文字</td><td><div class="icon-preview"><span class="cupertino">T</span> textformat</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>✂️</td><td>裁剪</td><td><div class="icon-preview"><span class="cupertino">✂</span> scissors</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🎨</td><td>色调</td><td><div class="icon-preview"><span class="cupertino">🎨</span> paintpalette</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🔍</td><td>滤镜</td><td><div class="icon-preview"><span class="cupertino">⊙</span> circle_grid_3x3</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🌫️</td><td>模糊</td><td><div class="icon-preview"><span class="cupertino">◎</span> circle_dashed</div></td><td><span class="tag svg">SVG</span></td></tr>
|
||
<tr><td>😀</td><td>表情</td><td><div class="icon-preview"><span class="cupertino">☺</span> smiley</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🎭</td><td>贴纸</td><td><div class="icon-preview"><span class="cupertino">🎭</span> stickers</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🌈</td><td>渐变</td><td><div class="icon-preview"><span class="cupertino">◐</span> gradient</div></td><td><span class="tag svg">SVG</span></td></tr>
|
||
<tr><td>💧</td><td>水印</td><td><div class="icon-preview"><span class="cupertino">💧</span> drop</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🖼️</td><td>壁纸</td><td><div class="icon-preview"><span class="cupertino">🖼</span> photo</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>💬</td><td>一言</td><td><div class="icon-preview"><span class="cupertino">💬</span> chat_bubble</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>📝</td><td>草稿</td><td><div class="icon-preview"><span class="cupertino">📋</span> doc_text</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🖼️</td><td>模板</td><td><div class="icon-preview"><span class="cupertino">⊞</span> square_grid_2x2</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🎯</td><td>取色</td><td><div class="icon-preview"><span class="cupertino">◎</span> eyedropper</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>📥</td><td>导入</td><td><div class="icon-preview"><span class="cupertino">⬇</span> arrow_down_doc</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>🧰</td><td>更多</td><td><div class="icon-preview"><span class="cupertino">⋯</span> ellipsis</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>✨</td><td>Shader</td><td><div class="icon-preview"><span class="cupertino">✦</span> sparkles</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>⏳</td><td>历史</td><td><div class="icon-preview"><span class="cupertino">⏱</span> clock</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>📚</td><td>图层</td><td><div class="icon-preview"><span class="cupertino">☰</span> list_bullet</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>↩️</td><td>撤销</td><td><div class="icon-preview"><span class="cupertino">↩</span> arrow_uturn_left</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
<tr><td>↪️</td><td>重做</td><td><div class="icon-preview"><span class="cupertino">↪</span> arrow_uturn_right</div></td><td><span class="tag cupertino">Cupertino</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<!-- Section 6: 库推荐 -->
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<div class="section">
|
||
<div class="section-title">📦 可扩展功能 & 库推荐</div>
|
||
<div class="section-desc">
|
||
基于现有库分析,推荐新增库和可扩展功能方向。
|
||
</div>
|
||
|
||
<div style="overflow-x:auto;">
|
||
<table class="lib-table">
|
||
<thead>
|
||
<tr>
|
||
<th>库</th>
|
||
<th>用途</th>
|
||
<th>对应功能</th>
|
||
<th>优先级</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td><code>flutter_quill</code></td>
|
||
<td>富文本编辑器</td>
|
||
<td>编辑器文字面板 — 粗体/斜体/列表/引用/代码</td>
|
||
<td><span class="priority p1">P1</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>flutter_staggered_grid_view</code></td>
|
||
<td>瀑布流布局</td>
|
||
<td>壁纸公共组件 — 瀑布流网格</td>
|
||
<td><span class="priority p1">P1</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>visibility_detector</code></td>
|
||
<td>可见性检测</td>
|
||
<td>壁纸列表懒加载 + 已加载优先排序</td>
|
||
<td><span class="priority p1">P1</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>escapable</code> / 自绘</td>
|
||
<td>键盘快捷键</td>
|
||
<td>编辑器快捷键支持 (Ctrl+Z撤销等)</td>
|
||
<td><span class="priority p2">P2</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>super_clipboard</code></td>
|
||
<td>剪贴板增强</td>
|
||
<td>复制/粘贴图片到编辑器</td>
|
||
<td><span class="priority p2">P2</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>reorderable_grid_view</code></td>
|
||
<td>可排序网格</td>
|
||
<td>图层拖拽排序可视化</td>
|
||
<td><span class="priority p2">P2</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>dotted_border</code></td>
|
||
<td>虚线边框</td>
|
||
<td>拖拽描边 — 虚线风格</td>
|
||
<td><span class="priority p2">P2</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>auto_size_text</code></td>
|
||
<td>自适应文字</td>
|
||
<td>编辑器文字层自动缩放适配</td>
|
||
<td><span class="priority p3">P3</span></td>
|
||
</tr>
|
||
<tr>
|
||
<td><code>flutter_colorpicker</code></td>
|
||
<td>颜色选择器</td>
|
||
<td>编辑器取色器增强 (已有flex_color_picker可替代)</td>
|
||
<td><span class="priority p3">P3</span></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div style="background:var(--bg-card);border-radius:var(--radius-lg);border:1px solid var(--border);padding:16px;margin-top:20px;">
|
||
<h4 style="font-size:13px;font-weight:600;margin-bottom:8px;">🔮 基于现有库的可扩展功能</h4>
|
||
<div style="font-size:12px;line-height:2;color:var(--text-secondary);">
|
||
<p>· <code>flutter_svg</code> → SVG贴纸编辑器 (缩放/旋转/颜色替换)</p>
|
||
<p>· <code>lottie</code> → Lottie贴纸参数控制 (速度/方向/颜色)</p>
|
||
<p>· <code>flutter_3d_controller</code> → 3D贴纸姿态预设库</p>
|
||
<p>· <code>adaptive_palette</code> → 主题色自动应用到文字/边框/阴影</p>
|
||
<p>· <code>flutter_shaders_ui</code> → Shader参数实时调节面板</p>
|
||
<p>· <code>pro_image_editor</code> → 自定义Layer交互 (旋转手柄/缩放边框)</p>
|
||
<p>· <code>cached_network_image</code> → 离线壁纸缓存管理 + 缓存大小显示</p>
|
||
<p>· <code>flutter_animate</code> → 图层入场/退场动画预设</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<!-- Footer -->
|
||
<!-- ═══════════════════════════════════════════ -->
|
||
<div style="text-align:center;padding:40px 0 20px;color:var(--text-hint);font-size:12px;">
|
||
<p>闲言APP · 编辑器增强设计方案 · 2026-05-04</p>
|
||
<p style="margin-top:4px;">Layout First · Design System First · Plan Before Code</p>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
function switchMode(mode) {
|
||
const tabs = document.querySelectorAll('#modeSwitch .tab');
|
||
tabs.forEach(t => t.classList.remove('active'));
|
||
|
||
const drawer = document.getElementById('drawerMode');
|
||
const fullscreen = document.getElementById('fullscreenMode');
|
||
|
||
if (mode === 'drawer') {
|
||
tabs[0].classList.add('active');
|
||
drawer.style.display = '';
|
||
fullscreen.style.display = 'none';
|
||
} else {
|
||
tabs[1].classList.add('active');
|
||
drawer.style.display = 'none';
|
||
fullscreen.style.display = '';
|
||
}
|
||
}
|
||
|
||
// Interactive source/category tabs
|
||
document.querySelectorAll('.source-tab').forEach(tab => {
|
||
tab.addEventListener('click', function() {
|
||
this.parentElement.querySelectorAll('.source-tab').forEach(t => t.classList.remove('active'));
|
||
this.classList.add('active');
|
||
});
|
||
});
|
||
document.querySelectorAll('.category-tab').forEach(tab => {
|
||
tab.addEventListener('click', function() {
|
||
this.parentElement.querySelectorAll('.category-tab').forEach(t => t.classList.remove('active'));
|
||
this.classList.add('active');
|
||
});
|
||
});
|
||
|
||
// Interactive masonry items (select/deselect)
|
||
document.querySelectorAll('.masonry-item').forEach(item => {
|
||
item.addEventListener('click', function() {
|
||
const parent = this.closest('.masonry');
|
||
parent.querySelectorAll('.masonry-item').forEach(i => i.classList.remove('selected'));
|
||
this.classList.add('selected');
|
||
|
||
const applyBtn = this.closest('#phoneContent').querySelector('.apply-btn');
|
||
if (applyBtn) applyBtn.disabled = false;
|
||
});
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|