Files
L-Ami-Fiduciaire/resources/js/components/ui/timeline/TimelineItem.vue

80 lines
2.1 KiB
Vue
Raw Normal View History

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import type { TimelineItemVariants } from "."
import { Check, Circle } from "lucide-vue-next"
import { cn } from "@/lib/utils"
import { timelineItemVariants } from "."
const props = withDefaults(
defineProps<{
title: string
date?: string
time?: string
state?: TimelineItemVariants["state"]
class?: HTMLAttributes["class"]
}>(),
{ state: "pending" },
)
</script>
<template>
<div
role="listitem"
data-slot="timeline-item"
:data-state="props.state"
:class="
cn(
'relative flex gap-4 pb-6 last:pb-0',
timelineItemVariants({ state: props.state }),
props.class,
)
"
>
<!-- Connector line (hidden on last item) -->
<div
aria-hidden
class="timeline-item-connector absolute left-[11px] top-6 h-[calc(100%-0.5rem)] w-px bg-border"
/>
<!-- Status indicator -->
<div
:class="
cn(
'relative z-10 flex shrink-0 items-center justify-center rounded-full border-2 transition-colors',
props.state === 'completed' &&
'border-primary bg-primary text-primary-foreground',
props.state === 'pending' && 'border-border bg-background',
props.state === 'current' && 'border-primary bg-primary/10 text-primary',
)
"
:style="{ width: '24px', height: '24px' }"
>
<Check v-if="props.state === 'completed'" class="size-3.5" :stroke-width="3" />
<Circle
v-else
class="size-2.5 fill-current"
stroke="none"
/>
</div>
<!-- Content -->
<div class="flex min-w-0 flex-1 flex-col gap-0.5 pt-0.5">
<div class="flex items-start justify-between gap-4">
<span class="text-sm font-medium leading-tight">
{{ props.title }}
</span>
<span
v-if="props.time"
class="shrink-0 text-xs text-muted-foreground"
>
{{ props.time }}
</span>
</div>
<span v-if="props.date" class="text-xs text-muted-foreground">
{{ props.date }}
</span>
<slot />
</div>
</div>
</template>