@waline/client 2.14.0 → 2.14.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.
Files changed (62) hide show
  1. package/dist/comment.cjs +1 -1
  2. package/dist/comment.cjs.map +1 -1
  3. package/dist/comment.js +1 -68
  4. package/dist/comment.js.map +1 -1
  5. package/dist/comment.mjs +1 -1
  6. package/dist/comment.mjs.map +1 -1
  7. package/dist/component.mjs +1 -1
  8. package/dist/component.mjs.map +1 -1
  9. package/dist/legacy.umd.d.ts +14 -5
  10. package/dist/legacy.umd.js +1 -1
  11. package/dist/legacy.umd.js.map +1 -1
  12. package/dist/pageview.cjs +1 -1
  13. package/dist/pageview.cjs.map +1 -1
  14. package/dist/pageview.js +1 -121
  15. package/dist/pageview.js.map +1 -1
  16. package/dist/pageview.mjs +1 -1
  17. package/dist/pageview.mjs.map +1 -1
  18. package/dist/shim.cjs +1 -1
  19. package/dist/shim.cjs.map +1 -1
  20. package/dist/shim.d.cts +15 -6
  21. package/dist/shim.d.mts +15 -6
  22. package/dist/shim.mjs +1 -1
  23. package/dist/shim.mjs.map +1 -1
  24. package/dist/waline.cjs +1 -1
  25. package/dist/waline.cjs.map +1 -1
  26. package/dist/waline.css +1 -1
  27. package/dist/waline.css.map +1 -1
  28. package/dist/waline.d.cts +15 -6
  29. package/dist/waline.d.mts +15 -6
  30. package/dist/waline.d.ts +15 -6
  31. package/dist/waline.js +1 -6787
  32. package/dist/waline.js.map +1 -1
  33. package/dist/waline.mjs +1 -1
  34. package/dist/waline.mjs.map +1 -1
  35. package/package.json +18 -18
  36. package/src/comment.ts +1 -2
  37. package/src/components/ArticleReaction.vue +120 -117
  38. package/src/components/CommentBox.vue +451 -488
  39. package/src/components/CommentCard.vue +109 -98
  40. package/src/components/ImageWall.vue +132 -131
  41. package/src/components/WalineComment.vue +683 -0
  42. package/src/composables/index.ts +1 -2
  43. package/src/composables/reaction.ts +16 -0
  44. package/src/composables/recaptchaV3.ts +4 -6
  45. package/src/config/default.ts +5 -0
  46. package/src/{entrys → entries}/api.ts +0 -0
  47. package/src/{entrys → entries}/comment.ts +0 -0
  48. package/src/entries/components.ts +2 -0
  49. package/src/{entrys → entries}/full.ts +0 -0
  50. package/src/{entrys → entries}/init.ts +0 -0
  51. package/src/{entrys → entries}/legacy.ts +0 -0
  52. package/src/{entrys → entries}/pageview.ts +0 -0
  53. package/src/init.ts +1 -1
  54. package/src/styles/reaction.scss +27 -16
  55. package/src/typings/base.ts +5 -0
  56. package/src/typings/waline.ts +14 -5
  57. package/src/utils/config.ts +27 -5
  58. package/src/utils/image.ts +1 -1
  59. package/src/components/Waline.vue +0 -509
  60. package/src/composables/timeAgo.ts +0 -15
  61. package/src/composables/vote.ts +0 -20
  62. package/src/entrys/components.ts +0 -2
@@ -1,509 +0,0 @@
1
- <template>
2
- <div data-waline>
3
- <Reaction />
4
- <CommentBox v-if="!reply" @submit="onSubmit" />
5
- <div class="wl-meta-head">
6
- <div class="wl-count">
7
- <span v-if="count" class="wl-num" v-text="count" />
8
- {{ i18n.comment }}
9
- </div>
10
- <ul class="wl-sort">
11
- <li
12
- v-for="item in sortingMethods"
13
- :key="item"
14
- :class="[item === commentSorting ? 'active' : '']"
15
- @click="onSortByChange(item)"
16
- >
17
- {{ i18n[item] }}
18
- </li>
19
- </ul>
20
- </div>
21
-
22
- <div class="wl-cards">
23
- <CommentCard
24
- v-for="comment in data"
25
- :key="comment.objectId"
26
- :root-id="comment.objectId"
27
- :comment="comment"
28
- :reply="reply"
29
- :edit="edit"
30
- @reply="onReply"
31
- @edit="onEdit"
32
- @submit="onSubmit"
33
- @status="onStatusChange"
34
- @delete="onDelete"
35
- @sticky="onSticky"
36
- @like="onLike"
37
- />
38
- </div>
39
-
40
- <div v-if="status === 'error'" class="wl-operation">
41
- <button
42
- type="button"
43
- class="wl-btn"
44
- @click="refresh"
45
- v-text="i18n.refresh"
46
- />
47
- </div>
48
-
49
- <template v-else>
50
- <div v-if="status === 'loading'" class="wl-loading">
51
- <LoadingIcon :size="30" />
52
- </div>
53
-
54
- <div v-else-if="!data.length" class="wl-empty" v-text="i18n.sofa" />
55
-
56
- <!-- Load more button -->
57
- <div v-else-if="page < totalPages" class="wl-operation">
58
- <button
59
- type="button"
60
- class="wl-btn"
61
- @click="loadMore"
62
- v-text="i18n.more"
63
- />
64
- </div>
65
- </template>
66
-
67
- <!-- Copyright Information -->
68
- <div v-if="config.copyright" class="wl-power">
69
- Powered by
70
- <a
71
- href="https://github.com/walinejs/waline"
72
- target="_blank"
73
- rel="noreferrer"
74
- >
75
- Waline
76
- </a>
77
- v{{ version }}
78
- </div>
79
- </div>
80
- </template>
81
-
82
- <script lang="ts">
83
- import { useStyleTag } from '@vueuse/core';
84
- import {
85
- computed,
86
- defineComponent,
87
- onMounted,
88
- onUnmounted,
89
- provide,
90
- ref,
91
- watch,
92
- } from 'vue';
93
- import Reaction from './ArticleReaction.vue';
94
- import CommentBox from './CommentBox.vue';
95
- import CommentCard from './CommentCard.vue';
96
- import { LoadingIcon } from './Icons';
97
- import { useUserInfo, useLikeStorage } from '../composables';
98
- import { defaultLocales } from '../config';
99
- import { deleteComment, getComment, updateComment } from '../api';
100
- import { getConfig, getDarkStyle } from '../utils';
101
-
102
- import type { PropType } from 'vue';
103
- import type {
104
- WalineComment,
105
- WalineCommentSorting,
106
- WalineCommentStatus,
107
- WalineEmojiInfo,
108
- WalineLoginStatus,
109
- WalineHighlighter,
110
- WalineTexRenderer,
111
- WalineImageUploader,
112
- WalineSearchOptions,
113
- WalineLocale,
114
- WalineProps,
115
- WalineMeta,
116
- } from '../typings';
117
-
118
- declare const SHOULD_VALIDATE: boolean;
119
- declare const VERSION: string;
120
-
121
- const props = [
122
- 'serverURL',
123
- 'path',
124
- 'meta',
125
- 'requiredMeta',
126
- 'dark',
127
- 'commentSorting',
128
- 'lang',
129
- 'locale',
130
- 'pageSize',
131
- 'wordLimit',
132
- 'emoji',
133
- 'login',
134
- 'highlighter',
135
- 'texRenderer',
136
- 'imageUploader',
137
- 'search',
138
- 'copyright',
139
- 'recaptchaV3Key',
140
- 'reaction',
141
- ];
142
-
143
- type SortKey = 'insertedAt_desc' | 'insertedAt_asc' | 'like_desc';
144
- const sortKeyMap: Record<WalineCommentSorting, SortKey> = {
145
- latest: 'insertedAt_desc',
146
- oldest: 'insertedAt_asc',
147
- hottest: 'like_desc',
148
- };
149
- const sortingMethods = Object.keys(sortKeyMap) as WalineCommentSorting[];
150
-
151
- const propsWithValidate = {
152
- serverURL: {
153
- type: String,
154
- required: true,
155
- },
156
-
157
- path: {
158
- type: String,
159
- required: true,
160
- },
161
-
162
- meta: {
163
- type: Array as PropType<WalineMeta[]>,
164
- default: (): WalineMeta[] => ['nick', 'mail', 'link'],
165
- validator: (value: unknown): boolean =>
166
- Array.isArray(value) &&
167
- value.every((item) => ['nick', 'mail', 'link'].includes(item)),
168
- },
169
-
170
- requiredMeta: {
171
- type: Array,
172
- default: (): WalineMeta[] => [],
173
- validator: (value: unknown): boolean =>
174
- Array.isArray(value) &&
175
- value.every((item) => ['nick', 'mail', 'link'].includes(item)),
176
- },
177
-
178
- dark: [String, Boolean],
179
-
180
- commentSorting: {
181
- type: String,
182
- default: 'latest',
183
- validator: (value: unknown): boolean =>
184
- typeof value === 'string' &&
185
- ['latest', 'oldest', 'hottest'].includes(value),
186
- },
187
-
188
- lang: {
189
- type: String,
190
- default: 'zh-CN',
191
- validator: (value: unknown): boolean =>
192
- Object.keys(defaultLocales).includes(value as string),
193
- },
194
-
195
- locale: Object as PropType<Partial<WalineLocale>>,
196
-
197
- pageSize: { type: Number, default: 10 },
198
-
199
- wordLimit: {
200
- type: [Number, Array] as PropType<number | [number, number]>,
201
- validator: (value: unknown): boolean =>
202
- typeof value === 'number' ||
203
- (Array.isArray(value) &&
204
- value.length === 2 &&
205
- value.every((item) => typeof item === 'number')),
206
- },
207
-
208
- emoji: {
209
- type: [Array, Boolean] as PropType<(string | WalineEmojiInfo)[] | false>,
210
- validator: (value: unknown): boolean =>
211
- value === false ||
212
- (Array.isArray(value) &&
213
- value.every(
214
- (item) =>
215
- typeof item === 'string' ||
216
- (typeof item === 'object' &&
217
- typeof item.name === 'string' &&
218
- typeof item.folder === 'string' &&
219
- typeof item.icon === 'string' &&
220
- Array.isArray(item.items) &&
221
- (item.items as unknown[]).every(
222
- (icon) => typeof icon === 'string'
223
- ))
224
- )),
225
- },
226
-
227
- login: String as PropType<WalineLoginStatus>,
228
-
229
- highlighter: Function as PropType<WalineHighlighter>,
230
-
231
- imageUploader: {
232
- type: [Function, Boolean] as PropType<WalineImageUploader | false>,
233
- default: undefined,
234
- },
235
-
236
- texRenderer: {
237
- type: [Function, Boolean] as PropType<WalineTexRenderer | false>,
238
- default: undefined,
239
- },
240
-
241
- search: {
242
- type: [Object, Boolean] as PropType<WalineSearchOptions | false>,
243
- default: undefined,
244
- },
245
-
246
- copyright: { type: Boolean, default: true },
247
-
248
- recaptchaV3Key: {
249
- type: String,
250
- default: '',
251
- },
252
-
253
- reaction: {
254
- type: [Array, Boolean] as PropType<string[] | false>,
255
- },
256
- };
257
-
258
- export default defineComponent({
259
- name: 'WalineRoot',
260
-
261
- components: {
262
- Reaction,
263
- CommentBox,
264
- CommentCard,
265
- LoadingIcon,
266
- },
267
-
268
- props: SHOULD_VALIDATE ? propsWithValidate : props,
269
-
270
- setup(_props) {
271
- const props = _props as unknown as WalineProps;
272
- const config = computed(() => getConfig(props));
273
-
274
- const userInfo = useUserInfo();
275
- const likeStorage = useLikeStorage();
276
-
277
- const status = ref<'loading' | 'success' | 'error'>('loading');
278
-
279
- const count = ref(0);
280
- const page = ref(1);
281
- const totalPages = ref(0);
282
- const commentSorting = ref(config.value.commentSorting);
283
-
284
- const data = ref<WalineComment[]>([]);
285
- const reply = ref<WalineComment | null>(null);
286
- const edit = ref<WalineComment | null>(null);
287
-
288
- const darkmodeStyle = computed(() => getDarkStyle(config.value.dark));
289
-
290
- useStyleTag(darkmodeStyle);
291
-
292
- // eslint-disable-next-line vue/no-setup-props-destructure
293
- let abort: () => void;
294
-
295
- const getCommentData = (pageNumber: number): void => {
296
- const { serverURL, path, pageSize } = config.value;
297
- const controller = new AbortController();
298
-
299
- status.value = 'loading';
300
-
301
- abort?.();
302
-
303
- getComment({
304
- serverURL,
305
- lang: config.value.lang,
306
- path,
307
- pageSize,
308
- sortBy: sortKeyMap[commentSorting.value],
309
- page: pageNumber,
310
- signal: controller.signal,
311
- token: userInfo.value?.token,
312
- })
313
- .then((resp) => {
314
- status.value = 'success';
315
- count.value = resp.count;
316
- data.value.push(...resp.data);
317
- page.value = pageNumber;
318
- totalPages.value = resp.totalPages;
319
- })
320
- .catch((err) => {
321
- if (err.name !== 'AbortError') {
322
- console.error(err.message);
323
- status.value = 'error';
324
- }
325
- });
326
-
327
- abort = controller.abort.bind(controller);
328
- };
329
-
330
- const loadMore = (): void => getCommentData(page.value + 1);
331
-
332
- const refresh = (): void => {
333
- count.value = 0;
334
- data.value = [];
335
- getCommentData(1);
336
- };
337
-
338
- const onSortByChange = (item: WalineCommentSorting): void => {
339
- if (commentSorting.value !== item) {
340
- commentSorting.value = item;
341
- refresh();
342
- }
343
- };
344
-
345
- const onReply = (comment: WalineComment | null): void => {
346
- reply.value = comment;
347
- };
348
-
349
- const onEdit = (comment: WalineComment | null): void => {
350
- edit.value = comment;
351
- };
352
-
353
- const onSubmit = (comment: WalineComment): void => {
354
- if (edit.value) {
355
- edit.value.comment = comment.comment;
356
- edit.value.orig = comment.orig;
357
- } else if (comment.rid) {
358
- const repliedComment = data.value.find(
359
- ({ objectId }) => objectId === comment.rid
360
- );
361
-
362
- if (!repliedComment) return;
363
-
364
- if (!Array.isArray(repliedComment.children))
365
- repliedComment.children = [];
366
-
367
- repliedComment.children.push(comment);
368
- } else data.value.unshift(comment);
369
- };
370
-
371
- const onStatusChange = async ({
372
- comment,
373
- status,
374
- }: {
375
- comment: WalineComment;
376
- status: WalineCommentStatus;
377
- }): Promise<void> => {
378
- if (comment.status === status) return;
379
-
380
- const { serverURL, lang } = config.value;
381
-
382
- await updateComment({
383
- serverURL,
384
- lang,
385
- token: userInfo.value?.token,
386
- objectId: comment.objectId,
387
- status,
388
- });
389
-
390
- comment.status = status;
391
- };
392
-
393
- const onSticky = async (comment: WalineComment): Promise<void> => {
394
- if (comment.rid) return;
395
-
396
- const { serverURL, lang } = config.value;
397
-
398
- await updateComment({
399
- serverURL,
400
- lang,
401
- token: userInfo.value?.token,
402
- objectId: comment.objectId,
403
- sticky: comment.sticky ? 0 : 1,
404
- });
405
-
406
- comment.sticky = !comment.sticky;
407
- };
408
-
409
- const onDelete = async ({ objectId }: WalineComment): Promise<void> => {
410
- if (!confirm('Are you sure you want to delete this comment?')) return;
411
-
412
- const { serverURL, lang } = config.value;
413
-
414
- await deleteComment({
415
- serverURL,
416
- lang,
417
- token: userInfo.value?.token,
418
- objectId: objectId,
419
- });
420
-
421
- // delete comment from data
422
- data.value.some((item, index) => {
423
- if (item.objectId === objectId) {
424
- data.value = data.value.filter((_item, i) => i !== index);
425
-
426
- return true;
427
- }
428
-
429
- return item.children.some((child, childIndex) => {
430
- if (child.objectId === objectId) {
431
- data.value[index].children = item.children.filter(
432
- (_item, i) => i !== childIndex
433
- );
434
-
435
- return true;
436
- }
437
-
438
- return false;
439
- });
440
- });
441
- };
442
-
443
- const onLike = async (comment: WalineComment): Promise<void> => {
444
- const { serverURL, lang } = config.value;
445
- const { objectId } = comment;
446
- const hasLiked = likeStorage.value.includes(objectId);
447
-
448
- await updateComment({
449
- serverURL,
450
- lang,
451
- objectId,
452
- token: userInfo.value?.token,
453
- like: !hasLiked,
454
- });
455
-
456
- if (hasLiked)
457
- likeStorage.value = likeStorage.value.filter((id) => id !== objectId);
458
- else {
459
- likeStorage.value = [...likeStorage.value, objectId];
460
-
461
- if (likeStorage.value.length > 50)
462
- likeStorage.value = likeStorage.value.slice(-50);
463
- }
464
-
465
- comment.like = (comment.like || 0) + (hasLiked ? -1 : 1);
466
- };
467
-
468
- provide('config', config);
469
-
470
- onMounted(() => {
471
- watch(
472
- () => [props.serverURL, props.path],
473
- () => refresh(),
474
- { immediate: true }
475
- );
476
- });
477
- onUnmounted(() => abort?.());
478
-
479
- return {
480
- config,
481
- darkmodeStyle,
482
- i18n: computed(() => config.value.locale),
483
-
484
- status,
485
- count,
486
- page,
487
- totalPages,
488
- commentSorting,
489
- sortingMethods,
490
- data,
491
- reply,
492
- edit,
493
-
494
- loadMore,
495
- refresh,
496
- onSortByChange,
497
- onReply,
498
- onSubmit,
499
- onStatusChange,
500
- onDelete,
501
- onSticky,
502
- onLike,
503
- onEdit,
504
-
505
- version: VERSION,
506
- };
507
- },
508
- });
509
- </script>
@@ -1,15 +0,0 @@
1
- import { useNow } from '@vueuse/core';
2
- import { computed } from 'vue';
3
- import { getTimeAgo } 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(() => getTimeAgo(date, now.value, locale));
15
- };
@@ -1,20 +0,0 @@
1
- import { useStorage } from '@vueuse/core';
2
-
3
- import type { Ref } from 'vue';
4
-
5
- const VOTE_KEY = 'WALINE_VOTE';
6
-
7
- export const VOTE_IDENTIFIER = 'id';
8
- export const VOTE_INDEX = 'i';
9
-
10
- export interface VoteLogItem {
11
- [VOTE_IDENTIFIER]: string;
12
- [VOTE_INDEX]: number;
13
- }
14
-
15
- export type VoteRef = Ref<VoteLogItem[]>;
16
-
17
- let voteStorage: VoteRef | null = null;
18
-
19
- export const useVoteStorage = (): VoteRef =>
20
- (voteStorage ??= useStorage<VoteLogItem[]>(VOTE_KEY, []));
@@ -1,2 +0,0 @@
1
- export { default as Waline } from '../components/Waline.vue';
2
- export * from '../version';