-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
1,102 additions
and
2,476 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,99 @@ | ||
.env | ||
.DS_store | ||
node_modules | ||
package-lock.json | ||
# Node.js 相关 | ||
node_modules/ | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# 日志文件 | ||
logs | ||
*.log | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# 运行时数据 | ||
lib-cov | ||
coverage/ | ||
*.lcov | ||
|
||
# jscoverage/JSCover 生成的目录 | ||
lib-cov | ||
|
||
# istanbul 使用的覆盖率目录 | ||
coverage/ | ||
|
||
# nyc 测试覆盖率输出目录 | ||
.nyc_output/ | ||
|
||
# Grunt 中间存储目录(https://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt/ | ||
|
||
# Bower 依赖目录(https://bower.io/) | ||
bower_components/ | ||
|
||
# 编译的二进制扩展(https://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# 依赖目录 | ||
jspm_packages/ | ||
|
||
# Next.js 构建输出 | ||
.next/ | ||
|
||
# dotenv 环境变量文件 | ||
.env.local | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
.env | ||
|
||
# Next.js 生成的文件 | ||
*.next | ||
out/ | ||
.next/ | ||
out/ | ||
build/ | ||
dist/ | ||
|
||
# macOS 特定文件 | ||
.DS_Store | ||
.AppleDouble | ||
.LSOverride | ||
|
||
# 图标文件必须以两个回车结尾 | ||
Icon\r\r | ||
|
||
# 缩略图 | ||
._* | ||
|
||
# 可能出现在卷根目录下的文件 | ||
.DocumentRevisions-V100 | ||
.fseventsd | ||
.Spotlight-V100 | ||
.TemporaryItems | ||
.Trashes | ||
.VolumeIcon.icns | ||
.com.apple.timemachine.donotpresent | ||
|
||
# 可能在远程 AFP 共享上创建的目录 | ||
.AppleDB | ||
.AppleDesktop | ||
Network Trash Folder | ||
Temporary Items | ||
.apdisk | ||
|
||
# 编辑器和 IDE 相关 | ||
.idea/ | ||
.vscode/ | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? | ||
|
||
# TypeScript 缓存文件 | ||
*.tsbuildinfo | ||
|
||
# 可选的 npm 缓存目录 | ||
.npm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
const fontData = { | ||
"fonts": [ | ||
{ | ||
"name": "Smiley Sans Oblique", | ||
"displayName": "得意黑" | ||
}, | ||
{ | ||
"name": "LXGW WenKai", | ||
"displayName": "霞鹜文楷" | ||
}, | ||
{ | ||
"name": "KingHwa_OldSong", | ||
"displayName": "京華老宋体" | ||
}, | ||
{ | ||
"name": "MuzaiPixel", | ||
"displayName": "目哉像素体" | ||
}, | ||
{ | ||
"name": "LXGW Marker Gothic", | ||
"displayName": "霞鹜漫黑" | ||
} | ||
] | ||
}; | ||
|
||
export const populateContextMenu = () => { | ||
const menu = document.getElementById('customContextMenu').querySelector('ul'); | ||
menu.innerHTML = ''; // 清空现有的菜单项,防止重复添加 | ||
|
||
fontData.fonts.forEach((font) => { | ||
let li = document.createElement('li'); | ||
li.textContent = font.displayName; // 显示中文字体名 | ||
li.style.cursor = 'pointer'; | ||
li.style.fontFamily = font.name; // 设置每个字体选项的字体样式 | ||
li.onclick = () => { | ||
changeFont(font.name); // 调用更改字体的函数 | ||
}; | ||
menu.appendChild(li); | ||
}); | ||
}; | ||
|
||
export const changeFont = (font) => { | ||
document.documentElement.style.setProperty('--main-font-family', `"${font}"`); | ||
setCookie('userFont', font, 7); // 更新Cookie,持续7天 | ||
updateMenuSelection(font); // 更新菜单选择状态 | ||
document.getElementById('customContextMenu').style.display = 'none'; // 隐藏菜单 | ||
}; | ||
|
||
const updateMenuSelection = (selectedFont) => { | ||
const items = document.querySelectorAll('#customContextMenu li'); | ||
items.forEach(item => { | ||
if (item.textContent.trim() === fontData.fonts.find(f => f.name === selectedFont).displayName) { // 使用正确的友好名称进行比较 | ||
item.classList.add('selected-font'); | ||
} else { | ||
item.classList.remove('selected-font'); | ||
} | ||
}); | ||
}; | ||
|
||
const setCookie = (name, value, days) => { | ||
var expires = ""; | ||
if (days) { | ||
var date = new Date(); | ||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); | ||
expires = "; expires=" + date.toUTCString(); | ||
} | ||
document.cookie = name + "=" + (value || "") + expires + "; path=/"; | ||
}; | ||
|
||
const getCookie = (name) => { | ||
var nameEQ = name + "="; | ||
var ca = document.cookie.split(';'); | ||
for (var i = 0; i < ca.length; i++) { | ||
var c = ca[i]; | ||
while (c.charAt(0) == ' ') c = c.substring(1, c.length); | ||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); | ||
} | ||
return null; | ||
}; | ||
|
||
const loadFont = () => { | ||
var userFont = getCookie('userFont'); | ||
if (userFont) { | ||
document.documentElement.style.setProperty('--main-font-family', userFont); | ||
updateMenuSelection(userFont); // 更新菜单选择状态 | ||
} | ||
}; | ||
|
||
export const initializeContextMenu = () => { | ||
populateContextMenu(); // 填充右键菜单 | ||
loadFont(); // 加载用户之前选择的字体 | ||
|
||
// 处理右键菜单事件 | ||
document.addEventListener('contextmenu', function (event) { | ||
event.preventDefault(); | ||
var contextMenu = document.getElementById('customContextMenu'); | ||
contextMenu.style.display = 'block'; | ||
contextMenu.style.left = event.pageX + 'px'; | ||
contextMenu.style.top = event.pageY + 'px'; | ||
}); | ||
|
||
// 处理点击事件,隐藏自定义的右键菜单 | ||
document.addEventListener('click', function (event) { | ||
var contextMenu = document.getElementById('customContextMenu'); | ||
if (event.target.offsetParent !== contextMenu) { | ||
contextMenu.style.display = 'none'; | ||
} | ||
}); | ||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// 随机排序 | ||
export const randomSort = arr => { | ||
for (let i = 0, l = arr.length; i < l; i++) { | ||
let rc = parseInt(Math.random() * l); | ||
const empty = arr[i]; | ||
arr[i] = arr[rc]; | ||
arr[rc] = empty; | ||
} | ||
return arr; | ||
}; | ||
// 去重 | ||
export const unique = arr => Array.from(new Set(arr)); | ||
// 提取tags | ||
export const extractTags = posts => { | ||
const allTags = new Set(); | ||
posts.forEach(post => { | ||
if (post.state !== '隐藏') {//避免隐藏网页的tag被写入 | ||
post.tags.forEach(tag => allTags.add(tag)); | ||
} | ||
}); | ||
return [...allTags]; | ||
}; | ||
|
||
// 通过tags筛选 | ||
export const filterPostsByTags = (posts, tags) => { | ||
return posts.filter(post => tags.every(tag => post.tags.includes(tag))); | ||
}; | ||
|
||
//通过搜索筛选 | ||
export const filterPostsBySearch = (posts, query) => { | ||
if(query === '隐藏'){ | ||
return posts | ||
} | ||
// 返回符合查询条件的帖子 | ||
return posts.filter(post => | ||
post.name.toLowerCase().includes(query.toLowerCase()) || | ||
post.brief.toLowerCase().includes(query.toLowerCase()) || | ||
post.tags.some(tag => tag.toLowerCase().includes(query.toLowerCase())) | ||
); | ||
}; | ||
|
||
|
||
export const renderTags = (tags, onList, toggleTagButton) => { | ||
return tags.map((tag, index) => ( | ||
<button | ||
key={index} | ||
id={`tag${index}`} | ||
className={onList.includes(tag) ? 'tag on' : 'tag off'} | ||
onClick={() => toggleTagButton(tag)} | ||
> | ||
{tag} | ||
</button> | ||
)); | ||
}; | ||
|
||
export const toggleTagButton = (tag, onList, setOnList, tags, setTags) => { | ||
let newOnList; | ||
if (onList.includes(tag)) { | ||
newOnList = onList.filter(item => item !== tag); | ||
} else { | ||
newOnList = [...onList, tag]; | ||
} | ||
setOnList(newOnList); | ||
// 重新排序标签列表,使选中的标签排在前面 | ||
const sortedTags = newOnList.concat(tags.filter(t => !newOnList.includes(t))); | ||
setTags(sortedTags); | ||
}; | ||
|
||
export const updateResults = (posts, onList, setFilteredPosts, setTags) => { | ||
const filtered = posts.filter(post => | ||
onList.every(tag => post.tags.includes(tag)) | ||
); | ||
setFilteredPosts(filtered); | ||
// 更新标签列表,只显示可选的标签 | ||
const availableTags = Array.from(new Set(filtered.flatMap(post => post.tags))); | ||
const sortedTags = onList.concat(availableTags.filter(tag => !onList.includes(tag))); | ||
setTags(sortedTags); | ||
}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { Client } from '@notionhq/client'; | ||
|
||
// 创建 Notion 客户端实例,使用环境变量中的 NOTION_TOKEN 进行身份验证 | ||
const notion = new Client({ auth: process.env.NOTION_TOKEN }); | ||
|
||
// 获取指定数据库的所有页面 | ||
export const getAllPages = async (databaseId) => { | ||
let results = []; // 存储所有页面的数组 | ||
let hasMore = true; // 用于迭代查询,检查是否还有更多页面需要获取 | ||
let startCursor = undefined; // 用于获取下一页的游标 | ||
|
||
// 当仍有更多页面需要获取时循环执行 | ||
while (hasMore) { | ||
// 查询数据库的一页数据 | ||
const response = await notion.databases.query({ | ||
database_id: databaseId, | ||
start_cursor: startCursor, | ||
}); | ||
|
||
// 将当前页的结果追加到结果数组中 | ||
results = results.concat(response.results); | ||
// 更新是否还有更多页面的标志 | ||
hasMore = response.has_more; | ||
// 更新下一页的游标,以便下次查询时获取下一页数据 | ||
startCursor = response.next_cursor; | ||
} | ||
|
||
return results; // 返回所有页面的数组 | ||
}; | ||
|
||
// 获取指定数据库的页面并转换为适合显示的格式 | ||
export const getDatabase = async (databaseId) => { | ||
// 获取指定数据库的所有页面 | ||
const pages = await getAllPages(databaseId); | ||
// 将页面格式化为适合显示的格式 | ||
return pages | ||
.filter(page => page.properties.empty.formula.string !== 'empty') // 过滤掉空的页面 | ||
.filter(page => page.properties.state.select.name !== '断开连接') // 过滤掉状态为 "断开连接" 的页面 | ||
.map(page => { | ||
const properties = page.properties; | ||
return { | ||
id: page.id, // 页面的 ID | ||
name: properties.name.title[0].plain_text, // 页面的名称 | ||
state: properties.state.select.name, // 页面的状态 | ||
brief: properties.brief.rich_text[0].plain_text, // 页面的简介 | ||
tags: properties.tags.multi_select.map(tag => tag.name), // 页面的标签数组 | ||
web: properties.web.url, // 页面的网址 | ||
}; | ||
}); | ||
}; |
Oops, something went wrong.