first push

This commit is contained in:
karimaldeen 2024-09-26 11:38:11 +03:00
commit 296d5f78aa
138 changed files with 12232 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

9
.prettierrc Normal file
View File

@ -0,0 +1,9 @@
{
"singleQuote": true,
"semi": true,
"tabWidth": 2,
"useTabs": false,
"jsxSingleQuote": false,
"jsxBracketSameLine": false,
"arrowParens": "always"
}

50
README.md Normal file
View File

@ -0,0 +1,50 @@
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
- Configure the top-level `parserOptions` property like this:
```js
export default tseslint.config({
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
});
```
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
- Optionally add `...tseslint.configs.stylisticTypeChecked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
```js
// eslint.config.js
import react from 'eslint-plugin-react';
export default tseslint.config({
// Set the react version
settings: { react: { version: '18.3' } },
plugins: {
// Add the react plugin
react,
},
rules: {
// other rules...
// Enable its recommended rules
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
},
});
```

4842
bundle-analysis.html Normal file

File diff suppressed because one or more lines are too long

28
eslint.config.js Normal file
View File

@ -0,0 +1,28 @@
import js from '@eslint/js';
import globals from 'globals';
import reactHooks from 'eslint-plugin-react-hooks';
import reactRefresh from 'eslint-plugin-react-refresh';
import tseslint from 'typescript-eslint';
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
);

19
index.html Normal file
View File

@ -0,0 +1,19 @@
<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="manifest" href="/site.webmanifest" />
<link
rel="icon"
type="image/webp"
href="/src/assets/core/Logo-192x192.webp"
/>
<meta name="description" content=" description of your web app" />
<title>Website</title>
</head>
<body>
<script type="module" src="/src/main.tsx"></script>
<div id="root"></div>
</body>
</html>

44
package.json Normal file
View File

@ -0,0 +1,44 @@
{
"name": "website",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"start": "vite --port=3000",
"build": "vite build",
"format": "prettier --write .",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@tanstack/react-query": "^5.53.1",
"antd": "^5.21.1",
"axios": "^1.7.5",
"formik": "^2.4.6",
"framer-motion": "^11.5.0",
"i18next": "^23.14.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-i18next": "^14.1.3",
"react-icons": "^5.3.0",
"react-player": "^2.16.0",
"react-router-dom": "^6.26.1",
"react-transition-group": "^4.4.5",
"swiper": "^11.1.14",
"zustand": "^4.5.5"
},
"devDependencies": {
"@types/node": "^22.5.1",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^8.57.0",
"prettier": "^3.3.3",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.77.8",
"typescript": "^5.5.4",
"vite": "^5.4.2",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-env-compatible": "^2.0.1"
}
}

3467
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load Diff

BIN
public/Download/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

BIN
public/Features/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
public/Features/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
public/Features/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
public/Features/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
public/Features/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
public/Features/6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
public/Features/main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
public/HomeImage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

BIN
public/HowItWorks/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 763 B

BIN
public/HowItWorks/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
public/HowItWorks/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
public/HowItWorks/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
public/HowItWorks/main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

BIN
public/LOGO.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
public/Note/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
public/Note/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
public/Slider.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
public/Video/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
public/Video/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

BIN
public/Video/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/Video/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
public/Video/Play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
public/Video/video.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

BIN
public/circle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
public/contact/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

BIN
public/contact/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

BIN
public/contact/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

3
public/shape.svg Normal file
View File

@ -0,0 +1,3 @@
<svg width="1440" height="476" viewBox="0 0 1440 476" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 316.38L717.5 0.5L1440 316.38V476H0V316.38Z" fill="#F5F7FB"/>
</svg>

After

Width:  |  Height:  |  Size: 182 B

1
public/vite.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

3
robots.txt Normal file
View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

26
site.webmanifest Normal file
View File

@ -0,0 +1,26 @@
{
"name": "My Web App",
"short_name": "WebApp",
"description": "A description of your web app.",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#000000",
"icons": [
{
"src": "/src/assets/core/Logo-192x192.webp",
"sizes": "192x192",
"type": "image/webp"
},
{
"src": "/src/assets/core/Logo-512x512.webp",
"sizes": "512x512",
"type": "image/webp"
},
{
"src": "/src/assets/core/Logo-192x192.png",
"sizes": "192x192",
"type": "image/png"
}
]
}

31
src/App.tsx Normal file
View File

@ -0,0 +1,31 @@
import Layout from './components/layout/Layout';
import DownloadPage from './pages/DownloadPage';
import FeaturesPage from './pages/FeaturesPage';
import HomePage from './pages/HomePage';
import HowItWork from './pages/HowItWork';
import NotePage from './pages/NotePage';
import ScreenShoot from './pages/ScreenShoot';
import VideoPage from './pages/VideoPage';
import ProviderContainer from './ProviderContainer';
import ContactPage from './pages/ContactPage';
import './styles/App/index.scss';
const App = () => {
return (
<ProviderContainer>
{/* <Routes /> */}
<Layout>
<HomePage />
<FeaturesPage/>
<HowItWork/>
<VideoPage/>
<ScreenShoot/>
<NotePage/>
<DownloadPage/>
<ContactPage/>
</Layout>
</ProviderContainer>
);
};
export default App;

13
src/ProviderContainer.tsx Normal file
View File

@ -0,0 +1,13 @@
import { BrowserRouter } from 'react-router-dom';
import QueryProvider from './lib/ReactQueryProvider';
import I18nProvider from './lib/I18nProvider';
function ProviderContainer({ children }: { children: React.ReactNode }) {
return (
<QueryProvider>
<I18nProvider>{children}</I18nProvider>
</QueryProvider>
);
}
export default ProviderContainer;

33
src/Routes.tsx Normal file
View File

@ -0,0 +1,33 @@
import { lazy, Suspense } from 'react';
import { Route, Routes as RoutesContainer } from 'react-router-dom';
import './styles/App/index.scss';
import SpinContainer from './components/layout/SpinContainer';
import HomePage from './pages/HomePage';
import Layout from './components/layout/Layout';
import { RoutesEnums } from './enums/RoutesEnums';
const Page404 = lazy(() => import('./components/layout/NotFoundPage'));
const Routes = () => {
return (
<RoutesContainer>
<Route
path={RoutesEnums.HOME}
element={
<Layout>
<HomePage />
</Layout>
}
/>
<Route
path={'/*'}
element={
<Suspense fallback={<SpinContainer />}>
<Page404 />
</Suspense>
}
/>
</RoutesContainer>
);
};
export default Routes;

BIN
src/apis/Logo-192x192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

22
src/apis/example.ts Normal file
View File

@ -0,0 +1,22 @@
import {
useAddMutation,
useDeleteMutation,
useGetQuery,
useUpdateMutation,
} from './helpers';
const API = {
GET: '/example',
ADD: '/example',
DELETE: '/example',
UPDATE: '/example',
};
const KEY = 'example';
export const useGetExample = (params?: any, options?: any) =>
useGetQuery(KEY, API.GET, params, options);
export const useAddExample = () => useAddMutation(KEY, API.ADD);
export const useUpdateExample = () => useUpdateMutation(KEY, API.ADD);
export const useDeleteExample = () => useDeleteMutation(KEY, API.ADD);

View File

@ -0,0 +1,41 @@
import axios, { AxiosInstance, AxiosRequestConfig, ResponseType } from 'axios';
class AxiosBuilder {
private baseURL: string = '';
private headers: Record<string, any> = {};
private timeout: number = 60000;
private responseType: ResponseType = 'json';
withBaseURL(baseURL: string): AxiosBuilder {
this.baseURL = baseURL;
return this;
}
withHeaders(headers: Record<string, any>): AxiosBuilder {
this.headers = { ...this.headers, ...headers };
return this;
}
withTimeout(timeout: number): AxiosBuilder {
this.timeout = timeout;
return this;
}
withResponseType(responseType: ResponseType): AxiosBuilder {
this.responseType = responseType;
return this;
}
build(): AxiosInstance {
const config: AxiosRequestConfig = {
baseURL: this.baseURL,
headers: this.headers,
timeout: this.timeout,
responseType: this.responseType,
};
return axios.create(config);
}
}
export default AxiosBuilder;

View File

@ -0,0 +1,5 @@
export { default as useDeleteMutation } from './useDeleteMutation';
export { default as useUpdateMutation } from './useUpdateMutation';
export { default as useAddMutation } from './useAddMutation';
export { default as useGetQuery } from './useGetQuery';
export { default as useGetQueryPagination } from './useGetQueryPagination';

View File

@ -0,0 +1,30 @@
import { useMutation, UseMutationResult } from '@tanstack/react-query';
import useAxios from './useAxios';
import { AxiosEnum } from '../../enums/Axios';
interface MutationData {
[key: string]: any;
}
function useAddMutation<TResponse = any>(
key: string,
url: string,
message: string = '',
): UseMutationResult<TResponse, unknown, MutationData, unknown> {
const axios = useAxios();
return useMutation<TResponse, unknown, MutationData, unknown>({
mutationFn: async (dataToSend: MutationData) => {
const response = await axios.post<TResponse>(url, dataToSend, {
headers: {
'Content-Type': 'multipart/form-data',
[AxiosEnum.HEADER_KEY]: key,
[AxiosEnum.HEADER_CUSTOM_MESSAGE]: message,
},
});
return response.data;
},
});
}
export default useAddMutation;

View File

@ -0,0 +1,15 @@
import AxiosBuilder from './AxiosBuilder';
import { AxiosEnum } from '../../enums/Axios';
function useAxios() {
const buildAxios = new AxiosBuilder()
.withBaseURL(AxiosEnum?.BASEURL as string)
.withResponseType(AxiosEnum.RESPONSE_TYPE)
.withTimeout(AxiosEnum.TIMEOUT)
.withHeaders({ Accept: 'application/json' });
const axios = buildAxios.build();
return axios;
}
export default useAxios;

View File

@ -0,0 +1,33 @@
import { useMutation, UseMutationResult } from '@tanstack/react-query';
import useAxios from './useAxios';
import { AxiosEnum } from '../../enums/Axios';
import { AxiosResponse } from '../../types/axios';
type DataToSend = {
id: number | string;
};
function useDeleteMutation<TResponse = any>(
key: string,
url: string,
message: string = '',
): UseMutationResult<AxiosResponse<TResponse>, unknown, DataToSend, unknown> {
const axios = useAxios();
return useMutation<AxiosResponse<TResponse>, unknown, DataToSend, unknown>({
mutationFn: async (dataToSend: DataToSend) => {
const { data } = await axios.delete<AxiosResponse<TResponse>>(
`${url}/${dataToSend.id}`,
{
headers: {
[AxiosEnum.HEADER_KEY]: key,
[AxiosEnum.HEADER_CUSTOM_MESSAGE]: message,
},
},
);
return data;
},
});
}
export default useDeleteMutation;

View File

@ -0,0 +1,23 @@
import { useQuery } from '@tanstack/react-query';
import useAxios from './useAxios';
function useGetQuery(
KEY: string | string[],
url: string,
params: Record<string, any> = {},
options: Record<string, any> = {},
) {
const axios = useAxios();
const KEYS = typeof KEY === 'string' ? [KEY, params] : [...KEY, params];
return useQuery({
queryKey: KEYS,
queryFn: async () => {
const response = await axios.get(url, { params });
return response?.data ?? [];
},
...options,
});
}
export default useGetQuery;

View File

@ -0,0 +1,41 @@
import { useQuery } from '@tanstack/react-query';
import useAxios from './useAxios';
import { QueryPaginationEnum } from '../../enums/TankStackQueryEnum';
function useGetQueryPagination(
KEY: string | string[],
url: string,
params: Record<string, any> = {},
options: Record<string, any> = {},
) {
const axios = useAxios();
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const page = urlParams.get('page') || QueryPaginationEnum.DEFAULT_PAGE;
const per_page =
urlParams.get('per_page') || QueryPaginationEnum.DEFAULT_PER_PAGE;
const KEYS =
typeof KEY === 'string'
? [KEY, params, page, per_page]
: [...KEY, params, page, per_page];
return useQuery({
queryKey: KEYS,
queryFn: async () => {
const response = await axios.get(url, {
params: {
...params,
page,
per_page,
},
});
return (response?.data as any) ?? [];
},
...options,
});
}
export default useGetQueryPagination;

View File

@ -0,0 +1,48 @@
import { useMutation, UseMutationResult } from '@tanstack/react-query';
import useAxios from './useAxios'; // Adjust the import path as necessary
import { AxiosEnum } from '../../enums/Axios';
type DataToSend = {
id: number | string;
newData: any; // Define the type for updated data
};
interface AxiosResponse<T = any> {
data: T;
status: number;
statusText: string;
headers: Record<string, any>;
config: Record<string, any>;
request?: any;
}
function useUpdateMutation<TResponse = any>(
key: string,
url: string,
message: string = '',
): UseMutationResult<AxiosResponse<TResponse>, unknown, DataToSend, unknown> {
const axios = useAxios();
return useMutation<AxiosResponse<TResponse>, unknown, DataToSend, unknown>({
mutationFn: async (dataToSend: DataToSend) => {
const { id, newData } = dataToSend;
const newUrl = `${url}/${id}`;
const MutateData =
newData instanceof FormData ? newData : { ...newData, _method: 'PUT' };
const { data } = await axios.post<AxiosResponse<TResponse>>(
newUrl,
MutateData,
{
headers: {
'Content-Type': 'multipart/form-data',
[AxiosEnum.HEADER_KEY]: key,
[AxiosEnum.HEADER_CUSTOM_MESSAGE]: message,
},
},
);
return data;
},
});
}
export default useUpdateMutation;

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

1
src/assets/core/logo.svg Normal file
View File

@ -0,0 +1 @@
<svg fill="none" height="28" viewBox="0 0 115 28" width="115" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path clip-rule="evenodd" d="m54.834 0h5.3192v4.75959h-4.207c-1.1108 0-1.6677.55492-1.6677 1.6662v.95192h5.8745v-.00103h5.5963v20.38432h-5.5963v-15.6643h-5.8745v15.6465h-5.2518l.0151.0179h-6.6809l-7.8498-9.4236v9.4236h-5.589l-.0014-.0015v-27.483864h5.589v16.491164l7.8512-9.39018h6.3214v-1.78548c0-1.79807.5163-3.17885 1.5474-4.14381 1.0325-.964954 2.5668-1.44743 4.6043-1.44743zm-6.1517 7.80026-8.2777 9.75194 8.2777 9.7839z" fill-rule="evenodd"/><path d="m27.269 27.7436v-11.0651h.0015c0-3.4107-.7686-5.8564-2.3029-7.33716-1.5343-1.48075-3.4934-2.22113-5.8746-2.22113-1.4821 0-2.7263.24341-3.7313.73313s-1.8649 1.1707-2.5799 2.04292l-.5162-2.53844h-4.88276v20.38728h5.59616v-10.4306c0-1.7719.3974-3.1469 1.1907-4.1249.7946-.978 1.9185-1.4677 3.3745-1.4677 2.7524 0 4.1286 1.7575 4.1286 5.2739v10.7478z"/><path d="m5.59623 27.7418v-20.38437h-5.59623v20.38437z"/><path d="m73.4106 23.1607c.7932.555 1.8127.8331 3.0569.8331 1.2443 0 2.1304-.1912 2.8177-.5752.6874-.3839 1.0326-.9316 1.0326-1.6459 0-.5288-.1581-.9258-.4757-1.1895-.3176-.2652-.7672-.4564-1.3501-.5752-.5815-.1188-1.5343-.2579-2.8583-.4159-1.7997-.2376-3.2948-.5418-4.4854-.9128-1.1906-.3694-2.1433-.9519-2.8583-1.7444-.7149-.7926-1.0717-1.8502-1.0717-3.1731 0-1.3228.364-2.492 1.092-3.5092.728-1.01854 1.7533-1.80382 3.0758-2.36019 1.3226-.55493 2.8453-.83312 4.5652-.83312 2.7785.02608 5.0219.62157 6.7288 1.78502 1.7068 1.16349 2.6262 2.77609 2.7582 4.83779h-5.3192c-.0798-.7664-.4829-1.3952-1.2109-1.8835-.728-.4897-1.6605-.7331-2.7988-.7331-1.0587 0-1.9114.1985-2.5596.5955-.6482.3969-.9731.9258-.9731 1.5865 0 .4752.1726.8331.5163 1.0707s.7932.41 1.3501.5158c.5554.1058 1.4821.2246 2.7785.3564 2.7524.3173 4.8625.9056 6.3315 1.7648s2.2028 2.3327 2.2028 4.422c0 1.3213-.3901 2.4848-1.1703 3.4903-.7802 1.0041-1.8649 1.7778-3.2556 2.3197-1.3893.5419-2.9975.8128-4.8233.8128-2.8307 0-5.1336-.6274-6.9072-1.8835-1.7735-1.2562-2.7118-2.9674-2.8177-5.1363h5.3193c.0797.8983.5162 1.6256 1.3095 2.1805z"/><path d="m106.754 27.762v-11.0651c0-3.4106-.773-5.8564-2.321-7.33712-1.548-1.48075-3.42-2.22114-5.9344-2.22114-2.5147 0-4.526.9128-6.0342 2.73694v-9.87558h-5.5963v27.7606h5.5963v-10.4696c0-1.7445.4031-3.1064 1.2109-4.0844.8077-.978 1.978-1.4677 3.3542-1.4677s2.4087.4433 3.0965 1.3286c.688.8867 1.032 2.1747 1.032 3.867v10.8275z"/><g clip-rule="evenodd" fill-rule="evenodd"><path d="m112.545 22.6713c.274.2304.412.5376.412.923 0 .2419-.061.4564-.182.6418-.12.1855-.297.3347-.527.4448l.758 1.3997h-1.038l-.643-1.1867h-.445v1.1867h-.94v-3.7555h1.517c.451 0 .814.1159 1.088.3462zm-1.139 1.433c.176 0 .317-.0464.421-.1406.104-.0927.157-.2173.157-.3709 0-.1651-.05-.2912-.148-.3796-.099-.0884-.242-.1318-.43-.1318h-.527v1.0214h.527z"/><path d="m109.494 21.1312c.561-.313 1.17-.4695 1.83-.4695s1.286.1565 1.846.4695c.561.3129 1.006.7418 1.336 1.2851.329.5434.494 1.1389.494 1.788s-.165 1.2605-.494 1.8038c-.33.5434-.775.9722-1.336 1.2852-.561.3129-1.176.4694-1.846.4694s-1.271-.1565-1.83-.4694c-.562-.313-1.007-.7418-1.336-1.2852-.329-.5433-.494-1.1388-.494-1.7879s.165-1.2605.494-1.8039c.329-.5433.774-.9722 1.336-1.2851zm3.223.6998c-.423-.242-.887-.3622-1.393-.3622s-.965.1202-1.376.3622c-.412.242-.74.5737-.982.9968s-.363.8925-.363 1.4083.121.9635.363 1.375.568.739.982.9809c.413.242.871.3622 1.376.3622.504 0 .97-.1202 1.393-.3622.424-.2419.756-.5708.998-.9881s.363-.878.363-1.3837-.121-.9693-.363-1.3924-.574-.7548-.998-.9968z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="42.67" height="32" viewBox="0 0 640 480"><defs><clipPath id="flagUm4x30"><path fill-opacity=".7" d="M0 0h682.7v512H0z"/></clipPath></defs><g fill-rule="evenodd" clip-path="url(#flagUm4x30)" transform="scale(.9375)"><g stroke-width="1pt"><path fill="#bd3d44" d="M0 0h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.7h972.8V197H0zm0 78.8h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.7h972.8v39.4H0zm0 78.8h972.8V512H0z"/><path fill="#fff" d="M0 39.4h972.8v39.4H0zm0 78.8h972.8v39.3H0zm0 78.7h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.8h972.8v39.4H0zm0 78.7h972.8v39.4H0z"/></g><path fill="#192f5d" d="M0 0h389.1v275.7H0z"/><path fill="#fff" d="M32.4 11.8L36 22.7h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H29zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9H177l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9H242l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.2-6.7h11.4zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zM64.9 39.4l3.5 10.9h11.5L70.6 57L74 67.9l-9-6.7l-9.3 6.7L59 57l-9-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.3 6.7L124 57l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.7l-9.3 6.7l3.5-10.9l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5L330 57l3.5 10.9l-9.2-6.7l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zM32.4 66.9L36 78h11.4l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.3-6.7H29zm64.9 0l3.5 11h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7h11.4zm64.8 0l3.6 11H177l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.3-6.7h11.5zm64.9 0l3.5 11H242l-9.3 6.7l3.6 10.9l-9.3-6.8l-9.3 6.8l3.6-11l-9.3-6.7h11.4zm64.8 0l3.6 11h11.4l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.2-6.7h11.4zm64.9 0l3.5 11h11.5l-9.3 6.7l3.6 10.9l-9.3-6.8l-9.3 6.8l3.6-11l-9.3-6.7h11.5zM64.9 94.5l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zM32.4 122.1L36 133h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H29zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.7l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9H177l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9H242l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.2-6.7h11.4zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zM64.9 149.7l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 10.9l-9.3-6.8l-9.3 6.8l3.6-11l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 10.9l-9.3-6.8l-9.2 6.8l3.5-11l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 10.9l-9.2-6.8l-9.3 6.8l3.5-11l-9.2-6.7h11.4zM32.4 177.2l3.6 11h11.4l-9.2 6.7l3.5 10.8l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.3-6.7H29zm64.9 0l3.5 11h11.5l-9.3 6.7l3.6 10.8l-9.3-6.7l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 11H177l-9.2 6.7l3.5 10.8l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.3-6.7h11.5zm64.9 0l3.5 11H242l-9.3 6.7l3.6 10.8l-9.3-6.7l-9.3 6.7l3.6-10.9l-9.3-6.7h11.4zm64.8 0l3.6 11h11.4l-9.2 6.7l3.5 10.8l-9.3-6.7l-9.2 6.7l3.5-10.9l-9.2-6.7h11.4zm64.9 0l3.5 11h11.5l-9.3 6.7l3.6 10.8l-9.3-6.7l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zM64.9 204.8l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.3 6.7l3.6 11l-9.3-6.8l-9.3 6.7l3.6-10.9l-9.3-6.7h11.5zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7H191zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 11l-9.3-6.8l-9.2 6.7l3.5-10.9l-9.3-6.7H256zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.5 11l-9.2-6.8l-9.3 6.7l3.5-10.9l-9.2-6.7h11.4zM32.4 232.4l3.6 10.9h11.4l-9.2 6.7l3.5 10.9l-9.3-6.7l-9.2 6.7l3.5-11l-9.3-6.7H29zm64.9 0l3.5 10.9h11.5L103 250l3.6 10.9l-9.3-6.7l-9.3 6.7l3.6-11l-9.3-6.7h11.4zm64.8 0l3.6 10.9H177l-9 6.7l3.5 10.9l-9.3-6.7l-9.2 6.7l3.5-11l-9.3-6.7h11.5zm64.9 0l3.5 10.9H242l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.3 6.7l3.6-11l-9.3-6.7h11.4zm64.8 0l3.6 10.9h11.4l-9.2 6.7l3.5 10.9l-9.3-6.7l-9.2 6.7l3.5-11l-9.2-6.7h11.4zm64.9 0l3.5 10.9h11.5l-9.3 6.7l3.6 10.9l-9.3-6.7l-9.3 6.7l3.6-11l-9.3-6.7h11.5z"/></g></svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,14 @@
<svg width="520" height="81" viewBox="0 0 520 81" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M455 16.0003H390V32.0006H455V16.0003Z" fill="red"/>
<path d="M325 16.0003H260V32.0006H325V16.0003Z" fill="red"/>
<path d="M195 16.0003H130V32.0006H195V16.0003Z" fill="red"/>
<path d="M64.9997 16.0003H0V32.0006H64.9997V16.0003Z" fill="red"/>
<path d="M520 31.9998L455 32.0006L455 48H520V31.9998Z" fill="red"/>
<path d="M260.001 0H195.001V16.0002L260 16.0003L260.001 0Z" fill="red"/>
<path d="M130 0H64.9999L64.9997 16.0003H130L130 0Z" fill="red"/>
<path d="M260.001 31.9998H195.001V48H260.001V31.9998Z" fill="red"/>
<path d="M195 64.5H260V81H195V64.5Z" fill="red"/>
<path d="M325 64.5H390V81H325V64.5Z" fill="red"/>
<path d="M455 64.5H520V81H455V64.5Z" fill="red"/>
<path d="M390 48H455L455 64.5H390L390 48Z" fill="red"/>
</svg>

After

Width:  |  Height:  |  Size: 835 B

View File

@ -0,0 +1,46 @@
import React from 'react'
const Left = () => {
const Left = [
{
title: "المكتب الرئيسي",
image: "/contact/1.png",
value: "121 King St , ملبورن VIC 3000, أستراليا"
},
{
title: "المكتب الرئيسي",
image: "/contact/2.png",
value: "121 King St , ملبورن VIC 3000, أستراليا"
},
{
title: "المكتب الرئيسي",
image: "/contact/3.png",
value: "121 King St , ملبورن VIC 3000, أستراليا"
}
]
return (
<div className='Left'>
<h1> تواصل معنا </h1>
<p>
من السهل جدا الاتصال بنا. ما عليك سوى استخدام نموذج الاتصال أو زيارتنا في المكتب. ابتكار التكنولوجيا التنافسية ديناميكيا بعد مجموعة موسعة من القيادة.
</p>
<div>
{Left?.map((item, index) => {
return (
<span key={index}>
<div>
<img src={item.image} alt="" />
<h6> {item.title} </h6>
</div>
<p> {item.value} </p>
</span>
)
})}
</div>
</div>
)
}
export default Left

View File

@ -0,0 +1,32 @@
import { Form, Formik } from 'formik'
import React from 'react'
import InputField from '../Field/InputField'
import TextAreaField from '../Field/TextAreaField'
const Right = () => {
const handleSubmit = ()=>{
}
return (
<div className='Right'>
<h1>تواصل معنا بسرعة</h1>
<Formik initialValues={handleSubmit} onSubmit={handleSubmit} >
<Form>
<div className='Forms'>
<InputField name='name' placeholder='أدخل الاسم' />
<InputField name='email' placeholder='أدخل البريد الإلكتروني' />
<InputField name='number' placeholder='هاتفك' />
<InputField name='company' placeholder='شركتك' />
<TextAreaField name='message' placeholder='رسالة' />
</div>
<button className='scale' >
ارسل رسالة
</button>
</Form>
</Formik>
</div>
)
}
export default Right

View File

@ -0,0 +1,25 @@
import { Input, InputProps } from "antd";
import React from "react";
import { Field } from "formik";
const InputField = ({
name,
...props
}: InputProps) => {
return (
<div className="ValidationField w-100">
<Field
as={Input}
name={name}
id={name}
size="large"
styles={{width:"100%"}}
{...props}
/>
</div>
);
};
export default React.memo(InputField);

View File

@ -0,0 +1,27 @@
import { InputProps } from "antd";
import React from "react";
import { Field } from "formik";
import TextArea from "antd/es/input/TextArea";
const TextAreaField = ({
name,
...props
}: InputProps) => {
return (
<div className="ValidationField TextAreaField">
<Field
as={TextArea}
name={name}
id={name}
size="large"
styles={{width:"100%"}}
autoSize={{ minRows: 4, maxRows: 10 }}
{...props}
/>
</div>
);
};
export default React.memo(TextAreaField);

View File

@ -0,0 +1,67 @@
import React from 'react';
// Import Swiper React components
import { Pagination, A11y ,Autoplay} from 'swiper/modules';
import { Swiper, SwiperSlide } from 'swiper/react';
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
import 'swiper/css/scrollbar';
const SwipeScreenShoot = () => {
const SwipeScreenShoot = [
{ image: "/SwipeScreenShoot/1.png" },
{ image: "/SwipeScreenShoot/2.png" },
{ image: "/SwipeScreenShoot/3.png" },
{ image: "/SwipeScreenShoot/4.png" },
{ image: "/SwipeScreenShoot/1.png" },
{ image: "/SwipeScreenShoot/2.png" },
{ image: "/SwipeScreenShoot/3.png" },
{ image: "/SwipeScreenShoot/1.png" },
{ image: "/SwipeScreenShoot/2.png" },
{ image: "/SwipeScreenShoot/3.png" },
{ image: "/SwipeScreenShoot/4.png" },
{ image: "/SwipeScreenShoot/1.png" },
{ image: "/SwipeScreenShoot/2.png" },
{ image: "/SwipeScreenShoot/3.png" },
];
return (
<div className='SwipeScreenShoot'>
<Swiper
modules={[Pagination, A11y, Autoplay]}
spaceBetween={10}
autoplay={{ delay: 3000 }} // Configure autoplay options
pagination={{ clickable: true }}
onSwiper={(swiper) => console.log(swiper)}
onSlideChange={() => console.log('slide change')}
breakpoints={{
400: {
slidesPerView: 1,
},
800: {
slidesPerView: 2,
},
1200: {
slidesPerView: 3,
},
1500: {
slidesPerView: 5,
},
2000: {
slidesPerView: 7,
},
}}
>
{SwipeScreenShoot.map((item, index) => (
<SwiperSlide key={index}>
<img src={item.image} alt={`Screenshot ${index + 1}`} />
</SwiperSlide>
))}
</Swiper>
</div>
);
}
export default SwipeScreenShoot;

View File

@ -0,0 +1,33 @@
import { Input } from "antd";
import { FaFacebook, FaInstagram, FaTelegram, FaTwitter } from "react-icons/fa";
const Footer = () => {
return (
<div className="Footer">
<img src="/LOGO.png" alt="logo" />
<div>
<FaTelegram/>
<FaFacebook/>
<FaInstagram/>
<FaTwitter/>
</div>
<p>
© زاكر 2024.جميع الحقوق محفوظة
</p>
<span className="FooterHeader">
<span>
<h1>اشترك في نشرتنا الإخبارية</h1>
<p>نحن فريق من غير المتشائمين الذين يهتمون حقا بعملنا.</p>
</span>
<div>
<Input placeholder="أدخل بريدك الإلكتروني" />
<div>
<FaTelegram/>
</div>
</div>
</span>
</div>
)
};
export default Footer;

View File

@ -0,0 +1,15 @@
import React from 'react';
import NavBar from './NavBar';
import Footer from './Footer';
const Layout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="Layout">
<NavBar />
{children}
<Footer />
</div>
);
};
export default Layout;

View File

@ -0,0 +1,87 @@
// NavBar.tsx
import React, { useState } from 'react';
import { RoutesEnums } from '../../enums/RoutesEnums';
import { useTranslation } from 'react-i18next';
import { MdLanguage } from "react-icons/md";
import { FaEllipsis } from 'react-icons/fa6';
import { Popover } from 'antd';
// Define an enum for the routes
// Define a type for the link objects
interface NavLink {
path: RoutesEnums;
label: string;
}
const NavBar: React.FC = () => {
// Define an array of link objects using the RoutesEnums
const [t] = useTranslation()
const links: NavLink[] = [
{ path: RoutesEnums.HOME, label: t('home') },
{ path: RoutesEnums.FEATURES, label: t('features') },
{ path: RoutesEnums.HOW_IT_WORK, label: t('how_it_work') },
{ path: RoutesEnums.SCREEN_SHOOT, label: t('screen_shoot') },
{ path: RoutesEnums.NOTE, label: t('note') },
{ path: RoutesEnums.CONTACT, label: t('contact_us') },
];
const [Open, setOpen] = useState(false)
const handleToggle = ()=>{
setOpen(!Open)
}
const NavBarContent = (
<div className='NavBarContent'>
<ul className='NavBarLinks'>
{links.map((link) =>{
return (
<li onClick={handleToggle} key={link.path} className={`${"activeLink"}`}>
<a href={link.path}>{link.label}</a>
</li>
)
})}
</ul>
</div>
);
const [Active, setActive] = useState(location.hash)
console.log(Active);
return (
<nav className='NavBar'>
<img src="/LOGO.png" className='scale' alt="" />
<ul className='NavBarLinks'>
{links.map((link) =>{
const handleClick =()=>{
setActive(link.path)
}
const isActive = Active === "" && link.path === "#" ? true : Active === link.path;
return (
<li key={link.path} onClick={handleClick} className={`${isActive ? "activeLink" : ""}`}>
<a href={link.path}>{link.label}</a>
</li>
)
})}
</ul>
<div>
<MdLanguage />
<article>
<Popover open={Open} content={NavBarContent} >
<FaEllipsis onClick={handleToggle} />
</Popover>
</article>
</div>
</nav>
);
};
export default NavBar;

View File

@ -0,0 +1,21 @@
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
function NotFoundPage() {
const navigate = useNavigate();
const [t] = useTranslation();
const handleNavigate = () => {
navigate('/');
};
return (
<div className="notFoundPage">
<div className="containerNotFound">
<p>404 | {t('This_page_could_not_be_found')}</p>
<div>
<button onClick={handleNavigate}>{t('home')}</button>
</div>
</div>
</div>
);
}
export default NotFoundPage;

View File

@ -0,0 +1,47 @@
import React, { useState, useEffect, ReactNode } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
interface PageTransitionProps {
to: string;
children: ReactNode;
}
const PageTransition: React.FC<PageTransitionProps> = ({ to, children }) => {
const [transitioning, setTransitioning] = useState(false);
const [reversed, setReversed] = useState(false);
const navigate = useNavigate();
const location = useLocation();
const handleClick = () => {
if (location.pathname === to) {
return; // Prevent navigation to the same route
}
setTransitioning(true);
setTimeout(() => {
navigate(to);
setReversed(true); // Set reversed for the entrance animation
}, 1000); // Match this timing with the exit animation duration
};
useEffect(() => {
if (reversed) {
setTimeout(() => {
setReversed(false); // Clear the reversed state after the animation
setTransitioning(false);
}, 1000); // Match this timing with the entrance animation duration
}
}, [reversed]);
return (
<>
<div
className={`transition-overlay ${transitioning ? (reversed ? 'enter' : 'exit') : ''}`}
/>
<div onClick={handleClick}>
{children}
</div>
</>
);
};
export default PageTransition;

View File

@ -0,0 +1,12 @@
import React from 'react';
const SpinContainer: React.FC = () => {
return (
<div className='full-screen-center'>
<div className="loader"></div>
</div>
);
};
export default SpinContainer;

View File

@ -0,0 +1,59 @@
import React, { useEffect, useState } from 'react';
import { Logo } from '../utils';
interface FirstLoadingProps {
seconds: number;
children: React.ReactNode; // Add children prop
}
const FirstLoading: React.FC<FirstLoadingProps> = ({ seconds,children }) => {
const [currentNumber, setCurrentNumber] = useState(1);
const [animate, setAnimate] = useState(false);
const [pageUp, setPageUp] = useState(false); // New state for page movement
const totalNumbers = 100;
useEffect(() => {
const intervalTime = (seconds * 1000) / totalNumbers;
const interval = setInterval(() => {
setCurrentNumber((prev) => {
if (prev < totalNumbers) {
setAnimate(true);
return prev + 1;
} else {
setPageUp(true); // Trigger page movement
clearInterval(interval);
return prev;
}
});
}, intervalTime);
return () => clearInterval(interval);
}, [seconds]);
useEffect(() => {
if (animate) {
const timer = setTimeout(() => setAnimate(false), 500);
return () => clearTimeout(timer);
}
}, [animate]);
return (
<>
<div className={`FirstLoading ${pageUp ? 'PageUp' : ''}`}>
<div>
<img src={Logo} className='Logo' alt="" />
<div className={`Info`}>
[{currentNumber} %]
</div>
</div>
</div>
{
pageUp && children
}
</>
);
};
export default FirstLoading;

28
src/enums/Axios.ts Normal file
View File

@ -0,0 +1,28 @@
export enum AxiosQueryEnum {
GET = 'get',
POST = 'post',
DELETE = 'delete',
}
export enum AxiosStatusEnum {
VALIDATION = 422,
AUTHENTICATED = 401,
}
export enum AxiosEnum {
BASEURL = import.meta.env.REACT_APP_BASE_URL,
IMAGE_BASE_URL = 'http://localhost:8000',
HEADER_KEY = 'X-Custom-Query-Key',
HEADER_CUSTOM_MESSAGE = 'X-Custom-message',
RESPONSE_TYPE = 'json',
TIMEOUT = 120000,
BEARER = 'Bearer ',
}
export enum AxiosQueryStatusEnum {
ERROR = 'error',
IDLE = 'idle',
PENDING = 'pending',
SUCCESS = 'success',
}

View File

@ -0,0 +1,8 @@
export enum LocalStorageEnum {
PROJECT_NAME = 'NERD',
LANGUAGE_KEY = LocalStorageEnum.PROJECT_NAME + '_L',
THEME_KEY = LocalStorageEnum.PROJECT_NAME + '_T',
TOKEN_KEY = LocalStorageEnum.PROJECT_NAME + '_TK',
USER_KEY = LocalStorageEnum.PROJECT_NAME + '_UK',
ABILITIES_KEY = LocalStorageEnum.PROJECT_NAME + '_AK',
}

8
src/enums/RoutesEnums.ts Normal file
View File

@ -0,0 +1,8 @@
export enum RoutesEnums {
HOME = '#',
FEATURES = '#features',
HOW_IT_WORK = '#how_it_work',
SCREEN_SHOOT = '#screen_shoot',
NOTE = '#note',
CONTACT = '#contact_us',
}

View File

@ -0,0 +1,11 @@
export enum QueryPaginationEnum {
DEFAULT_PER_PAGE = 10,
DEFAULT_PAGE = 1,
}
export enum QueryStatusEnum {
ERROR = 'error',
IDLE = 'idle',
PENDING = 'pending',
SUCCESS = 'success',
}

View File

@ -0,0 +1,52 @@
import { useState, useCallback, useEffect } from 'react';
import i18n from 'i18next';
import { setLanguageDirection } from '../utils/document/setLanguageDirection';
import { LocalStorageEnum } from '../enums/LocalStorage';
import en from '../../../assets/language/en.svg';
import ar from '../../../assets/language/ar.svg';
import { LocalStorageManager } from '../utils/class/LocalStorageManager';
const validLanguages = ['en', 'ar'];
export const useChangeLanguage = () => {
const getInitialLanguage = () => {
const storedLanguage = LocalStorageManager.getItem(
LocalStorageEnum.LANGUAGE_KEY,
) as string;
return validLanguages.includes(storedLanguage) ? storedLanguage : 'ar';
};
const [currentLanguage, setCurrentLanguage] =
useState<string>(getInitialLanguage());
const changeLanguage = useCallback((newLanguage: string) => {
if (validLanguages.includes(newLanguage)) {
setCurrentLanguage(newLanguage);
} else {
console.error(`Invalid language code: ${newLanguage}`);
}
}, []);
useEffect(() => {
const applyLanguage = async () => {
try {
await i18n.changeLanguage(currentLanguage);
setLanguageDirection(currentLanguage);
LocalStorageManager.setItem(
LocalStorageEnum.LANGUAGE_KEY,
currentLanguage,
);
} catch (error) {
console.error('Error changing language:', error);
}
};
applyLanguage();
}, [currentLanguage]);
return { currentLanguage, changeLanguage };
};
export const languageOptions = [
{ code: 'ar', icon: ar, label: 'Arabic' },
{ code: 'en', icon: en, label: 'English' },
];

29
src/hooks/useTheme.ts Normal file
View File

@ -0,0 +1,29 @@
import { useState, useEffect } from 'react';
import { LocalStorageEnum } from '../enums/LocalStorage';
import { LocalStorageManager } from '../utils/class/LocalStorageManager';
function useTheme(): [string, () => void] {
const [theme, setTheme] = useState(() => {
const storedTheme = LocalStorageManager.getItem(
LocalStorageEnum.THEME_KEY,
) as string;
return storedTheme ? storedTheme : 'light';
});
useEffect(() => {
// Update the body class when the theme changes
document.body.classList.remove(theme === 'light' ? 'dark' : 'light');
document.body.classList.add(theme);
// Save the new theme to local storage
LocalStorageManager.setItem(LocalStorageEnum.THEME_KEY, theme);
}, [theme]);
const changeTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return [theme, changeTheme];
}
export default useTheme;

23
src/lib/I18nProvider.tsx Normal file
View File

@ -0,0 +1,23 @@
import React, { ReactNode, useEffect } from 'react';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n'; // Import the pre-initialized i18n instance
import { LocalStorageEnum } from '../enums/LocalStorage';
import { LocalStorageManager } from '../utils/class/LocalStorageManager';
interface I18nProviderProps {
children: ReactNode;
}
const I18nProvider: React.FC<I18nProviderProps> = ({ children }) => {
useEffect(() => {
const currentLanguage =(LocalStorageManager.getItem(LocalStorageEnum.LANGUAGE_KEY) as string) ===
'en'
? 'en'
: 'ar';
i18n.changeLanguage(currentLanguage);
}, []);
return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
};
export default I18nProvider;

View File

@ -0,0 +1,17 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
function QueryProvider({ children }: { children: React.ReactNode }) {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
});
return (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}
export default QueryProvider;

22
src/lib/i18n.ts Normal file
View File

@ -0,0 +1,22 @@
// i18n.ts
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import translationEN from '../translate/en.json';
import translationAR from '../translate/ar.json';
i18n.use(initReactI18next).init({
resources: {
en: {
translation: translationEN,
},
ar: {
translation: translationAR,
},
},
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
});
export default i18n;

0
src/lib/index.ts Normal file
View File

4
src/main.tsx Normal file
View File

@ -0,0 +1,4 @@
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
createRoot(document.getElementById('root')!).render(<App />);

9
src/pages/AboutUs.tsx Normal file
View File

@ -0,0 +1,9 @@
import React from 'react'
const AboutUs = () => {
return (
<div className='AboutUs'>AboutUs</div>
)
}
export default AboutUs

15
src/pages/ContactPage.tsx Normal file
View File

@ -0,0 +1,15 @@
import React from 'react'
import Left from '../components/Contact/Left'
import Right from '../components/Contact/Right'
const ContactPage = () => {
return (
<div className='ContactPage' id='contact_us'>
<Left/>
<Right/>
</div>
)
}
export default ContactPage

View File

@ -0,0 +1,47 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { BsGooglePlay } from 'react-icons/bs'
import { FaApple } from 'react-icons/fa'
const DownloadPage = () => {
const { t } = useTranslation()
return (
<div className='DownloadPage' >
<main>
<h1>متوفر الآن على</h1>
<p>ابدأ العمل مع ذلك الذي يمكن أن يوفر كل ما تحتاجه لتوليد الوعي وزيادة حركة المرور والتواصل. تحويل القيمة الدقيقة بكفاءة من خلال المحتوى الذي يركز على العميل.</p>
<div>
<button>
<div>
<BsGooglePlay />
</div>
<div>
<h6>{t('download_on')}</h6>
<h5>{t('play_store')}</h5>
</div>
</button>
<button>
<div>
<FaApple />
</div>
<div>
<h6>{t('available_on')}</h6>
<h5>{t('google_play')}</h5>
</div>
</button>
</div>
</main>
<div>
<img className='circle' src="/circle.png" alt="" />
</div>
<img className='main scale' src="/Download/1.png" alt="" />
</div>
)
}
export default DownloadPage

View File

@ -0,0 +1,68 @@
import { useTranslation } from 'react-i18next'
const FeaturesPage = () => {
const features = [
{
"img": "1",
"title": "Friendly_Online_Support",
"description": "Providing_round_the_clock_technical_support_to_assist_you_with_any_inquiries"
},
{
"img": "2",
"title": "Unlimited_Features",
"description": "Enjoy_limitless_possibilities_to_customize_your_experience"
},
{
"img": "3",
"title": "Modular_and_Switchable_Component",
"description": "Easily_switch_between_layouts_and_even_demos"
},
{
"img": "4",
"title": "High_Resolution",
"description": "Get_high_quality_images_and_videos"
},
{
"img": "5",
"title": "Social_Sharing",
"description": "Easily_share_content_across_social_media_platforms"
},
{
"img": "6",
"title": "Use_on_Any_Device",
"description": "Compatibility_with_all_devices_for_a_seamless_experience"
}
]
const [t] = useTranslation()
return (
<div className='FeaturesPage' id='features'>
<h1> {t("Application_Features")} </h1>
<p> {t("Providing_professional_value_objectively_with_varied_web_readiness_Collaborative_wireless_customer_service_without_targeted_incentives_for_change_Collaboration")} </p>
<div>
<span>
{features.map((item, index) => {
return (
<article key={index}>
<img className='scale' src={`/Features/${item.img}.png`} alt={`${index}`} />
<div>
<h4>
{t(item.title)}
</h4>
<p>
{t(item.description)}
</p>
</div>
</article>
)
})}
</span>
<img className='scale' src="/Features/main.png" alt="" />
</div>
</div>
)
}
export default FeaturesPage

41
src/pages/HomePage.tsx Normal file
View File

@ -0,0 +1,41 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
import { BsGooglePlay } from 'react-icons/bs'
import { FaApple } from 'react-icons/fa'
const HomePage = () => {
const { t } = useTranslation()
return (
<div className='HomePage' id='#'>
<main>
<h1>{t('get_free_download')} <h2>{t('quiz_app')}</h2></h1>
<p>{t('reader_distracted')}</p>
<div>
<button>
<div>
<BsGooglePlay />
</div>
<div>
<h6>{t('download_on')}</h6>
<h5>{t('play_store')}</h5>
</div>
</button>
<button>
<div>
<FaApple />
</div>
<div>
<h6>{t('available_on')}</h6>
<h5>{t('google_play')}</h5>
</div>
</button>
</div>
</main>
<img className='circle' src="/circle.png" alt="" />
<img className='shape' src="/shape.svg" alt="" />
<img className='slider' src="/Slider.png" alt="" />
</div>
)
}
export default HomePage

77
src/pages/HowItWork.tsx Normal file
View File

@ -0,0 +1,77 @@
import React from 'react'
import { useTranslation } from 'react-i18next'
const HowItWork = () => {
const HowItWorks = [
{
"img": "1",
"title": "Friendly_Online_Support",
"description": "Providing_round_the_clock_technical_support_to_assist_you_with_any_inquiries"
},
{
"img": "2",
"title": "Unlimited_Features",
"description": "Enjoy_limitless_possibilities_to_customize_your_experience"
},
{
"img": "3",
"title": "Modular_and_Switchable_Component",
"description": "Easily_switch_between_layouts_and_even_demos"
},
{
"img": "4",
"title": "High_Resolution",
"description": "Get_high_quality_images_and_videos"
},
]
const [t] = useTranslation()
return (
<div className='HowItWork' id='how_it_work'>
<h1> كيف يعمل؟ </h1>
<p>
استضافة احترافية بسعر مناسب. تلخيص الكفاءات الأساسية التي تركز على المبدأ بشكل مميز من خلال الكفاءات الأساسية التي تركز على العميل.
</p>
<div>
<span>
{HowItWorks.slice(0,2).map((item, index) => {
return (
<article key={index}>
<img className='scale' src={`/HowItWorks/${item.img}.png`} alt={`${index}`} />
<div>
<h4>
{t(item.title)}
</h4>
<p>
{t(item.description)}
</p>
</div>
</article>
)
})}
</span>
<img className='scale' src="/HowItWorks/main.png" alt="" />
<span>
{HowItWorks.slice(2,4).map((item, index) => {
return (
<article key={index}>
<img src={`/HowItWorks/${item.img}.png`} alt={`${index}`} />
<div>
<h4>
{t(item.title)}
</h4>
<p>
{t(item.description)}
</p>
</div>
</article>
)
})}
</span>
</div>
</div>
)
}
export default HowItWork

58
src/pages/NotePage.tsx Normal file
View File

@ -0,0 +1,58 @@
import React from 'react'
import { Rate } from 'antd';
const NotePage = () => {
const Note = [
{
description:"تسهيل الضرورات الوظيفية بشكل جوهري بدون خدمات وصفية من الجيل التالي. إحداث ثورة مقنعة في المستخدمين في جميع أنحاء العالم مقابل أفضل ممارسات المؤسسة",
rate:4,
img:"/Note/1.png",
name:"إليسا اسكندر"
},
{
description:"تسهيل الضرورات الوظيفية بشكل جوهري بدون خدمات وصفية من الجيل التالي. إحداث ثورة مقنعة في المستخدمين في جميع أنحاء العالم مقابل أفضل ممارسات المؤسسة",
rate:4,
img:"/Note/1.png",
name:"إليسا اسكندر"
},
{
description:"تسهيل الضرورات الوظيفية بشكل جوهري بدون خدمات وصفية من الجيل التالي. إحداث ثورة مقنعة في المستخدمين في جميع أنحاء العالم مقابل أفضل ممارسات المؤسسة",
rate:4,
img:"/Note/1.png",
name:"إليسا اسكندر"
},
]
return (
<div className='NotePage' id='note' >
<h1> ماذا يقول عملاؤنا عن ذاكر </h1>
<p>
استضافة احترافية بسعر مناسب. تلخيص الكفاءات الأساسية التي تركز على المبدأ بشكل مميز من خلال الكفاءات الأساسية التي تركز على العميل.
</p>
<div>
{Note.map((item,index:number)=>{
return (
<article key={index}>
<div>
<p>
{item.description}
</p>
<Rate value={item.rate} />
</div>
<span>
<img src={item.img} alt="" />
<h5> {item.name} </h5>
</span>
</article>
)
})}
</div>
</div>
)
}
export default NotePage

18
src/pages/ScreenShoot.tsx Normal file
View File

@ -0,0 +1,18 @@
import React from 'react'
import SwipeScreenShoot from '../components/SwiperScreenShoot'
const ScreenShoot = () => {
return (
<div className='ScreenShoot' id='screen_shoot'>
<h1> لقطات شاشة التطبيق </h1>
<p>
استضافة احترافية بسعر مناسب. تلخيص الكفاءات الأساسية التي تركز على المبدأ بشكل مميز من خلال الكفاءات الأساسية التي تركز على العميل.
</p>
<SwipeScreenShoot/>
</div>
)
}
export default ScreenShoot

67
src/pages/VideoPage.tsx Normal file
View File

@ -0,0 +1,67 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FaPlayCircle } from 'react-icons/fa';
import { PiPlayCircle } from 'react-icons/pi';
import ReactPlayer from 'react-player';
const VideoPage = () => {
const [isPlaying, setIsPlaying] = useState(false);
const [t] = useTranslation();
const details = [
{
"img": "1",
"title": "Friendly_Online_Support",
"number": "1111"
},
{
"img": "2",
"title": "Unlimited_Features",
"number": "2222"
},
{
"img": "3",
"title": "Modular_and_Switchable_Component",
"number": "3333"
},
{
"img": "4",
"title": "High_Resolution",
"number": "4444"
},
];
const handlePlayPause = () => {
setIsPlaying(!isPlaying);
};
return (
<div className='VideoPage'>
<img src="/Video/video.png" alt="" />
<main>
<h1>منصة التطبيق الأكثر استخداما</h1>
<p>
ابدأ العمل مع ذلك الذي يمكن أن يوفر كل ما تحتاجه لتوليد الوعي وزيادة حركة المرور والتواصل. تحويل القيمة الدقيقة بكفاءة من خلال المحتوى الذي يركز على العميل.
</p>
<img src="/Video/Play.png" alt="" />
</main>
<span>
{details.map((item, index) => (
<article key={index}>
<img src={`/Video/${item.img}.png`} alt={`${index}`} />
<h4>{t(item.number)}</h4>
<p>{t(item.title)}</p>
</article>
))}
</span>
</div>
);
};
export default VideoPage;

View File

@ -0,0 +1,16 @@
import { create } from 'zustand';
// Define the type of the object you are editing
interface EditableObject {
[key: string]: any;
}
interface ModelState {
objectToEdit: {};
setObjectToEdit: (data: EditableObject) => void;
}
export const useObjectToEdit = create<ModelState>((set) => ({
objectToEdit: {},
setObjectToEdit: (data) => set({ objectToEdit: data }),
}));

82
src/styles/App/App.scss Normal file
View File

@ -0,0 +1,82 @@
html,
body {
background: var(--bg);
color: var(--text);
overflow-x: hidden;
font-family: 'Noto Sans Arabic';
@include Scrollbar();
direction: rtl;
padding: 0;
margin: 0;
}
* {
padding: 0;
margin: 0;
font-weight: 600;
// font-size: 16px;
}
h1,
h2,
h3,
h4,
h5,
h6,
p {
padding: 0;
margin: 0;
}
a {
color: inherit;
text-decoration: none !important;
cursor: pointer;
}
button,
svg {
cursor: pointer;
}
i {
@include Flex;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-box-shadow: 0 0 0 30px var(--bg) inset !important;
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active {
-webkit-background-clip: text;
-webkit-text-fill-color: var(--text);
transition: background-color 5000s ease-in-out 0s;
box-shadow: inset 0 0 20px 20px #23232329;
}
button{
cursor: pointer;
transition: .5s ease-in-out;
&:hover{
scale: 1.02;
}
}
svg,.scale{
cursor: pointer;
transition: .5s ease-in-out;
&:hover{
scale: 1.1;
}
}

224
src/styles/App/Mixing.scss Normal file
View File

@ -0,0 +1,224 @@
@mixin Shadow {
box-shadow: 2px 2px 2px 3px rgba(0, 0, 0, 0.04);
}
@mixin Flex {
display: flex;
justify-content: center;
align-items: center;
}
@mixin Hover {
&:hover {
color: var(--secondary);
}
}
@mixin Hover_outline_characters {
&:hover {
text-shadow: 2px 2px var(--secondary);
}
}
@mixin underLineText($color1, $color2) {
background-image: linear-gradient(90deg, $color1, $color2);
background-size: 0% 3px;
background-repeat: no-repeat;
background-position: left bottom;
transition: background-size 500ms ease-in-out;
&:hover {
background-size: 100% 3px;
}
}
.underLineText {
background-image: linear-gradient(90deg, var(--primary), var(--secondary));
background-size: 0% 3px;
background-repeat: no-repeat;
background-position: left bottom;
transition: background-size 500ms ease-in-out;
&:hover {
background-size: 100% 3px;
}
}
@mixin Typewriter {
// border-right: 5px solid var(--secondary);
width: 100%;
word-spacing: nowrap;
text-wrap: nowrap;
overflow: hidden;
animation: typing 6s;
}
@keyframes typing {
from {
width: 0;
}
}
@mixin Glitch {
letter-spacing: 5px;
animation: shift 8s ease-in-out infinite alternate;
}
@keyframes shift {
0%,
40%,
44%,
58%,
61%,
65%,
69%,
73%,
100% {
transform: skewX(0deg);
}
41% {
transform: skewX(10deg);
}
42% {
transform: skewX(-10deg);
}
59% {
transform: skewX(40deg) skewY(10deg);
}
60% {
transform: skewX(-40deg) skewY(-10deg);
}
63% {
transform: skewX(10deg) skewY(-5deg);
}
70% {
transform: skewX(-50deg) skewY(-20deg);
}
71% {
transform: skewX(10deg) skewY(-10deg);
}
}
@mixin Scrollbar() {
scroll-behavior: smooth;
scroll-padding: 10rem;
&::-webkit-scrollbar {
width: 0.4vw;
max-height: 10px;
}
/* Handle */
&::-webkit-scrollbar-thumb {
background-color: var(--primary);
border-radius: 5px; /* Adjust border-radius as needed */
}
/* Track */
&::-webkit-scrollbar-track {
border-radius: 5px; /* Adjust border-radius as needed */
background-color: #d3d5d7; /* Set to desired background color */
}
}
@mixin CustomScrollbar($color) {
scroll-behavior: smooth;
scroll-padding: 10rem;
&::-webkit-scrollbar {
width: 10px;
}
/* Handle */
&::-webkit-scrollbar-thumb {
background-color: $color;
border-radius: 5px; /* Adjust border-radius as needed */
}
/* Track */
&::-webkit-scrollbar-track {
border-radius: 5px; /* Adjust border-radius as needed */
background-color: transparent; /* Set to desired background color */
}
}
@mixin ScrollbarHover($color) {
scroll-behavior: smooth;
scroll-padding: 10rem;
&::-webkit-scrollbar {
width: 6px;
}
/* Handle */
&::-webkit-scrollbar-thumb {
background-color: transparent;
border-radius: 3px; /* Adjust border-radius as needed */
}
&:hover {
&::-webkit-scrollbar-thumb {
background-color: $color;
border-radius: 3px; /* Adjust border-radius as needed */
}
}
/* Track */
&::-webkit-scrollbar-track {
background-color: transparent; /* Set to desired background color */
}
}
.maxWidth150 {
white-space: nowrap; /* Prevents text from wrapping */
overflow: hidden; /* Hides any content that overflows the container */
text-overflow: ellipsis;
max-width: 150px;
}
.maxWidth200 {
white-space: nowrap; /* Prevents text from wrapping */
overflow: hidden; /* Hides any content that overflows the container */
text-overflow: ellipsis;
max-width: 200px;
}
// background-color: rgb(
// /* Random value between 0 and 255 for red */
// calc(255 * random()),
// /* Random value between 0 and 255 for green */
// calc(255 * random()),
// /* Random value between 0 and 255 for blue */
// calc(255 * random())
// );
@mixin colorIndicator($color) {
color: var(--secondary);
position: relative;
text-align: center;
width: 3vw;
&::after {
background-color: $color;
position: absolute;
right: -1.4vw;
top: 50%;
transform: translate(-50%, -50%);
content: '';
width: 0.7vw;
height: 0.7vw;
border-radius: 50%;
}
}
/* Apply the mixin using CSS variables */
h6[data-color='Red'] {
@include colorIndicator(red);
}
h6[data-color='Green'] {
@include colorIndicator(green);
}
h6[data-color='Orange'] {
@include colorIndicator(orange);
}

Some files were not shown because too many files have changed in this diff Show More