Merge pull request #121 from timlrx/comments

Comments system
This commit is contained in:
Timothy 2021-07-18 16:09:20 +08:00 committed by GitHub
commit 133c19e7fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 306 additions and 21 deletions

View file

@ -43,6 +43,7 @@ I wanted it to be nearly as feature-rich as popular blogging templates like [bea
- Support for multiple authors
- Blog templates
- Support for nested routing of blog posts
- Supports [giscus](https://github.com/laymonage/giscus), [utterances](https://github.com/utterance/utterances) or disqus
- Projects page
- SEO friendly with RSS feed, sitemaps and more!

View file

@ -0,0 +1,37 @@
import React, { useState } from 'react'
import siteMetadata from '@/data/siteMetadata'
const Disqus = ({ frontMatter }) => {
const [enableLoadComments, setEnabledLoadComments] = useState(true)
const COMMENTS_ID = 'disqus_thread'
function LoadComments() {
setEnabledLoadComments(false)
window.disqus_config = function () {
this.page.url = window.location.href
this.page.identifier = frontMatter.slug
}
if (window.DISQUS === undefined) {
const script = document.createElement('script')
script.src = 'https://' + siteMetadata.comment.disqus.shortname + '.disqus.com/embed.js'
script.setAttribute('data-timestamp', +new Date())
script.setAttribute('crossorigin', 'anonymous')
script.async = true
document.body.appendChild(script)
} else {
window.DISQUS.reset({ reload: true })
}
}
return (
<div className="pt-6 pb-6 text-center text-gray-700 dark:text-gray-300">
{enableLoadComments && <button onClick={LoadComments}>Load Comments</button>}
<div className="disqus-frame" id={COMMENTS_ID} />
</div>
)
}
export default Disqus

View file

@ -0,0 +1,50 @@
import React, { useState } from 'react'
import { useTheme } from 'next-themes'
import siteMetadata from '@/data/siteMetadata'
const Giscus = ({ mapping }) => {
const [enableLoadComments, setEnabledLoadComments] = useState(true)
const { theme, resolvedTheme } = useTheme()
const commentsTheme =
siteMetadata.comment.giscusConfig.themeURL === ''
? theme === 'dark' || resolvedTheme === 'dark'
? siteMetadata.comment.giscusConfig.darkTheme
: siteMetadata.comment.giscusConfig.theme
: siteMetadata.comment.giscusConfig.themeURL
const COMMENTS_ID = 'comments-container'
function LoadComments() {
setEnabledLoadComments(false)
const script = document.createElement('script')
script.src = 'https://giscus.app/client.js'
script.setAttribute('data-repo', siteMetadata.comment.giscusConfig.repo)
script.setAttribute('data-repo-id', siteMetadata.comment.giscusConfig.repositoryId)
script.setAttribute('data-category', siteMetadata.comment.giscusConfig.category)
script.setAttribute('data-category-id', siteMetadata.comment.giscusConfig.categoryId)
script.setAttribute('data-mapping', mapping)
script.setAttribute('data-reactions-enabled', siteMetadata.comment.giscusConfig.reactions)
script.setAttribute('data-emit-metadata', siteMetadata.comment.giscusConfig.metadata)
script.setAttribute('data-theme', commentsTheme)
script.setAttribute('crossorigin', 'anonymous')
script.async = true
const comments = document.getElementById(COMMENTS_ID)
if (comments) comments.appendChild(script)
return () => {
const comments = document.getElementById(COMMENTS_ID)
if (comments) comments.innerHTML = ''
}
}
return (
<div className="pt-6 pb-6 text-center text-gray-700 dark:text-gray-300">
{enableLoadComments && <button onClick={LoadComments}>Load Comments</button>}
<div className="giscus-frame" id={COMMENTS_ID} />
</div>
)
}
export default Giscus

View file

@ -0,0 +1,45 @@
import React, { useState } from 'react'
import { useTheme } from 'next-themes'
import siteMetadata from '@/data/siteMetadata'
const Utterances = ({ issueTerm }) => {
const [enableLoadComments, setEnabledLoadComments] = useState(true)
const { theme, resolvedTheme } = useTheme()
const commentsTheme =
theme === 'dark' || resolvedTheme === 'dark'
? siteMetadata.comment.utterancesConfig.darkTheme
: siteMetadata.comment.utterancesConfig.theme
const COMMENTS_ID = 'comments-container'
function LoadComments() {
setEnabledLoadComments(false)
const script = document.createElement('script')
script.src = 'https://utteranc.es/client.js'
script.setAttribute('repo', siteMetadata.comment.utterancesConfig.repo)
script.setAttribute('issue-term', issueTerm)
script.setAttribute('label', siteMetadata.comment.utterancesConfig.label)
script.setAttribute('theme', commentsTheme)
script.setAttribute('crossorigin', 'anonymous')
script.async = true
const comments = document.getElementById(COMMENTS_ID)
if (comments) comments.appendChild(script)
return () => {
const comments = document.getElementById(COMMENTS_ID)
if (comments) comments.innerHTML = ''
}
}
// Added `relative` to fix a weird bug with `utterances-frame` position
return (
<div className="pt-6 pb-6 text-center text-gray-700 dark:text-gray-300">
{enableLoadComments && <button onClick={LoadComments}>Load Comments</button>}
<div className="utterances-frame relative" id={COMMENTS_ID} />
</div>
)
}
export default Utterances

View file

@ -0,0 +1,54 @@
import siteMetadata from '@/data/siteMetadata'
import dynamic from 'next/dynamic'
const UtterancesComponent = dynamic(
() => {
return import('@/components/comments/Utterances')
},
{ ssr: false }
)
const GiscusComponent = dynamic(
() => {
return import('@/components/comments/Giscus')
},
{ ssr: false }
)
const DisqusComponent = dynamic(
() => {
return import('@/components/comments/Disqus')
},
{ ssr: false }
)
const Comments = ({ frontMatter }) => {
let term
switch (
siteMetadata.comment.giscusConfig.mapping ||
siteMetadata.comment.utterancesConfig.issueTerm
) {
case 'pathname':
term = frontMatter.slug
break
case 'url':
term = window.location.href
break
case 'title':
term = frontMatter.title
break
}
return (
<>
{siteMetadata.comment && siteMetadata.comment.provider === 'giscus' && (
<GiscusComponent mapping={term} />
)}
{siteMetadata.comment && siteMetadata.comment.provider === 'utterances' && (
<UtterancesComponent issueTerm={term} />
)}
{siteMetadata.comment && siteMetadata.comment.provider === 'disqus' && (
<DisqusComponent frontMatter={frontMatter} />
)}
</>
)
}
export default Comments

View file

@ -1,7 +1,7 @@
---
title: 'Introducing Tailwind Nexjs Starter Blog'
date: '2021-01-12'
lastmod: '2021-07-11'
lastmod: '2021-07-18'
tags: ['next-js', 'tailwind', 'guide']
draft: false
summary: 'Looking for a performant, out of the box template, with all the best in web technology to support your blogging needs? Checkout the Tailwind Nextjs Starter Blog template.'
@ -48,6 +48,7 @@ I wanted it to be nearly as feature-rich as popular blogging templates like [bea
- Support for multiple authors
- Blog templates
- Support for nested routing of blog posts
- Supports [giscus](https://github.com/laymonage/giscus), [utterances](https://github.com/utterance/utterances) or disqus
- Projects page
- SEO friendly with RSS feed, sitemaps and more!

View file

@ -1,6 +1,6 @@
---
title: 'New features in v1'
date: '2021-07-11'
date: '2021-07-18'
tags: ['next-js', 'tailwind', 'guide']
draft: false
summary: 'An overview of the new features released in v1 - code block copy, multiple authors, frontmatter layout and more'
@ -15,6 +15,7 @@ A post on the new features introduced in v1.0. New features:
- [Xdm MDX compiler](#xdm-mdx-compiler)
- [Layouts](#layouts)
- [Multiple authors](#multiple-authors)
- [Blog comments system](#blog-comments-system)
- [Copy button for code blocks](#copy-button-for-code-blocks)
- [Line highlighting and line numbers](#line-highlighting-and-line-numbers)
@ -140,6 +141,52 @@ export const MDXLayoutRenderer = ({ layout, mdxSource, ...rest }) => {
Use the component is a page where you want to accept a layout name to map to the desired layout.
You need to pass the layout name from the layout folder (it has to be an exact match) and the mdxSource content which is an output of the `seralize` function from the `next-mdx-remote` library.
## Blog comments system
We added support for [giscus](https://github.com/laymonage/giscus), [utterances](https://github.com/utterance/utterances) or disqus.
To enable, simply configure `siteMetadata.js` comments property with the desired provider and settings as specified in the config file.
```js
comment: {
provider: '', // supported providers: giscus, utterances, disqus
giscusConfig: {
repo: '', // username/repoName
// Visit the link below and copy/paste the 'repositoryId', 'category' and 'categoryId'
// https://giscus.app/api/discussions/categories?repo={username}%2F{repoName}
repositoryId: '',
category: [],
categoryId: '',
mapping: '', // supported options: pathname, url, title
reactions: '', // Emoji reactions: 1 = enable / 0 = disable
// Send discussion metadata periodically to the parent window: 1 = enable / 0 = disable
metadata: '',
// theme example: light, dark, dark_dimmed, dark_high_contrast
// transparent_dark, preferred_color_scheme, custom
theme: '',
// theme when dark mode
darkTheme: '',
// If the theme option above is set to 'custom`
// please provide a link below to your custom theme css file.
// example: https://giscus.app/themes/custom_example.css
themeURL: '',
},
utterancesConfig: {
repo: '', // username/repoName
issueTerm: '', // supported options: pathname, url, title
label: '', // label (optional): Comment 💬
// theme example: github-light, github-dark, preferred-color-scheme
// github-dark-orange, icy-dark, dark-blue, photon-dark, boxy-light
theme: '',
// theme when dark mode
darkTheme: '',
},
disqus: {
// https://help.disqus.com/en/articles/1717111-what-s-a-shortname
shortname: '',
},
}
```
## Multiple authors
Information on authors is now split from `siteMetadata.json` and stored in its own `data/authors` folder as a markdown file. Minimally, you will need to have a `default.md` file with authorship information. You can create additional files as required and the file name will be used as the reference to the author.

65
data/siteMetadata.js Normal file
View file

@ -0,0 +1,65 @@
const siteMetadata = {
title: 'Next.js Starter Blog',
author: 'Tails Azimuth',
headerTitle: 'TailwindBlog',
description: 'A blog created with Next.js and Tailwind.css',
language: 'en-us',
siteUrl: 'https://tailwind-nextjs-starter-blog.vercel.app',
siteRepo: 'https://github.com/timlrx/tailwind-nextjs-starter-blog',
siteLogo: '/static/images/logo.png',
image: '/static/images/avatar.png',
socialBanner: '/static/images/twitter-card.png',
email: 'address@yoursite.com',
github: 'https://github.com',
twitter: 'https://twitter.com/Twitter',
facebook: 'https://facebook.com',
youtube: 'https://youtube.com',
linkedin: 'https://www.linkedin.com',
locale: 'en-US',
comment: {
provider: 'giscus', // supported providers: giscus, utterances, disqus
giscusConfig: {
repo: 'timlrx/tailwind-nextjs-starter-blog', // username/repoName
// Visit the link below and copy/paste the 'repositoryId', 'category' and 'categoryId'
// https://giscus.app/api/discussions/categories?repo={username}%2F{repoName}
repositoryId: 'MDEwOlJlcG9zaXRvcnkzMjgxMjEyNjA=',
category: [
{ emoji: '📣', id: 'MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDM4NDYw', name: 'Announcements' },
{ emoji: '💬', id: 'MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDM4NDYx', name: 'General' },
{ emoji: '🙏', id: 'MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDM4NDYy', name: 'Q&A' },
{ emoji: '💡', id: 'MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDM4NDYz', name: 'Ideas' },
{ emoji: '🙌', id: 'MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDM4NDY0', name: 'Show and tell' },
],
categoryId: 'MDE4OkRpc2N1c3Npb25DYXRlZ29yeTMzMDM4NDYw',
mapping: 'pathname', // supported options: pathname, url, title
reactions: '1', // Emoji reactions: 1 = enable / 0 = disable
// Send discussion metadata periodically to the parent window: 1 = enable / 0 = disable
metadata: '0',
// theme example: light, dark, dark_dimmed, dark_high_contrast
// transparent_dark, preferred_color_scheme, custom
theme: 'light',
// theme when dark mode
darkTheme: 'transparent_dark',
// If the theme option above is set to 'custom`
// please provide a link below to your custom theme css file.
// example: https://giscus.app/themes/custom_example.css
themeURL: '',
},
utterancesConfig: {
repo: '', // username/repoName
issueTerm: '', // supported options: pathname, url, title
label: '', // label (optional): Comment 💬
// theme example: github-light, github-dark, preferred-color-scheme
// github-dark-orange, icy-dark, dark-blue, photon-dark, boxy-light
theme: '',
// theme when dark mode
darkTheme: '',
},
disqus: {
// https://help.disqus.com/en/articles/1717111-what-s-a-shortname
shortname: '',
},
},
}
module.exports = siteMetadata

View file

@ -1,19 +0,0 @@
{
"title": "Next.js Starter Blog",
"author": "Tails Azimuth",
"headerTitle": "TailwindBlog",
"description": "A blog created with Next.js and Tailwind.css",
"language": "en-us",
"siteUrl": "https://tailwind-nextjs-starter-blog.vercel.app",
"siteRepo": "https://github.com/timlrx/tailwind-nextjs-starter-blog",
"siteLogo": "/static/images/logo.png",
"image": "/static/images/avatar.png",
"socialBanner": "/static/images/twitter-card.png",
"email": "address@yoursite.com",
"github": "https://github.com",
"twitter": "https://twitter.com/Twitter",
"facebook": "https://facebook.com",
"youtube": "https://youtube.com",
"linkedin": "https://www.linkedin.com",
"locale": "en-US"
}

View file

@ -5,6 +5,7 @@ import { BlogSeo } from '@/components/SEO'
import Image from '@/components/Image'
import Tag from '@/components/Tag'
import siteMetadata from '@/data/siteMetadata'
import Comments from '@/components/comments'
const editUrl = (fileName) => `${siteMetadata.siteRepo}/blob/master/data/blog/${fileName}`
const discussUrl = (slug) =>
@ -91,6 +92,7 @@ export default function PostLayout({ frontMatter, authorDetails, next, prev, chi
{``}
<Link href={editUrl(fileName)}>{'View on GitHub'}</Link>
</div>
<Comments frontMatter={frontMatter} />
</div>
<footer>
<div className="text-sm font-medium leading-5 divide-gray-200 xl:divide-y dark:divide-gray-700 xl:col-start-1 xl:row-start-2">

View file

@ -4,6 +4,7 @@ import SectionContainer from '@/components/SectionContainer'
import { BlogSeo } from '@/components/SEO'
import siteMetadata from '@/data/siteMetadata'
import formatDate from '@/lib/utils/formatDate'
import Comments from '@/components/comments'
export default function PostLayout({ frontMatter, authorDetails, next, prev, children }) {
const { date, title } = frontMatter
@ -35,6 +36,7 @@ export default function PostLayout({ frontMatter, authorDetails, next, prev, chi
<div className="divide-y divide-gray-200 dark:divide-gray-700 xl:pb-0 xl:col-span-3 xl:row-span-2">
<div className="pt-10 pb-8 prose dark:prose-dark max-w-none">{children}</div>
</div>
<Comments frontMatter={frontMatter} />
<footer>
<div className="flex flex-col text-sm font-medium sm:flex-row sm:justify-between sm:text-base">
{prev && (