@waline/client 2.11.1 → 2.11.2
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/LICENSE +339 -0
- package/dist/api.cjs +2 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +1 -0
- package/dist/api.d.mts +1 -0
- package/dist/api.d.ts +1 -0
- package/dist/api.mjs +2 -0
- package/dist/api.mjs.map +1 -0
- package/dist/comment.cjs +2 -0
- package/dist/comment.cjs.map +1 -0
- package/dist/comment.d.cts +39 -0
- package/dist/comment.d.mts +39 -0
- package/dist/comment.d.ts +39 -0
- package/dist/comment.js +2 -0
- package/dist/comment.js.map +1 -0
- package/dist/comment.mjs +2 -0
- package/dist/comment.mjs.map +1 -0
- package/dist/component.mjs +1 -1
- package/dist/component.mjs.map +1 -1
- package/dist/legacy.umd.js +1 -1
- package/dist/legacy.umd.js.map +1 -1
- package/dist/pageview.cjs +1 -1
- package/dist/pageview.cjs.map +1 -1
- package/dist/pageview.js +1 -1
- package/dist/pageview.js.map +1 -1
- package/dist/pageview.mjs +1 -1
- package/dist/pageview.mjs.map +1 -1
- package/dist/shim.cjs +1 -1
- package/dist/shim.cjs.map +1 -1
- package/dist/shim.mjs +1 -1
- package/dist/shim.mjs.map +1 -1
- package/dist/waline-meta.css +1 -1
- package/dist/waline-meta.css.map +1 -1
- package/dist/waline.cjs +1 -1
- package/dist/waline.cjs.map +1 -1
- package/dist/waline.css +1 -1
- package/dist/waline.css.map +1 -1
- package/dist/waline.js +1 -1
- package/dist/waline.js.map +1 -1
- package/dist/waline.mjs +1 -1
- package/dist/waline.mjs.map +1 -1
- package/package.json +34 -13
- package/src/api/articleCounter.ts +53 -0
- package/src/api/comment.ts +147 -0
- package/src/api/commentCount.ts +30 -0
- package/src/api/index.ts +6 -0
- package/src/api/login.ts +53 -0
- package/src/api/pageview.ts +41 -0
- package/src/api/recentComment.ts +29 -0
- package/src/api/utils.ts +23 -0
- package/src/comment.ts +2 -10
- package/src/components/ArticleReaction.vue +18 -30
- package/src/components/CommentBox.vue +23 -48
- package/src/components/Waline.vue +9 -9
- package/src/composables/index.ts +3 -1
- package/src/composables/recaptchaV3.ts +23 -0
- package/src/composables/userInfo.ts +1 -12
- package/src/entrys/api.ts +1 -0
- package/src/entrys/comment.ts +2 -0
- package/src/init.ts +0 -11
- package/src/pageview.ts +2 -7
- package/src/styles/card.scss +1 -1
- package/src/styles/helpers/_svg.scss +12 -12
- package/src/styles/index.scss +1 -1
- package/src/styles/meta.scss +10 -14
- package/src/styles/reaction.scss +24 -18
- package/src/utils/config.ts +3 -3
- package/src/utils/index.ts +0 -1
- package/src/widgets/recentComments.ts +2 -1
- package/src/components/RecaptchaV3/IReCaptchaOptions.ts +0 -6
- package/src/components/RecaptchaV3/README.md +0 -3
- package/src/components/RecaptchaV3/RecaptchaVuePlugin.ts +0 -86
- package/src/utils/fetch.ts +0 -310
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waline/client",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.2",
|
|
4
4
|
"description": "client for waline comment system",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"valine",
|
|
@@ -25,6 +25,11 @@
|
|
|
25
25
|
"require": "./dist/shim.cjs",
|
|
26
26
|
"default": "./dist/shim.cjs"
|
|
27
27
|
},
|
|
28
|
+
"./api": {
|
|
29
|
+
"types": "./dist/api.d.ts",
|
|
30
|
+
"require": "./dist/api.cjs",
|
|
31
|
+
"default": "./dist/api.mjs"
|
|
32
|
+
},
|
|
28
33
|
"./component": {
|
|
29
34
|
"default": "./dist/component.mjs"
|
|
30
35
|
},
|
|
@@ -34,6 +39,12 @@
|
|
|
34
39
|
"require": "./dist/waline.cjs",
|
|
35
40
|
"default": "./dist/waline.js"
|
|
36
41
|
},
|
|
42
|
+
"./comment": {
|
|
43
|
+
"types": "./dist/comment.d.ts",
|
|
44
|
+
"import": "./dist/comment.mjs",
|
|
45
|
+
"require": "./dist/comment.cjs",
|
|
46
|
+
"default": "./dist/comment.js"
|
|
47
|
+
},
|
|
37
48
|
"./pageview": {
|
|
38
49
|
"types": "./dist/pageview.d.ts",
|
|
39
50
|
"import": "./dist/pageview.mjs",
|
|
@@ -42,9 +53,20 @@
|
|
|
42
53
|
},
|
|
43
54
|
"./waline.css": "./dist/waline.css",
|
|
44
55
|
"./waline-meta.css": "./dist/waline-meta.css",
|
|
56
|
+
"./dist/api": {
|
|
57
|
+
"types": "./dist/api.d.ts",
|
|
58
|
+
"require": "./dist/api.cjs",
|
|
59
|
+
"default": "./dist/api.mjs"
|
|
60
|
+
},
|
|
45
61
|
"./dist/component": {
|
|
46
62
|
"default": "./dist/component.mjs"
|
|
47
63
|
},
|
|
64
|
+
"./dist/comment": {
|
|
65
|
+
"types": "./dist/comment.d.ts",
|
|
66
|
+
"import": "./dist/comment.mjs",
|
|
67
|
+
"require": "./dist/comment.cjs",
|
|
68
|
+
"default": "./dist/comment.js"
|
|
69
|
+
},
|
|
48
70
|
"./dist/pageview": {
|
|
49
71
|
"types": "./dist/pageview.d.ts",
|
|
50
72
|
"import": "./dist/pageview.mjs",
|
|
@@ -71,17 +93,6 @@
|
|
|
71
93
|
"dist",
|
|
72
94
|
"src"
|
|
73
95
|
],
|
|
74
|
-
"scripts": {
|
|
75
|
-
"build": "pnpm rollup && pnpm style",
|
|
76
|
-
"clean": "rimraf ./dist",
|
|
77
|
-
"dev": "vite -c config/vite.config.js",
|
|
78
|
-
"lint": "eslint --ext .ts,.vue .",
|
|
79
|
-
"prepublishOnly": "pnpm clean && pnpm build",
|
|
80
|
-
"rollup": "rollup -c ./config/rollup.config.js",
|
|
81
|
-
"style": "pnpm style:main && pnpm style:meta",
|
|
82
|
-
"style:main": "sass ./src/styles/index.scss ./dist/waline.css --style=compressed",
|
|
83
|
-
"style:meta": "sass ./src/styles/meta.scss ./dist/waline-meta.css --style=compressed"
|
|
84
|
-
},
|
|
85
96
|
"browserslist": {
|
|
86
97
|
"production": [
|
|
87
98
|
">0.5%",
|
|
@@ -124,5 +135,15 @@
|
|
|
124
135
|
},
|
|
125
136
|
"engines": {
|
|
126
137
|
"node": ">=14"
|
|
138
|
+
},
|
|
139
|
+
"scripts": {
|
|
140
|
+
"build": "pnpm rollup && pnpm style",
|
|
141
|
+
"clean": "rimraf ./dist",
|
|
142
|
+
"dev": "vite -c config/vite.config.js",
|
|
143
|
+
"lint": "eslint --ext .ts,.vue .",
|
|
144
|
+
"rollup": "rollup -c ./config/rollup.config.js",
|
|
145
|
+
"style": "pnpm style:main && pnpm style:meta",
|
|
146
|
+
"style:main": "sass ./src/styles/index.scss ./dist/waline.css --style=compressed",
|
|
147
|
+
"style:meta": "sass ./src/styles/meta.scss ./dist/waline-meta.css --style=compressed"
|
|
127
148
|
}
|
|
128
|
-
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { JSON_HEADERS, errorCheck } from './utils';
|
|
2
|
+
|
|
3
|
+
export interface FetchArticleCounterOptions {
|
|
4
|
+
serverURL: string;
|
|
5
|
+
lang: string;
|
|
6
|
+
paths: string[];
|
|
7
|
+
signal: AbortSignal;
|
|
8
|
+
type: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const fetchArticleCounter = ({
|
|
12
|
+
serverURL,
|
|
13
|
+
lang,
|
|
14
|
+
paths,
|
|
15
|
+
type,
|
|
16
|
+
signal,
|
|
17
|
+
}: FetchArticleCounterOptions): Promise<
|
|
18
|
+
Record<string, number>[] | Record<string, number> | number[] | number
|
|
19
|
+
> =>
|
|
20
|
+
fetch(
|
|
21
|
+
`${serverURL}/article?path=${encodeURIComponent(
|
|
22
|
+
paths.join(',')
|
|
23
|
+
)}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,
|
|
24
|
+
{ signal }
|
|
25
|
+
)
|
|
26
|
+
.then(
|
|
27
|
+
(resp) =>
|
|
28
|
+
resp.json() as Promise<Record<string, number>[] | number[] | number>
|
|
29
|
+
)
|
|
30
|
+
.then((data) => errorCheck(data, 'article count'));
|
|
31
|
+
|
|
32
|
+
export interface UpdateArticleCounterOptions {
|
|
33
|
+
serverURL: string;
|
|
34
|
+
lang: string;
|
|
35
|
+
path: string;
|
|
36
|
+
type: string;
|
|
37
|
+
action?: 'inc' | 'desc';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const updateArticleCounter = ({
|
|
41
|
+
serverURL,
|
|
42
|
+
lang,
|
|
43
|
+
path,
|
|
44
|
+
type,
|
|
45
|
+
action,
|
|
46
|
+
}: UpdateArticleCounterOptions): Promise<number> =>
|
|
47
|
+
fetch(`${serverURL}/article?lang=${lang}`, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: JSON_HEADERS,
|
|
50
|
+
body: JSON.stringify({ path, type, action }),
|
|
51
|
+
})
|
|
52
|
+
.then((resp) => resp.json() as Promise<number>)
|
|
53
|
+
.then((data) => errorCheck(data, 'article count'));
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { JSON_HEADERS, errorCheck } from './utils';
|
|
2
|
+
import type { WalineComment, WalineCommentData } from '../typings';
|
|
3
|
+
|
|
4
|
+
export interface FetchCommentOptions {
|
|
5
|
+
serverURL: string;
|
|
6
|
+
path: string;
|
|
7
|
+
page: number;
|
|
8
|
+
pageSize: number;
|
|
9
|
+
sortBy: string;
|
|
10
|
+
signal: AbortSignal;
|
|
11
|
+
token?: string;
|
|
12
|
+
lang: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface CommentData {
|
|
16
|
+
count: number;
|
|
17
|
+
data: WalineComment[];
|
|
18
|
+
totalPages: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const fetchComment = ({
|
|
22
|
+
serverURL,
|
|
23
|
+
lang,
|
|
24
|
+
path,
|
|
25
|
+
page,
|
|
26
|
+
pageSize,
|
|
27
|
+
sortBy,
|
|
28
|
+
signal,
|
|
29
|
+
token,
|
|
30
|
+
}: FetchCommentOptions): Promise<CommentData> => {
|
|
31
|
+
const headers: Record<string, string> = {};
|
|
32
|
+
|
|
33
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
34
|
+
|
|
35
|
+
return fetch(
|
|
36
|
+
`${serverURL}/comment?path=${encodeURIComponent(
|
|
37
|
+
path
|
|
38
|
+
)}&pageSize=${pageSize}&page=${page}&lang=${lang}&sortBy=${sortBy}`,
|
|
39
|
+
{ signal, headers }
|
|
40
|
+
)
|
|
41
|
+
.then((resp) => resp.json() as Promise<CommentData>)
|
|
42
|
+
.then((data) => errorCheck(data, 'comment data'));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export interface PostCommentOptions {
|
|
46
|
+
serverURL: string;
|
|
47
|
+
lang: string;
|
|
48
|
+
token?: string;
|
|
49
|
+
comment: WalineCommentData;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface PostCommentResponse {
|
|
53
|
+
data?: WalineComment;
|
|
54
|
+
errmsg?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const postComment = ({
|
|
58
|
+
serverURL,
|
|
59
|
+
lang,
|
|
60
|
+
token,
|
|
61
|
+
comment,
|
|
62
|
+
}: PostCommentOptions): Promise<PostCommentResponse> => {
|
|
63
|
+
const headers: Record<string, string> = {
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
65
|
+
'Content-Type': 'application/json',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
69
|
+
|
|
70
|
+
if (comment.eid) {
|
|
71
|
+
return fetch(`${serverURL}/comment/${comment.eid}?lang=${lang}`, {
|
|
72
|
+
method: 'PUT',
|
|
73
|
+
headers,
|
|
74
|
+
body: JSON.stringify(comment),
|
|
75
|
+
}).then((resp) => resp.json() as Promise<PostCommentResponse>);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return fetch(`${serverURL}/comment?lang=${lang}`, {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers,
|
|
81
|
+
body: JSON.stringify(comment),
|
|
82
|
+
}).then((resp) => resp.json() as Promise<PostCommentResponse>);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export interface DeleteCommentOptions {
|
|
86
|
+
serverURL: string;
|
|
87
|
+
lang: string;
|
|
88
|
+
token: string;
|
|
89
|
+
objectId: string | number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export const deleteComment = ({
|
|
93
|
+
serverURL,
|
|
94
|
+
lang,
|
|
95
|
+
token,
|
|
96
|
+
objectId,
|
|
97
|
+
}: DeleteCommentOptions): Promise<void> =>
|
|
98
|
+
fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {
|
|
99
|
+
method: 'DELETE',
|
|
100
|
+
headers: {
|
|
101
|
+
Authorization: `Bearer ${token}`,
|
|
102
|
+
},
|
|
103
|
+
}).then((resp) => resp.json() as Promise<void>);
|
|
104
|
+
|
|
105
|
+
export interface LikeCommentOptions {
|
|
106
|
+
serverURL: string;
|
|
107
|
+
lang: string;
|
|
108
|
+
objectId: number | string;
|
|
109
|
+
like: boolean;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export const likeComment = ({
|
|
113
|
+
serverURL,
|
|
114
|
+
lang,
|
|
115
|
+
objectId,
|
|
116
|
+
like,
|
|
117
|
+
}: LikeCommentOptions): Promise<void> =>
|
|
118
|
+
fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {
|
|
119
|
+
method: 'PUT',
|
|
120
|
+
headers: JSON_HEADERS,
|
|
121
|
+
body: JSON.stringify({ like }),
|
|
122
|
+
}).then((resp) => resp.json() as Promise<void>);
|
|
123
|
+
|
|
124
|
+
export interface UpdateCommentOptions {
|
|
125
|
+
serverURL: string;
|
|
126
|
+
lang: string;
|
|
127
|
+
token: string;
|
|
128
|
+
objectId: number | string;
|
|
129
|
+
status?: 'approved' | 'waiting' | 'spam';
|
|
130
|
+
sticky?: number;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const updateComment = ({
|
|
134
|
+
serverURL,
|
|
135
|
+
lang,
|
|
136
|
+
token,
|
|
137
|
+
objectId,
|
|
138
|
+
...data
|
|
139
|
+
}: UpdateCommentOptions): Promise<void> =>
|
|
140
|
+
fetch(`${serverURL}/comment/${objectId}?lang=${lang}`, {
|
|
141
|
+
method: 'PUT',
|
|
142
|
+
headers: {
|
|
143
|
+
...JSON_HEADERS,
|
|
144
|
+
Authorization: `Bearer ${token}`,
|
|
145
|
+
},
|
|
146
|
+
body: JSON.stringify(data),
|
|
147
|
+
}).then((resp) => resp.json() as Promise<void>);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { errorCheck } from './utils';
|
|
2
|
+
|
|
3
|
+
export interface FetchCommentCountOptions {
|
|
4
|
+
serverURL: string;
|
|
5
|
+
lang: string;
|
|
6
|
+
paths: string[];
|
|
7
|
+
signal: AbortSignal;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const fetchCommentCount = ({
|
|
11
|
+
serverURL,
|
|
12
|
+
lang,
|
|
13
|
+
paths,
|
|
14
|
+
signal,
|
|
15
|
+
}: FetchCommentCountOptions): Promise<number[]> => {
|
|
16
|
+
const headers: Record<string, string> = {};
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
fetch(
|
|
20
|
+
`${serverURL}/comment?type=count&url=${encodeURIComponent(
|
|
21
|
+
paths.join(',')
|
|
22
|
+
)}&lang=${lang}`,
|
|
23
|
+
{ signal, headers }
|
|
24
|
+
)
|
|
25
|
+
.then((resp) => resp.json() as Promise<number | number[]>)
|
|
26
|
+
.then((data) => errorCheck(data, 'comment count'))
|
|
27
|
+
// TODO: Improve this API
|
|
28
|
+
.then((counts) => (Array.isArray(counts) ? counts : [counts]))
|
|
29
|
+
);
|
|
30
|
+
};
|
package/src/api/index.ts
ADDED
package/src/api/login.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
2
|
+
|
|
3
|
+
export interface LoginOptions {
|
|
4
|
+
lang: string;
|
|
5
|
+
serverURL: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface UserInfo {
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
10
|
+
display_name: string;
|
|
11
|
+
email: string;
|
|
12
|
+
url: string;
|
|
13
|
+
token: string;
|
|
14
|
+
avatar: string;
|
|
15
|
+
mailMd5: string;
|
|
16
|
+
objectId: string | number;
|
|
17
|
+
type: 'administrator' | 'guest';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const login = ({
|
|
21
|
+
lang,
|
|
22
|
+
serverURL,
|
|
23
|
+
}: LoginOptions): Promise<UserInfo & { remember: boolean }> => {
|
|
24
|
+
const width = 450;
|
|
25
|
+
const height = 450;
|
|
26
|
+
const left = (window.innerWidth - width) / 2;
|
|
27
|
+
const top = (window.innerHeight - height) / 2;
|
|
28
|
+
|
|
29
|
+
const handler = window.open(
|
|
30
|
+
`${serverURL}/ui/login?lng=${encodeURIComponent(lang)}`,
|
|
31
|
+
'_blank',
|
|
32
|
+
`width=${width},height=${height},left=${left},top=${top},scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no`
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
handler?.postMessage({ type: 'TOKEN', data: null }, '*');
|
|
36
|
+
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
+
const receiver = ({ data }: any): void => {
|
|
40
|
+
if (!data || typeof data !== 'object' || data.type !== 'userInfo') return;
|
|
41
|
+
|
|
42
|
+
if (data.data.token) {
|
|
43
|
+
handler?.close();
|
|
44
|
+
|
|
45
|
+
window.removeEventListener('message', receiver);
|
|
46
|
+
|
|
47
|
+
resolve(data.data as UserInfo & { remember: boolean });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
window.addEventListener('message', receiver);
|
|
52
|
+
});
|
|
53
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { fetchArticleCounter, updateArticleCounter } from './articleCounter';
|
|
2
|
+
|
|
3
|
+
interface FetchPageviewOptions {
|
|
4
|
+
serverURL: string;
|
|
5
|
+
lang: string;
|
|
6
|
+
paths: string[];
|
|
7
|
+
signal: AbortSignal;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const fetchPageviews = ({
|
|
11
|
+
serverURL,
|
|
12
|
+
lang,
|
|
13
|
+
paths,
|
|
14
|
+
signal,
|
|
15
|
+
}: FetchPageviewOptions): Promise<number[]> =>
|
|
16
|
+
fetchArticleCounter({
|
|
17
|
+
serverURL,
|
|
18
|
+
lang,
|
|
19
|
+
paths,
|
|
20
|
+
type: ['time'],
|
|
21
|
+
signal,
|
|
22
|
+
})
|
|
23
|
+
// TODO: Improve this API
|
|
24
|
+
.then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<
|
|
25
|
+
number[]
|
|
26
|
+
>;
|
|
27
|
+
|
|
28
|
+
export interface UpdatePageviewOptions {
|
|
29
|
+
serverURL: string;
|
|
30
|
+
lang: string;
|
|
31
|
+
path: string;
|
|
32
|
+
action?: 'inc' | 'desc';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const updatePageviews = (
|
|
36
|
+
options: UpdatePageviewOptions
|
|
37
|
+
): Promise<number> =>
|
|
38
|
+
updateArticleCounter({
|
|
39
|
+
...options,
|
|
40
|
+
type: 'time',
|
|
41
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { errorCheck } from './utils';
|
|
2
|
+
import type { WalineComment } from '../typings';
|
|
3
|
+
|
|
4
|
+
export interface FetchRecentCommentOptions {
|
|
5
|
+
serverURL: string;
|
|
6
|
+
lang: string;
|
|
7
|
+
count: number;
|
|
8
|
+
signal: AbortSignal;
|
|
9
|
+
token?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const fetchRecentComment = ({
|
|
13
|
+
serverURL,
|
|
14
|
+
lang,
|
|
15
|
+
count,
|
|
16
|
+
signal,
|
|
17
|
+
token,
|
|
18
|
+
}: FetchRecentCommentOptions): Promise<WalineComment[]> => {
|
|
19
|
+
const headers: Record<string, string> = {};
|
|
20
|
+
|
|
21
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
22
|
+
|
|
23
|
+
return fetch(`${serverURL}/comment?type=recent&count=${count}&lang=${lang}`, {
|
|
24
|
+
signal,
|
|
25
|
+
headers,
|
|
26
|
+
})
|
|
27
|
+
.then((resp) => resp.json() as Promise<WalineComment[]>)
|
|
28
|
+
.then((data) => errorCheck(data, 'recent comment'));
|
|
29
|
+
};
|
package/src/api/utils.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface FetchErrorData {
|
|
2
|
+
errno: number;
|
|
3
|
+
errmsg: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const JSON_HEADERS: Record<string, string> = {
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const errorCheck = <T = unknown>(
|
|
12
|
+
data: T | FetchErrorData,
|
|
13
|
+
name = ''
|
|
14
|
+
): T => {
|
|
15
|
+
if (typeof data === 'object' && (data as FetchErrorData).errno)
|
|
16
|
+
throw new TypeError(
|
|
17
|
+
`Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${
|
|
18
|
+
(data as FetchErrorData).errmsg
|
|
19
|
+
}`
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
return data as T;
|
|
23
|
+
};
|
package/src/comment.ts
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
decodePath,
|
|
4
|
-
errorHandler,
|
|
5
|
-
fetchCommentCount,
|
|
6
|
-
getServerURL,
|
|
7
|
-
} from './utils';
|
|
1
|
+
import { fetchCommentCount } from './api';
|
|
2
|
+
import { decodePath, errorHandler, getServerURL } from './utils';
|
|
8
3
|
import type { WalineAbort } from './typings';
|
|
9
4
|
|
|
10
5
|
export interface WalineCommentCountOptions {
|
|
@@ -55,8 +50,6 @@ WalineCommentCountOptions): WalineAbort => {
|
|
|
55
50
|
// comment count
|
|
56
51
|
const elements = document.querySelectorAll<HTMLElement>(selector);
|
|
57
52
|
|
|
58
|
-
const userInfo = useUserInfo();
|
|
59
|
-
|
|
60
53
|
if (elements.length)
|
|
61
54
|
void fetchCommentCount({
|
|
62
55
|
serverURL: getServerURL(serverURL),
|
|
@@ -65,7 +58,6 @@ WalineCommentCountOptions): WalineAbort => {
|
|
|
65
58
|
),
|
|
66
59
|
lang,
|
|
67
60
|
signal: controller.signal,
|
|
68
|
-
token: userInfo.value?.token,
|
|
69
61
|
})
|
|
70
62
|
.then((counts) => {
|
|
71
63
|
elements.forEach((element, index) => {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div v-if="reaction && reaction.length" class="wl-reaction">
|
|
3
|
-
<h4
|
|
3
|
+
<h4 v-text="locale.reactionTitle" />
|
|
4
4
|
<ul>
|
|
5
5
|
<li
|
|
6
6
|
v-for="(item, index) in reaction"
|
|
7
7
|
:key="index"
|
|
8
|
-
:class="item.active
|
|
9
|
-
@click="
|
|
8
|
+
:class="{ active: item.active }"
|
|
9
|
+
@click="vote(index)"
|
|
10
10
|
>
|
|
11
|
-
<div class="wl-
|
|
11
|
+
<div class="wl-reaction-img">
|
|
12
12
|
<img :src="item.icon" :alt="item.desc" />
|
|
13
|
-
<div class="wl-
|
|
13
|
+
<div class="wl-reaction-votes">{{ item.vote }}</div>
|
|
14
14
|
</div>
|
|
15
|
-
<div class="wl-
|
|
15
|
+
<div class="wl-reaction-text">{{ item.desc }}</div>
|
|
16
16
|
</li>
|
|
17
17
|
</ul>
|
|
18
18
|
</div>
|
|
@@ -28,12 +28,10 @@ import {
|
|
|
28
28
|
onUnmounted,
|
|
29
29
|
ref,
|
|
30
30
|
} from 'vue';
|
|
31
|
-
import {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} from '../utils';
|
|
36
|
-
import { useVoteStorage } from '../composables/vote';
|
|
31
|
+
import { fetchArticleCounter, updateArticleCounter } from '../api';
|
|
32
|
+
import { useVoteStorage } from '../composables';
|
|
33
|
+
import type { WalineConfig } from '../utils';
|
|
34
|
+
import type { WalineLocale } from '../typings';
|
|
37
35
|
|
|
38
36
|
interface ReactionItem {
|
|
39
37
|
icon: string;
|
|
@@ -46,21 +44,15 @@ export default defineComponent({
|
|
|
46
44
|
setup() {
|
|
47
45
|
const votes = ref<ReactionItem['vote'][]>([]);
|
|
48
46
|
const voteStorage = useVoteStorage();
|
|
49
|
-
const config = inject<ComputedRef<WalineConfig>>(
|
|
50
|
-
'config'
|
|
51
|
-
) as ComputedRef<WalineConfig>;
|
|
47
|
+
const config = inject<ComputedRef<WalineConfig>>('config')!;
|
|
52
48
|
const locale = computed(() => config.value.locale);
|
|
53
49
|
const reaction = computed((): ReactionItem[] => {
|
|
54
|
-
const { path } = config.value;
|
|
55
|
-
|
|
56
|
-
if (!Array.isArray(config.value.reaction)) {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
50
|
+
const { reaction, path } = config.value;
|
|
59
51
|
|
|
60
|
-
return
|
|
52
|
+
return (Array.isArray(reaction) ? reaction : []).map((icon, index) => ({
|
|
61
53
|
icon,
|
|
62
54
|
vote: votes.value[index] || 0,
|
|
63
|
-
desc: locale.value[`reaction${index}` as
|
|
55
|
+
desc: locale.value[`reaction${index}` as keyof WalineLocale],
|
|
64
56
|
active: Boolean(
|
|
65
57
|
voteStorage.value.find(({ u, i }) => u === path && i === index)
|
|
66
58
|
),
|
|
@@ -84,21 +76,17 @@ export default defineComponent({
|
|
|
84
76
|
signal: controller.signal,
|
|
85
77
|
});
|
|
86
78
|
|
|
87
|
-
if (Array.isArray(resp) || typeof resp === 'number')
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
79
|
+
if (Array.isArray(resp) || typeof resp === 'number') return;
|
|
90
80
|
|
|
91
81
|
votes.value = reaction.map((_, k) => resp[`reaction${k}`]);
|
|
92
82
|
};
|
|
93
83
|
|
|
94
|
-
const
|
|
84
|
+
const vote = async (index: number): Promise<void> => {
|
|
95
85
|
const { serverURL, lang, path } = config.value;
|
|
96
86
|
const hasVoted = voteStorage.value.find(({ u }) => u === path);
|
|
97
87
|
const hasVotedTheReaction = hasVoted && hasVoted.i === index;
|
|
98
88
|
|
|
99
|
-
if (hasVotedTheReaction)
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
89
|
+
if (hasVotedTheReaction) return;
|
|
102
90
|
|
|
103
91
|
await updateArticleCounter({
|
|
104
92
|
serverURL,
|
|
@@ -134,7 +122,7 @@ export default defineComponent({
|
|
|
134
122
|
return {
|
|
135
123
|
reaction,
|
|
136
124
|
locale,
|
|
137
|
-
|
|
125
|
+
vote,
|
|
138
126
|
};
|
|
139
127
|
},
|
|
140
128
|
});
|