Untitled

 avatar
unknown
plain_text
a month ago
4.9 kB
2
Indexable
<template>
    <div
        v-if="!displaySmallMode"
        class="mb-10 h-[104px] w-full justify-between divide-x divide-slate-300 overflow-hidden rounded-lg border border-gray-300 bg-light-100 dark:divide-slate-800 dark:border-gray-800 dark:bg-dark-100 flex md:h-16 lg:h-[72px]"
    >
        <button
            v-for="(step, index) in steps"
            :key="`step-${index}`"
            class="flex w-1/3 items-center gap-4 pr-1.5 md:gap-2 lg:gap-4"
            :class="{
                'bg-light-300 dark:bg-dark-50': step.number === selectedStep,
                'dark:bg-emerald-300/10 bg-emerald-300/30':
                    step.isDone && step.number !== selectedStep && step.number < selectedStep
            }"
            :disabled="isDisabled(index)"
            @click="onStepClick(step.number)"
        >
            <div class="flex flex-col gap-2 overflow-hidden md:flex-row lg:gap-4 mx-4">
                <div
                    class="flex size-10 flex-none items-center justify-center rounded-full border-2 text-sm leading-4"
                    :class="{
                        'dark:border-emerald-600 dark:bg-emerald-600 bg-emerald-300 border-emerald-300':
                            step.isDone && step.number !== selectedStep && step.number < selectedStep,
                        'border-rose-500': !!step.error,
                        'dark:border-gray-700 border-gray-300': !step.isDone && !step.error,
                        'dark:border-gray-300 border-gray-500': step.isDone && step.number === selectedStep
                    }"
                >
                    <span v-if="!!step.error" class="text-2xl text-rose-500">!</span>

                    <mdicon
                        v-else
                        :name="
                            step.isDone && step.number !== selectedStep && step.number < selectedStep
                                ? 'check'
                                : step.iconName
                        "
                        :size="20"
                        :class="[step.isDone ? 'text-white ' : 'dark:text-white text-gray-500']"
                    />
                </div>
                <div class="flex flex-col items-start text-start">
                    <span
                        class="text-xs font-semibold"
                        :class="{
                            'text-slate-900 dark:text-slate-200':
                                (step.isDone && step.number !== selectedStep) ||
                                (!step.isDone && step.number === selectedStep),
                            'text-slate-500 dark:text-slate-400': !step.isDone && step.number !== selectedStep,
                            'text-rose-500 dark:text-rose-400': !!step.error && step.number === selectedStep
                        }"
                    >
                        {{ $t('createPost.step', { count: step.number }) }}
                    </span>
                    <span class="line-clamp-1 text-sm text-slate-500 dark:text-slate-400">{{ step.title }}</span>
                </div>
            </div>
        </button>
    </div>
    <div v-else>
        <div class="flex gap-2 text-sm dark:text-slate-300 text-slate-700 w-full mb-1">
            {{ $t('createPost.step', { count: selectedStep }) }} / {{ steps.length }}
        </div>
        <div class="w-full mb-4 bg-slate-300 rounded-full h-2.5 dark:bg-gray-700">
            <div class="bg-blue-500 dark:bg-blue-600 h-2.5 rounded-full" :style="progressStyle" />
        </div>
    </div>
</template>

<script lang="ts">
import { defineComponent, type PropType } from 'vue';

import type { IStepItem } from '@/types/create-post';

export default defineComponent({
    name: 'NavigationSteps',

    props: {
        selectedStep: {
            type: Number,
            required: true
        },

        steps: {
            type: Array as PropType<IStepItem[]>,
            required: true
        }
    },

    emits: ['step-click'],

    data() {
        return {
            windowWidth: window.innerWidth
        };
    },

    computed: {
        displaySmallMode() {
            return this.windowWidth < 1024;
        },

        progressStyle() {
            return { width: `${(this.selectedStep / this.steps.length) * 100}%` };
        }
    },

    mounted() {
        window.addEventListener('resize', this.handleResize);
    },

    beforeUnmount() {
        window.removeEventListener('resize', this.handleResize);
    },

    methods: {
        onStepClick(number: number) {
            this.$emit('step-click', number);
        },

        isDisabled(index: number) {
            return index === 0 ? false : !this.steps[index - 1].isDone && !this.steps[index].isDone;
        },

        handleResize() {
            this.windowWidth = window.innerWidth;
        }
    }
});
</script>
Leave a Comment