moving from hexo theme to my own react design
This commit is contained in:
parent
7ff3176072
commit
379c1c60d9
96 changed files with 1990 additions and 50291 deletions
1
source/.eslintignore
Normal file
1
source/.eslintignore
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules/
|
47
source/.eslintrc
Normal file
47
source/.eslintrc
Normal file
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"extends": [
|
||||
"plugin:react/recommended",
|
||||
"plugin:json/recommended",
|
||||
"prettier"
|
||||
],
|
||||
"settings": {
|
||||
"node": {
|
||||
"tryExtensions": [".js", ".jsx", ".json"]
|
||||
},
|
||||
"react": {
|
||||
"version": "17.0"
|
||||
}
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"sourceType": "module"
|
||||
},
|
||||
"plugins": ["react", "@typescript-eslint"],
|
||||
"rules": {
|
||||
"react/jsx-uses-vars": "error",
|
||||
"react/no-unknown-property": [
|
||||
"error",
|
||||
{
|
||||
"ignore": [
|
||||
"class",
|
||||
"onclick",
|
||||
"onload",
|
||||
"onsubmit",
|
||||
"crossorigin"
|
||||
]
|
||||
}
|
||||
],
|
||||
"react/react-in-jsx-scope": ["off"],
|
||||
"react/prop-types": ["off"],
|
||||
"react/display-name": ["off"],
|
||||
"react/jsx-key": ["off"],
|
||||
"react/jsx-no-target-blank": [
|
||||
"error",
|
||||
{
|
||||
"allowReferrer": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
73
source/generate.ts
Normal file
73
source/generate.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
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 removeExceptionArray = ["content", "meta"] // gray-matter creates unnecessary properties
|
||||
|
||||
let pageList: any = {} // data that will be converted to JSON string
|
||||
|
||||
// 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) {
|
||||
// ignore if file/directory name starts with a underscore
|
||||
let fileOrFolderName = filesPath.substring(filesPath.lastIndexOf("/") + 1)
|
||||
if (fileOrFolderName.startsWith("_")) return
|
||||
|
||||
// not perfect. Some filenames might cause problem.
|
||||
let stats = fs.lstatSync(filesPath) // checks if the path leads to a directory or a file
|
||||
let urlPath = `/${path.relative(dirPath, filesPath)}` // path tha will be used for url
|
||||
.replace(/\.[^/.]+$/, "") // remove .md file extension
|
||||
.replaceAll(" ", "-") // 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 (stats.isDirectory()) {
|
||||
fs.readdirSync(filesPath).map((child) =>
|
||||
addFiles(`${filesPath}/${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}`)
|
||||
return
|
||||
}
|
||||
|
||||
pageList[urlPath] = matter(fs.readFileSync(filesPath, "utf8")) // parse markdown metadata
|
||||
|
||||
// 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]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// start recursive function + check if it's a directory
|
||||
if (fs.lstatSync(dirPath).isDirectory()) {
|
||||
addFiles(dirPath)
|
||||
} else {
|
||||
console.log("Path is not a directory. Result file will be empty.")
|
||||
}
|
||||
|
||||
// write to json file
|
||||
fs.writeFileSync(outPath, JSON.stringify(pageList) + "\n")
|
10
source/markdown/_template.md
Normal file
10
source/markdown/_template.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title:
|
||||
comment:
|
||||
licenses:
|
||||
widgets:
|
||||
article:
|
||||
author:
|
||||
---
|
||||
|
||||
Put something here
|
16
source/markdown/about.md
Normal file
16
source/markdown/about.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
title: About
|
||||
author: developomp
|
||||
date: April 20, 2021
|
||||
---
|
||||
|
||||
About page
|
||||
|
||||
- about me
|
||||
|
||||
- email: developomp@gmail.com
|
||||
- discord: developomp#0001 (yes I have nitro)
|
||||
- [github profile](https://github.com/developomp)
|
||||
- me as a person
|
||||
- [goals](/goals)
|
||||
- [Portfolio](/portfolio)
|
25
source/markdown/blog/guide to arch linux.md
Normal file
25
source/markdown/blog/guide to arch linux.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
title: guide to arch linux
|
||||
author: developomp
|
||||
date: May 13, 2021
|
||||
---
|
||||
|
||||
# Guide to Arch Linux
|
||||
|
||||
## Why arch linux?
|
||||
|
||||
## Getting started
|
||||
|
||||
### Philosophy
|
||||
|
||||
### Arch wiki
|
||||
|
||||
### Command line
|
||||
|
||||
## Installation
|
||||
|
||||
## display manager
|
||||
|
||||
## window manager
|
||||
|
||||
# Conclusion
|
0
source/markdown/blog/why I write README.md
Normal file
0
source/markdown/blog/why I write README.md
Normal file
6
source/markdown/blog/work.md
Normal file
6
source/markdown/blog/work.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
학교로 갔다
|
||||
집으로 왔다
|
||||
일을 한다
|
||||
죽었다
|
||||
나는 죽었다
|
||||
나는 죽었다
|
9
source/markdown/games.md
Normal file
9
source/markdown/games.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
title: games
|
||||
date: Aug 16, 2020
|
||||
author: developomp
|
||||
---
|
||||
|
||||
- [TicTacToe](/games/tictactoe)
|
||||
- [pong](/games/pong)
|
||||
- [click](/games/click)
|
17
source/markdown/goals.md
Normal file
17
source/markdown/goals.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: goals
|
||||
date: May 11, 2021
|
||||
author: developomp
|
||||
---
|
||||
|
||||
- skill
|
||||
- type 400 letters per minute (both english and korean)
|
||||
- milestone
|
||||
- make a high quality video with at least 1M views on YouTube
|
||||
- 1000 star on a gh repository
|
||||
- completely switch to RISC based CPU powered laptop
|
||||
- project
|
||||
- create fully functional discord clone from scratch
|
||||
- make a multiplayer game that can pay for itself
|
||||
- assemble my own linux distro
|
||||
- assemble my own mechanical keyboard
|
10
source/markdown/quotes/1.md
Normal file
10
source/markdown/quotes/1.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: Quote NO.1
|
||||
date: Aug 16, 2020
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> "Get the fuck out of my lawn"
|
||||
|
||||
<div style="text-align: right"> <i>- Mahatma Ghanghi (1885)</i> </div>
|
15
source/markdown/quotes/2.md
Normal file
15
source/markdown/quotes/2.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
title: Quote NO.2
|
||||
date: Feb 20, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
In a Q&A session in Aalto Talk with Linus Torvalds, hosted by Aalto Center for Entrepreneurship (ACE) in Otaniemi.
|
||||
|
||||
<div style="padding: 56.25% 0px 0px; position: relative;"><iframe src="https://www.youtube.com/embed/MShbP3OpASA?cc_load_policy=1&end=3005&iv_load_policy=3&rel=0&start=2993" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen scrolling="no" style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%;"></iframe></div>
|
||||
<br>
|
||||
|
||||
> "Nvidia, Fuck you!"
|
||||
|
||||
<div style="text-align: right"> <i>- Linus Torvalds (2012)</i> </div>
|
12
source/markdown/quotes/3.md
Normal file
12
source/markdown/quotes/3.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: Quote NO.3
|
||||
date: March 18, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
In the introduction of one of his book: "The Future of the mind" (9th paragraph)
|
||||
|
||||
> "To fathom the greatest secrets in the universe, one did not need telepathic or superhuman abilities. One just had to have a open, determined, and and curious mind."
|
||||
|
||||
<div style="text-align: right"> <i>- Michio Kaku (2014)</i> </div>
|
15
source/markdown/quotes/me/1.md
Normal file
15
source/markdown/quotes/me/1.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
title: My Quote NO.1
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Let's find problems in ourselves first
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
||||
|
||||
To fix a problem, one should first understand the problem.
|
||||
If one tries to fix what is not the problem, it will make the problem worse, or make another problem.
|
||||
And the first place to look for problems is not other than ourselves.
|
||||
Because often times, solution to our problems turns out to be, or in ourselves.<br>
|
10
source/markdown/quotes/me/10.md
Executable file
10
source/markdown/quotes/me/10.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.10
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Don't forget what you planned to be
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/11.md
Executable file
10
source/markdown/quotes/me/11.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.11
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Yesterday is a lecture for today
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/12.md
Executable file
10
source/markdown/quotes/me/12.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.12
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Practice isn't a action. Its a formation.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/13.md
Executable file
10
source/markdown/quotes/me/13.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.13
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Don't forget the peaks and the valleys of your life.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
12
source/markdown/quotes/me/14.md
Executable file
12
source/markdown/quotes/me/14.md
Executable file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: My Quote NO.14
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Those who see only the present lose their future.<br />
|
||||
> Those who see only the future lose both the present and the future. <br />
|
||||
> Only those who can see both the present and the future are given the future.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/15.md
Executable file
10
source/markdown/quotes/me/15.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.15
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> The depth of a proverb is proportional to the depth of the reader's thoughts.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/16.md
Executable file
10
source/markdown/quotes/me/16.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.16
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Words of wisdom deepens the more you think about it.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/17.md
Executable file
10
source/markdown/quotes/me/17.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.17
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> God didn't bless us with the best, so let's do it ourself.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
11
source/markdown/quotes/me/18.md
Executable file
11
source/markdown/quotes/me/18.md
Executable file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: My Quote NO.18
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> I got a purpose now, so why sit down?<br>
|
||||
> I got ceilings to break and things to do.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/19.md
Executable file
10
source/markdown/quotes/me/19.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.19
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Finding the problem is the first step to solving anything
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/2.md
Normal file
10
source/markdown/quotes/me/2.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.2
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Don't be great for your fame, but be famous for your greatness.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
11
source/markdown/quotes/me/20.md
Executable file
11
source/markdown/quotes/me/20.md
Executable file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: My Quote NO.20
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Look at the clock and wait for the next minute to come.<br>
|
||||
> You'll see the preciousness of time.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
11
source/markdown/quotes/me/21.md
Executable file
11
source/markdown/quotes/me/21.md
Executable file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: My Quote NO.21
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Kill an ant. Throw it and try to find it.<br>
|
||||
> That's how almost all life ended. Forgotten.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/22.md
Executable file
10
source/markdown/quotes/me/22.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.22
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Lot of things learned, nothing useful.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
11
source/markdown/quotes/me/23.md
Executable file
11
source/markdown/quotes/me/23.md
Executable file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: My Quote NO.23
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> To give 10, one should know a 100.
|
||||
> So when someone gives a 10, don't think he's in the same level as you.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/24.md
Executable file
10
source/markdown/quotes/me/24.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.24
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Think about everything
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/25.md
Normal file
10
source/markdown/quotes/me/25.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.25
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Challenge yourself to give your best at all time.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/26.md
Normal file
10
source/markdown/quotes/me/26.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.26
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Escape from the valleys of life doesn't happen in an instant.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
13
source/markdown/quotes/me/27.md
Normal file
13
source/markdown/quotes/me/27.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: My Quote NO.27
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Sometimes I am amazed by the fact that I am aware of anything.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
||||
|
||||
Learning about AI
|
||||
This folded sheet of protein is capable to understand the laws that govern the universe
|
10
source/markdown/quotes/me/28.md
Normal file
10
source/markdown/quotes/me/28.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.28
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Mind is like a sword. It will be dull if you stop sharpening it.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/29.md
Normal file
10
source/markdown/quotes/me/29.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.29
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> 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.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/3.md
Normal file
10
source/markdown/quotes/me/3.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.3
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> 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.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/30.md
Normal file
10
source/markdown/quotes/me/30.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.30
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> If you think too much about the answer, you'll forget what the question was.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/31.md
Normal file
10
source/markdown/quotes/me/31.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.31
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> People earns highest respect from me are those who appreciate critiques.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2020</i> </div>
|
10
source/markdown/quotes/me/32.md
Normal file
10
source/markdown/quotes/me/32.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.32
|
||||
date: May 10, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Any field is fascinating as long as there are no exams.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2021</i> </div>
|
15
source/markdown/quotes/me/4.md
Normal file
15
source/markdown/quotes/me/4.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
title: My Quote NO.4
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> I don't want to call it learning that I didn't learn with my heart when I learn.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
||||
|
||||
When we learn in school, we systematically memorize and recite information and immediately forget everything after an exam.
|
||||
Some of us may remember some of it, but most of us don't remember most of the information we were taught.
|
||||
I don't want to call that learning. Learning for me is when I know that topic of that subject by heart.
|
||||
Something that you don't just get information, but the spirit of it too.
|
10
source/markdown/quotes/me/5.md
Normal file
10
source/markdown/quotes/me/5.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.5
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Don't define anything different from normality as a failure.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
10
source/markdown/quotes/me/6.md
Normal file
10
source/markdown/quotes/me/6.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.6
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> What did you do when everyone in the world ran?
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
11
source/markdown/quotes/me/7.md
Executable file
11
source/markdown/quotes/me/7.md
Executable file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: My Quote NO.7
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> The 1000 miles you've walked so far are not important. What's important is
|
||||
> that you still have the will to walk another mile.
|
||||
|
||||
<div style="text-align: right"><i>- developomp 2019</i></div>
|
15
source/markdown/quotes/me/8.md
Executable file
15
source/markdown/quotes/me/8.md
Executable file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
title: My Quote NO.8
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> Out of all the thing you've done and haven't done, which one do you regret more?
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
||||
|
||||
Many people regret not doing something
|
||||
...
|
||||
To them I want to ask this one question:
|
||||
"So, what are the things you need to do now?"
|
10
source/markdown/quotes/me/9.md
Executable file
10
source/markdown/quotes/me/9.md
Executable file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: My Quote NO.9
|
||||
date: March 22, 2021
|
||||
tags: quotes
|
||||
author: developomp
|
||||
---
|
||||
|
||||
> People who don't know what they're talking about are the poorest people in the world.
|
||||
|
||||
<div style="text-align: right"> <i>- developomp 2019</i> </div>
|
82
source/package.json
Normal file
82
source/package.json
Normal file
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
"name": "developomp-site",
|
||||
"version": "1.0.0",
|
||||
"description": "website source for https://developomp.com",
|
||||
"author": "developomp <developomp@gmail.com>",
|
||||
"homepage": ".",
|
||||
"repository": "https://github.com/developomp/developomp-site.git",
|
||||
"bugs": {
|
||||
"url": "https://github.com/developomp/developomp-site/issues"
|
||||
},
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"generate": "ts-node -O '{\"module\":\"commonjs\"}' ./generate.ts",
|
||||
"start": "yarn generate && react-scripts start",
|
||||
"build": "yarn generate && react-scripts build",
|
||||
"test": "yarn generate && react-scripts test",
|
||||
"pretty": "yarn generate && prettier --write ./source"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
||||
"@testing-library/jest-dom": "^5.12.0",
|
||||
"@testing-library/react": "^11.2.6",
|
||||
"@testing-library/user-event": "^13.1.8",
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/react": "^17.0.5",
|
||||
"@types/react-dom": "^17.0.4",
|
||||
"dompurify": "^2.2.8",
|
||||
"gray-matter": "^4.0.3",
|
||||
"local-storage-fallback": "^4.1.2",
|
||||
"markdown-toc": "^1.2.0",
|
||||
"marked": "^2.0.3",
|
||||
"react": "^17.0.2",
|
||||
"react-burger-menu": "^3.0.6",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-spinners": "^0.10.6",
|
||||
"react-tooltip": "^4.2.19",
|
||||
"styled-components": "^5.3.0",
|
||||
"styled-theming": "^2.2.0",
|
||||
"web-vitals": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^15.0.2",
|
||||
"@types/styled-components": "^5.1.9",
|
||||
"@types/styled-theming": "^2.2.5",
|
||||
"@typescript-eslint/eslint-plugin": "^4.23.0",
|
||||
"@typescript-eslint/parser": "^4.23.0",
|
||||
"eslint": "^7.26.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-json": "^3.0.0",
|
||||
"eslint-plugin-react": "^7.23.2",
|
||||
"prettier": "^2.3.0",
|
||||
"ts-node": "^9.1.1",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"typescript": "^4.2.4"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
8
source/src/App.test.tsx
Normal file
8
source/src/App.test.tsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { render } from "@testing-library/react"
|
||||
import App from "./App"
|
||||
|
||||
test("renders content", () => {
|
||||
const { getByTestId } = render(<App />)
|
||||
const content = getByTestId("content")
|
||||
expect(content).toBeInTheDocument()
|
||||
})
|
212
source/src/App.tsx
Normal file
212
source/src/App.tsx
Normal file
|
@ -0,0 +1,212 @@
|
|||
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
|
||||
import { ThemeProvider, createGlobalStyle, css } from "styled-components"
|
||||
import storage from "local-storage-fallback"
|
||||
import { useState, useEffect } from "react"
|
||||
import theme from "styled-theming"
|
||||
import Loader from "react-spinners/HashLoader"
|
||||
|
||||
import theming from "./theming"
|
||||
|
||||
import Navbar from "./components/Navbar"
|
||||
import Footer from "./components/Footer"
|
||||
|
||||
import Home from "./pages/home"
|
||||
import Page from "./pages/page"
|
||||
import NotFound from "./pages/notfound"
|
||||
import Portfolio from "./pages/portfolio"
|
||||
|
||||
// Theme that will be used throughout the website
|
||||
const GlobalStyle = createGlobalStyle`
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
html, body, #root {
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: ${theme("mode", {
|
||||
light: theming.light.backgroundColor1,
|
||||
dark: theming.dark.backgroundColor1,
|
||||
})};
|
||||
color: ${theme("mode", {
|
||||
light: theming.light.color1,
|
||||
dark: theming.dark.color1,
|
||||
})};
|
||||
font-size: ${theming.size.medium};
|
||||
font-family: ${theming.font.regular};
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar {
|
||||
width: ${theming.size.x_small};
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar-track {
|
||||
border-radius: ${theming.size.x2_small};
|
||||
background: rgba(0,0,0,0.06);
|
||||
box-shadow: inset 0 0 5px rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
body::-webkit-scrollbar-thumb {
|
||||
border-radius: ${theming.size.x2_small};
|
||||
background: rgba(0,0,0,0.1);
|
||||
box-shadow: inset 0 0 10px rgb(0 0 0 / 20%);
|
||||
}
|
||||
|
||||
#content {
|
||||
display:inline-block;
|
||||
flex: 1 1 auto;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: ${theming.font.code};
|
||||
}
|
||||
|
||||
.link-color a {
|
||||
text-decoration: none;
|
||||
color: ${theming.color.linkColor};
|
||||
|
||||
&:visited {
|
||||
color: ${theming.color.linkColor};
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
background-color: rgba(0, 0, 0, 5%);
|
||||
border-left: 0.4rem solid rgba(0, 0, 0, 10%);
|
||||
padding-top: 0.1rem;
|
||||
padding-right: 1rem;
|
||||
padding-bottom: 0.1rem;
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: auto;
|
||||
background-color: ${theme("mode", {
|
||||
light: "white",
|
||||
dark: "#2F3136",
|
||||
})};
|
||||
padding: 2rem;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 10px rgb(0 0 0 / 5%), 0 0 1px rgb(0 0 0 / 10%);
|
||||
|
||||
@media screen and (max-width: ${theming.size.screen_size1}) {
|
||||
& {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-top: 3rem;
|
||||
width: 50%;
|
||||
|
||||
@media screen and (max-width: ${theming.size.screen_size1}) {
|
||||
& {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
transition: color 0.1s linear;
|
||||
}
|
||||
`
|
||||
|
||||
// the loader is not compatible with styled-components so I'm converting it to string.
|
||||
// doing this gives intellisense and stuff in my IDE
|
||||
const LoaderStyle = css`
|
||||
position: absolute;
|
||||
top: 0%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 50%);
|
||||
`.toString()
|
||||
|
||||
function App() {
|
||||
const [usingTheme, _setTheme] = useState(() => {
|
||||
const savedTheme = storage.getItem("theme")
|
||||
return savedTheme ? JSON.parse(savedTheme) : { mode: "dark" }
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
storage.setItem("theme", JSON.stringify(usingTheme))
|
||||
}, [usingTheme])
|
||||
|
||||
const [isLoading, setLoading] = useState(true)
|
||||
|
||||
// show loading screen until all fonts are loaded.
|
||||
// Experimental feature. Not fully supported on all browsers (ehem IE ehem).
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet
|
||||
useEffect(() => {
|
||||
// checks if document.fonts.onloadingdone is supported on the browser
|
||||
if (typeof document.fonts.onloadingdone != undefined) {
|
||||
document.fonts.onloadingdone = (_: EventListener) => {
|
||||
setLoading(false)
|
||||
}
|
||||
} else {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
theme={{
|
||||
...usingTheme,
|
||||
setTheme: ({ setTheme, ...theme }) => _setTheme(theme),
|
||||
}}
|
||||
>
|
||||
<GlobalStyle />
|
||||
<Router>
|
||||
<Navbar />
|
||||
<div id="content">
|
||||
{isLoading ? (
|
||||
<Loader
|
||||
color={
|
||||
usingTheme.mode == "light"
|
||||
? theming.light.color1
|
||||
: theming.dark.color1
|
||||
}
|
||||
css={LoaderStyle}
|
||||
size={200}
|
||||
/>
|
||||
) : (
|
||||
<Switch>
|
||||
<Route
|
||||
exact
|
||||
path="/"
|
||||
component={() => (
|
||||
<Home howMany={4} title="Home" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/archives"
|
||||
component={() => <Home title="Archives" />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/portfolio"
|
||||
component={Portfolio}
|
||||
/>
|
||||
<Route exact path="/404" component={NotFound} />
|
||||
<Route exact path="/:path*" component={Page} />
|
||||
</Switch>
|
||||
)}
|
||||
</div>
|
||||
<Footer />
|
||||
</Router>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
66
source/src/components/Footer.tsx
Normal file
66
source/src/components/Footer.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import { faGithub } from "@fortawesome/free-brands-svg-icons"
|
||||
import styled from "styled-components"
|
||||
import theme from "styled-theming"
|
||||
import { HashRouter as Router, Link } from "react-router-dom"
|
||||
|
||||
const StyledFooter = styled.footer`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1px; /* footer goes outside the page by 1 px for some reason */
|
||||
padding: 50px 10px;
|
||||
background-color: white;
|
||||
background-color: ${theme("mode", {
|
||||
light: "white",
|
||||
dark: "black",
|
||||
})};
|
||||
color: ${theme("mode", {
|
||||
light: "black",
|
||||
dark: "white",
|
||||
})};
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.logo {
|
||||
color: gray;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledLink = styled.a`
|
||||
width: 30px;
|
||||
font-size: 2rem;
|
||||
color: ${theme("mode", {
|
||||
light: "lightgrey",
|
||||
dark: "grey",
|
||||
})};
|
||||
|
||||
&:hover {
|
||||
color: ${theme("mode", {
|
||||
light: "black",
|
||||
dark: "white",
|
||||
})};
|
||||
}
|
||||
`
|
||||
|
||||
function Footer() {
|
||||
return (
|
||||
<StyledFooter>
|
||||
<div className="logo">
|
||||
Copyright © <strong>develo</strong>pomp
|
||||
</div>
|
||||
|
||||
<Router className="icons">
|
||||
<StyledLink
|
||||
href="https://github.com/developomp/developomp-site"
|
||||
target="_blank"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
</StyledLink>
|
||||
</Router>
|
||||
</StyledFooter>
|
||||
)
|
||||
}
|
||||
|
||||
export default Footer
|
100
source/src/components/Navbar.tsx
Normal file
100
source/src/components/Navbar.tsx
Normal file
|
@ -0,0 +1,100 @@
|
|||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import { faGithub } from "@fortawesome/free-brands-svg-icons"
|
||||
import styled, { ThemeConsumer } from "styled-components"
|
||||
import theme from "styled-theming"
|
||||
import ReactTooltip from "react-tooltip"
|
||||
import NavbarData from "../data/NavbarData"
|
||||
import theming from "../theming"
|
||||
|
||||
import { Link } from "react-router-dom"
|
||||
import SearchBox from "./SearchBox"
|
||||
import Sidebar from "./Sidebar"
|
||||
import ThemeToggleButton from "./ThemeToggleButton"
|
||||
import { faLanguage } from "@fortawesome/free-solid-svg-icons"
|
||||
|
||||
const StyledNav = styled.nav`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 2rem;
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
background-color: ${theme("mode", {
|
||||
light: theming.light.backgroundColor0,
|
||||
dark: theming.dark.backgroundColor0,
|
||||
})};
|
||||
color: ${theme("mode", {
|
||||
light: theming.light.color0,
|
||||
dark: theming.dark.color0,
|
||||
})};
|
||||
box-shadow: 0 4px 10px rgb(0 0 0 / 5%);
|
||||
|
||||
.right {
|
||||
margin-left: auto;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledNavLinks = styled.div`
|
||||
@media only screen and (max-width: ${theming.size.screen_size1}) {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledImg = styled.img`
|
||||
height: 2rem;
|
||||
margin: 1rem;
|
||||
`
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
${theming.styles.navbarButtonStyle}
|
||||
`
|
||||
|
||||
const StyledALink = styled.a`
|
||||
${theming.styles.navbarButtonStyle}
|
||||
`
|
||||
|
||||
function Navbar() {
|
||||
return (
|
||||
<StyledNav>
|
||||
<Link to="/">
|
||||
<StyledImg
|
||||
src={process.env.PUBLIC_URL + "/icon/icon_circle.svg"}
|
||||
/>
|
||||
</Link>
|
||||
<StyledNavLinks>
|
||||
{NavbarData.map((item, index) => {
|
||||
return (
|
||||
<StyledLink key={index} to={item.path}>
|
||||
{item.title}
|
||||
</StyledLink>
|
||||
)
|
||||
})}
|
||||
</StyledNavLinks>
|
||||
|
||||
<ThemeToggleButton />
|
||||
|
||||
<StyledALink data-tip data-for="language">
|
||||
<FontAwesomeIcon icon={faLanguage} />
|
||||
</StyledALink>
|
||||
<ReactTooltip id="language" type="dark" effect="solid">
|
||||
<span>Change to Korean/English</span>
|
||||
</ReactTooltip>
|
||||
|
||||
<StyledALink
|
||||
data-tip
|
||||
data-for="github"
|
||||
href="https://github.com/developomp/developomp-site"
|
||||
target="_blank"
|
||||
>
|
||||
<FontAwesomeIcon icon={faGithub} />
|
||||
</StyledALink>
|
||||
<ReactTooltip id="github" type="dark" effect="solid">
|
||||
<span>View source code</span>
|
||||
</ReactTooltip>
|
||||
|
||||
<SearchBox />
|
||||
<Sidebar />
|
||||
</StyledNav>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar
|
51
source/src/components/SearchBox.tsx
Normal file
51
source/src/components/SearchBox.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import { faSearch } from "@fortawesome/free-solid-svg-icons"
|
||||
import styled, { ThemeConsumer, css } from "styled-components"
|
||||
import theme from "styled-theming"
|
||||
|
||||
const StyledSearchBoxContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
background-color: ${theme("mode", {
|
||||
light: "white",
|
||||
dark: "#202225",
|
||||
})};
|
||||
color: ${theme("mode", {
|
||||
light: "black",
|
||||
dark: "#CFD0D0",
|
||||
})};
|
||||
|
||||
&:hover {
|
||||
background-color: ${theme("mode", {
|
||||
light: "whitesmoke",
|
||||
dark: "#36393F",
|
||||
})};
|
||||
}
|
||||
`
|
||||
|
||||
const StyledSearchBox = styled.input`
|
||||
width: 80%;
|
||||
border: none;
|
||||
border-right: 1rem;
|
||||
outline: none;
|
||||
padding: 10px 10px;
|
||||
text-decoration: none;
|
||||
background-color: inherit;
|
||||
color: inherit;
|
||||
`
|
||||
|
||||
const StyledSearchButton = styled(FontAwesomeIcon)`
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
function Navbar() {
|
||||
return (
|
||||
<StyledSearchBoxContainer>
|
||||
<StyledSearchBox type="text" name="search" placeholder="Search" />
|
||||
<StyledSearchButton icon={faSearch} />
|
||||
</StyledSearchBoxContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar
|
124
source/src/components/Sidebar.tsx
Normal file
124
source/src/components/Sidebar.tsx
Normal file
|
@ -0,0 +1,124 @@
|
|||
import { useEffect, useState } from "react"
|
||||
import styled, { css } from "styled-components"
|
||||
import NavbarData from "../data/NavbarData"
|
||||
import theme from "styled-theming"
|
||||
import ReactTooltip from "react-tooltip"
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import { faEllipsisV, faTimes } from "@fortawesome/free-solid-svg-icons"
|
||||
|
||||
import theming from "../theming"
|
||||
import SubMenu from "./SubMenu"
|
||||
|
||||
interface StateProps {
|
||||
isSidebarOpen: boolean
|
||||
}
|
||||
|
||||
const CommonSidebarToggleButtonStyle = css`
|
||||
${theming.styles.navbarButtonStyle}
|
||||
font-size: "1.5rem";
|
||||
width: 1.5rem;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
margin: 0.1rem;
|
||||
@media only screen and (min-width: ${theming.size.screen_size1}) {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledToggleSidebarButton = styled.div`
|
||||
${CommonSidebarToggleButtonStyle}
|
||||
`
|
||||
|
||||
const StyledToggleSidebarButton2 = styled.div`
|
||||
${CommonSidebarToggleButtonStyle}
|
||||
border-radius: 0;
|
||||
margin: auto;
|
||||
width: 90%;
|
||||
height: 2rem;
|
||||
font-size: 1.1rem;
|
||||
`
|
||||
|
||||
const StyledOverlay = styled.div<StateProps>`
|
||||
display: ${(props) => (props.isSidebarOpen ? "block" : "none")};
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 20;
|
||||
transition-property: opacity;
|
||||
background-color: rgba(0, 0, 0, 25%);
|
||||
|
||||
* {
|
||||
overflow: scroll;
|
||||
}
|
||||
`
|
||||
|
||||
const SidebarNav = styled.nav<StateProps>`
|
||||
width: 250px;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: ${(props) => (props.isSidebarOpen ? "0" : "-100%")};
|
||||
transition: 350ms;
|
||||
z-index: 30;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
background-color: ${theme("mode", {
|
||||
light: theming.light.backgroundColor0,
|
||||
dark: theming.dark.backgroundColor0,
|
||||
})};
|
||||
color: ${theme("mode", {
|
||||
light: theming.light.color0,
|
||||
dark: theming.dark.color0,
|
||||
})};
|
||||
`
|
||||
|
||||
const SidebarWrap = styled.div`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
const Sidebar = () => {
|
||||
const [isSidebarOpen, setSidebar] = useState(false)
|
||||
|
||||
function toggleSidebar() {
|
||||
setSidebar(!isSidebarOpen)
|
||||
document.body.style.overflow = isSidebarOpen ? "scroll" : "hidden"
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledOverlay
|
||||
isSidebarOpen={isSidebarOpen}
|
||||
onClick={toggleSidebar}
|
||||
/>
|
||||
|
||||
<StyledToggleSidebarButton
|
||||
data-tip
|
||||
data-for="sidebar"
|
||||
onClick={toggleSidebar}
|
||||
>
|
||||
<FontAwesomeIcon icon={faEllipsisV}></FontAwesomeIcon>
|
||||
<ReactTooltip id="sidebar" type="dark" effect="solid">
|
||||
<span>open sidebar</span>
|
||||
</ReactTooltip>
|
||||
</StyledToggleSidebarButton>
|
||||
|
||||
<SidebarNav isSidebarOpen={isSidebarOpen}>
|
||||
<SidebarWrap>
|
||||
<StyledToggleSidebarButton2 onClick={toggleSidebar}>
|
||||
<FontAwesomeIcon icon={faTimes}></FontAwesomeIcon> Close
|
||||
</StyledToggleSidebarButton2>
|
||||
{NavbarData.map((item, index) => {
|
||||
return <SubMenu item={item} key={index} />
|
||||
})}
|
||||
</SidebarWrap>
|
||||
</SidebarNav>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Sidebar
|
74
source/src/components/SubMenu.tsx
Normal file
74
source/src/components/SubMenu.tsx
Normal file
|
@ -0,0 +1,74 @@
|
|||
import { useState } from "react"
|
||||
import { Link } from "react-router-dom"
|
||||
import styled from "styled-components"
|
||||
import theming from "../theming"
|
||||
|
||||
const SidebarLink = styled(Link)`
|
||||
${theming.styles.navbarButtonStyle};
|
||||
display: flex;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
justify-content: space-between;
|
||||
height: 2rem;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
list-style: none;
|
||||
`
|
||||
|
||||
const SidebarLabel = styled.span`
|
||||
margin-left: 16px;
|
||||
`
|
||||
|
||||
const DropdownLink = styled(Link)`
|
||||
background: #414757;
|
||||
height: 60px;
|
||||
padding-left: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: #f5f5f5;
|
||||
font-size: 18px;
|
||||
|
||||
&:hover {
|
||||
background: #632ce4;
|
||||
cursor: pointer;
|
||||
}
|
||||
`
|
||||
|
||||
function SubMenu({ item }) {
|
||||
const [isSubNavOpen, setSubNav] = useState(false)
|
||||
|
||||
const showSubNav = () => setSubNav(!isSubNavOpen)
|
||||
|
||||
return (
|
||||
<>
|
||||
<SidebarLink to={item.path} onClick={item.subNav && showSubNav}>
|
||||
<div>
|
||||
{item.icon}
|
||||
<SidebarLabel>{item.title}</SidebarLabel>
|
||||
</div>
|
||||
<div>
|
||||
{item.subNav && isSubNavOpen
|
||||
? item.iconOpened
|
||||
: item.subNav
|
||||
? item.iconClosed
|
||||
: null}
|
||||
</div>
|
||||
</SidebarLink>
|
||||
|
||||
{/* not used as of the moment */}
|
||||
{isSubNavOpen &&
|
||||
item.subNav.map((item, index) => {
|
||||
return (
|
||||
<DropdownLink to={item.path} key={index}>
|
||||
{item.icon}
|
||||
<SidebarLabel>{item.title}</SidebarLabel>
|
||||
</DropdownLink>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default SubMenu
|
50
source/src/components/ThemeToggleButton.tsx
Normal file
50
source/src/components/ThemeToggleButton.tsx
Normal file
|
@ -0,0 +1,50 @@
|
|||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import { faAdjust } from "@fortawesome/free-solid-svg-icons"
|
||||
import styled, { ThemeConsumer } from "styled-components"
|
||||
import theme from "styled-theming"
|
||||
|
||||
import ReactTooltip from "react-tooltip"
|
||||
|
||||
import theming from "../theming"
|
||||
|
||||
const StyledThemeButton = styled.div`
|
||||
${theming.styles.navbarButtonStyle}
|
||||
transition: transform 0.2s linear;
|
||||
${theme("mode", {
|
||||
light: "",
|
||||
dark: "transform: scaleX(-1);\
|
||||
-moz-transform: scaleX(-1);\
|
||||
-webkit-transform: scaleX(-1);\
|
||||
-ms-transform: scaleX(-1);",
|
||||
})};
|
||||
`
|
||||
|
||||
function Navbar() {
|
||||
return (
|
||||
<ThemeConsumer>
|
||||
{(_theme) => (
|
||||
<>
|
||||
<StyledThemeButton
|
||||
data-tip
|
||||
data-for="theme"
|
||||
className="right"
|
||||
onClick={(_: any) =>
|
||||
_theme.setTheme(
|
||||
_theme.mode === "dark"
|
||||
? { ..._theme, mode: "light" }
|
||||
: { ..._theme, mode: "dark" }
|
||||
)
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon icon={faAdjust} />
|
||||
</StyledThemeButton>
|
||||
<ReactTooltip id="theme" type="dark" effect="solid">
|
||||
<span>Change theme</span>
|
||||
</ReactTooltip>
|
||||
</>
|
||||
)}
|
||||
</ThemeConsumer>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar
|
42
source/src/data/NavbarData.tsx
Normal file
42
source/src/data/NavbarData.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
import {
|
||||
faHome,
|
||||
faArchive,
|
||||
faUserTie,
|
||||
faHashtag,
|
||||
faListUl,
|
||||
faHiking,
|
||||
} from "@fortawesome/free-solid-svg-icons"
|
||||
|
||||
export default [
|
||||
{
|
||||
title: "Home",
|
||||
path: "/",
|
||||
icon: <FontAwesomeIcon icon={faHome} />,
|
||||
},
|
||||
{
|
||||
title: "Archives",
|
||||
path: "/archives",
|
||||
icon: <FontAwesomeIcon icon={faArchive} />,
|
||||
},
|
||||
{
|
||||
title: "Categories",
|
||||
path: "/categories",
|
||||
icon: <FontAwesomeIcon icon={faListUl} />,
|
||||
},
|
||||
{
|
||||
title: "Tags",
|
||||
path: "/tags",
|
||||
icon: <FontAwesomeIcon icon={faHashtag} />,
|
||||
},
|
||||
{
|
||||
title: "Explore",
|
||||
path: "/explore",
|
||||
icon: <FontAwesomeIcon icon={faHiking} />,
|
||||
},
|
||||
{
|
||||
title: "Portfolio",
|
||||
path: "/portfolio",
|
||||
icon: <FontAwesomeIcon icon={faUserTie} />,
|
||||
},
|
||||
]
|
14
source/src/index.tsx
Normal file
14
source/src/index.tsx
Normal file
|
@ -0,0 +1,14 @@
|
|||
import React from "react"
|
||||
import ReactDOM from "react-dom"
|
||||
|
||||
import App from "./App"
|
||||
import reportWebVitals from "./reportWebVitals"
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById("root")
|
||||
)
|
||||
|
||||
reportWebVitals()
|
118
source/src/pages/home.tsx
Normal file
118
source/src/pages/home.tsx
Normal file
|
@ -0,0 +1,118 @@
|
|||
import { Link } from "react-router-dom"
|
||||
import styled from "styled-components"
|
||||
import theme from "styled-theming"
|
||||
import marked from "marked"
|
||||
import Helmet from "react-helmet"
|
||||
|
||||
import pages from "../pages.json"
|
||||
|
||||
const StyledPostList = styled.div`
|
||||
padding-top: 2rem;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
color: ${theme("mode", {
|
||||
light: "#111111",
|
||||
dark: "#EEEEEE",
|
||||
})};
|
||||
`
|
||||
|
||||
const StyledH1 = styled.h1`
|
||||
margin-bottom: 20px;
|
||||
font-weight: 500;
|
||||
margin: 0;
|
||||
`
|
||||
|
||||
const StyledTitle = styled.h1`
|
||||
font-size: 2rem;
|
||||
font-style: bold;
|
||||
`
|
||||
|
||||
const StyledLink = styled(Link)`
|
||||
text-decoration: none;
|
||||
|
||||
color: ${theme("mode", {
|
||||
light: "black",
|
||||
dark: "white",
|
||||
})};
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`
|
||||
|
||||
const StyledPostCard = styled.div`
|
||||
box-shadow: 0 4px 10px rgb(0 0 0 / 10%);
|
||||
text-align: left;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 20px;
|
||||
`
|
||||
|
||||
function Home(props) {
|
||||
let PostCards: Array<any> = []
|
||||
let howMany = props.howMany
|
||||
let isLimited = Boolean(howMany)
|
||||
|
||||
let h1Text = "All posts"
|
||||
if (isLimited) {
|
||||
h1Text = `${howMany} recent posts`
|
||||
}
|
||||
|
||||
for (const pagePath in pages) {
|
||||
if (isLimited && howMany <= 0) continue
|
||||
|
||||
let post = pages[pagePath]
|
||||
post.title = post.meta?.title ? post.meta.title : "Unknown title"
|
||||
post.date = post.meta?.date ? post.meta.date : "Unknown date"
|
||||
post.author = post.meta?.author ? post.meta.author : "Unknown author"
|
||||
|
||||
PostCards.push(
|
||||
<StyledPostCard key={pagePath} className="card main-content">
|
||||
<StyledTitle>
|
||||
<StyledLink to={pagePath}>{post.title}</StyledLink>
|
||||
</StyledTitle>
|
||||
<small>
|
||||
Published on {post.date} by {post.author}
|
||||
</small>
|
||||
<hr />
|
||||
<div
|
||||
className="link-color"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: marked(
|
||||
post.content.split(" ").slice(0, 20).join(" ") +
|
||||
"..."
|
||||
),
|
||||
}}
|
||||
></div>
|
||||
<small>
|
||||
<StyledLink to={pagePath}>Read more</StyledLink>
|
||||
</small>
|
||||
</StyledPostCard>
|
||||
)
|
||||
howMany--
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>pomp | {props.title}</title>
|
||||
|
||||
<meta property="og:title" content={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"
|
||||
/>
|
||||
<meta property="og:description" content="" />
|
||||
</Helmet>
|
||||
|
||||
<StyledPostList>
|
||||
<StyledH1>{h1Text}</StyledH1>
|
||||
<br />
|
||||
{PostCards}
|
||||
</StyledPostList>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
42
source/src/pages/notfound.tsx
Normal file
42
source/src/pages/notfound.tsx
Normal file
|
@ -0,0 +1,42 @@
|
|||
import styled from "styled-components"
|
||||
import theme from "styled-theming"
|
||||
import Helmet from "react-helmet"
|
||||
|
||||
const StyledNotFound = styled.div`
|
||||
margin: auto;
|
||||
margin-top: 2rem;
|
||||
text-align: center;
|
||||
color: ${theme("mode", {
|
||||
light: "#111111",
|
||||
dark: "#EEEEEE",
|
||||
})};
|
||||
`
|
||||
|
||||
const Styled404 = styled.h1`
|
||||
font-size: 3rem;
|
||||
`
|
||||
|
||||
function NotFound() {
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>pomp | 404</title>
|
||||
|
||||
<meta property="og:title" content="Page Not Found" />
|
||||
<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" />
|
||||
</Helmet>
|
||||
<StyledNotFound className="card main-content">
|
||||
<Styled404>404</Styled404>
|
||||
the page you are looking for does not exist. :(
|
||||
</StyledNotFound>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotFound
|
71
source/src/pages/page.tsx
Normal file
71
source/src/pages/page.tsx
Normal file
|
@ -0,0 +1,71 @@
|
|||
import marked from "marked"
|
||||
import NotFound from "./notfound"
|
||||
import Helmet from "react-helmet"
|
||||
|
||||
import pages from "../pages.json"
|
||||
import { useParams } from "react-router-dom"
|
||||
|
||||
function Page() {
|
||||
const path = `/${useParams().path}`
|
||||
let fetched = pages[path]
|
||||
if (!fetched) return <NotFound />
|
||||
|
||||
// to prevent wrapping. I don't want to touch prettier stuff
|
||||
const idk = "Unknown"
|
||||
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 : `${idk} date`
|
||||
fetched.author = fetched.meta?.author
|
||||
? fetched.meta.author
|
||||
: `${idk} author`
|
||||
|
||||
const TableOfContents = fetched.toc && (
|
||||
<>
|
||||
<div className="card">
|
||||
<strong>Table of Content:</strong>
|
||||
<div
|
||||
className="link-color"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: marked(fetched.toc),
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<hr />
|
||||
</>
|
||||
) // add toc if it exists
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>pomp | {fetched.title}</title>
|
||||
|
||||
<meta property="og:title" content="Page Not Found" />
|
||||
<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" />
|
||||
</Helmet>
|
||||
|
||||
<div className="card main-content">
|
||||
<h2>{fetched.title}</h2>
|
||||
<small>
|
||||
Published on {fetched.date} by {fetched.author}
|
||||
</small>
|
||||
<hr />
|
||||
{TableOfContents}
|
||||
<div
|
||||
className="link-color"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: marked(fetched.content),
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Page
|
37
source/src/pages/portfolio.tsx
Normal file
37
source/src/pages/portfolio.tsx
Normal file
|
@ -0,0 +1,37 @@
|
|||
import styled from "styled-components"
|
||||
import theme from "styled-theming"
|
||||
import Helmet from "react-helmet"
|
||||
|
||||
const StyledPortfolio = styled.div``
|
||||
|
||||
const StyledH1 = styled.h1`
|
||||
font-size: 3rem;
|
||||
`
|
||||
|
||||
function Portfolio() {
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>pomp | Portfolio</title>
|
||||
|
||||
<meta property="og:title" content="developomp's Portfolio" />
|
||||
<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="developomp's Portfolio"
|
||||
/>
|
||||
</Helmet>
|
||||
<StyledPortfolio className="card main-content">
|
||||
<StyledH1>Portfolio</StyledH1>
|
||||
My projects
|
||||
</StyledPortfolio>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Portfolio
|
6
source/src/react-app-env.d.ts
vendored
Normal file
6
source/src/react-app-env.d.ts
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
/// <reference types="react-scripts" />
|
||||
declare module "*.md"
|
||||
|
||||
interface Document {
|
||||
[fonts: string]: any
|
||||
}
|
17
source/src/reportWebVitals.ts
Normal file
17
source/src/reportWebVitals.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { ReportHandler } from "web-vitals"
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import("web-vitals").then(
|
||||
({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry)
|
||||
getFID(onPerfEntry)
|
||||
getFCP(onPerfEntry)
|
||||
getLCP(onPerfEntry)
|
||||
getTTFB(onPerfEntry)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default reportWebVitals
|
6
source/src/setupTests.ts
Normal file
6
source/src/setupTests.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
|
||||
import "@testing-library/jest-dom"
|
63
source/src/theming.ts
Normal file
63
source/src/theming.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
/** theming.ts
|
||||
* stores values that are used across
|
||||
* It makes changing values easier
|
||||
*/
|
||||
|
||||
import theme from "styled-theming"
|
||||
import { css } from "styled-components"
|
||||
|
||||
export default {
|
||||
font: {
|
||||
regular: "'Noto Sans KR', sans-serif",
|
||||
code: "'Source Code Pro', monospace",
|
||||
},
|
||||
size: {
|
||||
x2_small: "3px",
|
||||
x_small: "8px",
|
||||
small: 0,
|
||||
medium: "14px",
|
||||
large: 0,
|
||||
x_large: 0,
|
||||
screen_size1: "950px",
|
||||
},
|
||||
color: {
|
||||
linkColor: "#3273dc",
|
||||
},
|
||||
dark: {
|
||||
backgroundColor0: "#202225",
|
||||
backgroundColor1: "#36393F",
|
||||
color0: "#FFFFFF",
|
||||
color1: "#EEEEEE",
|
||||
},
|
||||
light: {
|
||||
backgroundColor0: "#FFFFFF",
|
||||
backgroundColor1: "#F7F7F7",
|
||||
color0: "#000000",
|
||||
color1: "#111111",
|
||||
},
|
||||
styles: {
|
||||
navbarButtonStyle: css`
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
border-radius: 0.5rem;
|
||||
float: left;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
margin: 0.1em;
|
||||
color: ${theme("mode", {
|
||||
light: "black",
|
||||
dark: "#CFD0D0",
|
||||
})};
|
||||
background-color: ${theme("mode", {
|
||||
light: "white",
|
||||
dark: "#202225",
|
||||
})};
|
||||
&:hover {
|
||||
background-color: ${theme("mode", {
|
||||
light: "lightgrey",
|
||||
dark: "#36393F",
|
||||
})};
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
21
source/tsconfig.json
Normal file
21
source/tsconfig.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": false,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
},
|
||||
"include": ["src/**/*", "generate.ts"]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue