mirror of
https://github.com/d0zingcat/nextjs-notion-starter-kit.git
synced 2026-05-13 15:09:47 +00:00
feat: add blog comments via utterances
This commit is contained in:
@@ -25,6 +25,7 @@ import { Loading } from './Loading'
|
||||
import { Page404 } from './Page404'
|
||||
import { PageHead } from './PageHead'
|
||||
import { Footer } from './Footer'
|
||||
import { ReactUtterances } from './ReactUtterances'
|
||||
|
||||
import styles from './styles.module.css'
|
||||
|
||||
@@ -87,6 +88,20 @@ export const NotionPage: React.FC<types.PageProps> = ({
|
||||
const canonicalPageUrl =
|
||||
!isDev && getCanonicalPageUrl(site, recordMap)(pageId)
|
||||
|
||||
let comments: React.ReactNode = null
|
||||
|
||||
if (block.type === 'page' && block.parent_table === 'collection') {
|
||||
comments = (
|
||||
<ReactUtterances
|
||||
repo='transitive-bullshit/transitivebullsh.it'
|
||||
issueMap='issue-term'
|
||||
issueTerm='title'
|
||||
label='blog'
|
||||
theme='preferred-color-scheme'
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<IconContext.Provider value={{ style: { verticalAlign: 'middle' } }}>
|
||||
<PageHead site={site} />
|
||||
@@ -144,6 +159,7 @@ export const NotionPage: React.FC<types.PageProps> = ({
|
||||
mapPageUrl={siteMapPageUrl}
|
||||
mapImageUrl={mapNotionImageUrl}
|
||||
searchNotion={searchNotion}
|
||||
pageFooter={comments}
|
||||
footer={<Footer />}
|
||||
/>
|
||||
|
||||
|
||||
96
components/ReactUtterances.tsx
Normal file
96
components/ReactUtterances.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import React from 'react'
|
||||
|
||||
import styles from './styles.module.css'
|
||||
|
||||
export type MappingType =
|
||||
| 'pathname'
|
||||
| 'url'
|
||||
| 'title'
|
||||
| 'og:title'
|
||||
| 'issue-number'
|
||||
| 'issue-term'
|
||||
|
||||
export type Theme =
|
||||
| 'github-light'
|
||||
| 'github-dark'
|
||||
| 'preferred-color-scheme'
|
||||
| 'github-dark-orange'
|
||||
| 'icy-dark'
|
||||
| 'dark-blue'
|
||||
| 'photon-dark'
|
||||
|
||||
interface ReactUtterancesProps {
|
||||
repo: string
|
||||
issueMap: MappingType
|
||||
issueTerm?: string
|
||||
issueNumber?: number
|
||||
label?: string
|
||||
theme: Theme
|
||||
}
|
||||
|
||||
interface ReactUtterancesState {
|
||||
pending: boolean
|
||||
}
|
||||
|
||||
export class ReactUtterances extends React.Component<
|
||||
ReactUtterancesProps,
|
||||
ReactUtterancesState
|
||||
> {
|
||||
reference: React.RefObject<HTMLDivElement>
|
||||
|
||||
constructor(props: ReactUtterancesProps) {
|
||||
super(props)
|
||||
|
||||
if (props.issueMap === 'issue-term' && props.issueTerm === undefined) {
|
||||
throw Error(
|
||||
"Property 'issueTerm' must be provided with issueMap 'issue-term'"
|
||||
)
|
||||
}
|
||||
|
||||
if (props.issueMap === 'issue-number' && props.issueNumber === undefined) {
|
||||
throw Error(
|
||||
"Property 'issueNumber' must be provided with issueMap 'issue-number'"
|
||||
)
|
||||
}
|
||||
|
||||
this.reference = React.createRef<HTMLDivElement>()
|
||||
this.state = { pending: true }
|
||||
}
|
||||
|
||||
componentDidMount(): void {
|
||||
const { repo, issueMap, issueTerm, issueNumber, label, theme } = this.props
|
||||
const scriptElement = document.createElement('script')
|
||||
scriptElement.src = 'https://utteranc.es/client.js'
|
||||
scriptElement.async = true
|
||||
scriptElement.defer = true
|
||||
scriptElement.setAttribute('repo', repo)
|
||||
scriptElement.setAttribute('crossorigin', 'annonymous')
|
||||
scriptElement.setAttribute('theme', theme)
|
||||
scriptElement.onload = () => this.setState({ pending: false })
|
||||
|
||||
if (label) {
|
||||
scriptElement.setAttribute('label', label)
|
||||
}
|
||||
|
||||
if (issueMap === 'issue-number') {
|
||||
scriptElement.setAttribute('issue-number', issueNumber!.toString())
|
||||
} else if (issueMap === 'issue-term') {
|
||||
scriptElement.setAttribute('issue-term', issueTerm!)
|
||||
} else {
|
||||
scriptElement.setAttribute('issue-term', issueMap)
|
||||
}
|
||||
|
||||
// TODO: Check current availability
|
||||
this.reference.current!.appendChild(scriptElement)
|
||||
}
|
||||
|
||||
render(): React.ReactElement {
|
||||
return (
|
||||
<div className={styles.comments}>
|
||||
<div className={styles.utterances} ref={this.reference}>
|
||||
{this.state.pending && <p>Loading Comments...</p>}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -86,3 +86,22 @@
|
||||
.linkedin:hover {
|
||||
color: #0077b5;
|
||||
}
|
||||
|
||||
.comments {
|
||||
width: 100%;
|
||||
margin-top: 2em;
|
||||
border-top: 1px solid var(--fg-color-0);
|
||||
}
|
||||
|
||||
.utterances {
|
||||
margin-top: 2em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 567px) {
|
||||
.utterances {
|
||||
width: calc(100% + 60px);
|
||||
position: relative;
|
||||
left: -60px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,7 @@ html {
|
||||
body {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.utterances {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
@@ -68,3 +68,27 @@
|
||||
filter: grayscale(0.25);
|
||||
}
|
||||
*/
|
||||
|
||||
.notion-quote {
|
||||
padding: 0.2em 0.75em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.notion-h1,
|
||||
.notion-h2,
|
||||
.notion-h3 {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.notion-callout {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.notion-hr {
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
.notion-dark .notion-collection-card {
|
||||
border: 1px solid var(--fg-color-0);
|
||||
box-shadow: unset;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user