@waline/client 2.3.2 → 2.4.0

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 (53) hide show
  1. package/dist/component.esm.js +1 -1
  2. package/dist/component.esm.js.map +1 -1
  3. package/dist/component.js +1 -1
  4. package/dist/component.js.map +1 -1
  5. package/dist/legacy.d.ts +3 -8
  6. package/dist/legacy.js +1 -1
  7. package/dist/legacy.js.map +1 -1
  8. package/dist/pageview.cjs.d.ts +47 -0
  9. package/dist/pageview.cjs.js +1 -1
  10. package/dist/pageview.cjs.js.map +1 -1
  11. package/dist/pageview.esm.d.ts +47 -0
  12. package/dist/pageview.esm.js +1 -1
  13. package/dist/pageview.esm.js.map +1 -1
  14. package/dist/pageview.js +1 -1
  15. package/dist/pageview.js.map +1 -1
  16. package/dist/shim.d.ts +45 -10
  17. package/dist/shim.esm.d.ts +45 -10
  18. package/dist/shim.esm.js +1 -1
  19. package/dist/shim.esm.js.map +1 -1
  20. package/dist/shim.js +1 -1
  21. package/dist/shim.js.map +1 -1
  22. package/dist/waline.cjs.d.ts +45 -10
  23. package/dist/waline.cjs.js +1 -1
  24. package/dist/waline.cjs.js.map +1 -1
  25. package/dist/waline.css +1 -1
  26. package/dist/waline.css.map +1 -1
  27. package/dist/waline.d.ts +45 -10
  28. package/dist/waline.esm.d.ts +45 -10
  29. package/dist/waline.esm.js +1 -1
  30. package/dist/waline.esm.js.map +1 -1
  31. package/dist/waline.js +1 -1
  32. package/dist/waline.js.map +1 -1
  33. package/package.json +14 -14
  34. package/src/components/CommentCard.vue +69 -6
  35. package/src/components/Icons.ts +28 -2
  36. package/src/components/Waline.vue +93 -2
  37. package/src/composables/index.ts +1 -0
  38. package/src/composables/likeStorage.ts +11 -0
  39. package/src/composables/userInfo.ts +2 -0
  40. package/src/config/i18n/en.ts +2 -0
  41. package/src/config/i18n/generate.ts +2 -0
  42. package/src/config/i18n/jp.ts +2 -0
  43. package/src/config/i18n/pt-BR.ts +2 -0
  44. package/src/config/i18n/ru.ts +2 -0
  45. package/src/config/i18n/vi-VN.ts +2 -0
  46. package/src/config/i18n/zh-CN.ts +2 -0
  47. package/src/config/i18n/zh-TW.ts +2 -0
  48. package/src/styles/card.scss +24 -0
  49. package/src/typings/comment.ts +56 -1
  50. package/src/typings/locale.ts +3 -8
  51. package/src/utils/config.ts +1 -1
  52. package/src/utils/fetch.ts +77 -4
  53. package/LICENSE +0 -339
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waline/client",
3
- "version": "2.3.2",
3
+ "version": "2.4.0",
4
4
  "description": "client for waline comment system",
5
5
  "keywords": [
6
6
  "valine",
@@ -56,6 +56,15 @@
56
56
  "dist",
57
57
  "src"
58
58
  ],
59
+ "scripts": {
60
+ "build": "pnpm rollup && pnpm style",
61
+ "clean": "rimraf ./dist",
62
+ "dev": "vite -c config/vite.config.js",
63
+ "lint": "eslint --ext .ts,.vue .",
64
+ "prepublish": "pnpm clean && pnpm build",
65
+ "rollup": "rollup -c ./config/rollup.config.js",
66
+ "style": "sass ./src/styles/index.scss ./dist/waline.css --style=compressed"
67
+ },
59
68
  "browserslist": {
60
69
  "production": [
61
70
  ">0.5%",
@@ -71,7 +80,7 @@
71
80
  ]
72
81
  },
73
82
  "dependencies": {
74
- "@vueuse/core": "^8.4.0",
83
+ "@vueuse/core": "^8.4.2",
75
84
  "autosize": "^5.0.1",
76
85
  "marked": "^4.0.15",
77
86
  "vue": "^3.2.33"
@@ -79,19 +88,10 @@
79
88
  "devDependencies": {
80
89
  "@types/autosize": "^4.0.1",
81
90
  "@types/marked": "^4.0.3",
82
- "@vitejs/plugin-vue": "^2.3.1",
83
- "vite": "^2.9.7"
91
+ "@vitejs/plugin-vue": "^2.3.2",
92
+ "vite": "^2.9.8"
84
93
  },
85
94
  "engines": {
86
95
  "node": ">=12.20.0"
87
- },
88
- "scripts": {
89
- "build": "pnpm rollup && pnpm style",
90
- "clean": "rimraf ./dist",
91
- "dev": "vite -c config/vite.config.js",
92
- "lint": "eslint --ext .ts,.vue .",
93
- "prepublish": "pnpm clean && pnpm build",
94
- "rollup": "rollup -c ./config/rollup.config.js",
95
- "style": "sass ./src/styles/index.scss ./dist/waline.css --style=compressed"
96
96
  }
97
- }
97
+ }
@@ -25,11 +25,10 @@
25
25
  <span v-if="comment.label" class="wl-badge" v-text="comment.label" />
26
26
  <span v-if="comment.sticky" class="wl-badge" v-text="locale.sticky" />
27
27
  <span
28
- v-if="comment.level >= 0"
28
+ v-if="comment.level && comment.level >= 0"
29
29
  :class="`wl-badge level${comment.level}`"
30
30
  v-text="locale[`level${comment.level}`] || `Level ${comment.level}`"
31
31
  />
32
-
33
32
  <span class="wl-time" v-text="time" />
34
33
 
35
34
  <button
@@ -40,6 +39,23 @@
40
39
  >
41
40
  <ReplyIcon />
42
41
  </button>
42
+
43
+ <button
44
+ class="wl-like"
45
+ @click="$emit('like', comment)"
46
+ :title="like ? locale.cancelLike : locale.like"
47
+ >
48
+ <LikeIcon :active="like" />
49
+ <span v-if="'like' in comment" v-text="comment.like" />
50
+ </button>
51
+
52
+ <button
53
+ class="wl-delete"
54
+ v-if="isAdmin || isOwner"
55
+ @click="$emit('delete', comment)"
56
+ >
57
+ <DeleteIcon />
58
+ </button>
43
59
  </div>
44
60
  <div class="wl-meta" aria-hidden="true">
45
61
  <span v-if="comment.addr" v-text="comment.addr" />
@@ -48,6 +64,27 @@
48
64
  </div>
49
65
  <div class="wl-content" v-html="comment.comment" />
50
66
 
67
+ <div v-if="isAdmin" class="wl-admin-actions">
68
+ <span class="wl-comment-status">
69
+ <button
70
+ v-for="status in commentStatus"
71
+ :key="status"
72
+ :class="`wl-btn wl-${status}`"
73
+ :disabled="comment.status === status"
74
+ @click="$emit('status', { status, comment })"
75
+ v-text="status"
76
+ />
77
+ </span>
78
+
79
+ <button
80
+ class="wl-btn wl-sticky"
81
+ v-if="isAdmin && !comment.rid"
82
+ @click="$emit('sticky', comment)"
83
+ >
84
+ {{ comment.sticky ? 'unsticky' : 'sticky' }}
85
+ </button>
86
+ </div>
87
+
51
88
  <div v-if="isReplyingCurrent" class="wl-reply-wrapper">
52
89
  <CommentBox
53
90
  :replyId="comment.objectId"
@@ -66,6 +103,9 @@
66
103
  :rootId="rootId"
67
104
  @reply="$emit('reply', $event)"
68
105
  @submit="$emit('submit', $event)"
106
+ @like="$emit('like', $event)"
107
+ @status="$emit('status', $event)"
108
+ @sticky="$emit('sticky', $event)"
69
109
  />
70
110
  </div>
71
111
  </div>
@@ -75,13 +115,15 @@
75
115
  <script lang="ts">
76
116
  import { computed, defineComponent, inject } from 'vue';
77
117
  import CommentBox from './CommentBox.vue';
78
- import { ReplyIcon, VerifiedIcon } from './Icons';
118
+ import { DeleteIcon, LikeIcon, ReplyIcon, VerifiedIcon } from './Icons';
79
119
  import { isLinkHttp } from '../utils';
80
- import { useTimeAgo } from '../composables';
120
+ import { useTimeAgo, useLikeStorage, useUserInfo } from '../composables';
81
121
 
82
122
  import type { ComputedRef, PropType } from 'vue';
83
123
  import type { WalineConfig } from '../utils';
84
- import type { WalineComment } from '../typings';
124
+ import type { WalineComment, WalineCommentStatus } from '../typings';
125
+
126
+ const commentStatus: WalineCommentStatus[] = ['approved', 'waiting', 'spam'];
85
127
 
86
128
  export default defineComponent({
87
129
  props: {
@@ -100,16 +142,21 @@ export default defineComponent({
100
142
 
101
143
  components: {
102
144
  CommentBox,
145
+ DeleteIcon,
146
+ LikeIcon,
103
147
  ReplyIcon,
104
148
  VerifiedIcon,
105
149
  },
106
150
 
107
- emits: ['submit', 'reply'],
151
+ emits: ['submit', 'reply', 'like', 'delete', 'status', 'sticky'],
108
152
 
109
153
  setup(props) {
110
154
  const config = inject<ComputedRef<WalineConfig>>(
111
155
  'config'
112
156
  ) as ComputedRef<WalineConfig>;
157
+ const likes = useLikeStorage();
158
+ const userInfo = useUserInfo();
159
+
113
160
  const locale = computed(() => config.value.locale);
114
161
 
115
162
  const link = computed(() => {
@@ -118,8 +165,18 @@ export default defineComponent({
118
165
  return link ? (isLinkHttp(link) ? link : `https://${link}`) : '';
119
166
  });
120
167
 
168
+ const like = computed(() => likes.value.includes(props.comment.objectId));
169
+
121
170
  const time = useTimeAgo(props.comment.insertedAt, locale.value);
122
171
 
172
+ const isAdmin = computed(() => userInfo.value.type === 'administrator');
173
+
174
+ const isOwner = computed(
175
+ () =>
176
+ props.comment.user_id &&
177
+ userInfo.value.objectId === props.comment.user_id
178
+ );
179
+
123
180
  const isReplyingCurrent = computed(
124
181
  () => props.comment.objectId === props.reply?.objectId
125
182
  );
@@ -130,7 +187,13 @@ export default defineComponent({
130
187
 
131
188
  isReplyingCurrent,
132
189
  link,
190
+ like,
133
191
  time,
192
+
193
+ isAdmin,
194
+ isOwner,
195
+
196
+ commentStatus,
134
197
  };
135
198
  },
136
199
  });
@@ -22,6 +22,16 @@ export const CloseIcon: FunctionalComponent<{ size: number }> = ({ size }) =>
22
22
  ]
23
23
  );
24
24
 
25
+ export const DeleteIcon: FunctionalComponent = () =>
26
+ h(
27
+ 'svg',
28
+ { viewBox: '0 0 1024 1024', width: '24', height: '24' },
29
+ h('path', {
30
+ d: 'm341.013 394.667 27.755 393.45h271.83l27.733-393.45h64.106l-28.01 397.952a64 64 0 0 1-63.83 59.498H368.768a64 64 0 0 1-63.83-59.52l-28.053-397.93h64.128zm139.307 19.818v298.667h-64V414.485h64zm117.013 0v298.667h-64V414.485h64zM181.333 288h640v64h-640v-64zm453.483-106.667v64h-256v-64h256z',
31
+ fill: 'red',
32
+ })
33
+ );
34
+
25
35
  export const EmojiIcon: FunctionalComponent = () =>
26
36
  h(
27
37
  'svg',
@@ -44,6 +54,22 @@ export const ImageIcon: FunctionalComponent = () =>
44
54
  }),
45
55
  ]);
46
56
 
57
+ export const LikeIcon: FunctionalComponent<{ active: boolean }> = ({
58
+ active = false,
59
+ }: {
60
+ active?: boolean;
61
+ }) =>
62
+ h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [
63
+ h('path', {
64
+ d: `M850.654 323.804c-11.042-25.625-26.862-48.532-46.885-68.225-20.022-19.61-43.258-34.936-69.213-45.73-26.78-11.124-55.124-16.727-84.375-16.727-40.622 0-80.256 11.123-114.698 32.135A214.79 214.79 0 0 0 512 241.819a214.79 214.79 0 0 0-23.483-16.562c-34.442-21.012-74.076-32.135-114.698-32.135-29.25 0-57.595 5.603-84.375 16.727-25.872 10.711-49.19 26.12-69.213 45.73-20.105 19.693-35.843 42.6-46.885 68.225-11.453 26.615-17.303 54.877-17.303 83.963 0 27.439 5.603 56.03 16.727 85.117 9.31 24.307 22.659 49.52 39.715 74.981 27.027 40.293 64.188 82.316 110.33 124.915 76.465 70.615 152.189 119.394 155.402 121.371l19.528 12.525c8.652 5.52 19.776 5.52 28.427 0l19.529-12.525c3.213-2.06 78.854-50.756 155.401-121.371 46.143-42.6 83.304-84.622 110.33-124.915 17.057-25.46 30.487-50.674 39.716-74.981 11.124-29.087 16.727-57.678 16.727-85.117.082-29.086-5.768-57.348-17.221-83.963z${
65
+ active
66
+ ? ''
67
+ : 'M512 761.5S218.665 573.55 218.665 407.767c0-83.963 69.461-152.023 155.154-152.023 60.233 0 112.473 33.618 138.181 82.727 25.708-49.109 77.948-82.727 138.18-82.727 85.694 0 155.155 68.06 155.155 152.023C805.335 573.551 512 761.5 512 761.5z'
68
+ }`,
69
+ fill: active ? 'red' : 'currentColor',
70
+ }),
71
+ ]);
72
+
47
73
  export const PreviewIcon: FunctionalComponent = () =>
48
74
  h('svg', { viewBox: '0 0 1024 1024', width: '24', height: '24' }, [
49
75
  h('path', {
@@ -69,9 +95,9 @@ export const MarkdownIcon: FunctionalComponent = () =>
69
95
  export const ReplyIcon: FunctionalComponent = () =>
70
96
  h(
71
97
  'svg',
72
- { viewBox: '0 0 1024 1024', width: '18', height: '18' },
98
+ { viewBox: '0 0 1024 1024', width: '24', height: '24' },
73
99
  h('path', {
74
- d: 'M1019.2 720C1001.6 625.6 968 566.4 904 497.6c-89.6-89.6-214.4-150.4-347.2-176v-120c0-25.6-8-51.2-25.6-64-33.6-30.4-81.6-30.4-112-4.8L33.6 441.6C12.8 459.2 0 484.8 0 510.4c0 25.6 12.8 51.2 30.4 68.8l385.6 312c17.6 12.8 33.6 17.6 51.2 17.6 12.8 0 25.6-4.8 38.4-8C536 888 552 857.6 552 824v-99.2c124.8 20.8 248 86.4 339.2 140.8 25.6 17.6 59.2 17.6 89.6 0 25.6-17.6 43.2-46.4 43.2-76.8 0-33.6 0-56-4.8-68.8zm-500.8-89.6-46.4-4.8v193.6L86.4 510.4 472 201.6V400l38.4 4.8c128 12.8 248 68.8 334.4 153.6 51.2 56 76.8 102.4 94.4 179.2 0 4.8 4.8 20.8 4.8 51.2C835.2 720 672 640 518.4 630.4z',
100
+ d: 'M810.667 213.333a64 64 0 0 1 64 64V704a64 64 0 0 1-64 64H478.336l-146.645 96.107a21.333 21.333 0 0 1-33.024-17.856V768h-85.334a64 64 0 0 1-64-64V277.333a64 64 0 0 1 64-64h597.334zm0 64H213.333V704h149.334v63.296L459.243 704h351.424V277.333zm-271.36 213.334v64h-176.64v-64h176.64zm122.026-128v64H362.667v-64h298.666z',
75
101
  fill: 'currentColor',
76
102
  })
77
103
  );
@@ -15,6 +15,10 @@
15
15
  :reply="reply"
16
16
  @reply="onReply"
17
17
  @submit="onSubmit"
18
+ @status="onStatusChange"
19
+ @delete="onDelete"
20
+ @sticky="onSticky"
21
+ @like="onLike"
18
22
  />
19
23
  </div>
20
24
 
@@ -66,13 +70,21 @@ import { computed, defineComponent, onMounted, provide, ref, watch } from 'vue';
66
70
  import CommentBox from './CommentBox.vue';
67
71
  import CommentCard from './CommentCard.vue';
68
72
  import { LoadingIcon } from './Icons';
69
- import { useUserInfo } from '../composables';
73
+ import { useUserInfo, useLikeStorage } from '../composables';
70
74
  import { defaultLocales } from '../config';
71
- import { fetchCommentList, getConfig, getDarkStyle } from '../utils';
75
+ import {
76
+ deleteComment,
77
+ fetchCommentList,
78
+ likeComment,
79
+ getConfig,
80
+ getDarkStyle,
81
+ updateComment,
82
+ } from '../utils';
72
83
 
73
84
  import type { PropType } from 'vue';
74
85
  import type {
75
86
  WalineComment,
87
+ WalineCommentStatus,
76
88
  WalineEmojiInfo,
77
89
  WalineHighlighter,
78
90
  WalineTexRenderer,
@@ -203,6 +215,7 @@ export default defineComponent({
203
215
  const config = computed(() => getConfig(props as unknown as WalineProps));
204
216
 
205
217
  const userInfo = useUserInfo();
218
+ const likeStorage = useLikeStorage();
206
219
 
207
220
  const status = ref<'loading' | 'success' | 'error'>('loading');
208
221
 
@@ -281,6 +294,80 @@ export default defineComponent({
281
294
  } else data.value.unshift(comment);
282
295
  };
283
296
 
297
+ const onStatusChange = async ({
298
+ comment,
299
+ status,
300
+ }: {
301
+ comment: WalineComment;
302
+ status: WalineCommentStatus;
303
+ }): Promise<void> => {
304
+ if (comment.status === status) return;
305
+
306
+ const { serverURL, lang } = config.value;
307
+
308
+ await updateComment({
309
+ serverURL,
310
+ lang,
311
+ token: userInfo.value?.token,
312
+ objectId: comment.objectId,
313
+ status,
314
+ });
315
+ // todo: render comment list
316
+ };
317
+
318
+ const onSticky = async (comment: WalineComment): Promise<void> => {
319
+ if (comment.rid) return;
320
+
321
+ const { serverURL, lang } = config.value;
322
+
323
+ await updateComment({
324
+ serverURL,
325
+ lang,
326
+ token: userInfo.value?.token,
327
+ objectId: comment.objectId,
328
+ sticky: comment.sticky ? 0 : 1,
329
+ });
330
+ // todo: render comment list
331
+ };
332
+
333
+ const onDelete = async (comment: WalineComment): Promise<void> => {
334
+ if (!confirm('Are you sure you want to delete this comment?')) return;
335
+
336
+ const { serverURL, lang } = config.value;
337
+
338
+ await deleteComment({
339
+ serverURL,
340
+ lang,
341
+ token: userInfo.value?.token,
342
+ objectId: comment.objectId,
343
+ });
344
+ // todo render comment list
345
+ };
346
+
347
+ const onLike = async (comment: WalineComment): Promise<void> => {
348
+ const { serverURL, lang } = config.value;
349
+ const hasLiked = likeStorage.value.includes(comment.objectId);
350
+
351
+ await likeComment({
352
+ serverURL,
353
+ lang,
354
+ objectId: comment.objectId,
355
+ like: !hasLiked,
356
+ });
357
+
358
+ if (hasLiked)
359
+ likeStorage.value = likeStorage.value.filter(
360
+ (id) => id !== comment.objectId
361
+ );
362
+ else {
363
+ likeStorage.value.push(comment.objectId);
364
+
365
+ if (likeStorage.value.length > 50) likeStorage.value.slice(-50);
366
+ }
367
+
368
+ comment.like = (comment.like || 0) + (hasLiked ? -1 : 1);
369
+ };
370
+
284
371
  provide('config', config);
285
372
 
286
373
  watch(() => (props as unknown as WalineProps).path, refresh);
@@ -303,6 +390,10 @@ export default defineComponent({
303
390
  refresh,
304
391
  onReply,
305
392
  onSubmit,
393
+ onStatusChange,
394
+ onDelete,
395
+ onSticky,
396
+ onLike,
306
397
 
307
398
  version: VERSION,
308
399
  };
@@ -1,3 +1,4 @@
1
1
  export * from './inputs';
2
2
  export * from './timeAgo';
3
3
  export * from './userInfo';
4
+ export * from './likeStorage';
@@ -0,0 +1,11 @@
1
+ import { useStorage } from '@vueuse/core';
2
+
3
+ import type { Ref } from 'vue';
4
+
5
+ const LIKE_KEY = 'WALIKE_LIKE';
6
+
7
+ export type LikeID = number | string;
8
+
9
+ export type LikeRef = Ref<LikeID[]>;
10
+
11
+ export const useLikeStorage = (): LikeRef => useStorage<LikeID[]>(LIKE_KEY, []);
@@ -10,6 +10,8 @@ export interface UserInfo {
10
10
  token: string;
11
11
  avatar: string;
12
12
  mailMd5: string;
13
+ objectId: string | number;
14
+ type: 'administrator' | 'guest';
13
15
  }
14
16
 
15
17
  export const USER_KEY = 'WALINE_USER';
@@ -10,6 +10,8 @@ export default generateLocale([
10
10
  'Comment here...',
11
11
  'No comment yet.',
12
12
  'Submit',
13
+ 'Like',
14
+ 'Cancel like',
13
15
  'Reply',
14
16
  'Cancel reply',
15
17
  'Comments',
@@ -10,6 +10,8 @@ const localeKeys = [
10
10
  'placeholder',
11
11
  'sofa',
12
12
  'submit',
13
+ 'like',
14
+ 'cancelLike',
13
15
  'reply',
14
16
  'cancelReply',
15
17
  'comment',
@@ -10,6 +10,8 @@ export default generateLocale([
10
10
  'ここにコメント',
11
11
  'コメントしましょう~',
12
12
  '提出する',
13
+ 'Like',
14
+ 'Cancel like',
13
15
  '返信する',
14
16
  'キャンセル',
15
17
  'コメント',
@@ -10,6 +10,8 @@ export default generateLocale([
10
10
  'Comente aqui...',
11
11
  'Nenhum comentário, ainda.',
12
12
  'Enviar',
13
+ 'Like',
14
+ 'Cancel like',
13
15
  'Responder',
14
16
  'Cancelar resposta',
15
17
  'Comentários',
@@ -10,6 +10,8 @@ export default generateLocale([
10
10
  'Комментарий здесь...',
11
11
  'Пока нет комментариев.',
12
12
  'Отправить',
13
+ 'Like',
14
+ 'Cancel like',
13
15
  'Отвечать',
14
16
  'Отменить ответ',
15
17
  'Комментарии',
@@ -10,6 +10,8 @@ export default generateLocale([
10
10
  'Hãy bình luận có văn hoá!',
11
11
  'Chưa có bình luận',
12
12
  'Gửi',
13
+ 'Like',
14
+ 'Cancel like',
13
15
  'Trả lời',
14
16
  'Hủy bỏ',
15
17
  'bình luận',
@@ -10,6 +10,8 @@ export default generateLocale([
10
10
  '欢迎评论',
11
11
  '来发评论吧~',
12
12
  '提交',
13
+ '喜欢',
14
+ '取消喜欢',
13
15
  '回复',
14
16
  '取消回复',
15
17
  '评论',
@@ -10,6 +10,8 @@ export default generateLocale([
10
10
  '歡迎評論',
11
11
  '來發評論吧~',
12
12
  '提交',
13
+ '喜歡',
14
+ '取消喜歡',
13
15
  '回覆',
14
16
  '取消回覆',
15
17
  '評論',
@@ -101,6 +101,8 @@
101
101
  font-size: 0.75em;
102
102
  }
103
103
 
104
+ .wl-delete,
105
+ .wl-like,
104
106
  .wl-reply {
105
107
  float: right;
106
108
 
@@ -213,6 +215,28 @@
213
215
  }
214
216
  }
215
217
 
218
+ .wl-admin-actions {
219
+ margin: 8px 0;
220
+ text-align: right;
221
+ font-size: 12px;
222
+ }
223
+
224
+ .wl-comment-status {
225
+ margin: 0 8px;
226
+
227
+ .wl-btn {
228
+ border-radius: 0;
229
+
230
+ &:first-child {
231
+ border-radius: 0.5em 0 0 0.5em;
232
+ }
233
+
234
+ &:last-child {
235
+ border-radius: 0 0.5em 0.5em 0;
236
+ }
237
+ }
238
+ }
239
+
216
240
  .wl-quote {
217
241
  border-left: 1px dashed rgb(237 237 237 / 50%);
218
242
 
@@ -1,21 +1,71 @@
1
1
  export interface WalineCommentData {
2
+ /**
3
+ * User Nickname
4
+ */
2
5
  nick: string;
6
+
7
+ /**
8
+ * User email
9
+ */
3
10
  mail: string;
11
+
12
+ /**
13
+ * User link
14
+ */
4
15
  link?: string;
16
+
17
+ /**
18
+ * Content of comment
19
+ */
5
20
  comment: string;
21
+
22
+ /**
23
+ * User Agent
24
+ */
6
25
  ua: string;
7
26
 
27
+ /**
28
+ * Parent comment id
29
+ */
30
+
8
31
  pid?: string;
32
+
33
+ /**
34
+ * Root comment id
35
+ */
9
36
  rid?: string;
37
+
38
+ /**
39
+ * User id being at
40
+ */
10
41
  at?: string;
42
+
43
+ /**
44
+ * Comment link
45
+ */
11
46
  url: string;
12
47
  }
13
48
 
49
+ export type WalineCommentStatus = 'approved' | 'waiting' | 'spam';
50
+
14
51
  export interface WalineComment extends Exclude<WalineCommentData, 'ua'> {
52
+ /**
53
+ * User avatar
54
+ */
15
55
  avatar: string;
16
- type?: string;
56
+
57
+ /**
58
+ * User type
59
+ */
60
+ type?: 'administrator' | 'guest' | `verify:${string}`;
61
+
17
62
  objectId: string;
63
+
64
+ /**
65
+ * Time ISOString when the comment is created
66
+ */
18
67
  createdAt: string;
68
+
19
69
  insertedAt: string;
20
70
  updatedAt: string;
21
71
  children: WalineComment[];
@@ -25,4 +75,9 @@ export interface WalineComment extends Exclude<WalineCommentData, 'ua'> {
25
75
  level?: number;
26
76
  addr?: string;
27
77
  label?: string;
78
+ // TODO: Rename it to `userId` in next major version
79
+ // eslint-disable-next-line @typescript-eslint/naming-convention
80
+ user_id?: string | number;
81
+ status?: WalineCommentStatus;
82
+ like?: number;
28
83
  }
@@ -6,14 +6,7 @@ export interface WalineDateLocale {
6
6
  now: string;
7
7
  }
8
8
 
9
- export interface WalineLevelLocale {
10
- level0: string;
11
- level1: string;
12
- level2: string;
13
- level3: string;
14
- level4: string;
15
- level5: string;
16
- }
9
+ export type WalineLevelLocale = Record<`level${number}`, string>;
17
10
 
18
11
  export interface WalineLocale extends WalineDateLocale, WalineLevelLocale {
19
12
  nick: string;
@@ -25,6 +18,8 @@ export interface WalineLocale extends WalineDateLocale, WalineLevelLocale {
25
18
  placeholder: string;
26
19
  sofa: string;
27
20
  submit: string;
21
+ like: string;
22
+ cancelLike: string;
28
23
  reply: string;
29
24
  cancelReply: string;
30
25
  comment: string;
@@ -68,7 +68,7 @@ export const getConfig = ({
68
68
  locale: {
69
69
  ...(defaultLocales[lang] || defaultLocales[defaultLang]),
70
70
  ...(typeof locale === 'object' ? locale : {}),
71
- },
71
+ } as WalineLocale,
72
72
  wordLimit: getWordLimit(wordLimit),
73
73
  meta: getMeta(meta),
74
74
  requiredMeta: getMeta(requiredMeta),