├── src ├── index.css ├── hooks │ ├── useAuth.jsx │ └── useAxiosSecure.jsx ├── routes │ ├── PrivateRoute.jsx │ └── Routes.jsx ├── firebase │ └── Firebase.config.js ├── main.jsx ├── layouts │ ├── Main.jsx │ ├── loadingSpinner.json │ └── loadingSpinner2.json ├── pages │ ├── ErrorPage.jsx │ ├── Home.jsx │ ├── Blogs.jsx │ ├── AllJob.jsx │ ├── MyJobs.jsx │ ├── AppliedJobs.jsx │ ├── Login.jsx │ ├── JobDetails.jsx │ ├── Register.jsx │ ├── AddJob.jsx │ └── UpdateJob.jsx ├── components │ ├── AppliedJobsPDF.jsx │ ├── Banner.jsx │ ├── JobCard.jsx │ ├── JobByCategory.jsx │ ├── ContactUs.jsx │ ├── FaqSection.jsx │ ├── Footer.jsx │ └── Navbar.jsx ├── providers │ └── AuthProvider.jsx └── assets │ └── react.svg ├── .firebaserc ├── public ├── JobHorizon.png ├── bannerimg.png ├── JobHorizonCrop.png ├── JobHorizonCrop2.png └── vite.svg ├── postcss.config.js ├── vite.config.js ├── firebase.json ├── tailwind.config.js ├── .gitignore ├── .firebase ├── hosting.cHVibGlj.cache └── hosting.ZGlzdA.cache ├── index.html ├── .eslintrc.cjs └── package.json /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "b9a11-jobhorizon" 4 | } 5 | } 6 | 7 | -------------------------------------------------------------------------------- /public/JobHorizon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Job-Horizon-Client/HEAD/public/JobHorizon.png -------------------------------------------------------------------------------- /public/bannerimg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Job-Horizon-Client/HEAD/public/bannerimg.png -------------------------------------------------------------------------------- /public/JobHorizonCrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Job-Horizon-Client/HEAD/public/JobHorizonCrop.png -------------------------------------------------------------------------------- /public/JobHorizonCrop2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hazrat-Ali9/Job-Horizon-Client/HEAD/public/JobHorizonCrop2.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | 8 | // postcss config 9 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | 9 | // Vite Config 10 | -------------------------------------------------------------------------------- /src/hooks/useAuth.jsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { AuthContext } from "../providers/AuthProvider"; 3 | 4 | // Use Auth 5 | const useAuth = () => { 6 | const auth = useContext(AuthContext) 7 | return auth 8 | } 9 | 10 | export default useAuth; -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "dist", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | "./index.html", 5 | "./src/**/*.{js,ts,jsx,tsx}", 6 | ], 7 | darkMode: ['selector'], 8 | theme: { 9 | extend: {}, 10 | }, 11 | plugins: [require('daisyui'), require('@tailwindcss/forms')], 12 | } 13 | 14 | // Tailwind Config 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | * gitingore 27 | -------------------------------------------------------------------------------- /.firebase/hosting.cHVibGlj.cache: -------------------------------------------------------------------------------- 1 | index.html,1715627958903,9eaa69e6f3828fbf36e5245dc87909960749a8b9e6a810dffc09735ffb68e8fa 2 | vite.svg,1711381528520,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 3 | Banner.svg,1715612683914,65d8989605bf0335d00bd8daea4fe69a0d152ea184f1c60cad8f192a5d7aa623 4 | bannerimg.png,1715613054697,da52b1d0ee5acb6e144918b760aa19634a359c41c4daeb52560915c6100ebf9d 5 | 6 | .firebase upload 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Job Horizon 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/routes/PrivateRoute.jsx: -------------------------------------------------------------------------------- 1 | import { Navigate, useLocation } from 'react-router-dom'; 2 | import PropTypes from 'prop-types'; 3 | import useAuth from '../hooks/useAuth'; 4 | 5 | const PrivateRoute = ({ children }) => { 6 | const { user } = useAuth(); 7 | const location = useLocation(); 8 | 9 | if (user) { 10 | return children; 11 | } 12 | return 13 | }; 14 | 15 | export default PrivateRoute; 16 | 17 | PrivateRoute.propTypes = { 18 | children: PropTypes.node, 19 | } 20 | 21 | // Private Route -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true, node: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react/jsx-no-target-blank': 'off', 16 | 'react-refresh/only-export-components': [ 17 | 'warn', 18 | { allowConstantExport: true }, 19 | ], 20 | }, 21 | } 22 | 23 | // Eslintrc 24 | -------------------------------------------------------------------------------- /src/firebase/Firebase.config.js: -------------------------------------------------------------------------------- 1 | // Import the functions you need from the SDKs you need 2 | import { initializeApp } from "firebase/app"; 3 | import { getAuth } from "firebase/auth"; 4 | // TODO: Add SDKs for Firebase products that you want to use 5 | // https://firebase.google.com/docs/web/setup#available-libraries 6 | 7 | // Your web app's Firebase configuration 8 | const firebaseConfig = { 9 | apiKey: import.meta.env.VITE_APIKEY, 10 | authDomain: import.meta.env.VITE_AUTHDOMAIN, 11 | projectId: import.meta.env.VITE_PROJECTID, 12 | storageBucket: import.meta.env.VITE_STORAGEBUCKET, 13 | messagingSenderId: import.meta.env.VITE_MESSAGINGSENDERID, 14 | appId: import.meta.env.VITE_APPID, 15 | }; 16 | 17 | // Initialize Firebase 18 | const app = initializeApp(firebaseConfig); 19 | 20 | export const auth = getAuth(app); 21 | 22 | // Firebase Config -------------------------------------------------------------------------------- /src/hooks/useAxiosSecure.jsx: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const axiosSecure = axios.create({ 4 | baseURL: import.meta.env.VITE_API_URL, 5 | withCredentials: true, 6 | }) 7 | 8 | // Use Axios Secure 9 | const useAxiosSecure = () => { 10 | 11 | // Response Interceptor 12 | // axiosSecure.interceptors.response.use( 13 | // res => { 14 | // return res 15 | // }, 16 | // async error => { 17 | // console.log('Error from axios interceptor', error.response) 18 | // if (error.response.status === 401 || error.response.status === 403) { 19 | // await logOut() 20 | // navigate('/login') 21 | // } 22 | // return Promise.reject(error) 23 | // } 24 | // ) 25 | 26 | return axiosSecure; 27 | }; 28 | 29 | export default useAxiosSecure; 30 | 31 | -------------------------------------------------------------------------------- /.firebase/hosting.ZGlzdA.cache: -------------------------------------------------------------------------------- 1 | Banner.svg,1715612683914,65d8989605bf0335d00bd8daea4fe69a0d152ea184f1c60cad8f192a5d7aa623 2 | bannerimg.png,1715613054697,da52b1d0ee5acb6e144918b760aa19634a359c41c4daeb52560915c6100ebf9d 3 | JobHorizon.png,1715682669847,421823c0e8e3c967bace7fdc3b05d3de1ad19db9ffd7487a08634f76e1e07bfd 4 | JobHorizonCrop.png,1715682974264,a44ecc616a6a15fb0a76ae784be25b9a2c9913157c8b5c0708c49aaddf28deff 5 | JobHorizonCrop2.png,1715683051747,4cf6ed240e27b0ab92e8f8a9e932fba7b8584e22c5d8d5db8f396e8c45ea292a 6 | vite.svg,1711381528520,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 7 | index.html,1715690917232,2d2bba60fff7a95b1d54aa9dbc042f56458cfb363d63635eba8ad8d961d45ee2 8 | assets/index-8fsEswD6.css,1715690917232,b3ab4cedd97e71b96ff330910fe5414f1e5337a79d32a28a3d84e82c0246e7fd 9 | assets/index-Bnik6l96.js,1715690917235,dd97c5fbb49a7d735c59d5ff883babf76f26b6cecb0fdc15cd3ec8cf13524f57 10 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import './index.css' 4 | import { RouterProvider } from 'react-router-dom' 5 | import { router } from './routes/Routes.jsx' 6 | import AuthProvider from './providers/AuthProvider.jsx' 7 | import { Toaster } from 'react-hot-toast' 8 | import { QueryClient, QueryClientProvider } from '@tanstack/react-query' 9 | import { ReactQueryDevtools } from '@tanstack/react-query-devtools' 10 | 11 | const queryClient = new QueryClient() 12 | 13 | ReactDOM.createRoot(document.getElementById('root')).render( 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | , 23 | ) 24 | 25 | // Main js 26 | -------------------------------------------------------------------------------- /src/layouts/Main.jsx: -------------------------------------------------------------------------------- 1 | import Navbar from '../components/Navbar'; 2 | import { Outlet } from 'react-router-dom'; 3 | import Footer from '../components/Footer'; 4 | import useAuth from '../hooks/useAuth'; 5 | 6 | import Lottie from "lottie-react"; 7 | import loadingAnimation from "./loadingSpinner.json"; 8 | const style = { 9 | display: 'flex', 10 | justifyContent: 'center', 11 | alignItems: 'center', 12 | height: '100vh', 13 | }; 14 | 15 | const Main = () => { 16 | const { loading } = useAuth(); 17 | 18 | if (loading) { 19 | return <> 20 | 24 | 25 | } 26 | 27 | return ( 28 |
29 | {/* Navbar */} 30 | 31 | {/* Outlet */} 32 |
33 | 34 |
35 | {/* Footer */} 36 |
37 |
38 | ); 39 | }; 40 | 41 | export default Main; 42 | 43 | // main js -------------------------------------------------------------------------------- /src/pages/ErrorPage.jsx: -------------------------------------------------------------------------------- 1 | import { Helmet } from 'react-helmet'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | const ErrorPage = () => { 5 | return ( 6 |
7 | 8 | JobHorizon | Error 404! 9 | 10 | 11 |
12 |
13 |

404

14 | 15 |

16 | Uh-oh! 17 |

18 | 19 |

We can't find that page.

20 | 21 | 25 | Go Back Home 26 | 27 |
28 |
29 |
30 | ); 31 | }; 32 | 33 | export default ErrorPage; 34 | 35 | // Error Page -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client-side", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@react-pdf/renderer": "^3.4.4", 14 | "@tanstack/react-query": "^5.35.1", 15 | "@tanstack/react-query-devtools": "^5.35.1", 16 | "axios": "^1.6.8", 17 | "check-valid-url": "^0.1.0", 18 | "firebase": "^10.11.1", 19 | "framer-motion": "^11.1.9", 20 | "localforage": "^1.10.0", 21 | "lottie-react": "^2.4.0", 22 | "match-sorter": "^6.3.4", 23 | "prop-types": "^15.8.1", 24 | "react": "^18.2.0", 25 | "react-datepicker": "^6.9.0", 26 | "react-dom": "^18.2.0", 27 | "react-helmet": "^6.1.0", 28 | "react-hot-toast": "^2.4.1", 29 | "react-router-dom": "^6.23.0", 30 | "react-tabs": "^6.0.2", 31 | "react-to-pdf": "^1.0.1", 32 | "react-tooltip": "^5.26.4", 33 | "sort-by": "^1.2.0", 34 | "sweetalert2": "^11.10.8" 35 | }, 36 | "devDependencies": { 37 | "@tailwindcss/forms": "^0.5.7", 38 | "@types/react": "^18.2.66", 39 | "@types/react-dom": "^18.2.22", 40 | "@vitejs/plugin-react": "^4.2.1", 41 | "autoprefixer": "^10.4.19", 42 | "daisyui": "^4.11.1", 43 | "eslint": "^8.57.0", 44 | "eslint-plugin-react": "^7.34.1", 45 | "eslint-plugin-react-hooks": "^4.6.0", 46 | "eslint-plugin-react-refresh": "^0.4.6", 47 | "postcss": "^8.4.38", 48 | "tailwindcss": "^3.4.3", 49 | "vite": "^5.2.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/pages/Home.jsx: -------------------------------------------------------------------------------- 1 | import { motion, useScroll, useSpring } from 'framer-motion'; 2 | import Banner from '../components/Banner'; 3 | import ContactUs from '../components/ContactUs'; 4 | import FaqSection from '../components/FaqSection'; 5 | import JobByCategory from '../components/JobByCategory'; 6 | import { Helmet } from 'react-helmet'; 7 | 8 | const Home = () => { 9 | const { scrollYProgress } = useScroll(); 10 | const springScaleX = useSpring(scrollYProgress, { 11 | stiffness: 100, 12 | damping: 30, 13 | restDelta: 0.001, 14 | }); 15 | 16 | return ( 17 |
18 | 19 | JobHorizon | Home 20 | 21 | 22 | {/* Progress bar using Framer Motion */} 23 | 38 | 39 | {/* Content sections */} 40 | 41 | 42 | 43 | 44 |
45 | ); 46 | }; 47 | 48 | export default Home; 49 | 50 | // Home Js 51 | -------------------------------------------------------------------------------- /src/components/AppliedJobsPDF.jsx: -------------------------------------------------------------------------------- 1 | import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer'; 2 | import PropTypes from 'prop-types'; // ES6 3 | // Applied Jobs pdf 4 | const styles = StyleSheet.create({ 5 | page: { 6 | flexDirection: 'column', 7 | padding: 20, 8 | }, 9 | heading: { 10 | fontSize: 20, 11 | marginBottom: 10, 12 | textAlign: 'center', 13 | }, 14 | jobItem: { 15 | marginBottom: 10, 16 | }, 17 | }); 18 | 19 | const AppliedJobsPDF = ({ jobs }) => { 20 | return ( 21 | // 22 | 23 | 24 | Applied Jobs Summary 25 | {jobs.map((job) => ( 26 | 27 | Job Title: {job.jobTitle} 28 | Application Deadline: {new Date(job.applicationDeadline).toLocaleDateString()} 29 | Job Category: {job.jobCategory} 30 | Salary Range: ${job.salaryRange} 31 | Applicant Name: {job.application.applicantUserName} 32 | Applicant Email: {job.application.applicantUserEmail} 33 | Resume Link: {job.application.resumeLink} 34 | 35 | ))} 36 | 37 | 38 | // 39 | ); 40 | }; 41 | 42 | export default AppliedJobsPDF; 43 | 44 | AppliedJobsPDF.propTypes = { 45 | jobs: PropTypes.array, 46 | } 47 | 48 | // Applied Job Pdf 49 | -------------------------------------------------------------------------------- /src/routes/Routes.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | createBrowserRouter, 3 | } from "react-router-dom"; 4 | import Main from "../layouts/Main"; 5 | import Home from "../pages/Home"; 6 | import ErrorPage from "../pages/ErrorPage"; 7 | import Login from "../pages/Login"; 8 | import Register from "../pages/Register"; 9 | import AddJob from "../pages/AddJob"; 10 | import AllJob from "../pages/AllJob"; 11 | import JobDetails from "../pages/JobDetails"; 12 | import PrivateRoute from "./PrivateRoute"; 13 | import MyJobs from "../pages/MyJobs"; 14 | import UpdateJob from "../pages/UpdateJob"; 15 | import AppliedJobs from "../pages/AppliedJobs"; 16 | import Blogs from "../pages/Blogs"; 17 | 18 | export const router = createBrowserRouter([ 19 | { 20 | path: "/", 21 | element:
, 22 | errorElement: , 23 | children: [ 24 | { 25 | path: '/', 26 | element: 27 | }, 28 | { 29 | path: '/login', 30 | element: 31 | }, 32 | { 33 | path: '/register', 34 | element: 35 | }, 36 | { 37 | path: '/add-job', 38 | element: 39 | }, 40 | { 41 | path: '/all-job', 42 | element: 43 | }, 44 | { 45 | path: '/job/:id', 46 | element: 47 | }, 48 | { 49 | path: '/my-jobs', 50 | element: 51 | }, 52 | { 53 | path: '/applied-jobs', 54 | element: 55 | }, 56 | { 57 | path: '/update-job/:id', 58 | element: 59 | }, 60 | { 61 | path: '/blogs', 62 | element: 63 | } 64 | ], 65 | }, 66 | ]); 67 | 68 | // Router jsx -------------------------------------------------------------------------------- /src/components/Banner.jsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { Link } from "react-router-dom"; 3 | // Banner jsx 4 | const Banner = () => { 5 | return ( 6 |
7 |
8 |
9 |
10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |
18 |

21 | Discover Your Next Opportunity. 22 | 23 | Find the Perfect Job. 24 |

25 | 26 |

27 | Explore a curated collection of job listings and unlock new career possibilities. Whether you're seeking remote positions, part-time roles, or on-site opportunities, we have the jobs tailored for you. 28 |

29 | 30 |
31 | 34 | Find Job 35 | 36 | 37 | 40 | Learn More 41 | 42 |
43 |
44 |
45 |
46 |
47 | ); 48 | }; 49 | 50 | export default Banner; 51 | // Banner -------------------------------------------------------------------------------- /src/components/JobCard.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import useAuth from "../hooks/useAuth"; 3 | import toast from "react-hot-toast"; 4 | import PropTypes from 'prop-types'; // ES6 5 | 6 | const JobCard = ({ job }) => { 7 | const { user } = useAuth(); 8 | const { 9 | _id, 10 | jobBannerUrl, 11 | jobTitle, 12 | userName, 13 | // userEmail, 14 | // jobCategory, 15 | salaryRange, 16 | // jobDescription, 17 | jobPostingDate, 18 | applicationDeadline, 19 | jobApplicantsNumber, 20 | } = job 21 | 22 | return ( 23 |
24 |
25 |

Application Deadine: {new Date(applicationDeadline).toLocaleDateString()}

26 |

27 | product image 28 |

29 |
30 | Posted By: {userName} 31 |

32 |

{jobTitle}
33 |

34 | 35 |

Posting Date: {new Date(jobPostingDate).toLocaleDateString()}

36 |

Applicants Number: {jobApplicantsNumber}

37 | 38 |
39 | ${salaryRange} 40 | user || toast.error('You have to log in first to view details')} to={`/job/${_id}`} className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">View Details 41 |
42 |
43 |
44 | 45 |
46 | ); 47 | }; 48 | 49 | export default JobCard; 50 | 51 | JobCard.propTypes = { 52 | job: PropTypes.object, 53 | } 54 | 55 | // job Card -------------------------------------------------------------------------------- /src/providers/AuthProvider.jsx: -------------------------------------------------------------------------------- 1 | import { createContext, useEffect, useState } from "react"; 2 | import { GithubAuthProvider, GoogleAuthProvider, createUserWithEmailAndPassword, onAuthStateChanged, signInWithEmailAndPassword, signInWithPopup, signOut, updateProfile } from "firebase/auth"; 3 | import { auth } from "../firebase/Firebase.config"; 4 | import PropTypes from 'prop-types'; 5 | import axios from "axios"; 6 | 7 | export const AuthContext = createContext(null); 8 | const googleProvider = new GoogleAuthProvider(); 9 | const githubProvider = new GithubAuthProvider(); 10 | 11 | const AuthProvider = ({ children }) => { 12 | const [user, setUser] = useState(null); 13 | const [loading, setLoading] = useState(true); 14 | 15 | 16 | const createUser = (email, password) => { 17 | // setLoading(true); 18 | return createUserWithEmailAndPassword(auth, email, password); 19 | } 20 | 21 | const loginUser = (email, password) => { 22 | // setLoading(true); 23 | return signInWithEmailAndPassword(auth, email, password); 24 | } 25 | 26 | const googleLoginUser = () => { 27 | // setLoading(true); 28 | return signInWithPopup(auth, googleProvider); 29 | } 30 | 31 | const githubLoginUser = () => { 32 | // setLoading(true); 33 | return signInWithPopup(auth, githubProvider); 34 | } 35 | 36 | const updateUserProfile = (userName, userPhotoURL) => { 37 | // setLoading(true); 38 | return updateProfile(auth.currentUser, { 39 | displayName: userName, photoURL: userPhotoURL 40 | }) 41 | } 42 | 43 | const logOut = () => { 44 | setLoading(true); 45 | return signOut(auth); 46 | } 47 | 48 | useEffect(() => { 49 | const unSubscribe = onAuthStateChanged(auth, (currentUser) => { 50 | const userEmail = currentUser?.email || user?.email; 51 | const loggedUser = { email: userEmail } 52 | setUser(currentUser); 53 | console.log("current user", currentUser); 54 | setLoading(false); 55 | // if User Exists 56 | if (currentUser) { 57 | axios.post(`${import.meta.env.VITE_API_URL}/jwt`, loggedUser, { withCredentials: true }) 58 | .then(res => { 59 | console.log('token response', res.data); 60 | }) 61 | } 62 | else { 63 | axios.post(`${import.meta.env.VITE_API_URL}/logout`, loggedUser, { withCredentials: true }) 64 | .then(res => { 65 | console.log(res.data); 66 | }) 67 | } 68 | }); 69 | return () => { 70 | unSubscribe(); 71 | } 72 | }, [user?.email]); 73 | 74 | const authInfo = { 75 | user, 76 | createUser, 77 | loginUser, 78 | googleLoginUser, 79 | githubLoginUser, 80 | logOut, 81 | updateUserProfile, 82 | setLoading, 83 | loading, 84 | }; 85 | return ( 86 | 87 | {children} 88 | 89 | ); 90 | }; 91 | 92 | export default AuthProvider; 93 | 94 | AuthProvider.propTypes = { 95 | children: PropTypes.node, 96 | } 97 | 98 | // Auth Provider jsx 99 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/JobByCategory.jsx: -------------------------------------------------------------------------------- 1 | import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; 2 | import 'react-tabs/style/react-tabs.css'; 3 | import useAxiosSecure from '../hooks/useAxiosSecure'; 4 | // import { useState } from 'react'; 5 | import { useQuery } from '@tanstack/react-query'; 6 | import JobCard from './JobCard'; 7 | const JobByCategory = () => { 8 | 9 | const axiosSecure = useAxiosSecure(); 10 | // const [searchText, setSearchText] = useState(''); 11 | const { data: jobs = [], isLoading } = useQuery({ 12 | queryKey: ['jobs-Category'], 13 | queryFn: async () => { 14 | // if (searchText) { 15 | // console.log(searchText); 16 | // const { data } = await axiosSecure.get(`/jobs?search=${searchText}`) 17 | // return data; 18 | // } 19 | const { data } = await axiosSecure.get(`/jobs`) 20 | return data; 21 | } 22 | }) 23 | // console.log(jobs) 24 | 25 | if (isLoading) { 26 | return
27 | 28 |
29 | } 30 | 31 | return ( 32 |
33 |
34 |

Job by Category

35 |
36 |
37 | 38 | 39 |
40 | 41 | All Jobs 42 | On-Site Job 43 | Remote Job 44 | Hybrid 45 | Part-Time 46 | 47 |
48 | 49 | 50 | 51 |
52 | { 53 | jobs.map(job => ( 54 | 58 | )) 59 | } 60 |
61 | 62 |
63 | 64 |
65 | { 66 | jobs.filter(j => j.jobCategory === 'On-Site Job').map(job => ( 67 | 71 | )) 72 | } 73 |
74 | 75 |
76 | 77 |
78 | { 79 | jobs.filter(j => j.jobCategory === 'Remote Job').map(job => ( 80 | 84 | )) 85 | } 86 |
87 | 88 |
89 | 90 |
91 | { 92 | jobs.filter(j => j.jobCategory === 'Hybrid').map(job => ( 93 | 97 | )) 98 | } 99 |
100 | 101 |
102 | 103 |
104 | { 105 | jobs.filter(j => j.jobCategory === 'Part-Time').map(job => ( 106 | 110 | )) 111 | } 112 |
113 | 114 |
115 | 116 |
117 |
118 |
119 | ); 120 | }; 121 | 122 | export default JobByCategory; 123 | 124 | // Job By Catagory jsx -------------------------------------------------------------------------------- /src/pages/Blogs.jsx: -------------------------------------------------------------------------------- 1 | import { Helmet } from "react-helmet"; 2 | import { Link } from "react-router-dom"; 3 | 4 | const Blogs = () => { 5 | 6 | return ( 7 |
8 | 9 | JobHorizon | Blogs 10 | 11 | 12 |
13 |

Understanding Access Tokens and Express.js vs. NestJS

14 | 15 | {/* What is an Access Token and Refresh Token? */} 16 |
17 |

1. What is an Access Token and Refresh Token?

18 |

19 | Access tokens and refresh tokens are used in authentication systems to grant access to resources on behalf of 20 | a user. An access token is typically a short-lived token used to access protected resources, while a refresh 21 | token is a long-lived token used to obtain new access tokens when they expire. 22 |

23 |

  • How do they work and where should 24 | we store them on the client side?
  • 25 |

    26 | Access tokens are sent with each request to authenticate the user, while refresh tokens are securely stored on 27 | the client side and used to obtain new access tokens without requiring the user to log in again. 28 |

    29 | 30 |

    31 | Access tokens should be stored in memory (e.g., in browser memory or a secure storage mechanism) for security 32 | reasons. Refresh tokens should be stored securely on the client side, such as in an HTTP-only cookie or secure 33 | storage, to prevent unauthorized access. 34 |

    35 |
    36 | 37 | {/* What is Express.js and NestJS? */} 38 |
    39 |

    2. What is Express.js and NestJS?

    40 |

    41 | Express.js is a minimalist web framework for Node.js that provides a robust set of features for building web 42 | applications and APIs. It is known for its simplicity, flexibility, and performance. 43 |

    44 |

    45 | NestJS, on the other hand, is a progressive Node.js framework that uses TypeScript and is inspired by 46 | Angular's architecture. It provides a structured and scalable way to build server-side applications, 47 | incorporating modern design patterns and best practices. 48 |

    49 |

    50 | NestJS offers features like dependency injection, middleware support, and modular architecture, making it ideal 51 | for building complex and maintainable applications. 52 |

    53 |
    54 | 55 | {/* Explain Your Job-Seeking Website Project */} 56 |
    57 |

    3. Explain Your Job-Seeking Website Project

    58 |

    59 | We are developing a user-friendly job-seeking website using React, MongoDB, Node.js, Express.js, Firebase, and JWT Token 60 | authentication. The features of our website include: 61 |

    62 |
      63 |
    • User can post job listings.
    • 64 |
    • Other users can view and apply for job positions.
    • 65 |
    • User can edit or delete their posted jobs but not jobs posted by others.
    • 66 |
    • User can view the list of jobs they have applied for but cannot see jobs applied by other users.
    • 67 |
    68 |

    69 | This project aims to create a seamless and secure platform for job seekers and employers to interact and manage job 70 | listings effectively. Firebase is used for real-time database capabilities, enabling dynamic updates and interactions 71 | within the platform. 72 |

    73 |
    74 | 75 | 76 | {/* Conclusion and Call to Action */} 77 |
    78 |

    79 | Hopefully, this blog post has helped clarify the concepts of access tokens, refresh tokens, Express.js, and 80 | NestJS. If you're interested in learning more or trying out these technologies, check out the official 81 | documentation for Express.js and{' '} 82 | NestJS. 83 |

    84 |

    Happy coding!

    85 |
    86 |
    87 |
    88 | ); 89 | }; 90 | 91 | export default Blogs; 92 | // Blogs -------------------------------------------------------------------------------- /src/pages/AllJob.jsx: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import { useState } from 'react'; 3 | import useAxiosSecure from '../hooks/useAxiosSecure'; 4 | import { Link } from 'react-router-dom'; 5 | import { Helmet } from 'react-helmet'; 6 | import toast from 'react-hot-toast'; 7 | import useAuth from '../hooks/useAuth'; 8 | 9 | const AllJob = () => { 10 | const axiosSecure = useAxiosSecure(); 11 | const {user } = useAuth(); 12 | const [searchText, setSearchText] = useState(''); 13 | const { data: jobs = [], isLoading, refetch } = useQuery({ 14 | queryKey: ['jobs'], 15 | queryFn: async () => { 16 | if (searchText) { 17 | console.log(searchText); 18 | const { data } = await axiosSecure.get(`/jobs?search=${searchText}`) 19 | return data; 20 | } 21 | const { data } = await axiosSecure.get(`/jobs`) 22 | return data; 23 | } 24 | }) 25 | const handleSearch = e => { 26 | e.preventDefault(); 27 | refetch(); 28 | } 29 | 30 | if (isLoading) { 31 | return
    32 | 33 |
    34 | } 35 | return ( 36 |
    37 | 38 | JobHorizon | All Jobs 39 | 40 | 41 |
    42 | 52 |
    53 | 54 | 55 |
    56 | 59 | 60 | 61 | 62 | 65 | 66 | 69 | 72 | 73 | 74 | 75 | 76 | 77 | { 78 | jobs.map(job => ( 79 | 80 | 83 | 84 | 85 | 86 | 95 | 96 | )) 97 | } 98 | 99 | 100 | 101 |
    Job Title 63 | Job Posting Date 64 | Application Deadline 67 | Salary range 68 | 70 | Action 71 |
    81 | {job.jobTitle} 82 | {new Date(job.jobPostingDate).toLocaleDateString()}{new Date(job.applicationDeadline).toLocaleDateString()}${job.salaryRange} 87 | user || toast.error('You have to log in first to view details')} 89 | to={`/job/${job._id}`} 90 | className="inline-block rounded bg-indigo-600 px-4 py-2 text-xs font-medium text-white hover:bg-indigo-700" 91 | > 92 | View Details 93 | 94 |
    102 |
    103 |
    104 | ); 105 | }; 106 | 107 | export default AllJob; 108 | 109 | // All Job -------------------------------------------------------------------------------- /src/components/ContactUs.jsx: -------------------------------------------------------------------------------- 1 | const ContactUs = () => { 2 | return ( 3 |
    4 |
    5 |
    6 |
    7 |

    Contact us

    8 | 9 |

    Get in touch

    10 | 11 |

    Our friendly team would love to hear from you.

    12 |
    13 | 14 |
    15 |
    16 |
    17 | 18 | 19 | 20 | 21 | 22 | 23 |

    Email

    24 |

    Feel free to reach out to us via email:

    25 |

    hello@JobHorizon.com

    26 |
    27 | 28 |
    29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |

    Office

    37 |

    Visit us at our office headquarters

    38 |

    100 Example Road, Dhaka
    39 | Dhaka, Bangladesh

    40 |
    41 | 42 |
    43 | 44 | 45 | 46 | 47 | 48 | 49 |

    Phone

    50 |

    Mon-Fri from 8am to 5pm.

    51 |

    +880 1234 567890

    52 |
    53 |
    54 | 55 |
    56 | 57 | {/* */} 58 |
    59 |
    60 |
    61 |
    62 |
    63 | ); 64 | }; 65 | 66 | export default ContactUs; 67 | // Contact Js -------------------------------------------------------------------------------- /src/components/FaqSection.jsx: -------------------------------------------------------------------------------- 1 | const FaqSection = () => { 2 | return ( 3 |
    4 |
    5 |
    6 |
    7 |

    8 | What our clients are saying 9 |

    10 | 11 |
    12 | 13 | 14 | 15 |
    16 |
    17 | 18 | {/*
    19 | 24 | 25 | 30 |
    */} 31 |
    32 | 33 |
    34 |
    35 |

    36 | “I had an outstanding experience working with this team! They were attentive to our needs and delivered exceptional results. I highly recommend their services to anyone looking for quality and professionalism”. 37 |

    38 | 39 |
    40 | 41 | 42 |
    43 |

    John Doe,

    44 | CEO of ABC Company 45 |
    46 |
    47 |
    48 | 49 |
    50 |

    51 | “Working with this company was a game-changer for our business. Their attention to detail and innovative solutions helped us achieve our goals effectively. We look forward to continuing our partnership”. 52 |

    53 | 54 |
    55 | 56 | 57 |
    58 |

    Jeny Doe

    59 | Marketing Director at XYZ Corporation 60 |
    61 |
    62 |
    63 | 64 |
    65 |

    66 | “I couldn't be happier with the services provided by this team. They were responsive, knowledgeable, and went above and beyond to ensure our project's success. I will definitely work with them again in the future.”. 67 |

    68 | 69 |
    70 | 71 | 72 |
    73 |

    Ema Watson

    74 | Founder of DEF Startup 75 |
    76 |
    77 |
    78 |
    79 |
    80 |
    81 | ); 82 | }; 83 | 84 | export default FaqSection; 85 | 86 | // Faq Section -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | const Footer = () => { 4 | return ( 5 |
    6 | 45 |
    46 | ); 47 | }; 48 | 49 | export default Footer; 50 | 51 | // Footer js -------------------------------------------------------------------------------- /src/pages/MyJobs.jsx: -------------------------------------------------------------------------------- 1 | import { useQuery } from '@tanstack/react-query'; 2 | import useAxiosSecure from '../hooks/useAxiosSecure'; 3 | import useAuth from '../hooks/useAuth'; 4 | import { Link } from 'react-router-dom'; 5 | import Swal from 'sweetalert2'; 6 | import toast from 'react-hot-toast'; 7 | import { Helmet } from 'react-helmet'; 8 | 9 | const MyJobs = () => { 10 | const axiosSecure = useAxiosSecure(); 11 | const { user } = useAuth(); 12 | const { data: jobs = [], isLoading, refetch } = useQuery({ 13 | queryKey: ['jobs'], 14 | queryFn: async () => { 15 | const { data } = await axiosSecure.get(`/my-jobs/${user.email}`) 16 | return data; 17 | } 18 | }) 19 | 20 | if (isLoading) { 21 | return
    22 | 23 |
    24 | } 25 | 26 | const handleDelete = async (id) => { 27 | Swal.fire({ 28 | title: "Are you sure?", 29 | text: "You won't be able to revert this!", 30 | icon: "warning", 31 | showCancelButton: true, 32 | confirmButtonColor: "#3085d6", 33 | cancelButtonColor: "#d33", 34 | confirmButtonText: "Yes, delete it!" 35 | }).then(() => { 36 | axiosSecure.delete(`/job/${id}`) 37 | .then(res => { 38 | // console.log(res); 39 | if (res.data.success === true) { 40 | Swal.fire({ 41 | title: "Deleted!", 42 | text: "Job post has been deleted.", 43 | icon: "success" 44 | }); 45 | toast.success("Job deleted successfully") 46 | } 47 | refetch(); 48 | }) 49 | .catch(err => { 50 | console.log(err); 51 | }) 52 | 53 | }); 54 | 55 | 56 | } 57 | 58 | return ( 59 |
    60 | 61 | JobHorizon | My Posted Jobs 62 | 63 | 64 |
    65 | 68 | 69 | 70 | 71 | 72 | 73 | 76 | 77 | 78 | 81 | 84 | 85 | 86 | 87 | 88 | 89 | { 90 | jobs.map(job => ( 91 | 92 | 95 | 98 | 101 | 102 | 103 | 106 | 107 | 120 | 121 | )) 122 | } 123 | 124 | 125 | 126 |
    TitleCategoryDescription 74 | Posting Date 75 | Application DeadlineApplicants Number 79 | Salary range 80 | 82 | Action 83 |
    93 | {job.jobTitle} 94 | 96 | {job.jobCategory} 97 | 99 | {job.jobDescription} 100 | {new Date(job.jobPostingDate).toLocaleDateString()}{new Date(job.applicationDeadline).toLocaleDateString()} 104 | {job.jobApplicantsNumber} 105 | ${job.salaryRange} 108 | 112 | Update 113 | 114 | 119 |
    127 |
    128 |
    129 | ); 130 | }; 131 | 132 | export default MyJobs; 133 | // My Jobs -------------------------------------------------------------------------------- /src/components/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { Link, NavLink } from "react-router-dom"; 3 | import { Tooltip } from 'react-tooltip' 4 | import { isUrl } from "check-valid-url"; 5 | import useAuth from "../hooks/useAuth"; 6 | 7 | const NavBar = () => { 8 | const { user, logOut } = useAuth(); 9 | const [theme, setTheme] = useState('light') 10 | 11 | const handleToggle = e => { 12 | if (e.target.checked) { 13 | setTheme('dark') 14 | } else { 15 | setTheme('light') 16 | } 17 | } 18 | 19 | useEffect(() => { 20 | localStorage.setItem('theme', theme) 21 | const localTheme = localStorage.getItem('theme') 22 | 23 | // add custom data-theme attribute 24 | document.querySelector('html').setAttribute('data-theme', localTheme) 25 | document.querySelector('html').setAttribute('class', localTheme) 26 | }, [theme]) 27 | 28 | const handleLogout = () => { 29 | logOut() 30 | .then() 31 | .catch() 32 | } 33 | 34 | const NavLinks = <> 35 |
  • Home
  • 36 |
  • All Jobs
  • 37 | { 38 | user 39 | ? <> 40 |
  • Applied Jobs
  • 41 |
  • Add A Job
  • 42 |
  • My Jobs
  • 43 | 44 | 45 | : <> 46 | 47 | } 48 |
  • Blogs
  • 49 | 50 | 51 | return ( 52 |
    53 |
    54 |
    55 |
    56 |
    57 | 58 |
    59 |
      60 | {NavLinks} 61 |
    62 |
    63 |
    64 | 65 | JobHorizon 66 |
    67 |
    68 |
    69 |
      70 | {NavLinks} 71 |
    72 |
    73 |
    74 |
    75 | 111 |
    112 | { 113 | user 114 | ? <> 115 | 116 | 117 |
    118 |
    119 |
    123 | Profile Pic 124 |
    125 |
    126 |
      127 |
    • 128 |
    129 |
    130 | 131 | : <> 132 | Login 133 | Register 134 | 135 | } 136 | 137 | 138 |
    139 |
    140 | 141 |
    142 | ); 143 | }; 144 | 145 | export default NavBar; 146 | 147 | // Navbar -------------------------------------------------------------------------------- /src/pages/AppliedJobs.jsx: -------------------------------------------------------------------------------- 1 | import { useQuery } from "@tanstack/react-query"; 2 | import useAuth from "../hooks/useAuth"; 3 | import useAxiosSecure from "../hooks/useAxiosSecure"; 4 | import { useState } from "react"; 5 | import AppliedJobsPDF from "../components/AppliedJobsPDF"; 6 | import { PDFDownloadLink } from "@react-pdf/renderer"; 7 | import { Helmet } from "react-helmet"; 8 | 9 | 10 | 11 | const AppliedJobs = () => { 12 | const axiosSecure = useAxiosSecure(); 13 | const { user } = useAuth(); 14 | const [filter, setFilter] = useState(''); 15 | const [showDownloadLink, setShowDownloadLink] = useState(false) 16 | const handleCategoryFilter = (e) => { 17 | e.preventDefault(); 18 | refetch(); 19 | } 20 | 21 | const { data: jobs = [], isLoading, refetch, isFetching } = useQuery({ 22 | queryKey: ['applied-jobs'], 23 | queryFn: async () => { 24 | const { data } = await axiosSecure.get(`/applied-jobs/${user.email}?filter=${filter}`) 25 | return data; 26 | } 27 | }) 28 | 29 | if (isLoading) { 30 | return
    31 | 32 |
    33 | } 34 | 35 | 36 | const handleGeneratePDF = () => { 37 | setShowDownloadLink(true); 38 | }; 39 | 40 | return ( 41 | 42 |
    43 | 44 | JobHorizon | My Applied Jobs 45 | 46 | 47 |
    48 |
    51 | 67 | 71 |
    72 | 73 | {/* Button to trigger PDF generation */} 74 | 77 | 78 | {/* Conditionally render the download link when PDF is ready */} 79 | {showDownloadLink && ( 80 | } 83 | fileName={`${user?.displayName}'s Applied Jobs.pdf`}> 84 | {({ blob, url, loading, error }) => 85 | loading ? 'Loading document...' : 'Download now!' 86 | } 87 | 88 | )} 89 |
    90 | 91 | 92 | { 93 | isFetching &&
    94 | 95 |
    96 | } 97 | 98 |
    102 | 105 | 106 | 107 | 108 | 111 | 112 | 115 | 118 | 121 | 124 | 125 | 126 | 127 | 128 | 129 | { 130 | jobs.map(job => ( 131 | 132 | 135 | 136 | 137 | 138 | 139 | 140 | 148 | 149 | )) 150 | } 151 | 152 |
    Job Title 109 | Application Deadline 110 | Job Category 113 | Salary range 114 | 116 | Applicant Name 117 | 119 | Applicant Email 120 | 122 | Resume Link 123 |
    133 | {job.jobTitle} 134 | {new Date(job.applicationDeadline).toLocaleDateString()}{job.jobCategory}${job.salaryRange}{job.application.applicantUserName}{job.application.applicantUserEmail} 141 | 145 | Resume 146 | 147 |
    153 |
    154 |
    155 | ); 156 | }; 157 | 158 | export default AppliedJobs; 159 | 160 | // Applied Job -------------------------------------------------------------------------------- /src/pages/Login.jsx: -------------------------------------------------------------------------------- 1 | import { Link, useLocation, useNavigate } from "react-router-dom"; 2 | import toast from "react-hot-toast"; 3 | import { Helmet } from "react-helmet"; 4 | import useAuth from "../hooks/useAuth"; 5 | 6 | const Login = () => { 7 | 8 | const { loginUser, googleLoginUser } = useAuth(); 9 | const location = useLocation(); 10 | const navigate = useNavigate(); 11 | 12 | const handleFormLogin = e => { 13 | e.preventDefault(); 14 | const form = new FormData(e.currentTarget); 15 | const email = form.get("email"); 16 | const password = form.get("password"); 17 | loginUser(email, password) 18 | .then((result) => { 19 | console.log(result.user); 20 | toast.success(`Successfully Login user: ${result.user.displayName}`) 21 | navigate(location?.state ? location.state : "/"); 22 | }) 23 | .catch((error) => { 24 | console.log(error); 25 | toast.error(`${error.message}`) 26 | }) 27 | }; 28 | 29 | const handleGoogleLogin = () => { 30 | googleLoginUser() 31 | .then((result) => { 32 | console.log(result.user) 33 | toast.success(`Successfully Login user: ${result.user.displayName}`) 34 | navigate(location?.state ? location.state : "/"); 35 | }) 36 | .catch((error) => { 37 | console.log(error) 38 | toast.error(error.message); 39 | }) 40 | } 41 | 42 | return ( 43 |
    44 | 45 | JobHorizon | Login 46 | 47 | 48 |
    49 |
    50 |
    51 |

    Get started today!

    52 | 53 |

    54 | Welcome back! Log in to access your account and continue your journey with us 55 |

    56 |
    57 | 58 |
    59 |
    60 | 61 | 62 |
    63 | 69 | 70 | 71 | 78 | 84 | 85 | 86 |
    87 |
    88 | 89 |
    90 | 91 | 92 |
    93 | 99 | 100 | 101 | 108 | 114 | 120 | 121 | 122 |
    123 |
    124 | 125 |
    126 |

    127 | No account? 128 | Sign up 129 |

    130 | 131 | 137 |
    138 | 154 |
    155 |
    156 | 157 |
    158 | 164 |
    165 |
    166 | 167 |
    168 | ); 169 | }; 170 | 171 | export default Login; 172 | 173 | // Login Details -------------------------------------------------------------------------------- /src/pages/JobDetails.jsx: -------------------------------------------------------------------------------- 1 | import { useQuery } from "@tanstack/react-query"; 2 | import useAxiosSecure from "../hooks/useAxiosSecure"; 3 | import { useParams } from "react-router-dom"; 4 | import useAuth from "../hooks/useAuth"; 5 | import toast from "react-hot-toast"; 6 | import { Helmet } from "react-helmet"; 7 | 8 | const JobDetails = () => { 9 | const axiosSecure = useAxiosSecure() 10 | const { user } = useAuth(); 11 | const { id } = useParams() 12 | const { data, isLoading, refetch } = useQuery({ 13 | queryKey: ['job'], 14 | queryFn: async () => { 15 | const { data } = await axiosSecure.get(`/job/${id}`) 16 | return data; 17 | } 18 | }) 19 | 20 | if (isLoading) { 21 | return
    22 | 23 |
    24 | } 25 | 26 | const { 27 | _id, 28 | jobBannerUrl, 29 | jobTitle, 30 | userName, 31 | userEmail, 32 | jobCategory, 33 | salaryRange, 34 | jobDescription, 35 | jobPostingDate, 36 | applicationDeadline, 37 | jobApplicantsNumber } = data; 38 | 39 | const handleApply = async (e) => { 40 | e.preventDefault(); 41 | const form = e.target; 42 | const jobData = { 43 | jobId: _id, 44 | jobBannerUrl, 45 | jobTitle, 46 | userName, 47 | userEmail, 48 | jobCategory, 49 | salaryRange, 50 | jobDescription, 51 | jobPostingDate, 52 | applicationDeadline, 53 | jobApplicantsNumber, 54 | application: { 55 | applicantUserName: form.applicantUserName.value, 56 | applicantUserEmail: form.applicantUserEmail.value, 57 | resumeLink: form.resumeLink.value, 58 | } 59 | } 60 | 61 | 62 | if (user.email === userEmail) { 63 | return toast.error("Employer can't apply for his own job") 64 | } 65 | 66 | const currentDate = new Date(); 67 | const applicationDeadlineValue = new Date(applicationDeadline); 68 | if (currentDate > applicationDeadlineValue) { 69 | return toast.error("Deadline is over") 70 | } 71 | 72 | 73 | axiosSecure.post('/apply-job', jobData) 74 | .then(res => { 75 | console.log(res.data); 76 | if (res.data.success === true) { 77 | refetch(); 78 | toast.success("Job applied Successfully") 79 | const close = document.getElementById('modal-close') 80 | close 81 | } 82 | 83 | }) 84 | .catch(err => { 85 | // console.log(err) 86 | toast.error(err.response.data.message) 87 | }) 88 | 89 | } 90 | 91 | 92 | 93 | 94 | return ( 95 |
    96 | 97 | JobHorizon | Job Details 98 | 99 | 100 |
    101 | 104 |
    105 | 106 |
    107 |
    108 |
    111 |
    Job Title
    112 |
    {jobTitle}
    113 |
    114 | 115 |
    118 |
    Description
    119 |
    {jobDescription}
    120 |
    121 | 122 |
    125 |
    Salary Range
    126 |
    {salaryRange}
    127 |
    128 | 129 |
    132 |
    Number of Applicants
    133 |
    {jobApplicantsNumber}
    134 |
    135 | 136 | 137 | 138 |
    141 |
    Apply Now
    142 | 143 | 150 | 151 |
    152 |
    153 | {/* Model Body */} 154 |
    155 |
    158 |
    159 |

    160 | Apply For Job 🦑 161 |

    162 | 163 | {/*

    164 | Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eligendi nam dolorum aliquam, 165 | quibusdam aperiam voluptatum. 166 |

    */} 167 | 168 |
    169 |
    170 | 176 | 177 | 185 |
    186 | 187 | 188 |
    189 | 192 | 193 | 201 |
    202 | 203 |
    204 | 207 | 208 | 215 |
    216 | 217 | 218 | 219 |
    220 | 228 |
    229 |
    230 |
    231 |
    232 |
    233 |
    234 |
    235 |
    236 | 237 |
    238 |
    239 | 240 |
    241 |
    242 |
    243 |
    244 | ); 245 | }; 246 | 247 | export default JobDetails; 248 | 249 | // Job Details -------------------------------------------------------------------------------- /src/pages/Register.jsx: -------------------------------------------------------------------------------- 1 | import { Link, useNavigate } from "react-router-dom"; 2 | import toast from "react-hot-toast"; 3 | import { Helmet } from "react-helmet"; 4 | import useAuth from "../hooks/useAuth"; 5 | 6 | const Register = () => { 7 | 8 | const { createUser, updateUserProfile } = useAuth(); 9 | const navigate = useNavigate(); 10 | 11 | 12 | const handleRegister = e => { 13 | e.preventDefault(); 14 | const form = new FormData(e.currentTarget); 15 | const name = form.get("name"); 16 | const photoURL = form.get("photoURL"); 17 | const email = form.get("email"); 18 | const password = form.get("password"); 19 | const hasLowerCase = /[a-z]/.test(password); 20 | const hasUpperCase = /[A-Z]/.test(password); 21 | 22 | if (password.length < 6) { 23 | toast.error("Password must be at least 6 characters long."); 24 | return; 25 | } 26 | if (!hasLowerCase) { 27 | toast.error("Password must contain at least one lowercase letter."); 28 | return; 29 | } 30 | if (!hasUpperCase) { 31 | toast.error("Password must contain at least one uppercase letter."); 32 | return; 33 | } 34 | 35 | 36 | createUser(email, password) 37 | .then((result) => { 38 | console.log(result.user); 39 | updateUserProfile(name, photoURL) 40 | .then(() => { 41 | // console.log("profile updateed" + result) 42 | }) 43 | .catch(() => { 44 | // console.log(error) 45 | }) 46 | toast.success(`Successfully registered user: ${name}`) 47 | navigate("/"); 48 | }) 49 | .catch((error) => { 50 | // console.log(error); 51 | toast.error(error.message); 52 | }) 53 | } 54 | 55 | return ( 56 |
    57 | 58 | JobHorizon | Register 59 | 60 | 61 |
    62 |
    63 |
    64 | 69 | 70 |
    71 |

    72 | Home 73 | {/* 79 | 83 | */} 84 | 85 |

    86 | 87 |

    88 | Welcome to Job Horizon 💼 89 |

    90 | 91 |

    92 | Join us today to start exploring and planning your next adventure! Create your account to unlock exclusive travel insights and personalized recommendations 93 |

    94 |
    95 |
    96 | 97 |
    100 |
    101 |
    102 |

    105 | Home 106 | {/* 112 | 116 | */} 117 | 118 |

    119 | 120 |

    121 | Welcome to Squid 💼 122 |

    123 | 124 |

    125 | Create your account to unlock exciting job opportunities and streamline your job search experience. Join our community of job seekers and employers today! 126 |

    127 |
    128 | 129 |
    130 |
    131 | 137 | 138 | 145 |
    146 | 147 |
    148 | 154 | 155 | 162 |
    163 | 164 |
    165 | 169 | 170 | 177 |
    178 | 179 |
    180 | 186 | 187 | 194 |
    195 | 196 |
    197 | 202 | 203 |

    204 | Already have an account? 205 | Log in. 206 |

    207 |
    208 |
    209 |
    210 |
    211 |
    212 |
    213 |
    214 | ); 215 | }; 216 | 217 | export default Register; 218 | 219 | // Registers -------------------------------------------------------------------------------- /src/pages/AddJob.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import DatePicker from "react-datepicker"; 3 | import "react-datepicker/dist/react-datepicker.css"; 4 | import useAuth from '../hooks/useAuth'; 5 | import useAxiosSecure from '../hooks/useAxiosSecure'; 6 | import toast from 'react-hot-toast'; 7 | import { useNavigate } from 'react-router-dom'; 8 | import { Helmet } from 'react-helmet'; 9 | 10 | const AddJob = () => { 11 | const [startDate, setStartDate] = useState(new Date()) 12 | const axiosSecure = useAxiosSecure(); 13 | const navigate = useNavigate(); 14 | const { user } = useAuth(); 15 | const handleform = async e => { 16 | e.preventDefault(); 17 | const form = e.target; 18 | const jobBannerUrl = form.jobBannerUrl.value; 19 | const jobTitle = form.jobTitle.value; 20 | const userName = form.userName.value; 21 | const userEmail = form.userEmail.value; 22 | const jobCategory = form.jobCategory.value; 23 | const salaryRange = parseFloat(form.salaryRange.value); 24 | const jobDescription = form.jobDescription.value; 25 | const jobPostingDate = new Date(); 26 | const applicationDeadline = startDate; 27 | const jobApplicantsNumber = 0; 28 | 29 | const jobData = { 30 | jobBannerUrl, 31 | jobTitle, 32 | userName, 33 | userEmail, 34 | jobCategory, 35 | salaryRange, 36 | jobDescription, 37 | jobPostingDate, 38 | applicationDeadline, 39 | jobApplicantsNumber, 40 | } 41 | // console.log(jobData); 42 | try { 43 | const { data } = await axiosSecure.post('add-job', jobData) 44 | console.log(data) 45 | if (data.success === true) { 46 | navigate('/all-job') 47 | toast.success("Job Posted Successfully") 48 | } 49 | 50 | } catch (error) { 51 | console.log(error) 52 | } 53 | 54 | } 55 | return ( 56 |
    57 | 58 | JobHorizon | Post Job 59 | 60 | 61 |
    62 |
    63 | 71 | 72 |
    75 |
    76 | 77 | Home 78 | {/* 84 | 88 | */} 89 | 90 | 91 |

    92 | Post Your Job 💼 93 |

    94 | 95 |

    96 | Are you looking to expand your team? Post your job listing here to reach a diverse pool of talented individuals ready to contribute to your organization's success. 97 |

    98 | 99 |
    100 |
    101 | 107 | 108 | 115 |
    116 |
    117 | 123 | 124 | 131 |
    132 |
    133 | 139 | 140 | 149 |
    150 |
    151 | 157 | 158 | 167 |
    168 |
    169 | 175 | 176 | 188 | 189 |
    190 |
    191 | 197 | 198 | 205 |
    206 |
    207 | 213 | 214 | 221 |
    222 |
    223 | 229 | 230 | setStartDate(date)} 233 | // type="text" 234 | // id="jobPostingDate" 235 | // name="jobPostingDate" 236 | disabled 237 | required 238 | className="mt-1 w-full rounded-md border-gray-200 bg-white text-sm text-gray-700 shadow-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200" 239 | /> 240 |
    241 |
    242 | 248 | 249 | setStartDate(date)} 252 | // type="text" 253 | // id="applicationDeadline" 254 | // name="jobDesapplicationDeadlinecription" 255 | required 256 | className="mt-1 w-full rounded-md border-gray-200 bg-white text-sm text-gray-700 shadow-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200" 257 | /> 258 |
    259 | 260 |
    261 | 266 |
    267 |
    268 |
    269 |
    270 |
    271 |
    272 |
    273 | ); 274 | }; 275 | 276 | export default AddJob; 277 | 278 | // Add Job -------------------------------------------------------------------------------- /src/pages/UpdateJob.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | import DatePicker from "react-datepicker"; 3 | import useAxiosSecure from '../hooks/useAxiosSecure'; 4 | import { useQuery } from '@tanstack/react-query'; 5 | import { useNavigate, useParams } from 'react-router-dom'; 6 | import useAuth from '../hooks/useAuth'; 7 | import toast from 'react-hot-toast'; 8 | import { Helmet } from 'react-helmet'; 9 | // Update job 10 | const UpdateJob = () => { 11 | const axiosSecure = useAxiosSecure(); 12 | const navigate = useNavigate(); 13 | const { user } = useAuth(); 14 | const [startDate, setStartDate] = useState(new Date()) 15 | const { id } = useParams() 16 | 17 | // fetch Data 18 | const { data, isLoading, refetch } = useQuery({ 19 | queryKey: [`job-update-${id}`], 20 | queryFn: async () => { 21 | const { data } = await axiosSecure.get(`/job/${id}`) 22 | setStartDate(new Date(data.applicationDeadline)) 23 | return data; 24 | } 25 | }) 26 | 27 | if (isLoading) { 28 | return
    29 | 30 |
    31 | } 32 | 33 | // console.log(data) 34 | 35 | const { 36 | _id, 37 | jobBannerUrl, 38 | jobTitle, 39 | userName, 40 | userEmail, 41 | jobCategory, 42 | salaryRange, 43 | jobDescription, 44 | jobPostingDate, 45 | // applicationDeadline, 46 | // jobApplicantsNumber 47 | } = data; 48 | 49 | const handleform = async e => { 50 | e.preventDefault(); 51 | const form = e.target; 52 | const jobBannerUrl = form.jobBannerUrl.value; 53 | const jobTitle = form.jobTitle.value; 54 | const userName = form.userName.value; 55 | const userEmail = form.userEmail.value; 56 | const jobCategory = form.jobCategory.value; 57 | const salaryRange = parseFloat(form.salaryRange.value); 58 | const jobDescription = form.jobDescription.value; 59 | const jobPostingDate = data.jobPostingDate; 60 | const applicationDeadline = startDate; 61 | const jobApplicantsNumber = data.jobApplicantsNumber; 62 | 63 | const jobData = { 64 | jobBannerUrl, 65 | jobTitle, 66 | userName, 67 | userEmail, 68 | jobCategory, 69 | salaryRange, 70 | jobDescription, 71 | jobPostingDate, 72 | applicationDeadline, 73 | jobApplicantsNumber, 74 | } 75 | 76 | if (user.email !== userEmail) { 77 | return toast.error("You can't modify others job") 78 | } 79 | 80 | try { 81 | const { data } = await axiosSecure.put(`/job/${_id}`, jobData) 82 | console.log(data); 83 | if (data.success === true) { 84 | toast.success("Job Updated Successfully"); 85 | refetch(); 86 | navigate('/my-jobs') 87 | } 88 | } 89 | catch (error) { 90 | console.log(error) 91 | } 92 | } 93 | 94 | 95 | 96 | 97 | return ( 98 |
    99 | 100 | JobHorizon | Update Job 101 | 102 | 103 |
    104 |
    105 | {/* */} 113 | 114 |
    117 |
    118 | 119 | Home 120 | {/* 126 | 130 | */} 131 | 132 | 133 |

    134 | Update Your Job 💼 135 |

    136 | 137 |

    138 | Update the details of your job listing to attract top talent and optimize your recruitment process. Make changes to job title, category, salary range, and description effortlessly. 139 |

    140 | 141 |
    142 |
    143 | 149 | 150 | 157 |
    158 |
    159 | 165 | 166 | 173 |
    174 |
    175 | 181 | 182 | 190 |
    191 |
    192 | 198 | 199 | 207 |
    208 |
    209 | 215 | 216 | 228 | 229 |
    230 |
    231 | 237 | 238 | 245 |
    246 |
    247 | 253 | 254 | 261 |
    262 |
    263 | 269 | 270 | setStartDate(date)} 273 | // type="text" 274 | // id="jobPostingDate" 275 | // name="jobPostingDate" 276 | disabled 277 | className="mt-1 w-full rounded-md border-gray-200 bg-white text-sm text-gray-700 shadow-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200" 278 | /> 279 |
    280 |
    281 | 287 | 288 | setStartDate(date)} 291 | // type="text" 292 | // id="applicationDeadline" 293 | // name="jobDesapplicationDeadlinecription" 294 | className="mt-1 w-full rounded-md border-gray-200 bg-white text-sm text-gray-700 shadow-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-200" 295 | /> 296 |
    297 | 298 |
    299 | 304 | 305 | 306 |
    307 |
    308 |
    309 |
    310 |
    311 |
    312 |
    313 | ); 314 | }; 315 | 316 | export default UpdateJob; 317 | 318 | -------------------------------------------------------------------------------- /src/layouts/loadingSpinner.json: -------------------------------------------------------------------------------- 1 | {"v":"4.12.2","fr":29.9700012207031,"ip":0,"op":95.0000038694293,"w":680,"h":680,"nm":"loading","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL CONTROL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[-360]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[-360],"e":[-720]},{"t":94.0000038286985}],"ix":10},"p":{"a":0,"k":[340,340,0],"ix":2},"a":{"a":0,"k":[60,60,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":600.000024438501,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"形状图层 6","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":114.894,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[61.294,60.321,0],"e":[17.276,0.758,0],"to":[-7.33628749847412,-9.92708110809326,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":23,"s":[17.276,0.758,0],"e":[61.294,60.321,0],"to":[0,0,0],"ti":[-7.33628749847412,-9.92708110809326,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[61.294,60.321,0],"e":[17.276,0.758,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":70,"s":[17.276,0.758,0],"e":[61.294,60.321,0],"to":[0,0,0],"ti":[0,0,0]},{"t":94.0000038286985}],"ix":2},"a":{"a":0,"k":[20.746,53.191,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[30,30],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.156862745098,0.8,0.917647058824,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[20.746,53.191],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[114.47,114.47],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600.000024438501,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"形状图层 5","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":114.894,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[61.294,60.321,0],"e":[28.784,126.814,0],"to":[-5.41830158233643,11.082221031189,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":23,"s":[28.784,126.814,0],"e":[61.294,60.321,0],"to":[0,0,0],"ti":[-5.41830158233643,11.082221031189,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[61.294,60.321,0],"e":[28.784,126.814,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":70,"s":[28.784,126.814,0],"e":[61.294,60.321,0],"to":[0,0,0],"ti":[0,0,0]},{"t":94.0000038286985}],"ix":2},"a":{"a":0,"k":[20.746,53.191,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[30,30],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.156862745098,0.8,0.917647058824,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[20.746,53.191],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[114.47,114.47],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600.000024438501,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"形状图层 4","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":114.894,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[61.294,60.321,0],"e":[128.427,53.44,0],"to":[11.1889200210571,-1.14673674106598,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":23,"s":[128.427,53.44,0],"e":[61.294,60.321,0],"to":[0,0,0],"ti":[11.1889200210571,-1.14673674106598,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[61.294,60.321,0],"e":[128.427,53.44,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":70,"s":[128.427,53.44,0],"e":[61.294,60.321,0],"to":[0,0,0],"ti":[0,0,0]},{"t":94.0000038286985}],"ix":2},"a":{"a":0,"k":[20.746,53.191,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[30,30],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.156862745098,0.8,0.917647058824,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[20.746,53.191],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[114.47,114.47],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"椭圆 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600.000024438501,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"形状图层 2","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":114.894,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[44.25,26.233,0],"e":[60.664,59.757,0],"to":[2.7356116771698,5.58729076385498,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":23,"s":[60.664,59.757,0],"e":[44.25,26.233,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[44.25,26.233,0],"e":[60.664,59.757,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":70,"s":[60.664,59.757,0],"e":[44.25,26.233,0],"to":[0,0,0],"ti":[2.7356116771698,5.58729076385498,0]},{"t":94.0000038286985}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-35,-61],[74,1]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":6,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.169,0.792,0.922,0.5,0.086,0.835,0.896,1,0.004,0.878,0.871],"ix":8}},"s":{"a":0,"k":[0,0],"ix":4},"e":{"a":0,"k":[100,0],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"nm":"渐变描边 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"形状 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[50],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":23,"s":[0],"e":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[50],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[0],"e":[50]},{"t":94.0000038286985}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[50],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":23,"s":[100],"e":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[50],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[100],"e":[50]},{"t":94.0000038286985}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":600.000024438501,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"形状图层 3","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":114.894,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[96.328,55.361,0],"e":[60.21,59.546,0],"to":[-6.01959657669067,0.69762498140335,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":23,"s":[60.21,59.546,0],"e":[96.328,55.361,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[96.328,55.361,0],"e":[60.21,59.546,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":70,"s":[60.21,59.546,0],"e":[96.328,55.361,0],"to":[0,0,0],"ti":[-6.01959657669067,0.69762498140335,0]},{"t":94.0000038286985}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[74.5,0.5],[-35,64]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":6,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.169,0.792,0.922,0.5,0.086,0.835,0.896,1,0.004,0.878,0.871],"ix":8}},"s":{"a":0,"k":[0,0],"ix":4},"e":{"a":0,"k":[100,0],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"nm":"渐变描边 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"形状 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[50],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":23,"s":[0],"e":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[50],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[0],"e":[50]},{"t":94.0000038286985}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[50],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":23,"s":[100],"e":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[50],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[100],"e":[50]},{"t":94.0000038286985}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":600.000024438501,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"形状图层 1","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":114.894,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":0,"s":[45.478,91.295,0],"e":[60.21,59.546,0],"to":[2.45545268058777,-5.29136371612549,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":23,"s":[60.21,59.546,0],"e":[45.478,91.295,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[45.478,91.295,0],"e":[60.21,59.546,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":70,"s":[60.21,59.546,0],"e":[45.478,91.295,0],"to":[0,0,0],"ti":[2.45545268058777,-5.29136371612549,0]},{"t":94.0000038286985}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-35,-61],[-35,64]],"c":false},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":6,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.169,0.792,0.922,0.5,0.086,0.835,0.896,1,0.004,0.878,0.871],"ix":8}},"s":{"a":0,"k":[0,0],"ix":4},"e":{"a":0,"k":[100,0],"ix":5},"t":1,"lc":1,"lj":1,"ml":4,"nm":"渐变描边 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"形状 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[50],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":23,"s":[0],"e":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[50],"e":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[0],"e":[50]},{"t":94.0000038286985}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[50],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":23,"s":[100],"e":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":47,"s":[50],"e":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":70,"s":[100],"e":[50]},{"t":94.0000038286985}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":600.000024438501,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"“图层 1”轮廓 6","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":27.338,"s":[20],"e":[40]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":39.766,"s":[40],"e":[0]},{"t":94.0000038286985}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[340.001,340,0],"ix":2},"a":{"a":0,"k":[180,180,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":27.338,"s":[80,80,100],"e":[218,218,100]},{"t":94.0000038286985}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-82.843],[82.843,0],[0,82.843],[-82.842,0]],"o":[[0,82.843],[-82.842,0],[0,-82.843],[82.843,0]],"v":[[150,0],[-0.001,150],[-150,0],[-0.001,-150]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":2,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.404,0.675,0.992,0.5,0.204,0.776,0.931,1,0.004,0.878,0.871],"ix":8}},"s":{"a":0,"k":[-65.848,134.836],"ix":4},"e":{"a":0,"k":[64.391,-132.25],"ix":5},"t":1,"lc":2,"lj":1,"ml":10,"nm":"渐变描边 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[180,180],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":27.0000010997325,"op":625.000025456772,"st":25.0000010182709,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"“图层 1”轮廓 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":17.169,"s":[20],"e":[40]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":29.598,"s":[40],"e":[0]},{"t":83.8312534145168}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[340.001,340,0],"ix":2},"a":{"a":0,"k":[180,180,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":17.169,"s":[80,80,100],"e":[218,218,100]},{"t":83.8312534145168}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-82.843],[82.843,0],[0,82.843],[-82.842,0]],"o":[[0,82.843],[-82.842,0],[0,-82.843],[82.843,0]],"v":[[150,0],[-0.001,150],[-150,0],[-0.001,-150]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":2,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.404,0.675,0.992,0.5,0.204,0.776,0.931,1,0.004,0.878,0.871],"ix":8}},"s":{"a":0,"k":[-65.848,134.836],"ix":4},"e":{"a":0,"k":[64.391,-132.25],"ix":5},"t":1,"lc":2,"lj":1,"ml":10,"nm":"渐变描边 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[180,180],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":17.0000006924242,"op":616.000025090194,"st":16.0000006516934,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"“图层 1”轮廓 4","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":7,"s":[20],"e":[40]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":19.429,"s":[40],"e":[0]},{"t":73.6625030003351}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[340.001,340,0],"ix":2},"a":{"a":0,"k":[180,180,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":7,"s":[80,80,100],"e":[218,218,100]},{"t":73.6625030003351}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-82.843],[82.843,0],[0,82.843],[-82.842,0]],"o":[[0,82.843],[-82.842,0],[0,-82.843],[82.843,0]],"v":[[150,0],[-0.001,150],[-150,0],[-0.001,-150]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":2,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.404,0.675,0.992,0.5,0.204,0.776,0.931,1,0.004,0.878,0.871],"ix":8}},"s":{"a":0,"k":[-65.848,134.836],"ix":4},"e":{"a":0,"k":[64.391,-132.25],"ix":5},"t":1,"lc":2,"lj":1,"ml":10,"nm":"渐变描边 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[180,180],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":7.00000028511585,"op":607.000024723617,"st":7.00000028511585,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"“图层 1”轮廓 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[20],"e":[40]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":11,"s":[40],"e":[0]},{"t":59.0000024031193}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[340.001,340,0],"ix":2},"a":{"a":0,"k":[180,180,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"n":["0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167","0p833_0p833_0p167_0p167"],"t":0,"s":[80,80,100],"e":[218,218,100]},{"t":59.0000024031193}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-82.843],[82.843,0],[0,82.843],[-82.842,0]],"o":[[0,82.843],[-82.842,0],[0,-82.843],[82.843,0]],"v":[[150,0],[-0.001,150],[-150,0],[-0.001,-150]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"gs","o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":2,"ix":10},"g":{"p":3,"k":{"a":0,"k":[0,0.404,0.675,0.992,0.5,0.204,0.776,0.931,1,0.004,0.878,0.871],"ix":8}},"s":{"a":0,"k":[-65.848,134.836],"ix":4},"e":{"a":0,"k":[64.391,-132.25],"ix":5},"t":1,"lc":2,"lj":1,"ml":10,"nm":"渐变描边 1","mn":"ADBE Vector Graphic - G-Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[180,180],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"修剪路径 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":600.000024438501,"st":0,"bm":0}]} -------------------------------------------------------------------------------- /src/layouts/loadingSpinner2.json: -------------------------------------------------------------------------------- 1 | {"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":30,"ip":0,"op":31,"w":800,"h":200,"nm":"Loading Files","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Search","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.97,"y":1},"o":{"x":0.69,"y":0},"t":0,"s":[351.535,97.918,0],"to":[6,-17,0],"ti":[11,14.25,0]},{"t":30,"s":[351.535,99.418,0]}],"ix":2},"a":{"a":0,"k":[352.535,96.918,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[16.521,-0.045],[-0.013,-34.356],[-34.356,0.012],[0.011,34.356],[11.651,11.659]],"o":[[-34.356,0.012],[0.011,34.356],[34.356,-0.013],[-0.006,-16.483],[-11.651,-11.715]],"v":[[-0.089,-62.489],[-62.274,-0.26],[-0.046,61.927],[62.142,-0.304],[43.936,-44.254]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[9.639,0.013],[-0.054,41.136],[-41.136,-0.054],[0.054,-41.137],[28.059,-11.391]],"o":[[-41.136,-0.054],[0.054,-41.137],[41.136,0.055],[-0.039,30.282],[-8.929,3.626]],"v":[[-0.098,74.485],[-74.484,-0.097],[0.098,-74.485],[74.484,0.098],[28.019,69.014]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.792156875134,0.807843148708,0.835294127464,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[383.401,89.476],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Subtraction 48","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[2.999,-2.999],[0,0],[2.999,2.999],[0,0]],"o":[[0,0],[0,0],[0,0],[2.999,2.999],[0,0],[-2.999,2.999],[0,0],[0,0]],"v":[[-25.254,-8.902],[-8.902,-25.254],[-8.902,-25.254],[23.005,6.653],[23.005,17.514],[17.514,23.005],[6.653,23.005],[-25.254,-8.902]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.713725507259,0.733333349228,0.768627464771,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[446.9,153.591],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 4757","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":510,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Files 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.24],"y":[1]},"o":{"x":[0.167],"y":[0.172]},"t":0,"s":[0]},{"t":30,"s":[50]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.24,"y":1},"o":{"x":0.167,"y":0.172},"t":0,"s":[723.194,100.918,0],"to":[-25.25,-0.583,0],"ti":[25.25,0.583,0]},{"t":30,"s":[571.694,97.418,0]}],"ix":2},"a":{"a":0,"k":[723.194,96.918,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.24,0.24,0.24],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.172,0.172,11.207]},"t":0,"s":[100,100,100]},{"t":30,"s":[165,165,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.019,-0.326],[0,0],[0.326,-0.019],[0,0],[0.019,0.326],[0,0],[-0.326,0.019]],"o":[[0,0],[0.326,0.019],[0,0],[-0.019,0.326],[0,0],[-0.326,-0.019],[0,0],[0.019,-0.326],[0,0]],"v":[[-18.935,-8.56],[-10.273,-8.56],[-9.669,-7.956],[-9.669,-5.943],[-10.273,-5.338],[-18.935,-5.338],[-19.54,-5.943],[-19.54,-7.957],[-18.935,-8.562]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.019,-0.326],[0,0],[0.326,-0.019],[0,0],[0.019,0.326],[0,0],[-0.326,0.019]],"o":[[0,0],[0.326,0.019],[0,0],[-0.019,0.326],[0,0],[-0.326,-0.019],[0,0],[0.019,-0.326],[0,0]],"v":[[-18.935,-0.906],[18.935,-0.906],[19.54,-0.301],[19.54,1.713],[18.935,2.318],[-18.935,2.318],[-19.54,1.713],[-19.54,-0.302],[-18.935,-0.907]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-0.325,0.019],[0,0],[-0.019,-0.326],[0,0],[0.326,-0.019],[0,0],[0.019,0.326],[0,0]],"o":[[0,0],[0.326,0.019],[0,0],[-0.019,0.326],[0,0],[-0.326,-0.019],[0,0],[0.019,-0.325]],"v":[[-18.935,5.943],[18.935,5.943],[19.54,6.547],[19.54,8.562],[18.935,9.166],[-18.935,9.166],[-19.54,8.562],[-19.54,6.546]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-0.326,0.019],[0,0],[-0.019,-0.326],[0,0],[0.326,-0.019],[0,0],[0.019,0.326],[0,0]],"o":[[0,0],[0.326,0.019],[0,0],[-0.019,0.326],[0,0],[-0.326,-0.019],[0,0],[0.019,-0.326]],"v":[[-18.935,12.791],[-0.604,12.791],[0.001,13.396],[0.001,15.41],[-0.604,16.014],[-18.935,16.014],[-19.54,15.41],[-19.54,13.396]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[-0.326,0.019],[0,0],[-0.019,-0.326],[0,0],[0.326,-0.019],[0,0],[0.019,0.326],[0,0]],"o":[[0,0],[0.326,0.019],[0,0],[-0.019,0.326],[0,0],[-0.326,-0.019],[0,0],[0.019,-0.326]],"v":[[-18.935,-16.014],[-6.446,-16.014],[-5.842,-15.41],[-5.842,-13.396],[-6.446,-12.791],[-18.935,-12.791],[-19.54,-13.396],[-19.54,-15.41]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[723.194,96.817],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2951","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-9.468,-9.468],[9.468,9.468],[-9.468,9.468]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[738.705,74.961],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2950","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.025,0],[0,0],[0,0],[0,0],[2.872,-0.021],[0.025,0],[0,0],[0.022,2.872],[0,0.026],[0,0],[-2.872,0.021]],"o":[[0,0],[0,0],[0,0],[0.021,2.872],[-0.025,0],[0,0],[-2.872,0.022],[0,-0.026],[0,0],[-0.021,-2.872],[0.025,0]],"v":[[-19.64,-31.424],[5.942,-31.424],[24.878,-12.489],[24.878,26.187],[19.715,31.424],[19.64,31.424],[-19.638,31.424],[-24.878,26.264],[-24.878,26.187],[-24.878,-26.187],[-19.715,-31.424]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.890196084976,0.921568632126,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[723.094,96.918],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2949","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":510,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Files 4","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.24],"y":[1]},"o":{"x":[0.167],"y":[0.172]},"t":0,"s":[50]},{"t":30,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.24,"y":1},"o":{"x":0.167,"y":0.172},"t":0,"s":[570.918,96.918,0],"to":[-30,0,0],"ti":[30,0,0]},{"t":30,"s":[390.918,96.918,0]}],"ix":2},"a":{"a":0,"k":[570.918,96.918,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.24,0.24,0.24],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.172,0.172,4.483]},"t":0,"s":[100,100,100]},{"t":30,"s":[126,126,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0],[-0.549,0.032]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549],[0,0]],"v":[[-31.928,-14.435],[-17.322,-14.435],[-16.303,-13.415],[-16.303,-10.021],[-17.322,-9.001],[-31.928,-9.001],[-32.948,-10.021],[-32.948,-13.417],[-31.928,-14.436]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0],[-0.549,0.032]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549],[0,0]],"v":[[-31.928,-1.527],[31.928,-1.527],[32.948,-0.508],[32.948,2.889],[31.928,3.908],[-31.928,3.908],[-32.948,2.889],[-32.948,-0.51],[-31.928,-1.529]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-0.549,0.032],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.033,-0.548]],"v":[[-31.928,10.021],[31.928,10.021],[32.948,11.04],[32.948,14.436],[31.928,15.456],[-31.928,15.456],[-32.948,14.436],[-32.948,11.038]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-0.549,0.032],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549]],"v":[[-31.928,21.568],[-1.018,21.568],[0.001,22.588],[0.001,25.984],[-1.018,27.004],[-31.928,27.004],[-32.948,25.984],[-32.948,22.588]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[-0.549,0.032],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549]],"v":[[-31.928,-27.004],[-10.87,-27.004],[-9.85,-25.984],[-9.85,-22.588],[-10.87,-21.568],[-31.928,-21.568],[-32.948,-22.588],[-32.948,-25.984]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[570.918,96.747],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2951","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-15.965,-15.965],[15.965,15.965],[-15.965,15.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[597.073,59.895],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2950","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.042,0],[0,0],[0,0],[0,0],[4.843,-0.035],[0.042,0],[0,0],[0.037,4.843],[0,0.043],[0,0],[-4.843,0.035]],"o":[[0,0],[0,0],[0,0],[0.035,4.843],[-0.042,0],[0,0],[-4.843,0.037],[0,-0.043],[0,0],[-0.035,-4.843],[0.042,0]],"v":[[-33.117,-52.988],[10.02,-52.988],[41.949,-21.059],[41.949,44.156],[33.243,52.988],[33.117,52.988],[-33.113,52.988],[-41.949,44.286],[-41.949,44.156],[-41.949,-44.156],[-33.243,-52.988]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.890196084976,0.921568632126,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[570.748,96.918],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2949","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":510,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Files 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.24],"y":[1]},"o":{"x":[0.167],"y":[0.172]},"t":0,"s":[100]},{"t":30,"s":[50]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.24,"y":1},"o":{"x":0.167,"y":0.172},"t":0,"s":[390.535,96.918,0],"to":[-30,0,0],"ti":[30,0,0]},{"t":30,"s":[210.535,96.918,0]}],"ix":2},"a":{"a":0,"k":[390.535,96.918,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.24,0.24,0.24],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.172,0.172,-3.793]},"t":0,"s":[100,100,100]},{"t":30,"s":[78,78,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.04,-0.692],[0,0],[0.692,-0.04],[0,0],[0.04,0.692],[0,0],[-0.692,0.04]],"o":[[0,0],[0.692,0.04],[0,0],[-0.04,0.692],[0,0],[-0.692,-0.04],[0,0],[0.04,-0.692],[0,0]],"v":[[-40.242,-18.193],[-21.833,-18.193],[-20.548,-16.908],[-20.548,-12.63],[-21.833,-11.345],[-40.242,-11.345],[-41.526,-12.63],[-41.526,-16.911],[-40.242,-18.195]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.04,-0.692],[0,0],[0.692,-0.04],[0,0],[0.04,0.692],[0,0],[-0.692,0.04]],"o":[[0,0],[0.692,0.04],[0,0],[-0.04,0.692],[0,0],[-0.692,-0.04],[0,0],[0.04,-0.692],[0,0]],"v":[[-40.242,-1.925],[40.242,-1.925],[41.526,-0.64],[41.526,3.641],[40.242,4.926],[-40.242,4.926],[-41.526,3.641],[-41.526,-0.642],[-40.242,-1.927]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-0.691,0.04],[0,0],[-0.04,-0.692],[0,0],[0.692,-0.04],[0,0],[0.04,0.692],[0,0]],"o":[[0,0],[0.692,0.04],[0,0],[-0.04,0.692],[0,0],[-0.692,-0.04],[0,0],[0.041,-0.691]],"v":[[-40.242,12.63],[40.242,12.63],[41.526,13.914],[41.526,18.195],[40.242,19.48],[-40.242,19.48],[-41.526,18.195],[-41.526,13.912]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-0.692,0.04],[0,0],[-0.04,-0.692],[0,0],[0.692,-0.04],[0,0],[0.04,0.692],[0,0]],"o":[[0,0],[0.692,0.04],[0,0],[-0.04,0.692],[0,0],[-0.692,-0.04],[0,0],[0.04,-0.692]],"v":[[-40.242,27.184],[-1.284,27.184],[0.001,28.469],[0.001,32.75],[-1.284,34.035],[-40.242,34.035],[-41.526,32.75],[-41.526,28.469]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[-0.692,0.04],[0,0],[-0.04,-0.692],[0,0],[0.692,-0.04],[0,0],[0.04,0.692],[0,0]],"o":[[0,0],[0.692,0.04],[0,0],[-0.04,0.692],[0,0],[-0.692,-0.04],[0,0],[0.04,-0.692]],"v":[[-40.242,-34.035],[-13.7,-34.035],[-12.415,-32.75],[-12.415,-28.469],[-13.7,-27.184],[-40.242,-27.184],[-41.526,-28.469],[-41.526,-32.75]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[390.534,96.702],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2951","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-20.121,-20.121],[20.121,20.121],[-20.121,20.121]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[423.5,50.255],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2950","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.053,0],[0,0],[0,0],[0,0],[6.104,-0.044],[0.053,0],[0,0],[0.047,6.104],[0,0.055],[0,0],[-6.104,0.044]],"o":[[0,0],[0,0],[0,0],[0.044,6.104],[-0.053,0],[0,0],[-6.104,0.047],[0,-0.055],[0,0],[-0.044,-6.104],[0.053,0]],"v":[[-41.74,-66.785],[12.628,-66.785],[52.871,-26.542],[52.871,55.653],[41.899,66.785],[41.74,66.785],[-41.735,66.785],[-52.871,55.817],[-52.871,55.653],[-52.871,-55.653],[-41.899,-66.785]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.890196084976,0.921568632126,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[390.321,96.918],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2949","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":510,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Files 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.24],"y":[1]},"o":{"x":[0.167],"y":[0.172]},"t":0,"s":[50]},{"t":30,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.24,"y":1},"o":{"x":0.167,"y":0.172},"t":0,"s":[210.152,96.918,0],"to":[-22,0,0],"ti":[22,0,0]},{"t":30,"s":[78.151,96.918,0]}],"ix":2},"a":{"a":0,"k":[210.152,96.918,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.24,0.24,0.24],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.172,0.172,-6.897]},"t":0,"s":[100,100,100]},{"t":30,"s":[60,60,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0],[-0.549,0.032]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549],[0,0]],"v":[[-31.928,-14.435],[-17.322,-14.435],[-16.303,-13.415],[-16.303,-10.021],[-17.322,-9.001],[-31.928,-9.001],[-32.948,-10.021],[-32.948,-13.417],[-31.928,-14.436]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0],[-0.549,0.032]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549],[0,0]],"v":[[-31.928,-1.527],[31.928,-1.527],[32.948,-0.508],[32.948,2.889],[31.928,3.908],[-31.928,3.908],[-32.948,2.889],[-32.948,-0.51],[-31.928,-1.529]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[-0.549,0.032],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.033,-0.548]],"v":[[-31.928,10.021],[31.928,10.021],[32.948,11.04],[32.948,14.436],[31.928,15.456],[-31.928,15.456],[-32.948,14.436],[-32.948,11.038]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-0.549,0.032],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549]],"v":[[-31.928,21.568],[-1.018,21.568],[0.001,22.588],[0.001,25.984],[-1.018,27.004],[-31.928,27.004],[-32.948,25.984],[-32.948,22.588]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ind":4,"ty":"sh","ix":5,"ks":{"a":0,"k":{"i":[[-0.549,0.032],[0,0],[-0.032,-0.549],[0,0],[0.549,-0.032],[0,0],[0.032,0.549],[0,0]],"o":[[0,0],[0.549,0.032],[0,0],[-0.032,0.549],[0,0],[-0.549,-0.032],[0,0],[0.032,-0.549]],"v":[[-31.928,-27.004],[-10.87,-27.004],[-9.85,-25.984],[-9.85,-22.588],[-10.87,-21.568],[-31.928,-21.568],[-32.948,-22.588],[-32.948,-25.984]],"c":true},"ix":2},"nm":"Path 5","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[210.151,96.747],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2951","np":6,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-15.965,-15.965],[15.965,15.965],[-15.965,15.965]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.698039233685,0.75686275959,0.819607853889,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[236.306,59.895],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2950","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.042,0],[0,0],[0,0],[0,0],[4.843,-0.035],[0.042,0],[0,0],[0.037,4.843],[0,0.043],[0,0],[-4.843,0.035]],"o":[[0,0],[0,0],[0,0],[0.035,4.843],[-0.042,0],[0,0],[-4.843,0.037],[0,-0.043],[0,0],[-0.035,-4.843],[0.042,0]],"v":[[-33.117,-52.988],[10.02,-52.988],[41.949,-21.059],[41.949,44.156],[33.243,52.988],[33.117,52.988],[-33.113,52.988],[-41.949,44.286],[-41.949,44.156],[-41.949,-44.156],[-33.243,-52.988]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.850980401039,0.890196084976,0.921568632126,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[209.981,96.918],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2949","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":510,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":1,"nm":"BG","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[400,100,0],"ix":2},"a":{"a":0,"k":[400,100,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"sw":800,"sh":200,"sc":"#ffffff","ip":0,"op":510,"st":0,"bm":0}],"markers":[]} --------------------------------------------------------------------------------