mirror of
https://codeberg.org/HPCesia/AstralHalo.git
synced 2025-04-08 17:34:27 +08:00
feat(comment): supports artalk
This commit is contained in:
parent
1a6cd77bf8
commit
01a23952ac
@ -33,6 +33,7 @@
|
|||||||
"@swup/scroll-plugin": "^3.3.2",
|
"@swup/scroll-plugin": "^3.3.2",
|
||||||
"@tailwindcss/vite": "^4.1.2",
|
"@tailwindcss/vite": "^4.1.2",
|
||||||
"@waline/client": "^3.5.6",
|
"@waline/client": "^3.5.6",
|
||||||
|
"artalk": "^2.9.1",
|
||||||
"astro": "^5.6.1",
|
"astro": "^5.6.1",
|
||||||
"astro-compress": "2.3.5",
|
"astro-compress": "2.3.5",
|
||||||
"astro-icon": "^1.1.5",
|
"astro-icon": "^1.1.5",
|
||||||
|
@ -3,6 +3,7 @@ import { commentConfig } from '@/config';
|
|||||||
import Giscus from '@components/comment/Giscus.astro';
|
import Giscus from '@components/comment/Giscus.astro';
|
||||||
import Twikoo from '@components/comment/Twikoo.astro';
|
import Twikoo from '@components/comment/Twikoo.astro';
|
||||||
import Waline from '@components/comment/Waline.astro';
|
import Waline from '@components/comment/Waline.astro';
|
||||||
|
import Artalk from './comment/Artalk.astro';
|
||||||
---
|
---
|
||||||
|
|
||||||
<div id="page-comment">
|
<div id="page-comment">
|
||||||
@ -15,6 +16,8 @@ import Waline from '@components/comment/Waline.astro';
|
|||||||
return <Giscus />;
|
return <Giscus />;
|
||||||
case 'waline':
|
case 'waline':
|
||||||
return <Waline />;
|
return <Waline />;
|
||||||
|
case 'artalk':
|
||||||
|
return <Artalk />;
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import { asideConfig, commentConfig } from '@/config';
|
import { asideConfig, commentConfig } from '@/config';
|
||||||
import I18nKey from '@i18n/I18nKey';
|
import I18nKey from '@i18n/I18nKey';
|
||||||
import { i18n } from '@i18n/translation';
|
import { i18n } from '@i18n/translation';
|
||||||
|
import ArtalkRecentCommentScript from './recent-comments/Artalk.astro';
|
||||||
import TwikooRecentCommentScript from './recent-comments/Twikoo.astro';
|
import TwikooRecentCommentScript from './recent-comments/Twikoo.astro';
|
||||||
import WalineRecentCommentScript from './recent-comments/Waline.astro';
|
import WalineRecentCommentScript from './recent-comments/Waline.astro';
|
||||||
---
|
---
|
||||||
@ -50,6 +51,8 @@ import WalineRecentCommentScript from './recent-comments/Waline.astro';
|
|||||||
return <TwikooRecentCommentScript />;
|
return <TwikooRecentCommentScript />;
|
||||||
case 'waline':
|
case 'waline':
|
||||||
return <WalineRecentCommentScript />;
|
return <WalineRecentCommentScript />;
|
||||||
|
case 'artalk':
|
||||||
|
return <ArtalkRecentCommentScript />;
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unsupported comment provider: '${commentConfig.provider}' for recent comments`
|
`Unsupported comment provider: '${commentConfig.provider}' for recent comments`
|
||||||
|
73
src/components/aside/recent-comments/Artalk.astro
Normal file
73
src/components/aside/recent-comments/Artalk.astro
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<script>
|
||||||
|
import { asideConfig, commentConfig } from '@/config';
|
||||||
|
import {
|
||||||
|
cleanCommentHtml,
|
||||||
|
cleanPlaceholders,
|
||||||
|
createCommentItem,
|
||||||
|
getTemplate,
|
||||||
|
} from './utils.ts';
|
||||||
|
|
||||||
|
async function 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) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
const getAvatarUrl = (email: string) => {
|
||||||
|
return `${configData.gravatar.mirror}${email}?${configData.gravatar.params}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { container, template } = getTemplate()!;
|
||||||
|
if (container && !template) {
|
||||||
|
// 说明已经加载完毕, 模板被删除了
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
commentData.forEach((item) =>
|
||||||
|
createCommentItem(container, template!, {
|
||||||
|
avatarUrl: getAvatarUrl(item.email_encrypted),
|
||||||
|
commentContent: cleanCommentHtml(item.content_marked),
|
||||||
|
commentUrl: `${item.page_url}#atk-comment-${item.id}`,
|
||||||
|
author: item.nick,
|
||||||
|
time: new Date(item.date),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
cleanPlaceholders(container, template!);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('astro:page-load', setup);
|
||||||
|
await setup();
|
||||||
|
</script>
|
@ -10,8 +10,10 @@
|
|||||||
async function setup() {
|
async function setup() {
|
||||||
const walineConfig = commentConfig.waline!;
|
const walineConfig = commentConfig.waline!;
|
||||||
const commentCount = asideConfig.recentComment.count;
|
const commentCount = asideConfig.recentComment.count;
|
||||||
const apiUrl = `${walineConfig.serverURL}/api/comment?type=recent&count=${commentCount}`;
|
const apiUrl = new URL(
|
||||||
console.log('apiUrl', apiUrl);
|
`api/comment?type=recent&count=${commentCount}`,
|
||||||
|
walineConfig.serverURL
|
||||||
|
).toString();
|
||||||
|
|
||||||
const response = await fetch(apiUrl, {
|
const response = await fetch(apiUrl, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
42
src/components/comment/Artalk.astro
Normal file
42
src/components/comment/Artalk.astro
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
---
|
||||||
|
import 'artalk/Artalk.css';
|
||||||
|
---
|
||||||
|
|
||||||
|
<div id="artalk-wrapper" class="mt-6"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { commentConfig, siteConfig } from '@/config';
|
||||||
|
import Artalk from 'artalk';
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
function getCurrentMode(): boolean {
|
||||||
|
if (!('darkMode' in localStorage)) {
|
||||||
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
}
|
||||||
|
return localStorage.darkMode === 'true';
|
||||||
|
}
|
||||||
|
|
||||||
|
const artalk = Artalk.init({
|
||||||
|
el: '#artalk-wrapper',
|
||||||
|
darkMode: getCurrentMode(),
|
||||||
|
pageKey: window.location.pathname,
|
||||||
|
pageTitle: document.title,
|
||||||
|
server: commentConfig.artalk?.serverURL,
|
||||||
|
site: siteConfig.title,
|
||||||
|
locale: commentConfig.artalk?.locale || siteConfig.lang,
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('blog:darkmode-change', (e) => {
|
||||||
|
// @ts-expect-error CustomEvent.detail is not defined in TypeScript
|
||||||
|
const { isDark } = e.detail;
|
||||||
|
artalk.setDarkMode(isDark);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('astro:before-swap', () => {
|
||||||
|
artalk.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('astro:page-load', setup);
|
||||||
|
setup();
|
||||||
|
</script>
|
@ -199,4 +199,8 @@ export const commentConfig: CommentConfig = {
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
reaction: false,
|
reaction: false,
|
||||||
},
|
},
|
||||||
|
artalk: {
|
||||||
|
serverURL: 'https://artalk.yourdomain.com',
|
||||||
|
// locale: 'en', // Optional, default is site language.
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -498,7 +498,7 @@ export type CommentConfig = {
|
|||||||
*
|
*
|
||||||
* 评论的提供者。
|
* 评论的提供者。
|
||||||
*/
|
*/
|
||||||
provider: 'twikoo' | 'giscus' | 'waline';
|
provider: 'twikoo' | 'giscus' | 'waline' | 'artalk';
|
||||||
/**
|
/**
|
||||||
* The configuration of Twikoo.
|
* The configuration of Twikoo.
|
||||||
*
|
*
|
||||||
@ -708,4 +708,32 @@ export type CommentConfig = {
|
|||||||
*/
|
*/
|
||||||
reaction?: boolean | string[];
|
reaction?: boolean | string[];
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* The configuration of Artalk.
|
||||||
|
* Most settings should be configured on the server side,
|
||||||
|
* so only the most basic configuration is provided here.
|
||||||
|
*
|
||||||
|
* Artalk 的配置。大多数设置应当在服务端进行配置,因此这里仅提供最基本的配置。
|
||||||
|
*
|
||||||
|
* @see https://artalk.js.org/
|
||||||
|
*/
|
||||||
|
artalk?: {
|
||||||
|
/**
|
||||||
|
* The server URL of Artalk.
|
||||||
|
*
|
||||||
|
* Artalk 的服务端地址。
|
||||||
|
*
|
||||||
|
* @see https://artalk.js.org/en/guide/frontend/config.html#server
|
||||||
|
*/
|
||||||
|
serverURL: string;
|
||||||
|
/**
|
||||||
|
* Language setting of Artalk.
|
||||||
|
*
|
||||||
|
* 语言设置
|
||||||
|
*
|
||||||
|
* @default siteConfig.lang
|
||||||
|
* @see https://artalk.js.org/en/guide/frontend/config.html#locale
|
||||||
|
*/
|
||||||
|
locale?: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user