bootstrap docs layout & sidebar (#4)

bootstrap docs layout & sidebar
This commit is contained in:
Jean-Philippe Sirois
2019-07-27 04:17:52 -04:00
committed by GitHub
18 changed files with 391 additions and 21 deletions
+8 -1
View File
@@ -19,6 +19,13 @@ module.exports = {
path: `${__dirname}/src/images`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `site`,
path: `${__dirname}/src/content/site`,
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
@@ -34,7 +41,7 @@ module.exports = {
resolve: `gatsby-plugin-manifest`,
options: {
name: `The Programmers Hangout`,
short_name: `starter`,
short_name: `TPH`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#ba1a2e`,
+32 -3
View File
@@ -1745,6 +1745,11 @@
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw=="
},
"@types/ramda": {
"version": "0.26.18",
"resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.26.18.tgz",
"integrity": "sha512-wK3NLaAkL/ht7Nw4IZsOagJuYqzZgoboFvILolOPtmoKyy25gTdz/uvB/bXsv6vdWENYv+ml5ph873P2d/+9HA=="
},
"@types/reach__router": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.2.4.tgz",
@@ -1785,15 +1790,26 @@
"version": "0.60.2",
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.60.2.tgz",
"integrity": "sha512-K4+/etirpv52xu24xAc++OdhbD0VQEt0Kq0h6dZrLU82OlA+I7BhpKF3JBvx9tbmrFaZDxhHp8N4TEvRYS4fdQ==",
"dev": true,
"requires": {
"@types/prop-types": "*",
"@types/react": "*"
}
},
"@types/react-treeview": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@types/react-treeview/-/react-treeview-0.4.2.tgz",
"integrity": "sha512-pL2IuQrSPbOgn4wQ4B24bekCjyoa6KpereAtYroMwt3dAeFivchksF00oWkNjEoX3NBQ0gZGuu6fa1AzL5Whgw==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"@types/styled-components": {
"version": "4.1.18",
"resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-4.1.18.tgz",
"integrity": "sha512-VrHkgvjbxQXOw0xWSUckusUUZ4y/jqN1u7kF29ngh0oE6uOrlZHleTgqeUqylQqHQIeQ8MxFb50BRHy8ju5DHg==",
"dev": true,
"requires": {
"@types/react": "*",
"@types/react-native": "*",
@@ -13765,9 +13781,9 @@
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
},
"ramda": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz",
"integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU="
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz",
"integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ=="
},
"randombytes": {
"version": "2.1.0",
@@ -14094,6 +14110,14 @@
"shallowequal": "^1.0.1"
}
},
"react-treeview": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/react-treeview/-/react-treeview-0.4.7.tgz",
"integrity": "sha1-9kfgT3BJbrEfsJEsNRh+gOtg1Fg=",
"requires": {
"prop-types": "^15.5.8"
}
},
"read": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
@@ -16253,6 +16277,11 @@
"json5": "^0.5.0"
}
},
"ramda": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz",
"integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU="
},
"xml2js": {
"version": "0.4.17",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz",
+5 -1
View File
@@ -5,7 +5,7 @@
"version": "0.1.0",
"author": "TPH",
"dependencies": {
"@types/styled-components": "^4.1.18",
"@types/ramda": "^0.26.18",
"axios": "^0.19.0",
"babel-plugin-styled-components": "^1.10.6",
"gatsby": "^2.13.39",
@@ -27,10 +27,12 @@
"highlight.js": "^9.15.8",
"node-sass": "^4.12.0",
"prismjs": "^1.17.1",
"ramda": "^0.26.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-helmet": "^5.2.1",
"react-perfect-scrollbar": "^1.5.3",
"react-treeview": "^0.4.7",
"styled-components": "^4.3.2"
},
"devDependencies": {
@@ -38,6 +40,8 @@
"@types/react": "^16.8.23",
"@types/react-dom": "^16.8.5",
"@types/react-helmet": "^5.0.8",
"@types/react-treeview": "^0.4.2",
"@types/styled-components": "^4.1.18",
"prettier": "^1.18.2",
"@graphql-codegen/typescript": "1.4.0",
"@graphql-codegen/typescript-operations": "1.4.0",
-5
View File
@@ -1,5 +0,0 @@
import React from "react";
const Sidebar = () => { }
export default Sidebar;
-1
View File
@@ -1 +0,0 @@
export { default as Sidebar } from "./Sidebar";
+46
View File
@@ -0,0 +1,46 @@
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.org/docs/use-static-query/
*/
import React, { PropsWithChildren } from "react"
import { useStaticQuery, graphql } from "gatsby"
import Container from "../Container"
import DocsSidebar from "../DocsSidebar"
import { Main, MainContent } from "./styles"
import Scrollbar from "react-perfect-scrollbar"
import "react-perfect-scrollbar/dist/css/styles.css"
const DocsLayout = ({ children }: PropsWithChildren<{}>) => {
const data = useStaticQuery(graphql`
query {
site {
siteMetadata {
title
}
}
}
`)
return (
<Scrollbar>
<Main>
<DocsSidebar />
<MainContent>
<h1>{data.site.siteMetadata.title}</h1>
{children}
</MainContent>
</Main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</Scrollbar>
)
}
export default DocsLayout
+41
View File
@@ -0,0 +1,41 @@
// TODO: refactor this into styled components
html {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/**
* If you already use line highlighting
*/
/* Adjust the position of the line numbers */
.gatsby-highlight pre[class*="language-"].line-numbers {
padding-left: 2.8em;
}
/**
* If you only want to use line numbering
*/
.gatsby-highlight {
background-color: #fdf6e3;
border-radius: 0.3em;
margin: 0.5em 0;
padding: 1em;
overflow: auto;
}
.gatsby-highlight pre[class*="language-"].line-numbers {
padding: 0;
padding-left: 2.8em;
overflow: initial;
}
+19
View File
@@ -0,0 +1,19 @@
import styled from "styled-components"
export const Main = styled.div`
display: flex;
margin: 128px auto 64px !important;
width: 100%;
`
export const MainContent = styled.main`
flex: 1 0 auto;
& > :first-child {
margin-top: 0;
}
& > :last-child {
margin-bottom: 0;
}
`
+142
View File
@@ -0,0 +1,142 @@
import * as R from "ramda"
import React from "react"
import Tree from "react-treeview"
import { useStaticQuery, graphql } from "gatsby"
export interface DocsSidebarProps {
readonly width: string | number
}
interface IFile {
title: string
type: "file"
}
interface IFolder {
title: string
type: "folder"
children: IFileOrFolder[]
}
type IFileOrFolder = IFile | IFolder
const traverse = ([head, ...tail]: string[]): IFileOrFolder => {
const isFile = !tail.length
if (isFile) {
// probably not more than one dot
const [name] = head.split(".")
return {
title: name,
type: "file",
}
}
return {
title: head,
type: "folder",
children: [traverse(tail)],
}
}
const generateFolder = ({
title,
targets,
}: {
title: IFolder["title"]
targets: IFolder[]
}): IFolder => {
const children = join(R.chain(target => target.children, targets))
return {
title,
type: "folder",
children,
}
}
const generateFile = ({ title }: { title: IFile["title"] }): IFile => {
return {
title,
type: "file",
}
}
const join = ([head, ...tail]: IFileOrFolder[]): IFileOrFolder[] => {
if (!head) return []
const [similarFs, remaining] = R.partition(
obj => obj.title === head.title && obj.type === head.type,
tail
)
const targets = [head, ...similarFs]
const { title } = head
const current =
head.type === "folder"
? generateFolder({ title, targets: targets as IFolder[] })
: generateFile({ title })
return [current, ...join(remaining)]
}
interface IFileQuery {
node: {
relativePath: string
childMarkdownRemark: {
frontmatter: {
author: string
date: string
}
}
}
}
interface IAllDocsQuery {
allFile: {
edges: IFileQuery[]
}
}
const ALL_DOCS = graphql`
query {
allFile(filter: { sourceInstanceName: { eq: "docs" } }) {
edges {
node {
relativePath
childMarkdownRemark {
frontmatter {
author
date
}
}
}
}
}
}
`
const plantTree = (item: IFileOrFolder) => {
if (item.type === "file") {
return <div>{item.title}</div>
}
return (
<Tree nodeLabel={<div>{item.title}</div>}>
{item.children.map(plantTree)}
</Tree>
)
}
const DocsSidebar = ({ width }: DocsSidebarProps) => {
const docs = useStaticQuery<IAllDocsQuery>(ALL_DOCS)
const objects = docs.allFile.edges.map(({ node: file }: IFileQuery) =>
traverse(file.relativePath.split("/"))
)
const results = join(objects)
console.log(results)
return <div style={{ width }}>{results.map(node => plantTree(node))}</div>
}
export default DocsSidebar
+6
View File
@@ -0,0 +1,6 @@
import styled from "styled-components"
export const DocsSidebarScroller = styled.div`
display: flex;
flex-direction: column;
`
@@ -0,0 +1,20 @@
import React from "react"
import { SidebarTitle } from "./style"
export interface DocsSidebarSectionProps {
readonly title: string
}
const DocsSidebarSection = ({
title,
children,
}: React.PropsWithChildren<DocsSidebarSectionProps>) => {
return (
<div>
<SidebarTitle>{title}</SidebarTitle>
{children}
</div>
)
}
export default DocsSidebarSection
@@ -0,0 +1,5 @@
import styled from "styled-components";
export const SidebarTitle = styled.h3`
text-transform: uppercase;
`;
+1 -1
View File
@@ -18,7 +18,7 @@ import "react-perfect-scrollbar/dist/css/styles.css"
const Layout = ({ children }: PropsWithChildren<{}>) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
query {
site {
siteMetadata {
title
+41
View File
@@ -39,3 +39,44 @@ body {
padding-left: 2.8em;
overflow: initial;
}
/* temp */
/* the tree node's style */
.tree-view {
overflow-y: hidden;
}
.tree-view_item {
display: flex;
}
/* style for the children nodes container */
.tree-view_children {
margin-left: 16px;
}
.tree-view_children-collapsed {
height: 0px;
}
.tree-view_arrow {
cursor: pointer;
margin-right: 6px;
display: inline-block;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.tree-view_arrow:after {
content: "";
}
/* rotate the triangle to close it */
.tree-view_arrow-collapsed {
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
transform: rotate(-90deg);
}
@@ -8,6 +8,7 @@ recommended_reading:
- javascript/callbacks
- javascript/es6/arrow-functions
---
# A Promise to Keep
A `Promise` in Javascript represents an action that has already started, but one that will be
+15
View File
@@ -0,0 +1,15 @@
---
path: /
---
# The Programmers Hangout
The Programmer's Hangout (TPH) is a Discord community of programmers with members of
all skill levels. If you're interested in programming, you're welcome here regardless
of how much experience you have. You'll find that we're always learning here regardless
of expertise.
## How do I join?
All you need to do is click!
<!-- Insert link here later -->
+9 -9
View File
@@ -1,25 +1,25 @@
import React from "react";
import { graphql } from "gatsby";
import SEO from "../components/SEO";
import Layout from "../components/Layout";
import React from "react"
import { graphql } from "gatsby"
import SEO from "../components/SEO"
import DocsLayout from "../components/DocsLayout"
// @todo maybe find alternative type for data
const LanguagePost = ({ data }: any) => {
const { html, frontmatter } = data.file.post;
const { html, frontmatter } = data.file.post
console.log(data)
return (
<Layout>
<DocsLayout>
<SEO title={frontmatter.title} />
<div dangerouslySetInnerHTML={{ __html: html }} />
</Layout >
</DocsLayout>
)
}
export default LanguagePost;
export default LanguagePost
export const query = graphql`
query LanguagePost($file: String!) {
file(relativePath: {eq: $file }) {
file(relativePath: { eq: $file }) {
post: childMarkdownRemark {
html
frontmatter {