重构:提交全新项目代码
This commit is contained in:
79
packages/bookmark-sync/src/controller.ts
Normal file
79
packages/bookmark-sync/src/controller.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
export class Controller {
|
||||
/**
|
||||
* 书签栏 (Bookmarks Bar) 固定ID为 "1"
|
||||
*
|
||||
* 其他书签 (Other Bookmarks) 固定ID为 "2"
|
||||
*
|
||||
* 移动设备书签 (Mobile Bookmarks) 固定ID为 "3"
|
||||
*/
|
||||
rootFolder: string;
|
||||
|
||||
constructor(rootFolder: string = "1") {
|
||||
this.rootFolder = rootFolder;
|
||||
}
|
||||
|
||||
init() {}
|
||||
|
||||
setRootFolder(rootFolder: string) {
|
||||
this.rootFolder = rootFolder;
|
||||
}
|
||||
|
||||
async createBookmark(parentId: string, title: string, url?: string) {
|
||||
try {
|
||||
await browser.bookmarks.create({
|
||||
parentId: parentId,
|
||||
title: title,
|
||||
url: url,
|
||||
type: "bookmark",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("❌ 创建书签失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async createFolder(parentId: string, title: string, url?: string) {
|
||||
try {
|
||||
await browser.bookmarks.create({
|
||||
parentId: parentId,
|
||||
title: title,
|
||||
url: url,
|
||||
type: "folder",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async createSeparator(parentId: string) {
|
||||
try {
|
||||
await browser.bookmarks.create({
|
||||
parentId: parentId,
|
||||
type: "separator",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async deleteNode(id: string) {
|
||||
const results = await browser.bookmarks.get(id);
|
||||
if (results[0].type === "bookmark" || results[0].type === "separator") {
|
||||
deleteBookmarkOrSeparator(id);
|
||||
} else if (results[0].type === "folder") {
|
||||
deleteFolder(id);
|
||||
}
|
||||
}
|
||||
|
||||
async moveNode(id: string, destinationId: string, index: number) {
|
||||
try {
|
||||
await browser.bookmarks.move(id, {
|
||||
parentId: destinationId,
|
||||
index: index,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
packages/bookmark-sync/src/custom-bookmark-bar/newtab.html
Normal file
47
packages/bookmark-sync/src/custom-bookmark-bar/newtab.html
Normal file
@@ -0,0 +1,47 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>我的自定义书签</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
#bookmark-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.bookmark-item {
|
||||
display: block;
|
||||
width: 120px;
|
||||
padding: 15px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
}
|
||||
.bookmark-item:hover {
|
||||
background: #e0e0e0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>我的书签管理器</h2>
|
||||
<!-- 文件夹切换下拉框 -->
|
||||
<select id="folder-selector">
|
||||
<option value="1">书签栏 (ID: 1)</option>
|
||||
<!-- 其他文件夹可以通过代码动态加载到这里 -->
|
||||
</select>
|
||||
|
||||
<!-- 书签渲染容器 -->
|
||||
<div id="bookmark-container"></div>
|
||||
|
||||
<script src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
76
packages/bookmark-sync/src/custom-bookmark-bar/popup.ts
Normal file
76
packages/bookmark-sync/src/custom-bookmark-bar/popup.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
// 递归提取某个节点下的所有书签 URL(防止文件夹嵌套)
|
||||
function extractUrls(
|
||||
bookmarkNode: chrome.bookmarks.BookmarkTreeNode[],
|
||||
): string[] {
|
||||
let urls: string[] = [];
|
||||
for (const node of bookmarkNode) {
|
||||
if (node.url) {
|
||||
urls.push(node.url);
|
||||
} else if (node.children) {
|
||||
urls = urls.concat(extractUrls(node.children));
|
||||
}
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
// 渲染指定 ID 文件夹下的书签
|
||||
async function renderBookmarksByFolderId(folderId: string) {
|
||||
try {
|
||||
const results = await chrome.bookmarks.getSubTree(folderId);
|
||||
const folderNode = results[0];
|
||||
|
||||
if (!folderNode || !folderNode.children) return;
|
||||
|
||||
const container = document.getElementById("bookmark-container");
|
||||
if (container) container.innerHTML = "";
|
||||
|
||||
// 遍历直接子节点
|
||||
folderNode.children.forEach((bookmark) => {
|
||||
if (bookmark.url) {
|
||||
const link = document.createElement("a");
|
||||
link.className = "bookmark-item";
|
||||
link.href = bookmark.url;
|
||||
link.textContent = bookmark.title || bookmark.url;
|
||||
// 自动获取网站 favicon 图标
|
||||
const faviconUrl = `https://www.google.com/s2/favicons?domain=${new URL(bookmark.url).hostname}&sz=32`;
|
||||
link.innerHTML = `<img src="${faviconUrl}" style="vertical-align: middle; margin-right: 5px;">${bookmark.title}`;
|
||||
container?.appendChild(link);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("获取书签失败:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化:自动获取所有一级文件夹并填充到下拉框
|
||||
async function initFolderSelector() {
|
||||
const results = await chrome.bookmarks.getTree();
|
||||
const bookmarkBar = results[0].children?.[0]; // ID为1的书签栏
|
||||
const selector = document.getElementById(
|
||||
"folder-selector",
|
||||
) as HTMLSelectElement;
|
||||
|
||||
if (bookmarkBar && bookmarkBar.children) {
|
||||
bookmarkBar.children.forEach((folder) => {
|
||||
// 只把文件夹加到下拉框里
|
||||
if (!folder.url && folder.id !== "1") {
|
||||
const option = document.createElement("option");
|
||||
option.value = folder.id || "";
|
||||
option.textContent = folder.title || "未命名文件夹";
|
||||
selector.appendChild(option);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定切换事件
|
||||
selector.addEventListener("change", (e) => {
|
||||
const targetId = (e.target as HTMLSelectElement).value;
|
||||
renderBookmarksByFolderId(targetId);
|
||||
});
|
||||
|
||||
// 默认渲染书签栏
|
||||
renderBookmarksByFolderId("1");
|
||||
}
|
||||
|
||||
// 页面加载完成后启动
|
||||
document.addEventListener("DOMContentLoaded", initFolderSelector);
|
||||
5
packages/bookmark-sync/src/types.ts
Normal file
5
packages/bookmark-sync/src/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
export type Account = { id: string; email: string; password: string };
|
||||
|
||||
export type BookmarkTreeNode = browser.Bookmarks.BookmarkTreeNode;
|
||||
20
packages/bookmark-sync/src/utils.ts
Normal file
20
packages/bookmark-sync/src/utils.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
async function getLastIndex(parentId: string) {
|
||||
const children = await browser.bookmarks.getChildren(parentId);
|
||||
return children.length > 0 ? children[children.length - 1].index : 0;
|
||||
}
|
||||
|
||||
async function deleteBookmarkOrSeparator(id: string) {
|
||||
try {
|
||||
await browser.bookmarks.remove(id);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteFolder(id: string) {
|
||||
try {
|
||||
await browser.bookmarks.removeTree(id);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user