├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── pull_request_template.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── eslint.config.js ├── index.html ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── assets │ ├── mlsa-logo.png │ └── react.svg └── vite.svg ├── src ├── App.jsx ├── Layout.jsx ├── components │ ├── BlogForm.jsx │ ├── Button.jsx │ ├── Footer.jsx │ ├── HeroSection.jsx │ ├── LoadMoreButton.jsx │ ├── LoginForm.jsx │ ├── NavBar.jsx │ ├── PostCard.jsx │ ├── PrivateRoute.jsx │ ├── RecentPosts.jsx │ ├── RegisterForm.jsx │ ├── ScrollToTopButton.jsx │ ├── TextEditor.jsx │ ├── loader │ │ ├── Loader.jsx │ │ └── loader.css │ └── svgs │ │ ├── Address.jsx │ │ ├── Email.jsx │ │ ├── Facebook.jsx │ │ ├── Fax.jsx │ │ ├── Github.jsx │ │ ├── Instagram.jsx │ │ ├── Moon.jsx │ │ ├── Phone.jsx │ │ ├── SocialX.jsx │ │ └── Sun.jsx ├── context │ └── ThemeProvider.jsx ├── hooks │ └── useFetch.js ├── index.css ├── main.jsx └── pages │ ├── CreateBlogs.jsx │ ├── Home.jsx │ ├── Login.jsx │ ├── PageNotFound.jsx │ └── Register.jsx ├── tailwind.config.js └── vite.config.js /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: good first issue, hacktoberfest 6 | assignees: rycerzes, sohambuilds 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: enhancement, help wanted 6 | assignees: sohambuilds, rycerzes, SourasishBasu 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/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | **Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.** 4 | 5 | Fixes # (issue) *(only if applicable)* 6 | 7 | ### Type of Change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | - [ ] Other (please specify): 16 | 17 | ### Checklist: 18 | 19 | - [ ] My code follows the style guidelines of this project 20 | - [ ] I have performed a self-review of my own code 21 | - [ ] I have commented my code, particularly in hard-to-understand areas 22 | - [ ] I have made corresponding changes to the documentation 23 | - [ ] My changes generate no new warnings 24 | - [ ] New and existing unit tests pass locally with my changes 25 | 26 | ### Screenshots (if applicable) 27 | 28 | **Please include any relevant screenshots or images that help explain the changes made.** 29 | 30 | #### Additional Information 31 | - Name: 32 | - Email: 33 | - Roll No: 34 | - Branch: 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # MLSA KIIT Hacktoberfest: Stable Diffusion Fine-tuning Project Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | As members, contributors, and leaders of the MLSA KIIT community, we pledge to make participation in our Stable Diffusion fine-tuning project a positive and enriching experience for everyone. We aim to create an environment that fosters learning, innovation, and collaboration in the field of AI and machine learning. 6 | 7 | ## Our Standards 8 | 9 | Behaviors that contribute to a positive environment for our community include: 10 | 11 | * Sharing knowledge and assisting others in understanding Stable Diffusion and LoRA techniques 12 | * Respecting diverse approaches to model fine-tuning and image generation 13 | * Providing constructive feedback on others' fine-tuning results and generated images 14 | * Being open to learning from others' implementations and ideas 15 | * Focusing on the technical aspects of the project and maintaining a professional atmosphere 16 | 17 | Examples of unacceptable behavior include: 18 | 19 | * Using inappropriate language or imagery in code, documentation, or project communications 20 | * Trolling, insulting comments, or personal attacks, particularly regarding fine-tuning choices or results 21 | * Sharing or using datasets or generating images that could be considered harmful or unethical 22 | * Publishing others' private information, such as contact details or private model weights, without permission 23 | * Any conduct which could reasonably be considered inappropriate in an academic or professional setting 24 | 25 | ## Project-Specific Guidelines 26 | 27 | 1. Dataset Usage: Ensure you have the right to use and share any datasets used for fine-tuning. 28 | 2. Image Generation: Be mindful of the content you generate. Avoid creating or sharing inappropriate or offensive images. 29 | 3. Model Sharing: Only share LoRA weights, not entire fine-tuned models, to respect project guidelines. 30 | 4. Collaboration: Be open to collaboration and knowledge sharing about Stable Diffusion and LoRA techniques. 31 | 32 | ## Scope 33 | 34 | This Code of Conduct applies to all spaces related to the MLSA KIIT Hacktoberfest Stable Diffusion fine-tuning project, including GitHub repositories, discussion forums, and any project-related events. 35 | 36 | ## Enforcement 37 | 38 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the MLSA KIIT team responsible for enforcement at [MLSA KIIT Discord](https://discord.gg/DymVbhCmJf). All complaints will be reviewed and investigated promptly and fairly. 39 | 40 | ## Enforcement Guidelines 41 | 42 | MLSA KIIT community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: 43 | 44 | 1. Correction: A private, written warning, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. 45 | 46 | 2. Warning: A warning with consequences for continued behavior. No interaction with the people involved for a specified period of time. 47 | 48 | 3. Temporary Ban: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. 49 | 50 | 4. Permanent Ban: A permanent ban from any sort of public interaction within the project community. 51 | 52 | ## Attribution 53 | 54 | This Code of Conduct is adapted from the Contributor Covenant, version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 55 | 56 | By participating in this project, you agree to abide by this Code of Conduct and the policies of MLSA KIIT. -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Stable Diffusion 1.4 Fine-tuning with LoRA 2 | 3 | Thank you for your interest in contributing to our Hacktoberfest project! This document outlines the process for contributing your own fine-tuned Stable Diffusion 1.4 model using LoRA. 4 | 5 | ## How to Contribute 6 | 7 | ### 1. Fork the Repository 8 | 9 | 1. Navigate to the main page of the repository on GitHub. 10 | 2. In the top-right corner of the page, click the "Fork" button. 11 | 3. Select your GitHub account as the destination for the fork. 12 | 4. Wait for GitHub to create a copy of the repository in your account. 13 | 14 | ### 2. Clone Your Fork 15 | 16 | 1. On your forked repository's page, click the "Code" button and copy the URL. 17 | 2. Open a terminal on your local machine and run: 18 | ``` 19 | git clone https://github.com/your-username/repository-name.git 20 | cd repository-name 21 | ``` 22 | 23 | ### 3. Create a New Branch 24 | 25 | Create a new branch for your contribution: 26 | ``` 27 | git checkout -b your-concept-name 28 | ``` 29 | 30 | ### 4. Implement Your Fine-tuning 31 | 32 | 1. Create a new folder in the root directory with your GitHub username or a unique identifier: 33 | ``` 34 | mkdir your-username-concept 35 | cd your-username-concept 36 | ``` 37 | 2. Implement your fine-tuning code within this folder. Include: 38 | - All necessary Python scripts for fine-tuning 39 | - A `requirements.txt` file if you use additional dependencies 40 | 41 | 3. Create a `concept.md` file in your folder describing the concept you chose for fine-tuning. Include: 42 | - A brief description of your concept 43 | - Any special techniques or modifications you made to the base code 44 | - Challenges you faced and how you overcame them 45 | 46 | 4. Provide a link to your fine-tuning dataset in the `concept.md` file. If the dataset is small enough, you can include it in your folder. 47 | 48 | 5. Create a `samples` folder within your concept folder and include at least 10 sample images generated using your fine-tuned model. 49 | 50 | 6. Export and save your LoRA weights: 51 | - After training, save only the LoRA weights (not the entire model) 52 | - Include a script or instructions for loading and applying these weights to the base SD 1.4 model 53 | - Name the weights file `lora_weights.pt` or similar 54 | 55 | 56 | ### 5. Commit and Push Your Changes 57 | 58 | 1. Stage your changes: 59 | ``` 60 | git add . 61 | ``` 62 | 2. Commit your changes: 63 | ``` 64 | git commit -m "Add fine-tuned SD 1.4 model for [Your Concept]" 65 | ``` 66 | 3. Push to your fork: 67 | ``` 68 | git push origin your-concept-name 69 | ``` 70 | 71 | ### 6. Create a Pull Request 72 | 73 | 1. Navigate to the original repository on GitHub. 74 | 2. Click on the "Pull requests" tab. 75 | 3. Click the "New pull request" button. 76 | 4. Click "compare across forks" and select your fork and branch. 77 | 5. Click "Create pull request". 78 | 6. Fill in the title and description of your pull request, explaining your changes. 79 | 7. Click "Create pull request" to submit. 80 | 81 | ## Project Structure and Your Contribution 82 | 83 | The current project structure looks like this: 84 | 85 | ``` 86 | repository-root/ 87 | ├── CONTRIBUTING.md 88 | ├── CODE_OF_CONDUCT.md 89 | ├── LICENSE 90 | ├── README.md 91 | ├── requirements.txt 92 | ├── src/ (Example implementation) 93 | │ ├── Dataset/ 94 | │ │ ├── ImageCaptions/ 95 | │ │ │ └── example1.txt 96 | │ │ └── Images/ 97 | │ │ └── example1.png 98 | │ ├── dataset.py 99 | │ ├── generate.py 100 | │ ├── lora.py 101 | │ ├── main.py 102 | │ ├── train.py 103 | │ └── utils.py 104 | └── CONTRIBUTIONS/ 105 | └── (This is where you'll add your folder) 106 | ``` 107 | 108 | When adding your contribution: 109 | 110 | 1. Create a new folder inside the `CONTRIBUTIONS` directory. Name it with your GitHub username or a unique identifier for your concept: 111 | 112 | ``` 113 | mkdir CONTRIBUTIONS/your-username-concept 114 | cd CONTRIBUTIONS/your-username-concept 115 | ``` 116 | 117 | 2. Inside your folder, create the following structure: 118 | 119 | ``` 120 | your-username-concept/ 121 | ├── fine_tuning_script.py 122 | ├── other_necessary_scripts.py 123 | ├── requirements.txt (if you have additional dependencies) 124 | ├── concept.md 125 | ├── lora_weights.pt 126 | ├── load_lora_weights.py (or instructions in concept.md) 127 | └── samples/ 128 | ├── sample1.png 129 | ├── sample2.png 130 | └── ... (at least 10 samples) 131 | ``` 132 | 133 | 3. Implement your fine-tuning code, create your concept.md file, save your LoRA weights, and add your sample images as described in the previous sections. 134 | 135 | 4. When you're ready to submit, make sure your changes only affect files within your folder in the `CONTRIBUTIONS` directory. 136 | 137 | 138 | 139 | ## Guidelines for LoRA Weights 140 | 141 | - Save only the LoRA weights, not the entire fine-tuned model. 142 | - Provide clear instructions on how to apply these weights to the base SD 1.4 model. 143 | - Ensure the weights file is not too large (preferably under 100MB). If it's larger, consider uploading to a file sharing service and providing a link. 144 | 145 | ## Code of Conduct 146 | 147 | Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. 148 | 149 | ## Questions? 150 | 151 | If you have any questions or need further clarification, please open an issue in the repository, and we'll be happy to help! 152 | 153 | Thank you for contributing to our Hacktoberfest project! -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 MLSAKIIT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DevBlogs Frontend 2 | 3 | ## Overview 4 | 5 | This is the frontend for DevBlogs, a Full Stack Blogging site for Developers by Developers. It's part of the MLSA HACKTOBER 2024: WEBDEV project. 6 | 7 | ## Tech Stack 8 | 9 | - React for dynamic user interfaces 10 | - Tailwind CSS for styling 11 | - Vite as the build tool 12 | 13 | ## Features 14 | 15 | 1. Complete user authentication with protected routes 16 | 2. Curated recommendations on homepage 17 | 3. Infinite scrolling layout 18 | 4. Responsive and modern UI 19 | 20 | ## Prerequisites 21 | 22 | - Node.js 23 | - npm or yarn 24 | - React 25 | - Tailwind CSS 26 | - React Hook Form / Yup 27 | 28 | ## Getting Started 29 | 30 | 1. Clone the repository to your local machine. 31 | 2. Navigate to the frontend directory of the project. 32 | 3. Install the required dependencies: 33 | ``` 34 | npm install 35 | ``` 36 | or 37 | ``` 38 | yarn install 39 | ``` 40 | 4. Start the development server: 41 | ``` 42 | npm run dev 43 | ``` 44 | or 45 | ``` 46 | yarn dev 47 | ``` 48 | 5. The frontend should now be running on a local port, typically http://localhost:5173. 49 | 50 | ## Folder Structure 51 | 52 | ``` 53 | . 54 | ├── README.md 55 | ├── eslint.config.js 56 | ├── index.html 57 | ├── package.json 58 | ├── postcss.config.js 59 | ├── public/ 60 | │ ├── assets/ 61 | │ └── vite.svg 62 | ├── src/ 63 | │ ├── App.jsx 64 | │ ├── components/ 65 | │ ├── index.css 66 | │ ├── main.jsx 67 | │ └── pages/ 68 | ├── tailwind.config.js 69 | └── vite.config.js 70 | ``` 71 | 72 | ## Contributing 73 | 74 | We welcome contributions to improve this project! Here's how you can contribute: 75 | 76 | 1. Fork the repository 77 | 2. Create your feature branch (`git checkout -b feature/AmazingFeature`) 78 | 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) 79 | 4. Push to the branch (`git push origin feature/AmazingFeature`) 80 | 5. Open a Pull Request 81 | 82 | ## Issues & Features 83 | - Create and validate login and registration forms using `react-hook-form` and `yup`. 84 | - Fetch blogs and implement pagination. 85 | - Dark mode toggle with Tailwind CSS. 86 | - Rich text editor integration using `react-quill`. 87 | - Route protection for authenticated routes. 88 | 89 | Check the main project documentation for a list of current issues and tasks for the frontend. 90 | 91 | ## References 92 | 93 | - Form validation: 94 | - https://dev.to/franciscomendes10866/react-form-validation-with-react-hook-form-and-yup-4a98 95 | - https://www.youtube.com/watch?v=wlltgs5jmZw 96 | - Simple authentication: 97 | - https://dev.to/sanjayttg/jwt-authentication-in-react-with-react-router-1d03 98 | - https://www.tutorialspoint.com/localstorage-in-reactjs 99 | - Route protection: 100 | - https://medium.com/@dennisivy/creating-protected-routes-with-react-router-v6-2c4bbaf7bc1c 101 | - https://www.youtube.com/watch?v=pyfwQUc5Ssk 102 | - Dark mode: 103 | - https://mujeebkhan1831.medium.com/how-to-implement-darkmode-in-react-using-tailwind-css-3c47d009209a 104 | - https://www.youtube.com/watch?v=06IpGhvEtYg 105 | - 404 Page: 106 | - https://www.geeksforgeeks.org/how-to-setup-404-page-in-react-routing/ 107 | - React-quill: 108 | - https://www.npmjs.com/package/react-quill 109 | - https://www.youtube.com/watch?v=ahNdQaq0mHg 110 | - https://www.youtube.com/watch?v=I3JQNq7Cbt0 111 | - Pagination: 112 | - https://www.youtube.com/watch?v=koG_UErY24I 113 | - React headers: 114 | - https://jasonwatmore.com/react-fetch-add-bearer-token-authorization-header-to-http-request 115 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import globals from "globals"; 3 | import react from "eslint-plugin-react"; 4 | import reactHooks from "eslint-plugin-react-hooks"; 5 | import reactRefresh from "eslint-plugin-react-refresh"; 6 | 7 | export default [ 8 | { ignores: ["dist"] }, 9 | { 10 | files: ["**/*.{js,jsx}"], 11 | languageOptions: { 12 | ecmaVersion: 2020, 13 | globals: globals.browser, 14 | parserOptions: { 15 | ecmaVersion: "latest", 16 | ecmaFeatures: { jsx: true }, 17 | sourceType: "module", 18 | }, 19 | }, 20 | settings: { react: { version: "18.3" } }, 21 | plugins: { 22 | react, 23 | "react-hooks": reactHooks, 24 | "react-refresh": reactRefresh, 25 | }, 26 | rules: { 27 | ...js.configs.recommended.rules, 28 | ...react.configs.recommended.rules, 29 | ...react.configs["jsx-runtime"].rules, 30 | ...reactHooks.configs.recommended.rules, 31 | "react/jsx-no-target-blank": "off", 32 | "react-refresh/only-export-components": [ 33 | "warn", 34 | { allowConstantExport: true }, 35 | ], 36 | "react/prop-types": "off", // Disable prop types validation 37 | }, 38 | }, 39 | ]; 40 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DevBlogs | Enhance Your Skills and Knowledge 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "front-end", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@hookform/resolvers": "^3.9.0", 14 | "framer-motion": "^11.11.9", 15 | "lucide-react": "^0.453.0", 16 | "react": "^18.3.1", 17 | "react-dom": "^18.3.1", 18 | "react-error-boundary": "^4.1.0", 19 | "react-hook-form": "^7.53.0", 20 | "react-icons": "^5.3.0", 21 | "react-quill": "^2.0.0", 22 | "react-router-dom": "^6.26.2", 23 | "yup": "^1.4.0" 24 | }, 25 | "devDependencies": { 26 | "@eslint/js": "^9.11.1", 27 | "@types/react": "^18.3.10", 28 | "@types/react-dom": "^18.3.0", 29 | "@vitejs/plugin-react": "^4.3.2", 30 | "autoprefixer": "^10.4.20", 31 | "eslint": "^9.11.1", 32 | "eslint-plugin-react": "^7.37.0", 33 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 34 | "eslint-plugin-react-refresh": "^0.4.12", 35 | "globals": "^15.9.0", 36 | "postcss": "^8.4.47", 37 | "sharp": "^0.33.5", 38 | "svgo": "^3.3.2", 39 | "tailwindcss": "^3.4.13", 40 | "vite": "^5.4.8", 41 | "vite-plugin-image-optimizer": "^1.1.8" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/assets/mlsa-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSAKIIT/devblogs-frontend/7da715bdcc13c1d841da123f9a7c7799445f6f10/public/assets/mlsa-logo.png -------------------------------------------------------------------------------- /public/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { createBrowserRouter, RouterProvider } from "react-router-dom"; 3 | import { createContext, useContext, useEffect } from "react"; 4 | import Home from "./pages/Home"; 5 | import CreateBlogs from "./pages/CreateBlogs"; 6 | import PageNotFound from "./pages/PageNotFound"; 7 | import Login from "./pages/Login"; // Import Login 8 | import Register from "./pages/Register"; //Import Register 9 | import Layout from "./Layout"; // Import the layout component 10 | 11 | export const ThemeContext = createContext(); 12 | 13 | const router = createBrowserRouter([ 14 | { 15 | path: "/", 16 | element: , // Use Layout for these routes 17 | children: [ 18 | { path: "/", element: }, 19 | { path: "/create", element: }, 20 | { path: "/login", element: }, 21 | { path: "/register", element: }, 22 | ], 23 | }, 24 | { 25 | path: "*", 26 | element: , 27 | }, 28 | ]); 29 | 30 | function App() { 31 | const { theme } = useContext(ThemeContext); 32 | 33 | useEffect(() => { 34 | if (theme === "dark") { 35 | document.body.classList.add("dark"); 36 | } else { 37 | document.body.classList.remove("dark"); 38 | } 39 | }, [theme]); 40 | 41 | return ( 42 | <> 43 | 44 | 45 | ); 46 | } 47 | 48 | export default App; 49 | -------------------------------------------------------------------------------- /src/Layout.jsx: -------------------------------------------------------------------------------- 1 | // Layout.jsx 2 | import React from "react"; 3 | import { Outlet } from "react-router-dom"; 4 | import NavBar from "./components/NavBar"; 5 | 6 | const Layout = () => { 7 | return ( 8 | <> 9 | 10 | {/* This will render the routed page components */} 11 | 12 | ); 13 | }; 14 | 15 | export default Layout; 16 | -------------------------------------------------------------------------------- /src/components/BlogForm.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import ReactQuill from 'react-quill'; 3 | import 'react-quill/dist/quill.snow.css'; 4 | import { useForm, Controller } from "react-hook-form"; 5 | import { yupResolver } from "@hookform/resolvers/yup"; 6 | import * as Yup from "yup"; 7 | 8 | const BlogForm = ({ onCreateBlog }) => { 9 | const schema = Yup.object().shape({ 10 | title: Yup.string().required("Title is required"), 11 | author: Yup.string().required("Author is required"), 12 | description: Yup.string().required("Description is required"), 13 | imgUrl: Yup.string().url("Must be a valid URL").required("Image URL is required"), 14 | }); 15 | 16 | const { register, handleSubmit, control, formState: { errors } } = useForm({ 17 | resolver: yupResolver(schema), 18 | }); 19 | 20 | const onSubmit = (data) => { 21 | const newBlog = { 22 | ...data, 23 | date: new Date().toLocaleDateString(), 24 | }; 25 | onCreateBlog(newBlog); 26 | }; 27 | 28 | return ( 29 |
30 |

31 | Create New Blog 32 |

33 |
34 |
35 | 38 | 45 | {errors.title && {errors.title.message}} 46 |
47 |
48 | 51 | 58 | {errors.author && {errors.author.message}} 59 |
60 |
61 | 64 | ( 68 | 75 | )} 76 | /> 77 | {errors.description && {errors.description.message}} 78 |
79 |
80 | 83 | 90 | {errors.imgUrl && {errors.imgUrl.message}} 91 |
92 | 98 |
99 |
100 | ); 101 | }; 102 | 103 | export default BlogForm; -------------------------------------------------------------------------------- /src/components/Button.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const Button = ({ label, onClick, className }) => { 3 | return ( 4 | 12 | ); 13 | }; 14 | 15 | export default Button; 16 | -------------------------------------------------------------------------------- /src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { motion, AnimatePresence } from 'framer-motion'; 3 | import { Github, Linkedin, Instagram, Mail, MapPin } from 'lucide-react'; 4 | 5 | const ParticleBackground = () => ( 6 |
7 | {[...Array(50)].map((_, i) => ( 8 | 31 | ))} 32 |
33 | ); 34 | 35 | const CircuitLines = () => ( 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | ); 48 | 49 | const Footer = () => { 50 | const [hoveredLink, setHoveredLink] = useState(null); 51 | 52 | const quickLinks = [ 53 | { name: 'Home', path: '/' }, 54 | { name: 'Create Blogs', path: '/create' }, 55 | { name: 'Our Team', path: 'https://mlsakiit.com/members' }, 56 | { name: 'Official Website', path: 'https://mlsakiit.com', external: true } 57 | ]; 58 | 59 | return ( 60 |
61 | 62 | 63 |
64 |
65 | 71 | 76 | MLSA KIIT 77 | 78 |

Empowering students through cutting-edge technology and innovation.

79 | 85 | Join the Future 86 | 87 |
88 | 89 | 95 |

Quick Links

96 | 134 |
135 | 136 | 142 |

Connect with Us

143 |
144 | {[ 145 | { icon: MapPin, text: "KIIT University, Bhubaneswar, Odisha" }, 146 | { icon: Mail, text: "MlSAKIIT@OUTLOOK.COM" } 147 | ].map((item, index) => ( 148 | 154 | 155 | {item.text} 156 | 157 | ))} 158 |
159 |
160 | {[ 161 | { icon: Github, href: "https://github.com/MLSAKIIT" }, 162 | { icon: Linkedin, href: "https://www.linkedin.com/company/msckiit" }, 163 | { icon: Instagram, href: "https://www.instagram.com/mlsakiit/" } 164 | ].map((social, index) => ( 165 | 174 | 175 | 176 | ))} 177 |
178 |
179 |
180 | 186 |

© {new Date().getFullYear()} MLSA KIIT. Shaping the future of technology.

187 |
188 |
189 |
190 | ); 191 | }; 192 | 193 | export default Footer; -------------------------------------------------------------------------------- /src/components/HeroSection.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import useFetch from "../hooks/useFetch"; 3 | import Loader from "./loader/Loader"; 4 | 5 | const HeroSection = ({ posts, autoSlideInterval = 5000 }) => { 6 | const { data: apiPosts, loading, error } = useFetch("/get-blogs"); 7 | const postsToDisplay = error || !apiPosts ? posts : apiPosts; 8 | const [currentIndex, setCurrentIndex] = useState(0); 9 | 10 | // Function to go to the next post 11 | const handleNextPost = () => { 12 | setCurrentIndex((prevIndex) => 13 | prevIndex === postsToDisplay.length - 1 ? 0 : prevIndex + 1 14 | ); 15 | }; 16 | 17 | // Function to go to the previous post 18 | const handlePrevPost = () => { 19 | setCurrentIndex((prevIndex) => 20 | prevIndex === 0 ? postsToDisplay.length - 1 : prevIndex - 1 21 | ); 22 | }; 23 | 24 | // Auto-slide functionality 25 | useEffect(() => { 26 | const slideInterval = setInterval(handleNextPost, autoSlideInterval); 27 | 28 | // Clear interval on unmount to prevent memory leaks 29 | return () => clearInterval(slideInterval); 30 | }, [currentIndex, autoSlideInterval]); 31 | 32 | const post = postsToDisplay[currentIndex]; 33 | 34 | return ( 35 |
36 |
37 | {loading ? ( 38 |
39 | 40 |
41 | ) : ( 42 | <> 43 | {/* Background Image */} 44 | {post.title} 49 | 50 | {/* Content Overlay */} 51 |
52 |
53 | 54 | Featured 55 | 56 |

57 | {post.title} 58 |

59 |

60 | {post.description} 61 |

62 | 65 |
66 | 67 | {/* Arrow Buttons */} 68 |
69 | 88 |
89 |
90 | 109 |
110 |
111 | 112 | )} 113 |
114 |
115 | ); 116 | }; 117 | 118 | export default HeroSection; 119 | -------------------------------------------------------------------------------- /src/components/LoadMoreButton.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const LoadMoreButton = () => { 4 | return ( 5 |
6 | 9 |
10 | ); 11 | }; 12 | 13 | export default LoadMoreButton; 14 | -------------------------------------------------------------------------------- /src/components/LoginForm.jsx: -------------------------------------------------------------------------------- 1 | 2 | import React, { useState } from "react"; 3 | import { yupResolver } from "@hookform/resolvers/yup"; 4 | import { useForm } from "react-hook-form"; 5 | import { useNavigate } from "react-router-dom"; 6 | import { object, string } from "yup"; 7 | 8 | 9 | const LoginForm = () => { 10 | const schema = object({ 11 | email: string() 12 | .email("must be a valid email") 13 | .required("email is required"), 14 | password: string() 15 | .matches( 16 | /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/gm, 17 | "enter valid password" 18 | ) 19 | .required("password is required"), 20 | }); 21 | 22 | const navigate = useNavigate(); 23 | const { 24 | register, 25 | handleSubmit, 26 | formState: { errors }, 27 | } = useForm({ resolver: yupResolver(schema) }); 28 | 29 | const handleLogin = (data) => { 30 | //auth logic here. 31 | // console.log(data); 32 | }; 33 | 34 | return ( 35 |
36 |

Welcome to Dev Blogs!

37 |

38 | Please enter your Details 39 |

40 |
41 |
42 | 43 | 49 | {errors.email && ( 50 | 51 | {errors.email.message} 52 | 53 | )} 54 |
55 |
56 | 57 | 63 | {errors.password && ( 64 | 65 | {errors.password.message} 66 | 67 | )} 68 |
69 | 70 |
71 | 74 |
75 |
76 | 82 |
83 |
84 |

Don't have an account?

85 | 91 |
92 |
93 |
94 | ); 95 | }; 96 | 97 | export default LoginForm; 98 | -------------------------------------------------------------------------------- /src/components/NavBar.jsx: -------------------------------------------------------------------------------- 1 | 2 | import React, { useEffect, useState } from "react"; 3 | 4 | import { useContext } from "react"; 5 | import { ThemeContext } from "../App"; 6 | 7 | import { useNavigate } from "react-router-dom"; 8 | import Sun from "./svgs/Sun"; 9 | import Moon from "./svgs/Moon"; 10 | 11 | const NavBar = () => { 12 | const { theme, toggleTheme } = useContext(ThemeContext); 13 | const navigate = useNavigate(); // Initialize useNavigate 14 | 15 | return ( 16 | 63 | ); 64 | }; 65 | 66 | export default NavBar; 67 | -------------------------------------------------------------------------------- /src/components/PostCard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const PostCard = ({ post }) => { 4 | return ( 5 |
6 | {post.title} 11 |
12 |

{post.title}

13 |

14 | By {post.author} on {post.date} 15 |

16 |
17 |
18 | ); 19 | }; 20 | 21 | export default PostCard; 22 | -------------------------------------------------------------------------------- /src/components/PrivateRoute.jsx: -------------------------------------------------------------------------------- 1 | //TODO: Replace with actual auth logic 2 | import {Route,Navigate, Outlet} from 'react-router-dom' 3 | const PrivateRoute=({})=>{ 4 | let auth={'token':false} 5 | return( 6 | auth.token?: 7 | ) 8 | } 9 | export default PrivateRoute 10 | -------------------------------------------------------------------------------- /src/components/RecentPosts.jsx: -------------------------------------------------------------------------------- 1 | 2 | import React, { useEffect, useState } from "react"; 3 | import PostCard from "./PostCard"; 4 | import LoadMoreButton from "./LoadMoreButton"; 5 | 6 | const RecentPosts = () => { 7 | const [posts, setPosts] = useState([]); 8 | const [loading, setLoading] = useState(true); 9 | const [error, setError] = useState(null); 10 | 11 | // Fetch posts from the /get-blogs route 12 | useEffect(() => { 13 | const fetchPosts = async () => { 14 | try { 15 | const response = await fetch("/get-blogs"); 16 | 17 | // Check if the response is JSON because sometime response geting is not in json 18 | const contentType = response.headers.get("content-type"); 19 | if (!contentType || !contentType.includes("application/json")) { 20 | throw new Error("Expected JSON, received: " + contentType); 21 | } 22 | 23 | const data = await response.json(); 24 | setPosts(data); 25 | setLoading(false); 26 | } catch (error) { 27 | setError(error.message); 28 | setLoading(false); 29 | } 30 | }; 31 | 32 | fetchPosts(); 33 | }, []); 34 | 35 | if (loading) { 36 | return

Loading...

; 37 | } 38 | 39 | if (error) { 40 | return

Error: {error}

; 41 | } 42 | 43 | return ( 44 |
45 |

46 | Recent blog posts 47 |

48 |
49 | {posts.length > 0 ? ( 50 | posts.map((post) => ) 51 | ) : ( 52 |

No posts available

53 | )} 54 |
55 | 56 |
57 | ); 58 | }; 59 | 60 | export default RecentPosts; 61 | -------------------------------------------------------------------------------- /src/components/RegisterForm.jsx: -------------------------------------------------------------------------------- 1 | import { yupResolver } from "@hookform/resolvers/yup"; 2 | import { useForm } from "react-hook-form"; 3 | import { useNavigate } from "react-router-dom"; 4 | import * as Yup from "yup"; 5 | 6 | const RegisterForm = () => { 7 | // Defining the validation schema using Yup 8 | const schema = Yup.object().shape({ 9 | userName: Yup.string().required("Username is required").min(3, "Username must be at least 3 characters"), 10 | email: Yup.string().email("Must be a valid email").required("Email is required"), 11 | password: Yup.string() 12 | .matches( 13 | /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/, 14 | "Password must contain at least 8 characters, one uppercase, one lowercase, and one number" 15 | ) 16 | .required("Password is required"), 17 | }); 18 | 19 | const navigate = useNavigate(); 20 | 21 | // Use react-hook-form and connect to yup schema 22 | const { 23 | register, 24 | handleSubmit, 25 | formState: { errors }, 26 | } = useForm({ 27 | resolver: yupResolver(schema), 28 | }); 29 | 30 | const handleRegister = (data) => { 31 | //auth logic here. 32 | }; 33 | 34 | return ( 35 |
36 |

Welcome to Dev Blogs!

37 |

38 | Please enter your Details 39 |

40 |
41 |
42 | 43 | 49 | {errors.userName && ( 50 | 51 | {errors.userName.message} 52 | 53 | )} 54 |
55 |
56 | 57 | 63 | {errors.email && ( 64 | 65 | {errors.email.message} 66 | 67 | )} 68 |
69 |
70 | 71 | 77 | {errors.password && ( 78 | 79 | {errors.password.message} 80 | 81 | )} 82 |
83 | 84 |
85 | 91 |
92 |
93 |

Already have an account?

94 | 101 |
102 |
103 |
104 | ); 105 | }; 106 | 107 | export default RegisterForm; 108 | -------------------------------------------------------------------------------- /src/components/ScrollToTopButton.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { FaChevronUp } from "react-icons/fa"; 3 | 4 | const ScrollToTopButton = () => { 5 | const [isVisible, setIsVisible] = useState(false); 6 | 7 | const handleScroll = () => { 8 | if (window.scrollY > 300) { 9 | setIsVisible(true); 10 | } else { 11 | setIsVisible(false); 12 | } 13 | } 14 | 15 | const scrollToTop = () => { 16 | window.scrollTo({ top: 0, behavior: "smooth" }) 17 | } 18 | 19 | useEffect(() => { 20 | window.addEventListener('scroll', handleScroll); 21 | return () => { 22 | window.removeEventListener('scroll', handleScroll); 23 | } 24 | }, []) 25 | return ( 26 | <> 27 | {isVisible && ()} 28 | 29 | ) 30 | } 31 | 32 | export default ScrollToTopButton 33 | -------------------------------------------------------------------------------- /src/components/TextEditor.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import ReactQuill from 'react-quill'; 3 | import 'react-quill/dist/quill.snow.css'; 4 | 5 | function MyComponent() { 6 | const [value, setValue] = useState(''); 7 | 8 | return ; 9 | } 10 | -------------------------------------------------------------------------------- /src/components/loader/Loader.jsx: -------------------------------------------------------------------------------- 1 | import "./loader.css" 2 | 3 | function Loader() { 4 | return ( 5 |
6 | ) 7 | } 8 | 9 | export default Loader -------------------------------------------------------------------------------- /src/components/loader/loader.css: -------------------------------------------------------------------------------- 1 | /* HTML:
*/ 2 | .loader { 3 | width: 60px; 4 | aspect-ratio: 2; 5 | --_g: no-repeat radial-gradient(circle closest-side,#fff 90%,#0000); 6 | background: 7 | var(--_g) 0% 50%, 8 | var(--_g) 50% 50%, 9 | var(--_g) 100% 50%; 10 | background-size: calc(100%/3) 50%; 11 | animation: l3 1s infinite linear; 12 | } 13 | @keyframes l3 { 14 | 20%{background-position:0% 0%, 50% 50%,100% 50%} 15 | 40%{background-position:0% 100%, 50% 0%,100% 50%} 16 | 60%{background-position:0% 50%, 50% 100%,100% 0%} 17 | 80%{background-position:0% 50%, 50% 50%,100% 100%} 18 | } -------------------------------------------------------------------------------- /src/components/svgs/Address.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Address = (props) => { 4 | return ( 5 | 10 | 13 | 16 | 17 | ); 18 | }; 19 | 20 | export default Address; 21 | -------------------------------------------------------------------------------- /src/components/svgs/Email.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Email = (props) => { 4 | return ( 5 | 10 | 13 | 16 | 17 | ); 18 | }; 19 | 20 | export default Email; 21 | -------------------------------------------------------------------------------- /src/components/svgs/Facebook.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Facebook = (props) => { 4 | return ( 5 | 11 | 14 | 15 | ); 16 | }; 17 | 18 | export default Facebook; 19 | -------------------------------------------------------------------------------- /src/components/svgs/Fax.jsx: -------------------------------------------------------------------------------- 1 | const Fax = (props) => { 2 | return ( 3 | 4 | 9 | 10 | ); 11 | }; 12 | 13 | export default Fax; 14 | -------------------------------------------------------------------------------- /src/components/svgs/Github.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Github = (props) => { 4 | return ( 5 | 11 | 14 | 15 | ); 16 | }; 17 | 18 | export default Github; 19 | -------------------------------------------------------------------------------- /src/components/svgs/Instagram.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Instagram = (props) => { 4 | return ( 5 | 11 | 14 | 15 | ); 16 | }; 17 | 18 | export default Instagram; 19 | -------------------------------------------------------------------------------- /src/components/svgs/Moon.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Moon = (props) => { 4 | return ( 5 | 12 | 17 | 18 | ); 19 | }; 20 | 21 | export default Moon; 22 | -------------------------------------------------------------------------------- /src/components/svgs/Phone.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Phone = (props) => { 4 | return ( 5 | 6 | 11 | 12 | ); 13 | }; 14 | 15 | export default Phone; 16 | -------------------------------------------------------------------------------- /src/components/svgs/SocialX.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const SocialX = (props) => { 4 | return ( 5 | 11 | 14 | 15 | ); 16 | }; 17 | 18 | export default SocialX; 19 | -------------------------------------------------------------------------------- /src/components/svgs/Sun.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const Sun = (props) => { 4 | return ( 5 | 13 | 17 | 23 | 24 | ); 25 | }; 26 | 27 | export default Sun; 28 | -------------------------------------------------------------------------------- /src/context/ThemeProvider.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { ThemeContext } from "../App"; 3 | 4 | const ThemeProvider = ({ children }) => { 5 | const [theme, setTheme] = useState("light"); 6 | 7 | const toggleTheme = () => { 8 | setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light")); 9 | }; 10 | 11 | return ( 12 | 13 | {children} 14 | 15 | ); 16 | }; 17 | 18 | export default ThemeProvider; 19 | -------------------------------------------------------------------------------- /src/hooks/useFetch.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | export default function useFetch(url, options) { 4 | const [data, setData] = useState(null); 5 | const [error, setError] = useState(null); 6 | const [loading, setLoading] = useState(true); 7 | 8 | useEffect(() => { 9 | const fetchData = async () => { 10 | try { 11 | const response = await fetch(url, options); 12 | if (!response.ok) { 13 | throw new Error(`HTTP error! status: ${response.status}`); 14 | } 15 | const json = await response.json(); 16 | setData(json); 17 | } catch (error) { 18 | console.error(error); 19 | setError(error.message); 20 | } finally { 21 | setLoading(false); 22 | } 23 | }; 24 | 25 | fetchData(); 26 | }, [url, options]); 27 | 28 | return { data, error, loading }; 29 | } 30 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --bg-color: #FFFFFF; /* Light mode background */ 7 | --text-color: #000000; /* Light mode text color */ 8 | } 9 | 10 | .dark { 11 | --bg-color: #2E2E2E; /* Dark mode background */ 12 | --text-color: #FFFFFF; /* Dark mode text color */ 13 | } 14 | 15 | body { 16 | background-color: var(--bg-color); /* Apply the background color */ 17 | color: var(--text-color); /* Apply the text color */ 18 | } 19 | 20 | .bg-dark-2{ 21 | /* background-color: rgb(31 42 55); */ 22 | background: inherit; 23 | } 24 | .border-dark-2{ 25 | /* border-color: rgba(31, 42, 55, 0.5) */ 26 | border-color: rgba(255, 255, 255, 0.4); 27 | /* border-color: #151515; */ 28 | } 29 | 30 | .ql-editor { 31 | color: black; 32 | background-color: white; 33 | } 34 | 35 | /* Apply dark mode styles */ 36 | .dark .ql-editor { 37 | color: white; 38 | background-color: #374151; /* Adjust as needed for dark backgrounds */ 39 | } 40 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React, { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import App from "./App.jsx"; 4 | import ThemeProvider from "./context/ThemeProvider.jsx"; 5 | import "./index.css"; 6 | createRoot(document.getElementById("root")).render( 7 | 8 | 9 | 10 | 11 | 12 | ); 13 | -------------------------------------------------------------------------------- /src/pages/CreateBlogs.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import BlogForm from "../components/BlogForm"; 3 | 4 | const CreateBlogs = () => { 5 | return ( 6 |
7 | 8 |
9 | ); 10 | }; 11 | 12 | export default CreateBlogs; 13 | -------------------------------------------------------------------------------- /src/pages/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Footer from "../components/Footer"; 3 | import HeroSection from "../components/HeroSection"; 4 | import RecentPosts from "../components/RecentPosts"; 5 | import ScrollToTopButton from "../components/ScrollToTopButton"; 6 | 7 | const Home = () => { 8 | const heroPosts = [ 9 | { 10 | title: 11 | "Breaking Into Product Design: Advice from Untitled Founder, Frankie", 12 | description: 13 | "Learn key strategies to break into the product design field with insights from Frankie.", 14 | img: "https://images.unsplash.com/photo-1651066471224-b970dd45acc3?q=80&w=1974&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 15 | }, 16 | { 17 | title: "Mastering UX Design: Tips from Industry Experts", 18 | description: 19 | "Discover how leading UX designers build intuitive experiences.", 20 | img: "https://plus.unsplash.com/premium_photo-1681755915233-9acafb348a7f?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 21 | }, 22 | { 23 | title: "The Importance of Wireframing in UX Design", 24 | description: 25 | "How wireframing can streamline your design process and improve outcomes.", 26 | img: "https://images.unsplash.com/photo-1657639466571-15adb5ab7bea?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 27 | }, 28 | ]; 29 | 30 | const blogPosts = [ 31 | { 32 | id: 1, 33 | title: "Migrating to Linear 101", 34 | author: "Leslie Alexander", 35 | date: "Mar 16, 2020", 36 | img: "https://images.unsplash.com/photo-1719937206109-7f4e933230c8?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 37 | }, 38 | { 39 | id: 2, 40 | title: "Building your API Stack", 41 | author: "Michael Foster", 42 | date: "Mar 10, 2020", 43 | img: "https://plus.unsplash.com/premium_photo-1727537538673-07a31d71efe3?q=80&w=1932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 44 | }, 45 | { 46 | id: 3, 47 | title: "Migrating to Linear 101", 48 | author: "Leslie Alexander", 49 | date: "Mar 16, 2020", 50 | img: "https://images.unsplash.com/photo-1719937206109-7f4e933230c8?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 51 | }, 52 | { 53 | id: 4, 54 | title: "Building your API Stack", 55 | author: "Michael Foster", 56 | date: "Mar 10, 2020", 57 | img: "https://plus.unsplash.com/premium_photo-1727537538673-07a31d71efe3?q=80&w=1932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 58 | }, 59 | { 60 | id: 5, 61 | title: "Migrating to Linear 101", 62 | author: "Leslie Alexander", 63 | date: "Mar 16, 2020", 64 | img: "https://images.unsplash.com/photo-1719937206109-7f4e933230c8?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 65 | }, 66 | { 67 | id: 6, 68 | title: "Building your API Stack", 69 | author: "Michael Foster", 70 | date: "Mar 10, 2020", 71 | img: "https://plus.unsplash.com/premium_photo-1727537538673-07a31d71efe3?q=80&w=1932&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", 72 | }, 73 | // More posts... 74 | ]; 75 | 76 | return ( 77 |
78 | {/* Hero Section with multiple posts */} 79 | 80 | 81 | {/* Recent Blog Posts */} 82 | 83 | 84 |
85 | 86 |
87 | ); 88 | }; 89 | 90 | export default Home; 91 | -------------------------------------------------------------------------------- /src/pages/Login.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import LoginForm from "../components/LoginForm"; 3 | 4 | const Login = () => { 5 | return ( 6 |
7 |
8 | 9 |
10 |
11 | ); 12 | }; 13 | 14 | export default Login; 15 | -------------------------------------------------------------------------------- /src/pages/PageNotFound.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useNavigate } from "react-router-dom"; 3 | 4 | const NotFound = () => { 5 | const navigate = useNavigate(); 6 | 7 | return ( 8 |
9 |

404

10 |

11 | We can not seem to find the page you are looking for. 12 |

13 | 19 |
20 | ); 21 | }; 22 | 23 | export default NotFound; 24 | -------------------------------------------------------------------------------- /src/pages/Register.jsx: -------------------------------------------------------------------------------- 1 | import RegisterForm from "../components/RegisterForm"; 2 | 3 | const Register = () => { 4 | return ( 5 |
6 |
7 | 8 |
9 |
10 | ); 11 | }; 12 | 13 | export default Register; 14 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | darkMode: 'class', // Enables class-based dark mode 5 | theme: { 6 | extend: { 7 | colors: { 8 | text: "#fff", // Light mode text color 9 | primary: "#9D5AE3", 10 | secondary: "#484848", 11 | darkFooter: "#333333", // Dark mode footer color 12 | lightFooter: "#F9FAFB", // Light mode footer color 13 | }, 14 | }, 15 | }, 16 | plugins: [], 17 | }; 18 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { ViteImageOptimizer } from "vite-plugin-image-optimizer"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig(() => { 7 | return { 8 | plugins: [ 9 | react(), 10 | ViteImageOptimizer({ 11 | jpg: { 12 | quality: 100, 13 | }, 14 | }), 15 | ], 16 | }; 17 | }); 18 | --------------------------------------------------------------------------------