artalk 2.2.9 → 2.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Artalk.css +1 -1
- package/dist/Artalk.es.js +476 -99
- package/dist/Artalk.iife.js +1 -1
- package/dist/Artalk.js +1 -1
- package/index.html +3 -1
- package/package.json +4 -3
- package/src/api/index.ts +4 -3
- package/src/api/request.ts +49 -80
- package/src/artalk.ts +20 -7
- package/src/components/comment.ts +8 -5
- package/src/components/editor.ts +14 -11
- package/src/components/list-lite.ts +10 -15
- package/src/defaults.ts +5 -3
- package/types/artalk-config.d.ts +5 -2
- package/vite.config.ts +0 -6
package/index.html
CHANGED
|
@@ -38,7 +38,9 @@
|
|
|
38
38
|
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
|
39
39
|
<script>
|
|
40
40
|
// VConsole will be exported to `window.VConsole` by default.
|
|
41
|
-
|
|
41
|
+
if (navigator.userAgentData.mobile) {
|
|
42
|
+
var vConsole = new window.VConsole();
|
|
43
|
+
}
|
|
42
44
|
</script>
|
|
43
45
|
</head>
|
|
44
46
|
<body>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "artalk",
|
|
3
|
-
"version": "2.2.
|
|
4
|
-
"backendMinVersion": "2.1.
|
|
3
|
+
"version": "2.2.12",
|
|
4
|
+
"backendMinVersion": "2.1.6",
|
|
5
5
|
"license": "LGPL-3.0",
|
|
6
6
|
"description": "A Selfhosted Comment System",
|
|
7
7
|
"keywords": [
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"hanabi": "^0.4.0",
|
|
31
31
|
"insane": "^2.6.2",
|
|
32
|
-
"marked": "^4.0.14"
|
|
32
|
+
"marked": "^4.0.14",
|
|
33
|
+
"abortcontroller-polyfill": "^1.7.3"
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
35
36
|
"dev": "vite",
|
package/src/api/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import ArtalkConfig from '~/types/artalk-config'
|
|
|
3
3
|
import Context from '../context'
|
|
4
4
|
import { Fetch, ToFormData, POST, GET } from './request'
|
|
5
5
|
import * as Utils from '../lib/utils'
|
|
6
|
+
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'
|
|
6
7
|
|
|
7
8
|
export default class Api {
|
|
8
9
|
private ctx: Context
|
|
@@ -95,8 +96,6 @@ export default class Api {
|
|
|
95
96
|
/** 用户 · 获取 */
|
|
96
97
|
public userGet(name: string, email: string) {
|
|
97
98
|
const ctrl = new AbortController()
|
|
98
|
-
const { signal } = ctrl
|
|
99
|
-
|
|
100
99
|
const params: any = {
|
|
101
100
|
name, email, site_name: (this.ctx.conf.site || '')
|
|
102
101
|
}
|
|
@@ -104,7 +103,7 @@ export default class Api {
|
|
|
104
103
|
const req = Fetch(this.ctx, `${this.baseURL}/user-get`, {
|
|
105
104
|
method: 'POST',
|
|
106
105
|
body: ToFormData(params),
|
|
107
|
-
signal,
|
|
106
|
+
signal: ctrl.signal,
|
|
108
107
|
}).then((json) => ({
|
|
109
108
|
user: json.data.user as UserData|null,
|
|
110
109
|
is_login: json.data.is_login as boolean,
|
|
@@ -307,6 +306,8 @@ export default class Api {
|
|
|
307
306
|
conf.emoticons = conf.emoticons.trim()
|
|
308
307
|
if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
|
|
309
308
|
conf.emoticons = JSON.parse(conf.emoticons) // pase json
|
|
309
|
+
} else if (conf.emoticons === "false") {
|
|
310
|
+
conf.emoticons = false
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
|
package/src/api/request.ts
CHANGED
|
@@ -4,81 +4,55 @@ import Context from '../context'
|
|
|
4
4
|
export async function Fetch(ctx: Context, input: RequestInfo, init: RequestInit, timeout?: number): Promise<any> {
|
|
5
5
|
// JWT
|
|
6
6
|
if (ctx.user.data.token) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
init.headers = requestHeaders
|
|
7
|
+
const headers = new Headers(init.headers) // 保留原有 headers
|
|
8
|
+
headers.set('Authorization', `Bearer ${ctx.user.data.token}`)
|
|
9
|
+
init.headers = headers
|
|
11
10
|
}
|
|
12
11
|
|
|
13
12
|
// 请求操作
|
|
14
|
-
|
|
13
|
+
const resp = await timeoutFetch(input, timeout || ctx.conf.reqTimeout || 15000, init)
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} else {
|
|
20
|
-
// 请求超时检测
|
|
21
|
-
resp = await timeoutPromise(timeout || ctx.conf.reqTimeout || 15000, fetch(input, init))
|
|
22
|
-
}
|
|
15
|
+
const respHttpCode = resp.status
|
|
16
|
+
const noAccessCodes = [401, 400]
|
|
17
|
+
const isNoAccess = noAccessCodes.includes(respHttpCode)
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
if (!resp.ok && !isNoAccess)
|
|
20
|
+
throw new Error(`请求响应 ${respHttpCode}`)
|
|
25
21
|
|
|
26
|
-
|
|
22
|
+
// 解析获取响应的 json
|
|
23
|
+
let json: any = await resp.json()
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
// 重新发起请求
|
|
26
|
+
const recall = (resolve, reject) => {
|
|
27
|
+
Fetch(ctx, input, init)
|
|
28
|
+
.then(d => { resolve(d) })
|
|
29
|
+
.catch(e => { reject(e) })
|
|
30
|
+
}
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
// 请求弹出层验证
|
|
33
|
+
if (json.data?.need_captcha) {
|
|
34
|
+
// 请求需要验证码
|
|
35
|
+
json = await (new Promise<any>((resolve, reject) => {
|
|
36
|
+
ctx.trigger('checker-captcha', {
|
|
37
|
+
imgData: json.data.img_data,
|
|
38
|
+
iframe: json.data.iframe,
|
|
39
|
+
onSuccess: () => { recall(resolve, reject) },
|
|
40
|
+
onCancel: () => { reject(json) }
|
|
37
41
|
})
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
recall(resolve, reject)
|
|
49
|
-
},
|
|
50
|
-
onCancel: () => {
|
|
51
|
-
reject(json)
|
|
52
|
-
}
|
|
53
|
-
})
|
|
54
|
-
}))
|
|
55
|
-
} else if ((json.data && json.data.need_login) || noAccessCodes.includes(resp.status)) {
|
|
56
|
-
// 请求需要管理员权限
|
|
57
|
-
json = await (new Promise<any>((resolve, reject) => {
|
|
58
|
-
ctx.trigger('checker-admin', {
|
|
59
|
-
onSuccess: () => {
|
|
60
|
-
recall(resolve, reject)
|
|
61
|
-
},
|
|
62
|
-
onCancel: () => {
|
|
63
|
-
reject(json)
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
}))
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!json.success) throw json // throw 相当于 reject(json)
|
|
70
|
-
|
|
71
|
-
return json
|
|
72
|
-
|
|
73
|
-
} catch (err) {
|
|
74
|
-
// 错误处理
|
|
75
|
-
console.error(err)
|
|
42
|
+
}))
|
|
43
|
+
} else if (json.data?.need_login || isNoAccess) {
|
|
44
|
+
// 请求需要管理员权限
|
|
45
|
+
json = await (new Promise<any>((resolve, reject) => {
|
|
46
|
+
ctx.trigger('checker-admin', {
|
|
47
|
+
onSuccess: () => { recall(resolve, reject) },
|
|
48
|
+
onCancel: () => { reject(json) }
|
|
49
|
+
})
|
|
50
|
+
}))
|
|
51
|
+
}
|
|
76
52
|
|
|
77
|
-
|
|
78
|
-
throw new Error(`网络错误`)
|
|
53
|
+
if (!json.success) throw json // throw 相当于 reject(json)
|
|
79
54
|
|
|
80
|
-
|
|
81
|
-
}
|
|
55
|
+
return json
|
|
82
56
|
}
|
|
83
57
|
|
|
84
58
|
/** 公共 POST 请求 */
|
|
@@ -108,21 +82,16 @@ export function ToFormData(object: {[key: string]: any}): FormData {
|
|
|
108
82
|
}
|
|
109
83
|
|
|
110
84
|
/** 我靠,fetch 一个 timeout,都要丑陋的实现 */
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
promise.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
},
|
|
122
|
-
(err) => {
|
|
123
|
-
clearTimeout(timeoutId)
|
|
124
|
-
reject(err)
|
|
125
|
-
}
|
|
126
|
-
)
|
|
85
|
+
function timeoutFetch(url: RequestInfo, ms: number, opts: RequestInit) {
|
|
86
|
+
const controller = new AbortController()
|
|
87
|
+
opts.signal?.addEventListener('abort', () => controller.abort()) // 保留原有 signal 功能
|
|
88
|
+
let promise = fetch(url, { ...opts, signal: controller.signal })
|
|
89
|
+
if (ms > 0) {
|
|
90
|
+
const timer = setTimeout(() => controller.abort(), ms)
|
|
91
|
+
promise.finally(() => { clearTimeout(timer) })
|
|
92
|
+
}
|
|
93
|
+
promise = promise.catch((err) => {
|
|
94
|
+
throw ((err || {}).name === 'AbortError') ? new Error('请求超时或意外终止') : err
|
|
127
95
|
})
|
|
96
|
+
return promise
|
|
128
97
|
}
|
package/src/artalk.ts
CHANGED
|
@@ -47,6 +47,11 @@ export default class Artalk {
|
|
|
47
47
|
this.conf.pageTitle = `${document.title}`
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// 列表显示模式
|
|
51
|
+
if (this.conf.nestMax && this.conf.nestMax <= 1) {
|
|
52
|
+
this.conf.flatMode = true
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
// 装载元素
|
|
51
56
|
if (!!this.conf.el && this.conf.el instanceof HTMLElement) {
|
|
52
57
|
this.$root = this.conf.el
|
|
@@ -181,8 +186,23 @@ export default class Artalk {
|
|
|
181
186
|
|
|
182
187
|
/** 暗黑模式 · 初始化 */
|
|
183
188
|
public initDarkMode() {
|
|
189
|
+
if (this.conf.darkMode === 'auto') {
|
|
190
|
+
// 自动切换暗黑模式,事件监听
|
|
191
|
+
const darkModeMedia = window.matchMedia('(prefers-color-scheme: dark)')
|
|
192
|
+
darkModeMedia.addEventListener('change', (e) => { this.setDarkMode(e.matches) })
|
|
193
|
+
this.setDarkMode(darkModeMedia.matches)
|
|
194
|
+
} else {
|
|
195
|
+
this.setDarkMode(this.conf.darkMode || false)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** 暗黑模式 · 设定 */
|
|
200
|
+
public setDarkMode(darkMode: boolean) {
|
|
184
201
|
const darkModeClassName = 'atk-dark-mode'
|
|
185
202
|
|
|
203
|
+
this.ctx.conf.darkMode = darkMode
|
|
204
|
+
this.ctx.trigger('conf-updated')
|
|
205
|
+
|
|
186
206
|
if (this.conf.darkMode) {
|
|
187
207
|
this.$root.classList.add(darkModeClassName)
|
|
188
208
|
} else {
|
|
@@ -200,13 +220,6 @@ export default class Artalk {
|
|
|
200
220
|
}
|
|
201
221
|
}
|
|
202
222
|
|
|
203
|
-
/** 暗黑模式 · 设定 */
|
|
204
|
-
public setDarkMode(darkMode: boolean) {
|
|
205
|
-
this.ctx.conf.darkMode = darkMode
|
|
206
|
-
this.ctx.trigger('conf-updated')
|
|
207
|
-
this.initDarkMode()
|
|
208
|
-
}
|
|
209
|
-
|
|
210
223
|
/** PV */
|
|
211
224
|
public async initPV() {
|
|
212
225
|
const pvNum = await new Api(this.ctx).pv()
|
|
@@ -16,6 +16,7 @@ export default class Comment extends Component {
|
|
|
16
16
|
public $main!: HTMLElement
|
|
17
17
|
public $header!: HTMLElement
|
|
18
18
|
public $headerNick!: HTMLElement
|
|
19
|
+
public $headerBadge?: HTMLElement
|
|
19
20
|
public $body!: HTMLElement
|
|
20
21
|
public $content!: HTMLElement
|
|
21
22
|
public $children!: HTMLElement|null
|
|
@@ -132,13 +133,14 @@ export default class Comment extends Component {
|
|
|
132
133
|
this.$headerNick.innerText = this.data.nick
|
|
133
134
|
}
|
|
134
135
|
|
|
135
|
-
|
|
136
|
+
this.$headerBadge = this.$el.querySelector<HTMLElement>('.atk-badge')!
|
|
136
137
|
if (this.data.badge_name) {
|
|
137
|
-
|
|
138
|
+
this.$headerBadge.innerText = this.data.badge_name
|
|
138
139
|
if (this.data.badge_color)
|
|
139
|
-
|
|
140
|
+
this.$headerBadge.style.backgroundColor = this.data.badge_color
|
|
140
141
|
} else {
|
|
141
|
-
|
|
142
|
+
this.$headerBadge.remove()
|
|
143
|
+
this.$headerBadge = undefined
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
if (this.data.is_pinned) {
|
|
@@ -204,7 +206,8 @@ export default class Comment extends Component {
|
|
|
204
206
|
this.$replyAt.querySelector<HTMLElement>('.atk-nick')!.innerText = `${this.replyTo.nick}`
|
|
205
207
|
this.$replyAt.onclick = () => { this.goToReplyComment() }
|
|
206
208
|
|
|
207
|
-
this.$
|
|
209
|
+
const $after = this.$headerBadge || this.$headerNick
|
|
210
|
+
$after.insertAdjacentElement('afterend', this.$replyAt)
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
// 回复的对象
|
package/src/components/editor.ts
CHANGED
|
@@ -153,6 +153,7 @@ export default class Editor extends Component {
|
|
|
153
153
|
this.getInputEl('link')!.value = data.user.link
|
|
154
154
|
}
|
|
155
155
|
})
|
|
156
|
+
.catch(() => {})
|
|
156
157
|
.finally(() => {
|
|
157
158
|
this.queryUserInfo.abortFunc = null // 清理
|
|
158
159
|
})
|
|
@@ -213,22 +214,14 @@ export default class Editor extends Component {
|
|
|
213
214
|
this.openedPlugName = null
|
|
214
215
|
this.$plugBtnWrap.innerHTML = ''
|
|
215
216
|
|
|
216
|
-
//
|
|
217
|
+
// 初始化 plug 按钮
|
|
217
218
|
this.LOADABLE_PLUG_LIST.forEach((PlugObj) => {
|
|
219
|
+
if (PlugObj.Name === 'emoticons' && !this.conf.emoticons) return
|
|
220
|
+
|
|
218
221
|
// 切换按钮
|
|
219
222
|
const btnElem = Utils.createElement(`<span class="atk-plug-btn" data-plug-name="${PlugObj.Name}">${PlugObj.BtnHTML}</span>`)
|
|
220
223
|
this.$plugBtnWrap.appendChild(btnElem)
|
|
221
224
|
|
|
222
|
-
// 表情包插件预加载
|
|
223
|
-
if (PlugObj.Name === 'emoticons') {
|
|
224
|
-
const emoPlug = new PlugObj(this) as EmoticonsPlug
|
|
225
|
-
this.plugList[PlugObj.Name] = emoPlug
|
|
226
|
-
|
|
227
|
-
window.setTimeout(() => {
|
|
228
|
-
emoPlug.loadEmoticonsData()
|
|
229
|
-
}, 1000) // 延迟 1s 加载
|
|
230
|
-
}
|
|
231
|
-
|
|
232
225
|
btnElem.addEventListener('click', () => {
|
|
233
226
|
let plug = this.plugList[PlugObj.Name]
|
|
234
227
|
if (!plug) {
|
|
@@ -272,6 +265,16 @@ export default class Editor extends Component {
|
|
|
272
265
|
})
|
|
273
266
|
})
|
|
274
267
|
|
|
268
|
+
// 表情包插件预加载
|
|
269
|
+
if (this.conf.emoticons) {
|
|
270
|
+
const emoPlug = new EmoticonsPlug(this)
|
|
271
|
+
this.plugList[EmoticonsPlug.Name] = emoPlug
|
|
272
|
+
|
|
273
|
+
window.setTimeout(() => {
|
|
274
|
+
emoPlug.loadEmoticonsData()
|
|
275
|
+
}, 1000) // 延迟 1s 加载
|
|
276
|
+
}
|
|
277
|
+
|
|
275
278
|
this.initImgUpload()
|
|
276
279
|
}
|
|
277
280
|
|
|
@@ -25,7 +25,7 @@ export default class ListLite extends Component {
|
|
|
25
25
|
public flatMode = false
|
|
26
26
|
|
|
27
27
|
/** 嵌套模式 */
|
|
28
|
-
public nestSortBy
|
|
28
|
+
public nestSortBy!: ListNest.SortByType
|
|
29
29
|
|
|
30
30
|
/** 分页 */
|
|
31
31
|
public pageMode: 'pagination'|'read-more' = 'pagination'
|
|
@@ -58,6 +58,9 @@ export default class ListLite extends Component {
|
|
|
58
58
|
// 评论为空时显示字符
|
|
59
59
|
if (ctx.conf.noComment) this.noCommentText = ctx.conf.noComment
|
|
60
60
|
|
|
61
|
+
// 嵌套排序方式
|
|
62
|
+
this.nestSortBy = this.ctx.conf.nestSort || 'DATE_ASC'
|
|
63
|
+
|
|
61
64
|
// 评论时间自动更新
|
|
62
65
|
window.setInterval(() => {
|
|
63
66
|
this.$el.querySelectorAll<HTMLElement>('[data-atk-comment-date]').forEach(el => {
|
|
@@ -305,6 +308,12 @@ export default class ListLite extends Component {
|
|
|
305
308
|
// 子评论查找回复对象
|
|
306
309
|
comment.replyTo = (cData.rid ? ctxData.find(c => c.id === cData.rid) : undefined)
|
|
307
310
|
|
|
311
|
+
// 渲染元素
|
|
312
|
+
comment.render()
|
|
313
|
+
|
|
314
|
+
// 放入 comment 总表中
|
|
315
|
+
this.commentList.push(comment)
|
|
316
|
+
|
|
308
317
|
return comment
|
|
309
318
|
}
|
|
310
319
|
|
|
@@ -325,28 +334,21 @@ export default class ListLite extends Component {
|
|
|
325
334
|
const rootNodes = ListNest.makeNestCommentNodeList(srcData, this.nestSortBy, this.conf.nestMax)
|
|
326
335
|
rootNodes.forEach((rootNode: ListNest.CommentNode) => {
|
|
327
336
|
const rootC = this.createComment(rootNode.comment, srcData)
|
|
328
|
-
rootC.render()
|
|
329
337
|
|
|
330
338
|
// 显示并播放渐入动画
|
|
331
339
|
this.$commentsWrap.appendChild(rootC.getEl())
|
|
332
340
|
rootC.playFadeInAnim()
|
|
333
341
|
|
|
334
|
-
// 评论放入 comments 总表中
|
|
335
|
-
this.commentList.push(rootC)
|
|
336
|
-
|
|
337
342
|
// 加载子评论
|
|
338
343
|
const that = this
|
|
339
344
|
;(function loadChildren(parentC: Comment, parentNode: ListNest.CommentNode) {
|
|
340
345
|
parentNode.children.forEach((node: ListNest.CommentNode) => {
|
|
341
346
|
const childD = node.comment
|
|
342
347
|
const childC = that.createComment(childD, srcData)
|
|
343
|
-
childC.render()
|
|
344
348
|
|
|
345
349
|
// 插入到父评论中
|
|
346
350
|
parentC.putChild(childC)
|
|
347
351
|
|
|
348
|
-
that.commentList.push(childC)
|
|
349
|
-
|
|
350
352
|
// 递归加载子评论
|
|
351
353
|
loadChildren(childC, node)
|
|
352
354
|
})
|
|
@@ -361,10 +363,6 @@ export default class ListLite extends Component {
|
|
|
361
363
|
private putCommentFlatMode(cData: CommentData, ctxData: CommentData[], insertMode: 'append'|'prepend') {
|
|
362
364
|
if (cData.is_collapsed) cData.is_allow_reply = false
|
|
363
365
|
const comment = this.createComment(cData, ctxData)
|
|
364
|
-
comment.render()
|
|
365
|
-
|
|
366
|
-
// 将评论导入 comments 总表中
|
|
367
|
-
this.commentList.push(comment)
|
|
368
366
|
|
|
369
367
|
// 可见评论添加到界面
|
|
370
368
|
// 注:不可见评论用于显示 “引用内容”
|
|
@@ -388,14 +386,11 @@ export default class ListLite extends Component {
|
|
|
388
386
|
|
|
389
387
|
if (commentData.rid === 0) {
|
|
390
388
|
// root评论 新增
|
|
391
|
-
comment.render()
|
|
392
389
|
this.$commentsWrap.prepend(comment.getEl())
|
|
393
|
-
this.commentList.push(comment)
|
|
394
390
|
} else {
|
|
395
391
|
// 子评论 新增
|
|
396
392
|
const parent = this.findComment(commentData.rid)
|
|
397
393
|
if (parent) {
|
|
398
|
-
comment.render()
|
|
399
394
|
parent.putChild(comment, (this.nestSortBy === 'DATE_ASC' ? 'append' : 'prepend'))
|
|
400
395
|
|
|
401
396
|
// 若父评论存在 “子评论部分” 限高,取消限高
|
package/src/defaults.ts
CHANGED
|
@@ -9,9 +9,13 @@ const defaults: ArtalkConfig = {
|
|
|
9
9
|
placeholder: '键入内容...',
|
|
10
10
|
noComment: '「此时无声胜有声」',
|
|
11
11
|
sendBtn: '发送评论',
|
|
12
|
-
darkMode:
|
|
12
|
+
darkMode: 'auto',
|
|
13
13
|
editorTravel: true,
|
|
14
14
|
|
|
15
|
+
flatMode: 'auto',
|
|
16
|
+
nestMax: 2,
|
|
17
|
+
nestSort: 'DATE_ASC',
|
|
18
|
+
|
|
15
19
|
emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json",
|
|
16
20
|
|
|
17
21
|
vote: true,
|
|
@@ -19,8 +23,6 @@ const defaults: ArtalkConfig = {
|
|
|
19
23
|
uaBadge: true,
|
|
20
24
|
listSort: true,
|
|
21
25
|
pvEl: '#ArtalkPV',
|
|
22
|
-
flatMode: 'auto',
|
|
23
|
-
nestMax: 3,
|
|
24
26
|
|
|
25
27
|
gravatar: {
|
|
26
28
|
default: 'mp',
|
package/types/artalk-config.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export default interface ArtalkConfig {
|
|
|
27
27
|
editorTravel?: boolean
|
|
28
28
|
|
|
29
29
|
/** 表情包 */
|
|
30
|
-
emoticons?: any
|
|
30
|
+
emoticons?: object|any[]|string|false
|
|
31
31
|
|
|
32
32
|
/** Gravatar 头像 */
|
|
33
33
|
gravatar?: {
|
|
@@ -66,7 +66,7 @@ export default interface ArtalkConfig {
|
|
|
66
66
|
pvEl?: string
|
|
67
67
|
|
|
68
68
|
/** 暗黑模式 */
|
|
69
|
-
darkMode?: boolean
|
|
69
|
+
darkMode?: boolean|'auto'
|
|
70
70
|
|
|
71
71
|
/** 请求超时(单位:秒) */
|
|
72
72
|
reqTimeout?: number
|
|
@@ -77,6 +77,9 @@ export default interface ArtalkConfig {
|
|
|
77
77
|
/** 嵌套模式 · 最大层数 */
|
|
78
78
|
nestMax?: number
|
|
79
79
|
|
|
80
|
+
/** 嵌套模式 · 排序方式 */
|
|
81
|
+
nestSort?: 'DATE_ASC'|'DATE_DESC'
|
|
82
|
+
|
|
80
83
|
/** 显示 UA 徽标 */
|
|
81
84
|
uaBadge?: boolean
|
|
82
85
|
|
package/vite.config.ts
CHANGED
|
@@ -15,18 +15,12 @@ export default defineConfig({
|
|
|
15
15
|
formats: ["es", "umd", "iife"]
|
|
16
16
|
},
|
|
17
17
|
rollupOptions: {
|
|
18
|
-
// 确保外部化处理那些你不想打包进库的依赖
|
|
19
|
-
external: ['vue'],
|
|
20
18
|
output: {
|
|
21
19
|
assetFileNames: assetInfo => {
|
|
22
20
|
if (/\.css$/.test(assetInfo.name)) {
|
|
23
21
|
return 'Artalk.css'
|
|
24
22
|
}
|
|
25
23
|
return "[name].[ext]"
|
|
26
|
-
},
|
|
27
|
-
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
|
|
28
|
-
globals: {
|
|
29
|
-
vue: 'Vue'
|
|
30
24
|
}
|
|
31
25
|
}
|
|
32
26
|
}
|