-
Notifications
You must be signed in to change notification settings - Fork 0
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
GIVCAMP-88 | data card #245
Changes from all commits
7961e15
dc08ee9
9776dd4
4aed440
c106fc9
6324adc
61c13fb
a1ba733
7df2e00
83eb366
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { cnb } from 'cnbuilder'; | ||
|
||
export const animateWrapper = 'h-full'; | ||
// Use border-black-50/50 which works well on both light and dark backgrounds | ||
export const root = 'relative overflow-hidden size-full break-words border-l-2 border-black-50/50'; | ||
|
||
export const flex = 'h-full'; | ||
export const content = ( | ||
hasBarColor?: boolean, | ||
) => cnb('rs-pl-2', { | ||
'border-l-[1.4rem] md:border-l-[2rem]': hasBarColor, | ||
}); | ||
|
||
export const heading = 'rs-mb-3 ml-22 whitespace-pre-line mt-auto'; | ||
export const body = '*:*:leading-snug'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👀 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a WYSIWYG 🤣 |
||
export const cta = 'rs-mt-2'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { cnb } from 'cnbuilder'; | ||
import { AnimateInView, type AnimationType } from '@/components/Animate'; | ||
import { NumberCounter } from '@/components/NumberCounter'; | ||
import { Container } from '@/components/Container'; | ||
import { FlexBox } from '@/components/FlexBox'; | ||
import { Heading, type HeadingType } from '../Typography'; | ||
import { accentBorderColors, type AccentBorderColorType, type PaddingType } from '@/utilities/datasource'; | ||
import { splitNumberString } from '@/utilities/splitNumberString'; | ||
import * as styles from './DataCard.styles'; | ||
|
||
export type DataCardProps = React.HTMLAttributes<HTMLDivElement> & { | ||
heading?: string; | ||
headingLevel?: HeadingType; | ||
isDarkTheme?: boolean; | ||
barColor?: AccentBorderColorType; | ||
body?: React.ReactNode; | ||
paddingTop?: PaddingType; | ||
cta?: React.ReactNode; | ||
isCounter?: boolean; | ||
// In number of seconds | ||
counterDuration?: number; | ||
animation?: AnimationType; | ||
delay?: number; | ||
}; | ||
|
||
export const DataCard = ({ | ||
heading, | ||
headingLevel = 'h3', | ||
barColor, | ||
body, | ||
cta, | ||
paddingTop, | ||
isDarkTheme, | ||
isCounter, | ||
counterDuration, | ||
animation = 'slideUp', | ||
delay, | ||
children, | ||
className, | ||
...props | ||
}: DataCardProps) => { | ||
const headingProcessed = isCounter ? splitNumberString(heading) : undefined; | ||
|
||
return ( | ||
<AnimateInView animation={animation} delay={delay} className={styles.animateWrapper}> | ||
<Container | ||
as="article" | ||
width="full" | ||
pt={paddingTop} | ||
className={styles.root} | ||
{...props} | ||
> | ||
<FlexBox direction="col" className={styles.flex}> | ||
{/* If number counter is enabled, aria-hidden the animated heading and add a SR only heading */} | ||
{isCounter && heading && ( | ||
<Heading as={headingLevel} srOnly>{heading}</Heading> | ||
)} | ||
Comment on lines
+54
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there is a number counter in the heading, add a SR only heading with all static heading, then aria-hidden the visible heading with the number counter. |
||
{heading && ( | ||
<Heading | ||
as={headingLevel} | ||
font="druk" | ||
leading="druk" | ||
color={isDarkTheme ? 'white' : 'black'} | ||
size="f5" | ||
aria-hidden={isCounter} | ||
className={styles.heading} | ||
> | ||
{isCounter ? ( | ||
<> | ||
{headingProcessed?.beforeNumber} | ||
<NumberCounter number={headingProcessed?.number} duration={counterDuration} /> | ||
{headingProcessed?.afterNumber} | ||
</> | ||
) : ( | ||
heading | ||
)} | ||
</Heading> | ||
)} | ||
<div className={cnb(styles.content(!!barColor), accentBorderColors[barColor])}> | ||
<div className={styles.body}> | ||
{body} | ||
</div> | ||
{!!cta && ( | ||
<div className={styles.cta}> | ||
{cta} | ||
</div> | ||
)} | ||
</div> | ||
</FlexBox> | ||
</Container> | ||
</AnimateInView> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './DataCard'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { storyblokEditable, type SbBlokData } from '@storyblok/react/rsc'; | ||
import { type StoryblokRichtext } from 'storyblok-rich-text-react-renderer-ts'; | ||
import { CreateBloks } from '@/components/CreateBloks'; | ||
import { DataCard } from '@/components/DataCard'; | ||
import { RichText } from '@/components/RichText'; | ||
import { type AnimationType } from '@/components/Animate'; | ||
import { type HeadingType } from '@/components/Typography'; | ||
import { paletteAccentColors, type PaletteAccentHexColorType } from '@/utilities/colorPalettePlugin'; | ||
import { type PaddingType } from '@/utilities/datasource'; | ||
import { getNumBloks } from '@/utilities/getNumBloks'; | ||
import { hasRichText } from '@/utilities/hasRichText'; | ||
|
||
export type SbDataCardProps = { | ||
blok: { | ||
_uid: string; | ||
heading?: string; | ||
headingLevel?: HeadingType; | ||
isSmallHeading?: boolean; | ||
superhead?: string; | ||
body: StoryblokRichtext; | ||
cta?: SbBlokData[]; | ||
paddingTop?: PaddingType; | ||
isDarkTheme?: boolean; | ||
isCounter?: boolean; | ||
counterDuration?: number; | ||
barColor?: { | ||
value?: PaletteAccentHexColorType; | ||
} | ||
animation?: AnimationType; | ||
delay?: number; | ||
}; | ||
}; | ||
|
||
export const SbDataCard = ({ | ||
blok: { | ||
heading, | ||
headingLevel, | ||
body, | ||
cta, | ||
paddingTop, | ||
isDarkTheme, | ||
isCounter, | ||
counterDuration, | ||
barColor: { value } = {}, | ||
animation, | ||
delay, | ||
}, | ||
blok, | ||
}: SbDataCardProps) => { | ||
const Body = hasRichText(body) ? <RichText wysiwyg={body} textColor={isDarkTheme ? 'white' : 'black'} /> : undefined; | ||
const Cta = !!getNumBloks(cta) ? <CreateBloks blokSection={cta} /> : undefined; | ||
|
||
return ( | ||
<DataCard | ||
{...storyblokEditable(blok)} | ||
heading={heading} | ||
headingLevel={headingLevel} | ||
isDarkTheme={isDarkTheme} | ||
isCounter={isCounter} | ||
counterDuration={counterDuration} | ||
barColor={paletteAccentColors[value]} | ||
cta={Cta} | ||
body={Body} | ||
paddingTop={paddingTop} | ||
animation={animation} | ||
delay={delay} | ||
/> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/** | ||
* Giving Campaign colors | ||
* Momentum colors | ||
*/ | ||
module.exports = function () { | ||
return { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/** | ||
* Giving Campaign fonts | ||
* Momentum fonts | ||
*/ | ||
module.exports = function () { | ||
return { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* Momentum line heights | ||
*/ | ||
module.exports = function () { | ||
return { | ||
// Extra tight line height for Druk font in some components, e.g., Data Card, Moment Poster | ||
druk: '0.9', | ||
}; | ||
}; | ||
Comment on lines
+1
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add extra tight leading utility for Druk font that are used in a few places |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/** | ||
* Separates a string into three parts: text before the number, the number itself, and text after the number. | ||
* | ||
* @param str The input string containing a number. | ||
* @returns An object with three properties: beforeNumber, number, and afterNumber. | ||
*/ | ||
export const splitNumberString = (str: string): { beforeNumber: string; number?: number; afterNumber: string } => { | ||
const numberRegex = /\d+/; | ||
const numberMatch = str.match(numberRegex); | ||
|
||
if (numberMatch) { | ||
const number = parseFloat(numberMatch[0]); | ||
const numberIndex = numberMatch.index ?? 0; | ||
const beforeNumber = str.substring(0, numberIndex); | ||
const afterNumber = str.substring(numberIndex + (numberMatch[0]?.length ?? 0)); | ||
|
||
return { | ||
beforeNumber: beforeNumber ?? '', | ||
number: number, | ||
afterNumber: afterNumber ?? '', | ||
}; | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updating some readme