pixel perfect
This commit is contained in:
@@ -21,11 +21,11 @@ export const metadata = {
|
|||||||
const About: NextPage = () => {
|
const About: NextPage = () => {
|
||||||
return (
|
return (
|
||||||
<div className='mt-24'>
|
<div className='mt-24'>
|
||||||
<div className='flex items-start justify-between max-w-maxWidth mx-auto'>
|
<div className='flex xl:flex-row flex-col items-start justify-between max-w-maxWidth mx-auto'>
|
||||||
<h1 className='text-2xl font-bold'>
|
<h1 className='text-2xl font-bold'>
|
||||||
درباره ی داناک
|
درباره ی داناک
|
||||||
</h1>
|
</h1>
|
||||||
<div className='max-w-[500px] text-sm leading-6'>
|
<div className='max-w-[500px] mt-4 xl:mt-0 text-sm leading-6'>
|
||||||
قبل از تبدیل شدن داناک به یک شرکت ، یک ایده بودیم. ایده ای نه برای ساخت یک محصول یا خدمت جدید، ایده ای برای ساخت یک فرهنگ خلاقانه و ارزش محور. داناک با این باور متولد شده که استعداد ، توانایی و تعهد افراد می تواند موتور محرکه شرکتی رو به آینده باشد. شرکتی که توانایی انجام کارهای شگفت انگیز و فوق العاده ای دارد و غیر ممکن ها را ممکن می سازد. داناک ترکیبی از بهترین مهندسین ، توانمندترین متخصصین ، جدیدترین تکنولوژی ها و خلاقانه ترین ایده هاست. به پشتوانه این ترکیب فوق العاده می توانیم با ارائه راه کار های مبتنی بر نرم افزار ، هوش مصنوعی و آنالیز داده به شما کمک کنیم تا سازمان خود را بهتر رصد کنید و تصمیم های هوشمندانه تری اتخاذ نمایید.
|
قبل از تبدیل شدن داناک به یک شرکت ، یک ایده بودیم. ایده ای نه برای ساخت یک محصول یا خدمت جدید، ایده ای برای ساخت یک فرهنگ خلاقانه و ارزش محور. داناک با این باور متولد شده که استعداد ، توانایی و تعهد افراد می تواند موتور محرکه شرکتی رو به آینده باشد. شرکتی که توانایی انجام کارهای شگفت انگیز و فوق العاده ای دارد و غیر ممکن ها را ممکن می سازد. داناک ترکیبی از بهترین مهندسین ، توانمندترین متخصصین ، جدیدترین تکنولوژی ها و خلاقانه ترین ایده هاست. به پشتوانه این ترکیب فوق العاده می توانیم با ارائه راه کار های مبتنی بر نرم افزار ، هوش مصنوعی و آنالیز داده به شما کمک کنیم تا سازمان خود را بهتر رصد کنید و تصمیم های هوشمندانه تری اتخاذ نمایید.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const BigBlogItem: FC<BigBlogItemProps> = ({ item }) => {
|
|||||||
return (
|
return (
|
||||||
<div className='w-full rounded-4xl bg-white p-7 flex xl:flex-row flex-col gap-6'>
|
<div className='w-full rounded-4xl bg-white p-7 flex xl:flex-row flex-col gap-6'>
|
||||||
<Link href={`/blogs/${item.slug}`}>
|
<Link href={`/blogs/${item.slug}`}>
|
||||||
<Image src={item.imageUrl} alt='blog' width={300} height={300} className='size-[150px] object-cover mx-auto xl:mx-0 rounded-4xl' />
|
<Image src={item.imageUrl} alt='blog' width={300} height={300} className='xl:size-[150px] object-cover mx-auto xl:mx-0 rounded-4xl' />
|
||||||
</Link>
|
</Link>
|
||||||
<div className='flex-1'>
|
<div className='flex-1'>
|
||||||
<Link href={`/blogs/${item.slug}`}>
|
<Link href={`/blogs/${item.slug}`}>
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ const BlogList: FC = () => {
|
|||||||
|
|
||||||
<div className='mt-10 flex xl:flex-row flex-col gap-8'>
|
<div className='mt-10 flex xl:flex-row flex-col gap-8'>
|
||||||
<div className='xl:w-[261px] w-full'>
|
<div className='xl:w-[261px] w-full'>
|
||||||
|
<div className='hidden xl:block'>
|
||||||
<Category />
|
<Category />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -68,6 +70,8 @@ const BlogList: FC = () => {
|
|||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='flex-1 flex flex-col gap-8'>
|
<div className='flex-1 flex flex-col gap-8'>
|
||||||
@@ -76,6 +80,9 @@ const BlogList: FC = () => {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className='block xl:hidden'>
|
||||||
|
<Category />
|
||||||
|
</div>
|
||||||
<div className='xl:w-[261px] w-full'>
|
<div className='xl:w-[261px] w-full'>
|
||||||
<MostVisited />
|
<MostVisited />
|
||||||
<div className='mt-6'>
|
<div className='mt-6'>
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import Button from '../../../components/Button'
|
|||||||
import { useFormik } from 'formik'
|
import { useFormik } from 'formik'
|
||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { ErrorType } from '../../../helpers/types'
|
import { ErrorType } from '../../../helpers/types'
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import { useCreateBlogComment } from '../hooks/useBlogsData'
|
import { useCreateBlogComment } from '../hooks/useBlogsData'
|
||||||
import { CreateBlogCommentType } from '../types/BlogTypes'
|
import { CreateBlogCommentType } from '../types/BlogTypes'
|
||||||
import { useSharedStore } from '@/shared/store/sharedStore'
|
import { useSharedStore } from '@/shared/store/sharedStore'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { LOGIN_URL } from '@/config/const'
|
import { LOGIN_URL } from '@/config/const'
|
||||||
|
import { toast } from '@/components/Toast'
|
||||||
type Props = {
|
type Props = {
|
||||||
refetch: () => void
|
refetch: () => void
|
||||||
id: string
|
id: string
|
||||||
@@ -41,7 +41,7 @@ const CreateReview: FC<Props> = ({ refetch, id }) => {
|
|||||||
if (error.response && 'status' in error.response && error.response.status === 401) {
|
if (error.response && 'status' in error.response && error.response.status === 401) {
|
||||||
window.location.href = LOGIN_URL + '?redirect=' + window.location.href
|
window.location.href = LOGIN_URL + '?redirect=' + window.location.href
|
||||||
} else {
|
} else {
|
||||||
toast.error(error.response?.data?.error?.message?.[0] || 'An error occurred')
|
toast(error.response?.data?.error?.message?.[0] || 'An error occurred', 'error')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { CreateContactType } from './types/ContactTypes'
|
|||||||
import { useFormik } from 'formik'
|
import { useFormik } from 'formik'
|
||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { useCreateContact } from './hooks/useContactData'
|
import { useCreateContact } from './hooks/useContactData'
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import { ErrorType } from '@/helpers/types'
|
import { ErrorType } from '@/helpers/types'
|
||||||
|
import { toast } from '@/components/Toast'
|
||||||
|
|
||||||
const ContactForm = () => {
|
const ContactForm = () => {
|
||||||
|
|
||||||
@@ -33,11 +33,11 @@ const ContactForm = () => {
|
|||||||
onSubmit: (values) => {
|
onSubmit: (values) => {
|
||||||
createContact.mutate(values, {
|
createContact.mutate(values, {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success('پیام شما با موفقیت ثبت شد')
|
toast('پیام شما با موفقیت ثبت شد', 'success')
|
||||||
formik.resetForm()
|
formik.resetForm()
|
||||||
},
|
},
|
||||||
onError: (error: ErrorType) => {
|
onError: (error: ErrorType) => {
|
||||||
toast.error(error.response?.data?.error.message[0])
|
toast(error.response?.data?.error.message[0] || 'An error occurred', 'error')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ const HeroSection: FC = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='absolute flex items-center z-1 top-0 left-0 w-full h-full bg-black/10 rounded-4xl'>
|
<div className='absolute flex items-center z-1 top-0 left-0 w-full h-full bg-black/10 rounded-4xl'>
|
||||||
<div className='max-w-maxWidth w-full mx-auto px-10 xl:text-4xl text-lg text-white'>
|
<div className='max-w-maxWidth flex flex-col mt-1 xl:mt-0 xl:items-start items-center w-full mx-auto px-10 xl:text-4xl text-lg text-white'>
|
||||||
<p>{item.title}</p>
|
<p className='xl:text-lg text-sm'>{item.title}</p>
|
||||||
<p className='xl:mt-5 font-bold'>{item.description}</p>
|
<p className='xl:mt-5 mt-2 xl:text-2xl text-sm font-bold'>{item.description}</p>
|
||||||
|
|
||||||
<Link href={item.link}>
|
<Link href={item.link}>
|
||||||
<Button
|
<Button
|
||||||
className='xl:mt-12 mt-5 !w-fit px-10 bg-white !text-black'
|
className='xl:mt-5 mt-2 !w-fit xl:px-10 px-5 h-8 xl:h-10 bg-white !text-black'
|
||||||
label='بیشتر بدانید'
|
label='بیشتر بدانید'
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
+3
-1
@@ -4,13 +4,14 @@ import "swiper/css";
|
|||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import 'rc-rate/assets/index.css';
|
import 'rc-rate/assets/index.css';
|
||||||
import "@/assets/fonts/irancell/style.css";
|
import "@/assets/fonts/irancell/style.css";
|
||||||
import { ToastContainer } from 'react-toastify';
|
// import { ToastContainer } from 'react-toastify';
|
||||||
import Header from "@/shared/Header";
|
import Header from "@/shared/Header";
|
||||||
import Footer from "@/shared/Footer";
|
import Footer from "@/shared/Footer";
|
||||||
import SideBar from "@/shared/SideBar";
|
import SideBar from "@/shared/SideBar";
|
||||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
||||||
|
|
||||||
import QueryProvider from "@/config/QueryProvider";
|
import QueryProvider from "@/config/QueryProvider";
|
||||||
|
import ToastContainer from "@/components/Toast";
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
@@ -48,6 +49,7 @@ export default function RootLayout({
|
|||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
|
{/* <ToastContainer /> */}
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
|
|
||||||
</QueryProvider>
|
</QueryProvider>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const Products: FC = () => {
|
|||||||
<div className='rounded-4xl overflow-hidden relative'>
|
<div className='rounded-4xl overflow-hidden relative'>
|
||||||
<Link href={`/products/${item.id}`}>
|
<Link href={`/products/${item.id}`}>
|
||||||
<Image
|
<Image
|
||||||
src={item.images[0].imageUrl}
|
src={item.coverUrl}
|
||||||
alt='product'
|
alt='product'
|
||||||
width={1080}
|
width={1080}
|
||||||
height={1080}
|
height={1080}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export interface DanakService {
|
|||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
link: string;
|
link: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
|
coverUrl: string;
|
||||||
category: {
|
category: {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
'use client'
|
||||||
|
import { CloseCircle, InfoCircle, TickCircle } from 'iconsax-react';
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
interface Toast {
|
||||||
|
id: string;
|
||||||
|
message: string;
|
||||||
|
type?: 'success' | 'error' | 'info';
|
||||||
|
}
|
||||||
|
|
||||||
|
let addToast: (toast: Toast) => void;
|
||||||
|
|
||||||
|
const ToastContainer: React.FC = () => {
|
||||||
|
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||||
|
|
||||||
|
// ثبت toast جدید
|
||||||
|
const showToast = (toast: Toast) => {
|
||||||
|
setToasts((prev) => [...prev, toast]);
|
||||||
|
|
||||||
|
// حذف خودکار بعد از ۳ ثانیه
|
||||||
|
setTimeout(() => {
|
||||||
|
setToasts((prev) => prev.filter((t) => t.id !== toast.id));
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
|
// تخصیص تابع نمایش toast به متغیر سراسری
|
||||||
|
useEffect(() => {
|
||||||
|
addToast = showToast;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed top-4 text-sm right-0 left-0 mx-auto w-fit z-50 flex flex-col gap-2">
|
||||||
|
{toasts.map((toast) => (
|
||||||
|
<div
|
||||||
|
key={toast.id}
|
||||||
|
className={`px-4 flex items-center gap-2 backdrop-blur-2xl h-16 min-w-[300px] rounded-2xl shadow-md transition-transform ${toast.type === 'success'
|
||||||
|
? 'bg-white/70 text-black'
|
||||||
|
: toast.type === 'error'
|
||||||
|
? 'bg-white/70 text-black'
|
||||||
|
: 'bg-white/70 text-black'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
toast.type === 'success' ? <TickCircle className='size-5' color='green' /> :
|
||||||
|
toast.type === 'error' ? <CloseCircle className='size-5' color='red' /> :
|
||||||
|
<InfoCircle className='size-5' color='blue' />
|
||||||
|
}
|
||||||
|
{toast.message}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toast = (message: string, type: 'success' | 'error' | 'info' = 'info') => {
|
||||||
|
addToast({ id: Date.now().toString(), message, type });
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ToastContainer;
|
||||||
@@ -93,7 +93,7 @@ const Footer: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='w-full flex-1 max-w-[204px]'>
|
<div className='w-full flex-1 xl:max-w-[204px]'>
|
||||||
<h6 className='font-bold xl:text-base text-xs'>
|
<h6 className='font-bold xl:text-base text-xs'>
|
||||||
خبرنامه
|
خبرنامه
|
||||||
</h6>
|
</h6>
|
||||||
@@ -173,6 +173,10 @@ const Footer: FC = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<a referrerPolicy='origin' target='_blank' href='https://trustseal.enamad.ir/?id=587664&Code=5mx5bxt3mnywD3cXcgFawApYNfTjmYGX'>
|
||||||
|
<img referrerPolicy='origin' src='https://trustseal.enamad.ir/logo.aspx?id=587664&Code=5mx5bxt3mnywD3cXcgFawApYNfTjmYGX' alt='enamad trust seal' style={{ cursor: 'pointer' }} />
|
||||||
|
</a>
|
||||||
|
|
||||||
<div className='xl:text-sm text-xs dltr pb-4 xl:pb-0'>
|
<div className='xl:text-sm text-xs dltr pb-4 xl:pb-0'>
|
||||||
© 2025 Danak. All rights reserved.
|
© 2025 Danak. All rights reserved.
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user