321
This commit is contained in:
parent
e8816c1ffb
commit
c3c9eb1acd
|
|
@ -107,7 +107,7 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 三、前端重构计划
|
## 三、前端重构计划(已完成)
|
||||||
|
|
||||||
### 3.1 需要修改的文件清单
|
### 3.1 需要修改的文件清单
|
||||||
|
|
||||||
|
|
@ -674,12 +674,26 @@ function renderSearchResult(bookmark) {
|
||||||
- 标签管理入口
|
- 标签管理入口
|
||||||
- [x] 构建验证通过
|
- [x] 构建验证通过
|
||||||
|
|
||||||
### 8.3 浏览器插件重构(待开始)
|
### 8.3 浏览器插件重构(已完成 ✅)
|
||||||
|
|
||||||
- [ ] 修改 shared/api.js
|
- [x] 修改 shared/api.js
|
||||||
- [ ] 修改 content/content.js 搜索结果渲染
|
- getBookmarks 新增 folderId 参数
|
||||||
- [ ] 修改 newtab/index.html 书签显示
|
- 新增 getFolders() 方法
|
||||||
- [ ] 修改 popup/popup.js 保存功能
|
- 新增 createTag() 方法
|
||||||
|
- [x] 修改 content/content.js 搜索结果渲染
|
||||||
|
- 适配新的 Tag 对象结构(tag.name, tag.color)
|
||||||
|
- [x] 修改 newtab/index.html 书签显示
|
||||||
|
- 搜索结果中添加标签显示
|
||||||
|
- 支持标签颜色
|
||||||
|
- [x] 修改 popup/popup.js 保存功能
|
||||||
|
- 新增文件夹选择器
|
||||||
|
- 保存时支持 folderId
|
||||||
|
- [x] 修改 background/background.js
|
||||||
|
- 新增 getFolders 消息处理
|
||||||
|
- [x] 修改 popup/popup.html
|
||||||
|
- 新增文件夹选择器 UI
|
||||||
|
- [x] 修改 popup/popup.css
|
||||||
|
- 新增文件夹选择器样式
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -695,8 +709,8 @@ function renderSearchResult(bookmark) {
|
||||||
|
|
||||||
## 十、版本信息
|
## 十、版本信息
|
||||||
|
|
||||||
- 文档版本:v2.1
|
- 文档版本:v2.2
|
||||||
- 创建日期:2024-12-25
|
- 创建日期:2024-12-25
|
||||||
- 最后更新:2024-12-25
|
- 最后更新:2025-12-25
|
||||||
- 作者:Claude Code
|
- 作者:Claude Code
|
||||||
- 更新说明:完成前端重构
|
- 更新说明:完成浏览器插件重构
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,13 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.action === 'getFolders') {
|
||||||
|
api.getFolders().then(result => {
|
||||||
|
sendResponse(result)
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('Bookmark extension background script loaded')
|
console.log('Bookmark extension background script loaded')
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ function updateSearchResults(results) {
|
||||||
</div>
|
</div>
|
||||||
${item.tags.length > 0 ? `
|
${item.tags.length > 0 ? `
|
||||||
<div class="bm-search-item-tags">
|
<div class="bm-search-item-tags">
|
||||||
${item.tags.slice(0, 2).map(tag => `<span class="bm-search-tag">${escapeHtml(tag)}</span>`).join('')}
|
${item.tags.slice(0, 2).map(tag => `<span class="bm-search-tag"${tag.color ? ` style="background-color: ${tag.color}"` : ''}>${escapeHtml(tag.name)}</span>`).join('')}
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,20 @@
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-tags {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-tag {
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #e0e7ff;
|
||||||
|
color: #4f46e5;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -292,6 +306,11 @@
|
||||||
<div class="result-content">
|
<div class="result-content">
|
||||||
<div class="result-title">${escapeHtml(b.title)}</div>
|
<div class="result-title">${escapeHtml(b.title)}</div>
|
||||||
<div class="result-url">${escapeHtml(b.url)}</div>
|
<div class="result-url">${escapeHtml(b.url)}</div>
|
||||||
|
${b.tags && b.tags.length > 0 ? `
|
||||||
|
<div class="result-tags">
|
||||||
|
${b.tags.slice(0, 3).map(tag => `<span class="result-tag"${tag.color ? ` style="background-color: ${tag.color}; color: #fff"` : ''}>${escapeHtml(tag.name)}</span>`).join('')}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
`).join('')}
|
`).join('')}
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,20 @@ body {
|
||||||
border-color: #667eea;
|
border-color: #667eea;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#quick-save select {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
outline: none;
|
||||||
|
background: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#quick-save select:focus {
|
||||||
|
border-color: #667eea;
|
||||||
|
}
|
||||||
|
|
||||||
#save-btn {
|
#save-btn {
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
background: #667eea;
|
background: #667eea;
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@
|
||||||
<input type="text" id="bookmark-title" placeholder="标题" />
|
<input type="text" id="bookmark-title" placeholder="标题" />
|
||||||
<input type="url" id="bookmark-url" placeholder="URL" />
|
<input type="url" id="bookmark-url" placeholder="URL" />
|
||||||
<input type="text" id="bookmark-tags" placeholder="标签(逗号分隔)" />
|
<input type="text" id="bookmark-tags" placeholder="标签(逗号分隔)" />
|
||||||
|
<select id="bookmark-folder">
|
||||||
|
<option value="">选择文件夹(可选)</option>
|
||||||
|
</select>
|
||||||
<button id="save-btn">收藏当前页</button>
|
<button id="save-btn">收藏当前页</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="save-result"></div>
|
<div id="save-result"></div>
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ const deviceName = document.getElementById('device-name')
|
||||||
const bookmarkTitle = document.getElementById('bookmark-title')
|
const bookmarkTitle = document.getElementById('bookmark-title')
|
||||||
const bookmarkUrl = document.getElementById('bookmark-url')
|
const bookmarkUrl = document.getElementById('bookmark-url')
|
||||||
const bookmarkTags = document.getElementById('bookmark-tags')
|
const bookmarkTags = document.getElementById('bookmark-tags')
|
||||||
|
const bookmarkFolder = document.getElementById('bookmark-folder')
|
||||||
const saveBtn = document.getElementById('save-btn')
|
const saveBtn = document.getElementById('save-btn')
|
||||||
const saveResult = document.getElementById('save-result')
|
const saveResult = document.getElementById('save-result')
|
||||||
const autoSyncCheckbox = document.getElementById('auto-sync')
|
const autoSyncCheckbox = document.getElementById('auto-sync')
|
||||||
|
|
@ -25,6 +26,7 @@ async function init() {
|
||||||
await loadUserInfo()
|
await loadUserInfo()
|
||||||
await loadCurrentTab()
|
await loadCurrentTab()
|
||||||
await loadSettings()
|
await loadSettings()
|
||||||
|
await loadFolders()
|
||||||
} else {
|
} else {
|
||||||
showLoginView()
|
showLoginView()
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +78,37 @@ async function loadSettings() {
|
||||||
showNotificationCheckbox.checked = settings.showNotification
|
showNotificationCheckbox.checked = settings.showNotification
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 加载文件夹列表
|
||||||
|
async function loadFolders() {
|
||||||
|
try {
|
||||||
|
const result = await chrome.runtime.sendMessage({ action: 'getFolders' })
|
||||||
|
if (result.success && result.data) {
|
||||||
|
// 清空现有选项(保留第一个默认选项)
|
||||||
|
while (bookmarkFolder.options.length > 1) {
|
||||||
|
bookmarkFolder.remove(1)
|
||||||
|
}
|
||||||
|
// 添加文件夹选项
|
||||||
|
renderFolderOptions(result.data, 0)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to load folders:', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归渲染文件夹选项
|
||||||
|
function renderFolderOptions(folders, level) {
|
||||||
|
folders.forEach(folder => {
|
||||||
|
const option = document.createElement('option')
|
||||||
|
option.value = folder.id
|
||||||
|
option.textContent = ' '.repeat(level) + (level > 0 ? '└ ' : '') + folder.name
|
||||||
|
bookmarkFolder.appendChild(option)
|
||||||
|
// 递归渲染子文件夹
|
||||||
|
if (folder.children && folder.children.length > 0) {
|
||||||
|
renderFolderOptions(folder.children, level + 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 保存设置
|
// 保存设置
|
||||||
async function saveSettings() {
|
async function saveSettings() {
|
||||||
await storage.setSettings({
|
await storage.setSettings({
|
||||||
|
|
@ -130,16 +163,17 @@ saveBtn.addEventListener('click', async () => {
|
||||||
const title = bookmarkTitle.value.trim()
|
const title = bookmarkTitle.value.trim()
|
||||||
const url = bookmarkUrl.value.trim()
|
const url = bookmarkUrl.value.trim()
|
||||||
const tags = bookmarkTags.value.split(',').map(t => t.trim()).filter(Boolean)
|
const tags = bookmarkTags.value.split(',').map(t => t.trim()).filter(Boolean)
|
||||||
|
const folderId = bookmarkFolder.value || null
|
||||||
|
|
||||||
if (!title || !url) {
|
if (!title || !url) {
|
||||||
showSaveResult('请填写标题和URL', false)
|
showSaveResult('请填写标题和URL', false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await chrome.runtime.sendMessage({
|
const result = await chrome.runtime.sendMessage({
|
||||||
action: 'createBookmark',
|
action: 'createBookmark',
|
||||||
data: { title, url, tags }
|
data: { title, url, tags, folderId }
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
|
|
||||||
|
|
@ -104,9 +104,12 @@ export const api = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取书签列表
|
// 获取书签列表
|
||||||
async getBookmarks(tag) {
|
async getBookmarks(tag = null, folderId = null) {
|
||||||
const params = tag ? `?tag=${encodeURIComponent(tag)}` : ''
|
const params = new URLSearchParams()
|
||||||
return request(`/bookmarks${params}`)
|
if (tag) params.append('tag', tag)
|
||||||
|
if (folderId) params.append('folderId', folderId)
|
||||||
|
const queryString = params.toString()
|
||||||
|
return request(`/bookmarks${queryString ? '?' + queryString : ''}`)
|
||||||
},
|
},
|
||||||
|
|
||||||
// 搜索书签
|
// 搜索书签
|
||||||
|
|
@ -135,6 +138,19 @@ export const api = {
|
||||||
// 获取标签列表
|
// 获取标签列表
|
||||||
async getTags() {
|
async getTags() {
|
||||||
return request('/tags')
|
return request('/tags')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取文件夹列表
|
||||||
|
async getFolders() {
|
||||||
|
return request('/folders')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 创建标签
|
||||||
|
async createTag(name, color = null, icon = null) {
|
||||||
|
return request('/tags', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({ name, color, icon })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user