diff --git a/.env.example b/.env.example index 97ce54d..ede613c 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,7 @@ NEXT_PUBLIC_UTTERANCES_REPO= NEXT_PUBLIC_DISQUS_SHORTNAME= NEXT_PUBLIC_CUSDIS_APPID= NEXT_PUBLIC_CUSDIS_HOST= +NEXT_PUBLIC_COMMENTO_URL= MAILCHIMP_API_KEY= diff --git a/.vscode/settings.json b/.vscode/settings.json index bb6031b..83cf3ff 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "cSpell.words": [ "alpn", "blackhole", + "Commento", "Cusdis", "Disqus", "dokodemo", diff --git a/components/comments/Commento.tsx b/components/comments/Commento.tsx new file mode 100644 index 0000000..51ebbd9 --- /dev/null +++ b/components/comments/Commento.tsx @@ -0,0 +1,30 @@ +import React, { useMemo, useState } from 'react' + +import siteMetadata from '@/data/siteMetadata' +import { PostFrontMatter } from 'types/PostFrontMatter' +import { useTheme } from 'next-themes' +import ReactCommento from './commento/ReactCommento' + +interface Props { + frontMatter: PostFrontMatter +} + +const Commento = ({ frontMatter }: Props) => { + const { resolvedTheme } = useTheme() + const commentsTheme = useMemo(() => { + switch (resolvedTheme) { + case 'light': + case 'dark': + return resolvedTheme + default: + return 'auto' + } + }, [resolvedTheme]) + return ( +
+ +
+ ) +} + +export default Commento diff --git a/components/comments/commento/ReactCommento.tsx b/components/comments/commento/ReactCommento.tsx new file mode 100644 index 0000000..227bcf0 --- /dev/null +++ b/components/comments/commento/ReactCommento.tsx @@ -0,0 +1,83 @@ +import { createRef } from 'preact' +import React, { useLayoutEffect, useMemo, useRef } from 'react' + +interface DataAttributes { + [key: string]: string | boolean | undefined +} + +const insertScript = ( + src: string, + id: string, + dataAttributes: DataAttributes, + onload = () => {} +) => { + const script = window.document.createElement('script') + script.async = true + script.src = src + script.id = id + console.log(document.getElementById(id)) + if (document.getElementById(id)) { + return + } + script.addEventListener('load', onload, { capture: true, once: true }) + + Object.entries(dataAttributes).forEach(([key, value]) => { + if (value === undefined) { + return + } + script.setAttribute(`data-${key}`, value.toString()) + }) + + document.body.appendChild(script) + + return () => { + script.remove() + } +} + +const ReactCommento = ({ + url, + cssOverride, + autoInit, + noFonts, + hideDeleted, + pageId, +}: { + url: string + cssOverride?: string + autoInit?: boolean + noFonts?: boolean + hideDeleted?: boolean + pageId?: string +}) => { + const containerId = useMemo(() => `commento-${Math.random().toString().slice(2, 8)}`, []) + const container = createRef() + const initializing = useRef(false) + + useLayoutEffect(() => { + if (!window) { + return + } + + window['commento'] = container.current + + const removeScript = insertScript( + url, + `${containerId}-script`, + { + 'css-override': cssOverride, + 'auto-init': autoInit, + 'no-fonts': noFonts, + 'hide-deleted': hideDeleted, + 'page-id': pageId, + 'id-root': containerId, + }, + () => { + removeScript() + } + ) + }, [autoInit, cssOverride, hideDeleted, noFonts, pageId, url, containerId, container]) + + return
+} +export default ReactCommento diff --git a/components/comments/index.tsx b/components/comments/index.tsx index 9e30231..8d59051 100644 --- a/components/comments/index.tsx +++ b/components/comments/index.tsx @@ -32,6 +32,12 @@ const CusdisComponent = dynamic( }, { ssr: false } ) +const CommentoComponent = dynamic( + () => { + return import('@/components/comments/Commento') + }, + { ssr: false } +) const Comments = ({ frontMatter }: Props) => { let term @@ -63,6 +69,9 @@ const Comments = ({ frontMatter }: Props) => { {siteMetadata.comment && siteMetadata.comment.provider === 'cusdis' && ( )} + {siteMetadata.comment && siteMetadata.comment.provider === 'commento' && ( + + )}
) } diff --git a/data/siteMetadata.js b/data/siteMetadata.js index 6a7eb5e..9edd783 100644 --- a/data/siteMetadata.js +++ b/data/siteMetadata.js @@ -40,7 +40,7 @@ const siteMetadata = { // content security policy in the `next.config.js` file. // Select a provider and use the environment variables associated to it // https://vercel.com/docs/environment-variables - provider: 'cusdis', // supported providers: giscus, utterances, disqus + provider: 'commento', // supported providers: giscus, utterances, disqus giscusConfig: { // Visit the link below, and follow the steps in the 'configuration' section // https://giscus.app/ @@ -82,6 +82,9 @@ const siteMetadata = { appId: process.env.NEXT_PUBLIC_CUSDIS_APPID, host: process.env.NEXT_PUBLIC_CUSDIS_HOST, }, + commentoConfig: { + url: process.env.NEXT_PUBLIC_COMMENTO_URL, + }, }, } diff --git a/next.config.js b/next.config.js index 225c42a..cb1522a 100644 --- a/next.config.js +++ b/next.config.js @@ -10,7 +10,7 @@ const ContentSecurityPolicy = ` img-src * blob: data:; media-src 'none'; connect-src *; - font-src 'self'; + font-src 'self' comment.ivanli.cc; frame-src giscus.app comment.ivanli.cc ` diff --git a/package-lock.json b/package-lock.json index b56132e..d987b05 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index dabc5c0..53e82a3 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "postcss": "^8.4.17", "preact": "^10.11.1", "react": "18.2.0", + "react-commento": "^1.0.0", "react-cusdis": "^2.1.3", "react-dom": "18.2.0", "reading-time": "1.5.0",