├── .gitignore ├── craco.config.js ├── package.json ├── postcss.config.js ├── public ├── img │ ├── favicon.png │ ├── loading.gif │ ├── logo-type.png │ ├── posts │ │ ├── dhanishgajjar │ │ │ └── 903f882b-8723-404f-bb7b-0e0b545309b0.jpg │ │ ├── fazurrehman │ │ │ └── e1c0bf86-c283-4d77-96c5-af2948131fdb.jpg │ │ └── ui_migulko │ │ │ └── f3474bb2-6d63-485c-9745-a62b640fbc6f.jpg │ └── users │ │ ├── andrew.eugene.jpg │ │ ├── behnamkhandann.jpg │ │ ├── dhanishgajjar.jpg │ │ ├── fazurrehman.jpg │ │ ├── jakobowsky.jpg │ │ ├── joeel56.jpg │ │ ├── lubnadev.jpg │ │ ├── marziuxd.jpg │ │ ├── mehradhiddenofficial.jpg │ │ ├── neysidev.jpeg │ │ ├── onlysiamak.jpg │ │ ├── russcodes.jpg │ │ ├── ryanswich.jpg │ │ ├── sajon.co.jpg │ │ ├── samirarahimi.jpg │ │ ├── sepide_moqadasi.jpg │ │ ├── sinamehraad.jpg │ │ ├── ui.amjad.jpg │ │ └── ui_migulko.jpg └── index.html ├── src ├── assets │ └── icons │ │ ├── add.svg │ │ ├── close.svg │ │ ├── comment.svg │ │ ├── direct.svg │ │ ├── emoji.svg │ │ ├── explore.svg │ │ ├── home.svg │ │ ├── like.svg │ │ ├── more.svg │ │ ├── save.svg │ │ ├── search.svg │ │ └── share.svg ├── components │ ├── Alerts │ │ ├── AlertContainer.css │ │ └── AlertContainer.tsx │ ├── Elements │ │ └── Story.tsx │ ├── Home │ │ ├── Details │ │ │ ├── Details.tsx │ │ │ ├── Footer.css │ │ │ ├── Footer.tsx │ │ │ ├── Profile.tsx │ │ │ └── Suggestions │ │ │ │ ├── Suggestion.tsx │ │ │ │ ├── Suggestions.tsx │ │ │ │ └── SuggestionsHeader.tsx │ │ ├── Home.tsx │ │ ├── Main │ │ │ ├── Backdrop.tsx │ │ │ ├── Main.tsx │ │ │ ├── Post.tsx │ │ │ ├── Posts.tsx │ │ │ └── Story.tsx │ │ └── Navbar │ │ │ ├── Actions.tsx │ │ │ ├── Links.tsx │ │ │ ├── Logo.tsx │ │ │ ├── Menu.tsx │ │ │ ├── Mobile.tsx │ │ │ ├── Navbar.tsx │ │ │ └── Search.tsx │ ├── Layout.tsx │ └── Modals │ │ ├── ModalsWrapper.css │ │ ├── ModalsWrapper.tsx │ │ ├── PostsOptions.css │ │ └── PostsOptions.tsx ├── constants │ ├── messages.ts │ └── stories.ts ├── containers │ └── App.tsx ├── index.css ├── index.tsx ├── pages │ ├── Direct │ │ ├── Direct.css │ │ ├── Direct.tsx │ │ ├── DirectTabs.css │ │ ├── DirectTabs.tsx │ │ ├── MessagesList.css │ │ ├── MessagesList.tsx │ │ ├── NoMessagesSelected.css │ │ ├── NoMessagesSelected.tsx │ │ ├── SwitchAccounts.css │ │ └── SwitchAccounts.tsx │ └── Home │ │ ├── Details │ │ ├── Details.jsx │ │ ├── Footer.css │ │ ├── Footer.jsx │ │ ├── Profile.jsx │ │ └── Suggestions │ │ │ ├── Suggestion.jsx │ │ │ ├── Suggestions.jsx │ │ │ └── SuggestionsHeader.jsx │ │ ├── Home.jsx │ │ ├── Main │ │ ├── Backdrop.jsx │ │ ├── Backdrop.module.css │ │ ├── Main.jsx │ │ ├── Post.jsx │ │ ├── Posts.jsx │ │ └── Story.jsx │ │ └── Navbar │ │ ├── Actions.jsx │ │ ├── Links.jsx │ │ ├── Links.module.css │ │ ├── Logo.jsx │ │ ├── Menu.jsx │ │ ├── Menu.module.css │ │ ├── Mobile.jsx │ │ ├── Navbar.jsx │ │ └── Search.jsx ├── react-app-env.d.ts └── routes │ └── index.tsx ├── tailwind.config.js ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /craco.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | style: { 3 | postcss: { 4 | plugins: [require("tailwindcss"), require("autoprefixer")] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-instagram", 3 | "version": "1.0.0", 4 | "private": true, 5 | "author": { 6 | "name": "Mehdi Neysi", 7 | "email": "dev.mehdineysi@gmail.com", 8 | "url": "https://github.com/neysidev" 9 | }, 10 | "prettier": { 11 | "arrowParens": "avoid", 12 | "semi": false, 13 | "trailingComma": "none" 14 | }, 15 | "scripts": { 16 | "start": "craco start", 17 | "build": "craco build", 18 | "test": "craco test", 19 | "eject": "react-scripts eject", 20 | "format": "npx prettier --write ." 21 | }, 22 | "dependencies": { 23 | "@craco/craco": "^6.4.3", 24 | "react": "18.0.0", 25 | "react-dom": "18.0.0", 26 | "react-icons": "^4.2.0", 27 | "react-router-dom": "^5.2.0", 28 | "react-scripts": "4.0.3", 29 | "web-vitals": "^1.0.1" 30 | }, 31 | "devDependencies": { 32 | "@tailwindcss/postcss7-compat": "^2.0.4", 33 | "@testing-library/jest-dom": "^5.16.4", 34 | "@testing-library/react": "^13.0.0", 35 | "@testing-library/user-event": "^14.0.4", 36 | "@types/jest": "^27.4.1", 37 | "@types/node": "^17.0.23", 38 | "@types/react": "^18.0.0", 39 | "@types/react-dom": "^18.0.0", 40 | "@types/react-router-dom": "^5.3.3", 41 | "prettier": "^2.2.1", 42 | "prop-types": "^15.7.2", 43 | "typescript": "^4.6.3", 44 | "autoprefixer": "^9.8.6", 45 | "postcss": "^7.0.35", 46 | "tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.4" 47 | }, 48 | "eslintConfig": { 49 | "extends": [ 50 | "react-app", 51 | "react-app/jest" 52 | ] 53 | }, 54 | "browserslist": { 55 | "production": [ 56 | ">0.2%", 57 | "not dead", 58 | "not op_mini all" 59 | ], 60 | "development": [ 61 | "last 1 chrome version", 62 | "last 1 firefox version", 63 | "last 1 safari version" 64 | ] 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/favicon.png -------------------------------------------------------------------------------- /public/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/loading.gif -------------------------------------------------------------------------------- /public/img/logo-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/logo-type.png -------------------------------------------------------------------------------- /public/img/posts/dhanishgajjar/903f882b-8723-404f-bb7b-0e0b545309b0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/posts/dhanishgajjar/903f882b-8723-404f-bb7b-0e0b545309b0.jpg -------------------------------------------------------------------------------- /public/img/posts/fazurrehman/e1c0bf86-c283-4d77-96c5-af2948131fdb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/posts/fazurrehman/e1c0bf86-c283-4d77-96c5-af2948131fdb.jpg -------------------------------------------------------------------------------- /public/img/posts/ui_migulko/f3474bb2-6d63-485c-9745-a62b640fbc6f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/posts/ui_migulko/f3474bb2-6d63-485c-9745-a62b640fbc6f.jpg -------------------------------------------------------------------------------- /public/img/users/andrew.eugene.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/andrew.eugene.jpg -------------------------------------------------------------------------------- /public/img/users/behnamkhandann.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/behnamkhandann.jpg -------------------------------------------------------------------------------- /public/img/users/dhanishgajjar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/dhanishgajjar.jpg -------------------------------------------------------------------------------- /public/img/users/fazurrehman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/fazurrehman.jpg -------------------------------------------------------------------------------- /public/img/users/jakobowsky.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/jakobowsky.jpg -------------------------------------------------------------------------------- /public/img/users/joeel56.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/joeel56.jpg -------------------------------------------------------------------------------- /public/img/users/lubnadev.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/lubnadev.jpg -------------------------------------------------------------------------------- /public/img/users/marziuxd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/marziuxd.jpg -------------------------------------------------------------------------------- /public/img/users/mehradhiddenofficial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/mehradhiddenofficial.jpg -------------------------------------------------------------------------------- /public/img/users/neysidev.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/neysidev.jpeg -------------------------------------------------------------------------------- /public/img/users/onlysiamak.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/onlysiamak.jpg -------------------------------------------------------------------------------- /public/img/users/russcodes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/russcodes.jpg -------------------------------------------------------------------------------- /public/img/users/ryanswich.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/ryanswich.jpg -------------------------------------------------------------------------------- /public/img/users/sajon.co.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/sajon.co.jpg -------------------------------------------------------------------------------- /public/img/users/samirarahimi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/samirarahimi.jpg -------------------------------------------------------------------------------- /public/img/users/sepide_moqadasi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/sepide_moqadasi.jpg -------------------------------------------------------------------------------- /public/img/users/sinamehraad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/sinamehraad.jpg -------------------------------------------------------------------------------- /public/img/users/ui.amjad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/ui.amjad.jpg -------------------------------------------------------------------------------- /public/img/users/ui_migulko.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/public/img/users/ui_migulko.jpg -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Instagram 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/assets/icons/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/direct.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/emoji.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/explore.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/like.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/more.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/save.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/assets/icons/share.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/components/Alerts/AlertContainer.css: -------------------------------------------------------------------------------- 1 | .alert-container { 2 | @apply bg-gray-800 text-white px-4 py-3 text-sm fixed left-0 right-0 -bottom-20; 3 | } 4 | 5 | .alert-container.show { 6 | @apply bottom-0; 7 | } 8 | -------------------------------------------------------------------------------- /src/components/Alerts/AlertContainer.tsx: -------------------------------------------------------------------------------- 1 | import "./AlertContainer.css" 2 | import { useEffect } from "react" 3 | import { createPortal } from "react-dom" 4 | 5 | type Props = { 6 | show: boolean 7 | text: string 8 | onClose: () => void 9 | } 10 | 11 | export default function AlertContainer(props: Props) { 12 | let children = null 13 | const classes = ["alert-container"] 14 | 15 | useEffect(() => { 16 | if (props.show) setTimeout(() => props.onClose(), 3000) 17 | }, [props.show]) 18 | 19 | if (props.show) { 20 | classes.push("show") 21 | children =
{props.text}
22 | } 23 | 24 | return createPortal( 25 | children, 26 | document.getElementById("app-alerts") || document.body 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /src/components/Elements/Story.tsx: -------------------------------------------------------------------------------- 1 | type Status = "unseen" | "seen" 2 | type Props = { 3 | status: Status 4 | src: string 5 | text: string 6 | size: number | string 7 | } 8 | 9 | export default function Story(props: Props) { 10 | const containerClasses = ["p-0.5 rounded-full"] 11 | 12 | if (props.status === "seen") containerClasses.push("bg-gray-200") 13 | else if (props.status === "unseen") 14 | containerClasses.push("bg-gradient-to-tr from-yellow-400 to-fuchsia-600") 15 | else containerClasses.push("bg-transparent") 16 | 17 | return ( 18 |
19 |
23 | {props.text} 28 |
29 |
30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Home/Details/Details.tsx: -------------------------------------------------------------------------------- 1 | import Profile from "./Profile" 2 | import Suggestions from "./Suggestions/Suggestions" 3 | import Footer from "./Footer" 4 | 5 | const Details = () => { 6 | return ( 7 | 12 | ) 13 | } 14 | 15 | export default Details 16 | -------------------------------------------------------------------------------- /src/components/Home/Details/Footer.css: -------------------------------------------------------------------------------- 1 | #footer ul li:after { 2 | content: "\00B7"; 3 | margin: 0 0.25em; 4 | } 5 | #footer ul li:last-child:after { 6 | content: ""; 7 | } 8 | #footer ul li a { 9 | font-size: 11px; 10 | } 11 | #footer p { 12 | font-size: 11px; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Home/Details/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | import "./Footer.css" 4 | 5 | const Footer = () => { 6 | return ( 7 | 47 | ) 48 | } 49 | 50 | export default Footer 51 | -------------------------------------------------------------------------------- /src/components/Home/Details/Profile.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const Profile = () => { 4 | return ( 5 |
6 |
7 | 8 |
9 | Mehdi Neysi 14 |
15 | 16 |
17 | 18 | neysidev 19 | 20 |

Mehdi Neysi

21 |
22 |
23 | 26 |
27 | ) 28 | } 29 | 30 | export default Profile 31 | -------------------------------------------------------------------------------- /src/components/Home/Details/Suggestions/Suggestion.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | export default function Suggestion({ 4 | userImg, 5 | username 6 | }: { 7 | userImg: string 8 | username: string 9 | }) { 10 | return ( 11 |
  • 12 |
    13 | 14 | {username 19 | 20 |
    21 | 22 | {username} 23 | 24 | New to Instagram 25 |
    26 |
    27 | 30 |
  • 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /src/components/Home/Details/Suggestions/Suggestions.tsx: -------------------------------------------------------------------------------- 1 | import Suggestion from "./Suggestion" 2 | import SuggestionsHeader from "./SuggestionsHeader" 3 | 4 | const Suggestions = () => { 5 | return ( 6 |
    7 | 8 | 15 |
    16 | ) 17 | } 18 | 19 | export default Suggestions 20 | -------------------------------------------------------------------------------- /src/components/Home/Details/Suggestions/SuggestionsHeader.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const suggestionsHeader = () => ( 4 |
    5 |

    Suggestions For You

    6 | 7 | See All 8 | 9 |
    10 | ) 11 | 12 | export default suggestionsHeader 13 | -------------------------------------------------------------------------------- /src/components/Home/Home.tsx: -------------------------------------------------------------------------------- 1 | import Details from "./Details/Details" 2 | import Main from "./Main/Main" 3 | 4 | export default function Home() { 5 | return ( 6 |
    7 |
    8 |
    9 |
    10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Home/Main/Backdrop.tsx: -------------------------------------------------------------------------------- 1 | export default function Backdrop({ show }: { show: boolean }) { 2 | return show ? ( 3 |
    4 | ) : null 5 | } 6 | -------------------------------------------------------------------------------- /src/components/Home/Main/Main.tsx: -------------------------------------------------------------------------------- 1 | import Posts from "./Posts" 2 | import Story from "./Story" 3 | 4 | const Main = () => { 5 | return ( 6 |
    7 | 8 | 9 |
    10 | ) 11 | } 12 | 13 | export default Main 14 | -------------------------------------------------------------------------------- /src/components/Home/Main/Post.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | import Story from "../../Elements/Story" 3 | 4 | interface Props { 5 | name: string 6 | username: string 7 | profilePicture?: string 8 | imgName: string 9 | likes: string 10 | time: string 11 | status: "seen" | "unseen" 12 | } 13 | 14 | export default function Post(props: Props) { 15 | const { name, username, imgName, likes, time, status } = props 16 | 17 | return ( 18 |
    19 |
    20 | 21 | 27 | 28 | {username} 29 | 30 | 31 | 62 |
    63 |
    64 | Dashboard 69 |
    70 |
    71 |
    72 |
    73 | 84 | 99 | 110 |
    111 | 122 |
    123 | 124 | {likes} likes 125 | 126 | 131 | {time} 132 | 133 |
    134 |
    135 | 147 | 152 | 155 |
    156 |
    157 | ) 158 | } 159 | -------------------------------------------------------------------------------- /src/components/Home/Main/Posts.tsx: -------------------------------------------------------------------------------- 1 | import Post from "./Post" 2 | const Posts = () => { 3 | return ( 4 |
    5 | 13 | 21 | 29 |
    30 | ) 31 | } 32 | 33 | export default Posts 34 | -------------------------------------------------------------------------------- /src/components/Home/Main/Story.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const Story = () => { 4 | return ( 5 |
    6 | 106 |
    107 | ) 108 | } 109 | 110 | export default Story 111 | -------------------------------------------------------------------------------- /src/components/Home/Navbar/Actions.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | export default function Actions() { 4 | return ( 5 |
    6 | 10 | 17 | 18 | 19 | 20 | 24 | 31 | 32 | 33 | 34 | 35 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 62 | 63 | 64 | 65 | 69 | neysidev 74 | 75 |
    76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /src/components/Home/Navbar/Links.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import { 3 | IoHome, 4 | IoCompassOutline, 5 | IoHeartOutline, 6 | IoChatbubbleOutline 7 | } from "react-icons/io5" 8 | import { Link } from "react-router-dom" 9 | import Menu from "./Menu" 10 | 11 | export default function Links() { 12 | const [showMenu, setShowMenu] = useState(false) 13 | 14 | const toggleOpen = () => { 15 | if (showMenu) { 16 | setShowMenu(false) 17 | } else { 18 | setShowMenu(true) 19 | } 20 | } 21 | 22 | return ( 23 |
    24 | 59 |
    60 | ) 61 | } 62 | -------------------------------------------------------------------------------- /src/components/Home/Navbar/Logo.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | export default function Logo() { 4 | return ( 5 |
    6 | 7 | Instagram Logo 8 | 9 |
    10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Home/Navbar/Menu.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | import { 3 | IoBookmarkOutline, 4 | IoCogOutline, 5 | IoLogOutOutline, 6 | IoPersonCircleOutline, 7 | IoReloadOutline 8 | } from "react-icons/io5" 9 | 10 | type Props = { 11 | show: boolean 12 | onClose: () => void 13 | } 14 | 15 | export default function Menu(props: Props) { 16 | const className = [ 17 | "absolute top-12 -right-6", 18 | "w-56 select-none bg-white", 19 | "overflow-hidden rounded-lg shadow-lg" 20 | ] 21 | props.show ? className.push("block z-50") : className.push("hidden") 22 | 23 | return ( 24 | <> 25 |
    31 |
    32 |
      33 |
    • 34 | 35 |
      36 | 37 | Profile 38 |
      39 | 40 |
    • 41 |
    • 42 | 43 |
      44 | 45 | Saved 46 |
      47 | 48 |
    • 49 |
    • 50 | 51 |
      52 | 53 | Settings 54 |
      55 | 56 |
    • 57 |
    • 58 | 59 |
      60 | 61 | Switch Accounts 62 |
      63 | 64 |
    • 65 |
      66 |
    • 67 | 68 |
      69 | 70 | Log out 71 |
      72 | 73 |
    • 74 |
    75 |
    76 | 77 | ) 78 | } 79 | -------------------------------------------------------------------------------- /src/components/Home/Navbar/Mobile.tsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | export default function Mobile() { 4 | return ( 5 |
    6 | 7 | Instagram Logo 8 | 9 | 10 | 17 | 18 | 19 | 20 |
    21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /src/components/Home/Navbar/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | import Actions from "./Actions" 4 | import Links from "./Links" 5 | import Logo from "./Logo" 6 | import Mobile from "./Mobile" 7 | import Search from "./Search" 8 | 9 | export default function Navbar() { 10 | const [openSearch, setOpenSearch] = useState(false) 11 | 12 | return ( 13 | <> 14 |
    15 |
    16 |
    17 | 18 | setOpenSearch(true)} 21 | onClose={() => setOpenSearch(false)} 22 | /> 23 | 24 |
    25 | 26 |
    27 |
    28 | 29 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/components/Home/Navbar/Search.tsx: -------------------------------------------------------------------------------- 1 | type Props = { 2 | open: boolean 3 | onOpen: () => void 4 | onClose: () => void 5 | } 6 | 7 | export default function Search(props: Props) { 8 | let content 9 | if (props.open) { 10 | content = ( 11 |
    12 | 20 | 21 | 22 | 23 | 44 | element && element.focus()} 48 | type="text" 49 | /> 50 |
    51 | ) 52 | } else { 53 | content = ( 54 |
    59 |
    68 | 76 | 77 | 78 | 79 | Search 80 |
    81 |
    85 |
    86 | ) 87 | } 88 | 89 | return
    {content}
    90 | } 91 | -------------------------------------------------------------------------------- /src/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Navbar from "./Home/Navbar/Navbar" 3 | 4 | interface LayoutProps { 5 | children: React.ReactNode 6 | } 7 | 8 | export default function Layout({ children }: LayoutProps) { 9 | return ( 10 | <> 11 | 12 |
    {children}
    13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /src/components/Modals/ModalsWrapper.css: -------------------------------------------------------------------------------- 1 | .modals-wrapper .overlay { 2 | @apply fixed inset-0 bg-black bg-opacity-75 z-40; 3 | } 4 | 5 | .modals-wrapper .content { 6 | @apply fixed inset-0 z-50 grid place-items-center; 7 | } 8 | -------------------------------------------------------------------------------- /src/components/Modals/ModalsWrapper.tsx: -------------------------------------------------------------------------------- 1 | import "./ModalsWrapper.css" 2 | import { useEffect } from "react" 3 | import { createPortal } from "react-dom" 4 | 5 | type Props = { 6 | open: boolean 7 | children: any 8 | } 9 | 10 | export default function ModalsWrappers(props: Props) { 11 | useEffect(() => { 12 | if (props.open) document.body.style.overflow = "hidden" 13 | 14 | return () => { 15 | document.body.style.overflow = "" 16 | } 17 | }, [props.open]) 18 | 19 | let modalChildren = null 20 | if (props.open) { 21 | modalChildren = ( 22 |
    23 |
    24 |
    {props.children}
    25 |
    26 | ) 27 | } 28 | 29 | return createPortal( 30 | modalChildren, 31 | document.querySelector("#app-modals") || document.body 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /src/components/Modals/PostsOptions.css: -------------------------------------------------------------------------------- 1 | .posts-options { 2 | @apply bg-white w-96 overflow-hidden rounded-2xl select-none text-center divide-y; 3 | } 4 | 5 | .posts-options .option { 6 | @apply py-3 text-sm cursor-pointer hover:bg-gray-50; 7 | } 8 | 9 | .posts-options .option.option-red { 10 | @apply font-semibold text-red-500; 11 | } 12 | -------------------------------------------------------------------------------- /src/components/Modals/PostsOptions.tsx: -------------------------------------------------------------------------------- 1 | import "./PostsOptions.css" 2 | import ModalsWrappers from "./ModalsWrapper" 3 | 4 | type Props = { 5 | open: boolean 6 | copyLink: () => void 7 | onClose: () => void 8 | } 9 | 10 | export default function PostsOptions(props: Props) { 11 | return ( 12 | 13 |
      14 |
    • Report
    • 15 |
    • Unfollow
    • 16 |
    • Go to post
    • 17 |
    • Tagged accounts
    • 18 |
    • Share to...
    • 19 |
    • { 22 | props.copyLink() 23 | props.onClose() 24 | }} 25 | > 26 | Copy link 27 |
    • 28 |
    • Embed
    • 29 |
    • 30 | Cancel 31 |
    • 32 |
    33 |
    34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/constants/messages.ts: -------------------------------------------------------------------------------- 1 | export interface IDirectMessage { 2 | id: string 3 | user: { 4 | avatar: string 5 | username: string 6 | } 7 | lastMessage: { 8 | text: string 9 | time: string 10 | } 11 | } 12 | 13 | export const PRIMARY_MESSAGES: IDirectMessage[] = [ 14 | { 15 | id: "message-1", 16 | user: { 17 | avatar: "https://avatars.githubusercontent.com/u/6355370?v=4", 18 | username: "ianschmitz" 19 | }, 20 | lastMessage: { 21 | text: "Yeah, I think we should do that", 22 | time: "1h" 23 | } 24 | }, 25 | { 26 | id: "message-2", 27 | user: { 28 | avatar: "https://avatars.githubusercontent.com/u/22095598?v=4", 29 | username: "jurrehoutkamp" 30 | }, 31 | lastMessage: { 32 | text: "Good job Mehdi!", 33 | time: "3h" 34 | } 35 | }, 36 | { 37 | id: "message-3", 38 | user: { 39 | avatar: "https://avatars.githubusercontent.com/u/1016365?v=4", 40 | username: "PatrickJS" 41 | }, 42 | lastMessage: { 43 | text: "Wow, that is a cool feature", 44 | time: "6h" 45 | } 46 | } 47 | ] 48 | -------------------------------------------------------------------------------- /src/constants/stories.ts: -------------------------------------------------------------------------------- 1 | export const USER_STORIES = [ 2 | { _id: "6250414ab8df8591dd07a5a5", username: "russcodes" }, 3 | { _id: "625042d3b224a02f3ba6af2e", username: "onlysiamak" }, 4 | { _id: "6250435b7d72373e7bc543e2", username: "sepide_moqadasi" }, 5 | { _id: "62504355f2319d44346d9cbe", username: "ui.amjad" }, 6 | { _id: "625043508410226f2682b39b", username: "mehradhiddenofficial" }, 7 | { _id: "6250434b7fb183398e50fd2a", username: "fazurrehman" }, 8 | { _id: "625043450b1e79bb83a6fad1", username: "sajon.co" }, 9 | { _id: "62504745f91e4741b1dbb4f7", username: "samirarahimi" }, 10 | { _id: "62504792f022aa1979045da5", username: "sinamehraad" } 11 | ] 12 | -------------------------------------------------------------------------------- /src/containers/App.tsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from "react" 2 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom" 3 | 4 | import Layout from "../components/Layout" 5 | import routes from "../routes" 6 | 7 | export default function App() { 8 | return ( 9 | 10 | 11 | 12 | 13 | {routes.map(route => ( 14 | 20 | ))} 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import "./index.css" 2 | 3 | import { createRoot } from "react-dom/client" 4 | import App from "./containers/App" 5 | 6 | const container = document.getElementById("app") as HTMLElement 7 | createRoot(container).render() 8 | -------------------------------------------------------------------------------- /src/pages/Direct/Direct.css: -------------------------------------------------------------------------------- 1 | section.direct { 2 | @apply bg-white w-full flex divide-x-2 rounded border border-gray-200; 3 | height: calc(100vh - 7rem); 4 | } 5 | 6 | section.direct .direct__left { 7 | @apply w-1/3 flex flex-col; 8 | } 9 | 10 | section.direct .direct__right { 11 | @apply w-2/3; 12 | } 13 | -------------------------------------------------------------------------------- /src/pages/Direct/Direct.tsx: -------------------------------------------------------------------------------- 1 | import "./Direct.css" 2 | 3 | import { PRIMARY_MESSAGES } from "../../constants/messages" 4 | 5 | import DirectTabs from "./DirectTabs" 6 | import MessagesList from "./MessagesList" 7 | import NoMessagesSelected from "./NoMessagesSelected" 8 | import SwitchAccounts from "./SwitchAccounts" 9 | 10 | export default function Direct() { 11 | return ( 12 |
    13 |
    14 | 15 | 16 | 17 |
    18 |
    19 | 20 |
    21 |
    22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /src/pages/Direct/DirectTabs.css: -------------------------------------------------------------------------------- 1 | .direct__tabs { 2 | @apply flex items-center uppercase text-sm; 3 | } 4 | 5 | .direct__tab { 6 | @apply flex flex-1 justify-center border-b border-gray-200 text-gray-400; 7 | } 8 | 9 | .direct__tab.active { 10 | @apply text-gray-800 border-gray-800; 11 | } 12 | 13 | .direct__tab a { 14 | @apply inline-block py-3 px-4; 15 | } 16 | -------------------------------------------------------------------------------- /src/pages/Direct/DirectTabs.tsx: -------------------------------------------------------------------------------- 1 | import "./DirectTabs.css" 2 | import { Link, useLocation } from "react-router-dom" 3 | 4 | export default function DirectTabs() { 5 | const location = useLocation() 6 | 7 | const isPrimary = location.pathname === "/direct/inbox" 8 | const isGeneral = location.pathname === "/direct/inbox/general" 9 | 10 | const primaryClasses = ["direct__tab"] 11 | const generalClasses = ["direct__tab"] 12 | 13 | if (isPrimary) primaryClasses.push("active") 14 | if (isGeneral) generalClasses.push("active") 15 | 16 | return ( 17 |
      18 |
    • 19 | Primary 20 |
    • 21 |
    • 22 | General 23 |
    • 24 |
    25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /src/pages/Direct/MessagesList.css: -------------------------------------------------------------------------------- 1 | .messages-list { 2 | @apply flex-1 overflow-y-auto; 3 | } 4 | 5 | .messages-list .message { 6 | @apply px-4 py-2 cursor-pointer select-none flex items-center space-x-2 hover:bg-gray-50; 7 | } 8 | 9 | .messages-list .message .message-username { 10 | @apply font-medium text-sm; 11 | } 12 | 13 | .messages-list .message .message-user-avatar { 14 | @apply w-12 h-12 rounded-full border object-cover; 15 | } 16 | 17 | .messages-list .message .message-content { 18 | @apply flex-1; 19 | } 20 | 21 | .messages-list .message .message-text { 22 | @apply flex space-x-1 text-xs text-gray-500; 23 | } 24 | 25 | .messages-list .message .message-text p { 26 | @apply truncate; 27 | } 28 | -------------------------------------------------------------------------------- /src/pages/Direct/MessagesList.tsx: -------------------------------------------------------------------------------- 1 | import "./MessagesList.css" 2 | 3 | import { IDirectMessage } from "../../constants/messages" 4 | 5 | interface Props { 6 | messages: IDirectMessage[] 7 | } 8 | 9 | export default function MessagesList({ messages }: Props) { 10 | return ( 11 |
      12 | {messages.map(message => ( 13 |
    • 14 | {message.user.username} 19 |
      20 |

      {message.user.username}

      21 |
      22 | {message.lastMessage.time} · 23 |

      {message.lastMessage.text}

      24 |
      25 |
      26 |
    • 27 | ))} 28 |
    29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /src/pages/Direct/NoMessagesSelected.css: -------------------------------------------------------------------------------- 1 | .no-messages-selected { 2 | @apply grid place-items-center h-full; 3 | } 4 | 5 | .no-messages-selected > div { 6 | @apply flex flex-col items-center space-y-4; 7 | } 8 | 9 | .no-messages-selected .icon { 10 | @apply inline-block rounded-full p-5 border-4 border-gray-700 text-gray-700; 11 | } 12 | 13 | .no-messages-selected .content { 14 | @apply text-center; 15 | } 16 | 17 | .no-messages-selected .content h2 { 18 | @apply font-semibold text-2xl text-gray-700; 19 | } 20 | 21 | .no-messages-selected .content p { 22 | @apply text-gray-500; 23 | } 24 | 25 | .no-messages-selected .action { 26 | @apply py-1 px-2 text-sm rounded transition duration-150 ease-in-out text-white bg-blue-500 hover:bg-blue-600 focus:outline-none focus:bg-blue-700; 27 | } 28 | -------------------------------------------------------------------------------- /src/pages/Direct/NoMessagesSelected.tsx: -------------------------------------------------------------------------------- 1 | import "./NoMessagesSelected.css" 2 | import { IoChatbubbleOutline } from "react-icons/io5" 3 | 4 | export default function NoMessagesSelected() { 5 | return ( 6 |
    7 |
    8 |
    9 | 10 |
    11 |
    12 |

    Your Messages

    13 |

    Send private photos and messages to a friend or group.

    14 |
    15 | 16 |
    17 |
    18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/pages/Direct/SwitchAccounts.css: -------------------------------------------------------------------------------- 1 | .switch-accounts { 2 | @apply flex py-3 px-4 border-b border-gray-200 items-center justify-between; 3 | } 4 | 5 | .switch-accounts .switch-account-hidden { 6 | @apply opacity-0 pointer-events-none; 7 | } 8 | 9 | .switch-accounts .account-button { 10 | @apply flex flex-1 justify-center items-center font-semibold space-x-2 focus:outline-none; 11 | } 12 | 13 | .switch-accounts .new-message { 14 | @apply text-gray-600 hover:text-gray-800 focus:outline-none; 15 | } 16 | -------------------------------------------------------------------------------- /src/pages/Direct/SwitchAccounts.tsx: -------------------------------------------------------------------------------- 1 | import "./SwitchAccounts.css" 2 | import { IoChevronDown, IoCreateOutline } from "react-icons/io5" 3 | 4 | export default function SwitchAccounts() { 5 | return ( 6 |
    7 |
    8 | 9 |
    10 | 14 | 17 |
    18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /src/pages/Home/Details/Details.jsx: -------------------------------------------------------------------------------- 1 | import Profile from "./Profile" 2 | import Suggestions from "./Suggestions/Suggestions" 3 | import Footer from "./Footer" 4 | 5 | const Details = () => { 6 | return ( 7 | 12 | ) 13 | } 14 | 15 | export default Details 16 | -------------------------------------------------------------------------------- /src/pages/Home/Details/Footer.css: -------------------------------------------------------------------------------- 1 | #footer ul li:after { 2 | content: "\00B7"; 3 | margin: 0 0.25em; 4 | } 5 | #footer ul li:last-child:after { 6 | content: ""; 7 | } 8 | #footer ul li a { 9 | font-size: 11px; 10 | } 11 | #footer p { 12 | font-size: 11px; 13 | } 14 | -------------------------------------------------------------------------------- /src/pages/Home/Details/Footer.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | import "./Footer.css" 4 | 5 | const Footer = () => { 6 | return ( 7 |
    8 |
      9 |
    • 10 | About 11 |
    • 12 |
    • 13 | Help 14 |
    • 15 |
    • 16 | Press 17 |
    • 18 |
    • 19 | API 20 |
    • 21 |
    • 22 | Jobs 23 |
    • 24 |
    • 25 | Privacy 26 |
    • 27 |
    • 28 | Terms 29 |
    • 30 |
    • 31 | Locations 32 |
    • 33 |
    • 34 | Top Accounts 35 |
    • 36 |
    • 37 | Hashtags 38 |
    • 39 |
    • 40 | Languages 41 |
    • 42 |
    43 |

    44 | © 2021 instagram from facebook 45 |

    46 |
    47 | ) 48 | } 49 | 50 | export default Footer 51 | -------------------------------------------------------------------------------- /src/pages/Home/Details/Profile.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const Profile = () => { 4 | return ( 5 |
    6 |
    7 | 8 |
    9 | Mehdi Neysi 14 |
    15 | 16 |
    17 | 18 | neysidev 19 | 20 |

    Mehdi Neysi

    21 |
    22 |
    23 | 26 |
    27 | ) 28 | } 29 | 30 | export default Profile 31 | -------------------------------------------------------------------------------- /src/pages/Home/Details/Suggestions/Suggestion.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const suggestion = props => { 4 | // props 5 | const { userImg, username } = props 6 | return ( 7 |
  • 8 |
    9 | 10 | {username 15 | 16 |
    17 | 18 | {username} 19 | 20 | New to Instagram 21 |
    22 |
    23 | 26 |
  • 27 | ) 28 | } 29 | 30 | export default suggestion 31 | -------------------------------------------------------------------------------- /src/pages/Home/Details/Suggestions/Suggestions.jsx: -------------------------------------------------------------------------------- 1 | import Suggestion from "./Suggestion" 2 | import SuggestionsHeader from "./SuggestionsHeader" 3 | 4 | const Suggestions = () => { 5 | return ( 6 |
    7 | 8 |
      9 | 10 | 11 | 12 | 13 | 14 |
    15 |
    16 | ) 17 | } 18 | 19 | export default Suggestions 20 | -------------------------------------------------------------------------------- /src/pages/Home/Details/Suggestions/SuggestionsHeader.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const suggestionsHeader = () => ( 4 |
    5 |

    Suggestions For You

    6 | 7 | See All 8 | 9 |
    10 | ) 11 | 12 | export default suggestionsHeader 13 | -------------------------------------------------------------------------------- /src/pages/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import Details from "./Details/Details" 2 | import Main from "./Main/Main" 3 | 4 | const Home = () => { 5 | return ( 6 | <> 7 |
    8 |
    9 |
    10 |
    11 | 12 | ) 13 | } 14 | 15 | export default Home 16 | -------------------------------------------------------------------------------- /src/pages/Home/Main/Backdrop.jsx: -------------------------------------------------------------------------------- 1 | import classes from "./Backdrop.module.css" 2 | 3 | const backdrop = props => 4 | props.show ? ( 5 |
    6 | ) : null 7 | 8 | export default backdrop 9 | -------------------------------------------------------------------------------- /src/pages/Home/Main/Backdrop.module.css: -------------------------------------------------------------------------------- 1 | .Backdrop { 2 | top: 0; 3 | left: 0; 4 | width: 100%; 5 | height: 100%; 6 | z-index: 100; 7 | position: fixed; 8 | background-color: transparent; 9 | } 10 | -------------------------------------------------------------------------------- /src/pages/Home/Main/Main.jsx: -------------------------------------------------------------------------------- 1 | import Posts from "./Posts" 2 | import Story from "./Story" 3 | 4 | const Main = () => { 5 | return ( 6 |
    7 | 8 | 9 |
    10 | ) 11 | } 12 | 13 | export default Main 14 | -------------------------------------------------------------------------------- /src/pages/Home/Main/Post.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types" 2 | import { useState } from "react" 3 | import { Link } from "react-router-dom" 4 | 5 | import AlertContainer from "../../../components/Alerts/AlertContainer" 6 | import PostsOptions from "../../../components/Modals/PostsOptions" 7 | import Story from "../../../components/Elements/Story" 8 | 9 | const Post = ({ name, username, imgName, likes, time, status }) => { 10 | const [open, setOpen] = useState(false) 11 | const [copied, setCopied] = useState(false) 12 | 13 | return ( 14 | <> 15 | setCopied(true)} 18 | onClose={() => setOpen(false)} 19 | /> 20 | setCopied(false)} 24 | /> 25 | 26 |
    27 |
    28 | 29 | 35 | 36 | {username} 37 | 38 | 39 | 70 |
    71 |
    72 | Dashboard 77 |
    78 |
    79 |
    80 |
    81 | 92 | 107 | 118 |
    119 | 130 |
    131 | 132 | {likes} likes 133 | 134 | 139 | {time} 140 | 141 |
    142 |
    143 | 155 | 160 | 163 |
    164 |
    165 | 166 | ) 167 | } 168 | 169 | Post.propTypes = { 170 | name: PropTypes.string, 171 | username: PropTypes.string, 172 | imgUrl: PropTypes.string, 173 | imgName: PropTypes.string, 174 | likes: PropTypes.string, 175 | time: PropTypes.string, 176 | status: PropTypes.string 177 | } 178 | 179 | export default Post 180 | -------------------------------------------------------------------------------- /src/pages/Home/Main/Posts.jsx: -------------------------------------------------------------------------------- 1 | import Post from "./Post" 2 | const Posts = () => { 3 | return ( 4 |
    5 | 13 | 21 | 28 |
    29 | ) 30 | } 31 | 32 | export default Posts 33 | -------------------------------------------------------------------------------- /src/pages/Home/Main/Story.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import { Link } from "react-router-dom" 3 | import { HiChevronLeft, HiChevronRight } from "react-icons/hi" 4 | 5 | import { USER_STORIES } from "../../../constants/stories" 6 | 7 | // TODO: auto scroll to the start/end 8 | export default function Story() { 9 | const usersContainerWidth = USER_STORIES.length * 64 10 | const [translateX, setTranslateX] = useState(0) 11 | 12 | const gotoNext = () => { 13 | setTranslateX(translateX - 264) 14 | } 15 | 16 | const gotoPrev = () => { 17 | setTranslateX(translateX + 264) 18 | } 19 | 20 | return ( 21 |
    22 |
      29 | {USER_STORIES.map(user => ( 30 |
    • 34 | 35 |
      36 |
      37 | {user.username} 42 |
      43 |
      44 | {user.username} 45 | 46 |
    • 47 | ))} 48 |
    49 | 50 | 61 | 62 | 69 |
    70 | ) 71 | } 72 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Actions.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const Actions = () => { 4 | return ( 5 |
    6 | 10 | 17 | 18 | 19 | 20 | 24 | 31 | 32 | 33 | 34 | 35 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 55 | 62 | 63 | 64 | 65 | 69 | neysidev 74 | 75 |
    76 | ) 77 | } 78 | 79 | export default Actions 80 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Links.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import { Link } from "react-router-dom" 3 | import classes from "./Links.module.css" 4 | import Menu from "./Menu" 5 | 6 | const Links = () => { 7 | const [showMenu, setShowMenu] = useState(false) 8 | const handleCloseMenu = () => { 9 | setShowMenu(false) 10 | } 11 | const handleOpenMenu = () => { 12 | setShowMenu(true) 13 | } 14 | return ( 15 |
    16 |
      17 |
    • 18 | 19 | 26 | 27 | 28 | 29 | 30 |
    • 31 |
    • 32 | 33 | 40 | 41 | 42 | 43 |
    • 44 |
    • 45 | 46 | 53 | 58 | 59 | 60 |
    • 61 |
    • 62 | 63 | 70 | 71 | 72 | 73 |
    • 74 |
    • 78 | 81 | Mehdi Neysi 86 | 87 |
    • 88 |
    89 |
    90 | ) 91 | } 92 | 93 | export default Links 94 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Links.module.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neysidev/react-instagram/b883a7c3a0f353851abddaaa6fad24ec877f1c84/src/pages/Home/Navbar/Links.module.css -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Logo.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const Logo = () => { 4 | return ( 5 |
    6 | 7 | Instagram Logo 8 | 9 |
    10 | ) 11 | } 12 | 13 | export default Logo 14 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Menu.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | import Backdrop from "../Main/Backdrop" 3 | import classes from "./Menu.module.css" 4 | const Menu = props => { 5 | // props 6 | const { show, closed } = props 7 | return ( 8 | <> 9 |
    15 |
    16 |
      17 |
    • 18 | 19 |
      20 | 28 | 29 | 30 | profile 31 |
      32 | 33 |
    • 34 |
    • 35 | 36 |
      37 | 45 | 46 | 47 | saved 48 |
      49 | 50 |
    • 51 |
    • 52 | 53 |
      54 | 62 | 63 | 64 | setting 65 |
      66 | 67 |
    • 68 |
    • 69 | 70 |
      71 | 79 | 80 | 81 | Switch Accounts 82 |
      83 | 84 |
    • 85 |
    • 86 | 87 |
      88 | Log out 89 |
      90 | 91 |
    • 92 |
    93 |
    94 | 95 | 96 | ) 97 | } 98 | export default Menu 99 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Menu.module.css: -------------------------------------------------------------------------------- 1 | .Show { 2 | display: block !important; 3 | z-index: 101; 4 | } 5 | .Menu { 6 | display: none; 7 | } 8 | .MenuTriangle { 9 | z-index: 99; 10 | width: 15px; 11 | height: 15px; 12 | background: #ffffff; 13 | display: inline-block; 14 | clip-path: polygon(50% 0%, 0% 100%, 100% 100%); 15 | position: absolute; 16 | left: 77.5%; 17 | top: -10px; 18 | box-shadow: 1px 1px 1px #090707; 19 | } 20 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Mobile.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom" 2 | 3 | const Mobile = () => { 4 | return ( 5 |
    6 | 7 | Instagram Logo 8 | 9 | 10 | 17 | 18 | 19 | 20 |
    21 | ) 22 | } 23 | 24 | export default Mobile 25 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | import Actions from "./Actions" 4 | import Links from "./Links" 5 | import Logo from "./Logo" 6 | import Mobile from "./Mobile" 7 | import Search from "./Search" 8 | 9 | const Navbar = () => { 10 | const [openSearch, setOpenSearch] = useState(false) 11 | 12 | const handleShowSearch = () => setOpenSearch(true) 13 | const handleHideSearch = () => setOpenSearch(false) 14 | 15 | document.addEventListener("click", event => { 16 | if (!document.querySelector("#search-open")) return 17 | 18 | event.target.closest("#search-close") || 19 | event.target.closest("#search-close-wrapper") || 20 | event.target.closest("#search-close-background") || 21 | event.target.closest("#search-open") || 22 | event.target.closest("#search-open svg") || 23 | event.target.closest("#search-open button") || 24 | event.target.closest("#search-open input") 25 | ? handleShowSearch() 26 | : handleHideSearch() 27 | }) 28 | 29 | return ( 30 | <> 31 |
    32 |
    33 |
    34 | 35 | 40 | 41 |
    42 | 43 |
    44 |
    45 | 46 | 47 | ) 48 | } 49 | 50 | export default Navbar 51 | -------------------------------------------------------------------------------- /src/pages/Home/Navbar/Search.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types" 2 | 3 | const Search = ({ hide, open, show }) => { 4 | let content 5 | if (open) { 6 | content = ( 7 |
    8 | 17 | 18 | 19 | 20 | 41 | element && element.focus()} 45 | type="text" 46 | /> 47 |
    48 | ) 49 | } else { 50 | content = ( 51 |
    56 |
    65 | 73 | 74 | 75 | 76 | Search 77 |
    78 |
    82 |
    83 | ) 84 | } 85 | 86 | return
    {content}
    87 | } 88 | 89 | Search.propTypes = { 90 | hide: PropTypes.func, 91 | open: PropTypes.bool, 92 | show: PropTypes.func 93 | } 94 | 95 | export default Search 96 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { lazy } from "react" 2 | 3 | const routes = [ 4 | { 5 | exact: true, 6 | path: "/", 7 | component: lazy(() => import("../pages/Home/Home")) 8 | }, 9 | { 10 | exact: true, 11 | path: "/direct/inbox", 12 | component: lazy(() => import("../pages/Direct/Direct")) 13 | }, 14 | { 15 | exact: true, 16 | path: "/direct/inbox/general", 17 | component: lazy(() => import("../pages/Direct/Direct")) 18 | } 19 | ] 20 | 21 | export default routes 22 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const colors = require("tailwindcss/colors") 2 | 3 | module.exports = { 4 | purge: ["./src/**/*.{js,jsx,ts,tsx}", "./public/index.html"], 5 | darkMode: false, 6 | theme: { 7 | extend: { 8 | colors: { 9 | gray: colors.gray, 10 | fuchsia: colors.fuchsia, 11 | lightBlue: colors.lightBlue 12 | } 13 | } 14 | }, 15 | variants: {}, 16 | plugins: [] 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | --------------------------------------------------------------------------------