@waline/client 2.0.2 → 2.0.3
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/component.js +1 -1
- package/dist/component.js.map +1 -1
- package/dist/legacy.js +1 -1
- package/dist/legacy.js.map +1 -1
- package/dist/pageview.cjs.js +1 -1
- package/dist/pageview.esm.js +1 -1
- package/dist/pageview.js +1 -1
- package/dist/shim.esm.js +1 -1
- package/dist/shim.esm.js.map +1 -1
- package/dist/shim.js +1 -1
- package/dist/shim.js.map +1 -1
- package/dist/waline.cjs.js +1 -1
- package/dist/waline.cjs.js.map +1 -1
- package/dist/waline.esm.js +1 -1
- package/dist/waline.esm.js.map +1 -1
- package/dist/waline.js +1 -1
- package/dist/waline.js.map +1 -1
- package/package.json +15 -8
- package/src/comment.ts +1 -1
- package/src/components/CommentBox.vue +13 -18
- package/src/components/CommentCard.vue +6 -3
- package/src/components/Waline.vue +3 -25
- package/src/composables/index.ts +1 -1
- package/src/composables/inputs.ts +9 -21
- package/src/composables/timeAgo.ts +61 -0
- package/src/composables/userInfo.ts +14 -21
- package/src/init.ts +1 -1
- package/src/utils/date.ts +17 -0
- package/src/utils/emoji.ts +8 -6
- package/src/utils/{data.ts → image.ts} +0 -0
- package/src/utils/index.ts +2 -3
- package/src/widgets/recentComments.ts +4 -2
- package/src/composables/store.ts +0 -38
- package/src/utils/timeAgo.ts +0 -75
- package/src/utils/userInfo.ts +0 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waline/client",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"description": "client for waline comment system",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"valine",
|
|
@@ -9,9 +9,15 @@
|
|
|
9
9
|
"blog"
|
|
10
10
|
],
|
|
11
11
|
"repository": {
|
|
12
|
-
"url": "https://github.com/walinejs/waline"
|
|
12
|
+
"url": "https://github.com/walinejs/waline",
|
|
13
|
+
"directory": "packages/client"
|
|
13
14
|
},
|
|
14
15
|
"license": "MIT",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Mr.Hope",
|
|
18
|
+
"email": "mister-hope@outlook.com",
|
|
19
|
+
"url": "https://mrhope.site"
|
|
20
|
+
},
|
|
15
21
|
"exports": {
|
|
16
22
|
".": {
|
|
17
23
|
"import": "./dist/shim.esm.js",
|
|
@@ -53,14 +59,15 @@
|
|
|
53
59
|
]
|
|
54
60
|
},
|
|
55
61
|
"dependencies": {
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
62
|
+
"@vueuse/core": "^8.3.1",
|
|
63
|
+
"autosize": "^5.0.1",
|
|
64
|
+
"hanabi": "^0.4.0",
|
|
65
|
+
"marked": "^4.0.14",
|
|
66
|
+
"vue": "^3.2.33"
|
|
60
67
|
},
|
|
61
68
|
"devDependencies": {
|
|
62
|
-
"@types/autosize": "4.0.1",
|
|
63
|
-
"@types/marked": "4.0.3"
|
|
69
|
+
"@types/autosize": "^4.0.1",
|
|
70
|
+
"@types/marked": "^4.0.3"
|
|
64
71
|
},
|
|
65
72
|
"engines": {
|
|
66
73
|
"node": ">=12.20.0"
|
package/src/comment.ts
CHANGED
|
@@ -40,7 +40,7 @@ WalineCommentCountOptions): WalineAbort => {
|
|
|
40
40
|
// comment count
|
|
41
41
|
const elements = document.querySelectorAll<HTMLElement>(selector);
|
|
42
42
|
|
|
43
|
-
const
|
|
43
|
+
const userInfo = useUserInfo();
|
|
44
44
|
|
|
45
45
|
if (elements.length)
|
|
46
46
|
void fetchCommentCount({
|
|
@@ -273,8 +273,8 @@ export default defineComponent({
|
|
|
273
273
|
setup(props, { emit }) {
|
|
274
274
|
const config = inject<ComputedRef<Config>>('config') as ComputedRef<Config>;
|
|
275
275
|
|
|
276
|
-
const
|
|
277
|
-
const
|
|
276
|
+
const inputs = useInputs();
|
|
277
|
+
const userInfo = useUserInfo();
|
|
278
278
|
|
|
279
279
|
const inputRefs = ref<Record<string, HTMLInputElement>>({});
|
|
280
280
|
const editorRef = ref<HTMLTextAreaElement | null>(null);
|
|
@@ -308,7 +308,7 @@ export default defineComponent({
|
|
|
308
308
|
const endPosition = textArea.selectionEnd || 0;
|
|
309
309
|
const scrollTop = textArea.scrollTop;
|
|
310
310
|
|
|
311
|
-
inputs.editor =
|
|
311
|
+
inputs.value.editor =
|
|
312
312
|
textArea.value.substring(0, startPosition) +
|
|
313
313
|
content +
|
|
314
314
|
textArea.value.substring(endPosition, textArea.value.length);
|
|
@@ -333,7 +333,7 @@ export default defineComponent({
|
|
|
333
333
|
return Promise.resolve()
|
|
334
334
|
.then(() => (config.value.imageUploader as WalineImageUploader)(file))
|
|
335
335
|
.then((url) => {
|
|
336
|
-
inputs.editor = inputs.editor.replace(
|
|
336
|
+
inputs.value.editor = inputs.value.editor.replace(
|
|
337
337
|
uploadText,
|
|
338
338
|
`\r\n`
|
|
339
339
|
);
|
|
@@ -374,9 +374,9 @@ export default defineComponent({
|
|
|
374
374
|
|
|
375
375
|
const comment: WalineCommentData = {
|
|
376
376
|
comment: content.value,
|
|
377
|
-
nick: inputs.nick,
|
|
378
|
-
mail: inputs.mail,
|
|
379
|
-
link: inputs.link,
|
|
377
|
+
nick: inputs.value.nick,
|
|
378
|
+
mail: inputs.value.mail,
|
|
379
|
+
link: inputs.value.link,
|
|
380
380
|
ua: navigator.userAgent,
|
|
381
381
|
url: config.value.path,
|
|
382
382
|
};
|
|
@@ -441,18 +441,12 @@ export default defineComponent({
|
|
|
441
441
|
.then((resp) => {
|
|
442
442
|
isSubmitting.value = false;
|
|
443
443
|
|
|
444
|
-
store.update({
|
|
445
|
-
nick: comment.nick,
|
|
446
|
-
link: comment.link,
|
|
447
|
-
mail: comment.mail,
|
|
448
|
-
});
|
|
449
|
-
|
|
450
444
|
if (resp.errmsg) return alert(resp.errmsg);
|
|
451
445
|
|
|
452
446
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
453
447
|
emit('submit', resp.data!);
|
|
454
448
|
|
|
455
|
-
inputs.editor = '';
|
|
449
|
+
inputs.value.editor = '';
|
|
456
450
|
|
|
457
451
|
previewText.value = '';
|
|
458
452
|
|
|
@@ -488,7 +482,7 @@ export default defineComponent({
|
|
|
488
482
|
|
|
489
483
|
if (data.data.token) {
|
|
490
484
|
handler?.close();
|
|
491
|
-
|
|
485
|
+
userInfo.value = data.data;
|
|
492
486
|
(data.data.remember ? localStorage : sessionStorage).setItem(
|
|
493
487
|
'WALINE_USER',
|
|
494
488
|
JSON.stringify(data.data)
|
|
@@ -502,7 +496,7 @@ export default defineComponent({
|
|
|
502
496
|
};
|
|
503
497
|
|
|
504
498
|
const onLogout = (): void => {
|
|
505
|
-
|
|
499
|
+
userInfo.value = {};
|
|
506
500
|
localStorage.setItem('WALINE_USER', 'null');
|
|
507
501
|
sessionStorage.setItem('WALINE_USER', 'null');
|
|
508
502
|
};
|
|
@@ -529,7 +523,8 @@ export default defineComponent({
|
|
|
529
523
|
const receiver = ({ data }: any): void => {
|
|
530
524
|
if (!data || data.type !== 'profile') return;
|
|
531
525
|
|
|
532
|
-
|
|
526
|
+
userInfo.value = { ...userInfo.value, ...data };
|
|
527
|
+
|
|
533
528
|
[localStorage, sessionStorage]
|
|
534
529
|
.filter((store) => store.getItem('WALINE_USER'))
|
|
535
530
|
.forEach((store) =>
|
|
@@ -551,7 +546,7 @@ export default defineComponent({
|
|
|
551
546
|
|
|
552
547
|
// watch editor
|
|
553
548
|
watch(
|
|
554
|
-
() => inputs.editor,
|
|
549
|
+
() => inputs.value.editor,
|
|
555
550
|
(value) => {
|
|
556
551
|
const { highlighter, texRenderer } = config.value;
|
|
557
552
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
/>
|
|
25
25
|
<span v-if="comment.sticky" class="wl-badge" v-text="locale.sticky" />
|
|
26
26
|
|
|
27
|
-
<span class="wl-time" v-text="
|
|
27
|
+
<span class="wl-time" v-text="time" />
|
|
28
28
|
|
|
29
29
|
<button
|
|
30
30
|
class="wl-reply"
|
|
@@ -69,7 +69,8 @@
|
|
|
69
69
|
import { computed, defineComponent, inject } from 'vue';
|
|
70
70
|
import CommentBox from './CommentBox.vue';
|
|
71
71
|
import { ReplyIcon, VerifiedIcon } from './Icons';
|
|
72
|
-
import { isLinkHttp
|
|
72
|
+
import { isLinkHttp } from '../utils';
|
|
73
|
+
import { useTimeAgo } from '../composables';
|
|
73
74
|
|
|
74
75
|
import type { ComputedRef, PropType } from 'vue';
|
|
75
76
|
import type { Config } from '../utils';
|
|
@@ -108,6 +109,8 @@ export default defineComponent({
|
|
|
108
109
|
return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';
|
|
109
110
|
});
|
|
110
111
|
|
|
112
|
+
const time = useTimeAgo(props.comment.insertedAt, locale.value);
|
|
113
|
+
|
|
111
114
|
const isReplyingCurrent = computed(
|
|
112
115
|
() => props.comment.objectId === props.reply?.objectId
|
|
113
116
|
);
|
|
@@ -118,7 +121,7 @@ export default defineComponent({
|
|
|
118
121
|
|
|
119
122
|
isReplyingCurrent,
|
|
120
123
|
link,
|
|
121
|
-
|
|
124
|
+
time,
|
|
122
125
|
};
|
|
123
126
|
},
|
|
124
127
|
});
|
|
@@ -114,7 +114,6 @@ export default defineComponent({
|
|
|
114
114
|
|
|
115
115
|
meta: {
|
|
116
116
|
type: Array,
|
|
117
|
-
// default: (): Meta[] => ['nick', 'mail', 'link'],
|
|
118
117
|
...(SHOULD_VALIDATE
|
|
119
118
|
? {
|
|
120
119
|
validator: (value: unknown): boolean =>
|
|
@@ -126,7 +125,6 @@ export default defineComponent({
|
|
|
126
125
|
|
|
127
126
|
requiredMeta: {
|
|
128
127
|
type: Array,
|
|
129
|
-
// default: (): Meta[] => [],
|
|
130
128
|
...(SHOULD_VALIDATE
|
|
131
129
|
? {
|
|
132
130
|
validator: (value: unknown): boolean =>
|
|
@@ -138,17 +136,14 @@ export default defineComponent({
|
|
|
138
136
|
|
|
139
137
|
visitor: {
|
|
140
138
|
type: Boolean,
|
|
141
|
-
// default: false,
|
|
142
139
|
},
|
|
143
140
|
|
|
144
141
|
dark: {
|
|
145
142
|
type: [String, Boolean],
|
|
146
|
-
// default: false,
|
|
147
143
|
},
|
|
148
144
|
|
|
149
145
|
lang: {
|
|
150
146
|
type: String,
|
|
151
|
-
// default: 'zh-CN',
|
|
152
147
|
...(SHOULD_VALIDATE
|
|
153
148
|
? {
|
|
154
149
|
validator: (value: unknown): boolean =>
|
|
@@ -163,7 +158,6 @@ export default defineComponent({
|
|
|
163
158
|
|
|
164
159
|
pageSize: {
|
|
165
160
|
type: Number,
|
|
166
|
-
// default: 10,
|
|
167
161
|
},
|
|
168
162
|
|
|
169
163
|
wordLimit: {
|
|
@@ -182,9 +176,6 @@ export default defineComponent({
|
|
|
182
176
|
|
|
183
177
|
emoji: {
|
|
184
178
|
type: Array as PropType<(string | WalineEmojiInfo)[]>,
|
|
185
|
-
// default: (): string[] => [
|
|
186
|
-
// 'https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo',
|
|
187
|
-
// ],
|
|
188
179
|
...(SHOULD_VALIDATE
|
|
189
180
|
? {
|
|
190
181
|
validator: (value: unknown): boolean =>
|
|
@@ -207,38 +198,25 @@ export default defineComponent({
|
|
|
207
198
|
|
|
208
199
|
login: {
|
|
209
200
|
type: String as PropType<'enable' | 'disable' | 'force'>,
|
|
210
|
-
// default: 'enable',
|
|
211
201
|
},
|
|
212
202
|
|
|
213
203
|
highlighter: {
|
|
214
204
|
type: Function as PropType<WalineHighlighter>,
|
|
215
|
-
// default: (text: string): string => text,
|
|
216
205
|
},
|
|
217
206
|
|
|
218
207
|
imageUploader: {
|
|
219
|
-
type: [Function,
|
|
220
|
-
// default: (file: File): Promise<string> =>
|
|
221
|
-
// new Promise((resolve, reject) => {
|
|
222
|
-
// const reader = new FileReader();
|
|
223
|
-
// reader.readAsDataURL(file);
|
|
224
|
-
// reader.onload = (): void => resolve(reader.result?.toString() || '');
|
|
225
|
-
// reader.onerror = reject;
|
|
226
|
-
// }),
|
|
208
|
+
type: [Function, Boolean] as PropType<WalineImageUploader | false>,
|
|
227
209
|
},
|
|
228
210
|
|
|
229
211
|
texRenderer: {
|
|
230
|
-
type: Function as PropType<WalineTexRenderer>,
|
|
231
|
-
// default: (blockMode: boolean): string =>
|
|
232
|
-
// blockMode === true
|
|
233
|
-
// ? '<p class="wl-tex">Tex is not available in preview</p>'
|
|
234
|
-
// : '<span class="wl-tex">Tex is not available in preview</span>',
|
|
212
|
+
type: [Function, Boolean] as PropType<WalineTexRenderer | false>,
|
|
235
213
|
},
|
|
236
214
|
},
|
|
237
215
|
|
|
238
216
|
setup(props) {
|
|
239
217
|
const config = computed(() => getConfig(props as WalineProps));
|
|
240
218
|
|
|
241
|
-
const
|
|
219
|
+
const userInfo = useUserInfo();
|
|
242
220
|
|
|
243
221
|
const status = ref<'loading' | 'success' | 'error'>('loading');
|
|
244
222
|
|
package/src/composables/index.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import type { Store } from './store';
|
|
1
|
+
import { useStorage } from '@vueuse/core';
|
|
2
|
+
import type { RemovableRef } from '@vueuse/core';
|
|
5
3
|
|
|
6
4
|
export interface Inputs {
|
|
7
5
|
nick: string;
|
|
@@ -10,20 +8,10 @@ export interface Inputs {
|
|
|
10
8
|
editor: string;
|
|
11
9
|
}
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
inputs = reactive({
|
|
21
|
-
nick: store.get<string>('nick') || '',
|
|
22
|
-
mail: store.get<string>('mail') || '',
|
|
23
|
-
link: store.get<string>('link') || '',
|
|
24
|
-
editor: '',
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return { inputs, store };
|
|
29
|
-
};
|
|
11
|
+
export const useInputs = (): RemovableRef<Inputs> =>
|
|
12
|
+
useStorage<Inputs>('WALINE_USER_CACHE', {
|
|
13
|
+
nick: '',
|
|
14
|
+
mail: '',
|
|
15
|
+
link: '',
|
|
16
|
+
editor: '',
|
|
17
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useNow } from '@vueuse/core';
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
import { dateFormat } from '../utils';
|
|
4
|
+
|
|
5
|
+
import type { ComputedRef } from 'vue';
|
|
6
|
+
import type { WalineLocale } from '../typings';
|
|
7
|
+
|
|
8
|
+
export const useTimeAgo = (
|
|
9
|
+
date: Date | string,
|
|
10
|
+
locale: WalineLocale
|
|
11
|
+
): ComputedRef<string> => {
|
|
12
|
+
const now = useNow();
|
|
13
|
+
|
|
14
|
+
return computed(() => {
|
|
15
|
+
if (!date) return '';
|
|
16
|
+
|
|
17
|
+
const time =
|
|
18
|
+
typeof date === 'string'
|
|
19
|
+
? new Date(date.indexOf(' ') !== -1 ? date.replace(/-/g, '/') : date)
|
|
20
|
+
: date;
|
|
21
|
+
|
|
22
|
+
const timepassed = now.value.getTime() - time.getTime();
|
|
23
|
+
|
|
24
|
+
const days = Math.floor(timepassed / (24 * 3600 * 1000));
|
|
25
|
+
|
|
26
|
+
if (days === 0) {
|
|
27
|
+
// 计算相差小时数
|
|
28
|
+
|
|
29
|
+
// 计算天数后剩余的毫秒数
|
|
30
|
+
const leave1 = timepassed % (24 * 3600 * 1000);
|
|
31
|
+
const hours = Math.floor(leave1 / (3600 * 1000));
|
|
32
|
+
|
|
33
|
+
if (hours === 0) {
|
|
34
|
+
//计算相差分钟数
|
|
35
|
+
|
|
36
|
+
// 计算小时数后剩余的毫秒数
|
|
37
|
+
const leave2 = leave1 % (3600 * 1000);
|
|
38
|
+
const minutes = Math.floor(leave2 / (60 * 1000));
|
|
39
|
+
|
|
40
|
+
// 计算相差秒数
|
|
41
|
+
if (minutes === 0) {
|
|
42
|
+
// 计算分钟数后剩余的毫秒数
|
|
43
|
+
const leave3 = leave2 % (60 * 1000);
|
|
44
|
+
const seconds = Math.round(leave3 / 1000);
|
|
45
|
+
|
|
46
|
+
return `${seconds} ${locale.seconds}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return `${minutes} ${locale.minutes}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return `${hours} ${locale.hours}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (days < 0) return locale.now;
|
|
56
|
+
|
|
57
|
+
if (days < 8) return `${days} ${locale.days}`;
|
|
58
|
+
|
|
59
|
+
return dateFormat(time);
|
|
60
|
+
});
|
|
61
|
+
};
|
|
@@ -1,27 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getUserInfo } from '../utils';
|
|
1
|
+
import { useStorage } from '@vueuse/core';
|
|
3
2
|
|
|
4
3
|
import type { Ref } from 'vue';
|
|
5
|
-
import type { UserInfo } from '../utils';
|
|
6
4
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
export interface UserInfo {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
7
|
+
display_name: string;
|
|
8
|
+
email: string;
|
|
9
|
+
url: string;
|
|
10
|
+
token: string;
|
|
11
|
+
avatar: string;
|
|
12
|
+
mailMd5: string;
|
|
13
|
+
}
|
|
10
14
|
|
|
11
|
-
export const
|
|
12
|
-
userInfo: UserInfoRef;
|
|
13
|
-
setUserInfo: (userInfo: UserInfo | Record<string, never>) => void;
|
|
14
|
-
} => {
|
|
15
|
-
if (!userInfo.value.token) {
|
|
16
|
-
const info = getUserInfo();
|
|
15
|
+
export const USER_KEY = 'WALINE_USER';
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
}
|
|
17
|
+
export type UserInfoRef = Ref<UserInfo | Record<string, never>>;
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
setUserInfo: (info: UserInfo | Record<string, never>): void => {
|
|
24
|
-
userInfo.value = info;
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
};
|
|
19
|
+
export const useUserInfo = (): UserInfoRef =>
|
|
20
|
+
useStorage<UserInfo | Record<string, never>>('USER_KEY', {});
|
package/src/init.ts
CHANGED
|
@@ -97,7 +97,7 @@ export const init = ({
|
|
|
97
97
|
path = window.location.pathname,
|
|
98
98
|
...newProps
|
|
99
99
|
}: Partial<Omit<WalineInitOptions, 'el'>>): void => {
|
|
100
|
-
Object.entries(newProps).
|
|
100
|
+
Object.entries(newProps).forEach(([key, value]) => {
|
|
101
101
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
102
102
|
// @ts-ignore
|
|
103
103
|
// eslint-disable-next-line
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const padWithZeros = (vNumber: number, width: number): string => {
|
|
2
|
+
let numAsString = vNumber.toString();
|
|
3
|
+
|
|
4
|
+
while (numAsString.length < width) {
|
|
5
|
+
numAsString = '0' + numAsString;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return numAsString;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const dateFormat = (date: Date): string => {
|
|
12
|
+
const vDay = padWithZeros(date.getDate(), 2);
|
|
13
|
+
const vMonth = padWithZeros(date.getMonth() + 1, 2);
|
|
14
|
+
const vYear = padWithZeros(date.getFullYear(), 2);
|
|
15
|
+
|
|
16
|
+
return `${vYear}-${vMonth}-${vDay}`;
|
|
17
|
+
};
|
package/src/utils/emoji.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useStorage } from '@vueuse/core';
|
|
2
2
|
import { removeEndingSplash } from './path';
|
|
3
3
|
|
|
4
4
|
import type { EmojiConfig } from './config';
|
|
5
5
|
import type { WalineEmojiInfo } from '../typings';
|
|
6
6
|
|
|
7
|
-
let store: Store;
|
|
8
|
-
|
|
9
7
|
const hasVersion = (url: string): boolean =>
|
|
10
8
|
Boolean(/@[0-9]+\.[0-9]+\.[0-9]+/.test(url));
|
|
11
9
|
|
|
12
10
|
const fetchEmoji = (link: string): Promise<WalineEmojiInfo> => {
|
|
13
|
-
|
|
11
|
+
const emojiStore = useStorage<Record<string, WalineEmojiInfo>>(
|
|
12
|
+
'WALINE_EMOJI',
|
|
13
|
+
{}
|
|
14
|
+
);
|
|
14
15
|
|
|
15
16
|
const result = hasVersion(link);
|
|
16
17
|
|
|
17
18
|
if (result) {
|
|
18
|
-
const info =
|
|
19
|
+
const info = emojiStore.value.link;
|
|
20
|
+
|
|
19
21
|
if (info) return Promise.resolve(info);
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -27,7 +29,7 @@ const fetchEmoji = (link: string): Promise<WalineEmojiInfo> => {
|
|
|
27
29
|
...emojiInfo,
|
|
28
30
|
};
|
|
29
31
|
|
|
30
|
-
if (result)
|
|
32
|
+
if (result) emojiStore.value.link = info;
|
|
31
33
|
|
|
32
34
|
return info;
|
|
33
35
|
});
|
|
File without changes
|
package/src/utils/index.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
export * from './config';
|
|
2
2
|
export * from './darkmode';
|
|
3
|
-
export * from './
|
|
3
|
+
export * from './date';
|
|
4
4
|
export * from './emoji';
|
|
5
5
|
export * from './error';
|
|
6
6
|
export * from './fetch';
|
|
7
7
|
export * from './getRoot';
|
|
8
|
+
export * from './image';
|
|
8
9
|
export * from './markdown';
|
|
9
10
|
export * from './path';
|
|
10
11
|
export * from './query';
|
|
11
|
-
export * from './timeAgo';
|
|
12
|
-
export * from './userInfo';
|
|
13
12
|
export * from './wordCount';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useUserInfo } from '../composables';
|
|
2
|
+
import { fetchRecentComment, getRoot } from '../utils';
|
|
2
3
|
|
|
3
4
|
import type { WalineComment } from '../typings';
|
|
4
5
|
|
|
@@ -46,6 +47,7 @@ export const RecentComments = ({
|
|
|
46
47
|
serverURL,
|
|
47
48
|
count,
|
|
48
49
|
}: WalineRecentCommentsOptions): Promise<WalineRecentCommentsResult> => {
|
|
50
|
+
const userInfo = useUserInfo();
|
|
49
51
|
const root = getRoot(el);
|
|
50
52
|
const controller = new AbortController();
|
|
51
53
|
|
|
@@ -53,7 +55,7 @@ export const RecentComments = ({
|
|
|
53
55
|
serverURL,
|
|
54
56
|
count,
|
|
55
57
|
signal: controller.signal,
|
|
56
|
-
token:
|
|
58
|
+
token: userInfo.value?.token,
|
|
57
59
|
}).then((comments) => {
|
|
58
60
|
if (root && comments.length) {
|
|
59
61
|
root.innerHTML = `<ul class="wl-recent-list">${comments
|
package/src/composables/store.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export interface Store {
|
|
2
|
-
get: <T = unknown>(key: string) => T | null;
|
|
3
|
-
set: <T = unknown>(key: string, content: T) => void;
|
|
4
|
-
update: <T = unknown>(content: T) => void;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export const useStore = (cacheKey: string): Store => {
|
|
8
|
-
let storage: Record<string, unknown> = {};
|
|
9
|
-
const content = localStorage.getItem(cacheKey);
|
|
10
|
-
|
|
11
|
-
if (content) {
|
|
12
|
-
try {
|
|
13
|
-
storage = JSON.parse(content) as Record<string, unknown>;
|
|
14
|
-
} catch (err) {
|
|
15
|
-
// do nothing
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
get: <T>(key: string): T | null => (storage[key] as T) || null,
|
|
21
|
-
|
|
22
|
-
set<T>(key: string, content: T): void {
|
|
23
|
-
try {
|
|
24
|
-
// make sure the content can be stringify and make a deep copy here
|
|
25
|
-
storage[key] = JSON.parse(JSON.stringify(content));
|
|
26
|
-
localStorage.setItem(cacheKey, JSON.stringify(storage));
|
|
27
|
-
} catch (err) {
|
|
28
|
-
// do nothing
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
|
|
32
|
-
update<T>(content: T): void {
|
|
33
|
-
// make sure the content can be stringify and make a deep copy here
|
|
34
|
-
storage = JSON.parse(JSON.stringify(content)) as Record<string, unknown>;
|
|
35
|
-
localStorage.setItem(cacheKey, JSON.stringify(storage));
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
};
|
package/src/utils/timeAgo.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { WalineLocale } from '../typings';
|
|
2
|
-
|
|
3
|
-
const padWithZeros = (vNumber: number, width: number): string => {
|
|
4
|
-
let numAsString = vNumber.toString();
|
|
5
|
-
|
|
6
|
-
while (numAsString.length < width) {
|
|
7
|
-
numAsString = '0' + numAsString;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return numAsString;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const dateFormat = (date: Date): string => {
|
|
14
|
-
const vDay = padWithZeros(date.getDate(), 2);
|
|
15
|
-
const vMonth = padWithZeros(date.getMonth() + 1, 2);
|
|
16
|
-
const vYear = padWithZeros(date.getFullYear(), 2);
|
|
17
|
-
|
|
18
|
-
return `${vYear}-${vMonth}-${vDay}`;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const timeAgo = (date: Date | string, locale: WalineLocale): string => {
|
|
22
|
-
if (date)
|
|
23
|
-
try {
|
|
24
|
-
if (typeof date === 'string') {
|
|
25
|
-
// compat with mysql output date
|
|
26
|
-
date = new Date(
|
|
27
|
-
date.indexOf(' ') !== -1 ? date.replace(/-/g, '/') : date
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
const oldTime = date.getTime();
|
|
31
|
-
const currTime = new Date().getTime();
|
|
32
|
-
const diffValue = currTime - oldTime;
|
|
33
|
-
|
|
34
|
-
const days = Math.floor(diffValue / (24 * 3600 * 1000));
|
|
35
|
-
|
|
36
|
-
// 计算相差小时数
|
|
37
|
-
if (days === 0) {
|
|
38
|
-
// 计算天数后剩余的毫秒数
|
|
39
|
-
const leave1 = diffValue % (24 * 3600 * 1000);
|
|
40
|
-
const hours = Math.floor(leave1 / (3600 * 1000));
|
|
41
|
-
|
|
42
|
-
//计算相差分钟数
|
|
43
|
-
if (hours === 0) {
|
|
44
|
-
// 计算小时数后剩余的毫秒数
|
|
45
|
-
const leave2 = leave1 % (3600 * 1000);
|
|
46
|
-
const minutes = Math.floor(leave2 / (60 * 1000));
|
|
47
|
-
|
|
48
|
-
// 计算相差秒数
|
|
49
|
-
if (minutes === 0) {
|
|
50
|
-
// 计算分钟数后剩余的毫秒数
|
|
51
|
-
const leave3 = leave2 % (60 * 1000);
|
|
52
|
-
const seconds = Math.round(leave3 / 1000);
|
|
53
|
-
|
|
54
|
-
return `${seconds} ${locale.seconds}`;
|
|
55
|
-
}
|
|
56
|
-
return `${minutes} ${locale.minutes}`;
|
|
57
|
-
}
|
|
58
|
-
return `${hours} ${locale.hours}`;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (days < 0) {
|
|
62
|
-
return locale.now;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (days < 8) {
|
|
66
|
-
return `${days} ${locale.days}`;
|
|
67
|
-
} else {
|
|
68
|
-
return dateFormat(date);
|
|
69
|
-
}
|
|
70
|
-
} catch (error) {
|
|
71
|
-
console.log(error);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return '';
|
|
75
|
-
};
|
package/src/utils/userInfo.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export interface UserInfo {
|
|
2
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
3
|
-
display_name: string;
|
|
4
|
-
email: string;
|
|
5
|
-
url: string;
|
|
6
|
-
token: string;
|
|
7
|
-
avatar: string;
|
|
8
|
-
mailMd5: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const USER_KEY = 'WALINE_USER';
|
|
12
|
-
|
|
13
|
-
export const getUserInfo = (): UserInfo | null => {
|
|
14
|
-
try {
|
|
15
|
-
const localStorageData = localStorage.getItem(USER_KEY);
|
|
16
|
-
const sessionStorageData = sessionStorage.getItem(USER_KEY);
|
|
17
|
-
|
|
18
|
-
return localStorageData
|
|
19
|
-
? (JSON.parse(localStorageData) as UserInfo)
|
|
20
|
-
: sessionStorageData
|
|
21
|
-
? (JSON.parse(sessionStorageData) as UserInfo)
|
|
22
|
-
: null;
|
|
23
|
-
} catch (err) {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
};
|