create single project page and set blog section in home page

This commit is contained in:
2025-06-19 20:17:15 +03:30
parent e69e2bf7e1
commit d44e8037b1
25 changed files with 423 additions and 109 deletions
+6
View File
@@ -45,6 +45,12 @@ declare const messages: {
"com_home_projects_show_more": "More Projects", "com_home_projects_show_more": "More Projects",
"com_home_projects_details_CTA": "Show Details", "com_home_projects_details_CTA": "Show Details",
"com_home_blog_title": "Our Blog",
"com_home_blog_title_bold": "initiatives",
"com_home_blog_description": "Our blog content",
"com_home_blog_show_more": "More Content",
"com_home_blog_details_CTA": "Show Details",
"footer_title": "Industrial Solutions for a Modern World", "footer_title": "Industrial Solutions for a Modern World",
"footer_description": "We are committed to providing personalized industrial solutions that meet the unique needs of our clients. Our team of experts is dedicated to delivering high-quality products and services that drive success in todays competitive market.", "footer_description": "We are committed to providing personalized industrial solutions that meet the unique needs of our clients. Our team of experts is dedicated to delivering high-quality products and services that drive success in todays competitive market.",
"footer_slogan": "We are committed to providing personalized industrial solutions.", "footer_slogan": "We are committed to providing personalized industrial solutions.",
+6
View File
@@ -42,6 +42,12 @@
"com_home_projects_show_more": "More Projects", "com_home_projects_show_more": "More Projects",
"com_home_projects_details_CTA": "Show Details", "com_home_projects_details_CTA": "Show Details",
"com_home_blog_title": "Our Blog",
"com_home_blog_title_bold": "initiatives",
"com_home_blog_description": "Our blog content",
"com_home_blog_show_more": "More Content",
"com_home_blog_details_CTA": "Show Details",
"footer_title": "Industrial Solutions for a Modern World", "footer_title": "Industrial Solutions for a Modern World",
"footer_description": "We are committed to providing personalized industrial solutions that meet the unique needs of our clients. Our team of experts is dedicated to delivering high-quality products and services that drive success in todays competitive market.", "footer_description": "We are committed to providing personalized industrial solutions that meet the unique needs of our clients. Our team of experts is dedicated to delivering high-quality products and services that drive success in todays competitive market.",
"footer_slogan": "We are committed to providing personalized industrial solutions.", "footer_slogan": "We are committed to providing personalized industrial solutions.",
+2 -2
View File
@@ -13,7 +13,7 @@
"pages_contact_title": "تماس با ما", "pages_contact_title": "تماس با ما",
"pages_product_categories_title": "محصولات", "pages_product_categories_title": "محصولات",
"pages_products_title": "محصولات", "pages_products_title": "محصولات",
"pages_blog_title": "وبلاگ", "pages_blog_title": "مقالات",
"pages_projects_title": "پروژه‌ها", "pages_projects_title": "پروژه‌ها",
"pages_contact_description": "از طریق این صفحه با ما در تماس باشید", "pages_contact_description": "از طریق این صفحه با ما در تماس باشید",
"com_home_banner_title": "نوآوری در تعالی", "com_home_banner_title": "نوآوری در تعالی",
@@ -109,7 +109,7 @@
"page_products_metadata_title": "محصولات", "page_products_metadata_title": "محصولات",
"page_products_metadata_description": "انواع آجرهای سنتی و صنعتی را در این بخش مشاهده کنید؛ مناسب برای پروژه‌های ساختمانی گوناگون.", "page_products_metadata_description": "انواع آجرهای سنتی و صنعتی را در این بخش مشاهده کنید؛ مناسب برای پروژه‌های ساختمانی گوناگون.",
"page_blog_metadata_title": "بلاگ", "page_blog_metadata_title": "مقالات",
"page_blog_metadata_description": "با مقالات، اخبار و آموزش‌های ما در حوزه آجر و مصالح ساختمانی به‌روز بمانید.", "page_blog_metadata_description": "با مقالات، اخبار و آموزش‌های ما در حوزه آجر و مصالح ساختمانی به‌روز بمانید.",
"page_blog_details_CTA": "جزییات مقاله", "page_blog_details_CTA": "جزییات مقاله",
+12 -1
View File
@@ -12,6 +12,17 @@ interface IPageParams extends ILayoutLocaleParams {
id: string; id: string;
} }
export async function generateMetadata({ params }: { params: IPageParams }) {
const { id: postId, locale } = await params;
const t = await getTranslations({ locale });
const postData = await getPost(postId);
return {
title: postData.title,
description: t('page_blog_metadata_description'),
};
}
export default async function PostPage({ params }: { params: IPageParams }) { export default async function PostPage({ params }: { params: IPageParams }) {
const paramsData = await params; const paramsData = await params;
const t = await getTranslations({ locale: paramsData.locale }); const t = await getTranslations({ locale: paramsData.locale });
@@ -32,7 +43,7 @@ export default async function PostPage({ params }: { params: IPageParams }) {
return ( return (
<main className="flex flex-col items-center justify-between"> <main className="flex flex-col items-center justify-between">
<InnerPageBanner <InnerPageBanner
title={t('pages_blog_title')} subtitle={postData.title}
imageSrc={images.blogBanner.src} imageSrc={images.blogBanner.src}
/> />
<div className="container-fluid mx-auto my-12 md:my-24"> <div className="container-fluid mx-auto my-12 md:my-24">
+3 -1
View File
@@ -1,5 +1,6 @@
import Header from '@/components/layout/header'; import Header from '@/components/layout/header';
import AboutTopInfo from '@/components/pages/about/TopInfo'; import AboutTopInfo from '@/components/pages/about/TopInfo';
import HomePageBlog from '@/components/pages/home/HomePageBlog';
import HomeStorySection from '@/components/pages/home/HomeStorySection'; import HomeStorySection from '@/components/pages/home/HomeStorySection';
import HomePageProducts from '@/components/pages/home/Products'; import HomePageProducts from '@/components/pages/home/Products';
import HomePageProjects from '@/components/pages/home/Projects'; import HomePageProjects from '@/components/pages/home/Projects';
@@ -27,7 +28,8 @@ export default async function Home({ params }: { params: IPageParams }) {
<AboutTopInfo /> <AboutTopInfo />
<HomePageProducts locale={locale} /> <HomePageProducts locale={locale} />
<HomePageProjects locale={locale} /> <HomePageProjects locale={locale} />
<HomeStorySection className="my-24 max-lg:my-12" /> <HomeStorySection className="my-12 lg:my-24" />
<HomePageBlog locale={locale} className="my-12 lg:my-24" />
</main> </main>
); );
} }
+59
View File
@@ -0,0 +1,59 @@
import routeFactory from '@/assets/constants/routeFactory';
import images from '@/assets/images/images';
import Breadcrumb from '@/components/layout/breadcrumb';
import { IBreadcrumbItem } from '@/components/layout/breadcrumb/breadcrumb';
import ContentGenerator from '@/components/layout/contentGenerator';
import InnerPageBanner from '@/components/layout/innerPages/banner';
import { ILayoutLocaleParams } from '@/models/layout';
import { getProject } from '@/services/projects';
import { getTranslations } from 'next-intl/server';
interface IPageParams extends ILayoutLocaleParams {
id: string;
}
export async function generateMetadata({ params }: { params: IPageParams }) {
const { id: projectId, locale } = await params;
const t = await getTranslations({ locale });
const project = await getProject(projectId);
return {
title: project.title,
description: t('page_blog_metadata_description'),
};
}
export default async function ProjectPage({ params }: { params: IPageParams }) {
const paramsData = await params;
const t = await getTranslations({ locale: paramsData.locale });
const { id: projectId, locale } = await params;
const routes = routeFactory(t, locale);
const project = await getProject(projectId);
const breadcrumbItems = [
{
...routes.projects,
href: routes.projects.route(),
},
{ title: project?.title },
] as IBreadcrumbItem[];
return (
<main className="flex flex-col items-center justify-between">
<InnerPageBanner
subtitle={project.title}
imageSrc={images.projectImg_1.src}
/>
<div className="container-fluid mx-auto my-12 md:my-24">
<Breadcrumb items={breadcrumbItems} />
{project.content && project.content.length ? (
<ContentGenerator data={project.content} className="mt-10" />
) : (
<></>
)}
</div>
</main>
);
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { IProjectCardProps } from '@/app/api/projects/data'; import { IProjectData } from '@/app/api/projects/data';
import routeFactory from '@/assets/constants/routeFactory'; import routeFactory from '@/assets/constants/routeFactory';
import images from '@/assets/images/images'; import images from '@/assets/images/images';
import InnerPageBanner from '@/components/layout/innerPages/banner'; import InnerPageBanner from '@/components/layout/innerPages/banner';
-1
View File
@@ -1,4 +1,3 @@
import images from '@/assets/images/images';
import { IDynamicContent } from '@/models/dynamicContent'; import { IDynamicContent } from '@/models/dynamicContent';
export interface IPostThumbResponseData { export interface IPostThumbResponseData {
@@ -7,7 +7,7 @@ import {
zardCategoryProducts, zardCategoryProducts,
} from './productsSeparatedByCode'; } from './productsSeparatedByCode';
const productsRelatedByCategory = { export const productsRelatedByCategory = {
'1': ghazaghiCategoryProducts, '1': ghazaghiCategoryProducts,
'2': ghermezCategoryProducts, '2': ghermezCategoryProducts,
'3': zardCategoryProducts, '3': zardCategoryProducts,
@@ -4,14 +4,6 @@ import { NextResponse, NextRequest } from 'next/server';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
import { productCategoriesData } from '../data'; import { productCategoriesData } from '../data';
interface IContext {
params: {
id: string;
};
}
interface IParams {}
export async function GET(request: NextRequest, context: any) { export async function GET(request: NextRequest, context: any) {
const cookieStore = await cookies(); const cookieStore = await cookies();
const lang = cookieStore.get('locale')?.value || 'en'; const lang = cookieStore.get('locale')?.value || 'en';
+2 -12
View File
@@ -127,16 +127,6 @@ interface APIProductCategoryEntity {
fa_priceTypeTitle?: string; fa_priceTypeTitle?: string;
bestForTitle: string; bestForTitle: string;
fa_bestForTitle?: string; fa_bestForTitle?: string;
fa_description?: `Facing Bricks: Characteristics and Features fa_description?: string;
Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions. description?: string;
Facing Bricks: Characteristics and Features
Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions.
Facing Bricks: Characteristics and Features`;
description?: `Facing Bricks: Characteristics and Features
Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions.
Facing Bricks: Characteristics and Features
Facing bricks, also known as face bricks or veneer bricks, are specially designed for visible areas of a building, primarily the exterior facades, but also for interior walls where aesthetics are important. Unlike common bricks which are often covered by plaster or other materials, facing bricks are chosen for their visual appeal and ability to withstand environmental conditions.
Facing Bricks: Characteristics and Features`;
} }
+14 -9
View File
@@ -2,6 +2,18 @@ import { NextResponse } from 'next/server';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
import { APIProductCategoryEntity } from '@/models/api'; import { APIProductCategoryEntity } from '@/models/api';
import { productCategoriesData } from './data'; import { productCategoriesData } from './data';
import { productsRelatedByCategory } from './[id]/products/data';
const getTypesCount = (categoryId: string) =>
productsRelatedByCategory[categoryId]?.length || 0;
const setRelatedLocaleData = (productCategory: APIProductCategoryEntity) => ({
title: productCategory.fa_title || productCategory.title,
priceTypeTitle:
productCategory.fa_priceTypeTitle || productCategory.priceTypeTitle,
bestForTitle: productCategory.fa_bestForTitle || productCategory.bestForTitle,
description: productCategory.fa_description || productCategory.description,
});
export async function GET(request: Request) { export async function GET(request: Request) {
try { try {
@@ -10,18 +22,11 @@ export async function GET(request: Request) {
const cookieStore = await cookies(); const cookieStore = await cookies();
const lang = (await cookieStore).get('locale')?.value || 'en'; const lang = (await cookieStore).get('locale')?.value || 'en';
if (lang === 'fa') {
data = productCategoriesData.map((productCategory) => ({ data = productCategoriesData.map((productCategory) => ({
...productCategory, ...productCategory,
title: (lang && productCategory.fa_title) || productCategory.title, ...(lang === 'fa' ? setRelatedLocaleData(productCategory) : {}),
priceTypeTitle: typesCount: getTypesCount(productCategory.id),
productCategory.fa_priceTypeTitle || productCategory.priceTypeTitle,
bestForTitle:
productCategory.fa_bestForTitle || productCategory.bestForTitle,
description:
productCategory.fa_description || productCategory.description,
})); }));
}
return NextResponse.json({ data }); return NextResponse.json({ data });
} catch (error) { } catch (error) {
+28
View File
@@ -0,0 +1,28 @@
import { NextResponse } from 'next/server';
import { cookies } from 'next/headers';
import { projects } from '../data';
export async function GET(request: Request, context: any) {
const params = await context.params;
const projectId = params.id;
const cookieStore = await cookies();
const lang = cookieStore.get('locale')?.value || 'en';
let project = projects.find((project) => project.id === projectId);
if (!project) {
return NextResponse.json({ error: 'Not found' }, { status: 404 });
}
if (lang === 'fa') {
project = {
...project,
title: project.fa_title || project.title,
content: project.fa_content || project.content,
};
}
return NextResponse.json({
data: project,
});
}
+22 -3
View File
@@ -1,10 +1,23 @@
import images from '@/assets/images/images'; import images from '@/assets/images/images';
import { tempContent } from '@/assets/temp/tempContent';
import { IDynamicContent } from '@/models/dynamicContent';
export interface IProjectCardProps { export interface IProjectData {
id: string; id: string;
title: string; title: string;
fa_title?: string; fa_title?: string;
imageSrc: string; imageSrc: string;
content: IDynamicContent[];
fa_content: IDynamicContent[];
}
export interface IProjectThumbResponseData {
id: string;
title: string;
imageSrc: string;
}
export interface IProjectResponseData extends IProjectThumbResponseData {
content: IDynamicContent[];
} }
export const projects = [ export const projects = [
@@ -13,40 +26,46 @@ export const projects = [
title: 'Sustainable Practices Reducing Waste in Industrial Production', title: 'Sustainable Practices Reducing Waste in Industrial Production',
fa_title: 'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی', fa_title: 'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
imageSrc: `/images/project1.jpeg`, imageSrc: `/images/project1.jpeg`,
...tempContent,
}, },
{ {
id: '2', id: '2',
title: 'Advanced Robotics Revolutionizing Industrial Workflows', title: 'Advanced Robotics Revolutionizing Industrial Workflows',
fa_title: 'رباتیک پیشرفته و تحول فرآیندهای صنعتی', fa_title: 'رباتیک پیشرفته و تحول فرآیندهای صنعتی',
imageSrc: `/images/project2.jpeg`, imageSrc: `/images/project2.jpeg`,
...tempContent,
}, },
{ {
id: '3', id: '3',
title: 'Top Benefits of the Robotics in Manufacturing', title: 'Top Benefits of the Robotics in Manufacturing',
fa_title: 'مزایای اصلی استفاده از رباتیک در تولید', fa_title: 'مزایای اصلی استفاده از رباتیک در تولید',
imageSrc: `/images/project3.jpeg`, imageSrc: `/images/project3.jpeg`,
...tempContent,
}, },
{ {
id: '4', id: '4',
title: 'Leveraging Data Analytics for Smarter Production', title: 'Leveraging Data Analytics for Smarter Production',
fa_title: 'استفاده از تحلیل داده برای تولید هوشمندتر', fa_title: 'استفاده از تحلیل داده برای تولید هوشمندتر',
imageSrc: `/images/project4.jpeg`, imageSrc: `/images/project4.jpeg`,
...tempContent,
}, },
{ {
id: '5', id: '5',
title: 'Reducing Operational Costs Through Automation', title: 'Reducing Operational Costs Through Automation',
fa_title: 'کاهش هزینه‌ها با اتوماسیون', fa_title: 'کاهش هزینه‌ها با اتوماسیون',
imageSrc: `/images/project1.jpeg`, imageSrc: `/images/project1.jpeg`,
...tempContent,
}, },
{ {
id: '6', id: '6',
title: 'The Advantages of Customized Manufacturing Solutions', title: 'The Advantages of Customized Manufacturing Solutions',
fa_title: 'مزایای راه‌حل‌های سفارشی‌سازی در تولید', fa_title: 'مزایای راه‌حل‌های سفارشی‌سازی در تولید',
imageSrc: `/images/project1.jpeg`, imageSrc: `/images/project1.jpeg`,
...tempContent,
}, },
] as IProjectCardProps[]; ] as IProjectData[];
export function generateProjects(): IProjectCardProps[] { export function generateProjects(): IProjectData[] {
return [...projects, ...projects, ...projects, ...projects, ...projects].map( return [...projects, ...projects, ...projects, ...projects, ...projects].map(
(e, i) => ({ (e, i) => ({
...e, ...e,
+16 -12
View File
@@ -1,10 +1,14 @@
import { NextResponse } from 'next/server'; import { NextResponse } from 'next/server';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
import { generateProjects } from './data'; import {
generateProjects,
IProjectData,
IProjectThumbResponseData,
} from './data';
export async function GET(request: Request) { export async function GET(request: Request) {
let projects = generateProjects(); let projects = generateProjects();
let data = projects; let data = projects as IProjectThumbResponseData[];
const cookieStore = await cookies(); const cookieStore = await cookies();
const lang = (await cookieStore).get('lang')?.value || 'fa'; const lang = (await cookieStore).get('lang')?.value || 'fa';
@@ -19,20 +23,20 @@ export async function GET(request: Request) {
const end = start + perPage; const end = start + perPage;
const paginatedProjects = projects.slice(start, end); const paginatedProjects = projects.slice(start, end);
if (lang === 'fa') { const setRelatedLocaleData = (project: IProjectData) => ({
data = paginatedProjects.map((project) => {
if (lang === 'fa') {
return {
...project,
title: project.fa_title || project.title, title: project.fa_title || project.title,
};
}
return project;
}); });
}
data = paginatedProjects.map((project) => ({
id: project.id,
imageSrc: project.imageSrc,
...(lang === 'fa'
? setRelatedLocaleData(project)
: { title: project.title }),
}));
return NextResponse.json({ return NextResponse.json({
data: data, data,
pagination: { pagination: {
page, page,
perPage, perPage,
@@ -6,6 +6,7 @@ type RouteFactory = (
productCategories: { title: string; route: () => string }; productCategories: { title: string; route: () => string };
products: { title: string; route: (productId: string) => string }; products: { title: string; route: (productId: string) => string };
projects: { title: string; route: () => string }; projects: { title: string; route: () => string };
project: { title: string; route: (projectId: string) => string };
about: { title: string; route: () => string }; about: { title: string; route: () => string };
blog: { title: string; route: () => string }; blog: { title: string; route: () => string };
singlePost: { title: string; route: (postId: string) => string }; singlePost: { title: string; route: (postId: string) => string };
@@ -29,6 +30,10 @@ const routeFactory: RouteFactory = (t, locale) => ({
title: t('pages_projects_title'), title: t('pages_projects_title'),
route: () => `/${locale}/projects`, route: () => `/${locale}/projects`,
}, },
project: {
title: '',
route: (projectId: string) => `/${locale}/projects/${projectId}`,
},
about: { about: {
title: t('pages_about_title'), title: t('pages_about_title'),
route: () => `/${locale}/about-us`, route: () => `/${locale}/about-us`,
+97
View File
@@ -0,0 +1,97 @@
export const tempContent = {
content: [
{
type: 'title',
data: 'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
},
{
type: 'content',
data: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است.',
},
{
type: 'bullet',
data: [
'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
'رباتیک پیشرفته و تحول فرآیندهای صنعتی',
'مزایای اصلی استفاده از رباتیک در تولید',
'استفاده از تحلیل داده برای تولید هوشمندتر',
'کاهش هزینه‌ها با اتوماسیون',
'مزایای راه‌حل‌های سفارشی‌سازی در تولید',
],
},
{
type: 'image',
data: {
src: '/images/project2.jpeg',
alt: '',
thumbTitle:
'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است.',
},
},
{
type: 'numberList',
data: [
'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
'رباتیک پیشرفته و تحول فرآیندهای صنعتی',
'مزایای اصلی استفاده از رباتیک در تولید',
'استفاده از تحلیل داده برای تولید هوشمندتر',
'کاهش هزینه‌ها با اتوماسیون',
'مزایای راه‌حل‌های سفارشی‌سازی در تولید',
],
},
],
fa_content: [
{
type: 'title',
data: 'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
},
{
type: 'content',
data: {
links: [
{
link: '/',
key: '_link',
label: 'ایپسوم',
},
],
data: 'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم\n متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم _link متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده\n از طراحان گرافیک است. لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است.',
},
},
{
type: 'bullet',
data: [
'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
'رباتیک پیشرفته و تحول فرآیندهای صنعتی',
'مزایای اصلی استفاده از رباتیک در تولید',
'استفاده از تحلیل داده برای تولید هوشمندتر',
'کاهش هزینه‌ها با اتوماسیون',
'مزایای راه‌حل‌های سفارشی‌سازی در تولید',
],
},
{
type: 'image',
data: {
src: '/images/project1.jpeg',
alt: '',
thumbTitle:
'لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک است.',
},
},
{
type: 'title',
data: 'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
},
{
type: 'numberList',
data: [
'روش‌های پایدار برای کاهش ضایعات در تولید صنعتی',
'رباتیک پیشرفته و تحول فرآیندهای صنعتی',
'مزایای اصلی استفاده از رباتیک در تولید',
'استفاده از تحلیل داده برای تولید هوشمندتر',
'کاهش هزینه‌ها با اتوماسیون',
'مزایای راه‌حل‌های سفارشی‌سازی در تولید',
],
},
],
};
+2 -1
View File
@@ -1,4 +1,5 @@
export interface IInnerPageBannerProps { export interface IInnerPageBannerProps {
imageSrc: string; imageSrc: string;
title: string; title?: string;
subtitle?: string;
} }
@@ -4,6 +4,7 @@ import { IInnerPageBannerProps } from './banner';
export default function InnerPageBanner({ export default function InnerPageBanner({
title, title,
imageSrc, imageSrc,
subtitle,
}: IInnerPageBannerProps) { }: IInnerPageBannerProps) {
return ( return (
<header <header
@@ -13,7 +14,8 @@ export default function InnerPageBanner({
<div className="absolute inset-0 z-0 bg-black opacity-50" /> <div className="absolute inset-0 z-0 bg-black opacity-50" />
<Navbar /> <Navbar />
<div className="relative z-10 container mx-auto flex flex-col bg-cover bg-right-top py-20 text-white"> <div className="relative z-10 container mx-auto flex flex-col bg-cover bg-right-top py-20 text-white">
<h2 className="text-[4rem] text-white">{title}</h2> {title ? <h2 className="text-[4rem] text-white">{title}</h2> : <></>}
{subtitle ? <h2 className="text-lg text-white">{subtitle}</h2> : <></>}
</div> </div>
</header> </header>
); );
+4 -35
View File
@@ -3,19 +3,17 @@
import { useState } from 'react'; import { useState } from 'react';
import Pagination from '@/components/layout/pagination'; import Pagination from '@/components/layout/pagination';
import Image from 'next/image';
import Link from 'next/link';
import { getPosts } from '@/services/blog'; import { getPosts } from '@/services/blog';
import { IPostData } from '@/app/api/blog/data'; import { IPostThumbResponseData } from '@/app/api/blog/data';
import { IPagination } from '@/models/response'; import { IPagination } from '@/models/response';
import routeFactory from '@/assets/constants/routeFactory'; import routeFactory from '@/assets/constants/routeFactory';
import { useParams } from 'next/navigation'; import { useParams } from 'next/navigation';
import { TLocales } from '@/models/layout'; import { TLocales } from '@/models/layout';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import Button from '@/components/uikit/button'; import PostsGridView from './PostsGridView';
export interface IPostsGridProps { export interface IPostsGridProps {
initialPosts: IPostData[]; initialPosts: IPostThumbResponseData[];
initialPagination: IPagination; initialPagination: IPagination;
} }
@@ -45,36 +43,7 @@ export default function PostsGrid({
return ( return (
<div className="container mx-auto px-4 py-14 md:py-28"> <div className="container mx-auto px-4 py-14 md:py-28">
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"> <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{posts.map((post) => ( <PostsGridView posts={posts} locale={locale as TLocales} />
<div
key={post.id}
className="group flex flex-col gap-4 overflow-hidden bg-white md:gap-6"
>
<div className="relative aspect-[1.09] w-full overflow-hidden rounded-4xl">
<Image
src={post.imageSrc}
alt={post.title}
fill
className="h-auto w-full object-cover"
/>
<div className="invisible absolute inset-0 flex items-center justify-center bg-black/20 opacity-0 backdrop-blur-xs transition-all group-hover:visible group-hover:opacity-100">
<Button
link={routes.singlePost.route(post.id)}
endIcon="showMore"
>
{t('page_blog_details_CTA')}
</Button>
</div>
</div>
<Link
href={routes.singlePost.route(post.id)}
className="group-hover:text-primary text-center text-gray-500"
>
<h2 className="text-xl font-semibold">{post.title}</h2>
</Link>
</div>
))}
</div> </div>
<Pagination {...pagination} onPageChange={fetchPage} /> <Pagination {...pagination} onPageChange={fetchPage} />
</div> </div>
@@ -0,0 +1,53 @@
import { IPostThumbResponseData } from '@/app/api/blog/data';
import routeFactory from '@/assets/constants/routeFactory';
import Button from '@/components/uikit/button';
import { TLocales } from '@/models/layout';
import { getTranslations } from 'next-intl/server';
import Image from 'next/image';
import Link from 'next/link';
export default async function PostsGridView({
posts,
locale,
}: {
posts: IPostThumbResponseData[];
locale: TLocales;
}) {
const t = await getTranslations({ locale });
const routes = routeFactory(t, locale);
return (
<>
{posts.map((post) => (
<div
key={post.id}
className="group flex flex-col gap-3 overflow-hidden bg-white md:gap-5"
>
<div className="relative aspect-[1.09] w-full overflow-hidden rounded-2xl">
<Image
src={post.imageSrc}
alt={post.title}
fill
className="h-auto w-full object-cover"
/>
<div className="invisible absolute inset-0 flex items-center justify-center bg-black/20 opacity-0 backdrop-blur-xs transition-all group-hover:visible group-hover:opacity-100">
<Button
link={routes.singlePost.route(post.id)}
endIcon="showMore"
>
{t('page_blog_details_CTA')}
</Button>
</div>
</div>
<Link
href={routes.singlePost.route(post.id)}
className="group-hover:text-primary mb-4 text-center text-gray-500"
>
<h2 className="text-base font-medium">{post.title}</h2>
</Link>
</div>
))}
</>
);
}
@@ -0,0 +1,54 @@
import SectionTitle from '@/components/layout/sectionTitle';
import { getTranslations } from 'next-intl/server';
import { TLocales } from '@/models/layout';
import Button from '@/components/uikit/button';
import routeFactory from '@/assets/constants/routeFactory';
import { getPosts } from '@/services/blog';
import PostsGridView from '../blog/PostsGridView';
interface Props {
locale: TLocales;
className?: string;
}
export default async function HomePageBlog({ locale, className }: Props) {
const t = await getTranslations({ locale });
const posts = await getPosts();
const routes = routeFactory(t, locale);
return (
<div className={`w-full ${className}`}>
<div className="relative container mx-auto w-full bg-white">
<div className="relative z-20 grid grid-cols-1 lg:grid-cols-2 lg:gap-28">
<SectionTitle
title={t('pages_blog_title')}
description={t('com_home_blog_title')}
description_bold={t('com_home_blog_title_bold')}
locale={locale}
/>
<div className="pt-10 max-lg:hidden">
<h4 className="text-base font-extralight tracking-normal max-lg:hidden">
{t('com_home_blog_description')}
</h4>
<Button
link={routes.blog.route()}
endIcon="showMore"
className="mt-5"
>
{t('com_home_blog_show_more')}
</Button>
</div>
</div>
<div className="mt-10 grid grid-cols-1 gap-4 md:grid-cols-2 md:gap-6 lg:grid-cols-3 lg:gap-8">
<PostsGridView posts={posts.data?.slice(0, 3)} locale={locale} />
</div>
<Button
link={routes.blog.route()}
endIcon="showMore"
className="mx-auto mt-10 lg:hidden"
>
{t('com_home_blog_show_more')}
</Button>
</div>
</div>
);
}
+11 -2
View File
@@ -5,6 +5,9 @@ import Link from 'next/link';
import { IProjectCardProps } from './project'; import { IProjectCardProps } from './project';
import Button from '@/components/uikit/button'; import Button from '@/components/uikit/button';
import { useTranslations } from 'next-intl'; import { useTranslations } from 'next-intl';
import routeFactory from '@/assets/constants/routeFactory';
import { useParams } from 'next/navigation';
import { TLocales } from '@/models/layout';
export default function ProjectsGrid({ export default function ProjectsGrid({
projects, projects,
@@ -14,6 +17,9 @@ export default function ProjectsGrid({
className?: string; className?: string;
}) { }) {
const t = useTranslations(); const t = useTranslations();
const { locale } = useParams();
const routes = routeFactory(t, locale as TLocales);
return ( return (
<div <div
@@ -29,14 +35,17 @@ export default function ProjectsGrid({
className="h-auto w-full object-cover" className="h-auto w-full object-cover"
/> />
<div className="invisible absolute inset-0 flex items-center justify-center bg-black/20 opacity-0 backdrop-blur-xs transition-all group-hover:visible group-hover:opacity-100"> <div className="invisible absolute inset-0 flex items-center justify-center bg-black/20 opacity-0 backdrop-blur-xs transition-all group-hover:visible group-hover:opacity-100">
<Button endIcon="showMore"> <Button
endIcon="showMore"
link={routes.project.route(project.id)}
>
{t('com_home_projects_details_CTA')} {t('com_home_projects_details_CTA')}
</Button> </Button>
</div> </div>
</div> </div>
<Link <Link
href={'/'} href={routes.project.route(project.id)}
key={index} key={index}
className="group-hover:text-primary mb-4 text-center text-gray-500" className="group-hover:text-primary mb-4 text-center text-gray-500"
> >
+1 -1
View File
@@ -1,7 +1,7 @@
export interface IProjectCardProps { export interface IProjectCardProps {
imageSrc: string; imageSrc: string;
title: string; title: string;
link: string; id: string;
} }
export interface IProjectGridViewProps { export interface IProjectGridViewProps {
+16 -13
View File
@@ -1,5 +1,6 @@
'use server'; 'use server';
import { IProjectResponseData } from '@/app/api/projects/data';
import api from '@/lib/axios'; import api from '@/lib/axios';
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
@@ -17,16 +18,18 @@ export async function getProjects(page = 1 as number) {
.catch((error) => Promise.reject(error)); .catch((error) => Promise.reject(error));
} }
// export async function getProjectById( export async function getProject(
// projectId: string, projectId: string,
// ): Promise<IProjectCardProps> { ): Promise<IProjectResponseData> {
// const cookiesStore = await cookies(); const cookiesStore = await cookies();
// return api return api
// .get(`/projects/${projectId}`, { .get(`/projects/${projectId}`, {
// headers: { headers: {
// Cookie: cookiesStore.toString(), Cookie: cookiesStore.toString(),
// }, },
// }) })
// .then(({ data }) => Promise.resolve(data.data)) .then(({ data }) => {
// .catch((error) => Promise.reject(error)); return Promise.resolve(data.data);
// } })
.catch((error) => Promise.reject(error));
}