Skip to content
This repository has been archived by the owner on Dec 3, 2024. It is now read-only.

CAR-4260 extract header #187

Merged
merged 44 commits into from
May 27, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
d36f5ee
WIP: first draft desktop header
lkappeler May 18, 2020
62f0d93
feat: desktop layouts for header variations
lkappeler May 18, 2020
19dcc6d
feat: mobile navigations
lkappeler May 19, 2020
7338ef9
chore: cleanup and update code examples
lkappeler May 19, 2020
457aba1
chore remove .DS_Store
lkappeler May 19, 2020
f97e2c4
chore: fix format
lkappeler May 19, 2020
4be4fd6
chore: update snapshots
lkappeler May 19, 2020
358da1b
unify classNames to use one condition per theme
lkappeler May 19, 2020
53bc1c6
chore: use ternary operation to determine fill color
lkappeler May 19, 2020
07a67b7
chore: move theme conditions to context
lkappeler May 19, 2020
14164a2
feat: use tailwind propertiers for svg icon components
lkappeler May 19, 2020
9db36a1
chore: use tailwind colors everywhere
lkappeler May 19, 2020
089904e
fix: propper BEM name for custom class
lkappeler May 19, 2020
072e5f9
chore: update snapshots
lkappeler May 19, 2020
0d3b9f0
chore: cleanup remove unused classes
lkappeler May 19, 2020
6707772
fix: make demo with carforyou content responsive
lkappeler May 19, 2020
de426bd
chore: update snapshot
lkappeler May 19, 2020
fb9468d
chore: minor optimizations
lkappeler May 20, 2020
2ca9426
fix: export all header types and components
lkappeler May 20, 2020
c38ce92
fix: export all the icons
lkappeler May 20, 2020
d064016
chore: white text by default for transparent theme
lkappeler May 25, 2020
5649f2b
chore: add transparent example and tweak some missed theme specific c…
lkappeler May 26, 2020
9dd2748
fix: add grey border to light theme
lkappeler May 26, 2020
4ccff85
chore: optimize dropdowns
lkappeler May 26, 2020
22b39ef
BREAKING CHANGE: refactor button size interface
lkappeler May 26, 2020
fe37d3f
chore: update snapshots
lkappeler May 26, 2020
36a9b07
Merge branch 'master' into CAR-4260-extract-header
lkappeler May 26, 2020
2ce8e58
chore: format to the new rules
lkappeler May 26, 2020
a1fe15d
fix: mixed up button sizes
lkappeler May 26, 2020
0bbee04
chore: use bigger logo for ld breakpoint
lkappeler May 26, 2020
22d9edd
fix: z-index for menues
lkappeler May 26, 2020
123694e
fix: update snapshots
lkappeler May 26, 2020
3b83f12
chore: make navigation fit width and create a separate z-index for th…
lkappeler May 26, 2020
fd2920d
chore: update snapshots
lkappeler May 26, 2020
dab800f
fix: trigger pre release
lkappeler May 26, 2020
b64fe2d
chore: clean up logo
lkappeler May 27, 2020
1437f73
chore: clean up icons and move examples to storybook folder
lkappeler May 27, 2020
e1542ed
fix: only export required icons
lkappeler May 27, 2020
d759a80
fix: remove render props where not needed
lkappeler May 27, 2020
29f9436
fix: clean up themeing colors
lkappeler May 27, 2020
adc305f
chore: change interface for language navigation
lkappeler May 27, 2020
775dbe3
fix: update snapshots
lkappeler May 27, 2020
e145621
fix: remove unused variable
lkappeler May 27, 2020
bc3dbb0
fix: move sections to named functions
lkappeler May 27, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions assets/header.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.bg-header--transparent {
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
background: linear-gradient(
-180deg,
rgba(0, 0, 0, 0.5) 0%,
rgba(0, 0, 0, 0.5) 22%,
rgba(0, 0, 0, 0.3) 38%,
rgba(0, 0, 0, 0.2) 53%,
rgba(0, 0, 0, 0.1) 79%,
rgba(0, 0, 0, 0) 100%
);
}
1 change: 1 addition & 0 deletions assets/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
@import "./input/index.css";
@import "./spinner.css";
@import "./intercom.css";
@import "./header.css";
10 changes: 10 additions & 0 deletions src/__tests__/__snapshots__/node.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ Object {
"checkbox": "24px",
"clearButton": "32px",
"full": "100%",
"header": "85px",
"headerSmall": "60px",
"headerTransparent": "166px",
"input": "52px",
"radioIndicator": "12px",
"screen": "100vh",
Expand Down Expand Up @@ -231,17 +234,20 @@ Object {
},
},
"margin": Object {
"-headerMenu": "-15px",
"-selectMenu": "-21px",
"-selectWithHintMenu": "-43px",
"0": "0",
"10": "10px",
"15": "15px",
"20": "20px",
"22": "22px",
"25": "25px",
"30": "30px",
"40": "40px",
"5": "5px",
"auto": "auto",
"headerMenu": "15px",
"labelPopupIcon": "3px",
"px": "1px",
},
Expand Down Expand Up @@ -353,9 +359,13 @@ Object {
"auto": "auto",
"checkbox": "24px",
"clearButton": "32px",
"logoDefault": "170px",
"logoSmall": "140px",
"menuDropdown": "220px",
"modal": "570px",
"modalLarge": "770px",
"modalSmall": "370px",
"profileDropdown": "320px",
"radioIndicator": "12px",
"screen": "100vw",
"scrollbar": "14px",
Expand Down
103 changes: 103 additions & 0 deletions src/components/header/dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, { FC, useState, useEffect, useContext } from "react"
import classNames from "classnames"

import ArrowDownM from "../icons/arrowDownMCrop"
import HeaderThemeContext, { HeaderTheme } from "./themeContext"
masone marked this conversation as resolved.
Show resolved Hide resolved

interface Props {
renderParent: () => JSX.Element
children: JSX.Element
theme?: HeaderTheme
stickOut?: "left" | "right"
}

const HeaderDropdown: FC<Props> = ({
renderParent,
stickOut = "right",
children,
}) => {
const [isOpen, setIsOpen] = useState(false)
const theme = useContext(HeaderThemeContext)

useEffect(() => {
if (isOpen) {
document.addEventListener("click", toggle)
document.addEventListener("keydown", toggle)
}

return () => {
document.removeEventListener("click", toggle)
document.removeEventListener("keydown", toggle)
}
}, [isOpen])

const toggle = () => setIsOpen(!isOpen)

const renderClosedState = () => {
return (
<div
className={classNames(
"flex items-center cursor-pointer text-black py-10 lg:py-0",
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
{
"lg:text-black": theme === HeaderTheme.LIGHT,
"lg:text-white":
theme === HeaderTheme.DARK || theme === HeaderTheme.TRANSPARENT,
}
)}
onClick={toggle}
>
{renderParent()}
<ArrowDownM
height="28"
width="28"
color="#000"
className={classNames("inline-block", {
"lg:text-white":
theme === HeaderTheme.DARK || theme === HeaderTheme.TRANSPARENT,
})}
/>
</div>
)
}

const renderOpenState = () => {
return (
<div className="text-black bg-grey-1 lg:bg-transparent relative z-dropdownMenu cursor-pointer -mx-headerMenu lg:mx-0 px-15 lg:px-0 py-10 lg:py-0">
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
<div
className={classNames("flex items-center font-bold", {
"lg:text-white":
theme === HeaderTheme.DARK || theme === HeaderTheme.TRANSPARENT,
})}
onClick={toggle}
>
{renderParent()}
<ArrowDownM
height="28"
width="28"
className={classNames("inline-block, customRotate-180", {
"lg:text-white":
theme === HeaderTheme.DARK || theme === HeaderTheme.TRANSPARENT,
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
})}
/>
</div>
<div
className={classNames(
"bg-grey-1 lg:bg-white relative lg:absolute lg:border lg:border-grey-2 lg:rounded-4",
{
"right-0": stickOut === "left",
"bg-white":
theme === HeaderTheme.LIGHT || theme === HeaderTheme.DARK,
"text-black": theme === HeaderTheme.DARK,
}
)}
>
{children}
</div>
</div>
)
}

return <>{isOpen ? renderOpenState() : renderClosedState()}</>
Copy link
Contributor

Choose a reason for hiding this comment

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

the fragments should not be required here

Suggested change
return <>{isOpen ? renderOpenState() : renderClosedState()}</>
return isOpen ? renderOpenState() : renderClosedState()

}

export default HeaderDropdown
170 changes: 170 additions & 0 deletions src/components/header/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import React, { FC } from "react"
import classNames from "classnames"

import Logo from "../icons/logo"
import Profile from "../icons/profile"

import HeaderDropdown from "./dropdown"
import { HeaderTheme, HeaderThemeProvider } from "./themeContext"
import useModal from "../../hooks/useModal"

interface Props {
renderLogo?: () => JSX.Element
links?: Array<() => JSX.Element>
renderCTAButton?: () => JSX.Element
iconButtons?: Array<() => JSX.Element>
profile?: {
renderWelcomeMessage: () => JSX.Element
renderContent: () => JSX.Element
}
renderLanguageNavigation?: () => JSX.Element
theme?: HeaderTheme
mobileMenuText?: string
}

const Header: FC<Props> = ({
theme = HeaderTheme.LIGHT,
renderLogo = () => <Logo />,
links = [],
renderCTAButton = () => null,
iconButtons = [],
profile = {
renderWelcomeMessage: () => null,
renderContent: () => null,
},
renderLanguageNavigation = () => null,
mobileMenuText = "MENU",
}) => {
let iconColor = "#A0A7AB"
if (theme === HeaderTheme.DARK || theme === HeaderTheme.TRANSPARENT) {
iconColor = "#FFF"
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
}

const languageNavigation = renderLanguageNavigation()

const renderMobileNavigation = () => {
return (
<div className="min-w-screen text-black">
<div className="min-w-100 w-logoDefault mx-headerMenu my-22">
<Logo />
</div>
<div className="px-15">
{profile.renderWelcomeMessage()}
<hr className="-mx-headerMenu text-grey-1" />
{links.map((renderLink, index) => {
return <div key={`navigationLink-${index}`}>{renderLink()}</div>
})}
<hr className="-mx-headerMenu text-grey-1" />
{profile.renderContent()}
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
<hr className="-mx-headerMenu text-grey-1" />
{languageNavigation}
</div>
</div>
)
}

const { openModal, renderModal } = useModal(renderMobileNavigation, {
size: "fullscreen",
style: "white",
})

return (
<HeaderThemeProvider value={theme}>
<div
className={classNames({
"h-headerTransparent": theme === HeaderTheme.TRANSPARENT,
"bg-header--transparent": theme === HeaderTheme.TRANSPARENT,
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
})}
>
<header
className={classNames(
"h-headerSmall lg:h-header px-15 md:px-20 py-15 flex items-center",
{
"bg-white": theme === HeaderTheme.LIGHT,
"bg-grey-dark": theme === HeaderTheme.DARK,
"text-white": theme === HeaderTheme.DARK,
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
}
)}
>
<nav className="w-12/12 flex items-center">
{/* Logo Section */}
<div className="min-w-100 w-logoSmall lg:w-logoDefault mr-20 lg:mr-40">
{renderLogo()}
</div>
{/* Links - LG / Desktop */}
Copy link
Contributor

Choose a reason for hiding this comment

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

comments like these are a great pointer to extracting the code into functions where you can slap a name on it renderDesktopLinks()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice input, makes it a look easier to read with the named functions :)

<div className="flex flex-grow">
<div className="hidden lg:flex items-center">
{links.map((renderLink, index) => {
return (
<div
className="mr-headerMenu"
key={`navigationLink-${index}`}
>
{renderLink()}
</div>
)
})}
</div>
</div>
{/* Right Section */}
<div className="flex items-center">
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
{/* CTA Button */}
<div className="mr-headerMenu cursor-pointer">
{renderCTAButton()}
</div>
{/* Icons Button */}
<div className="cursor-pointer">
{iconButtons.map((renderIconButton, index) => {
return (
<div
className="mr-headerMenu"
key={`navigationLink-${index}`}
>
{renderIconButton()}
</div>
)
})}
</div>
{/* Profile - LG / Desktop */}
<div
className={classNames("hidden lg:block cursor-pointer", {
"mr-headerMenu": languageNavigation,
})}
>
<HeaderDropdown
renderParent={() => <Profile color={iconColor} />}
theme={theme}
stickOut="left"
>
<div className="m-headerMenu w-profileDropdown">
{profile.renderWelcomeMessage()}
<hr className="-mx-headerMenu text-grey-1 mb-20" />
{profile.renderContent()}
</div>
</HeaderDropdown>
</div>
{/* Language Navigation - LG / Desktop */}
<div className="hidden lg:block">{languageNavigation}</div>
{/* Menu Block Groups for mobile */}
<div className="block lg:hidden">
<a
onClick={openModal}
className={classNames("cursor-pointer", {
"text-grey-3": theme === HeaderTheme.LIGHT,
"text-white":
theme === HeaderTheme.DARK || HeaderTheme.TRANSPARENT,
})}
>
{mobileMenuText}
</a>
{renderModal()}
</div>
</div>
</nav>
</header>
</div>
</HeaderThemeProvider>
)
}

export default Header
12 changes: 12 additions & 0 deletions src/components/header/themeContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createContext } from "react"

export enum HeaderTheme {
LIGHT = "light",
DARK = "dark",
TRANSPARENT = "transparent",
}

const HeaderThemeContext = createContext(HeaderTheme.LIGHT)

export const HeaderThemeProvider = HeaderThemeContext.Provider
export default HeaderThemeContext
19 changes: 19 additions & 0 deletions src/components/icons/heart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { FC } from "react"

interface Props {
color?: string
width?: number
height?: number
}

const Heart: FC<Props> = ({ color = "#A0A7AB", width = 32, height = 32 }) => (
lkappeler marked this conversation as resolved.
Show resolved Hide resolved
<svg width={width} height={height} xmlns="http://www.w3.org/2000/svg">
<path
d="M20.417 7C23.495 7 26 9.513 26 12.603c0 1.45-.544 2.806-1.52 3.841L16 25l-8.443-8.516A5.59 5.59 0 016 12.603C6 9.513 8.505 7 11.583 7c1.76 0 3.375.822 4.417 2.175A5.564 5.564 0 0120.417 7zm0 1.6a3.962 3.962 0 00-3.004 1.372l-.145.179L16 11.797l-1.268-1.646A3.963 3.963 0 0011.583 8.6C9.39 8.6 7.6 10.396 7.6 12.603c0 .96.336 1.871.938 2.581l.156.173L16 22.727l7.18-7.243a3.963 3.963 0 001.213-2.647l.007-.234c0-2.207-1.79-4.003-3.983-4.003z"
fill={color}
fill-rule="evenodd"
/>
</svg>
)

export default Heart
Loading