diff --git a/src/App.tsx b/src/App.tsx index 1cda332..e4aebcd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,6 +19,7 @@ import Login from './pages/auth/Login'; import { EmailWebSocketProvider } from './contexts/EmailWebSocketContext'; import SocketManagment from './lib/SocketManagment'; import NajvaToken from './components/NajvaToken'; +import { ThemeProvider } from './contexts/ThemeContext'; declare global { interface Window { @@ -121,23 +122,25 @@ const App: FC = () => { }, []); return ( - - - - {isLogin === 'isLogin' && userToken ? ( - -
- - - - ) : isLogin === 'isNotLogin' ? ( - - ) : null} - - - - - + + + + + {isLogin === 'isLogin' && userToken ? ( + +
+ + + + ) : isLogin === 'isNotLogin' ? ( + + ) : null} + + + + + + ) } diff --git a/src/components/Button.tsx b/src/components/Button.tsx index 4dd4cf6..b000aee 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -1,39 +1,40 @@ -import { FC, ReactNode } from 'react' +import { FC, ReactNode, ButtonHTMLAttributes } from 'react' import { clx } from '../helpers/utils' import MoonLoader from "react-spinners/ClipLoader" -interface ButtonProps { - label?: string; - children?: ReactNode; - className?: string; - loading?: boolean; - onClick?: () => void; - type?: 'button' | 'submit' | 'reset'; - disabled?: boolean; +type ButtonBaseProps = Omit, 'className' | 'children'> + +interface ButtonProps extends ButtonBaseProps { + label?: string + children?: ReactNode + className?: string + loading?: boolean variant?: 'primary' | 'secondary' } const Button: FC = (props) => { + const { label, children, className, loading, variant, type, disabled, ...rest } = props + const buttonClass = clx( - 'w-full bg-primary text-white cursor-pointer rounded-xl font-normal text-xs md:text-sm h-10 px-3 md:px-4 transition-all duration-200 hover:bg-opacity-90 disabled:opacity-50 disabled:cursor-not-allowed', - props.variant === 'secondary' && 'bg-[#ECEEF5] text-black', - props.className + 'w-full bg-primary text-primary-foreground cursor-pointer rounded-xl font-normal text-xs md:text-sm h-10 px-3 md:px-4 transition-all duration-200 hover:bg-opacity-90 disabled:opacity-50 disabled:cursor-not-allowed', + variant === 'secondary' && 'bg-[#ECEEF5] text-black', + className ) return ( ) diff --git a/src/components/DefaultTableSkeleton.tsx b/src/components/DefaultTableSkeleton.tsx index 9e7257a..19776c5 100644 --- a/src/components/DefaultTableSkeleton.tsx +++ b/src/components/DefaultTableSkeleton.tsx @@ -1,5 +1,5 @@ import { FC, Fragment } from 'react' -import Td from './Td' +import Td from '@/components/Td' import Skeleton from 'react-loading-skeleton' type Props = { @@ -8,15 +8,18 @@ type Props = { } const DefaultTableSkeleton: FC = ({ tdCount, trCount = 5 }) => { + const isDark = typeof document !== 'undefined' && document.documentElement.classList.contains('dark') + const baseColor = isDark ? '#2d2d30' : '#e5e7eb' + const highlightColor = isDark ? '#3c3c3c' : '#f3f4f6' return ( { Array.from({ length: trCount }).map((_, rowIndex) => ( - + { Array.from({ length: tdCount }).map((_, colIndex) => ( - + )) } diff --git a/src/components/EmailNotifications.tsx b/src/components/EmailNotifications.tsx index 08b7672..ad26eb6 100644 --- a/src/components/EmailNotifications.tsx +++ b/src/components/EmailNotifications.tsx @@ -3,6 +3,7 @@ import { useEmailWebSocket } from '@/hooks/useEmailWebSocket'; import { useEmailEvents, EmailPayload, UnreadCountPayload, EmailStatusPayload } from '@/hooks/useEmailEvents'; import { useNotificationSound } from '@/hooks/useNotificationSound'; import { Notification as NotificationIcon, VolumeHigh } from 'iconsax-react'; +import { getIconColor } from '@/utils/colorUtils'; interface EmailNotificationsProps { userToken: string; @@ -94,17 +95,17 @@ export const EmailNotifications: React.FC = ({ onClick={() => { playSound(); }} - className="p-2 rounded-full hover:bg-gray-100 transition-colors" + className="p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors" title="تست صدا" > - +
setIsVisible(!isVisible)} > - + {unreadCount > 0 && ( {unreadCount > 99 ? '99+' : unreadCount} @@ -113,20 +114,20 @@ export const EmailNotifications: React.FC = ({
{isVisible && ( -
-
+
+

📧 نوتیفیکیشن‌های ایمیل

- {unreadCount} خوانده نشده + {unreadCount} خوانده نشده
{notifications.length === 0 ? ( -
ایمیل جدیدی وجود ندارد
+
ایمیل جدیدی وجود ندارد
) : ( notifications.map((email) => (
onEmailClick?.(email)} >
@@ -136,8 +137,8 @@ export const EmailNotifications: React.FC = ({ {email.hasAttachments && 📎}
{email.subject}
-
{email.preview}
-
+
{email.preview}
+
{new Date(email.timestamp).toLocaleString('fa-IR')}
diff --git a/src/components/Input.tsx b/src/components/Input.tsx index 6ef0b9d..3bdb577 100644 --- a/src/components/Input.tsx +++ b/src/components/Input.tsx @@ -1,6 +1,7 @@ import { FC, InputHTMLAttributes, useEffect, useState } from 'react' import { clx } from '../helpers/utils'; import { Eye, SearchNormal } from 'iconsax-react'; +import { getIconColor } from '@/utils/colorUtils'; import Error from './Error'; type Variant = "floating_outlined" | "primary" | "search"; @@ -34,8 +35,8 @@ const Input: FC = (props: Props) => { const [search, setSearch] = useState('') const inputClass = clx( - 'w-full bg-white h-10 text-black block px-4 text-xs rounded-xl border border-border', - props.readOnly && 'bg-gray-100 border-0 text-description', + 'w-full input-surface h-10 block px-4 text-xs rounded-xl transition-colors', + props.readOnly && 'bg-muted border-0 text-muted-foreground', props.variant === 'search' && 'ps-10', props.className ); @@ -79,7 +80,7 @@ const Input: FC = (props: Props) => { return (
-