Navbar restructure, footer redesign, cobe globe, approach section - Navbar: نبض صنعت (->/pulse), رسانه و رویداد dropdown (videocast/sessions/events), generalized NavDropdown; logo -> Frame 2095585206 (2).png - Footer: 3-col RTL layout (brand+socials / nav / contact+badges+newsletter), white logo, gold copyright bar - RadarTechSection: replace tech-frontier with «رویکرد ما» approach cards - MapEventsSection: swap static map for animated cobe WebGL globe (blue theme) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> @
This commit is contained in:
parent
121082abc9
commit
9043f62b27
|
|
@ -12,6 +12,7 @@
|
|||
"@tanstack/react-query": "^5.100.14",
|
||||
"apexcharts": "^5.13.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cobe": "^2.0.1",
|
||||
"dotted-map": "^3.1.0",
|
||||
"framer-motion": "^12.40.0",
|
||||
"gsap": "^3.15.0",
|
||||
|
|
@ -1712,6 +1713,12 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/cobe": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cobe/-/cobe-2.0.1.tgz",
|
||||
"integrity": "sha512-aaa6vcIlaC8C1SF50LDH0Anybo/EAXnrxqe+bwvr4+YUtZydqjeBjTTD7ziCCkbRrRGSns3I3F6cZsf3W+L+ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
|
|
@ -3318,6 +3325,17 @@
|
|||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vazir-font": {
|
||||
"version": "30.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vazir-font/-/vazir-font-30.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
"@tanstack/react-query": "^5.100.14",
|
||||
"apexcharts": "^5.13.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cobe": "^2.0.1",
|
||||
"dotted-map": "^3.1.0",
|
||||
"framer-motion": "^12.40.0",
|
||||
"gsap": "^3.15.0",
|
||||
|
|
|
|||
|
|
@ -1,68 +1,92 @@
|
|||
import { useState } from 'react'
|
||||
import { Send, Share2, AtSign, MessageCircle, MapPin, Phone, Mail } from 'lucide-react'
|
||||
|
||||
function SocialIcon({ label, name, href }: { label: string; name: string; href: string }) {
|
||||
const NAVY = '#071d49'
|
||||
const GOLD = '#c9a227'
|
||||
|
||||
/* round social buttons (gold filled, like the screenshot) */
|
||||
const SOCIALS = [
|
||||
{ Icon: Send, name: 'تلگرام', href: '#' },
|
||||
{ Icon: Share2, name: 'لینکدین', href: '#' },
|
||||
{ Icon: AtSign, name: 'توییتر', href: '#' },
|
||||
{ Icon: MessageCircle, name: 'آپارات', href: '#' },
|
||||
]
|
||||
|
||||
function SocialIcon({ Icon, name, href }: { Icon: typeof Send; name: string; href: string }) {
|
||||
const [hovered, setHovered] = useState(false)
|
||||
return (
|
||||
<a
|
||||
href={href} target="_blank" rel="noopener noreferrer" aria-label={name} title={name}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)}
|
||||
style={{
|
||||
width: 36, height: 36, borderRadius: 8,
|
||||
border: `1px solid ${hovered ? 'rgba(255,255,255,0.4)' : 'rgba(255,255,255,0.15)'}`,
|
||||
background: hovered ? 'rgba(255,255,255,0.08)' : 'transparent',
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
fontSize: 11, fontWeight: 700, textDecoration: 'none',
|
||||
color: hovered ? '#fff' : 'rgba(255,255,255,0.5)',
|
||||
cursor: 'pointer', transition: 'all 150ms', flexShrink: 0,
|
||||
width: 42, height: 42, borderRadius: '50%', flexShrink: 0,
|
||||
background: GOLD, color: NAVY, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
textDecoration: 'none', cursor: 'pointer', transition: 'transform 150ms, opacity 150ms',
|
||||
transform: hovered ? 'translateY(-3px)' : 'none', opacity: hovered ? 0.9 : 1,
|
||||
}}
|
||||
>{label}</a>
|
||||
>
|
||||
<Icon size={19} strokeWidth={2} />
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
const SOCIALS = [
|
||||
{ label: 'in', name: 'لینکدین', href: '#' },
|
||||
{ label: 'X', name: 'توییتر', href: '#' },
|
||||
{ label: 'آپ', name: 'آپارات', href: '#' },
|
||||
{ label: 'tg', name: 'تلگرام', href: '#' },
|
||||
/* center nav — the navbar items */
|
||||
const NAV_LINKS = [
|
||||
{ label: 'رادار آینده', href: '/radar' },
|
||||
{ label: 'آمار و داده', href: '#' },
|
||||
{ label: 'چندرسانهای', href: '#' },
|
||||
{ label: 'در یک نگاه', href: '/at-a-glance' },
|
||||
{ label: 'شبکه خبرگان', href: '#' },
|
||||
{ label: 'درباره ما', href: '#' },
|
||||
]
|
||||
|
||||
function NavItem({ href, label }: { href: string; label: string }) {
|
||||
const [hovered, setHovered] = useState(false)
|
||||
return (
|
||||
<a href={href}
|
||||
onMouseEnter={() => setHovered(true)} onMouseLeave={() => setHovered(false)}
|
||||
style={{
|
||||
display: 'flex', alignItems: 'center', gap: 8, padding: '6px 0',
|
||||
fontSize: 13.5, color: hovered ? '#fff' : 'rgba(255,255,255,0.6)',
|
||||
textDecoration: 'none', transition: 'color 150ms', flexDirection: 'row-reverse', justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
<span style={{ width: 4, height: 4, borderRadius: '50%', background: GOLD, flexShrink: 0 }} />
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
/* contact rows */
|
||||
const CONTACT = [
|
||||
{ Icon: MapPin, label: 'نشانی:', value: 'اصفهان، خیابان سعادتآباد' },
|
||||
{ Icon: Phone, label: 'شماره تماس:', value: '۰۳۱ - ۳۸۸۸۴۵۳۹', ltr: true },
|
||||
{ Icon: Mail, label: 'پست الکترونیک:', value: 'info@steelfutures.com', ltr: true, accent: true },
|
||||
]
|
||||
|
||||
function NewsletterBox() {
|
||||
const [email, setEmail] = useState('')
|
||||
const [done, setDone] = useState(false)
|
||||
return (
|
||||
<div style={{ marginTop: 8 }}>
|
||||
<div style={{
|
||||
fontSize: 11, fontWeight: 700,
|
||||
color: 'rgba(255,255,255,0.4)',
|
||||
letterSpacing: '2px', textTransform: 'uppercase',
|
||||
marginBottom: 12,
|
||||
}}>
|
||||
خبرنامه فولاد آینده
|
||||
</div>
|
||||
<div style={{ display: 'flex', border: '1px solid rgba(255,255,255,0.18)' }}>
|
||||
<div>
|
||||
<div style={{ fontSize: 13, fontWeight: 700, color: '#fff', marginBottom: 12 }}>عضویت در خبرنامه اندیشکده</div>
|
||||
<div style={{ display: 'flex', border: '1px solid rgba(255,255,255,0.18)', borderRadius: 8, overflow: 'hidden', background: 'rgba(255,255,255,0.05)' }}>
|
||||
<input
|
||||
type="email" value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
placeholder="ایمیل خود را وارد کنید..."
|
||||
disabled={done}
|
||||
type="email" value={email} onChange={e => setEmail(e.target.value)}
|
||||
placeholder="ایمیل خود را وارد کنید..." disabled={done}
|
||||
style={{
|
||||
flex: 1, border: 'none', padding: '10px 14px', fontSize: 13,
|
||||
fontFamily: 'inherit', background: 'rgba(255,255,255,0.07)',
|
||||
color: '#fff', outline: 'none', direction: 'rtl', minWidth: 0,
|
||||
flex: 1, border: 'none', padding: '11px 14px', fontSize: 13, fontFamily: 'inherit',
|
||||
background: 'transparent', color: '#fff', outline: 'none', direction: 'rtl', minWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onClick={() => { if (email) setDone(true) }}
|
||||
disabled={done}
|
||||
onClick={() => { if (email) setDone(true) }} disabled={done}
|
||||
style={{
|
||||
background: done ? 'rgba(255,255,255,0.15)' : '#00AEEF',
|
||||
color: '#fff', border: 'none', padding: '10px 16px',
|
||||
fontSize: 12, fontWeight: 700, fontFamily: 'inherit',
|
||||
cursor: done ? 'default' : 'pointer', whiteSpace: 'nowrap', flexShrink: 0,
|
||||
background: GOLD, color: NAVY, border: 'none', padding: '11px 22px',
|
||||
fontSize: 12, fontWeight: 800, fontFamily: 'inherit', cursor: done ? 'default' : 'pointer', whiteSpace: 'nowrap', flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
{done ? '✓ ثبت شد' : 'عضویت'}
|
||||
{done ? '✓ ثبت شد' : 'ثبت'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -71,53 +95,72 @@ function NewsletterBox() {
|
|||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer dir="rtl" style={{ backgroundColor: 'var(--ink)', color: 'rgba(255,255,255,0.6)' }}>
|
||||
<div style={{ maxWidth: 1280, margin: '0 auto', padding: '60px 48px 52px' }}
|
||||
className="max-md:!px-6 max-md:!py-10">
|
||||
<footer dir="rtl" style={{ backgroundColor: NAVY, color: 'rgba(255,255,255,0.6)' }}>
|
||||
<div style={{ maxWidth: 1280, margin: '0 auto', padding: '60px 48px 48px' }} className="max-md:!px-6 max-md:!py-10">
|
||||
|
||||
<div className="grid grid-cols-2 max-md:grid-cols-1 gap-12 max-md:gap-8">
|
||||
<div className="grid grid-cols-[1.3fr_0.8fr_1.2fr] max-lg:grid-cols-2 max-md:grid-cols-1 gap-12 max-md:gap-10">
|
||||
|
||||
{/* ── BRAND (right side in RTL) ── */}
|
||||
<div style={{ textAlign: 'right' }}>
|
||||
<img src="/logo%20white.png" alt="اندیشکده فولاد آینده" style={{ height: 64, width: 'auto', display: 'inline-block', marginBottom: 12 }} />
|
||||
<div style={{ fontSize: 22, fontWeight: 900, color: '#fff', lineHeight: 1.3, marginBottom: 4 }}>اندیشکده فولاد آینده</div>
|
||||
<div style={{ fontSize: 10, letterSpacing: 2, color: 'rgba(255,255,255,0.35)', textTransform: 'uppercase', marginBottom: 18 }}>The Steel Futures Institute</div>
|
||||
|
||||
{/* Brand */}
|
||||
<div>
|
||||
<div style={{ fontSize: 24, fontWeight: 900, color: '#fff', lineHeight: 1.3, marginBottom: 6 }}>
|
||||
اندیشکده فولاد آینده
|
||||
</div>
|
||||
<div style={{
|
||||
fontSize: 10, letterSpacing: 2,
|
||||
color: 'rgba(255,255,255,0.3)',
|
||||
textTransform: 'uppercase',
|
||||
marginBottom: 18,
|
||||
lineHeight: 1.6,
|
||||
}}>
|
||||
The Steel Futures Institute
|
||||
</div>
|
||||
<p style={{
|
||||
fontSize: 14, lineHeight: 2, color: 'rgba(255,255,255,0.6)',
|
||||
maxWidth: 460, margin: '0 0 26px',
|
||||
fontSize: 13, lineHeight: 2, color: 'rgba(255,255,255,0.62)',
|
||||
border: '1px solid rgba(255,255,255,0.15)', borderRadius: 14, padding: '16px 18px', margin: '0 0 26px',
|
||||
}}>
|
||||
فضایی همدلانه برای اندیشیدن به فردای صنعت؛ جایی که دانش، آیندهپژوهی و نوآوری به بینشهایی برای توسعه صنعتی تبدیل میشوند.
|
||||
</p>
|
||||
<div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
|
||||
{SOCIALS.map(s => (
|
||||
<SocialIcon key={s.name} label={s.label} name={s.name} href={s.href} />
|
||||
|
||||
<div style={{ fontSize: 13, fontWeight: 700, color: '#fff', marginBottom: 14 }}>ما را در شبکههای اجتماعی دنبال کنید.</div>
|
||||
<div style={{ display: 'flex', gap: 12, justifyContent: 'flex-start' }}>
|
||||
{SOCIALS.map((s) => (
|
||||
<SocialIcon key={s.name} Icon={s.Icon} name={s.name} href={s.href} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Newsletter */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'flex-start' }}>
|
||||
{/* ── NAV (center) ── */}
|
||||
<nav aria-label="پیوندهای پایین" style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
{NAV_LINKS.map((l) => (
|
||||
<NavItem key={l.label} href={l.href} label={l.label} />
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* ── CONTACT + badges + newsletter (left side in RTL) ── */}
|
||||
<div>
|
||||
<div style={{ fontSize: 14, fontWeight: 800, color: '#fff', marginBottom: 18 }}>اطلاعات تماس</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginBottom: 26 }}>
|
||||
{CONTACT.map((c) => (
|
||||
<div key={c.label} style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 13 }}>
|
||||
<c.Icon size={15} color={GOLD} style={{ flexShrink: 0 }} />
|
||||
<span style={{ color: 'rgba(255,255,255,0.45)' }}>{c.label}</span>
|
||||
<span style={{ color: c.accent ? GOLD : 'rgba(255,255,255,0.75)', direction: c.ltr ? 'ltr' : 'rtl' }}>{c.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* certification badges (placeholders — swap for real images) */}
|
||||
<div style={{ display: 'flex', gap: 12, marginBottom: 26 }}>
|
||||
{[0, 1, 2].map((i) => (
|
||||
<div key={i} style={{ width: 66, height: 66, borderRadius: 10, background: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
|
||||
<span style={{ fontSize: 9, color: 'rgba(7,29,73,0.4)', fontWeight: 700 }}>نشان</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<NewsletterBox />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ borderTop: '1px solid rgba(255,255,255,0.08)' }}>
|
||||
<div style={{ maxWidth: 1280, margin: '0 auto', padding: '20px 48px', textAlign: 'center', fontSize: 13, color: 'rgba(255,255,255,0.7)', lineHeight: 1.8 }}
|
||||
className="max-md:!px-6">
|
||||
<div>تمامی حقوق این وب سایت محفوظ و متعلق به شرکت فولاد مبارکه است.</div>
|
||||
<div style={{ color: 'rgba(255,255,255,0.4)', marginTop: 4, fontSize: 12 }}>
|
||||
با افتخار قدرت گرفته از دیدوان؛ چشم همیشه باز مدیران
|
||||
</div>
|
||||
{/* copyright bar */}
|
||||
<div style={{ background: GOLD, color: NAVY }}>
|
||||
<div style={{ maxWidth: 1280, margin: '0 auto', padding: '14px 48px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap', fontSize: 12, fontWeight: 700 }}
|
||||
className="max-md:!px-6 max-md:!justify-center max-md:!text-center">
|
||||
<span>تمامی حقوق مادی و معنوی این وبسایت برای شرکت فولاد مبارکه اصفهان محفوظ میباشد.</span>
|
||||
<span style={{ opacity: 0.8 }}>طراحی شده توسط شرکت دانشبنیان نواندیشان آتی نگار فرتاک</span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState, useEffect, useRef } from 'react'
|
||||
import type { CSSProperties } from 'react'
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { Search, Menu, X, ChevronDown, Radar, Leaf, Globe, Cpu, BarChart3 } from 'lucide-react'
|
||||
import { Search, Menu, X, ChevronDown, Radar, Leaf, Globe, Cpu, BarChart3, Video, Mic, CalendarDays } from 'lucide-react'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import { useLang } from '@/context/LangContext'
|
||||
|
||||
|
|
@ -17,8 +17,10 @@ const T = {
|
|||
red: 'var(--red)',
|
||||
} as const
|
||||
|
||||
type Section = { fa: string; en: string; to: string; Icon: React.ElementType }
|
||||
|
||||
/* ─── dropdown sections under رادار آینده ─── */
|
||||
const SECTIONS: { fa: string; en: string; to: string; Icon: React.ElementType }[] = [
|
||||
const SECTIONS: Section[] = [
|
||||
{ fa: 'آیندهپژوهی و رصد هوشمند', en: 'Foresight & Intelligence', to: '/radar', Icon: Radar },
|
||||
{ fa: 'پایداری و فولاد سبز', en: 'Sustainability & Green Steel', to: '/sustainability', Icon: Leaf },
|
||||
{ fa: 'ژئوپلیتیک و اقتصاد جهانی', en: 'Geopolitics & Global Economy', to: '/geopolitics', Icon: Globe },
|
||||
|
|
@ -26,11 +28,19 @@ const SECTIONS: { fa: string; en: string; to: string; Icon: React.ElementType }[
|
|||
{ fa: 'بازار و زنجیره فولاد', en: 'Market & Steel Chain', to: '/pulse', Icon: BarChart3 },
|
||||
]
|
||||
|
||||
/* ─── dropdown sections under رسانه و رویداد ─── */
|
||||
const MEDIA: Section[] = [
|
||||
{ fa: 'ویدیوکست و پادکست', en: 'Videocast & Podcast', to: '#', Icon: Video },
|
||||
{ fa: 'نشستهای تخصصی', en: 'Expert Sessions', to: '#', Icon: Mic },
|
||||
{ fa: 'رویدادها', en: 'Events', to: '#', Icon: CalendarDays },
|
||||
]
|
||||
|
||||
/* ─── top-level nav items ─── */
|
||||
const TOP_NAV: { fa: string; en: string; to?: string; dropdown?: boolean }[] = [
|
||||
{ fa: 'رادار آینده', en: 'Radar', dropdown: true },
|
||||
{ fa: 'تحلیلهای استراتژیک', en: 'Strategic Analysis', to: '#' },
|
||||
{ fa: 'چندرسانهای', en: 'Multimedia', to: '#' },
|
||||
type TopNav = { fa: string; en: string; to?: string; dropdown?: 'radar' | 'media' }
|
||||
const TOP_NAV: TopNav[] = [
|
||||
{ fa: 'رادار آینده', en: 'Radar', dropdown: 'radar' },
|
||||
{ fa: 'نبض صنعت', en: 'Industry Pulse', to: '/pulse' },
|
||||
{ fa: 'رسانه و رویداد', en: 'Media & Events', dropdown: 'media' },
|
||||
{ fa: 'در یک نگاه', en: 'At a Glance', to: '/at-a-glance' },
|
||||
{ fa: 'شبکه خبرگان', en: 'Expert Network', to: '#' },
|
||||
{ fa: 'درباره ما', en: 'About', to: '#' },
|
||||
|
|
@ -43,8 +53,8 @@ const META_LEFT: { fa: string; en: string }[] = [
|
|||
{ fa: 'رسانه', en: 'Press' },
|
||||
]
|
||||
|
||||
/* ─── رادار آینده dropdown card ─── */
|
||||
function RadarDropdown({ lang }: { lang: 'fa' | 'en' }) {
|
||||
/* ─── generic nav dropdown card ─── */
|
||||
function NavDropdown({ lang, label, sections }: { lang: 'fa' | 'en'; label: string; sections: Section[] }) {
|
||||
const [open, setOpen] = useState(false)
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
|
|
@ -70,7 +80,7 @@ function RadarDropdown({ lang }: { lang: 'fa' | 'en' }) {
|
|||
borderBottom: open ? `2px solid ${T.red}` : '2px solid transparent',
|
||||
}}
|
||||
>
|
||||
{lang === 'fa' ? 'رادار آینده' : 'Radar'}
|
||||
{label}
|
||||
<ChevronDown size={12} style={{ transform: open ? 'rotate(180deg)' : 'none', transition: 'transform 200ms' }} />
|
||||
</button>
|
||||
|
||||
|
|
@ -92,9 +102,9 @@ function RadarDropdown({ lang }: { lang: 'fa' | 'en' }) {
|
|||
direction: lang === 'fa' ? 'rtl' : 'ltr',
|
||||
}}
|
||||
>
|
||||
{SECTIONS.map((item, i) => (
|
||||
{sections.map((item, i) => (
|
||||
<NavLink
|
||||
key={item.to}
|
||||
key={i}
|
||||
to={item.to}
|
||||
onClick={() => setOpen(false)}
|
||||
style={({ isActive }: { isActive: boolean }): CSSProperties => ({
|
||||
|
|
@ -102,7 +112,7 @@ function RadarDropdown({ lang }: { lang: 'fa' | 'en' }) {
|
|||
padding: '15px 20px', textDecoration: 'none',
|
||||
color: isActive ? T.red : '#3d3d3d',
|
||||
background: isActive ? 'rgba(155,28,28,0.04)' : 'transparent',
|
||||
borderBottom: i < SECTIONS.length - 1 ? '1px solid rgba(7,29,73,0.07)' : 'none',
|
||||
borderBottom: i < sections.length - 1 ? '1px solid rgba(7,29,73,0.07)' : 'none',
|
||||
transition: 'background 100ms', fontSize: 14, fontWeight: 600,
|
||||
})}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLElement).style.background = 'rgba(7,29,73,0.03)' }}
|
||||
|
|
@ -219,7 +229,7 @@ export default function Header() {
|
|||
to="/"
|
||||
style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: 12, textDecoration: 'none', flexShrink: 0, lineHeight: 1 }}
|
||||
>
|
||||
<img src="/logo.png?v=2" alt="" aria-hidden="true"
|
||||
<img src="/Frame%202095585206%20(2).png" alt="" aria-hidden="true"
|
||||
style={{ height: 52, width: 'auto', display: 'block', flexShrink: 0, marginTop: -8 }}
|
||||
className="max-md:h-[40px]"
|
||||
/>
|
||||
|
|
@ -242,7 +252,7 @@ export default function Header() {
|
|||
>
|
||||
{TOP_NAV.map((item) =>
|
||||
item.dropdown
|
||||
? <RadarDropdown key="radar" lang={lang} />
|
||||
? <NavDropdown key={item.fa} lang={lang} label={lang === 'fa' ? item.fa : item.en} sections={item.dropdown === 'radar' ? SECTIONS : MEDIA} />
|
||||
: <PlainNavItem key={item.fa} label={lang === 'fa' ? item.fa : item.en} to={item.to!} />
|
||||
)}
|
||||
</nav>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
import { useEffect, useRef } from 'react'
|
||||
import createGlobe from 'cobe'
|
||||
|
||||
/* Lightweight WebGL globe (cobe) — auto-rotating, blue dotted landmasses with
|
||||
glowing cyan markers, matching the reference. */
|
||||
export default function Globe({ size = 600 }: { size?: number }) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current
|
||||
if (!canvas) return
|
||||
|
||||
let phi = 0
|
||||
let raf = 0
|
||||
let width = canvas.offsetWidth
|
||||
const onResize = () => { width = canvas.offsetWidth }
|
||||
window.addEventListener('resize', onResize)
|
||||
|
||||
const globe = createGlobe(canvas, {
|
||||
devicePixelRatio: 2,
|
||||
width: width * 2,
|
||||
height: width * 2,
|
||||
phi: 0,
|
||||
theta: 0.25,
|
||||
dark: 1,
|
||||
diffuse: 1.4,
|
||||
mapSamples: 18000,
|
||||
mapBrightness: 7,
|
||||
baseColor: [0.06, 0.13, 0.4], // deep blue landmass dots
|
||||
markerColor: [0.22, 0.68, 1], // glowing cyan/blue markers
|
||||
glowColor: [0.18, 0.36, 0.85], // blue atmosphere glow
|
||||
markers: [
|
||||
{ location: [35.69, 51.39], size: 0.10 }, // Tehran
|
||||
{ location: [31.23, 121.47], size: 0.09 }, // Shanghai / Dalian
|
||||
{ location: [33.31, 44.36], size: 0.06 }, // Baghdad / Basra
|
||||
{ location: [51.92, 4.47], size: 0.06 }, // Rotterdam
|
||||
{ location: [25.20, 55.27], size: 0.06 }, // Dubai
|
||||
{ location: [41.01, 28.97], size: 0.06 }, // Istanbul
|
||||
{ location: [19.07, 72.88], size: 0.07 }, // Mumbai
|
||||
{ location: [-23.55, -46.63], size: 0.07 },// São Paulo
|
||||
{ location: [55.75, 37.62], size: 0.06 }, // Moscow
|
||||
{ location: [37.56, 126.97], size: 0.06 }, // Seoul
|
||||
{ location: [-1.29, 36.82], size: 0.06 }, // Nairobi
|
||||
{ location: [40.71, -74.0], size: 0.07 }, // New York
|
||||
],
|
||||
})
|
||||
|
||||
// cobe v2 drives the loop externally via globe.update()
|
||||
const tick = () => {
|
||||
phi += 0.0045
|
||||
globe.update({ phi, width: width * 2, height: width * 2 })
|
||||
raf = requestAnimationFrame(tick)
|
||||
}
|
||||
raf = requestAnimationFrame(tick)
|
||||
requestAnimationFrame(() => { canvas.style.opacity = '1' })
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(raf)
|
||||
globe.destroy()
|
||||
window.removeEventListener('resize', onResize)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div style={{ width: '100%', maxWidth: size, aspectRatio: '1', margin: '0 auto', position: 'relative' }}>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
style={{ width: '100%', height: '100%', contain: 'layout paint size', opacity: 0, transition: 'opacity 1s ease' }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,25 +1,9 @@
|
|||
import { Link } from 'react-router-dom'
|
||||
import { motion } from 'framer-motion'
|
||||
import WorldMap from '@/components/ui/world-map'
|
||||
import Globe from '@/components/ui/globe'
|
||||
import { events } from '@/data/events'
|
||||
import { useLang } from '@/context/LangContext'
|
||||
|
||||
const ROUTES = [
|
||||
{ start: { lat: 35.69, lng: 51.39 }, end: { lat: 33.31, lng: 44.36 } },
|
||||
{ start: { lat: 35.69, lng: 51.39 }, end: { lat: 41.30, lng: 69.24 } },
|
||||
{ start: { lat: 31.23, lng: 121.47 }, end: { lat: 51.92, lng: 4.47 } },
|
||||
{ start: { lat: 31.23, lng: 121.47 }, end: { lat: 6.45, lng: 3.39 } },
|
||||
{ start: { lat: 31.23, lng: 121.47 }, end: { lat: 1.35, lng: 103.82 } },
|
||||
{ start: { lat: 55.75, lng: 37.62 }, end: { lat: 39.91, lng: 116.39 } },
|
||||
{ start: { lat: 55.75, lng: 37.62 }, end: { lat: 35.69, lng: 51.39 } },
|
||||
{ start: { lat: 19.07, lng: 72.88 }, end: { lat: 25.20, lng: 55.27 } },
|
||||
{ start: { lat: 19.07, lng: 72.88 }, end: { lat: -4.05, lng: 39.67 } },
|
||||
{ start: { lat: -23.55, lng: -46.63 }, end: { lat: 31.23, lng: 121.47 } },
|
||||
{ start: { lat: 37.56, lng: 126.97 }, end: { lat: 1.35, lng: 103.82 } },
|
||||
{ start: { lat: 41.01, lng: 28.97 }, end: { lat: 52.52, lng: 13.40 } },
|
||||
{ start: { lat: -33.87, lng: 151.21 }, end: { lat: 31.23, lng: 121.47 } },
|
||||
]
|
||||
|
||||
const TYPE_COLOR: Record<string, string> = {
|
||||
conference: 'var(--ink)', exhibition: '#6b4a00',
|
||||
seminar: '#1a4a2a', international: 'var(--red)',
|
||||
|
|
@ -69,7 +53,7 @@ export default function MapEventsSection() {
|
|||
<p style={{ fontSize: 13, color: 'var(--ink-4)', lineHeight: 1.7, maxWidth: 460 }}>{t.mapSub}</p>
|
||||
</div>
|
||||
<div style={{ padding: '8px 16px 32px' }}>
|
||||
<WorldMap dots={ROUTES} lineColor="#9b1c1c" dotColor="#c8c2bc" />
|
||||
<Globe size={460} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,55 +1,25 @@
|
|||
import { Link } from 'react-router-dom'
|
||||
import { Telescope, Scale, Database, Users, Lightbulb, type LucideIcon } from 'lucide-react'
|
||||
import { useLang } from '@/context/LangContext'
|
||||
import { RadarCard } from '@/pages/Radar/Radar'
|
||||
import { RADAR_ITEMS } from '@/content/radar'
|
||||
|
||||
/* ─── Tech data ──────────────────────────────────────── */
|
||||
const TECHS = {
|
||||
/* ─── رویکرد ما — the institute's approach (new content, not duplicated in the navbar) ─── */
|
||||
type Area = { Icon: LucideIcon; color: string; title: string; desc: string }
|
||||
const RESEARCH_AREAS: Record<'fa' | 'en', Area[]> = {
|
||||
fa: [
|
||||
{
|
||||
num: '۰۱', tag: 'انرژی پاک',
|
||||
title: 'فولاد هیدروژنی (DRI-H₂)',
|
||||
desc: 'جایگزینی کک با هیدروژن سبز در کورههای احیای مستقیم؛ اولین کارخانه تجاری اروپایی در ۲۰۲۴ وارد مرحله تولید شد. ظرفیت تولید ۲.۵ میلیون تن در سال.',
|
||||
img: '/news/photo-1613665813446-82a78c468a1d.jpg',
|
||||
horizon: '۲۰۲۷–۲۰۳۰', accentColor: '#0d6b3e',
|
||||
},
|
||||
{
|
||||
num: '۰۲', tag: 'هوش مصنوعی',
|
||||
title: 'دیجیتالسازی و AI در تولید فولاد',
|
||||
desc: 'یادگیری ماشین در بهینهسازی فرآیند ذوب، کنترل کیفیت آنلاین و پیشبینی خرابی تجهیزات. کاهش ۱۵–۲۰٪ ضایعات و صرفهجویی ۸٪ در مصرف انرژی.',
|
||||
img: '/news/photo-1485827404703-89b55fcc595e.jpg',
|
||||
horizon: '۲۰۲۵–۲۰۲۸', accentColor: '#1a4a7a',
|
||||
},
|
||||
{
|
||||
num: '۰۳', tag: 'فناوری نوین',
|
||||
title: 'الکترولیز اکسید مذاب (MOE)',
|
||||
desc: 'تولید فولاد از طریق الکترولیز مستقیم اکسید آهن با برق تجدیدپذیر — بدون انتشار CO₂. MIT این فناوری را «انقلاب صنعتی بعدی» نامیده است.',
|
||||
img: '/news/photo-1451187580459-43490279c0fa.jpg',
|
||||
horizon: '۲۰۳۰–۲۰۳۵', accentColor: '#6b21a8',
|
||||
},
|
||||
{ Icon: Telescope, color: '#c9a227', title: 'آیندهنگاری علمی', desc: 'بهجای پیشبینی تکنقطهای، با سناریوپردازی و تحلیل روند، چند آیندهٔ محتمل صنعت فولاد را ترسیم میکنیم.' },
|
||||
{ Icon: Database, color: '#2471a3', title: 'تحلیل دادهمحور', desc: 'هر بینش بر پایهٔ دادههای معتبر جهانی و داخلی است، نه گمانهزنی؛ تصمیمسازی با شواهد قابلاتکا.' },
|
||||
{ Icon: Scale, color: '#1e8449', title: 'بیطرفی و استقلال', desc: 'تحلیلهای ما مستقل از منافع کوتاهمدت است؛ شفاف و بدون جانبداری از یک بازیگر خاص.' },
|
||||
{ Icon: Users, color: '#7d3c98', title: 'هماندیشی خبرگان', desc: 'شبکهای از مدیران، پژوهشگران و فعالان صنعت که دانش پراکنده را به بینش جمعی تبدیل میکند.' },
|
||||
{ Icon: Lightbulb, color: '#c0392b', title: 'از تحلیل تا اقدام', desc: 'یافتهها را به راهبردهای عملی و قابلاجرا برای رهبران صنعت ترجمه میکنیم، نه گزارشهای روی طاقچه.' },
|
||||
],
|
||||
en: [
|
||||
{
|
||||
num: '01', tag: 'Clean Energy',
|
||||
title: 'Hydrogen Steel (DRI-H₂)',
|
||||
desc: "Replacing coke with green hydrogen in direct reduction furnaces; Europe's first commercial plant entered production in 2024 with 2.5 million ton annual capacity.",
|
||||
img: '/news/photo-1613665813446-82a78c468a1d.jpg',
|
||||
horizon: '2027–2030', accentColor: '#0d6b3e',
|
||||
},
|
||||
{
|
||||
num: '02', tag: 'Artificial Intelligence',
|
||||
title: 'Digitalization & AI in Steel Production',
|
||||
desc: 'Machine learning for smelting optimization, online quality control, and equipment failure prediction. Cuts waste by 15–20% and energy use by 8%.',
|
||||
img: '/news/photo-1485827404703-89b55fcc595e.jpg',
|
||||
horizon: '2025–2028', accentColor: '#1a4a7a',
|
||||
},
|
||||
{
|
||||
num: '03', tag: 'Emerging Tech',
|
||||
title: 'Molten Oxide Electrolysis (MOE)',
|
||||
desc: 'Producing steel by direct electrolysis of iron oxide using renewable electricity — zero CO₂ emissions. MIT has called it "the next industrial revolution".',
|
||||
img: '/news/photo-1451187580459-43490279c0fa.jpg',
|
||||
horizon: '2030–2035', accentColor: '#6b21a8',
|
||||
},
|
||||
{ Icon: Telescope, color: '#c9a227', title: 'Scientific Foresight', desc: 'Instead of single-point prediction, we map several plausible futures of the steel industry through scenario planning.' },
|
||||
{ Icon: Database, color: '#2471a3', title: 'Data-Driven Analysis', desc: 'Every insight rests on credible global and domestic data — evidence, not guesswork.' },
|
||||
{ Icon: Scale, color: '#1e8449', title: 'Independence & Neutrality', desc: 'Our analysis is independent of short-term interests — transparent and unbiased toward any single actor.' },
|
||||
{ Icon: Users, color: '#7d3c98', title: 'Expert Collaboration', desc: 'A network of executives, researchers and practitioners turning scattered knowledge into collective insight.' },
|
||||
{ Icon: Lightbulb, color: '#c0392b', title: 'From Analysis to Action', desc: 'We translate findings into practical strategies for industry leaders — not shelf-ware reports.' },
|
||||
],
|
||||
}
|
||||
|
||||
|
|
@ -58,26 +28,21 @@ const T = {
|
|||
radarOverline: 'FUTURE RADAR', radarHeading: 'رادار آینده',
|
||||
radarSub: 'سیگنالهای جهانی با اثر مستقیم بر صنعت فولاد ایران',
|
||||
radarAll: 'همه سیگنالها ←',
|
||||
techOverline: 'TECH FRONTIER', techHeading: 'مرز فناوری',
|
||||
techSub: 'فناوریهای نوظهور و افق کاربرد آنها در صنعت فولاد',
|
||||
techAll: 'همه فناوریها ←',
|
||||
horizon: 'افق زمانی',
|
||||
areasOverline: 'OUR APPROACH', areasHeading: 'رویکرد ما',
|
||||
areasSub: 'اصول و روش کار اندیشکده فولاد آینده در تحلیل و آیندهنگاری صنعت',
|
||||
},
|
||||
en: {
|
||||
radarOverline: 'FUTURE RADAR', radarHeading: 'Future Radar',
|
||||
radarSub: 'Global signals with direct impact on Iran\'s steel industry',
|
||||
radarAll: 'All Signals →',
|
||||
techOverline: 'TECH FRONTIER', techHeading: 'Tech Frontier',
|
||||
techSub: 'Emerging technologies and their application horizon in the steel industry',
|
||||
techAll: 'All Technologies →',
|
||||
horizon: 'Horizon',
|
||||
areasOverline: 'OUR APPROACH', areasHeading: 'Our Approach',
|
||||
areasSub: 'How the Steel Futures Institute works — its principles for analysis and foresight',
|
||||
},
|
||||
}
|
||||
|
||||
export default function RadarTechSection() {
|
||||
const { lang } = useLang()
|
||||
const t = T[lang]
|
||||
const techs = TECHS[lang]
|
||||
|
||||
return (
|
||||
<section dir={lang === 'fa' ? 'rtl' : 'ltr'} style={{ background: 'var(--paper-2)' }}>
|
||||
|
|
@ -104,61 +69,43 @@ export default function RadarTechSection() {
|
|||
{/* divider */}
|
||||
<div style={{ height: 1, background: 'var(--rule-thin)' }} />
|
||||
|
||||
{/* ══ مرز فناوری ══ */}
|
||||
{/* ══ حوزههای پژوهشی ══ */}
|
||||
<div style={{ paddingTop: 56, paddingBottom: 64 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 32, flexWrap: 'wrap', gap: 12 }}>
|
||||
<div>
|
||||
<div style={{ fontSize: 9, fontWeight: 700, letterSpacing: '3px', textTransform: 'uppercase', color: 'var(--ink-4)', marginBottom: 6 }}>{t.techOverline}</div>
|
||||
<h2 style={{ fontSize: 'clamp(22px,2.5vw,32px)', fontWeight: 900, color: 'var(--ink)', letterSpacing: '-0.5px', marginBottom: 6 }}>{t.techHeading}</h2>
|
||||
<p style={{ fontSize: 13, color: 'var(--ink-4)' }}>{t.techSub}</p>
|
||||
<div style={{ fontSize: 9, fontWeight: 700, letterSpacing: '3px', textTransform: 'uppercase', color: 'var(--ink-4)', marginBottom: 6 }}>{t.areasOverline}</div>
|
||||
<h2 style={{ fontSize: 'clamp(22px,2.5vw,32px)', fontWeight: 900, color: 'var(--ink)', letterSpacing: '-0.5px', marginBottom: 6 }}>{t.areasHeading}</h2>
|
||||
<p style={{ fontSize: 13, color: 'var(--ink-4)' }}>{t.areasSub}</p>
|
||||
</div>
|
||||
<Link to="/technology" style={{ fontSize: 12, fontWeight: 700, color: 'var(--red)', textDecoration: 'none', whiteSpace: 'nowrap' }}>{t.techAll}</Link>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 max-md:grid-cols-1" style={{ gap: 16 }}>
|
||||
{techs.map((tech, i) => (
|
||||
<div className="grid grid-cols-3 max-md:grid-cols-1 max-lg:grid-cols-2" style={{ gap: 16 }}>
|
||||
{RESEARCH_AREAS[lang].map((a, i) => {
|
||||
const Icon = a.Icon
|
||||
return (
|
||||
<div
|
||||
key={i}
|
||||
style={{
|
||||
background: '#fff', overflow: 'hidden',
|
||||
boxShadow: '0 2px 12px rgba(0,0,0,0.07)',
|
||||
display: 'flex', flexDirection: 'column',
|
||||
transition: 'transform 0.2s, box-shadow 0.2s', cursor: 'pointer',
|
||||
background: '#fff', borderRadius: 16, padding: '26px 24px',
|
||||
boxShadow: '0 2px 12px rgba(0,0,0,0.06)', display: 'flex', flexDirection: 'column', gap: 14,
|
||||
border: '1px solid var(--rule-thin)', transition: 'transform 0.2s, box-shadow 0.2s',
|
||||
}}
|
||||
onMouseEnter={e => { (e.currentTarget as HTMLDivElement).style.transform = 'translateY(-4px)'; (e.currentTarget as HTMLDivElement).style.boxShadow = '0 10px 30px rgba(0,0,0,0.12)' }}
|
||||
onMouseLeave={e => { (e.currentTarget as HTMLDivElement).style.transform = 'translateY(0)'; (e.currentTarget as HTMLDivElement).style.boxShadow = '0 2px 12px rgba(0,0,0,0.07)' }}
|
||||
onMouseEnter={e => { const d = e.currentTarget as HTMLElement; d.style.transform = 'translateY(-4px)'; d.style.boxShadow = '0 14px 34px -18px rgba(7,29,73,0.25)' }}
|
||||
onMouseLeave={e => { const d = e.currentTarget as HTMLElement; d.style.transform = 'translateY(0)'; d.style.boxShadow = '0 2px 12px rgba(0,0,0,0.06)' }}
|
||||
>
|
||||
{/* Image */}
|
||||
<div style={{ position: 'relative', height: 160, overflow: 'hidden' }}>
|
||||
<img src={tech.img} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block', transition: 'transform 0.4s' }}
|
||||
onMouseEnter={e => (e.currentTarget.style.transform = 'scale(1.06)')}
|
||||
onMouseLeave={e => (e.currentTarget.style.transform = 'scale(1)')}
|
||||
/>
|
||||
<div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to top, rgba(0,0,0,0.5) 0%, transparent 60%)' }} />
|
||||
<div style={{
|
||||
position: 'absolute', bottom: 12,
|
||||
right: lang === 'fa' ? 12 : 'auto', left: lang === 'en' ? 12 : 'auto',
|
||||
width: 52, height: 52, borderRadius: 14, flexShrink: 0,
|
||||
background: `${a.color}15`, display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
}}>
|
||||
<span style={{ background: tech.accentColor, color: '#fff', fontSize: 9, fontWeight: 700, padding: '2px 8px', letterSpacing: '1px', textTransform: 'uppercase' }}>{tech.tag}</span>
|
||||
<Icon size={26} color={a.color} strokeWidth={2} />
|
||||
</div>
|
||||
<div style={{
|
||||
position: 'absolute', top: 12,
|
||||
right: lang === 'fa' ? 12 : 'auto', left: lang === 'en' ? 12 : 'auto',
|
||||
fontSize: 36, fontWeight: 900, color: 'rgba(255,255,255,0.25)', direction: 'ltr', lineHeight: 1,
|
||||
}}>{tech.num}</div>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ padding: '20px', flex: 1, display: 'flex', flexDirection: 'column', gap: 10, borderTop: `3px solid ${tech.accentColor}` }}>
|
||||
<h3 style={{ fontSize: 14, fontWeight: 800, color: 'var(--ink)', lineHeight: 1.5 }}>{tech.title}</h3>
|
||||
<p style={{ fontSize: 12, color: 'var(--ink-4)', lineHeight: 1.75, flex: 1 }}>{tech.desc}</p>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 'auto' }}>
|
||||
<span style={{ fontSize: 9, fontWeight: 700, color: 'var(--ink-5)', letterSpacing: '1px', textTransform: 'uppercase' }}>{t.horizon}:</span>
|
||||
<span style={{ fontSize: 11, fontWeight: 700, color: tech.accentColor }}>{tech.horizon}</span>
|
||||
<div>
|
||||
<h3 style={{ fontSize: 16, fontWeight: 900, color: 'var(--ink)', lineHeight: 1.4, margin: '0 0 8px' }}>{a.title}</h3>
|
||||
<p style={{ fontSize: 12.5, color: 'var(--ink-4)', lineHeight: 1.85, margin: 0 }}>{a.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue