feat: various improvements

- add Terms of Service
- add dark mode
- use cards for blog with excerpt
This commit is contained in:
Felix Schröter 2022-11-15 19:15:11 +01:00
parent 5df4d34780
commit df2fd8a520
Signed by: felschr
GPG key ID: 671E39E6744C807D
12 changed files with 1021 additions and 268 deletions

View file

@ -0,0 +1,25 @@
import { ReactNode } from "react"
import { Box, useTheme } from "@mui/material"
export type FooterProps = {
children: ReactNode
}
export const Footer = ({ children }: FooterProps) => {
const theme = useTheme()
return (
<Box
position="fixed"
display="flex"
bottom={0}
padding={2}
width="100%"
borderTop={`1px solid ${theme.palette.grey[200].toString()}`}
gap={2}
style={{ backgroundColor: theme.palette.background.default.toString()}}
>
{children}
</Box>
)
}

View file

@ -1,17 +1,97 @@
import * as React from "react"
import { AppBar, Box, Button, Container, createTheme, CssBaseline, Link, ThemeProvider, Toolbar, Typography, useMediaQuery, useTheme } from "@mui/material"
import CodeIcon from "@mui/icons-material/Code"
import { ReactNode, useMemo } from "react"
import { Link as GatsbyLink } from "gatsby"
import { Footer } from "../atoms/Footer"
const pages = [
{ title: "Home", href: "/" },
{ title: "Blog", href: "/blog" },
]
type LayoutProps = {
pageTitle: string
children: React.ReactNode
pageTitle: string | ReactNode
children: ReactNode
}
const Layout = ({ pageTitle, children }: LayoutProps) => {
const theme = useTheme()
return (
<div>
<h1>{pageTitle}</h1>
{children}
</div>
<main style={{ border: 0 }}>
<title>{pageTitle}</title>
<AppBar position="fixed">
<Toolbar>
<CodeIcon sx={{ display: "flex", mr: 1 }} />{" "}
<Typography
variant="h6"
noWrap
component="a"
href="/"
sx={{
mr: 2,
display: { xs: "none", md: "flex" },
fontFamily: "monospace",
fontWeight: 700,
letterSpacing: ".3rem",
color: "inherit",
textDecoration: "none",
}}
>
Felix Schröter
</Typography>
<Box sx={{ flexGrow: 1, display: "flex", justifyContent: "end" }}>
{pages.map(({ title, href }) => (
<Button
key={href}
color="inherit"
sx={{ my: 2, color: "white", display: "block" }}
{...{ href }}
>
{title}
</Button>
))}
</Box>
</Toolbar>
</AppBar>
<Container style={{ marginTop: 68.5, marginBottom: 80, minHeight: "100%" }}>
<Typography variant="h1">{pageTitle}</Typography>
{children}
</Container>
<Footer>
<Link rel="me" href="https://todon.eu/@felschr">Mastodon</Link>
<GatsbyLink to="/terms-of-service">Terms of Service</GatsbyLink>
</Footer>
</main>
)
}
export default Layout
const AppLayout = (props: LayoutProps) => {
const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
const theme = useMemo(
() =>
createTheme({
palette: {
mode: prefersDarkMode ? "dark" : "light",
},
typography: {
h1: { fontSize: 48, paddingBottom: 20 },
}
}),
[prefersDarkMode],
);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Layout {...props} />
</ThemeProvider>
)
}
export default AppLayout

9
src/global.css Normal file
View file

@ -0,0 +1,9 @@
body {
margin: 0;
--deckgo-highlight-code-carbon-toolbar-display: none;
}
a {
color: rgb(51, 125, 255);
}

View file

@ -1,27 +1,73 @@
import * as React from "react"
import { graphql, Link, PageProps } from "gatsby"
import { ReactNode } from "react"
import { GatsbyLinkProps, graphql, Link, PageProps } from "gatsby"
import Layout from "../../components/organisms/Layout"
import { Card, CardContent, Grid, Typography } from "@mui/material"
import styled from "@emotion/styled"
type PostProps = {
size?: "normal" | "highlight"
post: Queries.BlogQuery["allMdx"]["edges"][0]["node"]
}
const Post = ({ size = "normal", post }: PostProps) => {
const PostLink = styled((props: { children: ReactNode }) => (
<Link to={`/blog/${post.slug}`} {...props} />
))`
color: inherit;
text-decoration: inherit;
&:hover {
opacity: 0.8;
}
`
return (
<Grid item xs={size === "highlight" ? 12 : 4}>
<Card>
<CardContent>
<Typography variant="h5" gutterBottom>
<PostLink>
{post.frontmatter?.title}
</PostLink>
</Typography>
<Typography fontStyle="normal" color="GrayText">
<PostLink>
{post.excerpt}
</PostLink>
</Typography>
</CardContent>
</Card>
</Grid>
)
}
const Blog = ({ data: { allMdx } }: PageProps<Queries.BlogQuery>) => {
console.log("allMdx", allMdx)
const [highlight, ...posts] = allMdx.edges
return (
<Layout pageTitle="Blog">
{allMdx.edges.map(({ node: post }) => (
<Link to={`/blog/${post.slug}`}>
<h2>{post.frontmatter?.title}</h2>
</Link>
))}
<Grid container spacing={2} alignItems="stretch">
<Post size="highlight" post={highlight.node} />
{posts.map(({ node: post }) => (
<Post post={post} />
))}
</Grid>
</Layout>
)
}
export const query = graphql`
query Blog {
allMdx {
allMdx(
sort: { fields: [frontmatter___published], order: DESC }
filter: { fields: { source: { eq: "posts" } }, frontmatter: { published: { ne: null } } }
) {
edges {
node {
id
slug
excerpt(pruneLength: 400)
frontmatter {
title
published

View file

@ -1,14 +1,43 @@
import * as React from "react"
import { graphql, PageProps } from "gatsby"
import React from "react"
import { graphql, Link as GatsbyLink, PageProps } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import NavigateNextIcon from "@mui/icons-material/NavigateNext"
import Layout from "../../components/organisms/Layout"
import { defineCustomElements as deckDeckGoHighlightElement } from "@deckdeckgo/highlight-code/dist/loader";
import { Breadcrumbs, Link } from "@mui/material";
deckDeckGoHighlightElement();
const BlogPost = ({ data: { mdx } }: PageProps<Queries.BlogPostQuery>) => {
const BlogPost = ({ data: { mdx }, path }: PageProps<Queries.BlogPostQuery>) => {
return (
<Layout pageTitle={mdx?.frontmatter?.title ?? ""}>
<Layout
pageTitle={
<>
<Breadcrumbs
separator={<NavigateNextIcon fontSize="small" />}
aria-label="breadcrumb"
>
<Link
underline="hover"
color="inherit"
to="/blog"
component={GatsbyLink}
>
Blog
</Link>
<Link
underline="hover"
color="inherit"
to={path}
component={GatsbyLink}
>
{mdx?.frontmatter?.title}
</Link>
</Breadcrumbs>
{mdx?.frontmatter?.title ?? ""}
</>
}
>
<MDXRenderer>
{mdx?.body ?? ""}
</MDXRenderer>
@ -18,7 +47,7 @@ const BlogPost = ({ data: { mdx } }: PageProps<Queries.BlogPostQuery>) => {
export const query = graphql`
query BlogPost($id: String) {
mdx(id: {eq: $id}) {
mdx(fields: { source: { eq: "posts" } }, id: { eq: $id }) {
id
body
frontmatter {

View file

@ -1,194 +1,88 @@
import * as React from "react"
import styled from "@emotion/styled"
import { Card as Card_, CardContent, Grid, Typography } from "@mui/material"
import { Link } from "gatsby"
import Layout from "../components/organisms/Layout"
// styles
const pageStyles = {
color: "#232129",
padding: 96,
fontFamily: "-apple-system, Roboto, sans-serif, serif",
}
const headingStyles = {
marginTop: 0,
marginBottom: 64,
maxWidth: 320,
}
const headingAccentStyles = {
color: "#663399",
}
const paragraphStyles = {
marginBottom: 48,
}
const codeStyles = {
color: "#8A6534",
padding: 4,
backgroundColor: "#FFF4DB",
fontSize: "1.25rem",
borderRadius: 4,
}
const listStyles = {
marginBottom: 96,
paddingLeft: 0,
}
const doclistStyles = {
paddingLeft: 0,
}
const listItemStyles = {
fontWeight: 300,
fontSize: 24,
maxWidth: 560,
marginBottom: 30,
}
const Card = styled(Card_)`
height: 100%;
`
const linkStyle = {
color: "#8954A8",
fontWeight: "bold",
fontSize: 16,
verticalAlign: "5%",
}
const docLinkStyle = {
...linkStyle,
listStyleType: "none",
display: `inline-block`,
marginBottom: 24,
marginRight: 12,
}
const descriptionStyle = {
color: "#232129",
fontSize: 14,
marginTop: 10,
marginBottom: 0,
lineHeight: 1.25,
}
const docLinks = [
{
text: "TypeScript Documentation",
url: "https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/",
color: "#8954A8",
},
{
text: "GraphQL Typegen Documentation",
url: "https://www.gatsbyjs.com/docs/how-to/local-development/graphql-typegen/",
color: "#8954A8",
}
]
const badgeStyle = {
color: "#fff",
backgroundColor: "#088413",
border: "1px solid #088413",
fontSize: 11,
fontWeight: "bold",
letterSpacing: 1,
borderRadius: 4,
padding: "4px 6px",
display: "inline-block",
position: "relative" as "relative",
top: -2,
marginLeft: 10,
lineHeight: 1,
}
// data
const links = [
{
text: "Tutorial",
url: "https://www.gatsbyjs.com/docs/tutorial/",
description:
"A great place to get started if you're new to web development. Designed to guide you through setting up your first Gatsby site.",
color: "#E95800",
},
{
text: "How to Guides",
url: "https://www.gatsbyjs.com/docs/how-to/",
description:
"Practical step-by-step guides to help you achieve a specific goal. Most useful when you're trying to get something done.",
color: "#1099A8",
},
{
text: "Reference Guides",
url: "https://www.gatsbyjs.com/docs/reference/",
description:
"Nitty-gritty technical descriptions of how Gatsby works. Most useful when you need detailed information about Gatsby's APIs.",
color: "#BC027F",
},
{
text: "Conceptual Guides",
url: "https://www.gatsbyjs.com/docs/conceptual/",
description:
"Big-picture explanations of higher-level Gatsby concepts. Most useful for building understanding of a particular topic.",
color: "#0D96F2",
},
{
text: "Plugin Library",
url: "https://www.gatsbyjs.com/plugins",
description:
"Add functionality and customize your Gatsby site or app with thousands of plugins built by our amazing developer community.",
color: "#8EB814",
},
{
text: "Build and Host",
url: "https://www.gatsbyjs.com/cloud",
badge: true,
description:
"Now youre ready to show the world! Give your Gatsby site superpowers: Build and host on Gatsby Cloud. Get started for free!",
color: "#663399",
},
]
// markup
const IndexPage = () => {
return (
<main style={pageStyles}>
<title>Home Page</title>
<h1 style={headingStyles}>
Congratulations
<br />
<span style={headingAccentStyles}> you just made a Gatsby site! </span>
🎉🎉🎉
</h1>
<p style={paragraphStyles}>
Edit <code style={codeStyles}>src/pages/index.tsx</code> to see this page
update in real-time. 😎
</p>
<ul style={doclistStyles}>
{docLinks.map(doc => (
<li key={doc.url} style={docLinkStyle}>
<a
style={linkStyle}
href={`${doc.url}?utm_source=starter&utm_medium=ts-docs&utm_campaign=minimal-starter-ts`}
>
{doc.text}
</a>
</li>
))}
</ul>
<ul style={listStyles}>
{links.map(link => (
<li key={link.url} style={{ ...listItemStyles, color: link.color }}>
<span>
<a
style={linkStyle}
href={`${link.url}?utm_source=starter&utm_medium=start-page&utm_campaign=minimal-starter-ts`}
>
{link.text}
</a>
{link.badge && (
<span style={badgeStyle} aria-label="New Badge">
NEW!
</span>
)}
<p style={descriptionStyle}>{link.description}</p>
</span>
</li>
))}
</ul>
<img
alt="Gatsby G Logo"
src="data:image/svg+xml,%3Csvg width='24' height='24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 2a10 10 0 110 20 10 10 0 010-20zm0 2c-3.73 0-6.86 2.55-7.75 6L14 19.75c3.45-.89 6-4.02 6-7.75h-5.25v1.5h3.45a6.37 6.37 0 01-3.89 4.44L6.06 9.69C7 7.31 9.3 5.63 12 5.63c2.13 0 4 1.04 5.18 2.65l1.23-1.06A7.959 7.959 0 0012 4zm-8 8a8 8 0 008 8c.04 0 .09 0-8-8z' fill='%23639'/%3E%3C/svg%3E"
/>
</main>
<Layout pageTitle="Home">
<Grid container spacing={2} alignItems="stretch">
<Grid item xs={4}>
<Card>
<CardContent>
<Typography variant="h5" gutterBottom>
Cloud
</Typography>
I'm experienced in designing & implementing Cloud-native software on all major Cloud platforms that is tailored to the customer's needs. Containers, microservices, serverless setups I'm familiar with all the important tools.
</CardContent>
</Card>
</Grid>
<Grid item xs={4}>
<Card>
<CardContent>
<Typography variant="h5" gutterBottom>
Type safety
</Typography>
I love strong type systems. They avoid runtime exceptions like{" "}
<Link to="https://en.wikipedia.org/wiki/Null_pointer#History">
the billion-dollar mistake
</Link>{" "}
by checking for errors at compile time. A good type system enforces error handling & allows developers to focus more on actual application logic.
</CardContent>
</Card>
</Grid>
<Grid item xs={4}>
<Card>
<CardContent>
<Typography variant="h5" gutterBottom>
Reproducibility
</Typography>
"But it works on my machine" how many times did you hear this?
Running into issues building software can be frustrating & time consuming.
That's where reproducible builds with declarative environments come to the rescue!
Nix is one such system that allows you to use the same dependencies on all developers' machines & in CI/CD pipelines.
</CardContent>
</Card>
</Grid>
<Grid item xs={4}>
<Card>
<CardContent>
<Typography variant="h5" gutterBottom>
DevOps
</Typography>
Plan, Develop, Deliver, Operate Repeat
DevOps is about continually providing value to customers.
Teams who adopt DevOps streamline their processes & automate their systems. This allows rapidly delivering features & maintaining a reliable system.
</CardContent>
</Card>
</Grid>
<Grid item xs={4}>
<Card>
<CardContent>
<Typography variant="h5" gutterBottom>
Learning
</Typography>
Software development is such a vast field and I love learning about new technologies.
You can expect software built on modern state-of-the-art technologies & methodologies from me.
</CardContent>
</Card>
</Grid>
</Grid>
</Layout>
)
}

View file

@ -0,0 +1,30 @@
---
title: Terms of Service
---
Information in accordance with Section 5 TMG
Felix Schröter
Salzwedeler Str. 1
21339 Lüneburg
Germany
## Contact Information
Telephone: +491723956877
E-Mail: admin@felschr.com
Website: [felschr.com](https://felschr.com)
## Disclaimer
### Accountability for content
The contents of our pages have been created with the utmost care. However, we cannot guarantee the contents' accuracy, completeness or topicality. According to statutory provisions, we are furthermore responsible for our own content on these web pages. In this matter, please note that we are not obliged to monitor the transmitted or saved information of third parties, or investigate circumstances pointing to illegal activity. Our obligations to remove or block the use of information under generally applicable laws remain unaffected by this as per §§ 8 to 10 of the Telemedia Act (TMG).
### Accountability for links
Responsibility for the content of external links (to web pages of third parties) lies solely with the operators of the linked pages. No violations were evident to us at the time of linking. Should any legal infringement become known to us, we will remove the respective link immediately.
### Copyright
Our web pages and their contents are subject to German copyright law. Unless expressly permitted by law, every form of utilizing, reproducing or processing works subject to copyright protection on our web pages requires the prior consent of the respective owner of the rights. Individual reproductions of a work are only allowed for private use. The materials from these pages are copyrighted and any unauthorized use may violate copyright laws.

29
src/pages/{mdx.slug}.tsx Normal file
View file

@ -0,0 +1,29 @@
import React from "react"
import { graphql, PageProps } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import Layout from "../components/organisms/Layout"
const Page = ({ data: { mdx }, path }: PageProps<Queries.PageQuery>) => {
console.log("Page...", { path, mdx })
return (
<Layout pageTitle={mdx?.frontmatter?.title ?? ""}>
<MDXRenderer>
{mdx?.body ?? ""}
</MDXRenderer>
</Layout>
)
}
export const query = graphql`
query Page($id: String) {
mdx(fields: { source: { eq: "pages" } }, id: { eq: $id }) {
id
body
frontmatter {
title
}
}
}
`
export default Page