diff --git a/web/admin/index.html b/web/admin/index.html
index cdee1a6..c635df0 100644
--- a/web/admin/index.html
+++ b/web/admin/index.html
@@ -518,6 +518,41 @@
.backlink-item:hover { background: #f1f3f4; text-decoration: underline; }
.backlink-empty { padding: 10px; font-size: 12px; color: #999; }
+ /* 侧栏筛选(收藏/分类) */
+ .side-filter {
+ border-bottom: 1px solid #e0e0e0;
+ flex-shrink: 0;
+ max-height: 45%;
+ overflow-y: auto;
+ background: #fff;
+ }
+ .side-filter-header {
+ padding: 8px 14px;
+ font-size: 13px;
+ font-weight: 600;
+ color: #666;
+ }
+ .filter-chip-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ padding: 4px 12px 10px;
+ }
+ .filter-chip {
+ padding: 4px 10px;
+ border: 1px solid #e0e0e0;
+ border-radius: 14px;
+ background: #fff;
+ color: #555;
+ font-size: 12px;
+ cursor: pointer;
+ white-space: nowrap;
+ }
+ .filter-chip:hover { background: #f1f3f4; }
+ .filter-chip.active { background: #1a73e8; color: #fff; border-color: #1a73e8; }
+ .filter-chip.star { color: #e5a00d; }
+ .filter-chip.star.active { background: #e5a00d; color: #fff; border-color: #e5a00d; }
+
/* 预览中的 wiki 链接 */
.preview-content .wiki-link {
color: #1a73e8;
@@ -583,6 +618,12 @@
body.dark .backlink-item { color: #7aa2f7; }
body.dark .backlink-item:hover { background: #1e232d; }
body.dark .backlink-empty { color: #9aa0aa; }
+ body.dark .side-filter { background: #15181e; border-bottom-color: #232733; }
+ body.dark .side-filter-header { color: #9aa0aa; }
+ body.dark .filter-chip { background: #1a1e26; border-color: #2a3040; color: #c9ced8; }
+ body.dark .filter-chip:hover { background: #2a3040; }
+ body.dark .filter-chip.active { background: #1a73e8; color: #fff; border-color: #1a73e8; }
+ body.dark .filter-chip.star.active { background: #e5a00d; color: #fff; border-color: #e5a00d; }
body.dark .preview-content .wiki-link { color: #7aa2f7; border-bottom-color: #7aa2f7; }
body.dark .preview-content .wiki-link:hover { background: #1b2a44; }
body.dark .graph-node circle { fill: #6aa1f7; stroke: #0f1115; }
@@ -627,6 +668,7 @@
+
@@ -822,6 +870,8 @@
let searchTimer = null; // 搜索防抖定时器
let searchMode = false; // 是否处于搜索模式(隐藏树形)
let autosaveInlineOpen = false; // 草稿已加载标志
+ let filterMode = { type: 'all', value: '' }; // 侧栏筛选:all / fav / category:xxx
+ let categoryList = []; // 分类列表(用于筛选 chips)
// 初始化
async function init() {
@@ -903,6 +953,7 @@
if (data.code === 0) {
treeData = data.data;
renderTree();
+ renderSideFilter();
}
} catch (err) {
showToast('加载目录失败', 'error');
@@ -916,12 +967,81 @@
container.innerHTML = '
暂无内容,点击 + 新建
';
return;
}
-
+
+ // 若处于筛选模式(收藏/分类),渲染扁平结果列表
+ if (filterMode.type !== 'all') {
+ const list = getFilteredList();
+ if (list.length === 0) {
+ container.innerHTML = '
' +
+ (filterMode.type === 'fav' ? '暂无收藏笔记' : '该分类暂无笔记') + '
';
+ } else {
+ container.innerHTML = list.map(item => {
+ const isActive = currentItem && currentItem.id === item.id;
+ return `
+
+
+
${escapeHtml(item.title)}
+ ${item.is_favorite ? '
★' : ''}
+
+ `;
+ }).join('');
+ }
+ return;
+ }
+
// 构建树形结构
const rootItems = treeData.filter(item => item.parent_id === 0);
container.innerHTML = renderTreeItems(rootItems);
}
+ // 根据当前筛选模式返回扁平笔记列表
+ function getFilteredList() {
+ if (filterMode.type === 'fav') {
+ return treeData.filter(i => !i.is_folder && i.is_favorite);
+ }
+ if (filterMode.type === 'category' && filterMode.value) {
+ return treeData.filter(i => !i.is_folder && i.category === filterMode.value);
+ }
+ return treeData.filter(i => !i.is_folder);
+ }
+
+ // 渲染侧栏筛选条(收藏 + 分类)
+ function renderSideFilter() {
+ const box = document.getElementById('sideFilter');
+ if (!box) return;
+ // 汇总分类
+ const catSet = new Set();
+ treeData.forEach(i => { if (!i.is_folder && i.category) catSet.add(i.category); });
+ categoryList = Array.from(catSet);
+
+ let html = '
';
+ html += `全部`;
+ html += `★ 收藏`;
+ categoryList.forEach(cat => {
+ const hot = filterMode.type === 'category' && filterMode.value === cat;
+ html += `${escapeHtml(cat)}`;
+ });
+ // 清理没有笔记的分类(含已删除引用)
+ if (categoryList.length === 0) {
+ html += '暂无分类';
+ }
+ html += '
';
+
+ box.innerHTML = html;
+ box.style.display = 'block';
+ }
+
+ // 设置筛选模式并重绘
+ function setFilter(type, value) {
+ filterMode = { type, value };
+ // 筛选时退出目录模式(避免编辑目录)
+ if (type !== 'all') {
+ searchMode = false;
+ }
+ renderSideFilter();
+ renderTree();
+ }
+
function renderTreeItems(items) {
return items.map(item => {
const children = treeData.filter(c => c.parent_id === item.id);
@@ -1022,6 +1142,7 @@
}
}
+ updateFavUI();
renderTree();
}
} catch (err) {
@@ -1116,9 +1237,54 @@
document.getElementById('noteTags').value = '';
document.getElementById('noteContent').value = '';
updatePreview();
+ updateFavUI();
}
// 保存笔记
+ // 收藏切换按钮(点击直接调接口即时生效)
+ async function toggleFavorite() {
+ const btn = document.getElementById('favBtn');
+ if (!currentItem || !currentItem.id || currentItem.is_folder) {
+ showToast('请先打开一篇笔记', 'error');
+ return;
+ }
+ const newVal = btn.dataset.fav !== '1';
+ try {
+ const res = await fetch(`${ADMIN_API}/notes/${currentItem.id}`, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ is_favorite: newVal })
+ });
+ const data = await res.json();
+ if (data.code === 0) {
+ currentItem.is_favorite = newVal;
+ btn.dataset.fav = newVal ? '1' : '0';
+ document.getElementById('favText').textContent = newVal ? '已收藏' : '收藏';
+ document.getElementById('favStar').style.fill = newVal ? '#e5a00d' : '#ccc';
+ showToast(newVal ? '已收藏' : '已取消收藏', 'success');
+ // 若当前正处于收藏筛选,刷新列表
+ if (filterMode.type === 'fav' || filterMode.type === 'all') {
+ await loadTree();
+ }
+ } else {
+ showToast(data.message || '操作失败', 'error');
+ }
+ } catch (err) {
+ showToast('操作失败', 'error');
+ }
+ }
+
+ // 根据 currentItem 刷新收藏按钮状态
+ function updateFavUI() {
+ const btn = document.getElementById('favBtn');
+ if (!btn) return;
+ const fav = currentItem && currentItem.id && currentItem.is_favorite;
+ btn.dataset.fav = fav ? '1' : '0';
+ document.getElementById('favText').textContent = fav ? '已收藏' : '收藏';
+ document.getElementById('favStar').style.fill = fav ? '#e5a00d' : '#ccc';
+ btn.style.display = (!currentItem || currentItem.is_folder) ? 'none' : 'flex';
+ }
+
async function saveNote() {
const title = document.getElementById('noteTitle').value.trim();
const content = document.getElementById('noteContent').value;
@@ -1144,6 +1310,7 @@
category,
tags,
is_public: isPublic,
+ is_favorite: document.getElementById('favBtn').dataset.fav === '1',
parent_id: currentItem && currentItem.parent_id ? currentItem.parent_id : 0
};
diff --git a/web/index.html b/web/index.html
index d701251..98ebb95 100644
--- a/web/index.html
+++ b/web/index.html
@@ -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 @@
收藏笔记
+