steelforesight/src/pages/Events/Events.tsx

148 lines
7.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from 'react'
import { events } from '@/data/events'
import type { EventType } from '@/data/events'
import { useLang } from '@/context/LangContext'
type FilterValue = 'all' | EventType
const TYPE_BORDER_COLORS: Record<EventType, string> = {
conference: 'var(--ink)',
exhibition: '#6b4a00',
seminar: '#1a4a2a',
international: 'var(--red)',
}
const TYPE_LABELS = {
fa: { conference: 'کنگره', exhibition: 'نمایشگاه', seminar: 'سمینار', international: 'جهانی' },
en: { conference: 'Conference', exhibition: 'Exhibition', seminar: 'Seminar', international: 'International' },
}
const FILTERS = {
fa: [
{ label: 'همه', value: 'all' as FilterValue },
{ label: 'کنگره', value: 'conference' as FilterValue },
{ label: 'نمایشگاه', value: 'exhibition' as FilterValue },
{ label: 'سمینار', value: 'seminar' as FilterValue },
{ label: 'جهانی', value: 'international' as FilterValue },
],
en: [
{ label: 'All', value: 'all' as FilterValue },
{ label: 'Conference', value: 'conference' as FilterValue },
{ label: 'Exhibition', value: 'exhibition' as FilterValue },
{ label: 'Seminar', value: 'seminar' as FilterValue },
{ label: 'International', value: 'international' as FilterValue },
],
}
const T = {
fa: { heading: 'رویدادهای پیش‌رو', year: '۱۴۰۳–۱۴۰۴', empty: 'رویدادی در این دسته‌بندی یافت نشد' },
en: { heading: 'Upcoming Events', year: '14031404', empty: 'No events found in this category' },
}
function EventCard({ event, lang }: { event: (typeof events)[0]; lang: 'fa' | 'en' }) {
const [hovered, setHovered] = useState(false)
const borderColor = TYPE_BORDER_COLORS[event.type]
const typeLabels = TYPE_LABELS[lang]
return (
<article
style={{ border: '1px solid var(--rule-thin)', background: hovered ? 'var(--paper-2)' : 'var(--paper)', transition: 'background 140ms', display: 'flex', flexDirection: 'column' }}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
>
<div style={{ display: 'flex', borderBottom: '2px solid var(--ink)' }}>
<div style={{ padding: '18px 24px', borderLeft: '1px solid var(--rule-thin)', minWidth: 100, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', background: 'var(--paper)', flexShrink: 0 }}>
<span style={{ fontSize: 52, fontWeight: 900, lineHeight: 1, color: 'var(--ink)', letterSpacing: '-2px', display: 'block' }}>
{event.date.toLocaleString(lang === 'fa' ? 'fa-IR' : 'en-US')}
</span>
<span style={{ fontSize: 11, fontWeight: 500, color: 'var(--ink-4)', marginTop: 4, display: 'block', whiteSpace: 'nowrap' }}>
{event.month} {event.year.toLocaleString(lang === 'fa' ? 'fa-IR' : 'en-US')}
</span>
</div>
<div style={{ flex: 1, padding: '18px 20px', display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 8 }}>
<span style={{ display: 'inline-block', alignSelf: 'flex-start', fontSize: 10, fontWeight: 700, letterSpacing: '1.2px', color: borderColor, border: `1px solid ${borderColor}`, padding: '2px 8px' }}>
{typeLabels[event.type]}
</span>
<h3 style={{ fontSize: 16, fontWeight: 800, lineHeight: 1.45, color: 'var(--ink)', letterSpacing: '-0.3px' }}>{event.title}</h3>
</div>
</div>
<div style={{ padding: '16px 20px', flex: 1, display: 'flex', flexDirection: 'column', gap: 10 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
<span style={{ width: 4, height: 4, background: 'var(--ink-4)', flexShrink: 0, display: 'inline-block' }} />
<span style={{ fontSize: 12, color: 'var(--ink-4)', fontWeight: 400 }}>{event.location}،&nbsp;{event.city}</span>
</div>
<p style={{ fontSize: 13, fontWeight: 300, color: 'var(--ink-3)', lineHeight: 1.8 }}>{event.description}</p>
</div>
<div style={{ borderTop: '1px solid var(--rule-thin)', padding: '12px 20px', display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
{event.registrationOpen ? (
<a href="#" style={{ fontSize: 13, fontWeight: 700, color: 'var(--red)', textDecoration: 'none', display: 'flex', alignItems: 'center', gap: 4 }}>
{lang === 'fa' ? 'ثبت‌نام' : 'Register'}<span style={{ fontSize: 15 }}></span>
</a>
) : (
<span style={{ fontSize: 11, fontWeight: 500, color: 'var(--ink-5)' }}>
{lang === 'fa' ? 'به‌زودی' : 'Coming Soon'}
</span>
)}
</div>
</article>
)
}
export default function Events() {
const { lang } = useLang()
const t = T[lang]
const filters = FILTERS[lang]
const [activeFilter, setActiveFilter] = useState<FilterValue>('all')
const filtered = activeFilter === 'all' ? events : events.filter(e => e.type === activeFilter)
return (
<div style={{ maxWidth: 1280, margin: '0 auto', padding: '64px 48px', direction: lang === 'fa' ? 'rtl' : 'ltr' }}>
<div style={{ display: 'flex', alignItems: 'stretch', borderBottom: '3px solid var(--ink)', marginBottom: 36 }}>
<div style={{ background: 'var(--ink)', padding: '14px 28px', display: 'flex', alignItems: 'center' }}>
<h1 style={{ fontSize: 24, fontWeight: 900, color: 'var(--paper)', letterSpacing: '-0.5px', whiteSpace: 'nowrap' }}>{t.heading}</h1>
</div>
<div style={{ flex: 1 }} />
<div style={{ display: 'flex', alignItems: 'center', padding: '14px 0 14px 4px' }}>
<span style={{ fontSize: 13, fontWeight: 500, color: 'var(--ink-4)' }}>{t.year}</span>
</div>
</div>
<div style={{ display: 'flex', gap: 0, borderBottom: '1px solid var(--rule-thin)', marginBottom: 40, overflowX: 'auto', scrollbarWidth: 'none' }}>
{filters.map(f => {
const isActive = activeFilter === f.value
return (
<button
key={f.value}
onClick={() => setActiveFilter(f.value)}
style={{ padding: '10px 24px', fontSize: 13, fontWeight: isActive ? 700 : 500, border: 'none', background: isActive ? 'var(--ink)' : 'transparent', color: isActive ? 'var(--paper)' : 'var(--ink-4)', cursor: 'pointer', fontFamily: 'inherit', whiteSpace: 'nowrap', flexShrink: 0, transition: 'all 120ms', marginBottom: -1, outline: 'none' }}
>
{f.label}
{f.value !== 'all' && (
<span style={{ marginLeft: 6, fontSize: 10, color: isActive ? 'rgba(244,239,231,0.6)' : 'var(--ink-6)' }}>
({events.filter(e => e.type === f.value).length})
</span>
)}
</button>
)
})}
</div>
<div className="events-grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 1, background: 'var(--rule-thin)' }}>
{filtered.map(event => <EventCard key={event.id} event={event} lang={lang} />)}
{filtered.length % 2 !== 0 && <div style={{ background: 'var(--paper)' }} />}
</div>
{filtered.length === 0 && (
<div style={{ padding: '80px 0', textAlign: 'center', color: 'var(--ink-5)' }}>
<p style={{ fontSize: 15, fontWeight: 300 }}>{t.empty}</p>
</div>
)}
<style>{`@media (max-width: 767px) { .events-grid { grid-template-columns: 1fr !important; } }`}</style>
</div>
)
}