Repository: PaulieScanlon/gatsby-theme-terminal
Branch: main
Commit: d842c15744b3
Files: 86
Total size: 148.0 KB
Directory structure:
gitextract_xb6i9ro3/
├── .commitlintrc.js
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── .husky/
│ ├── commit-msg
│ └── pre-commit
├── .prettierignore
├── .prettierrc.js
├── @pauliescanlon/
│ └── gatsby-theme-terminal/
│ ├── README.md
│ ├── gatsby-browser.js
│ ├── gatsby-config.js
│ ├── gatsby-node.js
│ ├── gatsby-ssr.js
│ ├── index.js
│ ├── package.json
│ └── src/
│ ├── components/
│ │ ├── logo/
│ │ │ ├── index.js
│ │ │ └── logo.js
│ │ ├── main/
│ │ │ ├── index.js
│ │ │ └── main.js
│ │ ├── nav/
│ │ │ ├── index.js
│ │ │ └── nav.js
│ │ ├── page-element/
│ │ │ ├── index.js
│ │ │ └── page-element.js
│ │ ├── seo/
│ │ │ ├── index.js
│ │ │ └── seo.js
│ │ ├── site-metadata/
│ │ │ ├── index.js
│ │ │ └── site-metadata.js
│ │ ├── source-article/
│ │ │ ├── index.js
│ │ │ └── source-article.js
│ │ ├── source-days/
│ │ │ ├── index.js
│ │ │ └── source-days.js
│ │ ├── source-list/
│ │ │ ├── index.js
│ │ │ └── source-list.js
│ │ ├── source-months/
│ │ │ ├── index.js
│ │ │ └── source-months.js
│ │ ├── source-tags/
│ │ │ ├── index.js
│ │ │ └── source-tags.js
│ │ └── source-words/
│ │ ├── index.js
│ │ └── source-words.js
│ ├── context/
│ │ └── index.js
│ ├── data/
│ │ ├── index.js
│ │ ├── use-config.js
│ │ ├── use-dates.js
│ │ ├── use-navigation.js
│ │ ├── use-source.js
│ │ ├── use-tags.js
│ │ └── use-words.js
│ ├── gatsby-plugin-theme-ui/
│ │ └── index.js
│ ├── layouts/
│ │ ├── page-layout.js
│ │ └── source-layout.js
│ ├── pages/
│ │ └── 404.js
│ └── utils/
│ └── index.js
├── README.md
├── copy-readme.js
├── demo/
│ ├── LICENSE
│ ├── README.md
│ ├── gatsby-browser.js
│ ├── gatsby-config.js
│ ├── gatsby-node.js
│ ├── gatsby-ssr.js
│ ├── package.json
│ └── src/
│ ├── @pauliescanlon/
│ │ └── gatsby-theme-terminal/
│ │ └── components/
│ │ └── Logo/
│ │ └── Logo.js
│ ├── _temp/
│ │ ├── source-days.mdx
│ │ ├── source-list.mdx
│ │ ├── source-months.mdx
│ │ ├── source-tags.mdx
│ │ └── source-words.mdx
│ ├── pages/
│ │ ├── components.mdx
│ │ ├── index.mdx
│ │ ├── markdown.mdx
│ │ ├── posts.mdx
│ │ ├── projects.mdx
│ │ └── theme-ui-components.mdx
│ ├── posts/
│ │ ├── 2019/
│ │ │ ├── 03/
│ │ │ │ └── a-pinned-post.mdx
│ │ │ └── post-2.mdx
│ │ ├── 2020/
│ │ │ ├── 01/
│ │ │ │ └── post-3.mdx
│ │ │ ├── 02/
│ │ │ │ ├── post-4.mdx
│ │ │ │ └── post-5.mdx
│ │ │ └── 04/
│ │ │ └── private.mdx
│ │ ├── 2021/
│ │ │ ├── local-image-post.mdx
│ │ │ └── remote-image-post.mdx
│ │ └── post-1.mdx
│ └── projects/
│ ├── 2019/
│ │ └── project-2.mdx
│ ├── 2020/
│ │ └── 01/
│ │ └── project-3.mdx
│ └── project-1.mdx
├── netlify.toml
└── package.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .commitlintrc.js
================================================
module.exports = {
extends: ['@commitlint/config-conventional'],
}
================================================
FILE: .github/FUNDING.yml
================================================
github: [pauliescanlon]
ko_fi: pauliescanlon
================================================
FILE: .gitignore
================================================
wip-readme.md
demo/src/pages/source-days.mdx
demo/src/pages/source-list.mdx
demo/src/pages/source-months.mdx
demo/src/pages/source-tags.mdx
demo/src/pages/source-words.mdx
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# dotenv environment variables file
.env
# gatsby files
.cache/
public
# Mac files
.DS_Store
# Yarn
yarn-error.log
.pnp/
.pnp.js
# Yarn Integrity file
.yarn-integrity
.netlify/
================================================
FILE: .husky/commit-msg
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx commitlint --edit
================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run prettier
================================================
FILE: .prettierignore
================================================
demo/.cache
demo/public
================================================
FILE: .prettierrc.js
================================================
module.exports = {
semi: false,
trailingComma: 'all',
singleQuote: true,
printWidth: 120,
tabWidth: 2,
proseWrap: 'always',
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/README.md
================================================
<a href="https://gatsbythemeterminal.gatsbyjs.io/" target="_blank">
<img src="https://gatsbythemeterminal.gatsbyjs.io/images/terminal-open-graph-image.jpg" alt="gatsby-theme-termninal main image" />
</a>
## gatsby-theme-terminal
Gatsby Theme Terminal aims to be a **zero component theme**. It provides _data_ components to aid in the abstraction of
presentational and data layers which together provide the most flexibility
The theme handles the data but how it's displayed is up to you!
You can create any page layout or component combination you like using your own components or components provided by
[theme-ui/components](https://theme-ui.com/components)
## 👀 Preview
- [Live Demo](https://gatsbythemeterminal.gatsbyjs.io/)
## 🚀 Getting started
To help you get started you can either clone the starter
[gatsby-starter-terminal](https://github.com/PaulieScanlon/gatsby-starter-terminal) or read the below.
### Install
```
npm install @pauliescanlon/gatsby-theme-terminal
```
### Install Peer Dependencies
```
npm install @mdx-js/mdx @mdx-js/react gatsby gatsby-plugin-mdx gatsby-source-filesystem react react-dom
```
## Setup
### gatsby-config.js
Add the `siteMetaData` and `@pauliescanlon/gatsby-theme-terminal` to your `gatsby-config.js`
```
// gatsby-config.js
module.exports = {
siteMetadata: {
name: "Your blog title",
description: "I like tech",
keywords: ["tech", "blog", "boop"],
siteUrl: 'https://gatsby-theme-terminal.netlify.com',
siteImage: 'name-of-open-graph-image.jpg', // pop an image in the static folder to use it as the og:image,
profileImage: 'name-of-profile-image.jpg'
lang: `eng`,
config: {
sidebarWidth: 240 // optional,
},
},
plugins: ['@pauliescanlon/gatsby-theme-terminal']
}
```
### directory structure
To add pages create `.mdx` files in the `src/pages` directory. You need at least one file called `index.mdx` located at
`src/pages` or you'll see a GraphQL error.
<!-- prettier-ignore -->
```
|-- src
|-- pages
|-- index.mdx
|-- about.mdx
|-- contact.mdx
```
### frontmatter setup
#### Pages
Pages must include `navigationLabel` in the `frontmatter`
```
// src/pages/about.mdx
---
navigationLabel: About
---
# About
This is about page
```
#### Theme options
Additional `.mdx` can be sourced from _anywhere_ outside the `pages` directory but you need to tell the theme where to
source these files from.
Use the `source` option in `gatsby-config.js`
```
// gatsby-config.js
...
plugins: [
{
resolve: `@pauliescanlon/gatsby-theme-terminal`,
options: {
source: [
{
name: "posts",
dir: "posts",
},
{
name: "projects",
dir: "projects",
},
] // can be an object or array of objects
},
},
],
}
```
Then create the relevant files and directories
<!-- prettier-ignore -->
```
|-- src
|-- pages
...
|-- posts
|--2020
|--02
|-- some-post.mdx
|-- featuredImage: markus-spiske-466ENaLuhLY-unsplash.jpg
|-- markus-spiske-FXFz-sW0uwo-unsplash.jpg
|-- projects
|-- some-project.mdx
```
Any file that is _not_ sourced from `pages` can contain any of the following `frontmatter` but a `title` is required,
this is how the theme distinguishes between pages and other `.mdx` files
<!-- prettier-ignore -->
```
// src/posts/2020/02/some-post.mdx
---
title: Some Post
tags: ["JavaScript", "React", "GatsbyJs", "HTML", "CSS", "theme-ui"]
date: 2020-01-01
dateModified: 20-20-2020
author: Paul Scanlon
status: draft // => means it won't be rendered
isPrivate: // => it will be rendered but you can use this prop as a filter
url: "https://example.com" // => could be an external url
misc: "Ahoy" // => use how you wish
pinned: false // => Could be used as a filter for pinned posts
featuredImage: markus-spiske-466ENaLuhLY-unsplash.jpg
featuredImageUrl: https://via.placeholder.com/936x528
embeddedImages:
- markus-spiske-FXFz-sW0uwo-unsplash.jpg
embeddedImageUrls:
- https://via.placeholder.com/468x264
---
```
### Embedded Images
By using the The `<GatsbyImage />` component from `gatsby-plugin-image` you can pass the image data queried by GraphQL
and pass it on via the `image` prop
The `gatsbyImageData`, data is available via `props.embedded.image(n)`
```
<GatsbyImage image={props.embedded.image1} />
```
You can also use the Theme UI `<Image />` component by passing it a `src`
```
<Image src={props.embedded.image1.gatsbyImageData.images.fallback.src} />
```
`image1` in this example would be `markus-spiske-FXFz-sW0uwo-unsplash.jpg`
EmbeddedImages can also be sourced from a remote url, in this case use the `<Image />` component and pass it the same
props
```
<Image src={props.embedded.image2.gatsbyImageData.images.fallback.src} />
```
### markdown
The theme supports the complete markdown spec and you can see how to use markdown in the
[demo](https://gatsbythemeterminal.gatsbyjs.io/markdown/)
### theme-ui/components
The theme supports _all_ the components provided by [theme-ui/components](https://theme-ui.com/components) and you can
see in the [demo](https://gatsbythemeterminal.gatsbyjs.io/theme-ui-components/) how they are used.
### gatsby-theme-terminal/components
The theme also comes with it's own components _but_... These are purely to provide access to the source nodes. What you
choose to render is completely up to you!
For example to display a list of _all_ files sourced from the `source` theme option you _could_ do something like this.
This component can be used in ANY `.mdx` file 😎
```javascript
<SourceList>
{(source) => (
<ul>
{source.map((edge, index) => {
const {
frontmatter: { title },
} = edge.node
return <li key={index}>{title}</li>
})}
</ul>
)}
</SourceList>
```
You can see more about how to use the theme components in the
[demo](https://gatsbythemeterminal.gatsbyjs.io/components/)
### Component Shadowing
There is very little to shadow because almost everything is exposed by the components but you might want to add your own
logo.
To do this create the following directories `@pauliescanlon/gatsby-theme-terminal/components/Logo` in the `src`
directory of your project and then create a `Logo.js` file. You can do anything you like in here.
```
|-- src
|-- @pauliescanlon
|-- gatsby-theme-terminal
|-- components
|-- Logo
|-- Logo.js
```
If you would like to customize any part of the theme you can do so by shadowing the theme file.
To do this create the following directory `src/gatsby-plugin-theme-ui` and then create an `index.js`
```javascript
// src/gatsby-plugin-theme-ui/index.js
import baseTheme from '@pauliescanlon/gatsby-theme-terminal/src/gatsby-plugin-theme-ui'
export default {
...baseTheme,
colors: {
...baseTheme.colors,
primary: '#FF4081',
secondary: '#03A9F4',
success: '#FFEB3B',
background: '#232323',
surface: '#393939',
},
}
```
### favicon
favicon(s) need to be saved in `static/images` and named `favicon-16x16.png` and `favicon-32x32.png` along with an
`.icon` file called `favicon.ico`
If you're using **gatsby-theme-terminal** in your project i'd love to hear from you
[@pauliescanlon](https://twitter.com/PaulieScanlon)
[](https://ko-fi.com/P5P31B7G8)
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/gatsby-browser.js
================================================
const React = require('react')
const { PageElement } = require('./src/components/page-element')
const anchorScroll = (location) => {
const anchor = document.querySelectorAll(`a[href="${location.hash}"]`)[0]
if (location && location.hash && anchor) {
const item = document.querySelectorAll(`a[href="${location.hash}"]`)[0].offsetTop
const mainNavHeight = document.querySelector(`header`).offsetHeight
setTimeout(() => {
window.scrollTo({
top: item - mainNavHeight,
behavior: 'smooth',
})
}, 50)
}
}
exports.onRouteUpdate = ({ location }) => {
anchorScroll(location)
return true
}
exports.wrapPageElement = ({ element }) => {
return <PageElement>{element}</PageElement>
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/gatsby-config.js
================================================
const path = require('path')
module.exports = (themeOptions) => {
const { source } = themeOptions
let filesystemSources = []
if (source) {
const sourceFilesystemOption = (item) => {
if (source) {
return {
resolve: `gatsby-source-filesystem`,
options: {
name: `${item.name}`,
path: path.resolve(`src/${item.dir}`),
},
}
}
}
if (Array.isArray(source)) {
for (let item of source) {
filesystemSources.push(sourceFilesystemOption(item))
}
} else {
filesystemSources.push(sourceFilesystemOption(source))
}
}
return {
siteMetadata: {
name: ``,
description: ``,
keywords: [],
siteUrl: ``,
siteImage: ``,
profileImage: ``,
lang: ``,
config: {
sidebarWidth: 260,
},
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-image`,
`gatsby-transformer-sharp`,
{
resolve: `gatsby-plugin-sharp`,
options: {
defaults: {
quality: 70,
formats: ['auto', 'webp', 'avif'],
placeholder: 'blurred',
},
},
},
`gatsby-plugin-theme-ui`,
{
resolve: `gatsby-plugin-mdx`,
options: {
defaultLayouts: {
default: require.resolve(`./src/layouts/page-layout.js`),
},
},
},
// Demo pages
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'pages',
path: path.resolve(`src/pages`),
},
},
// Demo 'src/whatever' the user has defined in options.source
...filesystemSources,
],
}
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/gatsby-node.js
================================================
const { createFilePath, createRemoteFileNode } = require('gatsby-source-filesystem')
const path = require('path')
exports.createSchemaCustomization = async ({ actions }) => {
const { createTypes } = actions
createTypes(`
type Mdx implements Node {
frontmatter: Frontmatter
featuredImageUrl: File @link(from: "fields.featuredImageUrl")
embeddedImageUrls: [File] @link(from: "fields.embeddedImageUrls")
}
type Frontmatter @dontInfer {
title: String
navigationLabel: String
tags: [String]
date: String
dateModified: String
author: String
status: String
isPrivate: Boolean
url: String
misc: String
pinned: Boolean
featuredImage: File @fileByRelativePath
featuredImageUrl: String
embeddedImages: [File] @fileByRelativePath
embeddedImageUrls: [String]
}
`)
// Logs out all typeDefs
// actions.printTypeDefinitions({ path: './typeDefs.txt' })
}
exports.onCreateNode = async (
{ node, actions: { createNodeField, createNode }, getNode, store, cache, createNodeId },
themeOptions,
) => {
const { source } = themeOptions
if (node.internal.type === 'Mdx') {
let basePath = ''
if (Array.isArray(source)) {
source.map((item) => {
const { name, dir } = item
if (node.fileAbsolutePath.includes(name)) {
basePath = `/${dir}`
}
})
} else {
if (node.fileAbsolutePath.includes(source.name)) {
basePath = `/${source.dir}`
}
}
const value = createFilePath({ node, getNode })
await createNodeField({
node,
name: 'slug',
value: node.frontmatter.navigationLabel ? value : `${basePath}${value}`,
})
if (node.frontmatter.featuredImageUrl) {
let featuredImageUrl = await createRemoteFileNode({
url: node.frontmatter.featuredImageUrl,
parentNodeId: node.id,
createNode,
createNodeId,
cache,
store,
})
if (featuredImageUrl) {
createNodeField({ node, name: 'featuredImageUrl', value: featuredImageUrl.id })
}
}
if (node.frontmatter.embeddedImageUrls) {
let embeddedImageUrls = await Promise.all(
node.frontmatter.embeddedImageUrls.map((url) => {
return createRemoteFileNode({
url,
parentNodeId: node.id,
createNode,
createNodeId,
cache,
store,
})
}),
)
if (embeddedImageUrls) {
createNodeField({
node,
name: 'embeddedImageUrls',
value: embeddedImageUrls.map((embeddedImageUrl) => {
return embeddedImageUrl.id
}),
})
}
}
}
}
exports.createPages = async ({ graphql, actions, reporter }, themeOptions) => {
const { source } = themeOptions
const { createPage } = actions
if (!source) return
const result = await graphql(`
query {
allMdx(
filter: { frontmatter: { status: { ne: "draft" }, navigationLabel: { eq: null } } }
sort: { order: DESC, fields: [frontmatter___date] }
) {
edges {
node {
id
frontmatter {
title
navigationLabel
}
fields {
slug
}
}
}
}
}
`)
if (result.errors) {
reporter.panicOnBuild('🚨 ERROR: Loading "createPages" query')
}
const data = result.data.allMdx.edges
data.forEach(({ node }) => {
createPage({
path: node.fields.slug,
component: path.join(__dirname, `src/layouts/source-layout.js`),
context: {
id: node.id,
},
})
})
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/gatsby-ssr.js
================================================
const React = require('react')
const { PageElement } = require('./src/components/page-element')
exports.wrapPageElement = ({ element }) => {
return <PageElement>{element}</PageElement>
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/index.js
================================================
// Data Components
export { Main } from './src/components/main'
// Data Components
export { SourceDays } from './src/components/source-days'
export { SourceList } from './src/components/source-list'
export { SourceMonths } from './src/components/source-months'
export { SourceTags } from './src/components/source-tags'
export { SourceWords } from './src/components/source-words'
// Data
export { useConfig } from './src/data/use-config'
export { useNavigation } from './src/data/use-navigation'
export { useDates } from './src/data/use-dates'
export { useTags } from './src/data/use-tags'
export { useWords } from './src/data/use-words'
export { useSource } from './src/data/use-source'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/package.json
================================================
{
"name": "@pauliescanlon/gatsby-theme-terminal",
"description": "A zero component Gatsby theme for developers",
"version": "2.0.0",
"author": "Paul Scanlon <pauliescanlon@gmail.com>",
"dependencies": {
"@emotion/react": "^11.4.0",
"@theme-ui/color": "^0.11.3",
"@theme-ui/prism": "^0.11.3",
"date-fns": "^2.23.0",
"gatsby-plugin-image": "^2.0.0",
"gatsby-plugin-mdx": "^3.0.0",
"gatsby-plugin-react-helmet": "^5.0.0",
"gatsby-plugin-sharp": "^4.0.0",
"gatsby-plugin-theme-ui": "^0.11.3",
"gatsby-source-filesystem": "^4.0.0",
"gatsby-transformer-sharp": "^4.0.0",
"husky": "^7.0.1",
"prettier": "^2.3.2",
"prop-types": "15.7.2",
"react-helmet": "^6.1.0",
"theme-ui": "^0.11.3"
},
"peerDependencies": {
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"gatsby": "^4.0.0",
"gatsby-plugin-mdx": "^3.0.0",
"gatsby-source-filesystem": "^4.0.0",
"react": "^17.0.0",
"react-dom": "^17.0.0"
},
"keywords": [
"gatsby",
"gatsby-theme",
"gatsby-plugin"
],
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1",
"publish": "npm login"
},
"repository": {
"type": "git",
"url": "git+https://github.com/pauliescanlon/gatsby-theme-terminal.git"
},
"bugs": {
"url": "https://github.com/pauliescanlon/gatsby-theme-terminal/issues"
},
"homepage": "https://gatsby-theme-terminal.netlify.com/",
"main": "index.js"
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/logo/index.js
================================================
export { Logo } from './logo'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/logo/logo.js
================================================
/** @jsx jsx */
import { jsx } from 'theme-ui'
export const Logo = () => <span />
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/main/index.js
================================================
export { Main } from './main'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/main/main.js
================================================
import React, { Fragment, useContext } from 'react'
import PropTypes from 'prop-types'
import { MDXProvider } from '@mdx-js/react'
import Prism from '@theme-ui/prism'
import { Link as GatsbyLink } from 'gatsby'
import { Context } from '../../context'
import { Nav } from '../nav'
import { useConfig } from '../../data'
// Mdx components
import * as themeUiComponents from 'theme-ui'
import { GatsbyImage, getImage } from 'gatsby-plugin-image'
import { Container, Box, Close, Image, MenuButton, Link } from 'theme-ui'
import { transparentize } from '@theme-ui/color'
// Theme specific components
import { Logo } from '../logo'
import { SiteMetaData } from '../site-metadata'
import { SourceList } from '../source-list'
import { SourceDays } from '../source-days'
import { SourceMonths } from '../source-months'
import { SourceWords } from '../source-words'
import { SourceTags } from '../source-tags'
const components = {
a: ({ href, children }) => {
// If it's an external url use Link and target _blank
if (href.match(/^(http|https):/g)) {
return (
<Link href={href} target="_blank" rel="noopener">
{children}
</Link>
)
}
// if it's a # use Link which will fires an anchorScroll in gatsby-browser
if (href.match(/#/gi)) {
return <Link href={href}>{children}</Link>
}
// if it's anything else use GatsbyLink
return (
<Link as={GatsbyLink} to={href}>
{children}
</Link>
)
},
pre: ({ children }) => <Fragment>{children}</Fragment>,
code: Prism,
Fragment,
SiteMetaData,
SourceList,
SourceDays,
SourceMonths,
SourceWords,
SourceTags,
GatsbyImage: (props) => <GatsbyImage alt={props.alt} image={getImage(props.image)} />,
...themeUiComponents,
}
export const Main = ({ children }) => {
const {
site: {
siteMetadata: {
config: { sidebarWidth },
},
},
} = useConfig()
const {
state: { isNavOpen },
dispatch,
} = useContext(Context)
return (
<Fragment>
<Box
as="header"
sx={{
alignItems: 'center',
backgroundColor: 'background',
borderBottom: (theme) => `${theme.borderWidths[1]}px solid ${theme.colors.surface}`,
display: 'flex',
justifyContent: 'space-between',
height: (theme) => `${theme.space[5]}px`,
ml: [0, 0, 0, sidebarWidth],
overflow: 'hidden',
position: 'fixed',
px: [3, 4],
width: ['100%', '100%', '100%', `calc(100% - ${sidebarWidth}px)`],
zIndex: 997,
}}
>
<Box
sx={{
alignItems: 'center',
display: ['flex', 'flex', 'flex', 'none'],
}}
>
<Logo />
</Box>
<Box
sx={{
alignItems: 'center',
display: ['flex', 'flex', 'flex', 'none'],
flexBasis: '100%',
justifyContent: 'flex-end',
}}
>
<MenuButton aria-label="Toggle Menu" onClick={() => dispatch({ type: 'openNav' })} />
</Box>
</Box>
<Container
sx={{
margin: '0 auto',
maxWidth: 1200,
}}
>
<Box
sx={{
backgroundColor: 'background',
height: '100%',
left: [
isNavOpen ? '0px' : `-${sidebarWidth}px`,
isNavOpen ? '0px' : `-${sidebarWidth}px`,
isNavOpen ? '0px' : `-${sidebarWidth}px`,
'0px',
],
position: 'fixed',
transition: '.3s ease-in-out left',
width: sidebarWidth,
zIndex: 999,
}}
>
<Box
sx={{
borderRight: (theme) => `${theme.borderWidths[1]}px solid ${theme.colors.surface}`,
height: '100%',
left: [
`${isNavOpen ? 0 : `-${sidebarWidth}px`}`,
`${isNavOpen ? 0 : `-${sidebarWidth}px`}`,
`${isNavOpen ? 0 : `-${sidebarWidth}px`}`,
0,
],
transition: '.3s ease-in-out left',
position: 'relative',
}}
>
<Nav />
</Box>
</Box>
<Box
role="button"
tabIndex="0"
sx={{
backgroundColor: transparentize('black', 0.2),
display: [isNavOpen ? 'flex' : 'none', isNavOpen ? 'flex' : 'none', isNavOpen ? 'flex' : 'none', 'none'],
height: '100%',
justifyContent: 'flex-end',
px: [3, 4],
py: 2,
position: 'fixed',
transition: '.2s linear background-color',
width: '100%',
zIndex: 998,
':focus': {
outline: 'none',
backgroundColor: transparentize('black', 0.4),
},
}}
onClick={() => dispatch({ type: 'closeNav' })}
onKeyDown={(event) => (event.key === 'Enter' ? dispatch({ type: 'closeNav' }) : {})}
>
<Close />
</Box>
<MDXProvider components={components}>
<Box
as="main"
sx={{
display: 'block',
ml: [0, 0, 0, sidebarWidth],
px: [3, 4],
py: 6,
transition: '.3s ease-in-out margin-left',
}}
>
{children}
</Box>
</MDXProvider>
</Container>
</Fragment>
)
}
Main.propTypes = {
/** React children */
children: PropTypes.any,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/nav/index.js
================================================
export { Nav } from './nav'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/nav/nav.js
================================================
import React, { Fragment } from 'react'
import { Box, NavLink } from 'theme-ui'
import { Link as GatsbyLink } from 'gatsby'
import { useNavigation } from '../../data'
import { Logo } from '../logo'
export const Nav = () => {
const {
allMdx: { edges },
} = useNavigation()
const navigation = edges.reduce((routes, route) => {
return route.node.fields.slug === '/' ? [route, ...routes] : [...routes, route]
}, [])
return (
<Fragment>
<Box
sx={{
alignItems: 'center',
display: 'flex',
height: (theme) => `${theme.space[5]}px`,
justifyContent: ['flex-start', 'flex-start', 'flex-start', 'flex-end'],
overFlow: 'hidden',
px: 4,
}}
>
<Logo />
</Box>
<Box
as="nav"
sx={{
height: '100%',
py: 3,
px: 4,
}}
>
<Box
as="ul"
sx={{
listStyle: 'none',
mt: 2,
p: 0,
}}
>
{navigation.map((route, index) => {
const {
frontmatter: { navigationLabel },
fields: { slug },
} = route.node
return (
<Box
key={index}
as="li"
sx={{
textAlign: ['left', 'left', 'left', 'right'],
}}
>
<NavLink as={GatsbyLink} to={slug}>
{navigationLabel}
</NavLink>
</Box>
)
})}
</Box>
</Box>
</Fragment>
)
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/page-element/index.js
================================================
export { PageElement } from './page-element'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/page-element/page-element.js
================================================
import React, { useEffect } from 'react'
import { Global, css } from '@emotion/react'
import { Fragment } from 'react'
import { useConfig } from '../../data'
export const PageElement = ({ children }) => {
useEffect(() => {
window.scrollTo({ top: 0 })
}, [])
const {
site: {
siteMetadata: { siteUrl },
},
} = useConfig()
return (
<Fragment>
<Global
styles={css`
@font-face {
font-family: 'Inconsolata';
src: url('${siteUrl}/fonts/Inconsolata-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Inconsolata';
src: url('${siteUrl}/fonts/Inconsolata-Bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
}
`}
/>
{children}
</Fragment>
)
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/seo/index.js
================================================
export { Seo } from './seo'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/seo/seo.js
================================================
import React from 'react'
import PropTypes from 'prop-types'
import { Helmet } from 'react-helmet'
export const Seo = ({ type, title, titleTemplate, description, siteUrl, canonical, image, path, keywords, lang }) => {
const formatTitleTemplate = `${title} ${titleTemplate ? `| ${titleTemplate}` : ''}`
return (
<Helmet>
<html lang={lang} />
<title>{formatTitleTemplate}</title>
<link rel="canonical" href={`${siteUrl}${canonical}`} />
<meta name="description" content={description} />
<meta name="image" content={image} />
<meta name="image:alt" content={description} />
<meta name="gatsby-theme" content="@pauliescanlon/gatsby-theme-terminal" />
<meta name="keywords" content={keywords ? keywords.join(', ') : null} />
{/* Facebook */}
<meta property="og:type" content={type} />
<meta property="og:title" content={formatTitleTemplate} />
<meta property="og:url" content={`${siteUrl}${path ? path : ''}`} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image} />
<meta property="og:image:alt" content={description}></meta>
{/* Twitter */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={formatTitleTemplate} />
<meta name="twitter:url" content={`${siteUrl}${path ? path : ''}`} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={image} />
<meta name="twitter:image:alt" content={description}></meta>
{/* favicon */}
<link
rel="icon"
type="image/png"
sizes="16x16"
href={`${siteUrl}/images/favicon-16x16.png`}
data-react-helmet="true"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href={`${siteUrl}/images/favicon-32x32.png`}
data-react-helmet="true"
/>
</Helmet>
)
}
Seo.propTypes = {
/** The type of meta - useful for Facebook */
type: PropTypes.oneOf(['website', 'article']),
/** The site title */
title: PropTypes.string.isRequired,
/** The site individual route */
titleTemplate: PropTypes.string.isRequired,
/** The site description */
description: PropTypes.string.isRequired,
/** The site URL */
siteUrl: PropTypes.string.isRequired,
/** The canonical URL */
canonical: PropTypes.string.isRequired,
/** Image url to use for opengraph image */
image: PropTypes.string,
/** Absolute URL path */
path: PropTypes.string.isRequired,
/** Keywords to use in meta keywords */
keywords: PropTypes.arrayOf(PropTypes.string),
/** Lang to use as meta lang */
lang: PropTypes.string,
}
Seo.defaultProps = {
lang: 'en',
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/site-metadata/index.js
================================================
export { SiteMetaData } from './site-metadata'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/site-metadata/site-metadata.js
================================================
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { useConfig } from '../../data'
export const SiteMetaData = ({ children }) => {
const {
site: { siteMetadata },
} = useConfig()
return <Fragment>{children(siteMetadata)}</Fragment>
}
SiteMetaData.propTypes = {
/** React children */
children: PropTypes.func,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-article/index.js
================================================
export { SourceArticle } from './source-article'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-article/source-article.js
================================================
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { MDXRenderer } from 'gatsby-plugin-mdx'
import { MDXProvider } from '@mdx-js/react'
import { Heading, Badge, Text, Flex, Box, Divider, Alert } from '@theme-ui/components'
import { mix } from '@theme-ui/color'
import { format } from 'date-fns'
import { Main } from '../main'
import { GatsbyImage } from 'gatsby-plugin-image'
const formatDate = (date) => format(new Date(date), 'd-MMM-u')
export const SourceArticle = ({
title,
tags,
date,
dateModified,
author,
isPrivate,
featuredImage,
featuredImageUrl,
embedded,
body,
timeToRead,
wordCount,
slug,
}) => {
return (
<Main>
{title ? (
<Fragment>
{isPrivate && (
<Fragment>
<Alert variant="error" sx={{ mb: 4 }}>
This is a private post
</Alert>
</Fragment>
)}
<Box sx={{ mb: 4 }}>
{featuredImage && featuredImage.childImageSharp && (
<GatsbyImage alt={`${title}-image`} image={featuredImage.childImageSharp.gatsbyImageData} />
)}
{featuredImageUrl && featuredImageUrl.childImageSharp && (
<GatsbyImage alt={`${title}-image`} image={featuredImageUrl.childImageSharp.gatsbyImageData} />
)}
</Box>
<Heading as="h1" variant="styles.h1" sx={{ mb: 4 }}>
{title}
</Heading>
<Flex sx={{ flexWrap: 'wrap', mb: 1 }}>
<Box
sx={{
width: ['100%', '50%'],
}}
>
{date && (
<Text as="div" sx={{ color: 'muted' }}>
Date published: {formatDate(date)}
</Text>
)}
</Box>
<Box
sx={{
width: ['100%', '50%'],
}}
>
{dateModified && (
<Text
as="div"
sx={{
color: 'muted',
textAlign: ['left', 'right'],
}}
>
Date modified: {formatDate(dateModified)}
</Text>
)}
</Box>
</Flex>
<Flex sx={{ flexWrap: 'wrap', mb: 3 }}>
<Box
sx={{
width: ['100%', '50%'],
}}
>
<Text as="div" sx={{ color: 'muted' }}>{`${timeToRead} min read / ${wordCount.words} words`}</Text>
</Box>
{author && (
<Box
sx={{
width: ['100%', '50%'],
}}
>
<Text as="div" sx={{ color: 'muted', textAlign: ['left', 'right'] }}>
Author: {author}
</Text>
</Box>
)}
</Flex>
</Fragment>
) : null}
{tags ? (
<Box sx={{ mb: 3 }}>
{tags.map((tag, index) => (
<Badge
key={index}
variant="primary"
sx={{
mb: 2,
mr: 2,
color: mix('muted', 'primary', `${index / tags.length}`),
borderColor: mix('muted', 'primary', `${index / tags.length}`),
}}
>
{tag}
</Badge>
))}
</Box>
) : null}
<MDXProvider>
<MDXRenderer embedded={embedded}>{body}</MDXRenderer>
</MDXProvider>
</Main>
)
}
SourceArticle.propTypes = {
/** Title frommatter" */
title: PropTypes.string,
/** Tags from frontmatter */
tags: PropTypes.arrayOf(PropTypes.string),
/** Date from frontmatter */
date: PropTypes.string,
/** DateModified from frontmatter */
dateModified: PropTypes.string,
/** Author from frontmatter */
author: PropTypes.string,
/** isPrivate from frontMatter */
isPrivate: PropTypes.bool,
/** FeaturedImage from frontmatter */
featuredImage: PropTypes.any,
/** featuredImageUrl from frontmatter */
featuredImageUrl: PropTypes.any,
/** embeddedImage array from SourceLayout */
embedded: PropTypes.any,
/** body from SourceLayout */
body: PropTypes.any,
/** timeToRead from SourceLayout */
timeToRead: PropTypes.number,
/** wordCount from SourceLayout */
wordCount: PropTypes.shape({
words: PropTypes.number,
}),
/** slug from SourceLayout */
slug: PropTypes.string,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-days/index.js
================================================
export { SourceDays } from './source-days'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-days/source-days.js
================================================
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { useDates } from '../../data'
import { graphql, useStaticQuery } from 'gatsby'
const name = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']
const abbreviation = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
const initial = ['m', 't', 'w', 't', 'f', 's', 's']
const createDayObject = (day, year) => {
return {
year: year,
name: name[day],
abbreviation: abbreviation[day],
initial: initial[day],
number: day === 0 ? 7 : day,
count: -1,
percent: 0,
}
}
export const SourceDays = ({ filter, children }) => {
const defaultValues = name.map((_, index) => createDayObject(index, 0))
const count = useDates(filter)
.reduce((items, item) => {
const {
node: {
frontmatter: { date },
},
} = item
let day = new Date(date).getDay()
let year = new Date(date).getFullYear()
items[year] = items[year] || [...defaultValues]
items[year].push(createDayObject(day, year))
return items
}, [])
.map((year) => {
let yearValue = year.reduce((a, b) => (b.year !== 0 ? (a = b.year) : null))
return Object.values(
year.reduce((items, item) => {
const { name } = item
items[name] = items[name] || {
...item,
year: yearValue,
}
items[name].count += 1
return items
}, {}),
)
})
const days = Object.values(
count.map((year) => {
let total = year.reduce((a, b) => ({ count: a.count + b.count }))
return year.map((day) => {
return {
...day,
percent: Math.round((day.count / total.count) * 100),
}
})
}),
)
return <Fragment>{days.length ? children(days) : null}</Fragment>
}
SourceDays.propTypes = {
/** A string used as a filter for the allMdx GraphQL query */
filter: PropTypes.string,
/** React children */
children: PropTypes.func,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-list/index.js
================================================
export { SourceList } from './source-list'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-list/source-list.js
================================================
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { useSource } from '../../data'
export const SourceList = ({ filter, children }) => {
return <Fragment>{children(useSource(filter))}</Fragment>
}
SourceList.propTypes = {
/** A string used as a filter for the allMdx GraphQL query */
filter: PropTypes.string,
/** React children */
children: PropTypes.func,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-months/index.js
================================================
export { SourceMonths } from './source-months'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-months/source-months.js
================================================
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { useDates } from '../../data'
const name = [
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'september',
'october',
'november',
'december',
]
const abbreviation = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
const initial = ['j', 'f', 'm', 'a', 'm', 'j', 'j', 'a', 's', 'o', 'n', 'd']
const createMonthObject = (month, year) => {
return {
year: year,
name: name[month],
abbreviation: abbreviation[month],
initial: initial[month],
count: -1,
percent: 0,
}
}
export const SourceMonths = ({ filter, children }) => {
const defaultValues = name.map((_, index) => createMonthObject(index, 0))
const count = useDates(filter)
.reduce((items, item) => {
let month = new Date(item.node.frontmatter.date).getMonth()
let year = new Date(item.node.frontmatter.date).getFullYear()
items[year] = items[year] || [...defaultValues]
items[year].push(createMonthObject(month, year))
return items
}, [])
.map((year) => {
let yearValue = year.reduce((a, b) => (b.year !== 0 ? (a = b.year) : null))
return Object.values(
year.reduce((items, item) => {
const { name } = item
items[name] = items[name] || {
...item,
year: yearValue,
}
items[name].count += 1
return items
}, {}),
)
})
const months = Object.values(
count.map((year) => {
let total = year.reduce((a, b) => ({ count: a.count + b.count }))
return year.map((month) => {
return {
...month,
percent: Math.round((month.count / total.count) * 100),
}
})
}),
)
return <Fragment>{months.length ? children(months) : null}</Fragment>
}
SourceMonths.propTypes = {
/** A string used as a filter for the allMdx GraphQL query */
filter: PropTypes.string,
/** React children */
children: PropTypes.func,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-tags/index.js
================================================
export { SourceTags } from './source-tags'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-tags/source-tags.js
================================================
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { useTags } from '../../data'
export const SourceTags = ({ filter, children }) => {
const count = Object.values(
useTags(filter)
.filter((edge) => edge.node.frontmatter.tags)
.reduce((items, item) => {
const { tags } = item.node.frontmatter
tags.forEach((tag) => {
items.push({
name: tag,
count: 1,
percent: 1,
})
})
return items
}, [])
.reduce((items, item) => {
const { count, name } = item
items[name] = items[name] || { count: 0, name }
items[name].count += count
return items
}, []),
)
const total = count.reduce((a, b) => a + b.count, 0)
const tags = count.map((item) => {
return {
...item,
percent: Math.round((item.count / total) * 100),
}
})
return <Fragment>{tags.length ? children(tags) : null}</Fragment>
}
SourceTags.propTypes = {
/** A string used as a filter for the allMdx GraphQL query */
filter: PropTypes.string,
/** React children */
children: PropTypes.func,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-words/index.js
================================================
export { SourceWords } from './source-words'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/components/source-words/source-words.js
================================================
import React, { Fragment } from 'react'
import PropTypes from 'prop-types'
import { useWords } from '../../data'
const name = [
'january',
'february',
'march',
'april',
'may',
'june',
'july',
'august',
'september',
'october',
'november',
'december',
]
const abbreviation = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
const initial = ['j', 'f', 'm', 'a', 'm', 'j', 'j', 'a', 's', 'o', 'n', 'd']
const createMonthObject = (month, year, words) => {
return {
year: year,
name: name[month],
abbreviation: abbreviation[month],
initial: initial[month],
words: words,
}
}
export const SourceWords = ({ filter, children }) => {
const defaultValues = name.map((_, index) => createMonthObject(index, 0, 0))
const mdx = useWords(filter)
const wordCountTotal = mdx.reduce((a, b) => a + b.node.wordCount.words, 0)
const wordCountAverage = Math.round(wordCountTotal / mdx.length)
const timeToReadTotal = mdx.reduce((a, b) => a + b.node.timeToRead, 0)
const timeToReadAverage = Math.round(timeToReadTotal / mdx.length)
const wordCountHighest = Math.max(...mdx.map((item) => item.node.wordCount.words))
const wordCountLowest = Math.min(...mdx.map((item) => item.node.wordCount.words))
const wordCountByMonth = mdx
.reduce((items, item) => {
let month = new Date(item.node.frontmatter.date).getMonth()
let year = new Date(item.node.frontmatter.date).getFullYear()
let words = item.node.wordCount.words
items[year] = items[year] || [...defaultValues]
items[year].push(createMonthObject(month, year, words))
return items
}, [])
.map((year) => {
let yearValue = year.reduce((a, b) => (b.year !== 0 ? (a = b.year) : null))
return Object.values(
year.reduce((items, item) => {
const { name, words } = item
items[name] = items[name] || {
...item,
year: yearValue,
}
items[name].words += words
return items
}, {}),
)
})
return (
<Fragment>
{mdx.length
? children({
wordCountTotal: wordCountTotal,
wordCountAverage: wordCountAverage,
wordCountHighest: wordCountHighest,
wordCountLowest: wordCountLowest,
timeToReadTotal: timeToReadTotal,
timeToReadAverage: timeToReadAverage,
sourceTotal: mdx.length,
wordCountByMonth: wordCountByMonth,
})
: null}
</Fragment>
)
}
SourceWords.propTypes = {
/** A string used as a filter for the allMdx GraphQL query */
filter: PropTypes.string,
/** React children */
children: PropTypes.func,
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/context/index.js
================================================
import React from 'react'
//https://medium.com/@seantheurgel/react-hooks-as-state-management-usecontext-useeffect-usereducer-a75472a862fe
const initialState = { isNavOpen: false }
const reducer = (state, actions) => {
switch (actions.type) {
case 'openNav':
return { ...state, isNavOpen: true }
case 'closeNav':
return { ...state, isNavOpen: false }
default:
return
}
}
export const Context = React.createContext(initialState)
export const ContextProvider = ({ children }) => {
const [state, dispatch] = React.useReducer(reducer, initialState)
return <Context.Provider value={{ state, dispatch }}>{children}</Context.Provider>
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/data/index.js
================================================
export { useConfig } from './use-config'
export { useNavigation } from './use-navigation'
export { useDates } from './use-dates'
export { useTags } from './use-tags'
export { useWords } from './use-words'
export { useSource } from './use-source'
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/data/use-config.js
================================================
import { useStaticQuery, graphql } from 'gatsby'
export const useConfig = () => {
return useStaticQuery(
graphql`
query {
site {
siteMetadata {
name
description
keywords
siteUrl
siteImage
profileImage
lang
config {
sidebarWidth
}
}
}
}
`,
)
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/data/use-dates.js
================================================
import { useStaticQuery, graphql } from 'gatsby'
export const useDates = (filter) => {
const query = useStaticQuery(graphql`
query dates {
allMdx(
filter: { frontmatter: { status: { ne: "draft" }, navigationLabel: { eq: null } } }
sort: { order: DESC, fields: [frontmatter___date] }
) {
edges {
node {
frontmatter {
date
status
isPrivate
}
fields {
slug
}
}
}
}
}
`)
if (!filter) return query.allMdx.edges.filter((edge) => edge.node.frontmatter.isPrivate !== true)
return query.allMdx.edges
.map((edge) => edge)
.filter((edge) => edge.node.fields.slug.includes(filter) && edge.node.frontmatter.isPrivate !== true)
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/data/use-navigation.js
================================================
import { useStaticQuery, graphql } from 'gatsby'
export const useNavigation = () => {
return useStaticQuery(
graphql`
query navigation {
allMdx(filter: { frontmatter: { navigationLabel: { ne: null } } }) {
edges {
node {
id
fields {
slug
}
frontmatter {
title
navigationLabel
}
}
}
}
}
`,
)
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/data/use-source.js
================================================
import { useStaticQuery, graphql } from 'gatsby'
export const useSource = (filter) => {
const query = useStaticQuery(graphql`
query source {
allMdx(
filter: { frontmatter: { status: { ne: "draft" }, navigationLabel: { eq: null } } }
sort: { order: DESC, fields: [frontmatter___date] }
) {
edges {
node {
id
body
excerpt
timeToRead
wordCount {
words
}
frontmatter {
title
tags
date
dateModified
author
status
isPrivate
url
misc
pinned
featuredImage {
childImageSharp {
gatsbyImageData(layout: FULL_WIDTH)
}
}
}
featuredImageUrl {
childImageSharp {
gatsbyImageData(layout: FULL_WIDTH)
}
}
fields {
slug
}
}
}
}
}
`)
if (!filter)
return query.allMdx.edges.filter((edge) => {
return edge.node.frontmatter.isPrivate !== true
})
return query.allMdx.edges
.map((edge) => edge)
.filter((edge) => {
return edge.node.fields.slug.includes(filter) && edge.node.frontmatter.isPrivate !== true
})
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/data/use-tags.js
================================================
import { useStaticQuery, graphql } from 'gatsby'
export const useTags = (filter) => {
const query = useStaticQuery(graphql`
query tags {
allMdx(
filter: { frontmatter: { status: { ne: "draft" }, navigationLabel: { eq: null } } }
sort: { order: DESC, fields: [frontmatter___date] }
) {
edges {
node {
frontmatter {
tags
date
status
isPrivate
}
fields {
slug
}
}
}
}
}
`)
if (!filter) return query.allMdx.edges.filter((edge) => edge.node.frontmatter.isPrivate !== true)
return query.allMdx.edges
.map((edge) => edge)
.filter((edge) => edge.node.fields.slug.includes(filter) && edge.node.frontmatter.isPrivate !== true)
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/data/use-words.js
================================================
import { useStaticQuery, graphql } from 'gatsby'
export const useWords = (filter) => {
const query = useStaticQuery(graphql`
query words {
allMdx(
filter: { frontmatter: { status: { ne: "draft" }, navigationLabel: { eq: null } } }
sort: { order: DESC, fields: [frontmatter___date] }
) {
edges {
node {
timeToRead
wordCount {
words
}
frontmatter {
date
status
isPrivate
}
fields {
slug
}
}
}
}
}
`)
if (!filter) return query.allMdx.edges.filter((edge) => edge.node.frontmatter.isPrivate !== true)
return query.allMdx.edges
.map((edge) => edge)
.filter((edge) => edge.node.fields.slug.includes(filter) && edge.node.frontmatter.isPrivate !== true)
}
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/gatsby-plugin-theme-ui/index.js
================================================
import codeTheme from '@theme-ui/prism/presets/night-owl.json'
import { lighten } from '@theme-ui/color'
const theme = {
borderWidths: [0, 1, 4],
colors: {
text: '#ffffff',
background: '#282a36',
muted: '#8394ca',
highlight: '#5a6084',
surface: '#323442',
primary: '#ff79c6',
secondary: '#8be9fd',
success: '#50fa7b',
error: '#ff5555',
black: '#000000',
},
fonts: {
body: 'Inconsolata, monospace',
heading: 'Inconsolata, monospace',
code: 'monospace',
},
fontWeights: {
body: 400,
heading: 700,
bold: 700,
},
lineHeights: {
body: 1.75,
heading: 1.125,
},
fontSizes: [12, 16, 18, 28],
space: [0, 4, 8, 16, 32, 48, 64],
shadows: [
`0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)`,
`0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)`,
`0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23)`,
`0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22)`,
`0 19px 38px rgba(0,0,0,0.30), 0 15px 12px rgba(0,0,0,0.22)`,
],
styles: {
root: {
fontFamily: 'body',
fontWeight: 'body',
fontSize: 1,
lineHeight: 'body',
'input:-webkit-autofill:first-line': {
color: (theme) => `${theme.colors.primary}!important`,
},
a: {
variant: 'styles.focus',
},
pre: {
...codeTheme,
fontFamily: 'code',
borderRadius: 0,
overflow: 'auto',
fontSize: '13px',
overflow: 'auto',
p: 3,
my: '48px!important',
},
},
focus: {
transition: '.2s linear box-shadow',
':focus': {
outline: 'none',
boxShadow: (theme) => `0 2px 0 0 ${theme.colors.primary}`,
},
},
h1: {
variant: 'text.specialHeading',
color: 'primary',
fontSize: 3,
},
h2: {
variant: 'text.specialHeading',
color: 'primary',
},
h3: {
variant: 'text.heading',
color: 'secondary',
},
h4: {
variant: 'text.heading',
color: 'text',
},
h5: {
variant: 'text.heading',
color: 'success',
},
h6: {
variant: 'text.heading',
color: 'error',
},
p: {
mt: 0,
mb: 3,
code: {
variant: 'styles.code',
},
},
small: {
color: 'muted',
fontSize: 0,
},
a: {
color: 'muted',
variant: 'styles.focus',
},
code: {
fontFamily: 'code',
color: 'inherit',
backgroundColor: 'surface',
fontSize: '13px',
p: 1,
},
hr: {
border: 'none',
mt: 0,
mb: 3,
},
ol: {
mt: 0,
mb: 3,
pl: 4,
},
ul: {
mt: 0,
mb: 3,
// special case so ul lines up with ol
pl: '24px',
listStyle: 'square',
},
li: {
mb: 1,
code: {
variant: 'styles.code',
},
pre: {
variant: 'styles.pre',
},
},
table: {
borderCollapse: 'collapse',
mb: 3,
border: 'none',
thead: {
backgroundColor: lighten('background', 0.03),
tr: {
th: {
border: (theme) => `${theme.borderWidths[1]}px solid ${theme.colors.surface}`,
padding: (theme) => `${theme.space[2]}px ${theme.space[3]}px`,
},
},
td: {
color: '#666',
},
},
tbody: {
'tr:nth-of-type(even)': {
backgroundColor: lighten('background', 0.01),
},
tr: {
td: {
padding: (theme) => `${theme.space[2]}px ${theme.space[3]}px`,
border: (theme) => `${theme.borderWidths[1]}px solid ${theme.colors.surface}`,
},
},
},
},
blockquote: {
borderRadius: 0,
borderLeftColor: 'muted',
borderLeftStyle: 'solid',
borderLeftWidth: 2,
mt: 0,
ml: 2,
mb: 3,
mr: 0,
p: {
p: 3,
mb: 0,
},
},
progress: {
primary: {
backgroundColor: 'surface',
color: 'primary',
},
secondary: {
backgroundColor: 'surface',
color: 'secondary',
},
success: {
backgroundColor: 'surface',
color: 'success',
},
error: {
backgroundColor: 'surface',
color: 'error',
},
},
donut: {
primary: {
color: 'primary',
},
secondary: {
color: 'secondary',
},
success: {
color: 'success',
},
error: {
color: 'error',
},
},
spinner: {
primary: {
color: 'primary',
},
secondary: {
color: 'secondary',
},
success: {
color: 'success',
},
error: {
color: 'error',
},
},
},
// components
alerts: {
primary: {
fontWeight: 'body',
borderRadius: 0,
px: 3,
py: 2,
color: 'text',
backgroundColor: 'primary',
},
secondary: {
variant: 'alerts.primary',
color: 'background',
backgroundColor: 'secondary',
},
success: {
variant: 'alerts.primary',
color: 'background',
backgroundColor: 'success',
},
error: {
variant: 'alerts.primary',
backgroundColor: 'error',
},
},
badges: {
primary: {
color: 'primary',
borderColor: 'primary',
fontSize: 0,
borderRadius: 0,
borderWidth: 1,
borderStyle: 'solid',
backgroundColor: 'transparent',
px: 2,
py: 1,
},
secondary: {
variant: 'badges.primary',
color: 'secondary',
borderColor: 'secondary',
},
success: {
variant: 'badges.primary',
color: 'success',
borderColor: 'success',
},
error: {
variant: 'badges.primary',
color: 'error',
borderColor: 'error',
},
},
buttons: {
focus: {
':focus': {
outline: 'none',
transition: '.2s linear box-shadow',
boxShadow: (theme) => `0 0 0 2px ${theme.colors.muted}`,
},
},
primary: {
borderRadius: 0,
cursor: 'pointer',
minWidth: 120,
px: 3,
py: 2,
variant: 'buttons.focus',
},
secondary: {
variant: 'buttons.primary',
color: 'background',
backgroundColor: 'secondary',
},
success: {
variant: 'buttons.primary',
color: 'background',
backgroundColor: 'success',
},
error: {
variant: 'buttons.primary',
backgroundColor: 'error',
},
ghost: {
variant: 'buttons.primary',
backgroundColor: 'background',
},
icon: {
cursor: 'pointer',
borderRadius: 0,
variant: 'buttons.focus',
},
close: {
cursor: 'pointer',
borderRadius: 0,
variant: 'buttons.focus',
},
menu: {
cursor: 'pointer',
borderRadius: 0,
variant: 'buttons.focus',
},
},
cards: {
primary: {
boxShadow: 0,
backgroundColor: 'surface',
},
},
links: {
variant: 'styles.a',
nav: {
variant: 'styles.a',
fontWeight: 'body',
':before': {
pr: [2, 2, 2, 0],
content: [`"-"`, `"-"`, `"-"`, `""`],
},
':after': {
pl: [0, 0, 0, 2],
content: [`""`, `""`, `""`, `"-"`],
},
':hover': {
color: 'text',
transition: '.2s linear color',
},
'&[aria-current="page"]': {
color: 'text',
pointerEvents: 'none',
},
},
},
text: {
color: 'text',
heading: {
fontFamily: 'heading',
fontWeight: 'heading',
fontSize: 2,
mt: 0,
mb: 3,
a: {
color: 'inherit',
},
},
specialHeading: {
variant: 'text.heading',
'::before': {
content: `'→'`,
color: 'success',
mr: 2,
},
'::after': {
content: `'()'`,
color: 'secondary',
ml: 1,
},
},
},
images: {
avatar: {},
},
forms: {
label: {
fontWeight: 'bold',
},
input: {
borderRadius: 0,
borderColor: 'muted',
variant: 'styles.focus',
},
select: {
borderRadius: 0,
borderColor: 'muted',
variant: 'styles.focus',
},
textarea: {
borderRadius: 0,
borderColor: 'muted',
variant: 'styles.focus',
},
slider: {
backgroundColor: 'muted',
},
radio: {
color: 'muted',
backgroundColor: 'background',
},
checkbox: {
color: 'muted',
backgroundColor: 'background',
},
},
hr: {},
embed: {},
sizes: {
container: {},
},
layouts: {
container: {},
},
messages: {
default: {
borderRadius: 0,
backgroundColor: 'surface',
},
primary: {
variant: 'messages.default',
borderLeftColor: 'primary',
},
secondary: {
variant: 'messages.default',
borderLeftColor: 'secondary',
},
success: {
variant: 'messages.default',
borderLeftColor: 'success',
},
error: {
variant: 'messages.default',
borderLeftColor: 'error',
},
},
}
export default theme
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/layouts/page-layout.js
================================================
/** @jsx jsx */
import { Fragment } from 'react'
import { jsx } from 'theme-ui'
import { Location } from '@reach/router'
import { ContextProvider } from '../context'
import { Seo } from '../components/seo'
import { Main } from '../components/main'
import { useConfig } from '../data'
const PageLayout = ({ children }) => {
const {
site: {
siteMetadata: { name, description, keywords, siteUrl, siteImage, lang },
},
} = useConfig()
return (
<ContextProvider>
<Main>
<Location>
{({ location }) => {
const { pathname } = location
const titleTemplate = pathname.replace(/\//gm, '')
return (
<Fragment>
<Seo
type="website"
title={name}
titleTemplate={titleTemplate}
description={description}
siteUrl={siteUrl}
canonical={pathname}
image={siteImage}
path={pathname}
keywords={keywords || ['']}
lang={lang}
/>
</Fragment>
)
}}
</Location>
{children}
</Main>
</ContextProvider>
)
}
export default PageLayout
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/layouts/source-layout.js
================================================
import React, { Fragment } from 'react'
import { Location } from '@reach/router'
import { graphql } from 'gatsby'
import { ContextProvider } from '../context'
import { Seo } from '../components/seo'
import { SourceArticle } from '../components/source-article'
import { useConfig } from '../data'
import { transformImages } from '../utils'
const IMAGE_KEY = 'image'
const SourceLayout = ({
data: {
mdx: {
body,
excerpt,
frontmatter,
featuredImageUrl,
embeddedImageUrls,
fields: { slug },
timeToRead,
wordCount,
},
},
}) => {
const {
site: {
siteMetadata: { name, siteUrl, siteImage, lang },
},
} = useConfig()
const { title, tags, date, dateModified, author, isPrivate, featuredImage, embeddedImages } = frontmatter
const getSeoImage = () => {
if (featuredImage) {
return `${siteUrl}${featuredImage.childImageSharp.gatsbyImageData.images.fallback.src}`
}
if (featuredImageUrl) {
return `${siteUrl}${featuredImageUrl.childImageSharp.gatsbyImageData.images.fallback.src}`
}
return siteImage
}
const combinedEmbedded = [...(embeddedImages || []), ...(embeddedImageUrls || [])].filter((n) => n)
return (
<ContextProvider>
<Location>
{({ location }) => {
const { pathname } = location
return (
<Fragment>
<Seo
type="article"
title={name}
titleTemplate={title}
description={excerpt}
siteUrl={siteUrl}
canonical={slug}
image=""
image={getSeoImage()}
path={pathname}
keywords={tags || ['']}
lang={lang}
/>
<SourceArticle
title={title}
tags={tags}
date={date}
dateModified={dateModified}
author={author}
isPrivate={isPrivate}
featuredImage={featuredImage}
featuredImageUrl={featuredImageUrl}
embedded={transformImages(combinedEmbedded)}
body={body}
timeToRead={timeToRead}
wordCount={wordCount}
slug={slug}
/>
</Fragment>
)
}}
</Location>
</ContextProvider>
)
}
// {
// mdx(id: {eq: "ff24e77a-aa63-564b-a244-24e2298aa659"}) {
// frontmatter {
// url
// }
// }
// }
export const singleMdx = graphql`
query singleMdx($id: String) {
mdx(id: { eq: $id }) {
id
body
excerpt
timeToRead
wordCount {
words
}
slug
frontmatter {
title
tags
date
dateModified
author
status
isPrivate
url
misc
pinned
featuredImage {
childImageSharp {
gatsbyImageData(layout: FULL_WIDTH)
}
}
embeddedImages {
childImageSharp {
gatsbyImageData(layout: FULL_WIDTH)
}
}
}
featuredImageUrl {
childImageSharp {
gatsbyImageData(layout: FULL_WIDTH)
}
}
embeddedImageUrls {
childImageSharp {
gatsbyImageData
}
}
fields {
slug
}
}
}
`
export default SourceLayout
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/pages/404.js
================================================
import React from 'react'
export default () => <div>404 page not found</div>
================================================
FILE: @pauliescanlon/gatsby-theme-terminal/src/utils/index.js
================================================
const IMAGE_KEY = 'image'
export const transformImages = (imageArray) => {
if (Array.isArray(imageArray)) {
return imageArray.reduce((images, image, index) => {
images[`${IMAGE_KEY}${index + 1}`] =
images[`${IMAGE_KEY}${index + 1}`] || image
? image.url
? image.url[0].childImageSharp
: image.childImageSharp
: null
return images
}, {})
}
return {}
}
================================================
FILE: README.md
================================================
<a href="https://gatsbythemeterminal.gatsbyjs.io/" target="_blank">
<img src="https://gatsbythemeterminal.gatsbyjs.io/images/terminal-open-graph-image.jpg" alt="gatsby-theme-termninal main image" />
</a>
## gatsby-theme-terminal
Gatsby Theme Terminal aims to be a **zero component theme**. It provides _data_ components to aid in the abstraction of
presentational and data layers which together provide the most flexibility
The theme handles the data but how it's displayed is up to you!
You can create any page layout or component combination you like using your own components or components provided by
[theme-ui/components](https://theme-ui.com/components)
## 👀 Preview
- [Live Demo](https://gatsbythemeterminal.gatsbyjs.io/)
## 🚀 Getting started
To help you get started you can either clone the starter
[gatsby-starter-terminal](https://github.com/PaulieScanlon/gatsby-starter-terminal) or read the below.
### Install
```
npm install @pauliescanlon/gatsby-theme-terminal
```
### Install Peer Dependencies
```
npm install @mdx-js/mdx @mdx-js/react gatsby gatsby-plugin-mdx gatsby-source-filesystem react react-dom
```
## Setup
### gatsby-config.js
Add the `siteMetaData` and `@pauliescanlon/gatsby-theme-terminal` to your `gatsby-config.js`
```
// gatsby-config.js
module.exports = {
siteMetadata: {
name: "Your blog title",
description: "I like tech",
keywords: ["tech", "blog", "boop"],
siteUrl: 'https://gatsby-theme-terminal.netlify.com',
siteImage: 'name-of-open-graph-image.jpg', // pop an image in the static folder to use it as the og:image,
profileImage: 'name-of-profile-image.jpg'
lang: `eng`,
config: {
sidebarWidth: 240 // optional,
},
},
plugins: ['@pauliescanlon/gatsby-theme-terminal']
}
```
### directory structure
To add pages create `.mdx` files in the `src/pages` directory. You need at least one file called `index.mdx` located at
`src/pages` or you'll see a GraphQL error.
<!-- prettier-ignore -->
```
|-- src
|-- pages
|-- index.mdx
|-- about.mdx
|-- contact.mdx
```
### frontmatter setup
#### Pages
Pages must include `navigationLabel` in the `frontmatter`
```
// src/pages/about.mdx
---
navigationLabel: About
---
# About
This is about page
```
#### Theme options
Additional `.mdx` can be sourced from _anywhere_ outside the `pages` directory but you need to tell the theme where to
source these files from.
Use the `source` option in `gatsby-config.js`
```
// gatsby-config.js
...
plugins: [
{
resolve: `@pauliescanlon/gatsby-theme-terminal`,
options: {
source: [
{
name: "posts",
dir: "posts",
},
{
name: "projects",
dir: "projects",
},
] // can be an object or array of objects
},
},
],
}
```
Then create the relevant files and directories
<!-- prettier-ignore -->
```
|-- src
|-- pages
...
|-- posts
|--2020
|--02
|-- some-post.mdx
|-- featuredImage: markus-spiske-466ENaLuhLY-unsplash.jpg
|-- markus-spiske-FXFz-sW0uwo-unsplash.jpg
|-- projects
|-- some-project.mdx
```
Any file that is _not_ sourced from `pages` can contain any of the following `frontmatter` but a `title` is required,
this is how the theme distinguishes between pages and other `.mdx` files
<!-- prettier-ignore -->
```
// src/posts/2020/02/some-post.mdx
---
title: Some Post
tags: ["JavaScript", "React", "GatsbyJs", "HTML", "CSS", "theme-ui"]
date: 2020-01-01
dateModified: 20-20-2020
author: Paul Scanlon
status: draft // => means it won't be rendered
isPrivate: // => it will be rendered but you can use this prop as a filter
url: "https://example.com" // => could be an external url
misc: "Ahoy" // => use how you wish
pinned: false // => Could be used as a filter for pinned posts
featuredImage: markus-spiske-466ENaLuhLY-unsplash.jpg
featuredImageUrl: https://via.placeholder.com/936x528
embeddedImages:
- markus-spiske-FXFz-sW0uwo-unsplash.jpg
embeddedImageUrls:
- https://via.placeholder.com/468x264
---
```
### Embedded Images
By using the The `<GatsbyImage />` component from `gatsby-plugin-image` you can pass the image data queried by GraphQL
and pass it on via the `image` prop
The `gatsbyImageData`, data is available via `props.embedded.image(n)`
```
<GatsbyImage image={props.embedded.image1} />
```
You can also use the Theme UI `<Image />` component by passing it a `src`
```
<Image src={props.embedded.image1.gatsbyImageData.images.fallback.src} />
```
`image1` in this example would be `markus-spiske-FXFz-sW0uwo-unsplash.jpg`
EmbeddedImages can also be sourced from a remote url, in this case use the `<Image />` component and pass it the same
props
```
<Image src={props.embedded.image2.gatsbyImageData.images.fallback.src} />
```
### markdown
The theme supports the complete markdown spec and you can see how to use markdown in the
[demo](https://gatsbythemeterminal.gatsbyjs.io/markdown/)
### theme-ui/components
The theme supports _all_ the components provided by [theme-ui/components](https://theme-ui.com/components) and you can
see in the [demo](https://gatsbythemeterminal.gatsbyjs.io/theme-ui-components/) how they are used.
### gatsby-theme-terminal/components
The theme also comes with it's own components _but_... These are purely to provide access to the source nodes. What you
choose to render is completely up to you!
For example to display a list of _all_ files sourced from the `source` theme option you _could_ do something like this.
This component can be used in ANY `.mdx` file 😎
```javascript
<SourceList>
{(source) => (
<ul>
{source.map((edge, index) => {
const {
frontmatter: { title },
} = edge.node
return <li key={index}>{title}</li>
})}
</ul>
)}
</SourceList>
```
You can see more about how to use the theme components in the
[demo](https://gatsbythemeterminal.gatsbyjs.io/components/)
### Component Shadowing
There is very little to shadow because almost everything is exposed by the components but you might want to add your own
logo.
To do this create the following directories `@pauliescanlon/gatsby-theme-terminal/components/Logo` in the `src`
directory of your project and then create a `Logo.js` file. You can do anything you like in here.
```
|-- src
|-- @pauliescanlon
|-- gatsby-theme-terminal
|-- components
|-- Logo
|-- Logo.js
```
If you would like to customize any part of the theme you can do so by shadowing the theme file.
To do this create the following directory `src/gatsby-plugin-theme-ui` and then create an `index.js`
```javascript
// src/gatsby-plugin-theme-ui/index.js
import baseTheme from '@pauliescanlon/gatsby-theme-terminal/src/gatsby-plugin-theme-ui'
export default {
...baseTheme,
colors: {
...baseTheme.colors,
primary: '#FF4081',
secondary: '#03A9F4',
success: '#FFEB3B',
background: '#232323',
surface: '#393939',
},
}
```
### favicon
favicon(s) need to be saved in `static/images` and named `favicon-16x16.png` and `favicon-32x32.png` along with an
`.icon` file called `favicon.ico`
If you're using **gatsby-theme-terminal** in your project i'd love to hear from you
[@pauliescanlon](https://twitter.com/PaulieScanlon)
[](https://ko-fi.com/P5P31B7G8)
================================================
FILE: copy-readme.js
================================================
const fs = require('fs')
fs.copyFile('./README.md', './@pauliescanlon/gatsby-theme-terminal/README.md', (err) => {
if (err) {
throw err
}
console.log('README copied to theme ok!')
})
================================================
FILE: demo/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 gatsbyjs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: demo/README.md
================================================
<!-- AUTO-GENERATED-CONTENT:START (STARTER) -->
<p align="center">
<a href="https://www.gatsbyjs.org">
<img alt="Gatsby" src="https://www.gatsbyjs.org/monogram.svg" width="60" />
</a>
</p>
<h1 align="center">
Gatsby's default starter
</h1>
Kick off your project with this default boilerplate. This starter ships with the main Gatsby configuration files you might need to get up and running blazing fast with the blazing fast app generator for React.
_Have another more specific idea? You may want to check out our vibrant collection of [official and community-created starters](https://www.gatsbyjs.org/docs/gatsby-starters/)._
## 🚀 Quick start
1. **Create a Gatsby site.**
Use the Gatsby CLI to create a new site, specifying the default starter.
```shell
# create a new Gatsby site using the default starter
gatsby new my-default-starter https://github.com/gatsbyjs/gatsby-starter-default
```
1. **Start developing.**
Navigate into your new site’s directory and start it up.
```shell
cd my-default-starter/
gatsby develop
```
1. **Open the source code and start editing!**
Your site is now running at `http://localhost:8000`!
_Note: You'll also see a second link: _`http://localhost:8000/___graphql`_. This is a tool you can use to experiment with querying your data. Learn more about using this tool in the [Gatsby tutorial](https://www.gatsbyjs.org/tutorial/part-five/#introducing-graphiql)._
Open the `my-default-starter` directory in your code editor of choice and edit `src/pages/index.js`. Save your changes and the browser will update in real time!
## 🧐 What's inside?
A quick look at the top-level files and directories you'll see in a Gatsby project.
.
├── node_modules
├── src
├── .gitignore
├── .prettierrc
├── gatsby-browser.js
├── gatsby-config.js
├── gatsby-node.js
├── gatsby-ssr.js
├── LICENSE
├── package-lock.json
├── package.json
└── README.md
1. **`/node_modules`**: This directory contains all of the modules of code that your project depends on (npm packages) are automatically installed.
2. **`/src`**: This directory will contain all of the code related to what you will see on the front-end of your site (what you see in the browser) such as your site header or a page template. `src` is a convention for “source code”.
3. **`.gitignore`**: This file tells git which files it should not track / not maintain a version history for.
4. **`.prettierrc`**: This is a configuration file for [Prettier](https://prettier.io/). Prettier is a tool to help keep the formatting of your code consistent.
5. **`gatsby-browser.js`**: This file is where Gatsby expects to find any usage of the [Gatsby browser APIs](https://www.gatsbyjs.org/docs/browser-apis/) (if any). These allow customization/extension of default Gatsby settings affecting the browser.
6. **`gatsby-config.js`**: This is the main configuration file for a Gatsby site. This is where you can specify information about your site (metadata) like the site title and description, which Gatsby plugins you’d like to include, etc. (Check out the [config docs](https://www.gatsbyjs.org/docs/gatsby-config/) for more detail).
7. **`gatsby-node.js`**: This file is where Gatsby expects to find any usage of the [Gatsby Node APIs](https://www.gatsbyjs.org/docs/node-apis/) (if any). These allow customization/extension of default Gatsby settings affecting pieces of the site build process.
8. **`gatsby-ssr.js`**: This file is where Gatsby expects to find any usage of the [Gatsby server-side rendering APIs](https://www.gatsbyjs.org/docs/ssr-apis/) (if any). These allow customization of default Gatsby settings affecting server-side rendering.
9. **`LICENSE`**: Gatsby is licensed under the MIT license.
10. **`package-lock.json`** (See `package.json` below, first). This is an automatically generated file based on the exact versions of your npm dependencies that were installed for your project. **(You won’t change this file directly).**
11. **`package.json`**: A manifest file for Node.js projects, which includes things like metadata (the project’s name, author, etc). This manifest is how npm knows which packages to install for your project.
12. **`README.md`**: A text file containing useful reference information about your project.
## 🎓 Learning Gatsby
Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.org/). Here are some places to start:
- **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.org/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process.
- **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.org/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar.
## 💫 Deploy
[](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-default)
<!-- AUTO-GENERATED-CONTENT:END -->
================================================
FILE: demo/gatsby-browser.js
================================================
/**
* Implement Gatsby's Browser APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/
// You can delete this file if you're not using it
================================================
FILE: demo/gatsby-config.js
================================================
module.exports = {
siteMetadata: {
name: `gatsby-theme-terminal`,
description: `A zero component Gatsby theme for developers`,
keywords: [`gatsby`, `gatsbyjs`, `gatsby-theme`],
siteUrl: `https://gatsbythemeterminal.gatsbyjs.io`,
siteImage: `https://gatsbythemeterminal.gatsbyjs.io/images/terminal-open-graph-image.jpg`,
profileImage: `https://gatsbythemeterminal.gatsbyjs.io/images/terminal-profile-image.jpg`,
lang: `en`,
config: {
sidebarWidth: 280,
},
},
plugins: [
{
resolve: `@pauliescanlon/gatsby-theme-terminal`,
options: {
source: [
{
name: 'posts',
dir: 'posts',
},
{
name: 'projects',
dir: 'projects',
},
],
},
},
{
resolve: 'gatsby-plugin-google-analytics',
options: {
trackingId: 'UA-76055934-8',
},
},
],
}
================================================
FILE: demo/gatsby-node.js
================================================
/**
* Implement Gatsby's Node APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/node-apis/
*/
// You can delete this file if you're not using it
================================================
FILE: demo/gatsby-ssr.js
================================================
/**
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/ssr-apis/
*/
// You can delete this file if you're not using it
================================================
FILE: demo/package.json
================================================
{
"name": "demo",
"private": true,
"description": "A simple starter using gatsby-theme-terminal",
"version": "0.1.0",
"author": "Paul Scanlon <pauliescanlon@gmail.com>",
"dependencies": {
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@pauliescanlon/gatsby-theme-terminal": "*",
"date-fns": "^2.23.0",
"gatsby": "^4.0.0",
"gatsby-plugin-google-analytics": "^4.0.0",
"gatsby-plugin-mdx": "^3.0.0",
"gatsby-source-filesystem": "^4.0.0",
"react": "^17.0.0",
"react-dom": "^17.0.0"
},
"keywords": [
"gatsby"
],
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
},
"browserslist": [
">0.25%",
"not dead",
"IE 11"
]
}
================================================
FILE: demo/src/@pauliescanlon/gatsby-theme-terminal/components/Logo/Logo.js
================================================
/** @jsx jsx */
import { Box, jsx } from 'theme-ui'
import { Link as GatsbyLink } from 'gatsby'
export const Logo = () => (
<Box
sx={{
a: {
':focus': {
outline: 'none',
},
},
}}
>
<GatsbyLink to="/">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 96 25"
width="96"
height="25"
sx={{
mt: 2,
}}
>
<g>
<path
sx={{ fill: 'success' }}
d="M2.6,12.5c0-5.1,4.2-9.4,9.4-9.4l0,0V0.5c-3,0-5.6,1-7.8,2.9c-5,4.4-5.5,11.9-1.2,16.9l2-1.7
C3.5,17,2.6,14.8,2.6,12.5z"
/>
<path
sx={{ fill: 'secondary' }}
d="M12,21.9c-2.8,0-5.4-1.2-7.1-3.2l-2,1.7c0.4,0.5,0.9,0.9,1.4,1.3c5,4.3,12.6,3.6,16.8-1.5l-2-1.7
C17.4,20.6,14.8,21.9,12,21.9z"
/>
<path
sx={{ fill: 'primary' }}
d="M12,0.5v2.6c5.1,0,9.4,4.2,9.4,9.4c0,2.3-0.8,4.4-2.2,6l2,1.7c1.9-2.3,2.8-4.7,2.8-7.7
C23.9,5.9,18.6,0.5,12,0.5z"
/>
<path sx={{ fill: 'text' }} d="M11.3,16V9.9h-2V8.8h5.3v1.1h-2V16H11.3z" />
</g>
<g>
<path sx={{ fill: 'text' }} d="M32.4,18.5V9.6h-2.9V8h7.8v1.7h-3v8.9H32.4z" />
<path
sx={{ fill: 'text' }}
d="M40.2,18.3c-0.6-0.3-1.1-0.8-1.4-1.4c-0.3-0.6-0.5-1.4-0.5-2.2c0-0.9,0.2-1.6,0.5-2.2c0.3-0.6,0.8-1.1,1.3-1.5
s1.2-0.5,1.9-0.5c0.6,0,1.2,0.1,1.7,0.4c0.5,0.3,0.9,0.7,1.2,1.3c0.3,0.6,0.4,1.3,0.4,2.1c0,0.1,0,0.3,0,0.6l0,0.2h-5.2
c0.1,0.7,0.3,1.3,0.7,1.6c0.4,0.4,0.8,0.6,1.3,0.6c0.4,0,0.7-0.1,1.1-0.3c0.4-0.2,0.7-0.4,0.9-0.7l1.1,1.1c-0.8,1-1.8,1.4-3,1.4
C41.5,18.8,40.8,18.7,40.2,18.3z M43.5,13.7c0-0.3-0.1-0.6-0.2-0.9c-0.1-0.3-0.3-0.5-0.6-0.7c-0.2-0.2-0.5-0.3-0.8-0.3
c-0.5,0-0.8,0.2-1.2,0.5c-0.3,0.3-0.5,0.8-0.5,1.3H43.5z"
/>
<path
sx={{ fill: 'text' }}
d="M53.3,13L53.3,13c-0.2-0.4-0.4-0.6-0.7-0.7c-0.2-0.1-0.5-0.2-0.9-0.2c-0.4,0-0.8,0.1-1.1,0.3
c-0.3,0.2-0.6,0.5-0.8,0.8s-0.3,0.8-0.3,1.2v4.1h-1.9v-7.9h2v1.1c0.2-0.4,0.5-0.7,0.9-1c0.4-0.2,0.9-0.3,1.4-0.3
c0.4,0,0.8,0.1,1.2,0.2c0.4,0.1,0.7,0.4,1,0.7L53.3,13z M53,13C53,13,53,13,53,13C53.1,13,53.1,13,53,13c0.1,0.1,0.2,0.1,0.2,0.1
l0,0L53,13L53,13z M53.3,13c0,0.1,0,0.1,0,0.1c0,0,0,0,0,0C53.3,13.2,53.3,13.1,53.3,13L53.3,13z"
/>
<path
sx={{ fill: 'text' }}
d="M55.2,10.5h1.6V11c0.2-0.2,0.4-0.4,0.6-0.6c0.2-0.1,0.5-0.2,0.8-0.2c0.3,0,0.5,0.1,0.8,0.2
c0.2,0.1,0.4,0.4,0.6,0.7c0.2-0.3,0.4-0.6,0.7-0.7c0.2-0.2,0.6-0.2,0.9-0.2c0.6,0,1,0.2,1.2,0.6c0.2,0.4,0.4,1,0.4,1.8v5.9H61V13
c0-0.4,0-0.8-0.1-0.9s-0.2-0.3-0.4-0.3c-0.4,0-0.6,0.5-0.6,1.6v5.2h-1.7v-5.4c0-0.5,0-0.9-0.1-1s-0.2-0.3-0.4-0.3
c-0.2,0-0.4,0.1-0.5,0.3c-0.1,0.2-0.2,0.6-0.2,1.2v5.3h-1.7V10.5z"
/>
<path
sx={{ fill: 'text' }}
d="M64.6,18.5V17h1.9v-4.9h-1.8v-1.5h3.7V17h1.7v1.5H64.6z M66.8,9.1c-0.2-0.1-0.3-0.2-0.4-0.4
c-0.1-0.2-0.2-0.4-0.2-0.6c0-0.3,0.1-0.6,0.3-0.8C66.7,7.1,67,7,67.4,7C67.6,7,67.8,7,68,7.2c0.2,0.1,0.3,0.2,0.4,0.4
c0.1,0.2,0.2,0.4,0.2,0.6c0,0.2-0.1,0.4-0.2,0.6C68.3,8.9,68.2,9,68,9.1c-0.2,0.1-0.4,0.2-0.6,0.2C67.2,9.2,67,9.2,66.8,9.1z"
/>
<path
sx={{ fill: 'text' }}
d="M72.6,10.6h1.9v0.8c0.3-0.3,0.6-0.6,1-0.7c0.4-0.2,0.8-0.3,1.3-0.3c0.8,0,1.4,0.3,1.8,0.8
c0.5,0.5,0.7,1.4,0.7,2.5v4.8h-1.9v-4.8c0-0.6-0.1-1-0.3-1.3c-0.2-0.3-0.5-0.4-1-0.4c-0.3,0-0.5,0.1-0.8,0.2s-0.4,0.3-0.6,0.5
s-0.2,0.5-0.2,0.8v5.1h-1.9V10.6z"
/>
<path
sx={{ fill: 'text' }}
d="M86.7,11.1c0.6,0.5,0.9,1.4,0.9,2.6v4.8h-1.8v-0.7c-0.3,0.3-0.7,0.5-1.1,0.7c-0.4,0.2-0.9,0.2-1.4,0.2
c-0.8,0-1.5-0.2-1.9-0.6c-0.4-0.4-0.6-1-0.6-1.7c0-0.6,0.2-1,0.5-1.4s0.9-0.7,1.5-0.9c0.7-0.2,1.5-0.3,2.4-0.3h0.6
c-0.1-0.7-0.2-1.2-0.5-1.5c-0.3-0.3-0.7-0.4-1.3-0.4c-0.4,0-0.7,0.1-1.1,0.3c-0.4,0.2-0.8,0.5-1.1,0.8l-1-1.3c0.5-0.5,1-0.8,1.6-1
c0.6-0.2,1.1-0.3,1.7-0.3C85.2,10.4,86.1,10.6,86.7,11.1z M85.3,16.8c0.3-0.4,0.5-0.9,0.6-1.7h-0.4c-1,0-1.7,0.1-2.1,0.3
s-0.7,0.5-0.7,1c0,0.3,0.1,0.5,0.3,0.7c0.2,0.1,0.5,0.2,0.9,0.2C84.5,17.3,85,17.1,85.3,16.8z"
/>
<path sx={{ fill: 'text' }} d="M89.7,18.5v-1.5h2.2V8.6h-2.1V7.1h4v10H96v1.5H89.7z" />
</g>
</svg>
</GatsbyLink>
</Box>
)
================================================
FILE: demo/src/_temp/source-days.mdx
================================================
---
navigationLabel: SourceDays
---
<SourceDays>
{(sourceDays) => {
const currentYear = sourceDays[sourceDays.length - 1]
return (
<Box>
{currentYear
.sort((a, b) => a.number - b.number)
.map((day, index) => {
const { name, count, percent } = day
return (
<Flex
key={index}
sx={{
backgroundColor: 'surface',
flexDirection: 'column',
mb: 2,
position: 'relative',
}}
>
<Box
sx={{
backgroundColor: 'primary',
height: '100%',
position: 'absolute',
width: `${percent}%`,
}}
/>
<Box
sx={{
position: 'relative',
display: 'flex',
justifyContent: 'space-between',
}}
>
<Text sx={{ textTransform: 'capitalize', pl: 2 }}>{name}</Text>
<Text sx={{ pr: 2 }}>{`x${count}`}</Text>
</Box>
</Flex>
)
})}
</Box>
)
}}
</SourceDays>
================================================
FILE: demo/src/_temp/source-list.mdx
================================================
---
navigationLabel: sourceList
---
<SourceList>
{(source) => (
<ul>
{source.map((edge, index) => {
const {
frontmatter: { title },
} = edge.node
return <li key={index}>{title}</li>
})}
</ul>
)}
</SourceList>
================================================
FILE: demo/src/_temp/source-months.mdx
================================================
---
navigationLabel: SourceMonths
---
<SourceMonths>
{(sourceMonths) => {
const currentYear = sourceMonths[sourceMonths.length - 1]
return (
<Box sx={{ backgroundColor: 'surface', p: 3 }}>
<Heading variant="styles.h4">{currentYear[0].year}</Heading>
<Box sx={{ display: 'flex', flex: '1 1 auto', height: 300 }}>
<Flex sx={{ flexWrap: 'wrap', width: '100%' }}>
{currentYear.map((month, index) => {
const { initial, count, percent } = month
return (
<Box
key={index}
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
pl: 1,
pr: 1,
width: `${100 / currentYear.length}%`,
}}
>
<Text
sx={{
textAlign: 'center',
}}
>
{`x${count}`}
</Text>
<Box
sx={{
backgroundColor: 'primary',
height: `${percent}%`,
p: 1,
}}
/>
<Text
sx={{
textTransform: 'uppercase',
textAlign: 'center',
}}
>
{initial}
</Text>
</Box>
)
})}
</Flex>
</Box>
</Box>
)
}}
</SourceMonths>
================================================
FILE: demo/src/_temp/source-tags.mdx
================================================
---
navigationLabel: SourceTags
---
<SourceTags>
{(source) => (
<Flex sx={{ flexDirection: 'column' }}>
{source.map((tag, index) => {
const { name, count, percent } = tag
return (
<Box key={index}>
{`${name} x${count}`}
<Box mb={2} bg="muted" sx={{ width: `${percent}%`, height: 4 }}></Box>
</Box>
)
})}
</Flex>
)}
</SourceTags>
================================================
FILE: demo/src/_temp/source-words.mdx
================================================
---
navigationLabel: SourceWords
---
<SourceWords>
{(source) => {
const { wordCountTotal, wordCountAverage, wordCountHighest, wordCountLowest, timeToReadTotal, timeToReadAverage } =
source
return (
<Flex
sx={{
flexWrap: 'wrap',
mx: (theme) => `-${theme.space[2]}px`,
}}
>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
mb: 3,
px: 2,
width: ['100%', '50%', '33.333333333%'],
}}
>
<Flex
sx={{
alignItems: 'center',
backgroundColor: 'surface',
flex: '1 1 auto',
flexDirection: 'column',
justifyContent: 'center',
p: 3,
position: 'relative',
}}
>
<Heading as="h4" variant="styles.h4">
Average word count
</Heading>
<Donut sx={{ mx: 3, mb: 2 }} value={wordCountAverage / wordCountTotal} />
<Box sx={{ position: 'absolute' }}>
<Text
sx={{
textAlign: 'center',
color: 'primary',
fontSize: '22px',
fontWeight: 'bold',
lineHeight: '1',
}}
>
{wordCountAverage}
</Text>
<Text sx={{ textAlign: 'center', color: 'primary', lineHeight: '1' }}>Words</Text>
</Box>
<Text sx={{ textAlign: 'center' }}>{`Total words: ${wordCountTotal}`}</Text>
</Flex>
</Box>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
mb: 3,
px: 2,
width: ['100%', '50%', '33.333333333%'],
}}
>
<Flex
sx={{
alignItems: 'center',
backgroundColor: 'surface',
flex: '1 1 auto',
flexDirection: 'column',
justifyContent: 'center',
p: 3,
position: 'relative',
}}
>
<Heading as="h4" variant="styles.h4">
Average time to read
</Heading>
<Donut variant="styles.donut.secondary" sx={{ mx: 3, mb: 2 }} value={timeToReadAverage / timeToReadTotal} />
<Box sx={{ position: 'absolute' }}>
<Text
sx={{
textAlign: 'center',
color: 'secondary',
fontSize: '20px',
fontWeight: 'bold',
lineHeight: '1',
}}
>
{timeToReadAverage}
</Text>
<Text sx={{ textAlign: 'center', color: 'secondary', lineHeight: '1' }}>Minute</Text>
</Box>
<Text sx={{ textAlign: 'center' }}>{`Total read time: ${timeToReadTotal} mins`}</Text>
</Flex>
</Box>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
mb: 3,
px: 2,
width: ['100%', '50%', '33.333333333%'],
}}
>
<Flex
sx={{
alignItems: 'center',
backgroundColor: 'surface',
flex: '1 1 auto',
flexDirection: 'column',
justifyContent: 'center',
p: 3,
position: 'relative',
}}
>
<Heading as="h4" variant="styles.h4">
Highest word count
</Heading>
<Donut variant="styles.donut.success" sx={{ mx: 3, mb: 2 }} value={wordCountHighest / wordCountTotal} />
<Box sx={{ position: 'absolute' }}>
<Text
sx={{
textAlign: 'center',
color: 'success',
fontSize: '20px',
fontWeight: 'bold',
lineHeight: '1',
}}
>
{wordCountHighest}
</Text>
<Text sx={{ textAlign: 'center', color: 'success', lineHeight: '1' }}>Words</Text>
</Box>
<Text sx={{ textAlign: 'center' }}>{`Total words: ${wordCountTotal}`}</Text>
</Flex>
</Box>
</Flex>
)
}}
</SourceWords>
================================================
FILE: demo/src/pages/components.mdx
================================================
---
navigationLabel: Components
---
# [gatsby-theme-terminal](#-gatsby-theme-terminal)
gatsby-theme-terminal has some of it's own components, and below is how you use them.
## [SiteMetaData](#site-meta-data)
The `<SiteMetaData />` component returns all fields specified by `siteMetadata` in `gatsby-config.js`
```javascript
<SiteMetaData>
{(siteMetadata) => {
const { name, description } = siteMetadata
return (
<ul>
<li>{name}</li>
<li>{description}</li>
</ul>
)
}}
</SiteMetaData>
```
<SiteMetaData>
{(siteMetadata) => {
const { name, description } = siteMetadata
return (
<ul>
<li>{name}</li>
<li>{description}</li>
</ul>
)
}}
</SiteMetaData>
<Divider />
## [SourceList](#source-list)
By default the source list returns all `.mdx` found from the directories defined in `gatsby-config.js`. You can also use
the `filter` prop with this component eg: `<SourceList filter='posts' />`
_NOTE:_ the `filter` source _must_ be one from your `gatsby-config.js`
```javascript
<SourceList>
{(source) => (
<ul>
{source.map((edge, index) => {
const {
frontmatter: { title },
} = edge.node
return <li key={index}>{title}</li>
})}
</ul>
)}
</SourceList>
```
<SourceList>
{(source) => (
<ul>
{source.map((edge, index) => {
const {
frontmatter: { title },
} = edge.node
return <li key={index}>{title}</li>
})}
</ul>
)}
</SourceList>
<Divider />
## [SourceDays](#source-days)
By default source days returns an accumulated count and percent of all `frontmatter` date fields grouped by year. You
can also use the `filter` prop with this component eg: `<SourceDays filter='posts' />`
_NOTE:_ the `filter` source _must_ be one from your `gatsby-config.js`
```javascript
<SourceDays>
{(sourceDays) => {
const currentYear = sourceDays[sourceDays.length - 1]
return (
<Box>
{currentYear
.sort((a, b) => a.number - b.number)
.map((day, index) => {
const { name, count, percent } = day
return (
<Flex
key={index}
sx={{
backgroundColor: 'surface',
flexDirection: 'column',
mb: 2,
position: 'relative',
}}
>
<Box
sx={{
backgroundColor: 'primary',
height: '100%',
position: 'absolute',
width: `${percent}%`,
}}
/>
<Box
sx={{
position: 'relative',
display: 'flex',
justifyContent: 'space-between',
}}
>
<Text sx={{ textTransform: 'capitalize', pl: 2 }}>{name}</Text>
<Text sx={{ pr: 2 }}>{`x${count}`}</Text>
</Box>
</Flex>
)
})}
</Box>
)
}}
</SourceDays>
```
<SourceDays>
{(sourceDays) => {
const currentYear = sourceDays[sourceDays.length - 1]
return (
<Box>
{currentYear
.sort((a, b) => a.number - b.number)
.map((day, index) => {
const { name, count, percent } = day
return (
<Flex
key={index}
sx={{
backgroundColor: 'surface',
flexDirection: 'column',
mb: 2,
position: 'relative',
}}
>
<Box
sx={{
backgroundColor: 'primary',
height: '100%',
position: 'absolute',
width: `${percent}%`,
}}
/>
<Box
sx={{
position: 'relative',
display: 'flex',
justifyContent: 'space-between',
}}
>
<Text sx={{ textTransform: 'capitalize', pl: 2 }}>{name}</Text>
<Text sx={{ pr: 2 }}>{`x${count}`}</Text>
</Box>
</Flex>
)
})}
</Box>
)
}}
</SourceDays>
<Divider />
## [SourceMonths](#source-months)
By default source months returns an accumulated count and percent of all `frontmatter` date fields grouped by year. You
can also use the `filter` prop with this component eg: `<SourceMonths filter='posts' />`
_NOTE:_ the `filter` source _must_ be one from your `gatsby-config.js`
```javascript
<SourceMonths>
{(sourceMonths) => {
const currentYear = sourceMonths[sourceMonths.length - 1]
return (
<Box sx={{ backgroundColor: 'surface', p: 3 }}>
<Heading variant="styles.h4">{currentYear[0].year}</Heading>
<Box sx={{ display: 'flex', flex: '1 1 auto', height: 300 }}>
<Flex sx={{ flexWrap: 'wrap', width: '100%' }}>
{currentYear.map((month, index) => {
const { initial, count, percent } = month
return (
<Box
key={index}
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
pl: 1,
pr: 1,
width: `${100 / currentYear.length}%`,
}}
>
<Text
sx={{
textAlign: 'center',
}}
>
{`x${count}`}
</Text>
<Box
sx={{
backgroundColor: 'primary',
height: `${percent}%`,
p: 1,
}}
/>
<Text
sx={{
textTransform: 'uppercase',
textAlign: 'center',
}}
>
{initial}
</Text>
</Box>
)
})}
</Flex>
</Box>
</Box>
)
}}
</SourceMonths>
```
<SourceMonths>
{(sourceMonths) => {
const currentYear = sourceMonths[sourceMonths.length - 1]
return (
<Box sx={{ backgroundColor: 'surface', p: 3 }}>
<Heading variant="styles.h4">{currentYear[0].year}</Heading>
<Box sx={{ display: 'flex', flex: '1 1 auto', height: 300 }}>
<Flex sx={{ flexWrap: 'wrap', width: '100%' }}>
{currentYear.map((month, index) => {
const { initial, count, percent } = month
return (
<Box
key={index}
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
pl: 1,
pr: 1,
width: `${100 / currentYear.length}%`,
}}
>
<Text
sx={{
textAlign: 'center',
}}
>
{`x${count}`}
</Text>
<Box
sx={{
backgroundColor: 'primary',
height: `${percent}%`,
p: 1,
}}
/>
<Text
sx={{
textTransform: 'uppercase',
textAlign: 'center',
}}
>
{initial}
</Text>
</Box>
)
})}
</Flex>
</Box>
</Box>
)
}}
</SourceMonths>
<Divider />
## [SourceTags](#tag-list)
By default source tags returns all tags found in the `.mdx` sourced from the directories defined in `gatsby-config.js.
You can also use the `filter` prop with this component eg: `<SourceTags filter='posts' />`
_NOTE:_ the `filter` source _must_ be one from your `gatsby-config.js``
```javascript
<SourceTags>
{source => (
<Flex
sx={{flexDirection: 'column'}}
>
{
source.map((tag, index) => {
const {name, count, percent} = tag
return (<Box key={index}>
{`${name} x${count}`}
<Box mb={2} bg='muted' sx={{width: `${percent}%`, height: 4}} />
</Box>
})
}
</Flex>
)}
</SourceTags>
```
<SourceTags>
{(source) => (
<Flex sx={{ flexDirection: 'column' }}>
{source.map((tag, index) => {
const { name, count, percent } = tag
return (
<Box key={index}>
{`${name} x${count}`}
<Box mb={2} bg="muted" sx={{ width: `${percent}%`, height: 4 }}></Box>
</Box>
)
})}
</Flex>
)}
</SourceTags>
<Divider />
## [embeddedImages](#embedded-images)
Using a frontmatter field called `embeddedImages` you can define a _list_ of locally sourced images to embed in the
`.mdx` body.
_NOTE:_ this method won't work for `.mdx` sourced from `src/pages`
```javascript
---
title: Post 1
embeddedImages:
- markus-spiske-FXFz-sW0uwo-unsplash.jpg
---
```
<Divider />
You can then use the `<EmbeddedImage />` component like this in your `.mdx`.
The `image1` object key refers to the position in the `embeddedImages` list in frontmatter
<Divider />
```javascript
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi
<EmbeddedImage src={props.embedded.image1} />
```
<Divider />
## [SourceWords](#source-words)
By default source words returns a word count for all words found in the `.mdx` sourced from the directories defined in
`gatsby-config.js.
You can also use the `filter` prop with this component eg: `<SourceTags filter='posts' />`
_NOTE:_ the `filter` source _must_ be one from your `gatsby-config.js``
```javascript
<SourceWords>
{(source) => {
const { wordCountTotal, wordCountAverage, wordCountHighest, wordCountLowest, timeToReadTotal, timeToReadAverage } =
source
return (
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
mb: 3,
px: 2,
width: ['100%', '50%', '33.333333333%'],
}}
>
<Flex
sx={{
alignItems: 'center',
backgroundColor: 'surface',
flex: '1 1 auto',
flexDirection: 'column',
justifyContent: 'center',
p: 3,
position: 'relative',
}}
>
<Heading as="h4" variant="styles.h4">
Average word count
</Heading>
<Donut sx={{ mx: 3, mb: 2 }} value={wordCountAverage / wordCountTotal} />
<Box sx={{ position: 'absolute' }}>
<Text
sx={{
textAlign: 'center',
color: 'primary',
fontSize: '22px',
fontWeight: 'bold',
lineHeight: '1',
}}
>
{wordCountAverage}
</Text>
<Text sx={{ textAlign: 'center', color: 'primary', lineHeight: '1' }}>Words</Text>
</Box>
<Text sx={{ textAlign: 'center' }}>{`Total words: ${wordCountTotal}`}</Text>
</Flex>
</Box>
)
}}
</SourceWords>
```
<SourceWords>
{(source) => {
const { wordCountTotal, wordCountAverage, wordCountHighest, wordCountLowest, timeToReadTotal, timeToReadAverage } =
source
return (
<Flex
sx={{
flexWrap: 'wrap',
mx: (theme) => `-${theme.space[2]}px`,
}}
>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
mb: 3,
px: 2,
width: ['100%', '50%', '33.333333333%'],
}}
>
<Flex
sx={{
alignItems: 'center',
backgroundColor: 'surface',
flex: '1 1 auto',
flexDirection: 'column',
justifyContent: 'center',
p: 3,
position: 'relative',
}}
>
<Heading as="h4" variant="styles.h4">
Average word count
</Heading>
<Donut sx={{ mx: 3, mb: 2 }} value={wordCountAverage / wordCountTotal} />
<Box sx={{ position: 'absolute' }}>
<Text
sx={{
textAlign: 'center',
color: 'primary',
fontSize: '22px',
fontWeight: 'bold',
lineHeight: '1',
}}
>
{wordCountAverage}
</Text>
<Text sx={{ textAlign: 'center', color: 'primary', lineHeight: '1' }}>Words</Text>
</Box>
<Text sx={{ textAlign: 'center' }}>{`Total words: ${wordCountTotal}`}</Text>
</Flex>
</Box>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
mb: 3,
px: 2,
width: ['100%', '50%', '33.333333333%'],
}}
>
<Flex
sx={{
alignItems: 'center',
backgroundColor: 'surface',
flex: '1 1 auto',
flexDirection: 'column',
justifyContent: 'center',
p: 3,
position: 'relative',
}}
>
<Heading as="h4" variant="styles.h4">
Average time to read
</Heading>
<Donut variant="styles.donut.secondary" sx={{ mx: 3, mb: 2 }} value={timeToReadAverage / timeToReadTotal} />
<Box sx={{ position: 'absolute' }}>
<Text
sx={{
textAlign: 'center',
color: 'secondary',
fontSize: '20px',
fontWeight: 'bold',
lineHeight: '1',
}}
>
{timeToReadAverage}
</Text>
<Text sx={{ textAlign: 'center', color: 'secondary', lineHeight: '1' }}>Minute</Text>
</Box>
<Text sx={{ textAlign: 'center' }}>{`Total read time: ${timeToReadTotal} mins`}</Text>
</Flex>
</Box>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
mb: 3,
px: 2,
width: ['100%', '50%', '33.333333333%'],
}}
>
<Flex
sx={{
alignItems: 'center',
backgroundColor: 'surface',
flex: '1 1 auto',
flexDirection: 'column',
justifyContent: 'center',
p: 3,
position: 'relative',
}}
>
<Heading as="h4" variant="styles.h4">
Highest word count
</Heading>
<Donut variant="styles.donut.success" sx={{ mx: 3, mb: 2 }} value={wordCountHighest / wordCountTotal} />
<Box sx={{ position: 'absolute' }}>
<Text
sx={{
textAlign: 'center',
color: 'success',
fontSize: '20px',
fontWeight: 'bold',
lineHeight: '1',
}}
>
{wordCountHighest}
</Text>
<Text sx={{ textAlign: 'center', color: 'success', lineHeight: '1' }}>Words</Text>
</Box>
<Text sx={{ textAlign: 'center' }}>{`Total words: ${wordCountTotal}`}</Text>
</Flex>
</Box>
</Flex>
)
}}
</SourceWords>
<Divider />
```javascript
<SourceWords>
{(sourceWords) => {
const currentYear = sourceWords.wordCountByMonth[sourceWords.wordCountByMonth.length - 1]
return (
<Box sx={{ backgroundColor: 'surface', p: 3 }}>
<Flex>
<Heading variant="styles.h4" sx={{ mr: 2 }}>
{currentYear[0].year}
</Heading>
<Text>Word count by month</Text>
</Flex>
<Box sx={{ display: 'flex', flex: '1 1 auto', height: 300 }}>
<Flex sx={{ flexWrap: 'wrap', width: '100%' }}>
{currentYear.map((month, index) => {
const { initial, words } = month
return (
<Box
key={index}
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
pl: 1,
pr: 1,
width: `${100 / currentYear.length}%`,
}}
>
<Text
sx={{
textAlign: 'center',
}}
>
{`x${words}`}
</Text>
<Box
sx={{
backgroundColor: 'primary',
height: `${words}%`,
p: 1,
}}
/>
<Text
sx={{
textTransform: 'uppercase',
textAlign: 'center',
}}
>
{initial}
</Text>
</Box>
)
})}
</Flex>
</Box>
</Box>
)
}}
</SourceWords>
```
<SourceWords>
{(sourceWords) => {
const currentYear = sourceWords.wordCountByMonth[sourceWords.wordCountByMonth.length - 1]
return (
<Box sx={{ backgroundColor: 'surface', p: 3 }}>
<Flex>
<Heading variant="styles.h4" sx={{ mr: 2 }}>
{currentYear[0].year}
</Heading>
<Text>Word count by month</Text>
</Flex>
<Box sx={{ display: 'flex', flex: '1 1 auto', height: 300 }}>
<Flex sx={{ flexWrap: 'wrap', width: '100%' }}>
{currentYear.map((month, index) => {
const { initial, words } = month
return (
<Box
key={index}
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
pl: 1,
pr: 1,
width: `${100 / currentYear.length}%`,
}}
>
<Text
sx={{
textAlign: 'center',
}}
>
{`x${words}`}
</Text>
<Box
sx={{
backgroundColor: 'primary',
height: `${words}%`,
p: 1,
}}
/>
<Text
sx={{
textTransform: 'uppercase',
textAlign: 'center',
}}
>
{initial}
</Text>
</Box>
)
})}
</Flex>
</Box>
</Box>
)
}}
</SourceWords>
================================================
FILE: demo/src/pages/index.mdx
================================================
---
navigationLabel: Home
---
import { format } from 'date-fns'
<Grid
sx={{
mb: 6
}}
>
<SiteMetaData>
{(siteMetadata) => {
const { name, description } = siteMetadata
return (
<Fragment>
<Heading variant="styles.h1">{name}</Heading>
<Text>{description}</Text>
</Fragment>
)
}}
</SiteMetaData>
<Grid
sx={{
alignItems: 'center',
gridTemplateColumns: 'auto 1fr'
}}
>
<Button
sx={{ mb: 2 }}
as="a"
variant="success"
href="https://github.com/PaulieScanlon/gatsby-theme-terminal"
target="_blank"
>
View theme on GitHub
</Button>
<Link sx={{ whiteSpace: 'nowrap' }} href="https://github.com/PaulieScanlon/gatsby-theme-terminal" target="_blank">
gatsby-theme-terminal
</Link>
</Grid>
<Alert variant="success">Alert... My website is faster than yours!</Alert>
</Grid>
<Grid
sx={{
gap: 0,
mb: 6
}}
>
## About
Write anything you want in `src/pages/index.mdx` and it'll go here.
</Grid>
<Grid sx={{ gridTemplateColumns: ['1fr', '1fr', '1fr 1fr'] }}>
<Box>
## Contact
<Heading variant="styles.h3" sx={{ mb: 0 }}>
Email
</Heading>
<Link href="mailto:******@gmail.com" variant="styles.a">
******@gmail.com
</Link>
<Heading variant="styles.h3" sx={{ mb: 0 }}>
Twitter
</Heading>
<Link href="https://twitter.com/PaulieScanlon/" variant="styles.a">
https://twitter.com/PaulieScanlon/
</Link>
<Heading variant="styles.h3" sx={{ mb: 0 }}>
GitHub
</Heading>
<Link href="https://github.com/PaulieScanlon/" variant="styles.a">
https://github.com/PaulieScanlon/
</Link>
<Heading variant="styles.h3" sx={{ mb: 0 }}>
LinkedIn
</Heading>
<Link href="https://www.linkedin.com/in/PaulieScanlon/" variant="styles.a">
https://linkedin.com/in/PaulieScanlon/
</Link>
</Box>
<Box>
## Top 5 tags
<SourceTags filter="posts">
{(tags) => (
<Flex sx={{ flexDirection: 'column' }}>
{tags
.splice(0, 5)
.sort((a, b) => b.percent - a.percent)
.map((tag, index) => {
const { name, count, percent } = tag
return (
<Box key={index} sx={{ color: 'muted', mb: 3, svg: { fill: 'muted' } }}>
<Flex sx={{ lineHeight: 'normal' }}>
<Text sx={{ color: 'secondary', mr: 2, mb: 0 }}>{`${name}`}</Text>
<Text sx={{ color: 'muted' }}>{percent}</Text>
<Text sx={{ color: 'error' }}>%</Text>
</Flex>
<Flex>
<Box>{'['}</Box>
<Box sx={{ flexBasis: '100%' }}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 8" width="100%" height="8">
<rect width={`${percent * 3}%`} height={4} />
</svg>
</Box>
<Box> {']'}</Box>
</Flex>
</Box>
)
})}
</Flex>
)}
</SourceTags>
</Box>
</Grid>
================================================
FILE: demo/src/pages/markdown.mdx
================================================
---
navigationLabel: Markdown
---
# [markdown](#markdown)
gatsby-theme-terminal supports the full set of
[markdown shortcodes](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)
<hr />
## [Heading](#heading)
```markdown
# h1
## h2
### h3
#### h4
##### h5
###### h6
Alternatively, for h1 and h2, an underline-ish style:
# Alt-h1
Alt-h2
```
# h1
## h2
### h3
#### h4
##### h5
###### h6
Alternatively, for h1 and h2, an underline-ish style:
## [Alt-h1](#alt-h1)
Alt-h2
## [Emphasis](#emphasis)
```markdown
Emphasis, aka italics, with _asterisks_ or _underscores_.
Strong emphasis, aka bold, with **asterisks** or **underscores**.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
```
Emphasis, aka italics, with _asterisks_ or _underscores_.
Strong emphasis, aka bold, with **asterisks** or **underscores**.
Combined emphasis with **asterisks and _underscores_**.
Strikethrough uses two tildes. ~~Scratch this.~~
<hr />
## [Lists](#lists)
(In this example, leading and trailing spaces are shown with with dots: ⋅)
```markdown
1. First ordered list item
2. Another item
3. Actual numbers don't matter, just that it's a number
4. And another item.
5. Code in list `boop`
- Unordered list can use asterisks
* Or minuses
- Or pluses
```
1. First ordered list item
2. Another item
3. Actual numbers don't matter, just that it's a number
4. And another item.
5. Code in list `boop`
- Unordered list can use asterisks
* Or minuses
- Or pluses
<hr />
## [Links](#links)
There are two ways to create links.
```markdown
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][arbitrary case-insensitive reference text]
[I'm a relative reference to a repository file](../blob/master/LICENSE)
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or
<http://www.example.com> and sometimes example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
```
[I'm an inline-style link](https://www.google.com)
[I'm an inline-style link with title](https://www.google.com "Google's Homepage")
[I'm a reference-style link][arbitrary case-insensitive reference text]
[I'm a relative reference to a repository file](../blob/master/LICENSE)
[You can use numbers for reference-style link definitions][1]
Or leave it empty and use the [link text itself].
URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com or
<http://www.example.com> and sometimes example.com (but not on Github, for example).
Some text to show that the reference links can follow later.
[arbitrary case-insensitive reference text]: https://www.mozilla.org
[1]: http://slashdot.org
[link text itself]: http://www.reddit.com
## [Images](#images)
```markdown
Here's our logo (hover to see the title text):
Inline-style:

Reference-style: ![alt text][logo]
[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 2'
```
Here's our logo (hover to see the title text):
Inline-style:

Reference-style: ![alt text][logo]
[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png 'Logo Title Text 2'
## [Code and Syntax Highlighting](#code-and-syntax-highlighting)
Code blocks are part of the Markdown spec, but syntax highlighting isn't.
```markdown
Inline `code` has `back-ticks around` it.
```
Inline `code` has `back-ticks around` it.
Blocks of code are either fenced by lines with three back-ticks ```, or are indented with four spaces. I recommend only
using the fenced code blocks -- they're easier and only they support syntax highlighting, but you must provide a
language or none
````markdown
```javascript
var s = 'JavaScript syntax highlighting'
alert(s)
```
```python
s = "Python syntax highlighting"
print s
```
```html
<div>HTML syntax highlighting</div>
```
```none
var s = "JavaScript syntax highlighting"
alert(s)
```
````
```javascript
var s = 'JavaScript syntax highlighting'
alert(s)
```
```python
s = "Python syntax highlighting"
print s
```
```html
<div>HTML syntax highlighting</div>
```
```none
var s = "JavaScript syntax highlighting"
alert(s)
```
## [Tables](#tables)
Tables aren't part of the core Markdown spec, but they are part of GFM and Markdown Here supports them. They are an easy
way of adding tables to your email -- a task that would otherwise require copy-pasting from another application.
```markdown
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- | :-----------: | -----: |
| col 3 is | right-aligned | \$1600 |
| col 2 is | centered | \$12 |
| zebra stripes | are neat | \$1 |
There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to
make the raw Markdown line up prettily. You can also use inline Markdown.
| Markdown | Less | Pretty |
| -------- | --------- | ---------- |
| _Still_ | `renders` | **nicely** |
| 1 | 2 | 3 |
```
Colons can be used to align columns.
| Tables | Are | Cool |
| ------------- | :-----------: | -----: |
| col 3 is | right-aligned | \$1600 |
| col 2 is | centered | \$12 |
| zebra stripes | are neat | \$1 |
There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to
make the raw Markdown line up prettily. You can also use inline Markdown.
| Markdown | Less | Pretty |
| -------- | --------- | ---------- |
| _Still_ | `renders` | **nicely** |
| 1 | 2 | 3 |
<hr />
## [Blockquotes](#blockquotes)
```markdown
> Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this
> is long enough to actually wrap for everyone. Oh, you can _put_ **Markdown** into a blockquote.
```
> Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.
Quote break.
> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this
> is long enough to actually wrap for everyone. Oh, you can _put_ **Markdown** into a blockquote.
## [Inline HTML](#inline-html)
You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
```markdown
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
```
<dl>
<dt>Definition list</dt>
<dd>Is something people use sometimes.</dd>
<dt>Markdown in HTML</dt>
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
<hr />
## [Horizontal Rule](#horizontal-rule)
```markdown
Three or more...
---
Hyphens
---
Asterisks
---
Underscores
```
Three or more...
---
Hyphens
---
Asterisks
---
Underscores
## [Line Breaks](#line-breaks)
My basic recommendation for learning how line breaks work is to experiment and discover -- hit `<Enter>` once (i.e.,
insert one newline), then hit it twice (i.e., insert two new lines), see what happens. You'll soon learn to get what you
want. "Markdown Toggle" is your friend.
```markdown
Here's a line for us to start with.
This line is separated from the one above by two newlines, so it will be a _separate paragraph_.
This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line
in the _same paragraph_.
```
================================================
FILE: demo/src/pages/posts.mdx
================================================
---
navigationLabel: Posts
---
import { format } from 'date-fns'
# posts
You can use the `<SourceList filter="posts" />` component from any `.mdx`.
Here we use it to return all the `posts` by using the filter prop
<SourceList filter="posts">
{(posts) => (
<Grid
sx={{
gridTemplateColumns: ['1fr', '1fr', '1fr 1fr'],
}}
>
{posts
.filter((edge) => !edge.node.frontmatter.isPrivate)
.reduce((routes, route) => {
return route.node.frontmatter.pinned ? [route, ...routes] : [...routes, route]
}, [])
.map((edge, index) => {
const {
featuredImageUrl,
frontmatter: { title, featuredImage, tags, date, pinned },
excerpt,
fields: { slug },
} = edge.node
return (
<Box
key={index}
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
}}
>
<Link
href={slug}
sx={{
textDecoration: 'none',
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
minHeight: '1px',
}}
>
<Card
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
minHeight: '1px',
}}
>
<Box sx={{ minHeight: '1px' }}>
{featuredImage ? <GatsbyImage alt={title} image={featuredImage.childImageSharp} /> : null}
{featuredImageUrl ? <GatsbyImage alt={title} image={featuredImageUrl.childImageSharp} /> : null}
</Box>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
p: 3,
}}
>
<Heading variant="styles.h4" sx={{ color: pinned ? 'primary' : 'text' }}>
{title}
</Heading>
<Text sx={{ mb: 1, color: 'muted' }}>{format(new Date(date), 'd-MMM-u')}</Text>
<Text sx={{ mb: 1, color: 'text' }}>{excerpt}</Text>
</Box>
<Box sx={{ p: 3 }}>
<Text>View Post</Text>
</Box>
</Card>
</Link>
</Box>
)
})}
</Grid>
)}
</SourceList>
================================================
FILE: demo/src/pages/projects.mdx
================================================
---
navigationLabel: Projects
---
import { format } from 'date-fns'
# projects
You can use the `<SourceList filter="projects" />` component from any `.mdx`.
Here we use it to return all the `projects` by using the filter prop
<SourceList filter="projects">
{(projects) => (
<Grid
sx={{
gridTemplateColumns: ['1fr', '1fr', '1fr 1fr'],
}}
>
{projects
.filter((edge) => !edge.node.frontmatter.isPrivate)
.reduce((routes, route) => {
return route.node.frontmatter.pinned ? [route, ...routes] : [...routes, route]
}, [])
.map((edge, index) => {
const {
featuredImageUrl,
frontmatter: { title, featuredImage, tags, date, pinned },
excerpt,
fields: { slug },
} = edge.node
return (
<Box
key={index}
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
}}
>
<Link
href={slug}
sx={{
textDecoration: 'none',
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
minHeight: '1px',
}}
>
<Card
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
minHeight: '1px',
}}
>
<Box sx={{ minHeight: '1px' }}>
{featuredImage ? <GatsbyImage alt={title} image={featuredImage.childImageSharp} /> : null}
{featuredImageUrl ? <GatsbyImage alt={title} image={featuredImageUrl.url.childImageSharp} /> : null}
</Box>
<Box
sx={{
display: 'flex',
flex: '1 1 auto',
flexDirection: 'column',
p: 3,
}}
>
<Heading variant="styles.h4" sx={{ color: pinned ? 'primary' : 'text' }}>
{title}
</Heading>
<Text sx={{ mb: 1, color: 'muted' }}>{format(new Date(date), 'd-MMM-u')}</Text>
<Text sx={{ mb: 1, color: 'text' }}>{excerpt}</Text>
</Box>
<Box sx={{ p: 3 }}>
<Text>View Post</Text>
</Box>
</Card>
</Link>
</Box>
)
})}
</Grid>
)}
</SourceList>
================================================
FILE: demo/src/pages/theme-ui-components.mdx
================================================
---
navigationLabel: Theme UI
---
# [theme-ui/components](#theme-ui-components)
gatsby-theme-terminal also supports the full set of [theme-ui/components](https://theme-ui.com/components) and below is
how you use them.
If you'd like to see the default theme `.js` that file can be found in
[here](https://github.com/PaulieScanlon/gatsby-theme-terminal/blob/master/%40pauliescanlon/gatsby-theme-terminal/src/gatsby-plugin-theme-ui/index.js)
## [Box](#box)
```javascript
<Box p={4} color="white" bg="primary">
Beep
</Box>
```
<Box p={4} color="white" bg="primary">
Beep
</Box>
<Divider />
## [Flex](#flex)
```javascript
<Flex>
<Box p={2} bg="primary" sx={{ flex: '1 1 auto' }}>
Flex
</Box>
<Box p={2} bg="muted">
Box
</Box>
</Flex>
```
<Flex>
<Box p={2} bg="primary" sx={{ flex: '1 1 auto' }}>
Flex
</Box>
<Box p={2} bg="muted">
Box
</Box>
</Flex>
<Divider />
## [Grid](#grid)
```javascript
<Grid gap={2} columns={[2, '1fr 2fr']}>
<Box bg="primary">Box</Box>
<Box bg="muted">Box</Box>
</Grid>
```
<Grid gap={2} columns={[2, '1fr 2fr']}>
<Box bg="primary">Box</Box>
<Box bg="muted">Box</Box>
</Grid>
<Divider />
## [Buttons](#buttons)
```javascript
<Button>primary</Button>
<Button variant='secondary'>secondary</Button>
<Button variant='success'>success</Button>
<Button variant='error'>error</Button>
<Button variant='ghost' />
```
<Grid sx={{ gridTemplateColumns: 'auto auto auto auto auto' }}>
<Button>primary</Button>
<Button variant="secondary">secondary</Button>
<Button variant="success">success</Button>
<Button variant="error">error</Button>
<Button variant="ghost">ghost</Button>
</Grid>
<Divider />
## [Text](#text)
```javascript
<Text>Hello</Text>
<Text as="p" >Hello</Text>
<Text as="p">Hello <Link href='www.example.com'>www.example.com</Link></Text>
<Text variant='styles.small'>Hello</Text>
```
<Text>Hello</Text>
<Text as="p">Hello</Text>
<Text as="p">
Hello <Link href="www.example.com">www.example.com</Link>
</Text>
<Text variant="styles.small">Hello</Text>
<Divider />
## [Heading](#heading)
```javascript
<Heading as='h1' variant='styles.h1'>h1</Heading>
<Heading as='h2 'variant='styles.h2'>h2</Heading>
<Heading as='h3 'variant='styles.h3'>h3</Heading>
<Heading as='h4 'variant='styles.h4'>h4</Heading>
<Heading as='h5 'variant='styles.h5'>h5</Heading>
<Heading as='h6 'variant='styles.h6'>h6</Heading>
```
<Heading as="h1" variant="styles.h1">
h1
</Heading>
<Heading as="h2" variant="styles.h2">
h2
</Heading>
<Heading as="h3" variant="styles.h3">
h3
</Heading>
<Heading as="h4" variant="styles.h4">
h4
</Heading>
<Heading as="h5" variant="styles.h5">
h5
</Heading>
<Heading as="h6" variant="styles.h6">
h6
</Heading>
## [Link](#link)
```javascript
<Link href="#!">Hello</Link>
```
<Link href="#!">Hello</Link>
<Divider />
## [Image](#image)
```javascript
<Image src="https://placekitten.com/g/400/400" />
```
<Image src="https://placekitten.com/g/400/400" />
<Divider />
## [Card](#card)
```javascript
<Card
sx={{
maxWidth: 400,
}}
>
<Image src="https://placekitten.com/g/800/600" />
<Box p={3}>
<Heading variant="styles.h4">Heading</Heading>
<Text>Text</Text>
</Box>
</Card>
```
<Card
sx={{
maxWidth: 400,
}}
>
<Image src="https://placekitten.com/g/800/600" />
<Box p={3}>
<Heading variant="styles.h4">Heading</Heading>
<Text>Text</Text>
</Box>
</Card>
<Divider />
## [Forms](#forms)
```javascript
<Box as="form">
<Label htmlFor="input">Input</Label>
<Input name="username" mb={3} />
<Label mb={3}>
<Checkbox />
Checkbox
</Label>
<Label mb={3}>
<Radio name="radio" /> Radio A
</Label>
<Label mb={3}>
<Radio name="radio" /> Radio B
</Label>
<Label htmlFor="select">Select</Label>
<Select name="select" mb={3}>
<option>Beep</option>
<option>Boop</option>
<option>Blip</option>
</Select>
<Label htmlFor="textarea">Text Area</Label>
<Textarea name="textarea" rows="6" mb={3} />
</Box>
```
<Box as='form' >
<Label htmlFor='input'>Input</Label>
<Input
name='username'
mb={3}
/>
<Label mb={3}>
<Checkbox />
Checkbox
</Label>
<Label mb={3}>
<Radio name="radio" /> Radio A
</Label>
<Label mb={3}>
<Radio name="radio" /> Radio B
</Label>
<Label htmlFor="select">Select</Label>
<Select name="select" mb={3}>
<option>Beep</option>
<option>Boop</option>
<option>Blip</option>
</Select>
<Label htmlFor='textarea'>Text Area</Label>
<Textarea
name='textarea'
rows='6'
mb={3}
/>
</Box>
## [Label](#label)
```javascript
<Label htmlFor="input">Label</Label>
```
<Label htmlFor="input">Label</Label>
<Divider />
## [Input](#input)
```javascript
<Input name="username" />
```
<Input name="username" />
<Divider />
## [Select](#select)
```javascript
<Select defaultValue="Hello">
<option>Hello</option>
<option>Hi</option>
<option>Beep</option>
<option>Boop</option>
</Select>
```
<Select defaultValue="Hello">
<option>Hello</option>
<option>Hi</option>
<option>Beep</option>
<option>Boop</option>
</Select>
<Divider />
## [Textarea](#text-area)
```javascript
<Textarea defaultValue="Hello" rows={8} />
```
<Textarea defaultValue="Hello" rows={8} />
<Divider />
## [Radio](#radio)
```javascript
<Label mb={1}>
<Radio
name='dark-mode'
value='true'
defaultChecked={true}
/>
Dark Mode
</Label>
<Label mb={1}>
<Radio
name='dark-mode'
value='false'
/>
Light Mode
</Label>
```
<Label mb={1}>
<Radio name="dark-mode" value="true" defaultChecked={true} />
Dark Mode
</Label>
<Label mb={1}>
<Radio name="dark-mode" value="false" />
Light Mode
</Label>
<Divider />
## [Checkbox](#checkbox)
```javascript
<Label>
<Checkbox />
Checkbox
</Label>
```
<Label>
<Checkbox />
Checkbox
</Label>
<Divider />
## [Slider](#slider)
```javascript
<Slider defaultValue={25} />
```
<Slider defaultValue={25} />
<Divider />
## [Field](#field)
```javascript
<Field label="Email" name="email" defaultValue="" />
```
<Field label="Email" name="email" defaultValue="" />
<Divider />
## [Progress](#progress)
```javascript
<Progress max={1} value={1/2}> 50% </Progress>
<Progress max={1} value={1/2} variant='styles.progress.secondary'> 50% </Progress>
<Progress max={1} value={1/2} variant='styles.progress.success'> 50% </Progress>
<Progress max={1} value={1/2} variant='styles.progress.error'> 50% </Progress>
```
<Progress max={1} value={1 / 2}>
{' '}
50%{' '}
</Progress>
<Divider />
<Progress max={1} value={1 / 2} variant="styles.progress.secondary">
{' '}
50%{' '}
</Progress>
<Divider />
<Progress max={1} value={1 / 2} variant="styles.progress.success">
{' '}
50%{' '}
</Progress>
<Divider />
<Progress max={1} value={1 / 2} variant="styles.progress.error">
{' '}
50%{' '}
</Progress>
<Divider />
## [Donut](#donut)
```javascript
<Donut value={1/2}/>
<Donut value={1/2} variant='styles.donut.secondary'/>
<Donut value={1/2} variant='styles.donut.success'/>
<Donut value={1/2} variant='styles.donut.error'/>
```
<Donut value={1 / 2} />
<Donut value={1 / 2} variant="styles.donut.secondary" />
<Donut value={1 / 2} variant="styles.donut.success" />
<Donut value={1 / 2} variant="styles.donut.error" />
<Divider />
## [Spinner](#spinner)
```javascript
<Spinner />
<Spinner variant='styles.spinner.secondary'/>
<Spinner variant='styles.spinner.success'/>
<Spinner variant='styles.spinner.error'/>
```
<Spinner />
<Spinner variant="styles.spinner.secondary" />
<Spinner variant="styles.spinner.success" />
<Spinner variant="styles.spinner.error" />
<Divider />
## [Avatar](#avatar)
```javascript
<Avatar src="https://placekitten.com/g/50/50" />
```
<Avatar src="https://placekitten.com/g/50/50" />
## [Badge](#badge)
Badges need a variant, the default can't be styled at the moment
```javascript
<Badge variant='primary'>
Beep boop, this is an badge!
</Badge>
<Badge variant='secondary'>
Beep boop, this is an badge!
</Badge>
<Badge variant='success'>
Beep boop, this is an badge!
</Badge>
<Badge variant='error'>
Beep boop, this is an badge!
</Badge>
```
<Grid sx={{gridTemplateColumns: 'auto auto auto auto'}}>
<Badge variant='primary'>
Beep boop, this is an badge!
</Badge>
<Badge variant="secondary">Beep boop, this is an badge!</Badge>
<Badge variant="success">Beep boop, this is an badge!</Badge>
<Badge variant='error'>
Beep boop, this is an badge!
</Badge>
</Grid>
<Divider />
## [Alert](#alert)
```javascript
<Alert variant='primary' mb={2}>
Beep boop, this is an alert!
</Alert>
<Alert variant='secondary' mb={2}>
Beep boop, this is an alert!
</Alert>
<Alert variant='success' mb={2}>
Beep boop, this is an alert!
</Alert>
<Alert variant='error'>
Beep boop, this is an alert!
</Alert>
```
<Alert variant="primary" mb={2}>
Beep boop, this is an alert!
</Alert>
<Alert variant="secondary" mb={2}>
Beep boop, this is an alert!
</Alert>
<Alert variant="success" mb={2}>
Beep boop, this is an alert!
</Alert>
<Alert variant="error">Beep boop, this is an alert!</Alert>
<Divider />
## [Divider](#divider)
```javascript
<Divider />
```
<Divider />
<Divider />
## Embed
```javascript
<Embed src="https://www.youtube.com/embed/GNCd_ERZvZM" />
```
<Embed src="https://www.youtube.com/embed/GNCd_ERZvZM" />
<Divider />
## [AspectRatio](#aspect-ratio)
```javascript
<AspectRatio ratio={16 / 9}>
<Image
src="https://placekitten.com/g/1200/1200"
sx={{
objectFit: 'cover',
}}
/>
</AspectRatio>
```
<AspectRatio ratio={16 / 9}>
<Image
src="https://placekitten.com/g/1200/1200"
sx={{
objectFit: 'cover',
}}
/>
</AspectRatio>
<Divider />
## [AspectImage](#aspect-image)
```javascript
<AspectImage ratio={4 / 3} src="https://placekitten.com/g/1200/1200" />
```
<AspectImage ratio={4 / 3} src="https://placekitten.com/g/1200/1200" />
<Divider />
## [Container](#container)
```javascript
<Container p={4} bg="surface">
Centered container
</Container>
```
<Container p={4} bg="surface">
Centered container
</Container>
<Divider />
## [NavLink](#nav-link)
```javascript
<Flex as="nav">
<NavLink href="#!" p={2}>
Home
</NavLink>
<NavLink href="#!" p={2}>
Blog
</NavLink>
<NavLink href="#!" p={2}>
About
</NavLink>
</Flex>
```
<Flex as="nav">
<NavLink href="#!" p={2}>
Home
</NavLink>
<NavLink href="#!" p={2}>
Blog
</NavLink>
<NavLink href="#!" p={2}>
About
</NavLink>
</Flex>
<Divider />
## [Message](#message)
```javascript
<Message variant='primary' mb={2}>
This is just a message for someone to read
</Message>
<Message variant='secondary' mb={2}>
This is just a message for someone to read
</Message>
<Message variant='success' mb={2}>
This is just a message for someone to read
</Message>
<Message variant='error' mb={2}>
This is just a message for someone to read
</Message>
```
<Message variant="primary" mb={2}>
This is just a message for someone to read
</Message>
<Message variant="secondary" mb={2}>
This is just a message for someone to read
</Message>
<Message variant="success" mb={2}>
This is just a message for someone to read
</Message>
<Message variant="error" mb={2}>
This is just a message for someone to read
</Message>
<Divider />
## [Close](#close)
```javascript
<Close />
```
<Close />
<Divider />
## [IconButton](#icon-button)
```javascript
<IconButton aria-label="Toggle dark mode">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentcolor">
<circle r={11} cx={12} cy={12} fill="none" stroke="currentcolor" strokeWidth={2} />
</svg>
</IconButton>
```
<IconButton aria-label="Toggle dark mode">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" fill="currentcolor">
<circle r={11} cx={12} cy={12} fill="none" stroke="currentcolor" strokeWidth={2} />
</svg>
</IconButton>
<Divider />
## [MenuButton](#menu-button)
```javascript
<MenuButton aria-label="Toggle Menu" />
```
<MenuButton aria-label="Toggle Menu" />
<Divider />
================================================
FILE: demo/src/posts/2019/03/a-pinned-post.mdx
================================================
---
title: A Pinned Post
tags: ['React', 'TypeScript']
featuredImage: pankaj-patel-SXihyA4oEJs-unsplash.jpg
pinned: true
date: 2019-03-05
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
- [/posts/post-1/](/posts/post-1/)
- [/posts/2020/02/post-5/](/posts/2020/02/post-5/)
- [https://example.com](https://example.com)
- [http://example.com](http://example.com)
## [Dummy Copy](#dummy-copy)
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dui eros, rhoncus at ex eget, commodo lobortis justo.
Aenean eget aliquam risus. Aenean auctor luctus convallis. Pellentesque tincidunt odio ut risus pretium, id gravida quam
cursus. Quisque at eros facilisis, auctor purus ut, sodales elit. Donec accumsan laoreet enim, ut dictum lacus feugiat
eget. Fusce magna ligula, molestie quis egestas eu, varius eget ante. Suspendisse massa lectus, sollicitudin vel aliquam
at, convallis ac dui.
Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas pellentesque congue
blandit. Etiam facilisis dapibus dolor, vitae semper neque. Phasellus fermentum, odio quis pharetra aliquam, purus justo
gravida risus, a fringilla nisl mi nec dui. Nunc suscipit condimentum fringilla. Duis sit amet porttitor ligula, sed
maximus velit. Sed at lectus diam. Donec malesuada euismod sodales. Etiam pretium gravida feugiat. Donec cursus enim
consequat hendrerit mollis. Quisque ultrices molestie neque et ullamcorper. Aenean fermentum lectus eget ultricies
rutrum. Nullam blandit enim non vulputate dapibus. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vestibulum finibus mattis feugiat. Vestibulum orci nibh, fermentum at fringilla a, malesuada id lacus. Donec sit amet
mollis odio. Donec condimentum, est ultricies placerat accumsan, ipsum ex varius purus, ut convallis tellus diam in
nisl. Donec gravida hendrerit leo, quis porttitor purus varius eget. Maecenas in lorem velit. Sed feugiat ac velit vitae
tempus. In eget arcu vitae ipsum faucibus pretium sed eu sem. Phasellus nec lorem sollicitudin, vehicula odio in, ornare
quam. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam tristique
condimentum ipsum quis pellentesque. Morbi vestibulum id tellus ut tincidunt.
Morbi sit amet pulvinar ex. Etiam aliquam est convallis quam placerat dictum. Sed ligula ante, laoreet sit amet laoreet
quis, semper nec ex. Donec tristique dolor nec maximus sagittis. Duis dictum leo quis volutpat euismod. Praesent porta
felis et sem sodales, scelerisque sollicitudin odio porta. Curabitur ultricies nisl a ligula aliquam porttitor.
Curabitur ligula urna, mattis aliquam dolor nec, scelerisque congue mi.
Duis finibus sagittis tellus at faucibus. Ut sed consequat tellus. Aliquam nec erat dignissim, eleifend lorem sit amet,
elementum felis. Morbi efficitur massa ut turpis facilisis, nec blandit massa cursus. Cras fringilla, ante a dignissim
tincidunt, ligula libero blandit nunc, et egestas lectus tortor eget arcu. Nunc venenatis nibh mauris, quis euismod
lectus congue at. Duis lacinia ligula non est lacinia elementum vitae a ipsum. Mauris et mi nisl. Vivamus facilisis,
lorem at pellentesque dictum, erat nisl malesuada nisl, ac tincidunt dolor magna non libero. Mauris luctus felis vel
magna imperdiet, et molestie est cursus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere
cubilia curae; Fusce vitae mattis nibh. Vestibulum quis augue nunc. Ut fringilla, neque ultrices mattis facilisis, felis
lectus ullamcorper ante, et fermentum lectus justo at nibh.
================================================
FILE: demo/src/posts/2019/post-2.mdx
================================================
---
title: Post 2
tags: ['React', 'GatsbyJs', 'ES6', 'theme-ui']
featuredImage: markus-spiske-70Rir5vB96U-unsplash.jpg
date: 2019-02-17
dateModified: 2019-03-17
author: Paul Scanlon
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis.
================================================
FILE: demo/src/posts/2020/01/post-3.mdx
================================================
---
title: Post 3
tags: ['React', 'HTML']
featuredImage: florian-olivo-Ek9Znm8lQ1U-unsplash.jpg
date: 2020-01-17
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
================================================
FILE: demo/src/posts/2020/02/post-4.mdx
================================================
---
title: Post 4
tags: ['React', 'TypeScript']
status: draft
date: 2020-02-12
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
================================================
FILE: demo/src/posts/2020/02/post-5.mdx
================================================
---
title: Post 5
tags: ['React', 'TypeScript', 'GraphQL', 'Fauna']
featuredImage: pankaj-patel-_SgRNwAVNKw-unsplash.jpg
date: 2020-02-12
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vivamus luctus tincidunt varius. In hac habitasse platea dictumst. Sed eu iaculis velit, in porttitor augue. Ut vitae
sapien vestibulum, bibendum ipsum in, finibus arcu. Vestibulum euismod velit ex, et posuere elit iaculis vel. Donec
sodales imperdiet posuere. Phasellus dui dolor, placerat in elementum vitae, gravida in quam
<Button>Click me</Button>
================================================
FILE: demo/src/posts/2020/04/private.mdx
================================================
---
title: Private
tags: ['React', 'TypeScript', 'GraphQL', 'Fauna']
date: 2020-04-22
isPrivate: true
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Vivamus luctus tincidunt varius. In hac habitasse platea dictumst. Sed eu iaculis velit, in porttitor augue. Ut vitae
sapien vestibulum, bibendum ipsum in, finibus arcu. Vestibulum euismod velit ex, et posuere elit iaculis vel. Donec
sodales imperdiet posuere. Phasellus dui dolor, placerat in elementum vitae, gravida in quam
================================================
FILE: demo/src/posts/2021/local-image-post.mdx
================================================
---
title: Local Image Post
date: 2021-01-14
tags: ['React', 'GatsbyJs', 'ES6', 'Css']
featuredImage: pankaj-patel-SXihyA4oEJs-unsplash.jpg
embeddedImages:
- pankaj-patel-SXihyA4oEJs-unsplash.jpg
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis.
### Gatsby
```javascript
<GatsbyImage alt='...' image={...}/>
```
`<GatsbyImage alt='...' image={...}/>`
<Box>
<GatsbyImage alt="embedded-image-1" image={props.embedded.image1} />
</Box>
<Box as="pre">{JSON.stringify(props.embedded.image1, null, 2)}</Box>
### Theme UI
`<Image src={...} />`
<Box>
<Image src={props.embedded.image1.gatsbyImageData.images.fallback.src} />
</Box>
<Box as="pre">{JSON.stringify(props.embedded.image1.gatsbyImageData.images.fallback.src, null, 2)}</Box>
================================================
FILE: demo/src/posts/2021/remote-image-post.mdx
================================================
---
title: Remote Image Post
date: 2021-01-13
author: Paul Scanlon
tags: ['JavaScript', 'React', 'GatsbyJs', 'HTML', 'CSS', 'theme-ui']
featuredImageUrl: https://res.cloudinary.com/www-paulie-dev/image/upload/v1603273280/paulie.dev/placeholder_ekfnq2.jpg
embeddedImageUrls:
- https://res.cloudinary.com/www-paulie-dev/image/upload/v1603273280/paulie.dev/placeholder_ekfnq2.jpg
- https://res.cloudinary.com/www-paulie-dev/image/upload/v1603273280/paulie.dev/placeholder_ekfnq2.jpg
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis. Donec non tellus
justo. Ut sit amet elit mauris. Praesent eleifend cursus luctus. Praesent posuere rhoncus maximus. Donec nec felis nec
metus semper pharetra ut ut libero. Ut hendrerit dui ut tincidunt egestas. Donec interdum pharetra arcu, vel egestas
turpis ornare a. Phasellus quis euismod diam, sed convallis dolor.
<GatsbyImage alt="" image={props.embedded.image1} />
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis. Donec non tellus
justo. Ut sit amet elit mauris. Praesent eleifend cursus luctus. Praesent posuere rhoncus maximus. Donec nec felis nec
metus semper pharetra ut ut libero. Ut hendrerit dui ut tincidunt egestas. Donec interdum pharetra arcu, vel egestas
turpis ornare a. Phasellus quis euismod diam, sed convallis dolor.
<GatsbyImage alt="" image={props.embedded.image2} />
================================================
FILE: demo/src/posts/post-1.mdx
================================================
---
title: Post 1
date: 2020-04-26
dateModified: 2020-05-05
author: Paul Scanlon
tags: ['JavaScript', 'React', 'GatsbyJs', 'HTML', 'CSS', 'theme-ui']
featuredImage: markus-spiske-466ENaLuhLY-unsplash.jpg
embeddedImages:
- markus-spiske-FXFz-sW0uwo-unsplash.jpg
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis. Donec non tellus
justo. Ut sit amet elit mauris. Praesent eleifend cursus luctus. Praesent posuere rhoncus maximus. Donec nec felis nec
metus semper pharetra ut ut libero. Ut hendrerit dui ut tincidunt egestas. Donec interdum pharetra arcu, vel egestas
turpis ornare a. Phasellus quis euismod diam, sed convallis dolor.
```sh
npm install aThing `aThing` 'aThing' "aThing"
```
```javascript
<SourceArticle
title={title}
tags={tags}
date={date}
dateModified={dateModified}
author={author}
isPrivate={isPrivate}
featuredImage={featuredImage}
embedded={embedded}
body={body}
timeToRead={timeToRead}
wordCount={wordCount}
/>
```
<Grid sx={{ gridTemplateColumns: ['1fr', '1fr 1fr'] }}>
<Box>
Donec nec felis nec metus semper pharetra ut ut libero. Ut hendrerit dui ut tincidunt egestas. Donec interdum
pharetra arcu, vel egestas turpis ornare a. Phasellus quis euismod diam, sed convallis dolor.
</Box>
<Box>
<GatsbyImage alt="embedded-image-1" image={props.embedded.image1} />
</Box>
</Grid>
### [Gatsby](#gatsby)
`<GatsbyImage alt='...' image={...}/>`
<Box as="pre">{JSON.stringify(props.embedded.image1, null, 2)}</Box>
================================================
FILE: demo/src/projects/2019/project-2.mdx
================================================
---
title: Project 2
tags: ['Automotive', 'FinTech', 'Publishing']
date: 2019-01-29
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis. Donec non tellus
justo. Ut sit amet elit mauris. Praesent eleifend cursus luctus. Praesent posuere rhoncus maximus. Donec nec felis nec
metus semper pharetra ut ut libero. Ut hendrerit dui ut tincidunt egestas. Donec interdum pharetra arcu, vel egestas
turpis ornare a. Phasellus quis euismod diam, sed convallis dolor.
================================================
FILE: demo/src/projects/2020/01/project-3.mdx
================================================
---
title: Project 3
tags: ['Automotive']
date: 2020-01-26
url: https://example.com
misc: Ahoy
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis. Donec non tellus
justo. Ut sit amet elit mauris. Praesent eleifend cursus luctus. Praesent posuere rhoncus maximus. Donec nec felis nec
metus semper pharetra ut ut libero. Ut hendrerit dui ut tincidunt egestas. Donec interdum pharetra arcu, vel egestas
turpis ornare a. Phasellus quis euismod diam, sed convallis dolor.
================================================
FILE: demo/src/projects/project-1.mdx
================================================
---
title: Project 1
tags: ['Publishing']
date: 2020-02-27
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id enim et mauris elementum lobortis. Donec non tellus
justo. Ut sit amet elit mauris. Praesent eleifend cursus luctus. Praesent posuere rhoncus maximus. Donec nec felis nec
metus semper pharetra ut ut libero. Ut hendrerit dui ut tincidunt egestas. Donec interdum pharetra arcu, vel egestas
turpis ornare a. Phasellus quis euismod diam, sed convallis dolor.
================================================
FILE: netlify.toml
================================================
[build]
command = "yarn build"
publish = "demo/public"
================================================
FILE: package.json
================================================
{
"private": true,
"scripts": {
"clean": "yarn workspace demo clean",
"serve": "yarn workspace demo serve",
"develop": "yarn workspace demo develop",
"build": "yarn workspace demo build",
"prettier": "prettier --config ./.prettierrc.js --ignore-path ./.prettierignore --write \"**/*.{json,js,ts,tsx,mdx}\"",
"release": "node copy-readme.js && yarn workspace @pauliescanlon/gatsby-theme-terminal publish"
},
"postinstall": "husky install",
"workspaces": [
"@pauliescanlon/gatsby-theme-terminal",
"demo"
],
"devDependencies": {
"@commitlint/cli": "^12.1.4",
"@commitlint/config-conventional": "^12.1.4",
"husky": "^7.0.1",
"prettier": "^2.3.2"
}
}
gitextract_xb6i9ro3/ ├── .commitlintrc.js ├── .github/ │ └── FUNDING.yml ├── .gitignore ├── .husky/ │ ├── commit-msg │ └── pre-commit ├── .prettierignore ├── .prettierrc.js ├── @pauliescanlon/ │ └── gatsby-theme-terminal/ │ ├── README.md │ ├── gatsby-browser.js │ ├── gatsby-config.js │ ├── gatsby-node.js │ ├── gatsby-ssr.js │ ├── index.js │ ├── package.json │ └── src/ │ ├── components/ │ │ ├── logo/ │ │ │ ├── index.js │ │ │ └── logo.js │ │ ├── main/ │ │ │ ├── index.js │ │ │ └── main.js │ │ ├── nav/ │ │ │ ├── index.js │ │ │ └── nav.js │ │ ├── page-element/ │ │ │ ├── index.js │ │ │ └── page-element.js │ │ ├── seo/ │ │ │ ├── index.js │ │ │ └── seo.js │ │ ├── site-metadata/ │ │ │ ├── index.js │ │ │ └── site-metadata.js │ │ ├── source-article/ │ │ │ ├── index.js │ │ │ └── source-article.js │ │ ├── source-days/ │ │ │ ├── index.js │ │ │ └── source-days.js │ │ ├── source-list/ │ │ │ ├── index.js │ │ │ └── source-list.js │ │ ├── source-months/ │ │ │ ├── index.js │ │ │ └── source-months.js │ │ ├── source-tags/ │ │ │ ├── index.js │ │ │ └── source-tags.js │ │ └── source-words/ │ │ ├── index.js │ │ └── source-words.js │ ├── context/ │ │ └── index.js │ ├── data/ │ │ ├── index.js │ │ ├── use-config.js │ │ ├── use-dates.js │ │ ├── use-navigation.js │ │ ├── use-source.js │ │ ├── use-tags.js │ │ └── use-words.js │ ├── gatsby-plugin-theme-ui/ │ │ └── index.js │ ├── layouts/ │ │ ├── page-layout.js │ │ └── source-layout.js │ ├── pages/ │ │ └── 404.js │ └── utils/ │ └── index.js ├── README.md ├── copy-readme.js ├── demo/ │ ├── LICENSE │ ├── README.md │ ├── gatsby-browser.js │ ├── gatsby-config.js │ ├── gatsby-node.js │ ├── gatsby-ssr.js │ ├── package.json │ └── src/ │ ├── @pauliescanlon/ │ │ └── gatsby-theme-terminal/ │ │ └── components/ │ │ └── Logo/ │ │ └── Logo.js │ ├── _temp/ │ │ ├── source-days.mdx │ │ ├── source-list.mdx │ │ ├── source-months.mdx │ │ ├── source-tags.mdx │ │ └── source-words.mdx │ ├── pages/ │ │ ├── components.mdx │ │ ├── index.mdx │ │ ├── markdown.mdx │ │ ├── posts.mdx │ │ ├── projects.mdx │ │ └── theme-ui-components.mdx │ ├── posts/ │ │ ├── 2019/ │ │ │ ├── 03/ │ │ │ │ └── a-pinned-post.mdx │ │ │ └── post-2.mdx │ │ ├── 2020/ │ │ │ ├── 01/ │ │ │ │ └── post-3.mdx │ │ │ ├── 02/ │ │ │ │ ├── post-4.mdx │ │ │ │ └── post-5.mdx │ │ │ └── 04/ │ │ │ └── private.mdx │ │ ├── 2021/ │ │ │ ├── local-image-post.mdx │ │ │ └── remote-image-post.mdx │ │ └── post-1.mdx │ └── projects/ │ ├── 2019/ │ │ └── project-2.mdx │ ├── 2020/ │ │ └── 01/ │ │ └── project-3.mdx │ └── project-1.mdx ├── netlify.toml └── package.json
SYMBOL INDEX (2 symbols across 2 files) FILE: @pauliescanlon/gatsby-theme-terminal/src/layouts/source-layout.js constant IMAGE_KEY (line 14) | const IMAGE_KEY = 'image' FILE: @pauliescanlon/gatsby-theme-terminal/src/utils/index.js constant IMAGE_KEY (line 1) | const IMAGE_KEY = 'image'
Condensed preview — 86 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (165K chars).
[
{
"path": ".commitlintrc.js",
"chars": 69,
"preview": "module.exports = {\n extends: ['@commitlint/config-conventional'],\n}\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 45,
"preview": "github: [pauliescanlon]\nko_fi: pauliescanlon\n"
},
{
"path": ".gitignore",
"chars": 1157,
"preview": "wip-readme.md\ndemo/src/pages/source-days.mdx\ndemo/src/pages/source-list.mdx\ndemo/src/pages/source-months.mdx\ndemo/src/pa"
},
{
"path": ".husky/commit-msg",
"chars": 65,
"preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx commitlint --edit \n"
},
{
"path": ".husky/pre-commit",
"chars": 59,
"preview": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpm run prettier\n"
},
{
"path": ".prettierignore",
"chars": 23,
"preview": "demo/.cache\ndemo/public"
},
{
"path": ".prettierrc.js",
"chars": 138,
"preview": "module.exports = {\n semi: false,\n trailingComma: 'all',\n singleQuote: true,\n printWidth: 120,\n tabWidth: 2,\n prose"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/README.md",
"chars": 7476,
"preview": "<a href=\"https://gatsbythemeterminal.gatsbyjs.io/\" target=\"_blank\">\n<img src=\"https://gatsbythemeterminal.gatsbyjs.io/im"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/gatsby-browser.js",
"chars": 730,
"preview": "const React = require('react')\nconst { PageElement } = require('./src/components/page-element')\n\nconst anchorScroll = (l"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/gatsby-config.js",
"chars": 1734,
"preview": "const path = require('path')\n\nmodule.exports = (themeOptions) => {\n const { source } = themeOptions\n\n let filesystemSo"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/gatsby-node.js",
"chars": 3762,
"preview": "const { createFilePath, createRemoteFileNode } = require('gatsby-source-filesystem')\n\nconst path = require('path')\n\nexpo"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/gatsby-ssr.js",
"chars": 190,
"preview": "const React = require('react')\nconst { PageElement } = require('./src/components/page-element')\n\nexports.wrapPageElement"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/index.js",
"chars": 689,
"preview": "// Data Components\nexport { Main } from './src/components/main'\n\n// Data Components\nexport { SourceDays } from './src/co"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/package.json",
"chars": 1726,
"preview": "{\n \"name\": \"@pauliescanlon/gatsby-theme-terminal\",\n \"description\": \"A zero component Gatsby theme for developers\",\n \""
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/logo/index.js",
"chars": 30,
"preview": "export { Logo } from './logo'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/logo/logo.js",
"chars": 83,
"preview": "/** @jsx jsx */\nimport { jsx } from 'theme-ui'\n\nexport const Logo = () => <span />\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/main/index.js",
"chars": 30,
"preview": "export { Main } from './main'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/main/main.js",
"chars": 5590,
"preview": "import React, { Fragment, useContext } from 'react'\nimport PropTypes from 'prop-types'\nimport { MDXProvider } from '@mdx"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/nav/index.js",
"chars": 28,
"preview": "export { Nav } from './nav'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/nav/nav.js",
"chars": 1632,
"preview": "import React, { Fragment } from 'react'\nimport { Box, NavLink } from 'theme-ui'\nimport { Link as GatsbyLink } from 'gats"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/page-element/index.js",
"chars": 45,
"preview": "export { PageElement } from './page-element'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/page-element/page-element.js",
"chars": 909,
"preview": "import React, { useEffect } from 'react'\nimport { Global, css } from '@emotion/react'\nimport { Fragment } from 'react'\n\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/seo/index.js",
"chars": 28,
"preview": "export { Seo } from './seo'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/seo/seo.js",
"chars": 2765,
"preview": "import React from 'react'\nimport PropTypes from 'prop-types'\nimport { Helmet } from 'react-helmet'\n\nexport const Seo = ("
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/site-metadata/index.js",
"chars": 47,
"preview": "export { SiteMetaData } from './site-metadata'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/site-metadata/site-metadata.js",
"chars": 360,
"preview": "import React, { Fragment } from 'react'\nimport PropTypes from 'prop-types'\n\nimport { useConfig } from '../../data'\n\nexpo"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-article/index.js",
"chars": 49,
"preview": "export { SourceArticle } from './source-article'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-article/source-article.js",
"chars": 4511,
"preview": "import React, { Fragment } from 'react'\nimport PropTypes from 'prop-types'\nimport { MDXRenderer } from 'gatsby-plugin-md"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-days/index.js",
"chars": 43,
"preview": "export { SourceDays } from './source-days'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-days/source-days.js",
"chars": 2038,
"preview": "import React, { Fragment } from 'react'\nimport PropTypes from 'prop-types'\n\nimport { useDates } from '../../data'\nimport"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-list/index.js",
"chars": 43,
"preview": "export { SourceList } from './source-list'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-list/source-list.js",
"chars": 404,
"preview": "import React, { Fragment } from 'react'\nimport PropTypes from 'prop-types'\n\nimport { useSource } from '../../data'\n\nexpo"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-months/index.js",
"chars": 47,
"preview": "export { SourceMonths } from './source-months'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-months/source-months.js",
"chars": 2078,
"preview": "import React, { Fragment } from 'react'\nimport PropTypes from 'prop-types'\n\nimport { useDates } from '../../data'\n\nconst"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-tags/index.js",
"chars": 43,
"preview": "export { SourceTags } from './source-tags'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-tags/source-tags.js",
"chars": 1165,
"preview": "import React, { Fragment } from 'react'\nimport PropTypes from 'prop-types'\n\nimport { useTags } from '../../data'\n\nexport"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-words/index.js",
"chars": 45,
"preview": "export { SourceWords } from './source-words'\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/components/source-words/source-words.js",
"chars": 2735,
"preview": "import React, { Fragment } from 'react'\nimport PropTypes from 'prop-types'\n\nimport { useWords } from '../../data'\n\nconst"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/context/index.js",
"chars": 674,
"preview": "import React from 'react'\n//https://medium.com/@seantheurgel/react-hooks-as-state-management-usecontext-useeffect-usered"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/data/index.js",
"chars": 246,
"preview": "export { useConfig } from './use-config'\nexport { useNavigation } from './use-navigation'\nexport { useDates } from './us"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/data/use-config.js",
"chars": 426,
"preview": "import { useStaticQuery, graphql } from 'gatsby'\n\nexport const useConfig = () => {\n return useStaticQuery(\n graphql`"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/data/use-dates.js",
"chars": 817,
"preview": "import { useStaticQuery, graphql } from 'gatsby'\n\nexport const useDates = (filter) => {\n const query = useStaticQuery(g"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/data/use-navigation.js",
"chars": 496,
"preview": "import { useStaticQuery, graphql } from 'gatsby'\n\nexport const useNavigation = () => {\n return useStaticQuery(\n grap"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/data/use-source.js",
"chars": 1440,
"preview": "import { useStaticQuery, graphql } from 'gatsby'\n\nexport const useSource = (filter) => {\n const query = useStaticQuery("
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/data/use-tags.js",
"chars": 834,
"preview": "import { useStaticQuery, graphql } from 'gatsby'\n\nexport const useTags = (filter) => {\n const query = useStaticQuery(gr"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/data/use-words.js",
"chars": 898,
"preview": "import { useStaticQuery, graphql } from 'gatsby'\n\nexport const useWords = (filter) => {\n const query = useStaticQuery(g"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/gatsby-plugin-theme-ui/index.js",
"chars": 9232,
"preview": "import codeTheme from '@theme-ui/prism/presets/night-owl.json'\nimport { lighten } from '@theme-ui/color'\n\nconst theme = "
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/layouts/page-layout.js",
"chars": 1280,
"preview": "/** @jsx jsx */\nimport { Fragment } from 'react'\nimport { jsx } from 'theme-ui'\nimport { Location } from '@reach/router'"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/layouts/source-layout.js",
"chars": 3445,
"preview": "import React, { Fragment } from 'react'\nimport { Location } from '@reach/router'\nimport { graphql } from 'gatsby'\n\nimpor"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/pages/404.js",
"chars": 78,
"preview": "import React from 'react'\n\nexport default () => <div>404 page not found</div>\n"
},
{
"path": "@pauliescanlon/gatsby-theme-terminal/src/utils/index.js",
"chars": 431,
"preview": "const IMAGE_KEY = 'image'\n\nexport const transformImages = (imageArray) => {\n if (Array.isArray(imageArray)) {\n retur"
},
{
"path": "README.md",
"chars": 7476,
"preview": "<a href=\"https://gatsbythemeterminal.gatsbyjs.io/\" target=\"_blank\">\n<img src=\"https://gatsbythemeterminal.gatsbyjs.io/im"
},
{
"path": "copy-readme.js",
"chars": 194,
"preview": "const fs = require('fs')\n\nfs.copyFile('./README.md', './@pauliescanlon/gatsby-theme-terminal/README.md', (err) => {\n if"
},
{
"path": "demo/LICENSE",
"chars": 1076,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 gatsbyjs\n\nPermission is hereby granted, free of charge, to any person obtainin"
},
{
"path": "demo/README.md",
"chars": 5214,
"preview": "<!-- AUTO-GENERATED-CONTENT:START (STARTER) -->\n<p align=\"center\">\n <a href=\"https://www.gatsbyjs.org\">\n <img alt=\"G"
},
{
"path": "demo/gatsby-browser.js",
"chars": 164,
"preview": "/**\n * Implement Gatsby's Browser APIs in this file.\n *\n * See: https://www.gatsbyjs.org/docs/browser-apis/\n */\n\n// You "
},
{
"path": "demo/gatsby-config.js",
"chars": 934,
"preview": "module.exports = {\n siteMetadata: {\n name: `gatsby-theme-terminal`,\n description: `A zero component Gatsby theme "
},
{
"path": "demo/gatsby-node.js",
"chars": 158,
"preview": "/**\n * Implement Gatsby's Node APIs in this file.\n *\n * See: https://www.gatsbyjs.org/docs/node-apis/\n */\n\n// You can de"
},
{
"path": "demo/gatsby-ssr.js",
"chars": 180,
"preview": "/**\n * Implement Gatsby's SSR (Server Side Rendering) APIs in this file.\n *\n * See: https://www.gatsbyjs.org/docs/ssr-ap"
},
{
"path": "demo/package.json",
"chars": 975,
"preview": "{\n \"name\": \"demo\",\n \"private\": true,\n \"description\": \"A simple starter using gatsby-theme-terminal\",\n \"version\": \"0."
},
{
"path": "demo/src/@pauliescanlon/gatsby-theme-terminal/components/Logo/Logo.js",
"chars": 4334,
"preview": "/** @jsx jsx */\nimport { Box, jsx } from 'theme-ui'\nimport { Link as GatsbyLink } from 'gatsby'\n\nexport const Logo = () "
},
{
"path": "demo/src/_temp/source-days.mdx",
"chars": 1306,
"preview": "---\nnavigationLabel: SourceDays\n---\n\n<SourceDays>\n {(sourceDays) => {\n const currentYear = sourceDays[sourceDays.len"
},
{
"path": "demo/src/_temp/source-list.mdx",
"chars": 268,
"preview": "---\nnavigationLabel: sourceList\n---\n\n<SourceList>\n {(source) => (\n <ul>\n {source.map((edge, index) => {\n "
},
{
"path": "demo/src/_temp/source-months.mdx",
"chars": 1670,
"preview": "---\nnavigationLabel: SourceMonths\n---\n\n<SourceMonths>\n {(sourceMonths) => {\n const currentYear = sourceMonths[source"
},
{
"path": "demo/src/_temp/source-tags.mdx",
"chars": 423,
"preview": "---\nnavigationLabel: SourceTags\n---\n\n<SourceTags>\n {(source) => (\n <Flex sx={{ flexDirection: 'column' }}>\n {so"
},
{
"path": "demo/src/_temp/source-words.mdx",
"chars": 4484,
"preview": "---\nnavigationLabel: SourceWords\n---\n\n<SourceWords>\n {(source) => {\n const { wordCountTotal, wordCountAverage, wordC"
},
{
"path": "demo/src/pages/components.mdx",
"chars": 19656,
"preview": "---\nnavigationLabel: Components\n---\n\n# [gatsby-theme-terminal](#-gatsby-theme-terminal)\n\ngatsby-theme-terminal has some "
},
{
"path": "demo/src/pages/index.mdx",
"chars": 2881,
"preview": "---\nnavigationLabel: Home\n---\n\nimport { format } from 'date-fns'\n\n<Grid\n sx={{\n mb: 6\n }}\n>\n\n<SiteMetaData>\n {(sit"
},
{
"path": "demo/src/pages/markdown.mdx",
"chars": 8337,
"preview": "---\nnavigationLabel: Markdown\n---\n\n# [markdown](#markdown)\n\ngatsby-theme-terminal supports the full set of\n[markdown sho"
},
{
"path": "demo/src/pages/posts.mdx",
"chars": 2685,
"preview": "---\nnavigationLabel: Posts\n---\n\nimport { format } from 'date-fns'\n\n# posts\n\nYou can use the `<SourceList filter=\"posts\" "
},
{
"path": "demo/src/pages/projects.mdx",
"chars": 2710,
"preview": "---\nnavigationLabel: Projects\n---\n\nimport { format } from 'date-fns'\n\n# projects\n\nYou can use the `<SourceList filter=\"p"
},
{
"path": "demo/src/pages/theme-ui-components.mdx",
"chars": 12075,
"preview": "---\nnavigationLabel: Theme UI\n---\n\n# [theme-ui/components](#theme-ui-components)\n\ngatsby-theme-terminal also supports th"
},
{
"path": "demo/src/posts/2019/03/a-pinned-post.mdx",
"chars": 3584,
"preview": "---\ntitle: A Pinned Post\ntags: ['React', 'TypeScript']\nfeaturedImage: pankaj-patel-SXihyA4oEJs-unsplash.jpg\npinned: true"
},
{
"path": "demo/src/posts/2019/post-2.mdx",
"chars": 288,
"preview": "---\ntitle: Post 2\ntags: ['React', 'GatsbyJs', 'ES6', 'theme-ui']\nfeaturedImage: markus-spiske-70Rir5vB96U-unsplash.jpg\nd"
},
{
"path": "demo/src/posts/2020/01/post-3.mdx",
"chars": 175,
"preview": "---\ntitle: Post 3\ntags: ['React', 'HTML']\nfeaturedImage: florian-olivo-Ek9Znm8lQ1U-unsplash.jpg\ndate: 2020-01-17\n---\n\nLo"
},
{
"path": "demo/src/posts/2020/02/post-4.mdx",
"chars": 141,
"preview": "---\ntitle: Post 4\ntags: ['React', 'TypeScript']\nstatus: draft\ndate: 2020-02-12\n---\n\nLorem ipsum dolor sit amet, consecte"
},
{
"path": "demo/src/posts/2020/02/post-5.mdx",
"chars": 555,
"preview": "---\ntitle: Post 5\ntags: ['React', 'TypeScript', 'GraphQL', 'Fauna']\nfeaturedImage: pankaj-patel-_SgRNwAVNKw-unsplash.jpg"
},
{
"path": "demo/src/posts/2020/04/private.mdx",
"chars": 492,
"preview": "---\ntitle: Private\ntags: ['React', 'TypeScript', 'GraphQL', 'Fauna']\ndate: 2020-04-22\nisPrivate: true\n---\n\nLorem ipsum d"
},
{
"path": "demo/src/posts/2021/local-image-post.mdx",
"chars": 902,
"preview": "---\ntitle: Local Image Post\ndate: 2021-01-14\ntags: ['React', 'GatsbyJs', 'ES6', 'Css']\nfeaturedImage: pankaj-patel-SXihy"
},
{
"path": "demo/src/posts/2021/remote-image-post.mdx",
"chars": 1440,
"preview": "---\ntitle: Remote Image Post\ndate: 2021-01-13\nauthor: Paul Scanlon\ntags: ['JavaScript', 'React', 'GatsbyJs', 'HTML', 'CS"
},
{
"path": "demo/src/posts/post-1.mdx",
"chars": 1534,
"preview": "---\ntitle: Post 1\ndate: 2020-04-26\ndateModified: 2020-05-05\nauthor: Paul Scanlon\ntags: ['JavaScript', 'React', 'GatsbyJs"
},
{
"path": "demo/src/projects/2019/project-2.mdx",
"chars": 510,
"preview": "---\ntitle: Project 2\ntags: ['Automotive', 'FinTech', 'Publishing']\ndate: 2019-01-29\n---\n\nLorem ipsum dolor sit amet, con"
},
{
"path": "demo/src/projects/2020/01/project-3.mdx",
"chars": 521,
"preview": "---\ntitle: Project 3\ntags: ['Automotive']\ndate: 2020-01-26\nurl: https://example.com\nmisc: Ahoy\n---\n\nLorem ipsum dolor si"
},
{
"path": "demo/src/projects/project-1.mdx",
"chars": 485,
"preview": "---\ntitle: Project 1\ntags: ['Publishing']\ndate: 2020-02-27\n---\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit."
},
{
"path": "netlify.toml",
"chars": 59,
"preview": "[build]\n command = \"yarn build\"\n publish = \"demo/public\"\n"
},
{
"path": "package.json",
"chars": 710,
"preview": "{\n \"private\": true,\n \"scripts\": {\n \"clean\": \"yarn workspace demo clean\",\n \"serve\": \"yarn workspace demo serve\",\n"
}
]
About this extraction
This page contains the full source code of the PaulieScanlon/gatsby-theme-terminal GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 86 files (148.0 KB), approximately 43.5k tokens, and a symbol index with 2 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.