diff --git a/packages/frontend/src/components/projects/create/DeployStep.tsx b/packages/frontend/src/components/projects/create/DeployStep.tsx index 71283ddb..de78f789 100644 --- a/packages/frontend/src/components/projects/create/DeployStep.tsx +++ b/packages/frontend/src/components/projects/create/DeployStep.tsx @@ -101,7 +101,12 @@ const DeployStep = ({ )} {status === DeployStatus.COMPLETE && (
- +
+ +
{' '}
)} diff --git a/packages/frontend/src/components/shared/CustomIcon/CheckRoundFilledIcon.tsx b/packages/frontend/src/components/shared/CustomIcon/CheckRoundFilledIcon.tsx index 145e68e1..7811a1ec 100644 --- a/packages/frontend/src/components/shared/CustomIcon/CheckRoundFilledIcon.tsx +++ b/packages/frontend/src/components/shared/CustomIcon/CheckRoundFilledIcon.tsx @@ -3,17 +3,11 @@ import { CustomIcon, CustomIconProps } from './CustomIcon'; export const CheckRoundFilledIcon = (props: CustomIconProps) => { return ( - + 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..8e2b7a53 --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/Step/Step.theme.ts @@ -0,0 +1,52 @@ +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', + 'whitespace-nowrap', + ], + connector: [], + }, + variants: { + orientation: { + vertical: { + connector: ['bg-border-interactive-hovered', 'w-px', 'h-3', 'ml-5'], + }, + horizontal: { + connector: ['text-border-interactive-hovered', 'h-3', 'w-3'], + }, + }, + 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..9d731139 --- /dev/null +++ b/packages/frontend/src/components/shared/Steps/Step/Step.tsx @@ -0,0 +1,67 @@ +import React, { useCallback, ComponentPropsWithoutRef } from 'react'; +import { stepTheme, StepTheme } from './Step.theme'; +import { + CheckRoundFilledIcon, + ChevronRight, +} 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 === 1) { + return null; + } + + return ( +
+ {orientation === 'horizontal' && } +
+ ); + }, + [orientation, theme], + ); + + return ( + <> + {renderConnector(index)} +
  • + { +
    + {completed ? ( + + ) : ( + index + )} +
    + } +

    {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..4c3b2acb --- /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', 'gap-1'] }, + }, + }, + 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..cac61ff9 --- /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'; diff --git a/packages/frontend/src/pages/components/index.tsx b/packages/frontend/src/pages/components/index.tsx index aab2d652..feee4595 100644 --- a/packages/frontend/src/pages/components/index.tsx +++ b/packages/frontend/src/pages/components/index.tsx @@ -26,6 +26,7 @@ import { import { renderInputs } from './renders/input'; import { RADIO_OPTIONS } from './renders/radio'; import { SEGMENTED_CONTROLS_OPTIONS } from './renders/segmentedControls'; +import { renderHorizontalSteps, renderVerticalSteps } from './renders/steps'; import { renderTabWithBadges, renderTabs, @@ -56,6 +57,19 @@ const Page: React.FC = () => {
    + {/* Steps */} +
    +
    +

    Steps

    +
    + {renderVerticalSteps()} + {renderHorizontalSteps()} +
    +
    +
    + +
    + {/* Tag */}
    diff --git a/packages/frontend/src/pages/components/renders/steps.tsx b/packages/frontend/src/pages/components/renders/steps.tsx new file mode 100644 index 00000000..2d3f3da5 --- /dev/null +++ b/packages/frontend/src/pages/components/renders/steps.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import { Steps } from 'components/shared/Steps'; + +export const renderVerticalSteps = () => { + return ( + + ); +}; + +export const renderHorizontalSteps = () => { + return ( + + ); +}; diff --git a/packages/frontend/src/pages/org-slug/projects/create/Template.tsx b/packages/frontend/src/pages/org-slug/projects/create/Template.tsx index d819a6f1..0633540c 100644 --- a/packages/frontend/src/pages/org-slug/projects/create/Template.tsx +++ b/packages/frontend/src/pages/org-slug/projects/create/Template.tsx @@ -8,8 +8,8 @@ import { import { Avatar } from '@material-tailwind/react'; -import Stepper from '../../../../components/Stepper'; import templates from '../../../../assets/templates'; +import { Steps } from 'components/shared/Steps'; // TODO: Set dynamic route for template and load details from DB const CreateWithTemplate = () => { @@ -62,7 +62,7 @@ const CreateWithTemplate = () => {
    - +