├── .eslintrc.cjs ├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public └── vite.svg ├── src ├── App.jsx ├── Layout.css ├── Layout.jsx ├── assets │ └── react.svg ├── components │ ├── accordions │ │ ├── ImageAccordion │ │ │ ├── ImageAccordion.jsx │ │ │ └── styles.css │ │ ├── ImageAccordionExample │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.jpg │ │ │ ├── ImageAccordionExample.jsx │ │ │ └── styles.css │ │ └── index.js │ ├── buttons │ │ ├── DeleteButton │ │ │ ├── DeleteButton.jsx │ │ │ └── styles.css │ │ ├── FabButton │ │ │ ├── FabButton.css │ │ │ └── FabButton.jsx │ │ ├── TrashButton │ │ │ ├── TrashButton.css │ │ │ ├── TrashButton.jsx │ │ │ ├── paper.svg │ │ │ └── shredded.svg │ │ └── index.js │ ├── cards │ │ ├── Card1 │ │ │ ├── Card1.jsx │ │ │ └── styles.css │ │ ├── Card2 │ │ │ ├── Card2.css │ │ │ ├── Card2.jsx │ │ │ ├── Card2Example.jsx │ │ │ └── image.jpg │ │ ├── Card3 │ │ │ ├── Card3.css │ │ │ ├── Card3.jsx │ │ │ ├── Card3Example.css │ │ │ ├── Card3Example.jsx │ │ │ ├── avatar.png │ │ │ └── logo.svg │ │ └── index.js │ ├── carousels │ │ ├── Carousel1 │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── Carousel1.jsx │ │ │ └── styles.css │ │ ├── Carousel2 │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ ├── 3.jpg │ │ │ ├── 4.jpg │ │ │ ├── 5.jpg │ │ │ ├── 6.jpg │ │ │ ├── 7.jpg │ │ │ ├── 8.jpg │ │ │ ├── 9.jpg │ │ │ ├── Carousel2.jsx │ │ │ └── styles.css │ │ └── index.js │ ├── controls │ │ ├── AutoSuggest │ │ │ ├── AutoSuggest.jsx │ │ │ ├── Joegle.svg │ │ │ └── styles.css │ │ ├── EditableText │ │ │ ├── EditableText.css │ │ │ ├── EditableText.jsx │ │ │ ├── EditableTextExample.css │ │ │ ├── EditableTextExample.jsx │ │ │ └── image.jpg │ │ ├── PasswordStrength │ │ │ ├── PasswordStrength.jsx │ │ │ ├── logo.svg │ │ │ └── styles.css │ │ ├── PasswordVisibility │ │ │ ├── Password.css │ │ │ ├── Password.jsx │ │ │ ├── PasswordVisibilityExample.css │ │ │ ├── PasswordVisibilityExample.jsx │ │ │ └── bg.svg │ │ └── index.js │ ├── dropdowns │ │ ├── Dropdown1 │ │ │ ├── Dropdown1.css │ │ │ ├── Dropdown1.jsx │ │ │ └── Dropdown1Example.jsx │ │ ├── Dropdown2 │ │ │ ├── Dropdown2.css │ │ │ ├── Dropdown2.jsx │ │ │ ├── Dropdown2Example.css │ │ │ ├── Dropdown2Example.jsx │ │ │ ├── icons.png │ │ │ ├── joe.png │ │ │ └── logo.svg │ │ ├── Dropdown3 │ │ │ ├── Dropdown3.css │ │ │ └── Dropdown3.jsx │ │ ├── Dropdown4 │ │ │ ├── Dropdown4.css │ │ │ ├── Dropdown4.jsx │ │ │ ├── Dropdown4Example.css │ │ │ └── Dropdown4Example.jsx │ │ └── index.js │ ├── gsap │ │ ├── ScrollReveal │ │ │ ├── ScrollReveal.jsx │ │ │ └── styles.css │ │ ├── TypedMessage │ │ │ ├── TypedMessage.css │ │ │ ├── TypedMessage.jsx │ │ │ ├── TypedMessageExample.css │ │ │ ├── TypedMessageExample.jsx │ │ │ ├── image.jpg │ │ │ ├── logo.svg │ │ │ └── video.mp4 │ │ └── index.js │ ├── index.js │ ├── libraries │ │ ├── index.js │ │ ├── rc-slider │ │ │ ├── RcSlider.css │ │ │ └── RcSlider.jsx │ │ ├── react-dropzone │ │ │ ├── ReactDropzone.css │ │ │ ├── ReactDropzone.jsx │ │ │ └── icon.svg │ │ └── react-xarrows │ │ │ ├── ReactXarrows.css │ │ │ └── ReactXarrows.jsx │ ├── logins │ │ ├── Login1 │ │ │ ├── Login1.jsx │ │ │ ├── logo.svg │ │ │ └── styles.css │ │ └── index.js │ ├── modals │ │ ├── Modal1 │ │ │ ├── Modal1.jsx │ │ │ ├── logo.svg │ │ │ └── styles.css │ │ ├── Modal2 │ │ │ ├── Modal2 copy.css │ │ │ ├── Modal2.css │ │ │ ├── Modal2.jsx │ │ │ ├── Modal2Example.css │ │ │ ├── Modal2Example.jsx │ │ │ └── logo.svg │ │ └── index.js │ ├── navbars │ │ ├── Navbar1 │ │ │ ├── 1.svg │ │ │ ├── 2.svg │ │ │ ├── 3.svg │ │ │ ├── 4.svg │ │ │ ├── 5.svg │ │ │ ├── 6.svg │ │ │ ├── Navbar1.css │ │ │ └── Navbar1.jsx │ │ ├── Navbar2 │ │ │ ├── Navbar2.css │ │ │ └── Navbar2.jsx │ │ ├── Navbar3 │ │ │ ├── Navbar3.css │ │ │ ├── Navbar3.jsx │ │ │ └── avatar.png │ │ └── index.js │ ├── parallax │ │ ├── index.js │ │ └── parallax-1 │ │ │ ├── Parallax1.jsx │ │ │ ├── bg.png │ │ │ └── styles.css │ ├── sidebars │ │ ├── Sidebar1 │ │ │ ├── Sidebar1.jsx │ │ │ └── styles.css │ │ ├── Sidebar2 │ │ │ ├── Sidebar2.jsx │ │ │ ├── logo.svg │ │ │ └── styles.css │ │ ├── Sidebar3 │ │ │ ├── Sidebar3.jsx │ │ │ ├── bg.jpeg │ │ │ ├── logo.svg │ │ │ └── styles.css │ │ ├── Sidebar4 │ │ │ ├── Sidebar4.css │ │ │ ├── Sidebar4.jsx │ │ │ └── logo.png │ │ ├── Sidebar5 │ │ │ ├── Sidebar5.css │ │ │ ├── Sidebar5.jsx │ │ │ └── logo.svg │ │ ├── Sidebar6 │ │ │ ├── Sidebar6.css │ │ │ ├── Sidebar6.jsx │ │ │ └── logo.svg │ │ ├── Sidebar7 │ │ │ ├── Sidebar7.jsx │ │ │ ├── logo.svg │ │ │ └── styles.css │ │ ├── Sidebar8 │ │ │ ├── Sidebar8 copy.css │ │ │ ├── Sidebar8.css │ │ │ ├── Sidebar8.jsx │ │ │ └── logo.svg │ │ └── index.js │ ├── signups │ │ └── index.js │ ├── tables │ │ ├── Table1 │ │ │ ├── Table1.css │ │ │ ├── Table1.jsx │ │ │ ├── Table1Example.css │ │ │ ├── Table1Example.jsx │ │ │ ├── bg.svg │ │ │ └── logo.svg │ │ ├── Table2 │ │ │ ├── Table2.css │ │ │ ├── Table2.jsx │ │ │ ├── Table2Example.css │ │ │ └── Table2Example.jsx │ │ ├── Table3 │ │ │ ├── Table3.css │ │ │ ├── Table3.jsx │ │ │ ├── Table3Example.css │ │ │ ├── Table3Example.jsx │ │ │ └── image.svg │ │ └── index.js │ └── widgets │ │ ├── Widget1 │ │ ├── Widget1.jsx │ │ └── styles.css │ │ ├── Widget2 │ │ ├── Widget2.jsx │ │ ├── styles copy.css │ │ └── styles.css │ │ └── index.js ├── index.css ├── main.jsx └── routes.jsx ├── vite.config.js └── yarn.lock /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:react/recommended', 7 | 'plugin:react/jsx-runtime', 8 | 'plugin:react-hooks/recommended', 9 | ], 10 | ignorePatterns: ['dist', '.eslintrc.cjs'], 11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, 12 | settings: { react: { version: '18.2' } }, 13 | plugins: ['react-refresh'], 14 | rules: { 15 | 'react-refresh/only-export-components': [ 16 | 'warn', 17 | { allowConstantExport: true }, 18 | ], 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React Components 8 | 9 | 10 | 11 | 15 | 19 | 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-components", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite --open", 8 | "build": "vite build", 9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@gsap/react": "^2.1.0", 14 | "framer-motion": "^11.0.18", 15 | "gsap": "^3.13.0", 16 | "rc-slider": "^10.6.2", 17 | "react": "^18.2.0", 18 | "react-dom": "^18.2.0", 19 | "react-draggable": "^4.4.6", 20 | "react-dropzone": "^14.3.5", 21 | "react-router-dom": "^6.22.3", 22 | "react-toastify": "^11.0.5", 23 | "react-xarrows": "^2.0.2", 24 | "swiper": "^11.1.4" 25 | }, 26 | "devDependencies": { 27 | "@types/react": "^18.2.43", 28 | "@types/react-dom": "^18.2.17", 29 | "@vitejs/plugin-react": "^4.2.1", 30 | "eslint": "^8.55.0", 31 | "eslint-plugin-react": "^7.33.2", 32 | "eslint-plugin-react-hooks": "^4.6.0", 33 | "eslint-plugin-react-refresh": "^0.4.5", 34 | "vite": "^5.0.8" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import { createBrowserRouter, RouterProvider } from "react-router-dom"; 2 | import { Layout } from "./Layout"; 3 | import { routes } from "./routes"; 4 | 5 | const router = createBrowserRouter([ 6 | { 7 | path: "/", 8 | element: , 9 | }, 10 | ...routes, 11 | ]); 12 | 13 | function App() { 14 | return ; 15 | } 16 | 17 | export default App; 18 | -------------------------------------------------------------------------------- /src/Layout.jsx: -------------------------------------------------------------------------------- 1 | import { Link, useNavigate } from "react-router-dom"; 2 | import { routes } from "./routes"; 3 | import "./Layout.css"; 4 | 5 | export const Layout = () => { 6 | const sortedRoutes = routes.sort((a, b) => a.name.localeCompare(b.name)); 7 | 8 | const navigate = useNavigate(); 9 | 10 | return ( 11 |
12 |
13 |
14 |

15 | {/* */} 16 | React Components 17 |

18 | 30 |
31 |
32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | {sortedRoutes.map((route) => ( 42 | navigate(route.path)} key={route.path}> 43 | 46 | 47 | ))} 48 | 49 |
Name
44 | {route.name} 45 |
50 |
51 |
52 |
53 | ); 54 | }; 55 | -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordion/ImageAccordion.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./styles.css"; 3 | 4 | export const ImageAccordion = ({ items }) => { 5 | const [active, setActive] = useState(0); 6 | 7 | const handleToggle = (index) => setActive(index); 8 | 9 | return ( 10 |
11 | {items.map((item, index) => { 12 | const isActive = active === index ? "active" : ""; 13 | return ( 14 |
handleToggle(index)} 18 | > 19 | 20 |
21 | photo_camera 22 |
23 |

{item.header}

24 |

{item.text}

25 |
26 |
27 |
28 | ); 29 | })} 30 |
31 | ); 32 | }; 33 | -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordion/styles.css: -------------------------------------------------------------------------------- 1 | .image-accordion { 2 | display: flex; 3 | gap: 10px; 4 | cursor: pointer; 5 | } 6 | 7 | .image-accordion-item { 8 | position: relative; 9 | overflow: hidden; 10 | width: 64px; 11 | height: 500px; 12 | border-radius: 36px; 13 | display: flex; 14 | align-items: flex-end; 15 | opacity: 0.5; 16 | transition: 0.5s; 17 | } 18 | 19 | .image-accordion-item:hover { 20 | opacity: 0.75; 21 | } 22 | 23 | .image-accordion :is(h2, p) { 24 | margin: 0; 25 | } 26 | 27 | .image-accordion-item h2 { 28 | font-size: 24px; 29 | font-weight: 400; 30 | color: rgb(255 255 255 / 96%); 31 | } 32 | 33 | .image-accordion-item p { 34 | color: rgb(255 255 255 / 66%); 35 | } 36 | 37 | .image-accordion-item.active { 38 | width: 400px; 39 | opacity: 1; 40 | } 41 | 42 | .image-accordion-item .material-symbols-outlined { 43 | display: grid; 44 | place-items: center; 45 | width: 50px; 46 | height: 50px; 47 | color: rgb(0 0 0 / 80%); 48 | background: rgb(255 255 255 / 70%); 49 | border-radius: 50%; 50 | font-size: 28px; 51 | } 52 | 53 | .image-accordion-item .content { 54 | position: absolute; 55 | bottom: 0; 56 | left: 0; 57 | width: 400px; 58 | z-index: 1; 59 | opacity: 0; 60 | visibility: hidden; 61 | padding: 100px 0 20px 20px; 62 | display: flex; 63 | align-items: center; 64 | gap: 14px; 65 | background: linear-gradient(to bottom, rgb(0 0 0 / 0%), rgb(0 0 0 / 80%)); 66 | transition: 0.25s; 67 | } 68 | 69 | .image-accordion-item.active .content { 70 | opacity: 1; 71 | visibility: visible; 72 | } 73 | 74 | .image-accordion-item img { 75 | position: absolute; 76 | z-index: 0; 77 | top: 50%; 78 | left: 50%; 79 | translate: -50% -50%; 80 | height: 150%; 81 | filter: grayscale(0.6); 82 | } 83 | -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/accordions/ImageAccordionExample/1.jpg -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/accordions/ImageAccordionExample/2.jpg -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/accordions/ImageAccordionExample/3.jpg -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/accordions/ImageAccordionExample/4.jpg -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/accordions/ImageAccordionExample/5.jpg -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/accordions/ImageAccordionExample/6.jpg -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/ImageAccordionExample.jsx: -------------------------------------------------------------------------------- 1 | import { ImageAccordion } from "../ImageAccordion/ImageAccordion"; 2 | import image1 from "./6.jpg"; 3 | import image2 from "./2.jpg"; 4 | import image3 from "./3.jpg"; 5 | import image4 from "./4.jpg"; 6 | import image5 from "./5.jpg"; 7 | 8 | const coolImages = [ 9 | { 10 | header: "Canada", 11 | image: image2, 12 | text: `Image description`, 13 | }, 14 | 15 | { 16 | header: "New Zealand", 17 | image: image1, 18 | text: `Image description`, 19 | }, 20 | 21 | { 22 | header: "Indonesia", 23 | image: image4, 24 | text: `Image description`, 25 | }, 26 | { 27 | header: "South Africa", 28 | image: image5, 29 | text: `Image description`, 30 | }, 31 | { 32 | header: "Spain", 33 | image: image3, 34 | text: `Image description`, 35 | }, 36 | ]; 37 | 38 | export const ImageAccordionExample = () => ( 39 |
40 | 41 |
42 | ); 43 | -------------------------------------------------------------------------------- /src/components/accordions/ImageAccordionExample/styles.css: -------------------------------------------------------------------------------- 1 | .page.image-accordion-page { 2 | background: #141415; 3 | } 4 | -------------------------------------------------------------------------------- /src/components/accordions/index.js: -------------------------------------------------------------------------------- 1 | export * from "./ImageAccordion/ImageAccordion"; 2 | export * from "./ImageAccordionExample/ImageAccordionExample"; 3 | -------------------------------------------------------------------------------- /src/components/buttons/DeleteButton/DeleteButton.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./styles.css"; 3 | 4 | export const DeleteButton = () => { 5 | const [isDeleting, setIsDeleting] = useState(false); 6 | const [isDeleted, setIsDeleted] = useState(false); 7 | 8 | const handleClick = () => { 9 | setIsDeleting(true); 10 | // do something async 11 | setTimeout(() => { 12 | setIsDeleting(false); 13 | setIsDeleted(true); 14 | setTimeout(() => { 15 | setIsDeleted(false); 16 | }, 1250); 17 | }, 2500); 18 | }; 19 | 20 | return ( 21 |
22 | 38 |
39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/components/buttons/DeleteButton/styles.css: -------------------------------------------------------------------------------- 1 | .page-wrapper { 2 | background: #000; 3 | } 4 | 5 | .delete-button { 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | border-radius: 10px; 10 | border: 0; 11 | background: #fc3b51; 12 | font-size: 24px; 13 | font-weight: 400; 14 | font-family: "Euclid Circular A"; 15 | color: #f9f9f9; 16 | padding: 0 10px 0 32px; 17 | height: 74px; 18 | text-align: left; 19 | cursor: pointer; 20 | outline: none; 21 | transition: 0.3s; 22 | } 23 | 24 | .delete-button .button-text { 25 | display: block; 26 | text-align: center; 27 | min-width: 94px; 28 | } 29 | 30 | .delete-button .animation { 31 | position: relative; 32 | overflow: hidden; 33 | display: grid; 34 | place-items: center; 35 | width: 64px; 36 | height: 74px; 37 | flex: 0 0 64px; 38 | min-width: 0; 39 | } 40 | 41 | .delete-button .can { 42 | overflow: hidden; 43 | position: relative; 44 | translate: 0 2px; 45 | width: 20px; 46 | height: 22px; 47 | border-bottom-left-radius: 5px; 48 | border-bottom-right-radius: 5px; 49 | border: 2px solid #ffffff; 50 | border-top: 0; 51 | } 52 | 53 | @keyframes lid-open { 54 | 0% { 55 | rotate: 0; 56 | } 57 | 15%, 58 | 90% { 59 | rotate: -75deg; 60 | translate: -70% -20%; 61 | width: 20px; 62 | } 63 | } 64 | 65 | .delete-button .lid { 66 | position: absolute; 67 | top: 24px; 68 | left: 50%; 69 | translate: -50% 0; 70 | transform-origin: 0% 0%; 71 | width: 24px; 72 | height: 2px; 73 | background: #ffffff; 74 | } 75 | 76 | @keyframes balls-drop { 77 | 0%, 78 | 20% { 79 | translate: -50% 0; 80 | } 81 | 40% { 82 | scale: 1 1; 83 | } 84 | 40%, 85 | 100% { 86 | translate: -50% 72px; 87 | } 88 | 89 | 50%, 90 | 100% { 91 | scale: 2.1 1; 92 | } 93 | } 94 | 95 | .delete-button .balls { 96 | position: absolute; 97 | top: -32px; 98 | left: 50%; 99 | translate: -50% 0; 100 | width: 9px; 101 | height: 9px; 102 | border-radius: 50%; 103 | background: #ffffff; 104 | } 105 | 106 | @keyframes fill { 107 | 0%, 108 | 20% { 109 | translate: 0 0; 110 | } 111 | 50%, 112 | 70% { 113 | translate: 0 -50%; 114 | } 115 | 90%, 116 | 100% { 117 | translate: 0 -100%; 118 | } 119 | } 120 | 121 | .delete-button .filler { 122 | position: absolute; 123 | top: 100%; 124 | left: 50%; 125 | margin-left: -32px; 126 | width: 64px; 127 | height: 120%; 128 | background: #ffffff; 129 | } 130 | 131 | .delete-button:disabled { 132 | cursor: not-allowed; 133 | } 134 | 135 | .delete-button.deleting .balls { 136 | animation: balls-drop 2 linear 1.25s; 137 | } 138 | 139 | .delete-button.deleting .filler { 140 | animation: fill 2.5s both; 141 | } 142 | 143 | .delete-button.deleting .lid { 144 | animation: lid-open 2.5s both; 145 | } 146 | -------------------------------------------------------------------------------- /src/components/buttons/FabButton/FabButton.css: -------------------------------------------------------------------------------- 1 | .page.fab-button-page { 2 | background: #16151b; 3 | } 4 | 5 | .fab { 6 | position: fixed; 7 | right: 30px; 8 | bottom: 38px; 9 | border-radius: 50%; 10 | box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); 11 | } 12 | 13 | .fab button { 14 | cursor: pointer; 15 | border: 0; 16 | background: transparent; 17 | } 18 | 19 | .fab > button { 20 | position: relative; 21 | z-index: 1; 22 | display: grid; 23 | place-items: center; 24 | width: 64px; 25 | height: 64px; 26 | border-radius: 50%; 27 | border: 0; 28 | background: #e952de; 29 | border: 0; 30 | color: #f9f9f9; 31 | transition: 0.2s; 32 | rotate: 0deg; 33 | } 34 | 35 | .fab > button > span { 36 | font-size: 36px; 37 | } 38 | 39 | .fab-menu { 40 | position: absolute; 41 | z-index: 0; 42 | top: 50%; 43 | left: 50%; 44 | width: 360px; 45 | height: 360px; 46 | translate: -50% -50%; 47 | border: 80px solid #282633; 48 | border-radius: 50%; 49 | rotate: -220deg; 50 | scale: 0.7; 51 | opacity: 0; 52 | transition: 0.4s ease-out; 53 | } 54 | 55 | .fab.open > button { 56 | rotate: 45deg; 57 | } 58 | 59 | .fab.open .fab-menu { 60 | rotate: 0deg; 61 | scale: 1; 62 | opacity: 1; 63 | } 64 | 65 | .fab-menu > button { 66 | position: absolute; 67 | color: #e0e0e0; 68 | transition: 0.4s; 69 | } 70 | 71 | .fab-menu > button:hover { 72 | scale: 1.2; 73 | color: #f9f9f9; 74 | } 75 | 76 | .fab .material-symbols-outlined { 77 | font-size: 36px; 78 | } 79 | 80 | .fab-menu > button:nth-child(1) { 81 | left: 78px; 82 | top: -58px; 83 | } 84 | 85 | .fab-menu > button:nth-child(2) { 86 | left: -16px; 87 | top: -16px; 88 | } 89 | 90 | .fab-menu > button:nth-child(3) { 91 | left: -58px; 92 | top: 78px; 93 | } 94 | -------------------------------------------------------------------------------- /src/components/buttons/FabButton/FabButton.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./FabButton.css"; 3 | 4 | const Icon = ({ children }) => ( 5 | {children} 6 | ); 7 | 8 | export const FabButton = () => { 9 | const [isOpen, setIsOpen] = useState(false); 10 | 11 | return ( 12 |
13 |
14 | 17 |
18 | 21 | 24 | 27 |
28 |
29 |
30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/components/buttons/TrashButton/TrashButton.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./TrashButton.css"; 3 | import paper from "./paper.svg"; 4 | import shredded from "./shredded.svg"; 5 | 6 | export const TrashButton = () => { 7 | const [isDeleting, setIsDeleting] = useState(false); 8 | 9 | const handleClick = () => { 10 | setIsDeleting(true); 11 | // do something async 12 | setTimeout(() => { 13 | setIsDeleting(false); 14 | }, 2500); 15 | }; 16 | 17 | return ( 18 |
19 | 39 |
40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /src/components/buttons/TrashButton/paper.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/buttons/TrashButton/shredded.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/components/buttons/index.js: -------------------------------------------------------------------------------- 1 | export * from "./DeleteButton/DeleteButton"; 2 | export * from "./TrashButton/TrashButton"; 3 | export * from "./FabButton/FabButton"; 4 | -------------------------------------------------------------------------------- /src/components/cards/Card1/Card1.jsx: -------------------------------------------------------------------------------- 1 | import "./styles.css"; 2 | 3 | const cards = [ 4 | { 5 | name: "summary", 6 | total: 21, 7 | description: "Due Tasks", 8 | footer: "Completed: 13", 9 | more: "More Information", 10 | }, 11 | { 12 | name: "overdue", 13 | total: 17, 14 | description: "Projects", 15 | footer: "Yesterday: 9", 16 | more: "More Information", 17 | }, 18 | { 19 | name: "features", 20 | total: 38, 21 | description: "Proposals", 22 | footer: "Implemented: 6", 23 | more: "More Information", 24 | }, 25 | ]; 26 | 27 | export const Card1 = () => { 28 | return ( 29 |
30 |
31 | {cards.map((card) => ( 32 | 53 | ))} 54 |
55 |
56 | ); 57 | }; 58 | -------------------------------------------------------------------------------- /src/components/cards/Card1/styles.css: -------------------------------------------------------------------------------- 1 | .page.card-1-page { 2 | margin: 0; 3 | height: 100vh; 4 | display: grid; 5 | place-items: center; 6 | color: #f7f7f7; 7 | background: #121212; 8 | font-family: "Euclid Circular A", "Poppins"; 9 | } 10 | 11 | .card-1-page h2, 12 | .card-1-page h3, 13 | .card-1-page h4 { 14 | margin: 0; 15 | font-weight: 500; 16 | } 17 | 18 | .card-1-page .cards { 19 | display: flex; 20 | gap: 30px; 21 | } 22 | 23 | .card-1-page .card { 24 | position: relative; 25 | perspective: 1000px; 26 | width: 300px; 27 | height: 300px; 28 | } 29 | 30 | .card-1-page .card header { 31 | display: flex; 32 | justify-content: space-between; 33 | align-items: center; 34 | height: 40px; 35 | margin-bottom: 26px; 36 | } 37 | 38 | .card-1-page .card header h2 { 39 | font-size: 20px; 40 | text-transform: capitalize; 41 | } 42 | 43 | .card-1-page .card .front, 44 | .card-1-page .card .back { 45 | position: absolute; 46 | top: 0; 47 | left: 0; 48 | right: 0; 49 | bottom: 0; 50 | backface-visibility: hidden; 51 | background: #1e1e1e; 52 | border-radius: 10px; 53 | padding: 36px 36px 44px 44px; 54 | transition: 0.6s; 55 | cursor: pointer; 56 | } 57 | 58 | .card-1-page .back { 59 | transform: rotateY(180deg); 60 | } 61 | 62 | .card-1-page input { 63 | position: absolute; 64 | scale: 0; 65 | } 66 | 67 | .card-1-page input:checked ~ .card .back { 68 | transform: rotateY(0); 69 | } 70 | 71 | .card-1-page input:checked ~ .card .front { 72 | transform: rotateY(-180deg); 73 | } 74 | 75 | .card-1-page .card var { 76 | font-style: normal; 77 | font-size: 80px; 78 | line-height: 1; 79 | } 80 | 81 | .card-1-page .card h3 { 82 | margin: 0 0 30px; 83 | font-weight: 500; 84 | } 85 | 86 | .card-1-page #summary :is(var, h3) { 87 | color: #3b82f6; 88 | } 89 | 90 | .card-1-page #overdue :is(var, h3) { 91 | color: #e56363; 92 | } 93 | 94 | .card-1-page #features :is(var, h3) { 95 | color: #25b697; 96 | } 97 | 98 | .card-1-page .card :is(h4, p) { 99 | opacity: 0.6; 100 | font-size: 20px; 101 | } 102 | 103 | .card-1-page .card p { 104 | margin-top: 76px; 105 | } 106 | -------------------------------------------------------------------------------- /src/components/cards/Card2/Card2.css: -------------------------------------------------------------------------------- 1 | .page.card-2-example-page { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | margin: 0; 6 | height: 100vh; 7 | background: linear-gradient(45deg, #0cd2d1, #0857c0); 8 | color: #fdfcfd; 9 | font-family: "Euclid Circular A", "Poppins"; 10 | } 11 | 12 | .card-2 { 13 | display: flex; 14 | align-items: center; 15 | width: 75vw; 16 | max-width: 650px; 17 | padding: 50px 30px 50px 20px; 18 | background: #121017; 19 | border-radius: 24px; 20 | box-shadow: 0 80px 60px rgb(0 0 0 / 12%); 21 | } 22 | 23 | .card-2 img { 24 | max-width: 280px; 25 | width: 32vw; 26 | height: 300px; 27 | object-fit: cover; 28 | margin-left: -60px; 29 | margin-right: 30px; 30 | border-radius: inherit; 31 | box-shadow: 0 60px 40px rgb(0 0 0 / 12%); 32 | transition: border-radius 0.3s; 33 | } 34 | 35 | .card-2 h2 { 36 | font-size: 26px; 37 | font-weight: 400; 38 | margin-top: 0; 39 | margin-right: 30px; 40 | margin-bottom: 6px; 41 | } 42 | 43 | .card-2 h3 { 44 | font-size: 16px; 45 | font-weight: 400; 46 | margin: 0 0 12px; 47 | opacity: 0.66; 48 | } 49 | 50 | .card-2 p { 51 | font-size: 14px; 52 | font-weight: 400; 53 | margin-bottom: 30px; 54 | opacity: 0.42; 55 | } 56 | 57 | .card-2 .buttons { 58 | display: flex; 59 | gap: 12px; 60 | } 61 | 62 | .card-2 button { 63 | border: 1px solid #f8f8f8; 64 | background: transparent; 65 | color: #f8f8f8; 66 | width: 40%; 67 | min-width: 100px; 68 | text-align: center; 69 | font-family: inherit; 70 | padding: 12px 26px; 71 | font-size: 16px; 72 | border-radius: 40px; 73 | } 74 | 75 | .card-2 button.primary { 76 | background: #ffffff; 77 | color: #121017; 78 | } 79 | 80 | @media (width <= 600px) { 81 | .card-2 { 82 | margin: 0 40px; 83 | padding-left: 50px; 84 | padding-right: 50px; 85 | padding-bottom: 60px; 86 | width: 100%; 87 | text-align: center; 88 | flex-direction: column; 89 | } 90 | 91 | .card-2 .buttons { 92 | justify-content: center; 93 | } 94 | 95 | .card-2 .buttons button { 96 | width: 50%; 97 | } 98 | 99 | .card-2 h2 { 100 | margin-right: 0; 101 | font-size: 26px; 102 | } 103 | 104 | .card-2 img { 105 | margin: -100px 0 30px 0; 106 | width: 100%; 107 | max-width: 1000px; 108 | height: 250px; 109 | } 110 | 111 | .card-2 p { 112 | max-width: 400px; 113 | } 114 | } 115 | 116 | @media (width <= 420px) { 117 | .card-2 img { 118 | height: 50vw; 119 | width: 50vw; 120 | border-radius: 50%; 121 | margin: -140px 0 30px 0; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/components/cards/Card2/Card2.jsx: -------------------------------------------------------------------------------- 1 | import "./Card2.css"; 2 | 3 | export const Card2 = ({ 4 | image, 5 | title, 6 | subtitle, 7 | description, 8 | onProfile, 9 | onFollow, 10 | }) => ( 11 |
12 | 13 |
14 |

{title}

15 |

{subtitle}

16 |

{description}

17 |
18 | 19 | 22 |
23 |
24 |
25 | ); 26 | -------------------------------------------------------------------------------- /src/components/cards/Card2/Card2Example.jsx: -------------------------------------------------------------------------------- 1 | import { Card2 } from "./Card2"; 2 | import image from "./image.jpg"; 3 | 4 | export const Card2Example = () => { 5 | const handleProfile = () => { 6 | // goto profile 7 | }; 8 | 9 | const handleFollow = () => { 10 | // follow account 11 | }; 12 | 13 | return ( 14 |
15 | 23 |
24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/components/cards/Card2/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/cards/Card2/image.jpg -------------------------------------------------------------------------------- /src/components/cards/Card3/Card3.css: -------------------------------------------------------------------------------- 1 | .card-3 { 2 | --color-primary: #356aff; 3 | --color-muted: #9895a2; 4 | --color-highlight: #242328; 5 | --border: 1px solid #2f2e32; 6 | position: relative; 7 | border-radius: 24px; 8 | width: clamp(200px, 80vw, 500px); 9 | padding-top: 30px; 10 | background: #1c1b20; 11 | } 12 | 13 | .card-3 > img { 14 | position: absolute; 15 | top: 0; 16 | left: 50%; 17 | translate: -50% -50%; 18 | width: 92px; 19 | aspect-ratio: 1/1; 20 | border-radius: 50%; 21 | background: var(--color-highlight); 22 | padding: 20px; 23 | box-shadow: 0 20px 150px rgb(0 0 0 / 8%); 24 | } 25 | 26 | .card-3 .main { 27 | padding: 24px 24px 0; 28 | display: flex; 29 | flex-direction: column; 30 | justify-content: center; 31 | text-align: center; 32 | } 33 | 34 | .card-3 :is(h2, h3, h4, h5) { 35 | font-weight: 400; 36 | margin: 0; 37 | } 38 | 39 | .card-3 em { 40 | font-style: normal; 41 | color: var(--color-primary); 42 | } 43 | 44 | .card-3 h2 { 45 | font-weight: 600; 46 | font-size: 20px; 47 | margin-top: 18px; 48 | margin-bottom: 18px; 49 | } 50 | 51 | .card-3 h3 { 52 | font-weight: 300; 53 | font-size: clamp(16px, 4vw, 20px); 54 | color: var(--color-muted); 55 | } 56 | 57 | .card-3 h4 { 58 | font-weight: 500; 59 | font-size: clamp(22px, 5.5vw, 26px); 60 | margin-bottom: 6px; 61 | } 62 | 63 | .card-3 h5 { 64 | color: var(--color-muted); 65 | font-size: clamp(14px, 4vw, 16px); 66 | margin-bottom: 40px; 67 | } 68 | 69 | .card-3 .details { 70 | display: flex; 71 | align-items: center; 72 | justify-content: space-between; 73 | padding: 0 24px; 74 | margin-bottom: 20px; 75 | font-size: clamp(14px, 4vw, 16px); 76 | } 77 | 78 | .card-3 .salary em { 79 | color: var(--color-muted); 80 | } 81 | 82 | .card-3 .date { 83 | color: var(--color-muted); 84 | } 85 | 86 | .card-3 .footer { 87 | display: flex; 88 | align-items: center; 89 | justify-content: space-between; 90 | gap: 8px; 91 | padding: 16px 24px; 92 | border-top: var(--border); 93 | } 94 | 95 | .card-3 .footer button { 96 | background: transparent; 97 | border: var(--border); 98 | width: 40px; 99 | height: 40px; 100 | border-radius: 50%; 101 | display: grid; 102 | place-items: center; 103 | color: inherit; 104 | } 105 | 106 | .card-3 .footer button span { 107 | font-size: 22px; 108 | } 109 | 110 | .card-3 .badge { 111 | display: inline-flex; 112 | margin-right: auto; 113 | align-items: center; 114 | gap: 12px; 115 | padding-right: 20px; 116 | font-size: 14px; 117 | border-radius: 50px; 118 | background: var(--color-highlight); 119 | } 120 | 121 | .card-3 .badge .text { 122 | display: none; 123 | } 124 | 125 | .card-3 .badge img { 126 | width: 40px; 127 | } 128 | 129 | .card-3 .badge p { 130 | color: var(--color-muted); 131 | } 132 | 133 | @media (width >= 430px) { 134 | .card-3 { 135 | padding-top: 0; 136 | } 137 | 138 | .card-3 > img { 139 | position: absolute; 140 | top: 20px; 141 | right: 20px; 142 | left: auto; 143 | translate: 0; 144 | width: clamp(68px, 12vw, 80px); 145 | padding: 16px; 146 | border-color: transparent; 147 | box-shadow: none; 148 | } 149 | 150 | .card-3 .main { 151 | text-align: left; 152 | } 153 | 154 | .card-3 .badge .text { 155 | display: inline; 156 | } 157 | 158 | .card-3 h5 { 159 | margin-bottom: 28px; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/components/cards/Card3/Card3.jsx: -------------------------------------------------------------------------------- 1 | import logo from "./logo.svg"; 2 | import avatar from "./avatar.png"; 3 | import "./Card3.css"; 4 | 5 | export const Card3 = ({ 6 | company, 7 | level, 8 | role, 9 | location, 10 | isRemote, 11 | salary, 12 | when, 13 | profileMatch, 14 | onShare, 15 | onSave, 16 | }) => ( 17 |
18 | 19 |
20 |

{company}

21 |

{level}

22 |

{role}

23 |
24 | {location} {isRemote && (Remote)} 25 |
26 |
27 |
28 | 29 | {" "} 30 | {salary} 31 | /month{" "} 32 | 33 | {when} 34 |
35 | 50 |
51 | ); 52 | -------------------------------------------------------------------------------- /src/components/cards/Card3/Card3Example.css: -------------------------------------------------------------------------------- 1 | .page.card-3-page { 2 | background: #111116; 3 | color: #ffffff; 4 | height: 100vh; 5 | margin: 0; 6 | display: grid; 7 | place-items: center; 8 | font-family: "Euclid Circular B", "Poppins"; 9 | } 10 | -------------------------------------------------------------------------------- /src/components/cards/Card3/Card3Example.jsx: -------------------------------------------------------------------------------- 1 | import { Card3 } from "./Card3"; 2 | import "./Card3Example.css"; 3 | 4 | export const Card3Example = () => { 5 | const onShare = () => console.log("share"); 6 | const onSave = () => console.log("share"); 7 | 8 | return ( 9 |
10 | 22 |
23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /src/components/cards/Card3/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/cards/Card3/avatar.png -------------------------------------------------------------------------------- /src/components/cards/Card3/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Google-color 6 | Created with Sketch. 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/components/cards/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Card1/Card1"; 2 | export * from "./Card2/Card2Example"; 3 | export * from "./Card3/Card3Example"; 4 | -------------------------------------------------------------------------------- /src/components/carousels/Carousel1/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel1/1.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel1/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel1/2.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel1/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel1/3.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel1/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel1/4.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel1/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel1/5.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel1/Carousel1.jsx: -------------------------------------------------------------------------------- 1 | import { Swiper, SwiperSlide } from "swiper/react"; 2 | import { EffectCoverflow, Pagination } from "swiper/modules"; 3 | import "./styles.css"; 4 | import "swiper/css"; 5 | import "swiper/css/navigation"; 6 | import "swiper/css/pagination"; 7 | 8 | import image1 from "./1.jpg"; 9 | import image2 from "./2.jpg"; 10 | import image3 from "./3.jpg"; 11 | import image4 from "./4.jpg"; 12 | import image5 from "./5.jpg"; 13 | 14 | const slides = [ 15 | { 16 | title: "1 Series", 17 | image: image1, 18 | }, 19 | { 20 | title: "2 Series", 21 | image: image2, 22 | }, 23 | { 24 | title: "3 Series", 25 | image: image3, 26 | }, 27 | { 28 | title: "4 Series", 29 | image: image4, 30 | }, 31 | { 32 | title: "5 Series", 33 | image: image5, 34 | }, 35 | ]; 36 | 37 | export const Carousel1 = () => { 38 | return ( 39 |
40 | 56 | {slides.map((slide) => ( 57 | 63 |
64 |
65 |

{slide.title}

66 | explore 67 |
68 |
69 |
70 | ))} 71 |
72 |
73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /src/components/carousels/Carousel1/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | .page.carousel-1-page { 8 | position: relative; 9 | display: flex; 10 | align-items: center; 11 | gap: 50px; 12 | padding: 0 8vw; 13 | background: linear-gradient(45deg, #2c3d46, #0c0f13); 14 | color: #f9f9f9; 15 | } 16 | 17 | .swiper a { 18 | display: inline-block; 19 | text-decoration: none; 20 | text-transform: uppercase; 21 | color: #717171; 22 | font-weight: 500; 23 | background: #fff; 24 | border-radius: 3.125rem; 25 | margin: 0 auto; 26 | padding: 10px 26px; 27 | font-size: 0.9rem; 28 | transition: 0.3s ease-in-out; 29 | } 30 | 31 | .swiper { 32 | width: 100%; 33 | max-width: 800px; 34 | height: 440px; 35 | } 36 | 37 | .swiper-slide { 38 | overflow: hidden; 39 | display: flex; 40 | flex-direction: column; 41 | justify-content: end; 42 | align-items: center; 43 | filter: grayscale(0.6); 44 | background-size: cover; 45 | background-position: center; 46 | } 47 | 48 | .swiper-slide h2 { 49 | color: #fff; 50 | font-weight: 100; 51 | font-size: 20px; 52 | line-height: 1.4; 53 | margin-bottom: 0.625rem; 54 | text-transform: uppercase; 55 | letter-spacing: 1px; 56 | text-align: center; 57 | } 58 | 59 | .swiper-slide a:hover { 60 | color: #005baa; 61 | } 62 | 63 | .swiper-slide div { 64 | position: absolute; 65 | z-index: 1; 66 | inset: 0; 67 | background: linear-gradient(rgb(0 0 0 / 0%) 55%, rgb(0 0 0 / 80%)); 68 | transition: 0.25s; 69 | opacity: 0; 70 | align-self: stretch; 71 | padding-bottom: 70px; 72 | height: 100%; 73 | display: flex; 74 | align-items: center; 75 | flex-direction: column; 76 | justify-content: flex-end; 77 | } 78 | 79 | .swiper-slide-active div { 80 | opacity: 1; 81 | } 82 | 83 | .swiper-slide > div > div { 84 | translate: 0 100px; 85 | transition: 0.3s; 86 | } 87 | 88 | .swiper-slide-active > div > div { 89 | translate: 0; 90 | } 91 | 92 | .swiper-pagination-bullet, 93 | .swiper-pagination-bullet-active { 94 | background: #fff !important; 95 | } 96 | 97 | .swiper-pagination { 98 | bottom: 10px !important; 99 | transform: scale(1.3); 100 | } 101 | -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/1.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/2.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/3.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/4.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/5.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/6.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/7.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/8.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/carousels/Carousel2/9.jpg -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/Carousel2.jsx: -------------------------------------------------------------------------------- 1 | import { Swiper, SwiperSlide } from "swiper/react"; 2 | import { EffectCoverflow } from "swiper/modules"; 3 | 4 | import "swiper/css"; 5 | import "swiper/css/effect-coverflow"; 6 | import "./styles.css"; 7 | 8 | import image1 from "./1.jpg"; 9 | import image2 from "./2.jpg"; 10 | import image3 from "./3.jpg"; 11 | import image4 from "./4.jpg"; 12 | import image5 from "./5.jpg"; 13 | import image6 from "./6.jpg"; 14 | import image7 from "./7.jpg"; 15 | import image8 from "./8.jpg"; 16 | import image9 from "./9.jpg"; 17 | 18 | const slides = [image2, image3, image4, image5, image6, image7, image8, image9]; 19 | 20 | export const Carousel2 = () => { 21 | return ( 22 |
23 | 38 |
39 | {slides.map((slide) => ( 40 | 46 | ))} 47 |
48 |
49 |
50 |
51 | ); 52 | }; 53 | -------------------------------------------------------------------------------- /src/components/carousels/Carousel2/styles.css: -------------------------------------------------------------------------------- 1 | .page.carousel-2-page { 2 | background: #010101; 3 | font-size: 14px; 4 | color: #010101; 5 | margin: 0; 6 | padding: 0; 7 | height: 100vh; 8 | width: 100vw; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | } 13 | 14 | .swiper { 15 | padding-top: 50px; 16 | padding-bottom: 140px; 17 | } 18 | 19 | .swiper .swiper-slide { 20 | background-position: center; 21 | background-size: cover; 22 | border-radius: 10px; 23 | width: 300px; 24 | height: 250px; 25 | filter: saturate(1.2); 26 | -webkit-box-reflect: below 1px 27 | linear-gradient(transparent, transparent, #0006); 28 | } 29 | -------------------------------------------------------------------------------- /src/components/carousels/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Carousel1/Carousel1"; 2 | export * from "./Carousel2/Carousel2"; 3 | -------------------------------------------------------------------------------- /src/components/controls/AutoSuggest/styles.css: -------------------------------------------------------------------------------- 1 | .page.auto-suggest-page { 2 | background: #18181b; 3 | display: flex; 4 | flex-direction: column; 5 | justify-content: center; 6 | align-items: center; 7 | gap: 50px; 8 | padding-top: 0; 9 | } 10 | 11 | .auto-suggest-page img { 12 | width: 240px; 13 | margin: 0 auto; 14 | } 15 | 16 | .auto-suggest-page button { 17 | padding: 10px 16px; 18 | border-radius: 4px; 19 | border: 0; 20 | background: #303134; 21 | color: inherit; 22 | font-family: inherit; 23 | } 24 | 25 | .auto-suggest-page p { 26 | margin: 0; 27 | font-size: 13px; 28 | } 29 | 30 | .auto-suggest-page p a { 31 | color: #8ab4f7; 32 | } 33 | 34 | .auto-suggest { 35 | position: relative; 36 | } 37 | 38 | .auto-suggest input { 39 | width: 440px; 40 | height: 44px; 41 | padding: 0 20px 0 44px; 42 | border-radius: 22px; 43 | border: 1px solid #5f6367; 44 | background: transparent; 45 | color: #e8eaed; 46 | font-size: 16px; 47 | font-family: inherit; 48 | outline: none; 49 | } 50 | 51 | .auto-suggest input:focus { 52 | background: #2c2e34; 53 | border-color: #2c2e34; 54 | border-bottom-right-radius: 0; 55 | border-bottom-left-radius: 0; 56 | } 57 | 58 | .auto-suggest span:nth-child(1) { 59 | position: absolute; 60 | top: 50%; 61 | left: 14px; 62 | translate: 0 -50%; 63 | } 64 | 65 | .auto-suggest-buttons { 66 | display: flex; 67 | gap: 16px; 68 | } 69 | 70 | .auto-suggest .menu { 71 | display: none; 72 | position: absolute; 73 | z-index: 1; 74 | overflow: hidden; 75 | top: 44px; 76 | left: 0; 77 | width: 100%; 78 | max-height: 228px; 79 | padding: 0 16px 6px; 80 | background: #2c2e34; 81 | border-bottom-right-radius: 22px; 82 | border-bottom-left-radius: 22px; 83 | } 84 | 85 | .auto-suggest input:focus ~ .menu, 86 | .auto-suggest .menu:hover { 87 | display: block; 88 | } 89 | 90 | .auto-suggest .menu > div { 91 | padding: 8px 0; 92 | border-top: 1px solid #5f6367; 93 | line-height: 1.8; 94 | } 95 | 96 | .auto-suggest .menu > div button { 97 | display: block; 98 | background: transparent; 99 | padding: 0; 100 | height: 30px; 101 | font-size: 16px; 102 | cursor: pointer; 103 | width: 100%; 104 | text-align: left; 105 | } 106 | -------------------------------------------------------------------------------- /src/components/controls/EditableText/EditableText.css: -------------------------------------------------------------------------------- 1 | .editable-text { 2 | display: flex; 3 | align-items: center; 4 | gap: 8px; 5 | } 6 | 7 | .editable-text-value.is-editing ~ .editable-text-buttons { 8 | opacity: 1; 9 | visibility: visible; 10 | } 11 | 12 | .editable-text-buttons { 13 | display: flex; 14 | gap: 2px; 15 | opacity: 0; 16 | visibility: hidden; 17 | transition: 0.3s; 18 | } 19 | 20 | .editable-text:hover .editable-text-buttons { 21 | opacity: 1; 22 | visibility: visible; 23 | } 24 | 25 | .editable-text-buttons button { 26 | cursor: pointer; 27 | background: transparent; 28 | border: 0; 29 | display: grid; 30 | place-items: center; 31 | color: inherit; 32 | opacity: 0.5; 33 | transition: 0.3s; 34 | } 35 | 36 | .editable-text-buttons button:hover { 37 | opacity: 0.8; 38 | } 39 | 40 | .editable-text-value { 41 | outline: none; 42 | } 43 | -------------------------------------------------------------------------------- /src/components/controls/EditableText/EditableText.jsx: -------------------------------------------------------------------------------- 1 | import { useLayoutEffect, useRef, useState } from "react"; 2 | import "./EditableText.css"; 3 | 4 | const setCaret = (el) => { 5 | if (!el) return; 6 | try { 7 | const range = document.createRange(); 8 | const sel = window.getSelection(); 9 | range.setStart(el.childNodes[0], el.innerText.length); 10 | range.collapse(true); 11 | sel.removeAllRanges(); 12 | sel.addRange(range); 13 | } catch (err) { 14 | console.log("Error Setting Caret: ", err); 15 | } 16 | }; 17 | 18 | const IconButton = ({ children, onClick }) => ( 19 | 22 | ); 23 | 24 | export const EditableText = ({ name, defaultValue, onSave, className }) => { 25 | const [isEditing, setIsEditing] = useState(false); 26 | 27 | const nextValue = useRef(""); 28 | 29 | const spanRef = useRef(null); 30 | 31 | const handleChange = (e) => (nextValue.current = e.target.innerText); 32 | 33 | const handleSave = () => { 34 | toggleIsEditing(); 35 | onSave(name, nextValue.current); 36 | }; 37 | 38 | const toggleIsEditing = () => setIsEditing(!isEditing); 39 | 40 | useLayoutEffect(() => { 41 | if (isEditing) { 42 | spanRef.current.focus(); 43 | setCaret(spanRef.current); 44 | } else { 45 | spanRef.current.innerText = defaultValue; 46 | nextValue.current = defaultValue; 47 | } 48 | }, [isEditing]); 49 | 50 | return ( 51 | 52 | 61 | {defaultValue} 62 | 63 | 64 | {isEditing ? ( 65 | <> 66 | check_circle 67 | cancel 68 | 69 | ) : ( 70 | edit 71 | )} 72 | 73 | 74 | ); 75 | }; 76 | -------------------------------------------------------------------------------- /src/components/controls/EditableText/EditableTextExample.css: -------------------------------------------------------------------------------- 1 | .page.editable-text-page { 2 | --gradient: linear-gradient(45deg, #ff7c7d, #ffda67); 3 | --card: #272524; 4 | display: flex; 5 | align-items: center; 6 | justify-content: center; 7 | margin: 0; 8 | height: 100vh; 9 | background: var(--gradient); 10 | color: #fdfcfd; 11 | font-family: "Euclid Circular B", "Poppins"; 12 | } 13 | 14 | .editable-text-card { 15 | display: flex; 16 | align-items: center; 17 | width: 75vw; 18 | max-width: 650px; 19 | padding: 44px 30px 44px 20px; 20 | background: var(--card); 21 | border-radius: 24px; 22 | } 23 | 24 | .editable-text-card img { 25 | max-width: 280px; 26 | width: 36vw; 27 | height: 300px; 28 | object-fit: cover; 29 | margin-left: -60px; 30 | margin-right: 30px; 31 | border-radius: inherit; 32 | box-shadow: 0 60px 40px rgb(0 0 0 / 8%); 33 | transition: border-radius 0.3s; 34 | } 35 | 36 | .editable-text-card-title { 37 | display: block; 38 | font-size: 24px; 39 | font-weight: 400; 40 | margin-top: 0; 41 | margin-bottom: 10px; 42 | } 43 | 44 | .editable-text-card-role { 45 | display: block; 46 | font-size: 16px; 47 | font-weight: 400; 48 | margin: 0 0 5px; 49 | opacity: 0.75; 50 | } 51 | 52 | .editable-text-card p { 53 | font-size: 14px; 54 | font-weight: 400; 55 | margin-bottom: 30px; 56 | opacity: 0.5; 57 | } 58 | 59 | .editable-text-socials { 60 | display: flex; 61 | align-items: center; 62 | gap: 8px; 63 | } 64 | 65 | .editable-text-socials > button { 66 | position: relative; 67 | border: 0; 68 | background: transparent; 69 | color: #f8f8f8; 70 | padding: 0; 71 | } 72 | 73 | .editable-text-socials > button:first-child::before { 74 | content: ""; 75 | position: absolute; 76 | z-index: 0; 77 | top: 50%; 78 | left: 50%; 79 | width: 52px; 80 | height: 52px; 81 | translate: -50% -50%; 82 | border-radius: 50%; 83 | border: 2px solid #ff7c7d; 84 | transition: 0.3s; 85 | transform: translateY(0); 86 | } 87 | 88 | .editable-text-socials > button > i { 89 | position: relative; 90 | z-index: 1; 91 | border: 4px solid var(--card); 92 | background: rgb(255 255 255 / 12%); 93 | display: grid; 94 | place-items: center; 95 | font-size: 24px; 96 | width: 50px; 97 | height: 50px; 98 | border-radius: 40px; 99 | } 100 | 101 | @media (width <= 600px) { 102 | .editable-text-card { 103 | margin: 0 40px; 104 | padding-left: 50px; 105 | padding-right: 50px; 106 | padding-bottom: 60px; 107 | width: 100%; 108 | text-align: center; 109 | flex-direction: column; 110 | } 111 | 112 | .editable-text-card h2 { 113 | margin-right: 0; 114 | font-size: 26px; 115 | } 116 | 117 | .editable-text-card img { 118 | margin: -100px 0 30px 0; 119 | width: 100%; 120 | max-width: 1000px; 121 | height: 250px; 122 | } 123 | 124 | .editable-text-card p { 125 | max-width: 360px; 126 | } 127 | 128 | .editable-text-socials { 129 | justify-content: center; 130 | } 131 | } 132 | 133 | @media (width <= 440px) { 134 | .editable-text-card img { 135 | height: 50vw; 136 | width: 50vw; 137 | border-radius: 50%; 138 | border: 12px solid var(--card); 139 | box-shadow: none; 140 | margin: -140px 0 30px 0; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/components/controls/EditableText/EditableTextExample.jsx: -------------------------------------------------------------------------------- 1 | import image from "./image.jpg"; 2 | import "./EditableTextExample.css"; 3 | import { EditableText } from "./EditableText"; 4 | import { useState } from "react"; 5 | 6 | export const EditableTitleExample = () => { 7 | const [state, setState] = useState({ 8 | title: "Jill Scott", 9 | role: "Frontend Engineer", 10 | }); 11 | 12 | const { title, role } = state; 13 | 14 | const handleSave = (name, value) => 15 | setState({ 16 | ...state, 17 | [name]: value, 18 | }); 19 | 20 | return ( 21 |
22 |
23 | 24 |
25 | 31 | 37 |

38 | Transforming ideas into realities, creating interfaces that inspire 39 | and engage users dreams. 40 |

41 |
42 | 45 | 48 | 51 |
52 |
53 |
54 |
55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /src/components/controls/EditableText/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/controls/EditableText/image.jpg -------------------------------------------------------------------------------- /src/components/controls/PasswordStrength/PasswordStrength.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import logo from "./logo.svg"; 3 | import "./styles.css"; 4 | 5 | const strengthLabels = ["weak", "medium", "medium", "strong"]; 6 | 7 | export const PasswordStrength = ({ placeholder, onChange }) => { 8 | const [strength, setStrength] = useState(""); 9 | 10 | const getStrength = (password) => { 11 | let strengthIndicator = -1; 12 | 13 | if (/[a-z]/.test(password)) strengthIndicator++; 14 | if (/[A-Z]/.test(password)) strengthIndicator++; 15 | if (/\d/.test(password)) strengthIndicator++; 16 | if (/[^a-zA-Z0-9]/.test(password)) strengthIndicator++; 17 | 18 | if (password.length >= 16) strengthIndicator++; 19 | 20 | return strengthLabels[strengthIndicator]; 21 | }; 22 | 23 | const handleChange = (event) => { 24 | setStrength(getStrength(event.target.value)); 25 | onChange(event.target.value); 26 | }; 27 | 28 | return ( 29 | <> 30 | 38 |
39 |
40 |
41 |
{strength && `${strength} password`}
42 | 43 | ); 44 | }; 45 | 46 | export const PasswordStrengthExample = () => { 47 | const handleChange = (value) => console.log(value); 48 | 49 | return ( 50 |
51 |
52 | 53 |

Sign Up

54 |
55 |
56 | 64 |
65 |
66 | 67 | 70 | 71 |
72 |
73 | ); 74 | }; 75 | -------------------------------------------------------------------------------- /src/components/controls/PasswordStrength/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .page { 6 | display: grid; 7 | place-items: center; 8 | margin: 0; 9 | background: #000000; 10 | font-family: "Euclid Circular A", "Poppins"; 11 | color: #fdfdfd; 12 | } 13 | 14 | .login-card { 15 | width: 400px; 16 | padding: 60px 30px 30px; 17 | border-radius: 16px; 18 | background: #0e0d0d; 19 | text-align: center; 20 | } 21 | 22 | .login-card > h2 { 23 | font-size: 36px; 24 | font-weight: 600; 25 | margin: 0 0 30px; 26 | } 27 | 28 | .login-card img { 29 | width: 260px; 30 | margin-bottom: 20px; 31 | } 32 | 33 | .login-form { 34 | width: 100%; 35 | margin: 0; 36 | display: grid; 37 | } 38 | 39 | .login-form input.control::placeholder { 40 | color: #9f9d9e; 41 | } 42 | 43 | .control { 44 | outline: none; 45 | width: 100%; 46 | height: 56px; 47 | padding: 0 16px; 48 | color: inherit; 49 | background: #181919; 50 | border: 0; 51 | border-radius: 6px; 52 | margin: 8px 0; 53 | font-family: inherit; 54 | font-size: 18px; 55 | transition: 0.4s; 56 | } 57 | 58 | button.control { 59 | cursor: pointer; 60 | width: 100%; 61 | height: 56px; 62 | padding: 0 16px; 63 | background: #0079ea; 64 | text-align: center; 65 | } 66 | 67 | .bars { 68 | margin: 8px 0; 69 | flex: 1 1 auto; 70 | display: flex; 71 | align-items: center; 72 | gap: 8px; 73 | height: 6px; 74 | border-radius: 3px; 75 | background: #181919; 76 | } 77 | 78 | .bars div { 79 | height: 6px; 80 | border-radius: 3px; 81 | transition: 0.4s; 82 | width: 0%; 83 | } 84 | 85 | .bars.weak div { 86 | background: #e24c71; 87 | width: 33.33%; 88 | } 89 | 90 | .bars.medium div { 91 | background: #f39845; 92 | width: 66.66%; 93 | } 94 | 95 | .bars.strong div { 96 | background: #57c558; 97 | width: 100%; 98 | } 99 | 100 | .strength { 101 | text-align: left; 102 | height: 30px; 103 | text-transform: capitalize; 104 | color: #868b94; 105 | } 106 | -------------------------------------------------------------------------------- /src/components/controls/PasswordVisibility/Password.css: -------------------------------------------------------------------------------- 1 | .password-control input { 2 | --color-primary: #0088ff; 3 | --color-muted: #5a616c; 4 | border: 0; 5 | width: 100%; 6 | height: 60px; 7 | background: transparent; 8 | font-family: inherit; 9 | font-size: 16px; 10 | outline: none; 11 | } 12 | 13 | .password-visibility .password-control { 14 | position: relative; 15 | margin-bottom: 16px; 16 | } 17 | 18 | .password-control > span { 19 | position: absolute; 20 | top: 50%; 21 | translate: 0 -50%; 22 | left: 0; 23 | font-size: 22px; 24 | pointer-events: none; 25 | color: var(--color-muted); 26 | transition: 0.3s; 27 | } 28 | 29 | .password-control input { 30 | padding: 0 24px 0 36px; 31 | color: rgb(255 255 255 / 96%); 32 | height: 72px; 33 | transition: 0.3s; 34 | } 35 | 36 | .password-control :is(input:focus, input:valid) ~ label { 37 | translate: -36px -44px; 38 | scale: 0.875; 39 | } 40 | 41 | .password-control input:focus ~ label { 42 | color: var(--color-primary); 43 | } 44 | 45 | .password-control .border { 46 | position: absolute; 47 | left: 0; 48 | right: 0; 49 | bottom: 0; 50 | width: 100%; 51 | height: 2px; 52 | border-radius: 2px; 53 | background: rgb(255 255 255 / 6%); 54 | } 55 | 56 | .password-control .border::after { 57 | content: ""; 58 | position: absolute; 59 | inset: 0; 60 | border-radius: inherit; 61 | background: var(--color-primary); 62 | transform: scaleX(0); 63 | opacity: 0; 64 | transition: 0.3s; 65 | } 66 | 67 | .password-control input:focus ~ .border::after { 68 | transform: scaleX(1); 69 | opacity: 1; 70 | } 71 | 72 | .password-control :is(input:focus, input:valid) ~ span { 73 | color: rgb(255 255 255 / 96%); 74 | } 75 | 76 | .password-control label { 77 | position: absolute; 78 | top: 50%; 79 | left: 30px; 80 | translate: 0 -50%; 81 | color: var(--color-muted); 82 | pointer-events: none; 83 | text-transform: capitalize; 84 | transition: 0.4s; 85 | } 86 | 87 | .password-control { 88 | margin-bottom: 20px; 89 | } 90 | 91 | .password-control input { 92 | padding-right: 50px; 93 | } 94 | 95 | .password-control button { 96 | position: absolute; 97 | top: 50%; 98 | right: 0; 99 | display: grid; 100 | place-items: center; 101 | padding: 0; 102 | height: 36px; 103 | width: 36px; 104 | translate: 0 -50%; 105 | cursor: pointer; 106 | } 107 | 108 | .password-control button span { 109 | color: var(--color-muted); 110 | transition: 0.3s; 111 | } 112 | 113 | .password-control button:hover span { 114 | color: rgb(255 255 255 / 96%); 115 | } 116 | -------------------------------------------------------------------------------- /src/components/controls/PasswordVisibility/Password.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./Password.css"; 3 | 4 | export const Icon = ({ children }) => ( 5 | {children} 6 | ); 7 | 8 | export const Password = ({ name, onInput }) => { 9 | const [showPassword, setShowPassword] = useState(false); 10 | 11 | const handleMouseDown = (e) => { 12 | e.preventDefault(); 13 | setShowPassword(!showPassword); 14 | }; 15 | 16 | const handleInput = (e) => onInput(name, e.target.value); 17 | 18 | return ( 19 |
20 | 25 | 26 | lock 27 | 30 |
31 |
32 | ); 33 | }; 34 | -------------------------------------------------------------------------------- /src/components/controls/PasswordVisibility/PasswordVisibilityExample.css: -------------------------------------------------------------------------------- 1 | .page.password-visibility-page { 2 | display: grid; 3 | place-items: center; 4 | margin: 0; 5 | padding: 0 20px; 6 | background: #3284ce; 7 | font-family: "Euclid Circular A", "Poppins"; 8 | box-sizing: border-box; 9 | } 10 | 11 | .password-visibility :is(button, input) { 12 | border: 0; 13 | width: 100%; 14 | height: 60px; 15 | background: transparent; 16 | font-family: inherit; 17 | font-size: 16px; 18 | outline: none; 19 | } 20 | 21 | @keyframes clouds { 22 | 0% { 23 | scale: 1; 24 | translate: 0; 25 | } 26 | 50% { 27 | scale: 1.25; 28 | } 29 | 100% { 30 | scale: 1; 31 | translate: -100px 0; 32 | } 33 | } 34 | 35 | .password-visibility-clouds { 36 | position: fixed; 37 | top: -50vh; 38 | left: 0; 39 | height: 150vh; 40 | animation: clouds 15s both infinite alternate linear; 41 | } 42 | 43 | .password-visibility { 44 | --color-primary: #0088ff; 45 | --color-muted: #5a616c; 46 | position: fixed; 47 | display: flex; 48 | flex-direction: column; 49 | justify-content: center; 50 | z-index: 2; 51 | top: 0; 52 | left: 0; 53 | height: 100%; 54 | width: 70%; 55 | max-width: 400px; 56 | padding: 200px 60px; 57 | background: #121216; 58 | } 59 | 60 | .password-visibility > h2 { 61 | font-size: 32px; 62 | font-weight: 300; 63 | margin: 0 0 10px; 64 | color: rgb(255 255 255 / 96%); 65 | } 66 | 67 | .password-visibility > h3 { 68 | font-size: 16px; 69 | font-weight: 400; 70 | margin: 0 0 30px; 71 | color: var(--color-muted); 72 | } 73 | 74 | .password-visibility > form { 75 | margin: 0; 76 | display: grid; 77 | gap: 16px; 78 | } 79 | 80 | .password-visibility > form > button { 81 | display: flex; 82 | align-items: center; 83 | justify-content: space-between; 84 | cursor: pointer; 85 | padding: 0 12px 0 24px; 86 | border-radius: 6px; 87 | background: var(--color-primary); 88 | color: #f9f9f9; 89 | border: 0; 90 | font-family: inherit; 91 | letter-spacing: 1px; 92 | font-size: 16px; 93 | font-weight: 500; 94 | transition: 0.3s; 95 | } 96 | 97 | .password-visibility form > button:disabled { 98 | opacity: 0.5; 99 | cursor: not-allowed; 100 | } 101 | 102 | .password-visibility p > a { 103 | color: var(--color-primary); 104 | text-decoration: none; 105 | } 106 | -------------------------------------------------------------------------------- /src/components/controls/PasswordVisibility/PasswordVisibilityExample.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import bg from "./bg.svg"; 3 | import "./PasswordVisibilityExample.css"; 4 | import { Icon, Password } from "./Password"; 5 | 6 | export const PasswordVisibilityExample = () => { 7 | const [state, setState] = useState({ 8 | password: "", 9 | }); 10 | 11 | const handleInput = (name, value) => { 12 | setState({ 13 | ...state, 14 | [name]: value, 15 | }); 16 | }; 17 | 18 | return ( 19 |
20 | 21 |
22 |

Login

23 |

Welcome back Jack!

24 |
25 | 26 | 30 | 31 |
32 |
33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /src/components/controls/index.js: -------------------------------------------------------------------------------- 1 | export * from "./PasswordStrength/PasswordStrength"; 2 | export * from "./AutoSuggest/AutoSuggest"; 3 | export * from "./PasswordVisibility/PasswordVisibilityExample"; 4 | export * from "./EditableText/EditableTextExample"; 5 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown1/Dropdown1.css: -------------------------------------------------------------------------------- 1 | .dropdown-1 { 2 | position: relative; 3 | perspective: 1000px; 4 | width: 144px; 5 | } 6 | 7 | .dropdown-1 button { 8 | display: flex; 9 | align-items: center; 10 | gap: 4px; 11 | padding: 0; 12 | width: 100%; 13 | height: 64px; 14 | color: rgb(255 255 255 / 55%); 15 | background: #2d2f31; 16 | border: 0; 17 | cursor: pointer; 18 | font-size: 16px; 19 | font-family: "Euclid Circular A"; 20 | } 21 | 22 | .dropdown-1 > button { 23 | background: transparent; 24 | gap: 10px; 25 | margin: 0 -4px; 26 | white-space: nowrap; 27 | } 28 | 29 | .dropdown-1 > button > .chevron { 30 | } 31 | 32 | .dropdown-1:hover > button, 33 | .dropdown-1.open > button { 34 | color: rgb(255 255 255 / 95%); 35 | } 36 | 37 | .dropdown-1.open > button .chevron { 38 | rotate: -180deg; 39 | } 40 | 41 | .dropdown-1 > button > .span { 42 | font-size: 30px; 43 | } 44 | 45 | .dropdown-1 button .chevron { 46 | margin-left: auto; 47 | transition: rotate 0.3s; 48 | } 49 | 50 | .dropdown-1-menu { 51 | position: absolute; 52 | overflow: hidden; 53 | z-index: 1; 54 | top: 64px; 55 | left: 0; 56 | margin: 0 -20px; 57 | width: calc(100% + 40px); 58 | height: 168px; 59 | opacity: 0; 60 | transform: rotateX(-90deg); 61 | transform-origin: 0% 0%; 62 | visibility: hidden; 63 | background: #2d2f31; 64 | transition: 0.3s; 65 | } 66 | 67 | .dropdown-1.open .dropdown-1-menu { 68 | opacity: 1; 69 | transform: rotateX(0); 70 | visibility: visible; 71 | } 72 | 73 | .dropdown-1-menu .main-menu { 74 | width: 50%; 75 | } 76 | 77 | .dropdown-1-menu .menu-inner { 78 | position: absolute; 79 | width: 200%; 80 | display: flex; 81 | transition: 0.4s; 82 | } 83 | 84 | .dropdown-1-menu .menu-inner.open { 85 | translate: -50%; 86 | } 87 | 88 | .dropdown-1-menu button { 89 | border: 0; 90 | height: 56px; 91 | border-radius: 0; 92 | gap: 10px; 93 | padding: 0 8px 0 16px; 94 | text-transform: capitalize; 95 | } 96 | 97 | .dropdown-1-menu button:hover { 98 | color: rgb(255 255 255 / 95%); 99 | } 100 | 101 | .dropdown-1-menu .sub-menu { 102 | position: absolute; 103 | width: 100%; 104 | left: 50%; 105 | top: 0; 106 | } 107 | 108 | .dropdown-1 button .material-symbols-outlined:first-child { 109 | font-size: 22px; 110 | } 111 | 112 | .page.dropdown-1-page { 113 | margin: 0; 114 | display: grid; 115 | place-items: center; 116 | background: #212324; 117 | height: 100vh; 118 | } 119 | 120 | .dropdown-1-nav { 121 | position: fixed; 122 | top: 0; 123 | left: 0; 124 | z-index: 2; 125 | background: #771dff; 126 | width: 100%; 127 | padding: 0 20px; 128 | display: flex; 129 | align-items: center; 130 | justify-content: space-between; 131 | } 132 | 133 | .dropdown-1-nav > h1 { 134 | font-weight: 400; 135 | margin-right: auto; 136 | margin-left: 14px; 137 | font-size: 16px; 138 | } 139 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown1/Dropdown1.jsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import "./Dropdown1.css"; 3 | 4 | const MenuButton = ({ 5 | name, 6 | icon, 7 | index, 8 | hasSubItems, 9 | subMenuHeight, 10 | onClick, 11 | }) => { 12 | return ( 13 | 20 | ); 21 | }; 22 | 23 | const MenuItem = ({ name, icon, index, activeSubMenu, subItems, onClick }) => { 24 | const subMenuRef = useRef(); 25 | const isActive = activeSubMenu === index; 26 | return ( 27 | <> 28 | null} 30 | name={name} 31 | icon={icon || name} 32 | index={index} 33 | hasSubItems={Boolean(subItems)} 34 | subMenuHeight={subMenuRef.current?.clientHeight} 35 | /> 36 | {subItems?.length && ( 37 |
38 | <> 39 | 40 | {subItems.map((subItem) => ( 41 | 42 | ))} 43 | 44 |
45 | )} 46 | 47 | ); 48 | }; 49 | 50 | export const Dropdown1 = ({ items }) => { 51 | const [isOpen, setIsOpen] = useState(false); 52 | 53 | const [isSubMenuOpen, setIsSubMenuOpen] = useState(false); 54 | 55 | const [subMenuHeight, setSubMenuHeight] = useState(); 56 | 57 | const [activeSubMenu, setActiveSubMenu] = useState(); 58 | 59 | const handleClick = (index, subMenuHeight) => { 60 | if (index > -1) setActiveSubMenu(index); 61 | setSubMenuHeight(subMenuHeight); 62 | setIsSubMenuOpen(index > -1); 63 | }; 64 | 65 | return ( 66 |
67 | 72 |
76 |
77 |
78 | {items.map((item, index) => ( 79 | 88 | ))} 89 |
90 |
91 |
92 |
93 | ); 94 | }; 95 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown1/Dropdown1Example.jsx: -------------------------------------------------------------------------------- 1 | import { Dropdown1 } from "./Dropdown1"; 2 | import "./Dropdown1.css"; 3 | 4 | const items = [ 5 | { 6 | name: "settings", 7 | subItems: ["analytics", "database", "terminal"], 8 | }, 9 | { 10 | name: "devices", 11 | subItems: ["smartphone", "mouse", "keyboard", "headphones"], 12 | }, 13 | { 14 | name: "lock", 15 | displayName: "Account", 16 | }, 17 | ]; 18 | 19 | export const Dropdown1Example = () => { 20 | return ( 21 |
22 | 27 |
28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown2/Dropdown2.css: -------------------------------------------------------------------------------- 1 | .dropdown-2 { 2 | position: relative; 3 | display: grid; 4 | place-items: center; 5 | height: 72px; 6 | } 7 | 8 | .dropdown-2-overlay { 9 | position: fixed; 10 | inset: 0; 11 | background: rgb(0 0 0 / 40%); 12 | opacity: 0; 13 | visibility: hidden; 14 | transition: 0.3s; 15 | } 16 | 17 | .dropdown-2-overlay.open { 18 | opacity: 1; 19 | visibility: visible; 20 | } 21 | 22 | .dropdown-2 > button { 23 | position: relative; 24 | display: grid; 25 | place-items: center; 26 | width: 36px; 27 | height: 36px; 28 | background: transparent; 29 | } 30 | 31 | .dropdown-2-menu { 32 | overflow-x: hidden; 33 | overflow-y: auto; 34 | position: fixed; 35 | translate: 0 20px; 36 | display: grid; 37 | grid-template-columns: repeat(3, 1fr); 38 | grid-auto-rows: max-content; 39 | width: 270px; 40 | max-height: 286px; 41 | padding: 10px; 42 | background: #ffffff; 43 | border-radius: 8px; 44 | border: 1px solid #ebebeb; 45 | box-shadow: 0 0 10px rgb(0 0 0 / 8%); 46 | opacity: 0; 47 | visibility: hidden; 48 | transition: 0.3s; 49 | appearance: none; 50 | } 51 | 52 | .dropdown-2-menu::-webkit-scrollbar { 53 | width: 15px; 54 | } 55 | 56 | .dropdown-2-menu::-webkit-scrollbar-thumb { 57 | background: #dadce0; 58 | border-radius: 10px; 59 | border: 4px solid transparent; 60 | background-clip: padding-box; 61 | } 62 | 63 | .dropdown-2-menu.open { 64 | opacity: 1; 65 | visibility: visible; 66 | translate: 0; 67 | } 68 | 69 | .dropdown-2-menu > button { 70 | display: flex; 71 | align-items: center; 72 | justify-content: center; 73 | flex-direction: column; 74 | gap: 6px; 75 | font-family: inherit; 76 | color: #6d696b; 77 | border: 0; 78 | background: transparent; 79 | } 80 | 81 | .dropdown-2-menu > button > img { 82 | width: 64px; 83 | height: 64px; 84 | padding: 16px; 85 | } 86 | 87 | .dropdown-2-menu > button > span:first-child { 88 | display: block; 89 | width: 64px; 90 | height: 64px; 91 | scale: 0.7; 92 | background-image: url("./icons.png"); 93 | background-position: 0 -3105px; 94 | background-size: 64px 3307px; 95 | background-repeat: no-repeat; 96 | } 97 | 98 | .dropdown-2-menu > button > span:last-child { 99 | font-size: 12px; 100 | translate: 0 -12px; 101 | } 102 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown2/Dropdown2Example.css: -------------------------------------------------------------------------------- 1 | .page.dropdown-2-page { 2 | color: #6d696b; 3 | background: #f7f7f7; 4 | font-family: "Euclid Circular A", "Poppins"; 5 | } 6 | 7 | .dropdown-2-nav { 8 | margin-top: -40px; 9 | border-radius: 6px; 10 | display: flex; 11 | align-items: center; 12 | justify-content: space-between; 13 | width: 80%; 14 | height: 72px; 15 | padding: 0 20px; 16 | background: #ffffff; 17 | box-shadow: 0 0 20px rgb(0 0 0 / 6%); 18 | } 19 | 20 | .dropdown-2-nav .logo { 21 | display: flex; 22 | align-items: center; 23 | } 24 | 25 | .dropdown-2-nav .logo img { 26 | width: 36px; 27 | padding: 0; 28 | margin-left: 4px; 29 | margin-right: 6px; 30 | } 31 | 32 | .dropdown-2-nav span.material-symbols-outlined { 33 | display: grid; 34 | place-items: center; 35 | width: 40px; 36 | height: 72px; 37 | font-size: 24px; 38 | } 39 | 40 | .dropdown-2-nav h2 { 41 | font-size: 19px; 42 | font-weight: 400; 43 | } 44 | 45 | .dropdown-2-nav .nav-right > img { 46 | width: 36px; 47 | height: 36px; 48 | border-radius: 50%; 49 | object-fit: contain; 50 | margin-left: 8px; 51 | } 52 | 53 | .dropdown-2-nav button { 54 | background: transparent; 55 | border: 0; 56 | color: inherit; 57 | cursor: pointer; 58 | } 59 | 60 | .dropdown-2-nav .nav-right { 61 | display: flex; 62 | align-items: center; 63 | } 64 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown2/Dropdown2Example.jsx: -------------------------------------------------------------------------------- 1 | import { Dropdown2 } from "./Dropdown2"; 2 | import joe from "./joe.png"; 3 | import logo from "./logo.svg"; 4 | import "./Dropdown2Example.css"; 5 | 6 | export const Dropdown2Example = () => { 7 | return ( 8 |
9 | 22 |
23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown2/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/dropdowns/Dropdown2/icons.png -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown2/joe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/dropdowns/Dropdown2/joe.png -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown2/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown3/Dropdown3.css: -------------------------------------------------------------------------------- 1 | .page.dropdown-3-page { 2 | margin: 0; 3 | display: grid; 4 | place-items: center; 5 | background: #1b1921; 6 | height: 100vh; 7 | --color-menu: #2b2935; 8 | } 9 | 10 | .dropdown-3 { 11 | position: relative; 12 | } 13 | 14 | .dropdown-3 button { 15 | display: flex; 16 | align-items: center; 17 | gap: 10px; 18 | padding: 0 16px; 19 | width: 204px; 20 | height: 64px; 21 | color: #afb3b5; 22 | background: var(--color-menu); 23 | border: 0; 24 | cursor: pointer; 25 | font-size: 18px; 26 | font-family: "Euclid Circular A"; 27 | transition: 0.3s ease; 28 | } 29 | 30 | .dropdown-3 > button { 31 | background: #6f3dcd; 32 | border-radius: 10px; 33 | color: #f9f9f9; 34 | } 35 | 36 | .dropdown-3.open > button .chevron { 37 | rotate: -180deg; 38 | } 39 | 40 | .dropdown-3 button .chevron { 41 | margin-left: auto; 42 | transition: 0.3s ease; 43 | } 44 | 45 | .dropdown-3 .menu { 46 | position: absolute; 47 | overflow: hidden; 48 | z-index: 1; 49 | top: 74px; 50 | left: 0; 51 | width: 100%; 52 | opacity: 0; 53 | translate: 0 -20px; 54 | visibility: hidden; 55 | border-radius: 10px; 56 | background: var(--color-menu); 57 | transition: 0.4s ease; 58 | } 59 | 60 | .dropdown-3.open .menu { 61 | opacity: 1; 62 | translate: 0; 63 | visibility: visible; 64 | } 65 | 66 | .dropdown-3 .menu-inner { 67 | position: absolute; 68 | width: 460px; 69 | display: flex; 70 | transition: 0.4s ease; 71 | } 72 | 73 | .dropdown-3 .menu-inner.open { 74 | translate: -50%; 75 | } 76 | 77 | .dropdown-3 .menu button { 78 | border: 0; 79 | height: 56px; 80 | border-radius: 0; 81 | text-transform: capitalize; 82 | } 83 | 84 | .dropdown-3 .menu button:hover { 85 | background: #393646; 86 | color: #f9f9f9; 87 | } 88 | 89 | .dropdown-3 .sub-menu { 90 | position: absolute; 91 | width: 230px; 92 | left: 230px; 93 | top: 0; 94 | opacity: 0; 95 | visibility: hidden; 96 | } 97 | 98 | .dropdown-3 .sub-menu.open { 99 | opacity: 1; 100 | visibility: visible; 101 | } 102 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown3/Dropdown3.jsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import "./Dropdown3.css"; 3 | 4 | const items = [ 5 | { 6 | name: "build", 7 | subItems: ["description", "folder", "article"], 8 | }, 9 | { 10 | name: "devices", 11 | subItems: ["storage", "mouse", "keyboard", "headphones"], 12 | }, 13 | { 14 | name: "logout", 15 | }, 16 | ]; 17 | 18 | const Icon = ({ icon, className }) => ( 19 | {icon} 20 | ); 21 | 22 | const MenuButton = ({ 23 | name, 24 | icon, 25 | index, 26 | hasSubItems, 27 | subMenuHeight, 28 | onClick, 29 | }) => { 30 | return ( 31 | 36 | ); 37 | }; 38 | 39 | const MenuItem = ({ name, index, activeSubMenu, subItems, onClick }) => { 40 | const subMenuRef = useRef(null); 41 | const isActive = activeSubMenu === index; 42 | return ( 43 | <> 44 | null} 46 | name={name} 47 | index={index} 48 | hasSubItems={Boolean(subItems)} 49 | subMenuHeight={subMenuRef.current?.clientHeight} 50 | /> 51 | {subItems?.length && ( 52 |
53 | <> 54 | 55 | {subItems.map((subItem) => ( 56 | 57 | ))} 58 | 59 |
60 | )} 61 | 62 | ); 63 | }; 64 | 65 | export const Dropdown3 = () => { 66 | const [isOpen, setIsOpen] = useState(false); 67 | 68 | const [isSubMenuOpen, setIsSubMenuOpen] = useState(false); 69 | 70 | const [subMenuHeight, setSubMenuHeight] = useState(); 71 | 72 | const [activeSubMenu, setActiveSubMenu] = useState(); 73 | 74 | const handleClick = (index, subMenuHeight) => { 75 | if (index > -1) setActiveSubMenu(index); 76 | setSubMenuHeight(subMenuHeight); 77 | setIsSubMenuOpen(index > -1); 78 | }; 79 | 80 | return ( 81 |
82 |
86 | 91 |
92 |
93 |
94 | {items.map((item, index) => ( 95 | 103 | ))} 104 |
105 |
106 |
107 |
108 |
109 | ); 110 | }; 111 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown4/Dropdown4.css: -------------------------------------------------------------------------------- 1 | .dropdown-4 { 2 | position: relative; 3 | perspective: 400px; 4 | color: #f9f9f9; 5 | font-family: "Euclid Circular A", "Poppins"; 6 | } 7 | 8 | .dropdown-4 :is(button, ul, .button-inner) { 9 | transform-origin: 50% 0; 10 | backface-visibility: hidden; 11 | transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275), 12 | background 0.3s, scale 0.3s; 13 | } 14 | 15 | .dropdown-4 button { 16 | position: relative; 17 | z-index: 1; 18 | background: transparent; 19 | border: 0; 20 | color: inherit; 21 | display: flex; 22 | align-items: center; 23 | justify-content: space-between; 24 | font-family: inherit; 25 | height: 60px; 26 | width: 160px; 27 | gap: 12px; 28 | padding: 0 20px 0 32px; 29 | cursor: pointer; 30 | } 31 | 32 | .dropdown-4 > button span { 33 | font-size: 28px; 34 | } 35 | 36 | .dropdown-4 > button .button-inner { 37 | flex: 1 1 auto; 38 | display: flex; 39 | align-items: center; 40 | justify-content: space-between; 41 | font-size: 16px; 42 | } 43 | 44 | .dropdown-4 ul { 45 | position: absolute; 46 | top: 0; 47 | left: 0; 48 | list-style: none; 49 | padding: 0; 50 | margin: 0; 51 | background: #3b1977; 52 | transform: rotateX(-90deg) translateZ(60px); 53 | } 54 | 55 | .dropdown-4.open ul { 56 | transform: rotate(0) translateZ(60px); 57 | } 58 | 59 | .dropdown-4 ul button { 60 | justify-content: flex-start; 61 | gap: 12px; 62 | text-transform: capitalize; 63 | padding: 0 16px; 64 | } 65 | 66 | .dropdown-4 ul button i { 67 | font-size: 20px; 68 | } 69 | 70 | .dropdown-4 ul button:hover { 71 | background: rgb(255 255 255 / 12%); 72 | } 73 | 74 | .dropdown-4 > button { 75 | background: #5d13f1; 76 | transform: rotate(0); 77 | } 78 | 79 | .dropdown-4:not(.open) > button:hover { 80 | scale: 1.05; 81 | } 82 | 83 | .dropdown-4.open > button { 84 | transform: rotateX(90deg); 85 | } 86 | 87 | .dropdown-4.open > button .button-inner { 88 | opacity: 0; 89 | } 90 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown4/Dropdown4.jsx: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect, useState } from "react"; 2 | import "./Dropdown4.css"; 3 | 4 | // Example items 5 | 6 | // const items = [ 7 | // "Trainers", 8 | // "Joggers", 9 | // "Tracksuits" 10 | // ] 11 | 12 | const useClickOutside = (ref, callback) => { 13 | const handleClick = (e) => { 14 | if (ref.current && !ref.current.contains(e.target)) { 15 | callback(); 16 | } 17 | }; 18 | useEffect(() => { 19 | document.addEventListener("click", handleClick); 20 | 21 | return () => { 22 | document.removeEventListener("click", handleClick); 23 | }; 24 | }); 25 | }; 26 | 27 | export const Dropdown4 = ({ buttonText, items, onItemClick }) => { 28 | const dropdownRef = useRef(null); 29 | 30 | const [isOpen, setIsOpen] = useState(false); 31 | 32 | const toggleIsOpen = () => setIsOpen(!isOpen); 33 | 34 | const handleItemClick = (item) => { 35 | onItemClick(item); 36 | toggleIsOpen(); 37 | }; 38 | 39 | useClickOutside(dropdownRef, () => setIsOpen(false)); 40 | 41 | return ( 42 |
43 | 49 |
    50 | {items.map((item) => ( 51 |
  • 52 | 56 |
  • 57 | ))} 58 |
59 |
60 | ); 61 | }; 62 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown4/Dropdown4Example.css: -------------------------------------------------------------------------------- 1 | .page.dropdown-4-page { 2 | background: #fdfcf1; 3 | color: #5f5a67; 4 | } 5 | 6 | .page.dropdown-4-page > div { 7 | translate: 0 -60px; 8 | } 9 | 10 | .Toastify__toast { 11 | font-family: inherit; 12 | text-transform: capitalize; 13 | } 14 | 15 | /* .Toastify__toast .Toastify__progress-bar--wrp { 16 | display: none; 17 | } */ 18 | -------------------------------------------------------------------------------- /src/components/dropdowns/Dropdown4/Dropdown4Example.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { ToastContainer, toast, cssTransition } from "react-toastify"; 3 | import { Dropdown4 } from "./Dropdown4"; 4 | import "./Dropdown4Example.css"; 5 | 6 | const items = ["instagram", "twitter", "github"]; 7 | 8 | export const Dropdown4Example = () => { 9 | const handleItemClick = (item) => 10 | toast.success(`Followed on ${item}`, { 11 | position: "bottom-center", 12 | autoClose: true, 13 | closeButton: false, 14 | }); 15 | 16 | return ( 17 | <> 18 | 19 |
20 |
21 | 26 |
27 |
28 | 29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /src/components/dropdowns/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Dropdown1/Dropdown1Example"; 2 | export * from "./Dropdown2/Dropdown2Example"; 3 | export * from "./Dropdown3/Dropdown3"; 4 | export * from "./Dropdown4/Dropdown4Example"; 5 | -------------------------------------------------------------------------------- /src/components/gsap/ScrollReveal/styles.css: -------------------------------------------------------------------------------- 1 | .scroll-reveal { 2 | display: flex; 3 | flex-wrap: wrap; 4 | justify-content: center; 5 | gap: 20px; 6 | padding: 20px 0; 7 | margin: 0 auto; 8 | } 9 | 10 | .scroll-reveal > div { 11 | background: #121419; 12 | height: 190px; 13 | width: 30%; 14 | opacity: 0; 15 | transition: background 0.3s; 16 | } 17 | 18 | .scroll-reveal > div:hover { 19 | background: #3e70ff; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/gsap/TypedMessage/TypedMessage.css: -------------------------------------------------------------------------------- 1 | .message { 2 | font-weight: inherit; 3 | line-height: inherit; 4 | font-size: 80px; 5 | text-shadow: 0 0 10px rgb(0 0 0 / 10%); 6 | } 7 | -------------------------------------------------------------------------------- /src/components/gsap/TypedMessage/TypedMessage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useRef } from "react"; 2 | import { gsap } from "gsap"; 3 | import { SplitText } from "gsap/all"; 4 | import { useGSAP } from "@gsap/react"; 5 | import "./TypedMessage.css"; 6 | 7 | gsap.registerPlugin(SplitText); 8 | 9 | export const TypedMessage = ({ message }) => { 10 | const blockRef = useRef(null); 11 | const tlRef = useRef(); 12 | 13 | useGSAP(() => { 14 | const s = new SplitText(blockRef.current, { 15 | type: "lines,words", 16 | }); 17 | 18 | const tl = gsap.timeline({ 19 | delay: 0.5, 20 | repeatDelay: 0.5, 21 | repeat: -1, 22 | }); 23 | 24 | tl.addLabel("enter"); 25 | 26 | tl.fromTo( 27 | s.words, 28 | { yPercent: 100 }, 29 | { 30 | yPercent: 0, 31 | ease: "circ.out", 32 | stagger: 0.2, 33 | }, 34 | "enter" 35 | ); 36 | 37 | tl.fromTo( 38 | s.words, 39 | { opacity: 0 }, 40 | { 41 | opacity: 1, 42 | ease: "power1.out", 43 | stagger: 0.2, 44 | }, 45 | "enter" 46 | ); 47 | 48 | tl.addPause(); 49 | 50 | tl.to( 51 | s.words, 52 | { 53 | yPercent: -200, 54 | opacity: 0, 55 | ease: "circ.in", 56 | stagger: 0.1, 57 | duration: 0.4, 58 | }, 59 | "exit" 60 | ); 61 | 62 | tl.to( 63 | s.words, 64 | { 65 | opacity: 0, 66 | ease: "power1.in", 67 | stagger: 0.1, 68 | duration: 0.4, 69 | }, 70 | "exit" 71 | ); 72 | 73 | tlRef.current = tl; 74 | }, []); 75 | 76 | const handleClick = () => { 77 | if (tlRef.current) { 78 | tlRef.current.play(); 79 | } 80 | }; 81 | 82 | return ( 83 |

84 | {message} 85 |

86 | ); 87 | }; 88 | -------------------------------------------------------------------------------- /src/components/gsap/TypedMessage/TypedMessageExample.css: -------------------------------------------------------------------------------- 1 | .typed-message-page { 2 | color: #222222; 3 | min-height: 100vh; 4 | background: url("./image.jpg"); 5 | background-size: cover; 6 | background-position: -360px; 7 | font-family: "Euclid Circular B", "Poppins"; 8 | } 9 | 10 | .typed-message-page::before { 11 | content: ""; 12 | z-index: 0; 13 | position: absolute; 14 | inset: 0; 15 | background: linear-gradient(rgb(0 0 0 / 86%), rgb(0 0 0 / 0%) 120%); 16 | } 17 | 18 | .typed-message-page nav { 19 | position: fixed; 20 | width: 100%; 21 | z-index: 2; 22 | display: flex; 23 | padding: 0 40px; 24 | align-items: center; 25 | height: 96px; 26 | color: #f7f7f7; 27 | } 28 | 29 | .typed-message-search { 30 | position: relative; 31 | flex: 1 1 auto; 32 | } 33 | 34 | .typed-message-search span { 35 | position: absolute; 36 | z-index: 3; 37 | top: 50%; 38 | left: 16px; 39 | translate: 0 -50%; 40 | } 41 | 42 | .typed-message-search input { 43 | border: 0; 44 | border-radius: 40px; 45 | height: 50px; 46 | background: rgb(255 255 255 / 10%); 47 | backdrop-filter: blur(10px); 48 | width: 100%; 49 | font-family: inherit; 50 | font-size: 16px; 51 | padding-left: 46px; 52 | } 53 | 54 | .typed-message-search input::placeholder { 55 | color: rgb(255 255 255 / 60%); 56 | } 57 | 58 | .typed-message-banner { 59 | position: relative; 60 | height: 100vh; 61 | border-radius: 50px; 62 | color: #ffffff; 63 | } 64 | 65 | .background-video { 66 | position: absolute; 67 | z-index: 0; 68 | inset: 0; 69 | overflow: hidden; 70 | top: 0; 71 | height: 100%; 72 | object-fit: cover; 73 | } 74 | 75 | .banner-overlay { 76 | position: absolute; 77 | z-index: 1; 78 | inset: 0; 79 | background: linear-gradient(rgb(0 0 0 / 40%), rgb(0 0 0 / 0%)); 80 | } 81 | 82 | .typed-message-banner-content { 83 | position: relative; 84 | z-index: 3; 85 | padding-top: 320px; 86 | padding-inline: 82px; 87 | display: flex; 88 | flex-direction: column; 89 | gap: 30px; 90 | } 91 | 92 | .typed-message-wrapper { 93 | font-size: 48px; 94 | font-weight: 400; 95 | max-width: 450px; 96 | line-height: 1.2; 97 | } 98 | 99 | .typed-message-banner-content > button { 100 | background: rgb(247 247 247 / 12%); 101 | color: #f7f7f7; 102 | backdrop-filter: blur(10px); 103 | font-family: inherit; 104 | padding: 0 32px; 105 | height: 64px; 106 | border-radius: 32px; 107 | border: 0; 108 | font-size: 22px; 109 | align-self: baseline; 110 | } 111 | 112 | .typed-message-logo { 113 | width: 140px; 114 | padding-right: 40px; 115 | } 116 | 117 | .typed-message-links { 118 | display: flex; 119 | width: 140px; 120 | justify-content: flex-end; 121 | align-items: center; 122 | gap: 16px; 123 | } 124 | 125 | .typed-message-links span { 126 | font-size: 24px; 127 | } 128 | -------------------------------------------------------------------------------- /src/components/gsap/TypedMessage/TypedMessageExample.jsx: -------------------------------------------------------------------------------- 1 | import { TypedMessage } from "./TypedMessage"; 2 | import "./TypedMessageExample.css"; 3 | import image from "./image.jpg"; 4 | import logo from "./logo.svg"; 5 | import video from "./video.mp4"; 6 | 7 | export const TypedMessageExample = () => { 8 | return ( 9 |
10 | 22 |
23 | 27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 |
35 | ); 36 | }; 37 | -------------------------------------------------------------------------------- /src/components/gsap/TypedMessage/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/gsap/TypedMessage/image.jpg -------------------------------------------------------------------------------- /src/components/gsap/TypedMessage/video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/gsap/TypedMessage/video.mp4 -------------------------------------------------------------------------------- /src/components/gsap/index.js: -------------------------------------------------------------------------------- 1 | export * from "./ScrollReveal/ScrollReveal"; 2 | export * from "./TypedMessage/TypedMessageExample"; 3 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | export * from "./buttons"; 2 | export * from "./carousels"; 3 | export * from "./controls"; 4 | export * from "./sidebars"; 5 | export * from "./gsap"; 6 | export * from "./libraries"; 7 | export * from "./accordions"; 8 | export * from "./logins"; 9 | export * from "./cards"; 10 | export * from "./modals"; 11 | export * from "./parallax"; 12 | export * from "./dropdowns"; 13 | export * from "./widgets"; 14 | export * from "./navbars"; 15 | export * from "./tables"; 16 | export * from "./signups"; 17 | -------------------------------------------------------------------------------- /src/components/libraries/index.js: -------------------------------------------------------------------------------- 1 | export * from "./rc-slider/RcSlider"; 2 | export * from "./react-dropzone/ReactDropzone"; 3 | export * from "./react-xarrows/ReactXarrows"; 4 | -------------------------------------------------------------------------------- /src/components/libraries/rc-slider/RcSlider.css: -------------------------------------------------------------------------------- 1 | .page.rc-slider-page { 2 | background: #393965; 3 | font-family: "Euclid Circular A", "Poppins"; 4 | } 5 | 6 | .slider-card { 7 | --color-primary: #756bea; 8 | --color-card: #26263c; 9 | display: grid; 10 | gap: 14px; 11 | padding: 20px 20px 24px; 12 | width: 260px; 13 | background: var(--color-card); 14 | border-radius: 10px; 15 | box-shadow: 0 20px 30px rgb(0 0 0 / 10%); 16 | } 17 | 18 | .slider-card h2 { 19 | margin: 0 0 8px; 20 | font-size: 14px; 21 | font-weight: 400; 22 | color: rgb(255 255 255 / 50%); 23 | } 24 | 25 | .slider-card var { 26 | margin: 0; 27 | font-size: 38px; 28 | font-weight: 400; 29 | font-style: normal; 30 | color: rgb(255 255 255 / 100%); 31 | } 32 | 33 | .slider-card var abbr { 34 | color: rgb(255 255 255 / 25%); 35 | margin-right: 4px; 36 | } 37 | 38 | body .rc-slider-rail { 39 | background: rgb(255 255 255 / 12%); 40 | } 41 | 42 | body .rc-slider-handle { 43 | border-color: var(--color-card); 44 | background: var(--color-primary); 45 | opacity: 1; 46 | scale: 1.5; 47 | } 48 | 49 | body .rc-slider-handle:hover, 50 | body .rc-slider-handle-dragging { 51 | box-shadow: none !important; 52 | border-color: var(--color-card) !important; 53 | cursor: pointer; 54 | } 55 | 56 | body .rc-slider-track { 57 | background: var(--color-primary); 58 | } 59 | -------------------------------------------------------------------------------- /src/components/libraries/rc-slider/RcSlider.jsx: -------------------------------------------------------------------------------- 1 | import Slider from "rc-slider"; 2 | import "rc-slider/assets/index.css"; 3 | import { useState } from "react"; 4 | import "./RcSlider.css"; 5 | 6 | export const RcSlider = () => { 7 | const [value, setValue] = useState(20000); 8 | 9 | const handleChange = (val) => setValue(Number(val)); 10 | 11 | return ( 12 |
13 |
14 |
15 |

Mortgage Value

16 | 17 | $ 18 | {value.toLocaleString("en-US")} 19 | 20 |
21 | 22 |
23 |
24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/components/libraries/react-dropzone/ReactDropzone.css: -------------------------------------------------------------------------------- 1 | .page.dropzone-page { 2 | background: #212224; 3 | --color-card: #161718; 4 | } 5 | 6 | .dropzone-card { 7 | border-radius: 6px; 8 | background: var(--color-card); 9 | padding: 40px; 10 | display: flex; 11 | flex-direction: column; 12 | justify-content: center; 13 | align-items: center; 14 | gap: 16px; 15 | text-align: center; 16 | } 17 | 18 | .dropzone-card h2 { 19 | font-weight: 400; 20 | margin: 0 0 6px; 21 | } 22 | 23 | .dropzone-card h3 { 24 | font-weight: 400; 25 | opacity: 0.5; 26 | margin: 0 0 50px; 27 | } 28 | 29 | .dropzone-card img { 30 | position: absolute; 31 | top: -50px; 32 | width: 100px; 33 | border-radius: 50%; 34 | border: 8px solid var(--color-card); 35 | } 36 | 37 | .dropzone { 38 | position: relative; 39 | flex: 1; 40 | display: flex; 41 | flex-direction: column; 42 | align-items: center; 43 | justify-content: center; 44 | padding: 20px; 45 | width: 280px; 46 | min-height: 200px; 47 | border-width: 2px; 48 | border-radius: 6px; 49 | border-color: #464646; 50 | border-style: dashed; 51 | background-color: transparent; 52 | color: #bdbdbd; 53 | outline: none; 54 | } 55 | -------------------------------------------------------------------------------- /src/components/libraries/react-dropzone/ReactDropzone.jsx: -------------------------------------------------------------------------------- 1 | import "./ReactDropzone.css"; 2 | import { useDropzone } from "react-dropzone"; 3 | import icon from "./icon.svg"; 4 | 5 | export const ReactDropzone = () => { 6 | const onDrop = (acceptedFiles) => { 7 | // Do something with the files 8 | }; 9 | const { getRootProps, getInputProps, isDragActive, acceptedFiles } = 10 | useDropzone({ onDrop }); 11 | const files = acceptedFiles.map((file) => ( 12 |
  • {file.path}
  • 13 | )); 14 | 15 | return ( 16 |
    17 |
    18 |
    19 |

    Upload Files

    20 |

    Fast and easy

    21 |
    22 |
    23 | 24 | 25 | {isDragActive ? ( 26 |

    Drop the files here ...

    27 | ) : ( 28 |

    Drag 'n' drop some files here, or click to select files

    29 | )} 30 |
    31 | {files.length > 0 && ( 32 | <> 33 |

    Files

    34 |
      {files}
    35 | 36 | )} 37 |
    38 |
    39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /src/components/libraries/react-dropzone/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 12 | 13 | 18 | 24 | 25 | -------------------------------------------------------------------------------- /src/components/libraries/react-xarrows/ReactXarrows.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/libraries/react-xarrows/ReactXarrows.css -------------------------------------------------------------------------------- /src/components/libraries/react-xarrows/ReactXarrows.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Xarrow, { useXarrow, Xwrapper } from "react-xarrows"; 3 | import Draggable from "react-draggable"; 4 | 5 | const boxStyle = { 6 | border: "grey solid 2px", 7 | borderRadius: "10px", 8 | padding: "5px", 9 | }; 10 | 11 | const DraggableBox = ({ id }) => { 12 | const updateXarrow = useXarrow(); 13 | return ( 14 | 15 |
    16 | {id} 17 |
    18 |
    19 | ); 20 | }; 21 | 22 | export const ReactXarrows = () => { 23 | return ( 24 |
    27 | 28 | 29 | 30 | 31 | 32 |
    33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /src/components/logins/Login1/Login1.jsx: -------------------------------------------------------------------------------- 1 | import "./styles.css"; 2 | import logo from "./logo.svg"; 3 | 4 | export const Login1 = () => { 5 | return ( 6 |
    7 |
    8 |
    9 | 10 |

    Welcome back

    11 |
    12 | 13 | 14 | 15 |
    16 |
    17 | Need an account? Sign up here 18 |
    19 |
    20 |
    21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /src/components/logins/Login1/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/logins/Login1/styles.css: -------------------------------------------------------------------------------- 1 | .page.login-1 { 2 | display: grid; 3 | place-items: center; 4 | gap: 50px; 5 | margin: 0; 6 | height: 100vh; 7 | padding: 0 32px; 8 | color: #aaaaaa; 9 | background: #eff9ff; 10 | font-family: "Euclid Circular A", "Poppins"; 11 | } 12 | 13 | @media (width >= 500px) { 14 | .page.login-1 { 15 | padding: 0; 16 | } 17 | } 18 | 19 | .login-1-background { 20 | position: fixed; 21 | top: -50vmin; 22 | left: -50vmin; 23 | width: 100vmin; 24 | height: 100vmin; 25 | border-radius: 47% 53% 61% 39% / 45% 51% 49% 55%; 26 | background: #65c8ff; 27 | } 28 | 29 | .login-1-background::after { 30 | content: ""; 31 | position: inherit; 32 | right: -50vmin; 33 | bottom: -55vmin; 34 | width: inherit; 35 | height: inherit; 36 | border-radius: inherit; 37 | background: #143d81; 38 | } 39 | 40 | .login-1-card { 41 | overflow: hidden; 42 | position: relative; 43 | z-index: 3; 44 | width: 94%; 45 | margin: 0 20px; 46 | padding: 170px 30px 54px; 47 | border-radius: 24px; 48 | background: #ffffff; 49 | text-align: center; 50 | box-shadow: 0 100px 100px rgb(0 0 0 / 10%); 51 | } 52 | 53 | .login-1-card::before { 54 | content: ""; 55 | position: absolute; 56 | top: -880px; 57 | left: 50%; 58 | translate: -50% 0; 59 | width: 1000px; 60 | height: 1000px; 61 | border-radius: 50%; 62 | background: #216ce7; 63 | } 64 | 65 | @media (width >= 500px) { 66 | .login-1-card { 67 | margin: 0; 68 | width: 360px; 69 | } 70 | } 71 | 72 | .login-1-card > img { 73 | position: absolute; 74 | top: 30px; 75 | left: 50%; 76 | translate: -50% 0; 77 | width: 64px; 78 | height: 64px; 79 | } 80 | 81 | .login-1-card > h2 { 82 | font-size: 22px; 83 | font-weight: 400; 84 | margin: 0 0 38px; 85 | color: rgb(0 0 0 / 38%); 86 | } 87 | 88 | .login-1-card form { 89 | margin: 0 0 44px; 90 | display: grid; 91 | gap: 12px; 92 | } 93 | 94 | .login-1-card form :is(input, button) { 95 | width: 100%; 96 | height: 56px; 97 | border-radius: 28px; 98 | font-size: 16px; 99 | font-family: inherit; 100 | } 101 | 102 | .login-1-card form > input { 103 | border: 0; 104 | padding: 0 24px; 105 | color: #222222; 106 | background: #ededed; 107 | } 108 | 109 | .login-1-card form > input::placeholder { 110 | color: rgb(0 0 0 / 28%); 111 | } 112 | 113 | .login-1-card form > button { 114 | border: 0; 115 | color: #f9f9f9; 116 | background: #226ce7; 117 | display: grid; 118 | place-items: center; 119 | font-weight: 500; 120 | cursor: pointer; 121 | } 122 | 123 | .login-1-card form > footer { 124 | color: #a1a1a1; 125 | } 126 | 127 | .login-1-card form > footer > a { 128 | color: #216ce7; 129 | } 130 | -------------------------------------------------------------------------------- /src/components/logins/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Login1/Login1"; 2 | -------------------------------------------------------------------------------- /src/components/modals/Modal1/Modal1.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./styles.css"; 3 | import logo from "./logo.svg"; 4 | 5 | export const Modal1 = () => { 6 | const [isOpen, setIsOpen] = useState(false); 7 | 8 | const toggleModal = () => setIsOpen(!isOpen); 9 | 10 | return ( 11 |
    12 |
    16 |
    17 |
    18 |

    Sign Up

    19 |

    Try Hologram today

    20 |
    21 |
    22 |
    23 | account_circle 24 | 25 |
    26 |
    27 | lock 28 | 29 |
    30 | 38 |
    39 |

    No credit card information required

    40 |
    41 |
    42 | 90 |
    91 | ); 92 | }; 93 | -------------------------------------------------------------------------------- /src/components/modals/Modal2/Modal2 copy.css: -------------------------------------------------------------------------------- 1 | .overlay, 2 | .dialog { 3 | position: fixed; 4 | } 5 | 6 | @keyframes overlay-in { 7 | 0% { 8 | scale: 0 0.003; 9 | } 10 | 33%, 11 | 36% { 12 | scale: 1 0.003; 13 | } 14 | 66%, 15 | 100% { 16 | scale: 1 1; 17 | } 18 | } 19 | 20 | .overlay { 21 | z-index: 1; 22 | top: 0; 23 | left: 0; 24 | right: 0; 25 | bottom: 0; 26 | background: rgb(0 0 0 / 75%); 27 | display: grid; 28 | place-items: center; 29 | } 30 | 31 | .overlay.open { 32 | animation: overlay-in 1s both; 33 | } 34 | 35 | .overlay.closed { 36 | animation: overlay-in 1s 0.25s reverse both; 37 | } 38 | 39 | .overlay.default { 40 | scale: 0; 41 | } 42 | 43 | @keyframes modal-in { 44 | 0% { 45 | opacity: 0; 46 | visibility: hidden; 47 | scale: 0.5; 48 | } 49 | 100% { 50 | opacity: 1; 51 | visibility: visible; 52 | scale: 1; 53 | } 54 | } 55 | 56 | .dialog { 57 | z-index: 2; 58 | width: 380px; 59 | top: 50%; 60 | left: 50%; 61 | background: #ffffff; 62 | border-radius: 12px; 63 | padding: 0 40px 50px; 64 | translate: -50% -50%; 65 | box-shadow: 0 10px 30px rgb(0 0 0 / 24%); 66 | } 67 | 68 | .dialog.default { 69 | opacity: 0; 70 | visibility: hidden; 71 | } 72 | 73 | .dialog.open { 74 | animation: modal-in 0.5s 0.6s both; 75 | } 76 | 77 | .dialog.closed { 78 | animation: modal-in 0.5s reverse both; 79 | } 80 | 81 | .dialog header { 82 | background: linear-gradient(90deg, #9d50bb, #6e48aa); 83 | margin: -85px -20px 30px; 84 | border-radius: 12px; 85 | height: 170px; 86 | display: flex; 87 | justify-content: center; 88 | flex-direction: column; 89 | padding-left: 40px; 90 | box-shadow: 0 16px 30px rgb(0 0 0 / 12%); 91 | } 92 | 93 | .dialog header h2 { 94 | margin-bottom: 10px; 95 | font-size: 29px; 96 | } 97 | 98 | .dialog header h3 { 99 | opacity: 0.45; 100 | font-weight: 400; 101 | } 102 | -------------------------------------------------------------------------------- /src/components/modals/Modal2/Modal2.css: -------------------------------------------------------------------------------- 1 | .modal-2-overlay, 2 | .modal-2-modal { 3 | position: fixed; 4 | } 5 | 6 | @keyframes overlay-in { 7 | 0% { 8 | scale: 0 0.003; 9 | } 10 | 33%, 11 | 36% { 12 | scale: 1 0.003; 13 | } 14 | 66%, 15 | 100% { 16 | scale: 1 1; 17 | } 18 | } 19 | 20 | .modal-2-overlay { 21 | z-index: 1; 22 | top: 0; 23 | left: 0; 24 | right: 0; 25 | bottom: 0; 26 | background: rgb(0 0 0 / 75%); 27 | display: grid; 28 | place-items: center; 29 | } 30 | 31 | .modal-2-overlay.open { 32 | animation: overlay-in 1s both; 33 | } 34 | 35 | .modal-2-overlay.closed { 36 | animation: overlay-in 1s 0.25s reverse both; 37 | } 38 | 39 | .modal-2-overlay.default { 40 | scale: 0; 41 | } 42 | 43 | @keyframes modal-in { 44 | 0% { 45 | opacity: 0; 46 | visibility: hidden; 47 | scale: 0.5; 48 | } 49 | 100% { 50 | opacity: 1; 51 | visibility: visible; 52 | scale: 1; 53 | } 54 | } 55 | 56 | .modal-2-modal { 57 | z-index: 2; 58 | width: 380px; 59 | top: 50%; 60 | left: 50%; 61 | background: #ffffff; 62 | border-radius: 12px; 63 | padding: 0 40px 50px; 64 | translate: -50% -50%; 65 | box-shadow: 0 10px 30px rgb(0 0 0 / 24%); 66 | } 67 | 68 | .modal-2-modal.default { 69 | opacity: 0; 70 | visibility: hidden; 71 | } 72 | 73 | .modal-2-modal.open { 74 | animation: modal-in 0.5s 0.6s both; 75 | } 76 | 77 | .modal-2-modal.closed { 78 | animation: modal-in 0.5s reverse both; 79 | } 80 | 81 | .modal-2-modal header { 82 | background: linear-gradient(90deg, #9d50bb, #6e48aa); 83 | margin: -85px -20px 30px; 84 | border-radius: 12px; 85 | height: 170px; 86 | display: flex; 87 | justify-content: center; 88 | flex-direction: column; 89 | padding-left: 40px; 90 | box-shadow: 0 16px 30px rgb(0 0 0 / 12%); 91 | } 92 | 93 | .modal-2-modal header h2 { 94 | margin-bottom: 10px; 95 | font-size: 29px; 96 | } 97 | 98 | .modal-2-modal header h3 { 99 | opacity: 0.45; 100 | font-weight: 400; 101 | } 102 | -------------------------------------------------------------------------------- /src/components/modals/Modal2/Modal2.jsx: -------------------------------------------------------------------------------- 1 | import { createPortal } from "react-dom"; 2 | import "./Modal2.css"; 3 | 4 | export const Modal2 = ({ 5 | title, 6 | subtitle, 7 | modalContent, 8 | toggleModal, 9 | isOpen, 10 | }) => { 11 | const open = isOpen === null ? "default" : isOpen ? "open" : "closed"; 12 | 13 | const Overlay = () => ( 14 |
    15 | ); 16 | 17 | const Dialog = () => ( 18 |
    e.stopPropagation()} 21 | > 22 |
    23 |

    {title}

    24 |

    {subtitle}

    25 |
    26 | {modalContent} 27 |
    28 | ); 29 | 30 | return ( 31 | <> 32 | {createPortal(, document.body)} 33 | {createPortal(, document.body)} 34 | 35 | ); 36 | }; 37 | -------------------------------------------------------------------------------- /src/components/modals/Modal2/Modal2Example.css: -------------------------------------------------------------------------------- 1 | .page.modal-2-page { 2 | background: #ffffff; 3 | } 4 | 5 | .page.modal-2-page .container { 6 | max-width: 700px; 7 | margin: 0 auto; 8 | } 9 | 10 | .modal-2-footer { 11 | position: fixed; 12 | left: 0; 13 | bottom: 0; 14 | right: 0; 15 | height: calc(50vh + 1px); 16 | padding-bottom: 20px; 17 | background: #161022; 18 | color: #e5e2e9; 19 | } 20 | 21 | .modal-2-footer article { 22 | display: flex; 23 | flex-direction: column; 24 | align-items: center; 25 | justify-content: space-between; 26 | gap: 16px; 27 | padding: 20px 40px 40px; 28 | margin: -99px 20px 20px; 29 | border-radius: 10px; 30 | background: linear-gradient(90deg, #9d50bb, #6e48aa); 31 | } 32 | 33 | .modal-2-footer article h2 { 34 | font-weight: 400; 35 | color: #f9f9f9; 36 | } 37 | 38 | .signup-button { 39 | display: flex; 40 | align-items: center; 41 | justify-content: space-between; 42 | gap: 10px; 43 | padding: 0 20px 0 20px; 44 | width: 100%; 45 | height: 56px; 46 | background: #161022; 47 | border: 0; 48 | border-radius: 6px; 49 | color: #e5e2e9; 50 | font-family: inherit; 51 | font-size: 16px; 52 | cursor: pointer; 53 | } 54 | 55 | .modal-2-footer section { 56 | padding: 0 50px; 57 | } 58 | 59 | .modal-2-footer section.top { 60 | padding-top: 30px; 61 | margin-bottom: 48px; 62 | } 63 | 64 | .modal-2-footer section.top img { 65 | display: block; 66 | height: 30px; 67 | margin: 0 0 30px; 68 | } 69 | 70 | .modal-2-footer section.top ul { 71 | list-style: none; 72 | padding: 0; 73 | margin: 0; 74 | display: grid; 75 | gap: 30px; 76 | grid-template-columns: repeat(2, 1fr); 77 | } 78 | 79 | @media (width > 480px) { 80 | .modal-2-footer article button { 81 | width: 70%; 82 | } 83 | 84 | .modal-2-footer section.top ul { 85 | padding-right: 10%; 86 | } 87 | } 88 | 89 | @media (width > 600px) { 90 | .modal-2-footer article { 91 | flex-direction: row; 92 | min-height: 140px; 93 | margin: -70px 20px 20px; 94 | padding: 30px 50px 30px; 95 | } 96 | 97 | .modal-2-footer article button { 98 | width: auto; 99 | padding: 0 20px 0 24px; 100 | } 101 | 102 | .modal-2-footer section.top ul { 103 | grid-template-columns: repeat(4, 1fr); 104 | padding-right: 0; 105 | } 106 | } 107 | 108 | .modal-2-footer section.top ul li a { 109 | display: block; 110 | margin-bottom: 18px; 111 | color: #e5e2e9; 112 | } 113 | 114 | .modal-2-footer section.top h3 { 115 | color: #9a90a9; 116 | font-weight: 400; 117 | text-transform: uppercase; 118 | font-size: 12px; 119 | letter-spacing: 1px; 120 | margin-bottom: 20px; 121 | } 122 | 123 | .modal-2-modal form { 124 | display: grid; 125 | gap: 16px; 126 | } 127 | 128 | .modal-2-modal input { 129 | border: 0; 130 | background: #ececec; 131 | height: 56px; 132 | border-radius: 6px; 133 | font-family: inherit; 134 | padding: 0 20px; 135 | font-size: 16px; 136 | } 137 | 138 | .modal-2-modal input::placeholder { 139 | color: #96939c; 140 | } 141 | 142 | .modal-2-modal > p { 143 | color: #96939c; 144 | margin: 30px 0 0; 145 | text-align: center; 146 | } 147 | -------------------------------------------------------------------------------- /src/components/modals/Modal2/Modal2Example.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./Modal2Example.css"; 3 | import { Modal2 } from "./Modal2"; 4 | import logo from "./logo.svg"; 5 | 6 | export const Modal2Example = () => { 7 | const [isOpen, setIsOpen] = useState(null); 8 | 9 | const toggleModal = () => setIsOpen(!isOpen); 10 | 11 | return ( 12 |
    13 | 20 |
    21 | 22 | 23 | 30 |
    31 |

    No credit card information required

    32 | 33 | } 34 | /> 35 | 83 |
    84 | ); 85 | }; 86 | -------------------------------------------------------------------------------- /src/components/modals/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Modal1/Modal1"; 2 | export * from "./Modal2/Modal2"; 3 | export * from "./Modal2/Modal2Example"; 4 | -------------------------------------------------------------------------------- /src/components/navbars/Navbar1/Navbar1.css: -------------------------------------------------------------------------------- 1 | .page.navbar-1-page { 2 | background: #09090b; 3 | color: #faf9f5; 4 | font-family: "Euclid Circular A", "Poppins"; 5 | padding-top: 72px; 6 | margin: 0; 7 | } 8 | 9 | .navbar-1 { 10 | position: fixed; 11 | z-index: 1; 12 | top: 0; 13 | left: 0; 14 | translate: 0 -72px; 15 | display: flex; 16 | align-items: center; 17 | justify-content: space-between; 18 | gap: 20px; 19 | padding: 0 20px; 20 | width: 100%; 21 | height: 72px; 22 | box-shadow: 0 10px 20px rgb(0 0 0 / 10%); 23 | background: #4f52ff; 24 | transition: 0.3s; 25 | } 26 | 27 | .navbar-1.visible { 28 | top: 0; 29 | translate: 0; 30 | } 31 | 32 | .navbar-1 > h1 { 33 | width: 36px; 34 | height: 36px; 35 | background: #f9f9f9; 36 | color: #4f52ff; 37 | display: grid; 38 | place-items: center; 39 | border-radius: 50%; 40 | } 41 | 42 | .navbar-1 .nav-items { 43 | display: flex; 44 | align-items: center; 45 | gap: 16px; 46 | } 47 | 48 | .navbar-1 .nav-items > a { 49 | text-decoration: none; 50 | font-weight: 400; 51 | color: rgb(255 255 255 / 96%); 52 | height: 72px; 53 | display: grid; 54 | place-items: center; 55 | } 56 | 57 | .navbar-1 .nav-items > a:hover { 58 | color: rgb(255 255 255 / 96%); 59 | } 60 | 61 | .page.navbar-1-page h2 { 62 | font-size: 20px; 63 | margin: 0 0 4px; 64 | cursor: default; 65 | } 66 | 67 | .page.navbar-1-page section { 68 | display: flex; 69 | align-items: center; 70 | gap: 40px; 71 | padding: 100px 60px; 72 | } 73 | 74 | .page.navbar-1-page p { 75 | opacity: 0.6; 76 | } 77 | 78 | .page.navbar-1-page section.shaded { 79 | background: #0e0e11; 80 | } 81 | 82 | .page.navbar-1-page section > img { 83 | width: 200px; 84 | height: 200px; 85 | } 86 | 87 | .page.navbar-1-page section.shaded > img { 88 | padding: 20px; 89 | } 90 | 91 | .page.navbar-1-page section > p { 92 | line-height: 1.7; 93 | } 94 | -------------------------------------------------------------------------------- /src/components/navbars/Navbar2/Navbar2.css: -------------------------------------------------------------------------------- 1 | .navbar-2 { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | right: 0; 6 | height: 72px; 7 | border-bottom: 1px solid rgb(255 255 255 / 10%); 8 | display: flex; 9 | align-items: center; 10 | padding: 0 24px; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/navbars/Navbar2/Navbar2.jsx: -------------------------------------------------------------------------------- 1 | export const Navbar2 = () => { 2 | return ( 3 | 8 | ); 9 | }; 10 | -------------------------------------------------------------------------------- /src/components/navbars/Navbar3/Navbar3.css: -------------------------------------------------------------------------------- 1 | .page.navbar-3-page { 2 | background: #f8f7ff; 3 | font-family: "Euclid Circular A", "Poppins"; 4 | } 5 | 6 | .navbar-3 { 7 | --color-primary: #6f5bf3; 8 | position: fixed; 9 | top: 0; 10 | left: 0; 11 | z-index: 1; 12 | display: flex; 13 | align-items: center; 14 | padding: 0 20px; 15 | height: 72px; 16 | width: 100%; 17 | background: #ffffff; 18 | color: #5b5968; 19 | box-shadow: 0 10px 50px rgb(0 0 0 / 2%); 20 | } 21 | 22 | .navbar-3 a { 23 | padding: 0 12px; 24 | display: flex; 25 | align-items: center; 26 | cursor: pointer; 27 | width: 100%; 28 | height: 72px; 29 | font-size: 15px; 30 | } 31 | 32 | .navbar-3 > img { 33 | margin: 0 24px 0 0; 34 | height: 36px; 35 | width: 36px; 36 | } 37 | 38 | .navbar-3-menu { 39 | display: flex; 40 | align-items: center; 41 | justify-content: center; 42 | font-weight: 500; 43 | } 44 | 45 | .navbar-3-dropdown { 46 | position: fixed; 47 | z-index: 1; 48 | top: 82px; 49 | left: 0; 50 | height: 0; 51 | width: 120px; 52 | padding: 6px 0; 53 | overflow: hidden; 54 | display: grid; 55 | opacity: 0; 56 | visibility: hidden; 57 | transition: 0.3s; 58 | border-radius: 6px; 59 | background: #ffffff; 60 | box-shadow: 0 0 30px rgb(0 0 0 / 4%); 61 | transition: 0.3s; 62 | } 63 | 64 | .navbar-3 a:is(:hover, .active) { 65 | color: var(--color-primary); 66 | } 67 | 68 | .navbar-3-dropdown.visible { 69 | opacity: 1; 70 | visibility: visible; 71 | height: max-content; 72 | } 73 | 74 | .navbar-3-dropdown::after { 75 | content: ""; 76 | position: absolute; 77 | inset: 0; 78 | top: -12px; 79 | } 80 | 81 | .navbar-3-dropdown > a { 82 | position: relative; 83 | z-index: 1; 84 | height: 40px; 85 | font-size: 14px; 86 | white-space: nowrap; 87 | } 88 | 89 | .navbar-3-search { 90 | position: relative; 91 | margin-left: auto; 92 | } 93 | 94 | .navbar-3-search span { 95 | position: absolute; 96 | top: 50%; 97 | left: 12px; 98 | translate: 0 -50%; 99 | font-size: 18px; 100 | } 101 | 102 | .navbar-3-search input { 103 | border: 0; 104 | border-radius: 6px; 105 | height: 36px; 106 | width: 100%; 107 | max-width: 200px; 108 | background: #f6f5fd; 109 | padding-left: 36px; 110 | font-size: 15px; 111 | } 112 | 113 | .navbar-3-search span, 114 | .navbar-3-search input::placeholder { 115 | color: #9b98b1; 116 | } 117 | -------------------------------------------------------------------------------- /src/components/navbars/Navbar3/Navbar3.jsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import avatar from "./avatar.png"; 3 | import "./Navbar3.css"; 4 | 5 | const items = [ 6 | { 7 | name: "About", 8 | }, 9 | { 10 | name: "Skills", 11 | items: ["UI/UX", "Development", "Design"], 12 | }, 13 | { 14 | name: "Projects", 15 | items: ["Chatbot", "Calculator", "Weather"], 16 | }, 17 | { 18 | name: "Work", 19 | items: ["Portfolio", "Resume", "GitHub"], 20 | }, 21 | ]; 22 | 23 | const Link = ({ item, activeItem, onHover }) => { 24 | const linkRef = useRef(); 25 | 26 | const handleHover = () => { 27 | const rect = linkRef.current.getBoundingClientRect(); 28 | onHover(item, `${rect.x}px`); 29 | }; 30 | 31 | return ( 32 | 37 | {item.name} 38 | 39 | ); 40 | }; 41 | 42 | const Search = () => ( 43 |
    44 | search 45 | 46 |
    47 | ); 48 | 49 | export const Navbar3 = () => { 50 | const [translateX, setTranslateX] = useState("0"); 51 | const [activeItem, setActiveItem] = useState(null); 52 | 53 | const handleLinkHover = (item, x) => { 54 | setActiveItem(item || null); 55 | setTranslateX(x); 56 | }; 57 | 58 | return ( 59 |
    60 | 83 |
    84 | ); 85 | }; 86 | -------------------------------------------------------------------------------- /src/components/navbars/Navbar3/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/navbars/Navbar3/avatar.png -------------------------------------------------------------------------------- /src/components/navbars/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Navbar1/Navbar1"; 2 | export * from "./Navbar2/Navbar2"; 3 | export * from "./Navbar3/Navbar3"; 4 | -------------------------------------------------------------------------------- /src/components/parallax/index.js: -------------------------------------------------------------------------------- 1 | export * from "./parallax-1/Parallax1"; 2 | -------------------------------------------------------------------------------- /src/components/parallax/parallax-1/Parallax1.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import "./styles.css"; 3 | 4 | export const Parallax1 = () => { 5 | const [scrollPosition, setScrollPosition] = useState(0); 6 | 7 | const handleScroll = () => setScrollPosition(window.scrollY); 8 | 9 | useEffect(() => { 10 | window.addEventListener("scroll", handleScroll, { passive: true }); 11 | 12 | return () => { 13 | window.removeEventListener("scroll", handleScroll); 14 | }; 15 | }, []); 16 | 17 | return ( 18 |
    19 |
    25 |

    Parallax

    26 | 27 |
    28 |
    29 |

    What is parallax?

    30 |

    31 | Parallax is a displacement or difference in the apparent position of 32 | an object viewed along two different lines of sight and is measured by 33 | the angle or half-angle of inclination between those two lines. Due to 34 | foreshortening, nearby objects show a larger parallax than farther 35 | objects, so parallax can be used to determine distances. 36 |

    37 |

    38 | Parallax also affects optical instruments such as rifle scopes, 39 | binoculars, microscopes, and twin-lens reflex cameras that view 40 | objects from slightly different angles. Many animals, along with 41 | humans, have two eyes with overlapping visual fields that use parallax 42 | to gain depth perception; this process is known as stereopsis. In 43 | computer vision the effect is used for computer stereo vision, and 44 | there is a device called a parallax rangefinder that uses it to find 45 | the range, and in some variations also altitude to a target. 46 |

    47 |

    48 | Parallax is a displacement or difference in the apparent position of 49 | an object viewed along two different lines of sight and is measured by 50 | the angle or half-angle of inclination between those two lines. Due to 51 | foreshortening, nearby objects show a larger parallax than farther 52 | objects, so parallax can be used to determine distances. 53 |

    54 |

    55 | Parallax also affects optical instruments such as rifle scopes, 56 | binoculars, microscopes, and twin-lens reflex cameras that view 57 | objects from slightly different angles. Many animals, along with 58 | humans, have two eyes with overlapping visual fields that use parallax 59 | to gain depth perception; this process is known as stereopsis. In 60 | computer vision the effect is used for computer stereo vision, and 61 | there is a device called a parallax rangefinder that uses it to find 62 | the range, and in some variations also altitude to a target. 63 |

    64 |
    65 |
    66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /src/components/parallax/parallax-1/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/parallax/parallax-1/bg.png -------------------------------------------------------------------------------- /src/components/parallax/parallax-1/styles.css: -------------------------------------------------------------------------------- 1 | .page.parallax-1-page { 2 | background: #0e0d0e; 3 | height: 100%; 4 | font-family: "Euclid Circular A", "Poppins"; 5 | } 6 | 7 | * { 8 | box-sizing: border-box; 9 | } 10 | 11 | .parallax-banner { 12 | display: flex; 13 | justify-content: center; 14 | align-items: center; 15 | flex-direction: column; 16 | background-image: url("./bg.png"); 17 | background-size: cover; 18 | background-repeat: no-repeat; 19 | background-position: 50% 70%; 20 | height: 600px; 21 | width: 100vw; 22 | transition: 0.05s linear; 23 | } 24 | 25 | .parallax-banner h2 { 26 | font-size: 48px; 27 | color: #f8f8f8; 28 | padding-top: 0; 29 | margin-top: 0; 30 | margin-bottom: 10px; 31 | } 32 | 33 | .parallax-banner button { 34 | border: 0; 35 | background: #ffffff; 36 | color: #222222; 37 | padding: 10px 24px; 38 | border-radius: 30px; 39 | font-family: inherit; 40 | font-size: 16px; 41 | font-weight: 600; 42 | } 43 | 44 | .parallax-container { 45 | padding: 0 10%; 46 | } 47 | 48 | .parallax-banner h2 { 49 | margin-top: 0; 50 | margin-bottom: 40px; 51 | padding-top: 60px; 52 | } 53 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar1/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .page.sidebar-1-page { 6 | margin: 0; 7 | background: #12131a; 8 | font-family: "Euclid Circular A"; 9 | } 10 | 11 | .sidebar-1 button { 12 | background: transparent; 13 | border: 0; 14 | padding: 0; 15 | cursor: pointer; 16 | text-align: left; 17 | } 18 | 19 | .sidebar-1 { 20 | position: fixed; 21 | top: 0; 22 | left: 0; 23 | display: flex; 24 | flex-direction: column; 25 | gap: 8px; 26 | width: 260px; 27 | height: 100%; 28 | padding: 0 16px; 29 | background: #1d212a; 30 | border-right: 1px solid #2e303e; 31 | transition: width 0.4s; 32 | } 33 | 34 | .sidebar-1 .sidebar-header { 35 | display: flex; 36 | align-items: center; 37 | height: 72px; 38 | padding: 0 1.25rem 0 0; 39 | border-bottom: 1px solid #2e303e; 40 | color: #e1ecff; 41 | } 42 | 43 | .sidebar-1 .sidebar-header button { 44 | width: 54px; 45 | } 46 | 47 | .sidebar-1 .sidebar-logo { 48 | height: 20px; 49 | } 50 | 51 | .sidebar-1 button { 52 | position: relative; 53 | display: flex; 54 | gap: 16px; 55 | align-items: center; 56 | height: 50px; 57 | width: 100%; 58 | border-radius: 6px; 59 | font-family: inherit; 60 | font-size: 16px; 61 | font-weight: 400; 62 | line-height: 1; 63 | padding: 0 16px; 64 | color: #e1ecff; 65 | transition: background 0.3s; 66 | } 67 | 68 | .sidebar-1 button span:nth-child(2) { 69 | flex: 1 1 auto; 70 | } 71 | 72 | .sidebar-1 button:is(.active, :hover) { 73 | background: #004fee; 74 | color: #e1ecff; 75 | } 76 | 77 | .sidebar-1 button span { 78 | transition: 0.3s; 79 | } 80 | 81 | .sidebar-1 button.active > span:nth-child(3) { 82 | rotate: -180deg; 83 | } 84 | 85 | .sidebar-1 button:not(.active):hover { 86 | background: #2e303e; 87 | } 88 | 89 | .sidebar-1 .sub-nav button.active::before { 90 | background: #e1ecff; 91 | } 92 | 93 | .sidebar-1 .sub-nav { 94 | overflow: hidden; 95 | /* height: 0; */ 96 | transition: 0.5s; 97 | } 98 | 99 | /* .sub-nav.open { 100 | height: 200px; 101 | } */ 102 | 103 | .sidebar-1 .sub-nav button { 104 | padding-left: 54px; 105 | } 106 | 107 | .sidebar-1 .sub-nav button::before { 108 | content: ""; 109 | position: absolute; 110 | top: 50%; 111 | left: 25px; 112 | translate: 0 -50%; 113 | width: 5px; 114 | height: 5px; 115 | border-radius: 50%; 116 | background-color: #e1ecff; 117 | } 118 | 119 | .sidebar-1 .material-symbols-outlined { 120 | font-size: 22px; 121 | } 122 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar2/Sidebar2.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import logo from "./logo.svg"; 3 | import "./styles.css"; 4 | 5 | const navItems = ["home", "settings", "build", "cloud", "mail", "bookmark"]; 6 | 7 | export const Sidebar2 = () => { 8 | const [isOpen, setIsOpen] = useState(false); 9 | return ( 10 |
    11 | 35 |
    36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar2/styles.css: -------------------------------------------------------------------------------- 1 | .page.sidebar-2-page { 2 | background: #17132a; 3 | } 4 | 5 | .sidebar-2 { 6 | position: absolute; 7 | overflow: hidden; 8 | top: 0; 9 | left: 0; 10 | width: 56px; 11 | height: 100%; 12 | background: #4f2cd4; 13 | transition: width 0.4s; 14 | } 15 | 16 | .sidebar-2.open { 17 | width: 260px; 18 | } 19 | 20 | .sidebar-2 .inner { 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | width: 260px; 25 | } 26 | 27 | .sidebar-2 header { 28 | display: flex; 29 | align-items: center; 30 | height: 64px; 31 | padding: 0 6px; 32 | background: rgb(0 0 0 / 25%); 33 | } 34 | 35 | .sidebar-2-burger { 36 | width: 44px; 37 | height: 72px; 38 | display: grid; 39 | place-items: center; 40 | color: #f9f9f9; 41 | } 42 | 43 | .sidebar-2 header > img { 44 | height: 28px; 45 | } 46 | 47 | .sidebar-2 nav { 48 | display: grid; 49 | padding: 6px; 50 | gap: 2px; 51 | } 52 | 53 | .sidebar-2 nav > button { 54 | display: flex; 55 | gap: 12px; 56 | align-items: center; 57 | height: 44px; 58 | width: 44px; 59 | font-family: "Poppins"; 60 | font-size: 16px; 61 | text-transform: capitalize; 62 | line-height: 1; 63 | padding: 0 12px; 64 | border-radius: 8px; 65 | color: #f9f9f9; 66 | } 67 | 68 | .sidebar-2 nav > button:hover { 69 | background: rgb(0 0 0 / 30%); 70 | } 71 | 72 | .sidebar-2 header > img, 73 | .sidebar-2 nav > button p { 74 | opacity: 0; 75 | transition: 0.3s; 76 | } 77 | 78 | .sidebar-2.open :is(nav button p, header > img) { 79 | opacity: 1; 80 | } 81 | 82 | .sidebar-2.open nav > button { 83 | width: 100%; 84 | } 85 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar3/Sidebar3.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import logo from "./logo.svg"; 3 | import "./styles.css"; 4 | 5 | const navItems = ["home", "settings", "build", "cloud", "mail"]; 6 | 7 | export const Sidebar3 = () => { 8 | const [isOpen, setIsOpen] = useState(false); 9 | return ( 10 |
    11 | 35 |
    36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar3/bg.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/sidebars/Sidebar3/bg.jpeg -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar3/styles.css: -------------------------------------------------------------------------------- 1 | .page.sidebar-3-page { 2 | background: #17132a url("./bg.jpeg"); 3 | background-size: cover; 4 | } 5 | 6 | .page.sidebar-3-page::after { 7 | content: ""; 8 | position: fixed; 9 | z-index: 0; 10 | inset: 0; 11 | background: rgb(0 0 0 / 15%); 12 | } 13 | 14 | .sidebar-3 { 15 | position: absolute; 16 | z-index: 2; 17 | top: 20px; 18 | left: 20px; 19 | bottom: 20px; 20 | border-radius: 8px; 21 | width: 56px; 22 | background: rgb(0 0 0 / 25%); 23 | backdrop-filter: blur(10px); 24 | transition: width 0.45s; 25 | } 26 | 27 | .sidebar-3 button { 28 | border: 0; 29 | background: transparent; 30 | cursor: pointer; 31 | } 32 | 33 | .sidebar-3 .material-symbols-outlined { 34 | font-size: 20px; 35 | } 36 | 37 | .sidebar-3.open { 38 | width: 190px; 39 | } 40 | 41 | .sidebar-3 .inner { 42 | position: absolute; 43 | top: 0; 44 | left: 0; 45 | width: 190px; 46 | } 47 | 48 | .sidebar-3 header { 49 | display: flex; 50 | align-items: center; 51 | height: 64px; 52 | border-top-left-radius: 8px; 53 | border-top-right-radius: 8px; 54 | padding: 0 6px; 55 | } 56 | 57 | .sidebar-3-burger { 58 | width: 44px; 59 | height: 72px; 60 | display: grid; 61 | place-items: center; 62 | color: #f9f9f9; 63 | } 64 | 65 | .sidebar-3 header > img { 66 | height: 18px; 67 | } 68 | 69 | .sidebar-3 nav { 70 | display: grid; 71 | padding: 0 6px; 72 | gap: 2px; 73 | } 74 | 75 | .sidebar-3 nav > button { 76 | display: flex; 77 | gap: 12px; 78 | align-items: center; 79 | height: 44px; 80 | width: 44px; 81 | font-family: "Poppins"; 82 | font-size: 14px; 83 | text-transform: capitalize; 84 | line-height: 1; 85 | padding: 0 12px; 86 | border-radius: 8px; 87 | opacity: 0.7; 88 | color: #f9f9f9; 89 | } 90 | 91 | .sidebar-3 nav > button:hover { 92 | background: rgb(0 0 0 / 30%); 93 | opacity: 1; 94 | } 95 | 96 | .sidebar-3:not(.open) nav > button:hover p { 97 | opacity: 1; 98 | background: rgb(0 0 0 / 70%); 99 | padding: 4px 8px; 100 | border-radius: 6px; 101 | translate: 10px 0; 102 | } 103 | 104 | .sidebar-3 header > img, 105 | .sidebar-3 nav > button p { 106 | opacity: 0; 107 | transition: 0.25s; 108 | } 109 | 110 | .sidebar-3.open :is(nav button p, header > img) { 111 | opacity: 1; 112 | } 113 | 114 | .sidebar-3.open nav > button { 115 | width: 100%; 116 | } 117 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar4/Sidebar4.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | .page.sidebar-4-page { 6 | background: #36367f; 7 | } 8 | 9 | .sidebar-4 button { 10 | background: transparent; 11 | border: 0; 12 | padding: 0; 13 | cursor: pointer; 14 | } 15 | 16 | .sidebar-4 { 17 | position: absolute; 18 | overflow: hidden; 19 | top: 20px; 20 | left: 20px; 21 | bottom: 30px; 22 | width: 64px; 23 | border-radius: 16px; 24 | background: #21214c; 25 | transition: width 0.4s; 26 | } 27 | 28 | .sidebar-4:hover { 29 | width: 260px; 30 | } 31 | 32 | .sidebar-4 .inner { 33 | position: absolute; 34 | top: 0; 35 | left: 0; 36 | bottom: 0; 37 | width: 260px; 38 | } 39 | 40 | .sidebar-4 .header { 41 | display: flex; 42 | align-items: center; 43 | height: 72px; 44 | padding: 0 20px; 45 | background: rgb(0 0 0 / 15%); 46 | } 47 | 48 | .sidebar-4 .header h1 { 49 | margin-left: 12px; 50 | font-weight: 500; 51 | font-size: 14px; 52 | letter-spacing: 2px; 53 | } 54 | 55 | .sidebar-4 .logo { 56 | height: 28px; 57 | scale: 1.1; 58 | transition: 0.5s; 59 | } 60 | 61 | .sidebar-4 .menu { 62 | position: relative; 63 | display: grid; 64 | } 65 | 66 | .sidebar-4 .menu::after { 67 | content: ""; 68 | position: absolute; 69 | top: 0; 70 | left: 0; 71 | height: 56px; 72 | width: 6px; 73 | background: #6154f7; 74 | translate: 0 var(--top); 75 | transition: 0.5s; 76 | } 77 | 78 | .sidebar-4 .menu button { 79 | display: flex; 80 | gap: 16px; 81 | align-items: center; 82 | height: 56px; 83 | width: 100%; 84 | font-family: "Poppins"; 85 | font-size: 17px; 86 | text-transform: capitalize; 87 | line-height: 1; 88 | padding: 0 22px; 89 | color: rgb(255 255 255 / 60%); 90 | cursor: pointer; 91 | opacity: 0.8; 92 | transition: 0.5s; 93 | } 94 | 95 | .sidebar-4:hover .menu button:hover:not(.active) { 96 | background: rgb(0 0 0 / 8%); 97 | } 98 | 99 | .sidebar-4 .menu :is(button:hover, .active) { 100 | background: rgb(0 0 0 / 35%); 101 | color: rgb(255 255 255 / 100%); 102 | opacity: 1; 103 | } 104 | 105 | .sidebar-4:hover .menu .active { 106 | cursor: default; 107 | } 108 | 109 | .sidebar-4 .menu button:hover > span { 110 | opacity: 1; 111 | } 112 | 113 | .sidebar-4 .menu button p, 114 | .sidebar-4 .header h1 { 115 | opacity: 0; 116 | transition: 0.5s; 117 | } 118 | 119 | .sidebar-4:hover :is(.sidebar-4 .menu button p, .sidebar-4 .header h1) { 120 | opacity: 1; 121 | } 122 | 123 | .sidebar-4:hover .logo { 124 | scale: 1; 125 | } 126 | 127 | .sidebar-4 .menu button > img { 128 | width: 24px; 129 | height: 24px; 130 | } 131 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar4/Sidebar4.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import logo from "./logo.png"; 3 | import "./Sidebar4.css"; 4 | 5 | const navItems = [ 6 | "home", 7 | "dashboard", 8 | "mail", 9 | "cloud", 10 | "workspaces", 11 | "settings", 12 | ]; 13 | 14 | export const Sidebar4 = () => { 15 | const [active, setActive] = useState(1); 16 | 17 | const goto = (index) => setActive(index); 18 | 19 | return ( 20 |
    21 | 45 |
    46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar4/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/sidebars/Sidebar4/logo.png -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar5/Sidebar5.css: -------------------------------------------------------------------------------- 1 | .page.sidebar-5-page { 2 | margin: 0; 3 | background: #1c376d; 4 | height: 100vh; 5 | overflow: hidden; 6 | } 7 | 8 | .lni { 9 | font-size: 24px; 10 | } 11 | 12 | .sidebar-5 button { 13 | background: transparent; 14 | border: 0; 15 | padding: 0; 16 | cursor: pointer; 17 | } 18 | 19 | .sidebar-5 { 20 | position: absolute; 21 | overflow: hidden; 22 | top: 0; 23 | left: 0; 24 | bottom: 0; 25 | width: 260px; 26 | background: rgb(0 0 0 / 40%); 27 | } 28 | 29 | .sidebar-5 .sidebar-inner { 30 | position: absolute; 31 | top: 0; 32 | left: 0; 33 | width: 260px; 34 | } 35 | 36 | .sidebar-5 .sidebar-header { 37 | display: flex; 38 | align-items: center; 39 | height: 72px; 40 | padding-top: 10px; 41 | } 42 | 43 | .sidebar-5 .sidebar-burger { 44 | width: 60px; 45 | height: 60px; 46 | display: grid; 47 | place-items: center; 48 | color: #f9f9f9; 49 | } 50 | 51 | .sidebar-5 .sidebar-logo { 52 | height: 22px; 53 | } 54 | 55 | .sidebar-5 .sidebar-menu { 56 | display: grid; 57 | padding: 0 10px; 58 | } 59 | 60 | .sidebar-5 .sidebar-button { 61 | display: flex; 62 | gap: 16px; 63 | align-items: center; 64 | height: 56px; 65 | width: 100%; 66 | font-family: "Poppins"; 67 | font-size: 17px; 68 | text-transform: capitalize; 69 | line-height: 1; 70 | padding: 0 10px; 71 | border-radius: 8px; 72 | color: #b8c2d8; 73 | opacity: 0.9; 74 | } 75 | 76 | .sidebar-5 .sidebar-button p { 77 | font-size: 15px; 78 | margin-left: 1px; 79 | } 80 | 81 | .sidebar-5 .handle { 82 | position: absolute; 83 | z-index: 100; 84 | width: 8px; 85 | top: 0; 86 | bottom: 0; 87 | right: 0; 88 | user-select: none; 89 | transition: 0.3s; 90 | } 91 | 92 | .sidebar-5 .handle:hover, 93 | .sidebar-5 .handle:active { 94 | background: rgb(255 255 255 / 6%); 95 | cursor: col-resize; 96 | } 97 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar5/Sidebar5.jsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from "react"; 2 | import logo from "./logo.svg"; 3 | import "./Sidebar5.css"; 4 | 5 | const items = [ 6 | { 7 | name: "home", 8 | icon: "home-2", 9 | }, 10 | { 11 | name: "favourites", 12 | icon: "heart", 13 | }, 14 | { 15 | name: "products", 16 | icon: "cart-2", 17 | }, 18 | { 19 | name: "testimonials", 20 | icon: "comment-1", 21 | }, 22 | { 23 | name: "security", 24 | icon: "locked-2", 25 | }, 26 | { 27 | name: "settings", 28 | icon: "gear-1", 29 | }, 30 | ]; 31 | 32 | const Icon = ({ children }) => ; 33 | 34 | export const Sidebar5 = () => { 35 | const [width, setWidth] = useState(60); 36 | const sidebarRef = useRef(null); 37 | const sidebar = sidebarRef.current; 38 | 39 | const resize = (e) => { 40 | let newWidth = e.clientX - sidebar?.offsetLeft; 41 | if (newWidth < 60) newWidth = 60; 42 | if (newWidth > 259) newWidth = 260; 43 | setWidth(newWidth); 44 | }; 45 | 46 | const stopResize = () => { 47 | document.body.style.cursor = "default"; 48 | window.removeEventListener("mousemove", resize); 49 | window.removeEventListener("mouseup", stopResize); 50 | }; 51 | 52 | const initResize = () => { 53 | document.body.style.cursor = "col-resize"; 54 | window.addEventListener("mousemove", resize); 55 | window.addEventListener("mouseup", stopResize); 56 | }; 57 | 58 | return ( 59 |
    60 | 83 |
    84 | ); 85 | }; 86 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar6/Sidebar6.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import logo from "./logo.svg"; 3 | import "./Sidebar6.css"; 4 | 5 | const navItems = [ 6 | "dashboard", 7 | "leaderboard", 8 | "groups", 9 | "analytics", 10 | "message", 11 | "settings", 12 | ]; 13 | 14 | export const Sidebar6 = () => { 15 | const [active, setActive] = useState(1); 16 | 17 | const goto = (index) => setActive(index); 18 | 19 | return ( 20 |
    21 | 45 |
    46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar6/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar7/Sidebar7.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import logo from "./logo.svg"; 3 | import "./styles.css"; 4 | 5 | const navItems = ["home", "build", "cloud", "mail", "favorite"]; 6 | 7 | const Icon = ({ icon }) => ( 8 | {icon} 9 | ); 10 | 11 | const Button = ({ item }) => ( 12 | 16 | ); 17 | 18 | const Header = () => ( 19 |
    20 | 21 |
    22 | ); 23 | 24 | export const Sidebar7 = () => { 25 | const [isOpen, setIsOpen] = useState(false); 26 | return ( 27 |
    28 | 35 | 46 |
    47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar7/styles.css: -------------------------------------------------------------------------------- 1 | .page.sidebar-7-page { 2 | background: #1c1b23; 3 | } 4 | 5 | .page.sidebar-7-page button { 6 | background: transparent; 7 | border: 0; 8 | cursor: pointer; 9 | } 10 | 11 | .sidebar-7 { 12 | position: absolute; 13 | z-index: 1; 14 | top: 0; 15 | left: 0; 16 | bottom: 0; 17 | width: 56px; 18 | background: #5331ff; 19 | backdrop-filter: blur(10px); 20 | transition: 0.45s; 21 | } 22 | 23 | .sidebar-7 .material-symbols-outlined { 24 | font-size: 20px; 25 | } 26 | 27 | .sidebar-7.open { 28 | width: 190px; 29 | overflow: hidden; 30 | } 31 | 32 | .sidebar-7 .inner { 33 | position: absolute; 34 | top: 0; 35 | left: 0; 36 | width: 190px; 37 | height: 100%; 38 | display: flex; 39 | flex-direction: column; 40 | } 41 | 42 | .sidebar-7 header { 43 | display: flex; 44 | align-items: center; 45 | height: 64px; 46 | padding: 0 6px 0 48px; 47 | } 48 | 49 | .sidebar-7-burger { 50 | position: fixed; 51 | z-index: 2; 52 | top: 0; 53 | left: 0; 54 | width: 56px; 55 | height: 64px; 56 | display: grid; 57 | place-items: center; 58 | color: #f9f9f9; 59 | } 60 | 61 | .sidebar-7 header > img { 62 | height: 18px; 63 | } 64 | 65 | .sidebar-7 nav { 66 | display: flex; 67 | flex-direction: column; 68 | padding: 0 8px 20px; 69 | gap: 2px; 70 | flex: 1 1 auto; 71 | } 72 | 73 | .sidebar-7 nav > button { 74 | display: flex; 75 | gap: 12px; 76 | align-items: center; 77 | height: 40px; 78 | width: 40px; 79 | font-family: "Poppins"; 80 | font-size: 14px; 81 | text-transform: capitalize; 82 | line-height: 1; 83 | padding: 0 10px; 84 | border-radius: 8px; 85 | color: #f9f9f9; 86 | } 87 | 88 | .sidebar-7 nav > button:last-child { 89 | margin-top: auto; 90 | } 91 | 92 | .sidebar-7 nav > button:hover { 93 | background: rgb(0 0 0 / 24%); 94 | } 95 | 96 | .sidebar-7:not(.open) nav p { 97 | visibility: hidden; 98 | } 99 | 100 | .sidebar-7:not(.open) nav > button:hover p { 101 | opacity: 1; 102 | visibility: visible; 103 | background: #2e2a47; 104 | padding: 5px 10px; 105 | font-size: 13px; 106 | border-radius: 6px; 107 | translate: 12px 0; 108 | } 109 | 110 | .sidebar-7 header > img, 111 | .sidebar-7 nav > button p { 112 | opacity: 0; 113 | transition: 0.25s; 114 | } 115 | 116 | .sidebar-7.open :is(nav button p, header > img) { 117 | opacity: 1; 118 | } 119 | 120 | .sidebar-7.open nav > button { 121 | width: 100%; 122 | } 123 | 124 | @media (width <= 400px) { 125 | .sidebar-7 { 126 | translate: -100% 0; 127 | } 128 | 129 | .sidebar-7.open { 130 | translate: 0; 131 | } 132 | 133 | .sidebar-7:not(.open) button span { 134 | transition: 0.3s; 135 | opacity: 0; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar8/Sidebar8 copy.css: -------------------------------------------------------------------------------- 1 | .sidebar-8 header :is(h2, h3) { 2 | margin: 0; 3 | } 4 | 5 | .sidebar-8 { 6 | --color-hover: #313132; 7 | --border: 1px solid #2d2d2d; 8 | position: fixed; 9 | overflow: hidden; 10 | top: 24px; 11 | left: 24px; 12 | bottom: 28px; 13 | display: flex; 14 | flex-direction: column; 15 | gap: 8px; 16 | width: 80px; 17 | border-radius: 18px; 18 | border: var(--border); 19 | transition: 0.4s; 20 | background: #1c1c1c; 21 | } 22 | 23 | .sidebar-8 button { 24 | border: 0; 25 | background: transparent; 26 | font-size: 22px; 27 | color: inherit; 28 | border-radius: 8px; 29 | font-family: inherit; 30 | cursor: pointer; 31 | transition: 0.3s; 32 | } 33 | 34 | .sidebar-8-left, 35 | .sidebar-8-right { 36 | position: absolute; 37 | top: 0; 38 | bottom: 0; 39 | transition: 0.4s; 40 | display: flex; 41 | flex-direction: column; 42 | align-items: center; 43 | } 44 | 45 | .sidebar-8-left { 46 | z-index: 1; 47 | left: 0; 48 | width: 80px; 49 | } 50 | 51 | .sidebar-8-dots { 52 | position: absolute; 53 | top: 10px; 54 | left: 18px; 55 | width: 10px; 56 | height: 10px; 57 | border-radius: 50%; 58 | background: #ee6c5f; 59 | } 60 | 61 | .sidebar-8-dots::before, 62 | .sidebar-8-dots::after { 63 | content: ""; 64 | width: inherit; 65 | height: inherit; 66 | border-radius: inherit; 67 | position: inherit; 68 | } 69 | 70 | .sidebar-8-dots::before { 71 | left: 16px; 72 | background: #f7bc50; 73 | } 74 | 75 | .sidebar-8-dots::after { 76 | left: 32px; 77 | background: #61c453; 78 | } 79 | 80 | .sidebar-8-left img { 81 | width: 40px; 82 | margin: 36px 0 14px; 83 | } 84 | 85 | .sidebar-8-left button { 86 | width: 44px; 87 | height: 44px; 88 | display: grid; 89 | place-items: center; 90 | opacity: 0.8; 91 | } 92 | 93 | .sidebar-8-left button:hover { 94 | opacity: 1; 95 | background: var(--color-hover); 96 | } 97 | 98 | .sidebar-8-left div:last-of-type { 99 | margin-top: auto; 100 | margin-bottom: 16px; 101 | } 102 | 103 | .sidebar-8-right { 104 | left: 76px; 105 | height: 100%; 106 | position: relative; 107 | } 108 | 109 | .sidebar-8-right-inner { 110 | position: absolute; 111 | inset: 8px; 112 | left: 6px; 113 | border-radius: 12px; 114 | background: #1a1a1a; 115 | border: var(--border); 116 | } 117 | 118 | .sidebar-8-right header { 119 | display: flex; 120 | align-items: center; 121 | justify-content: space-between; 122 | padding: 30px 16px 18px; 123 | } 124 | 125 | .sidebar-8-right h2 { 126 | font-size: 16px; 127 | font-weight: 600; 128 | } 129 | 130 | .sidebar-8-right h3 { 131 | font-size: 12px; 132 | font-weight: 500; 133 | color: #7e7f82; 134 | } 135 | 136 | .sidebar-8-right nav { 137 | padding: 0 12px; 138 | } 139 | 140 | .sidebar-8-right button { 141 | padding: 0 12px; 142 | background: transparent; 143 | display: flex; 144 | align-items: center; 145 | gap: 10px; 146 | width: 100%; 147 | height: 44px; 148 | font-size: 15px; 149 | opacity: 0.7; 150 | } 151 | 152 | .sidebar-8-right button:hover { 153 | opacity: 1; 154 | background: var(--color-hover); 155 | } 156 | 157 | .sidebar-8-right button i { 158 | font-size: 18px; 159 | } 160 | 161 | .sidebar-8:hover { 162 | width: 300px; 163 | } 164 | 165 | .sidebar-8:hover .sidebar-8-right { 166 | width: 225px; 167 | } 168 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar8/Sidebar8.jsx: -------------------------------------------------------------------------------- 1 | import logo from "./logo.svg"; 2 | import "./Sidebar8.css"; 3 | 4 | const navItems = ["home-alt1", "heart", "mention", "plus"]; 5 | 6 | const footerItems = ["gear", "link-out"]; 7 | 8 | const innerItems = [ 9 | { 10 | name: "Dashboard", 11 | icon: "dashboard", 12 | }, 13 | { 14 | name: "Products", 15 | icon: "shipping-box-v1", 16 | }, 17 | { 18 | name: "Customers", 19 | icon: "person", 20 | }, 21 | { 22 | name: "Messages", 23 | icon: "open-envelope", 24 | }, 25 | { 26 | name: "Images", 27 | icon: "image", 28 | }, 29 | { 30 | name: "Inventory", 31 | icon: "data", 32 | }, 33 | { 34 | name: "Hashtags", 35 | icon: "hashtag", 36 | }, 37 | ]; 38 | 39 | const Icon = ({ icon }) => ; 40 | 41 | const Button = ({ item }) => ( 42 | 46 | ); 47 | 48 | const Header = () => ( 49 |
    50 |
    51 |

    Untitled UI

    52 |

    store.untitledui.com

    53 |
    54 | 55 |
    56 | ); 57 | 58 | export const Sidebar8 = () => { 59 | return ( 60 |
    61 | 89 |
    90 | ); 91 | }; 92 | -------------------------------------------------------------------------------- /src/components/sidebars/Sidebar8/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/components/sidebars/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Sidebar1/Sidebar1"; 2 | export * from "./Sidebar2/Sidebar2"; 3 | export * from "./Sidebar3/Sidebar3"; 4 | export * from "./Sidebar4/Sidebar4"; 5 | export * from "./Sidebar5/Sidebar5"; 6 | export * from "./Sidebar6/Sidebar6"; 7 | export * from "./Sidebar7/Sidebar7"; 8 | export * from "./Sidebar8/Sidebar8"; 9 | -------------------------------------------------------------------------------- /src/components/signups/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/frontend-joe/react-components/7addf3d8106d807f5013ba8e2942f4d51e60d20c/src/components/signups/index.js -------------------------------------------------------------------------------- /src/components/tables/Table1/Table1.css: -------------------------------------------------------------------------------- 1 | .table-1-wrapper { 2 | overflow: auto; 3 | position: relative; 4 | z-index: 2; 5 | width: 440px; 6 | min-width: 440px; 7 | max-width: 440px; 8 | } 9 | 10 | .table-1-card table { 11 | width: 100%; 12 | border-collapse: collapse; 13 | text-align: left; 14 | } 15 | 16 | .table-1-card table th { 17 | opacity: 0.5; 18 | font-weight: 400; 19 | user-select: none; 20 | text-transform: capitalize; 21 | background: rgb(255 255 255 / 6%); 22 | } 23 | 24 | .table-1-card table :is(th, td) { 25 | position: relative; 26 | overflow: hidden; 27 | white-space: nowrap; 28 | height: 36px; 29 | padding: 0 10px; 30 | border: 1px solid rgb(255 255 255 / 10%); 31 | } 32 | 33 | .table-1-card table th .draggable { 34 | position: absolute; 35 | top: 0; 36 | right: 0; 37 | bottom: 0; 38 | width: 6px; 39 | cursor: col-resize; 40 | } 41 | -------------------------------------------------------------------------------- /src/components/tables/Table1/Table1.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState, createRef } from "react"; 2 | import "./Table1.css"; 3 | 4 | const TableHeader = ({ index, column, columnRef, initResize }) => { 5 | const width = !!initResize ? column.width : "100%"; 6 | 7 | return ( 8 | 16 | {column.name} 17 | {!!initResize && ( 18 | initResize(e, index)} 21 | > 22 | )} 23 | 24 | ); 25 | }; 26 | 27 | export const Table1 = ({ columns, data }) => { 28 | const [columnState, setColumnState] = useState(columns); 29 | const [columnRefs, setColumnRefs] = useState([]); 30 | 31 | const wrapperRef = useRef(null); 32 | const activeIndex = useRef(null); 33 | 34 | const resize = (e) => { 35 | const columnsCopy = [...columns]; 36 | const column = columnsCopy[activeIndex.current]; 37 | const columnRef = columnRefs[activeIndex.current]; 38 | const nextWidth = 39 | e.clientX - 40 | 48 - 41 | columnRef.current.offsetLeft - 42 | (wrapperRef.current.offsetLeft - wrapperRef.current.scrollLeft); 43 | 44 | console.log("nextWidth", nextWidth); 45 | 46 | column.width = nextWidth; 47 | 48 | setColumnState(columnsCopy); 49 | }; 50 | 51 | const stopResize = () => { 52 | document.body.style.cursor = "default"; 53 | window.removeEventListener("mousemove", resize); 54 | window.removeEventListener("mouseup", stopResize); 55 | }; 56 | 57 | const initResize = (e, index) => { 58 | activeIndex.current = index; 59 | e.stopPropagation(); 60 | document.body.style.cursor = "col-resize"; 61 | window.addEventListener("mousemove", resize); 62 | window.addEventListener("mouseup", stopResize); 63 | }; 64 | 65 | useEffect(() => { 66 | setColumnRefs( 67 | Array(columns.length) 68 | .fill() 69 | .map((_, i) => columnRefs[i] || createRef()) 70 | ); 71 | }, []); 72 | 73 | return ( 74 |
    75 | 76 | 77 | 78 | {columnState.map((column, index) => ( 79 | 88 | ))} 89 | 90 | 91 | 92 | {data.map((item) => ( 93 | 94 | {columnState.map((column) => ( 95 | 98 | ))} 99 | 100 | ))} 101 | 102 | 103 |
    96 | {item[column.name]} 97 |
    104 |
    105 | ); 106 | }; 107 | -------------------------------------------------------------------------------- /src/components/tables/Table1/Table1Example.css: -------------------------------------------------------------------------------- 1 | .page.table-1-page { 2 | background: linear-gradient(45deg, #2c3c5e, #1a2239); 3 | color: #f9f9f9; 4 | display: flex; 5 | align-items: flex-start; 6 | display: grid; 7 | place-items: center; 8 | } 9 | 10 | .table-1-card { 11 | background: rgb(255 255 255 / 3%); 12 | border: 2px solid rgb(255 255 255 / 3%); 13 | backdrop-filter: blur(10px); 14 | border-radius: 12px; 15 | padding: 24px; 16 | font-size: 12px; 17 | } 18 | 19 | .table-1-card .header { 20 | display: flex; 21 | justify-content: space-between; 22 | margin-bottom: 24px; 23 | } 24 | 25 | .table-1-card .header h2 { 26 | font-weight: 400; 27 | opacity: 0.6; 28 | display: flex; 29 | align-items: center; 30 | } 31 | 32 | .table-1-card .header button { 33 | background: #2e5fdc; 34 | color: rgb(255 255 255 / 96%); 35 | font-size: 12px; 36 | border: 0; 37 | border-radius: 20px; 38 | font-family: inherit; 39 | padding: 8px 14px; 40 | } 41 | -------------------------------------------------------------------------------- /src/components/tables/Table1/Table1Example.jsx: -------------------------------------------------------------------------------- 1 | import { Table1 } from "./Table1"; 2 | import "./Table1Example.css"; 3 | import logo from "./logo.svg"; 4 | 5 | const columns = [ 6 | { 7 | name: "name", 8 | width: 125, 9 | }, 10 | { 11 | name: "age", 12 | width: 50, 13 | }, 14 | { 15 | name: "level", 16 | width: 170, 17 | }, 18 | ]; 19 | 20 | const data = [ 21 | { 22 | name: "Alice Johnson", 23 | age: 29, 24 | level: "Intermediate", 25 | languages: ["Python", "JavaScript", "HTML"], 26 | }, 27 | { 28 | name: "Bob Smith", 29 | age: 35, 30 | level: "Advanced", 31 | languages: ["Java", "Kotlin", "Scala"], 32 | }, 33 | { 34 | name: "Charlie Evans", 35 | age: 23, 36 | level: "Beginner", 37 | languages: ["Python", "C++"], 38 | }, 39 | { 40 | name: "Diana Lee", 41 | age: 41, 42 | level: "Expert", 43 | languages: ["C#", "F#", "SQL"], 44 | }, 45 | { 46 | name: "Edward Kim", 47 | age: 28, 48 | level: "Intermediate", 49 | languages: ["JavaScript", "TypeScript", "Node.js"], 50 | }, 51 | { 52 | name: "Fiona Garcia", 53 | age: 32, 54 | level: "Advanced", 55 | languages: ["Ruby", "Go", "Elixir"], 56 | }, 57 | { 58 | name: "George Thompson", 59 | age: 26, 60 | level: "Intermediate", 61 | languages: ["PHP", "Python", "JavaScript"], 62 | }, 63 | ]; 64 | 65 | export const Table1Example = () => { 66 | return ( 67 |
    68 |
    69 |
    70 |

    Developers

    71 | 72 |
    73 | 74 |
    75 |
    76 | ); 77 | }; 78 | -------------------------------------------------------------------------------- /src/components/tables/Table1/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/tables/Table2/Table2.css: -------------------------------------------------------------------------------- 1 | .table-2 { 2 | border-collapse: collapse; 3 | text-align: left; 4 | width: 100%; 5 | } 6 | 7 | .table-2 thead { 8 | position: sticky; 9 | top: 0; 10 | left: 0; 11 | z-index: 1; 12 | } 13 | 14 | .table-2 thead tr th:not(:last-child) { 15 | width: 120px; 16 | max-width: 120px; 17 | } 18 | 19 | .table-2 :is(th, td) { 20 | position: relative; 21 | overflow: hidden; 22 | white-space: nowrap; 23 | padding: 0 6px; 24 | height: 50px; 25 | font-size: 13px; 26 | } 27 | 28 | .table-2 th { 29 | font-weight: 500; 30 | user-select: none; 31 | text-transform: capitalize; 32 | color: #706d84; 33 | height: 56px; 34 | cursor: pointer; 35 | vertical-align: middle; 36 | transition: 0.3s; 37 | } 38 | 39 | .table-2 th i { 40 | font-size: 11px; 41 | translate: 0 -1px; 42 | margin-left: 6px; 43 | } 44 | 45 | .table-2 th:is(.active, :hover) { 46 | color: inherit; 47 | } 48 | 49 | .table-2 td { 50 | opacity: 0.65; 51 | transition: opacity 0.3s; 52 | } 53 | 54 | .table-2 tbody tr:hover td { 55 | opacity: 1; 56 | } 57 | 58 | .table-2 tr { 59 | cursor: pointer; 60 | border-bottom: 1px solid #34323c; 61 | } 62 | 63 | .table-2 tbody tr:last-child { 64 | border: 0; 65 | } 66 | 67 | .table-2 tbody tr:nth-child(odd) { 68 | background: #1e1d25; 69 | } 70 | -------------------------------------------------------------------------------- /src/components/tables/Table2/Table2.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./Table2.css"; 3 | 4 | const TableHeader = ({ column, onSort, sortOrder, sortColumn }) => { 5 | const isActive = column === sortColumn; 6 | return ( 7 | onSort(column)}> 8 | {column} 9 | {isActive && ( 10 | 13 | )} 14 | 15 | ); 16 | }; 17 | 18 | export const Table2 = ({ rows, columns }) => { 19 | const [sortColumn, setSortColumn] = useState(columns[0]); 20 | const [sortOrder, setSortOrder] = useState("asc"); 21 | 22 | const sortedRows = rows.sort((a, b) => { 23 | const [valA, valB] = [a[sortColumn], b[sortColumn]]; 24 | return typeof valA === typeof valB 25 | ? sortOrder === "asc" 26 | ? valA > valB 27 | ? 1 28 | : -1 29 | : valA < valB 30 | ? 1 31 | : -1 32 | : 0; 33 | }); 34 | 35 | const handleSort = (column) => { 36 | console.log("name", column); 37 | setSortColumn(column); 38 | setSortOrder( 39 | sortColumn !== column ? "asc" : sortOrder === "asc" ? "desc" : "asc" 40 | ); 41 | }; 42 | 43 | return ( 44 | 45 | 46 | 47 | {columns.map((column) => ( 48 | 55 | ))} 56 | 57 | 58 | 59 | {sortedRows.map((row) => ( 60 | 61 | {columns.map((column) => ( 62 | 63 | ))} 64 | 65 | ))} 66 | 67 |
    {row[column]}
    68 | ); 69 | }; 70 | -------------------------------------------------------------------------------- /src/components/tables/Table2/Table2Example.css: -------------------------------------------------------------------------------- 1 | .table-2-page { 2 | background: #222129; 3 | color: #f5f3f9; 4 | margin: 0; 5 | height: 100vh; 6 | font-size: 110%; 7 | font-family: "Euclid Circular A", "Poppins"; 8 | } 9 | 10 | .table-2-page .wrapper { 11 | overflow: auto; 12 | position: relative; 13 | z-index: 2; 14 | } 15 | 16 | .table-2-page header { 17 | position: relative; 18 | overflow: hidden; 19 | margin: 0 0 18px; 20 | } 21 | 22 | .table-2-page header .content { 23 | position: relative; 24 | z-index: 1; 25 | display: flex; 26 | align-items: center; 27 | justify-content: space-between; 28 | height: 240px; 29 | max-width: 700px; 30 | margin: 0 auto; 31 | padding: 0 70px 60px; 32 | } 33 | 34 | .table-2-page header::before { 35 | content: ""; 36 | position: absolute; 37 | bottom: 0; 38 | left: 50%; 39 | translate: -50% 0; 40 | z-index: 0; 41 | background: #5926fc; 42 | width: 500vw; 43 | aspect-ratio: 1/1; 44 | border-radius: 50%; 45 | } 46 | 47 | .table-2-page header button { 48 | font-family: inherit; 49 | background: rgb(0 0 0 / 16%); 50 | color: inherit; 51 | border: 0; 52 | border-radius: 8px; 53 | padding: 12px 18px 12px 20px; 54 | font-size: 13.5px; 55 | display: flex; 56 | align-items: center; 57 | gap: 4px; 58 | } 59 | 60 | .table-2-page header button span { 61 | font-size: 16px; 62 | translate: 0 -1px; 63 | } 64 | 65 | .table-2-page header h2 { 66 | font-size: 20px; 67 | font-weight: 400; 68 | display: flex; 69 | align-items: center; 70 | } 71 | 72 | .table-2-page header h2 i { 73 | margin-right: 8px; 74 | background: rgb(0 0 0 / 16%); 75 | display: grid; 76 | place-items: center; 77 | width: 40px; 78 | height: 40px; 79 | border-radius: 8px; 80 | } 81 | 82 | .table-2-page .card { 83 | max-width: 600px; 84 | margin: 0 auto; 85 | position: relative; 86 | z-index: 1; 87 | background: #1a191e; 88 | border-radius: 8px; 89 | box-shadow: 0 30px 40px rgb(0 0 0 / 12%); 90 | padding: 10px 18px 18px; 91 | font-size: 12px; 92 | margin: -100px auto 30px; 93 | } 94 | 95 | @media (width < 706px) { 96 | .table-2-page .card { 97 | margin: -100px 50px 30px; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/components/tables/Table2/Table2Example.jsx: -------------------------------------------------------------------------------- 1 | import { Table2 } from "./Table2"; 2 | import "./Table2Example.css"; 3 | 4 | const rows = [ 5 | { 6 | name: "Zoe Blogs", 7 | level: "Intermediate", 8 | age: 21, 9 | language: "JavaScript", 10 | location: "USA", 11 | }, 12 | { 13 | name: "Jane Doe", 14 | level: "Advanced", 15 | age: 25, 16 | language: "Python", 17 | location: "Canada", 18 | }, 19 | { 20 | name: "Alice Smith", 21 | level: "Junior", 22 | age: 22, 23 | language: "Ruby", 24 | location: "UK", 25 | }, 26 | { 27 | name: "Bob Kohler", 28 | level: "Senior", 29 | age: 35, 30 | language: "C#", 31 | location: "Germany", 32 | }, 33 | { 34 | name: "Dana White", 35 | level: "Junior", 36 | age: 23, 37 | language: "PHP", 38 | location: "France", 39 | }, 40 | { 41 | name: "Ethan Hunt", 42 | level: "Advanced", 43 | age: 28, 44 | language: "JavaScript", 45 | location: "USA", 46 | }, 47 | { 48 | name: "Fiona Green", 49 | level: "Senior", 50 | age: 40, 51 | language: "Java", 52 | location: "Ireland", 53 | }, 54 | { 55 | name: "Luuk Black", 56 | level: "Intermediate", 57 | age: 30, 58 | language: "JavaScript", 59 | location: "Netherlands", 60 | }, 61 | { 62 | name: "Hannah Isak", 63 | level: "Junior", 64 | age: 24, 65 | language: "Kotlin", 66 | location: "Sweden", 67 | }, 68 | ]; 69 | 70 | const columns = ["name", "level", "language", "location"]; 71 | 72 | export const Table2Example = () => { 73 | return ( 74 |
    75 |
    76 |
    77 |

    78 | {/* */} 79 | Developers 80 |

    81 | 93 |
    94 |
    95 |
    96 |
    97 | 98 |
    99 |
    100 |
    101 | ); 102 | }; 103 | -------------------------------------------------------------------------------- /src/components/tables/Table3/Table3.css: -------------------------------------------------------------------------------- 1 | .table-3 { 2 | width: 100%; 3 | border-collapse: collapse; 4 | } 5 | 6 | .table-3 td { 7 | padding: 16px; 8 | white-space: nowrap; 9 | } 10 | 11 | .table-3 tr td:last-of-type { 12 | text-align: right; 13 | } 14 | 15 | .table-3 th:first-of-type { 16 | width: 20px; 17 | } 18 | 19 | .table-3 tr td:first-child, 20 | .table-3 tr th:first-child { 21 | padding-right: 2px; 22 | } 23 | 24 | .table-3 tr td:last-child, 25 | .table-3 tr th:last-child { 26 | padding-right: 12px; 27 | } 28 | 29 | .table-3 th:nth-child(2) { 30 | width: 133px; 31 | max-width: 133px; 32 | min-width: 133px; 33 | } 34 | 35 | .table-3 th:nth-child(3) { 36 | width: 180px; 37 | max-width: 180px; 38 | min-width: 180px; 39 | } 40 | 41 | .table-3 th { 42 | padding: 20px 16px; 43 | font-weight: 500; 44 | text-align: left; 45 | text-transform: capitalize; 46 | } 47 | 48 | .table-3 :is(td, th) { 49 | border-bottom: 1px solid #2d2d2d; 50 | } 51 | 52 | .table-3-footer { 53 | display: flex; 54 | align-items: center; 55 | } 56 | 57 | .table-3-footer p { 58 | margin: 0; 59 | font-size: 14px; 60 | color: #8a8a8a; 61 | } 62 | 63 | .table-3-footer p em { 64 | color: #ffffff; 65 | font-style: normal; 66 | } 67 | 68 | .table-3-pagination { 69 | padding: 16px; 70 | display: flex; 71 | } 72 | 73 | .table-3-pagination > button { 74 | background: transparent; 75 | border: 1px solid #2d2d2d; 76 | border-right: 0; 77 | color: #ffffff; 78 | font-family: inherit; 79 | padding: 0 12px; 80 | display: flex; 81 | align-items: center; 82 | justify-content: center; 83 | height: 40px; 84 | width: 40px; 85 | font-size: 14px; 86 | transition: 0.3s; 87 | } 88 | 89 | .table-3-pagination > button:first-child { 90 | border-top-left-radius: 6px; 91 | border-bottom-left-radius: 6px; 92 | } 93 | 94 | .table-3-pagination > button:last-child { 95 | border-top-right-radius: 6px; 96 | border-bottom-right-radius: 6px; 97 | border-right: 1px solid #2d2d2d; 98 | } 99 | 100 | .table-3-pagination > button:hover { 101 | background: rgb(255 255 255 / 1%); 102 | } 103 | 104 | .table-3-pagination > button.active { 105 | background: #2d2d2d; 106 | } 107 | -------------------------------------------------------------------------------- /src/components/tables/Table3/Table3.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./Table3.css"; 3 | import { Checkbox } from "./Table3Example"; 4 | 5 | const pageSize = 5; 6 | 7 | const PaginatedTable = ({ pageNumber, totalPages, totalRows, goToPage }) => { 8 | return ( 9 |
    10 |
    11 | {[...Array(totalPages)].map((_, index) => ( 12 | 20 | ))} 21 |
    22 |

    23 | Viewing{" "} 24 | 25 | {pageNumber === 1 ? 1 : (pageNumber - 1) * pageSize + 1}- 26 | {pageNumber * pageSize} 27 | {" "} 28 | of {totalRows} rows 29 |

    30 |
    31 | ); 32 | }; 33 | 34 | export const Table3 = ({ columns, rows }) => { 35 | const [pageNumber, setPageNumber] = useState(1); 36 | 37 | const totalPages = Math.ceil(rows.length / pageSize); 38 | 39 | const paginateArray = (array, pageSize, pageNumber) => { 40 | return array.slice((pageNumber - 1) * pageSize, pageNumber * pageSize); 41 | }; 42 | 43 | const goToPage = (page) => setPageNumber(page); 44 | 45 | return ( 46 | <> 47 | 48 | 49 | 50 | 53 | {columns.map((column, index) => ( 54 | 55 | ))} 56 | 57 | 58 | 59 | {paginateArray(rows, pageSize, pageNumber).map((row, index) => ( 60 | 61 | {row.map((control, index) => ( 62 | 63 | ))} 64 | 65 | ))} 66 | 67 |
    51 | 52 | {column}
    {control}
    68 | 74 | 75 | ); 76 | }; 77 | -------------------------------------------------------------------------------- /src/components/tables/Table3/image.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/components/tables/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Table1/Table1Example"; 2 | export * from "./Table2/Table2Example"; 3 | export * from "./Table3/Table3Example"; 4 | -------------------------------------------------------------------------------- /src/components/widgets/Widget1/Widget1.jsx: -------------------------------------------------------------------------------- 1 | import { createRef, useEffect, useState } from "react"; 2 | import "./styles.css"; 3 | 4 | const buttonWidth = 56; 5 | const tabWidth = 300; 6 | 7 | const tabs = [ 8 | { 9 | title: "Home", 10 | icon: "home", 11 | content: 12 | "Some information inside the tab widget, that will auto resize it's height.", 13 | }, 14 | { 15 | title: "Settings", 16 | icon: "settings", 17 | content: 18 | "Some information inside the tab widget, that will auto resize it's height. This one has extra information so is a bit taller. Let's add one more sentence to see it's height grow even more!", 19 | }, 20 | { 21 | title: "Account", 22 | icon: "lock", 23 | content: 24 | "Some information inside the tab widget, that will auto resize it's height. This one has extra information so is a bit taller. ", 25 | }, 26 | ]; 27 | 28 | const WidgetHeader = ({ onClick, activeIndex }) => { 29 | return ( 30 |
    31 | {tabs.map((tab, index) => ( 32 | 41 | ))} 42 |
    48 |
    49 | ); 50 | }; 51 | 52 | const WidgetTab = ({ tabRef, title, content }) => { 53 | return ( 54 |
    55 |

    {title}

    56 |

    {content}

    57 |
    58 | ); 59 | }; 60 | 61 | export const Widget1 = () => { 62 | const [activeIndex, setActiveIndex] = useState(0); 63 | 64 | const [height, setHeight] = useState(140); 65 | 66 | const [refs, setRefs] = useState([]); 67 | 68 | const handleClick = (index) => { 69 | setActiveIndex(index); 70 | setHeight(refs[index].current.clientHeight); 71 | }; 72 | 73 | useEffect(() => { 74 | setRefs(tabs.map(() => createRef())); 75 | }, []); 76 | 77 | useEffect(() => { 78 | if (!refs.length) return; 79 | setHeight(refs[0].current.clientHeight); 80 | }, [refs.length]); 81 | 82 | return ( 83 |
    84 | 85 |
    86 |
    92 | {tabs.map((tab, index) => ( 93 | 99 | ))} 100 |
    101 |
    102 |
    103 | ); 104 | }; 105 | 106 | export const Widget1Example = () => ( 107 |
    108 | 109 |
    110 | ); 111 | -------------------------------------------------------------------------------- /src/components/widgets/Widget1/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --color-primary: #5644fd; 3 | --tab-width: 300px; 4 | --button-width: 56px; 5 | } 6 | 7 | .page.widget-1-page { 8 | display: flex; 9 | flex-direction: column; 10 | justify-content: start; 11 | padding-top: 260px; 12 | font-family: "Euclid Circular A", "Poppins"; 13 | line-height: 1.5; 14 | background: #24232b; 15 | color: #f9f9f9; 16 | } 17 | 18 | .widget { 19 | background: #18181d; 20 | width: var(--tab-width); 21 | border-radius: 8px; 22 | } 23 | 24 | .widget h2 { 25 | margin: 0; 26 | } 27 | 28 | .widget > header { 29 | position: relative; 30 | display: flex; 31 | border-bottom: 1px solid rgb(255 255 255 / 10%); 32 | } 33 | 34 | .widget > header > button { 35 | padding: 20px 0; 36 | font-size: 15px; 37 | width: var(--button-width); 38 | cursor: pointer; 39 | background: transparent; 40 | color: rgb(255 255 255 / 50%); 41 | display: grid; 42 | place-items: center; 43 | border: 0; 44 | font-size: 22px; 45 | transition: 0.5s; 46 | } 47 | 48 | .widget > header > button:not(.active) { 49 | opacity: 0.7; 50 | } 51 | 52 | .widget > header > button:hover:not(.active) { 53 | opacity: 1; 54 | } 55 | 56 | .widget > header > button.active { 57 | color: var(--color-primary); 58 | } 59 | 60 | .widget .content { 61 | position: relative; 62 | overflow: hidden; 63 | transition: 0.5s; 64 | } 65 | 66 | .widget .content-inner { 67 | position: absolute; 68 | top: 0; 69 | left: 0; 70 | display: flex; 71 | align-items: start; 72 | width: calc(var(--tab-width) * 3); 73 | transition: 0.5s; 74 | } 75 | 76 | .widget .underline { 77 | position: absolute; 78 | left: 0; 79 | bottom: 0; 80 | width: var(--button-width); 81 | height: 3px; 82 | background: var(--color-primary); 83 | transition: 0.2s; 84 | } 85 | 86 | .widget h2 { 87 | margin: 0 0 10px; 88 | font-size: 15px; 89 | font-weight: 400; 90 | } 91 | 92 | .widget p { 93 | margin: 0; 94 | font-size: 13px; 95 | opacity: 0.5; 96 | } 97 | 98 | .widget .content-inner > div { 99 | width: inherit; 100 | padding: 20px; 101 | } 102 | -------------------------------------------------------------------------------- /src/components/widgets/Widget2/Widget2.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./styles.css"; 3 | 4 | const menuHeight = getComputedStyle(document.body).getPropertyValue( 5 | "--widget-2-menu-height" 6 | ); 7 | 8 | const items = [ 9 | { 10 | name: "Home", 11 | content: 12 | "Vivamus volutpat ipsum ac ipsum feugiat, vel molestie elit vestibulum. Donec luctus commodo dictum. Aenean in turpis erat. Vestibulum imperdiet nibh. Ipsum ac ipsum feugiat, vel molestie.", 13 | }, 14 | { 15 | name: "Security", 16 | icon: "Encrypted", 17 | content: 18 | "Vivamus volutpat ipsum ac ipsum feugiat, vel molestie elit vestibulum. Donec luctus commodo dictum. Aenean in turpis erat. Vestibulum imperdiet nibh. Ipsum ac ipsum feugiat, vel molestie.", 19 | }, 20 | { 21 | name: "Stacks", 22 | content: 23 | "Vivamus volutpat ipsum ac ipsum feugiat, vel molestie elit vestibulum. Donec luctus commodo dictum. Aenean in turpis erat. Vestibulum imperdiet nibh. Ipsum ac ipsum feugiat, vel molestie.", 24 | }, 25 | { 26 | name: "Settings", 27 | content: 28 | "Vivamus volutpat ipsum ac ipsum feugiat, vel molestie elit vestibulum. Donec luctus commodo dictum. Aenean in turpis erat. Vestibulum imperdiet nibh. Ipsum ac ipsum feugiat, vel molestie.", 29 | }, 30 | ]; 31 | 32 | export const Widget2 = () => { 33 | const [activeBlock, setActiveBlock] = useState(0); 34 | 35 | const toggleMenuBlock = (index) => setActiveBlock(index); 36 | 37 | return ( 38 |
    39 |
    40 |
    41 | {items.map((item, index) => ( 42 | 52 | ))} 53 |
    54 |
    55 |
    61 | {items.map((item) => ( 62 |
    63 |

    {item.name}

    64 |

    {item.content}

    65 |
    66 | ))} 67 |
    68 |
    69 |
    70 |
    71 | ); 72 | }; 73 | -------------------------------------------------------------------------------- /src/components/widgets/Widget2/styles copy.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --widget-2-color-primary: #195adc; 3 | --widget-2-sidebar-width: 130px; 4 | --widget-2-menu-height: 200px; 5 | } 6 | 7 | .page.widget-2-page { 8 | margin: 0; 9 | display: grid; 10 | place-items: center; 11 | background: linear-gradient(-135deg, var(--widget-2-color-primary), #0f3278); 12 | color: #f0f5ff; 13 | } 14 | 15 | .widget-2-card { 16 | display: flex; 17 | padding: 0 20px; 18 | width: 440px; 19 | height: var(--widget-2-menu-height); 20 | border-radius: 10px; 21 | background: #101115; 22 | box-shadow: 0 20px 30px rgba(57, 76, 96, 0.06); 23 | } 24 | 25 | .widget-2-card .buttons { 26 | padding-top: 20px; 27 | width: var(--widget-2-sidebar-width); 28 | } 29 | 30 | .widget-2-card .buttons button { 31 | margin: 0; 32 | font-size: 14px; 33 | width: 100%; 34 | height: 40px; 35 | padding: 0 0 0 12px; 36 | background: transparent; 37 | border-radius: 6px; 38 | border: 0; 39 | display: flex; 40 | gap: 8px; 41 | align-items: center; 42 | font-weight: 400; 43 | font-family: inherit; 44 | cursor: pointer; 45 | color: inherit; 46 | } 47 | 48 | .widget-2-card .buttons button:focus { 49 | outline-color: var(--widget-2-color-primary); 50 | outline-offset: 0; 51 | } 52 | 53 | .widget-2-card .buttons button:hover { 54 | background-color: rgb(255 255 255 / 4%); 55 | } 56 | 57 | .widget-2-card .buttons button span { 58 | font-size: 16px; 59 | } 60 | 61 | .widget-2-card .buttons button.active { 62 | background: var(--widget-2-color-primary); 63 | color: #f9f9f9; 64 | } 65 | 66 | .widget-2-card .wrapper { 67 | position: relative; 68 | overflow: hidden; 69 | flex: 1 1 auto; 70 | } 71 | 72 | .widget-2-card .wrapper::before, 73 | .widget-2-card .wrapper::after { 74 | content: ""; 75 | position: absolute; 76 | z-index: 2; 77 | left: 0; 78 | width: 100%; 79 | height: 36px; 80 | } 81 | 82 | .widget-2-card .wrapper::before { 83 | top: 0; 84 | background: linear-gradient(#101115, rgb(24 24 29 / 0%)); 85 | } 86 | 87 | .widget-2-card .wrapper::after { 88 | bottom: 0; 89 | background: linear-gradient(rgb(24 24 29 / 0%), #101115); 90 | } 91 | 92 | .widget-2-card .content { 93 | position: absolute; 94 | z-index: 1; 95 | top: 0; 96 | left: 0; 97 | height: calc(var(--widget-2-menu-height) * 3); 98 | transition: 0.6s; 99 | } 100 | 101 | .widget-2-card .content p { 102 | display: flex; 103 | align-items: center; 104 | line-height: 1.6; 105 | font-size: 13px; 106 | margin: 0; 107 | opacity: 0.5; 108 | } 109 | 110 | .widget-2-card .block { 111 | display: flex; 112 | flex-direction: column; 113 | justify-content: center; 114 | padding: 0 20px; 115 | height: var(--widget-2-menu-height); 116 | } 117 | 118 | .widget-2-card .block h2 { 119 | margin: 0 0 6px; 120 | font-size: 18px; 121 | font-weight: 400; 122 | } 123 | -------------------------------------------------------------------------------- /src/components/widgets/Widget2/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --widget-2-color-primary: #195adc; 3 | --widget-2-sidebar-width: 130px; 4 | --widget-2-menu-height: 200px; 5 | } 6 | 7 | .page.widget-2-page { 8 | margin: 0; 9 | display: grid; 10 | place-items: center; 11 | background: linear-gradient(-135deg, var(--widget-2-color-primary), #0f3278); 12 | color: #f0f5ff; 13 | } 14 | 15 | .widget-2-card { 16 | display: flex; 17 | padding: 0 20px; 18 | width: 440px; 19 | height: var(--widget-2-menu-height); 20 | border-radius: 10px; 21 | background: #101115; 22 | box-shadow: 0 20px 30px rgba(57, 76, 96, 0.06); 23 | } 24 | 25 | .widget-2-card .buttons { 26 | padding-top: 20px; 27 | width: var(--widget-2-sidebar-width); 28 | } 29 | 30 | .widget-2-card .buttons button { 31 | margin: 0; 32 | font-size: 14px; 33 | width: 100%; 34 | height: 40px; 35 | padding: 0 0 0 12px; 36 | background: transparent; 37 | border-radius: 6px; 38 | border: 0; 39 | display: flex; 40 | gap: 8px; 41 | align-items: center; 42 | font-weight: 400; 43 | font-family: inherit; 44 | cursor: pointer; 45 | color: inherit; 46 | } 47 | 48 | .widget-2-card .buttons button:focus { 49 | outline-color: var(--widget-2-color-primary); 50 | outline-offset: 0; 51 | } 52 | 53 | .widget-2-card .buttons button:hover { 54 | background-color: rgb(255 255 255 / 4%); 55 | } 56 | 57 | .widget-2-card .buttons button span { 58 | font-size: 16px; 59 | } 60 | 61 | .widget-2-card .buttons button.active { 62 | background: var(--widget-2-color-primary); 63 | color: #f9f9f9; 64 | } 65 | 66 | .widget-2-card .wrapper { 67 | position: relative; 68 | overflow: hidden; 69 | flex: 1 1 auto; 70 | } 71 | 72 | .widget-2-card .wrapper::before, 73 | .widget-2-card .wrapper::after { 74 | content: ""; 75 | position: absolute; 76 | z-index: 2; 77 | left: 0; 78 | width: 100%; 79 | height: 36px; 80 | } 81 | 82 | .widget-2-card .wrapper::before { 83 | top: 0; 84 | background: linear-gradient(#101115, rgb(24 24 29 / 0%)); 85 | } 86 | 87 | .widget-2-card .wrapper::after { 88 | bottom: 0; 89 | background: linear-gradient(rgb(24 24 29 / 0%), #101115); 90 | } 91 | 92 | .widget-2-card .content { 93 | position: absolute; 94 | z-index: 1; 95 | top: 0; 96 | left: 0; 97 | height: calc(var(--widget-2-menu-height) * 3); 98 | transition: 0.6s; 99 | } 100 | 101 | .widget-2-card .content p { 102 | display: flex; 103 | align-items: center; 104 | line-height: 1.6; 105 | font-size: 13px; 106 | margin: 0; 107 | opacity: 0.5; 108 | } 109 | 110 | .widget-2-card .block { 111 | display: flex; 112 | flex-direction: column; 113 | justify-content: center; 114 | padding: 0 20px; 115 | height: var(--widget-2-menu-height); 116 | } 117 | 118 | .widget-2-card .block h2 { 119 | margin: 0 0 6px; 120 | font-size: 18px; 121 | font-weight: 400; 122 | } 123 | -------------------------------------------------------------------------------- /src/components/widgets/index.js: -------------------------------------------------------------------------------- 1 | export * from "./Widget1/Widget1"; 2 | export * from "./Widget2/Widget2"; 3 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | background: #000000; 4 | color: #f9f9f9; 5 | overflow: hidden; 6 | font-family: "Euclid Circular A", "Poppins"; 7 | } 8 | 9 | * { 10 | box-sizing: border-box; 11 | } 12 | 13 | .page { 14 | width: 100vw; 15 | height: 100vh; 16 | display: grid; 17 | place-items: center; 18 | } 19 | -------------------------------------------------------------------------------- /src/main.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.jsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------