Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add compound layout component #1363

Merged
merged 12 commits into from
Jul 11, 2024
24 changes: 24 additions & 0 deletions src/v2/components/Layout/Layout.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Meta, StoryFn } from "@storybook/react"
import { Layout } from "."

const meta: Meta = {
title: 'Design system/Layout',
parameters: {
layout: 'fullscreen'
}
}

export default meta

export const Static: StoryFn = () => (
<Layout.Root>
<Layout.Header>
<Layout.Banner />
<Layout.Headline title='Layout title' />
</Layout.Header>
<Layout.Main>
Page contents
</Layout.Main>
<Layout.Footer />
</Layout.Root>
)
76 changes: 76 additions & 0 deletions src/v2/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ReactNode } from "react"
import { PropsWithChildren } from "react"
import { PageBoundary } from "@/components/PageBoundary"
// import { Header as NavHeader } from "@/components/Header"
const NavHeader = () => <div className="h-16 border-border border-b">mocked header</div>

/* -------------------------------------------------------------------------------------------------
* Root
* -----------------------------------------------------------------------------------------------*/

const Root = ({ children }: PropsWithChildren) => (
<div className="flex min-h-screen flex-col">{children}</div>
)

/* -------------------------------------------------------------------------------------------------
* Header
* -----------------------------------------------------------------------------------------------*/

const Header = ({ children }: PropsWithChildren) => (
<header className="relative">
<NavHeader />
{children}
</header>
)

/* -------------------------------------------------------------------------------------------------
* Headline
* -----------------------------------------------------------------------------------------------*/

interface HeadlineProps {
title: ReactNode
}

const Headline = ({ title }: HeadlineProps) => (
<PageBoundary>
<h1 className="pb-14 pt-9 font-display text-4xl font-bold tracking-tight text-white sm:text-5xl">
{title}
</h1>
</PageBoundary>
)

/* -------------------------------------------------------------------------------------------------
* Banner
* -----------------------------------------------------------------------------------------------*/

const Banner = () => (
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component should only handle the size & position (and it could have a default background color) & we should pass the customization related stuff to it where we actually use it ;)

<div className="absolute inset-0 -bottom-28 -z-10 overflow-hidden">
<div className="absolute inset-0 bg-[hsl(240deg_4%_16%)]" />
<div className="absolute inset-0 bg-[url('/banner.png')] bg-[auto_115%] bg-[right_top_10px] bg-no-repeat opacity-10" />
<div className="absolute inset-0 bg-gradient-to-tr from-[hsl(240deg_2.65%_22.16%)] from-50% to-transparent" />
</div>
)

/* -------------------------------------------------------------------------------------------------
* Main
* -----------------------------------------------------------------------------------------------*/

const Main = ({ children }: PropsWithChildren) => (
<main>
<PageBoundary>{children}</PageBoundary>
</main>
)

/* -------------------------------------------------------------------------------------------------
* Footer
* -----------------------------------------------------------------------------------------------*/

const Footer = ({ children }: PropsWithChildren) => (
<footer className="mt-auto">
<PageBoundary>{children}</PageBoundary>
</footer>
)

/* -----------------------------------------------------------------------------------------------*/

export { Root, Header, Headline, Banner, Main, Footer }
3 changes: 3 additions & 0 deletions src/v2/components/Layout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Root, Headline, Banner, Header, Footer, Main } from "./Layout"

export const Layout = { Root, Headline, Banner, Header, Footer, Main }
12 changes: 12 additions & 0 deletions src/v2/components/PageBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import clsx from "clsx"
import { forwardRef } from "react"

export type PageBoundaryProps = React.HTMLAttributes<HTMLDivElement>
export const PageBoundary = forwardRef<HTMLDivElement, PageBoundaryProps>(({ children, className }, ref) => (
<div
className={clsx("mx-auto max-w-screen-lg px-4 sm:px-8 md:px-10", className)}
ref={ref}
>
{children}
</div>
))