Changed all functional components to class components. added better comments, minor optimizations here and there, removed some unfinished posts from blogs

This commit is contained in:
Kim, Jimin 2021-05-20 15:56:41 +09:00
parent c850184bc7
commit 046dd05713
20 changed files with 987 additions and 927 deletions

View file

@ -22,15 +22,8 @@
"sourceType": "module"
},
"plugins": ["react", "@typescript-eslint"],
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"rules": {
"@typescript-eslint/explicit-module-boundary-types": ["off"]
}
}
],
"rules": {
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"react/jsx-uses-vars": "error",
"react/no-unknown-property": [

View file

@ -1,8 +0,0 @@
---
title: death of miracle
author: developomp
date: May 15, 2021
---
Understanding things what we once called magic.
Science.

View file

@ -1,25 +0,0 @@
---
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

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

View file

@ -1,12 +1,12 @@
import React, { createContext } from "react"
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
import { ThemeProvider, createGlobalStyle } from "styled-components"
import { HelmetProvider } from "react-helmet-async"
import storage from "local-storage-fallback"
import { useState, useEffect } from "react"
import Spinner from "./components/Spinner"
import LanguageContext from "./LanguageContext"
import theming from "./theming"
import Spinner from "./components/Spinner"
import Navbar from "./components/Navbar"
import Footer from "./components/Footer"
@ -126,91 +126,98 @@ blockquote {
}
`
function App() {
/**
* Loading
*/
const [isLoading, setLoading] = useState(true)
interface AppProps {}
interface AppState {
isLoading: boolean
currentTheme: string
currentLanguage: string
}
export const LanguageContext = createContext({
language: "",
// eslint-disable-next-line @typescript-eslint/no-empty-function
toggleLanguage: () => {},
})
export default class App extends React.Component<AppProps, AppState> {
constructor(props) {
super(props)
this.state = {
isLoading: true,
currentTheme: storage.getItem("theme") || "dark", // get theme from storage and set to "dark" mode if not set already
currentLanguage: storage.getItem("lang") || "en", // get language from storage and set to "en" if not set already
}
}
componentDidMount() {
// show loading screen until all fonts are loaded.
// Experimental feature. Not fully supported on all browsers (IE, I'm looking at you).
// 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 = () => {
setLoading(false)
this.setState({ isLoading: false })
}
} else {
setLoading(false)
this.setState({ isLoading: false })
}
}
}, [])
/**
* Theme
*/
const [currentTheme, _setTheme] = useState(
storage.getItem("theme") || "dark" // get theme from storage and set to "dark" mode if not set already
)
componentDidUpdate(_, prevState) {
if (this.state.currentTheme !== prevState.currentTheme) {
// save theme when it is changed
useEffect(() => {
storage.setItem("theme", currentTheme)
}, [currentTheme])
/**
* Language
*/
const [currentLanguage, _setLanguage] = useState(
storage.getItem("lang") || "en" // get language from storage and set to "en" if not set already
)
// save language when it is changed
useEffect(() => {
storage.setItem("lang", currentLanguage)
}, [currentLanguage])
const languageState = {
language: currentLanguage,
toggleLanguage: () => {
// cycle through languages
let setLanguageTo = "en"
if (currentLanguage == "en") setLanguageTo = "kr"
_setLanguage(setLanguageTo)
},
storage.setItem("theme", this.state.currentTheme)
}
if (this.state.currentLanguage !== prevState.currentLanguage) {
// save language when it is changed
storage.setItem("lang", this.state.currentLanguage)
}
}
render() {
return (
<HelmetProvider>
<ThemeProvider
theme={{
currentTheme: currentTheme,
currentTheme: this.state.currentTheme,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
setTheme: (setThemeTo) => _setTheme(setThemeTo), // make setTheme function available in other components
setTheme: (setThemeTo) =>
this.setState({ currentTheme: setThemeTo }), // make setTheme function available in other components
}}
>
<LanguageContext.Provider
value={{
language: this.state.currentLanguage,
toggleLanguage: () => {
// cycle through languages
let setLanguageTo = "en"
if (this.state.currentLanguage == "en")
setLanguageTo = "kr"
this.setState({
currentLanguage: setLanguageTo,
})
},
}}
>
<LanguageContext.Provider value={languageState}>
<GlobalStyle />
<Router>
<Navbar />
<div id="content">
{isLoading ? (
<Spinner
size={200}
color={
currentTheme == "dark"
? theming.dark.color1
: theming.light.color1
}
/>
{this.state.isLoading ? (
<Spinner size={200} />
) : (
<Switch>
<Route
exact
path="/"
component={() => (
<Home howMany={4} title="Home" />
<Home
howMany={4}
title="Home"
/>
)}
/>
<Route
@ -244,6 +251,5 @@ function App() {
</ThemeProvider>
</HelmetProvider>
)
}
}
export default App

View file

@ -1,11 +0,0 @@
/**
* go to App.tsx and search for `languageState` to see the actual values
*/
import { createContext } from "react"
export default createContext({
language: "",
// eslint-disable-next-line @typescript-eslint/no-empty-function
toggleLanguage: () => {},
})

View file

@ -1,9 +1,11 @@
import React from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faGithub } from "@fortawesome/free-brands-svg-icons"
import styled from "styled-components"
import theming from "../theming"
const StyledFooter = styled.footer`
export default class Footer extends React.Component {
StyledFooter = styled.footer`
display: flex;
justify-content: space-between;
margin-bottom: 1px; /* footer goes outside the page by 1 px for some reason */
@ -27,9 +29,9 @@ const StyledFooter = styled.footer`
.logo {
color: gray;
}
`
`
const StyledLink = styled.a`
StyledLink = styled.a`
width: 30px;
font-size: 2rem;
color: ${(props) =>
@ -45,25 +47,29 @@ const StyledLink = styled.a`
dark: "white",
})};
}
`
`
function Footer() {
StyledStrong = styled.strong`
font-size: 1.1rem;
`
render() {
return (
<StyledFooter>
<this.StyledFooter>
<div className="logo">
Copyright &copy; develo<strong>p</strong>omp
Copyright &copy; develo
<this.StyledStrong>p</this.StyledStrong>omp
</div>
<div className="icons">
<StyledLink
<this.StyledLink
href="https://github.com/developomp/developomp-site"
target="_blank"
>
<FontAwesomeIcon icon={faGithub} />
</StyledLink>
</this.StyledLink>
</div>
</StyledFooter>
</this.StyledFooter>
)
}
}
export default Footer

View file

@ -1,12 +1,18 @@
import React from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faLanguage } from "@fortawesome/free-solid-svg-icons"
import styled from "styled-components"
import ReactTooltip from "react-tooltip"
import LanguageContext from "../LanguageContext"
import { LanguageContext } from "../App"
import theming from "../theming"
const StyledThemeButton = styled.div<{ language: string }>`
interface StyledThemeButtonProps {
language: string
}
export default class LanguageToggleButton extends React.Component {
StyledThemeButton = styled.div<StyledThemeButtonProps>`
${theming.styles.navbarButtonStyle}
${(props) =>
props.language == "en"
@ -15,34 +21,35 @@ const StyledThemeButton = styled.div<{ language: string }>`
-moz-transform: scaleX(-1);\
-webkit-transform: scaleX(-1);\
-ms-transform: scaleX(-1);"};
`
`
function LanguageToggleButton() {
function languageName(language) {
languageName = (language) => {
let name = "English"
if (language == "kr") name = "Korean"
return name
}
render() {
return (
<LanguageContext.Consumer>
{({ language, toggleLanguage }) => (
<>
<StyledThemeButton
<this.StyledThemeButton
data-tip
data-for="language"
onClick={toggleLanguage}
language={language}
>
<FontAwesomeIcon icon={faLanguage} />
</StyledThemeButton>
</this.StyledThemeButton>
<ReactTooltip id="language" type="dark" effect="solid">
<span>Using {languageName(language)} language</span>
<span>
Using {this.languageName(language)} language
</span>
</ReactTooltip>
</>
)}
</LanguageContext.Consumer>
)
}
}
export default LanguageToggleButton

View file

@ -1,3 +1,4 @@
import React from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faGithub } from "@fortawesome/free-brands-svg-icons"
import styled from "styled-components"
@ -11,7 +12,8 @@ import Sidebar from "./Sidebar"
import ThemeToggleButton from "./ThemeToggleButton"
import LanguageToggleButton from "./LanguageToggleButton"
const StyledNav = styled.nav`
export default class Navbar extends React.Component {
StyledNav = styled.nav`
display: flex;
align-items: center;
height: 2rem;
@ -32,64 +34,62 @@ const StyledNav = styled.nav`
.right {
margin-left: auto;
}
`
`
const StyledNavLinks = styled.div`
StyledNavLinks = styled.div`
@media only screen and (max-width: ${theming.size.screen_size1}) {
display: none;
}
`
`
const StyledImg = styled.img`
StyledImg = styled.img`
height: 2rem;
margin: 1rem;
`
`
const StyledLink = styled(Link)`
StyledLink = styled(Link)`
${theming.styles.navbarButtonStyle}
`
`
const StyledALink = styled.a`
StyledALink = styled.a`
${theming.styles.navbarButtonStyle}
`
function Navbar() {
`
render() {
return (
<StyledNav>
<this.StyledNav>
<Link to="/">
<StyledImg
<this.StyledImg
src={process.env.PUBLIC_URL + "/icon/icon_circle.svg"}
/>
</Link>
<StyledNavLinks>
<this.StyledNavLinks>
{NavbarData.map((item, index) => {
return (
<StyledLink key={index} to={item.path}>
<this.StyledLink key={index} to={item.path}>
{item.title}
</StyledLink>
</this.StyledLink>
)
})}
</StyledNavLinks>
</this.StyledNavLinks>
<ThemeToggleButton />
<LanguageToggleButton />
<StyledALink
<this.StyledALink
data-tip
data-for="github"
href="https://github.com/developomp/developomp-site"
target="_blank"
>
<FontAwesomeIcon icon={faGithub} />
</StyledALink>
</this.StyledALink>
<ReactTooltip id="github" type="dark" effect="solid">
<span>View source code</span>
</ReactTooltip>
<SearchBox />
<Sidebar />
</StyledNav>
</this.StyledNav>
)
}
}
export default Navbar

View file

@ -1,16 +1,19 @@
import React from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faSearch } from "@fortawesome/free-solid-svg-icons"
import styled from "styled-components"
import theming from "../theming"
const StyledSearchBoxContainer = styled.div`
export default class Navbar extends React.Component {
StyledSearchBoxContainer = styled.div`
display: flex;
justify-content: left;
margin: 0.5rem;
align-items: center;
background-color: ${(props) =>
theming.theme(props.theme.currentTheme, {
light: "white",
dark: "#202225",
dark: "#2F3136",
})};
color: ${(props) =>
theming.theme(props.theme.currentTheme, {
@ -25,9 +28,9 @@ const StyledSearchBoxContainer = styled.div`
dark: "#36393F",
})};
}
`
`
const StyledSearchBox = styled.input`
StyledSearchBox = styled.input`
width: 80%;
border: none;
border-right: 1rem;
@ -36,19 +39,22 @@ const StyledSearchBox = styled.input`
text-decoration: none;
background-color: inherit;
color: inherit;
`
`
const StyledSearchButton = styled(FontAwesomeIcon)`
StyledSearchButton = styled(FontAwesomeIcon)`
cursor: pointer;
`
`
function Navbar() {
render() {
return (
<StyledSearchBoxContainer>
<StyledSearchBox type="text" name="search" placeholder="Search" />
<StyledSearchButton icon={faSearch} />
</StyledSearchBoxContainer>
<this.StyledSearchBoxContainer>
<this.StyledSearchBox
type="text"
name="search"
placeholder="Search"
/>
<this.StyledSearchButton icon={faSearch} />
</this.StyledSearchBoxContainer>
)
}
}
export default Navbar

View file

@ -1,6 +1,6 @@
import { useState } from "react"
import React from "react"
import styled, { css } from "styled-components"
import NavbarData from "../data/NavbarData"
import NavbarData, { Item } from "../data/NavbarData"
import ReactTooltip from "react-tooltip"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
@ -9,36 +9,54 @@ import { faEllipsisV, faTimes } from "@fortawesome/free-solid-svg-icons"
import theming from "../theming"
import SubMenu from "./SubMenu"
interface StateProps {
interface SidebarProps {}
interface SidebarState {
isSidebarOpen: boolean
}
const CommonSidebarToggleButtonStyle = css`
export default class Sidebar extends React.Component<
SidebarProps,
SidebarState
> {
constructor(props) {
super(props)
this.state = {
isSidebarOpen: false,
}
}
// for some reason this.setState only works if this is an arrow function
toggleSidebar = () => {
this.setState({ isSidebarOpen: !this.state.isSidebarOpen })
document.body.style.overflow = this.state.isSidebarOpen
? "scroll"
: "hidden"
}
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}
`
StyledToggleSidebarButton = styled.div`
${this.CommonSidebarToggleButtonStyle}
`
const StyledToggleSidebarButton2 = styled.div`
${CommonSidebarToggleButtonStyle}
StyledToggleSidebarButton2 = styled.div`
${this.CommonSidebarToggleButtonStyle}
border-radius: 0;
margin: auto;
width: 90%;
height: 2rem;
font-size: 1.1rem;
`
`
const StyledOverlay = styled.div<StateProps>`
StyledOverlay = styled.div<SidebarState>`
display: ${(props) => (props.isSidebarOpen ? "block" : "none")};
position: fixed;
top: 0;
@ -52,9 +70,9 @@ const StyledOverlay = styled.div<StateProps>`
* {
overflow: scroll;
}
`
`
const SidebarNav = styled.nav<StateProps>`
SidebarNav = styled.nav<SidebarState>`
width: 250px;
height: 100vh;
display: flex;
@ -76,50 +94,45 @@ const SidebarNav = styled.nav<StateProps>`
light: theming.light.color0,
dark: theming.dark.color0,
})};
`
`
const SidebarWrap = styled.div`
SidebarWrap = styled.div`
width: 100%;
`
const Sidebar = () => {
const [isSidebarOpen, setSidebar] = useState(false)
function toggleSidebar() {
setSidebar(!isSidebarOpen)
document.body.style.overflow = isSidebarOpen ? "scroll" : "hidden"
}
`
render() {
return (
<>
<StyledOverlay
isSidebarOpen={isSidebarOpen}
onClick={toggleSidebar}
<this.StyledOverlay
isSidebarOpen={this.state.isSidebarOpen}
onClick={this.toggleSidebar}
/>
<StyledToggleSidebarButton
<this.StyledToggleSidebarButton
data-tip
data-for="sidebar"
onClick={toggleSidebar}
onClick={this.toggleSidebar}
>
<FontAwesomeIcon icon={faEllipsisV}></FontAwesomeIcon>
<ReactTooltip id="sidebar" type="dark" effect="solid">
<span>open sidebar</span>
</ReactTooltip>
</StyledToggleSidebarButton>
</this.StyledToggleSidebarButton>
<SidebarNav isSidebarOpen={isSidebarOpen}>
<SidebarWrap>
<StyledToggleSidebarButton2 onClick={toggleSidebar}>
<FontAwesomeIcon icon={faTimes}></FontAwesomeIcon> Close
</StyledToggleSidebarButton2>
{NavbarData.map((item, index) => {
<this.SidebarNav isSidebarOpen={this.state.isSidebarOpen}>
<this.SidebarWrap>
<this.StyledToggleSidebarButton2
onClick={this.toggleSidebar}
>
<FontAwesomeIcon icon={faTimes}></FontAwesomeIcon>{" "}
Close
</this.StyledToggleSidebarButton2>
{NavbarData.map((item: Item, index) => {
return <SubMenu item={item} key={index} />
})}
</SidebarWrap>
</SidebarNav>
</this.SidebarWrap>
</this.SidebarNav>
</>
)
}
}
export default Sidebar

View file

@ -2,56 +2,58 @@
* inspired by https://github.com/dmitrymorozoff/react-spinners-kit/tree/master/src/components/whisper
*/
import React from "react"
import styled, { keyframes } from "styled-components"
const motion = keyframes`
0% {
transform: scale(1, 1);
opacity: 1;
}
100% {
transform: scale(0, 0);
opacity: 0;
}
`
const spin = keyframes`
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(90deg);
}
50% {
transform: rotate(180deg);
}
75% {
transform: rotate(270deg);
}
100% {
transform: rotate(360deg);
}
`
interface BallInterface {
color: string
size: number
key: string
index: number
}
interface WrapperInterface {
size: number
}
const Ball = styled.div<BallInterface>`
interface SpinnerProps {
size: number
}
export default class Spinner extends React.Component<SpinnerProps> {
motion = keyframes`
from {
transform: scale(1, 1);
opacity: 1;
}
to {
transform: scale(0, 0);
opacity: 0;
}
`
spin = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`
Ball = styled.div<BallInterface>`
float: left;
clear: right;
margin: ${(props) => props.size / 15}px;
width: ${(props) => props.size / 5}px;
height: ${(props) => props.size / 5}px;
border-radius: 2px;
background-color: ${(props) => props.color};
animation-name: ${motion};
background-color: lightgrey;
animation-name: ${this.motion};
animation-direction: alternate;
animation-duration: 800ms;
animation-timing-function: linear;
animation-iteration-count: infinite;
/* use for loops here? */
&:nth-child(1) {
animation-delay: 200ms;
}
@ -79,29 +81,27 @@ const Ball = styled.div<BallInterface>`
&:nth-child(9) {
animation-delay: 1000ms;
}
`
`
interface WrapperInterface {
size: number
}
const Wrapper = styled.div<WrapperInterface>`
Wrapper = styled.div<WrapperInterface>`
margin: 5rem auto 0 auto;
width: 200px;
height: 200px;
animation: ${spin} 10s infinite;
`
animation-timing-function: linear;
animation: ${this.spin} 10s infinite;
`
balls: unknown[] = []
constructor(props) {
super(props)
function Spinner({ size, color }) {
const balls: unknown[] = []
let keyValue = 0
const countBallsInLine = 3
for (let i = 0; i < countBallsInLine; i++) {
for (let j = 0; j < countBallsInLine; j++) {
balls.push(
<Ball
color={color}
size={size}
this.balls.push(
<this.Ball
size={this.props.size}
key={keyValue.toString()}
index={keyValue}
/>
@ -109,8 +109,9 @@ function Spinner({ size, color }) {
keyValue++
}
}
}
return <Wrapper size={size}>{balls}</Wrapper>
render() {
return <this.Wrapper size={this.props.size}>{this.balls}</this.Wrapper>
}
}
export default Spinner

View file

@ -1,9 +1,22 @@
import { useState } from "react"
import React from "react"
import { Link } from "react-router-dom"
import styled from "styled-components"
import theming from "../theming"
import { Item } from "../data/NavbarData"
const SidebarLink = styled(Link)`
interface SubMenuProps {
item: Item
}
interface SubMenuState {
isSubNavOpen: boolean
}
export default class SubMenu extends React.Component<
SubMenuProps,
SubMenuState
> {
SidebarLink = styled(Link)`
${theming.styles.navbarButtonStyle};
display: flex;
width: 100%;
@ -14,13 +27,13 @@ const SidebarLink = styled(Link)`
align-items: center;
padding: 20px;
list-style: none;
`
`
const SidebarLabel = styled.span`
SidebarLabel = styled.span`
margin-left: 16px;
`
`
const DropdownLink = styled(Link)`
DropdownLink = styled(Link)`
background: #414757;
height: 60px;
padding-left: 3rem;
@ -34,41 +47,54 @@ const DropdownLink = styled(Link)`
background: #632ce4;
cursor: pointer;
}
`
`
function SubMenu({ item }) {
const [isSubNavOpen, setSubNav] = useState(false)
constructor(props) {
super(props)
this.state = {
isSubNavOpen: false,
}
}
const showSubNav = () => setSubNav(!isSubNavOpen)
showSubNav = () => this.setState({ isSubNavOpen: !this.state.isSubNavOpen })
render() {
return (
<>
<SidebarLink to={item.path} onClick={item.subNav && showSubNav}>
<this.SidebarLink
to={this.props.item.path}
onClick={this.props.item.subNav && this.showSubNav}
>
<div>
{item.icon}
<SidebarLabel>{item.title}</SidebarLabel>
{this.props.item.icon}
<this.SidebarLabel>
{this.props.item.title}
</this.SidebarLabel>
</div>
<div>
{item.subNav && isSubNavOpen
? item.iconOpened
: item.subNav
? item.iconClosed
{this.props.item.subNav && this.state.isSubNavOpen
? this.props.item.iconOpened
: this.props.item.subNav
? this.props.item.iconClosed
: null}
</div>
</SidebarLink>
</this.SidebarLink>
{/* not used as of the moment */}
{isSubNavOpen &&
item.subNav.map((item, index) => {
{this.state.isSubNavOpen && // check if subNav is open
this.props.item.subNav && // check if subNav exists in that item
this.props.item.subNav.map((item, index) => {
// shows all items in subNav
return (
<DropdownLink to={item.path} key={index}>
<this.DropdownLink to={item.path} key={index}>
{item.icon}
<SidebarLabel>{item.title}</SidebarLabel>
</DropdownLink>
<this.SidebarLabel>
{item.title}
</this.SidebarLabel>
</this.DropdownLink>
)
})}
</>
)
}
}
export default SubMenu

View file

@ -1,3 +1,4 @@
import React from "react"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faMoon, faSun } from "@fortawesome/free-solid-svg-icons"
import styled, { ThemeConsumer } from "styled-components"
@ -6,7 +7,8 @@ import ReactTooltip from "react-tooltip"
import theming from "../theming"
const StyledThemeButton = styled.div`
export default class Navbar extends React.Component {
StyledThemeButton = styled.div`
${theming.styles.navbarButtonStyle}
${(props) =>
theming.theme(props.theme.currentTheme, {
@ -16,19 +18,20 @@ const StyledThemeButton = styled.div`
-webkit-transform: scaleX(-1);\
-ms-transform: scaleX(-1);",
})};
`
function Navbar() {
`
render() {
return (
<ThemeConsumer>
{({ currentTheme, setTheme }) => (
<>
<StyledThemeButton
<this.StyledThemeButton
data-tip
data-for="theme"
className="right"
onClick={() =>
setTheme(currentTheme === "dark" ? "light" : "dark")
setTheme(
currentTheme === "dark" ? "light" : "dark"
)
}
>
{currentTheme == "dark" && (
@ -37,7 +40,7 @@ function Navbar() {
{currentTheme == "light" && (
<FontAwesomeIcon icon={faSun} />
)}
</StyledThemeButton>
</this.StyledThemeButton>
<ReactTooltip id="theme" type="dark" effect="solid">
<span>Using {currentTheme} theme</span>
</ReactTooltip>
@ -45,6 +48,5 @@ function Navbar() {
)}
</ThemeConsumer>
)
}
}
export default Navbar

View file

@ -8,7 +8,17 @@ import {
faHiking,
} from "@fortawesome/free-solid-svg-icons"
export default [
// item from sidebar data
export type Item = {
path: string
subNav?: Array<Item>
icon: JSX.Element
title: string
iconOpened?: JSX.Element
iconClosed?: JSX.Element
}
const NavbarData: Array<Item> = [
{
title: "Home",
path: "/",
@ -40,3 +50,5 @@ export default [
icon: <FontAwesomeIcon icon={faUserTie} />,
},
]
export default NavbarData

View file

@ -1,3 +1,4 @@
import React from "react"
import { Link } from "react-router-dom"
import styled from "styled-components"
import theming from "../theming"
@ -6,7 +7,16 @@ import { Helmet } from "react-helmet-async"
import pages from "../pages.json"
const StyledPostList = styled.div`
interface HomeProps {
title?: string
howMany?: number
}
export default class Home extends React.Component<HomeProps, { lol: boolean }> {
h1Text: string
PostCards: Array<unknown> = []
StyledPostList = styled.div`
padding-top: 2rem;
margin: auto;
text-align: center;
@ -15,20 +25,20 @@ const StyledPostList = styled.div`
light: "#111111",
dark: "#EEEEEE",
})};
`
`
const StyledH1 = styled.h1`
StyledH1 = styled.h1`
margin-bottom: 20px;
font-weight: 500;
margin: 0;
`
`
const StyledTitle = styled.h1`
StyledTitle = styled.h1`
font-size: 2rem;
font-style: bold;
`
`
const StyledLink = styled(Link)`
StyledLink = styled(Link)`
text-decoration: none;
color: ${(props) =>
@ -40,24 +50,21 @@ const StyledLink = styled(Link)`
&:hover {
text-decoration: underline;
}
`
`
const StyledPostCard = styled.div`
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) {
const PostCards: Array<unknown> = []
constructor(props) {
super(props)
let howMany = props.howMany
const isLimited = Boolean(howMany)
let h1Text = "All posts"
if (isLimited) {
h1Text = `${howMany} recent posts`
}
this.h1Text = isLimited ? "All posts" : `${howMany} recent posts`
for (const pagePath in pages) {
if (isLimited && howMany <= 0) continue
@ -65,13 +72,20 @@ function Home(props) {
const 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"
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>
this.PostCards.push(
<this.StyledPostCard
key={pagePath}
className="card main-content"
>
<this.StyledTitle>
<this.StyledLink to={pagePath}>
{post.title}
</this.StyledLink>
</this.StyledTitle>
<small>
Published on {post.date} by {post.author}
</small>
@ -86,19 +100,23 @@ function Home(props) {
}}
></div>
<small>
<StyledLink to={pagePath}>Read more</StyledLink>
<this.StyledLink to={pagePath}>
Read more
</this.StyledLink>
</small>
</StyledPostCard>
</this.StyledPostCard>
)
howMany--
}
}
render() {
return (
<>
<Helmet>
<title>pomp | {props.title}</title>
<title>pomp | {this.props.title}</title>
<meta property="og:title" content={props.title} />
<meta property="og:title" content={this.props.title} />
<meta property="og:type" content="website" />
<meta property="og:url" content="http://developomp.com" />
<meta
@ -108,13 +126,12 @@ function Home(props) {
<meta property="og:description" content="" />
</Helmet>
<StyledPostList>
<StyledH1>{h1Text}</StyledH1>
<this.StyledPostList>
<this.StyledH1>{this.h1Text}</this.StyledH1>
<br />
{PostCards}
</StyledPostList>
{this.PostCards}
</this.StyledPostList>
</>
)
}
}
export default Home

View file

@ -1,8 +1,10 @@
import React from "react"
import styled from "styled-components"
import theming from "../theming"
import { Helmet } from "react-helmet-async"
const StyledNotFound = styled.div`
export default class NotFound extends React.Component {
StyledNotFound = styled.div`
margin: auto;
margin-top: 2rem;
text-align: center;
@ -11,13 +13,13 @@ const StyledNotFound = styled.div`
light: "#111111",
dark: "#EEEEEE",
})};
`
`
const Styled404 = styled.h1`
Styled404 = styled.h1`
font-size: 3rem;
`
`
function NotFound() {
render() {
return (
<>
<Helmet>
@ -30,14 +32,16 @@ function NotFound() {
property="og:image"
content="http://developomp.com/icon/icon.svg"
/>
<meta property="og:description" content="Page does not exist" />
<meta
property="og:description"
content="Page does not exist"
/>
</Helmet>
<StyledNotFound className="card main-content">
<Styled404>404</Styled404>
<this.StyledNotFound className="card main-content">
<this.Styled404>404</this.Styled404>
the page you are looking for does not exist. :(
</StyledNotFound>
</this.StyledNotFound>
</>
)
}
}
export default NotFound

View file

@ -1,44 +1,38 @@
import React from "react"
import marked from "marked"
import NotFound from "./notfound"
import { Helmet } from "react-helmet-async"
import pages from "../pages.json"
import { useParams } from "react-router-dom"
function Page() {
const path = `/${useParams().path}`
const fetched = pages[path]
if (!fetched) return <NotFound />
export default class Page extends React.Component {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fetched: any
constructor(props) {
super(props)
const fetched = pages[props.location.pathname]
if (!fetched) return
// 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.date = fetched.meta?.date ? fetched.meta.date : "Unknown date"
fetched.author = fetched.meta?.author
? fetched.meta.author
: `${idk} author`
: "Unknown 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
this.fetched = fetched
}
render() {
if (!this.fetched) return <NotFound />
return (
<>
<Helmet>
<title>pomp | {fetched.title}</title>
<title>pomp | {this.fetched.title}</title>
<meta property="og:title" content="Page Not Found" />
<meta property="og:type" content="website" />
@ -47,25 +41,43 @@ function Page() {
property="og:image"
content="http://developomp.com/icon/icon.svg"
/>
<meta property="og:description" content="Page does not exist" />
<meta
property="og:description"
content="Page does not exist"
/>
</Helmet>
<div className="card main-content">
<h2>{fetched.title}</h2>
<h2>{this.fetched.title}</h2>
<small>
Published on {fetched.date} by {fetched.author}
Published on {this.fetched.date} by{" "}
{this.fetched.author}
</small>
<hr />
{TableOfContents}
{
this.fetched.toc && (
<>
<div className="card">
<strong>Table of Content:</strong>
<div
className="link-color"
dangerouslySetInnerHTML={{
__html: marked(fetched.content),
__html: marked(this.fetched.toc),
}}
></div>
</div>
<hr />
</>
) // add toc if it exists
}
<div
className="link-color"
dangerouslySetInnerHTML={{
__html: marked(this.fetched.content),
}}
></div>
</div>
</>
)
}
}
export default Page

View file

@ -1,19 +1,25 @@
import React from "react"
import styled from "styled-components"
import { Helmet } from "react-helmet-async"
const StyledPortfolio = styled.div``
export default class Portfolio extends React.Component {
StyledPortfolio = styled.div``
const StyledH1 = styled.h1`
StyledH1 = styled.h1`
font-size: 3rem;
`
`
function Portfolio() {
render() {
return (
<>
<Helmet>
<title>pomp | Portfolio</title>
<meta property="og:title" content="developomp's Portfolio" />
<meta
property="og:title"
content="developomp's Portfolio"
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="http://developomp.com" />
<meta
@ -25,12 +31,11 @@ function Portfolio() {
content="developomp's Portfolio"
/>
</Helmet>
<StyledPortfolio className="card main-content">
<StyledH1>Portfolio</StyledH1>
<this.StyledPortfolio className="card main-content">
<this.StyledH1>Portfolio</this.StyledH1>
My projects
</StyledPortfolio>
</this.StyledPortfolio>
</>
)
}
}
export default Portfolio