277 lines
13 KiB
TypeScript
277 lines
13 KiB
TypeScript
/* ─────────────────────────────────────────────────────────────
|
|
Radar category-detail pages content layer.
|
|
Each of the 5 "رادار آینده" categories gets its own detail page
|
|
at /radar/:slug with the SAME layout, only the content differs.
|
|
Kept separate from the component so it can be served from the
|
|
panel/API later (replace these objects with a fetch).
|
|
───────────────────────────────────────────────────────────── */
|
|
|
|
import type { RadarCategory } from './radar'
|
|
|
|
export type RadarSlug =
|
|
| 'foresight' // آیندهپژوهی و رصد هوشمند
|
|
| 'market' // بازار و زنجیره فولاد
|
|
| 'sustainability' // پایداری و فولاد سبز
|
|
| 'geopolitics' // ژئوپلیتیک و اقتصاد جهانی
|
|
| 'technology' // فناوری و نوآوری
|
|
|
|
export type RadarCard = {
|
|
id: string
|
|
img: string
|
|
fa: { title: string; excerpt: string; date: string }
|
|
en: { title: string; excerpt: string; date: string }
|
|
}
|
|
|
|
export type RadarCategoryPage = {
|
|
slug: RadarSlug
|
|
/** which RadarCategory(ies) from radar.ts this page draws its card pool from */
|
|
sourceCategories: RadarCategory[]
|
|
fa: {
|
|
label: string // breadcrumb + headings
|
|
latestHeading: string // "تازهترینهای …"
|
|
featured: { title: string; date: string; img: string }
|
|
banner: { kicker: string; title: string; desc: string }
|
|
}
|
|
en: {
|
|
label: string
|
|
latestHeading: string
|
|
featured: { title: string; date: string; img: string }
|
|
banner: { kicker: string; title: string; desc: string }
|
|
}
|
|
}
|
|
|
|
const BOOK_IMG = '/Horizontal_Book_Mockup_6 1.webp'
|
|
|
|
/* ── the 5 pages ─────────────────────────────────────────────── */
|
|
export const RADAR_CATEGORY_PAGES: Record<RadarSlug, RadarCategoryPage> = {
|
|
foresight: {
|
|
slug: 'foresight',
|
|
sourceCategories: ['market', 'tech', 'commodity', 'geo', 'energy'],
|
|
fa: {
|
|
label: 'آیندهپژوهی و رصد هوشمند',
|
|
latestHeading: 'تازهترینهای آیندهپژوهی',
|
|
featured: {
|
|
title: 'طلوع هوشمندی: چگونه هوش مصنوعی، زنجیره ارزش فولاد را بازتعریف میکند؟',
|
|
date: 'اردیبهشت ۱۴۰۵',
|
|
img: '/news/photo-1611974789855-9c2a0a7236a3.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'تحلیل ویژه',
|
|
title: 'نقشه راه آیندهپژوهی صنعت فولاد',
|
|
desc: 'جامعترین گزارش تحلیلی سال پیرامون سناریوهای محتمل برای آینده صنعت فولاد، روندهای نوظهور فناورانه و سیگنالهای راهبردی برای تصمیمسازان.',
|
|
},
|
|
},
|
|
en: {
|
|
label: 'Foresight & Smart Monitoring',
|
|
latestHeading: 'Latest in Foresight',
|
|
featured: {
|
|
title: 'The Dawn of Intelligence: How AI Is Redefining the Steel Value Chain',
|
|
date: 'May 2026',
|
|
img: '/news/photo-1611974789855-9c2a0a7236a3.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'Special Analysis',
|
|
title: 'A Foresight Roadmap for the Steel Industry',
|
|
desc: 'The most comprehensive analytical report of the year on plausible scenarios for the future of steel, emerging tech trends and strategic signals for decision-makers.',
|
|
},
|
|
},
|
|
},
|
|
|
|
market: {
|
|
slug: 'market',
|
|
sourceCategories: ['market', 'commodity'],
|
|
fa: {
|
|
label: 'بازار و زنجیره فولاد',
|
|
latestHeading: 'تازهترینهای بازار و زنجیره فولاد',
|
|
featured: {
|
|
title: 'طلوع هوشمندی: چگونه هوش مصنوعی، زنجیره ارزش فولاد را بازتعریف میکند؟',
|
|
date: 'اردیبهشت ۱۴۰۵',
|
|
img: '/news/photo-1611974789855-9c2a0a7236a3.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'تحلیل ویژه',
|
|
title: 'معماری نوین زنجیره تأمین',
|
|
desc: 'جامعترین گزارش تحلیلی سال پیرامون مسیر تجارت جهانی سنگآهن، تأثیرات قطعی استانداردهای کربنی اروپا (CBAM) و سناریوهای تابآوری برای فولادسازان خاورمیانه.',
|
|
},
|
|
},
|
|
en: {
|
|
label: 'Market & Steel Chain',
|
|
latestHeading: 'Latest in Market & Chain',
|
|
featured: {
|
|
title: 'The Dawn of Intelligence: How AI Is Redefining the Steel Value Chain',
|
|
date: 'May 2026',
|
|
img: '/news/photo-1611974789855-9c2a0a7236a3.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'Special Analysis',
|
|
title: 'A New Supply-Chain Architecture',
|
|
desc: "The most comprehensive analytical report of the year on global iron-ore trade routes, the decisive impact of Europe's carbon standards (CBAM) and resilience scenarios for Middle-Eastern steelmakers.",
|
|
},
|
|
},
|
|
},
|
|
|
|
sustainability: {
|
|
slug: 'sustainability',
|
|
sourceCategories: ['energy', 'commodity'],
|
|
fa: {
|
|
label: 'پایداری و فولاد سبز',
|
|
latestHeading: 'تازهترینهای پایداری و فولاد سبز',
|
|
featured: {
|
|
title: 'هیدروژن سبز؛ سوخت کربنزدایی صنعت فولاد در افق ۲۰۵۰',
|
|
date: 'اردیبهشت ۱۴۰۵',
|
|
img: '/news/photo-1466611653911-95081537e5b7.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'تحلیل ویژه',
|
|
title: 'مسیر کربنزدایی صنعت فولاد',
|
|
desc: 'جامعترین گزارش تحلیلی سال پیرامون فناوریهای احیای مستقیم بر پایه هیدروژن، برق تجدیدپذیر و سناریوهای دستیابی به فولاد بدون کربن تا افق ۲۰۵۰.',
|
|
},
|
|
},
|
|
en: {
|
|
label: 'Sustainability & Green Steel',
|
|
latestHeading: 'Latest in Sustainability',
|
|
featured: {
|
|
title: 'Green Hydrogen: The Decarbonization Fuel of Steel Toward 2050',
|
|
date: 'May 2026',
|
|
img: '/news/photo-1466611653911-95081537e5b7.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'Special Analysis',
|
|
title: 'The Steel Decarbonization Pathway',
|
|
desc: 'The most comprehensive analytical report of the year on hydrogen-based direct reduction, renewable power and scenarios for reaching carbon-free steel by 2050.',
|
|
},
|
|
},
|
|
},
|
|
|
|
geopolitics: {
|
|
slug: 'geopolitics',
|
|
sourceCategories: ['geo', 'market'],
|
|
fa: {
|
|
label: 'ژئوپلیتیک و اقتصاد جهانی',
|
|
latestHeading: 'تازهترینهای ژئوپلیتیک و اقتصاد جهانی',
|
|
featured: {
|
|
title: 'هندسه نوین قدرت؛ ژئوپلیتیک فولاد در جهانی چندقطبی',
|
|
date: 'اردیبهشت ۱۴۰۵',
|
|
img: '/news/photo-1518770660439-4636190af475.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'تحلیل ویژه',
|
|
title: 'ژئوپلیتیک تجارت فولاد',
|
|
desc: 'جامعترین گزارش تحلیلی سال پیرامون تنشهای تجاری، تعرفهها و بازآرایی مسیرهای صادراتی فولاد و پیامد آن بر رقابتپذیری ایران در بازارهای منطقهای.',
|
|
},
|
|
},
|
|
en: {
|
|
label: 'Geopolitics & Global Economy',
|
|
latestHeading: 'Latest in Geopolitics',
|
|
featured: {
|
|
title: 'A New Power Geometry: Steel Geopolitics in a Multipolar World',
|
|
date: 'May 2026',
|
|
img: '/news/photo-1518770660439-4636190af475.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'Special Analysis',
|
|
title: 'The Geopolitics of Steel Trade',
|
|
desc: "The most comprehensive analytical report of the year on trade tensions, tariffs and the realignment of steel export routes, and their fallout for Iran's regional competitiveness.",
|
|
},
|
|
},
|
|
},
|
|
|
|
technology: {
|
|
slug: 'technology',
|
|
sourceCategories: ['tech'],
|
|
fa: {
|
|
label: 'فناوری و نوآوری',
|
|
latestHeading: 'تازهترینهای فناوری و نوآوری',
|
|
featured: {
|
|
title: 'کارخانه هوشمند؛ تحول دیجیتال در خطوط تولید فولاد',
|
|
date: 'اردیبهشت ۱۴۰۵',
|
|
img: '/news/photo-1581092160607-ee22731c9b4e.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'تحلیل ویژه',
|
|
title: 'انقلاب دیجیتال در صنعت فولاد',
|
|
desc: 'جامعترین گزارش تحلیلی سال پیرامون هوش مصنوعی، دوقلوی دیجیتال، اینترنت اشیا صنعتی و اثر اتوماسیون هوشمند بر بهرهوری و کیفیت تولید فولاد.',
|
|
},
|
|
},
|
|
en: {
|
|
label: 'Technology & Innovation',
|
|
latestHeading: 'Latest in Technology',
|
|
featured: {
|
|
title: 'The Smart Factory: Digital Transformation in Steel Production Lines',
|
|
date: 'May 2026',
|
|
img: '/news/photo-1581092160607-ee22731c9b4e.jpg',
|
|
},
|
|
banner: {
|
|
kicker: 'Special Analysis',
|
|
title: 'The Digital Revolution in Steel',
|
|
desc: 'The most comprehensive analytical report of the year on AI, digital twins, industrial IoT and the impact of smart automation on steel productivity and quality.',
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
export const RADAR_SLUGS = Object.keys(RADAR_CATEGORY_PAGES) as RadarSlug[]
|
|
|
|
export { BOOK_IMG }
|
|
|
|
/* ── CMS wiring ─────────────────────────────────────────────────
|
|
Overwrites RADAR_CATEGORY_PAGES from the panel at startup.
|
|
Falls back to the static objects above when the panel is offline.
|
|
──────────────────────────────────────────────────────────────── */
|
|
const PANEL_API =
|
|
(import.meta as ImportMeta & { env?: Record<string, string> }).env?.VITE_PANEL_API ||
|
|
'http://localhost:3001'
|
|
|
|
const VALID_SLUGS = new Set(RADAR_SLUGS)
|
|
const VALID_CATS: RadarCategory[] = ['market', 'tech', 'commodity', 'geo', 'energy']
|
|
const asCats = (v: unknown): RadarCategory[] =>
|
|
Array.isArray(v) ? v.filter((c): c is RadarCategory => VALID_CATS.includes(c as RadarCategory)) : []
|
|
|
|
export async function bootstrapRadarPages(): Promise<void> {
|
|
try {
|
|
const res = await fetch(`${PANEL_API}/api/radar-pages`)
|
|
if (!res.ok) return
|
|
const rows = await res.json()
|
|
if (!Array.isArray(rows) || rows.length === 0) return
|
|
for (const r of rows as Record<string, unknown>[]) {
|
|
const slug = String(r.slug) as RadarSlug
|
|
if (!VALID_SLUGS.has(slug)) continue
|
|
const cats = asCats(r.sourceCategories)
|
|
RADAR_CATEGORY_PAGES[slug] = {
|
|
slug,
|
|
sourceCategories: cats.length ? cats : RADAR_CATEGORY_PAGES[slug].sourceCategories,
|
|
fa: {
|
|
label: String(r.labelFa ?? RADAR_CATEGORY_PAGES[slug].fa.label),
|
|
latestHeading: String(r.latestHeadingFa ?? RADAR_CATEGORY_PAGES[slug].fa.latestHeading),
|
|
featured: {
|
|
title: String(r.featuredTitleFa ?? RADAR_CATEGORY_PAGES[slug].fa.featured.title),
|
|
date: String(r.featuredDateFa ?? RADAR_CATEGORY_PAGES[slug].fa.featured.date),
|
|
img: String(r.featuredImg ?? RADAR_CATEGORY_PAGES[slug].fa.featured.img),
|
|
},
|
|
banner: {
|
|
kicker: String(r.bannerKickerFa ?? RADAR_CATEGORY_PAGES[slug].fa.banner.kicker),
|
|
title: String(r.bannerTitleFa ?? RADAR_CATEGORY_PAGES[slug].fa.banner.title),
|
|
desc: String(r.bannerDescFa ?? RADAR_CATEGORY_PAGES[slug].fa.banner.desc),
|
|
},
|
|
},
|
|
en: {
|
|
label: String(r.labelEn ?? RADAR_CATEGORY_PAGES[slug].en.label),
|
|
latestHeading: String(r.latestHeadingEn ?? RADAR_CATEGORY_PAGES[slug].en.latestHeading),
|
|
featured: {
|
|
title: String(r.featuredTitleEn ?? RADAR_CATEGORY_PAGES[slug].en.featured.title),
|
|
date: String(r.featuredDateEn ?? RADAR_CATEGORY_PAGES[slug].en.featured.date),
|
|
img: String(r.featuredImg ?? RADAR_CATEGORY_PAGES[slug].en.featured.img),
|
|
},
|
|
banner: {
|
|
kicker: String(r.bannerKickerEn ?? RADAR_CATEGORY_PAGES[slug].en.banner.kicker),
|
|
title: String(r.bannerTitleEn ?? RADAR_CATEGORY_PAGES[slug].en.banner.title),
|
|
desc: String(r.bannerDescEn ?? RADAR_CATEGORY_PAGES[slug].en.banner.desc),
|
|
},
|
|
},
|
|
}
|
|
}
|
|
} catch {
|
|
/* panel offline → keep static fallback */
|
|
}
|
|
}
|