Skip to content

Commit

Permalink
feat: add custom stepper icon
Browse files Browse the repository at this point in the history
  • Loading branch information
tewshi committed Jul 6, 2023
1 parent e8b39bf commit 4589953
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 29 deletions.
84 changes: 84 additions & 0 deletions example/src/views/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,90 @@ const steppers = ref([
},
],
},
{
custom: true,
steps: [
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
{
title: 'Active',
description: 'Lorem ipsum',
state: StepperState.active,
},
{
title: 'Done',
description: 'Lorem ipsum',
state: StepperState.done,
},
],
},
{
custom: true,
orientation: 'vertical',
steps: [
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
{
title: 'Active',
description: 'Lorem ipsum',
state: StepperState.active,
},
{
title: 'Done',
description: 'Lorem ipsum',
state: StepperState.done,
},
],
},
{
custom: true,
iconTop: true,
steps: [
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
{
title: 'Active',
description: 'Lorem ipsum',
state: StepperState.active,
},
{
title: 'Done',
description: 'Lorem ipsum',
state: StepperState.done,
},
],
},
{
custom: true,
iconTop: true,
orientation: 'vertical',
steps: [
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
{
title: 'Active',
description: 'Lorem ipsum',
state: StepperState.active,
},
{
title: 'Done',
description: 'Lorem ipsum',
state: StepperState.done,
},
],
},
]);
</script>

Expand Down
50 changes: 50 additions & 0 deletions src/components/steppers/Stepper.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const meta: Meta<typeof Stepper> = {
argTypes: {
steps: { control: 'array', table: { category: 'State' } },
iconTop: { control: 'boolean', table: { category: 'State' } },
custom: { control: 'boolean', table: { category: 'State' } },
orientation: {
control: 'select',
options: [StepperOrientation.horizontal, StepperOrientation.vertical],
Expand Down Expand Up @@ -183,4 +184,53 @@ export const StepOnlyAndVertical = {
},
};

export const Custom = {
args: {
custom: true,
steps: [
{ title: 'Done', description: 'Lorem ipsum', state: StepperState.done },
{
title: 'Active',
description: 'Lorem ipsum',
state: StepperState.active,
},
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
],
},
};

export const CustomVertical = {
args: {
custom: true,
orientation: StepperOrientation.vertical,
steps: [
{ title: 'Done', description: 'Lorem ipsum', state: StepperState.done },
{
title: 'Active',
description: 'Lorem ipsum',
state: StepperState.active,
},
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
{
title: 'Inactive',
description: 'Lorem ipsum',
state: StepperState.inactive,
},
],
},
};

export default meta;
74 changes: 55 additions & 19 deletions src/components/steppers/Stepper.vue
Original file line number Diff line number Diff line change
@@ -1,38 +1,65 @@
<script lang="ts" setup>
import { StepperOrientation, type StepperStep } from '@/types/stepper';
import {
StepperOrientation,
StepperState,
type StepperStep,
} from '@/types/stepper';
import StepperIcon from '@/components/steppers/StepperIcon.vue';
import StepperCustomIcon from '@/components/steppers/StepperCustomIcon.vue';
withDefaults(
const props = withDefaults(
defineProps<{
steps: StepperStep[];
iconTop?: boolean;
custom?: boolean;
orientation?: StepperOrientation;
}>(),
{
iconTop: false,
custom: false,
orientation: StepperOrientation.horizontal,
}
);
const css = useCssModule();
const { custom, steps } = toRefs(props);
// custom steps only supports 3 states.
const filteredSteps = computed(() => {
if (!get(custom)) {
return get(steps);
}
return get(steps).filter((step) =>
[StepperState.inactive, StepperState.active, StepperState.done].includes(
step.state
)
);
});
</script>

<template>
<div
:class="[
css.stepper,
css[orientation ?? ''],
{ [css['icon-top']]: iconTop },
{ [css['icon-top']]: iconTop, [css.custom]: custom },
]"
>
<template
v-for="({ title, description, state }, index) in steps"
v-for="({ title, description, state }, index) in filteredSteps"
:key="index"
>
<hr v-if="index > 0" :class="css.divider" />
<div :class="[css.step, css[state]]">
<slot name="icon" v-bind="{ state, index: index + 1 }">
<stepper-icon :index="index + 1" :state="state" />
<stepper-custom-icon
v-if="custom"
:index="index + 1"
:state="state"
/>
<stepper-icon v-else :index="index + 1" :state="state" />
</slot>
<div v-if="title || description" :class="css.label">
<span v-if="title" class="text-subtitle-2">{{ title }}</span>
Expand All @@ -44,6 +71,7 @@ const css = useCssModule();
</template>
<style lang="scss" module>
$colors: 'error', 'warning', 'info', 'success';
.stepper {
@apply flex;
Expand All @@ -58,6 +86,12 @@ const css = useCssModule();
@apply block min-h-[3rem] max-h-full h-full self-start -my-4 mx-3 border-l border-rui-grey-400;
}
&.custom {
.divider {
@apply mx-5;
}
}
&.icon-top {
.divider {
@apply self-center mx-auto;
Expand Down Expand Up @@ -85,20 +119,10 @@ const css = useCssModule();
@apply text-rui-primary;
}
&.error {
@apply text-rui-error;
}
&.warning {
@apply text-rui-warning;
}
&.info {
@apply text-rui-info;
}
&.success {
@apply text-rui-success;
@each $color in $colors {
&.#{$color} {
@apply text-rui-#{$color};
}
}
}
Expand All @@ -116,6 +140,18 @@ const css = useCssModule();
@apply block max-w-full h-0 max-h-0 self-center -mx-4 my-0 border-t border-rui-grey-400;
flex: 1 1 0;
}
&.custom {
.divider {
@apply border-rui-primary-lighter;
}
.step {
.label {
@apply text-rui-primary;
}
}
}
}
:global(.dark) {
Expand Down
60 changes: 60 additions & 0 deletions src/components/steppers/StepperCustomIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script lang="ts" setup>
import Icon from '@/components/icons/Icon.vue';
import { StepperState } from '@/types/stepper';
defineProps<{
state: StepperState;
index: number;
}>();
const css = useCssModule();
</script>

<template>
<span :class="[css.indicator, css[state]]">
<span v-if="state === StepperState.inactive" :class="css.text">
{{ index }}
</span>
<icon
v-else-if="state === StepperState.active"
name="checkbox-blank-circle-fill"
:size="26"
/>
<icon
v-else-if="state === StepperState.done"
:class="css.text"
:size="26"
name="check-line"
/>
<span v-else :class="css.text">
{{ index }}
</span>
</span>
</template>

<style lang="scss" module>
.indicator {
@apply inline-flex items-center justify-center rounded-full h-10 w-10 border bg-rui-primary border-rui-primary text-white;
&.inactive {
@apply text-xs bg-white;
.text {
@apply text-rui-primary;
}
}
}
:global(.dark) {
.indicator {
@apply bg-white text-rui-primary;
&.inactive {
@apply bg-rui-primary text-white border-white;
.text {
@apply text-white;
}
}
}
}
</style>
14 changes: 4 additions & 10 deletions src/components/steppers/StepperIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@
import Icon from '@/components/icons/Icon.vue';
import { StepperState } from '@/types/stepper';
withDefaults(
defineProps<{
state: StepperState;
index: number;
disabled?: boolean;
}>(),
{
disabled: false,
}
);
defineProps<{
state: StepperState;
index: number;
}>();
const css = useCssModule();
</script>
Expand Down
2 changes: 2 additions & 0 deletions src/composables/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type GeneratedIcon } from '@/types/icons';
import {
RiAlertFill,
RiCheckLine,
RiCheckboxBlankCircleFill,
RiCheckboxBlankLine,
RiCheckboxCircleFill,
RiCheckboxFill,
Expand All @@ -16,6 +17,7 @@ export const useIcons = createGlobalState(() => {
RiCheckboxCircleFill,
RiCheckboxIndeterminateFill,
RiCheckboxBlankLine,
RiCheckboxBlankCircleFill,
RiCheckLine,
RiErrorWarningFill,
RiAlertFill,
Expand Down

0 comments on commit 4589953

Please sign in to comment.