Files
365devnet/src/components/ui/CompactTimeline.astro
2025-02-26 01:53:49 +01:00

69 lines
2.2 KiB
Plaintext

---
import { Icon } from 'astro-icon/components';
import { twMerge } from 'tailwind-merge';
import type { Item } from '~/types';
export interface Props {
items?: Array<Item>;
defaultIcon?: string;
classes?: Record<string, string>;
}
const { items = [], classes = {}, defaultIcon } = Astro.props as Props;
const {
container: containerClass = '',
panel: panelClass = '',
title: titleClass = '',
description: descriptionClass = '',
icon: defaultIconClass = 'text-primary dark:text-slate-200 border-primary dark:border-blue-700',
} = classes;
---
{
items && items.length && (
<div class={twMerge("grid grid-cols-1 md:grid-cols-2 gap-4", containerClass)}>
{items.map(({ title, description, icon, classes: itemClasses = {} }) => (
<div
class={twMerge(
'flex intersect-once intersect-quarter motion-safe:md:opacity-0 motion-safe:md:intersect:animate-fade border border-gray-200 dark:border-gray-700 rounded-lg p-4 hover:shadow-md transition-all duration-300 ease-in-out hover:bg-gray-50 dark:hover:bg-gray-800',
panelClass,
itemClasses?.panel
)}
>
<div class="flex-shrink-0 mr-3 rtl:mr-0 rtl:ml-3">
{(icon || defaultIcon) && (
<Icon
name={icon || defaultIcon}
class={twMerge('w-8 h-8 p-1.5 rounded-full border-2', defaultIconClass, itemClasses?.icon)}
/>
)}
</div>
<div>
{title && <p class={twMerge('text-lg font-bold', titleClass, itemClasses?.title)} set:html={title} />}
{description && (
<div class="text-muted mt-2 overflow-hidden">
<div
class={twMerge('text-sm max-h-[4.5rem] hover:max-h-[300px] transition-all duration-500 ease-description', descriptionClass, itemClasses?.description)}
set:html={description}
/>
</div>
)}
</div>
</div>
))}
</div>
)
}
<style>
/* Custom easing function for description expansion */
.ease-description {
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
/* Fade effect for the gradient overlay */
.hover\:opacity-0:hover {
opacity: 0;
}
</style>