mirror of
https://github.com/Stone-Red-Code/website.git
synced 2026-09-04 17:25:59 +02:00
ui: first pass on redesign (#228)
This commit is contained in:
@@ -14,7 +14,7 @@ interface IBreadcrumbProps {
|
||||
basePath: string
|
||||
}
|
||||
|
||||
const Link: FC<ILinkProps> = ({ item }) => {
|
||||
const LinkItem: FC<ILinkProps> = ({ item }) => {
|
||||
return <SC.StyledLink to={item.path}>{humanize(item.title)}</SC.StyledLink>
|
||||
}
|
||||
|
||||
@@ -32,17 +32,17 @@ function flatten([
|
||||
export function Breadcrumb({ relativePath, basePath }: IBreadcrumbProps) {
|
||||
const paths = relativePath.split("/")
|
||||
const breadcrumbItems = flatten([traversePaths(paths, basePath)])
|
||||
let foldersDepth = 0;
|
||||
let foldersDepth = 0
|
||||
return (
|
||||
<SC.BreadcrumbWrapper>
|
||||
<SC.LinkWrapper>
|
||||
<Link
|
||||
<LinkItem
|
||||
item={{ path: "/", title: "home", type: "folder", children: [] }}
|
||||
/>
|
||||
<ChevronUp />
|
||||
</SC.LinkWrapper>
|
||||
<SC.LinkWrapper>
|
||||
<Link
|
||||
<LinkItem
|
||||
item={{
|
||||
path: basePath,
|
||||
title: basePath.replace(/\//, ""),
|
||||
@@ -55,18 +55,18 @@ export function Breadcrumb({ relativePath, basePath }: IBreadcrumbProps) {
|
||||
|
||||
{breadcrumbItems.map(item => {
|
||||
if (item.type === "folder") {
|
||||
foldersDepth++;
|
||||
foldersDepth++
|
||||
if (foldersDepth > 1) {
|
||||
return (
|
||||
<SC.LinkWrapper key={item.path}>
|
||||
{ item.title }
|
||||
<ChevronUp />
|
||||
</SC.LinkWrapper>
|
||||
<SC.LinkWrapper key={item.path}>
|
||||
{item.title}
|
||||
<ChevronUp />
|
||||
</SC.LinkWrapper>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<SC.LinkWrapper key={item.path}>
|
||||
<Link item={item} />
|
||||
<LinkItem item={item} />
|
||||
<ChevronUp />
|
||||
</SC.LinkWrapper>
|
||||
)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Link } from "gatsby"
|
||||
import { darken, lighten } from "polished"
|
||||
import styled from "styled-components"
|
||||
|
||||
export const BreadcrumbWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
@@ -16,6 +16,7 @@ export const LinkWrapper = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
white-space: nowrap;
|
||||
|
||||
svg {
|
||||
width: 12px;
|
||||
@@ -24,20 +25,21 @@ export const LinkWrapper = styled.div`
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: ${props => props.theme.main.link};
|
||||
fill: ${props => (props.theme.name === "dark" ? "#f9f9f9" : "#172129")};
|
||||
}
|
||||
`
|
||||
|
||||
export const StyledLink = styled(Link)`
|
||||
color: ${props => props.theme.main.link};
|
||||
color: ${props => (props.theme.name === "dark" ? "#f9f9f9" : "#172129")};
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
color: #045551;
|
||||
color: ${props =>
|
||||
props.theme.name === "dark"
|
||||
? lighten(0.15, props.theme.main.link)
|
||||
: darken(0.15, props.theme.main.link)};
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
`
|
||||
|
||||
@@ -45,4 +47,5 @@ export const CurrentPage = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
white-space: nowrap;
|
||||
`
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
import styled from "styled-components"
|
||||
|
||||
export const ContainerWrapper = styled.div``
|
||||
export const ContainerWrapper = styled.div`
|
||||
--padding: 64px;
|
||||
width: 650px;
|
||||
max-width: calc(100% - var(--padding) * 2);
|
||||
padding: 0px var(--padding);
|
||||
margin: 0 auto;
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
--padding: 32px;
|
||||
}
|
||||
`
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from "react"
|
||||
import * as SC from "./styles"
|
||||
|
||||
export const ContentPage: React.FC = ({ children, ...restProps }) => {
|
||||
return (
|
||||
<SC.ContentPageWrapper {...restProps}>{children}</SC.ContentPageWrapper>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import styled from "styled-components"
|
||||
|
||||
export const ContentPageWrapper = styled.div`
|
||||
width: calc(100% - 305px);
|
||||
margin-right: 305px;
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
`
|
||||
@@ -1,19 +1,17 @@
|
||||
import React, { FC } from "react"
|
||||
import packageJson from "../../../package.json"
|
||||
import { Container } from "../Container"
|
||||
import { Link } from "../Link"
|
||||
import * as SC from "./styles"
|
||||
|
||||
export const Footer: FC = () => {
|
||||
return (
|
||||
<SC.FooterWrapper>
|
||||
<Container>
|
||||
<p>
|
||||
© {new Date().getFullYear()}, Built with
|
||||
{` `}
|
||||
<a href="https://www.gatsbyjs.org">Gatsby</a> - Source on{" "}
|
||||
<a href={packageJson.repository.url}>GitHub</a>
|
||||
</p>
|
||||
</Container>
|
||||
<p>
|
||||
© {new Date().getFullYear()}, Built with
|
||||
{` `}
|
||||
<Link to="https://www.gatsbyjs.org">Gatsby</Link> - Source on{" "}
|
||||
<Link to={packageJson.repository.url}>GitHub</Link>
|
||||
</p>
|
||||
</SC.FooterWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,34 @@
|
||||
import styled from "styled-components"
|
||||
|
||||
export const FooterWrapper = styled.footer`
|
||||
margin-top: 128px;
|
||||
margin-top: 64px;
|
||||
|
||||
& a {
|
||||
display: inline;
|
||||
color: #0090d8;
|
||||
font-weight: 700;
|
||||
border-bottom: 2px solid;
|
||||
color: #fff;
|
||||
color: ${props => props.theme.main.foreground};
|
||||
font-weight: 700;
|
||||
text-decoration: none;
|
||||
transition: color 0.3s;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #5dbbea;
|
||||
transition: none;
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { FC, Fragment } from "react"
|
||||
import React from "react"
|
||||
import cx from "classnames"
|
||||
|
||||
import ChevronUp from "../../icons/chevron-up.svg"
|
||||
import { HeaderBarebone } from "../HeaderBarebone"
|
||||
import { Breadcrumb } from "../Breadcrumb"
|
||||
import { StackedAvatars } from "../StackedAvatars"
|
||||
import * as SC from "./styles"
|
||||
@@ -9,54 +10,24 @@ interface IHeaderProps {
|
||||
relativePath: string
|
||||
basePath: string
|
||||
title: string
|
||||
authors?: Array<{
|
||||
authors?: {
|
||||
avatar: string
|
||||
hash: string
|
||||
name: string
|
||||
}>
|
||||
}[]
|
||||
createdAt: string
|
||||
timeToRead: number
|
||||
recommendedReading?: string[]
|
||||
externalResources?: string[]
|
||||
shifted: boolean
|
||||
}
|
||||
|
||||
function ExtraLink({
|
||||
item,
|
||||
external = false,
|
||||
}: {
|
||||
item: string
|
||||
external?: boolean
|
||||
}) {
|
||||
const Inner = () => (
|
||||
<Fragment>
|
||||
<ChevronUp /> <SC.ExtraLinkText>{item}</SC.ExtraLinkText>
|
||||
</Fragment>
|
||||
)
|
||||
|
||||
if (external) {
|
||||
return (
|
||||
<SC.ExtraLinkExternal href={item} target="_blank">
|
||||
<Inner />
|
||||
</SC.ExtraLinkExternal>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<SC.ExtraLinkInternal to={`/resources/${item}.md`}>
|
||||
<Inner />
|
||||
</SC.ExtraLinkInternal>
|
||||
)
|
||||
}
|
||||
|
||||
export const Header: FC<IHeaderProps> = ({
|
||||
export const Header: React.FC<IHeaderProps> = ({
|
||||
basePath,
|
||||
relativePath,
|
||||
title,
|
||||
authors,
|
||||
createdAt,
|
||||
timeToRead,
|
||||
recommendedReading,
|
||||
externalResources,
|
||||
shifted,
|
||||
}) => {
|
||||
const date = new Date(createdAt)
|
||||
const month = date.toLocaleString("default", { month: "long" })
|
||||
@@ -65,48 +36,31 @@ export const Header: FC<IHeaderProps> = ({
|
||||
const dateToHuman = `${month} ${day}, ${year}`
|
||||
|
||||
return (
|
||||
<SC.HeaderWrapper>
|
||||
<Breadcrumb relativePath={relativePath} basePath={basePath} />
|
||||
|
||||
<SC.Title>{title}</SC.Title>
|
||||
|
||||
<SC.Top>
|
||||
{authors && (
|
||||
<HeaderBarebone
|
||||
above={<Breadcrumb relativePath={relativePath} basePath={basePath} />}
|
||||
title={title}
|
||||
className={cx({ shifted })}
|
||||
content={
|
||||
<SC.Top>
|
||||
{authors && (
|
||||
<SC.Meta>
|
||||
<StackedAvatars authors={authors} />
|
||||
<SC.PopoverToggler>
|
||||
{authors.length} contributor{authors.length > 1 && "s"}
|
||||
<SC.Popover>
|
||||
{authors
|
||||
.map(author => `${author.name}#${author.hash}`)
|
||||
.join(", ")}
|
||||
</SC.Popover>
|
||||
</SC.PopoverToggler>
|
||||
</SC.Meta>
|
||||
)}
|
||||
{dateToHuman && <SC.Meta>{dateToHuman}</SC.Meta>}
|
||||
<SC.Meta>
|
||||
<StackedAvatars authors={authors} />
|
||||
<SC.PopoverToggler>
|
||||
{authors.length} contributor{authors.length > 1 && "s"}
|
||||
<SC.Popover>
|
||||
{authors
|
||||
.map(author => `${author.name}#${author.hash}`)
|
||||
.join(", ")}
|
||||
</SC.Popover>
|
||||
</SC.PopoverToggler>
|
||||
{timeToRead} minute{timeToRead !== 1 && "s"} read time
|
||||
</SC.Meta>
|
||||
)}
|
||||
{dateToHuman && <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 <ExtraLink key={item} item={item} />
|
||||
})}
|
||||
</SC.RecommendedReading>
|
||||
)}
|
||||
|
||||
{externalResources && (
|
||||
<SC.ExternalResources>
|
||||
External Resources
|
||||
{externalResources.map(item => {
|
||||
return <ExtraLink key={item} item={item} external />
|
||||
})}
|
||||
</SC.ExternalResources>
|
||||
)}
|
||||
</SC.HeaderWrapper>
|
||||
</SC.Top>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,42 +1,31 @@
|
||||
import { Link } from "gatsby"
|
||||
import { darken, lighten } from "polished"
|
||||
import styled, { css } from "styled-components"
|
||||
import { fontFamily, modularScale } from "../../design/typography"
|
||||
|
||||
export const HeaderWrapper = styled.div`
|
||||
border-bottom: 1px solid #dbdbdb;
|
||||
padding-bottom: 32px;
|
||||
margin-bottom: 32px;
|
||||
`
|
||||
import { transparentize } from "polished"
|
||||
import styled from "styled-components"
|
||||
|
||||
export const Top = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
@media screen and (max-width: 1200px) {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
`
|
||||
|
||||
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;
|
||||
margin-top: 0;
|
||||
`
|
||||
|
||||
export const Meta = styled.div`
|
||||
display: flex;
|
||||
white-space: nowrap;
|
||||
align-items: center;
|
||||
color: ${props =>
|
||||
props.theme.name === "dark"
|
||||
? transparentize(0.1, props.theme.main.foreground)
|
||||
: transparentize(0.1, props.theme.main.foreground)};
|
||||
|
||||
& + &::before {
|
||||
content: "•";
|
||||
margin: 0 8px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
@media screen and (max-width: 1200px) {
|
||||
& + & {
|
||||
margin-top: 8px;
|
||||
}
|
||||
@@ -47,53 +36,6 @@ export const Meta = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const ExtraLinks = styled.div`
|
||||
margin-top: 16px;
|
||||
`
|
||||
|
||||
export const RecommendedReading = styled(ExtraLinks)``
|
||||
|
||||
export const ExternalResources = styled(ExtraLinks)``
|
||||
|
||||
const extraLink = css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: ${props => props.theme.main.link};
|
||||
margin-top: 4px;
|
||||
margin-left: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: ${props =>
|
||||
props.theme.name === "dark"
|
||||
? lighten(0.15, props.theme.main.link)
|
||||
: darken(0.15, props.theme.main.link)};
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 14px;
|
||||
flex: 0 0 14px;
|
||||
transform: rotate(90deg);
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: ${props => props.theme.main.link};
|
||||
}
|
||||
`
|
||||
|
||||
export const ExtraLinkInternal = styled(Link)`
|
||||
${extraLink};
|
||||
`
|
||||
|
||||
export const ExtraLinkExternal = styled.a`
|
||||
${extraLink};
|
||||
`
|
||||
|
||||
export const ExtraLinkText = styled.div`
|
||||
text-decoration: underline;
|
||||
`
|
||||
|
||||
export const Popover = styled.div`
|
||||
display: none;
|
||||
position: absolute;
|
||||
@@ -101,10 +43,11 @@ export const Popover = styled.div`
|
||||
margin-top: 8px;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
backdrop-filter: blur(14px);
|
||||
background: ${props =>
|
||||
props.theme.name === "dark"
|
||||
? lighten(0.1, props.theme.main.background)
|
||||
: darken(0.1, props.theme.main.background)};
|
||||
? transparentize(0.3, props.theme.main.background)
|
||||
: transparentize(0.3, props.theme.main.background)};
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
@@ -113,13 +56,14 @@ export const Popover = styled.div`
|
||||
content: "";
|
||||
width: 0;
|
||||
height: 0;
|
||||
backdrop-filter: blur(14px);
|
||||
border-style: solid;
|
||||
border-width: 0 3.5px 4px 3.5px;
|
||||
border-color: transparent transparent
|
||||
${props =>
|
||||
props.theme.name === "dark"
|
||||
? lighten(0.1, props.theme.main.background)
|
||||
: darken(0.1, props.theme.main.background)}
|
||||
? transparentize(0.3, props.theme.main.background)
|
||||
: transparentize(0.3, props.theme.main.background)}
|
||||
transparent;
|
||||
}
|
||||
`
|
||||
@@ -128,6 +72,11 @@ export const PopoverToggler = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
border-bottom: 1px dashed
|
||||
${props =>
|
||||
props.theme.name === "dark"
|
||||
? transparentize(0.1, props.theme.main.foreground)
|
||||
: transparentize(0.1, props.theme.main.foreground)};
|
||||
|
||||
&:hover ${Popover} {
|
||||
display: block;
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import React from "react"
|
||||
|
||||
import * as SC from "./styles"
|
||||
import { Container } from "../Container"
|
||||
|
||||
interface IHeaderBareboneProps {
|
||||
above?: React.ReactNode
|
||||
title: string
|
||||
content?: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const HeaderBarebone: React.FC<IHeaderBareboneProps> = props => {
|
||||
return (
|
||||
<SC.HeaderWrapper className={props.className}>
|
||||
<SC.BackgroundWrapper>
|
||||
<SC.StyledWavesBottom />
|
||||
<SC.StyledWavesTop />
|
||||
<SC.StyledCircles />
|
||||
</SC.BackgroundWrapper>
|
||||
|
||||
<Container>
|
||||
<SC.Box>
|
||||
{props.above}
|
||||
|
||||
<SC.Title>{props.title}</SC.Title>
|
||||
|
||||
{props.content}
|
||||
</SC.Box>
|
||||
</Container>
|
||||
</SC.HeaderWrapper>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { transparentize, darken } from "polished"
|
||||
import styled from "styled-components"
|
||||
import { fontFamily, modularScale } from "../../design/typography"
|
||||
import { WavesTop, WavesBottom } from "../Waves"
|
||||
import Circles from "../../images/circles.svg"
|
||||
|
||||
export const HeaderWrapper = styled.div`
|
||||
width: 100%;
|
||||
height: 391px;
|
||||
padding-top: 67px;
|
||||
position: relative;
|
||||
|
||||
&.shifted {
|
||||
width: calc(100% - 305px);
|
||||
padding-right: 305px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
width: 100% !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
height: auto;
|
||||
min-height: 391px;
|
||||
}
|
||||
`
|
||||
|
||||
export const BackgroundWrapper = styled.div`
|
||||
height: 391px;
|
||||
padding-top: 67px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
height: calc(100% - 67px);
|
||||
background: ${props => darken(0.2, props.theme.main.background)};
|
||||
}
|
||||
`
|
||||
|
||||
export const StyledCircles = styled(Circles)`
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -200px;
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
margin-top: -145px;
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
}
|
||||
`
|
||||
|
||||
export const StyledWavesTop = styled(WavesTop)`
|
||||
opacity: ${props => (props.theme.name === "dark" ? 0.8 : 0.2)};
|
||||
top: -10%;
|
||||
transform: scaleX(-1);
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
top: 0;
|
||||
}
|
||||
`
|
||||
|
||||
export const StyledWavesBottom = styled(WavesBottom)`
|
||||
opacity: ${props => (props.theme.name === "dark" ? 0.8 : 0.2)};
|
||||
bottom: -30%;
|
||||
transform: scaleX(-1);
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
bottom: 0;
|
||||
}
|
||||
`
|
||||
|
||||
export const Box = styled.div`
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
bottom: 40px;
|
||||
margin-left: -16px;
|
||||
background: ${props => transparentize(0.3, props.theme.main.background)};
|
||||
padding: 16px;
|
||||
backdrop-filter: blur(14px);
|
||||
max-width: 650px;
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
max-width: 100%;
|
||||
left: 32px;
|
||||
right: 32px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
position: static;
|
||||
bottom: auto;
|
||||
top: auto;
|
||||
margin: 32px 0;
|
||||
}
|
||||
`
|
||||
|
||||
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;
|
||||
margin-top: 0;
|
||||
margin: 0;
|
||||
|
||||
& + * {
|
||||
margin-top: 16px;
|
||||
}
|
||||
`
|
||||
@@ -10,7 +10,7 @@ export const HomeWrapper = styled.header`
|
||||
width: 100%;
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
background: #1f2a34;
|
||||
background: ${props => props.theme.main.background};
|
||||
overflow: hidden;
|
||||
`
|
||||
|
||||
|
||||
@@ -2,16 +2,31 @@ import { Link } from "gatsby"
|
||||
import styled, { css } from "styled-components"
|
||||
|
||||
const linkStyle = css`
|
||||
color: #0090d8;
|
||||
display: inline-block;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
color: ${props => props.theme.main.foreground};
|
||||
font-weight: 700;
|
||||
border-bottom: 2px solid;
|
||||
text-decoration: none;
|
||||
transition: color 0.3s;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: #5dbbea;
|
||||
transition: none;
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { darken, lighten } from "polished"
|
||||
import styled, { css } from "styled-components"
|
||||
import {
|
||||
BASE_FONT_SIZE,
|
||||
@@ -78,7 +77,7 @@ export const MarkdownWrapper = styled.div`
|
||||
}
|
||||
|
||||
code {
|
||||
background: #192129;
|
||||
background: ${props => props.theme.code.background};
|
||||
padding: 4px 8px;
|
||||
display: inline;
|
||||
border-radius: 3px;
|
||||
@@ -89,7 +88,7 @@ export const MarkdownWrapper = styled.div`
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
overflow-x: auto;
|
||||
background: #192129;
|
||||
background: ${props => props.theme.code.background};
|
||||
}
|
||||
|
||||
pre > code[class*="language-"] {
|
||||
@@ -122,16 +121,30 @@ export const MarkdownWrapper = styled.div`
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
a:not(.anchor) {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
font-weight: 700;
|
||||
color: ${props => (props.theme.name === "dark" ? "#f9f9f9" : "#172129")};
|
||||
text-decoration: none;
|
||||
word-break: break-word;
|
||||
color: ${props => props.theme.main.link};
|
||||
cursor: pointer;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: ${props =>
|
||||
props.theme.name === "dark"
|
||||
? lighten(0.15, props.theme.main.link)
|
||||
: darken(0.15, props.theme.main.link)};
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@@ -5,7 +5,8 @@ import Logo from "../../images/tph-logo.svg"
|
||||
|
||||
export const MobileHeaderWrapper = styled.div`
|
||||
z-index: 50;
|
||||
background: ${props => transparentize(0.2, props.theme.main.background)};
|
||||
background: ${props => transparentize(0.6, props.theme.main.background)};
|
||||
backdrop-filter: blur(14px);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import React, { FC, Fragment } from "react"
|
||||
|
||||
import { humanize } from "../../utils"
|
||||
import * as SC from "./styles"
|
||||
import { Container } from "../Container"
|
||||
|
||||
interface IPageContentProps {
|
||||
content: JSX.Element
|
||||
recommendedReading?: string[]
|
||||
externalResources?: string[]
|
||||
}
|
||||
|
||||
function ExtraLink({
|
||||
item,
|
||||
external = false,
|
||||
}: {
|
||||
item: string
|
||||
external?: boolean
|
||||
}) {
|
||||
const Inner = ({ text }: { text: string }) => (
|
||||
<Fragment>
|
||||
<SC.ExtraLinkText>{text}</SC.ExtraLinkText>
|
||||
</Fragment>
|
||||
)
|
||||
|
||||
if (external) {
|
||||
return (
|
||||
<SC.ExtraLinkExternal href={item} target="_blank">
|
||||
<Inner text={item} />
|
||||
</SC.ExtraLinkExternal>
|
||||
)
|
||||
}
|
||||
|
||||
const [internalText] = item.split("/").slice(-1)
|
||||
|
||||
return (
|
||||
<SC.ExtraLinkInternal to={`/resources/${item}.md`}>
|
||||
<Inner text={humanize(internalText)} />
|
||||
</SC.ExtraLinkInternal>
|
||||
)
|
||||
}
|
||||
|
||||
export const PageContent: FC<IPageContentProps> = ({
|
||||
content,
|
||||
recommendedReading,
|
||||
externalResources,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<SC.Content>
|
||||
<Container>{content}</Container>
|
||||
</SC.Content>
|
||||
|
||||
<SC.Sidebar>
|
||||
{recommendedReading && (
|
||||
<SC.RecommendedReading>
|
||||
<SC.SidebarHeader>Recommended reading</SC.SidebarHeader>
|
||||
{recommendedReading.map(item => {
|
||||
return <ExtraLink key={item} item={item} />
|
||||
})}
|
||||
</SC.RecommendedReading>
|
||||
)}
|
||||
|
||||
{externalResources && (
|
||||
<SC.ExternalResources>
|
||||
<SC.SidebarHeader>External Resources</SC.SidebarHeader>
|
||||
{externalResources.map(item => {
|
||||
return <ExtraLink key={item} item={item} external />
|
||||
})}
|
||||
</SC.ExternalResources>
|
||||
)}
|
||||
</SC.Sidebar>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import styled, { css } from "styled-components"
|
||||
import { Link } from "gatsby"
|
||||
import fontFamily from "../../design/typography"
|
||||
import { darken } from "polished"
|
||||
|
||||
export const Content = styled.div`
|
||||
flex: 1 1 calc(100% - 305px);
|
||||
width: calc(100% - 305px);
|
||||
padding: 64px 0;
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
width: 100%;
|
||||
flex-basis: auto;
|
||||
}
|
||||
`
|
||||
|
||||
export const Sidebar = styled.div`
|
||||
width: 240px;
|
||||
flex: 0 0 240px;
|
||||
border-left: 1px solid ${props => darken(0.1, props.theme.main.background)};
|
||||
color: ${props => (props.theme.name === "dark" ? "#f9f9f9" : "#172129")};
|
||||
margin: 64px 0;
|
||||
padding: 0 32px;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
width: auto;
|
||||
padding: 64px;
|
||||
flex-basis: auto;
|
||||
|
||||
& > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
`
|
||||
|
||||
export const SidebarHeader = styled.div`
|
||||
font-family: ${fontFamily.header};
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
margin-bottom: 8px;
|
||||
margin-top: 0;
|
||||
`
|
||||
|
||||
const ExtraLinks = styled.div`
|
||||
margin-top: 16px;
|
||||
`
|
||||
|
||||
export const RecommendedReading = styled(ExtraLinks)``
|
||||
|
||||
export const ExternalResources = styled(ExtraLinks)``
|
||||
|
||||
const extraLink = css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: ${props => (props.theme.name === "dark" ? "#f9f9f9" : "#172129")};
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
|
||||
& + & {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 14px;
|
||||
flex: 0 0 14px;
|
||||
transform: rotate(90deg);
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
svg path {
|
||||
fill: ${props => (props.theme.name === "dark" ? "#f9f9f9" : "#172129")};
|
||||
}
|
||||
`
|
||||
|
||||
export const ExtraLinkInternal = styled(Link)`
|
||||
${extraLink};
|
||||
`
|
||||
|
||||
export const ExtraLinkExternal = styled.a`
|
||||
${extraLink};
|
||||
`
|
||||
|
||||
export const ExtraLinkText = styled.div`
|
||||
word-break: break-word;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: linear-gradient(92.97deg, #feaf6d 0%, #ff70a5 100%);
|
||||
}
|
||||
`
|
||||
@@ -124,6 +124,10 @@ export const ExpandLanguagesHeader = styled.div`
|
||||
cursor: pointer;
|
||||
color: ${props => transparentize(0.5, props.theme.sidebar.foreground)};
|
||||
font-weight: 700;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
`
|
||||
|
||||
export const ExpandLanguagesList = styled.div`
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Link } from "gatsby"
|
||||
import React, { FC, HTMLAttributes, PropsWithChildren } from "react"
|
||||
import Scrollbar from "react-perfect-scrollbar"
|
||||
import "react-perfect-scrollbar/dist/css/styles.css"
|
||||
import Banner from "../../images/tph-banner.svg"
|
||||
import cx from "classnames"
|
||||
import { ThemeToggler } from "../ThemeToggler"
|
||||
import * as SC from "./styles"
|
||||
|
||||
@@ -22,18 +21,21 @@ export const Sidebar: FC<PropsWithChildren<
|
||||
HTMLAttributes<HTMLDivElement>
|
||||
>> = props => {
|
||||
const { children, ...restProps } = props
|
||||
const isBorderVisible = children === undefined ? false : true
|
||||
|
||||
return (
|
||||
<SC.SidebarWrapper {...restProps}>
|
||||
<Scrollbar>
|
||||
<Link to="/">
|
||||
<Banner />
|
||||
</Link>
|
||||
<SC.Title to="/">
|
||||
The
|
||||
<br />
|
||||
Programmer's
|
||||
<br />
|
||||
Hangout
|
||||
</SC.Title>
|
||||
<SC.Inner>
|
||||
{children}
|
||||
|
||||
<SC.Menu borderVisibility={isBorderVisible}>
|
||||
<SC.Menu className={cx({ "has-border": Boolean(children) })}>
|
||||
<MenuItem to="/about">about</MenuItem>
|
||||
<MenuItem to="/rules">rules</MenuItem>
|
||||
<MenuItem to="/resources">resources</MenuItem>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Link } from "gatsby"
|
||||
import styled, { css } from "styled-components"
|
||||
import { transparentize } from "polished"
|
||||
|
||||
export const SidebarWrapper = styled.div`
|
||||
box-sizing: border-box;
|
||||
@@ -27,17 +28,34 @@ export const SidebarWrapper = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
export const Title = styled(Link)`
|
||||
display: block;
|
||||
color: ${props => props.theme.sidebar.foreground};
|
||||
font-size: 30px;
|
||||
line-height: 34px;
|
||||
font-weight: 700;
|
||||
padding: 20px 0 0 20px;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
`
|
||||
|
||||
export const Inner = styled.div`
|
||||
padding: 30px 0 30px 20px;
|
||||
padding: 20px 0 30px 20px;
|
||||
`
|
||||
|
||||
export const Menu = styled.nav`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-top: ${props =>
|
||||
props.borderVisibility ? "1px dashed #a5a5a5" : "none"};
|
||||
margin: 20px 0 40px;
|
||||
padding-top: 20px;
|
||||
|
||||
&.has-border {
|
||||
border-top: ${props =>
|
||||
`1px dashed ${transparentize(0.8, props.theme.sidebar.foreground)}`};
|
||||
}
|
||||
`
|
||||
|
||||
export const menuItemStyles = css`
|
||||
|
||||
@@ -22,7 +22,7 @@ export const AuthorAvatar = styled.img<{ index: number }>`
|
||||
width: ${AVATAR_SIZE}px;
|
||||
height: ${AVATAR_SIZE}px;
|
||||
flex: 0 0 ${AVATAR_SIZE}px;
|
||||
border: 2px solid #fff;
|
||||
border: 2px solid #4c6780;
|
||||
border-radius: 50%;
|
||||
z-index: ${props => props.index};
|
||||
left: -${props => AVATAR_SIZE * OVERLAP_AMOUT * props.index}px;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import React, { FC } from "react"
|
||||
import * as SC from "./styles"
|
||||
|
||||
export const WavesTop: FC = () => {
|
||||
return <SC.StyledWavesTop />
|
||||
export const WavesTop: FC = props => {
|
||||
return <SC.StyledWavesTop {...props} />
|
||||
}
|
||||
|
||||
export const WavesBottom: FC = () => {
|
||||
return <SC.StyledWavesBottom />
|
||||
export const WavesTopTwo: FC = props => {
|
||||
return <SC.StyledWavesTopTwo {...props} />
|
||||
}
|
||||
|
||||
export const WavesBottom: FC = props => {
|
||||
return <SC.StyledWavesBottom {...props} />
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import styled, { css } from "styled-components"
|
||||
import WavesBottom from "../../images/waves-bot.svg"
|
||||
import WavesTop from "../../images/waves-top.svg"
|
||||
import WavesTopTwo from "../../images/waves-top2.svg"
|
||||
|
||||
const waves = css`
|
||||
display: block;
|
||||
@@ -17,6 +18,12 @@ export const StyledWavesTop = styled(WavesTop)`
|
||||
height: 87vh;
|
||||
`
|
||||
|
||||
export const StyledWavesTopTwo = styled(WavesTopTwo)`
|
||||
${waves};
|
||||
top: 0;
|
||||
height: 87vh;
|
||||
`
|
||||
|
||||
export const StyledWavesBottom = styled(WavesBottom)`
|
||||
${waves};
|
||||
bottom: 0;
|
||||
|
||||
Reference in New Issue
Block a user