Compare commits

...
9 Commits
Author SHA1 Message Date
qwqcode 296cfde58a v2.0.4 2021-10-29 11:34:52 +08:00
qwqcode f88631ad53 fix(GitHub Actions): NPM Publish.
Signed-off-by: qwqcode <qwqcode@gmail.com>
2021-10-29 11:17:10 +08:00
qwqcode 650d38b1dd fix(API): JWT expired check.
Signed-off-by: qwqcode <qwqcode@gmail.com>
2021-10-29 10:45:44 +08:00
qwqcode bf7878eabb fix(darkMode): Border-color inconsistent.
Signed-off-by: qwqcode <qwqcode@gmail.com>
2021-10-29 10:00:33 +08:00
qwqcode e3fa83806e fix(artrans): Frontend import Payload modify to JSON object.
Signed-off-by: qwqcode <qwqcode@gmail.com>
2021-10-29 08:27:26 +08:00
qwqcode 1a0aca42fa chore: Improve some details.
Signed-off-by: qwqcode <qwqcode@gmail.com>
2021-10-28 20:56:18 +08:00
qwqcode 7983658292 feat(artrans): New Importer.
Signed-off-by: qwqcode <qwqcode@gmail.com>
2021-10-28 19:50:33 +08:00
qwqcode 0a5714139f v2.0.3 2021-10-24 13:43:48 +08:00
qwqcode 8620420fb4 fix: Rename artalk.umd.js to artalk.js 2021-10-23 23:43:10 +08:00
8 changed files with 200 additions and 83 deletions

No files matched your search

+19 -16
View File
@@ -1,28 +1,31 @@
name: NPM Package
# https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
name: NPM Publish
on:
release:
types: [created]
workflow_dispatch:
push:
tags:
- v*
jobs:
publish:
if: github.repository == "ArtalkJS/Artalk"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v2
with:
node-version: '12.x'
registry-url: 'https://registry.npmjs.org'
- run: npm install
- run: npm build
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
# Setup .npmrc file to publish to GitHub Packages
- uses: actions/setup-node@v2
with:
node-version: '12'
registry-url: 'https://npm.pkg.github.com'
- name: Release
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
npx version-from-git --allow-same-version --template 'master.short'
- name: Publish
run: |
npm ci
npm publish
# Publish to GitHub Packages
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+24 -20
View File
@@ -4,8 +4,6 @@
# Artalk
> 🌌 一款简洁的自托管评论系统 | A Selfhosted Comment System.
[![](https://img.shields.io/npm/v/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![](https://img.shields.io/npm/dt/artalk.svg?style=flat-square)](https://www.npmjs.com/package/artalk)
[![](https://img.shields.io/github/last-commit/ArtalkJS/Artalk/master.svg?style=flat-square)](https://github.com/ArtalkJS/Artalk/commits/master)
@@ -14,7 +12,11 @@
[![](https://img.shields.io/travis/com/ArtalkJS/Artalk?style=flat-square)](https://travis-ci.com/ArtalkJS/Artalk)
[![](https://img.shields.io/github/license/ArtalkJS/Artalk.svg?style=flat-square)](./LICENSE)
## [官网前往](https://artalk.js.org) | [文档细节](https://artalk.js.org/docs)
> 🌌 一款简洁的自托管评论系统 | A Selfhosted Comment System.
前往:[“**官方文档**”](https://artalk.js.org)
---
- 轻量 (~30kB gzipped)
- 自托管 (隐私安全)
@@ -22,7 +24,7 @@
- Markdown 语法 (通用性)
- Golang 后端 (易部署 / 跨平台)
## 特色功能
## 特性
- 表 情 包 :统一管理 / 链接替换
- 通知中心:红点标记 / 已读记录
@@ -46,11 +48,16 @@
- TypeScript & Vanilla:纯天然无添加 / 无需依赖
- [Vite](https://github.com/vitejs/vite):开发者的极致体验
## 基本食用方针
## 食用方针
前往:[“**文档 · 部署**”](https://artalk.js.org/guide/deploy.html)
### 两步抵达
1. 后端程序部署:[ArtalkGo](https://github.com/ArtalkJS/ArtalkGo)
<details>
<summary>点击展开</summary>
1. 后端程序部署,前往:[“**文档 · 后端部署**”](https://artalk.js.org/guide/backend/install.html)
2. 前端页面引入:
```html
@@ -65,29 +72,26 @@
<body>
<!-- 给定元素 -->
<div id="ArtalkComments"></div>
<div id="Comments"></div>
<!-- 引入 JS -->
<script src="https://cdn.jsdelivr.net/npm/artalk@2/dist/Artalk.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/artalk@2/dist/Artalk.js"></script>
<!-- 配置 Artalk -->
<script>
new Artalk({
el: '#ArtalkComments',
placeholder: '说点什么 (づ ̄ 3 ̄)づ',
noComment: '此时无声胜有声',
pageKey: '', // 页面链接 (填写一个页面的完整 URL)
pageTitle: '', // 页面标题 (用于后台列表显示)
server: '', // 后端程序 (填写后端程序完整 URL;例如:https://domain/api)
site: '', // 站点名称(用于站点隔离,留空使用默认站点)
el: '#Comments',
pageKey: '<页面链接>',
pageTitle: '<页面标题>',
server: '<后端地址>',
site: '<站点名称>',
})
</script>
</body>
</html>
```
更多细节请 [查阅文档](https://artalk.js.org/docs)
</details>
### CDN 资源
@@ -98,7 +102,7 @@
<link href="https://cdn.jsdelivr.net/npm/artalk@2/dist/Artalk.css" rel="stylesheet">
<!-- JS -->
<script src="https://cdn.jsdelivr.net/npm/artalk@2/dist/Artalk.umd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/artalk@2/dist/Artalk.js"></script>
```
### NPM 引用
@@ -111,7 +115,7 @@ $ yarn add artalk
import Artalk from 'artalk'
new Artalk({
// ...your configs
// ...your config
})
```
@@ -130,4 +134,4 @@ Artalk 拥有 TypeScript 声明文件,能够在引用时帮助您进行代码
[GPL-3.0](./LICENSE)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_large)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2FArtalkJS%2FArtalk?ref=badge_large)
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "artalk",
"version": "2.0.2",
"version": "2.0.4",
"description": "A Fast, Slight & Delightful Comment",
"keywords": [
"comment-system",
@@ -16,7 +16,7 @@
"type": "git",
"url": "https://github.com/ArtalkJS/Artalk.git"
},
"main": "./dist/Artalk.umd.js",
"main": "./dist/Artalk.js",
"unpkg": "./dist/Artalk.iife.js",
"jsdelivr": "./dist/Artalk.iife.js",
"module": "./dist/Artalk.es.js",
@@ -24,7 +24,7 @@
"exports": {
".": {
"import": "./dist/Artalk.es.js",
"require": "./dist/Artalk.umd.js"
"require": "./dist/Artalk.js"
}
},
"scripts": {
+107 -27
View File
@@ -357,57 +357,137 @@ export default class AdminView extends SidebarView {
const settingEl = Utils.createElement(`
<div class="atk-setting">
<div class="atk-log-wrap" style="display: none;">
<div class="atk-log-back-btn">返回</div>
<div class="atk-log"></div>
</div>
<div class="atk-group atk-importer atk-form-wrap">
<div class="atk-title">导入评论数据</div>
<input type="file" name="importer_dataFile" accept="text/plain,.json" />
<div class="atk-label">数据类型:</div>
<div class="atk-label">数据类型</div>
<select name="importer_dataType">
<option value="artrans">Artrans (数据行囊)</option>
<option value="artalk_v1">Artalk v1 (PHP 旧版)</option>
<option value="typecho">Typecho</option>
<option value="wordpress">WordPress</option>
<option value="disqus">Disqus</option>
<option value="commento">Commento</option>
<option value="valine">Valine</option>
<option value="twikoo">Twikoo</option>
</select>
<div class="atk-label">目标站点名:</div>
<input type="file" name="importer_dataFile" accept="text/plain,.json" />
<div class="atk-label">目标站点名</div>
<input type="text" name="importer_siteName" />
<div class="atk-label">目标站点 URL</div>
<input type="text" name="importer_siteUrl" />
<div class="atk-label">启动参数</div>
<textarea name="importer_payload"></textarea>
<span class="atk-desc">启动参数请查阅:“<a href="https://artalk.js.org/guide/transfer.html" target="_blank">文档 · 数据搬家</a>”</span>
<button class="atk-btn" name="importer_submit">导入</button>
</div>
</div>`)
el.append(settingEl)
const formWrapEl = settingEl.querySelector<HTMLElement>('.atk-form-wrap')!
const logWrapEl = settingEl.querySelector<HTMLElement>('.atk-log-wrap')!
const logEl = logWrapEl.querySelector<HTMLElement>('.atk-log')!
const logBackBtnEl = logWrapEl?.querySelector<HTMLElement>('.atk-log-back-btn')!
logBackBtnEl.onclick = () => {
logWrapEl.style.display = 'none'
formWrapEl.style.display = ''
}
const impDataTypeEl = settingEl.querySelector<HTMLSelectElement>('[name="importer_dataType"]')!
const impDataFileEl = settingEl.querySelector<HTMLInputElement>('[name="importer_dataFile"]')!
const impSiteNameEl = settingEl.querySelector<HTMLInputElement>('[name="importer_siteName"]')!
const impDataTypeEl = settingEl.querySelector<HTMLSelectElement>('[name="importer_dataType"]')!
const impSubmitEl = settingEl.querySelector<HTMLButtonElement>('[name="importer_submit"]')!
const impSubmitTextOrg = impSubmitEl.innerText
impSubmitEl.onclick = () => {
const siteName = impSiteNameEl.value.trim()
const dataType = impDataTypeEl.value.trim()
const impSiteUrlEl = settingEl.querySelector<HTMLInputElement>('[name="importer_siteUrl"]')!
const impPayloadEl = settingEl.querySelector<HTMLInputElement>('[name="importer_payload"]')!
if (!impDataFileEl.files || impDataFileEl.files.length === 0) {
window.alert('请打开文件')
return
impDataTypeEl.onchange = () => {
if (['typecho'].includes(impDataTypeEl.value)) {
impDataFileEl.style.display = 'none'
} else {
impDataFileEl.style.display = ''
}
}
const impSubmitEl = settingEl.querySelector<HTMLButtonElement>('[name="importer_submit"]')!
impSubmitEl.onclick = () => {
const dataType = impDataTypeEl.value.trim()
const siteName = impSiteNameEl.value.trim()
const siteUrl = impSiteUrlEl.value.trim()
const payload = impPayloadEl.value.trim()
if (dataType === '') {
window.alert('请选择数据类型')
return
}
const createImportSession = (data?: string) => {
logWrapEl.style.display = ''
formWrapEl.style.display = 'none'
// 创建 iframe
const frameName = `f_${+new Date()}`
const frame = document.createElement('iframe')
frame.className = 'atk-iframe'
frame.name = frameName
logEl.innerHTML = ''
logEl.append(frame)
const formEl = document.createElement('form')
formEl.style.display = 'none'
formEl.setAttribute('method', 'post')
formEl.setAttribute('action', `${this.ctx.conf.server}/admin/artransfer`)
formEl.setAttribute("target", frameName)
let pJSON: any = {}
if (payload) {
// JSON 格式检验
try {
pJSON = JSON.parse(payload)
} catch (err) {
window.alert(`Payload JSON 格式有误:${String(err)}`)
}
if (pJSON !instanceof Object) {
window.alert(`Payload 需为 JSON 对象`)
}
}
if (siteName) pJSON.t_name = siteName
if (siteUrl) pJSON.t_url = siteUrl
if (data) pJSON.json_data = data
const formParams: {[k: string]: string} = {
type: dataType,
payload: JSON.stringify(pJSON),
token: this.ctx.user.data.token || '',
}
Object.entries(formParams).forEach(([key, val]) => {
const hiddenField = document.createElement('input')
hiddenField.setAttribute('type', 'hidden')
hiddenField.setAttribute('name', key)
hiddenField.value = val
formEl.appendChild(hiddenField)
})
logWrapEl.append(formEl)
formEl.submit()
formEl.remove()
}
const reader = new FileReader()
reader.onload = () => {
const data = String(reader.result)
if (!data) return
impSubmitEl.innerText = '请稍后...'
new Api(this.ctx).importer(data, dataType, siteName)
.then(() => {
window.alert(`导入成功`)
})
.catch((err) => {
console.error(err)
window.alert(`导入失败:${err.msg || '未知错误'}`)
})
.finally(() => {
impSubmitEl.innerText = impSubmitTextOrg
})
createImportSession(data)
}
reader.readAsText(impDataFileEl.files[0]);
if (impDataFileEl.files?.length) {
reader.readAsText(impDataFileEl.files[0])
return
}
createImportSession()
}
this.el.innerHTML = ''
+1 -14
View File
@@ -283,19 +283,6 @@ export default class Api {
body: getFormData(params),
}).then((json) => (json.success as boolean))
}
public importer(data: string, type: string, siteName: string) {
const params: any = {
data,
type,
site_name: siteName || '',
}
return CommonFetch(this.ctx, `${this.serverURL}/admin/importer`, {
method: 'POST',
body: getFormData(params),
}).then((json) => (json.success as boolean))
}
}
/** 公共请求函数 */
@@ -309,7 +296,7 @@ function CommonFetch(ctx: Context, input: RequestInfo, init: RequestInit): Promi
// 15s timeout
return timeoutPromise(15000, fetch(input, init)).then(async (resp) => {
if (!resp.ok) {
if (!resp.ok && resp.status !== 401) {
throw new Error(`请求响应 ${resp.status}`)
}
+1 -1
View File
@@ -257,7 +257,7 @@
.atk-comment-children {
.atk-comment-wrap {
margin-top: 10px;
border-left: 1px dashed hsla(0,0%,93%,.5);
border-left: 1px dashed var(--at-color-border);
.comment-small-size()
}
+44 -1
View File
@@ -124,6 +124,7 @@
cursor: pointer;
user-select: none;
border-radius: 50px;
margin-bottom: 5px;
&:hover {
color: #4285f4;
@@ -161,14 +162,20 @@
}
}
}
button {
width: 200px !important;
}
}
.atk-form-wrap, .atk-form-inline-wrap {
padding: 10px 10px;
input, select {
min-width: 200px;
}
input {
input, textarea {
display: block;
line-height: 30px;
padding: 0 10px;
@@ -176,6 +183,7 @@
border: none;
border-bottom: 1px solid @color-border;
outline: none;
width: 100%;
&:focus {
border-bottom-color: @color-main;
@@ -185,9 +193,15 @@
width: 200px;
cursor: pointer;
position: relative;
border: 0;
margin: 17px 0;
}
}
textarea {
min-height: 120px;
}
select {
display: block;
outline: none;
@@ -195,6 +209,7 @@
border-bottom: 1px solid @color-border;
height: 30px;
padding: 0 10px;
width: 100%;
}
button {
@@ -212,6 +227,34 @@
padding: 0 20px;
border-radius: 2px;
margin: 0 5px;
width: 100%;
}
.atk-desc {
font-size: 14px;
margin-top: 12px;
margin-left: 15px;
display: block;
}
}
.atk-admin-setting {
.atk-log-back-btn {
display: inline-block;
padding: 5px 30px;
cursor: pointer;
user-select: none;
&:hover {
background: #f4f4f4;
}
}
.atk-iframe {
width: 100%;
height: calc(100vh - 150px);
border: 0;
background: #f4f4f4;
border: 5px solid #eee;
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ export default defineConfig({
lib: {
entry: resolve(__dirname, 'src/main.ts'),
name: 'Artalk',
fileName: (format) => `Artalk.${format}.js`,
fileName: (format) => ((format == "umd") ? 'Artalk.js' : `Artalk.${format}.js`),
formats: ["es", "umd", "iife"]
},
rollupOptions: {