aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/EventDetails.astro
blob: 5923247d26acea82430a3f592ca2eb71b0b8eafe (plain) (blame)
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
---
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
}

interface EventDetailsProps {
  title?: string
  date?: string
  time?: string
  venue?: string
  requirements?: string
  registration?: string
  organiser?: string
  website?: string
  details?: Detail[]
  variant?: 'default' | 'compact'
  class?: 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 },
  registration && { icon: 'lucide:clipboard-check', label: 'Registration', value: registration, href: registration },
  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>

  <slot />
</div>