@waline/client 2.10.0 → 2.11.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.
- package/dist/component.mjs +1 -1
- package/dist/component.mjs.map +1 -1
- package/dist/legacy.umd.d.ts +14 -0
- 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.d.cts +14 -0
- package/dist/shim.d.mts +14 -0
- package/dist/shim.mjs +1 -1
- package/dist/shim.mjs.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.d.cts +14 -0
- package/dist/waline.d.mts +14 -0
- package/dist/waline.d.ts +14 -0
- 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 +5 -5
- package/src/components/ArticleReaction.vue +141 -0
- package/src/components/Waline.vue +11 -0
- package/src/composables/vote.ts +17 -0
- package/src/config/default.ts +9 -0
- package/src/config/i18n/en.ts +1 -0
- package/src/config/i18n/generate.ts +1 -0
- package/src/config/i18n/jp.ts +1 -0
- package/src/config/i18n/pt-BR.ts +1 -0
- package/src/config/i18n/ru.ts +1 -0
- package/src/config/i18n/vi-VN.ts +1 -0
- package/src/config/i18n/zh-CN.ts +1 -0
- package/src/config/i18n/zh-TW.ts +1 -0
- package/src/styles/card.scss +3 -1
- package/src/styles/index.scss +1 -0
- package/src/styles/reaction.scss +66 -0
- package/src/typings/locale.ts +10 -0
- package/src/typings/waline.ts +6 -1
- package/src/utils/config.ts +5 -1
- package/src/utils/fetch.ts +48 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@waline/client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "client for waline comment system",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"valine",
|
|
@@ -111,16 +111,16 @@
|
|
|
111
111
|
"@rollup/plugin-replace": "4.0.0",
|
|
112
112
|
"@types/autosize": "4.0.1",
|
|
113
113
|
"@types/marked": "4.0.7",
|
|
114
|
-
"@types/node": "18.7.
|
|
114
|
+
"@types/node": "18.7.21",
|
|
115
115
|
"@vitejs/plugin-vue": "3.1.0",
|
|
116
|
-
"recaptcha-v3": "
|
|
116
|
+
"recaptcha-v3": "1.10.0",
|
|
117
117
|
"rimraf": "3.0.2",
|
|
118
|
-
"rollup": "2.79.
|
|
118
|
+
"rollup": "2.79.1",
|
|
119
119
|
"rollup-plugin-dts": "4.2.2",
|
|
120
120
|
"rollup-plugin-terser": "7.0.2",
|
|
121
121
|
"rollup-plugin-ts": "3.0.2",
|
|
122
122
|
"typescript": "4.8.3",
|
|
123
|
-
"vite": "3.1.
|
|
123
|
+
"vite": "3.1.3"
|
|
124
124
|
},
|
|
125
125
|
"engines": {
|
|
126
126
|
"node": ">=14"
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="reaction && reaction.length" class="wl-reaction">
|
|
3
|
+
<h4>{{ locale.reactionTitle }}</h4>
|
|
4
|
+
<ul>
|
|
5
|
+
<li
|
|
6
|
+
v-for="(item, index) in reaction"
|
|
7
|
+
:key="index"
|
|
8
|
+
:class="item.active ? 'active' : ''"
|
|
9
|
+
@click="onVote(index)"
|
|
10
|
+
>
|
|
11
|
+
<div class="wl-reaction__img">
|
|
12
|
+
<img :src="item.icon" :alt="item.desc" />
|
|
13
|
+
<div class="wl-reaction__votes">{{ item.vote }}</div>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="wl-reaction__text">{{ item.desc }}</div>
|
|
16
|
+
</li>
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script lang="ts">
|
|
22
|
+
import {
|
|
23
|
+
defineComponent,
|
|
24
|
+
inject,
|
|
25
|
+
ComputedRef,
|
|
26
|
+
computed,
|
|
27
|
+
onMounted,
|
|
28
|
+
onUnmounted,
|
|
29
|
+
ref,
|
|
30
|
+
} from 'vue';
|
|
31
|
+
import {
|
|
32
|
+
fetchArticleCounter,
|
|
33
|
+
updateArticleCounter,
|
|
34
|
+
WalineConfig,
|
|
35
|
+
} from '../utils';
|
|
36
|
+
import { useVoteStorage } from '../composables/vote';
|
|
37
|
+
|
|
38
|
+
interface ReactionItem {
|
|
39
|
+
icon: string;
|
|
40
|
+
vote: number;
|
|
41
|
+
desc: string;
|
|
42
|
+
active?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default defineComponent({
|
|
46
|
+
setup() {
|
|
47
|
+
const votes = ref<ReactionItem['vote'][]>([]);
|
|
48
|
+
const voteStorage = useVoteStorage();
|
|
49
|
+
const config = inject<ComputedRef<WalineConfig>>(
|
|
50
|
+
'config'
|
|
51
|
+
) as ComputedRef<WalineConfig>;
|
|
52
|
+
const locale = computed(() => config.value.locale);
|
|
53
|
+
const reaction = computed((): ReactionItem[] => {
|
|
54
|
+
const { path } = config.value;
|
|
55
|
+
|
|
56
|
+
if (!Array.isArray(config.value.reaction)) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return config.value.reaction.map((icon, index) => ({
|
|
61
|
+
icon,
|
|
62
|
+
vote: votes.value[index] || 0,
|
|
63
|
+
desc: locale.value[`reaction${index}` as `reaction0`],
|
|
64
|
+
active: Boolean(
|
|
65
|
+
voteStorage.value.find(({ u, i }) => u === path && i === index)
|
|
66
|
+
),
|
|
67
|
+
}));
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const controller = new AbortController();
|
|
71
|
+
|
|
72
|
+
const fetchCounter = async (): Promise<void> => {
|
|
73
|
+
const { serverURL, lang, path, reaction } = config.value;
|
|
74
|
+
|
|
75
|
+
if (!Array.isArray(reaction)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const resp = await fetchArticleCounter({
|
|
80
|
+
serverURL,
|
|
81
|
+
lang,
|
|
82
|
+
paths: [path],
|
|
83
|
+
type: reaction.map((_, k) => `reaction${k}`),
|
|
84
|
+
signal: controller.signal,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (Array.isArray(resp) || typeof resp === 'number') {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
votes.value = reaction.map((_, k) => resp[`reaction${k}`]);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const onVote = async (index: number): Promise<void> => {
|
|
95
|
+
const { serverURL, lang, path } = config.value;
|
|
96
|
+
const hasVoted = voteStorage.value.find(({ u }) => u === path);
|
|
97
|
+
const hasVotedTheReaction = hasVoted && hasVoted.i === index;
|
|
98
|
+
|
|
99
|
+
if (hasVotedTheReaction) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
await updateArticleCounter({
|
|
104
|
+
serverURL,
|
|
105
|
+
lang,
|
|
106
|
+
path,
|
|
107
|
+
type: `reaction${index}`,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
votes.value[index] = (votes.value[index] || 0) + 1;
|
|
111
|
+
if (hasVoted) {
|
|
112
|
+
votes.value[hasVoted.i] = Math.max(votes.value[hasVoted.i] - 1, 0);
|
|
113
|
+
updateArticleCounter({
|
|
114
|
+
serverURL,
|
|
115
|
+
lang,
|
|
116
|
+
path,
|
|
117
|
+
type: `reaction${hasVoted.i}`,
|
|
118
|
+
action: 'desc',
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
hasVoted.i = index;
|
|
122
|
+
voteStorage.value = Array.from(voteStorage.value);
|
|
123
|
+
} else {
|
|
124
|
+
voteStorage.value = [...voteStorage.value, { u: path, i: index }];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (voteStorage.value.length > 50)
|
|
128
|
+
voteStorage.value = voteStorage.value.slice(-50);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
onMounted(() => fetchCounter());
|
|
132
|
+
onUnmounted(() => controller.abort());
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
reaction,
|
|
136
|
+
locale,
|
|
137
|
+
onVote,
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
</script>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div data-waline>
|
|
3
|
+
<Reaction />
|
|
3
4
|
<CommentBox v-if="!reply" @submit="onSubmit" />
|
|
4
5
|
<div class="wl-meta-head">
|
|
5
6
|
<div class="wl-count">
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
<script lang="ts">
|
|
82
83
|
import { useStyleTag } from '@vueuse/core';
|
|
83
84
|
import { computed, defineComponent, onMounted, provide, ref, watch } from 'vue';
|
|
85
|
+
import Reaction from './ArticleReaction.vue';
|
|
84
86
|
import CommentBox from './CommentBox.vue';
|
|
85
87
|
import CommentCard from './CommentCard.vue';
|
|
86
88
|
import { LoadingIcon } from './Icons';
|
|
@@ -237,12 +239,21 @@ const propsWithValidate = {
|
|
|
237
239
|
},
|
|
238
240
|
|
|
239
241
|
copyright: { type: Boolean, default: true },
|
|
242
|
+
|
|
243
|
+
recaptchav3key: {
|
|
244
|
+
type: String,
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
reaction: {
|
|
248
|
+
type: [Array, Boolean] as PropType<string[] | false>,
|
|
249
|
+
},
|
|
240
250
|
};
|
|
241
251
|
|
|
242
252
|
export default defineComponent({
|
|
243
253
|
name: 'WalineRoot',
|
|
244
254
|
|
|
245
255
|
components: {
|
|
256
|
+
Reaction,
|
|
246
257
|
CommentBox,
|
|
247
258
|
CommentCard,
|
|
248
259
|
LoadingIcon,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useStorage } from '@vueuse/core';
|
|
2
|
+
|
|
3
|
+
import type { Ref } from 'vue';
|
|
4
|
+
|
|
5
|
+
const VOTE_KEY = 'WALINE_VOTE';
|
|
6
|
+
|
|
7
|
+
export interface VoteLogItem {
|
|
8
|
+
u: string;
|
|
9
|
+
i: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type VoteRef = Ref<VoteLogItem[]>;
|
|
13
|
+
|
|
14
|
+
let voteStorage: VoteRef | null = null;
|
|
15
|
+
|
|
16
|
+
export const useVoteStorage = (): VoteRef =>
|
|
17
|
+
voteStorage || (voteStorage = useStorage<VoteLogItem[]>(VOTE_KEY, []));
|
package/src/config/default.ts
CHANGED
|
@@ -115,3 +115,12 @@ export const getDefaultSearchOptions = (): WalineSearchOptions => {
|
|
|
115
115
|
}),
|
|
116
116
|
};
|
|
117
117
|
};
|
|
118
|
+
|
|
119
|
+
export const defaultReaction = [
|
|
120
|
+
'//unpkg.com/@waline/emojis/tieba/tieba_agree.png',
|
|
121
|
+
'//unpkg.com/@waline/emojis/tieba/tieba_look_down.png',
|
|
122
|
+
'//unpkg.com/@waline/emojis/tieba/tieba_sunglasses.png',
|
|
123
|
+
'//unpkg.com/@waline/emojis/tieba/tieba_pick_nose.png',
|
|
124
|
+
'//unpkg.com/@waline/emojis/tieba/tieba_awkward.png',
|
|
125
|
+
'//unpkg.com/@waline/emojis/tieba/tieba_sleep.png',
|
|
126
|
+
];
|
package/src/config/i18n/en.ts
CHANGED
package/src/config/i18n/jp.ts
CHANGED
package/src/config/i18n/pt-BR.ts
CHANGED
package/src/config/i18n/ru.ts
CHANGED
package/src/config/i18n/vi-VN.ts
CHANGED
package/src/config/i18n/zh-CN.ts
CHANGED
package/src/config/i18n/zh-TW.ts
CHANGED
package/src/styles/card.scss
CHANGED
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
|
|
58
58
|
.wl-head {
|
|
59
59
|
line-height: 1.5;
|
|
60
|
+
overflow: hidden; // bfc to fix https://github.com/walinejs/waline/issues/1415
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
.wl-nick {
|
|
@@ -126,6 +127,7 @@
|
|
|
126
127
|
|
|
127
128
|
.wl-comment-actions {
|
|
128
129
|
float: right;
|
|
130
|
+
line-height: 1;
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
.wl-delete,
|
|
@@ -135,7 +137,7 @@
|
|
|
135
137
|
display: inline-flex;
|
|
136
138
|
align-items: center;
|
|
137
139
|
|
|
138
|
-
padding: 4px;
|
|
140
|
+
// padding: 4px;
|
|
139
141
|
border: none;
|
|
140
142
|
|
|
141
143
|
background: transparent;
|
package/src/styles/index.scss
CHANGED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
.wl-reaction {
|
|
2
|
+
text-align: center;
|
|
3
|
+
margin-bottom: 1.75em;
|
|
4
|
+
|
|
5
|
+
ul {
|
|
6
|
+
margin: 0;
|
|
7
|
+
list-style-type: none;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: row;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
gap: 16px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
li {
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
align-items: center;
|
|
19
|
+
|
|
20
|
+
&:hover img,
|
|
21
|
+
&.active img {
|
|
22
|
+
transform: scale(1.15);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
li.active .wl-reaction {
|
|
27
|
+
&__votes {
|
|
28
|
+
color: var(--waline-bgcolor);
|
|
29
|
+
background: var(--waline-theme-color);
|
|
30
|
+
}
|
|
31
|
+
&__text {
|
|
32
|
+
color: var(--waline-theme-color);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
img {
|
|
37
|
+
width: 100%;
|
|
38
|
+
height: 100%;
|
|
39
|
+
transition: all 250ms ease-in-out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
&__img {
|
|
43
|
+
position: relative;
|
|
44
|
+
width: 42px;
|
|
45
|
+
height: 42px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&__votes {
|
|
49
|
+
position: absolute;
|
|
50
|
+
top: -4px;
|
|
51
|
+
right: -5px;
|
|
52
|
+
font-size: 0.75em;
|
|
53
|
+
color: var(--waline-theme-color);
|
|
54
|
+
background: var(--waline-bgcolor);
|
|
55
|
+
border: 1px solid var(--waline-theme-color);
|
|
56
|
+
padding: 2px;
|
|
57
|
+
border-radius: 1em;
|
|
58
|
+
line-height: 1;
|
|
59
|
+
min-width: 1em;
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
&__text {
|
|
64
|
+
font-size: 0.875em;
|
|
65
|
+
}
|
|
66
|
+
}
|
package/src/typings/locale.ts
CHANGED
|
@@ -46,4 +46,14 @@ export interface WalineLocale extends WalineDateLocale, WalineLevelLocale {
|
|
|
46
46
|
oldest: string;
|
|
47
47
|
latest: string;
|
|
48
48
|
hottest: string;
|
|
49
|
+
reactionTitle: string;
|
|
50
|
+
reaction0: string;
|
|
51
|
+
reaction1: string;
|
|
52
|
+
reaction2: string;
|
|
53
|
+
reaction3: string;
|
|
54
|
+
reaction4: string;
|
|
55
|
+
reaction5: string;
|
|
56
|
+
reaction6: string;
|
|
57
|
+
reaction7: string;
|
|
58
|
+
reaction8: string;
|
|
49
59
|
}
|
package/src/typings/waline.ts
CHANGED
package/src/utils/config.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
defaultLang,
|
|
3
3
|
defaultLocales,
|
|
4
|
+
defaultReaction,
|
|
4
5
|
defaultUploadImage,
|
|
5
6
|
defaultHighlighter,
|
|
6
7
|
defaultTexRenderer,
|
|
@@ -22,7 +23,8 @@ export interface WalineEmojiConfig {
|
|
|
22
23
|
map: WalineEmojiMaps;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export interface WalineConfig
|
|
26
|
+
export interface WalineConfig
|
|
27
|
+
extends Required<Omit<WalineProps, 'wordLimit' | 'recaptchaV3Key'>> {
|
|
26
28
|
locale: WalineLocale;
|
|
27
29
|
wordLimit: [number, number] | false;
|
|
28
30
|
// emoji: Promise<EmojiConfig>;
|
|
@@ -63,6 +65,7 @@ export const getConfig = ({
|
|
|
63
65
|
copyright = true,
|
|
64
66
|
login = 'enable',
|
|
65
67
|
search = getDefaultSearchOptions(),
|
|
68
|
+
reaction,
|
|
66
69
|
...more
|
|
67
70
|
}: WalineProps): WalineConfig => ({
|
|
68
71
|
serverURL: getServerURL(serverURL),
|
|
@@ -84,5 +87,6 @@ export const getConfig = ({
|
|
|
84
87
|
login,
|
|
85
88
|
copyright,
|
|
86
89
|
search,
|
|
90
|
+
reaction: reaction === true ? defaultReaction : reaction || false,
|
|
87
91
|
...more,
|
|
88
92
|
});
|
package/src/utils/fetch.ts
CHANGED
|
@@ -13,8 +13,7 @@ const JSON_HEADERS: Record<string, string> = {
|
|
|
13
13
|
const errorCheck = <T = unknown>(data: T | FetchErrorData, name = ''): T => {
|
|
14
14
|
if (typeof data === 'object' && (data as FetchErrorData).errno)
|
|
15
15
|
throw new TypeError(
|
|
16
|
-
`Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${
|
|
17
|
-
(data as FetchErrorData).errmsg
|
|
16
|
+
`Fetch ${name} failed with ${(data as FetchErrorData).errno}: ${(data as FetchErrorData).errmsg
|
|
18
17
|
}`
|
|
19
18
|
);
|
|
20
19
|
|
|
@@ -232,45 +231,80 @@ export const updateComment = ({
|
|
|
232
231
|
}).then((resp) => resp.json() as Promise<void>);
|
|
233
232
|
};
|
|
234
233
|
|
|
235
|
-
export interface
|
|
234
|
+
export interface FetchArticleCounterOptions {
|
|
236
235
|
serverURL: string;
|
|
237
236
|
lang: string;
|
|
238
237
|
paths: string[];
|
|
238
|
+
type: string[];
|
|
239
239
|
signal: AbortSignal;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
-
export const
|
|
242
|
+
export const fetchArticleCounter = ({
|
|
243
243
|
serverURL,
|
|
244
244
|
lang,
|
|
245
245
|
paths,
|
|
246
|
+
type,
|
|
246
247
|
signal,
|
|
247
|
-
}:
|
|
248
|
+
}: FetchArticleCounterOptions): Promise<
|
|
249
|
+
Record<string, number>[] | Record<string, number> | number[] | number
|
|
250
|
+
> =>
|
|
248
251
|
fetch(
|
|
249
252
|
`${serverURL}/article?path=${encodeURIComponent(
|
|
250
253
|
paths.join(',')
|
|
251
|
-
)}&lang=${lang}`,
|
|
254
|
+
)}&type=${encodeURIComponent(type.join(','))}&lang=${lang}`,
|
|
252
255
|
{ signal }
|
|
253
256
|
)
|
|
254
|
-
.then(
|
|
255
|
-
|
|
257
|
+
.then(
|
|
258
|
+
(resp) =>
|
|
259
|
+
resp.json() as Promise<Record<string, number>[] | number[] | number>
|
|
260
|
+
)
|
|
261
|
+
.then((data) => errorCheck(data, 'article count'));
|
|
262
|
+
|
|
263
|
+
export const fetchPageviews = ({
|
|
264
|
+
serverURL,
|
|
265
|
+
lang,
|
|
266
|
+
paths,
|
|
267
|
+
signal,
|
|
268
|
+
}: Omit<FetchArticleCounterOptions, 'type'>): Promise<number[]> =>
|
|
269
|
+
fetchArticleCounter({
|
|
270
|
+
serverURL,
|
|
271
|
+
lang,
|
|
272
|
+
paths,
|
|
273
|
+
type: ['time'],
|
|
274
|
+
signal,
|
|
275
|
+
})
|
|
256
276
|
// TODO: Improve this API
|
|
257
|
-
.then((counts) => (Array.isArray(counts) ? counts : [counts]))
|
|
277
|
+
.then((counts) => (Array.isArray(counts) ? counts : [counts])) as Promise<
|
|
278
|
+
number[]
|
|
279
|
+
>;
|
|
258
280
|
|
|
259
|
-
export interface
|
|
281
|
+
export interface UpdateArticleCounterOptions {
|
|
260
282
|
serverURL: string;
|
|
261
283
|
lang: string;
|
|
262
284
|
path: string;
|
|
285
|
+
type: string;
|
|
286
|
+
action?: 'inc' | 'desc';
|
|
263
287
|
}
|
|
264
288
|
|
|
265
|
-
export const
|
|
289
|
+
export const updateArticleCounter = ({
|
|
266
290
|
serverURL,
|
|
267
291
|
lang,
|
|
268
292
|
path,
|
|
269
|
-
|
|
293
|
+
type,
|
|
294
|
+
action,
|
|
295
|
+
}: UpdateArticleCounterOptions): Promise<number> =>
|
|
270
296
|
fetch(`${serverURL}/article?lang=${lang}`, {
|
|
271
297
|
method: 'POST',
|
|
272
298
|
headers: JSON_HEADERS,
|
|
273
|
-
body: JSON.stringify({ path }),
|
|
299
|
+
body: JSON.stringify({ path, type, action }),
|
|
274
300
|
})
|
|
275
301
|
.then((resp) => resp.json() as Promise<number>)
|
|
276
|
-
.then((data) => errorCheck(data, '
|
|
302
|
+
.then((data) => errorCheck(data, 'article count'));
|
|
303
|
+
|
|
304
|
+
export const updatePageviews = (
|
|
305
|
+
options: Omit<UpdateArticleCounterOptions, 'type'>
|
|
306
|
+
): Promise<number> =>
|
|
307
|
+
updateArticleCounter({
|
|
308
|
+
...options,
|
|
309
|
+
type: 'time',
|
|
310
|
+
});
|