mirror of
https://github.com/Stone-Red-Code/website.git
synced 2026-09-04 09:15:58 +02:00
@@ -0,0 +1,35 @@
|
||||
import React, { useState } from "react"
|
||||
|
||||
interface SidebarProviderProps {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export interface SidebarContextInterface {
|
||||
current: number
|
||||
setCurrent: (index: number) => void
|
||||
}
|
||||
|
||||
export const SidebarContext = React.createContext<SidebarContextInterface | null>(
|
||||
null
|
||||
)
|
||||
|
||||
export function SidebarProvider({
|
||||
children,
|
||||
}: SidebarProviderProps): JSX.Element {
|
||||
const [current, setCurrent] = useState(0)
|
||||
|
||||
function selectFirstLevel(index: number) {
|
||||
setCurrent(index)
|
||||
}
|
||||
|
||||
return (
|
||||
<SidebarContext.Provider
|
||||
value={{
|
||||
current,
|
||||
setCurrent: selectFirstLevel,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SidebarContext.Provider>
|
||||
)
|
||||
}
|
||||
@@ -2,21 +2,12 @@ import styled, { css } from "styled-components"
|
||||
import {
|
||||
BASE_FONT_SIZE,
|
||||
BASE_LINE_HEIGHT,
|
||||
MODULAR_SCALE,
|
||||
fontFamily,
|
||||
modularScale,
|
||||
} from "../../design/typography"
|
||||
|
||||
function modularFontSize(power: number) {
|
||||
return BASE_FONT_SIZE * Math.pow(MODULAR_SCALE, power)
|
||||
}
|
||||
|
||||
function modularScale(power: number) {
|
||||
const fontSize = modularFontSize(power)
|
||||
|
||||
// attempt to fit line-height a little larger than font-size
|
||||
const paddedLineHeight = fontSize * 1.1
|
||||
const lineHeight =
|
||||
paddedLineHeight - (paddedLineHeight % BASE_LINE_HEIGHT) + BASE_LINE_HEIGHT
|
||||
function modularScaleCSS(power: number) {
|
||||
const { fontSize, lineHeight } = modularScale(power)
|
||||
|
||||
return css`
|
||||
font-size: ${fontSize}px;
|
||||
@@ -28,6 +19,14 @@ export const MarkdownWrapper = styled.div`
|
||||
font-size: ${BASE_FONT_SIZE}px;
|
||||
line-height: ${BASE_LINE_HEIGHT}px;
|
||||
|
||||
& > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
& > :first-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: ${BASE_LINE_HEIGHT}px 0;
|
||||
}
|
||||
@@ -45,26 +44,26 @@ export const MarkdownWrapper = styled.div`
|
||||
}
|
||||
|
||||
h1 {
|
||||
${modularScale(6)};
|
||||
${modularScaleCSS(6)};
|
||||
}
|
||||
|
||||
h2 {
|
||||
${modularScale(5)};
|
||||
${modularScaleCSS(5)};
|
||||
}
|
||||
|
||||
h3 {
|
||||
${modularScale(4)};
|
||||
${modularScaleCSS(4)};
|
||||
}
|
||||
|
||||
h4 {
|
||||
${modularScale(3)};
|
||||
${modularScaleCSS(3)};
|
||||
}
|
||||
|
||||
h5 {
|
||||
${modularScale(2)};
|
||||
${modularScaleCSS(2)};
|
||||
}
|
||||
|
||||
h6 {
|
||||
${modularScale(1)};
|
||||
${modularScaleCSS(1)};
|
||||
}
|
||||
`
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import React from "react"
|
||||
|
||||
import ChevronUp from "../../icons/chevron-up.svg"
|
||||
import * as SC from "./styles"
|
||||
|
||||
interface ResourceHeaderProps {
|
||||
title: any
|
||||
authors: any
|
||||
createdAt: any
|
||||
timeToRead: any
|
||||
recommendedReading: any
|
||||
}
|
||||
|
||||
export function ResourceHeader({
|
||||
title,
|
||||
authors,
|
||||
createdAt,
|
||||
timeToRead,
|
||||
recommendedReading,
|
||||
}: ResourceHeaderProps) {
|
||||
const date = new Date(createdAt)
|
||||
const month = date.toLocaleString("default", { month: "long" })
|
||||
const day = date.getDate()
|
||||
const year = date.getUTCFullYear()
|
||||
const dateToHuman = `${month} ${day}, ${year}`
|
||||
|
||||
return (
|
||||
<SC.ResourceHeaderWrapper>
|
||||
<SC.Title>{title}</SC.Title>
|
||||
|
||||
<SC.Top>
|
||||
<SC.AuthorAvatars>
|
||||
{authors.map(author => (
|
||||
<SC.AuthorAvatar src={author.avatar} />
|
||||
))}
|
||||
</SC.AuthorAvatars>
|
||||
<SC.Meta>
|
||||
{authors.length} contributor{authors.lenght > 1 && "s"}
|
||||
</SC.Meta>
|
||||
<SC.Meta>{dateToHuman}</SC.Meta>
|
||||
<SC.Meta>
|
||||
{timeToRead} minute{timeToRead !== 1 && "s"} read time
|
||||
</SC.Meta>
|
||||
</SC.Top>
|
||||
|
||||
{recommendedReading && (
|
||||
<SC.RecommendedReading>
|
||||
Recommended reading
|
||||
{recommendedReading.map(item => {
|
||||
return (
|
||||
<SC.ReadLink>
|
||||
<ChevronUp /> <SC.ReadLinkText>{item}</SC.ReadLinkText>
|
||||
</SC.ReadLink>
|
||||
)
|
||||
})}
|
||||
</SC.RecommendedReading>
|
||||
)}
|
||||
</SC.ResourceHeaderWrapper>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import styled from "styled-components"
|
||||
import { fontFamily, modularScale } from "../../design/typography"
|
||||
|
||||
export const ResourceHeaderWrapper = styled.div`
|
||||
border-bottom: 1px solid #dbdbdb;
|
||||
padding-bottom: 32px;
|
||||
margin-bottom: 32px;
|
||||
`
|
||||
|
||||
export const Top = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
export const Title = styled.h1`
|
||||
font-family: ${fontFamily.header};
|
||||
font-size: ${modularScale(6).fontSize}px;
|
||||
line-height: ${modularScale(6).lineHeight}px;
|
||||
letter-spacing: -1.75px;
|
||||
`
|
||||
|
||||
export const AuthorAvatars = styled.div`
|
||||
margin-right: 16px;
|
||||
`
|
||||
|
||||
export const AuthorAvatar = styled.img`
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 2px solid #fff;
|
||||
border-radius: 50%;
|
||||
`
|
||||
|
||||
export const Meta = styled.div`
|
||||
& + &::before {
|
||||
content: "•";
|
||||
margin: 0 8px;
|
||||
}
|
||||
`
|
||||
|
||||
export const RecommendedReading = styled.div`
|
||||
margin-top: 16px;
|
||||
`
|
||||
|
||||
export const ReadLink = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #04b0a6;
|
||||
margin-top: 4px;
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #045551;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 14px;
|
||||
transform: rotate(90deg);
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: #04b0a6;
|
||||
}
|
||||
`
|
||||
|
||||
export const ReadLinkText = styled.div`
|
||||
text-decoration: underline;
|
||||
`
|
||||
@@ -6,35 +6,22 @@
|
||||
*/
|
||||
|
||||
import React, { PropsWithChildren } from "react"
|
||||
import { useStaticQuery, graphql } from "gatsby"
|
||||
|
||||
import { GlobalStyles } from "../../globalStyles"
|
||||
import { ResourcesSidebar } from "../ResourcesSidebar"
|
||||
import { Footer } from "../Footer"
|
||||
import * as SC from "./styles"
|
||||
import { SidebarProvider } from "../../SidebarProvider"
|
||||
|
||||
export function ResourcesLayout({ children }: PropsWithChildren<{}>) {
|
||||
const data = useStaticQuery(graphql`
|
||||
query {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
`)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SidebarProvider>
|
||||
<GlobalStyles />
|
||||
<SC.Main>
|
||||
<ResourcesSidebar />
|
||||
<SC.MainContent>
|
||||
<h1>{data.site.siteMetadata.title}</h1>
|
||||
{children}
|
||||
<SC.Container>{children}</SC.Container>
|
||||
</SC.MainContent>
|
||||
</SC.Main>
|
||||
<Footer />
|
||||
</div>
|
||||
</SidebarProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,12 +2,13 @@ import styled from "styled-components"
|
||||
|
||||
export const Main = styled.div`
|
||||
display: flex;
|
||||
margin: 128px auto 64px !important;
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
`
|
||||
|
||||
export const MainContent = styled.main`
|
||||
flex: 1 1 auto;
|
||||
margin-top: 128px;
|
||||
|
||||
& > :first-child {
|
||||
margin-top: 0;
|
||||
@@ -17,3 +18,8 @@ export const MainContent = styled.main`
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`
|
||||
|
||||
export const Container = styled.div`
|
||||
width: 650px;
|
||||
margin: 0 auto;
|
||||
`
|
||||
|
||||
@@ -2,6 +2,8 @@ import React, { useState } from "react"
|
||||
import Tree from "react-treeview"
|
||||
import { useStaticQuery, graphql } from "gatsby"
|
||||
import useBuildTree from "./useBuildTree"
|
||||
import useSidebar from "./../../hooks/useSidebar"
|
||||
import banner from "../../images/tph-banner.png"
|
||||
import * as SC from "./styles"
|
||||
|
||||
export interface IFile {
|
||||
@@ -56,32 +58,63 @@ const ALL_RESOURCES = graphql`
|
||||
}
|
||||
`
|
||||
|
||||
function plantTree(item: IFileOrFolder) {
|
||||
function plantTree(item: IFileOrFolder, index?: number, firstLevel?: boolean) {
|
||||
if (item.type === "file") {
|
||||
return (
|
||||
<SC.PageLink to={item.path} activeClassName="active">
|
||||
<SC.PageLink key={item.title} to={item.path} activeClassName="active">
|
||||
{item.title}
|
||||
</SC.PageLink>
|
||||
)
|
||||
}
|
||||
|
||||
return <Folder item={item} />
|
||||
if (firstLevel && index !== undefined) {
|
||||
return <FirstLevelFolder key={item.title} item={item} index={index} />
|
||||
}
|
||||
|
||||
return <Folder key={item.title} item={item} />
|
||||
}
|
||||
|
||||
function Folder({ item }: { item: IFolder }) {
|
||||
const [collapsed, setCollapse] = useState(false)
|
||||
const [collapsed, setCollapse] = useState(true)
|
||||
|
||||
function toggleCollapse() {
|
||||
setCollapse(prevState => !prevState)
|
||||
}
|
||||
|
||||
return (
|
||||
<Tree
|
||||
collapsed={collapsed}
|
||||
nodeLabel={<div onClick={toggleCollapse}>{item.title}</div>}
|
||||
>
|
||||
{item.children.map(plantTree)}
|
||||
</Tree>
|
||||
<SC.TreeWrapper>
|
||||
<Tree
|
||||
collapsed={collapsed}
|
||||
nodeLabel={<SC.Label onClick={toggleCollapse}>{item.title}</SC.Label>}
|
||||
>
|
||||
{item.children.map(node => plantTree(node))}
|
||||
</Tree>
|
||||
</SC.TreeWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
function FirstLevelFolder({ item, index }: { item: IFolder; index: number }) {
|
||||
const { current, setCurrent } = useSidebar()
|
||||
const collapsed = current !== index
|
||||
|
||||
return (
|
||||
<SC.TreeWrapper>
|
||||
<Tree
|
||||
className="firstLevel"
|
||||
collapsed={collapsed}
|
||||
nodeLabel={
|
||||
<SC.FirstLabel
|
||||
className={!collapsed ? "active" : undefined}
|
||||
onClick={() => setCurrent(index)}
|
||||
>
|
||||
{item.title}
|
||||
<SC.CollapseToggler />
|
||||
</SC.FirstLabel>
|
||||
}
|
||||
>
|
||||
{item.children.map(node => plantTree(node))}
|
||||
</Tree>
|
||||
</SC.TreeWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -91,7 +124,10 @@ export function ResourcesSidebar() {
|
||||
|
||||
return (
|
||||
<SC.ResourcesSidebarWrapper>
|
||||
{tree.map(node => plantTree(node))}
|
||||
<SC.Banner src={banner} />
|
||||
<SC.Inner>
|
||||
{tree.map((node, index) => plantTree(node, index, true))}
|
||||
</SC.Inner>
|
||||
</SC.ResourcesSidebarWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,111 @@
|
||||
import styled from "styled-components"
|
||||
import { Link } from "gatsby"
|
||||
import ChevronUp from "../../icons/chevron-up.svg"
|
||||
|
||||
export const ResourcesSidebarWrapper = styled.div`
|
||||
box-sizing: border-box;
|
||||
padding: 0 16px;
|
||||
flex: 0 0 300px;
|
||||
background: #f9f9f9;
|
||||
`
|
||||
|
||||
export const Banner = styled.img`
|
||||
display: block;
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
export const TreeWrapper = styled.div`
|
||||
width: 100%;
|
||||
|
||||
& + & {
|
||||
border-top: 1px solid #dbdbdb;
|
||||
}
|
||||
`
|
||||
|
||||
export const Label = styled.div`
|
||||
padding: 4px 0;
|
||||
`
|
||||
|
||||
export const FirstLabel = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 12px 15px 12px 0;
|
||||
font-weight: 700;
|
||||
color: #a9a9a9;
|
||||
|
||||
&.active {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-left: auto;
|
||||
transform: rotate(90deg);
|
||||
transition: transform 0.3s;
|
||||
|
||||
path {
|
||||
fill: #a9a9a9;
|
||||
}
|
||||
}
|
||||
|
||||
&.active svg {
|
||||
transform: rotate(0);
|
||||
|
||||
path {
|
||||
fill: #000;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const CollapseToggler = styled(ChevronUp)``
|
||||
|
||||
export const Inner = styled.div`
|
||||
padding-top: 30px;
|
||||
padding-left: 20px;
|
||||
|
||||
.tree-view {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tree-view_item {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tree-view_children {
|
||||
margin-left: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.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: "▾";
|
||||
}
|
||||
|
||||
.tree-view_arrow.firstLevel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tree-view_arrow-collapsed {
|
||||
-webkit-transform: rotate(-90deg);
|
||||
-moz-transform: rotate(-90deg);
|
||||
-ms-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
`
|
||||
|
||||
export const PageLink = styled(Link)`
|
||||
|
||||
@@ -5,6 +5,6 @@ created_at: 2019/07/27
|
||||
title: Callbacks
|
||||
---
|
||||
|
||||
# Callbacks are everywhere
|
||||
## Callbacks are everywhere
|
||||
|
||||
If you've been doing javascript for any amount of time you'll have noticed that callbacks appear in just about every single piece of code.
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
authors:
|
||||
- "veksen#1060"
|
||||
created_at: "2019/07/27"
|
||||
title: Iterative vs Functional array helpers
|
||||
---
|
||||
|
||||
# Iterative vs Functional array helpers
|
||||
|
||||
-- placeholder --
|
||||
|
||||
## find
|
||||
|
||||
@@ -9,14 +9,14 @@ recommended_reading:
|
||||
- javascript/es6/arrow-functions
|
||||
---
|
||||
|
||||
# A Promise to Keep
|
||||
## A Promise to Keep
|
||||
|
||||
A `Promise` in Javascript represents an action that has already started, but one that will be
|
||||
completed at a later time. Much like in real life, when you create a promise, you are expected
|
||||
to fulfill that promise. However, sometimes things go wrong where you can no longer fulfill
|
||||
a promise you made. This is essentially the main idea behind how promises work in javascript.
|
||||
|
||||
## Basics
|
||||
### Basics
|
||||
|
||||
When you create a Promise or call a function that returns a Promise in Javascript, you're left
|
||||
with an object that can either resolve into the actual value that you were promised, or it
|
||||
@@ -24,7 +24,7 @@ can reject and leave you with an error for why that promise failed.
|
||||
|
||||
We can access these values using the `.then` and `.catch` methods on the `Promise` object respectively.
|
||||
|
||||
## A Simple Example
|
||||
### A Simple Example
|
||||
|
||||
First, let's explore a bit of a made-up example. Imagine we have a promise-returning function
|
||||
called `getMembers` that retrieves all the members in a discord server. When we execute this
|
||||
@@ -50,7 +50,7 @@ getMembers("The Programmers Hangout").then(members => {
|
||||
|
||||
This way we are able to make sure that we only try to `console.log` when the `getMembers` function has resolved and ready to be used.
|
||||
|
||||
## Beginner Mistakes
|
||||
### Beginner Mistakes
|
||||
|
||||
Promises are possibly the #1 most common source of confusion for beginners. In order
|
||||
to avoid falling in pitfalls yourself, you have to remember 2 things about Javascript when
|
||||
@@ -85,7 +85,7 @@ getWeather("Los Angeles").then(weather => {
|
||||
})
|
||||
```
|
||||
|
||||
## Real World Example
|
||||
### Real World Example
|
||||
|
||||
Here is a real function that gets character information from the Rick and Morty API.
|
||||
You can try it in your browser if you want to test it out.
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
authors:
|
||||
- "Xetera#0001"
|
||||
created_at: "2019/07/26"
|
||||
title: Simplifying Promises
|
||||
---
|
||||
|
||||
# Simplifying Promises
|
||||
|
||||
-- placeholder --
|
||||
|
||||
The first naive attempt, using new Promise for something that already returns a promise.
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
authors:
|
||||
- "supergrecko#3434"
|
||||
created_at: "2019/07/27"
|
||||
title: Singletons
|
||||
---
|
||||
|
||||
# Singletons
|
||||
|
||||
A singleton is a class which is only instantiated once during runtime. This is done by keeping a static property containing its instance on the singleton class.
|
||||
|
||||
There are multiple benefits to using a singleton class
|
||||
@@ -16,7 +15,7 @@ There are multiple benefits to using a singleton class
|
||||
|
||||
By using a singleton instead of a static class we expose a cleaner class to use and we can use regular instance properties instead of static properties.
|
||||
|
||||
# Creating a Singleton in PHP
|
||||
## Creating a Singleton in PHP
|
||||
|
||||
Creating a class which can be used as a singleton is very simple.
|
||||
|
||||
@@ -50,7 +49,7 @@ class Singleton
|
||||
}
|
||||
```
|
||||
|
||||
# Testing our Singleton
|
||||
## Testing our Singleton
|
||||
|
||||
To give a little functionality to our freshly baked Singleton we add these three members to the class
|
||||
|
||||
@@ -93,7 +92,7 @@ $first->setWord("Banana");
|
||||
var_dump($first->getWord() === $second->getWord()); // bool(true)
|
||||
```
|
||||
|
||||
# Further Research
|
||||
## Further Research
|
||||
|
||||
Here's a couple links which will help you understand Singletons better.
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
authors:
|
||||
- "Xetera#0001"
|
||||
date: 2019/06/26
|
||||
title: Some Python Article
|
||||
---
|
||||
|
||||
# Python
|
||||
## Python
|
||||
|
||||
This is a placeholder post
|
||||
|
||||
|
||||
@@ -5,6 +5,24 @@ export const BASE_FONT_SIZE = 18
|
||||
export const BASE_LINE_HEIGHT = 25
|
||||
export const MODULAR_SCALE = 1.1487
|
||||
|
||||
function modularFontSize(power: number) {
|
||||
return BASE_FONT_SIZE * Math.pow(MODULAR_SCALE, power)
|
||||
}
|
||||
|
||||
export function modularScale(power: number) {
|
||||
const fontSize = modularFontSize(power)
|
||||
|
||||
// attempt to fit line-height a little larger than font-size
|
||||
const paddedLineHeight = fontSize * 1.1
|
||||
const lineHeight =
|
||||
paddedLineHeight - (paddedLineHeight % BASE_LINE_HEIGHT) + BASE_LINE_HEIGHT
|
||||
|
||||
return {
|
||||
fontSize,
|
||||
lineHeight,
|
||||
}
|
||||
}
|
||||
|
||||
export const fontFamily = {
|
||||
header: FONT_MONTSERRAT,
|
||||
body: FONT_OXYGEN,
|
||||
|
||||
+1
-47
@@ -11,6 +11,7 @@ export const GlobalStyles = createGlobalStyle`
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-size: ${BASE_FONT_SIZE}px;
|
||||
line-height: ${BASE_LINE_HEIGHT}px;
|
||||
}
|
||||
@@ -33,51 +34,4 @@ export const GlobalStyles = createGlobalStyle`
|
||||
padding-left: 2.8em;
|
||||
overflow: initial;
|
||||
}
|
||||
|
||||
/* TODO: probably extract this */
|
||||
.tree-view {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.tree-view_item {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tree-view_item,
|
||||
.tree-view_children > div {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.tree-view_children {
|
||||
margin-left: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.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: "▾";
|
||||
}
|
||||
|
||||
.tree-view_arrow-collapsed {
|
||||
-webkit-transform: rotate(-90deg);
|
||||
-moz-transform: rotate(-90deg);
|
||||
-ms-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
`
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { useContext } from "react"
|
||||
import { SidebarContext, SidebarContextInterface } from "../SidebarProvider"
|
||||
|
||||
export default function useSidebar(): SidebarContextInterface {
|
||||
const sidebarContext = useContext(SidebarContext)
|
||||
|
||||
if (!sidebarContext) {
|
||||
throw Error("Need context")
|
||||
}
|
||||
|
||||
return sidebarContext
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="15" height="8" viewBox="0 0 15 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.72578 0.21176L0.213835 6.72587C-0.0712782 7.01171 -0.0712782 7.47481 0.213835 7.76136C0.498947 8.0472 0.962045 8.0472 1.24716 7.76136L7.24241 1.76394L13.2377 7.76064C13.5228 8.04648 13.9859 8.04648 14.2717 7.76064C14.5568 7.47481 14.5568 7.01099 14.2717 6.72515L7.75976 0.211038C7.47759 -0.0704669 7.00722 -0.070466 6.72578 0.21176Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 462 B |
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
@@ -3,14 +3,22 @@ import { graphql } from "gatsby"
|
||||
import { Markdown } from "../components/Markdown"
|
||||
import { SEO } from "../components/SEO"
|
||||
import { ResourcesLayout } from "../components/ResourcesLayout"
|
||||
import { ResourceHeader } from "../components/ResourceHeader"
|
||||
|
||||
// @todo maybe find alternative type for data
|
||||
function LanguagePost({ data }: any) {
|
||||
const { html, frontmatter } = data.file.post
|
||||
const { html, fields, frontmatter, timeToRead } = data.file.post
|
||||
console.log(data)
|
||||
return (
|
||||
<ResourcesLayout>
|
||||
<SEO title={frontmatter.title} />
|
||||
<ResourceHeader
|
||||
title={frontmatter.title}
|
||||
authors={fields.authors}
|
||||
createdAt={frontmatter.created_at}
|
||||
timeToRead={timeToRead}
|
||||
recommendedReading={frontmatter.recommended_reading}
|
||||
/>
|
||||
<Markdown content={html} />
|
||||
</ResourcesLayout>
|
||||
)
|
||||
@@ -31,9 +39,11 @@ export const query = graphql`
|
||||
}
|
||||
}
|
||||
frontmatter {
|
||||
date
|
||||
created_at
|
||||
title
|
||||
recommended_reading
|
||||
}
|
||||
timeToRead
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user