feat: 补全收藏与分类功能

- 后台编辑区新增★收藏切换按钮(即时生效)
- 后台侧栏新增快速筛选: 全部/★收藏/分类
- 前台快速筛选新增分类chips(按分类过滤)
- 两种模式均含暗色样式适配
This commit is contained in:
Your Name
2026-08-11 12:43:10 +08:00
parent b93c6f1e16
commit 2196189791
2 changed files with 235 additions and 1 deletions
+67
View File
@@ -72,6 +72,9 @@
body.dark .filter-item:hover { background: #1e232d; }
body.dark .filter-item.active { background: #1b2a44; color: #7aa2f7; }
body.dark .filter-item.active svg { fill: #7aa2f7; }
body.dark .filter-chip { background: #1a1e26; border-color: #2a3040; color: #c9ced8; }
body.dark .filter-chip:hover { background: #2a3040; }
body.dark .filter-chip.active { background: #1976d2; color: #fff; border-color: #1976d2; }
body.dark .note-list { border-top: 1px solid #232733; }
body.dark .note-item:hover { background: #1e232d; }
@@ -285,6 +288,21 @@
.filter-item:hover { background: #f1f3f4; }
.filter-item.active { background: #e3f2fd; color: #1976d2; }
.filter-item svg { width: 16px; height: 16px; }
/* 分类筛选 chips */
.filter-chip {
padding: 4px 11px;
border: 1px solid #e0e0e0;
border-radius: 14px;
background: #fff;
color: #555;
font-size: 12px;
cursor: pointer;
white-space: nowrap;
transition: all 0.2s;
}
.filter-chip:hover { background: #f1f3f4; }
.filter-chip.active { background: #1976d2; color: #fff; border-color: #1976d2; }
.note-list {
border-top: 1px solid #e0e0e0;
@@ -631,6 +649,7 @@
<svg viewBox="0 0 24 24"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
收藏笔记
</div>
<div class="cat-filters" id="catFilters" style="padding: 4px 16px 6px; display: flex; flex-wrap: wrap; gap: 6px;"></div>
</div>
</div>
@@ -677,6 +696,52 @@
async function init() {
await loadTree();
await loadCategories();
}
// 加载分类并在筛选区渲染 chips
async function loadCategories() {
try {
const res = await fetch(`${API}/categories`);
const data = await res.json();
const cats = data.data || [];
const box = document.getElementById('catFilters');
if (!box) return;
if (cats.length === 0) {
box.innerHTML = '';
return;
}
box.innerHTML = cats.map(cat =>
`<span class="filter-chip ${currentFilter.type === 'category' && currentFilter.value === cat ? 'active' : ''}" onclick="filterCategory('${escapeHtml(cat)}')">${escapeHtml(cat)}</span>`
).join('');
} catch (e) { /* 忽略 */ }
}
// 按分类筛选
async function filterCategory(cat) {
currentFilter = { type: 'category', value: cat };
updateFilterUI();
renderCatFilters();
try {
const res = await fetch(`${API}/notes?category=${encodeURIComponent(cat)}&page_size=100`);
const data = await res.json();
if (data.code === 0) {
flatNotes = data.data || [];
renderFlatNotes();
}
} catch (err) {
showToast('加载失败', 'error');
}
}
function renderCatFilters() {
const box = document.getElementById('catFilters');
if (!box) return;
const chips = box.querySelectorAll('.filter-chip');
chips.forEach(chip => {
chip.classList.toggle('active',
currentFilter.type === 'category' && chip.textContent === currentFilter.value);
});
}
async function loadTree() {
@@ -895,12 +960,14 @@
async function filterAll() {
currentFilter = { type: 'all' };
updateFilterUI();
renderCatFilters();
await loadTree();
}
async function filterFavorites() {
currentFilter = { type: 'favorites' };
updateFilterUI();
renderCatFilters();
try {
const res = await fetch(`${API}/notes?favorite=true&page_size=100`);
const data = await res.json();