Skip to content

Commit

Permalink
feat: Add Banner component and export hooks (#221)
Browse files Browse the repository at this point in the history
* feat: Add Banner component and export hooks

* fix: Styling

* fix: Use color from theme
  • Loading branch information
LautaroPetaccio authored Jan 15, 2025
1 parent 9fa513f commit 6dd88ba
Show file tree
Hide file tree
Showing 13 changed files with 295 additions and 310 deletions.
121 changes: 121 additions & 0 deletions src/components/Banner/Banner.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import styled from "@emotion/styled"
import { Box, Button as MuiButton, Typography } from "@mui/material"
import { neutral } from "../../theme/colors"

const LoadingContainer = styled(Box)({
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "100%",
})

const BannerContainer = styled(Box, {
shouldForwardProp: (prop) => prop !== "background",
})<{
background: string
}>((props) => {
const { theme, background } = props

return {
width: "100%",
overflow: "hidden",
display: "flex",
padding: "2rem",
justifyContent: "space-between",
flexDirection: "row",
backgroundImage: `url(${background})`,
backgroundSize: "cover",
backgroundPosition: "center",
alignItems: "center",
[theme.breakpoints.down("sm")]: {
flexDirection: "column-reverse",
},
}
})

const ContentWrapper = styled(Box)({
display: "flex",
flexDirection: "row",
flexGrow: 1,
marginRight: "20px",
})

const Content = styled(Box)((props) => {
const { theme } = props

return {
display: "flex",
flexDirection: "column",
gap: "0.1rem",
[theme.breakpoints.down("sm")]: {
padding: "1rem",
},
}
})

const Logo = styled("img")((props) => {
const { theme } = props

return {
flexShrink: 0,
maxWidth: "400px",
[theme.breakpoints.down("sm")]: {
maxWidth: "300px",
marginBottom: "1rem",
},
}
})

const Title = styled(Typography)((props) => {
const { theme } = props

return {
margin: 0,
color: "#fff",
fontSize: "28px",
textTransform: "uppercase",
fontWeight: 800,

[theme.breakpoints.down("sm")]: {
fontSize: "24px",
},
}
})

const Text = styled(Box)((props) => {
const { theme } = props

return {
color: neutral.white,
fontSize: "19px",
"& p": {
margin: 0,
padding: 0,
},
[theme.breakpoints.down("sm")]: {
fontSize: "16px",
},
}
})

const ButtonContainer = styled(Box)({
display: "flex",
marginTop: "1rem",
})

const Button = styled(MuiButton)({
textTransform: "uppercase",
minWidth: "300px",
})

export {
LoadingContainer,
BannerContainer,
Content,
ContentWrapper,
Logo,
Title,
Text,
ButtonContainer,
Button,
}
112 changes: 112 additions & 0 deletions src/components/Banner/Banner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { documentToReactComponents } from "@contentful/rich-text-react-renderer"
import CircularProgress from "@mui/material/CircularProgress"
import { Locales, getAssetUrl } from "../../hooks/contentful"
import { useTabletAndBelowMediaQuery } from "../Media"
import { BannerProps, LowercasedAlignment } from "./Banner.types"
import {
BannerContainer,
Button,
ButtonContainer,
Content,
LoadingContainer,
Logo,
Text,
Title,
} from "./Banner.styled"
import type { Property } from "csstype"

const convertAlignmentToFlex = (alignment: Property.TextAlign) => {
switch (alignment) {
case "left":
return "flex-start"
case "center":
return "center"
case "right":
return "flex-end"
default:
return "flex-start"
}
}

export const Banner: React.FC<BannerProps> = (props: BannerProps) => {
const { isLoading, fields, assets, locale = Locales.enUS, error } = props
const isMobileOrTablet = useTabletAndBelowMediaQuery()

if (isLoading) {
return (
<LoadingContainer>
<CircularProgress />
</LoadingContainer>
)
}

// If there is no banner fields or the banner is not supposed to be shown, return null
if (!fields || !fields.showBanner[Locales.enUS] || error) {
return null
}

// Build the parameteres based on the size of the screen
const bannerBackgroundImage = getAssetUrl(
assets,
Locales.enUS,
isMobileOrTablet
? fields.mobileBackground[Locales.enUS]
: fields.fullSizeBackground[Locales.enUS]
)
const title = isMobileOrTablet
? fields.mobileTitle[locale]
: fields.desktopTitle[locale]
const titleAlignment = (
isMobileOrTablet
? fields.mobileTitleAlignment[Locales.enUS]
: fields.desktopTitleAlignment[Locales.enUS]
)?.toLowerCase() as LowercasedAlignment
const text = isMobileOrTablet
? fields.mobileText[locale]
: fields.desktopText[locale]
const textAlignment = (
isMobileOrTablet
? fields.mobileTextAlignment[Locales.enUS]
: fields.desktopTextAlignment[Locales.enUS]
)?.toLowerCase() as LowercasedAlignment
const buttonAlignment = convertAlignmentToFlex(
(isMobileOrTablet
? fields.mobileButtonAlignment[Locales.enUS]
: fields.desktopButtonAlignment[Locales.enUS]
)?.toLowerCase() as LowercasedAlignment
)

return (
<BannerContainer background={bannerBackgroundImage}>
<Content>
<Title variant="h1" textAlign={titleAlignment}>
{title}
</Title>

<Text textAlign={textAlignment}>
{text ? documentToReactComponents(text) : null}
</Text>

{fields.showButton[Locales.enUS] &&
fields.buttonLink?.[Locales.enUS] &&
fields.buttonsText?.[locale] ? (
<ButtonContainer justifyContent={buttonAlignment}>
<Button
href={fields.buttonLink[Locales.enUS]}
variant="contained"
disableElevation
>
{fields.buttonsText[locale]}
</Button>
</ButtonContainer>
) : null}
</Content>
{fields.logo && fields.logo[Locales.enUS] && (
<Logo
src={getAssetUrl(assets, Locales.enUS, fields.logo[Locales.enUS])}
alt="Banner logo"
/>
)}
</BannerContainer>
)
}
41 changes: 41 additions & 0 deletions src/components/Banner/Banner.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
AlignmentFieldType,
ContentfulAsset,
Locales,
LocalizedField,
SysAssetLink,
} from "hooks/contentful"
import type { Document } from "@contentful/rich-text-types"

type IBannerFields = {
id: LocalizedField<string>
showBanner: LocalizedField<boolean>
desktopTitle: LocalizedField<string>
mobileTitle: LocalizedField<string>
mobileTitleAlignment: LocalizedField<AlignmentFieldType>
desktopTitleAlignment: LocalizedField<AlignmentFieldType>
desktopText: LocalizedField<Document>
mobileText: LocalizedField<Document>
desktopTextAlignment: LocalizedField<AlignmentFieldType>
mobileTextAlignment: LocalizedField<AlignmentFieldType>
showButton: LocalizedField<boolean>
buttonLink?: LocalizedField<string>
buttonsText?: LocalizedField<string>
desktopButtonAlignment: LocalizedField<AlignmentFieldType>
mobileButtonAlignment: LocalizedField<AlignmentFieldType>
fullSizeBackground: LocalizedField<SysAssetLink>
mobileBackground: LocalizedField<SysAssetLink>
logo?: LocalizedField<SysAssetLink>
}

type BannerProps = {
fields: IBannerFields | null
assets: Record<string, ContentfulAsset>
isLoading: boolean
locale?: Locales
error: string | null
}

type LowercasedAlignment = "left" | "center" | "right"

export type { BannerProps, IBannerFields, LowercasedAlignment }
2 changes: 2 additions & 0 deletions src/components/Banner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Banner } from "./Banner"
export type { BannerProps, IBannerFields } from "./Banner.types"
2 changes: 1 addition & 1 deletion src/components/MarketingBanner/MarketingBanner.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MarketingBanner } from "./MarketingBanner"
import { Locales } from "../../hooks/contenful"
import { Locales } from "../../hooks/contentful"
import type { Meta, StoryObj } from "@storybook/react"

const meta = {
Expand Down
Loading

0 comments on commit 6dd88ba

Please sign in to comment.