1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
---
import Link from '@/components/Link.astro'
import { cn } from '@/lib/utils'
import { Icon } from 'astro-icon/components'
interface Detail {
icon: string
label: string
value: string
href?: string
}
const {
title,
date,
time,
venue,
requirements,
registration,
organiser,
website,
details = [],
variant = 'default',
class: className,
} = Astro.props
const builtIns: Detail[] = [
date && { icon: 'lucide:calendar', label: 'Date', value: date },
time && { icon: 'lucide:clock', label: 'Time', value: time },
venue && { icon: 'lucide:map-pin', label: 'Venue', value: venue },
requirements && { icon: 'lucide:backpack', label: 'Requirements', value: requirements },
organiser && { icon: 'lucide:users', label: 'Organiser', value: organiser },
website && { icon: 'lucide:external-link', label: 'Website', value: website, href: website },
].filter(Boolean) as Detail[]
const allDetails = [...builtIns, ...details]
---
<div
class={cn(
'not-prose rounded-xl border',
variant === 'compact' ? 'p-3' : 'p-4',
className,
)}
>
{
title && (
<span
class={cn(
'text-foreground flex items-center gap-2 font-medium',
variant === 'compact' ? 'mb-2 text-sm' : 'mb-3 text-base',
)}
>
<Icon name="lucide:info" class="size-4" />
{title}
</span>
)
}
<dl class="flex flex-col divide-y">
{
allDetails.map((detail) => (
<div
class={cn(
'flex flex-wrap items-center gap-x-4',
variant === 'compact' ? 'gap-y-0.5 py-1.5' : 'gap-y-1 py-2',
'first:pt-0 last:pb-0',
)}
>
<dt
class={cn(
'text-muted-foreground flex items-center gap-x-1.5 text-xs font-medium',
variant === 'compact' ? 'min-w-[90px]' : 'min-w-[110px]',
)}
>
<Icon name={detail.icon} class="size-3.5 shrink-0" />
{detail.label}
</dt>
<dd class="flex-1 text-sm">
{detail.href ? (
<Link href={detail.href} external underline>
{detail.value}
</Link>
) : (
<span>{detail.value}</span>
)}
</dd>
</div>
))
}
</dl>
{
registration && (
<a
href={registration}
target="_blank"
rel="nofollow noreferrer noopener"
class={cn(
'mt-4 flex items-center justify-center gap-2 rounded-lg px-4 py-2.5 text-sm font-medium transition-all',
'bg-primary text-primary-foreground hover:bg-primary/90',
'focus-visible:ring-ring/50 focus-visible:ring-[3px]',
variant === 'compact' && 'text-xs px-3 py-2',
)}
>
<Icon name="lucide:ticket" class="size-4" />
Register Now
</a>
)
}
<slot />
</div>
|