From 6c42a2297214a3288465cf2bad4c8bdff733f4a7 Mon Sep 17 00:00:00 2001 From: Andre H Date: Mon, 4 Mar 2024 10:38:12 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20feat:=20implement=20steps/?= =?UTF-8?q?=20timeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../shared/Steps/Step/Step.theme.ts | 43 +++++++++++++ .../src/components/shared/Steps/Step/Step.tsx | 60 +++++++++++++++++++ .../src/components/shared/Steps/Step/index.ts | 2 + .../components/shared/Steps/Steps.theme.ts | 18 ++++++ .../src/components/shared/Steps/Steps.tsx | 42 +++++++++++++ .../src/components/shared/Steps/index.ts | 2 + 6 files changed, 167 insertions(+) create mode 100644 packages/frontend/src/components/shared/Steps/Step/Step.theme.ts create mode 100644 packages/frontend/src/components/shared/Steps/Step/Step.tsx create mode 100644 packages/frontend/src/components/shared/Steps/Step/index.ts create mode 100644 packages/frontend/src/components/shared/Steps/Steps.theme.ts create mode 100644 packages/frontend/src/components/shared/Steps/Steps.tsx create mode 100644 packages/frontend/src/components/shared/Steps/index.ts diff --git a/packages/frontend/src/components/shared/Steps/Step/Step.theme.ts b/packages/frontend/src/components/shared/Steps/Step/Step.theme.ts new file mode 100644 index 00000000..82531ace --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/Step/Step.theme.ts @@ -0,0 +1,43 @@ +import { VariantProps, tv } from 'tailwind-variants'; + +export const stepTheme = tv({ + slots: { + wrapper: ['relative', 'px-1.5', 'py-1.5', 'flex', 'gap-2', 'items-center'], + step: [ + 'bg-base-bg-emphasized', + 'rounded-full', + 'w-7', + 'h-7', + 'flex', + 'items-center', + 'justify-center', + 'text-elements-mid-em', + 'shadow-button', + 'shrink-0', + ], + label: ['text-sm', 'font-sans', 'text-elements-mid-em'], + connector: ['bg-border-interactive-hovered'], + }, + variants: { + orientation: { + vertical: { connector: ['w-px', 'h-3', 'ml-5'] }, + horizontal: { connector: ['h-px', 'w-full'] }, + }, + active: { + true: { + step: ['bg-controls-secondary-hovered', 'text-elements-on-secondary'], + label: ['text-elements-high-em'], + }, + }, + completed: { + true: { + step: ['text-controls-primary'], + }, + }, + }, + defaultVariants: { + orientation: 'vertical', + }, +}); + +export type StepTheme = VariantProps; diff --git a/packages/frontend/src/components/shared/Steps/Step/Step.tsx b/packages/frontend/src/components/shared/Steps/Step/Step.tsx new file mode 100644 index 00000000..001ed6b6 --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/Step/Step.tsx @@ -0,0 +1,60 @@ +import React, { useCallback, ComponentPropsWithoutRef } from 'react'; +import { stepTheme, StepTheme } from './Step.theme'; +import { CheckRoundFilledIcon } from 'components/shared/CustomIcon'; + +export interface StepProps extends ComponentPropsWithoutRef<'li'>, StepTheme { + /** + * The label for the step + */ + label: string; + /** + * The index of the step + */ + index: number; + /** + * The total number of steps + */ + currentIndex: number; +} + +export const Step = ({ + label, + index, + currentIndex, + orientation, + ...props +}: StepProps) => { + const theme = stepTheme(); + + const active = currentIndex === index; + const completed = currentIndex > index; + + const renderConnector = useCallback( + (index: number) => { + if (index === 0) { + return null; + } + + return
; + }, + [theme], + ); + + return ( + <> + {renderConnector(index)} +
  • + { +
    + {completed ? ( + + ) : ( + index + 1 + )} +
    + } +

    {label}

    +
  • + + ); +}; diff --git a/packages/frontend/src/components/shared/Steps/Step/index.ts b/packages/frontend/src/components/shared/Steps/Step/index.ts new file mode 100644 index 00000000..84d83fcb --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/Step/index.ts @@ -0,0 +1,2 @@ +export * from './Step'; +export * from './Step.theme'; diff --git a/packages/frontend/src/components/shared/Steps/Steps.theme.ts b/packages/frontend/src/components/shared/Steps/Steps.theme.ts new file mode 100644 index 00000000..a5d62e99 --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/Steps.theme.ts @@ -0,0 +1,18 @@ +import { VariantProps, tv } from 'tailwind-variants'; + +export const stepsTheme = tv({ + slots: { + root: [], + }, + variants: { + orientation: { + vertical: { root: ['flex', 'flex-col'] }, + horizontal: { root: ['flex', 'items-center'] }, + }, + }, + defaultVariants: { + orientation: 'vertical', + }, +}); + +export type StepsTheme = VariantProps; diff --git a/packages/frontend/src/components/shared/Steps/Steps.tsx b/packages/frontend/src/components/shared/Steps/Steps.tsx new file mode 100644 index 00000000..51d4eb2d --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/Steps.tsx @@ -0,0 +1,42 @@ +import React, { Fragment, ComponentPropsWithoutRef } from 'react'; +import { stepsTheme, StepsTheme } from './Steps.theme'; +import { Step, StepProps, StepTheme } from './Step'; + +interface StepsProps + extends ComponentPropsWithoutRef<'ul'>, + StepsTheme, + Pick { + /** + * The index of the current step + */ + currentIndex: number; + /** + * The steps to render + */ + steps: Pick[]; +} + +export const Steps = ({ + currentIndex, + steps = [], + className, + orientation, + ...props +}: StepsProps) => { + const theme = stepsTheme(); + + return ( +
      + {steps.map((step, i) => ( + + + + ))} +
    + ); +}; diff --git a/packages/frontend/src/components/shared/Steps/index.ts b/packages/frontend/src/components/shared/Steps/index.ts new file mode 100644 index 00000000..27d56a3b --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/index.ts @@ -0,0 +1,2 @@ +export * from './Steps'; +export * from './Steps.theme';