提交 b1846d48 编写于 作者: X xjh22222228

feat(#77): Bookmark Merge

上级 f79e8aa3
......@@ -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)
......
......@@ -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}`
}
})
}
......
......@@ -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
}
......@@ -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)
})
......
......@@ -290,7 +290,7 @@
<td>
<a [href]="data.url" target="_blank">{{ data.name }}</a>
</td>
<td>
<td nzWidth="100px">
<nz-tag *ngFor="let key of objectKeys(data.urls)" [nzColor]="tagMap[key].color || '#2db7f5'">
<a [href]="data.urls[key]" target="_blank">{{ key }}</a>
</nz-tag>
......@@ -298,8 +298,8 @@
<td>
<pre class="desc">{{ data.desc }}</pre>
</td>
<td>{{ data.createdAt }}</td>
<td>
<td nzWidth="200px">{{ data.createdAt }}</td>
<td nzWidth="100px">
<a (click)="toggleCreateWebModal(); websiteDetail = data; editIdx = idx">编辑</a>
<a
nz-popconfirm
......
......@@ -112,7 +112,7 @@ export default class WebpComponent {
path: LOGO_PATH,
branch: 'image'
}).then(() => {
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
})
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册