diff --git a/src/components/ui/EventCalendar.tsx b/src/components/ui/EventCalendar.tsx new file mode 100644 index 0000000..cecffe6 --- /dev/null +++ b/src/components/ui/EventCalendar.tsx @@ -0,0 +1,156 @@ +import { useState } from 'react' + +const NAVY = '#032340' +const GOLD = '#CD9E53' +const NEON = '#d4ff2e' // neon yellow for conference-date markers + +type EventItem = { + g: Date // Gregorian date of the event + title: string + city: string + time: string + type: string + color: string +} + +/* steel conferences during اردیبهشت ۱۴۰۵ (anchor month below) */ +const EVENTS: EventItem[] = [ + { g: new Date(2026, 3, 28), title: 'کنفرانس فولاد خاورمیانه', city: 'دبی، امارات', time: '۰۹:۰۰ – ۱۷:۰۰', type: 'کنفرانس بین‌المللی', color: '#9b1c1c' }, + { g: new Date(2026, 4, 5), title: 'نمایشگاه متالکس ۱۴۰۵', city: 'تهران، ایران', time: '۱۰:۰۰ – ۱۸:۰۰', type: 'نمایشگاه', color: GOLD }, + { g: new Date(2026, 4, 12), title: 'نشست تخصصی زنجیره فولاد', city: 'اصفهان، ایران', time: '۱۴:۰۰ – ۱۸:۰۰', type: 'نشست تخصصی', color: '#1e8449' }, + { g: new Date(2026, 4, 18), title: 'وبینار فولاد سبز و کربن‌زدایی', city: 'آنلاین', time: '۱۶:۰۰ – ۱۸:۰۰', type: 'وبینار', color: '#2471a3' }, +] + +const ANCHOR = new Date(2026, 4, 10) // a day inside اردیبهشت ۱۴۰۵ +const J_MONTHS = ['فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند'] +const WEEKDAYS = ['ش', 'ی', 'د', 'س', 'چ', 'پ', 'ج'] // شنبه … جمعه +const faDigits = (n: number) => n.toLocaleString('fa-IR', { useGrouping: false }) + +/* Jalali year/month/day for a Gregorian Date, via the browser's Persian calendar */ +function jParts(d: Date) { + const parts = new Intl.DateTimeFormat('en-US-u-ca-persian', { day: 'numeric', month: 'numeric', year: 'numeric' }).formatToParts(d) + const get = (t: string) => Number(parts.find((p) => p.type === t)?.value) + return { day: get('day'), month: get('month'), year: get('year') } +} + +const sameDay = (a: Date, b: Date) => + a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate() + +function buildMonth(anchor: Date) { + const { month, year } = jParts(anchor) + // walk back to the 1st of this Jalali month + const first = new Date(anchor) + while (jParts(first).day !== 1) first.setDate(first.getDate() - 1) + // collect every day until the Jalali month rolls over + const days: Date[] = [] + const cur = new Date(first) + while (jParts(cur).month === month && jParts(cur).year === year) { + days.push(new Date(cur)) + cur.setDate(cur.getDate() + 1) + } + const firstCol = (first.getDay() + 1) % 7 // Sat→0 … Fri→6 + return { month, year, days, firstCol } +} + +export default function EventCalendar() { + const { month, year, days, firstCol } = buildMonth(ANCHOR) + const [hover, setHover] = useState(null) + + const eventFor = (d: Date) => EVENTS.findIndex((e) => sameDay(e.g, d)) + + return ( +
+ {/* header */} +
+
تقویم رویدادها
+
{J_MONTHS[month - 1]} {faDigits(year)}
+
+ + {/* weekday row */} +
+ {WEEKDAYS.map((w, i) => ( +
{w}
+ ))} +
+ + {/* day grid */} +
+ {Array.from({ length: firstCol }).map((_, i) =>
)} + {days.map((d, i) => { + const j = jParts(d) + const ev = eventFor(d) + const marked = ev >= 0 + const isHover = hover === ev && marked + return ( +
+ + + {/* breathing neon ring on conference days */} + {marked && ( + + )} + + {/* hover card */} + {isHover && ( +
+
+ {EVENTS[ev].type} +
+
{EVENTS[ev].title}
+
+
📅 {faDigits(j.day)} {J_MONTHS[month - 1]} {faDigits(year)}
+
📍 {EVENTS[ev].city}
+
🕐 {EVENTS[ev].time}
+
+ {/* arrow */} + +
+ )} +
+ ) + })} +
+ + {/* legend */} +
+ + روزهای دارای رویداد — نشانگر را نگه دارید +
+ + +
+ ) +} diff --git a/src/pages/Home/sections/MapEventsSection.tsx b/src/pages/Home/sections/MapEventsSection.tsx index 41588a4..a88c3b1 100644 --- a/src/pages/Home/sections/MapEventsSection.tsx +++ b/src/pages/Home/sections/MapEventsSection.tsx @@ -1,18 +1,8 @@ import { Link } from 'react-router-dom' -import { motion } from 'framer-motion' import Globe from '@/components/ui/globe' -import { events } from '@/data/events' +import EventCalendar from '@/components/ui/EventCalendar' import { useLang } from '@/context/LangContext' -const TYPE_COLOR: Record = { - conference: 'var(--ink)', exhibition: '#6b4a00', - seminar: '#1a4a2a', international: 'var(--red)', -} -const TYPE_LABEL = { - fa: { conference: 'کنگره', exhibition: 'نمایشگاه', seminar: 'سمینار', international: 'جهانی' }, - en: { conference: 'Conference', exhibition: 'Exhibition', seminar: 'Seminar', international: 'International' }, -} - const T = { fa: { mapOverline: 'اسکنر جهانی', @@ -33,8 +23,6 @@ const T = { export default function MapEventsSection() { const { lang } = useLang() const t = T[lang] - const typeLabel = TYPE_LABEL[lang] - const displayed = events.slice(0, 5) return (
@@ -58,7 +46,7 @@ export default function MapEventsSection() {
{/* ── 30% · Events ── */} -
+
{t.eventsOverline}
@@ -67,48 +55,8 @@ export default function MapEventsSection() {
-
- {displayed.map((ev, i) => ( - - {/* Date */} -
-
- {ev.date.toLocaleString('fa-IR')} -
-
{ev.month}
-
- - {/* Content */} -
- - {typeLabel[ev.type]} - -
{ev.title}
-
{ev.city}
- {ev.registrationOpen - ? {t.register} - : {t.soon} - } -
-
- ))} +
+