hard coded post author, removed dompurify, separated blog post contents from metadata, removed post template file, and implemented tag and date order feature
This commit is contained in:
parent
bba728a0b6
commit
e907b9009f
44 changed files with 329 additions and 221 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,7 +4,8 @@ _/
|
|||
# auto generated files
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
pages.json
|
||||
posts.json
|
||||
posts/
|
||||
|
||||
# dependencies
|
||||
.pnp/
|
||||
|
|
|
@ -1,82 +1,166 @@
|
|||
/**
|
||||
* It reads markdown files and write its content and metadata to a json file that can be used by React.
|
||||
* - Files and directories names starting with a underscore (_ <- this thing), will be ignored
|
||||
* - Symbolic links are also be ignored as of the moment
|
||||
* - Filename-to-url encoder not perfect. Some filenames might cause problem (like files containing special characters)
|
||||
* It reads markdown files and write its content and metadata to json files that can be imported by React.
|
||||
* - Files and directories names starting with a underscore (_) will be ignored
|
||||
* - Symbolic links are ignored as of the moment
|
||||
* - Filename-to-url encoder is not perfect. Some non-url-friendly filenames might cause problems
|
||||
*/
|
||||
|
||||
import fs from "fs" // read and write files
|
||||
import path from "path" // get relative path
|
||||
import matter from "gray-matter" // parse markdown metadata
|
||||
// import createDOMPurify from "dompurify" // sanitize result html
|
||||
// import { JSDOM } from "jsdom" // create empty window for fom purifier to work. Morea info here: https://github.com/cure53/DOMPurify
|
||||
import toc from "markdown-toc" // table of contents generation
|
||||
|
||||
// const window = new JSDOM("").window
|
||||
// const DOMPurify = createDOMPurify(window)
|
||||
|
||||
const dirPath = "./markdown" // where it will look for markdown documents
|
||||
const outPath = "./src/pages.json" // path to the json database
|
||||
const outPath = "./src/data" // path to the json database
|
||||
|
||||
const removeExceptionArray = ["content", "meta"] // gray-matter creates unnecessary properties
|
||||
// data that will be converted to JSON string
|
||||
const result = {
|
||||
date: {},
|
||||
tags: {},
|
||||
posts: {},
|
||||
}
|
||||
|
||||
const pageList = {} // data that will be converted to JSON string
|
||||
// creates directory/directories
|
||||
// https://stackoverflow.com/a/40686946/12979111
|
||||
function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
|
||||
const sep = path.sep
|
||||
const initDir = path.isAbsolute(targetDir) ? sep : ""
|
||||
const baseDir = isRelativeToScript ? __dirname : "."
|
||||
|
||||
return targetDir.split(sep).reduce((parentDir, childDir) => {
|
||||
const curDir = path.resolve(baseDir, parentDir, childDir)
|
||||
try {
|
||||
fs.mkdirSync(curDir)
|
||||
} catch (err) {
|
||||
if (err.code === "EEXIST") {
|
||||
// curDir already exists!
|
||||
return curDir
|
||||
}
|
||||
|
||||
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
|
||||
if (err.code === "ENOENT") {
|
||||
// Throw the original parentDir error on curDir `ENOENT` failure.
|
||||
throw new Error(
|
||||
`EACCES: permission denied, mkdir '${parentDir}'`
|
||||
)
|
||||
}
|
||||
|
||||
const caughtErr =
|
||||
["EACCES", "EPERM", "EISDIR"].indexOf(err.code) > -1
|
||||
if (
|
||||
!caughtErr ||
|
||||
(caughtErr && curDir === path.resolve(targetDir))
|
||||
) {
|
||||
throw err // Throw if it's just the last created dir.
|
||||
}
|
||||
}
|
||||
|
||||
return curDir
|
||||
}, initDir)
|
||||
}
|
||||
|
||||
// big brain recursive function
|
||||
// only supports folders and files (no symbolic links)
|
||||
// does not scale well for large amount of folders and files
|
||||
function addFiles(filesPath: string) {
|
||||
// does not scale well for large number of folders
|
||||
// it calls itself for every directory it finds
|
||||
function recursiveParser(fileOrFolderPath: string) {
|
||||
// ignore if file/directory name starts with a underscore
|
||||
const fileOrFolderName = filesPath.substring(filesPath.lastIndexOf("/") + 1)
|
||||
const fileOrFolderName = fileOrFolderPath.substring(
|
||||
fileOrFolderPath.lastIndexOf("/") + 1
|
||||
)
|
||||
if (fileOrFolderName.startsWith("_")) return
|
||||
|
||||
// not perfect. Some filenames might cause problem.
|
||||
const stats = fs.lstatSync(filesPath) // checks if the path leads to a directory or a file
|
||||
// not perfect. Some filenames might cause problems.
|
||||
const stats = fs.lstatSync(fileOrFolderPath) // checks if the path leads to a directory or a file
|
||||
|
||||
// don't use replaceAll
|
||||
const urlPath = `/${path.relative(dirPath, filesPath)}` // path tha will be used for url
|
||||
.replace(/\.[^/.]+$/, "") // remove .md file extension
|
||||
const urlPath = `/${path.relative(dirPath, fileOrFolderPath)}` // path that will be used as site url
|
||||
.replace(/\.[^/.]+$/, "") // remove file extension
|
||||
.replace(/ /g, "-") // replace space with a dash "-"
|
||||
|
||||
// if it's a directory, apply this function to every files/folders in it
|
||||
// if it's a file, read and add it to pageList
|
||||
// if it's a file, parse and save it to file
|
||||
if (stats.isDirectory()) {
|
||||
fs.readdirSync(filesPath).map((child) =>
|
||||
addFiles(`${filesPath}/${child}`)
|
||||
fs.readdirSync(fileOrFolderPath).map((child) =>
|
||||
recursiveParser(`${fileOrFolderPath}/${child}`)
|
||||
)
|
||||
} else if (stats.isFile()) {
|
||||
// skip if file is not a markdown file
|
||||
if (!fileOrFolderName.endsWith(".md")) {
|
||||
console.log(`Ignoring non markdown file at: ${filesPath}`)
|
||||
console.log(`Ignoring non markdown file at: ${fileOrFolderPath}`)
|
||||
return
|
||||
}
|
||||
|
||||
pageList[urlPath] = matter(fs.readFileSync(filesPath, "utf8")) // parse markdown metadata
|
||||
const parsedMarkdown = matter(fs.readFileSync(fileOrFolderPath, "utf8")) // parse markdown metadata
|
||||
const contentJSONFile = `${outPath}/posts${urlPath}.json`
|
||||
|
||||
// sanitizing should happens here but this code removes blockquote for some reason
|
||||
// I might have to take a look at https://github.com/cure53/DOMPurify/issues/186 later
|
||||
// pageList[urlPath].content = DOMPurify.sanitize(
|
||||
// pageList[urlPath].content
|
||||
// )
|
||||
|
||||
pageList[urlPath].meta = pageList[urlPath].data // change property name from data to meta
|
||||
|
||||
pageList[urlPath].meta.toc = toc(pageList[urlPath].content).content
|
||||
// removes unnecessary data
|
||||
Object.keys(pageList[urlPath]).forEach(
|
||||
(key) =>
|
||||
removeExceptionArray.includes(key) ||
|
||||
delete pageList[urlPath][key]
|
||||
mkDirByPathSync(
|
||||
contentJSONFile.substring(0, contentJSONFile.lastIndexOf("/") + 1)
|
||||
)
|
||||
|
||||
// write content to json file
|
||||
fs.writeFileSync(
|
||||
contentJSONFile,
|
||||
JSON.stringify({
|
||||
content: parsedMarkdown.content,
|
||||
})
|
||||
)
|
||||
|
||||
result.posts[urlPath] = parsedMarkdown.data
|
||||
|
||||
// date
|
||||
if (!result.posts[urlPath].date) {
|
||||
throw Error(`Date does not exist in file: ${urlPath}`)
|
||||
}
|
||||
result.posts[urlPath].date = new Date(
|
||||
parsedMarkdown.data.date
|
||||
).toLocaleString("default", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})
|
||||
if (result.date[result.posts[urlPath].date])
|
||||
result.date[result.posts[urlPath].date].push(urlPath)
|
||||
else result.date[result.posts[urlPath].date] = [urlPath]
|
||||
|
||||
//tags
|
||||
if (result.posts[urlPath].tags) {
|
||||
result.posts[urlPath].tags.forEach((tag) => {
|
||||
if (result.tags[tag]) result.tags[tag].push(urlPath)
|
||||
else result.tags[tag] = [urlPath]
|
||||
})
|
||||
}
|
||||
|
||||
// toc
|
||||
result.posts[urlPath].toc = toc(result.posts[urlPath].content).content
|
||||
}
|
||||
}
|
||||
|
||||
// start recursive function + check if it's a directory
|
||||
/** Step 1
|
||||
* Deleting existing files
|
||||
*/
|
||||
try {
|
||||
fs.rmSync(`${outPath}/posts`, { recursive: true })
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (err) {}
|
||||
|
||||
try {
|
||||
fs.unlinkSync(`${outPath}/posts.json`)
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (err) {}
|
||||
|
||||
/** Step 2
|
||||
* Populate result and write to src/data/posts/
|
||||
*/
|
||||
|
||||
// check if it's a directory and start recursive function
|
||||
if (fs.lstatSync(dirPath).isDirectory()) {
|
||||
addFiles(dirPath)
|
||||
recursiveParser(dirPath)
|
||||
} else {
|
||||
console.log("Path is not a directory. Result file will be empty.")
|
||||
throw Error("Initial path given does not lead to a directory")
|
||||
}
|
||||
|
||||
// write to json file
|
||||
fs.writeFileSync(outPath, JSON.stringify(pageList) + "\n")
|
||||
/** Step 3
|
||||
* write to src/data/posts.json
|
||||
*/
|
||||
|
||||
fs.writeFileSync(`${outPath}/posts.json`, JSON.stringify(result) + "\n")
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
title:
|
||||
comment:
|
||||
licenses:
|
||||
widgets:
|
||||
article:
|
||||
author:
|
||||
---
|
||||
|
||||
Put something here
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
title: About
|
||||
author: developomp
|
||||
date: April 20, 2021
|
||||
---
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
title: games
|
||||
date: Aug 16, 2020
|
||||
author: developomp
|
||||
---
|
||||
|
||||
- [TicTacToe](/games/tictactoe)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
---
|
||||
title: goals
|
||||
date: May 11, 2021
|
||||
author: developomp
|
||||
date: 2021-05-11
|
||||
---
|
||||
|
||||
- skill
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: Quote NO.1
|
||||
date: Aug 16, 2020
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> "Get the fuck out of my lawn"
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: Quote NO.2
|
||||
date: Feb 20, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
In a Q&A session in Aalto Talk with Linus Torvalds, hosted by Aalto Center for Entrepreneurship (ACE) in Otaniemi.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: Quote NO.3
|
||||
date: March 18, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
In the introduction of one of his book: "The Future of the mind" (9th paragraph)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.1
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Let's find problems in ourselves first
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.10
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Don't forget what you planned to be
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.11
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Yesterday is a lecture for today
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.12
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Practice isn't a action. Its a formation.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.13
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Don't forget the peaks and the valleys of your life.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.14
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Those who see only the present lose their future.<br />
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.15
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> The depth of a proverb is proportional to the depth of the reader's thoughts.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.16
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Words of wisdom deepens the more you think about it.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.17
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> God didn't bless us with the best, so let's do it ourself.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.18
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> I got a purpose now, so why sit down?<br>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.19
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Finding the problem is the first step to solving anything
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.2
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Don't be great for your fame, but be famous for your greatness.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.20
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Look at the clock and wait for the next minute to come.<br>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.21
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Kill an ant. Throw it and try to find it.<br>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.22
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Lot of things learned, nothing useful.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.23
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> To give 10, one should know a 100.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.24
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Think about everything
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.25
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Challenge yourself to give your best at all time.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.26
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Escape from the valleys of life doesn't happen in an instant.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.27
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Sometimes I am amazed by the fact that I am aware of anything.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.28
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Mind is like a sword. It will be dull if you stop sharpening it.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.29
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Even if the day comes when we can live for hundreds of years, we'll still make a world where hard working is a necessity.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.3
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> If you have a proverbs, record it. Treat it as if it's a jewel. In the future, this fine gem will be the eyes of many, and a lamp to light the ways of people.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.30
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> If you think too much about the answer, you'll forget what the question was.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.31
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> People earns highest respect from me are those who appreciate critiques.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.32
|
||||
date: May 10, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Any field is fascinating as long as there are no exams.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.4
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> I don't want to call it learning that I didn't learn with my heart when I learn.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.5
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Don't define anything different from normality as a failure.
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.6
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> What did you do when everyone in the world ran?
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.7
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> The 1000 miles you've walked so far are not important. What's important is
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.8
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> Out of all the thing you've done and haven't done, which one do you regret more?
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
title: My Quote NO.9
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
tags:
|
||||
- quotes
|
||||
---
|
||||
|
||||
> People who don't know what they're talking about are the poorest people in the world.
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
"@testing-library/jest-dom": "^5.12.0",
|
||||
"@testing-library/react": "^11.2.7",
|
||||
"@testing-library/user-event": "^13.1.9",
|
||||
"dompurify": "^2.2.8",
|
||||
"gray-matter": "^4.0.3",
|
||||
"local-storage-fallback": "^4.1.2",
|
||||
"markdown-toc": "^1.2.0",
|
||||
|
|
|
@ -2,68 +2,91 @@ import React from "react"
|
|||
import marked from "marked"
|
||||
import { Helmet } from "react-helmet-async"
|
||||
|
||||
import pages from "../pages.json"
|
||||
import posts from "../data/posts.json"
|
||||
|
||||
import NotFound from "./NotFound"
|
||||
import Spinner from "../components/Spinner"
|
||||
|
||||
export default class Page extends React.Component {
|
||||
interface PageProps {}
|
||||
|
||||
interface PageState {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
fetched: any
|
||||
fetchedPage: any
|
||||
loading: boolean
|
||||
}
|
||||
|
||||
export default class Page extends React.Component<PageProps, PageState> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
fetchedPage: undefined,
|
||||
loading: true,
|
||||
}
|
||||
}
|
||||
|
||||
const fetched = pages[location.pathname.replace(/\/$/, "")] // remove a trailing slash
|
||||
if (!fetched) return
|
||||
async componentDidMount() {
|
||||
const url = location.pathname.replace(/\/$/, "")
|
||||
const fetchedPage = posts.posts[url] // remove a trailing slash
|
||||
|
||||
fetched.content = fetched?.content ? fetched.content : "No content"
|
||||
fetched.toc = fetched.meta?.toc ? fetched.meta.toc : undefined
|
||||
fetched.title = fetched.meta?.title ? fetched.meta.title : "No title"
|
||||
fetched.date = fetched.meta?.date ? fetched.meta.date : "Unknown date"
|
||||
fetched.author = fetched.meta?.author
|
||||
? fetched.meta.author
|
||||
: "Unknown author"
|
||||
if (!fetchedPage) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.fetched = fetched
|
||||
const fetched_content = (await import(`../data/posts${url}.json`))
|
||||
.content
|
||||
fetchedPage.content = fetched_content ? fetched_content : "No content"
|
||||
fetchedPage.toc = fetchedPage?.toc ? fetchedPage.toc : undefined
|
||||
fetchedPage.title = fetchedPage?.title ? fetchedPage.title : "No title"
|
||||
fetchedPage.date = fetchedPage?.date ? fetchedPage.date : "Unknown date"
|
||||
|
||||
this.setState({
|
||||
fetchedPage: fetchedPage,
|
||||
loading: false,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.fetched) return <NotFound />
|
||||
if (this.state.loading) {
|
||||
return <Spinner size={200} />
|
||||
} else {
|
||||
if (!this.state.fetchedPage) return <NotFound />
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>pomp | {this.fetched.title}</title>
|
||||
<title>pomp | {this.state.fetchedPage.title}</title>
|
||||
|
||||
<meta property="og:title" content="Page Not Found" />
|
||||
<meta
|
||||
property="og:title"
|
||||
content={this.state.fetchedPage.title}
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="http://developomp.com" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="http://developomp.com/icon/icon.svg"
|
||||
/>
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Page does not exist"
|
||||
content={`${process.env.PUBLIC_URL}/icon/icon.svg`}
|
||||
/>
|
||||
</Helmet>
|
||||
|
||||
<div className="card main-content">
|
||||
<h2>{this.fetched.title}</h2>
|
||||
<h2>{this.state.fetchedPage.title}</h2>
|
||||
<small>
|
||||
Published on {this.fetched.date} by{" "}
|
||||
{this.fetched.author}
|
||||
Published on {this.state.fetchedPage.date} by
|
||||
developomp
|
||||
</small>
|
||||
<hr />
|
||||
{
|
||||
this.fetched.toc && (
|
||||
this.state.fetchedPage.toc && (
|
||||
<>
|
||||
<div className="card">
|
||||
<strong>Table of Content:</strong>
|
||||
<div
|
||||
className="link-color"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: marked(this.fetched.toc),
|
||||
__html: marked(
|
||||
this.state.fetchedPage.toc
|
||||
),
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
|
@ -74,7 +97,7 @@ export default class Page extends React.Component {
|
|||
<div
|
||||
className="link-color"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: marked(this.fetched.content),
|
||||
__html: marked(this.state.fetchedPage.content),
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
|
@ -82,3 +105,4 @@ export default class Page extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import marked from "marked"
|
|||
import { Helmet } from "react-helmet-async"
|
||||
|
||||
import theming from "../theming"
|
||||
import pages from "../pages.json"
|
||||
import posts from "../data/posts.json"
|
||||
|
||||
const StyledPostList = styled.div`
|
||||
padding-top: 2rem;
|
||||
|
@ -50,62 +50,77 @@ const StyledPostCard = styled.div`
|
|||
padding: 10px 20px;
|
||||
`
|
||||
|
||||
interface HomeProps {
|
||||
interface PostListProps {
|
||||
title: string
|
||||
howMany?: number
|
||||
}
|
||||
|
||||
export default class PostList extends React.Component<HomeProps> {
|
||||
interface PostListState {
|
||||
howMany: number
|
||||
isLimited: boolean
|
||||
h1Text: string
|
||||
PostCards: Array<unknown> = []
|
||||
PostCards: Array<unknown>
|
||||
}
|
||||
|
||||
export default class PostList extends React.Component<
|
||||
PostListProps,
|
||||
PostListState
|
||||
> {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
let howMany = props.howMany | 0
|
||||
|
||||
const howMany = props.howMany | 0
|
||||
const isLimited = howMany ? true : false
|
||||
const h1Text = isLimited ? `${howMany} recent posts` : "All posts"
|
||||
|
||||
this.h1Text = isLimited ? `${howMany} recent posts` : "All posts"
|
||||
this.state = {
|
||||
howMany: howMany,
|
||||
isLimited: isLimited,
|
||||
h1Text: h1Text,
|
||||
PostCards: [],
|
||||
}
|
||||
}
|
||||
|
||||
for (const pagePath in pages) {
|
||||
if (isLimited && howMany <= 0) continue
|
||||
async componentDidMount() {
|
||||
const PostCards: Array<unknown> = []
|
||||
let howMany = this.state.howMany
|
||||
|
||||
const post = pages[pagePath]
|
||||
for (const postPath in posts.posts) {
|
||||
if (this.state.isLimited && howMany <= 0) continue
|
||||
const data = await import(`../data/posts${postPath}.json`)
|
||||
|
||||
this.PostCards.push(
|
||||
<StyledPostCard key={pagePath} className="card main-content">
|
||||
const post = posts.posts[postPath]
|
||||
|
||||
PostCards.push(
|
||||
<StyledPostCard key={postPath} className="card main-content">
|
||||
<StyledTitle>
|
||||
<StyledLink to={pagePath}>
|
||||
{post.meta?.title
|
||||
? post.meta.title
|
||||
: "Unknown title"}
|
||||
<StyledLink to={postPath}>
|
||||
{post?.title ? post.title : "Unknown title"}
|
||||
</StyledLink>
|
||||
</StyledTitle>
|
||||
<small>
|
||||
Published on{" "}
|
||||
{post.meta?.date ? post.meta.date : "Unknown date"} by{" "}
|
||||
{post.meta?.author
|
||||
? post.meta.author
|
||||
: "Unknown author"}
|
||||
Published on {post?.date ? post.date : "Unknown date"}
|
||||
</small>
|
||||
<hr />
|
||||
<div
|
||||
className="link-color"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: marked(
|
||||
post.content.split(" ").slice(0, 20).join(" ") +
|
||||
data.content.split(" ").slice(0, 20).join(" ") +
|
||||
"..."
|
||||
),
|
||||
}}
|
||||
></div>
|
||||
<small>
|
||||
<StyledLink to={pagePath}>Read more</StyledLink>
|
||||
<StyledLink to={postPath}>Read more</StyledLink>
|
||||
</small>
|
||||
</StyledPostCard>
|
||||
)
|
||||
howMany--
|
||||
}
|
||||
this.setState({
|
||||
PostCards: PostCards,
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -116,18 +131,16 @@ export default class PostList extends React.Component<HomeProps> {
|
|||
|
||||
<meta property="og:title" content={this.props.title} />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="http://developomp.com" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="http://developomp.com/icon/icon.svg"
|
||||
content={`${process.env.PUBLIC_URL}/icon/icon.svg`}
|
||||
/>
|
||||
<meta property="og:description" content="" />
|
||||
</Helmet>
|
||||
|
||||
<StyledPostList>
|
||||
<StyledH1>{this.h1Text}</StyledH1>
|
||||
<StyledH1>{this.state.h1Text}</StyledH1>
|
||||
<br />
|
||||
{this.PostCards}
|
||||
{this.state.PostCards}
|
||||
</StyledPostList>
|
||||
</>
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue