moving from hexo theme to my own react design

This commit is contained in:
Kim, Jimin 2021-05-15 00:30:19 +09:00
parent 7ff3176072
commit 379c1c60d9
96 changed files with 1990 additions and 50291 deletions

1
source/.eslintignore Normal file
View file

@ -0,0 +1 @@
node_modules/

47
source/.eslintrc Normal file
View 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
View 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")

View file

@ -0,0 +1,10 @@
---
title:
comment:
licenses:
widgets:
article:
author:
---
Put something here

16
source/markdown/about.md Normal file
View 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)

View 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

View file

@ -0,0 +1,6 @@
학교로 갔다
집으로 왔다
일을 한다
죽었다
나는 죽었다
나는 죽었다

9
source/markdown/games.md Normal file
View 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
View 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

View 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>

View 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>

View 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>

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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>

View 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
View 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
View 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
View 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
View 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
View 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>

View 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>

View 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>

View 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

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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.

View 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>

View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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 &copy; <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

View 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

View 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

View 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

View 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

View 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

View 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
View 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
View 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

View 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
View 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

View 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
View file

@ -0,0 +1,6 @@
/// <reference types="react-scripts" />
declare module "*.md"
interface Document {
[fonts: string]: any
}

View 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
View 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
View 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
View 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"]
}