Skip to content

Commit

Permalink
refactor: add custom Steps component
Browse files Browse the repository at this point in the history
fix #245
  • Loading branch information
gratestas committed Aug 4, 2023
1 parent 12487f2 commit 2208b95
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 145 deletions.
142 changes: 142 additions & 0 deletions src/components/presentational/steps/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
@use "src/stylesheets/variables/spacings";
@use "src/stylesheets/variables/typo";

.steps {
position: relative;
display: flex;
width: 100%;
&.vertical {
flex-direction: column;
}
}

.stepItem {
position: relative;
display: flex;
flex: 1 0 0;
align-items: center;
padding-bottom: spacings.$s-10;

.circleWrapper {
display: flex;
position: relative;

.circle {
display: flex;
justify-content: center;
align-items: center;
width: spacings.$s-10;
height: spacings.$s-10;
background-color: hsl(var(--english-breakfast-800));

.dot {
width: spacings.$s-2;
height: spacings.$s-2;
background-color: hsl(var(--english-breakfast-800));
border-radius: 50%;
}
svg {
width: spacings.$s-6;
height: spacings.$s-6;
}
/* svg {
path {
fill: hsl(var(--starbright-600));
stroke: hsl(var(--starbright-600));
}
} */
}
}

.title {
margin-top: spacings.$s-2;
font-size: typo.$m;
color: hsl(var(--english-breakfast-500));
}

.title,
.description {
text-align: center;
}
}

/* .stepItem:not(:first-child) .title {
margin-top: 0;
} */

.stepItem:not(:last-child) .circleWrapper::after {
content: "";
position: absolute;
background-color: hsl(var(--english-breakfast-500));
z-index: -1;
}

.stepItem {
&.vertical {
.circleWrapper {
width: auto;
padding-left: 0;
border-color: transparent;
}

&:not(:last-child) .circleWrapper::after {
right: 50%;
width: 1px;
height: 250%;
}

&:not(:first-child) .title {
margin-top: 0;
}

&.active .circleWrapper .circle .dot {
width: spacings.$s-4;
height: spacings.$s-4;
}

&.completed .circleWrapper .circle {
background-color: hsl(var(--background));
}
}

&.horizontal {
flex-direction: column;
.circleWrapper {
width: 100%;
padding-left: 40%;
.circle {
border: 1px solid hsl(var(--english-breakfast-500));
border-radius: 50%;
}
}
&:not(:last-child) .circleWrapper::after {
top: 50%;
width: 100%;
height: 1px;
}
&.active .circleWrapper .circle {
background-color: hsl(var(--english-breakfast-800));
}
&.awaiting .circleWrapper .circle {
&.withBorder {
border-color: hsl(var(--english-breakfast-500));
}
}
}
}

.stepItem {
&.completed .circleWrapper::after,
&.completed .circleWrapper .circle {
background-color: hsl(var(--english-breakfast-800));
}

&:not(.completed) .circleWrapper::after {
background-color: hsl(var(--english-breakfast-500));
}

&.active .circleWrapper .circle,
&.awaiting .circleWrapper .circle {
background-color: hsl(var(--background));
}
}
35 changes: 35 additions & 0 deletions src/components/presentational/steps/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from "react";
import StepItem, { Status } from "./stepItem";
import * as styles from "./index.module.scss";

type StepsProps = {
items: {
title: string;
description: string;
icon?: React.ReactNode;
}[];
current: number;
direction?: "vertical" | "horizontal";
completed?: boolean;
};

const Steps: React.FC<StepsProps> = ({ items, current, direction = "horizontal", completed }) => {
const itemsWithStatus = items.map((item, index) => ({
...item,
status: completed ? "completed" : getStatus(index, current),
}));

return (
<div className={`${styles.steps} ${styles[direction] ?? ""}`}>
{itemsWithStatus.map((item, index) => (
<StepItem key={index} {...{ ...item, direction }} />
))}
</div>
);
};

export default Steps;

const getStatus = (index: number, current: number): Status => {
return index < current ? "completed" : index === current ? "active" : "awaiting";
};
38 changes: 38 additions & 0 deletions src/components/presentational/steps/stepItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from "react";
import * as styles from "./index.module.scss";

import CheckIcon from "jsx:/src/assets/checkMark.svg";

export type Status = "completed" | "active" | "awaiting";

type StepItemProps = {
title: string;
description: string;
icon?: React.ReactNode;
status?: Status;
direction: "vertical" | "horizontal";
};

export default function StepItem({ title, description, icon, status = "awaiting", direction }: StepItemProps) {
icon = status === "completed" ? <CheckIcon /> : icon;
return (
<div className={`${styles.stepItem} ${styles[direction] ?? ""} ${styles[status] ?? ""} `}>
<Circle {...{ icon, direction }} />
<div>
<div className={styles.title}>{title}</div>
<div className={styles.description}>{description}</div>
</div>
</div>
);
}

function Circle({ icon, direction }: { direction: string; icon?: React.ReactNode }) {
const isVertical = direction === "vertical";
return (
<div className={`${styles.circleWrapper} blink`}>
<div className={`${styles.circle} ${icon && !isVertical ? styles.withBorder : ""}`}>
{icon && !isVertical ? icon : <div className={styles.dot} />}
</div>
</div>
);
}
21 changes: 0 additions & 21 deletions src/components/presentational/timeline/index.jsx

This file was deleted.

124 changes: 0 additions & 124 deletions src/components/presentational/timeline/index.module.scss

This file was deleted.

0 comments on commit 2208b95

Please sign in to comment.