@waline/client 2.14.1 → 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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@waline/client",
3
- "version": "2.14.1",
3
+ "version": "2.14.2",
4
4
  "description": "client for waline comment system",
5
5
  "keywords": [
6
6
  "valine",
@@ -96,6 +96,7 @@
96
96
  "browserslist": {
97
97
  "production": [
98
98
  ">0.5%",
99
+ "maintained node versions",
99
100
  "not dead",
100
101
  "not ie 11",
101
102
  "not op_mini all",
@@ -108,31 +109,31 @@
108
109
  ]
109
110
  },
110
111
  "dependencies": {
111
- "@vueuse/core": "^9.5.0",
112
- "autosize": "^5.0.1",
113
- "marked": "^4.2.2",
112
+ "@vueuse/core": "^9.7.0",
113
+ "autosize": "^5.0.2",
114
+ "marked": "^4.2.4",
114
115
  "vue": "^3.2.45"
115
116
  },
116
117
  "devDependencies": {
117
- "@babel/core": "7.20.2",
118
+ "@babel/core": "7.20.5",
118
119
  "@babel/preset-env": "7.20.2",
119
- "@giphy/js-types": "4.2.1",
120
- "@rollup/plugin-babel": "6.0.2",
121
- "@rollup/plugin-commonjs": "23.0.2",
120
+ "@giphy/js-types": "4.4.0",
121
+ "@rollup/plugin-babel": "6.0.3",
122
+ "@rollup/plugin-commonjs": "24.0.0",
122
123
  "@rollup/plugin-node-resolve": "15.0.1",
123
- "@rollup/plugin-replace": "5.0.1",
124
+ "@rollup/plugin-replace": "5.0.2",
124
125
  "@rollup/plugin-terser": "0.1.0",
125
126
  "@types/autosize": "4.0.1",
126
- "@types/marked": "4.0.7",
127
- "@types/node": "18.11.9",
128
- "@vitejs/plugin-vue": "3.2.0",
127
+ "@types/marked": "4.0.8",
128
+ "@types/node": "18.11.17",
129
+ "@vitejs/plugin-vue": "4.0.0",
129
130
  "recaptcha-v3": "1.10.0",
130
131
  "rimraf": "3.0.2",
131
- "rollup": "3.3.0",
132
+ "rollup": "3.7.5",
132
133
  "rollup-plugin-dts": "5.0.0",
133
134
  "rollup-plugin-ts": "3.0.2",
134
- "typescript": "4.9.3",
135
- "vite": "3.2.4"
135
+ "typescript": "4.9.4",
136
+ "vite": "4.0.2"
136
137
  },
137
138
  "engines": {
138
139
  "node": ">=14"
@@ -140,9 +141,8 @@
140
141
  "scripts": {
141
142
  "build": "pnpm rollup && pnpm style",
142
143
  "clean": "rimraf ./dist",
143
- "dev": "vite -c config/vite.config.js",
144
- "lint": "eslint --ext .ts,.vue .",
145
- "rollup": "rollup -c ./config/rollup.config.mjs",
144
+ "dev": "vite",
145
+ "rollup": "rollup -c",
146
146
  "style": "pnpm style:main && pnpm style:meta",
147
147
  "style:main": "sass ./src/styles/index.scss ./dist/waline.css --style=compressed",
148
148
  "style:meta": "sass ./src/styles/meta.scss ./dist/waline-meta.css --style=compressed"
package/src/comment.ts CHANGED
@@ -43,8 +43,7 @@ export const commentCount = ({
43
43
  path = window.location.pathname,
44
44
  selector = '.waline-comment-count',
45
45
  lang = 'zh-CN',
46
- }: // eslint-disable-next-line @typescript-eslint/no-explicit-any
47
- WalineCommentCountOptions): WalineAbort => {
46
+ }: WalineCommentCountOptions): WalineAbort => {
48
47
  const controller = new AbortController();
49
48
 
50
49
  // comment count
@@ -1,150 +1,153 @@
1
1
  <template>
2
- <div v-if="reaction.length" class="wl-reaction">
2
+ <div v-if="reactionsInfo.length" class="wl-reaction">
3
3
  <h4 v-text="locale.reactionTitle" />
4
- <ul>
4
+
5
+ <ul class="wl-reaction-list">
5
6
  <li
6
- v-for="(item, index) in reaction"
7
+ v-for="({ active, icon, desc }, index) in reactionsInfo"
7
8
  :key="index"
8
- :class="{ active: item.active }"
9
+ class="wl-reaction-item"
10
+ :class="{ active }"
9
11
  @click="vote(index)"
10
12
  >
11
13
  <div class="wl-reaction-img">
12
- <img :src="item.icon" :alt="item.desc" />
13
- <div class="wl-reaction-votes">{{ item.vote }}</div>
14
+ <img :src="icon" :alt="desc" />
15
+
16
+ <LoadingIcon
17
+ v-if="votingIndex === index"
18
+ class="wl-reaction-loading"
19
+ />
20
+
21
+ <div
22
+ v-else
23
+ class="wl-reaction-votes"
24
+ v-text="voteNumbers[index] || 0"
25
+ />
14
26
  </div>
15
- <div class="wl-reaction-text">{{ item.desc }}</div>
27
+
28
+ <div class="wl-reaction-text" v-text="desc" />
16
29
  </li>
17
30
  </ul>
18
31
  </div>
19
32
  </template>
20
33
 
21
- <script lang="ts">
22
- import {
23
- defineComponent,
24
- inject,
25
- ComputedRef,
26
- computed,
27
- onMounted,
28
- onUnmounted,
29
- ref,
30
- watch,
31
- } from 'vue';
32
- import { getArticleCounter, updateArticleCounter } from '../api';
33
- import { VOTE_IDENTIFIER, VOTE_INDEX, useVoteStorage } from '../composables';
34
- import type { WalineConfig } from '../utils';
35
- import type { WalineLocale } from '../typings';
34
+ <script setup lang="ts">
35
+ import { computed, inject, onMounted, onUnmounted, ref, watch } from 'vue';
36
+
37
+ import { LoadingIcon } from './Icons.js';
38
+ import { getArticleCounter, updateArticleCounter } from '../api/index.js';
39
+ import { useReactionStorage } from '../composables/index.js';
40
+
41
+ import type { ComputedRef } from 'vue';
42
+ import type { WalineConfig } from '../utils/index.js';
43
+ import type { WalineReactionLocale } from '../typings';
44
+
45
+ defineExpose();
36
46
 
37
47
  interface ReactionItem {
38
48
  icon: string;
39
- vote: number;
40
49
  desc: string;
41
50
  active?: boolean;
42
51
  }
43
52
 
44
- export default defineComponent({
45
- setup() {
46
- const votes = ref<ReactionItem['vote'][]>([]);
47
- const voteStorage = useVoteStorage();
48
- const config = inject<ComputedRef<WalineConfig>>('config')!;
49
- const locale = computed(() => config.value.locale);
50
- const reaction = computed((): ReactionItem[] => {
51
- const { reaction, path } = config.value;
52
-
53
- return reaction.map((icon, index) => ({
54
- icon,
55
- vote: votes.value[index] || 0,
56
- desc: locale.value[`reaction${index}` as keyof WalineLocale],
57
- active: Boolean(
58
- voteStorage.value.find(
59
- ({ [VOTE_IDENTIFIER]: voteIdentifier, [VOTE_INDEX]: voteIndex }) =>
60
- voteIdentifier === path && voteIndex === index
61
- )
62
- ),
63
- }));
53
+ const reactionStorage = useReactionStorage();
54
+ const config = inject<ComputedRef<WalineConfig>>('config')!;
55
+
56
+ const votingIndex = ref(-1);
57
+ const voteNumbers = ref<number[]>([]);
58
+
59
+ const locale = computed(() => config.value.locale);
60
+ const isReactionEnabled = computed(() => config.value.reaction.length > 0);
61
+
62
+ const reactionsInfo = computed<ReactionItem[]>(() => {
63
+ const { reaction, path } = config.value;
64
+
65
+ return reaction.map((icon, index) => ({
66
+ icon,
67
+ desc: locale.value[`reaction${index}` as keyof WalineReactionLocale],
68
+ active: reactionStorage.value[path] === index,
69
+ }));
70
+ });
71
+
72
+ let abort: () => void;
73
+
74
+ const fetchReaction = async (): Promise<void> => {
75
+ if (isReactionEnabled.value) {
76
+ const { serverURL, lang, path, reaction } = config.value;
77
+ const controller = new AbortController();
78
+
79
+ abort = controller.abort.bind(controller);
80
+
81
+ const resp = await getArticleCounter({
82
+ serverURL,
83
+ lang,
84
+ paths: [path],
85
+ type: reaction.map((_reaction, index) => `reaction${index}`),
86
+ signal: controller.signal,
64
87
  });
65
88
 
66
- let abort: () => void;
67
-
68
- const fetchCounter = (): void => {
69
- const { serverURL, lang, path, reaction } = config.value;
70
-
71
- if (reaction.length) {
72
- const controller = new AbortController();
73
-
74
- getArticleCounter({
75
- serverURL,
76
- lang,
77
- paths: [path],
78
- type: reaction.map((_, k) => `reaction${k}`),
79
- signal: controller.signal,
80
- }).then((resp) => {
81
- if (Array.isArray(resp) || typeof resp === 'number') return;
82
- votes.value = reaction.map((_, k) => resp[`reaction${k}`]);
83
- });
84
-
85
- abort = controller.abort.bind(controller);
86
- }
87
- };
88
-
89
- const vote = async (index: number): Promise<void> => {
90
- const { serverURL, lang, path } = config.value;
91
- const hasVoted = voteStorage.value.find(
92
- ({ [VOTE_IDENTIFIER]: voteIdentifier }) => voteIdentifier === path
93
- );
94
- const hasVotedTheReaction = hasVoted && hasVoted[VOTE_INDEX] === index;
89
+ // TODO: Remove this compact code
90
+ if (Array.isArray(resp) || typeof resp === 'number') return;
91
+
92
+ voteNumbers.value = reaction.map(
93
+ (_reaction, index) => resp[`reaction${index}`]
94
+ );
95
+ }
96
+ };
97
+
98
+ const vote = async (index: number): Promise<void> => {
99
+ // we should ensure that only one vote request is sent at a time
100
+ if (votingIndex.value === -1) {
101
+ const { serverURL, lang, path } = config.value;
102
+ const currentVoteItemIndex = reactionStorage.value[path];
95
103
 
96
- if (hasVotedTheReaction) return;
104
+ // mark voting status
105
+ votingIndex.value = index;
97
106
 
107
+ // if user already vote current article, decrease the voted item number
108
+ if (currentVoteItemIndex !== undefined) {
98
109
  await updateArticleCounter({
99
110
  serverURL,
100
111
  lang,
101
112
  path,
102
- type: `reaction${index}`,
113
+ type: `reaction${currentVoteItemIndex}`,
114
+ action: 'desc',
103
115
  });
104
116
 
105
- votes.value[index] = (votes.value[index] || 0) + 1;
106
- if (hasVoted) {
107
- votes.value[hasVoted[VOTE_INDEX]] = Math.max(
108
- votes.value[hasVoted[VOTE_INDEX]] - 1,
109
- 0
110
- );
111
- updateArticleCounter({
112
- serverURL,
113
- lang,
114
- path,
115
- type: `reaction${hasVoted.i}`,
116
- action: 'desc',
117
- });
118
-
119
- hasVoted.i = index;
120
- voteStorage.value = Array.from(voteStorage.value);
121
- } else {
122
- voteStorage.value = [
123
- ...voteStorage.value,
124
- { [VOTE_IDENTIFIER]: path, [VOTE_INDEX]: index },
125
- ];
126
- }
127
-
128
- if (voteStorage.value.length > 50)
129
- voteStorage.value = voteStorage.value.slice(-50);
130
- };
131
-
132
- onMounted(() => {
133
- watch(
134
- () => [config.value.serverURL, config.value.path],
135
- () => {
136
- fetchCounter();
137
- },
138
- { immediate: true }
117
+ voteNumbers.value[currentVoteItemIndex] = Math.max(
118
+ voteNumbers.value[currentVoteItemIndex] - 1,
119
+ 0
139
120
  );
140
- });
141
- onUnmounted(() => abort?.());
142
-
143
- return {
144
- reaction,
145
- locale,
146
- vote,
147
- };
148
- },
121
+ }
122
+
123
+ // increase voting number if current reaction item is not been voted
124
+ if (currentVoteItemIndex !== index) {
125
+ await updateArticleCounter({
126
+ serverURL,
127
+ lang,
128
+ path,
129
+ type: `reaction${index}`,
130
+ });
131
+ voteNumbers.value[index] = (voteNumbers.value[index] || 0) + 1;
132
+ }
133
+
134
+ // update vote info in local storage
135
+ if (currentVoteItemIndex === index) delete reactionStorage.value[path];
136
+ else reactionStorage.value[path] = index;
137
+
138
+ // voting is completed
139
+ votingIndex.value = -1;
140
+ }
141
+ };
142
+
143
+ onMounted(() => {
144
+ watch(
145
+ () => [config.value.serverURL, config.value.path],
146
+ () => {
147
+ void fetchReaction();
148
+ },
149
+ { immediate: true }
150
+ );
149
151
  });
152
+ onUnmounted(() => abort?.());
150
153
  </script>