feat: implement the Roadmap mdx component; refs #90

This commit is contained in:
Hossein Mehrabi
2023-07-10 05:27:35 +03:30
parent a962a56d3e
commit 4ecf45f55d
8 changed files with 262 additions and 6 deletions
@@ -17,14 +17,21 @@
line-height: inherit;
font-weight: inherit;
}
.lsd-button--large {
padding: 9px 39px;
}
.lsd-button--small {
padding: 5px 11px;
}
}
@include utils.responsive('lg', 'down') {
.mdx-cta-button {
@include lsd.typography('label2');
button {
padding: 6px 12px;
.lsd-button--large {
@include lsd.typography('label2');
padding: 5px 11px;
}
}
}
@@ -30,7 +30,7 @@ export const CallToActionButton: React.FC<CallToActionButtonProps> = ({
return (
<LinkElement
className={clsx('mdx-cta-button', className)}
variant="body1"
variant={size === 'large' ? 'label1' : 'label2'}
component="a"
href={href}
target={'_blank'}
@@ -0,0 +1,115 @@
@use '../../../css/utils';
@use '../../../css/lsd';
.mdx-roadmap {
width: 100%;
border-top: 1px solid rgb(var(--lsd-border-primary));
padding-top: 24px;
}
.mdx-roadmap__header {
display: flex;
flex-direction: row;
gap: 1rem;
> * {
flex-basis: 50%;
}
}
.mdx-roadmap__actions {
margin-top: 7.25rem;
display: flex;
flex-direction: row;
gap: 0 1rem;
}
.mdx-roadmap__timeline {
margin-top: 2rem;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
gap: 0 1rem;
overflow-y: scroll;
scroll-snap-type: x mandatory;
}
.mdx-roadmap__timeline-item {
width: 236px;
min-height: 308px;
gap: 1rem;
flex: 0 0 auto;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-bottom: 23px;
border-bottom: 1px solid rgb(var(--lsd-border-primary));
scroll-snap-align: start !important;
}
.mdx-roadmap__timeline-header {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
.mdx-roadmap__timeline-period-container {
width: 100%;
position: relative;
}
.mdx-roadmap__timeline-border {
top: 0;
left: 0;
width: calc(100% + 1rem);
height: 50%;
position: absolute;
border-bottom: 1px solid rgb(var(--lsd-border-primary));
z-index: -1;
}
.mdx-roadmap__timeline-border--dashed {
border-bottom-style: dashed;
}
.mdx-roadmap__timeline-period {
padding: 3px 12px;
display: inline-block;
border-radius: 10rem;
color: rgb(var(--lsd-text-secondary)) !important;
background-color: rgb(var(--lsd-surface-secondary));
}
.mdx-roadmap__timeline-item:last-child {
.mdx-roadmap__timeline-border {
display: none;
}
}
@include utils.responsive('lg', 'down') {
.mdx-roadmap__header {
flex-direction: column;
h2 {
@include lsd.typography('body1');
}
}
.mdx-roadmap__actions {
margin-top: 4rem;
}
.mdx-roadmap__timeline-item {
width: 204px;
min-height: 306px;
}
}
@include utils.responsive('sm', 'down') {
.mdx-roadmap__scroll {
display: none;
}
}
@@ -0,0 +1,120 @@
import {
IconButton,
IconButtonGroup,
NavigateBeforeIcon,
NavigateNextIcon,
Typography,
} from '@acid-info/lsd-react'
import clsx from 'clsx'
import React, { useRef } from 'react'
import './Roadmap.scss'
export type TimelineItem = {
period: string
description: string
borderStyle?: 'solid' | 'dashed'
}
export type RoadmapProps = Omit<
React.HTMLAttributes<HTMLDivElement>,
'title'
> & {
title: React.ReactNode
description?: React.ReactNode
timeline?: TimelineItem[]
}
export const Roadmap: React.FC<RoadmapProps> = ({
title,
description,
timeline = [],
className,
children,
...props
}) => {
const timelineRef = useRef<HTMLDivElement>(null)
const scroll = (direction: -1 | 1) => {
const el = timelineRef.current
if (!el) return
const itemWidth = el.children[0]?.getBoundingClientRect?.()?.width ?? 236
el.scrollTo({
behavior: 'smooth',
left:
el.scrollLeft +
(el.getBoundingClientRect()?.width - itemWidth) * direction,
})
}
return (
<div className={clsx(className, 'mdx-roadmap')} {...props}>
<div className="mdx-roadmap__header">
<Typography component="h2" variant="h6">
{title}
</Typography>
{description && (
<Typography component="p" variant="h4">
{description}
</Typography>
)}
</div>
<div className="mdx-roadmap__actions">
{children && <div className="mdx-roadmap__cta">{children}</div>}
<div className="mdx-roadmap__scroll">
<IconButtonGroup size="small" color="primary">
<IconButton size="small" onClick={scroll.bind(null, -1)}>
<NavigateBeforeIcon />
</IconButton>
<IconButton size="small" onClick={scroll.bind(null, 1)}>
<NavigateNextIcon />
</IconButton>
</IconButtonGroup>
</div>
</div>
{timeline.length > 0 && (
<div
ref={timelineRef}
className="mdx-roadmap__timeline hidden-scrollbar"
>
{timeline.map((item, index) => (
<div key={index} className="mdx-roadmap__timeline-item">
<div className="mdx-roadmap__timeline-header">
<div className="mdx-roadmap__timeline-period-container">
<div
className={clsx(
'mdx-roadmap__timeline-border',
item.borderStyle === 'dashed' &&
'mdx-roadmap__timeline-border--dashed',
)}
/>
<Typography
variant="subtitle1"
component="span"
className="mdx-roadmap__timeline-period"
>
{item.period}
</Typography>
</div>
<Typography
variant="h3"
component="span"
className="mdx-roadmap__timeline-index"
>
{`${index < 9 ? '0' : ''}${index + 1}`}
</Typography>
</div>
<Typography
variant="h6"
component="p"
className="mdx-roadmap__timeline-description"
dangerouslySetInnerHTML={{ __html: item.description }}
/>
</div>
))}
</div>
)}
</div>
)
}
@@ -0,0 +1 @@
export * from './Roadmap'
@@ -13,4 +13,5 @@ export * from './HeroTitle'
export * from './PoweredBy'
export * from './ScrollToBottom'
export * from './Showcase'
export * from './Roadmap'
export * from './HeroVideo'
@@ -1216,4 +1216,16 @@ code {
overflow: hidden;
}
.hidden-scrollbar {
/* Chrome, Safari and Opera */
&::-webkit-scrollbar {
width: 0;
display: none;
}
/* Firefox, Edge and IE */
-ms-overflow-style: none;
scrollbar-width: none;
}
@import './blog.scss';
@@ -27,7 +27,7 @@ export const SearchResults: React.FC<SearchResultsProps> = ({
return (
<div className={clsx(styles.root, total === 0 && styles.noResults)}>
{total === 0 && <SearchResultMessage>No result.</SearchResultMessage>}
<div className={clsx(styles.groups, 'hidden-scrollbar')}>
<div className={clsx(styles.groups)}>
{grouped.map(([category, items], index) => (
<React.Fragment key={index}>
<SearchResultGroup className={styles.group} title={category}>