feat(core): update
This commit is contained in:
14
app/[lang]/home/layout.js
Normal file
14
app/[lang]/home/layout.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import Header from '@/components/Header'
|
||||||
|
import Footer from '@/components/Footer'
|
||||||
|
|
||||||
|
export default async function HomeLayout({ params, children }) {
|
||||||
|
const { lang } = await params
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header lang={lang} />
|
||||||
|
{children}
|
||||||
|
<Footer lang={lang} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
17
app/[lang]/home/page.js
Normal file
17
app/[lang]/home/page.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import Hero from '@/components/Hero'
|
||||||
|
import Products from '@/components/Products'
|
||||||
|
import Production from '@/components/Production'
|
||||||
|
import About from '@/components/About'
|
||||||
|
|
||||||
|
export default async function Home({ params }) {
|
||||||
|
const { lang } = await params
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="flex h-full w-full flex-col bg-bg-1 scroll-x-hidden">
|
||||||
|
<Hero lang={lang} />
|
||||||
|
<About lang={lang} />
|
||||||
|
<Products lang={lang} />
|
||||||
|
<Production lang={lang} />
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
import '../globals.css'
|
import '../globals.css'
|
||||||
import localFont from 'next/font/local'
|
import localFont from 'next/font/local'
|
||||||
import Header from '@/components/Header'
|
|
||||||
import Footer from '@/components/Footer'
|
|
||||||
import {Providers} from "../providers";
|
import {Providers} from "../providers";
|
||||||
|
|
||||||
|
|
||||||
@@ -55,9 +53,7 @@ export default async function RootLayout({ params, children }) {
|
|||||||
<html lang={lang} dir={lang === "fa" ? "rtl" : "ltr"} className={dana.className + " scroll-smooth"}>
|
<html lang={lang} dir={lang === "fa" ? "rtl" : "ltr"} className={dana.className + " scroll-smooth"}>
|
||||||
<body className="flex flex-col relative h-full w-full max-w-screen">
|
<body className="flex flex-col relative h-full w-full max-w-screen">
|
||||||
<Providers >
|
<Providers >
|
||||||
<Header lang={lang} />
|
|
||||||
{children}
|
{children}
|
||||||
<Footer lang={lang} />
|
|
||||||
</Providers >
|
</Providers >
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
14
app/[lang]/management/layout.js
Normal file
14
app/[lang]/management/layout.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import Header from '@/components/Header'
|
||||||
|
import Footer from '@/components/Footer'
|
||||||
|
|
||||||
|
export default async function ManagementLayout({ params, children }) {
|
||||||
|
const { lang } = await params
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header lang={lang} />
|
||||||
|
{children}
|
||||||
|
<Footer lang={lang} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
113
app/[lang]/page.js
Executable file → Normal file
113
app/[lang]/page.js
Executable file → Normal file
@@ -1,21 +1,108 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
import Hero from '@/components/Hero'
|
function BrandMark() {
|
||||||
import Products from '@/components/Products'
|
return (
|
||||||
import SmartHome from '@/components/SmartHome'
|
<svg
|
||||||
import Production from '@/components/Production'
|
className="h-16 w-16 sm:h-20 sm:w-20"
|
||||||
import About from '@/components/About'
|
viewBox="0 0 80 80"
|
||||||
import BlogPosts from '@/components/BlogPosts'
|
fill="none"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<circle cx="40" cy="40" r="38" stroke="currentColor" strokeOpacity="0.16" />
|
||||||
|
<path
|
||||||
|
d="M40 14C25.64 14 14 25.64 14 40c0 11.55 7.53 21.34 17.95 24.72 3.25 1.05 5.45 4.08 5.45 7.5V75h5.2v-2.78c0-3.42 2.2-6.45 5.45-7.5C58.47 61.34 66 51.55 66 40 66 25.64 54.36 14 40 14Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
<circle cx="40" cy="40" r="13" className="fill-red-700" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default async function Home({ params }) {
|
export async function generateMetadata({ params }) {
|
||||||
const { lang } = await params
|
const { lang } = await params
|
||||||
|
const isFa = lang === 'fa'
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: isFa ? 'بهزودی برمیگردیم | رهاورد' : 'Coming soon | Rahavard',
|
||||||
|
description: isFa
|
||||||
|
? 'وبسایت رهاورد در حال بهروزرسانی است.'
|
||||||
|
: 'The Rahavard website is being updated.',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function ComingSoon({ params }) {
|
||||||
|
const { lang } = await params
|
||||||
|
const isFa = lang === 'fa'
|
||||||
|
const otherLanguage = isFa ? 'en' : 'fa'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex flex-col w-full h-full bg-bg-1 scroll-x-hidden" >
|
<main className="relative isolate flex min-h-screen overflow-hidden bg-[#f4f1eb] text-zinc-900">
|
||||||
<Hero lang={lang}/>
|
<div
|
||||||
<About lang={lang}/>
|
className="pointer-events-none absolute inset-0 opacity-[0.045]"
|
||||||
<Products lang={lang}/>
|
style={{
|
||||||
<Production lang={lang}/>
|
backgroundImage:
|
||||||
{/*<BlogPosts lang={lang}/>*/}
|
'linear-gradient(to right, #18181b 1px, transparent 1px), linear-gradient(to bottom, #18181b 1px, transparent 1px)',
|
||||||
|
backgroundSize: '48px 48px',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="pointer-events-none absolute -left-36 -top-36 h-[30rem] w-[30rem] rounded-full bg-red-700/[0.08] blur-3xl" />
|
||||||
|
<div className="pointer-events-none absolute -bottom-56 -right-40 h-[34rem] w-[34rem] rounded-full bg-zinc-900/[0.07] blur-3xl" />
|
||||||
|
|
||||||
|
<nav className="absolute inset-x-0 top-0 z-10 flex items-center justify-between px-6 py-6 sm:px-10 sm:py-8 lg:px-16">
|
||||||
|
<div className="flex items-center gap-3" aria-label={isFa ? 'رهاورد' : 'Rahavard'}>
|
||||||
|
<span className="h-2.5 w-2.5 rounded-full bg-red-700" />
|
||||||
|
<span className="text-sm font-[4] tracking-[0.18em] sm:text-base">
|
||||||
|
{isFa ? 'رهاورد منیزیم پارسه' : 'RAHAVARD MGP'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<Link
|
||||||
|
href={`/${otherLanguage}`}
|
||||||
|
hrefLang={otherLanguage}
|
||||||
|
className="rounded-full border border-zinc-900/15 bg-white/40 px-4 py-2 text-xs font-[5] backdrop-blur transition-colors hover:border-zinc-900/30 hover:bg-white/70 sm:text-sm"
|
||||||
|
>
|
||||||
|
{isFa ? 'English' : 'فارسی'}
|
||||||
|
</Link>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<section className="relative z-[1] mx-auto flex w-full max-w-6xl flex-col justify-center px-6 pb-24 pt-36 sm:px-10 lg:px-16">
|
||||||
|
<div className="mb-8 flex items-center gap-5 text-zinc-900 sm:mb-10">
|
||||||
|
<BrandMark />
|
||||||
|
<div className="h-px w-16 bg-zinc-900/20 sm:w-28" />
|
||||||
|
<span className="text-xs font-[5] tracking-[0.22em] text-zinc-500 sm:text-sm">
|
||||||
|
{isFa ? 'در حال بهروزرسانی' : 'UNDER CONSTRUCTION'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 className="max-w-4xl text-[clamp(3rem,10vw,7.5rem)] font-[4] leading-[0.95] tracking-[-0.045em]">
|
||||||
|
{isFa ? (
|
||||||
|
<>
|
||||||
|
بهزودی
|
||||||
|
<br />
|
||||||
|
<span className="text-red-700">برمیگردیم.</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
We'll be
|
||||||
|
<br />
|
||||||
|
<span className="text-red-700">back soon.</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div className="mt-9 flex max-w-2xl items-start gap-4 border-t border-zinc-900/15 pt-6 sm:mt-12 sm:gap-6 sm:pt-8">
|
||||||
|
<span className="mt-2 h-2 w-2 shrink-0 rounded-full bg-red-700 shadow-[0_0_0_6px_rgba(185,28,28,0.1)]" />
|
||||||
|
<p className="text-base font-[5] leading-8 text-zinc-600 sm:text-lg">
|
||||||
|
{isFa
|
||||||
|
? 'در حال آمادهسازی تجربهای تازه برای شما هستیم. وبسایت جدید رهاورد بهزودی در دسترس خواهد بود.'
|
||||||
|
: 'We are preparing a new experience for you. The new Rahavard website will be available shortly.'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div className="absolute bottom-7 left-6 right-6 z-10 flex items-end justify-between text-[10px] font-[5] uppercase tracking-[0.16em] text-zinc-500 sm:bottom-9 sm:left-10 sm:right-10 lg:left-16 lg:right-16">
|
||||||
|
<span>{isFa ? 'قم، ایران' : 'Qom, Iran'}</span>
|
||||||
|
<span dir="ltr">© {new Date().getFullYear()} RAHAVARD MGP</span>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,12 @@
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import PicAbout from '../public/PicAbout.png'
|
import PicAbout from '../public/PicAbout.png'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { getPublicContent } from '@/lib/content'
|
||||||
import { aboutImages } from '@/lib/localImages'
|
import { aboutImages } from '@/lib/localImages'
|
||||||
|
|
||||||
async function getData(id) {
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/public/content/index/${id}`)
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error('Failed to fetch data')
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function About({lang}) {
|
export default async function About({lang}) {
|
||||||
|
|
||||||
const data = await getData(lang === 'fa' ? 1 : 2);
|
const data = await getPublicContent(lang);
|
||||||
|
|
||||||
// Add safety checks for data structure
|
// Add safety checks for data structure
|
||||||
if (!data || typeof data !== 'object') {
|
if (!data || typeof data !== 'object') {
|
||||||
@@ -62,7 +53,7 @@ export default async function About({lang}) {
|
|||||||
</p>
|
</p>
|
||||||
<Image alt="" src={PicAbout} className=''/>
|
<Image alt="" src={PicAbout} className=''/>
|
||||||
</div>
|
</div>
|
||||||
<Image alt="" src={aboutImages.primary} width={800} height={800} className='row-span-3 h-full min-h-80 w-full object-cover rounded-xl'/>
|
<Image alt="" src={aboutImages.primary} width={800} height={800} unoptimized className='row-span-3 h-full min-h-80 w-full object-cover rounded-xl'/>
|
||||||
|
|
||||||
<div className='row-span-2 flex flex-col justify-between py-10 px-8 bg-zinc-100 rounded-xl h-full'>
|
<div className='row-span-2 flex flex-col justify-between py-10 px-8 bg-zinc-100 rounded-xl h-full'>
|
||||||
<span className='font-[4] text-xl'>{ data.about2Head?.[0]?.body || '' }</span>
|
<span className='font-[4] text-xl'>{ data.about2Head?.[0]?.body || '' }</span>
|
||||||
@@ -77,7 +68,7 @@ export default async function About({lang}) {
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<Image alt="" src={aboutImages.secondary} width={800} height={800} className='max-h-56 min-h-48 object-cover rounded-xl w-full h-full'/>
|
<Image alt="" src={aboutImages.secondary} width={800} height={800} unoptimized className='max-h-56 min-h-48 object-cover rounded-xl w-full h-full'/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import Crown from '@/components/Crown'
|
import Crown from '@/components/Crown'
|
||||||
|
import { getPublicContent } from '@/lib/content'
|
||||||
|
|
||||||
export function RMGPSVG (){
|
export function RMGPSVG (){
|
||||||
return (
|
return (
|
||||||
@@ -21,19 +22,8 @@ export function RMGPSVG (){
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getData(id) {
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/public/content/index/${id}`)
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error('Failed to fetch data')
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default async function Footer({ lang }){
|
export default async function Footer({ lang }){
|
||||||
const data = await getData(lang === 'fa' ? 1 : 2);
|
const data = await getPublicContent(lang);
|
||||||
|
|
||||||
// Add safety checks for data structure
|
// Add safety checks for data structure
|
||||||
if (!data || typeof data !== 'object') {
|
if (!data || typeof data !== 'object') {
|
||||||
|
|||||||
@@ -54,12 +54,12 @@ export default function Header({ lang = 'fa' }){
|
|||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
const isFa = lang === 'fa'
|
const isFa = lang === 'fa'
|
||||||
const basePath = `/${lang}`
|
const basePath = `/${lang}/home`
|
||||||
const items = [
|
const items = [
|
||||||
{ href: `${basePath}#about`, label: isFa ? 'درباره ما' : 'About' },
|
{ href: `${basePath}#about`, label: isFa ? 'درباره ما' : 'About' },
|
||||||
{ href: `${basePath}#products`, label: isFa ? 'محصولات' : 'Products' },
|
{ href: `${basePath}#products`, label: isFa ? 'محصولات' : 'Products' },
|
||||||
{ href: `${basePath}#production`, label: isFa ? 'تجهیزات' : 'Equipment' },
|
{ href: `${basePath}#production`, label: isFa ? 'تجهیزات' : 'Equipment' },
|
||||||
{ href: `${basePath}/management`, label: isFa ? 'مدیریت' : 'Management' },
|
{ href: `/${lang}/management`, label: isFa ? 'مدیریت' : 'Management' },
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import bg from '../public/bg.webp'
|
import bg from '../public/bg.webp'
|
||||||
import MG from '@/components/MG'
|
import MG from '@/components/MG'
|
||||||
|
import { getPublicContent } from '@/lib/content'
|
||||||
|
|
||||||
export function RMGPSVG (){
|
export function RMGPSVG (){
|
||||||
return (
|
return (
|
||||||
@@ -56,20 +57,9 @@ const circles = (
|
|||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async function getData(id) {
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/public/content/index/${id}`)
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error('Failed to fetch data')
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export default async function Hero({lang}){
|
export default async function Hero({lang}){
|
||||||
|
|
||||||
const data = await getData(lang === 'fa' ? 1 : 2);
|
const data = await getPublicContent(lang);
|
||||||
|
|
||||||
// Add safety checks for data structure
|
// Add safety checks for data structure
|
||||||
if (!data || typeof data !== 'object') {
|
if (!data || typeof data !== 'object') {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export default function ProductCard({ image, desc }) {
|
|||||||
return (
|
return (
|
||||||
<div className="flex w-[230px] shrink-0 flex-col overflow-hidden rounded-lg bg-red-950 sm:w-[270px] lg:w-[300px]" style={{boxShadow : "0px 32px 40px 0px rgba(0, 0, 0, 0.16)"}}>
|
<div className="flex w-[230px] shrink-0 flex-col overflow-hidden rounded-lg bg-red-950 sm:w-[270px] lg:w-[300px]" style={{boxShadow : "0px 32px 40px 0px rgba(0, 0, 0, 0.16)"}}>
|
||||||
<div className="flex aspect-square w-full items-center justify-center bg-white p-4">
|
<div className="flex aspect-square w-full items-center justify-center bg-white p-4">
|
||||||
<Image alt="" src={image} width={500} height={500} className="h-full w-full object-contain object-center"/>
|
<Image alt="" src={image} width={500} height={500} unoptimized className="h-full w-full object-contain object-center"/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-h-24 items-center bg-red-950 p-4 text-sm text-white sm:p-6 sm:text-md">
|
<div className="flex min-h-24 items-center bg-red-950 p-4 text-sm text-white sm:p-6 sm:text-md">
|
||||||
<p className="line-clamp-3">{ desc }</p>
|
<p className="line-clamp-3">{ desc }</p>
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
|
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
|
import { getPublicContent } from '@/lib/content'
|
||||||
import { equipmentImages } from '@/lib/localImages'
|
import { equipmentImages } from '@/lib/localImages'
|
||||||
|
|
||||||
async function getData(id) {
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/public/content/index/${id}`)
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error('Failed to fetch data')
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function Production({ lang }){
|
export default async function Production({ lang }){
|
||||||
|
|
||||||
const data = await getData(lang === 'fa' ? 1 : 2);
|
const data = await getPublicContent(lang);
|
||||||
|
|
||||||
// Add safety checks for data structure
|
// Add safety checks for data structure
|
||||||
if (!data || typeof data !== 'object') {
|
if (!data || typeof data !== 'object') {
|
||||||
@@ -64,14 +55,14 @@ export default async function Production({ lang }){
|
|||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 bg-zinc-100 font-[5] lg:grid-cols-2">
|
<div className="grid grid-cols-1 bg-zinc-100 font-[5] lg:grid-cols-2">
|
||||||
<div className="flex min-h-[220px] w-full overflow-hidden">
|
<div className="flex min-h-[220px] w-full overflow-hidden">
|
||||||
<Image alt="" src={equipmentImages[0]} width={500} height={500} className="min-h-[220px] w-1/2 object-cover"/>
|
<Image alt="" src={equipmentImages[0]} width={500} height={500} unoptimized className="min-h-[220px] w-1/2 object-cover"/>
|
||||||
<div className="flex w-1/2 flex-col justify-center p-4 text-sm sm:p-6 sm:text-base lg:p-10">
|
<div className="flex w-1/2 flex-col justify-center p-4 text-sm sm:p-6 sm:text-base lg:p-10">
|
||||||
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[0]?.body || '' }</span>
|
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[0]?.body || '' }</span>
|
||||||
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[0]?.body || '' }</p>
|
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[0]?.body || '' }</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-h-[220px] w-full flex-row-reverse overflow-hidden lg:flex-row">
|
<div className="flex min-h-[220px] w-full flex-row-reverse overflow-hidden lg:flex-row">
|
||||||
<Image alt="" src={equipmentImages[1]} width={500} height={500} className="min-h-[220px] w-1/2 object-cover"/>
|
<Image alt="" src={equipmentImages[1]} width={500} height={500} unoptimized className="min-h-[220px] w-1/2 object-cover"/>
|
||||||
<div className="flex w-1/2 flex-col justify-center p-4 text-sm sm:p-6 sm:text-base lg:p-10">
|
<div className="flex w-1/2 flex-col justify-center p-4 text-sm sm:p-6 sm:text-base lg:p-10">
|
||||||
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[1]?.body || '' }</span>
|
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[1]?.body || '' }</span>
|
||||||
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[1]?.body || '' }</p>
|
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[1]?.body || '' }</p>
|
||||||
@@ -82,14 +73,14 @@ export default async function Production({ lang }){
|
|||||||
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[2]?.body || '' }</span>
|
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[2]?.body || '' }</span>
|
||||||
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[2]?.body || '' }</p>
|
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[2]?.body || '' }</p>
|
||||||
</div>
|
</div>
|
||||||
<Image alt="" src={equipmentImages[2]} width={500} height={500} className="min-h-[220px] w-1/2 object-cover"/>
|
<Image alt="" src={equipmentImages[2]} width={500} height={500} unoptimized className="min-h-[220px] w-1/2 object-cover"/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-h-[220px] w-full overflow-hidden">
|
<div className="flex min-h-[220px] w-full overflow-hidden">
|
||||||
<div className="flex w-1/2 flex-col justify-center p-4 text-sm sm:p-6 sm:text-base lg:p-10">
|
<div className="flex w-1/2 flex-col justify-center p-4 text-sm sm:p-6 sm:text-base lg:p-10">
|
||||||
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[3]?.body || '' }</span>
|
<span className="pb-4 font-[4] text-xl text-black-1 lg:text-2xl"> { data.equipment3Title?.[3]?.body || '' }</span>
|
||||||
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[3]?.body || '' }</p>
|
<p className="font-[5] text-black-1">{ data.equipment3Desc?.[3]?.body || '' }</p>
|
||||||
</div>
|
</div>
|
||||||
<Image alt="" src={equipmentImages[3]} width={500} height={500} className="min-h-[220px] w-1/2 object-cover"/>
|
<Image alt="" src={equipmentImages[3]} width={500} height={500} unoptimized className="min-h-[220px] w-1/2 object-cover"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
import productbg from '../public/productbg.webp'
|
import productbg from '../public/productbg.webp'
|
||||||
import ProductCard from '@/components/ProductCard'
|
import ProductCard from '@/components/ProductCard'
|
||||||
|
import { getPublicContent } from '@/lib/content'
|
||||||
import { productImages } from '@/lib/localImages'
|
import { productImages } from '@/lib/localImages'
|
||||||
|
|
||||||
async function getData(id) {
|
|
||||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/public/content/index/${id}`)
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error('Failed to fetch data')
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function Products({ lang }){
|
export default async function Products({ lang }){
|
||||||
const data = await getData(lang === 'fa' ? 1 : 2);
|
const data = await getPublicContent(lang);
|
||||||
|
|
||||||
// Add safety checks for data structure
|
// Add safety checks for data structure
|
||||||
if (!data || typeof data !== 'object') {
|
if (!data || typeof data !== 'object') {
|
||||||
@@ -33,7 +24,7 @@ export default async function Products({ lang }){
|
|||||||
<div className="z-10 flex gap-4 overflow-x-auto px-6 py-16 sm:px-10 lg:flex-wrap lg:justify-center lg:gap-6 lg:px-28">
|
<div className="z-10 flex gap-4 overflow-x-auto px-6 py-16 sm:px-10 lg:flex-wrap lg:justify-center lg:gap-6 lg:px-28">
|
||||||
{
|
{
|
||||||
productImages.map((image, index) => (
|
productImages.map((image, index) => (
|
||||||
<ProductCard key={image} image={image} desc={data.productDescs?.[index]?.body || ''} />
|
<ProductCard key={image.src} image={image} desc={data.productDescs?.[index]?.body || ''} />
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
23
lib/content.js
Normal file
23
lib/content.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export async function getPublicContent(lang) {
|
||||||
|
const id = lang === 'fa' ? 1 : 2
|
||||||
|
const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL
|
||||||
|
|
||||||
|
if (!baseUrl) {
|
||||||
|
console.error('NEXT_PUBLIC_API_BASE_URL is not set')
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${baseUrl}/api/public/content/index/${id}`)
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
console.error(`Failed to fetch public content: ${res.status}`)
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch public content', error)
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,33 @@
|
|||||||
|
import aboutMagnesiumRock from '@/public/images/about-magnesium-rock.jpg'
|
||||||
|
import aboutProduction from '@/public/images/about-production.jpg'
|
||||||
|
import equipmentCastingMachine from '@/public/images/equipment-casting-machine.jpg'
|
||||||
|
import equipmentElectrothermLine from '@/public/images/equipment-electrotherm-line.jpg'
|
||||||
|
import equipmentFurnace from '@/public/images/equipment-furnace.jpg'
|
||||||
|
import equipmentPressMachine from '@/public/images/equipment-press-machine.jpg'
|
||||||
|
import productAnodeBars from '@/public/images/product-anode-bars.jpg'
|
||||||
|
import productCncParts from '@/public/images/product-cnc-parts.jpg'
|
||||||
|
import productIngotStack from '@/public/images/product-ingot-stack.jpg'
|
||||||
|
import productMachinedAnodes from '@/public/images/product-machined-anodes.jpg'
|
||||||
|
import productPlates from '@/public/images/product-plates.jpg'
|
||||||
|
import productSacrificialAnodes from '@/public/images/product-sacrificial-anodes.jpg'
|
||||||
|
|
||||||
export const aboutImages = {
|
export const aboutImages = {
|
||||||
primary: "/images/about-production.jpg",
|
primary: aboutProduction,
|
||||||
secondary: "/images/about-magnesium-rock.jpg",
|
secondary: aboutMagnesiumRock,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const productImages = [
|
export const productImages = [
|
||||||
"/images/product-ingot-stack.jpg",
|
productIngotStack,
|
||||||
"/images/product-plates.jpg",
|
productPlates,
|
||||||
"/images/product-anode-bars.jpg",
|
productAnodeBars,
|
||||||
"/images/product-cnc-parts.jpg",
|
productCncParts,
|
||||||
"/images/product-machined-anodes.jpg",
|
productMachinedAnodes,
|
||||||
"/images/product-sacrificial-anodes.jpg",
|
productSacrificialAnodes,
|
||||||
]
|
]
|
||||||
|
|
||||||
export const equipmentImages = [
|
export const equipmentImages = [
|
||||||
"/images/equipment-furnace.jpg",
|
equipmentFurnace,
|
||||||
"/images/equipment-electrotherm-line.jpg",
|
equipmentElectrothermLine,
|
||||||
"/images/equipment-casting-machine.jpg",
|
equipmentCastingMachine,
|
||||||
"/images/equipment-press-machine.jpg",
|
equipmentPressMachine,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -2,23 +2,25 @@ import { match } from '@formatjs/intl-localematcher'
|
|||||||
import Negotiator from 'negotiator'
|
import Negotiator from 'negotiator'
|
||||||
|
|
||||||
// Get the preferred locale, similar to the above or using a library
|
// Get the preferred locale, similar to the above or using a library
|
||||||
let locales = ['en', 'fa']
|
const locales = ['en', 'fa']
|
||||||
function getLocale(request) {
|
|
||||||
let headers = { 'accept-language': 'en-US,en;q=0.5' }
|
function getLocale(request) {
|
||||||
let languages = new Negotiator({ headers }).languages()
|
const hostname = request.headers.get('host')?.split(':')[0]
|
||||||
let defaultLocale = 'en-US';
|
|
||||||
let domains= [
|
if (hostname === 'rahavardmgp.ir' || hostname === 'www.rahavardmgp.ir') {
|
||||||
{
|
return 'fa'
|
||||||
domain: "rahavardmgp.ir",
|
}
|
||||||
defaultLocale: 'fa'
|
|
||||||
},
|
if (hostname === 'rahavardmgp.com' || hostname === 'www.rahavardmgp.com') {
|
||||||
{
|
return 'en'
|
||||||
domain: "rahavardmgp.com",
|
}
|
||||||
defaultLocale: 'en'
|
|
||||||
}
|
const headers = {
|
||||||
]
|
'accept-language': request.headers.get('accept-language') || 'fa'
|
||||||
|
}
|
||||||
return match(languages, locales, defaultLocale, domains) // -> 'en-US'
|
const languages = new Negotiator({ headers }).languages()
|
||||||
|
|
||||||
|
return match(languages, locales, 'fa')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function middleware(request) {
|
export function middleware(request) {
|
||||||
|
|||||||
Reference in New Issue
Block a user