Connect Meshkee-managed imagery and publish sitemap metadata
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
e664acb854
commit
00126e5777
+17
-1
@@ -18,7 +18,23 @@ const assetBase = "/assets";
|
||||
export const metadata: Metadata = {
|
||||
title: "درباره سامان اندیش | تجربه تخصصی صنعت سیم و کابل",
|
||||
description:
|
||||
"با تاریخچه، ارزشها و توانمندیهای تخصصی شرکت سامان اندیش در تأمین ماشینآلات صنعت سیم و کابل آشنا شوید.",
|
||||
"با تاریخچه، ارزشها و توانمندیهای سامان اندیش در تأمین ماشینآلات، مواد اولیه و خدمات مهندسی صنعت سیم و کابل، از ارزیابی تا راهاندازی آشنا شوید.",
|
||||
alternates: {
|
||||
canonical: "/about-us",
|
||||
},
|
||||
openGraph: {
|
||||
title: "درباره سامان اندیش | تجربه تخصصی صنعت سیم و کابل",
|
||||
description:
|
||||
"بیش از دو دهه تجربه در تأمین ماشینآلات و ارائه خدمات مهندسی برای خطوط تولید سیم و کابل.",
|
||||
url: "/about-us",
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: "/assets/trEfzlNgmz.jpg",
|
||||
alt: "ماشینآلات صنعت سیم و کابل سامان اندیش",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function AboutUsPage() {
|
||||
|
||||
+17
-1
@@ -16,7 +16,23 @@ const assetBase = "/assets";
|
||||
export const metadata: Metadata = {
|
||||
title: "تماس با سامان اندیش | مشاوره ماشینآلات صنعتی",
|
||||
description:
|
||||
"برای مشاوره خرید ماشینآلات، خدمات فنی و تأمین مواد اولیه صنعت سیم و کابل با کارشناسان سامان اندیش تماس بگیرید.",
|
||||
"برای مشاوره خرید ماشینآلات، دریافت خدمات فنی مهندسی یا تأمین مواد اولیه صنعت سیم و کابل، با کارشناسان تخصصی سامان اندیش در ارتباط باشید.",
|
||||
alternates: {
|
||||
canonical: "/contact-us",
|
||||
},
|
||||
openGraph: {
|
||||
title: "تماس با سامان اندیش | مشاوره ماشینآلات صنعتی",
|
||||
description:
|
||||
"برای انتخاب تجهیزات و راهکار مناسب خط تولید سیم و کابل با کارشناسان سامان اندیش گفتگو کنید.",
|
||||
url: "/contact-us",
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: "/assets/ZLxH2tZ4dR.jpg",
|
||||
alt: "تماس با کارشناسان ماشینآلات صنعتی سامان اندیش",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function ContactUsPage() {
|
||||
|
||||
+43
-4
@@ -326,8 +326,6 @@ button {
|
||||
|
||||
.hero__slide {
|
||||
z-index: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
opacity: 0;
|
||||
transform: scale(1.05);
|
||||
transition:
|
||||
@@ -335,11 +333,32 @@ button {
|
||||
transform 7s ease;
|
||||
}
|
||||
|
||||
.hero__slide > img,
|
||||
.hero__slide-link,
|
||||
.hero__slide-link > img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hero__slide > img,
|
||||
.hero__slide-link > img {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.hero__slide-link {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hero__slide.is-active {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.hero__overlay,
|
||||
.hero__pattern {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero__overlay {
|
||||
z-index: 1;
|
||||
background:
|
||||
@@ -1092,12 +1111,26 @@ button {
|
||||
min-height: 545px;
|
||||
}
|
||||
|
||||
.about__visual > img {
|
||||
.about__visual > img,
|
||||
.about__main-image {
|
||||
width: calc(100% - 85px);
|
||||
height: 495px;
|
||||
}
|
||||
|
||||
.about__visual > img,
|
||||
.about__main-image > img {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.about__main-image > img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.about__main-image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.about__visual::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@@ -1128,6 +1161,11 @@ button {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.about__small-image > a {
|
||||
display: block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.experience-badge {
|
||||
position: absolute;
|
||||
right: 29px;
|
||||
@@ -2015,7 +2053,8 @@ button {
|
||||
min-height: 405px;
|
||||
}
|
||||
|
||||
.about__visual > img {
|
||||
.about__visual > img,
|
||||
.about__main-image {
|
||||
width: calc(100% - 38px);
|
||||
height: 355px;
|
||||
}
|
||||
|
||||
+20
-1
@@ -2,9 +2,28 @@ import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL("https://samanandish.com"),
|
||||
title: "سامان اندیش | ماشینآلات صنعت سیم و کابل",
|
||||
description:
|
||||
"تامین ماشینآلات، مواد اولیه و خدمات فنی مهندسی صنعت سیم و کابل",
|
||||
"سامان اندیش، تأمینکننده تخصصی ماشینآلات، مواد اولیه و خدمات فنی مهندسی صنعت سیم و کابل؛ همراه شما از انتخاب تجهیزات تا نصب و راهاندازی خط تولید.",
|
||||
alternates: {
|
||||
canonical: "/",
|
||||
},
|
||||
openGraph: {
|
||||
title: "سامان اندیش | ماشینآلات صنعت سیم و کابل",
|
||||
description:
|
||||
"تأمین تخصصی ماشینآلات و راهکارهای فنی مهندسی خطوط تولید سیم و کابل، از انتخاب تجهیزات تا نصب و راهاندازی.",
|
||||
url: "/",
|
||||
siteName: "سامان اندیش",
|
||||
locale: "fa_IR",
|
||||
type: "website",
|
||||
images: [
|
||||
{
|
||||
url: "/assets/i8SsUDDMLv.jpg",
|
||||
alt: "ماشینآلات صنعت سیم و کابل سامان اندیش",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
export type StaticImage = {
|
||||
id: number | string;
|
||||
url: string;
|
||||
titleFa?: string | null;
|
||||
titleEn?: string | null;
|
||||
subtext?: string | null;
|
||||
linkUrl?: string | null;
|
||||
width?: number | null;
|
||||
height?: number | null;
|
||||
sortOrder?: number | null;
|
||||
};
|
||||
|
||||
export type StaticImageSlot = {
|
||||
key: string;
|
||||
pageKey: string;
|
||||
kind: "single" | "list";
|
||||
label: string;
|
||||
aspectRatio?: string | null;
|
||||
recommendedWidth?: number | null;
|
||||
itemCount?: number | null;
|
||||
images: StaticImage[];
|
||||
};
|
||||
|
||||
type StaticImageSlotsResponse = {
|
||||
items?: StaticImageSlot[];
|
||||
};
|
||||
|
||||
const API_BASE_URL =
|
||||
process.env.NEXT_PUBLIC_MESHKEE_API_URL?.replace(/\/$/, "") ??
|
||||
"https://api.meshkee.com/api/v1";
|
||||
|
||||
const WEBSITE_DOMAIN =
|
||||
process.env.NEXT_PUBLIC_MESHKEE_DOMAIN ?? "samanandish.com";
|
||||
|
||||
export async function fetchHomeStaticImageSlots(signal?: AbortSignal) {
|
||||
const endpoint = `${API_BASE_URL}/tenants/${encodeURIComponent(WEBSITE_DOMAIN)}/website/static-images?pageKey=home`;
|
||||
const response = await fetch(endpoint, {
|
||||
headers: { Accept: "application/json" },
|
||||
signal,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Static image request failed with ${response.status}`);
|
||||
}
|
||||
|
||||
const payload = (await response.json()) as StaticImageSlotsResponse;
|
||||
return Array.isArray(payload.items) ? payload.items : [];
|
||||
}
|
||||
|
||||
export function cssAspectRatio(value?: string | null) {
|
||||
if (!value || !/^\d+(?:\.\d+)?:\d+(?:\.\d+)?$/.test(value)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return value.replace(":", " / ");
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { readdirSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
export const dynamic = "force-static";
|
||||
export const runtime = "nodejs";
|
||||
|
||||
type StaticPage = {
|
||||
path: string;
|
||||
changefreq: "daily" | "weekly" | "monthly";
|
||||
priority: number;
|
||||
};
|
||||
|
||||
const EXCLUDED_SEGMENTS = new Set([
|
||||
"account",
|
||||
"admin",
|
||||
"api",
|
||||
"auth",
|
||||
"cart",
|
||||
"checkout",
|
||||
"login",
|
||||
"meshkee",
|
||||
"register",
|
||||
]);
|
||||
|
||||
function collectStaticPagePaths(
|
||||
directory: string,
|
||||
routeSegments: string[] = [],
|
||||
): string[] {
|
||||
const entries = readdirSync(directory, { withFileTypes: true });
|
||||
const paths: string[] = [];
|
||||
|
||||
if (entries.some((entry) => entry.isFile() && /^page\.[jt]sx?$/.test(entry.name))) {
|
||||
const path = routeSegments.length ? `/${routeSegments.join("/")}` : "/";
|
||||
paths.push(path);
|
||||
}
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory()) continue;
|
||||
|
||||
const isRouteGroup = entry.name.startsWith("(") && entry.name.endsWith(")");
|
||||
const isPrivateFolder = entry.name.startsWith("_");
|
||||
const isParallelRoute = entry.name.startsWith("@");
|
||||
const isDynamicRoute = entry.name.includes("[");
|
||||
|
||||
if (
|
||||
isPrivateFolder ||
|
||||
isParallelRoute ||
|
||||
isDynamicRoute ||
|
||||
EXCLUDED_SEGMENTS.has(entry.name)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
paths.push(
|
||||
...collectStaticPagePaths(
|
||||
join(directory, entry.name),
|
||||
isRouteGroup ? routeSegments : [...routeSegments, entry.name],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
function toStaticPage(path: string): StaticPage {
|
||||
if (path === "/") {
|
||||
return { path, changefreq: "daily", priority: 1 };
|
||||
}
|
||||
|
||||
if (path === "/about-us") {
|
||||
return { path, changefreq: "monthly", priority: 0.6 };
|
||||
}
|
||||
|
||||
if (path === "/contact-us") {
|
||||
return { path, changefreq: "monthly", priority: 0.5 };
|
||||
}
|
||||
|
||||
return { path, changefreq: "weekly", priority: 0.5 };
|
||||
}
|
||||
|
||||
export function GET() {
|
||||
const baseUrl = (
|
||||
process.env.NEXT_PUBLIC_SITE_URL ||
|
||||
process.env.SITE_URL ||
|
||||
"https://samanandish.com"
|
||||
).replace(/\/$/, "");
|
||||
|
||||
const staticPages = collectStaticPagePaths(join(process.cwd(), "app"))
|
||||
.sort((first, second) => {
|
||||
if (first === "/") return -1;
|
||||
if (second === "/") return 1;
|
||||
return first.localeCompare(second);
|
||||
})
|
||||
.map(toStaticPage);
|
||||
|
||||
return Response.json(
|
||||
{ baseUrl, staticPages },
|
||||
{
|
||||
headers: {
|
||||
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
const slots = [
|
||||
{
|
||||
key: "slider",
|
||||
label: "اسلایدر صفحه اصلی",
|
||||
kind: "list",
|
||||
pageKey: "home",
|
||||
aspectRatio: "17:5",
|
||||
itemCount: null,
|
||||
recommendedWidth: 1920,
|
||||
},
|
||||
{
|
||||
key: "three-categories",
|
||||
label: "سه دستهبندی صفحه اصلی",
|
||||
kind: "list",
|
||||
pageKey: "home",
|
||||
aspectRatio: "3:2",
|
||||
itemCount: 3,
|
||||
recommendedWidth: 900,
|
||||
},
|
||||
{
|
||||
key: "about-us-images",
|
||||
label: "تصاویر درباره ما در صفحه اصلی",
|
||||
kind: "list",
|
||||
pageKey: "home",
|
||||
aspectRatio: "1:1",
|
||||
itemCount: 2,
|
||||
recommendedWidth: 900,
|
||||
},
|
||||
] as const;
|
||||
|
||||
export function GET() {
|
||||
return Response.json(
|
||||
{ slots },
|
||||
{
|
||||
headers: {
|
||||
"Cache-Control": "public, max-age=300, stale-while-revalidate=3600",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
+180
-22
@@ -27,10 +27,24 @@ import {
|
||||
} from "lucide-react";
|
||||
import type { FormEvent } from "react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
cssAspectRatio,
|
||||
fetchHomeStaticImageSlots,
|
||||
type StaticImageSlot,
|
||||
} from "./lib/meshkee";
|
||||
|
||||
const assetBase = "/assets";
|
||||
|
||||
const heroSlides = [
|
||||
type HeroSlide = {
|
||||
image: string;
|
||||
eyebrow: string;
|
||||
title: string;
|
||||
text: string;
|
||||
linkUrl?: string;
|
||||
aspectRatio?: string;
|
||||
};
|
||||
|
||||
const heroSlides: HeroSlide[] = [
|
||||
{
|
||||
image: `${assetBase}/i8SsUDDMLv.jpg`,
|
||||
eyebrow: "WIRE & CABLE MACHINERY",
|
||||
@@ -164,15 +178,83 @@ export default function Home() {
|
||||
const [activeSlide, setActiveSlide] = useState(0);
|
||||
const [query, setQuery] = useState("");
|
||||
const [searchOpen, setSearchOpen] = useState(false);
|
||||
const [staticImageSlots, setStaticImageSlots] = useState<StaticImageSlot[]>([]);
|
||||
const searchInput = useRef<HTMLInputElement>(null);
|
||||
|
||||
const slotsByKey = useMemo(
|
||||
() => new Map(staticImageSlots.map((slot) => [slot.key, slot])),
|
||||
[staticImageSlots],
|
||||
);
|
||||
|
||||
const activeHeroSlides = useMemo<HeroSlide[]>(() => {
|
||||
const slot = slotsByKey.get("slider");
|
||||
if (!slot?.images.length) return heroSlides;
|
||||
|
||||
return slot.images.map((image, index) => {
|
||||
const fallback = heroSlides[index % heroSlides.length];
|
||||
return {
|
||||
image: image.url || fallback.image,
|
||||
eyebrow: image.titleEn || fallback.eyebrow,
|
||||
title: image.titleFa || fallback.title,
|
||||
text: image.subtext || fallback.text,
|
||||
linkUrl: image.linkUrl || undefined,
|
||||
aspectRatio: cssAspectRatio(slot.aspectRatio),
|
||||
};
|
||||
});
|
||||
}, [slotsByKey]);
|
||||
|
||||
const activeCategories = useMemo(() => {
|
||||
const slot = slotsByKey.get("three-categories");
|
||||
return categories.map((fallback, index) => {
|
||||
const image = slot?.images[index];
|
||||
if (!image) {
|
||||
return {
|
||||
...fallback,
|
||||
linkUrl: undefined,
|
||||
aspectRatio: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...fallback,
|
||||
image: image.url || fallback.image,
|
||||
title: image.titleFa || fallback.title,
|
||||
en: image.titleEn || fallback.en,
|
||||
count: image.subtext || fallback.count,
|
||||
linkUrl: image.linkUrl || undefined,
|
||||
aspectRatio: cssAspectRatio(slot?.aspectRatio),
|
||||
};
|
||||
});
|
||||
}, [slotsByKey]);
|
||||
|
||||
const aboutImages = slotsByKey.get("about-us-images");
|
||||
const aboutMainImage = aboutImages?.images[0];
|
||||
const aboutSecondaryImage = aboutImages?.images[1];
|
||||
const activeHeroIndex = activeSlide % activeHeroSlides.length;
|
||||
const activeHero = activeHeroSlides[activeHeroIndex];
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
|
||||
fetchHomeStaticImageSlots(controller.signal)
|
||||
.then(setStaticImageSlots)
|
||||
.catch(() => {
|
||||
// Keep the local image fallbacks when the API is unavailable.
|
||||
});
|
||||
|
||||
return () => controller.abort();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeHeroSlides.length <= 1) return;
|
||||
|
||||
const timer = window.setInterval(
|
||||
() => setActiveSlide((current) => (current + 1) % heroSlides.length),
|
||||
() =>
|
||||
setActiveSlide((current) => (current + 1) % activeHeroSlides.length),
|
||||
6500,
|
||||
);
|
||||
return () => window.clearInterval(timer);
|
||||
}, []);
|
||||
}, [activeHeroSlides.length]);
|
||||
|
||||
const results = useMemo(() => {
|
||||
const normalized = query.trim().toLowerCase();
|
||||
@@ -281,20 +363,32 @@ export default function Home() {
|
||||
</header>
|
||||
|
||||
<section className="hero">
|
||||
{heroSlides.map((slide, index) => (
|
||||
{activeHeroSlides.map((slide, index) => (
|
||||
<div
|
||||
className={`hero__slide ${index === activeSlide ? "is-active" : ""}`}
|
||||
key={slide.image}
|
||||
style={{ backgroundImage: `url("${slide.image}")` }}
|
||||
/>
|
||||
className={`hero__slide ${index === activeHeroIndex ? "is-active" : ""}`}
|
||||
key={`${slide.image}-${index}`}
|
||||
style={{ aspectRatio: slide.aspectRatio }}
|
||||
>
|
||||
{slide.linkUrl ? (
|
||||
<a
|
||||
className="hero__slide-link"
|
||||
href={slide.linkUrl}
|
||||
aria-label={slide.title}
|
||||
>
|
||||
<img src={slide.image} alt={slide.title} />
|
||||
</a>
|
||||
) : (
|
||||
<img src={slide.image} alt={slide.title} />
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div className="hero__overlay" />
|
||||
<div className="hero__pattern" />
|
||||
<div className="container hero__content">
|
||||
<div className="hero__copy">
|
||||
<p className="eyebrow">{heroSlides[activeSlide].eyebrow}</p>
|
||||
<h1>{heroSlides[activeSlide].title}</h1>
|
||||
<p className="hero__description">{heroSlides[activeSlide].text}</p>
|
||||
<p className="eyebrow">{activeHero.eyebrow}</p>
|
||||
<h1>{activeHero.title}</h1>
|
||||
<p className="hero__description">{activeHero.text}</p>
|
||||
<div className="hero__buttons">
|
||||
<a className="button button--red" href="#products">
|
||||
مشاهده محصولات
|
||||
@@ -321,7 +415,8 @@ export default function Home() {
|
||||
<button
|
||||
onClick={() =>
|
||||
setActiveSlide(
|
||||
(activeSlide - 1 + heroSlides.length) % heroSlides.length,
|
||||
(activeHeroIndex - 1 + activeHeroSlides.length) %
|
||||
activeHeroSlides.length,
|
||||
)
|
||||
}
|
||||
aria-label="اسلاید قبلی"
|
||||
@@ -329,17 +424,19 @@ export default function Home() {
|
||||
<ChevronRight />
|
||||
</button>
|
||||
<div>
|
||||
{heroSlides.map((slide, index) => (
|
||||
{activeHeroSlides.map((slide, index) => (
|
||||
<button
|
||||
className={index === activeSlide ? "active" : ""}
|
||||
key={slide.image}
|
||||
className={index === activeHeroIndex ? "active" : ""}
|
||||
key={`${slide.image}-${index}`}
|
||||
onClick={() => setActiveSlide(index)}
|
||||
aria-label={`اسلاید ${index + 1}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setActiveSlide((activeSlide + 1) % heroSlides.length)}
|
||||
onClick={() =>
|
||||
setActiveSlide((activeHeroIndex + 1) % activeHeroSlides.length)
|
||||
}
|
||||
aria-label="اسلاید بعدی"
|
||||
>
|
||||
<ChevronLeft />
|
||||
@@ -401,7 +498,7 @@ export default function Home() {
|
||||
{results.length ? (
|
||||
results.map((product) => (
|
||||
<a href="#products" key={product.id}>
|
||||
<img src={product.image} alt="" />
|
||||
<img src={product.image} alt={product.title} />
|
||||
<div>
|
||||
<strong>{product.title}</strong>
|
||||
<small dir="ltr">{product.en}</small>
|
||||
@@ -428,8 +525,17 @@ export default function Home() {
|
||||
title="سه مسیر، یک راهکار کامل صنعتی"
|
||||
/>
|
||||
<div className="category-grid">
|
||||
{categories.map((category, index) => (
|
||||
<a className="category-card" href="#" key={category.title}>
|
||||
{activeCategories.map((category, index) => (
|
||||
<a
|
||||
className="category-card"
|
||||
href={category.linkUrl || "#"}
|
||||
key={`${category.title}-${index}`}
|
||||
style={
|
||||
category.aspectRatio
|
||||
? { aspectRatio: category.aspectRatio, height: "auto" }
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<img src={category.image} alt={category.title} />
|
||||
<div className="category-card__shade" />
|
||||
<span className="category-card__number">0{index + 1}</span>
|
||||
@@ -487,9 +593,61 @@ export default function Home() {
|
||||
<section className="about" id="about">
|
||||
<div className="container about__grid">
|
||||
<div className="about__visual">
|
||||
<img src={`${assetBase}/trEfzlNgmz.jpg`} alt="تجهیزات صنعتی سامان اندیش" />
|
||||
<div className="about__small-image">
|
||||
<img src={`${assetBase}/rhipZeVqzD.jpg`} alt="ماشینآلات صنعت کابل" />
|
||||
{aboutMainImage?.linkUrl ? (
|
||||
<a
|
||||
className="about__main-image"
|
||||
href={aboutMainImage.linkUrl}
|
||||
style={{
|
||||
aspectRatio: cssAspectRatio(aboutImages?.aspectRatio),
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={aboutMainImage.url}
|
||||
alt={aboutMainImage.titleFa || "تجهیزات صنعتی سامان اندیش"}
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<img
|
||||
src={aboutMainImage?.url || `${assetBase}/trEfzlNgmz.jpg`}
|
||||
alt={aboutMainImage?.titleFa || "تجهیزات صنعتی سامان اندیش"}
|
||||
style={
|
||||
aboutMainImage
|
||||
? {
|
||||
aspectRatio: cssAspectRatio(aboutImages?.aspectRatio),
|
||||
height: "auto",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className="about__small-image"
|
||||
style={
|
||||
aboutSecondaryImage
|
||||
? {
|
||||
aspectRatio: cssAspectRatio(aboutImages?.aspectRatio),
|
||||
height: "auto",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{aboutSecondaryImage?.linkUrl ? (
|
||||
<a href={aboutSecondaryImage.linkUrl}>
|
||||
<img
|
||||
src={aboutSecondaryImage.url}
|
||||
alt={aboutSecondaryImage.titleFa || "ماشینآلات صنعت کابل"}
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<img
|
||||
src={
|
||||
aboutSecondaryImage?.url || `${assetBase}/rhipZeVqzD.jpg`
|
||||
}
|
||||
alt={
|
||||
aboutSecondaryImage?.titleFa || "ماشینآلات صنعت کابل"
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="experience-badge">
|
||||
<strong>۲۵</strong>
|
||||
|
||||
Reference in New Issue
Block a user