diff options
| author | Kevin Hoerr <kjhoerr@protonmail.com> | 2022-11-18 19:56:28 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-18 19:56:28 -0500 |
| commit | 1bbecf5d56f103784aa32c550c87048090da0ec1 (patch) | |
| tree | 645ce26fbfa164a384e54b087e0918e5794b1a02 /src | |
| parent | 866a9f7991f43242995879c18fa7fc717cc3e8b6 (diff) | |
| download | submelon.dev-1bbecf5d56f103784aa32c550c87048090da0ec1.tar.gz submelon.dev-1bbecf5d56f103784aa32c550c87048090da0ec1.tar.bz2 submelon.dev-1bbecf5d56f103784aa32c550c87048090da0ec1.zip | |
Site updates (#1)
* Add current page as reference
* Upgrade dependencies: Gatsby 5.0.1
* Refactor components and styles to be consistent
* Switch tense of BlockBody prop
* Remove header on stylesheet
* move timestamp to package version
* Commit public dir for use with static site builders
* Remove 1.0.7 file ref
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/BlockLink.tsx | 12 | ||||
| -rw-r--r-- | src/components/Footer.tsx | 103 | ||||
| -rw-r--r-- | src/components/SEO.tsx | 103 | ||||
| -rw-r--r-- | src/pages/404.tsx | 61 | ||||
| -rw-r--r-- | src/pages/index.tsx | 295 | ||||
| -rw-r--r-- | src/styles/BlockAnchor.ts | 21 | ||||
| -rw-r--r-- | src/styles/BlockBody.ts | 27 | ||||
| -rw-r--r-- | src/styles/BlockHeader.ts | 12 | ||||
| -rw-r--r-- | src/styles/Content.ts | 8 | ||||
| -rw-r--r-- | src/styles/Footer.ts | 13 | ||||
| -rw-r--r-- | src/styles/index.ts | 7 | ||||
| -rw-r--r-- | src/styles/main.css | 113 |
12 files changed, 319 insertions, 456 deletions
diff --git a/src/components/BlockLink.tsx b/src/components/BlockLink.tsx new file mode 100644 index 0000000..f2724e7 --- /dev/null +++ b/src/components/BlockLink.tsx @@ -0,0 +1,12 @@ +import React from "react"; +import { BlockAnchor, BlockBody } from "../styles"; + +const BlockLink = ({ children, ...attributes }) => { + return ( + <BlockBody theme={{ link: true }}> + <BlockAnchor {...attributes}>{children}</BlockAnchor> + </BlockBody> + ); +}; + +export default BlockLink; diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx new file mode 100644 index 0000000..3e6932b --- /dev/null +++ b/src/components/Footer.tsx @@ -0,0 +1,103 @@ +import React from "react"; +import { Footer } from "../styles"; + +const SHORT_CHARS = [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", +]; + +function toShort(valu: number): string { + return ( + valu + .toString() + .match(/.{1,2}/g) + ?.map((s) => SHORT_CHARS[parseInt(s)]) + .join("") ?? "" + ); +} + +function getTimestamp(seconds: number): string { + const date = new Date(seconds * 1000); + const dateArr = [ + date.getUTCFullYear(), + date.getUTCMonth(), + date.getUTCDate(), + date.getUTCHours(), + date.getUTCMinutes(), + ]; + + return dateArr.map(toShort).join(".") + "-0"; +} + +const FooterInfo = ({ timestamp }) => { + return ( + <Footer> + <span> + ©2022 kjhoerr@https://submelon.dev/: + {getTimestamp(parseInt(timestamp))} + </span> + </Footer> + ); +}; + +export default FooterInfo; diff --git a/src/components/SEO.tsx b/src/components/SEO.tsx index e3683df..6d3323b 100644 --- a/src/components/SEO.tsx +++ b/src/components/SEO.tsx @@ -1,88 +1,25 @@ import React from "react"; -import PropTypes from "prop-types"; -import { Helmet } from "react-helmet"; -import { useStaticQuery, graphql } from "gatsby"; -interface MetaProps { - name: string; - content: string; -} - -interface SEOProps { - description: string; - lang: string; - meta: MetaProps[]; - title: string; -} - -function SEO({ description, lang, meta, title }: SEOProps): React.ReactElement { - const { site } = useStaticQuery( - graphql` - query { - site { - siteMetadata { - title - description - author - } - } - } - ` - ); - const metaDescription = description || site.siteMetadata.description; +export function Head(): React.ReactElement { + const metaDescription = + "The official website of Kevin Hoerr, developer of websites."; return ( - <Helmet - htmlAttributes={{ - lang, - }} - title={title} - titleTemplate={`%s | ${site.siteMetadata.title}`} - meta={[ - { - name: `description`, - content: metaDescription, - }, - { - property: `og:title`, - content: title, - }, - { - property: `og:description`, - content: metaDescription, - }, - { - property: `og:type`, - content: `website`, - }, - { - name: `twitter:card`, - content: `summary`, - }, - { - name: `twitter:creator`, - content: site.siteMetadata.author, - }, - { - name: `twitter:title`, - content: title, - }, - { - name: `twitter:description`, - content: metaDescription, - }, - ].concat(meta)} - /> + <> + <meta name="twitter:description" content={metaDescription} /> + <meta + name="twitter:title" + content="Kevin J Hoerr <kjhoerr@submelon.tech>" + /> + <meta name="twitter:creator" content="Kevin J Hoerr" /> + <meta name="twitter:card" content="summary" /> + <meta property="og:type" content="website" /> + <meta property="og:description" content={metaDescription} /> + <meta + property="og:title" + content="Kevin J Hoerr <kjhoerr@submelon.tech>" + /> + <meta name="description" content={metaDescription} /> + <title>Kevin J Hoerr <kjhoerr@submelon.tech></title> + </> ); } -SEO.defaultProps = { - lang: `en`, - meta: [], - description: ``, -}; -SEO.propTypes = { - description: PropTypes.string, - lang: PropTypes.string, - meta: PropTypes.arrayOf(PropTypes.object), - title: PropTypes.string.isRequired, -}; -export default SEO; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 0f6164c..48de764 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,54 +1,27 @@ import * as React from "react"; -import { Link } from "gatsby"; - -// styles -const pageStyles = { - color: "#232129", - padding: "96px", - fontFamily: "-apple-system, Roboto, sans-serif, serif", -}; -const headingStyles = { - marginTop: 0, - marginBottom: 64, - maxWidth: 320, -}; - -const paragraphStyles = { - marginBottom: 48, -}; -const codeStyles = { - color: "#8A6534", - padding: 4, - backgroundColor: "#FFF4DB", - fontSize: "1.25rem", - borderRadius: 4, -}; +import BlockLink from "../components/BlockLink"; +import { BlockBody, BlockHeader, Content } from "../styles"; // markup const NotFoundPage = (): React.ReactElement => { return ( - <main style={pageStyles}> - <title>Not found</title> - <h1 style={headingStyles}>Page not found</h1> - <p style={paragraphStyles}> - Sorry{" "} - <span role="img" aria-label="Pensive emoji"> - 😔 - </span>{" "} - we couldn’t find what you were looking for. - <br /> - {process.env.NODE_ENV === "development" ? ( - <> - <br /> - Try creating a page in <code style={codeStyles}>src/pages/</code>. - <br /> - </> - ) : null} - <br /> - <Link to="/">Go home</Link>. - </p> + <main> + <Content> + <BlockHeader>Not found</BlockHeader> + <BlockBody> + Sorry{" "} + <span role="img" aria-label="Pensive emoji"> + 😔 + </span>{" "} + we couldn't find what you were looking for. + </BlockBody> + <BlockLink href="/" aria-label="Return to the front page"> + Home + </BlockLink> + </Content> </main> ); }; export default NotFoundPage; +export { Head } from "../components/SEO"; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index a1f4f35..7d92d74 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,256 +1,69 @@ import React from "react"; -import styled from "styled-components"; import { StaticImage } from "gatsby-plugin-image"; -import SEO from "../components/SEO"; import "../styles/main.css"; -import { FaMastodon } from "react-icons/fa"; - -const TIMESTAMP = "1641237448"; -const SHORT_CHARS = [ - "0", - "1", - "2", - "3", - "4", - "5", - "6", - "7", - "8", - "9", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", -]; - -function toShort(valu: number): string { - return valu - .toString() - .match(/.{1,2}/g) - .map((s) => SHORT_CHARS[parseInt(s)]) - .join(""); -} - -function getTimestamp(seconds: number): string { - const date = new Date(seconds * 1000); - const dateArr = [ - date.getUTCFullYear(), - date.getUTCMonth(), - date.getUTCDate(), - date.getUTCHours(), - date.getUTCMinutes(), - ]; - - return dateArr.map(toShort).join(".") + "-0"; -} - -// styles -const StyledContainer = styled.div` - div#content { - width: 350px; - margin: 0px auto; - margin-bottom: 120px; - padding-top: 136px; - } - div#header { - text-align: center; - pointer-events: none; - user-select: none; - } - div#tagline { - background-color: #000; - width: 100%; - text-align: center; - color: #fff; - font-size: 36px; - font-weight: bold; - } - div#info { - padding: 4px 8px; - } - div#info a, - div#info a:visited, - div#info a:hover { - text-decoration: none; - color: #000; - padding: 1px 3px; - } - div#info a, - div#info a:visited { - background-color: #e1e1e1; - } - div#info a:hover { - background-color: #d5d5d5; - } - div#info, - div.link { - background-color: #fff; - border: 1px #000 solid; - border-left: 3px #000 solid; - border-right: 3px #000 solid; - } - div.link, - div#tagline { - margin-top: 3px; - } - div.link > a, - div.link > a:visited, - div.link > a:active { - padding: 8px; - width: 328px; - display: block; - text-align: center; - text-decoration: none; - color: #666; - } - div.link:hover { - background-color: #ddd; - color: #222; - } - div.link:last-child, - div.link:last-child > a { - border-bottom-left-radius: 18px; - border-bottom-right-radius: 18px; - } - q, - p, - em { - display: block; - text-indent: 28px; - } - - p { - margin: 0px 0px 16px; - } - - div#meta { - width: 100%; - position: fixed; - left: 0px; - bottom: 0px; - text-align: center; - font-size: 12px; - } - div#meta > span { - background-color: #e1e1e1; - } -`; +import { FaGithub, FaMastodon } from "react-icons/fa"; +import BlockLink from "../components/BlockLink"; +import Footer from "../components/Footer"; +import { BlockBody, BlockHeader, Content } from "../styles"; +import { version } from "../../package.json"; // markup const IndexPage = (): React.ReactElement => { return ( <main> - <SEO title="Kevin J Hoerr <kjhoerr@submelon.tech>" /> - <StyledContainer> - <div id="content"> - <div id="header"> - <StaticImage - src="../images/main.png" - alt="Kevin J Hoerr" - placeholder="blurred" - layout="fixed" - width={340} - height={340} - /> - </div> - <div id="tagline">Hello!</div> - <div id="info"> - <p> - I'm a computer science and math graduate from Millersville - University. I work as an IT consultant and specialize in - development operations and systems validation for web - applications. - </p> - <p> - My most recent projects have been focused on full-stack - development. I use Kubernetes for orchestration, NextJS for - front-end, and rust+actix-web for my backend services with GraphQL - serving as the public API. - </p> - <p> - This site was recently rebuilt using GatsbyJS since the instance - formerly holding this website broke during upgrades. Thank - goodness for backups. - </p> - <em>- Kevin H.</em> - </div> - <div id="links"> - <div className="link"> - <a href="https://cybr.es/@kjhoerr" rel="me"> - <FaMastodon size={20} style={{ marginBottom: "-4px" }} />{" "} - @kjhoerr@cybr.es - </a> - </div> - <div className="link"> - <a href="https://order.blackrockbrews.com"> - Black Rock Brewing (recent project) - </a> - </div> - <div className="link"> - <a href="https://git.submelon.dev"> - My Gitea instance for pet projects - </a> - </div> - </div> + <Content> + <div> + <StaticImage + src="../images/main.png" + alt="Picture of Kevin Hoerr" + placeholder="tracedSVG" + layout="fixed" + width={350} + height={350} + /> </div> + <BlockHeader>Hello!</BlockHeader> + <BlockBody> + <p> + I'm a computer science and math graduate from Millersville + University. I work as an IT consultant and specialize in development + operations and systems validation for web applications. + </p> + <p> + My most recent projects have been focused on full-stack development. + I use Kubernetes for orchestration, NextJS for front-end, and + rust+actix-web for my backend services with GraphQL serving as the + public API. + </p> + <p> + This site was recently rebuilt using GatsbyJS since the instance + formerly holding this website broke during upgrades. Thank goodness + for backups. + </p> + <em>- Kevin H.</em> + </BlockBody> + <BlockLink + href="https://cybr.es/@kjhoerr" + rel="me" + aria-label="My Mastodon account" + > + <FaMastodon size={20} style={{ marginBottom: "-4px" }} />{" "} + @kjhoerr@cybr.es + </BlockLink> + <BlockLink + href="https://github.com/kjhoerr" + rel="me" + aria-label="My GitHub account with my most active personal projects" + > + <FaGithub size={20} style={{ marginBottom: "-4px" }} /> kjhoerr on + GitHub + </BlockLink> + </Content> - <div id="meta"> - <span> - ©2021 kjhoerr@https://submelon.dev/: - {getTimestamp(parseInt(TIMESTAMP))} - </span> - </div> - </StyledContainer> + <Footer timestamp={version} /> </main> ); }; export default IndexPage; +export { Head } from "../components/SEO"; diff --git a/src/styles/BlockAnchor.ts b/src/styles/BlockAnchor.ts new file mode 100644 index 0000000..05eb2a2 --- /dev/null +++ b/src/styles/BlockAnchor.ts @@ -0,0 +1,21 @@ +import styled from "styled-components"; + +export default styled.a` + padding: 8px; + width: 328px; + display: block; + text-align: center; + -webkit-text-decoration: none; + text-decoration: none; + color: #666; + &:visited, + &:active { + padding: 8px; + width: 328px; + display: block; + text-align: center; + -webkit-text-decoration: none; + text-decoration: none; + color: #666; + } +`; diff --git a/src/styles/BlockBody.ts b/src/styles/BlockBody.ts new file mode 100644 index 0000000..8fb655e --- /dev/null +++ b/src/styles/BlockBody.ts @@ -0,0 +1,27 @@ +import styled from "styled-components"; +import BlockAnchor from "./BlockAnchor"; + +export default styled.div` + & + & { + margin-top: 3px; + } + + background-color: #fff; + border: 1px #000 solid; + border-left: 3px #000 solid; + border-right: 3px #000 solid; + + padding: ${(props) => (props.theme.link ? "0" : "4px 8px")}; + + & > ${BlockAnchor} { + &:hover { + background-color: #ddd; + color: #222; + } + } + &:last-child, + &:last-child > ${BlockAnchor} { + border-bottom-left-radius: 18px; + border-bottom-right-radius: 18px; + } +`; diff --git a/src/styles/BlockHeader.ts b/src/styles/BlockHeader.ts new file mode 100644 index 0000000..eb6fe93 --- /dev/null +++ b/src/styles/BlockHeader.ts @@ -0,0 +1,12 @@ +import styled from "styled-components"; + +export default styled.div` + background-color: #000; + width: 100%; + text-align: center; + color: #fff; + font-size: 36px; + font-weight: bold; + margin-top: 3px; + padding-top: 4px; +`; diff --git a/src/styles/Content.ts b/src/styles/Content.ts new file mode 100644 index 0000000..388e12f --- /dev/null +++ b/src/styles/Content.ts @@ -0,0 +1,8 @@ +import styled from "styled-components"; + +export default styled.div` + width: 350px; + margin: 0px auto; + margin-bottom: 120px; + padding-top: 136px; +`; diff --git a/src/styles/Footer.ts b/src/styles/Footer.ts new file mode 100644 index 0000000..a121b68 --- /dev/null +++ b/src/styles/Footer.ts @@ -0,0 +1,13 @@ +import styled from "styled-components"; + +export default styled.div` + width: 100%; + position: fixed; + left: 0px; + bottom: 0px; + text-align: center; + font-size: 12px; + span { + background-color: #e1e1e1; + } +`; diff --git a/src/styles/index.ts b/src/styles/index.ts new file mode 100644 index 0000000..8eee62a --- /dev/null +++ b/src/styles/index.ts @@ -0,0 +1,7 @@ +import BlockAnchor from "./BlockAnchor"; +import BlockBody from "./BlockBody"; +import BlockHeader from "./BlockHeader"; +import Content from "./Content"; +import Footer from "./Footer"; + +export { BlockAnchor, BlockBody, BlockHeader, Content, Footer }; diff --git a/src/styles/main.css b/src/styles/main.css index 4553a42..f1b50d3 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -1,104 +1,41 @@ -/** https://submelon.tech/res/css/main.css - * Main stylesheet for submelon.tech website. - * Author: Kevin J Hoerr - */ body { - background-color: #e1e1e1; /* #e1e1e1, #d5d5d5 */ + background-color: #e1e1e1; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAC4jAAAuIwF4pT92AAAAGXpUWHRUaXRsZQAACNdLSkzOTi/KL81LAQAWSwQhPQTyzQAAABt6VFh0QXV0aG9yAAAI1/NOLcvMU/DITy0qAgAYDwQeUS3vvwAAAZNJREFUeNrt3bFtQ0EMREH5x+q/M3Wi3IJaMGR7yHtbwCWDBY4J+fV4PL5vH879fr9tz/P5/JV3rzAcjI+DhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhAGBhDHglxXG/+RdjisMB2N1QyZirAWZirESZDLGOpDpGKtANmCsAdmCsQJkE8Z4kG0Yo0E2YowF2YoxEmQzxjiQ7RijQE7AGANyCsYIkJMweJDTMGiQEzFYkFMxSJCTMTiQ0zEokDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAgkDAGTuph/E3e5bjCcDBGNOS03fRXGA4GDXLq1YYrDAeDBDn9nskVhoNBgYQBgYQBgYQBgYQBgYQBgYQBgYQBgYQBgYQBgYQBgYQBgYQBgYTxs7wA+yQwVSKvoHMAAAAASUVORK5CYII=); background-repeat: repeat; - font-family: Verdana; - font-size: 16px; + font-display: serif; + font-family: Merriweather, serif; + font-size: 16px } + ::selection { background-color: #999; - color: #fff; -} -div#content { - width: 350px; - margin: 0px auto; - margin-bottom: 120px; - padding-top: 136px; -} -div#header { - margin: 0px 5px; - text-align: center; - pointer-events: none; - user-select: none; -} -div#tagline { - background-color: #000; - width: 100%; - text-align: center; - color: #fff; - font-size: 36px; - font-weight: bold; -} -div#info { - padding: 4px 8px; -} -div#info a, -div#info a:visited, -div#info a:hover { - text-decoration: none; - color: #000; - padding: 1px 3px; -} -div#info a, -div#info a:visited { - background-color: #e1e1e1; -} -div#info a:hover { - background-color: #d5d5d5; + color: #fff } -div#info, -div.link { - background-color: #fff; - border: 1px #000 solid; - border-left: 3px #000 solid; - border-right: 3px #000 solid; -} -div.link, -div#tagline { - margin-top: 3px; -} -div.link > a, -div.link > a:visited, -div.link > a:active { - padding: 8px; - width: 328px; - display: block; - text-align: center; - text-decoration: none; - color: #666; -} -div.link:hover { - background-color: #ddd; - color: #222; -} -div.link:last-child, -div.link:last-child > a { - border-bottom-left-radius: 18px; - border-bottom-right-radius: 18px; -} -q, + +em, p, -em { +q { display: block; - text-indent: 28px; + text-indent: 28px } p { - margin: 0px 0px 16px; + margin: 0 0 16px } -div#meta { - width: 100%; - position: fixed; - left: 0px; - bottom: 0px; - text-align: center; - font-size: 12px; +p>a, +p>a:hover, +p>a:visited { + color: #000; + padding: 1px 3px; + text-decoration: none } -div#meta > span { - background-color: #e1e1e1; + +p>a, +p>a:visited { + background-color: #e1e1e1 } + +p>a:hover { + background-color: #d5d5d5 +}
\ No newline at end of file |
