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:
parent
c850184bc7
commit
046dd05713
20 changed files with 987 additions and 927 deletions
|
@ -22,15 +22,8 @@
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"plugins": ["react", "@typescript-eslint"],
|
"plugins": ["react", "@typescript-eslint"],
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": ["*.ts", "*.tsx"],
|
|
||||||
"rules": {
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": ["off"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"@typescript-eslint/no-empty-interface": "off",
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
"react/jsx-uses-vars": "error",
|
"react/jsx-uses-vars": "error",
|
||||||
"react/no-unknown-property": [
|
"react/no-unknown-property": [
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
title: death of miracle
|
|
||||||
author: developomp
|
|
||||||
date: May 15, 2021
|
|
||||||
---
|
|
||||||
|
|
||||||
Understanding things what we once called magic.
|
|
||||||
Science.
|
|
|
@ -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
|
|
|
@ -1,6 +0,0 @@
|
||||||
학교로 갔다
|
|
||||||
집으로 왔다
|
|
||||||
일을 한다
|
|
||||||
죽었다
|
|
||||||
나는 죽었다
|
|
||||||
나는 죽었다
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
import React, { createContext } from "react"
|
||||||
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
|
import { BrowserRouter as Router, Switch, Route } from "react-router-dom"
|
||||||
import { ThemeProvider, createGlobalStyle } from "styled-components"
|
import { ThemeProvider, createGlobalStyle } from "styled-components"
|
||||||
import { HelmetProvider } from "react-helmet-async"
|
import { HelmetProvider } from "react-helmet-async"
|
||||||
import storage from "local-storage-fallback"
|
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 theming from "./theming"
|
||||||
|
|
||||||
|
import Spinner from "./components/Spinner"
|
||||||
import Navbar from "./components/Navbar"
|
import Navbar from "./components/Navbar"
|
||||||
import Footer from "./components/Footer"
|
import Footer from "./components/Footer"
|
||||||
|
|
||||||
|
@ -126,124 +126,130 @@ blockquote {
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
function App() {
|
interface AppProps {}
|
||||||
/**
|
|
||||||
* Loading
|
interface AppState {
|
||||||
*/
|
isLoading: boolean
|
||||||
const [isLoading, setLoading] = useState(true)
|
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
|
||||||
|
|
||||||
// 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
|
// checks if document.fonts.onloadingdone is supported on the browser
|
||||||
if (typeof document.fonts.onloadingdone != undefined) {
|
if (typeof document.fonts.onloadingdone != undefined) {
|
||||||
document.fonts.onloadingdone = () => {
|
document.fonts.onloadingdone = () => {
|
||||||
setLoading(false)
|
this.setState({ isLoading: false })
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
componentDidUpdate(_, prevState) {
|
||||||
<HelmetProvider>
|
if (this.state.currentTheme !== prevState.currentTheme) {
|
||||||
<ThemeProvider
|
// save theme when it is changed
|
||||||
theme={{
|
storage.setItem("theme", this.state.currentTheme)
|
||||||
currentTheme: currentTheme,
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
setTheme: (setThemeTo) => _setTheme(setThemeTo), // make setTheme function available in other components
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LanguageContext.Provider value={languageState}>
|
|
||||||
<GlobalStyle />
|
|
||||||
<Router>
|
|
||||||
<Navbar />
|
|
||||||
<div id="content">
|
|
||||||
{isLoading ? (
|
|
||||||
<Spinner
|
|
||||||
size={200}
|
|
||||||
color={
|
|
||||||
currentTheme == "dark"
|
|
||||||
? theming.dark.color1
|
|
||||||
: theming.light.color1
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<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>
|
|
||||||
</LanguageContext.Provider>
|
|
||||||
</ThemeProvider>
|
|
||||||
</HelmetProvider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
if (this.state.currentLanguage !== prevState.currentLanguage) {
|
||||||
|
// save language when it is changed
|
||||||
|
storage.setItem("lang", this.state.currentLanguage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<HelmetProvider>
|
||||||
|
<ThemeProvider
|
||||||
|
theme={{
|
||||||
|
currentTheme: this.state.currentTheme,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<GlobalStyle />
|
||||||
|
<Router>
|
||||||
|
<Navbar />
|
||||||
|
<div id="content">
|
||||||
|
{this.state.isLoading ? (
|
||||||
|
<Spinner 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>
|
||||||
|
</LanguageContext.Provider>
|
||||||
|
</ThemeProvider>
|
||||||
|
</HelmetProvider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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: () => {},
|
|
||||||
})
|
|
|
@ -1,69 +1,75 @@
|
||||||
|
import React from "react"
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
import { faGithub } from "@fortawesome/free-brands-svg-icons"
|
import { faGithub } from "@fortawesome/free-brands-svg-icons"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
|
|
||||||
const StyledFooter = styled.footer`
|
export default class Footer extends React.Component {
|
||||||
display: flex;
|
StyledFooter = styled.footer`
|
||||||
justify-content: space-between;
|
display: flex;
|
||||||
margin-bottom: 1px; /* footer goes outside the page by 1 px for some reason */
|
justify-content: space-between;
|
||||||
padding: 50px 10px;
|
margin-bottom: 1px; /* footer goes outside the page by 1 px for some reason */
|
||||||
background-color: white;
|
padding: 50px 10px;
|
||||||
background-color: ${(props) =>
|
background-color: white;
|
||||||
theming.theme(props.theme.currentTheme, {
|
background-color: ${(props) =>
|
||||||
light: "white",
|
theming.theme(props.theme.currentTheme, {
|
||||||
dark: "black",
|
light: "white",
|
||||||
})};
|
dark: "black",
|
||||||
color: ${(props) =>
|
})};
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
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: ${(props) =>
|
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
light: "lightgrey",
|
|
||||||
dark: "grey",
|
|
||||||
})};
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: ${(props) =>
|
color: ${(props) =>
|
||||||
theming.theme(props.theme.currentTheme, {
|
theming.theme(props.theme.currentTheme, {
|
||||||
light: "black",
|
light: "black",
|
||||||
dark: "white",
|
dark: "white",
|
||||||
})};
|
})};
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledLink = styled.a`
|
||||||
|
width: 30px;
|
||||||
|
font-size: 2rem;
|
||||||
|
color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: "lightgrey",
|
||||||
|
dark: "grey",
|
||||||
|
})};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: "black",
|
||||||
|
dark: "white",
|
||||||
|
})};
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledStrong = styled.strong`
|
||||||
|
font-size: 1.1rem;
|
||||||
|
`
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<this.StyledFooter>
|
||||||
|
<div className="logo">
|
||||||
|
Copyright © develo
|
||||||
|
<this.StyledStrong>p</this.StyledStrong>omp
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="icons">
|
||||||
|
<this.StyledLink
|
||||||
|
href="https://github.com/developomp/developomp-site"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faGithub} />
|
||||||
|
</this.StyledLink>
|
||||||
|
</div>
|
||||||
|
</this.StyledFooter>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
`
|
|
||||||
|
|
||||||
function Footer() {
|
|
||||||
return (
|
|
||||||
<StyledFooter>
|
|
||||||
<div className="logo">
|
|
||||||
Copyright © develo<strong>p</strong>omp
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="icons">
|
|
||||||
<StyledLink
|
|
||||||
href="https://github.com/developomp/developomp-site"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faGithub} />
|
|
||||||
</StyledLink>
|
|
||||||
</div>
|
|
||||||
</StyledFooter>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Footer
|
|
||||||
|
|
|
@ -1,48 +1,55 @@
|
||||||
|
import React from "react"
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
import { faLanguage } from "@fortawesome/free-solid-svg-icons"
|
import { faLanguage } from "@fortawesome/free-solid-svg-icons"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import ReactTooltip from "react-tooltip"
|
import ReactTooltip from "react-tooltip"
|
||||||
|
|
||||||
import LanguageContext from "../LanguageContext"
|
import { LanguageContext } from "../App"
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
|
|
||||||
const StyledThemeButton = styled.div<{ language: string }>`
|
interface StyledThemeButtonProps {
|
||||||
${theming.styles.navbarButtonStyle}
|
language: string
|
||||||
${(props) =>
|
}
|
||||||
props.language == "en"
|
|
||||||
? ""
|
export default class LanguageToggleButton extends React.Component {
|
||||||
: "transform: scaleX(-1);\
|
StyledThemeButton = styled.div<StyledThemeButtonProps>`
|
||||||
|
${theming.styles.navbarButtonStyle}
|
||||||
|
${(props) =>
|
||||||
|
props.language == "en"
|
||||||
|
? ""
|
||||||
|
: "transform: scaleX(-1);\
|
||||||
-moz-transform: scaleX(-1);\
|
-moz-transform: scaleX(-1);\
|
||||||
-webkit-transform: scaleX(-1);\
|
-webkit-transform: scaleX(-1);\
|
||||||
-ms-transform: scaleX(-1);"};
|
-ms-transform: scaleX(-1);"};
|
||||||
`
|
`
|
||||||
|
|
||||||
function LanguageToggleButton() {
|
languageName = (language) => {
|
||||||
function languageName(language) {
|
|
||||||
let name = "English"
|
let name = "English"
|
||||||
if (language == "kr") name = "Korean"
|
if (language == "kr") name = "Korean"
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
render() {
|
||||||
<LanguageContext.Consumer>
|
return (
|
||||||
{({ language, toggleLanguage }) => (
|
<LanguageContext.Consumer>
|
||||||
<>
|
{({ language, toggleLanguage }) => (
|
||||||
<StyledThemeButton
|
<>
|
||||||
data-tip
|
<this.StyledThemeButton
|
||||||
data-for="language"
|
data-tip
|
||||||
onClick={toggleLanguage}
|
data-for="language"
|
||||||
language={language}
|
onClick={toggleLanguage}
|
||||||
>
|
language={language}
|
||||||
<FontAwesomeIcon icon={faLanguage} />
|
>
|
||||||
</StyledThemeButton>
|
<FontAwesomeIcon icon={faLanguage} />
|
||||||
<ReactTooltip id="language" type="dark" effect="solid">
|
</this.StyledThemeButton>
|
||||||
<span>Using {languageName(language)} language</span>
|
<ReactTooltip id="language" type="dark" effect="solid">
|
||||||
</ReactTooltip>
|
<span>
|
||||||
</>
|
Using {this.languageName(language)} language
|
||||||
)}
|
</span>
|
||||||
</LanguageContext.Consumer>
|
</ReactTooltip>
|
||||||
)
|
</>
|
||||||
|
)}
|
||||||
|
</LanguageContext.Consumer>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default LanguageToggleButton
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import React from "react"
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
import { faGithub } from "@fortawesome/free-brands-svg-icons"
|
import { faGithub } from "@fortawesome/free-brands-svg-icons"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
|
@ -11,85 +12,84 @@ import Sidebar from "./Sidebar"
|
||||||
import ThemeToggleButton from "./ThemeToggleButton"
|
import ThemeToggleButton from "./ThemeToggleButton"
|
||||||
import LanguageToggleButton from "./LanguageToggleButton"
|
import LanguageToggleButton from "./LanguageToggleButton"
|
||||||
|
|
||||||
const StyledNav = styled.nav`
|
export default class Navbar extends React.Component {
|
||||||
display: flex;
|
StyledNav = styled.nav`
|
||||||
align-items: center;
|
display: flex;
|
||||||
height: 2rem;
|
align-items: center;
|
||||||
margin: 0;
|
height: 2rem;
|
||||||
padding: 1rem;
|
margin: 0;
|
||||||
background-color: ${(props) =>
|
padding: 1rem;
|
||||||
theming.theme(props.theme.currentTheme, {
|
background-color: ${(props) =>
|
||||||
light: theming.light.backgroundColor0,
|
theming.theme(props.theme.currentTheme, {
|
||||||
dark: theming.dark.backgroundColor0,
|
light: theming.light.backgroundColor0,
|
||||||
})};
|
dark: theming.dark.backgroundColor0,
|
||||||
color: ${(props) =>
|
})};
|
||||||
theming.theme(props.theme.currentTheme, {
|
color: ${(props) =>
|
||||||
light: theming.light.color0,
|
theming.theme(props.theme.currentTheme, {
|
||||||
dark: theming.dark.color0,
|
light: theming.light.color0,
|
||||||
})};
|
dark: theming.dark.color0,
|
||||||
box-shadow: 0 4px 10px rgb(0 0 0 / 5%);
|
})};
|
||||||
|
box-shadow: 0 4px 10px rgb(0 0 0 / 5%);
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledNavLinks = styled.div`
|
||||||
|
@media only screen and (max-width: ${theming.size.screen_size1}) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledImg = styled.img`
|
||||||
|
height: 2rem;
|
||||||
|
margin: 1rem;
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledLink = styled(Link)`
|
||||||
|
${theming.styles.navbarButtonStyle}
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledALink = styled.a`
|
||||||
|
${theming.styles.navbarButtonStyle}
|
||||||
|
`
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<this.StyledNav>
|
||||||
|
<Link to="/">
|
||||||
|
<this.StyledImg
|
||||||
|
src={process.env.PUBLIC_URL + "/icon/icon_circle.svg"}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
<this.StyledNavLinks>
|
||||||
|
{NavbarData.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<this.StyledLink key={index} to={item.path}>
|
||||||
|
{item.title}
|
||||||
|
</this.StyledLink>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</this.StyledNavLinks>
|
||||||
|
|
||||||
|
<ThemeToggleButton />
|
||||||
|
<LanguageToggleButton />
|
||||||
|
|
||||||
|
<this.StyledALink
|
||||||
|
data-tip
|
||||||
|
data-for="github"
|
||||||
|
href="https://github.com/developomp/developomp-site"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faGithub} />
|
||||||
|
</this.StyledALink>
|
||||||
|
<ReactTooltip id="github" type="dark" effect="solid">
|
||||||
|
<span>View source code</span>
|
||||||
|
</ReactTooltip>
|
||||||
|
|
||||||
|
<SearchBox />
|
||||||
|
<Sidebar />
|
||||||
|
</this.StyledNav>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
`
|
|
||||||
|
|
||||||
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 />
|
|
||||||
<LanguageToggleButton />
|
|
||||||
|
|
||||||
<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
|
|
||||||
|
|
|
@ -1,54 +1,60 @@
|
||||||
|
import React from "react"
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
import { faSearch } from "@fortawesome/free-solid-svg-icons"
|
import { faSearch } from "@fortawesome/free-solid-svg-icons"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
|
|
||||||
const StyledSearchBoxContainer = styled.div`
|
export default class Navbar extends React.Component {
|
||||||
display: flex;
|
StyledSearchBoxContainer = styled.div`
|
||||||
justify-content: left;
|
display: flex;
|
||||||
align-items: center;
|
justify-content: left;
|
||||||
background-color: ${(props) =>
|
margin: 0.5rem;
|
||||||
theming.theme(props.theme.currentTheme, {
|
align-items: center;
|
||||||
light: "white",
|
|
||||||
dark: "#202225",
|
|
||||||
})};
|
|
||||||
color: ${(props) =>
|
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
light: "black",
|
|
||||||
dark: "#CFD0D0",
|
|
||||||
})};
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: ${(props) =>
|
background-color: ${(props) =>
|
||||||
theming.theme(props.theme.currentTheme, {
|
theming.theme(props.theme.currentTheme, {
|
||||||
light: "whitesmoke",
|
light: "white",
|
||||||
dark: "#36393F",
|
dark: "#2F3136",
|
||||||
})};
|
})};
|
||||||
|
color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: "black",
|
||||||
|
dark: "#CFD0D0",
|
||||||
|
})};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: "whitesmoke",
|
||||||
|
dark: "#36393F",
|
||||||
|
})};
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledSearchBox = styled.input`
|
||||||
|
width: 80%;
|
||||||
|
border: none;
|
||||||
|
border-right: 1rem;
|
||||||
|
outline: none;
|
||||||
|
padding: 10px 10px;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: inherit;
|
||||||
|
color: inherit;
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledSearchButton = styled(FontAwesomeIcon)`
|
||||||
|
cursor: pointer;
|
||||||
|
`
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<this.StyledSearchBoxContainer>
|
||||||
|
<this.StyledSearchBox
|
||||||
|
type="text"
|
||||||
|
name="search"
|
||||||
|
placeholder="Search"
|
||||||
|
/>
|
||||||
|
<this.StyledSearchButton icon={faSearch} />
|
||||||
|
</this.StyledSearchBoxContainer>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
`
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState } from "react"
|
import React from "react"
|
||||||
import styled, { css } from "styled-components"
|
import styled, { css } from "styled-components"
|
||||||
import NavbarData from "../data/NavbarData"
|
import NavbarData, { Item } from "../data/NavbarData"
|
||||||
import ReactTooltip from "react-tooltip"
|
import ReactTooltip from "react-tooltip"
|
||||||
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
|
@ -9,117 +9,130 @@ import { faEllipsisV, faTimes } from "@fortawesome/free-solid-svg-icons"
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
import SubMenu from "./SubMenu"
|
import SubMenu from "./SubMenu"
|
||||||
|
|
||||||
interface StateProps {
|
interface SidebarProps {}
|
||||||
|
interface SidebarState {
|
||||||
isSidebarOpen: boolean
|
isSidebarOpen: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const CommonSidebarToggleButtonStyle = css`
|
export default class Sidebar extends React.Component<
|
||||||
${theming.styles.navbarButtonStyle}
|
SidebarProps,
|
||||||
font-size: "1.5rem";
|
SidebarState
|
||||||
width: 1.5rem;
|
> {
|
||||||
text-align: center;
|
constructor(props) {
|
||||||
cursor: pointer;
|
super(props)
|
||||||
margin: 0.1rem;
|
this.state = {
|
||||||
@media only screen and (min-width: ${theming.size.screen_size1}) {
|
isSidebarOpen: false,
|
||||||
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: ${(props) =>
|
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
light: theming.light.backgroundColor0,
|
|
||||||
dark: theming.dark.backgroundColor0,
|
|
||||||
})};
|
|
||||||
color: ${(props) =>
|
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
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 (
|
// for some reason this.setState only works if this is an arrow function
|
||||||
<>
|
toggleSidebar = () => {
|
||||||
<StyledOverlay
|
this.setState({ isSidebarOpen: !this.state.isSidebarOpen })
|
||||||
isSidebarOpen={isSidebarOpen}
|
document.body.style.overflow = this.state.isSidebarOpen
|
||||||
onClick={toggleSidebar}
|
? "scroll"
|
||||||
/>
|
: "hidden"
|
||||||
|
}
|
||||||
|
|
||||||
<StyledToggleSidebarButton
|
CommonSidebarToggleButtonStyle = css`
|
||||||
data-tip
|
${theming.styles.navbarButtonStyle}
|
||||||
data-for="sidebar"
|
width: 1.5rem;
|
||||||
onClick={toggleSidebar}
|
text-align: center;
|
||||||
>
|
cursor: pointer;
|
||||||
<FontAwesomeIcon icon={faEllipsisV}></FontAwesomeIcon>
|
@media only screen and (min-width: ${theming.size.screen_size1}) {
|
||||||
<ReactTooltip id="sidebar" type="dark" effect="solid">
|
display: none;
|
||||||
<span>open sidebar</span>
|
}
|
||||||
</ReactTooltip>
|
`
|
||||||
</StyledToggleSidebarButton>
|
|
||||||
|
|
||||||
<SidebarNav isSidebarOpen={isSidebarOpen}>
|
StyledToggleSidebarButton = styled.div`
|
||||||
<SidebarWrap>
|
${this.CommonSidebarToggleButtonStyle}
|
||||||
<StyledToggleSidebarButton2 onClick={toggleSidebar}>
|
`
|
||||||
<FontAwesomeIcon icon={faTimes}></FontAwesomeIcon> Close
|
|
||||||
</StyledToggleSidebarButton2>
|
StyledToggleSidebarButton2 = styled.div`
|
||||||
{NavbarData.map((item, index) => {
|
${this.CommonSidebarToggleButtonStyle}
|
||||||
return <SubMenu item={item} key={index} />
|
border-radius: 0;
|
||||||
})}
|
margin: auto;
|
||||||
</SidebarWrap>
|
width: 90%;
|
||||||
</SidebarNav>
|
height: 2rem;
|
||||||
</>
|
font-size: 1.1rem;
|
||||||
)
|
`
|
||||||
|
|
||||||
|
StyledOverlay = styled.div<SidebarState>`
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
SidebarNav = styled.nav<SidebarState>`
|
||||||
|
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: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: theming.light.backgroundColor0,
|
||||||
|
dark: theming.dark.backgroundColor0,
|
||||||
|
})};
|
||||||
|
color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: theming.light.color0,
|
||||||
|
dark: theming.dark.color0,
|
||||||
|
})};
|
||||||
|
`
|
||||||
|
|
||||||
|
SidebarWrap = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
`
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<this.StyledOverlay
|
||||||
|
isSidebarOpen={this.state.isSidebarOpen}
|
||||||
|
onClick={this.toggleSidebar}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<this.StyledToggleSidebarButton
|
||||||
|
data-tip
|
||||||
|
data-for="sidebar"
|
||||||
|
onClick={this.toggleSidebar}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faEllipsisV}></FontAwesomeIcon>
|
||||||
|
<ReactTooltip id="sidebar" type="dark" effect="solid">
|
||||||
|
<span>open sidebar</span>
|
||||||
|
</ReactTooltip>
|
||||||
|
</this.StyledToggleSidebarButton>
|
||||||
|
|
||||||
|
<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} />
|
||||||
|
})}
|
||||||
|
</this.SidebarWrap>
|
||||||
|
</this.SidebarNav>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Sidebar
|
|
||||||
|
|
|
@ -2,115 +2,116 @@
|
||||||
* inspired by https://github.com/dmitrymorozoff/react-spinners-kit/tree/master/src/components/whisper
|
* inspired by https://github.com/dmitrymorozoff/react-spinners-kit/tree/master/src/components/whisper
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
import styled, { keyframes } from "styled-components"
|
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 {
|
interface BallInterface {
|
||||||
color: string
|
|
||||||
size: number
|
size: number
|
||||||
key: string
|
key: string
|
||||||
index: number
|
index: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const 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};
|
|
||||||
animation-direction: alternate;
|
|
||||||
animation-duration: 800ms;
|
|
||||||
animation-iteration-count: infinite;
|
|
||||||
&:nth-child(1) {
|
|
||||||
animation-delay: 200ms;
|
|
||||||
}
|
|
||||||
&:nth-child(2) {
|
|
||||||
animation-delay: 400ms;
|
|
||||||
}
|
|
||||||
&:nth-child(3) {
|
|
||||||
animation-delay: 600ms;
|
|
||||||
}
|
|
||||||
&:nth-child(4) {
|
|
||||||
animation-delay: 400ms;
|
|
||||||
}
|
|
||||||
&:nth-child(5) {
|
|
||||||
animation-delay: 600ms;
|
|
||||||
}
|
|
||||||
&:nth-child(6) {
|
|
||||||
animation-delay: 800ms;
|
|
||||||
}
|
|
||||||
&:nth-child(7) {
|
|
||||||
animation-delay: 600ms;
|
|
||||||
}
|
|
||||||
&:nth-child(8) {
|
|
||||||
animation-delay: 800ms;
|
|
||||||
}
|
|
||||||
&:nth-child(9) {
|
|
||||||
animation-delay: 1000ms;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
interface WrapperInterface {
|
interface WrapperInterface {
|
||||||
size: number
|
size: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper = styled.div<WrapperInterface>`
|
interface SpinnerProps {
|
||||||
margin: 5rem auto 0 auto;
|
size: number
|
||||||
width: 200px;
|
}
|
||||||
height: 200px;
|
|
||||||
animation: ${spin} 10s infinite;
|
|
||||||
`
|
|
||||||
|
|
||||||
function Spinner({ size, color }) {
|
export default class Spinner extends React.Component<SpinnerProps> {
|
||||||
const balls: unknown[] = []
|
motion = keyframes`
|
||||||
let keyValue = 0
|
from {
|
||||||
const countBallsInLine = 3
|
transform: scale(1, 1);
|
||||||
for (let i = 0; i < countBallsInLine; i++) {
|
opacity: 1;
|
||||||
for (let j = 0; j < countBallsInLine; j++) {
|
}
|
||||||
balls.push(
|
to {
|
||||||
<Ball
|
transform: scale(0, 0);
|
||||||
color={color}
|
opacity: 0;
|
||||||
size={size}
|
}
|
||||||
key={keyValue.toString()}
|
`
|
||||||
index={keyValue}
|
|
||||||
/>
|
spin = keyframes`
|
||||||
)
|
from {
|
||||||
keyValue++
|
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: 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;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
animation-delay: 400ms;
|
||||||
|
}
|
||||||
|
&:nth-child(3) {
|
||||||
|
animation-delay: 600ms;
|
||||||
|
}
|
||||||
|
&:nth-child(4) {
|
||||||
|
animation-delay: 400ms;
|
||||||
|
}
|
||||||
|
&:nth-child(5) {
|
||||||
|
animation-delay: 600ms;
|
||||||
|
}
|
||||||
|
&:nth-child(6) {
|
||||||
|
animation-delay: 800ms;
|
||||||
|
}
|
||||||
|
&:nth-child(7) {
|
||||||
|
animation-delay: 600ms;
|
||||||
|
}
|
||||||
|
&:nth-child(8) {
|
||||||
|
animation-delay: 800ms;
|
||||||
|
}
|
||||||
|
&:nth-child(9) {
|
||||||
|
animation-delay: 1000ms;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
Wrapper = styled.div<WrapperInterface>`
|
||||||
|
margin: 5rem auto 0 auto;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
animation-timing-function: linear;
|
||||||
|
animation: ${this.spin} 10s infinite;
|
||||||
|
`
|
||||||
|
|
||||||
|
balls: unknown[] = []
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
let keyValue = 0
|
||||||
|
const countBallsInLine = 3
|
||||||
|
for (let i = 0; i < countBallsInLine; i++) {
|
||||||
|
for (let j = 0; j < countBallsInLine; j++) {
|
||||||
|
this.balls.push(
|
||||||
|
<this.Ball
|
||||||
|
size={this.props.size}
|
||||||
|
key={keyValue.toString()}
|
||||||
|
index={keyValue}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
keyValue++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Wrapper size={size}>{balls}</Wrapper>
|
render() {
|
||||||
|
return <this.Wrapper size={this.props.size}>{this.balls}</this.Wrapper>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Spinner
|
|
||||||
|
|
|
@ -1,74 +1,100 @@
|
||||||
import { useState } from "react"
|
import React from "react"
|
||||||
import { Link } from "react-router-dom"
|
import { Link } from "react-router-dom"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
|
import { Item } from "../data/NavbarData"
|
||||||
|
|
||||||
const SidebarLink = styled(Link)`
|
interface SubMenuProps {
|
||||||
${theming.styles.navbarButtonStyle};
|
item: Item
|
||||||
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
|
interface SubMenuState {
|
||||||
|
isSubNavOpen: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class SubMenu extends React.Component<
|
||||||
|
SubMenuProps,
|
||||||
|
SubMenuState
|
||||||
|
> {
|
||||||
|
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;
|
||||||
|
`
|
||||||
|
|
||||||
|
SidebarLabel = styled.span`
|
||||||
|
margin-left: 16px;
|
||||||
|
`
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
this.state = {
|
||||||
|
isSubNavOpen: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showSubNav = () => this.setState({ isSubNavOpen: !this.state.isSubNavOpen })
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<this.SidebarLink
|
||||||
|
to={this.props.item.path}
|
||||||
|
onClick={this.props.item.subNav && this.showSubNav}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{this.props.item.icon}
|
||||||
|
<this.SidebarLabel>
|
||||||
|
{this.props.item.title}
|
||||||
|
</this.SidebarLabel>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{this.props.item.subNav && this.state.isSubNavOpen
|
||||||
|
? this.props.item.iconOpened
|
||||||
|
: this.props.item.subNav
|
||||||
|
? this.props.item.iconClosed
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
</this.SidebarLink>
|
||||||
|
|
||||||
|
{/* not used as of the moment */}
|
||||||
|
{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 (
|
||||||
|
<this.DropdownLink to={item.path} key={index}>
|
||||||
|
{item.icon}
|
||||||
|
<this.SidebarLabel>
|
||||||
|
{item.title}
|
||||||
|
</this.SidebarLabel>
|
||||||
|
</this.DropdownLink>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import React from "react"
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
import { faMoon, faSun } from "@fortawesome/free-solid-svg-icons"
|
import { faMoon, faSun } from "@fortawesome/free-solid-svg-icons"
|
||||||
import styled, { ThemeConsumer } from "styled-components"
|
import styled, { ThemeConsumer } from "styled-components"
|
||||||
|
@ -6,45 +7,46 @@ import ReactTooltip from "react-tooltip"
|
||||||
|
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
|
|
||||||
const StyledThemeButton = styled.div`
|
export default class Navbar extends React.Component {
|
||||||
${theming.styles.navbarButtonStyle}
|
StyledThemeButton = styled.div`
|
||||||
${(props) =>
|
${theming.styles.navbarButtonStyle}
|
||||||
theming.theme(props.theme.currentTheme, {
|
${(props) =>
|
||||||
light: "",
|
theming.theme(props.theme.currentTheme, {
|
||||||
dark: "transform: scaleX(-1);\
|
light: "",
|
||||||
|
dark: "transform: scaleX(-1);\
|
||||||
-moz-transform: scaleX(-1);\
|
-moz-transform: scaleX(-1);\
|
||||||
-webkit-transform: scaleX(-1);\
|
-webkit-transform: scaleX(-1);\
|
||||||
-ms-transform: scaleX(-1);",
|
-ms-transform: scaleX(-1);",
|
||||||
})};
|
})};
|
||||||
`
|
`
|
||||||
|
render() {
|
||||||
function Navbar() {
|
return (
|
||||||
return (
|
<ThemeConsumer>
|
||||||
<ThemeConsumer>
|
{({ currentTheme, setTheme }) => (
|
||||||
{({ currentTheme, setTheme }) => (
|
<>
|
||||||
<>
|
<this.StyledThemeButton
|
||||||
<StyledThemeButton
|
data-tip
|
||||||
data-tip
|
data-for="theme"
|
||||||
data-for="theme"
|
className="right"
|
||||||
className="right"
|
onClick={() =>
|
||||||
onClick={() =>
|
setTheme(
|
||||||
setTheme(currentTheme === "dark" ? "light" : "dark")
|
currentTheme === "dark" ? "light" : "dark"
|
||||||
}
|
)
|
||||||
>
|
}
|
||||||
{currentTheme == "dark" && (
|
>
|
||||||
<FontAwesomeIcon icon={faMoon} />
|
{currentTheme == "dark" && (
|
||||||
)}
|
<FontAwesomeIcon icon={faMoon} />
|
||||||
{currentTheme == "light" && (
|
)}
|
||||||
<FontAwesomeIcon icon={faSun} />
|
{currentTheme == "light" && (
|
||||||
)}
|
<FontAwesomeIcon icon={faSun} />
|
||||||
</StyledThemeButton>
|
)}
|
||||||
<ReactTooltip id="theme" type="dark" effect="solid">
|
</this.StyledThemeButton>
|
||||||
<span>Using {currentTheme} theme</span>
|
<ReactTooltip id="theme" type="dark" effect="solid">
|
||||||
</ReactTooltip>
|
<span>Using {currentTheme} theme</span>
|
||||||
</>
|
</ReactTooltip>
|
||||||
)}
|
</>
|
||||||
</ThemeConsumer>
|
)}
|
||||||
)
|
</ThemeConsumer>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Navbar
|
|
||||||
|
|
|
@ -8,7 +8,17 @@ import {
|
||||||
faHiking,
|
faHiking,
|
||||||
} from "@fortawesome/free-solid-svg-icons"
|
} 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",
|
title: "Home",
|
||||||
path: "/",
|
path: "/",
|
||||||
|
@ -40,3 +50,5 @@ export default [
|
||||||
icon: <FontAwesomeIcon icon={faUserTie} />,
|
icon: <FontAwesomeIcon icon={faUserTie} />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export default NavbarData
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import React from "react"
|
||||||
import { Link } from "react-router-dom"
|
import { Link } from "react-router-dom"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
|
@ -6,115 +7,131 @@ import { Helmet } from "react-helmet-async"
|
||||||
|
|
||||||
import pages from "../pages.json"
|
import pages from "../pages.json"
|
||||||
|
|
||||||
const StyledPostList = styled.div`
|
interface HomeProps {
|
||||||
padding-top: 2rem;
|
title?: string
|
||||||
margin: auto;
|
howMany?: number
|
||||||
text-align: center;
|
|
||||||
color: ${(props) =>
|
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
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: ${(props) =>
|
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
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) {
|
|
||||||
const PostCards: Array<unknown> = []
|
|
||||||
let howMany = props.howMany
|
|
||||||
const isLimited = Boolean(howMany)
|
|
||||||
|
|
||||||
let h1Text = "All posts"
|
|
||||||
if (isLimited) {
|
|
||||||
h1Text = `${howMany} recent posts`
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const pagePath in pages) {
|
|
||||||
if (isLimited && howMany <= 0) continue
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
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
|
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;
|
||||||
|
color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: "#111111",
|
||||||
|
dark: "#EEEEEE",
|
||||||
|
})};
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledH1 = styled.h1`
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
margin: 0;
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledTitle = styled.h1`
|
||||||
|
font-size: 2rem;
|
||||||
|
font-style: bold;
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledLink = styled(Link)`
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: "black",
|
||||||
|
dark: "white",
|
||||||
|
})};
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
StyledPostCard = styled.div`
|
||||||
|
box-shadow: 0 4px 10px rgb(0 0 0 / 10%);
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
`
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props)
|
||||||
|
let howMany = props.howMany
|
||||||
|
const isLimited = Boolean(howMany)
|
||||||
|
|
||||||
|
this.h1Text = isLimited ? "All posts" : `${howMany} recent posts`
|
||||||
|
|
||||||
|
for (const pagePath in pages) {
|
||||||
|
if (isLimited && howMany <= 0) continue
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
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>
|
||||||
|
<hr />
|
||||||
|
<div
|
||||||
|
className="link-color"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: marked(
|
||||||
|
post.content.split(" ").slice(0, 20).join(" ") +
|
||||||
|
"..."
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<small>
|
||||||
|
<this.StyledLink to={pagePath}>
|
||||||
|
Read more
|
||||||
|
</this.StyledLink>
|
||||||
|
</small>
|
||||||
|
</this.StyledPostCard>
|
||||||
|
)
|
||||||
|
howMany--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Helmet>
|
||||||
|
<title>pomp | {this.props.title}</title>
|
||||||
|
|
||||||
|
<meta property="og:title" content={this.props.title} />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content="http://developomp.com" />
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
content="http://developomp.com/icon/icon.svg"
|
||||||
|
/>
|
||||||
|
<meta property="og:description" content="" />
|
||||||
|
</Helmet>
|
||||||
|
|
||||||
|
<this.StyledPostList>
|
||||||
|
<this.StyledH1>{this.h1Text}</this.StyledH1>
|
||||||
|
<br />
|
||||||
|
{this.PostCards}
|
||||||
|
</this.StyledPostList>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,43 +1,47 @@
|
||||||
|
import React from "react"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import theming from "../theming"
|
import theming from "../theming"
|
||||||
import { Helmet } from "react-helmet-async"
|
import { Helmet } from "react-helmet-async"
|
||||||
|
|
||||||
const StyledNotFound = styled.div`
|
export default class NotFound extends React.Component {
|
||||||
margin: auto;
|
StyledNotFound = styled.div`
|
||||||
margin-top: 2rem;
|
margin: auto;
|
||||||
text-align: center;
|
margin-top: 2rem;
|
||||||
color: ${(props) =>
|
text-align: center;
|
||||||
theming.theme(props.theme.currentTheme, {
|
color: ${(props) =>
|
||||||
light: "#111111",
|
theming.theme(props.theme.currentTheme, {
|
||||||
dark: "#EEEEEE",
|
light: "#111111",
|
||||||
})};
|
dark: "#EEEEEE",
|
||||||
`
|
})};
|
||||||
|
`
|
||||||
|
|
||||||
const Styled404 = styled.h1`
|
Styled404 = styled.h1`
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
`
|
`
|
||||||
|
|
||||||
function NotFound() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>pomp | 404</title>
|
<title>pomp | 404</title>
|
||||||
|
|
||||||
<meta property="og:title" content="Page Not Found" />
|
<meta property="og:title" content="Page Not Found" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:url" content="http://developomp.com" />
|
<meta property="og:url" content="http://developomp.com" />
|
||||||
<meta
|
<meta
|
||||||
property="og:image"
|
property="og:image"
|
||||||
content="http://developomp.com/icon/icon.svg"
|
content="http://developomp.com/icon/icon.svg"
|
||||||
/>
|
/>
|
||||||
<meta property="og:description" content="Page does not exist" />
|
<meta
|
||||||
</Helmet>
|
property="og:description"
|
||||||
<StyledNotFound className="card main-content">
|
content="Page does not exist"
|
||||||
<Styled404>404</Styled404>
|
/>
|
||||||
the page you are looking for does not exist. :(
|
</Helmet>
|
||||||
</StyledNotFound>
|
<this.StyledNotFound className="card main-content">
|
||||||
</>
|
<this.Styled404>404</this.Styled404>
|
||||||
)
|
the page you are looking for does not exist. :(
|
||||||
|
</this.StyledNotFound>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NotFound
|
|
||||||
|
|
|
@ -1,71 +1,83 @@
|
||||||
|
import React from "react"
|
||||||
import marked from "marked"
|
import marked from "marked"
|
||||||
import NotFound from "./notfound"
|
import NotFound from "./notfound"
|
||||||
import { Helmet } from "react-helmet-async"
|
import { Helmet } from "react-helmet-async"
|
||||||
|
|
||||||
import pages from "../pages.json"
|
import pages from "../pages.json"
|
||||||
import { useParams } from "react-router-dom"
|
|
||||||
|
|
||||||
function Page() {
|
export default class Page extends React.Component {
|
||||||
const path = `/${useParams().path}`
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const fetched = pages[path]
|
fetched: any
|
||||||
if (!fetched) return <NotFound />
|
|
||||||
|
|
||||||
// to prevent wrapping. I don't want to touch prettier stuff
|
constructor(props) {
|
||||||
const idk = "Unknown"
|
super(props)
|
||||||
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 && (
|
const fetched = pages[props.location.pathname]
|
||||||
<>
|
if (!fetched) return
|
||||||
<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 (
|
fetched.content = fetched?.content ? fetched.content : "No content"
|
||||||
<>
|
fetched.toc = fetched.meta?.toc ? fetched.meta.toc : undefined
|
||||||
<Helmet>
|
fetched.title = fetched.meta?.title ? fetched.meta.title : "No title"
|
||||||
<title>pomp | {fetched.title}</title>
|
fetched.date = fetched.meta?.date ? fetched.meta.date : "Unknown date"
|
||||||
|
fetched.author = fetched.meta?.author
|
||||||
|
? fetched.meta.author
|
||||||
|
: "Unknown author"
|
||||||
|
|
||||||
<meta property="og:title" content="Page Not Found" />
|
this.fetched = fetched
|
||||||
<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">
|
render() {
|
||||||
<h2>{fetched.title}</h2>
|
if (!this.fetched) return <NotFound />
|
||||||
<small>
|
|
||||||
Published on {fetched.date} by {fetched.author}
|
return (
|
||||||
</small>
|
<>
|
||||||
<hr />
|
<Helmet>
|
||||||
{TableOfContents}
|
<title>pomp | {this.fetched.title}</title>
|
||||||
<div
|
|
||||||
className="link-color"
|
<meta property="og:title" content="Page Not Found" />
|
||||||
dangerouslySetInnerHTML={{
|
<meta property="og:type" content="website" />
|
||||||
__html: marked(fetched.content),
|
<meta property="og:url" content="http://developomp.com" />
|
||||||
}}
|
<meta
|
||||||
></div>
|
property="og:image"
|
||||||
</div>
|
content="http://developomp.com/icon/icon.svg"
|
||||||
</>
|
/>
|
||||||
)
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
content="Page does not exist"
|
||||||
|
/>
|
||||||
|
</Helmet>
|
||||||
|
|
||||||
|
<div className="card main-content">
|
||||||
|
<h2>{this.fetched.title}</h2>
|
||||||
|
<small>
|
||||||
|
Published on {this.fetched.date} by{" "}
|
||||||
|
{this.fetched.author}
|
||||||
|
</small>
|
||||||
|
<hr />
|
||||||
|
{
|
||||||
|
this.fetched.toc && (
|
||||||
|
<>
|
||||||
|
<div className="card">
|
||||||
|
<strong>Table of Content:</strong>
|
||||||
|
<div
|
||||||
|
className="link-color"
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__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
|
|
||||||
|
|
|
@ -1,36 +1,41 @@
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import { Helmet } from "react-helmet-async"
|
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;
|
font-size: 3rem;
|
||||||
`
|
`
|
||||||
|
|
||||||
function Portfolio() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>pomp | Portfolio</title>
|
<title>pomp | Portfolio</title>
|
||||||
|
|
||||||
<meta property="og:title" content="developomp's Portfolio" />
|
<meta
|
||||||
<meta property="og:type" content="website" />
|
property="og:title"
|
||||||
<meta property="og:url" content="http://developomp.com" />
|
content="developomp's Portfolio"
|
||||||
<meta
|
/>
|
||||||
property="og:image"
|
<meta property="og:type" content="website" />
|
||||||
content="http://developomp.com/icon/icon.svg"
|
<meta property="og:url" content="http://developomp.com" />
|
||||||
/>
|
<meta
|
||||||
<meta
|
property="og:image"
|
||||||
property="og:description"
|
content="http://developomp.com/icon/icon.svg"
|
||||||
content="developomp's Portfolio"
|
/>
|
||||||
/>
|
<meta
|
||||||
</Helmet>
|
property="og:description"
|
||||||
<StyledPortfolio className="card main-content">
|
content="developomp's Portfolio"
|
||||||
<StyledH1>Portfolio</StyledH1>
|
/>
|
||||||
My projects
|
</Helmet>
|
||||||
</StyledPortfolio>
|
<this.StyledPortfolio className="card main-content">
|
||||||
</>
|
<this.StyledH1>Portfolio</this.StyledH1>
|
||||||
)
|
My projects
|
||||||
|
</this.StyledPortfolio>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Portfolio
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue