From 809678383ad437a3eecd93f3101a067da146d2b5 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Sirois Date: Mon, 12 Aug 2019 20:07:46 -0400 Subject: [PATCH] feat(resources): implement breadcrumbs --- src/components/ResourceBreadcrumb/index.tsx | 47 +++++++++++++++++++ src/components/ResourceBreadcrumb/styles.tsx | 38 +++++++++++++++ src/components/ResourceHeader/index.tsx | 5 ++ src/components/ResourceHeader/styles.tsx | 1 + .../ResourcesSidebar/useBuildTree.tsx | 26 +--------- src/templates/languagePost.tsx | 3 ++ src/utils/index.ts | 24 ++++++++++ 7 files changed, 120 insertions(+), 24 deletions(-) create mode 100644 src/components/ResourceBreadcrumb/index.tsx create mode 100644 src/components/ResourceBreadcrumb/styles.tsx create mode 100644 src/utils/index.ts diff --git a/src/components/ResourceBreadcrumb/index.tsx b/src/components/ResourceBreadcrumb/index.tsx new file mode 100644 index 0000000..fa8749a --- /dev/null +++ b/src/components/ResourceBreadcrumb/index.tsx @@ -0,0 +1,47 @@ +import React from "react" + +import { IFileOrFolder } from "../ResourcesSidebar/index" +import ChevronUp from "../../icons/chevron-up.svg" +import { traversePaths } from "../../utils" +import * as SC from "./styles" + +interface ResourceBreadcrumbProps { + relativePath: any +} + +function Link({ item }: { item: IFileOrFolder }) { + return {item.title} +} + +function flatten([ + currNode, + ...previousNodes +]: IFileOrFolder[]): IFileOrFolder[] { + if (currNode.type === "file") { + return [...previousNodes, currNode] + } + + return flatten([...currNode.children, ...previousNodes, currNode]) +} + +export function ResourceBreadcrumb({ relativePath }: ResourceBreadcrumbProps) { + const paths = relativePath.split("/") + const breadcrumbItems = flatten([traversePaths(paths)]) + + return ( + + {breadcrumbItems.map(item => { + if (item.type === "folder") { + return ( + + + + + ) + } + + return {item.title} + })} + + ) +} diff --git a/src/components/ResourceBreadcrumb/styles.tsx b/src/components/ResourceBreadcrumb/styles.tsx new file mode 100644 index 0000000..3c7f8e5 --- /dev/null +++ b/src/components/ResourceBreadcrumb/styles.tsx @@ -0,0 +1,38 @@ +import styled from "styled-components" +import { Link } from "gatsby" + +export const ResourceBreadcrumbWrapper = styled.div` + display: flex; + align-items: flex-start; +` + +export const LinkWrapper = styled.div` + display: flex; + align-items: center; + height: 30px; + + svg { + width: 12px; + transform: rotate(90deg); + margin: 6px; + } + + svg path { + fill: #04b0a6; + } +` + +export const StyledLink = styled(Link)` + color: #04b0a6; + cursor: pointer; + + &:hover { + color: #045551; + } +` + +export const CurrentPage = styled.div` + display: flex; + align-items: center; + height: 30px; +` diff --git a/src/components/ResourceHeader/index.tsx b/src/components/ResourceHeader/index.tsx index 4a6eecf..8faf276 100644 --- a/src/components/ResourceHeader/index.tsx +++ b/src/components/ResourceHeader/index.tsx @@ -2,9 +2,11 @@ import React, { Fragment } from "react" import { StackedAvatars } from "../StackedAvatars" import ChevronUp from "../../icons/chevron-up.svg" +import { ResourceBreadcrumb } from "../ResourceBreadcrumb" import * as SC from "./styles" interface ResourceHeaderProps { + relativePath: any title: any authors: any createdAt: any @@ -42,6 +44,7 @@ function ExtraLink({ } export function ResourceHeader({ + relativePath, title, authors, createdAt, @@ -57,6 +60,8 @@ export function ResourceHeader({ return ( + + {title} diff --git a/src/components/ResourceHeader/styles.tsx b/src/components/ResourceHeader/styles.tsx index a73fbe1..30293b8 100644 --- a/src/components/ResourceHeader/styles.tsx +++ b/src/components/ResourceHeader/styles.tsx @@ -18,6 +18,7 @@ export const Title = styled.h1` font-size: ${modularScale(6).fontSize}px; line-height: ${modularScale(6).lineHeight}px; letter-spacing: -1.75px; + margin-top: 0; ` export const Meta = styled.div` diff --git a/src/components/ResourcesSidebar/useBuildTree.tsx b/src/components/ResourcesSidebar/useBuildTree.tsx index 7108fe8..201ff4f 100644 --- a/src/components/ResourcesSidebar/useBuildTree.tsx +++ b/src/components/ResourcesSidebar/useBuildTree.tsx @@ -1,6 +1,7 @@ import partition from "ramda/es/partition" import chain from "ramda/es/chain" +import { traversePaths } from "../../utils" import { IFileOrFolder, IFile, @@ -9,29 +10,6 @@ import { IFileQuery, } from "./index" -function traverse( - [head, ...tail]: string[], - basePath = "/resources" -): IFileOrFolder { - const path = basePath + "/" + head - const isFile = !tail.length - if (isFile) { - // probably not more than one dot - const [name] = head.split(".") - return { - title: name, - type: "file", - path, - } - } - return { - title: head, - type: "folder", - path, - children: [traverse(tail, path)], - } -} - function generateFolder({ title, path, @@ -85,7 +63,7 @@ function join([head, ...tail]: IFileOrFolder[]): IFileOrFolder[] { export default function useBuildTree(resources: IAllResourcesQuery) { const objects = resources.allFile.edges.map(({ node: file }: IFileQuery) => - traverse(file.relativePath.split("/")) + traversePaths(file.relativePath.split("/")) ) return join(objects) diff --git a/src/templates/languagePost.tsx b/src/templates/languagePost.tsx index c5f1f5d..ca907b2 100644 --- a/src/templates/languagePost.tsx +++ b/src/templates/languagePost.tsx @@ -6,12 +6,14 @@ import { ResourceHeader } from "../components/ResourceHeader" // @todo maybe find alternative type for data function LanguagePost({ data }: any) { + const { relativePath } = data.file const { html, fields, frontmatter, timeToRead } = data.file.post console.log(data) return (