|
| 1 | +import React from 'react' |
| 2 | + |
| 3 | +import styles from './styles.module.css' |
| 4 | + |
| 5 | +export type MappingType = |
| 6 | + | 'pathname' |
| 7 | + | 'url' |
| 8 | + | 'title' |
| 9 | + | 'og:title' |
| 10 | + | 'issue-number' |
| 11 | + | 'issue-term' |
| 12 | + |
| 13 | +export type Theme = |
| 14 | + | 'github-light' |
| 15 | + | 'github-dark' |
| 16 | + | 'preferred-color-scheme' |
| 17 | + | 'github-dark-orange' |
| 18 | + | 'icy-dark' |
| 19 | + | 'dark-blue' |
| 20 | + | 'photon-dark' |
| 21 | + |
| 22 | +interface ReactUtterancesProps { |
| 23 | + repo: string |
| 24 | + issueMap: MappingType |
| 25 | + issueTerm?: string |
| 26 | + issueNumber?: number |
| 27 | + label?: string |
| 28 | + theme: Theme |
| 29 | +} |
| 30 | + |
| 31 | +interface ReactUtterancesState { |
| 32 | + pending: boolean |
| 33 | +} |
| 34 | + |
| 35 | +export class ReactUtterances extends React.Component< |
| 36 | + ReactUtterancesProps, |
| 37 | + ReactUtterancesState |
| 38 | +> { |
| 39 | + reference: React.RefObject<HTMLDivElement> |
| 40 | + |
| 41 | + constructor(props: ReactUtterancesProps) { |
| 42 | + super(props) |
| 43 | + |
| 44 | + if (props.issueMap === 'issue-term' && props.issueTerm === undefined) { |
| 45 | + throw Error( |
| 46 | + "Property 'issueTerm' must be provided with issueMap 'issue-term'" |
| 47 | + ) |
| 48 | + } |
| 49 | + |
| 50 | + if (props.issueMap === 'issue-number' && props.issueNumber === undefined) { |
| 51 | + throw Error( |
| 52 | + "Property 'issueNumber' must be provided with issueMap 'issue-number'" |
| 53 | + ) |
| 54 | + } |
| 55 | + |
| 56 | + this.reference = React.createRef<HTMLDivElement>() |
| 57 | + this.state = { pending: true } |
| 58 | + } |
| 59 | + |
| 60 | + componentDidMount(): void { |
| 61 | + const { repo, issueMap, issueTerm, issueNumber, label, theme } = this.props |
| 62 | + const scriptElement = document.createElement('script') |
| 63 | + scriptElement.src = 'https://utteranc.es/client.js' |
| 64 | + scriptElement.async = true |
| 65 | + scriptElement.defer = true |
| 66 | + scriptElement.setAttribute('repo', repo) |
| 67 | + scriptElement.setAttribute('crossorigin', 'annonymous') |
| 68 | + scriptElement.setAttribute('theme', theme) |
| 69 | + scriptElement.onload = () => this.setState({ pending: false }) |
| 70 | + |
| 71 | + if (label) { |
| 72 | + scriptElement.setAttribute('label', label) |
| 73 | + } |
| 74 | + |
| 75 | + if (issueMap === 'issue-number') { |
| 76 | + scriptElement.setAttribute('issue-number', issueNumber!.toString()) |
| 77 | + } else if (issueMap === 'issue-term') { |
| 78 | + scriptElement.setAttribute('issue-term', issueTerm!) |
| 79 | + } else { |
| 80 | + scriptElement.setAttribute('issue-term', issueMap) |
| 81 | + } |
| 82 | + |
| 83 | + // TODO: Check current availability |
| 84 | + this.reference.current!.appendChild(scriptElement) |
| 85 | + } |
| 86 | + |
| 87 | + render(): React.ReactElement { |
| 88 | + return ( |
| 89 | + <div className={styles.comments}> |
| 90 | + <div className={styles.utterances} ref={this.reference}> |
| 91 | + {this.state.pending && <p>Loading Comments...</p>} |
| 92 | + </div> |
| 93 | + </div> |
| 94 | + ) |
| 95 | + } |
| 96 | +} |
0 commit comments