├── .dockerignore
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── dependabot.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── public
├── images
│ ├── animetrix192x192.png
│ ├── animetrix256.png
│ ├── animetrix384.png
│ ├── animetrix512x512.png
│ ├── apple-touch-icon.png
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── favicon.png
│ └── maskableicon.png
├── index.html
├── manifest.json
└── robot.txt
└── src
├── App.css
├── App.jsx
├── Components
├── AiringSchedule.jsx
├── AnimeImageSearchLayout.jsx
├── Bookmark.jsx
├── Card.jsx
├── ChatBody.jsx
├── ChatBotapi.js
├── ChatInput.jsx
├── Footer.jsx
├── ForYou.jsx
├── Header.jsx
├── History.jsx
├── ScrollToTop.jsx
├── Search.jsx
├── UpcomingSeason.jsx
├── UpcomingSeasonCard.jsx
├── constants.js
├── error404.jsx
├── index.js
└── slider.jsx
├── Loading
├── DetailsLoader.jsx
├── GenreLoading.jsx
├── HomePageLoader.jsx
├── OtherPagesCard.jsx
├── ProfileLoader.jsx
└── StreamLoader.jsx
├── Pages
├── AIChat.jsx
├── AnimeImageSearch.jsx
├── Details.jsx
├── DubAnime.jsx
├── ForgotPassword.jsx
├── Login.jsx
├── NewSeason.jsx
├── Popular.jsx
├── Profile.jsx
├── RecentAnime.jsx
├── Register.jsx
├── Stream.jsx
├── Terms.jsx
├── genre.jsx
├── index.js
├── movie.jsx
└── topAiring.jsx
├── css
├── AiringSchedule.css
├── Chatbot.css
├── Details.css
├── Footer.css
├── ForYou.css
├── Header.css
├── ImageSearch.css
├── Login.css
├── Profile.css
├── Root.css
├── Search.css
├── UpcomingSeason.css
├── card.css
├── error404.css
├── lastwatch.css
├── slider.css
├── stream.css
├── terms.css
├── titleandfilterbar.css
└── topScroll.css
├── img
├── loader.gif
├── loader.svg
└── spinner.svg
├── index.js
├── service-worker.js
├── serviceWorkerRegistration.js
└── utils
├── hooks.js
└── toast.js
/.dockerignore:
--------------------------------------------------------------------------------
1 | .gitignore
2 | node_modules
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "npm" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | heyitsshiva@protonmail.me.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14-alpine AS BUILDER
2 | ENV WEB_ROOT=/app/AnimeTrix
3 | RUN apk add --no-cache git curl
4 | RUN curl -sf https://gobinaries.com/tj/node-prune | sh
5 | WORKDIR /app
6 | RUN git clone https://github.com/ShivaBhattacharjee/AnimeTrix.git
7 | WORKDIR $WEB_ROOT
8 | RUN find . -type f -exec sed -i 's/\r$//' {} +
9 | RUN npm install --verbose
10 | RUN npm run build
11 | RUN rm -rf .git .github .gitignore .dockerignore .vscode LICENSE README.md
12 | RUN node-prune node_modules
13 | RUN chmod -R 777 .
14 |
15 | FROM node:14-alpine
16 | ENV WEB_ROOT=/app/AnimeTrix
17 | RUN mkdir /app
18 | RUN mkdir $WEB_ROOT
19 | WORKDIR $WEB_ROOT
20 | COPY --from=BUILDER $WEB_ROOT .
21 | EXPOSE 3000
22 | CMD npm start
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
AnimeTrix
7 |
8 |
9 | A go to platform to stream/download your favorite anime
10 |
11 |
12 |
13 | View Demo
14 | .
15 | Report Bug
16 | .
17 | Request Feature
18 |
19 |
20 |
21 |
22 |
23 | ## Table Of Contents
24 |
25 | * [About the Project](#about-the-project)
26 | * [Built With](#built-with)
27 | * [Getting Started](#getting-started)
28 | * [Prerequisites](#prerequisites)
29 | * [Installation](#installation)
30 | * [Hosting](#host-your-own)
31 | * [Contributing](#contributing)
32 | * [Issue Template](#raising-an-issue)
33 | * [Code of conduct](#code-of-conduct)
34 | * [License](#license)
35 | * [Authors](#authors)
36 |
37 | ## About The Project
38 |
39 | 
40 |
41 |
42 | Anime Trix is an anime streaming / downloading site that offers a vast collection of anime shows for streaming and downloading. With a user-friendly interface, you can easily find your favorite anime shows and watch them in high-definition quality. Our platform is updated regularly with the latest anime episodes, so you can stay up-to-date with your favorite shows. Anime Trix is the go-to destination for anime lovers who want to watch their favorite shows anytime, anywhere.
43 |
44 | ## Built With
45 |
46 | AnimeTrix is built using ReactJs and vanilla Css
47 |
48 | * [ReactJs](https://reactjs.org/docs/getting-started.html) (CRA i.e Create React App)
49 | * [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS)
50 | * [Express Js](http://expressjs.com/)
51 | * [Mongo DB](https://www.mongodb.com/)
52 |
53 | Disclaimer: Please note that the backend logic for comment, login, and validation is currently not available as an open source. However, you can still utilize the API provided in the "constant.js" file to access and use the functions for login and other login related stuff. We make no guarantees or warranties as to the performance or suitability of this API for your specific needs, and we are not responsible for any damages or issues that may arise from its use. Use of this API is entirely at your own risk.
54 |
55 | ## Getting Started
56 |
57 |
58 | ### Prerequisites
59 |
60 | Git is a distributed version control system used for software development. It allows multiple developers to work on the same codebase simultaneously, keeping track of changes and managing versions. It also enables users to revert changes and collaborate more effectively.
61 |
62 |
63 |
64 | NodeJs is a JavaScript runtime built on Chrome's V8 JavaScript engine. It allows developers to execute JavaScript code outside of a web browser, making it possible to create server-side applications with JavaScript. Node.js is fast, lightweight, and scalable, making it popular for building modern web applications.
65 |
66 | ### Installation
67 | ```bash
68 | git clone https://github.com/ShivaBhattacharjee/AnimeTrix.git
69 | ```
70 | ```
71 | cd AnimeTrix
72 | ```
73 | ```
74 | npm install
75 | ```
76 | ```
77 | npm start
78 | ```
79 | Server will start at http://localhost:3000/
80 |
81 | ## Host your own
82 | * ## Vercel
83 |
84 | [](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FShivaBhattacharjee%2FAnimeTrix)
85 |
86 |
87 |
88 | * ## Netlify
89 |
90 | [](https://app.netlify.com/start/deploy?repository=https://github.com/ShivaBhattacharjee/AnimeTrix)
91 |
92 |
93 |
94 | * ## Render
95 |
96 | [](https://render.com/deploy?repo=https://github.com/ShivaBhattacharjee/AnimeTrix)
97 |
98 | ## Contributing
99 |
100 | Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.
101 | * If you have suggestions for adding or removing projects, feel free to [open an issue](https://github.com/ShivaBhattacharjee/AnimeTrix/issues) to discuss it
102 |
103 | * Please make sure you check your spelling and grammar.
104 |
105 | ### Creating A Pull Request
106 |
107 | Wanna contribute to AnimeTrix ?
108 |
109 | 1. Fork the Project
110 | 2. Create your Feature Branch (`git checkout -b feature/FeatureName`)
111 | 3. Commit your Changes (`git commit -m 'Add some FeatureName'`)
112 | 4. Push to the Branch (`git push origin feature/FeatureName`)
113 | 5. Open a Pull Request
114 |
115 |
116 | ## Raising an issue
117 |
118 | If you're experiencing any problems with Animetrix, please be sure to review our [issue template](https://github.com/ShivaBhattacharjee/AnimeTrix/tree/main/.github/ISSUE_TEMPLATE) before opening a new issue. The template includes a list of questions and prompts that will help us better understand the issue you're experiencing, and it will ensure that we have all of the necessary information to investigate the problem.
119 |
120 | We kindly ask that you provide as much detail as possible when submitting an issue, including steps to reproduce the problem, any error messages that you have seen, and any other relevant information. This will help us to identify and fix the issue more quickly.
121 |
122 | Thank you for your cooperation, and we look forward to hearing from you!
123 |
124 | ## Code of conduct
125 |
126 | Developers are requested to go through our code of conduct thoroughly to maintain a peaceful environment within our project.
127 |
128 | ## License
129 |
130 | Distributed under the Apache License 2.0 . See [LICENSE](https://github.com/ShivaBhattacharjee/AnimeTrix/blob/main/LICENSE) for more information.
131 |
132 | ## Authors
133 |
134 | * **Shiva Bhattacharjee** - [Shiva Bhattacharjee](https://github.com/ShivaBhattacharjee) - *AnimeTrix*
135 | * **Dark-Knight** - [Dark-Knight-16](https://github.com/Dark-Knight-16) - *AnimeTrix*
136 |
137 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "animeTrix",
3 | "version": "2.2.2",
4 | "description": "Anime Trix is an anime streaming / downloading site that offers a vast collection of anime shows for streaming and downloading. With a user-friendly interface, you can easily find your favorite anime shows and watch them in high-definition quality. Our platform is updated regularly with the latest anime episodes, so you can stay up-to-date with your favorite shows. Anime Trix is the go-to destination for anime lovers who want to watch their favorite shows anytime, anywhere",
5 | "private": false,
6 | "keywords": [
7 | "react",
8 | "javascript",
9 | "web development",
10 | "frontend",
11 | "anime streaming",
12 | "anime downloading"
13 | ],
14 | "dependencies": {
15 | "@emotion/react": "^11.11.1",
16 | "@emotion/styled": "^11.11.0",
17 | "@formkit/auto-animate": "^1.0.0-pre-alpha.3",
18 | "@mui/icons-material": "^5.13.7",
19 | "@mui/material": "^5.13.7",
20 | "axios": "^1.4.0",
21 | "buffer": "^6.0.3",
22 | "js-cookie": "^3.0.5",
23 | "react": "^18.2.0",
24 | "react-copy-to-clipboard": "^5.1.0",
25 | "react-dom": "^18.2.0",
26 | "react-drag-drop-files": "^2.3.10",
27 | "react-helmet": "^6.1.0",
28 | "react-icons": "^4.10.1",
29 | "react-infinite-scroll-component": "^6.1.0",
30 | "react-lazy-load-image-component": "^1.6.0",
31 | "react-loading-skeleton": "^3.3.1",
32 | "react-query": "^3.39.3",
33 | "react-router-dom": "^6.14.1",
34 | "react-scripts": "5.0.1",
35 | "react-toastify": "^9.1.3",
36 | "react-top-loading-bar": "^2.3.1",
37 | "swiper": "^9.4.1",
38 | "web-vitals": "^3.3.2"
39 | },
40 | "scripts": {
41 | "start": "react-scripts start",
42 | "build": "react-scripts build",
43 | "test": "react-scripts test",
44 | "eject": "react-scripts eject"
45 | },
46 | "eslintConfig": {
47 | "extends": [
48 | "react-app",
49 | "react-app/jest"
50 | ]
51 | },
52 | "browserslist": {
53 | "production": [
54 | ">0.2%",
55 | "not dead",
56 | "not op_mini all"
57 | ],
58 | "development": [
59 | "last 1 chrome version",
60 | "last 1 firefox version",
61 | "last 1 safari version"
62 | ]
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/public/images/animetrix192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/animetrix192x192.png
--------------------------------------------------------------------------------
/public/images/animetrix256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/animetrix256.png
--------------------------------------------------------------------------------
/public/images/animetrix384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/animetrix384.png
--------------------------------------------------------------------------------
/public/images/animetrix512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/animetrix512x512.png
--------------------------------------------------------------------------------
/public/images/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/images/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/favicon-16x16.png
--------------------------------------------------------------------------------
/public/images/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/favicon-32x32.png
--------------------------------------------------------------------------------
/public/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/favicon.ico
--------------------------------------------------------------------------------
/public/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/favicon.png
--------------------------------------------------------------------------------
/public/images/maskableicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/public/images/maskableicon.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
29 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
39 |
40 |
42 |
44 |
45 | Watch Download Anime For Free On AnimeTrix
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "AnimeTrix",
3 | "short_name": "AnimeTrix",
4 | "theme_color": "#296dea",
5 | "background_color": "#100d16",
6 | "display": "standalone",
7 | "scope": "/",
8 | "start_url": "/",
9 | "description": "Anime Trix is an anime streaming / downloading site that offers a vast collection of anime shows for streaming and downloading. With a user-friendly interface, you can easily find your favorite anime shows and watch them in high-definition quality. Our platform is updated regularly with the latest anime episodes, so you can stay up-to-date with your favorite shows. Anime Trix is the go-to destination for anime lovers who want to watch their favorite shows anytime, anywhere.",
10 | "icons": [
11 | {
12 | "src":"images/maskableicon.png",
13 | "sizes":" 192x192",
14 | "type": "image/png",
15 | "purpose": "any maskable"
16 | },
17 | {
18 | "src": "images/animetrix192x192.png",
19 | "sizes": " 192x192",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "images/animetrix256.png",
24 | "sizes": " 256x256",
25 | "type": "image/png"
26 | },
27 | {
28 | "src": "images/animetrix512x512.png",
29 | "sizes": " 512x512",
30 | "type": "image/png"
31 | }
32 | ]
33 | }
--------------------------------------------------------------------------------
/public/robot.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | text-decoration: none;
5 | font-family: poppins;
6 | list-style-type: none;
7 | -webkit-tap-highlight-color: transparent;
8 | }
9 | .art-setting-quality {
10 | display: block !important;
11 | }
12 | *,
13 | *::before,
14 | *::after {
15 | box-sizing: border-box;
16 | }
17 |
18 | /* scroll bar */
19 | html {
20 | scroll-behavior: smooth;
21 | font-family: poppins;
22 | scrollbar-color: rgb(41, 109, 234);
23 | scrollbar-width: 0.5rem;
24 | }
25 |
26 |
27 | h1,
28 | h2,
29 | h3,
30 | h4,
31 | h5,
32 | h6 {
33 | color: #fff;
34 | }
35 |
36 | body{
37 | background: var(--background-color);
38 | max-height: 100%;
39 | min-height: 100vh;
40 | width: 100%;
41 | color: var(--text-color);
42 | }
43 |
44 | img {
45 | display: block;
46 | width: 100%;
47 | height: 100%;
48 | object-fit: cover;
49 | pointer-events: none;
50 | }
51 |
52 | input,
53 | button,
54 | select {
55 | font: inherit;
56 | background-color: none;
57 | border: none;
58 | outline: none;
59 | }
60 |
61 | button {
62 | color: var(--text-color);
63 | cursor: pointer;
64 | }
65 |
66 | a {
67 | text-decoration: none;
68 | display: block;
69 | color: var(--text-color);
70 | }
71 |
72 | ::-webkit-scrollbar {
73 | background: transparent;
74 | width: 6px;
75 | }
76 |
77 | ::-webkit-scrollbar-thumb {
78 | background-color:var(--scroll-bar);
79 | border-radius: 14px;
80 | }
81 |
82 |
83 |
84 | .react-loading-skeleton {
85 | display: block;
86 | animation: pulse 1.8s ease-in-out 0.5s infinite;
87 | transform: translateZ(0);
88 | background: linear-gradient(-90deg, #000000 0%, #646161 50%, #646161 50%);
89 | background-size: 400% 400%;
90 | }
91 |
92 | @keyframes pulse {
93 | 0% {
94 | background-position: 0% 0%;
95 | }
96 | 100% {
97 | background-position: -100% 90%;
98 | }
99 | }
100 |
101 |
--------------------------------------------------------------------------------
/src/Components/AiringSchedule.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import { useState, useEffect } from "react";
4 | function AiringSchedule(props) {
5 | const { airingList, ref } = props;
6 | const [dateTime, setDateTime] = useState(new Date().toLocaleString());
7 |
8 | useEffect(() => {
9 | const intervalID = setInterval(() => {
10 | setDateTime(new Date().toLocaleString());
11 | }, 1000);
12 |
13 | return () => {
14 | clearInterval(intervalID);
15 | };
16 | }, []);
17 | return (
18 |
19 |
20 |
Airing Schedule
21 | Today is {dateTime}
22 |
23 |
24 | {airingList?.map((airingSchedule) => {
25 | const { id, title, episode, airingAt } = airingSchedule;
26 |
27 | return (
28 |
29 |
30 |
31 | {new Date(airingAt * 1000).toLocaleString()}
32 |
33 |
{title.userPreferred}
34 |
35 |
36 |
Episode : {episode}
37 |
38 |
39 | );
40 | })}
41 |
42 |
43 | );
44 | }
45 |
46 | export default AiringSchedule;
47 |
--------------------------------------------------------------------------------
/src/Components/AnimeImageSearchLayout.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from "react"
2 | import { Link } from "react-router-dom"
3 | import { HomeApi } from "./constants"
4 | import { showErrorToast } from "../utils/toast"
5 | function AnimeImageSearchLayout({ searchResult, setToggle }) {
6 | const [loading, setLoading] = useState(true)
7 | const [view, setView] = useState([])
8 | const [select, setSelect] = useState(0)
9 | const prevAnilist = useRef()
10 | const getAnime = async (number) => {
11 | setLoading(true)
12 | try{
13 | if (prevAnilist.current !== searchResult.result[number].anilist.id) {
14 | const url = await fetch(
15 | `${HomeApi}/meta/anilist/info/${searchResult.result[number].anilist.id}`
16 | )
17 | const response = await url.json();
18 | const responseArray = [response]
19 | setView(responseArray)
20 | }
21 | prevAnilist.current = searchResult.result[number].anilist.id
22 | setLoading(false)
23 | }catch(error){
24 | showErrorToast('Cant find image!');
25 | }
26 | }
27 |
28 | useEffect(() => {
29 | getAnime(select)
30 | }, [searchResult.result, select, getAnime])
31 |
32 | return (
33 | <>
34 | {view.map((imageSearch) => {
35 | return (
36 | <>
37 | {!loading && (
38 |
39 |
40 |
41 |
Match?
42 |
43 |
44 |
45 |
47 |
48 |
49 |
55 |
56 |
57 |
58 | {(imageSearch.totalEpisodes)}
59 | {(imageSearch.rating / 10)}
60 |
61 |
{imageSearch.userPreferred || imageSearch.title.english || imageSearch.romaji}
62 |
63 |
64 |
65 |
66 |
67 | )}
68 | >
69 | )
70 | })}
71 |
72 |
73 |
74 |
Other Results
75 |
76 |
77 |
78 | {searchResult.result.map((item, i) => (
79 |
{
84 | setSelect(i)
85 | }}
86 | >
87 |
88 |
89 |
98 |
99 |
100 |
{item?.anilist?.title?.english ||
101 | item?.anilist?.title?.romaji ||
102 | item?.anilist?.title?.native}
103 | Episode - {item?.episode}
104 | {Math.round(item?.similarity * 10000) / 100}% similarity
105 |
106 |
107 |
108 |
109 | ))}
110 |
111 |
112 |
113 | setToggle(true)}
116 | >
117 | Another Image
118 |
119 |
120 | {/*
121 |
122 |
Expected Scene
123 |
124 |
132 |
*/}
133 |
134 |
135 |
136 | >
137 | )
138 | }
139 |
140 | export default AnimeImageSearchLayout
--------------------------------------------------------------------------------
/src/Components/Bookmark.jsx:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom'
2 | import { React, useEffect, useState } from 'react';
3 | import axios from "axios";
4 | import { ToastContainer } from 'react-toastify';
5 | import 'react-toastify/dist/ReactToastify.css';
6 | import Card from './Card';
7 | import { ServerApi } from './constants';
8 | import OtherPagesCard from '../Loading/OtherPagesCard';
9 | import { showErrorToast } from '../utils/toast';
10 | const Bookmark = () => {
11 | const [animeData, setAnimeData] = useState([])
12 | const [userId, setUserId] = useState("");
13 | const [loading, setLoading] = useState(true);
14 | const [bookmark, setBookmark] = useState([]);
15 | const [count, setCount] = useState(18);
16 |
17 | function getCookie(name) {
18 | const cookies = document.cookie.split(';');
19 | for (let i = 0; i < cookies.length; i++) {
20 | const cookie = cookies[i].trim();
21 | if (cookie.startsWith(name + '=')) {
22 | return cookie.substring(name.length + 1);
23 | }
24 | }
25 | return undefined;
26 | }
27 | const handleViewMoreClick = () => {
28 | setCount(count + 18);
29 | if (count >= 40) {
30 |
31 | }
32 | };
33 | const removeBookmark = (animeId) => {
34 | const newArray = bookmark.filter(item => item != animeId);
35 | const newAnimeData = animeData.filter(data => data.id != animeId);
36 | setAnimeData(newAnimeData);
37 | setBookmark(newArray);
38 | }
39 |
40 | useEffect(() => {
41 | const id = getCookie("id");
42 | setUserId(id);
43 | });
44 |
45 | useEffect(() => {
46 | window.scrollTo(0, 0);
47 | getBookmarks();
48 | }, [userId]);
49 |
50 |
51 | const getBookmarks = async () => {
52 | try {
53 | if (userId) {
54 | axios.interceptors.response.use(response => {
55 | return response;
56 | }, error => {
57 | showErrorToast(error.response.data.error);
58 | return;
59 | });
60 | const res = await axios.get(`${ServerApi}/user/bookmark/${userId}`);
61 | const bookmark = res.data;
62 | setBookmark(bookmark);
63 |
64 | const animeDataArray = await Promise.all(bookmark.map(async (bookmarkItem) => {
65 | const animeRes = await axios.get(`https://animetrix-api.vercel.app/meta/anilist/info/${bookmarkItem}`);
66 | return animeRes.data;
67 | }));
68 |
69 | setAnimeData(animeDataArray);
70 | setLoading(false);
71 | }
72 | } catch (err) {
73 | console.log(err);
74 | showErrorToast('Error loading Bookmark!');
75 | }
76 | }
77 | return (
78 | <>
79 |
80 | {loading ? (
81 | <>
82 |
83 |
84 | {/*
Hi, {user} */}
85 | Bookmarks
86 |
87 |
88 |
89 |
90 | Profile
91 |
92 | History
93 | Bookmark
94 |
95 |
96 |
97 |
98 | >
99 | )
100 | : (<>
101 |
102 |
103 | {/*
Hi, {user} */}
104 | Bookmarks
105 |
106 |
107 |
108 |
109 | Profile
110 |
111 | History
112 | Bookmark
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | {/*
Bookmarks */}
121 | {bookmark.length == 0 ?
No bookmark : ""}
122 |
123 | {animeData?.slice(0, count).reverse().map((animeDataHis, index) => {
124 | return (
125 |
126 | )
127 | })}
128 |
129 | {bookmark.length > 18 ?
130 | View More
131 |
: null}
132 |
133 |
134 |
135 |
136 |
137 | >)}
138 | >
139 | )
140 | }
141 |
142 | export default Bookmark
--------------------------------------------------------------------------------
/src/Components/Card.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { Link } from "react-router-dom";
3 | import { ToastContainer } from 'react-toastify';
4 | import axios from "axios";
5 | // import { ToastContainer, toast } from 'react-toastify';
6 | import 'react-toastify/dist/ReactToastify.css';
7 | import { ServerApi } from "./constants";
8 | import { LazyLoadImage } from "react-lazy-load-image-component";
9 | import { showErrorToast } from "../utils/toast";
10 | export default function Card(props) {
11 | const [isBookmark, setIsBookmark] = useState(false);
12 | const [isLoading, setIsLoading] = useState(false);
13 | const [userId, setUserId] = useState("");
14 | const goToBtn = () => {
15 | window.scrollTo({ top:0, left: 0, behavior: "smooth" })
16 | }
17 | function getCookie(name) {
18 | const cookies = document.cookie.split(';');
19 | for (let i = 0; i < cookies.length; i++) {
20 | const cookie = cookies[i].trim();
21 | if (cookie.startsWith(name + '=')) {
22 | return cookie.substring(name.length + 1);
23 | }
24 | }
25 | return undefined;
26 | }
27 |
28 | const [bookmark, setBookmark] = useState([]);
29 |
30 |
31 |
32 | useEffect(() => {
33 | const id = getCookie("id");
34 | setUserId(id);
35 | });
36 |
37 | useEffect(() => {
38 | getBookmarks();
39 | }, [userId]);
40 |
41 |
42 | const getBookmarks = async () => {
43 | try {
44 | if (userId) {
45 | axios.interceptors.response.use(response => {
46 | return response;
47 | }, error => {
48 | showErrorToast(error.response.data.error);
49 | return;
50 | });
51 | const res = await axios.get(`${ServerApi}/user/bookmark/${userId}`)
52 | const bookmark = res.data;
53 | setBookmark(bookmark);
54 | bookmark.includes(props.rec.id) ? setIsBookmark(true) : setIsBookmark(false);
55 | }
56 | } catch (err) {
57 | console.log(err);
58 | }
59 | }
60 |
61 | const toggleBookmark = async () => {
62 | try {
63 | setIsLoading(true);
64 | if (props.removeBookmark)
65 | props.removeBookmark(props.rec.id);
66 | if (userId) {
67 | const response = await axios.post(
68 | `${ServerApi}/user/bookmark`,
69 | {
70 | _id: userId,
71 | animeId: props.rec.id,
72 | }
73 | );
74 | setIsBookmark(!isBookmark);
75 | setIsLoading(false);
76 | } else {
77 | showErrorToast('Login first!');
78 | }
79 | } catch (error) {
80 | setIsLoading(false);
81 | showErrorToast('Something went wrong');
82 | }
83 | };
84 |
85 | return (
86 |
87 | <>
88 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
{ props.handelClick(); goToBtn(); }}>
97 |
102 |
103 |
104 |
105 | {(props.rec.type)}
106 | {(props.rec.rating / 10)}
107 |
108 | {props?.rec?.title?.english && props?.rec?.title?.english ? (
109 |
{props?.rec?.title?.english }
110 | ) : (
111 |
{props?.rec?.title?.romaji}
112 | )}
113 |
114 |
115 |
116 | >
117 | );
118 | }
--------------------------------------------------------------------------------
/src/Components/ChatBody.jsx:
--------------------------------------------------------------------------------
1 |
2 | import React, { useRef, useState } from "react";
3 | import autoAnimate from "@formkit/auto-animate";
4 | import { useEffect } from "react";
5 | import { CopyToClipboard } from 'react-copy-to-clipboard';
6 |
7 | const ChatBody = ({ chat }) => {
8 | const [copy, setCopy] = useState(false)
9 | const aiStyle =
10 | "ai-style";
11 |
12 | const parent = useRef(null);
13 | const bottomRef = useRef(null);
14 |
15 |
16 | useEffect(() => {
17 | parent.current && autoAnimate(parent.current);
18 | }, [parent])
19 |
20 |
21 | useEffect(() => {
22 | bottomRef.current?.scrollIntoView({ behavior: "smooth" })
23 | window.scrollTo(0, 0);
24 | }, [chat])
25 |
26 | useEffect(() => {
27 | let copiedTimeout;
28 |
29 | if (copy) {
30 | copiedTimeout = setTimeout(() => {
31 | setCopy(false);
32 | }, 3500);
33 | }
34 |
35 | return () => {
36 | if (copiedTimeout) {
37 | clearTimeout(copiedTimeout);
38 | }
39 | };
40 | }, [copy]);
41 |
42 | return (
43 |
44 | {chat.map((message, i) => {
45 | return (
46 |
51 |
52 | {message.message}
53 |
54 |
55 | {message.sender === "ai" && (
56 |
57 | {copy ? (
58 |
59 | Copied
60 |
61 | ) : (
62 | setCopy(true)}>
63 |
64 | Copy Text
65 |
66 |
67 | )}
68 |
69 | )}
70 |
71 | );
72 | })}
73 |
74 |
75 |
76 | );
77 | };
78 |
79 | export default ChatBody;
--------------------------------------------------------------------------------
/src/Components/ChatBotapi.js:
--------------------------------------------------------------------------------
1 |
2 | export const fetchResponse = async(chat) => {
3 | try {
4 | const response = await fetch('https://chatbot-6hzt.onrender.com/', {
5 | method: 'POST',
6 | headers: {
7 | "Content-Type": "application/json"
8 | },
9 | body: JSON.stringify({
10 | message: chat.map((message)=> message.message).join(" \n ")
11 | })
12 | })
13 |
14 | const data = await response.json()
15 | return data
16 | } catch (error) {
17 | console.log(error);
18 | }
19 | }
--------------------------------------------------------------------------------
/src/Components/ChatInput.jsx:
--------------------------------------------------------------------------------
1 |
2 | import React from "react";
3 | import { useState } from "react";
4 | import loader from '../img/loader.gif'
5 | import { AiOutlineSend } from "react-icons/ai"
6 | const ChatInput = ({ sendMessage, loading }) => {
7 | const [value, setValue] = useState("Hi, Can you help me?");
8 |
9 | const handleSubmit = () => {
10 | if (value === "") return;
11 | sendMessage({ sender: "user", message: value });
12 | setValue("");
13 | };
14 | return (
15 |
18 | {loading ? (
19 |
20 | ) : (
21 | <>
22 |
39 | );
40 | };
41 |
42 | export default ChatInput;
--------------------------------------------------------------------------------
/src/Components/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import InstagramIcon from "@mui/icons-material/Instagram";
3 | import GitHubIcon from "@mui/icons-material/GitHub";
4 | import { Link } from "react-router-dom";
5 |
6 | function Footer() {
7 |
8 | const githubUrl = () => {
9 | window.open('https://github.com/ShivaBhattacharjee/AnimeTrix')
10 | }
11 |
12 | const instagramUrl = () => {
13 | window.open('https://www.instagram.com/animetrix.200/')
14 | }
15 | const discordUrl = () => {
16 | window.open('https://discord.gg/t7xSMNr7zN')
17 | }
18 | return (
19 |
20 |
21 | Anime Trix
22 |
23 |
24 | AnimeTrix is not affiliated with or endorsed by any of the anime studios
25 | behind the creation of the anime presented on this site. This website is
26 | only an user interface presenting/linking various self-hosted files
27 | across the internet by other third-party providers for easy access.
28 | AnimeTrix never downloads the video from any source provider, link will
29 | be returned from the response hence it is completely not subjected to
30 | DMCA compliant.
31 |
32 |
Terms and conditon
33 |
34 | discordUrl()} aria-label="discord icon">
35 | instagramUrl()} aria-label="instagram icon">
36 |
37 |
38 | githubUrl()} aria-label="github icon">
39 |
40 |
41 |
42 |
43 | );
44 | }
45 | export default Footer;
46 |
--------------------------------------------------------------------------------
/src/Components/ForYou.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import Card from './Card';
3 | import { HomeApi } from './constants';
4 | import { showErrorToast } from '../utils/toast';
5 | const ForYou = () => {
6 | const [forYou, setforYou] = useState([])
7 | const getRandom = async () => {
8 | try {
9 | const api = await fetch(`${HomeApi}/meta/anilist/random-anime`)
10 | const response = await api.json()
11 | setforYou(response)
12 | }
13 | catch (error) {
14 | showErrorToast('Error loading You Might Like');
15 | }
16 | }
17 | useEffect(() => {
18 | getRandom();
19 | }, [])
20 | return (
21 | <>
22 | {forYou && (
23 |
24 |
25 |
26 |
27 |
You might like
28 |
29 |
30 |
31 |
32 |
33 |
34 | )}
35 | >
36 | )
37 | }
38 |
39 | export default ForYou
--------------------------------------------------------------------------------
/src/Components/Header.jsx:
--------------------------------------------------------------------------------
1 | import React, { forwardRef, useImperativeHandle, useState, useEffect, useRef } from "react";
2 | import { NavLink, useNavigate } from "react-router-dom";
3 | import Cookies from "js-cookie";
4 | // import LogoutIcon from '@mui/icons-material/Logout';
5 | // import AccountCircleIcon from '@mui/icons-material/AccountCircle';
6 | // import { FiLogOut } from "react-icons/fi"
7 | import { Link } from "react-router-dom";
8 | const Header = forwardRef((props, ref) => {
9 | const [togglemenu, setToggleMenu] = useState(true);
10 |
11 | const [searchActive, setSearchActive] = useState(false);
12 | const [profileActive, setProfileActive] = useState(false);
13 | const [isLoggedIn, setIsLoggedIn] = useState(false);
14 | const [isAdmin, setIsAdmin] = useState(false);
15 | const [img, setImg] = useState("https://i.pinimg.com/originals/b8/bf/ac/b8bfac2f45bdc9bfd3ac5d08be6e7de8.jpg");
16 |
17 | const navigate = useNavigate();
18 | let menuRef = useRef();
19 |
20 | useEffect(() => {
21 | let handler = (e) => {
22 | if (!menuRef.current.contains(e.target)) {
23 | setSearchActive(false);
24 | }
25 | };
26 | document.addEventListener("mousedown", handler)
27 |
28 | return () => {
29 | document.removeEventListener("mousedown", handler)
30 | }
31 | })
32 |
33 |
34 | function getCookie(name) {
35 | const cookies = document.cookie.split(';');
36 | for (let i = 0; i < cookies.length; i++) {
37 | const cookie = cookies[i].trim();
38 | if (cookie.startsWith(name + '=')) {
39 | return cookie.substring(name.length + 1);
40 | }
41 | }
42 | return undefined;
43 | }
44 | let profileRef = useRef();
45 | useEffect(() => {
46 | let handler = (e) => {
47 | if (profileRef.current && !profileRef.current.contains(e.target)) {
48 | setProfileActive(false);
49 | }
50 | };
51 | document.addEventListener("mousedown", handler)
52 |
53 | return () => {
54 | document.removeEventListener("mousedown", handler)
55 | }
56 | })
57 | let toggleref = useRef();
58 | useEffect(() => {
59 | let handler = (e) => {
60 | if (!toggleref.current.contains(e.target)) {
61 | setToggleMenu(true);
62 | }
63 | };
64 | document.addEventListener("mousedown", handler)
65 |
66 | return () => {
67 | document.removeEventListener("mousedown", handler)
68 | }
69 | })
70 |
71 | const getUser = async () => {
72 | const id = getCookie("id");
73 | const category = getCookie("category");
74 | setImg(getCookie("img"));
75 | if (id && id.length !== 0) {
76 | setIsLoggedIn(true);
77 | }
78 | if (category == "admin")
79 | setIsAdmin(true);
80 | }
81 |
82 | useEffect(() => {
83 | getUser();
84 | // console.log(userId);
85 | },);
86 |
87 | function scroll() {
88 | window.scrollTo({ top: 0, left: 0, behavior: "smooth" })
89 | }
90 | function ProfileView() {
91 | setProfileActive(profileActive => !profileActive)
92 | }
93 | const ProfileOpen = profileActive ? 'active' : null;
94 | function MobileView() {
95 | setSearchActive(!searchActive);
96 | scroll()
97 | }
98 | const [inputVal, setInputVal] = useState("");
99 | const handelChange = (e) => {
100 | const val = e.target.value;
101 | setInputVal(val);
102 | };
103 |
104 |
105 | const handleSearchSubmit = () => {
106 | props.handelChanges(inputVal);
107 | navigate("/search")
108 | setSearchActive(false)
109 | }
110 | const handleKeyDown = (event) => {
111 | if (event.key === 'Enter') {
112 | handleSearchSubmit();
113 | }
114 | }
115 | useImperativeHandle(ref, () => ({
116 | emptySearch() {
117 | setInputVal("");
118 | },
119 | }));
120 |
121 | const closeMenuWhenClickedLink = () => {
122 | if (window.innerWidth <= 1360) {
123 | setToggleMenu(!togglemenu);
124 | }
125 | };
126 |
127 | const logout = (e) => {
128 | Cookies.remove("id");
129 | setIsLoggedIn(false);
130 | }
131 |
132 | return (
133 | <>
134 |
135 |
136 |
137 | Anime {" "}
138 | Trix
139 |
140 |
141 |
142 |
143 |
144 | closeMenuWhenClickedLink()}>
145 | Home
146 |
147 |
148 |
149 | closeMenuWhenClickedLink()}>
150 | Trending
151 |
152 |
153 |
154 | closeMenuWhenClickedLink()}>
155 | Movies
156 |
157 |
158 |
159 | closeMenuWhenClickedLink()}>
160 | Genres
161 |
162 |
163 | {/*
164 |
165 | closeMenuWhenClickedLink()}
168 | >
169 | Dub Anime
170 |
171 | */}
172 |
173 | closeMenuWhenClickedLink()}>
174 | ChatterBox
175 |
176 |
177 |
178 |
179 | closeMenuWhenClickedLink()}>
180 | AniScan
181 |
182 |
183 |
184 |
185 |
195 |
196 |
197 |
198 |
199 | {!isLoggedIn ?
200 |
201 |
202 |
203 |
204 |
205 | :
206 |
207 |
208 |
209 |
210 |
211 |
Profile
212 |
213 |
214 |
Bookmark
215 |
216 |
217 |
History
218 |
219 | {isAdmin ?
220 |
Admin : ""}
221 |
{ logout(e) }}>Logout
222 |
223 |
}
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 | {
238 | setToggleMenu(!togglemenu);
239 | }}
240 | >
241 | {togglemenu ? (
242 |
243 |
244 |
245 |
246 |
247 | ) : (
248 |
249 |
250 |
251 |
252 |
253 | )}
254 |
255 |
256 | >
257 | );
258 | });
259 | export default Header;
260 |
--------------------------------------------------------------------------------
/src/Components/ScrollToTop.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 |
3 | const ScrollToTop = () => {
4 | const [isVisible, setIsVisible] = useState(false)
5 | const goToBtn = () => {
6 | window.scrollTo({ top:0, left: 0, behavior: "smooth" })
7 | }
8 |
9 | const listenToScroll = () => {
10 | let hidden = 500
11 | const winScroll =
12 | document.body.scrollTop || document.documentElement.scrollTop;
13 | if (winScroll > hidden) {
14 | setIsVisible(true)
15 | } else {
16 | setIsVisible(false)
17 | }
18 | };
19 |
20 | useEffect(() => {
21 | window.addEventListener("scroll", listenToScroll);
22 | return () => window.removeEventListener("scroll", listenToScroll);
23 | }, [])
24 | return (
25 | <>
26 | {
27 | isVisible && (
28 |
33 | )
34 | }
35 |
36 | >
37 |
38 | )
39 | }
40 |
41 | export default ScrollToTop
--------------------------------------------------------------------------------
/src/Components/Search.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import Card from "./Card";
3 | import OtherPagesCard from "../Loading/OtherPagesCard";
4 |
5 | export default function SearchJSX(props) {
6 | const handelClick = () => {
7 | props.handelClick();
8 | };
9 |
10 | useEffect(() => {
11 | window.scrollTo(0, 0);
12 | }, []);
13 | if (!props.searchResult || Object.keys(props.searchResult).length === 0) {
14 | return (
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | return (
22 |
23 |
Search Results
24 |
25 | {props.searchResult.results.map((rec) => (
26 |
32 | ))}
33 |
34 |
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/src/Components/UpcomingSeason.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { Link } from "react-router-dom";
3 | import { HomeApi } from './constants';
4 | import { useFetchInitialData } from "../utils/hooks";
5 | import { LazyLoadImage } from 'react-lazy-load-image-component';
6 | import UpcomingSeasonCard from './UpcomingSeasonCard';
7 | const UpcomingSeason = () => {
8 | const [summer, setSummer] = useState([])
9 | const [fall, setFall] = useState([]);
10 | const [spring, setSpring] = useState([])
11 | const [winter, setWinter] = useState([])
12 | const getSummer = async () => {
13 | const api = await fetch(`${HomeApi}/meta/anilist/advanced-search?season=SUMMER&&year=2023`, { timeout: 10000 });
14 | const response = await api.json();
15 | setSummer(response.results);
16 | }
17 | const getFall = async () => {
18 | const api = await fetch(`${HomeApi}/meta/anilist/advanced-search?season=FALL&&year=2023`, { timeout: 10000 });
19 | const response = await api.json();
20 | setFall(response.results);
21 | }
22 | const getSpring = async () => {
23 | const api = await fetch(`${HomeApi}/meta/anilist/advanced-search?season=SPRING&&year=2023`, { timeout: 1000 });
24 | const response = await api.json();
25 | setSpring(response.results);
26 | }
27 | const getWinter = async () => {
28 | const api = await fetch(`${HomeApi}/meta/anilist/advanced-search?season=WINTER&&year=2023`, { timeout: 1000 });
29 | const response = await api.json();
30 | setWinter(response.results);
31 | }
32 | useEffect(() => {
33 | getSummer();
34 | getSpring();
35 | getFall();
36 | getWinter();
37 | }, []);
38 |
39 | useFetchInitialData(summer, winter, fall, spring)
40 | return (
41 |
42 |
43 |
Upcoming Season
44 |
45 |
46 |
47 |
48 |
49 |
Fall
50 | {fall?.map((fallData) => {
51 | return (
52 | <>
53 |
56 | >
57 | )
58 | })}
59 |
60 |
61 |
62 |
63 |
64 |
Summer
65 | {summer?.map((fallData) => {
66 | return (
67 | <>
68 |
70 | >
71 | )
72 | })}
73 |
74 |
75 |
76 |
77 |
78 |
Winter
79 | {winter?.map((fallData) => {
80 | return (
81 | <>
82 |
85 | >
86 | )
87 | })}
88 |
89 |
90 |
91 |
92 |
93 |
Spring
94 | {spring?.map((fallData) => {
95 | return (
96 | <>
97 |
98 | >
99 | )
100 | })}
101 |
102 |
103 |
104 | )
105 | }
106 |
107 | export default UpcomingSeason
--------------------------------------------------------------------------------
/src/Components/UpcomingSeasonCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { LazyLoadImage } from 'react-lazy-load-image-component';
3 | import { Link } from "react-router-dom";
4 | const UpcomingSeasonCard = ({fallData}) => {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
{fallData?.title?.userPreferred}
12 |
13 | {fallData.type}
14 | {fallData.countryOfOrigin}
15 |
16 |
{fallData?.releaseDate}
17 |
18 | {fallData?.genres?.map((genrData) => (
19 | {genrData}
20 | ))}
21 |
22 |
23 |
24 | )
25 | }
26 |
27 | export default UpcomingSeasonCard
--------------------------------------------------------------------------------
/src/Components/constants.js:
--------------------------------------------------------------------------------
1 | export const HomeApi = "https://api.consumet.org"
2 | export const ServerApi = "https://animetrix-login-backend.vercel.app/api/v1"
3 | export const StreamApi = "https://api.amvstr.ml"
4 |
--------------------------------------------------------------------------------
/src/Components/error404.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | import { Helmet } from "react-helmet";
4 |
5 | function Error404() {
6 | return (
7 | <>
8 |
9 | Error 404 could not find the page
10 |
11 |
12 |
13 |
404
14 |
15 |
16 | Welcome to the 404 dimension
17 |
You have discovered a new dimension
18 | But unfortunately, this dimension has nothing at all
19 |
20 | Go back to the old dimension
21 |
22 |
23 |
24 | >
25 | )
26 | }
27 | export default Error404;
28 |
--------------------------------------------------------------------------------
/src/Components/index.js:
--------------------------------------------------------------------------------
1 | import Card from "./Card";
2 | import Error404 from "./error404";
3 | import Footer from "./Footer";
4 | import Header from "./Header";
5 | import ScrollToTop from "./ScrollToTop"
6 | import SearchJSX from "./Search"
7 | import ChatBody from "./ChatBody";
8 | import ChatInput from "./ChatInput";
9 | import AiringSchedule from "./AiringSchedule";
10 | import ForYou from "./ForYou";
11 | import History from "./History";
12 | import Bookmark from './Bookmark'
13 | import AnimeImageSearchLayout from "./AnimeImageSearchLayout";
14 | import UpcomingSeason from "./UpcomingSeason";
15 | export {
16 | Card,
17 | Error404,
18 | Footer,
19 | Header,
20 | ScrollToTop,
21 | SearchJSX,
22 | ChatBody,
23 | ChatInput,
24 | AiringSchedule,
25 | ForYou,
26 | History,
27 | Bookmark,
28 | AnimeImageSearchLayout,
29 | UpcomingSeason,
30 | }
--------------------------------------------------------------------------------
/src/Components/slider.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef, useEffect } from "react";
2 | import { Link } from "react-router-dom";
3 | import {HomeApi} from "./constants"
4 | // Import Swiper React components
5 | import { Swiper, SwiperSlide } from "swiper/react";
6 |
7 | // Import Swiper styles
8 | import "swiper/css";
9 | import "swiper/css/pagination";
10 | import "swiper/css/navigation"
11 |
12 | import "../css/slider.css";
13 |
14 | // import required modules
15 | import { Autoplay, Pagination, Mousewheel } from "swiper";
16 |
17 | export default function Slider() {
18 | const renderAfterCalled = useRef(false);
19 | const [sliderinfo, setSlider] = useState([]);
20 | const getSlider = async () => {
21 | const api = await fetch(`${HomeApi}/meta/anilist/trending?page=1`);
22 | const response = await api.json();
23 | setSlider(response.results);
24 | }
25 | useEffect(() => {
26 | if (!renderAfterCalled.current) {
27 | getSlider();
28 | }
29 | renderAfterCalled.current = true;
30 | }, []);
31 | return (
32 | <>
33 | {
50 | sliderinfo.map((data, uqley , swipe) => {
51 | return (
52 |
53 |
54 |
55 |
56 |
57 |
58 |
{data.title.english}
59 |
60 | Watch Now
61 |
62 |
63 |
64 |
65 |
66 | )
67 | })
68 | }
69 |
70 | >
71 | );
72 | }
--------------------------------------------------------------------------------
/src/Loading/DetailsLoader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Skeleton from 'react-loading-skeleton'
3 |
4 | const DetailsLoader = () => {
5 | return (
6 | <>
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
27 |
28 |
Recommended Anime
29 |
30 |
31 | {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(() => (
32 | <>
33 |
35 |
36 |
37 | >
38 | ))}
39 |
40 |
41 |
42 | >
43 | )
44 | }
45 | export default DetailsLoader
--------------------------------------------------------------------------------
/src/Loading/GenreLoading.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Skeleton from 'react-loading-skeleton'
3 | const GenreLoading = () => {
4 | return (
5 |
6 | {[1,2,3,4,5,6,7,8,9,10].map(()=>{
7 | return(
8 |
10 |
11 |
12 | )
13 | })}
14 |
15 | )
16 | }
17 |
18 | export default GenreLoading
--------------------------------------------------------------------------------
/src/Loading/HomePageLoader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | // Import Swiper React components
3 | import { Swiper, SwiperSlide } from "swiper/react";
4 | // Import Swiper styles
5 | import "swiper/css";
6 | import "swiper/css/pagination";
7 | import "swiper/css/navigation"
8 |
9 | import "../css/slider.css";
10 | import Skeleton from 'react-loading-skeleton';
11 | import { Footer } from '../Components';
12 |
13 | const HomePageLoader = () => {
14 | return (
15 | <>
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Recent Anime
28 |
29 |
30 |
31 | {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]?.map(() => {
32 | return (
33 |
35 |
36 |
37 | )
38 | })}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
Popular
48 |
49 |
50 |
51 | {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]?.map(() => {
52 | return (
53 |
55 |
56 |
57 | )
58 | })}
59 |
60 |
61 |
62 |
63 | >
64 |
65 | )
66 | }
67 |
68 | export default HomePageLoader
--------------------------------------------------------------------------------
/src/Loading/OtherPagesCard.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Skeleton from 'react-loading-skeleton';
3 | const OtherPagesCard = (props) => {
4 | const { title } = props
5 | return (
6 |
7 |
8 |
9 |
{title}
10 |
11 |
12 |
13 | {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]?.map(() => {
14 | return (
15 |
17 |
18 |
19 | )
20 | })}
21 |
22 |
23 | )
24 | }
25 |
26 | export default OtherPagesCard
--------------------------------------------------------------------------------
/src/Loading/ProfileLoader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Skeleton from 'react-loading-skeleton';
3 | import { Link } from 'react-router-dom';
4 | const ProfileLoader = () => {
5 | return (
6 | <>
7 |
8 |
9 |
Loading....
10 |
11 |
12 |
13 | Profile
14 | History
15 |
16 | Bookmark
17 |
18 |
19 |
20 |
21 |
37 | >
38 | )
39 | }
40 |
41 | export default ProfileLoader
--------------------------------------------------------------------------------
/src/Loading/StreamLoader.jsx:
--------------------------------------------------------------------------------
1 | import Skeleton from 'react-loading-skeleton'
2 | import React from 'react'
3 |
4 | const StreamLoader = () => {
5 | return (
6 | <>
7 |
8 |
9 |
10 |
11 |
12 | Note :- Refresh the page if player doesnt load or change to nspl player.
13 |
14 | To play the dubbed version, change the episode to the next available dub episode.
15 |
16 |
17 |
18 |
19 | {/* Video Player */}
20 |
21 |
22 |
23 |
24 | {/* Episode List */}
25 |
26 |
27 | {[1,2,3,4,5,6,7,8,9,10].map(()=>{
28 | return(
29 |
30 | )
31 | })}
32 |
33 |
34 |
35 |
36 | <>
37 |
38 |
39 |
Characters
40 |
41 |
42 | {
43 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(() => {
44 | return
45 |
46 |
47 | })
48 | }
49 |
50 |
51 | >
52 |
53 | >
54 | )
55 | }
56 |
57 | export default StreamLoader
--------------------------------------------------------------------------------
/src/Pages/AIChat.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { ChatBody, ChatInput } from "../Components";
3 | import { useMutation } from "react-query";
4 | import { fetchResponse } from "../Components/ChatBotapi.js";
5 | function AIChat() {
6 | const [chat, setChat] = useState([]);
7 |
8 | const mutation = useMutation({
9 | mutationFn: () => {
10 | return fetchResponse(chat);
11 | },
12 | onSuccess: (data) =>
13 | setChat((prev) => [
14 | ...prev,
15 | { sender: "ai", message: data.message.replace(/^\n\n/, "") },
16 | ]),
17 | });
18 |
19 | const sendMessage = async (message) => {
20 | await Promise.resolve(setChat((prev) => [...prev, message]));
21 | mutation.mutate();
22 | };
23 |
24 | return (
25 | <>
26 |
27 |
28 |
29 |
AnimeTrix Bot
30 |
Its a fun Ai bot which can recommend anime and chat with you
31 |
32 |
33 |
36 |
37 |
38 |
39 | {/* input */}
40 |
41 |
42 |
43 |
44 | >
45 | );
46 | }
47 |
48 | export default AIChat;
--------------------------------------------------------------------------------
/src/Pages/Details.jsx:
--------------------------------------------------------------------------------
1 |
2 | import React, { useEffect, useState } from "react";
3 | import { Link, useParams } from "react-router-dom";
4 | // import axios from "axios";
5 | import LoadingBar from 'react-top-loading-bar';
6 | import Footer from "../Components/Footer";
7 | import Card from "../Components/Card"
8 | import { ToastContainer, toast } from 'react-toastify';
9 | import 'react-toastify/dist/ReactToastify.css';
10 | import { HomeApi } from "../Components/constants";
11 | import DetailsLoader from "../Loading/DetailsLoader";
12 | // import DetailsLoader from "../Loading/DetailsLoader";
13 | import { Helmet } from 'react-helmet';
14 | import { showErrorToast } from "../utils/toast";
15 | export default function Details(props) {
16 |
17 | const { animeId } = useParams()
18 | const [detail, setDetail] = useState([]);
19 | const [watch, setWatch] = useState(" ");
20 | const [loading, setLoading] = useState(true)
21 | const handelClick = () => {
22 | props.handelClick();
23 | setLoading(true);
24 | };
25 | const getDetails = async () => {
26 | try {
27 | const api = await fetch(`${HomeApi}/meta/anilist/info/${animeId}`)
28 | const response = await api.json()
29 | const responseArray = [response];
30 | setDetail(responseArray);
31 | const firstEpisode = response.episodes.reduce(
32 | (smallestEpisode, currentEpisode) => {
33 | if (currentEpisode.number < smallestEpisode.number) {
34 | return currentEpisode;
35 | } else {
36 | return smallestEpisode;
37 | }
38 | }
39 | );
40 | if (firstEpisode) {
41 | setWatch(firstEpisode.id);
42 | } else {
43 | setWatch("");
44 | }
45 | setLoading(false);
46 | }
47 | catch (error) {
48 | showErrorToast('Error loading details!');
49 | }
50 | }
51 |
52 | const AnimeLoading = () => {
53 | setLoading(true)
54 | }
55 | useEffect(() => {
56 | window.scrollTo(0, 0);
57 | getDetails()
58 | AnimeLoading()
59 | }, [animeId]);
60 |
61 |
62 | if (loading) {
63 | return (
64 |
65 | )
66 | }
67 |
68 | return (
69 | <>
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | Watch Download Anime For Free On AnimeTrix
83 |
84 |
85 |
91 | {/* {loading ? (
92 |
93 | ) : (
94 | <> */}
95 |
96 | {detail.map((animeDetails) => (
97 |
98 |
99 |
100 |
101 |
106 |
107 |
108 |
109 | {animeDetails.title.english && animeDetails.title.english ? (
110 |
{animeDetails.title.english || animeDetails.title.romaji || animeDetails.title.romaji}
111 | ) : (
112 |
{animeDetails.title.romaji}
113 | )}
114 | {watch && (
115 |
116 |
Watch Now
117 |
118 | )}
119 |
120 |
Summary:-
121 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | {animeDetails.episodes.slice().sort((a, b) => a.number - b.number).map((episodeWatch) => {
131 | return (
132 |
133 | {episodeWatch.number}
134 |
135 | );
136 | })}
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | {animeDetails.trailer && (
147 | VIDEO
149 | )}
150 |
151 |
152 | {animeDetails && animeDetails?.recommendations == false ? (
153 | null
154 | ) : (
155 |
156 |
Recommended Anime
157 |
158 | )}
159 |
160 | {animeDetails?.recommendations?.map((rec) => (
161 | <>
162 |
163 | >
164 | ))}
165 |
166 |
167 | ))}
168 |
169 | {/* >
170 | )} */}
171 |
172 | >
173 | );
174 |
175 |
176 | }
--------------------------------------------------------------------------------
/src/Pages/DubAnime.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | // import { Helmet } from "react-helmet";
3 | import InfiniteScroll from "react-infinite-scroll-component";
4 | import Card from "../Components/Card";
5 | import spinner from "../img/spinner.svg";
6 |
7 | import { useFetchInitialData } from "../utils/hooks";
8 |
9 | const DubAnime = (props, ref) => {
10 | const clientRef = useRef(null);
11 |
12 | const handelClick = () => {
13 | props.handelClick();
14 | };
15 | const loadMore = () => {
16 | props.loadMoreDub();
17 | };
18 |
19 | const { loading, recent, loadMoreDub } = props;
20 |
21 | useFetchInitialData(loading, recent, loadMoreDub, clientRef, window)
22 |
23 | return (
24 | <>
25 | {Object.keys(props.recent).length === 0 ? (
26 |
34 | ) : (
35 | <>
36 |
37 |
38 |
39 |
Dubbed Anime
40 |
41 |
42 |
43 | {props.recent.map((rec) => (
44 |
45 | ))}
46 |
47 | }
52 | >
53 |
54 | >
55 | )}
56 | >
57 | );
58 | };
59 |
60 | export default DubAnime;
61 |
--------------------------------------------------------------------------------
/src/Pages/ForgotPassword.jsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import React, { useEffect, useState } from 'react'
3 | import { Link, useNavigate } from 'react-router-dom'
4 | import { ServerApi } from '../Components/constants';
5 | import { showErrorToast, showSuccessToast } from '../utils/toast';
6 | function ForgotPassword() {
7 | const [password, setPassword] = useState("");
8 | const [email, setEmail] = useState("");
9 | const [conPassword, setConPassword] = useState("");
10 | const [otp, setOtp] = useState("");
11 |
12 | const navigate = useNavigate()
13 |
14 | useEffect(()=>{
15 | const id = getCookie("id");
16 | if(id) {
17 | navigate("/");
18 | }
19 | });
20 |
21 | const changePassword = async() => {
22 | try {
23 | axios.interceptors.response.use(response => {
24 | return response;
25 | }, error => {
26 | showErrorToast(error.response.data.error)
27 | return ;
28 | });
29 | const res = await axios.post(`${ServerApi}/user/change/password`, {
30 | email: email,
31 | password: password
32 | })
33 | return res;
34 | } catch(err) {
35 | console.log(err);
36 | showErrorToast( 'Something went wrong!');
37 | }
38 | }
39 |
40 | function getCookie(name) {
41 | const cookies = document.cookie.split(';');
42 | for (let i = 0; i < cookies.length; i++) {
43 | const cookie = cookies[i].trim();
44 | if (cookie.startsWith(name + '=')) {
45 | return cookie.substring(name.length + 1);
46 | }
47 | }
48 | return undefined;
49 | }
50 |
51 | const userVerification = async() => {
52 | try {
53 | axios.interceptors.response.use(response => {
54 | return response;
55 | }, error => {
56 | showErrorToast(error.response.data.error);
57 | return ;
58 | });
59 | const res = await axios.post(`${ServerApi}/user/verify`, {
60 | email: email,
61 | verificationCode: otp
62 | })
63 | return res;
64 | } catch(err) {
65 | console.log(err);
66 | showErrorToast( 'Something went wrong!');
67 | }
68 | }
69 |
70 |
71 | const getOTP = async(e) => {
72 | e.preventDefault();
73 | if(conPassword === password) {
74 | if(password.length >= 8 && password.length <= 12) {
75 | const res = await changePassword(email, password);
76 | if(res) {
77 | alert(res.data.message);
78 | }
79 | } else {
80 | showErrorToast('Password should be 8 to 12 characters long!');
81 | setPassword("");
82 | setConPassword("");
83 | }
84 | } else {
85 | showErrorToast( 'Password doesnt match!');
86 | setPassword("");
87 | setConPassword("");
88 | }
89 | }
90 |
91 | const submitHandler = async(e) => {
92 | e.preventDefault();
93 | if(conPassword === password) {
94 | if(!(password.length < 8 && password.length >= 12)) {
95 | const res = await userVerification(email, otp);
96 | if(res) {
97 | showSuccessToast("Registration Successfull!");
98 | navigate("/login");
99 | }
100 | } else {
101 | showErrorToast('Password should be 8-12 characters long!');
102 | setPassword("");
103 | setConPassword("");
104 | }
105 | } else {
106 | showErrorToast('Password doesnt match!');
107 | setPassword("");
108 | setConPassword("");
109 | }
110 | }
111 | return (
112 |
113 |
114 |
Memorize with Care💡
115 |
159 |
160 | Remember Password? Login
161 |
162 | Register
163 |
164 |
165 |
166 | )
167 | }
168 |
169 | export default ForgotPassword
--------------------------------------------------------------------------------
/src/Pages/Login.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import React, { useEffect, useState } from "react";
3 | import { Link, useNavigate } from "react-router-dom";
4 | import Cookies from "js-cookie";
5 | import { ToastContainer } from 'react-toastify';
6 | import 'react-toastify/dist/ReactToastify.css';
7 | import { ServerApi } from "../Components/constants";
8 | import { showErrorToast, showSuccessToast } from '../utils/toast';
9 | function Login() {
10 | const [email, setEmail] = useState("");
11 | const [password, setPassword] = useState("");
12 | const [rememberMe, setRememberMe] = useState(false);
13 |
14 | const userLogin = async () => {
15 | try {
16 | axios.interceptors.response.use(response => {
17 | return response;
18 | }, error => {
19 | showErrorToast( error.response.data.error);
20 | return;
21 | });
22 | const res = await axios.post(`${ServerApi}/user/login`, {
23 | email: email,
24 | password: password
25 | })
26 | return res;
27 | } catch (err) {
28 | console.log(err);
29 | showErrorToast('Something went wrong!');
30 | }
31 | }
32 |
33 | function getCookie(name) {
34 | const cookies = document.cookie.split(';');
35 | for (let i = 0; i < cookies.length; i++) {
36 | const cookie = cookies[i].trim();
37 | if (cookie.startsWith(name + '=')) {
38 | return cookie.substring(name.length + 1);
39 | }
40 | }
41 | return undefined;
42 | }
43 |
44 | const navigate = useNavigate();
45 |
46 | useEffect(() => {
47 | const id = getCookie("id");
48 | if (id) {
49 | navigate("/");
50 | }
51 | });
52 |
53 | const submitHandler = async (e) => {
54 | e.preventDefault();
55 | const res = await userLogin();
56 | if (res) {
57 | showSuccessToast('Welcome to Animetrix');
58 | if (rememberMe) {
59 | Cookies.set("id", res.data._id, { expires: 7 });
60 | Cookies.set("category", res.data.category, { expires: 7 });
61 | Cookies.set("img", res.data.profile, { expires: 7 });
62 | window.location.reload();
63 | } else {
64 | Cookies.set("id", res.data._id, { expires: 1 });
65 | Cookies.set("category", res.data.category, { expires: 1 });
66 | Cookies.set("img", res.data.profile, { expires: 1 });
67 | window.location.reload();
68 | }
69 | }
70 | else {
71 | showErrorToast("Error");
72 | }
73 | }
74 | return (
75 | <>
76 |
77 |
78 |
79 |
Welcome back 👋
80 |
115 |
116 |
117 | >
118 | );
119 | }
120 |
121 | export default Login;
--------------------------------------------------------------------------------
/src/Pages/NewSeason.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useRef } from 'react'
3 | import spinner from "../img/spinner.svg";
4 | import { Card } from '../Components';
5 | import InfiniteScroll from "react-infinite-scroll-component";
6 | import OtherPagesCard from "../Loading/OtherPagesCard";
7 | import { useFetchInitialData } from "../utils/hooks";
8 | const NewSeason = (props) => {
9 | const ref = useRef(null);
10 | const handelClick = () => {
11 | props.handelClick();
12 | };
13 | const { loading, recent,loadmoreUpload } = props;
14 |
15 | const loadMore = () => {
16 | props.loadmoreUpload();
17 | };
18 |
19 | useFetchInitialData(loading, recent, loadmoreUpload, ref, window);
20 |
21 | return (
22 | <>
23 | {Object?.keys(recent).length === 0 ? (
24 |
25 | ) : (
26 | <>
27 |
28 |
29 |
30 |
Recent Anime
31 |
32 |
33 |
34 | {recent.map((rec) => (
35 |
36 | ))}
37 |
38 | }
43 | >
44 |
45 | >
46 | )}
47 | >
48 | );
49 | };
50 |
51 | export default NewSeason;
52 |
--------------------------------------------------------------------------------
/src/Pages/Popular.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | import InfiniteScroll from "react-infinite-scroll-component";
3 | import spinner from "../img/spinner.svg";
4 | import Card from "../Components/Card";
5 | import { Helmet } from 'react-helmet';
6 | import { useFetchInitialData } from "../utils/hooks";
7 | import OtherPagesCard from "../Loading/OtherPagesCard";
8 |
9 | const Popular = (props) => {
10 | const ref = useRef(null);
11 |
12 | const handelClick = () => {
13 | props.handelClick();
14 | };
15 | const loadMore = () => {
16 | props.loadMorePopular();
17 | };
18 |
19 | const { loading, popular, loadMorePopular } = props;
20 |
21 | useFetchInitialData(loading, popular, loadMorePopular, ref, window)
22 |
23 | return (
24 | <>
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | Watch Download Anime For Free On AnimeTrix
38 |
39 | {Object.keys(props.popular).length === 0 ? (
40 |
41 | ) : (
42 | <>
43 |
44 |
45 |
46 |
Popular Anime
47 |
48 |
49 |
50 |
51 | {props.popular.map((rec) => (
52 |
56 | ))}
57 |
58 | }
63 | >
64 |
65 | >
66 | )}
67 | >
68 | );
69 | };
70 |
71 | export default Popular;
72 |
--------------------------------------------------------------------------------
/src/Pages/Profile.jsx:
--------------------------------------------------------------------------------
1 | import { React, useState, useEffect } from 'react'
2 | import '../css/Profile.css'
3 | import { Link } from 'react-router-dom'
4 | import axios from 'axios'
5 | import { useNavigate } from 'react-router-dom'
6 | import { Footer } from '../Components'
7 | import { ToastContainer } from 'react-toastify';
8 | import 'react-toastify/dist/ReactToastify.css';
9 | import { ServerApi } from '../Components/constants'
10 | import { showErrorToast, showSuccessToast } from '../utils/toast'
11 | import ProfileLoader from '../Loading/ProfileLoader'
12 | const Profile = () => {
13 | const [userId, setUserId] = useState("");
14 | const [userName, setUserName] = useState("");
15 | const [details, setDetails] = useState({});
16 | const [img, setImg] = useState("https://i.pinimg.com/originals/b8/bf/ac/b8bfac2f45bdc9bfd3ac5d08be6e7de8.jpg");
17 | const [isUpdating, setIsUpdating] = useState(false);
18 | // const [changeAvatar, setChangeAvatar] = useState(false);
19 | // const [userImg, setUserImg] = useState("");
20 | // const [comp, setComp] = useState(1);
21 | const [loading, setLoading] = useState(true)
22 | const navigate = useNavigate();
23 |
24 | function getCookie(name) {
25 | const cookies = document.cookie.split(';');
26 | for (let i = 0; i < cookies.length; i++) {
27 | const cookie = cookies[i].trim();
28 | if (cookie.startsWith(name + '=')) {
29 | return cookie.substring(name.length + 1);
30 | }
31 | }
32 | return undefined;
33 | }
34 |
35 | useEffect(() => {
36 | const id = getCookie("id");
37 | if (id) {
38 | setUserId(id);
39 | } else {
40 | navigate("/");
41 | }
42 | },[navigate]);
43 |
44 |
45 | useEffect(() => {
46 | getDetails();
47 | }, [userId]);
48 |
49 | const getDetails = async () => {
50 |
51 | // profile images
52 | try {
53 | axios.interceptors.response.use(response => {
54 | return response;
55 | }, error => {
56 | showErrorToast( 'Something went wrong');
57 | return;
58 | });
59 | if (userId) {
60 | const res = await axios.get(`${ServerApi}/user/${userId}`);
61 | if (res.data) {
62 | setDetails(res.data.user);
63 | setUserName(res.data.user.name);
64 | setImg(res.data.user.profile);
65 | setLoading(false)
66 | }
67 | else
68 | setDetails({});
69 | }
70 | } catch (err) {
71 | showErrorToast('Error getting userId');
72 | }
73 | }
74 |
75 | const changeName = async () => {
76 | try {
77 | axios.interceptors.response.use(response => {
78 | return response;
79 | }, error => {
80 | showErrorToast(error.response.data.error);
81 | return;
82 | });
83 | const res = await axios.post(`${ServerApi}/user/change/name`, {
84 | name: userName,
85 | _id: userId
86 | })
87 | return res;
88 | } catch (err) {
89 | console.log(err);
90 | showErrorToast('Something went wrong');
91 | }
92 | }
93 |
94 | const sumbitHandler = async (e) => {
95 | e.preventDefault();
96 | if (isUpdating) {
97 | if (details.name !== userName) {
98 | const res = await changeName();
99 | showSuccessToast( res.data.message);
100 | } else {
101 | const errorMessage = 'Username already exists try another';
102 | showErrorToast(errorMessage);
103 | }
104 | }
105 | setIsUpdating(!isUpdating);
106 | }
107 |
108 | // const profileImages = [
109 | // {
110 | // id: 1,
111 | // imgUrl:
112 | // "https://i.ibb.co/56w2WWV/images-q-tbn-ANd9-Gc-Qo-Wng-A9o-rk-TEZWKg-T3zgh-QCmh-DR-Q2-KFm-Q3dt-Pw-W0-Co-Hio-B-m-VFQ44rdxd9-FQM4.jpg",
113 | // },
114 |
115 | // {
116 | // id: 2,
117 | // imgUrl:
118 | // "https://i.ibb.co/HG41T5g/images-q-tbn-ANd9-Gc-SIZBPpit-WVw-Vv-OWR3yn-Ki-Kg-HEYEm-Q2-Zm487w-usqp-CAU.jpg",
119 | // },
120 |
121 | // {
122 | // id: 3,
123 | // imgUrl:
124 | // "https://i.ibb.co/Lg0Wv8y/images-q-tbn-ANd9-Gc-Sspe4-Sy-j-XWf-Fw-QIp-Qpr-FPav-DGK5-SKArfhrw-usqp-CAU.jpg",
125 | // },
126 |
127 | // {
128 | // id: 4,
129 | // imgUrl: "https://i.ibb.co/sJPVdF8/2wPVNZ.jpg",
130 | // },
131 |
132 | // {
133 | // id: 5,
134 | // imgUrl: "https://i.ibb.co/QH8H6g5/wp10142858.jpg",
135 | // },
136 | // ];
137 |
138 | // const setImageHandler = (url) => {
139 | // setUserImg(url);
140 | // setChangeAvatar(!changeAvatar)
141 | // };
142 | return (
143 | <>
144 | {loading ? (
145 |
146 | ) : (
147 | <>
148 |
149 |
150 |
151 |
Hello, {details ? details.name : "User"}
152 |
153 |
154 |
155 | Profile
156 | History
157 |
158 | Bookmark
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 | {/*
168 | {profileImages.map((profileImg) => {
169 | return (
170 |
174 |
175 |
176 | );
177 | })}
178 |
*/}
179 |
180 |
193 |
194 |
195 |
196 | >
197 | )}
198 |
199 | >
200 | )
201 | }
202 |
203 | export default Profile
204 |
--------------------------------------------------------------------------------
/src/Pages/RecentAnime.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef, useEffect } from "react";
2 |
3 | import { Card, AiringSchedule, ForYou, Footer, UpcomingSeason } from "../Components"
4 | import { Link } from "react-router-dom";
5 | import { useFetchInitialData } from "../utils/hooks";
6 | import { HomeApi } from "../Components/constants";
7 | // Import Swiper React components
8 | import { Swiper, SwiperSlide } from "swiper/react";
9 | // Import Swiper styles
10 | import "swiper/css";
11 | import "swiper/css/pagination";
12 |
13 | import "../css/slider.css";
14 | import { Autoplay, Pagination, Mousewheel } from "swiper";
15 | import HomePageLoader from "../Loading/HomePageLoader";
16 | import { Helmet } from 'react-helmet';
17 | // import History from "../Components/History";
18 | const RecentAnime = (props) => {
19 | const renderAfterCalled = useRef(false);
20 | const [airingList, setairingList] = useState([])
21 | const getAiring = async () => {
22 | try {
23 | const api = await fetch(`${HomeApi}/meta/anilist/airing-schedule?notYetAired=true`)
24 | const response = await api.json()
25 | setairingList(response.results)
26 | }
27 | catch (error) {
28 | console.log("Error loading top airing list")
29 | }
30 | }
31 |
32 |
33 |
34 | useEffect(() => {
35 | window.scrollTo(0, 0);
36 | if (!renderAfterCalled.current) {
37 | getAiring()
38 | }
39 | renderAfterCalled.current = true;
40 | }, []);
41 | const ref = useRef(null);
42 |
43 | const handelClick = () => {
44 | props.handelClick();
45 | };
46 | function scroll() {
47 | window.scrollTo({ top: 0, left: 0, behavior: "smooth" })
48 | }
49 |
50 | const { loading, recent, loadMoreRecent, slider } = props;
51 |
52 | useFetchInitialData(loading, recent, loadMoreRecent, ref, window, slider)
53 |
54 | return (
55 | <>
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Watch Download Anime For Free On AnimeTrix
69 |
70 | {Object.keys(props.recent).length === 0 ? (
71 |
72 | ) : (
73 | <>
74 |
90 | {props.slider &&
91 | props.slider.map((rec) => (
92 |
93 |
94 |
95 |
96 |
97 |
{rec.title.english}
98 |
99 | Watch Now
100 |
101 |
102 |
103 |
104 | ))}
105 |
106 | {/* */}
107 |
108 |
109 |
110 |
Recent Anime
111 |
112 |
113 |
114 | {props.recent &&
115 | props.recent.map((rec) => (
116 |
117 | ))}
118 |
119 |
120 |
121 | View More
122 |
123 |
124 |
125 |
126 |
127 |
128 |
Popular
129 |
130 |
131 |
132 | {props.popular.map((rec) => (
133 |
137 | ))}
138 |
139 |
140 |
141 | View More
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | >
152 | )}
153 | >
154 | );
155 | };
156 | export default RecentAnime;
157 |
--------------------------------------------------------------------------------
/src/Pages/Register.jsx:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import React, { useEffect, useState } from 'react'
3 | import { Link, useNavigate } from 'react-router-dom'
4 | import { ToastContainer } from 'react-toastify';
5 | import 'react-toastify/dist/ReactToastify.css';
6 | import { ServerApi } from '../Components/constants';
7 | import { showErrorToast, showSuccessToast } from '../utils/toast';
8 | function Register() {
9 | const [name, setName] = useState("");
10 | const [password, setPassword] = useState("");
11 | const [email, setEmail] = useState("");
12 | const [conPassword, setConPassword] = useState("");
13 | const [otp, setOtp] = useState("");
14 |
15 | const navigate = useNavigate();
16 |
17 | function getCookie(name) {
18 | const cookies = document.cookie.split(';');
19 | for (let i = 0; i < cookies.length; i++) {
20 | const cookie = cookies[i].trim();
21 | if (cookie.startsWith(name + '=')) {
22 | return cookie.substring(name.length + 1);
23 | }
24 | }
25 | return undefined;
26 | }
27 |
28 | useEffect(() => {
29 | const id = getCookie("id");
30 | if (id) {
31 | navigate("/");
32 | }
33 | });
34 |
35 | const userSignup = async () => {
36 | try {
37 | axios.interceptors.response.use(response => {
38 | return response;
39 | }, error => {
40 | showErrorToast(error.response.data.error);
41 | return;
42 | });
43 | const res = await axios.post(`${ServerApi}/user/register`, {
44 | name: name,
45 | email: email,
46 | password: password
47 | })
48 | return res;
49 | } catch (err) {
50 | console.log(err);
51 | showErrorToast('Something went wrong!');
52 | }
53 | }
54 |
55 | const userVerification = async () => {
56 | try {
57 | axios.interceptors.response.use(response => {
58 | return response;
59 | }, error => {
60 | showErrorToast(error.response.data.error);
61 | return;
62 | });
63 | const res = await axios.post(`${ServerApi}/user/verify`, {
64 | email: email,
65 | verificationCode: otp
66 | })
67 | return res;
68 | } catch (err) {
69 | console.log(err);
70 | showErrorToast('Unable to send otp');
71 | }
72 | }
73 |
74 |
75 | const getOTP = async (e) => {
76 | e.preventDefault();
77 | if (conPassword === password) {
78 | if (password.length >= 8 && password.length <= 12) {
79 | const res = await userSignup(name, email, password);
80 | if (res) {
81 | showSuccessToast(res.data.message);
82 | }
83 | } else {
84 | showErrorToast( 'Password should be 8-12 characters long!');
85 | setPassword("");
86 | setConPassword("");
87 | }
88 | } else {
89 | showErrorToast('Password dont match');
90 | setPassword("");
91 | setConPassword("");
92 | }
93 | }
94 |
95 | const submitHandler = async (e) => {
96 | e.preventDefault();
97 | if (conPassword === password) {
98 | if (!(password.length < 8 && password.length >= 12)) {
99 | const res = await userVerification(email, otp);
100 | if (res) {
101 | showSuccessToast('Registration successfull');
102 | navigate("/login");
103 | }
104 | } else {
105 | showErrorToast('Password should be 8-12 character long');
106 | setPassword("");
107 | setConPassword("");
108 | }
109 | } else {
110 | showErrorToast('Password dont match');
111 | setPassword("");
112 | setConPassword("");
113 | }
114 | }
115 | return (
116 |
117 |
118 |
119 |
Join Us 🤝
120 |
175 |
176 |
177 | Already have an account ?
178 | Login
179 |
180 |
181 |
182 | )
183 | }
184 |
185 | export default Register
--------------------------------------------------------------------------------
/src/Pages/Terms.jsx:
--------------------------------------------------------------------------------
1 | import React, {useEffect } from 'react'
2 | import { Footer } from '../Components'
3 | import { Link } from "react-router-dom"
4 | const Terms = () => {
5 | useEffect(() => {
6 | window.scrollTo(0, 0);
7 | }, []);
8 | return (
9 | <>
10 |
11 |
⚠️Terms and Conditions for Animetrix :
12 |
13 | Content Disclaimer:
14 | Animetrix does not store any data on its servers. The website simply provides links to data and content available on the internet. Animetrix does not guarantee the accuracy, completeness, or legality of any content provided through the links. Users are responsible for their own use of the linked content and should abide by the respective terms and conditions of the sources.
15 |
16 | User Information:
17 | To access certain features or services on Animetrix, users may be required to provide their email address. By providing your email address, you consent to receive communications from Animetrix related to your account and website updates. Animetrix will handle user information in accordance with its Privacy Policy.
18 |
19 |
20 | Account Termination:
21 | Animetrix reserves the right to delete or terminate user accounts without any prior notice or explanation. This action may be taken if a user violates these terms and conditions or engages in any activity that is deemed harmful, illegal, or against the code of conduct.
22 |
23 |
24 | User Code of Conduct:
25 | Users of Animetrix are expected to comply with the code of conduct and guidelines set forth by the website. Any user found guilty of breaking the code of conduct or engaging in activities that promote unhealthy behavior, harassment, discrimination, or violation of any laws will be subject to being blacklisted and denied access to the website.
26 |
27 |
28 | Intellectual Property:
29 | The content, design, logo, and other materials on Animetrix are protected by intellectual property laws and are the property of their respective owners. Users agree not to reproduce, modify, distribute, or exploit any content from the website without prior written permission from the rightful own
30 |
31 |
32 | Limitation of Liability:
33 | Animetrix and its owners, employees, or affiliates shall not be held liable for any direct, indirect, incidental, consequential, or punitive damages arising out of the use or inability to use the website, including but not limited to loss of data, loss of profits, or any other losses.
34 |
35 |
36 | Modification of Terms and Conditions:
37 | Animetrix reserves the right to modify or update these terms and conditions at any time without prior notice. Users are advised to review the terms periodically for any changes. Continued use of the website after modifications implies acceptance of the updated terms and conditions.
38 |
39 |
40 |
41 |
42 | By using Animetrix, you acknowledge that you have read, understood, and agreed to these terms and conditions. If you do not agree to any of these terms, please refrain from using the website.
43 | Home
44 |
45 |
46 |
47 |
48 | >
49 | )
50 | }
51 |
52 | export default Terms
--------------------------------------------------------------------------------
/src/Pages/genre.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import InfiniteScroll from 'react-infinite-scroll-component';
3 | import spinner from "../img/spinner.svg";
4 | import { Card } from '../Components';
5 | import { ToastContainer} from 'react-toastify';
6 | import 'react-toastify/dist/ReactToastify.css';
7 | import { HomeApi } from '../Components/constants';
8 | import GenreLoading from '../Loading/GenreLoading';
9 | import { showErrorToast } from '../utils/toast';
10 | function Genre() {
11 |
12 | const [selectedOption, setSelectedOption] = useState('Action');
13 |
14 | const [data, setData] = useState([]);
15 |
16 | const [page, setPage] = useState(1);
17 |
18 | const [isLoading, setIsLoading] = useState(false);
19 | //bookmark
20 |
21 |
22 | useEffect(() => {
23 | fetchData();
24 | }, []);
25 |
26 | useEffect(() => {
27 | fetchData();
28 | }, [selectedOption]);
29 |
30 |
31 | async function fetchData() {
32 | try {
33 | setIsLoading(true);
34 | const response = await fetch(
35 | `${HomeApi}/meta/anilist/advanced-search?genres=["${selectedOption}"]&&page=${page}`
36 | );
37 | const responseData = await response.json();
38 | console.log(responseData)
39 | setData([...data, ...responseData.results]);
40 | setIsLoading(false);
41 | } catch (error) {
42 | console.error(error);
43 | showErrorToast('Error loading genre');
44 |
45 | }
46 | }
47 |
48 |
49 | function handleChange(event) {
50 |
51 | setSelectedOption(event.target.value);
52 | setPage(1);
53 | setData([]);
54 | }
55 |
56 |
57 | async function fetchMoreData() {
58 | try {
59 | setPage(page => page + 1);
60 | const response = await fetch(
61 | `${HomeApi}/meta/anilist/advanced-search?genres=["${selectedOption}"]&&page=${page + 1}`
62 | );
63 | const responseData = await response.json();
64 | setData([...data, ...responseData.results]);
65 | } catch (error) {
66 | console.error(error);
67 | }
68 | }
69 |
70 |
71 | useEffect(() => {
72 | setPage(1);
73 | }, [selectedOption]);
74 |
75 |
76 | return (
77 | <>
78 |
79 | {data && (
80 |
81 |
82 |
83 |
84 | {["Action", "Adventure", "Comedy", "Drama", "Fantasy", "Horror", "Mecha", "Mystery", "Romance", "Sci-Fi", "Sports", "Supernatural", "Thriller"].map((genreItem) => {
85 | return (
86 | {genreItem}
87 | )
88 | })}
89 |
90 |
91 |
92 |
Sort By Genre
93 |
94 |
95 | {isLoading ? (
96 |
97 | ) : (
98 | }
103 | >
104 |
105 | {data.map(rec => (
106 |
107 | ))}
108 |
109 |
110 | )}
111 |
112 | )}
113 | >
114 | );
115 | }
116 |
117 |
118 | export default Genre;
119 |
--------------------------------------------------------------------------------
/src/Pages/index.js:
--------------------------------------------------------------------------------
1 | import Details from "./Details";
2 | import DubAnime from "./DubAnime"
3 | import Genre from "./genre";
4 | import Movie from "./movie"
5 | import Popular from "./Popular"
6 | import RecentAnime from "./RecentAnime"
7 | import Stream from "./Stream"
8 | import TopAnimeAiring from "./topAiring"
9 | import NewSeason from "./NewSeason";
10 | import Login from "./Login"
11 | import Register from "./Register";
12 | import AIChat from "./AIChat";
13 | import Profile from "./Profile";
14 | import ForgotPassword from "./ForgotPassword";
15 | import AnimeImageSearch from "./AnimeImageSearch";
16 | import Terms from "./Terms";
17 | export{
18 | Details,
19 | DubAnime,
20 | Genre,
21 | Movie,
22 | Popular,
23 | RecentAnime,
24 | Stream,
25 | TopAnimeAiring,
26 | NewSeason,
27 | Login,
28 | Register,
29 | AIChat,
30 | Profile,
31 | ForgotPassword,
32 | AnimeImageSearch,
33 | Terms
34 | }
--------------------------------------------------------------------------------
/src/Pages/movie.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | import InfiniteScroll from "react-infinite-scroll-component";
3 | import spinner from "../img/spinner.svg";
4 | import Card from "../Components/Card";
5 | import { Helmet } from 'react-helmet';
6 | import { useFetchInitialData } from "../utils/hooks";
7 | import OtherPagesCard from "../Loading/OtherPagesCard";
8 | const Movie = (props) => {
9 | const ref = useRef(null);
10 |
11 | const handelClick = () => {
12 | props.handelClick();
13 | };
14 | const loadMore = () => {
15 | props.loadMoreMovies();
16 | };
17 |
18 | const { loading, movie, loadMoreMovies } = props;
19 |
20 | useFetchInitialData(loading, movie, loadMoreMovies, ref, window)
21 | return (
22 | <>
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | Watch Download Anime For Free On AnimeTrix
36 |
37 | {Object.keys(props.recent).length === 0 ? (
38 |
39 | ) : (
40 | <>
41 |
42 |
43 |
44 |
Movies
45 |
46 |
47 |
48 | {props.recent.map((rec) => (
49 |
50 | ))}
51 |
52 | }
57 | endMessage={
58 |
59 | Yay! You have seen it all
60 |
61 | }
62 | >
63 |
64 | >
65 | )}
66 | >
67 | );
68 | };
69 |
70 | export default Movie;
71 |
--------------------------------------------------------------------------------
/src/Pages/topAiring.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | import InfiniteScroll from "react-infinite-scroll-component";
3 | import spinner from "../img/spinner.svg";
4 | import Card from "../Components/Card";
5 | import OtherPagesCard from "../Loading/OtherPagesCard";
6 | import { useFetchInitialData } from "../utils/hooks";
7 | import { Helmet } from 'react-helmet';
8 | const TopAnimeAiring = (props) => {
9 | const ref = useRef(null);
10 |
11 | const handelClick = () => {
12 | props.handelClick();
13 | };
14 | const loadMore = () => {
15 | props.loadMoreTopAnime();
16 | };
17 |
18 | const { loading, topanime, loadMoreTopAnime } = props;
19 |
20 | useFetchInitialData(loading, topanime, loadMoreTopAnime, ref, window)
21 |
22 | return (
23 | <>
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | Watch Download Anime For Free On AnimeTrix
37 |
38 | {Object.keys(props.recent).length === 0 ? (
39 |
40 | ) : (
41 | <>
42 |
43 |
44 |
45 |
Trending
46 |
47 |
48 |
49 |
50 | {props.recent.map((rec) => (
51 |
55 | ))}
56 |
57 | }
62 | >
63 |
64 | >
65 | )}
66 | >
67 | );
68 | };
69 |
70 | export default TopAnimeAiring;
71 |
--------------------------------------------------------------------------------
/src/css/AiringSchedule.css:
--------------------------------------------------------------------------------
1 | .airing-schedule {
2 | margin: 50px 0;
3 | max-width: 95%;
4 | margin: auto;
5 | padding-bottom: 40px;
6 | }
7 |
8 | .airing-schedule-heading {
9 | padding: 20px 10px;
10 | margin: 20px 0;
11 | font-size: 50px;
12 | }
13 |
14 | .airing-schedule-heading h5 {
15 | margin-top: 2%;
16 | font-size: 40%;
17 | text-align: center;
18 | background: var(--airing-shedule-background);
19 | padding: 14px;
20 | max-width: 480px;
21 | border-radius: 8px;
22 | margin: auto;
23 | }
24 |
25 | .anime-airing {
26 | background-color: var(--airing-shedule-background);
27 | padding: 20px;
28 | border-radius: 10px;
29 | max-height: 400px;
30 | overflow-y: scroll;
31 | }
32 |
33 | .anime-schedule {
34 | padding: 10px;
35 | display: flex;
36 | justify-content: space-between;
37 | align-items: center;
38 | color: white;
39 | border-bottom: 1px solid rgb(61, 58, 58);
40 | }
41 |
42 | .anime-schedule .first-info {
43 | display: flex;
44 | justify-content: space-between;
45 | align-items: center;
46 | gap: 15px;
47 | }
48 |
49 | .anime-schedule .schedule-info {
50 | padding: 5px;
51 | border-radius: 5px;
52 | padding: 10px;
53 | width: 150px;
54 | text-align: center;
55 | background-color: var(--airing-shedule-btn);
56 | }
57 |
58 | @media screen and (max-width: 1500px) {
59 | .airing-schedule {
60 | width: 90%;
61 | }
62 |
63 | .airing-schedule-heading h3 {
64 | font-size: 40px;
65 | }
66 | }
67 |
68 | @media screen and (max-width: 900px) {
69 | .airing-schedule {
70 | width: 90%;
71 | }
72 |
73 | .airing-schedule-heading h3 {
74 | font-size: 35px;
75 | }
76 | }
77 |
78 | @media screen and (max-width: 800px) {
79 | .airing-schedule {
80 | width: 90%;
81 | }
82 |
83 | .anime-airing {
84 | padding: 0;
85 | }
86 |
87 | .anime-schedule {
88 | font-size: 12px;
89 | }
90 |
91 | .anime-schedule .first-info {
92 | flex-direction: column;
93 | align-items: flex-start;
94 | gap: 10px;
95 | width: 60%;
96 | }
97 | }
98 |
99 | @media screen and (max-width: 700px) {
100 | .airing-schedule-heading h3 {
101 | font-size: 35px;
102 | }
103 | }
104 |
105 | @media screen and (max-width: 600px) {
106 | .airing-schedule-heading h3 {
107 | font-size: 30px;
108 | }
109 |
110 | .airing-schedule-heading h5 {
111 | margin-top: 3%;
112 | font-size: 35%;
113 | }
114 | }
115 |
116 | @media screen and (max-width: 350px) {
117 | .airing-schedule-heading h3 {
118 | font-size: 20px;
119 | }
120 |
121 | .anime-schedule .schedule-info {
122 | padding: 5px;
123 | border-radius: 5px;
124 | padding: 10px;
125 | width: 100px;
126 | text-align: center;
127 | }
128 | }
--------------------------------------------------------------------------------
/src/css/Chatbot.css:
--------------------------------------------------------------------------------
1 | .chat-container {
2 | height: 85vh;
3 | width: 100%;
4 | position: relative;
5 | color: var(--text-color);
6 | overflow: hidden;
7 | display: flex;
8 | flex-direction: column;
9 | align-items: center;
10 | justify-content: space-between;
11 | }
12 |
13 | .chat-container-heading {
14 | text-transform: uppercase;
15 | font-weight: 600;
16 | font-size: 19px;
17 | text-align: center;
18 | margin-bottom: 30px;
19 | margin-top: 10px;
20 | }
21 | .chat-container-heading p {
22 | font-size: 11px;
23 | padding: 10px;
24 | font-weight: 500;
25 | opacity: .9;
26 | }
27 |
28 | .chat-body {
29 | height: 90%;
30 | overflow: auto;
31 | width: 100%;
32 | max-width: 56rem;
33 | min-width: 20rem;
34 | padding-top: 2rem;
35 | padding-bottom: 2rem;
36 | padding-left: 1rem;
37 | padding-right: 1rem;
38 | align-items: center;
39 | }
40 |
41 | .chat-input {
42 | width: 80%;
43 | /* min-width: 20rem; */
44 | align-items: center;
45 | }
46 | .chat-main-details{
47 | display: flex;
48 | flex-direction: column;
49 | gap: 4;
50 | }
51 |
52 | .ai-style {
53 | margin-right: auto;
54 | }
55 |
56 | .chat-aiandhuman {
57 | background: var(--chatbot-chat);
58 | border-radius: 8px;
59 | max-width: 80%;
60 | place-self: end;
61 | padding-left: 0.75rem;
62 | padding-right: 0.75rem;
63 | padding-top: 0.75rem;
64 | padding-bottom: 0.75rem;
65 | overflow-wrap: break-word;
66 | margin-bottom: 10px;
67 | }
68 |
69 | .chat-message {
70 | white-space: pre-wrap;
71 | font-size: 20px;
72 | font-weight: 500;
73 | }
74 |
75 | .height {
76 | height: 20px;
77 | }
78 |
79 | .input-main {
80 | width: 100%;
81 | background: var(--chatbot-chat);
82 | max-height: 10rem;
83 | border-radius: 8px;
84 | padding-left: 1rem;
85 | padding-right: 1rem;
86 | padding-top: 1rem;
87 | padding-bottom: 1rem;
88 | overflow: auto;
89 | position: relative;
90 | }
91 | .input-main textarea{
92 | resize: none;
93 | outline: none;
94 | border: none;
95 | background: transparent;
96 | width: 90%;
97 | color: var(--text-color);
98 | font-size: 18px;
99 | font-weight: 500;
100 | }
101 | .loader-input{
102 | margin: auto;
103 | width: 2rem;
104 | }
105 | .input-submit{
106 | position: absolute;
107 | top: 1rem;
108 | right: 0.75rem;
109 | cursor: pointer;
110 | transition: .2s ease-in;
111 | font-size: 30px;
112 | font-weight: 300;
113 | }
114 | .input-submit:hover{
115 | transform: scale(1.3);
116 | }
117 |
118 | .text-copy{
119 | border: none;
120 | background: transparent;
121 | position: relative;
122 | float: right;
123 | }
124 | .text-copy.copied{
125 | display: none;
126 | }
127 | @media(max-width:400px){
128 | .chat-container{
129 | height: 80vh;
130 | }
131 | .chat-container-heading {
132 | font-size: 14px;
133 | }
134 | .chat-input{
135 | width: 92%;
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/css/Details.css:
--------------------------------------------------------------------------------
1 | .details {
2 | width: 100%;
3 | display: flex;
4 | padding: 2rem 4rem;
5 | flex-direction: column;
6 | }
7 |
8 | .list-box.details {
9 | display: none;
10 | }
11 |
12 | .anime-trailer{
13 | display: flex;
14 | justify-content: left;
15 | align-items: left;
16 | padding: 30px;
17 | }
18 | .anime-trailer iframe{
19 | max-width: 700px;
20 | max-height: 500px;
21 | width: 500px;
22 | height: 300px;
23 | }
24 |
25 | .anime-details {
26 | width: 100%;
27 | display: flex;
28 | justify-content: space-between;
29 | }
30 | .anime-img .anime-image{
31 | width: 310px;
32 | height: 420px;
33 | margin: auto;
34 | border-radius: 14px;
35 | }
36 |
37 |
38 | .anime-info {
39 | height: 100%;
40 | width: 100%;
41 | padding: 0 30px;
42 | }
43 |
44 |
45 | .anime-title,
46 | .watch-anime,
47 | .anime-storyline {
48 | margin-left: 30px;
49 | }
50 |
51 | .anime-title {
52 | font-size: 40px;
53 | font-weight: 500;
54 | margin-bottom: 40px;
55 | letter-spacing: .1px;
56 | }
57 |
58 | .watch-anime-btn {
59 | background-color: var(--button-color);
60 | border: none;
61 | padding: 19px 50px 19px;
62 | font-size: 18px;
63 | font-weight: 500;
64 | border-radius: 10px;
65 | margin-bottom: 40px;
66 | margin-left: 30px;
67 | color: var(--text-color);
68 | text-align: center;
69 | }
70 |
71 | .anime-storyline {
72 | background-color: var(--episode-summary);
73 | padding: 15px;
74 | border-radius: 8px;
75 | max-height: 200px;
76 | overflow-y: scroll;
77 | padding-bottom: 40px;
78 | margin-left: 30px;
79 | }
80 |
81 | .anime-storyline>.summary {
82 | font-size: 25px;
83 | margin: 15px 0;
84 | word-spacing: 5px;
85 | font-weight: 600;
86 | }
87 |
88 | .anime-storyline>p {
89 | font-size: 18px;
90 | font-weight: 500;
91 | max-width: 900px;
92 | }
93 | .episode-detail-container{
94 | display: flex;
95 | justify-content: center;
96 | align-items: center;
97 | }
98 | .anime-episodes {
99 | background-color: var(--stream-background-color);
100 | padding: 20px 30px;
101 | border-radius: 10px;
102 | flex-direction: row;
103 | margin-top: 5%;
104 | flex-wrap: wrap;
105 | max-height: 400px;
106 | max-width: 900px;
107 | overflow: auto;
108 | }
109 | .anime-episodes::-webkit-scrollbar{
110 | display: none;
111 | }
112 | .anime-episodes .episodes-list{
113 | display: flex;
114 | gap: 10px;
115 | flex-wrap: wrap;
116 | overflow-x: hidden;
117 |
118 | }
119 | .anime-episodes .episodes-list button {
120 | width: 55px;
121 | padding: 10px;
122 | margin: 10px 0px;
123 | font-size: 15px;
124 | font-weight: 600;
125 | background-color: var(--episode-button-color);
126 | border-radius: 6px;
127 | box-sizing: border-box;
128 | display: flex;
129 | justify-content: center;
130 | }
131 |
132 |
133 |
134 |
135 | @media only screen and (max-width: 1500px) {
136 | .details {
137 | padding: 2rem 4rem;
138 | }
139 |
140 |
141 | .episode-list.details {
142 | margin-left: 0px;
143 | }
144 |
145 | .episode-list.details::-webkit-scrollbar-thumb {
146 | display: none;
147 | }
148 |
149 | .anime-details {
150 | width: 100%;
151 | }
152 | }
153 |
154 | @media(max-width:1300px) {
155 | .details {
156 | padding: 1rem 0px;
157 | }
158 | .recommended-anime h1{
159 | padding: 0px 4%;
160 | }
161 | }
162 |
163 | @media (max-width: 920px) {
164 | .watch-anime {
165 | display: flex;
166 | justify-content: center;
167 | align-items: center;
168 | }
169 |
170 | .watch-anime-btn {
171 | margin-left: 0px;
172 | }
173 |
174 | .anime-details {
175 | width: 100%;
176 | flex-direction: column;
177 | }
178 |
179 | .anime-img .anime-image {
180 | width: 300px;
181 | }
182 |
183 | .anime-info {
184 | display: flex;
185 | flex-direction: column;
186 | align-items: center;
187 | }
188 |
189 |
190 |
191 | .anime-title,
192 | .watch-anime,
193 | .anime-storyline {
194 | margin: 15px 0;
195 | }
196 |
197 | .anime-title {
198 | font-size: 25px;
199 | text-align: center;
200 | /* background-color: red; */
201 | max-width: 600px;
202 | }
203 |
204 | .anime-trailer{
205 | display: flex;
206 | justify-content: center;
207 | align-items: center;
208 | }
209 |
210 | }
211 |
212 |
213 |
214 | @media(max-width:600px) {
215 | .recommended-anime h1 {
216 | font-size: 30px;
217 | }
218 |
219 | .anime-trailer iframe{
220 | max-width: 700px;
221 | max-height: 500px;
222 | width: 300px;
223 | height: 200px;
224 | }
225 | }
226 |
227 | @media only screen and (max-width: 520px) {
228 | .anime-img .anime-image {
229 | width: 200px;
230 | height: 300px;
231 | }
232 |
233 | .anime-title {
234 | font-size: 20px;
235 | }
236 |
237 | .watch-anime-btn {
238 | padding: 15px 20px;
239 | }
240 | }
241 |
242 | @media(max-width:450px) {
243 | .recommended-anime h1 {
244 | font-size: 25px;
245 | }
246 | }
247 |
248 | @media(max-width:370px) {
249 | .anime-info {
250 | padding: 0 0px;
251 | }
252 |
253 | .recommended-anime h1 {
254 | font-size: 20px;
255 | }
256 |
257 | .watch-anime-btn {
258 | padding: 10px;
259 | }
260 | }
--------------------------------------------------------------------------------
/src/css/Footer.css:
--------------------------------------------------------------------------------
1 |
2 | .footer {
3 | display: flex;
4 | flex-direction: column;
5 | justify-content: center;
6 | align-items: center;
7 | gap: 10px;
8 | padding: 15px 0;
9 | background-color: var(--footer-bg );
10 | }
11 | .footer h1 {
12 | color: var(--footer-heading);
13 | display: flex;
14 | gap: 10px;
15 | }
16 | .footer h1 .white {
17 | color: white;
18 | }
19 | .footer .footer-about {
20 | font-size: 12px;
21 | width: 70%;
22 | text-align: center;
23 | }
24 | .footer-social {
25 | display: flex;
26 | align-items: center;
27 | gap: 15px;
28 | margin: 10px 0;
29 | }
30 | .footer-social button {
31 | display: flex;
32 | justify-content: center;
33 | align-items: center;
34 | padding: 10px;
35 | border-radius: 50%;
36 | background-color: var(--footer-social-btn);
37 | transition: .1s all ease-in;
38 | }
39 | .footer-social button:hover{
40 | transform: scale(1.2);
41 | }
42 | .terms{
43 | border-bottom: 2px solid var(--button-color);
44 | color: var(--text-color);
45 | }
46 | @media (max-width: 600px) {
47 | .footer .footer-about {
48 | width: 90%;
49 | }
50 | .footer .footer-about{
51 | font-size: 8px;
52 | }
53 | }
--------------------------------------------------------------------------------
/src/css/ForYou.css:
--------------------------------------------------------------------------------
1 | .movies.for{
2 | padding-bottom: 40px;
3 | }
--------------------------------------------------------------------------------
/src/css/Header.css:
--------------------------------------------------------------------------------
1 | .header {
2 | display: flex;
3 | justify-content: space-between;
4 | align-items: center;
5 | padding: 10px 60px;
6 | position: sticky;
7 | top: 0px;
8 | z-index: 999;
9 | background-color: rgb(0, 0, 0, 0.3);
10 | backdrop-filter: blur(50px);
11 | box-shadow: 0 20px 20px rgba(0, 0, 0, 0.15);
12 | }
13 |
14 | .login-tab ion-icon{
15 | font-size: 40px;
16 | color: var(--button-color);
17 | position: relative;
18 | right: 40px;
19 | }
20 | .mobile-search{
21 | display: none;
22 | }
23 | .logo > a {
24 | font-size: 40px;
25 | font-weight: 600;
26 | }
27 |
28 | .logo .white {
29 | color: var(--text-color) !important;
30 | }
31 |
32 | .logo .blue {
33 | color: var(--button-color);
34 | }
35 |
36 | .toggle {
37 | display: none;
38 | }
39 |
40 | .nav-links {
41 | display: flex;
42 | align-items: center;
43 | position: relative;
44 | }
45 |
46 | .nav-links > li {
47 | list-style: none;
48 | }
49 |
50 | .nav-links > li > a {
51 | text-decoration: none;
52 | margin: 0 20px;
53 | word-spacing: 3px;
54 | font-size: 17px;
55 | font-weight: 500;
56 | }
57 |
58 | .active {
59 | color: var(--button-color);
60 | }
61 |
62 | .login-btn{
63 | font-size: 40px;
64 | padding: 0px;
65 | color: var(--button-color);
66 | cursor: pointer;
67 | }
68 | .search > input {
69 | padding: 12px 20px;
70 | border-radius: 10px;
71 | background-color: var(--search-background);
72 | color: var(--text-color);
73 | width: 350px;
74 | }
75 | .search-submit{
76 | background: transparent;
77 | padding: 2px;
78 | color: var(--button-color);
79 | position: relative;
80 | left: calc(20% - 120px);
81 | font-size: 20px;
82 | transform: translateY(calc(90% - 12px));
83 | bottom: 20px;
84 | }
85 | .search-submit-mobile{
86 | display: none;
87 | }
88 | .search-submit-mobile.active{
89 | display: block;
90 | position: absolute;
91 | bottom: calc(90% - 139px);
92 | right: 16%;
93 | font-size: 25px;
94 | background: transparent;
95 | z-index: 999;
96 | }
97 | .search-btn {
98 | background: none;
99 | border: none;
100 | display: flex;
101 | align-items: center;
102 | position: relative;
103 | top: -1px;
104 | right: 35px;
105 | }
106 |
107 | .toggle-search {
108 | display: none;
109 | }
110 |
111 | .account-login{
112 | cursor: pointer;
113 | }
114 | .account-login img{
115 | width: 40px;
116 | height: 40px;
117 | border-radius: 50%;
118 | z-index: 9999;
119 | }
120 | .account-login .extra-options{
121 | display: inline;
122 | position: absolute;
123 | background:var(--account-login-background);
124 | padding: 30px;
125 | border-radius: 18px;
126 | right: 5%;
127 | margin-top: 10px;
128 | display: none;
129 | z-index: 99999;
130 | }
131 | .account-login .extra-options li{
132 | color: var(--text-color);
133 | font-size: 16px;
134 | margin-bottom: 10px;
135 | }
136 | .account-login .active{
137 | display: block;
138 | }
139 | @media only screen and (max-width: 1500px) {
140 | .header {
141 | padding: 25px 35px;
142 | }
143 | }
144 |
145 | @media only screen and (max-width: 1360px) {
146 | .search {
147 | position: relative;
148 | left: 25%;
149 | }
150 | .navbar-menu-btn {
151 | background: transparent;
152 | transition: 0.9s ease-in-out;
153 | position: relative;
154 | }
155 |
156 | .navbar-menu-btn span {
157 | display: block;
158 | background: var(--button-color);
159 | width: 35px;
160 | height: 3px;
161 | margin: 8px;
162 | transition: 0.5s ease-in-out;
163 | }
164 |
165 | .navbar-menu-btn .two {
166 | width: 30px;
167 | }
168 |
169 | .navbar-menu-btn .three {
170 | width: 25px;
171 | }
172 | .logo > a {
173 | font-size: 30px;
174 | padding-left: 10px;
175 | }
176 |
177 | .search {
178 | margin-right: 65px;
179 | z-index: -1;
180 | }
181 |
182 | .nav-links {
183 | display: none;
184 | }
185 |
186 | .toggle {
187 | display: block;
188 | position: absolute;
189 | top: 25px;
190 | right: 20px;
191 | cursor: pointer;
192 | }
193 |
194 | .toggle-links {
195 | position: absolute;
196 | width: 90%;
197 | margin-left: 30px;
198 | margin: auto;
199 | top: 100px;
200 | left: 0;
201 | right: 0;
202 | /* height: 200px; */
203 | flex-direction: column;
204 | padding: 15px;
205 | z-index: 9999;
206 | background-color: rgb(18, 26, 40);
207 | border-radius: 20px;
208 | }
209 |
210 |
211 | .toggle-links > li {
212 | margin: 15px 19px;
213 | }
214 | }
215 | @media(max-width:1360px){
216 | .account-login{
217 | position: relative;
218 | right: 5%;
219 | }
220 | }
221 | @media (max-width:1200px){
222 | .search {
223 | position: relative;
224 | left: 21%;
225 | }
226 | }
227 | @media (max-width:1000px){
228 | .search {
229 | position: relative;
230 | left: 17%;
231 | }
232 | }
233 | @media (max-width:900px){
234 | .search {
235 | position: relative;
236 | left: 10%;
237 | }
238 | }
239 | @media(max-width:850px){
240 | .account-login{
241 | position: relative;
242 | right: 6%;
243 | }
244 | }
245 | @media only screen and (max-width: 755px) {
246 | .header {
247 | padding-bottom: 20px;
248 | }
249 | .account-login{
250 | position: relative;
251 | left: 24%;
252 | }
253 | .login-tab ion-icon{
254 | font-size: 40px;
255 | position: relative;
256 | }
257 | .logo > a {
258 | font-size: 40px;
259 | position: relative;
260 | }
261 | .search {
262 | display: none;
263 | }
264 | .mobile-search{
265 | display: flex;
266 | justify-content: center;
267 | align-items: center;
268 | margin-right: 25px;
269 | margin-top: 3px;
270 | cursor: pointer;
271 | }
272 | .mobile-search .field-icon-search{
273 | width: 50px;
274 | font-size: 30px;
275 | color: var(--button-color);
276 | font-weight: 800;
277 | }
278 | .active-search-mobile{
279 | display: none;
280 | }
281 | .active-search-mobile.active{
282 | position: static;
283 | padding: 20px;
284 | display: flex;
285 | justify-content: center;
286 | align-items: center;
287 | width: 80%;
288 | overflow: hidden;
289 | position: absolute;
290 | top: 100px;
291 | left: 0;
292 | right: 0;
293 | margin: auto;
294 | border-radius: 14px;
295 | background-color: var(--search-background);
296 | color: #fff;
297 | }
298 |
299 | .mobile-view-search{
300 | display: none;
301 | }
302 | .toggle-search {
303 | padding: 30px;
304 | display: flex;
305 | justify-content: center;
306 | align-items: center;
307 | width: 80%;
308 | overflow: hidden;
309 | position: absolute;
310 | top: 350px;
311 | left: 0;
312 | right: 0;
313 | margin: auto;
314 | z-index: 9999;
315 | border-radius: 14px;
316 | }
317 |
318 |
319 |
320 | .toggle-links {
321 | height: 280px;
322 | }
323 | }
324 |
325 | @media only screen and (max-width: 750px) {
326 | .login-tab ion-icon{
327 | font-size: 35px;
328 | left: calc(25vw - 15px);
329 | }
330 | .logo > a {
331 | font-size: 35px;
332 | }
333 | }
334 | @media only screen and (max-width: 680px) {
335 | .login-tab ion-icon{
336 | font-size: 35px;
337 | left: 130px;
338 | }
339 | .account-login{
340 | position: relative;
341 | left: 22%;
342 | }
343 | }
344 | @media only screen and (max-width: 650px) {
345 | .account-login{
346 | position: relative;
347 | left: 20%;
348 | }
349 | .login-tab ion-icon{
350 | font-size: 35px;
351 | right: 0;
352 | }
353 | }
354 | @media only screen and (max-width: 623px) {
355 | .account-login{
356 | position: relative;
357 | left: 18%;
358 | }
359 | .login-tab ion-icon{
360 | font-size: 35px;
361 | left: 90px;
362 | }
363 | }
364 | @media only screen and (max-width: 560px) {
365 | .login-tab ion-icon{
366 | font-size: 35px;
367 | left: 80px;
368 | }
369 | }
370 | @media only screen and (max-width: 555px) {
371 | .account-login{
372 | position: relative;
373 | left: 13%;
374 | }
375 | .logo a{
376 | position: relative;
377 | right:20px;
378 | }
379 | .login-tab ion-icon{
380 | left: 60px;
381 | }
382 | }
383 |
384 | @media(max-width: 500px){
385 | .account-login{
386 | position: relative;
387 | left: 11%;
388 | }
389 | .login-tab ion-icon{
390 | left: calc(14vw - 10px);
391 | }
392 | .logo >a{
393 | font-size: 30px;
394 | }
395 | }
396 | @media(max-width:457px){
397 | .account-login{
398 | position: relative;
399 | left: 9%;
400 | }
401 | .login-tab ion-icon{
402 | left: calc(10vw - 10px);
403 | }
404 | }
405 | @media(max-width:432px){
406 | .account-login{
407 | left: 7%;
408 | }
409 | .login-tab ion-icon{
410 | font-size: 35px;
411 | left: calc(10vw - 10px);
412 | }
413 | }
414 | @media(max-width:417px){
415 | .account-login{
416 | left: calc(6vw - 15px);
417 | }
418 | .login-tab ion-icon{
419 | font-size: 35px;
420 | left: calc(10vw - 25px);
421 | }
422 | .logo>a{
423 | font-size: 30px;
424 | }
425 | }
426 | @media(max-width:386px){
427 | .account-login{
428 | left:calc(6vw - 10px);
429 | }
430 | .login-tab ion-icon{
431 | font-size: 35px;
432 | left: calc(6vw - 0px);
433 | }
434 | .logo>a{
435 | font-size: 23px;
436 | }
437 | }
438 | @media(max-width:360px){
439 | .account-login{
440 | left:4%;
441 | }
442 | }
443 | @media(max-width:340px){
444 | .account-login{
445 | left:2%;
446 | }
447 | .login-tab ion-icon{
448 | left: 0px;
449 | }
450 | }
451 | @media(max-width:321px){
452 | .account-login{
453 | left:calc(10vh - 62px);
454 | }
455 | }
--------------------------------------------------------------------------------
/src/css/ImageSearch.css:
--------------------------------------------------------------------------------
1 | .search-image {
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | font-size: 40px;
6 | padding-top: 20px;
7 | }
8 |
9 | .image-search-note {
10 | text-align: center;
11 | padding-bottom: 50px;
12 | padding: 20px;
13 | }
14 |
15 | .preview-image-submit {
16 | display: flex;
17 | justify-content: center;
18 | align-items: center;
19 | }
20 |
21 | .preview-image-container {
22 | display: flex;
23 | flex-direction: column;
24 | justify-content: center;
25 | align-items: center;
26 | }
27 |
28 | .image-prev {
29 | margin-top: 20px;
30 | max-width: 520px;
31 | height: 100%;
32 | border-radius: 14px;
33 | position: relative;
34 | }
35 |
36 | .image-search {
37 | aspect-ratio: 16/6;
38 | }
39 |
40 | .image-search img {
41 | position: relative;
42 | }
43 |
44 | .image-search i {
45 | color: var(--image-search-delete);
46 | font-size: 20px;
47 | position: absolute;
48 | background: var(--button-color);
49 | padding: 6px;
50 | border-radius: 50%;
51 | right: 10px;
52 | top: 10px;
53 | cursor: pointer;
54 | transition: .3s all ease-in-out;
55 | }
56 |
57 | .image-search i:hover {
58 | opacity: .8;
59 | }
60 |
61 | .other-image-container {
62 | display: flex;
63 | justify-content: space-between;
64 | gap: 40px;
65 | margin-top: 10%;
66 | }
67 |
68 | .other-image-label {
69 | cursor: pointer;
70 | background: var (--image-search-another-image );
71 | padding: 15px;
72 | border-radius: 6px;
73 | transition: .5s all ease-in-out;
74 | }
75 |
76 | .other-image-label:hover {
77 | opacity: .8;
78 | }
79 |
80 | .image-search-btn {
81 | padding: 10px;
82 | border-radius: 8px;
83 | margin-top: 20px;
84 | background-color: var(--button-color);
85 | color: var(--text-color);
86 | }
87 |
88 | .image-upload-else-container {
89 | display: flex;
90 | justify-content: center;
91 | align-items: center;
92 | }
93 |
94 | .file-upload-else {
95 | display: flex;
96 | flex-direction: column;
97 | justify-content: center;
98 | align-items: center;
99 | gap: 20px;
100 | }
101 |
102 | .upload-section {
103 | aspect-ratio: 16/9;
104 | max-width: 500px;
105 | width: 100%;
106 | height: 100%;
107 | }
108 |
109 | .url-container {
110 | display: flex;
111 | align-items: center;
112 | flex-direction: column;
113 | }
114 |
115 | .url-enter-search {
116 | margin-top: 20px;
117 | padding: 15px 30px;
118 | margin-bottom: 20px;
119 | background: var(--image-search-url);
120 | border-radius: 8px;
121 | color: var(--text-color);
122 | width: 400px;
123 | max-width: 700px;
124 | }
125 |
126 | /* image-search-result-layout */
127 |
128 | .image-btn-container {
129 | display: flex;
130 | justify-content: center;
131 | align-items: center;
132 | margin-top: 30px;
133 | flex-direction: column;
134 | gap: 40px;
135 | }
136 |
137 | .expected-scene {
138 | max-width: 00%;
139 | padding-top: 80px;
140 | margin-left: 3%;
141 | }
142 |
143 | .expected-scene .heading h1 {
144 | font-size: 40px;
145 | padding-bottom: 40px;
146 | }
147 |
148 | .expected-scene video {
149 | width: 100%;
150 | object-fit: contain;
151 | border-radius: 14px;
152 | outline: none;
153 | }
154 |
155 |
156 | @media(max-width:1000px) {
157 | .image-upload-else-container {
158 | padding-bottom: 45%;
159 | }
160 |
161 | .movies.image-search {
162 | margin-bottom: 15%;
163 | }
164 | }
165 |
166 | @media(max-width:550px) {
167 | .expected-scene {
168 | max-width: 100%;
169 | display: flex;
170 | flex-direction: column;
171 | justify-content: center;
172 | align-items: center;
173 | margin-left: 0%;
174 | padding: 30px;
175 | }
176 |
177 | .expected-scene .heading h1 {
178 | font-size: 30px;
179 | }
180 |
181 | .preview-image-container {
182 | padding: 20px;
183 | }
184 |
185 | .image-search-container .search-image {
186 | font-size: 25px;
187 | }
188 |
189 | .image-search-note {
190 | padding-bottom: 7%;
191 | }
192 |
193 | .upload-section {
194 | margin-right: 0px;
195 | }
196 |
197 | .url-enter-search {
198 | margin-top: 20px;
199 | padding: 15px 30px;
200 | margin-bottom: 20px;
201 | border-radius: 8px;
202 | width: 350px;
203 | max-width: 400px;
204 | }
205 | }
206 |
207 | @media(max-width:450px) {
208 | .expected-scene .heading h1 {
209 | font-size: 25px;
210 | }
211 | }
212 |
213 | @media(max-width:320px) {
214 | .upload-section {
215 | width: 120px
216 | }
217 |
218 | .url-enter-search {
219 | width: 290px;
220 | }
221 | }
222 |
223 |
224 |
225 |
226 | @keyframes spin {
227 | from {
228 | transform: rotate(0);
229 | }
230 |
231 | to {
232 | transform: rotate(359deg);
233 | }
234 | }
235 |
236 | @keyframes spin3D {
237 | from {
238 | transform: rotate3d(.5, .5, .5, 360deg);
239 | }
240 |
241 | to {
242 | transform: rotate3d(0deg);
243 | }
244 | }
245 |
246 | /* GRID STYLING */
247 |
248 |
249 | .spinner-box {
250 | width: 300px;
251 | height: 300px;
252 | display: flex;
253 | justify-content: center;
254 | align-items: center;
255 | background-color: transparent;
256 | position: absolute;
257 | top: 0;
258 | bottom: 0;
259 | left: 0;
260 | right: 0;
261 | margin: auto;
262 | background-color: var(--background-color);
263 | width: 100%;
264 | height: 100%;
265 | z-index: 999;
266 | }
267 |
268 | .text-message {
269 | font-size: 10px;
270 | position: absolute;
271 | bottom: 20%;
272 | display: flex;
273 | text-align: center;
274 | justify-content: center;
275 | align-items: center;
276 | padding: 0px 20px;
277 | }
278 |
279 | /* SOLAR SYSTEM */
280 |
281 | .solar-system {
282 | width: 250px;
283 | height: 250px;
284 | display: flex;
285 | justify-content: center;
286 | align-items: center;
287 | }
288 |
289 | .orbit {
290 | position: relative;
291 | display: flex;
292 | justify-content: center;
293 | align-items: center;
294 | border: 1px solid #fafbfC;
295 | border-radius: 50%;
296 | }
297 |
298 | .earth-orbit {
299 | width: 165px;
300 | height: 165px;
301 | -webkit-animation: spin 12s linear 0s infinite;
302 | }
303 |
304 | .venus-orbit {
305 | width: 120px;
306 | height: 120px;
307 | -webkit-animation: spin 7.4s linear 0s infinite;
308 | }
309 |
310 | .mercury-orbit {
311 | width: 90px;
312 | height: 90px;
313 | -webkit-animation: spin 3s linear 0s infinite;
314 | }
315 |
316 | .planet {
317 | position: absolute;
318 | top: -5px;
319 | width: 10px;
320 | height: 10px;
321 | border-radius: 50%;
322 | background-color: #3ff9dc;
323 | }
324 |
325 | .sun {
326 | width: 35px;
327 | height: 35px;
328 | border-radius: 50%;
329 | background-color: #ffab91;
330 | }
331 |
332 | .leo {
333 | position: absolute;
334 | display: flex;
335 | justify-content: center;
336 | align-items: center;
337 | border-radius: 50%;
338 | }
339 |
340 | .blue-orbit {
341 | width: 165px;
342 | height: 165px;
343 | border: 1px solid #91daffa5;
344 | -webkit-animation: spin3D 3s linear .2s infinite;
345 | }
346 |
347 | .green-orbit {
348 | width: 120px;
349 | height: 120px;
350 | border: 1px solid #91ffbfa5;
351 | -webkit-animation: spin3D 2s linear 0s infinite;
352 | }
353 |
354 | .red-orbit {
355 | width: 90px;
356 | height: 90px;
357 | border: 1px solid #ffca91a5;
358 | -webkit-animation: spin3D 1s linear 0s infinite;
359 | }
360 |
361 | .white-orbit {
362 | width: 60px;
363 | height: 60px;
364 | border: 2px solid #ffffff;
365 | -webkit-animation: spin3D 10s linear 0s infinite;
366 | }
367 |
368 | .w1 {
369 | transform: rotate3D(1, 1, 1, 90deg);
370 | }
371 |
372 | .w2 {
373 | transform: rotate3D(1, 2, .5, 90deg);
374 | }
375 |
376 | .w3 {
377 | transform: rotate3D(.5, 1, 2, 90deg);
378 | }
379 |
380 | .three-quarter-spinner {
381 | width: 50px;
382 | height: 50px;
383 | border: 3px solid #fb5b53;
384 | border-top: 3px solid transparent;
385 | border-radius: 50%;
386 | animation: spin .5s linear 0s infinite;
387 | }
--------------------------------------------------------------------------------
/src/css/Login.css:
--------------------------------------------------------------------------------
1 |
2 | .login{
3 | position: relative;
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | width: 90%;
8 | height: calc(100vh - 12vh);
9 | overflow-x: hidden;
10 | margin: auto;
11 | }
12 | .login-container {
13 | position: relative;
14 | padding:30px;
15 | background-color:var(--login-bg);
16 | width: 500px;
17 | display: flex;
18 | flex-direction: column;
19 | gap: 20px;
20 | border-radius: 14px;
21 | }
22 | .form-group{
23 | position: relative;
24 | }
25 | .login-container .login-group-input{
26 | position: relative;
27 | width: 100%;
28 | padding: 10px 20px;
29 | margin-bottom: 10px;
30 | background:transparent;
31 | border: 2px solid var(--button-color);
32 | color: var(--text-color);
33 | border-radius: 8px;
34 | background: transparent;
35 | margin-bottom: 10px;
36 | }
37 | .login-container .login-group-input::placeholder{
38 | color: var(--text-color);
39 | }
40 |
41 | .login-group-input-otp{
42 | position: relative;
43 | width: 50%;
44 | padding: 10px 20px;
45 | margin-bottom: 10px;
46 | background:transparent;
47 | border: 2px solid var(--button-color);
48 | color: var(--text-color);
49 | border-radius: 8px;
50 | }
51 | .otp-btn{
52 | padding: 10px 20px;
53 | border: 2px solid rgb(33,150,243);
54 | background: transparent;
55 | color: var(--text-color);
56 | font-weight: 600;
57 | letter-spacing: .1px;
58 | border-radius: 4px;
59 | position: absolute;
60 | right: 30px;
61 | }
62 | .login-group-input-otp::placeholder{
63 | color: var(--text-color);
64 | }
65 |
66 | .login-container h1{
67 | text-align: center;
68 | font-size: 30px;
69 | }
70 | .login-btn{
71 | display: flex;
72 | justify-content: center;
73 | align-items: center;
74 | font-size: 18px;
75 | margin: auto;
76 | }
77 | .login-register{
78 | padding: 10px 20px;
79 | background-color: var(--button-color);
80 | color: #000;
81 | font-weight: 600;
82 | letter-spacing: 2px;
83 | border-radius: 4px;
84 | /* width: 20%; */
85 | margin-left: 20px;
86 | }
87 | .form-group label{
88 | margin-left: 10px;
89 | }
90 | .login-sign-in{
91 | padding: 10px 20px;
92 | background-color: var(--button-color);
93 | color: #000;
94 | font-weight: 600;
95 | letter-spacing: 2px;
96 | border-radius: 4px;
97 | width: 90%;
98 | transition: .2s all ease-in-out;
99 | }
100 | .login-sign-in:hover{
101 | background: transparent;
102 | border: 2px solid var(--button-color);
103 | color: #fff;
104 | }
105 | .login-sign-reg{
106 | padding: 10px 20px;
107 | background-color: var(--button-color);
108 | color: #000;
109 | font-weight: 600;
110 | letter-spacing: 2px;
111 | border-radius: 4px;
112 | }
113 | .forgot-password{
114 | color:var(--button-color);
115 | }
116 | .remember-me-forget-pass{
117 | display: flex;
118 | justify-content: space-between;
119 | padding: 20px;
120 | }
121 | .create-acc{
122 | text-align: center;
123 | margin-top: 20px;
124 | }
125 | .register{
126 | font-size: 20px;
127 | color: var(--button-color) ;
128 | }
129 | .forgot{padding-bottom: 40px;}
130 |
131 | .login-toast{
132 | display: flex;
133 | padding: 20px;
134 | text-align: center;
135 | justify-content: center;
136 | align-items: center;
137 | border: 2px solid var(--button-color);
138 | max-width: 300px;
139 | border-radius: 9px;
140 | margin: auto;
141 | margin-top: 2%;
142 | }
143 | .login-toast small{
144 | font-size: 20px;
145 | font-weight: 500;
146 | }
147 |
148 | .check-remember input[type="checkbox"]{
149 | background: var(--button-color);
150 | }
151 | .check-remember input[type=checkbox] {
152 | accent-color: var(--button-color);
153 | }
154 | @media(max-width:420px){
155 | .remember-me-forget-pass{
156 | font-size: 12px;
157 | }
158 | }
--------------------------------------------------------------------------------
/src/css/Profile.css:
--------------------------------------------------------------------------------
1 | .user-picture {
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | flex-direction: column;
6 | }
7 |
8 | .user-img {
9 | width: 80px;
10 | height: 80px;
11 | border-radius: 50%;
12 | }
13 | /* .edit-user-profile{
14 | font-size: 10px;
15 | position: absolute;
16 | color: rgb(33, 150, 243);
17 | right: 41%;
18 | top: 17%;
19 | display: none;
20 | cursor: pointer;
21 | } */
22 | /* .edit-user-profile i{
23 | padding: 8px;
24 | background-color: #000;
25 | border-radius: 50%;
26 | }
27 | .edit-profile {
28 | position: absolute;
29 | left: 40%;
30 | width: 100px;
31 | opacity: 0;
32 | cursor: pointer;
33 | } */
34 |
35 | /* .edit-profile:hover {
36 | cursor: pointer;
37 | } */
38 | /* .profile-images-modal{
39 | display: flex;
40 | max-width: 700px;
41 | gap: 6px;
42 | position: absolute;
43 | background-color: black;
44 | padding: 20px;
45 | border-radius: 14px;
46 | overflow-x: hidden;
47 | flex-wrap: wrap;
48 | overflow-y: scroll;
49 | display: none;
50 | } */
51 | /* .profile-images-modal::-webkit-scrollbar{
52 | display: none;
53 | }
54 | .profile-images-modal img{
55 | width: 80px;
56 | } */
57 | .profile-wrapper {
58 | background-color: hsl(220, 47%, 20%);
59 | }
60 |
61 | .profile-wrapper .profile-greeting {
62 | display: flex;
63 | justify-content: center;
64 | font-size: 25px;
65 | }
66 |
67 | .profile-navbar {
68 | display: flex;
69 | justify-content: center;
70 | align-items: center;
71 | padding: 20px;
72 | }
73 |
74 | .profile-navbar ul {
75 | display: flex;
76 | gap: 40px;
77 | color: #fff;
78 | }
79 |
80 | .profile-display {
81 | display: flex;
82 | justify-content: center;
83 | align-items: center;
84 | padding: 40px;
85 | }
86 |
87 | .profile-display img {
88 | width: 40px;
89 | }
90 |
91 | .profile-contnet {
92 | background-color: blue;
93 | display: flex;
94 | }
95 |
96 | .profile-user-info {
97 | position: relative;
98 | display: flex;
99 | justify-content: center;
100 | align-items: center;
101 | width: 90%;
102 | height: 70vh;
103 | overflow-x: hidden;
104 | margin: auto;
105 | }
106 |
107 | .profile-btn {
108 | display: flex;
109 | justify-content: center;
110 | align-items: center;
111 | padding-top: 30px;
112 | }
113 |
114 | .profile-save {
115 | width: 100%;
116 | padding: 10px 20px;
117 | background-color: rgb(33, 150, 243);
118 | color: #000;
119 | font-weight: 600;
120 | letter-spacing: 2px;
121 | border-radius: 4px;
122 | }
123 | .clear-history{
124 | display: flex;
125 | justify-content: right;
126 | align-items: right;
127 | padding-bottom: 30px;
128 | margin-right: 20px;
129 | }
130 | .clear-history button{
131 | padding: 5px 15px;
132 | font-size: 12px;
133 | background-color: transparent;
134 | border-radius: 4px;
135 | border: 2px solid rgb(33, 150, 243);
136 | }
137 | .user-profile{
138 | min-width: 100%;
139 | padding: 50px 0 0 0;
140 | }
141 | .profile-top{
142 | display: flex;
143 | flex-direction: column;
144 | gap: 15px;
145 | justify-content: center;
146 | align-items: center;
147 | }
148 | .profile-top img{
149 | width: 100px;
150 | height: 100px;
151 | border-radius: 50%;
152 | }
153 |
154 | .profile-top button{
155 | background: blue;
156 | color: white;
157 | padding: 10px;
158 | border-radius: 10px;
159 | }
160 | .hide-image-list{
161 | display: none;
162 | }
163 |
164 | .image-list{
165 | display: flex;
166 | justify-content: center;
167 | align-items: center;
168 | gap: 10px;
169 | position: absolute;
170 | left: 0;
171 | right: 0;
172 | top: 20;
173 | z-index: 999;
174 | background-color: #162032;
175 | /* width: 700px; */
176 | height: 250px;
177 | margin: auto;
178 | border-radius: 10px;
179 | }
180 |
181 | .image-list .single-img{
182 | width: 100px;
183 | height: 100px;
184 | border-radius: 50%;
185 | overflow: hidden;
186 | cursor: pointer;
187 | }
188 |
189 | .profile-nav{
190 | margin: 20px 0;
191 | min-height: 100%;
192 | }
193 |
194 | .profile-nav ul{
195 | display: flex;
196 | gap: 40px;
197 | justify-content: center;
198 | font-size: 25px;
199 | }
200 |
201 | .profile-nav ul li{
202 | cursor: pointer;
203 | }
204 |
205 | .hide-profile, .hide-bookmark, .hide-history{
206 | display: none;
207 | }
208 |
209 | .edit-profile{
210 | display: flex;
211 | justify-content: center;
212 | margin: auto;
213 | width: 600px;
214 | padding: 20px;
215 | }
216 | .edit-profile-form-group{
217 | display: flex;
218 | flex-direction: column;
219 | gap: 10px;
220 | margin: 10px 0;
221 | }
222 | .edit-profile-form-group input{
223 | padding: 5px 10px;
224 | border-radius: 5px;
225 | }
226 | .edit-profile form button{
227 | background: blue;
228 | border-radius: 5px;
229 | padding: 10px;
230 | margin: 10px 0;
231 | }
232 |
233 | @media screen and (max-width: 900px){
234 | .profile-nav ul{
235 | font-size: 18px;
236 | }
237 | .edit-profile{
238 | width: 90%;
239 | padding: 0;
240 | }
241 | .edit-profile-form-group input{
242 | padding: 5px 5px;
243 | }
244 |
245 | }
246 |
247 | @media(max-width:500px){
248 | .profile-wrapper .profile-greeting {
249 | display: flex;
250 | justify-content: center;
251 | font-size: 20px;
252 | }
253 | }
--------------------------------------------------------------------------------
/src/css/Root.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --background-color: hsl(225, 25%, 7%);
3 | --button-color: rgb(33, 150, 243);
4 | --scroll-bar: rgb(33, 150, 243);
5 | --footer-heading: rgb(33, 150, 243);
6 | --episode-button-color: rgb(51, 51, 154);
7 | --stream-background-color: rgb(18, 26, 40);
8 | --episode-note-color: rgb(129, 174, 220);
9 | --upcoming-season-background: #162032;
10 | --chatbot-chat: rgb(33, 150, 243, 70%);
11 | --card-background: #162032;
12 | --search-background: #162032;
13 | --account-login-background: #162032;;
14 | --episode-summary: #162032;
15 | --image-search-url: #162032;
16 | --footer-social-btn : #162032;
17 | --airing-shedule-background: #162032;
18 | --airing-shedule-btn: rgb(0, 0, 0, 0.3);
19 | --text-color: #fff;
20 | --bookmark-bg: #000;
21 | --image-search-delete : #000;
22 | --image-search-another-image : #000;
23 | --footer-bg: #000;
24 | --comment-bg:rgb(22, 32, 50);
25 | --login-bg:hsl(220, 47%, 20%);
26 | --genre-filer-bar:hsl(218, 39%, 14%);
27 | --genre-background : #162032;
28 | --top-scroll-btn : hsl(219, 38%, 15%);
29 | --upcoming-season-bg: #162032;
30 | }
--------------------------------------------------------------------------------
/src/css/Search.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | .search-grid {
4 | padding: 0px 50px;
5 | display: grid;
6 | grid-template-columns: repeat(auto-fill, minmax(190px, 10fr));
7 | margin-top: 40px;
8 | gap: 30px;
9 | z-index: 9999;
10 | }
11 |
12 | @media(max-width:960px){
13 | .search-grid{
14 | margin-top: 100px;
15 | grid-template-columns: repeat(auto-fill,minmax(230px,1fr));
16 | }
17 | }
18 | @media(max-width:870px){
19 | .search-grid{
20 | grid-template-columns: repeat(auto-fill,minmax(200px,1fr));
21 | }
22 | }
23 | @media(max-width:770px){
24 | .search-grid{
25 | grid-template-columns: repeat(auto-fill,minmax(180px,1fr));
26 | }
27 | }
28 | @media(max-width:600px){
29 | .search-grid{
30 | grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
31 | padding: 0px 40px;
32 | }
33 | }
34 |
35 | @media(max-width:510px){
36 | .search-grid{
37 | padding: 0px 20px;
38 | height: auto;
39 | }
40 | }
41 | @media(max-width:450px){
42 | .search-grid{
43 | grid-template-columns: repeat(auto-fill, minmax(140px,1fr));
44 | }
45 | }
46 |
47 | @media(max-width:408px){
48 |
49 | .search-grid{
50 | grid-template-columns:repeat(auto-fill,minmax(100px,1fr)) ;
51 | }
52 | }
53 | @media(max-width:355px){
54 | .search-grid{
55 | grid-template-columns: repeat(auto-fill,minmax(100px,1fr));
56 | }
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/src/css/UpcomingSeason.css:
--------------------------------------------------------------------------------
1 | .upcoming-season{
2 | max-width: 95%;
3 | margin: auto;
4 | }
5 | .upcoming-season h1{
6 | padding-bottom: 30px;
7 | }
8 | .genre-upcoming{
9 | display: flex;
10 | gap: 8px;
11 | flex-wrap: wrap;
12 | overflow-x: hidden;
13 | }
14 | .seasons{
15 | width: 100%;
16 | display: grid;
17 | gap: 20px;
18 | grid-template-columns: repeat(4, 1fr);
19 | }
20 | .details-seasons{
21 | display: flex;
22 | gap: 10px;
23 | }
24 | .season-box{
25 | padding: 10px;
26 | display: flex;
27 | flex-direction: column;
28 | gap: 10px;
29 | background-color:var(--upcoming-season-bg);
30 | border-radius: 10px;
31 | max-height: 600px;
32 | overflow-y: scroll;
33 | padding-bottom: 30px;
34 | }
35 | .season-box h2{
36 | padding-bottom: 10px;
37 | }
38 | .season-box::-webkit-scrollbar{
39 | display: none;
40 | }
41 | .content{
42 | display: flex;
43 | gap: 10px;
44 | }
45 | .content>a>img{
46 | width: 100px;
47 | height: auto;
48 | }
49 | .content>.text{
50 | display: flex;
51 | flex-direction: column;
52 | gap: 5px;
53 | }
54 |
55 | @media screen and (max-width: 1400px){
56 | .upcoming-season{
57 | width: 90%;
58 | }
59 | .seasons{
60 | grid-template-columns: repeat(2, 1fr);
61 | }
62 | }
63 |
64 | @media screen and (max-width: 900px){
65 | .seasons{
66 | grid-template-columns: repeat(1, 1fr);
67 | }
68 | }
69 |
70 | @media screen and (max-width: 500px){
71 | .content>img{
72 | width: 40%;
73 | }
74 | .content .text{
75 | font-size: 10px;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/css/card.css:
--------------------------------------------------------------------------------
1 | .card-head{
2 | background: var(--card-background);
3 | width: 100%;
4 | padding-bottom: 30px;
5 | border-radius: 8px;
6 | }
7 | .card-img {
8 | height: 290px;
9 | object-fit: cover;
10 | border-top-left-radius: 8px;
11 | border-top-right-radius: 8px;
12 | }
13 |
14 | .movies-grid {
15 | padding: 0px 30px;
16 | display: grid;
17 | grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
18 | margin-top: 40px;
19 | gap: 20px;
20 | z-index: 9999;
21 | }
22 |
23 | .card-title {
24 | font-size: 16px;
25 | font-weight: 400;
26 | text-transform: capitalize;
27 | padding-right: 4px;
28 | text-align: center;
29 | text-align: center;
30 | overflow: hidden;
31 | text-overflow: ellipsis;
32 | display: -webkit-box;
33 | -webkit-line-clamp: 1;
34 | -webkit-box-orient: vertical;
35 | }
36 | .episode-total{
37 | border-radius: 3px;
38 | justify-content: right;
39 | display: flex;
40 | gap: 10px;
41 | padding-right: 10px;
42 | padding-bottom: 5px;
43 | font-size: 13px;
44 | margin-top: 10px;
45 | }
46 | .episode-total span{
47 | background-color: var(--button-color);
48 | padding: 0px 7px;
49 | position: relative;
50 | border-radius: 3px;
51 | color: var(--text-color);
52 | }
53 | .loadmore-recent {
54 | display: flex;
55 | justify-content: center;
56 | align-items: center;
57 | padding-top: 50px;
58 | padding-bottom: 40px;
59 | }
60 |
61 | .loadmore-recent .loadmore {
62 | padding: 10px 20px;
63 | background-color: var(--button-color);
64 | color: var(--text-color);
65 | font-size: 18px;
66 | border-radius: 9px;
67 | font-weight: 500;
68 | transition: .3s all ease-in-out;
69 | }
70 |
71 | .loadmore-recent .loadmore:hover {
72 | background: transparent;
73 | border: 2px solid var(--button-color);
74 | box-shadow: 2px 10px 90px var(--button-color);
75 | }
76 | .bookmark-icon{
77 | cursor: pointer;
78 | position: absolute;
79 | float: right;
80 | }
81 | .bookmark-icon i{
82 | font-size: 25px;
83 | display: flex;
84 | color: var(--button-color);
85 | background-color: var(--bookmark-bg);
86 | padding: 20px 20px;
87 | -webkit-clip-path: circle(34.7% at 50% 50%);
88 | clip-path: circle(34.7% at 50% 50%);
89 | }
90 |
91 |
92 |
93 | @media(max-width:950px){
94 | .card-img{
95 | height: 220px;
96 | }
97 | .movies-grid{
98 | grid-template-columns: repeat(auto-fill,minmax(165px,1fr));
99 | }
100 | }
101 |
102 | @media(max-width:610px){
103 | .card-head{
104 | height: 300px;
105 | }
106 | .card-img{
107 | height: 220px;
108 | width: 100%;
109 | }
110 | .movies-grid{
111 | grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
112 | /* padding: 0px 40px; */
113 | gap:20px;
114 | }
115 | }
116 |
117 | @media(max-width:550px){
118 | .card-head{
119 | height: 300px;
120 | }
121 | .movies-grid{
122 | padding: 0px 20px;
123 | grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
124 | height: auto;
125 | }
126 | }
127 | @media(max-width:480px){
128 | .card-head h5{
129 | font-size: 14px;
130 | font-weight: 500;
131 | }
132 | .card-img{
133 | height: 270px;
134 | }
135 | .movies-grid{
136 | grid-template-columns: repeat(auto-fill, minmax(140px,1fr));
137 | }
138 | }
139 |
140 | @media(max-width:470px){
141 | .card-head{
142 | height: 300px;
143 | }
144 | .card-img{
145 | height: 220px;
146 | }
147 | .card-head h5{
148 | font-size: 12px;
149 | }
150 | .movies-grid{
151 | grid-template-columns:repeat(auto-fill,minmax(140px,1fr)) ;
152 | }
153 | .loadmore-recent .loadmore {
154 | font-size: 12px;
155 | }
156 | }
157 | @media(max-width:355px){
158 | .movies-grid{
159 | grid-template-columns: repeat(auto-fill,minmax(100px,1fr));
160 | }
161 | }
162 |
163 |
--------------------------------------------------------------------------------
/src/css/error404.css:
--------------------------------------------------------------------------------
1 | .error-page{
2 | display: flex;
3 | justify-content: center;
4 | align-items: center;
5 | height: calc(100vh - 90px);
6 | background: rgba(0, 0, 0, 0.8);
7 | flex-direction: column;
8 | padding: 6px;
9 | }
10 | .error-page .error-background h1{
11 | font-size: 450px;
12 | opacity: .1;
13 | }
14 | .error-texts{
15 | display: flex;
16 | text-align: center;
17 | position: absolute;
18 | flex-direction: column;
19 | }
20 | .error-texts .top-error-heading{
21 | font-size: 20px;
22 | font-weight: 600;
23 | }
24 | .error-texts .top-error-heading span{
25 | color: var(--button-color);
26 | }
27 | .error-texts .error-description{
28 | font-size: 30px;
29 | font-weight: 600;
30 | }
31 | .error-texts .bottom-error-heading{
32 | font-size: 17px;
33 | font-weight: 600;
34 | }
35 | .error-texts button{
36 | background: transparent;
37 | outline: none;
38 | border:2px solid var(--button-color);
39 | padding: 17px;
40 | width: 60%;
41 | margin: 1.3rem auto;
42 | border-radius: 8px;
43 | transition: .3s all ease-in-out;
44 | color: #fff;
45 | font-size: 16px;
46 | font-weight: 600;
47 | }
48 | .error-texts button:hover{
49 | background: var(--button-color);
50 | }
51 |
52 | @media(max-width:940px){
53 | .error-page .error-background h1{
54 | font-size: 300px;
55 | }
56 |
57 | }
58 | @media(max-width:650px){
59 | .error-page .error-background h1{
60 | font-size: 250px;
61 | }
62 | .error-texts .top-error-heading{
63 | font-size: 20px;
64 | }
65 | .error-texts .error-description{
66 | font-size: 25px;
67 | }
68 | .error-texts .bottom-error-heading{
69 | font-size: 13px;
70 | }
71 | }
72 | @media(max-width:480px){
73 | .error-page{
74 | height: 90vh;
75 | }
76 | .error-page .error-background h1{
77 | font-size: 180px;
78 | }
79 | .error-texts .top-error-heading{
80 | font-size: 14px;
81 | }
82 | .error-texts .error-description{
83 | font-size: 20px;
84 | }
85 | .error-texts .bottom-error-heading{
86 | font-size: 13px;
87 | }
88 | .error-texts button{
89 | font-size: 12px;
90 | }
91 | }
92 |
93 | @media(max-width:400px){
94 | .error-page .error-background h1{
95 | font-size: 130px;
96 | }
97 | .error-texts .top-error-heading{
98 | font-size: 12px;
99 | }
100 | .error-texts .error-description{
101 | font-size: 16px;
102 | }
103 | .error-texts .bottom-error-heading{
104 | font-size: 11px;
105 | }
106 | .error-texts button{
107 | font-size: 10px;
108 | }
109 | }
110 | @media(max-width:350px){
111 | .error-page .error-background h1{
112 | font-size: 130px;
113 | }
114 | .error-texts .top-error-heading{
115 | font-size: 13px;
116 | }
117 | .error-texts .error-description{
118 | font-size: 15px;
119 | }
120 | .error-texts .bottom-error-heading{
121 | font-size: 10px;
122 | }
123 | .error-texts button{
124 | font-size: 10px;
125 | width: 90%;
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/src/css/lastwatch.css:
--------------------------------------------------------------------------------
1 | .lastwatch {
2 | display: none;
3 | padding-bottom: 30px;
4 | }
5 |
6 | .lastwatch.active {
7 | display: block;
8 | }
9 | .lastwatch-heading{
10 | font-size: 30px;
11 | }
12 | .lastwatch-close {
13 | position: absolute;
14 | left: auto;
15 | background: hsl(225, 25%, 7%);
16 | padding: 10px 20px;
17 | -webkit-clip-path: circle(34.7% at 50% 50%);
18 | clip-path: circle(34.7% at 50% 50%);
19 | cursor: pointer;
20 | }
21 |
22 | .lastwatch-close i {
23 | font-size: 30px;
24 | align-items: center;
25 | justify-content: center;
26 | display: flex;
27 | }
28 |
29 | .lastwatch-head{
30 | background: #162032;
31 | width: 200px;
32 | height: 350px;
33 | display: grid;
34 | border-radius: 4px;
35 | }
36 | .lastwatch-img {
37 | width: 100%;
38 | height: 250px;
39 | object-fit: cover;
40 | border-top-left-radius: 8px;
41 | border-top-right-radius: 8px;
42 | }
43 |
44 | .continue-icon{
45 | font-size: 35px;
46 | color: rgb(33,150,243);
47 | }
48 | .lastwatch-title {
49 | font-size: 16px;
50 | font-weight: 400;
51 | margin-top: 10px;
52 | text-transform: capitalize;
53 | padding: 5px 10px 20px;
54 | text-align: center;
55 | max-width: 200px;
56 | white-space: nowrap;
57 | overflow: hidden;
58 | text-overflow: ellipsis;
59 | }
60 | .last-ep{
61 | color: rgb(33,150,243);
62 | }
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/css/slider.css:
--------------------------------------------------------------------------------
1 | .swiper {
2 | width: 95%;
3 | height: 450px;
4 | border-radius: 14px;
5 | margin-top: 20px;
6 | }
7 |
8 | .swiper-slide {
9 | text-align: center;
10 | font-size: 18px;
11 |
12 | border-radius: 14px;
13 |
14 | display: -webkit-box;
15 | display: -ms-flexbox;
16 | display: -webkit-flex;
17 | display: flex;
18 | -webkit-box-pack: center;
19 | -ms-flex-pack: center;
20 | -webkit-justify-content: center;
21 | justify-content: center;
22 | -webkit-box-align: center;
23 | -ms-flex-align: center;
24 | -webkit-align-items: center;
25 | align-items: center;
26 | z-index: 9999;
27 | }
28 |
29 | .swiper-slide::after {
30 | content: '';
31 | position: absolute;
32 | width: 100%;
33 | height: 100%;
34 | top: 0;
35 | left: 0;
36 | background-color: rgba(0, 0, 0, 0.65);
37 | filter: drop-shadow(90px);
38 | }
39 |
40 | .banner-text {
41 | position: inherit;
42 | bottom: 200px;
43 | color: #fff;
44 | transform: translateY(-50%);
45 | z-index: 999;
46 | padding-left: 40px;
47 | padding-right: 40px;
48 | }
49 |
50 |
51 |
52 |
53 | .banner-text h4 {
54 | font-size: 30px;
55 | font-weight: 600;
56 | margin-bottom: 20px;
57 | overflow: hidden;
58 | }
59 |
60 | .watch {
61 | display: inline-block;
62 | text-align: center;
63 | vertical-align: middle;
64 | user-select: none;
65 | border: 1px solid transparent;
66 | padding: 14px 30px;
67 | line-height: 1.5;
68 | background-color: rgb(33,150,243);
69 | border-radius: 10px;
70 | color: #fff;
71 | font-weight: 700;
72 | margin-top: 10px;
73 | transition: .5s ease-in-out;
74 | }
75 |
76 | @media(max-width:1000px){
77 | .swiper{
78 | height: 350px;
79 | }
80 | .banner-text{
81 | bottom: 150px;
82 | }
83 | .banner-text h4{
84 | font-size: 30px;
85 | max-width: 700px;
86 | }
87 | .watch{
88 | padding: 9px 20px;
89 | }
90 | }
91 | @media(max-width: 850px){
92 | .swiper{
93 | height: 300px;
94 | }
95 | .banner-text h4{
96 | font-size: 25px;
97 | }
98 | .watch{
99 | padding: 15px 20px;
100 | font-size: 12px;
101 | }
102 | }
103 | @media(max-width:550px){
104 | .swiper{
105 | height: 200px;
106 | }
107 | .banner-text{
108 | bottom: 100px;
109 | }
110 | .banner-text h4{
111 | font-size: 14px;
112 | max-width: 500px;
113 | }
114 | .watch{
115 | font-size: 7px;
116 | font-size: 10px;
117 | margin-top: -10px;
118 | padding: 10px 20px;
119 | }
120 | }
121 | @media (max-width:400px){
122 | .swiper{
123 | height: 180px;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/css/terms.css:
--------------------------------------------------------------------------------
1 | .terms-div{
2 | padding: 10px 70px;
3 | padding-bottom: 90px;
4 | font-size: 90%;
5 | }
6 | .terms-div .wrap-terms{
7 | text-align: center;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | margin: auto;
12 | font-weight: 500;
13 | font-size: 12px;
14 | flex-direction: column;
15 | }
16 | .terms-div .wrap-terms a {
17 | padding: 15px 30px;
18 | background: var(--button-color);
19 | margin-top: 40px;
20 | border-radius: 8px;
21 | color: var(--text-color);
22 | font-size: 15px;
23 | }
24 | .terms-div li{
25 | list-style-type: decimal-leading-zero;
26 | margin-left: 50px;
27 | }
28 | .terms-div h2{
29 | margin-top: 30px;
30 | }
31 |
32 | @media(max-width:500px){
33 | .terms-div{
34 | padding: 0px 10px;
35 | }
36 | .terms-div h1{
37 | font-size: 18px;
38 | }
39 | .terms-div h2{
40 | font-size: 17px;
41 | }
42 | .terms-div li{
43 | font-size: 12px;
44 | margin-left: 20px;
45 | }
46 | .terms-div .wrap-terms a {
47 | background: rgb(33, 150, 243);
48 | color: #fff;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/css/titleandfilterbar.css:
--------------------------------------------------------------------------------
1 | .spinner {
2 | display: block;
3 | margin-left: auto;
4 | margin-right: auto;
5 | width: 15%;
6 | }
7 |
8 | .genres {
9 | font-weight: 200;
10 | color: var(--text-color);
11 | font-size: 12px;
12 | letter-spacing: 2px;
13 | }
14 |
15 | .movies {
16 | position: relative;
17 | top: 40px;
18 | margin: auto;
19 | }
20 |
21 | .filter-bar {
22 | display: flex;
23 | justify-content: space-between;
24 | align-items: center;
25 | padding: 0px 50px;
26 | border-radius: 20px;
27 | margin-bottom: 30px;
28 | }
29 | .filter-bar.genre{
30 | background-color: var(--genre-filer-bar);
31 | padding: 20px 50px 20px;
32 | width: 90%;
33 | margin: auto;
34 | }
35 | .filter-bar .heading h3{
36 | font-size: 50px;
37 | margin-top: -15px;
38 | }
39 | .filter-bar .heading h2{
40 | font-size: 30px;
41 | font-weight: 500;
42 | }
43 | select{
44 | background:transparent;
45 | color: #fff;
46 | font-size: 30px;
47 | display: flex;
48 | }
49 | option {
50 | border-radius: 15px;
51 | background-color: var(--genre-background);
52 | color: var(--text-color);
53 | }
54 | @media(max-width:1000px){
55 | .filter-bar .heading h3{
56 | font-size: 35px;
57 | }
58 | }
59 |
60 | @media(max-width: 700px){
61 | .filter-bar .heading h2{
62 | font-size: 30px;
63 | }
64 | }
65 | @media(max-width: 600px){
66 | .filter-bar .heading h3{
67 | font-size: 35px;
68 | }
69 |
70 | .filter-bar .heading h2{
71 | font-size: 23px;
72 | }
73 | }
74 |
75 | @media(max-width:410px){
76 | .filter-bar .heading h3{
77 | font-size: 30px;
78 | }
79 | }
80 |
81 |
82 | @media(max-width: 560px){
83 | .filter-bar{
84 | padding: 0px 20px;
85 | }
86 | .filter-bar select {
87 | font-size: 20px;
88 | margin: 0px;
89 | }
90 | .filter-bar .heading h2{
91 | font-size: 20px;
92 | }
93 | }
94 | @media(max-width: 418px){
95 | .filter-bar select {
96 | font-size: 12px;
97 | margin: 0px;
98 | }
99 | .filter-bar .heading h2{
100 | font-size: 18px;
101 | }
102 | }
103 | @media(max-width:450px){
104 | .filter-bar .heading h2{
105 | font-size: 17px;
106 | }
107 | }
--------------------------------------------------------------------------------
/src/css/topScroll.css:
--------------------------------------------------------------------------------
1 | .top-scroll{
2 | background: var(--top-scroll-btn);
3 | width: 60px;
4 | height: 60px;
5 | position: absolute;
6 | bottom: 60px;
7 | right: 40px;
8 | z-index: 100;
9 | position: fixed;
10 | cursor: pointer;
11 | border-radius: 50%;
12 | transition: .3s all ease-in-out;
13 | }
14 | .top-scroll:hover{
15 | transform: translateY(-25px);
16 | color: var(--button-color);
17 | }
18 | .top-scroll-icon{
19 | display: flex;
20 | justify-content: center;
21 | align-items: center;
22 | padding: 12px;
23 | }
24 | .top-scroll-icon i{
25 | font-size: 30px;
26 | }
--------------------------------------------------------------------------------
/src/img/loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShivaBhattacharjee/AnimeTrix/b04acf3ba3fedbc56be6b6b8cc90bd9ab20763cb/src/img/loader.gif
--------------------------------------------------------------------------------
/src/img/loader.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
12 |
13 |
--------------------------------------------------------------------------------
/src/img/spinner.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
12 |
13 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import App from "./App";
4 | import { QueryClientProvider, QueryClient } from 'react-query'
5 | import * as serviceWorkerRegistration
6 | from './serviceWorkerRegistration';
7 | const queryClient = new QueryClient()
8 | const root = ReactDOM.createRoot(document.getElementById("root"));
9 | root.render(
10 |
11 |
12 |
13 |
14 |
15 | );
16 | serviceWorkerRegistration.register();
17 |
18 |
--------------------------------------------------------------------------------
/src/service-worker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-restricted-globals */
2 |
3 | // This service worker can be customized!
4 | // See https://developers.google.com/web/tools/workbox/modules
5 | // for the list of available Workbox modules, or add any other
6 | // code you'd like.
7 | // You can also remove this file if you'd prefer not to use a
8 | // service worker, and the Workbox build step will be skipped.
9 |
10 | import { clientsClaim } from 'workbox-core';
11 | import { ExpirationPlugin } from 'workbox-expiration';
12 | import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
13 | import { registerRoute } from 'workbox-routing';
14 | import { StaleWhileRevalidate } from 'workbox-strategies';
15 |
16 | clientsClaim();
17 |
18 | // Precache all of the assets generated by your build process.
19 | // Their URLs are injected into the manifest variable below.
20 | // This variable must be present somewhere in your service worker file,
21 | // even if you decide not to use precaching. See https://cra.link/PWA
22 | precacheAndRoute(self.__WB_MANIFEST);
23 |
24 | // Set up App Shell-style routing, so that all navigation requests
25 | // are fulfilled with your index.html shell. Learn more at
26 | // https://developers.google.com/web/fundamentals/architecture/app-shell
27 | const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
28 | registerRoute(
29 | // Return false to exempt requests from being fulfilled by index.html.
30 | ({ request, url }) => {
31 | // If this isn't a navigation, skip.
32 | if (request.mode !== 'navigate') {
33 | return false;
34 | } // If this is a URL that starts with /_, skip.
35 |
36 | if (url.pathname.startsWith('/_')) {
37 | return false;
38 | } // If this looks like a URL for a resource, because it contains // a file extension, skip.
39 |
40 | if (url.pathname.match(fileExtensionRegexp)) {
41 | return false;
42 | } // Return true to signal that we want to use the handler.
43 |
44 | return true;
45 | },
46 | createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
47 | );
48 |
49 | // An example runtime caching route for requests that aren't handled by the
50 | // precache, in this case same-origin .png requests like those from in public/
51 | registerRoute(
52 | // Add in any other file extensions or routing criteria as needed.
53 | ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), // Customize this strategy as needed, e.g., by changing to CacheFirst.
54 | new StaleWhileRevalidate({
55 | cacheName: 'images',
56 | plugins: [
57 | // Ensure that once this runtime cache reaches a maximum size the
58 | // least-recently used images are removed.
59 | new ExpirationPlugin({ maxEntries: 50 }),
60 | ],
61 | })
62 | );
63 |
64 | // This allows the web app to trigger skipWaiting via
65 | // registration.waiting.postMessage({type: 'SKIP_WAITING'})
66 | self.addEventListener('message', (event) => {
67 | if (event.data && event.data.type === 'SKIP_WAITING') {
68 | self.skipWaiting();
69 | }
70 | });
71 |
72 | // Any other custom service worker logic can go here.
73 |
--------------------------------------------------------------------------------
/src/serviceWorkerRegistration.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://cra.link/PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
19 | );
20 |
21 | export function register(config) {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Let's check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl, config);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://cra.link/PWA'
45 | );
46 | });
47 | } else {
48 | // Is not localhost. Just register service worker
49 | registerValidSW(swUrl, config);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl, config) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then((registration) => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | if (installingWorker == null) {
62 | return;
63 | }
64 | installingWorker.onstatechange = () => {
65 | if (installingWorker.state === 'installed') {
66 | if (navigator.serviceWorker.controller) {
67 | // At this point, the updated precached content has been fetched,
68 | // but the previous service worker will still serve the older
69 | // content until all client tabs are closed.
70 | console.log(
71 | 'New content is available and will be used when all ' +
72 | 'tabs for this page are closed. See https://cra.link/PWA.'
73 | );
74 |
75 | // Execute callback
76 | if (config && config.onUpdate) {
77 | config.onUpdate(registration);
78 | }
79 | } else {
80 | // At this point, everything has been precached.
81 | // It's the perfect time to display a
82 | // "Content is cached for offline use." message.
83 | console.log('Content is cached for offline use.');
84 |
85 | // Execute callback
86 | if (config && config.onSuccess) {
87 | config.onSuccess(registration);
88 | }
89 | }
90 | }
91 | };
92 | };
93 | })
94 | .catch((error) => {
95 | console.error('Error during service worker registration:', error);
96 | });
97 | }
98 |
99 | function checkValidServiceWorker(swUrl, config) {
100 | // Check if the service worker can be found. If it can't reload the page.
101 | fetch(swUrl, {
102 | headers: { 'Service-Worker': 'script' },
103 | })
104 | .then((response) => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then((registration) => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log('No internet connection found. App is running in offline mode.');
124 | });
125 | }
126 |
127 | export function unregister() {
128 | if ('serviceWorker' in navigator) {
129 | navigator.serviceWorker.ready
130 | .then((registration) => {
131 | registration.unregister();
132 | })
133 | .catch((error) => {
134 | console.error(error.message);
135 | });
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/src/utils/hooks.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 |
3 | export const useFetchInitialData = (loading, data, fetchData, clientRef, container) => {
4 | useEffect(() => {
5 | if (clientRef && container && clientRef.current && !loading && (clientRef.current.clientHeight + 150 < container.innerHeight)) {
6 | fetchData();
7 | }
8 | }, [loading, data, clientRef, fetchData, container]);
9 | };
10 |
--------------------------------------------------------------------------------
/src/utils/toast.js:
--------------------------------------------------------------------------------
1 | import { toast } from 'react-toastify';
2 | import 'react-toastify/dist/ReactToastify.css';
3 | export const showErrorToast = (errorMessage) => {
4 | toast.error(errorMessage, {
5 | position: "top-center",
6 | autoClose: 1000,
7 | hideProgressBar: true,
8 | closeOnClick: true,
9 | pauseOnHover: true,
10 | draggable: true,
11 | progress: undefined,
12 | theme: "dark",
13 | });
14 | };
15 |
16 | export const showSuccessToast = (successMessage) => {
17 | toast.success(successMessage, {
18 | position: "top-center",
19 | autoClose: 1000,
20 | hideProgressBar: true,
21 | closeOnClick: true,
22 | pauseOnHover: true,
23 | draggable: true,
24 | progress: undefined,
25 | theme: "dark",
26 | });
27 | };
28 |
29 |
--------------------------------------------------------------------------------