├── .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 |
--------------------------------------------------------------------------------
/src/assets/icons/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/comment.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/direct.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/emoji.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/explore.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/home.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/like.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/more.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/save.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/search.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/icons/share.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 |

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 |

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 |

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 |
9 |
10 |
11 |
12 |
13 |
14 |
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 |

69 |
70 |
134 |
156 |
157 | )
158 | }
159 |
--------------------------------------------------------------------------------
/src/components/Home/Main/Posts.tsx:
--------------------------------------------------------------------------------
1 | import Post from "./Post"
2 | const Posts = () => {
3 | return (
4 |
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 |
7 | -
8 |
9 |
10 |
11 |

16 |
17 |
18 | russcodes
19 |
20 |
21 | -
22 |
23 |
24 |
25 |

30 |
31 |
32 | onlysiamak
33 |
34 |
35 | -
36 |
37 |
38 |
39 |

44 |
45 |
46 | sepide_moqadasi
47 |
48 |
49 | -
50 |
51 |
52 |
53 |

58 |
59 |
60 | ui.amjad
61 |
62 |
63 | -
64 |
65 |
66 |
67 |

72 |
73 |
74 | mehradhiddenofficial
75 |
76 |
77 | -
78 |
79 |
80 |
81 |

86 |
87 |
88 | fazurrehman
89 |
90 |
91 | -
92 |
93 |
94 |
95 |

100 |
101 |
102 | sajon.co
103 |
104 |
105 |
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 |
19 |
20 |
24 |
34 |
35 |
39 |
50 |
51 |
55 |
64 |
65 |
69 |

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 |
25 | -
26 |
27 |
28 |
29 |
30 | -
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 | -
41 |
42 |
43 |
44 |
45 | -
49 |
50 |
55 |
56 |
58 |
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 |

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 |
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 |

8 |
9 |
10 |
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 |
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 |
23 |
44 |
element && element.focus()}
48 | type="text"
49 | />
50 |
51 | )
52 | } else {
53 | content = (
54 |
59 |
68 |
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 |
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 |
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 |

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 |

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 |

77 |
78 |
142 |
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 |
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 |

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 |
19 |
20 |
24 |
34 |
35 |
39 |
50 |
51 |
55 |
64 |
65 |
69 |

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 |
28 |
29 |
30 |
31 | -
32 |
33 |
42 |
43 |
44 | -
45 |
46 |
59 |
60 |
61 | -
62 |
63 |
72 |
73 |
74 | -
78 |
81 |
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 |

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 |
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 |

8 |
9 |
10 |
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 |
20 |
41 |
element && element.focus()}
45 | type="text"
46 | />
47 |
48 | )
49 | } else {
50 | content = (
51 |
56 |
65 |
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 |
--------------------------------------------------------------------------------