diff --git a/README.md b/README.md index b728709dfb221e590ab773ca80d43b5c068b1958..9dc18d0112825c5f5de2590e5bec83e6149d265a 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,9 @@ ## 部署 -推荐使用 `github pages` 服务, 这样就不需要提供服务器, 并且项目里自带了自动化部署服务,像数 `321` 一样简单。 +像数 `321` 一样简单。 +#### 方式一(gh-pages免费) 1、Fork 当前项目。 2、[https://github.com/settings/tokens](https://github.com/settings/tokens) 申请 token, 勾选相应的权限, 如果不懂就全部选中,复制并保存Token。 @@ -79,6 +80,13 @@ 6、5分钟后打开 https://用户名.github.io/nav 就能看到一个非常强大的导航网站了。 +### 推荐方式二(Vercel免费) +和方式一的步骤一样,除了第4步不用。 + +具体使用跟着步骤走即可 [https://github.com/apps/vercel](https://github.com/apps/vercel) + + + 注:如果想部署到自己的域名,那么以上教程同样适合,因为它提供了自动化部署, 之后可以通过 `CNAME` 或 `反向代理` 实现: @@ -97,7 +105,7 @@ server { ## 书签导入 -支持从 Chrome 书签导入(WebKit内核应该都是支持的~),会自动检测满足三级分类的导航,其他一律跳过: +支持从 Chrome 书签导入(WebKit内核应该都是支持的~),会自动检测满足三级分类的导航,其他一律设为未分类: ![](https://raw.githubusercontent.com/xjh22222228/public/gh-pages/nav/import.png) diff --git a/src/services/index.ts b/src/services/index.ts index daeaa16da7d4aac37b0161d88d28d0f71ce4649a..e77d314b0b91c2458769d4792cb18125d2441bce 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -3,7 +3,6 @@ import config from '../../nav.config' import http from '../utils/http' import { encode } from 'js-base64' -import { getToken } from '../utils/user' const { gitRepoUrl } = config const s = gitRepoUrl.split('/') @@ -11,7 +10,6 @@ const DEFAULT_BRANCH = config.branch export const authorName = s[s.length - 2] export const repoName = s[s.length - 1] -const token = getToken() // 验证Token export function verifyToken(token: string) { @@ -23,12 +21,8 @@ export function verifyToken(token: string) { } // 获取文件信息 -export function getFileContent(path: string, authToken?: string, branch: string = DEFAULT_BRANCH) { - const _token = `${authToken ? authToken : token}`.trim() +export function getFileContent(path: string, branch: string = DEFAULT_BRANCH) { return http.get(`/repos/${authorName}/${repoName}/contents/${path}`, { - headers: { - Authorization: `token ${_token}` - }, params: { ref: branch } @@ -44,38 +38,37 @@ type Iupdate = { isEncode?: boolean } export async function updateFileContent( - { message, content, path, branch = DEFAULT_BRANCH, isEncode = true }: Iupdate, - authToken?: string + { + message, + content, + path, + branch = DEFAULT_BRANCH, + isEncode = true + }: Iupdate, ) { - const _token = `${authToken ? authToken : token}`.trim() - const fileInfo = await getFileContent(path, _token, branch) + const fileInfo = await getFileContent(path, branch) return http.put(`/repos/${authorName}/${repoName}/contents/${path}`, { message: `rebot(CI): ${message}`, branch, content: isEncode ? encode(content) : content, sha: fileInfo.data.sha - }, { - headers: { - Authorization: `token ${_token}` - } }) } export async function createFile( - { message, content, path, branch = DEFAULT_BRANCH, isEncode = true }: Iupdate, - authToken?: string + { + message, + content, + path, + branch = DEFAULT_BRANCH, + isEncode = true + }: Iupdate, ) { - const _token = `${authToken ? authToken : token}`.trim() - return http.put(`/repos/${authorName}/${repoName}/contents/${path}`, { message: `rebot(CI): ${message}`, branch, content: isEncode ? encode(content) : content, - }, { - headers: { - Authorization: `token ${_token}` - } }) } diff --git a/src/utils/bookmark.ts b/src/utils/bookmark.ts index 1efa86718db6f3227d5f98a3b251055e8724e53e..6ef2c934ff299936fde1f76be51c1dcdf550d121 100644 --- a/src/utils/bookmark.ts +++ b/src/utils/bookmark.ts @@ -5,11 +5,52 @@ import { INavProps } from '../types' import { websiteList } from '../store' export function parseBookmark(htmlStr: string) { + const copyWebList = JSON.parse(JSON.stringify(websiteList)) const data: INavProps[] = [] const importEl = document.createElement('div') importEl.innerHTML = htmlStr const roolDL = importEl.querySelector('dl dl') + // 未分类 + let hasNoCate = false + const cateCreateAt = new Date().toISOString() + const noCate: INavProps = { + title: '未分类', + createdAt: cateCreateAt, + nav: [ + { + createdAt: cateCreateAt, + title: '未分类', + nav: [ + { + title: '未分类', + nav: [] + } + ] + } + ] + } + + function findA(node: Element) { + let a = node.firstElementChild + if (!a && a.nodeName === 'a') return + + hasNoCate = true + const name = a.textContent + const createdAt = new Date(Number(a.getAttribute('add_date')) * 1000).toISOString() + const icon = a.getAttribute('icon') || null + const url = a.getAttribute('href') + noCate.nav[0].nav[0].nav.push({ + name, + createdAt, + icon, + url, + urls: {}, + desc: '', + rate: 5 + }) + } + let ii = 0 let jj = 0 let kk = 0 @@ -18,6 +59,7 @@ export function parseBookmark(htmlStr: string) { for (let i = 0; i < roolDL.childElementCount; i++) { const iItem = roolDL.childNodes[i] as any if (iItem && iItem.nodeName === 'DT') { + findA(iItem) const titleEl = iItem.querySelector('h3') if (!titleEl) continue ii++ @@ -36,6 +78,7 @@ export function parseBookmark(htmlStr: string) { for (let j = 0; j < DL.childElementCount; j++) { const jItem = DL.childNodes[j] if (jItem && jItem.nodeName === 'DT') { + findA(jItem) const titleEl = jItem.querySelector('h3') if (!titleEl) continue jj++ @@ -54,6 +97,7 @@ export function parseBookmark(htmlStr: string) { for (let k = 0; k < DL3.childElementCount; k++) { const kItem = DL3.childNodes[k] if (kItem && kItem.nodeName === 'DT') { + findA(kItem) const titleEl = kItem.querySelector('h3') if (!titleEl) continue kk++ @@ -99,16 +143,30 @@ export function parseBookmark(htmlStr: string) { return error } - const mergeList = [...data, ...websiteList] - const newList = []; + if (hasNoCate) { + data.push(noCate) + } + + // 增量导入 + function r(data: any[], list: any[]) { + for (let i = 0; i < data.length; i++) { + const item = data[i] as any + const title = item.title || item?.name + const idx = list.findIndex(item => (item.title || item.name) === title) - for (let i = 0; i < mergeList.length; i++) { - const item = mergeList[i] - const exists = newList.some(el => el.title === item.title) - if (!exists) { - newList.push(item) + // Repeat + if (idx !== -1) { + if (Array.isArray(item.nav)) { + r(item.nav, list[idx].nav) + } + } else { + list.push(item) + } } } + r(data, copyWebList) + + console.log(copyWebList) - return newList + return copyWebList } diff --git a/src/utils/http.ts b/src/utils/http.ts index fa06373ecb3edd6f18f8e8419eda09672bf46d8c..f0d83ffa80e7af5ec511aefe194405709182b796 100644 --- a/src/utils/http.ts +++ b/src/utils/http.ts @@ -4,34 +4,47 @@ import axios from 'axios' import NProgress from 'nprogress' import { getToken } from '../utils/user' +const token = getToken() +const DEFAULT_TITLE = document.title +const headers: {[k: string]: string} = {} + +if (token) { + headers.Authorization = `token ${token}` +} + const httpInstance = axios.create({ timeout: 60000 * 3, - baseURL: 'https://api.github.com' + baseURL: 'https://api.github.com', + headers }) -const token = getToken() + +function startLoad() { + NProgress.start() + document.title = 'Connecting...' +} + +function stopLoad() { + NProgress.done() + document.title = DEFAULT_TITLE +} Object.setPrototypeOf(httpInstance, axios) httpInstance.interceptors.request.use(function (config) { - NProgress.start() - - config.headers = { - Authorization: `token ${token}`, - ...config.headers - } + startLoad() return config }, function (error) { - NProgress.done() + stopLoad() return Promise.reject(error) }) httpInstance.interceptors.response.use(function (res) { - NProgress.done() + stopLoad() return res }, function (error) { - NProgress.done() + stopLoad() return Promise.reject(error) }) diff --git a/src/view/admin/index.component.html b/src/view/admin/index.component.html index 807976ae7433fb513e43fdc71c3d377513f7f653..e714eb0f2eebfb6e079ff3a8dced764135884d1b 100644 --- a/src/view/admin/index.component.html +++ b/src/view/admin/index.component.html @@ -290,7 +290,7 @@ {{ data.name }} - + {{ key }} @@ -298,8 +298,8 @@
{{ data.desc }}
- {{ data.createdAt }} - + {{ data.createdAt }} + 编辑 { - that.message.success('更换成功, 由于CDN缓存问题预计至少需要10分钟才能看到最新') + that.message.success('更换成功, 由于CDN缓存问题需要次日更新') }).catch(res => { logoEL.src = tempSrc that.notification.error( @@ -120,6 +120,7 @@ export default class WebpComponent { `${res?.response?.data?.message ?? '更换LOGO失败,请重试!'}` ) }).finally(() => { + e.target.value = '' that.uploading = false }) }