├── .env
├── image.png
├── favicon.ico
├── src
├── App.css
├── components
│ ├── arrow.gif
│ ├── ScrollToTop.jsx
│ ├── CardsList.jsx
│ ├── addNote.jsx
│ ├── Search.jsx
│ ├── LoginButton.jsx
│ ├── AddNotePopup.jsx
│ ├── Card.jsx
│ ├── MainContent.jsx
│ ├── Header.jsx
│ └── BottomHeader.jsx
├── main.jsx
├── App.jsx
└── index.css
├── postcss.config.js
├── vite.config.js
├── .prettierrc
├── tailwind.config.js
├── .gitignore
├── .github
└── workflows
│ ├── contribute.yml
│ └── congrats.yml
├── index.html
├── manifest.json
├── package.json
├── LICENSE
├── CONTRIBUTING.md
├── contributors.md
└── README.md
/.env:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danishzayan/YourQuotes-App/HEAD/image.png
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danishzayan/YourQuotes-App/HEAD/favicon.ico
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | /* Project Name: YourQutoesApp
2 | Date: 07-08-2022
3 | Developer: Danish Kamal */
--------------------------------------------------------------------------------
/src/components/arrow.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danishzayan/YourQuotes-App/HEAD/src/components/arrow.gif
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()]
7 | })
8 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": true,
3 | "singleQuote": true,
4 | "tabWidth": 2,
5 | "trailingComma": "es5",
6 | "printWidth": 80,
7 | "bracketSpacing": true,
8 | "arrowParens": "avoid"
9 | }
10 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: [
4 | "./index.html",
5 | "./src/**/*.{js,jsx}",
6 | ],
7 | theme: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/src/components/ScrollToTop.jsx:
--------------------------------------------------------------------------------
1 | import Arrow from "./arrow.gif"
2 |
3 | const ScrollToTop = () => {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 | );
11 | }
12 |
13 | export default ScrollToTop;
--------------------------------------------------------------------------------
/.github/workflows/contribute.yml:
--------------------------------------------------------------------------------
1 | name: Contribute List
2 | on:
3 | push:
4 | branches:
5 | - main
6 | workflow_dispatch:
7 |
8 | jobs:
9 | contrib-readme-job:
10 | runs-on: ubuntu-latest
11 | name: A job to automate contrib in readme
12 | steps:
13 | - name: Contribute List
14 | uses: akhilmhdh/contributors-readme-action@v2.3.10
15 | with:
16 | readme_path: 'contributors.md'
17 | env:
18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import { GoogleOAuthProvider } from '@react-oauth/google';
4 | import App from './App'
5 | import './index.css'
6 | const clientId = "537577681906-379ajvh68vgtnkrpd0am696qiuf72ulc.apps.googleusercontent.com";
7 | ReactDOM.createRoot(document.getElementById('root')).render(
8 |
9 | {/* */}
10 |
11 | {/* */}
12 |
13 | )
14 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
13 | Your Quotes
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "YourQuotes",
3 | "name": "YourQuotes",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#fd5202",
14 | "background_color": "#ffffff",
15 | "description": "YourQuotes is a user friendly and an eye catching App. User can post your qutoes without login and that user can delete YourQuotes not from other user. User can share quotes with friend, copy to clipboard and do download gradient quotes image..",
16 | "dir": "ltr",
17 | "lang": "en-EN",
18 | "orientation": "any"
19 | }
--------------------------------------------------------------------------------
/src/components/CardsList.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Card from "./Card";
3 | // import AddNote from "./addNote";
4 |
5 | const CardsList = ({ notes, handleAddNote, handleDeleteNote, searchText }) => {
6 | return (
7 |
8 | {searchText !== "" &&
{notes.length} Results }
9 |
10 | {[...notes].reverse().map((note) => (
11 |
21 | ))}
22 | {/*
*/}
23 |
24 |
25 | );
26 | };
27 |
28 | export default CardsList;
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "YourQuotes-App",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@emotion/react": "^11.13.0",
13 | "@emotion/styled": "^11.13.0",
14 | "@lottiefiles/react-lottie-player": "^3.4.7",
15 | "@mui/material": "^5.16.6",
16 | "@react-oauth/google": "^0.12.1",
17 | "axios": "^0.27.2",
18 | "dotenv": "^16.4.5",
19 | "html-to-image": "^1.10.8",
20 | "react": "^18.2.0",
21 | "react-dom": "^18.2.0",
22 | "react-icons": "^5.2.1",
23 | "react-toastify": "^9.0.8"
24 | },
25 | "devDependencies": {
26 | "@types/react": "^18.0.17",
27 | "@types/react-dom": "^18.0.6",
28 | "@vitejs/plugin-react": "^2.1.0",
29 | "autoprefixer": "^10.4.19",
30 | "postcss": "^8.4.38",
31 | "prettier": "^3.3.3",
32 | "tailwindcss": "^3.4.3",
33 | "vite": "^3.1.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Danish Zayan
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 |
--------------------------------------------------------------------------------
/src/components/addNote.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const AddNote = ({ handleAddNote }) => {
4 |
5 | const [noteText, setNoteText] = useState('');
6 |
7 | const characterLimit = 200;
8 |
9 | const handleChange = (event) => {
10 | if (characterLimit - event.target.value.length >= 0) {
11 | setNoteText(event.target.value);
12 | }
13 | }
14 |
15 | const handleSave = (e) => {
16 | e.preventDefault();
17 | if (noteText.trim().length > 0) {
18 | handleAddNote(noteText);
19 | setNoteText('');
20 | }
21 | }
22 |
23 | return (
24 |
25 |
32 |
33 |
34 | {characterLimit - noteText.length} Remaining
35 | Post
36 |
37 |
38 | );
39 | };
40 |
41 | export default AddNote;
42 |
--------------------------------------------------------------------------------
/src/components/Search.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Search = ({ handleSearchNote }) => {
4 | return (
5 | <>
6 |
7 |
14 |
21 |
22 |
Search icon
23 |
24 | handleSearchNote(event.target.value)}
26 | type="text"
27 | id="search-navbar"
28 | className="block w-full p-2 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
29 | placeholder="Search..."
30 | />
31 | >
32 | );
33 | };
34 |
35 | export default Search;
36 |
--------------------------------------------------------------------------------
/src/components/LoginButton.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useGoogleLogin } from "@react-oauth/google";
3 | import axios from "axios";
4 |
5 | export default function LoginButton({setUser,isLoggedIn}) {
6 | const login = useGoogleLogin({
7 | onSuccess: async (tokenResponse) => {
8 | try {
9 | localStorage.setItem("token",tokenResponse.access_token);
10 | const res = await axios.get(
11 | "https://www.googleapis.com/oauth2/v3/userinfo",
12 | {
13 | headers: {
14 | Authorization: `Bearer ${tokenResponse.access_token}`,
15 | },
16 | }
17 | );
18 | setUser(res.data);
19 | // console.log(res);
20 | } catch (err) {
21 | console.log(err);
22 | }
23 | },
24 | });
25 | const logout = () =>{
26 | setUser(null);
27 | localStorage.removeItem("token");
28 | }
29 | return (
30 |
31 | {
35 | if(isLoggedIn){
36 | logout();
37 | }else{
38 | login()
39 | }
40 | }}
41 | >
42 | {isLoggedIn ? "LOGOUT" : "LOGIN"}
43 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/.github/workflows/congrats.yml:
--------------------------------------------------------------------------------
1 | name: Congratulatory Message
2 |
3 | on:
4 | issues:
5 | types: [opened]
6 | push:
7 | branches: [main] # Change this to your default branch
8 | pull_request:
9 | types: [opened, closed]
10 |
11 | jobs:
12 | notify:
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - name: Checkout code
17 | uses: actions/checkout@v2
18 |
19 | - name: Send Congratulatory Message
20 | if: github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged == true
21 | run: |
22 | echo "Congratulations @${{ github.event.pull_request.user.login }}! Your PR has been merged! 🎉"
23 | # Optionally, you can call the OpenAI API to generate a unique message.
24 |
25 | # Install curl if it's not available
26 | sudo apt-get install curl
27 |
28 | # Set your OpenAI API Key in the repository secrets
29 | OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}
30 |
31 | # Call OpenAI API
32 | RESPONSE=$(curl https://api.openai.com/v1/chat/completions \
33 | -s \
34 | -H "Authorization: Bearer $OPENAI_API_KEY" \
35 | -H "Content-Type: application/json" \
36 | -d '{
37 | "model": "gpt-3.5-turbo",
38 | "messages": [{"role": "user", "content": "Generate a unique congratulatory message for a GitHub contributor."}],
39 | "max_tokens": 50
40 | }')
41 |
42 | # Extract the content from the response
43 | MESSAGE=$(echo $RESPONSE | jq -r '.choices[0].message.content')
44 |
45 | # Print the message
46 | echo "Message from OpenAI: $MESSAGE"
47 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | //API Details
2 | // 20220912223415
3 | // https://6315b6ef33e540a6d38296a9.mockapi.io/notepad-app
4 |
5 | import React, { useState, useEffect } from "react";
6 | import "./App.css";
7 | import Header from "./components/Header";
8 | import "react-toastify/dist/ReactToastify.css";
9 | import MainContent from "./components/MainContent";
10 |
11 | function App() {
12 | const [searchText, setSearchText] = useState("");
13 | const [darkMode, setDarkMode] = useState(false);
14 | const [addNotePopupIsOpen, setAddNotePopupIsOpen] = useState(false);
15 | const handlePopupOpen = () => {
16 | setAddNotePopupIsOpen(true);
17 | // console.log("here");
18 | };
19 | /*Checks the localstorage to see if the dark mode was enabled during last visit*/
20 | useEffect(() => {
21 | if (!localStorage.getItem("darkmode")) {
22 | return;
23 | }
24 | let darkmode = JSON.parse(localStorage.getItem("darkmode"));
25 | if (darkmode.isDark == true) {
26 | setDarkMode(true);
27 | }
28 | }, []);
29 |
30 | const checkIfClickedInside = (e) => {
31 | if (
32 | e.target.dataset.target != "popup" &&
33 | e.target.dataset.target != "add-btn"
34 | ) {
35 | setAddNotePopupIsOpen(false);
36 | }
37 | };
38 | // console.log("rendering app");
39 | return (
40 | <>
41 |
45 |
50 |
57 |
58 | >
59 | );
60 | }
61 |
62 | export default App;
63 |
--------------------------------------------------------------------------------
/src/components/AddNotePopup.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { toast, ToastContainer } from "react-toastify";
3 |
4 | const AddNotePopup = ({ handleAddNote, setAddNotePopupIsOpen }) => {
5 |
6 | const [noteText, setNoteText] = useState("");
7 | const [noteWriter, setNoteWriter] = useState("");
8 |
9 | const characterLimit = 200;
10 |
11 | const handleChange = (event) => {
12 | if (characterLimit - event.target.value.length >= 0) {
13 | setNoteText(event.target.value);
14 | }
15 | };
16 |
17 | const handleSave = (e) => {
18 | e.preventDefault();
19 | if (noteText.trim().length > 0) {
20 | handleAddNote(noteText, noteWriter);
21 | setNoteText("");
22 | setAddNotePopupIsOpen(false);
23 | }
24 | else {
25 | toast.error('Couldn\'t add an empty..', {
26 | position: "top-center",
27 | autoClose: 2000,
28 | hideProgressBar: false,
29 | closeOnClick: true,
30 | pauseOnHover: true,
31 | draggable: true,
32 | progress: undefined,
33 | });
34 | }
35 | };
36 |
37 | return (
38 | <>
39 |
40 |
41 |
42 | Add a YourQuote
43 |
44 |
51 |
{ setNoteWriter(e.target.value) }} />
52 |
53 |
54 | {characterLimit - noteText.length} Remaining
55 |
56 |
57 | Post
58 |
59 |
60 |
61 | >
62 | );
63 | };
64 |
65 | export default AddNotePopup;
66 |
--------------------------------------------------------------------------------
/src/components/Card.jsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { toast } from 'react-toastify';
3 | import 'react-toastify/dist/ReactToastify.css';
4 | import * as htmlToImage from 'html-to-image';
5 |
6 | const Card = ({ id, color1, color2, text, date, handleDeleteNote, writer }) => {
7 |
8 | // code for listen text speech
9 | const msg = new SpeechSynthesisUtterance();
10 | msg.text = text;
11 | const talk = () => {
12 | window.speechSynthesis.speak(msg);
13 | };
14 |
15 | // code for clipboard and toastify
16 | const handleCopyText = () => {
17 | navigator.clipboard.writeText(text).then(
18 | (success) =>
19 | toast('📋 Successfully Copied Text!', {
20 | position: 'top-center',
21 | autoClose: 2000,
22 | hideProgressBar: false,
23 | closeOnClick: true,
24 | pauseOnHover: true,
25 | draggable: true,
26 | progress: undefined,
27 | }),
28 | (err) => alert('Error copying text')
29 | );
30 | };
31 |
32 | // code for share button
33 | const handleShareText = () => {
34 | if (navigator.share) {
35 | navigator
36 | .share({
37 | text: `${text}`,
38 | url: 'https://your-quotess.netlify.app/',
39 | })
40 | .then(() => {
41 | console.log('Thanks for sharing!');
42 | })
43 | .catch((err) => {
44 | console.log('Error while using Web share API:' + err);
45 | });
46 | } else {
47 | alert("Browser doesn't support this API !");
48 | }
49 | };
50 |
51 |
52 | // code for convert html to image
53 | const domEl = useRef(null);
54 | const downloadImage = async () => {
55 | const dataUrl = await htmlToImage.toPng(domEl.current);
56 | const link = document.createElement('a');
57 | link.download = 'your-quotes.png';
58 | link.href = dataUrl;
59 | link.click();
60 | };
61 |
62 | return (
63 | <>
64 |
72 |
73 |
74 | {text}
75 |
76 |
77 |
78 |
~ By {writer ? writer : 'Danish'}
79 |
80 |
81 |
82 | {date}
83 |
84 |
85 |
86 |
87 |
88 |
89 | handleDeleteNote(id)}
92 | title="delete" >
93 |
94 |
95 |
96 |
97 | >
98 | );
99 | };
100 |
101 | export default Card;
102 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guidelines for YourQuotes App 👨💻
2 |
3 | ## 👨💻 Prerequisite Skills to Contribute
4 |
5 | - [Git](https://git-scm.com/)
6 | - [Basic JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
7 | - [NodeJS](https://nodejs.org/)
8 |
9 | ### Contribute in Documents
10 |
11 | - [Markdown](https://www.markdownguide.org/basic-syntax/)
12 |
13 | ---
14 |
15 | ## 💥 How to Contribute
16 |
17 | [](https://github.com/danishzayan/YourQuotes-App/pulls)
18 | [](https://github.com/danishzayan/YourQuotes-App/)
19 |
20 | - Take a look at the existing [Issues](https://github.com/danishzayan/YourQuotes-App/issues) or [create a new issue](https://github.com/danishzayan/YourQuotes-App/issues/new/choose)!
21 | - [Fork the Repo](https://github.com/danishzayan/YourQuotes-App/fork). Then, create a branch for any issue that you are working on. Finally, commit your work.
22 | - Create a **[Pull Request](https://github.com/danishzayan/YourQuotes-App/compare)** (_PR_), which will be promptly reviewed and given suggestions for improvements by the community.
23 | - Add screenshots or screen captures to your Pull Request to help us understand the effects of the changes proposed in your PR.
24 |
25 | ---
26 |
27 | ## ⭐ HOW TO MAKE A PULL REQUEST:
28 |
29 | **1.** Start by making a Fork of the [**YourQuotes**](https://github.com/danishzayan/YourQuotes-App) repository. Click on the Fork symbol at the top right corner.
30 |
31 | **2.** Clone your new fork of the repository in the terminal/CLI on your computer with the following command:
32 |
33 | ```bash
34 | git clone https://github.com//YourQuotes
35 | ```
36 |
37 | **3.** Navigate to the newly created LinkFree project directory:
38 |
39 | ```bash
40 | cd YourQuotes
41 | ```
42 |
43 | **4.** Create a new branch:
44 |
45 | ```bash
46 | git checkout -b YourBranchName
47 | ```
48 |
49 | ⚠️ **Make sure** not to commit `package.json` or `package-lock.json` file
50 |
51 | ⚠️ **Make sure** not to run the commands `git add .` or `git add *`. Instead, stage your changes for each file/folder
52 |
53 | **5.** Add those changes to the branch you just created using the git add command:
54 |
55 | ```bash
56 | git add .
57 | ```
58 |
59 | - After git add command see status with git status command:
60 |
61 | ```bash
62 | git status
63 | ```
64 |
65 | **6.** Now commit those changes using the git commit command::
66 |
67 | ```bash
68 | git commit -m ""
69 | ```
70 |
71 | **7.** Push your local commits to the remote repository:
72 |
73 | ```bash
74 | git push origin YourBranchName
75 | ```
76 |
77 | **8.** Create a [Pull Request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request)!
78 |
79 | **9.** **Congratulations!** You've made your first contribution to [**YourQuotes**](https://github.com/danishzayan/YourQuotes-App/graphs/contributors)! 🙌🏼
80 |
81 | **_:trophy: After this, the maintainers will review the PR and will merge it if it helps move the YourQuotes project forward. Otherwise, it will be given constructive feedback and suggestions for the changes needed to add the PR to the codebase._**
82 |
83 | ---
84 |
85 | ## Style Guide for Git Commit Messages :memo:
86 |
87 | **How you can add more value to your contribution logs:**
88 |
89 | - Use the present tense. (Example: "Add feature" instead of "Added feature")
90 | - Use the imperative mood. (Example: "Move item to...", instead of "Moves item to...")
91 | - Limit the first line (also called the Subject Line) to _50 characters or less_.
92 | - Capitalize the Subject Line.
93 | - Separate subject from body with a blank line.
94 | - Do not end the subject line with a period.
95 | - Wrap the body at _72 characters_.
96 | - Use the body to explain the _what_, _why_, _vs_, and _how_.
97 | - Reference [Issues](https://github.com/danishzayan/YourQuotes-App/issues) and [Pull Requests](https://github.com/danishzayan/YourQuotes-App/pulls) liberally after the first line.
98 |
99 | ---
100 |
101 | ## 💥 Issues
102 |
103 | In order to discuss changes, you are welcome to [open an issue](https://github.com/danishzayan/YourQuotes-App/issues/new/choose) about what you would like to contribute. Enhancements are always encouraged and appreciated.
104 |
105 | ## All the best! 🥇
106 |
107 | [](https://github.com/danishzayan/YourQuotes-App)
108 |
--------------------------------------------------------------------------------
/contributors.md:
--------------------------------------------------------------------------------
1 | # Contributors
2 |
3 | **Awesome people who messed with the code in this repo**
4 |
5 |
6 |
123 |
124 |
--------------------------------------------------------------------------------
/src/components/MainContent.jsx:
--------------------------------------------------------------------------------
1 | //API Details
2 | // 20220912223415
3 | // https://6315b6ef33e540a6d38296a9.mockapi.io/notepad-app
4 |
5 | import React, { useState, useEffect } from "react";
6 | import { Player } from "@lottiefiles/react-lottie-player";
7 | import AddNotePopup from "../components/AddNotePopup";
8 | import CardsList from "../components/CardsList";
9 | import { nanoid } from "nanoid";
10 | import axios from "axios";
11 | import { ToastContainer } from "react-toastify";
12 | // import Search from "./components/Search";
13 | import { toast } from "react-toastify";
14 | import "react-toastify/dist/ReactToastify.css";
15 | import ScrollToTop from "../components/ScrollToTop";
16 | import BottomHeader from "../components/BottomHeader";
17 |
18 | function MainContent({
19 | addNotePopupIsOpen,
20 | setAddNotePopupIsOpen,
21 | searchText,
22 | darkMode,
23 | handlePopupOpen
24 | }) {
25 | const randomColor1 = Math.floor(Math.random() * 16777215).toString(16);
26 | const randomColor2 = Math.floor(Math.random() * 16777215).toString(16);
27 | const ID = nanoid();
28 | // console.log("rendering main");
29 | const [notes, setNotes] = useState([
30 | {
31 | id: ID,
32 | color1: randomColor1,
33 | color2: randomColor2,
34 | text: "It's YourQuotes-App",
35 | writer: `Writer's name`,
36 | date: "15/06/2021",
37 | },
38 | ]);
39 |
40 | const [loading, setLoading] = useState(true);
41 |
42 | // read operaton
43 | const getData = () => {
44 | setLoading(true);
45 | axios
46 | .get("https://6315b6ef33e540a6d38296a9.mockapi.io/notepad-app")
47 | .then((res) => {
48 | setLoading(false);
49 | // console.log(res.data);
50 | setNotes(res.data);
51 | });
52 | };
53 |
54 | useEffect(() => {
55 | getData();
56 | }, []);
57 |
58 | const addNote = (text, writer) => {
59 | const date = new Date();
60 | const newNote = {
61 | id: ID,
62 | color1: randomColor1,
63 | color2: randomColor2,
64 | text: text,
65 | writer: writer,
66 | date: date.toLocaleDateString(),
67 | };
68 | const newNotes = [...notes, newNote];
69 | setNotes(newNotes);
70 | // console.log(newNotes);
71 |
72 | //create operation
73 | axios.post(
74 | "https://6315b6ef33e540a6d38296a9.mockapi.io/notepad-app",
75 | newNote
76 | );
77 | };
78 |
79 | const deleteNote = (id) => {
80 | const newNotes = notes.filter((note) => note.id !== id);
81 | console.log(newNotes);
82 | console.log(id);
83 | //delete operation
84 | if (true) {
85 | axios.delete(
86 | `https://6315b6ef33e540a6d38296a9.mockapi.io/notepad-app/${id}`
87 | );
88 | setNotes(newNotes);
89 | } else
90 | toast("📋 This is not YourQutoes", {
91 | position: "top-center",
92 | autoClose: 2000,
93 | hideProgressBar: false,
94 | closeOnClick: true,
95 | pauseOnHover: true,
96 | draggable: true,
97 | progress: undefined,
98 | });
99 | };
100 |
101 |
102 | return (
103 | <>
104 | {loading ? (
105 |
121 | ) : (
122 |
123 |
124 |
126 | note.text.toUpperCase().includes(searchText.toLocaleUpperCase())
127 | )}
128 | // we need this to see if the search input is empty
129 | searchText={searchText}
130 | handleAddNote={addNote}
131 | handleDeleteNote={deleteNote}
132 | />
133 |
144 |
145 |
146 |
147 |
148 |
149 | )}
150 | {addNotePopupIsOpen && (
151 |
155 | )}
156 |
157 | >
158 | );
159 | }
160 |
161 | export default MainContent;
162 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YourQuotes-App 📱
2 |
3 | "YourQuotes" is a visually stunning and user-friendly application built with Vite+React. It offers a seamless experience for users to post their favorite quotes, ensuring a streamlined process. Users can effortlessly share quotes with friends, copy them to the clipboard, or download them as gradient images. The app also includes essential features such as a Home feed, Notifications, Bookmarks, and Profile management. Additionally, users can interact with quotes using Like buttons and have the option to edit their own submissions. Exciting features like "Quotes of the Day" provide daily inspiration, while translation capabilities enhance accessibility for a global audience. With its intuitive interface and a myriad of features, YourQuotes is the ultimate destination for quote enthusiasts to engage, express, and inspire. Join us in the journey of sharing wisdom and inspiration with YourQuotes.
4 |
5 | [](https://app.netlify.com/sites/your-quotess/deploys)
6 |
7 |
8 | [](https://GitHub.com/danishzayan/YourQuotes-App/graphs/contributors/)
9 |
10 | [](https://github.com/danishzayan/YourQuotes-App/commit/)
11 | [](https://GitHub.com/danishzayan/YourQuotes-App/issues/)
12 | [](https://GitHub.com/danishzayan/YourQuotes-App/issues?q=is%3Aissue+is%3Aclosed)
13 |
14 |
15 |
16 | ## Screenshot of App 📷
17 |
18 | 
19 |
20 | ## Run YourQuotes-App
21 |
22 | ```bash
23 | npm install
24 | ```
25 |
26 | ```bash
27 | npm run dev
28 | ```
29 |
30 | # 📜 Quotes Application UI Features
31 |
32 | This application allows users to post, search, listen to, share, copy, download, and manage quotes with ease. Below is a detailed list of features to help contributors understand the current functionality and areas that need further development.
33 |
34 | ## ✅ Completed Features
35 |
36 | - **Quotes Posting** ➕
37 | - Users can post new quotes by clicking on the plus icon (`+`) at the bottom right corner.
38 | - **Search Functionality** 🔍
39 | - A search bar at the top allows users to search for quotes.
40 | - **Listening to Quotes** 🔊
41 | - Users can listen to quotes using the text-to-speech feature.
42 | - **Sharing Quotes** 📤
43 | - Users can share quotes via a share button.
44 | - **Copying Quotes** 📋
45 | - Users can copy quotes to the clipboard.
46 | - **Downloading Quotes** 📥
47 | - Users can download quotes.
48 | - **Dark Mode** 🌙
49 | - Users can toggle between dark mode and light mode.
50 |
51 | ## 🚧 Pending Features
52 |
53 | - **Pages** 📄
54 | - Home
55 | - Notification
56 | - Add
57 | - Bookmark
58 | - Profile
59 | - **Edit Quotes** ✏️
60 | - Implement functionality for users to edit existing quotes.
61 | - **User Authentication** 🔐
62 | - Add user login and registration features to personalize the experience.
63 | - **Commenting on Quotes** 💬
64 | - Allow users to add comments on individual quotes.
65 | - **Like Button** 👍
66 | - Implement a feature to allow users to like quotes.
67 | - **Favorites/Bookmarks** 📑
68 | - Allow users to mark quotes as favorites or bookmark them for later reference.
69 | - **Profile Management** 👤
70 | - Add user profile management to track posted quotes and activities.
71 | - **Quote Categories/Tags** 🏷️
72 | - Enable categorizing or tagging quotes for better organization and searchability.
73 | - **Quote Translations** 🌐
74 | - Provide a feature to translate quotes into different languages.
75 | - **Notification System** 🔔
76 | - Implement notifications for user activities and updates.
77 | - **Social Sharing** 🌐
78 | - Allow users to share quotes on social media platforms.
79 | - **Quote of the Day** 🌅
80 | - Feature a "Quote of the Day" on the homepage.
81 |
83 | - **Analytics Dashboard** 📊
84 | - Provide an analytics dashboard for users to see their quote interactions in profile.
85 | - **User Follow System** ➕👤
86 | - Allow users to follow other users and see their activity.
87 | - **Multimedia Quotes** 🎨
88 | - Enable users to add images or videos to quotes.
89 | - **Quote Collections** 📚
90 | - Allow users to create and share collections of quotes.
91 | - **Offline Mode** 📴
92 | - Provide an offline mode to access quotes without an internet connection.
93 | - **Localization** 🌍
94 | - Support multiple languages for the application interface.
95 |
96 | ## Contributing 👨💻
97 |
98 | [](https://github.com/ellerbrock/open-source-badges/)
99 |
100 | - Contributions make the open source community such an amazing place to learn, inspire, and create.
101 | - Any contributions you make are **greatly appreciated**.
102 | - Check out our [contribution guidelines](/CONTRIBUTING.md) for more information.
103 |
104 | ## License 🛡️
105 |
106 | YourQuotes-App is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
107 |
108 | ## Contributor Over Time ⏳
109 |
110 | [](https://www.apiseven.com/en/contributor-graph?chart=contributorOverTime&repo=danishzayan/YourQuotes-App)
111 |
112 |
113 | ## Project Contributors 🌟
114 |
115 | Thanks a lot for spending your time helping YourQuotes grow. Thanks a lot! Keep rocking 🎉
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | Made in :heart: INDIA and ⭐ Staring the repo..
124 |
125 |
--------------------------------------------------------------------------------
/src/components/Header.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Search from "../components/Search";
3 | import LoginButton from "./LoginButton";
4 | import { Tooltip } from "@mui/material";
5 | import axios from "axios";
6 | import { toast, ToastContainer } from "react-toastify";
7 |
8 | const Header = ({ handleToggleDarkMode, setSearch, darkMode }) => {
9 | const [dark, setDark] = useState(false);
10 | const [user, setUser] = useState(null);
11 | const isLoggedIn = user ? true : false;
12 | useEffect(() => {
13 | if (darkMode) {
14 | setDark(true);
15 | } else {
16 | setDark(false);
17 | }
18 | }, [darkMode]);
19 |
20 | useEffect(()=>{
21 | if(user){
22 | toast(`Welcome ${user.name}`, {
23 | position: "top-center",
24 | autoClose: 2000,
25 | hideProgressBar: false,
26 | closeOnClick: true,
27 | pauseOnHover: true,
28 | draggable: true,
29 | progress: undefined,
30 | });
31 | }
32 | },[isLoggedIn]);
33 | useEffect(() => {
34 | if (localStorage.getItem("token")) {
35 | const access_token = localStorage.getItem("token");
36 | async function getUser() {
37 | try{
38 | const res = await axios.get(
39 | "https://www.googleapis.com/oauth2/v3/userinfo",
40 | {
41 | headers: {
42 | Authorization: `Bearer ${access_token}`,
43 | },
44 | }
45 | );
46 | setUser(res.data);
47 | }catch(err){
48 | console.log(err);
49 | }
50 |
51 | }
52 | getUser();
53 | }
54 | }, []);
55 |
56 | const toggleDarkMode = () => {
57 | handleToggleDarkMode((previousDarkMode) => {
58 | const newDarkMode = !previousDarkMode;
59 | const darkmode = { isDark: newDarkMode };
60 | localStorage.setItem("darkmode", JSON.stringify(darkmode));
61 | setDark(newDarkMode);
62 | return newDarkMode;
63 | });
64 | };
65 |
66 | return (
67 |
72 |
73 |
74 |
75 |
80 |
85 | YourQutoes
86 |
87 |
88 |
89 |
111 |
112 |
118 |
126 |
127 |
128 |
136 |
137 |
138 | Toggle dark mode
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | {isLoggedIn && (
149 |
150 |
151 |
156 |
157 |
158 | )}
159 |
160 |
161 |
162 | );
163 | };
164 |
165 | export default Header;
166 |
--------------------------------------------------------------------------------
/src/components/BottomHeader.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 |
3 | const BottomHeader = ({darkMode,handlePopupOpen }) => {
4 | let darkmode = JSON.parse(localStorage.getItem("darkmode"));
5 | const [dark, setDark] = useState(false);
6 | // console.log("rendering bottom ");
7 |
8 | useEffect(() => {
9 | if (darkMode) {
10 | setDark(true);
11 | } else {
12 | setDark(false);
13 | }
14 | }, [darkmode]);
15 |
16 | return (
17 |
22 |
23 |
28 |
35 |
36 |
37 | Home
38 |
39 |
47 |
52 |
59 |
60 |
61 | Notification
62 |
63 |
71 |
72 |
79 |
87 |
95 |
96 | New item
97 |
98 |
99 |
107 |
112 |
119 |
120 |
121 | Bookmarks
122 |
123 |
131 |
136 |
143 |
144 |
145 | Profile
146 |
147 |
155 |
156 |
157 | );
158 | };
159 |
160 | export default BottomHeader;
161 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | /* Project Name: YourQuotes-App
2 | Date: 07-08-2022
3 | Developer: Danish Kamal */
4 |
5 | @import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;1,100;1,200;1,300&family=Roboto:ital,wght@0,100;0,300;0,400;1,300;1,400&display=swap");
6 | @tailwind base;
7 | @tailwind components;
8 | @tailwind utilities;
9 |
10 |
11 | html {
12 | scroll-behavior: smooth;
13 | }
14 |
15 | * {
16 | margin: 0;
17 | padding: 0;
18 | box-sizing: border-box;
19 | font-family: "Poppins", sans-serif;
20 | }
21 |
22 | .body {
23 | background-color: rgb(248, 248, 248);
24 | /* background-image: url("../src/assets/images/background.jpg"); */
25 | /* background:linear-gradient(rgba(6, 6, 6, 0.243), rgba(255, 255, 0, 0)), url("../src/assets/images/background.jpg"); */
26 | /* background-image: url("https://www.transparenttextures.com/patterns/cubes.png"), linear-gradient(to right top, #cf4af3, #e73bd7, #f631bc, #fd31a2, #ff3a8b, #ff4b78, #ff5e68, #ff705c, #ff8c51, #ffaa49, #ffc848, #ffe652); */
27 | /* background-repeat: no-repeat; */
28 | /* background-size: cover; */
29 | background-position: center;
30 | background-attachment: fixed;
31 |
32 | }
33 |
34 | .body-dark {
35 | background-color: #120f0f;
36 | /* background-image: url("https://www.transparenttextures.com/patterns/cubes.png"), linear-gradient(to right top, #000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000, #000000); */
37 | background-position: center;
38 | background-attachment: fixed;
39 | }
40 |
41 | .container {
42 | /* max-width: 960px; */
43 | width: 100%;
44 | margin: 0 auto;
45 | padding: 25px 20px;
46 | min-height: 100vh;
47 | }
48 |
49 | .add-note-btn {
50 | background-color: tomato;
51 | border-radius: 50%;
52 | width: 50px;
53 | height: 50px;
54 | font-size: 2rem;
55 | border: none;
56 | color: white;
57 | position: fixed;
58 | bottom: 20px;
59 | right: 20px;
60 | cursor: pointer;
61 | }
62 |
63 | .cards-list {
64 | display: grid;
65 | grid-gap: 1rem;
66 | grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
67 | padding-bottom: 1rem;
68 | }
69 |
70 | .card {
71 | background: linear-gradient(40deg, rgb(101, 48, 146) -200%, rgb(232, 230, 64) 150%);
72 | border-radius: 10px;
73 | border-bottom: 5px solid rgb(255 255 255 / 25%);
74 | padding: 1rem;
75 | min-height: 240px;
76 | display: flex;
77 | flex-direction: column;
78 | justify-content: space-between;
79 | white-space: pre-wrap;
80 | box-shadow: rgb(0 0 0 / 24%) 0px 3px 8px;
81 | }
82 |
83 | .card span {
84 | font-size: 14px;
85 | font-weight: 500;
86 | overflow: hidden;
87 | word-break: break-word;
88 | }
89 |
90 | .card .text {
91 | margin: 0 auto;
92 | }
93 |
94 | .text span {
95 | margin: 0 5px;
96 | text-transform: capitalize;
97 | }
98 |
99 | .card.new {
100 | background: #67e4d8;
101 | border: none;
102 | }
103 |
104 | .popup {
105 | position: fixed;
106 | top: 50%;
107 | left: 50%;
108 | transform: translate(-50%, -50%);
109 | width: 300px;
110 | box-shadow: 0 0 5px 1px #736a6ab5;
111 | z-index: 1;
112 | }
113 |
114 | .popup-title {
115 | font-size: 1.2rem;
116 | margin-bottom: 0.5rem;
117 | color: rgb(56, 56, 56);
118 | text-align: center;
119 | }
120 |
121 | .add-overlay {
122 | opacity: 0.5;
123 | }
124 |
125 | textarea {
126 | background: #67e4d8;
127 | border: none;
128 | resize: none;
129 | border: 1px solid #35c8bab8;
130 | border-radius: 8px;
131 | padding: 5px;
132 | margin-bottom: 0.3rem;
133 | }
134 |
135 | textarea:focus {
136 | outline: none;
137 | }
138 |
139 | .card.new input {
140 | outline: none;
141 | background: #67e4d8;
142 | border: none;
143 | border: 1px solid #35c8bab8;
144 | border-radius: 6px;
145 | padding: 4px;
146 | }
147 |
148 | .footer .save {
149 | color: #fff;
150 | border: none;
151 | padding: 0 15px;
152 | border-radius: 10px;
153 | background-color: #000000;
154 | outline: none;
155 | }
156 |
157 | .footer .save:hover {
158 | cursor: pointer;
159 | background-color: #141414e8;
160 | }
161 |
162 | .footer-writer span {
163 | font-size: 14px;
164 | font-style: italic;
165 | font-weight: 600;
166 | display: flex;
167 | justify-content: end;
168 | text-transform: capitalize;
169 | }
170 |
171 | .footer {
172 | display: flex;
173 | flex-direction: row;
174 | justify-content: space-between;
175 | align-items: center;
176 | background: #ffffff47;
177 | padding: 0 5px;
178 | border-radius: 5px;
179 | border: 1px solid #ffffff1f;
180 | margin-top: 1em;
181 | }
182 |
183 | .card.new .footer {
184 | background: none;
185 | border: none;
186 | }
187 |
188 | .footer small {
189 | font-size: 12px;
190 | font-weight: 500;
191 | }
192 |
193 | .footer .fa-calendar-day:before {
194 | font-size: 14px;
195 | color: black;
196 | margin-right: 5px;
197 | }
198 |
199 | .footer .fa-trash:before {
200 | font-size: 14px;
201 | color: #fb0000;
202 | cursor: pointer;
203 | }
204 |
205 | .footer .fa-copy:before {
206 | content: "\f0c5";
207 | font-size: 14px;
208 | color: #000000;
209 | cursor: pointer;
210 | margin-right: 10px;
211 | }
212 |
213 | .footer .fa-share:before {
214 | content: "\f064";
215 | margin-right: 10px;
216 | color: #000000;
217 | cursor: pointer;
218 | font-size: 15px;
219 | }
220 |
221 | .footer .fa-download:before {
222 | margin-right: 10px;
223 | color: #000000;
224 | cursor: pointer;
225 | font-size: 15px;
226 | }
227 |
228 | .footer .fa-volume-up:before {
229 | margin-right: 10px;
230 | color: #000000;
231 | cursor: pointer;
232 | font-size: 15px;
233 | }
234 |
235 | .search {
236 | display: flex;
237 | align-items: center;
238 | color: rgb(0, 0, 0);
239 | background-color: #ffffff;
240 | border: solid 2px #ffffff66;
241 | border-radius: 9px;
242 | padding: 5px 10px;
243 | gap: 0.4rem;
244 | width: 60%;
245 | transition: colors 0.3s ease, width 0.6s ease;
246 | }
247 |
248 | .search:focus-within {
249 | border: solid 2px #ffffff;
250 | caret-color: #ffffff;
251 | width: 75%;
252 | }
253 |
254 | .search input {
255 | border: none;
256 | background-color: white;
257 | width: 100%;
258 | }
259 |
260 | .search input::placeholder {
261 | color: #202020e4;
262 | transition: all 0.3s ease;
263 | }
264 |
265 | .search input:focus::placeholder {
266 | color: #000000;
267 | }
268 |
269 | .search input:focus {
270 | outline: none;
271 | }
272 |
273 | /* Style for header */
274 |
275 | .header {
276 | display: flex;
277 | flex-direction: row;
278 | justify-content: space-between;
279 | align-items: center;
280 |
281 | background-image: linear-gradient(139deg, #ff4b01, #ee7703, #ff4b01, #ee7703);
282 | margin-bottom: 1em;
283 | padding: 9px 15px;
284 | box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px;
285 | position: sticky;
286 | top: 0;
287 | z-index: 100;
288 | width: 100%;
289 | overflow: hidden;
290 | }
291 |
292 | .header-dark {
293 | display: flex;
294 | flex-direction: row;
295 | justify-content: space-between;
296 | align-items: center;
297 | background-image: linear-gradient(139deg, #000a1f, #000000, #060025, #0b0d1f);
298 | margin-bottom: 1em;
299 | padding: 9px 15px;
300 | box-shadow: rgba(202, 197, 197, 0.24) 0px 0px 8px;
301 | color: white;
302 | position: sticky;
303 | top: 0;
304 | z-index: 100;
305 | width: 100%;
306 | overflow: hidden;
307 | }
308 |
309 | .header>.header-top {
310 | display: flex;
311 | flex-direction: row;
312 | justify-content: space-between;
313 | align-items: center;
314 | width: 100%;
315 | }
316 |
317 | .header-dark>.header-top {
318 | display: flex;
319 | flex-direction: row;
320 | justify-content: space-between;
321 | align-items: center;
322 | width: 100%;
323 | }
324 |
325 | .header h1 {
326 | font-size: 25px;
327 | }
328 |
329 | .header-dark h1 {
330 | font-size: 25px;
331 | }
332 |
333 | /* The switch - the box around the slider */
334 | .switch {
335 | position: relative;
336 | display: inline-block;
337 | width: 50px;
338 | height: 25px;
339 | }
340 |
341 | /* Hide default HTML checkbox */
342 | .switch input {
343 | opacity: 0;
344 | width: 0;
345 | height: 0;
346 | }
347 |
348 | /* The slider */
349 | .slider {
350 | position: absolute;
351 | cursor: pointer;
352 | top: 0;
353 | left: 0;
354 | right: 0;
355 | bottom: 0;
356 | background-color: #ccc;
357 | -webkit-transition: 0.4s;
358 | transition: 0.4s;
359 | }
360 |
361 | .slider:before {
362 | position: absolute;
363 | content: "";
364 | height: 18px;
365 | width: 18px;
366 | left: 4px;
367 | bottom: 4px;
368 | background-color: white;
369 | -webkit-transition: 0.4s;
370 | transition: 0.4s;
371 | }
372 |
373 | input:checked+.slider {
374 | background-color: #2196f3;
375 | }
376 |
377 | input:focus+.slider {
378 | box-shadow: 0 0 1px #2196f3;
379 | }
380 |
381 | input:checked+.slider:before {
382 | -webkit-transform: translateX(26px);
383 | -ms-transform: translateX(26px);
384 | transform: translateX(26px);
385 | }
386 |
387 | /* Rounded sliders */
388 | .slider.round {
389 | border-radius: 34px;
390 | }
391 |
392 | .slider.round:before {
393 | border-radius: 50%;
394 | }
395 |
396 | /* start style for dark mode */
397 | /* .dark-mode {
398 | background-color: #000000;
399 | } */
400 |
401 | .dark-mode h1 {
402 | color: #fff;
403 | }
404 |
405 | .dark-mode h3 {
406 | color: #fff;
407 | }
408 |
409 | /* end style for dark mode */
410 |
411 | .header-left {
412 | display: flex;
413 | flex-direction: row;
414 | align-items: center;
415 | gap: 2rem;
416 | width: auto;
417 | }
418 |
419 | .header-right {
420 | display: flex;
421 | flex-direction: row;
422 | gap: 2rem;
423 | align-items: center;
424 | justify-content: flex-end;
425 | width: 40%;
426 | }
427 |
428 | .sm-show {
429 | display: none;
430 | }
431 |
432 | /* Start style for responsive */
433 | @media screen and (max-width: 768px) {
434 | .header {
435 | display: flex;
436 | flex-direction: column;
437 | gap: 0.5rem;
438 | padding-top: 0;
439 | }
440 |
441 | .header-dark {
442 | display: flex;
443 | flex-direction: column;
444 | gap: 0.5rem;
445 | padding-top: 0;
446 | }
447 |
448 | .header>.header-top {
449 | display: flex;
450 | flex-direction: row;
451 | justify-content: space-between;
452 | align-items: center;
453 | width: 100%;
454 | }
455 |
456 | .header-dark>.header-top {
457 | display: flex;
458 | flex-direction: row;
459 | justify-content: space-between;
460 | align-items: center;
461 | width: 100%;
462 | }
463 |
464 | .search {
465 | width: 80%;
466 | }
467 |
468 | .search:focus-within {
469 | width: 100%;
470 | }
471 |
472 | .sm-hide {
473 | display: none;
474 | }
475 |
476 | .sm-show {
477 | display: flex;
478 | }
479 | }
480 |
481 | /* End style for responsive */
482 |
483 | ::-webkit-scrollbar {
484 | width: 3px;
485 | }
486 |
487 | ::-webkit-scrollbar-thumb {
488 | border-radius: 1px;
489 | -webkit-box-shadow: inset 12px 0 16px #f36b03;
490 | }
491 |
492 | ::-webkit-scrollbar-track {
493 | -webkit-box-shadow: initial 0 0 6px #8e8e8e;
494 | border-radius: 1px;
495 | }
--------------------------------------------------------------------------------