added word count and read time

This commit is contained in:
Kim, Jimin 2021-08-10 09:31:26 +09:00
parent 4bd425061b
commit c977e14112
6 changed files with 79 additions and 17 deletions

View file

@ -8,7 +8,7 @@ Repository for my (developomp's) <a href="https://developomp.com" target="_blank
Tools / Frameworks / Packages used: Tools / Frameworks / Packages used:
| Name | Use | | Name | Use |
| -----------------------------------------------------------------: | :-------------------------- | | ------------------------------------------------------------------------: | :-------------------------- |
| [AWS](https://aws.amazon.com) | Domain register | | [AWS](https://aws.amazon.com) | Domain register |
| [Firebase](https://firebase.google.com) | Static site hosting | | [Firebase](https://firebase.google.com) | Static site hosting |
| [react](https://reactjs.org) | Front end framework | | [react](https://reactjs.org) | Front end framework |
@ -17,6 +17,7 @@ Tools / Frameworks / Packages used:
| [elasticlunr](https://github.com/weixsong/elasticlunr.js) | Search engine | | [elasticlunr](https://github.com/weixsong/elasticlunr.js) | Search engine |
| [gray-matter](https://github.com/jonschlinkert/gray-matter) | Markdown parsing | | [gray-matter](https://github.com/jonschlinkert/gray-matter) | Markdown parsing |
| [markdown-it](https://github.com/markdown-it/markdown-it) | Markdown rendering | | [markdown-it](https://github.com/markdown-it/markdown-it) | Markdown rendering |
| [read-time-estimate](https://github.com/pritishvaidya/read-time-estimate) | Post read time estimation |
# Setup # Setup

View file

@ -9,10 +9,11 @@
import fs from "fs" // read and write files import fs from "fs" // read and write files
import path from "path" // get relative path import path from "path" // get relative path
import elasticlunr from "elasticlunr" // search index generation import elasticlunr from "elasticlunr" // search index generation
import readTimeEstimate from "read-time-estimate" // post read time estimation
import matter from "gray-matter" // parse markdown metadata import matter from "gray-matter" // parse markdown metadata
import toc from "markdown-toc" // table of contents generation
import markdownIt from "markdown-it" // rendering markdown import markdownIt from "markdown-it" // rendering markdown
import hljs from "highlight.js" // code block highlighting import hljs from "highlight.js" // code block highlighting
import toc from "markdown-toc" // table of contents generation
import tm from "markdown-it-texmath" // rendering mathematical expression import tm from "markdown-it-texmath" // rendering mathematical expression
import katex from "katex" // rendering mathematical expression import katex from "katex" // rendering mathematical expression
@ -216,6 +217,15 @@ function recursiveParse(
md.render(markdownRaw.slice(nthIndex(markdownRaw, "---", 2) + 3)) || md.render(markdownRaw.slice(nthIndex(markdownRaw, "---", 2) + 3)) ||
"" ""
// https://github.com/pritishvaidya/read-time-estimate
const { humanizedDuration, totalWords } = readTimeEstimate(
markdownData.content,
275,
12,
500,
["img", "Image"]
)
if (mode == "posts") { if (mode == "posts") {
if (!markdownData.date) { if (!markdownData.date) {
throw Error(`Date is not defined in file: ${fileOrFolderPath}`) throw Error(`Date is not defined in file: ${fileOrFolderPath}`)
@ -234,6 +244,8 @@ function recursiveParse(
title: markdownData.title, title: markdownData.title,
preview: "", preview: "",
date: "", date: "",
readTime: humanizedDuration,
wordCount: totalWords,
tags: [], tags: [],
toc: toc(markdownRaw).content, toc: toc(markdownRaw).content,
} }
@ -333,6 +345,8 @@ function recursiveParse(
title: markdownData.title, title: markdownData.title,
preview: "", preview: "",
date: "", date: "",
readTime: humanizedDuration,
wordCount: totalWords,
tags: [], tags: [],
toc: toc(markdownData.content).content, toc: toc(markdownData.content).content,
} }

View file

@ -42,6 +42,7 @@
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3", "react-scripts": "^4.0.3",
"react-tooltip": "^4.2.21", "react-tooltip": "^4.2.21",
"read-time-estimate": "^0.0.3",
"styled-components": "^5.3.0", "styled-components": "^5.3.0",
"web-vitals": "^2.1.0" "web-vitals": "^2.1.0"
}, },

View file

@ -7,6 +7,12 @@ import theming from "../theming"
import Tag from "../components/Tag" import Tag from "../components/Tag"
import TagList from "../components/TagList" import TagList from "../components/TagList"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import {
faBook,
faCalendar,
faHourglass,
} from "@fortawesome/free-solid-svg-icons"
const StyledTitle = styled.h1` const StyledTitle = styled.h1`
font-size: 2rem; font-size: 2rem;
@ -14,13 +20,21 @@ const StyledTitle = styled.h1`
margin-bottom: 1rem; margin-bottom: 1rem;
` `
const StyledMetaContainer = styled.small`
color: ${(props) =>
theming.theme(props.theme.currentTheme, {
light: "#555",
dark: "lightgrey",
})};
`
const StyledLink = styled(Link)` const StyledLink = styled(Link)`
text-decoration: none; text-decoration: none;
color: ${(props) => color: ${(props) =>
theming.theme(props.theme.currentTheme, { theming.theme(props.theme.currentTheme, {
light: "black", light: theming.light.color1,
dark: "white", dark: theming.dark.color1,
})}; })};
&:hover { &:hover {
@ -48,6 +62,8 @@ interface PostCardProps {
url: string url: string
title: string | undefined title: string | undefined
preview: string preview: string
readTime: string
wordCount: number
tags: string[] tags: string[]
date: string | undefined date: string | undefined
} }
@ -69,7 +85,7 @@ export default class PostCard extends React.Component<PostCardProps> {
: "No title"} : "No title"}
</StyledLink> </StyledLink>
</StyledTitle> </StyledTitle>
<small> <StyledMetaContainer>
<TagList direction="left"> <TagList direction="left">
{this.props.postData.tags ? ( {this.props.postData.tags ? (
this.props.postData.tags.map((tag) => { this.props.postData.tags.map((tag) => {
@ -84,11 +100,21 @@ export default class PostCard extends React.Component<PostCardProps> {
<></> <></>
)} )}
</TagList> </TagList>
Published on{" "} <FontAwesomeIcon icon={faCalendar} /> Published on{" "}
{this.props.postData?.date {this.props.postData?.date
? this.props.postData.date ? this.props.postData.date
: "Unknown date"} : "Unknown date"}
</small> &nbsp;&nbsp;&nbsp;&nbsp;
<FontAwesomeIcon icon={faHourglass} />{" "}
{this.props.postData?.readTime
? this.props.postData.readTime + " read"
: "unknown length"}
&nbsp;&nbsp;&nbsp;&nbsp;
<FontAwesomeIcon icon={faBook} />{" "}
{this.props.postData?.wordCount
? this.props.postData.wordCount + " words"
: "unknown words"}
</StyledMetaContainer>
<hr /> <hr />
<StyledPostCardContent <StyledPostCardContent

View file

@ -12,6 +12,12 @@ import NotFound from "./NotFound"
import Spinner from "../components/Spinner" import Spinner from "../components/Spinner"
import map from "../data/map.json" import map from "../data/map.json"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import {
faBook,
faCalendar,
faHourglass,
} from "@fortawesome/free-solid-svg-icons"
const StyledTitle = styled.h1` const StyledTitle = styled.h1`
margin-bottom: 1rem; margin-bottom: 1rem;
@ -246,7 +252,16 @@ export default class Page extends React.Component<PageProps, PageState> {
{this.state.isUnsearchable ? ( {this.state.isUnsearchable ? (
<></> <></>
) : ( ) : (
<>Published on {this.state.fetchedPage.date}</> <>
<FontAwesomeIcon icon={faCalendar} />{" "}
Published on {this.state.fetchedPage.date}
&nbsp;&nbsp;&nbsp;&nbsp;
<FontAwesomeIcon icon={faHourglass} />{" "}
{this.state.fetchedPage.readTime} read
&nbsp;&nbsp;&nbsp;&nbsp;
<FontAwesomeIcon icon={faBook} />{" "}
{this.state.fetchedPage.wordCount} words
</>
)} )}
</small> </small>
{/* Horizontal Separator */} {/* Horizontal Separator */}

View file

@ -9923,6 +9923,11 @@ read-pkg@^5.2.0:
parse-json "^5.0.0" parse-json "^5.0.0"
type-fest "^0.6.0" type-fest "^0.6.0"
read-time-estimate@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/read-time-estimate/-/read-time-estimate-0.0.3.tgz#3791c6715b0625252f491f74851a12a8dfc2055a"
integrity sha512-TF87eHTuEyRtu/mwnQE8FoZYHpsN1Oj+U/oROL5nrsoEWsh/iGhBzkV50N6DdPEqZ9Jh2PSZk1ZA7KMucgb+ng==
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: "readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.7" version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"