create products page

This commit is contained in:
2025-06-03 12:59:05 +03:30
parent 05e50f0eee
commit bd368ab6b5
17 changed files with 408 additions and 64 deletions
+2 -2
View File
@@ -158,7 +158,7 @@
.container { .container {
width: 100%; width: 100%;
padding-inline: 10rem; padding-inline: 1rem;
@media (width >=40rem) { @media (width >=40rem) {
max-width: 40rem; max-width: 40rem;
@@ -167,7 +167,7 @@
@media (width >=48rem) { @media (width >=48rem) {
max-width: 48rem; max-width: 48rem;
padding-inline: 1rem; padding-inline: 2rem;
} }
@media (width >=64rem) { @media (width >=64rem) {
+55
View File
@@ -0,0 +1,55 @@
import images from '@/assets/images/images';
import InnerPageBanner from '@/components/layout/innerPages/banner';
import ProductsCategoryCard from '@/components/pages/products/ProductCategoryCard';
import type { IProductCategoryCardProps } from '@/components/pages/products/productCategoryCard.d';
import { t } from '@/locales/translates';
export default function ProductsPage() {
const productCategories = [
{
id: '1',
title: t('com_products_category_Ghazaghi_title') as string,
icon: 'categoryGhazaghi',
typesCount: 22,
priceTypeTitle: 'Economy',
bestForTitle: 'Best For Interior Part',
},
{
id: '2',
title: t('com_products_category_Ghermez_title') as string,
icon: 'categoryGhermez',
typesCount: 12,
priceTypeTitle: 'Luxury',
bestForTitle: 'Best For Exterior Part',
},
{
id: '3',
title: t('com_products_category_Zard_title') as string,
icon: 'categoryZard',
typesCount: 11,
priceTypeTitle: 'Economy',
bestForTitle: 'Best For Facing',
},
{
id: '40',
title: t('com_products_category_Semirom_title') as string,
icon: 'categorySemirom',
typesCount: 40,
priceTypeTitle: 'Economy',
bestForTitle: 'Best For Building',
},
] as IProductCategoryCardProps[];
return (
<main>
<InnerPageBanner
title={t('pages_projects_title') as string}
imageSrc={images.aboutBanner.src}
/>
<div className="container my-24 grid grid-cols-4 gap-4">
{productCategories.map((category) => (
<ProductsCategoryCard key={category.id} {...category} />
))}
</div>
</main>
);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

@@ -0,0 +1,39 @@
import { Icon } from '@/components/uikit/icons';
import type { IProductCategoryCardProps } from './productCategoryCard.d';
import AchievementTextBox from '@/components/layout/achievementTextBox';
import { t } from '@/locales/translates';
import Button from '@/components/uikit/button';
import routeFactory from '@/assets/constants/routeFactory';
export default function ProductsCategoryCard({
icon,
title,
typesCount,
priceTypeTitle,
bestForTitle,
id,
}: IProductCategoryCardProps) {
return (
<div className="relative overflow-hidden rounded-4xl bg-gray-100 p-12">
<div className="absolute -end-2 -top-2">
<Icon name={icon} className="text-primary h-36 w-36" />
</div>
<div className="flex flex-col gap-4 pt-32">
<h2 className="text-xl font-semibold text-gray-500">{title}</h2>
<AchievementTextBox
title={
t('com_products_category_types_count', {
count: typesCount,
}) as string
}
/>
<AchievementTextBox title={priceTypeTitle} />
<AchievementTextBox title={bestForTitle} />
</div>
<div className="mt-24">
<Button link={routeFactory.products.route()}>See All</Button>
</div>
</div>
);
}
+10
View File
@@ -0,0 +1,10 @@
import { IconName } from '@/components/uikit/icons';
export interface IProductCategoryCardProps {
id: string;
title: string;
icon: IconName;
typesCount: number;
priceTypeTitle: string;
bestForTitle: string;
}
+2
View File
@@ -1,3 +1,4 @@
import { URL } from 'url';
import { IconName } from '../icons'; import { IconName } from '../icons';
export interface IBaseButtonProps export interface IBaseButtonProps
@@ -6,6 +7,7 @@ export interface IBaseButtonProps
loading?: boolean; loading?: boolean;
disabled?: boolean; disabled?: boolean;
className?: string; className?: string;
link?: URL | string;
} }
export interface ITextButtonProps extends IBaseButtonProps { export interface ITextButtonProps extends IBaseButtonProps {
+27 -9
View File
@@ -2,6 +2,7 @@
import React from 'react'; import React from 'react';
import { IIconButtonProps, ITextButtonProps } from './button'; import { IIconButtonProps, ITextButtonProps } from './button';
import { Icon } from '../icons'; import { Icon } from '../icons';
import Link from 'next/link';
const Button: React.FC<ITextButtonProps> = ({ const Button: React.FC<ITextButtonProps> = ({
children, children,
@@ -9,14 +10,32 @@ const Button: React.FC<ITextButtonProps> = ({
disabled = false, disabled = false,
endIcon, endIcon,
className, className,
link,
...props ...props
}) => { }) => {
return ( const wrapperClass = `group bg-primary relative h-12 cursor-pointer rounded-[0.5625rem] p-[0.125rem] flex ${className || ''}`;
<button
className={`group bg-primary relative flex h-12 cursor-pointer rounded-[0.5625rem] p-[0.125rem] ${className || ''}`} return link ? (
disabled={disabled || loading} <Link href={link} className={wrapperClass} {...props}>
{...props} <ButtonBody {...props} loading={loading} endIcon={endIcon}>
> {children}
</ButtonBody>
</Link>
) : (
<button disabled={disabled || loading} {...props} className={wrapperClass}>
<ButtonBody {...props} loading={loading} endIcon={endIcon}>
{children}
</ButtonBody>
</button>
);
};
const ButtonBody: React.FC<ITextButtonProps> = ({
children,
loading,
endIcon,
}) => (
<div className="flex">
{loading ? ( {loading ? (
<svg <svg
className="text-primary mr-3 -ml-1 h-5 w-5 animate-spin" className="text-primary mr-3 -ml-1 h-5 w-5 animate-spin"
@@ -41,7 +60,7 @@ const Button: React.FC<ITextButtonProps> = ({
) : null} ) : null}
<div <div
className={`flex items-center justify-center rounded-lg bg-white px-3 text-[#222222]`} className={`flex items-center justify-center rounded-lg bg-white px-3 text-gray-500`}
> >
{children} {children}
</div> </div>
@@ -51,9 +70,8 @@ const Button: React.FC<ITextButtonProps> = ({
<Icon name={endIcon} className="text-white" /> <Icon name={endIcon} className="text-white" />
</span> </span>
) : null} ) : null}
</button> </div>
); );
};
export default Button; export default Button;
@@ -14,9 +14,9 @@ export const AchievementIcon = (props: React.SVGProps<SVGSVGElement>) => (
<path <path
d="M8.37988 12.0001L10.7899 14.4201L15.6199 9.58008" d="M8.37988 12.0001L10.7899 14.4201L15.6199 9.58008"
stroke="white" stroke="white"
stroke-width="1.5" strokeWidth="1.5"
stroke-linecap="round" strokeLinecap="round"
stroke-linejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
); );
@@ -0,0 +1,36 @@
export default function CategoryGhazaghiIcon(
props: React.SVGProps<SVGSVGElement>,
) {
return (
<svg
{...props}
width="125"
height="128"
viewBox="0 0 125 128"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M80.3061 51.2131C78.7169 51.9032 77.0029 52.2593 75.2704 52.2593C73.5378 52.2593 71.8238 51.9032 70.2346 51.2131L9.16319 22.9274C8.17149 22.4272 7.33809 21.6616 6.75582 20.7157C6.17354 19.7699 5.86523 18.681 5.86523 17.5703C5.86523 16.4596 6.17354 15.3707 6.75582 14.4248C7.33809 13.479 8.17149 12.7133 9.16319 12.2131L70.2346 -16.2869C71.8238 -16.9769 73.5378 -17.333 75.2704 -17.333C77.0029 -17.333 78.7169 -16.9769 80.3061 -16.2869L141.377 11.9988C142.369 12.499 143.202 13.2647 143.784 14.2105C144.367 15.1564 144.675 16.2453 144.675 17.356C144.675 18.4667 144.367 19.5556 143.784 20.5014C143.202 21.4473 142.369 22.2129 141.377 22.7131L80.3061 51.2131Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M144.916 56.0342L79.5594 86.1411C78.1636 86.7781 76.6472 87.1071 75.113 87.1071C73.5788 87.1071 72.0625 86.7781 70.6666 86.1411L5.63086 56.0342"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M144.916 90.854L79.5594 120.962C78.1636 121.598 76.6472 121.928 75.113 121.928C73.5788 121.928 72.0625 121.598 70.6666 120.962L5.63086 90.854"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
@@ -0,0 +1,43 @@
export default function CategoryGhermezIcon(
props: React.SVGProps<SVGSVGElement>,
) {
return (
<svg
width="126"
height="128"
viewBox="0 0 126 128"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M35.5034 41.5721C51.776 41.5721 64.9676 28.3805 64.9676 12.1078C64.9676 -4.16488 51.776 -17.3564 35.5034 -17.3564C19.2307 -17.3564 6.03906 -4.16488 6.03906 12.1078C6.03906 28.3805 19.2307 41.5721 35.5034 41.5721Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M115.863 41.5721C132.136 41.5721 145.327 28.3805 145.327 12.1078C145.327 -4.16488 132.136 -17.3564 115.863 -17.3564C99.59 -17.3564 86.3984 -4.16488 86.3984 12.1078C86.3984 28.3805 99.59 41.5721 115.863 41.5721Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M35.5034 121.931C51.776 121.931 64.9676 108.74 64.9676 92.4671C64.9676 76.1945 51.776 63.0029 35.5034 63.0029C19.2307 63.0029 6.03906 76.1945 6.03906 92.4671C6.03906 108.74 19.2307 121.931 35.5034 121.931Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M115.863 121.931C132.136 121.931 145.327 108.74 145.327 92.4671C145.327 76.1945 132.136 63.0029 115.863 63.0029C99.59 63.0029 86.3984 76.1945 86.3984 92.4671C86.3984 108.74 99.59 121.931 115.863 121.931Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
@@ -0,0 +1,55 @@
export default function categorySemiromIcon(
props: React.SVGProps<SVGSVGElement>,
) {
return (
<svg
width="125"
height="125"
viewBox="0 0 125 125"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M32.2168 37.4287V60.833H1.77148V37.4287H32.2168Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M71.4004 68.5767V91.981H1.77148V68.5767H71.4004Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M149.771 37.4287V60.833H119.326V37.4287H149.771Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M110.587 37.4287V60.833H40.9551V37.4287H110.587Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M110.587 99.7271V123.131H40.9551V99.7271H110.587Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M149.769 68.5767V91.981H80.1367V68.5767H149.769Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M71.4004 6.2793V29.6836H1.77148V6.2793H71.4004Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M149.769 6.2793V29.6836H80.1367V6.2793H149.769Z"
stroke="currentColor"
strokeWidth="2"
/>
</svg>
);
}
@@ -0,0 +1,58 @@
export default function CategoryZardIcon(props: React.SVGProps<SVGSVGElement>) {
return (
<svg
width="126"
height="126"
viewBox="0 0 126 126"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M29.2559 29.3745V72.0767H4.88086C2.8376 65.3161 1.75004 58.15 1.75 50.7261C1.75 43.3028 2.83946 36.1361 4.86914 29.3745H29.2559Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M146.632 29.3745C148.663 36.1359 149.75 43.3047 149.75 50.7261C149.75 58.1497 148.661 65.3158 146.619 72.0767H122.244V29.3745H146.632Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M113.056 29.3701V72.0742H38.4414V29.3701H113.056Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M80.3418 -23.2231C108.033 -21.5316 131.605 -4.58667 142.79 19.3345H80.3418V-23.2231Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M71.1611 19.3345H8.71289C19.9004 -4.5868 43.4703 -21.5318 71.1611 -23.2231V19.3345Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M142.803 82.1035C131.605 106.025 108.033 122.97 80.3418 124.661V82.1035H142.803Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M71.1621 82.1035V124.661C43.4714 122.97 19.899 106.025 8.70117 82.1035H71.1621Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M55.165 45.1328H55.166C58.245 45.1311 60.7479 47.6326 60.748 50.7236C60.748 53.813 58.2467 56.3174 55.165 56.3174C52.0832 56.3174 49.582 53.815 49.582 50.7236C49.5822 47.7314 51.9292 45.2893 54.8779 45.1396L55.165 45.1328Z"
stroke="currentColor"
strokeWidth="2"
/>
<path
d="M96.3447 45.1328H96.3457C99.4248 45.131 101.928 47.6326 101.928 50.7236C101.928 53.813 99.4264 56.3174 96.3447 56.3174C93.2626 56.3172 90.7598 53.8144 90.7598 50.7236C90.7599 47.7316 93.1067 45.2893 96.0576 45.1396L96.3447 45.1328Z"
stroke="currentColor"
strokeWidth="2"
/>
</svg>
);
}
+8
View File
@@ -6,6 +6,10 @@ import { AchievementIcon } from './achievementIcon';
import { PhoneIcon } from './phoneIcon'; import { PhoneIcon } from './phoneIcon';
import { InstagramIcon } from './instagramIcon'; import { InstagramIcon } from './instagramIcon';
import ShowMoreIcon from './showMoreIcon'; import ShowMoreIcon from './showMoreIcon';
import CategoryGhazaghiIcon from './categoryGhazaghiIcon';
import CategoryGhermezIcon from './categoryGhermezIcon';
import categorySemiromIcon from './categorySemiromIcon';
import CategoryZardIcon from './categoryZardIcon';
export const icons = { export const icons = {
close: CloseIcon, close: CloseIcon,
@@ -15,6 +19,10 @@ export const icons = {
phone: PhoneIcon, phone: PhoneIcon,
instagram: InstagramIcon, instagram: InstagramIcon,
showMore: ShowMoreIcon, showMore: ShowMoreIcon,
categoryGhazaghi: CategoryGhazaghiIcon,
categoryGhermez: CategoryGhermezIcon,
categorySemirom: categorySemiromIcon,
categoryZard: CategoryZardIcon,
}; };
export type IconName = keyof typeof icons; export type IconName = keyof typeof icons;
+8 -8
View File
@@ -11,22 +11,22 @@ export const PhoneIcon = (props: React.SVGProps<SVGSVGElement>) => (
<path <path
d="M21.97 18.33C21.97 18.69 21.89 19.06 21.72 19.42C21.55 19.78 21.33 20.12 21.04 20.44C20.55 20.98 20.01 21.37 19.4 21.62C18.8 21.87 18.15 22 17.45 22C16.43 22 15.34 21.76 14.19 21.27C13.04 20.78 11.89 20.12 10.75 19.29C9.6 18.45 8.51 17.52 7.47 16.49C6.44 15.45 5.51 14.36 4.68 13.22C3.86 12.08 3.2 10.94 2.72 9.81C2.24 8.67 2 7.58 2 6.54C2 5.86 2.12 5.21 2.36 4.61C2.6 4 2.98 3.44 3.51 2.94C4.15 2.31 4.85 2 5.59 2C5.87 2 6.15 2.06 6.4 2.18C6.66 2.3 6.89 2.48 7.07 2.74L9.39 6.01C9.57 6.26 9.7 6.49 9.79 6.71C9.88 6.92 9.93 7.13 9.93 7.32C9.93 7.56 9.86 7.8 9.72 8.03C9.59 8.26 9.4 8.5 9.16 8.74L8.4 9.53C8.29 9.64 8.24 9.77 8.24 9.93C8.24 10.01 8.25 10.08 8.27 10.16C8.3 10.24 8.33 10.3 8.35 10.36C8.53 10.69 8.84 11.12 9.28 11.64C9.73 12.16 10.21 12.69 10.73 13.22C11.27 13.75 11.79 14.24 12.32 14.69C12.84 15.13 13.27 15.43 13.61 15.61C13.66 15.63 13.72 15.66 13.79 15.69C13.87 15.72 13.95 15.73 14.04 15.73C14.21 15.73 14.34 15.67 14.45 15.56L15.21 14.81C15.46 14.56 15.7 14.37 15.93 14.25C16.16 14.11 16.39 14.04 16.64 14.04C16.83 14.04 17.03 14.08 17.25 14.17C17.47 14.26 17.7 14.39 17.95 14.56L21.26 16.91C21.52 17.09 21.7 17.3 21.81 17.55C21.91 17.8 21.97 18.05 21.97 18.33Z" d="M21.97 18.33C21.97 18.69 21.89 19.06 21.72 19.42C21.55 19.78 21.33 20.12 21.04 20.44C20.55 20.98 20.01 21.37 19.4 21.62C18.8 21.87 18.15 22 17.45 22C16.43 22 15.34 21.76 14.19 21.27C13.04 20.78 11.89 20.12 10.75 19.29C9.6 18.45 8.51 17.52 7.47 16.49C6.44 15.45 5.51 14.36 4.68 13.22C3.86 12.08 3.2 10.94 2.72 9.81C2.24 8.67 2 7.58 2 6.54C2 5.86 2.12 5.21 2.36 4.61C2.6 4 2.98 3.44 3.51 2.94C4.15 2.31 4.85 2 5.59 2C5.87 2 6.15 2.06 6.4 2.18C6.66 2.3 6.89 2.48 7.07 2.74L9.39 6.01C9.57 6.26 9.7 6.49 9.79 6.71C9.88 6.92 9.93 7.13 9.93 7.32C9.93 7.56 9.86 7.8 9.72 8.03C9.59 8.26 9.4 8.5 9.16 8.74L8.4 9.53C8.29 9.64 8.24 9.77 8.24 9.93C8.24 10.01 8.25 10.08 8.27 10.16C8.3 10.24 8.33 10.3 8.35 10.36C8.53 10.69 8.84 11.12 9.28 11.64C9.73 12.16 10.21 12.69 10.73 13.22C11.27 13.75 11.79 14.24 12.32 14.69C12.84 15.13 13.27 15.43 13.61 15.61C13.66 15.63 13.72 15.66 13.79 15.69C13.87 15.72 13.95 15.73 14.04 15.73C14.21 15.73 14.34 15.67 14.45 15.56L15.21 14.81C15.46 14.56 15.7 14.37 15.93 14.25C16.16 14.11 16.39 14.04 16.64 14.04C16.83 14.04 17.03 14.08 17.25 14.17C17.47 14.26 17.7 14.39 17.95 14.56L21.26 16.91C21.52 17.09 21.7 17.3 21.81 17.55C21.91 17.8 21.97 18.05 21.97 18.33Z"
stroke="currentColor" stroke="currentColor"
stroke-width="1.5" strokeWidth="1.5"
stroke-miterlimit="10" strokeMiterlimit="10"
/> />
<path <path
d="M18.5 9C18.5 8.4 18.03 7.48 17.33 6.73C16.69 6.04 15.84 5.5 15 5.5" d="M18.5 9C18.5 8.4 18.03 7.48 17.33 6.73C16.69 6.04 15.84 5.5 15 5.5"
stroke="currentColor" stroke="currentColor"
stroke-width="1.5" strokeWidth="1.5"
stroke-linecap="round" strokeLinecap="round"
stroke-linejoin="round" strokeLinejoin="round"
/> />
<path <path
d="M22 9C22 5.13 18.87 2 15 2" d="M22 9C22 5.13 18.87 2 15 2"
stroke="currentColor" stroke="currentColor"
stroke-width="1.5" strokeWidth="1.5"
stroke-linecap="round" strokeLinecap="round"
stroke-linejoin="round" strokeLinejoin="round"
/> />
</g> </g>
<defs> <defs>
+8 -8
View File
@@ -10,18 +10,18 @@ export const SettingIcon = (props: React.SVGProps<SVGSVGElement>) => (
<path <path
d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z"
stroke="currentColor" stroke="currentColor"
stroke-width="1.5" strokeWidth="1.5"
stroke-miterlimit="10" strokeMiterlimit="10"
stroke-linecap="round" strokeLinecap="round"
stroke-linejoin="round" strokeLinejoin="round"
/> />
<path <path
d="M2 12.8799V11.1199C2 10.0799 2.85 9.21994 3.9 9.21994C5.71 9.21994 6.45 7.93994 5.54 6.36994C5.02 5.46994 5.33 4.29994 6.24 3.77994L7.97 2.78994C8.76 2.31994 9.78 2.59994 10.25 3.38994L10.36 3.57994C11.26 5.14994 12.74 5.14994 13.65 3.57994L13.76 3.38994C14.23 2.59994 15.25 2.31994 16.04 2.78994L17.77 3.77994C18.68 4.29994 18.99 5.46994 18.47 6.36994C17.56 7.93994 18.3 9.21994 20.11 9.21994C21.15 9.21994 22.01 10.0699 22.01 11.1199V12.8799C22.01 13.9199 21.16 14.7799 20.11 14.7799C18.3 14.7799 17.56 16.0599 18.47 17.6299C18.99 18.5399 18.68 19.6999 17.77 20.2199L16.04 21.2099C15.25 21.6799 14.23 21.3999 13.76 20.6099L13.65 20.4199C12.75 18.8499 11.27 18.8499 10.36 20.4199L10.25 20.6099C9.78 21.3999 8.76 21.6799 7.97 21.2099L6.24 20.2199C5.33 19.6999 5.02 18.5299 5.54 17.6299C6.45 16.0599 5.71 14.7799 3.9 14.7799C2.85 14.7799 2 13.9199 2 12.8799Z" d="M2 12.8799V11.1199C2 10.0799 2.85 9.21994 3.9 9.21994C5.71 9.21994 6.45 7.93994 5.54 6.36994C5.02 5.46994 5.33 4.29994 6.24 3.77994L7.97 2.78994C8.76 2.31994 9.78 2.59994 10.25 3.38994L10.36 3.57994C11.26 5.14994 12.74 5.14994 13.65 3.57994L13.76 3.38994C14.23 2.59994 15.25 2.31994 16.04 2.78994L17.77 3.77994C18.68 4.29994 18.99 5.46994 18.47 6.36994C17.56 7.93994 18.3 9.21994 20.11 9.21994C21.15 9.21994 22.01 10.0699 22.01 11.1199V12.8799C22.01 13.9199 21.16 14.7799 20.11 14.7799C18.3 14.7799 17.56 16.0599 18.47 17.6299C18.99 18.5399 18.68 19.6999 17.77 20.2199L16.04 21.2099C15.25 21.6799 14.23 21.3999 13.76 20.6099L13.65 20.4199C12.75 18.8499 11.27 18.8499 10.36 20.4199L10.25 20.6099C9.78 21.3999 8.76 21.6799 7.97 21.2099L6.24 20.2199C5.33 19.6999 5.02 18.5299 5.54 17.6299C6.45 16.0599 5.71 14.7799 3.9 14.7799C2.85 14.7799 2 13.9199 2 12.8799Z"
stroke="currentColor" stroke="currentColor"
stroke-width="1.5" strokeWidth="1.5"
stroke-miterlimit="10" strokeMiterlimit="10"
stroke-linecap="round" strokeLinecap="round"
stroke-linejoin="round" strokeLinejoin="round"
/> />
</svg> </svg>
); );
+8
View File
@@ -51,6 +51,14 @@ const en = {
com_home_story_projects_count: 'Completed Projects', com_home_story_projects_count: 'Completed Projects',
com_home_story_customer_count: 'Happy Customers', com_home_story_customer_count: 'Happy Customers',
com_home_story_experience: 'Years of Experience', com_home_story_experience: 'Years of Experience',
// Products Page Components
com_products_category_Ghazaghi_title: 'Ghazaghi',
com_products_category_Ghermez_title: 'Ghermez',
com_products_category_Semirom_title: 'Semirom',
com_products_category_Zard_title: 'Zard',
com_products_category_types_count: ({ count }: { count: number }) =>
`${count} Types`,
}; };
export default en; export default en;
+17 -5
View File
@@ -39,19 +39,31 @@ export function changeLanguage(lang: TLocales, days = 365) {
} }
export const locales = { export const locales = {
en: en as Translates, en: en as unknown as Translates,
fa, fa,
} as Record<TLocales, Translates>; } as Record<TLocales, Translates>;
export const translates = (key: keyof Translates): string | (() => string) => { export const translates = (
key: keyof Translates,
dynamicValue?: Record<string, string | number>,
): string | ((dynamicValue: Record<string, string | number>) => string) => {
const lang = (getCookie('lang') || 'en') as TLocales; const lang = (getCookie('lang') || 'en') as TLocales;
return locales[lang][key] || locales.en[key] || key; const value = locales[lang][key] || locales.en[key] || key;
if (typeof value === 'function') {
return value(dynamicValue || {});
}
return value;
}; };
export const t = (key: keyof Translates) => translates(key); export const t = (
key: keyof Translates,
dynamicValue?: Record<string, string | number>,
) => translates(key, dynamicValue);
export type TLocales = 'en' | 'fa'; export type TLocales = 'en' | 'fa';
export type Translates = { export type Translates = {
[K in keyof typeof en]: string | (() => string); [K in keyof typeof en]:
| string
| ((dynamicValue: Record<string, string | number>) => string);
}; };