Commit 747c3ee
Changed files (5)
packages
i18n
src
src
components
aside
recent-comments
packages/i18n/src/en/web/index.ts
@@ -65,6 +65,8 @@ const en_web = {
image: '[Image]',
link: '[Link]',
code: '[Code]',
+ collapsed: '[Collapsed]',
+ pending: '[Pending]',
},
backLinks: 'Back Links',
devNote:
packages/i18n/src/zh-CN/web/index.ts
@@ -65,6 +65,8 @@ const zh_CN_web = {
image: '[图片]',
link: '[链接]',
code: '[代码]',
+ collapsed: '[已折叠]',
+ pending: '[待审]',
},
backLinks: '反向链接',
devNote:
packages/i18n/src/zh-TW/web/index.ts
@@ -65,6 +65,8 @@ const zh_TW_web = {
image: '[圖片]',
link: '[連結]',
code: '[程式碼]',
+ collapsed: '[已摺疊]',
+ pending: '[待審]',
},
backLinks: '反向連結',
devNote:
packages/i18n/src/i18n-types.ts
@@ -387,6 +387,14 @@ export type NamespaceWebTranslation = {
* [Code]
*/
code: string
+ /**
+ * [Collapsed]
+ */
+ collapsed: string
+ /**
+ * [Pending]
+ */
+ pending: string
}
/**
* Back Links
@@ -794,6 +802,14 @@ export type TranslationFunctions = {
* [Code]
*/
code: () => LocalizedString
+ /**
+ * [Collapsed]
+ */
+ collapsed: () => LocalizedString
+ /**
+ * [Pending]
+ */
+ pending: () => LocalizedString
}
/**
* Back Links
src/components/aside/recent-comments/Artalk.ts
@@ -1,54 +1,91 @@
import type { CommentData, CommentProvider } from './types';
import { cleanCommentHtml } from './utils';
import { asideConfig, commentConfig } from '@/config';
+import { t } from '@utils/i18n';
export const ArtalkProvider: CommentProvider = {
async setup() {
const artalkConfig = commentConfig.artalk!;
- const commentCount = asideConfig.recentComment.count;
-
- const apiCommentUrl = new URL(
- `api/v2/stats/latest_comments?limit=${commentCount}`,
- artalkConfig.serverURL
- ).toString();
- const apiConfigUrl = new URL(`api/v2/conf`, artalkConfig.serverURL).toString();
-
- const responseComment = fetch(apiCommentUrl, {
- method: 'GET',
- });
- const responseConfig = fetch(apiConfigUrl, {
- method: 'GET',
- });
- if (!(await responseComment).ok) {
- throw new Error('Failed to fetch recent comments');
- }
- if (!(await responseConfig).ok) {
+ const desiredCount = asideConfig.recentComment.count;
+
+ const apiBase = artalkConfig.serverURL;
+ const apiConfigUrl = new URL(`api/v2/conf`, apiBase).toString();
+
+ // fetch comment config first
+ const responseConfig = await fetch(apiConfigUrl, { method: 'GET' });
+ if (!responseConfig.ok) {
throw new Error('Failed to fetch comment config');
}
-
- const commentData: {
- id: number;
- nick: string;
- content_marked: string;
- date: string;
- email_encrypted: string;
- page_url: string;
- }[] = (await (await responseComment).json()).data;
const configData: {
gravatar: {
mirror: string;
params: string;
};
- } = (await (await responseConfig).json()).frontend_conf;
+ } = (await responseConfig.json()).frontend_conf;
const getAvatarUrl = (email: string) => {
return `${configData.gravatar.mirror}${email}?${configData.gravatar.params}`;
};
- return commentData.map(
+ // type for items returned by Artalk
+ type FetchItem = {
+ id: number;
+ nick: string;
+ content_marked: string;
+ date: string;
+ email_encrypted: string;
+ page_url: string;
+ is_collapsed: boolean;
+ visible: boolean;
+ }[];
+
+ const collected: FetchItem = [];
+ const seenIds = new Set<number>();
+ let attempt = 0;
+ let limit = desiredCount;
+ let prevCollectedCount = 0;
+
+ while (collected.length < desiredCount && attempt < 3) {
+ const apiCommentUrl = new URL(
+ `api/v2/stats/latest_comments?limit=${limit}`,
+ apiBase
+ ).toString();
+ const resp = await fetch(apiCommentUrl, { method: 'GET' });
+ if (!resp.ok) {
+ throw new Error('Failed to fetch recent comments');
+ }
+ const data: FetchItem = (await resp.json()).data || [];
+
+ let addedThisRound = 0;
+ for (const item of data) {
+ if (!item.visible) continue; // skip invisible comments
+ if (seenIds.has(item.id)) continue; // dedupe
+ collected.push(item);
+ seenIds.add(item.id);
+ addedThisRound++;
+ if (collected.length >= desiredCount) break;
+ }
+
+ // if increasing limit didn't yield any new visible comments, stop
+ if (addedThisRound === 0 && prevCollectedCount === collected.length) {
+ break;
+ }
+
+ prevCollectedCount = collected.length;
+ if (collected.length >= desiredCount) break;
+
+ // increase limit to try to fetch more next round
+ limit = limit + (desiredCount - collected.length);
+ attempt++;
+ }
+
+ // map to CommentData and return up to desiredCount
+ return collected.slice(0, desiredCount).map(
(item): CommentData => ({
avatarUrl: getAvatarUrl(item.email_encrypted),
- commentContent: cleanCommentHtml(item.content_marked),
+ commentContent: item.is_collapsed
+ ? t.info.commentAbbrs.collapsed()
+ : cleanCommentHtml(item.content_marked),
commentUrl: `${item.page_url}#atk-comment-${item.id}`,
author: item.nick,
time: new Date(item.date),