├── .gitignore ├── .prettierrc.js ├── README.md ├── components ├── AddPostModal │ ├── index.js │ └── styles.module.scss ├── AppHeader │ ├── index.js │ └── styles.module.scss ├── AppSidebar │ ├── index.js │ └── styles.module.scss ├── ContactList │ ├── index.js │ └── styles.module.scss ├── Container.js ├── EditProfileBtn │ ├── index.js │ └── styles.module.scss ├── HomeLayout │ ├── index.js │ └── styles.module.scss ├── InboxScreen │ ├── index.js │ └── styles.module.scss ├── Loader │ ├── index.js │ └── styles.module.scss ├── MessageContent │ ├── index.js │ └── styles.module.scss ├── MessageFooter │ ├── index.js │ └── styles.module.scss ├── MessageHeader │ ├── index.js │ └── styles.module.scss ├── MessageListItem │ ├── index.js │ └── styles.module.scss ├── MessageSection │ ├── index.js │ └── styles.module.scss ├── NewMessageModal │ ├── index.js │ └── styles.module.scss ├── NoMessage │ ├── index.js │ └── styles.module.scss ├── NotFoundScreen │ └── index.js ├── Profile │ ├── index.js │ └── styles.module.scss ├── ProfileFollowButton │ ├── index.js │ └── styles.module.scss ├── SearchResults │ ├── index.js │ └── styles.module.scss ├── SignInScreen │ ├── index.js │ └── styles.module.scss ├── SignUpScreen │ ├── index.js │ └── styles.module.scss ├── StoriesBar │ ├── index.js │ └── styles.module.scss ├── StoryItem │ ├── index.js │ └── styles.module.scss ├── SugessionUser │ ├── index.js │ └── styles.module.scss ├── UserImage │ ├── index.js │ └── styles.module.scss ├── UserInfo │ ├── index.js │ └── styles.module.scss ├── UserPost │ ├── index.js │ └── styles.module.scss ├── UserPosts │ ├── index.js │ └── styles.module.scss └── UserStatistics │ ├── index.js │ └── styles.module.scss ├── hooks ├── usePostsFormat.js └── useWindowSize.js ├── icons ├── AddPost.js ├── Back.js ├── Bookmark.js ├── BookmarkFill.js ├── Camera.js ├── Close.js ├── Comment.js ├── Emoji.js ├── Explore.js ├── ExploreFill.js ├── Home.js ├── HomeFill.js ├── Info.js ├── Like.js ├── LikeFill.js ├── Loader.js ├── Message.js ├── MessageFill.js ├── NewMessage.js ├── Options.js ├── Photo.js ├── Posts.js ├── Preferences.js ├── Search.js ├── Tagged.js ├── User.js └── index.js ├── lib ├── auth.js ├── db.js └── firebase.js ├── next.config.js ├── next.config.template.js ├── package-lock.json ├── package.json ├── pages ├── 404.js ├── [username] │ └── [[...index]].js ├── _app.js ├── accounts │ └── emailsignup.js ├── api │ └── hello.js ├── direct │ └── [[...index]].js └── index.js ├── public ├── betul.jpg ├── bill.jpg ├── elon.jpg ├── erkan.jpg ├── erkan2.jpg ├── facebook-logo.png ├── favicon.ico ├── hasan.jpg ├── instagram-dark.png ├── instagram.png ├── ivana.jpg ├── manifest.json ├── mustafa.jpg ├── owuzan.jpg ├── owuzan │ ├── 1.jpg │ ├── 10.jpg │ ├── 11.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg ├── photo-example.jpg ├── robots.txt ├── ronaldo.jpg ├── serdar.jpg ├── sign-up.png ├── suleyman-example.jpg ├── suleyman.jpg └── user.jpg ├── styles └── globals.scss ├── svgs ├── AddPost.svg ├── Back.svg ├── Bookmark.svg ├── BookmarkFill.svg ├── Camera.svg ├── Close.svg ├── Comment.svg ├── Emoji.svg ├── Explore.svg ├── ExploreFill.svg ├── Home.svg ├── HomeFill.svg ├── Info.svg ├── Like.svg ├── LikeFill.svg ├── Loader.svg ├── Message.svg ├── MessageFill.svg ├── NewMessage.svg ├── Options.svg ├── Photo.svg ├── Posts.svg ├── Preferences.svg ├── Search.svg ├── Tagged.svg └── User.svg ├── utility ├── follow.js ├── isFollowing.js ├── linkedText.js ├── sendMessage.js └── unfollow.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | .idea 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | # testing 8 | /coverage 9 | 10 | # next.js 11 | /.next/ 12 | /out/ 13 | 14 | # production 15 | /build 16 | 17 | # misc 18 | .DS_Store 19 | *.pem 20 | 21 | # debug 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | 26 | # local env files 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | next.config.js 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'es5', 3 | tabWidth: 4, 4 | semi: false, 5 | singleQuote: true, 6 | bracketSpacing: true, 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/import?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /components/AddPostModal/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.scss' 3 | 4 | import UserImage from '../UserImage' 5 | import * as Icons from '../../icons' 6 | 7 | import { uploadPost } from '../../lib/db' 8 | import { useAuth } from '../../lib/auth' 9 | 10 | const AddPostModal = (props) => { 11 | const { file, setFile } = props 12 | const user = useAuth().user 13 | const [caption, setCaption] = React.useState('') 14 | 15 | const handleShare = async () => { 16 | uploadPost(user.id, { 17 | file, 18 | caption, 19 | time: new Date(), 20 | }) 21 | setFile(null) 22 | setCaption('') 23 | } 24 | if (file) { 25 | return ( 26 |
27 |
28 | 34 |
Yeni Gönderi
35 | 41 |
42 |
43 |
44 | 45 |
46 |
47 | 51 |
52 |
53 | {file ? : ''} 54 |
55 |
56 | 61 |
62 | ) 63 | } 64 | return
65 | } 66 | 67 | export default AddPostModal 68 | -------------------------------------------------------------------------------- /components/AddPostModal/styles.module.scss: -------------------------------------------------------------------------------- 1 | .newPost { 2 | position: fixed; 3 | left: 0; 4 | top: 0; 5 | bottom: 0; 6 | right: 0; 7 | background-color: var(--white); 8 | z-index: 10; 9 | } 10 | .newPostHeader { 11 | display: flex; 12 | justify-content: space-between; 13 | align-items: center; 14 | padding: 0 15px; 15 | height: 44px; 16 | width: 100%; 17 | box-shadow: var(--shadow); 18 | border-bottom: 2px solid var(--border-color); 19 | } 20 | .closeIcon { 21 | all: unset; 22 | font-size: 24px; 23 | cursor: pointer; 24 | transform: rotate(-90deg); 25 | } 26 | .title { 27 | font-weight: 500; 28 | } 29 | .shareButton { 30 | all: unset; 31 | cursor: pointer; 32 | color: var(--blue); 33 | font-style: 24px; 34 | font-weight: 500; 35 | } 36 | .postDescription { 37 | display: flex; 38 | padding: 15px; 39 | align-items: flex-start; 40 | } 41 | .user { 42 | } 43 | .caption { 44 | flex: 1; 45 | textarea { 46 | width: 100%; 47 | padding: 3px 10px; 48 | font-size: 16px; 49 | border: 0; 50 | font-family: inherit; 51 | outline: 0; 52 | height: 100px; 53 | } 54 | } 55 | .image { 56 | max-width: 50px; 57 | height: auto; 58 | 59 | img { 60 | width: 100%; 61 | height: 100%; 62 | object-fit: contain; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /components/AppHeader/styles.module.scss: -------------------------------------------------------------------------------- 1 | header.header { 2 | background-color: var(--white); 3 | border-bottom: 1px solid var(--border-color); 4 | max-height: 54px; 5 | height: 100%; 6 | padding: 0 15px; 7 | @media (max-width: 599.98px) { 8 | // box-shadow: 0 10px 10px -10px rgba(0, 0, 0, .15); 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | right: 0; 13 | z-index: 10; 14 | } 15 | 16 | .headerInner { 17 | padding: 9px 0; 18 | display: flex; 19 | align-items: center; 20 | justify-content: space-between; 21 | color: var(--text-color); 22 | 23 | a { 24 | color: inherit; 25 | } 26 | .brand { 27 | @media (min-width: 600px) { 28 | max-width: 360px; 29 | } 30 | width: 100%; 31 | height: inherit; 32 | display: flex; 33 | justify-content: space-between; 34 | 35 | a { 36 | padding-top: 7px; 37 | } 38 | img { 39 | object-fit: contain; 40 | height: 29px; 41 | width: auto; 42 | // transform: translateY(7px); 43 | } 44 | } 45 | .searchArea { 46 | position: relative; 47 | input { 48 | height: 28px; 49 | width: 214px; 50 | background-color: var(--input-background); 51 | border: 1px solid var(--border-color); 52 | border-radius: 3px; 53 | outline: 0; 54 | padding: 0 1rem; 55 | color: inherit; 56 | 57 | &::placeholder { 58 | color: var(--border-color); 59 | text-align: center; 60 | } 61 | } 62 | 63 | button { 64 | all: unset; 65 | cursor: pointer; 66 | position: absolute; 67 | right: 5px; 68 | top: 50%; 69 | transform: translateY(-50%); 70 | width: 1.5em; 71 | height: 1.5em; 72 | font-size: 12px; 73 | background-color: red; 74 | display: flex; 75 | border-radius: 50px; 76 | background-color: var(--border-color); 77 | justify-content: center; 78 | color: var(--white); 79 | 80 | span { 81 | --top: -2px; 82 | position: absolute; 83 | top: var(--top); 84 | &:last-child { 85 | top: calc(var(--top) + 6px); 86 | } 87 | } 88 | } 89 | @media (max-width: 999.98px) { 90 | margin-right: 40px; 91 | } 92 | @media (max-width: 599.98px) { 93 | display: none; 94 | } 95 | } 96 | .navbar { 97 | display: flex; 98 | flex: 1; 99 | justify-content: flex-end; 100 | nav { 101 | svg path { 102 | fill: var(--text); 103 | } 104 | display: flex; 105 | margin-top: -22px; 106 | margin-left: -22px; 107 | 108 | & > a, 109 | & > div { 110 | font-size: 1.5rem; 111 | margin-top: 22px; 112 | margin-left: 22px; 113 | display: flex; 114 | align-items: center; 115 | justify-content: center; 116 | position: relative; 117 | } 118 | 119 | .profileDropdown { 120 | position: absolute; 121 | top: calc(100% + 15px); 122 | right: -10px; 123 | display: none; 124 | flex-direction: column; 125 | background-color: var(--white); 126 | box-shadow: 0 0 5px 0px rgba(0, 0, 0, 0.15); 127 | width: 230px; 128 | border-radius: 5px; 129 | 130 | &.show { 131 | display: flex; 132 | } 133 | 134 | &::before { 135 | content: ""; 136 | width: 15px; 137 | height: 15px; 138 | display: block; 139 | transform: rotate(45deg); 140 | background-color: var(--white); 141 | top: -7px; 142 | right: 15px; 143 | position: absolute; 144 | z-index: 0; 145 | box-shadow: 0 0 5px 0px rgba(0, 0, 0, 0.15); 146 | } 147 | 148 | a { 149 | z-index: 1; 150 | padding: 8px 16px; 151 | font-size: 14px; 152 | display: flex; 153 | text-decoration: none; 154 | align-items: center; 155 | background-color: var(--white); 156 | 157 | &:first-child { 158 | border-radius: 5px 5px 0 0; 159 | } 160 | 161 | &:last-child { 162 | border-radius: 0 0 5px 5px; 163 | } 164 | 165 | &:hover { 166 | background-color: var(--background-color); 167 | } 168 | 169 | div { 170 | margin-right: 10px; 171 | } 172 | } 173 | } 174 | } 175 | 176 | &.mobile { 177 | nav { 178 | position: fixed; 179 | left: 0; 180 | bottom: 0; 181 | right: 0; 182 | background-color: var(--white); 183 | border-top: 1px solid var(--border-color); 184 | justify-content: space-around; 185 | height: 50px; 186 | margin: 0; 187 | padding: 0; 188 | z-index: 1; 189 | 190 | a { 191 | margin: 0; 192 | flex: 1; 193 | } 194 | } 195 | } 196 | } 197 | } 198 | } 199 | .logoutLink { 200 | border-top: 2px solid var(--border-color); 201 | } 202 | -------------------------------------------------------------------------------- /components/AppSidebar/index.js: -------------------------------------------------------------------------------- 1 | import styles from './styles.module.scss' 2 | import UserImage from '../UserImage' 3 | import SuggessionUser from '../SugessionUser' 4 | import { getUserData } from '../../lib/db' 5 | import { useAuth } from '../../lib/auth' 6 | import React from 'react' 7 | 8 | export default function AppSidebar() { 9 | const { user } = useAuth() 10 | const [userData, setUserData] = React.useState('') 11 | 12 | React.useEffect(async () => { 13 | setUserData(await getUserData(await user?.id)) 14 | }, [user]) 15 | return ( 16 |
17 |
18 | 19 |
20 |

{userData.username}

21 | {userData.name} 22 |
23 | 24 |
25 |
26 |
27 |

Senin İçin Öneriler

28 | 29 |
30 | 67 |
68 | 108 |
109 | ) 110 | } 111 | -------------------------------------------------------------------------------- /components/AppSidebar/styles.module.scss: -------------------------------------------------------------------------------- 1 | .sidebarInner { 2 | position: sticky; 3 | top: 0px; 4 | } 5 | 6 | .changeBar { 7 | padding-top: 18px; 8 | display: flex; 9 | justify-content: space-between; 10 | align-items: center; 11 | font-size: 14px; 12 | color: var(--text); 13 | 14 | .userMeta { 15 | width: 141px; 16 | display: flex; 17 | flex-direction: column; 18 | p { 19 | margin: 0; 20 | font-weight: 500; 21 | } 22 | span { 23 | color: var(--muted-text); 24 | } 25 | } 26 | 27 | button { 28 | all: unset; 29 | cursor: pointer; 30 | color: var(--blue); 31 | font-weight: 500; 32 | font-size: 12px; 33 | } 34 | } 35 | 36 | .suggested { 37 | margin-top: 12px; 38 | 39 | .suggestedHeader { 40 | padding-top: 12px; 41 | font-weight: 500; 42 | font-size: 12px; 43 | display: flex; 44 | align-items: center; 45 | justify-content: space-between; 46 | 47 | p { 48 | color: var(--muted-text); 49 | font-size: 14px; 50 | } 51 | 52 | button { 53 | all: unset; 54 | color: var(--text); 55 | cursor: pointer; 56 | font-weight: 500; 57 | } 58 | } 59 | 60 | ul { 61 | margin: 0; 62 | margin-top: 8px; 63 | padding: 8px 0; 64 | list-style: none; 65 | 66 | li { 67 | display: flex; 68 | align-items: center; 69 | justify-content: space-between; 70 | margin-bottom: 10px; 71 | padding: 2px 0; 72 | 73 | &:last-child { 74 | margin-bottom: 0; 75 | } 76 | 77 | button { 78 | all: unset; 79 | cursor: pointer; 80 | color: var(--blue); 81 | font-size: 12px; 82 | font-weight: 500; 83 | } 84 | } 85 | } 86 | } 87 | 88 | .instagramFooter { 89 | margin-top: 25px; 90 | font-size: 11px; 91 | color: #c7c7c7; 92 | 93 | a { 94 | color: inherit; 95 | text-decoration: none; 96 | } 97 | 98 | ul { 99 | list-style: none; 100 | display: flex; 101 | flex-wrap: wrap; 102 | li { 103 | &::after { 104 | content: "\00B7"; 105 | margin: 0 0.25em 0 0.25em; 106 | } 107 | 108 | &:last-child::after { 109 | content: unset; 110 | } 111 | } 112 | } 113 | 114 | .footerText { 115 | text-transform: uppercase; 116 | margin-top: 20px; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /components/ContactList/index.js: -------------------------------------------------------------------------------- 1 | import styles from './styles.module.scss' 2 | import MessageListItem from '../MessageListItem' 3 | 4 | export default function ContactList(props) { 5 | const activeContact = props?.activeContact 6 | const setActiveContact = props?.setActiveContact 7 | const contacts = props?.contacts 8 | const setContacts = props?.setContacts 9 | const activeHandle = props?.activeHandle 10 | 11 | return ( 12 |
13 |
14 | {contacts.map((contact, index) => { 15 | index++ 16 | return ( 17 |
activeHandle(e, contact.id)} 20 | className={ 21 | activeContact === contact.id 22 | ? styles.contact + 23 | ' ' + 24 | styles.activeContact 25 | : styles.contact 26 | } 27 | > 28 | 29 |
30 | ) 31 | })} 32 |
33 |
34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /components/ContactList/styles.module.scss: -------------------------------------------------------------------------------- 1 | .contactListWrapper { 2 | flex: 1; 3 | padding: 8px 0 0 0; 4 | overflow-x: hidden; 5 | overflow-y: auto; 6 | 7 | .contactList { 8 | list-style: none; 9 | margin: 0; 10 | padding: 0; 11 | 12 | .contact { 13 | &:hover { 14 | background-color: var(--background-color); 15 | cursor: pointer; 16 | } 17 | &.activeContact { 18 | background-color: var(--border-light-color); 19 | } 20 | } 21 | 22 | a { 23 | padding: 8px 20px; 24 | display: flex; 25 | align-items: center; 26 | text-decoration: none; 27 | overflow: hidden; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /components/Container.js: -------------------------------------------------------------------------------- 1 | export default function Container({ children, ...props }) { 2 | return ( 3 |
4 | {children} 5 |
6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /components/EditProfileBtn/index.js: -------------------------------------------------------------------------------- 1 | import styles from './styles.module.scss' 2 | 3 | export default function EditProfileBtn() { 4 | return ( 5 | 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /components/EditProfileBtn/styles.module.scss: -------------------------------------------------------------------------------- 1 | .editProfileBtn { 2 | margin-left: 20px; 3 | font-size: 14px; 4 | border: 1px solid var(--border-color); 5 | color: inherit; 6 | border-radius: 4px; 7 | font-weight: 600; 8 | padding: 5px 9px; 9 | background-color: var(--background-color) !important; 10 | outline: 0; 11 | 12 | @media (max-width: 734.98px) { 13 | margin: 15px; 14 | display: block; 15 | width: calc(100% - 30px); 16 | background-color: var(--white) !important; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /components/HomeLayout/index.js: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | import UserPost from '../UserPost' 3 | import React, { useState, useEffect } from 'react' 4 | import AppSidebar from '../AppSidebar' 5 | import styles from './styles.module.scss' 6 | import StoriesBar from '../StoriesBar' 7 | import firebase from '../../lib/firebase' 8 | import { useAuth } from '../../lib/auth' 9 | import { getUserData } from '../../lib/db' 10 | import { ClipLoader } from 'react-spinners' 11 | import { css } from '@emotion/core' 12 | 13 | export default function Home() { 14 | const [posts, setPosts] = useState([]) 15 | const [loading, setLoading] = useState(true) 16 | const firestore = firebase.firestore() 17 | const auth = useAuth() 18 | 19 | useEffect(async () => { 20 | let userPosts = [] 21 | await firestore 22 | .collection(`users/${auth.user.id}/followings`) 23 | .get() 24 | .then((res) => 25 | res.docs.forEach(async (user) => { 26 | const username = await getUserData(user.id).then( 27 | (res) => res.username 28 | ) 29 | await firestore 30 | .collection(`users/${user.id}/posts`) 31 | .orderBy('time', 'desc') 32 | .limit(10) 33 | .get() 34 | .then((res) => { 35 | if (res.docs.length) { 36 | res.docs.reverse() 37 | res.docs.forEach((doc) => { 38 | userPosts = [ 39 | ...userPosts, 40 | { 41 | userId: user.id, 42 | username, 43 | id: doc.id, 44 | ...doc.data(), 45 | }, 46 | ] 47 | setPosts(userPosts) 48 | setLoading(false) 49 | }) 50 | } 51 | }) 52 | }) 53 | ) 54 | setLoading(false) 55 | }, []) 56 | 57 | return ( 58 | <> 59 |
60 |
61 | 62 |
63 | {loading && ( 64 |
65 | 70 |
71 | )} 72 | {posts.map((post, id) => { 73 | return 74 | })} 75 |
76 |
77 |
78 | 79 |
80 |
81 | 82 | ) 83 | } 84 | -------------------------------------------------------------------------------- /components/HomeLayout/styles.module.scss: -------------------------------------------------------------------------------- 1 | .homeLayout { 2 | display: flex; 3 | flex-wrap: wrap; 4 | margin-left: -14px; 5 | margin-right: -14px; 6 | margin-top: 30px; 7 | justify-content: space-between; 8 | @media (max-width: 599.98px) { 9 | margin-top: 0; 10 | } 11 | 12 | .mainLayout { 13 | flex: 1; 14 | max-width: 642px; 15 | padding-left: 14px; 16 | padding-right: 14px; 17 | width: 100%; 18 | } 19 | 20 | .sidebar { 21 | padding-left: 14px; 22 | padding-right: 14px; 23 | width: 325px; 24 | } 25 | 26 | @media (max-width: 999.98px) { 27 | max-width: 600px; 28 | margin-left: auto; 29 | margin-right: auto; 30 | .mainLayout { 31 | flex: 1; 32 | max-width: 642px; 33 | padding: 0; 34 | } 35 | 36 | .sidebar { 37 | display: none; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /components/InboxScreen/index.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | import styles from './styles.module.scss' 3 | 4 | import NoMessage from '../../components/NoMessage' 5 | import ContactList from '../../components/ContactList' 6 | import MessageContent from '../../components/MessageContent' 7 | import MessageHeader from '../../components/MessageHeader' 8 | import MessageFooter from '../../components/MessageFooter' 9 | import NewMessageModal from '../NewMessageModal' 10 | 11 | import useWindowSize from '../../hooks/useWindowSize' 12 | import NewMessage from '../../icons/NewMessage' 13 | import firebase from '../../lib/firebase' 14 | import { useAuth } from '../../lib/auth' 15 | import { useRouter } from 'next/router' 16 | 17 | export default function Messages() { 18 | const firestore = firebase.firestore() 19 | const router = useRouter() 20 | const auth = useAuth() 21 | const ww = useWindowSize().width 22 | const [activeContact, setActiveContact] = useState(null) 23 | const [contacts, setContacts] = useState([]) 24 | const [showModal, setShowModal] = useState(false) 25 | const activeHandle = (e, id) => { 26 | e.preventDefault() 27 | setActiveContact(id) 28 | } 29 | // let messageList 30 | useEffect(() => { 31 | if (router.query.contact) { 32 | setActiveContact(router.query.contact) 33 | } else { 34 | router.push('/direct/inbox') 35 | } 36 | let messageList = firestore 37 | .collection(`users/${auth.user.id}/contacts`) 38 | .orderBy('time', 'desc') 39 | .onSnapshot((res) => { 40 | let list = [] 41 | res.docs.forEach((lastMessage) => { 42 | list.push({ 43 | id: lastMessage.id, 44 | ...lastMessage.data(), 45 | }) 46 | }) 47 | setContacts(list) 48 | }) 49 | return () => { 50 | messageList() 51 | } 52 | }, []) 53 | 54 | // no-screen 55 | // no-message 56 | // messages 57 | const [contentScreen, setContentScreen] = useState('no-message') 58 | useEffect(() => { 59 | if (activeContact) { 60 | if (ww >= 735) { 61 | setContentScreen('messages') 62 | } else { 63 | setContentScreen('no-message') 64 | } 65 | } else { 66 | if (ww >= 735) { 67 | setContentScreen('no-message') 68 | } else { 69 | setContentScreen('no-screen') 70 | } 71 | } 72 | }) 73 | 74 | useEffect(() => { 75 | if (activeContact) { 76 | router.push(`/direct/t/${activeContact}`) 77 | } 78 | }, [activeContact, contentScreen]) 79 | 80 | return ( 81 |
82 |
83 |
84 |
85 |
86 |
owuzan
87 | 95 |
96 | {/* FIXME NoMessage componentinin genişlik ayarı yapılacak */} 97 | 104 |
105 |
106 | {contentScreen == 'no-message' && ( 107 | 108 | )} 109 | {contentScreen == 'messages' && ( 110 | <> 111 | 112 | 113 | 114 | 115 | )} 116 |
117 |
118 | {showModal && ( 119 | 123 | )} 124 |
125 | ) 126 | } 127 | -------------------------------------------------------------------------------- /components/InboxScreen/styles.module.scss: -------------------------------------------------------------------------------- 1 | .messagesPage { 2 | height: calc(100vh - 54px); 3 | padding: 20px 0; 4 | @media (max-width: 934.98px) { 5 | padding: 0; 6 | } 7 | @media (max-width: 599.98px) { 8 | height: calc(100vh - 100px); 9 | } 10 | 11 | .messagesWrapper { 12 | display: flex; 13 | border: 1px solid var(--border-color); 14 | border-radius: 3px; 15 | height: 100%; 16 | background-color: var(--white); 17 | @media (max-width: 934.98px) { 18 | border: 0; 19 | } 20 | 21 | .messagesSidebar { 22 | width: 350px; 23 | border-right: 1px solid var(--border-color); 24 | height: 100%; 25 | display: flex; 26 | flex-direction: column; 27 | 28 | @media (max-width: 599.98px) { 29 | width: 100%; 30 | } 31 | 32 | .sidebarHeader { 33 | width: 100%; 34 | height: 60px; 35 | border-bottom: 1px solid var(--border-color); 36 | display: flex; 37 | justify-content: space-between; 38 | align-items: center; 39 | padding: 0 20px; 40 | 41 | div { 42 | display: flex; 43 | } 44 | 45 | .sidebarTop { 46 | font-weight: 500; 47 | } 48 | 49 | .newMessageIcon { 50 | appearance: none; 51 | background: transparent; 52 | border: 0; 53 | outline: 0; 54 | cursor: pointer; 55 | } 56 | } 57 | } 58 | 59 | .messageContent { 60 | display: flex; 61 | flex-direction: column; 62 | flex: 1; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /components/Loader/index.js: -------------------------------------------------------------------------------- 1 | import styles from './styles.module.scss' 2 | import { ClipLoader } from 'react-spinners' 3 | import { css } from '@emotion/core' 4 | 5 | const Loader = () => { 6 | return ( 7 |
8 | 13 |
14 | ) 15 | } 16 | 17 | export default Loader 18 | -------------------------------------------------------------------------------- /components/Loader/styles.module.scss: -------------------------------------------------------------------------------- 1 | .loader { 2 | position: fixed; 3 | z-index: 9999; 4 | left: 0; 5 | top: 0; 6 | right: 0; 7 | bottom: 0; 8 | background-color: var(--background-color); 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | } 13 | -------------------------------------------------------------------------------- /components/MessageContent/index.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback, useRef } from 'react' 2 | import styles from './styles.module.scss' 3 | import MessageSection from '../MessageSection' 4 | import firebase from '../../lib/firebase' 5 | import { useAuth } from '../../lib/auth' 6 | import { getUserData } from '../../lib/db' 7 | 8 | export default function MessageContent({ userId }) { 9 | const auth = useAuth() 10 | const [messageGroups, setMessageGroups] = useState([]) 11 | const [userData, setUserData] = useState() 12 | const messageListBottomRef = useRef() 13 | 14 | const scrollToBottom = () => { 15 | messageListBottomRef?.current?.scrollIntoView({ 16 | behavior: 'smooth', 17 | block: 'end', 18 | }) 19 | } 20 | let groups = [], 21 | group = [], 22 | lastMe = null, 23 | getMessages = () => {} 24 | 25 | useEffect(async () => { 26 | const firestore = firebase.firestore() 27 | setUserData(await getUserData(userId)) 28 | 29 | let oldMessagesQuery = await firestore 30 | .collection(`users/${auth.user.id}/contacts/${userId}/messages`) 31 | .where('time', '<', new Date()) 32 | .limit(20) 33 | .orderBy('time', 'desc') 34 | .get() 35 | let oldMessages = oldMessagesQuery.docs.reverse() 36 | 37 | // userData?.id != userId && getMessages() 38 | getMessages = firestore 39 | .collection(`users/${auth.user.id}/contacts/${userId}/messages`) 40 | .orderBy('time', 'asc') 41 | .where('time', '>', new Date()) 42 | .onSnapshot((snapshot) => { 43 | // for (const doc of snapshot.docs) { 44 | // snapshot.docs.forEach((doc) => { 45 | // }) 46 | groups = [] 47 | let oldAndNewMessages = [...oldMessages, ...snapshot.docs] 48 | oldAndNewMessages.forEach((doc, index) => { 49 | const data = { 50 | id: doc.id, 51 | ...doc.data(), 52 | } 53 | if (data.me) { 54 | if (lastMe || lastMe == null) { 55 | group.push(data) 56 | lastMe = true 57 | } else { 58 | groups.push(group) 59 | group = [] 60 | group.push(data) 61 | lastMe = true 62 | } 63 | } else { 64 | if (!lastMe || lastMe == null) { 65 | group.push(data) 66 | lastMe = false 67 | } else { 68 | groups.push(group) 69 | group = [] 70 | group.push(data) 71 | lastMe = false 72 | } 73 | } 74 | }) 75 | groups.push(group) 76 | group = [] 77 | setMessageGroups(groups) 78 | scrollToBottom() 79 | }) 80 | 81 | return () => { 82 | userData?.id != userId && getMessages() 83 | } 84 | }, [userId]) 85 | return ( 86 |
87 | 104 |
105 | ) 106 | } 107 | -------------------------------------------------------------------------------- /components/MessageContent/styles.module.scss: -------------------------------------------------------------------------------- 1 | .messageContentInner { 2 | display: flex; 3 | flex: 1; 4 | overflow-y: auto; 5 | 6 | & > ul { 7 | display: flex; 8 | flex-direction: column; 9 | flex: 1; 10 | list-style: none; 11 | margin: 0; 12 | padding: 20px 20px 0 20px; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /components/MessageFooter/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from 'react' 2 | import styles from './styles.module.scss' 3 | import * as Icons from '../../icons' 4 | import sendMessage from '../../utility/sendMessage' 5 | import { useAuth } from '../../lib/auth' 6 | 7 | export default function MessageFooter({ userId }) { 8 | const [input, setInput] = useState('') 9 | const auth = useAuth() 10 | const inputRef = useRef(null) 11 | const inputKeyDownHandle = (e) => { 12 | if (e.keyCode === 13 && !e.shiftKey) { 13 | e.preventDefault() 14 | messageControlHandle(e) 15 | } 16 | } 17 | const inputHandle = (e) => { 18 | setInput(e.target.value) 19 | autoResizeHandle(e) 20 | } 21 | 22 | const messageControlHandle = (e) => { 23 | let tempInput = input.trim() 24 | if (tempInput.length > 0) { 25 | sendMessageHandle(e) 26 | } else { 27 | setInput('') 28 | e.target.setAttribute('rows', 1) 29 | } 30 | } 31 | const sendMessageHandle = (e) => { 32 | //Mesaj gönderme işlemleri 33 | sendMessage(auth.user.id, userId, input) 34 | setTimeout(() => { 35 | setInput('') 36 | e.target.setAttribute('rows', 1) 37 | }, 0) 38 | } 39 | 40 | const autoResizeHandle = (e) => { 41 | const textarea = e.target 42 | textarea.style.overflowY = 'hidden' 43 | textarea.style.resize = 'none' 44 | const rowsCount = textarea.value.split('\n').length 45 | if (rowsCount > 5) { 46 | textarea.setAttribute('rows', 5) 47 | textarea.style.overflowY = 'auto' 48 | } else { 49 | textarea.setAttribute('rows', rowsCount) 50 | } 51 | } 52 | 53 | useEffect(() => { 54 | inputRef.current.focus() 55 | }) 56 | return ( 57 |
58 |
59 |
60 | 63 | 64 | 73 | 74 | 77 | 80 |
81 |
82 |
83 | ) 84 | } 85 | -------------------------------------------------------------------------------- /components/MessageFooter/styles.module.scss: -------------------------------------------------------------------------------- 1 | .messageContentFooter { 2 | padding: 20px; 3 | background-color: var(--white); 4 | 5 | .messageFormInner { 6 | border: 1px solid var(--border-color); 7 | border-radius: 22px; 8 | padding: 0 8px 0 11px; 9 | display: flex; 10 | align-items: center; 11 | 12 | button { 13 | all: unset; 14 | cursor: pointer; 15 | padding: 8px; 16 | display: flex; 17 | } 18 | 19 | textarea { 20 | flex: 1; 21 | display: block; 22 | font-size: 14px; 23 | line-height: 18px; 24 | padding: 9px; 25 | display: flex; 26 | align-items: center; 27 | resize: none; 28 | font-family: inherit; 29 | border: 0; 30 | outline: 0; 31 | background-color: inherit; 32 | color: inherit; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /components/MessageHeader/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.scss' 3 | 4 | import UserUmage from '../UserImage' 5 | import Info from '../../icons/Info' 6 | import { getUserData } from '../../lib/db' 7 | import Link from 'next/link' 8 | 9 | export default function MessageHeader({ userId }) { 10 | const [userData, setUserData] = React.useState('') 11 | 12 | React.useEffect(async () => { 13 | setUserData(await getUserData(userId)) 14 | }, [userId]) 15 | 16 | return ( 17 |
18 |
19 | 20 | 21 | 22 | 23 | {userData.username} 24 | 25 | 26 | 27 |
28 | 34 |
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /components/MessageHeader/styles.module.scss: -------------------------------------------------------------------------------- 1 | .messageContentHeader { 2 | height: 60px; 3 | border-bottom: 1px solid var(--border-color); 4 | padding: 0 20px; 5 | display: flex; 6 | align-items: center; 7 | 8 | .contactInfo { 9 | display: flex; 10 | flex: 1; 11 | align-items: center; 12 | height: 100%; 13 | a { 14 | text-decoration: none; 15 | display: inline-flex; 16 | align-items: center; 17 | color: var(--text-color); 18 | } 19 | 20 | .contactUsername { 21 | margin-left: 12px; 22 | font-weight: 600; 23 | } 24 | } 25 | 26 | .userInfoButton { 27 | all: unset; 28 | align-self: center; 29 | cursor: pointer; 30 | display: flex; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /components/MessageListItem/index.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | import UserImage from '../UserImage' 3 | import styles from './styles.module.scss' 4 | import Link from 'next/link' 5 | import { getUserData } from '../../lib/db' 6 | 7 | export default function MessageListItem({ contact }) { 8 | const [user, setUser] = useState('') 9 | 10 | useEffect(async () => { 11 | const userData = await getUserData(contact.id) 12 | setUser(userData) 13 | }, []) 14 | 15 | return ( 16 | 17 | 18 |
19 | 20 |
21 |
22 | {user.username} 23 |

{contact.message}

24 |
25 |
26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /components/MessageListItem/styles.module.scss: -------------------------------------------------------------------------------- 1 | .messageListUserImage { 2 | margin-right: 12px; 3 | } 4 | 5 | .messageListUserMeta { 6 | font-size: 14px; 7 | display: flex; 8 | flex: 1; 9 | flex-direction: column; 10 | justify-content: center; 11 | overflow: hidden; 12 | 13 | span { 14 | color: var(--text); 15 | } 16 | p { 17 | white-space: nowrap; 18 | overflow: hidden; 19 | text-overflow: ellipsis; 20 | color: var(--muted-text); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /components/MessageSection/index.js: -------------------------------------------------------------------------------- 1 | import UserImage from '../UserImage' 2 | import styles from './styles.module.scss' 3 | 4 | export default function MessageSection({ 5 | src = '/user.jpg', 6 | me = false, 7 | list = [], 8 | }) { 9 | if (!list.length) { 10 | return false 11 | } 12 | return ( 13 |
  • 14 |
    15 |
    16 | 17 |
    18 |
    19 | {list.map((message, index) => { 20 | return ( 21 |
    22 | {message.message} 23 |
    24 | ) 25 | })} 26 |
    27 |
    28 |
  • 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /components/MessageSection/styles.module.scss: -------------------------------------------------------------------------------- 1 | .message { 2 | margin-bottom: 8px; 3 | 4 | &:last-child { 5 | margin-bottom: 0; 6 | } 7 | 8 | .messageSection { 9 | display: flex; 10 | align-items: flex-end; 11 | 12 | .userImage { 13 | margin-right: 8px; 14 | font-size: 24px; 15 | width: 1em; 16 | height: 1em; 17 | } 18 | } 19 | 20 | .sectionMessages { 21 | font-size: 14px; 22 | width: 100%; 23 | max-width: 235px; 24 | display: flex; 25 | flex-direction: column; 26 | 27 | .message { 28 | border: 1px solid var(--border-light-color); 29 | border-radius: 22px; 30 | padding: 16px; 31 | margin-bottom: 8px; 32 | align-self: flex-start; 33 | float: left; 34 | max-width: 100%; 35 | background-color: var(--other-message-background); 36 | overflow-wrap: break-word; 37 | 38 | &:last-child { 39 | margin-bottom: 0; 40 | } 41 | } 42 | } 43 | 44 | &.me { 45 | .messageSection { 46 | justify-content: flex-end; 47 | 48 | .sectionMessages { 49 | .message { 50 | align-self: flex-end; 51 | background-color: var(--border-light-color); 52 | } 53 | } 54 | } 55 | .userImage { 56 | display: none; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /components/NewMessageModal/index.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | import styles from './styles.module.scss' 3 | import * as Icons from '../../icons' 4 | import UserImage from '../UserImage' 5 | import { useAuth } from '../../lib/auth' 6 | import firebase from '../../lib/firebase' 7 | import { ClipLoader } from 'react-spinners' 8 | import { css } from '@emotion/core' 9 | 10 | const Modal = (props) => { 11 | const { setShowModal, setActiveContact } = props 12 | const auth = useAuth() 13 | const firestore = firebase.firestore() 14 | const [followings, setFollowings] = useState([]) 15 | const [loading, setLoading] = useState(true) 16 | const [search, setSearch] = useState('') 17 | const [contactList, setContactList] = useState([]) 18 | 19 | useEffect(async () => { 20 | const myFollowings = await firestore 21 | .collection(`users/${auth.user.id}/followings`) 22 | .get() 23 | .then((res) => { 24 | let ids = [] 25 | res.docs.forEach((user) => ids.push(user.id)) 26 | return ids 27 | }) 28 | myFollowings.forEach(async (user) => { 29 | let data = await firestore 30 | .doc(`users/${user}`) 31 | .get() 32 | .then((res) => { 33 | return res.data() 34 | }) 35 | setFollowings((users) => { 36 | return [...users, { id: user, ...data }] 37 | }) 38 | }) 39 | setLoading(false) 40 | return () => myFollowings() 41 | }, []) 42 | 43 | let filteredContacts = [] 44 | useEffect(() => { 45 | filteredContacts = followings.filter((user) => { 46 | let username = user.username.toLowerCase() 47 | let name = user.name.toLowerCase() 48 | let input = search.toLowerCase() 49 | return (username.includes(input) || name.includes(input)) && user 50 | }) 51 | if (search.trim().length) { 52 | setContactList(filteredContacts) 53 | } else { 54 | setContactList(followings) 55 | } 56 | }, [search, followings]) 57 | 58 | return ( 59 |
    { 62 | if (e.target == e.currentTarget) { 63 | setShowModal((showModal) => !showModal) 64 | } 65 | }} 66 | > 67 |
    68 |
    69 |
    70 | 77 |
    78 |
    Yeni Mesaj
    79 |
    80 |
    81 |
    82 | 83 |
    84 | setSearch(e.target.value)} 91 | /> 92 |
    93 |
    94 |
    95 |
    Önerilenler
    96 |
      97 | {loading ? ( 98 | <> 99 | 104 | 105 | ) : ( 106 | contactList.map((user) => { 107 | return ( 108 |
    • { 112 | setActiveContact(user.id) 113 | setShowModal(false) 114 | }} 115 | > 116 | 117 |
      118 |
      119 | {user.username} 120 |
      121 |
      122 | {user.name} 123 |
      124 |
      125 |
    • 126 | ) 127 | }) 128 | )} 129 |
    130 |
    131 |
    132 |
    133 | ) 134 | } 135 | 136 | export default Modal 137 | -------------------------------------------------------------------------------- /components/NewMessageModal/styles.module.scss: -------------------------------------------------------------------------------- 1 | .modal { 2 | position: fixed; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | left: 0; 7 | top: 0; 8 | bottom: 0; 9 | right: 0; 10 | background-color: rgba(0, 0, 0, 0.35); 11 | z-index: 10; 12 | 13 | .modalInner { 14 | max-width: 400px; 15 | width: 100%; 16 | background-color: var(--white); 17 | height: 50%; 18 | border-radius: 12px; 19 | display: flex; 20 | flex-direction: column; 21 | overflow: hidden; 22 | 23 | header { 24 | display: flex; 25 | height: 40px; 26 | justify-content: space-between; 27 | align-items: center; 28 | border-bottom: 1px solid var(--border-color); 29 | 30 | .close { 31 | height: 100%; 32 | button { 33 | appearance: none; 34 | display: flex; 35 | align-items: center; 36 | justify-content: center; 37 | border: 0; 38 | outline: 0; 39 | background: 0; 40 | height: inherit; 41 | width: 40px; 42 | cursor: pointer; 43 | font-size: 18px; 44 | } 45 | } 46 | 47 | .title { 48 | font-size: 16px; 49 | font-weight: 500; 50 | } 51 | 52 | .next { 53 | width: 40px; 54 | } 55 | } 56 | 57 | .search { 58 | font-size: 16px; 59 | height: 50px; 60 | display: flex; 61 | align-items: center; 62 | justify-content: flex-start; 63 | border-bottom: 1px solid var(--border-color); 64 | 65 | label { 66 | font-weight: 500; 67 | padding: 4px 12px; 68 | } 69 | 70 | .inputWrapper { 71 | padding: 4px 12px; 72 | flex: 1; 73 | 74 | input { 75 | display: block; 76 | width: 100%; 77 | height: 30px; 78 | outline: 0; 79 | border: 0; 80 | font-size: 14px; 81 | transform: translateY(2px); 82 | 83 | &::placeholder { 84 | color: var(--border-color); 85 | } 86 | } 87 | } 88 | } 89 | 90 | .contacts { 91 | font-size: 14px; 92 | flex: 1; 93 | align-self: stretch; 94 | display: flex; 95 | flex-direction: column; 96 | overflow-x: hidden; 97 | overflow-y: auto; 98 | 99 | .title { 100 | padding: 16px; 101 | font-weight: 500; 102 | } 103 | 104 | ul { 105 | display: flex; 106 | flex-direction: column; 107 | flex: 1; 108 | margin: 0; 109 | padding: 0; 110 | list-style: none; 111 | align-self: stretch; 112 | 113 | li { 114 | padding: 8px 16px; 115 | display: flex; 116 | align-items: center; 117 | background-color: var(--white); 118 | cursor: pointer; 119 | 120 | &:hover { 121 | background-color: var(--border-light-color); 122 | } 123 | 124 | .contactInfo { 125 | margin-left: 12px; 126 | flex: 1; 127 | display: flex; 128 | flex-direction: column; 129 | 130 | .username { 131 | font-weight: 500; 132 | } 133 | } 134 | } 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /components/NoMessage/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.scss' 3 | 4 | import * as Icons from '../../icons' 5 | 6 | export default function NoMessage({ setShowModal }) { 7 | return ( 8 |
    9 |
    10 |
    11 | 12 |
    13 |
    Mesajların
    14 |

    15 | Bir arkadaşına veya gruba gizli fotoğraflar ve mesajlar 16 | gönder. 17 |

    18 |
    19 | 22 |
    23 |
    24 |
    25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /components/NoMessage/styles.module.scss: -------------------------------------------------------------------------------- 1 | .noMessageWrapper { 2 | display: flex; 3 | flex: 1; 4 | align-items: center; 5 | justify-content: center; 6 | padding: 20px; 7 | 8 | .noMessage { 9 | color: var(--text); 10 | display: flex; 11 | flex-direction: column; 12 | 13 | .messageIcon { 14 | margin-left: auto; 15 | margin-right: auto; 16 | border: 3px solid var(--text); 17 | font-size: 42px; 18 | display: flex; 19 | justify-content: center; 20 | align-items: center; 21 | width: 95px; 22 | height: 95px; 23 | border-radius: 50%; 24 | } 25 | .pageTitle { 26 | text-align: center; 27 | font-size: 22px; 28 | font-weight: 400; 29 | margin-top: 28px; 30 | } 31 | .pageDescription { 32 | color: var(--muted-text); 33 | font-size: 14px; 34 | margin-top: 5px; 35 | margin-bottom: 32px; 36 | text-align: center; 37 | } 38 | 39 | .noMeesageFooter { 40 | text-align: center; 41 | button { 42 | background-color: var(--blue); 43 | border: 0; 44 | outline: 0; 45 | padding: 5px 9px; 46 | border-radius: 4px; 47 | color: var(--button-text); 48 | font-weight: 600; 49 | font-size: 14px; 50 | line-height: 1.5; 51 | display: inline-block; 52 | cursor: pointer; 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /components/NotFoundScreen/index.js: -------------------------------------------------------------------------------- 1 | const NotFoundScreen = () => { 2 | return ( 3 |
    4 |

    Üzgünüz, bu sayfaya ulaşılamıyor.

    5 |

    6 | Tıkladığın bağlantı bozuk olabilir veya sayfa kaldırılmış 7 | olabilir. Instagram'a geri dön. 8 |

    9 | 10 | 19 |
    20 | ) 21 | } 22 | export default NotFoundScreen 23 | -------------------------------------------------------------------------------- /components/Profile/styles.module.scss: -------------------------------------------------------------------------------- 1 | .profilePage { 2 | padding: 30px 0; 3 | 4 | header.profilePageHeader { 5 | margin-bottom: 44px; 6 | display: flex; 7 | flex-wrap: wrap; 8 | 9 | @media (max-width: 734.98px) { 10 | margin-bottom: 0; 11 | } 12 | 13 | .profileImageWrapper { 14 | display: flex; 15 | justify-content: center; 16 | flex-shrink: 0; 17 | margin-right: 30px; 18 | flex: 1; 19 | 20 | @media (max-width: 734.98px) { 21 | flex: 0; 22 | margin: 0 15px; 23 | } 24 | } 25 | 26 | .profileMetas { 27 | flex: 2; 28 | display: flex; 29 | flex-direction: column; 30 | 31 | @media (max-width: 734.98px) { 32 | justify-content: center; 33 | } 34 | 35 | .userHead { 36 | display: flex; 37 | margin-bottom: 20px; 38 | align-items: center; 39 | 40 | button { 41 | cursor: pointer; 42 | display: flex; 43 | background-color: transparent; 44 | outline: 0; 45 | } 46 | 47 | .usernameTitle { 48 | font-weight: 300; 49 | font-size: 28px; 50 | } 51 | .profileSettingsBtn { 52 | display: flex; 53 | justify-content: center; 54 | align-items: center; 55 | color: inherit; 56 | border: 0; 57 | margin-left: 5px; 58 | width: 40px; 59 | height: 40px; 60 | } 61 | } 62 | } 63 | } 64 | 65 | .userContents { 66 | .userContentTabs { 67 | display: flex; 68 | justify-content: center; 69 | align-items: center; 70 | height: 52px; 71 | border-top: 1px solid var(--border-color); 72 | margin-bottom: 2px; 73 | @media (max-width: 734.98px) { 74 | position: sticky; 75 | top: 0px; 76 | z-index: 20; 77 | background-color: var(--background-color); 78 | } 79 | @media (max-width: 599.98px) { 80 | top: 53px; 81 | background-color: var(--white); 82 | } 83 | 84 | button { 85 | display: flex; 86 | align-items: center; 87 | margin-right: 60px; 88 | text-decoration: none; 89 | text-transform: uppercase; 90 | font-weight: 600; 91 | height: 100%; 92 | color: var(--muted-text); 93 | background-color: transparent; 94 | outline: 0; 95 | border: 0; 96 | cursor: pointer; 97 | 98 | @media (max-width: 734.98px) { 99 | flex: 1; 100 | justify-content: center; 101 | } 102 | 103 | &.activeTab { 104 | color: var(--text); 105 | position: relative; 106 | 107 | &::after { 108 | content: ""; 109 | position: absolute; 110 | height: 0.5px; 111 | width: 100%; 112 | top: -1px; 113 | display: block; 114 | z-index: 1; 115 | background-color: var(--black); 116 | @media (max-width: 734.98px) { 117 | top: unset; 118 | height: 1px; 119 | bottom: 0; 120 | } 121 | } 122 | } 123 | 124 | span { 125 | display: flex; 126 | font-size: 12px; 127 | 128 | &.tab { 129 | margin-left: 6px; 130 | 131 | @media (max-width: 734.98px) { 132 | display: none; 133 | } 134 | } 135 | 136 | &.icon { 137 | @media (max-width: 734.98px) { 138 | font-size: 24px; 139 | } 140 | } 141 | } 142 | &:last-child { 143 | margin-right: 0; 144 | } 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /components/ProfileFollowButton/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.scss' 3 | import follow from '../../utility/follow' 4 | import unfollow from '../../utility/unfollow' 5 | import { useRouter } from 'next/router' 6 | 7 | const ProfileFollowButton = (props) => { 8 | const router = useRouter() 9 | const { auth, profileId, isUserFollowing, setIsUserFollowingHandle } = props 10 | if (isUserFollowing) { 11 | return ( 12 | <> 13 | 24 | 33 | 34 | ) 35 | } else { 36 | return ( 37 | 46 | ) 47 | } 48 | } 49 | 50 | export default ProfileFollowButton 51 | -------------------------------------------------------------------------------- /components/ProfileFollowButton/styles.module.scss: -------------------------------------------------------------------------------- 1 | .followButton, 2 | .alreadyFollowing, 3 | .unfollow { 4 | padding: 0 24px; 5 | height: 30px; 6 | font-weight: 500; 7 | color: var(--white); 8 | background-color: var(--blue) !important; 9 | display: inline-flex; 10 | align-self: center; 11 | align-items: center; 12 | border-radius: 3px; 13 | outline: 0; 14 | border: 0; 15 | margin-left: 20px; 16 | text-decoration: none; 17 | 18 | @media (max-width: 735px) { 19 | margin-left: 0; 20 | margin-top: 12px; 21 | align-self: flex-start; 22 | } 23 | } 24 | .alreadyFollowing { 25 | background-color: var(--background-color) !important; 26 | border: 1px solid var(--border-color); 27 | color: var(--text); 28 | padding: 0 9px; 29 | } 30 | 31 | .unfollow { 32 | background-color: var(--red) !important; 33 | border: 1px solid var(--red); 34 | color: var(--white); 35 | padding: 0 9px; 36 | } 37 | -------------------------------------------------------------------------------- /components/SearchResults/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import UserImage from '../UserImage' 3 | import styles from './styles.module.scss' 4 | import Link from 'next/link' 5 | 6 | const SearchResults = (props) => { 7 | const { result, setSearchInput } = props 8 | const clickHandle = (e) => { 9 | setSearchInput('') 10 | } 11 | 12 | return ( 13 |
    14 | 37 |
    38 | ) 39 | } 40 | 41 | export default SearchResults 42 | -------------------------------------------------------------------------------- /components/SearchResults/styles.module.scss: -------------------------------------------------------------------------------- 1 | .searchResults { 2 | position: absolute; 3 | top: 120%; 4 | width: 285px; 5 | background-color: var(--white); 6 | border-radius: 3px; 7 | border: 1px solid var(--border-color); 8 | z-index: 3; 9 | left: 50%; 10 | transform: translateX(-50%); 11 | &::before { 12 | content: ""; 13 | font-size: 1rem; 14 | width: 1em; 15 | height: 1em; 16 | position: absolute; 17 | border-top: 1px solid var(--border-color); 18 | border-right: 1px solid var(--border-color); 19 | top: -9px; 20 | left: 50%; 21 | z-index: 0; 22 | transform: rotate(-45deg); 23 | background: linear-gradient(to left bottom, var(--white) 50%, transparent 50%); 24 | } 25 | } 26 | .list { 27 | z-index: 1; 28 | list-style: none; 29 | margin: 0; 30 | background-color: var(--white); 31 | display: flex; 32 | max-height: 360px; 33 | flex-direction: column; 34 | overflow: hidden; 35 | overflow-y: auto; 36 | } 37 | .user { 38 | border-bottom: 1px solid var(--border-color); 39 | &:last-child { 40 | border: 0; 41 | } 42 | 43 | a { 44 | display: flex; 45 | padding: 10px; 46 | text-decoration: none; 47 | align-items: center; 48 | outline: 0; 49 | 50 | &:hover, 51 | &:focus { 52 | background-color: var(--background-color); 53 | } 54 | } 55 | } 56 | .image { 57 | margin-right: 10px; 58 | display: flex; 59 | align-items: center; 60 | } 61 | .about { 62 | font-size: 14px; 63 | display: flex; 64 | flex-direction: column; 65 | 66 | .username { 67 | font-weight: 500; 68 | } 69 | .name { 70 | font-weight: 50300; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /components/SignInScreen/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import styles from './styles.module.scss' 3 | import Link from 'next/link' 4 | import { useAuth } from '../../lib/auth' 5 | 6 | export default function SignInScreen() { 7 | const auth = useAuth() 8 | const refPassword = React.useRef() 9 | 10 | const [email, setEmail] = useState('') 11 | const [password, setPassword] = useState('') 12 | const [error, setError] = useState('') 13 | const handlePasswordInputType = (e) => { 14 | e.preventDefault() 15 | if (refPassword.current.type === 'password') { 16 | refPassword.current.type = 'text' 17 | e.target.innerText = 'Gizle' 18 | } else { 19 | refPassword.current.type = 'password' 20 | e.target.innerText = 'Göster' 21 | } 22 | } 23 | 24 | const handleSignIn = async (e) => { 25 | e.preventDefault() 26 | let isError = await auth.signIn(email, password) 27 | if (isError) { 28 | setError(isError.message) 29 | } 30 | } 31 | 32 | return ( 33 |
    34 |
    35 | 36 |
    37 |
    38 |
    39 |
    40 | 41 | 42 | 43 | 44 | 45 |
    46 |
    47 | setEmail(e.target.value)} 50 | placeholder="E-posta" 51 | value={email} 52 | tabIndex="1" 53 | autoFocus={true} 54 | /> 55 |
    56 |
    57 | setPassword(e.target.value)} 63 | tabIndex="1" 64 | className={styles.passwordInput} 65 | /> 66 |
    handlePasswordInputType(e)} 69 | className={styles.showOrHide} 70 | > 71 | Göster 72 |
    73 |
    74 |
    75 | 82 |
    83 |
    84 |
    ya da
    85 |
    86 |
    87 |
    88 | 89 | Facebook ile Giriş Yap 90 |
    91 | {error ? ( 92 |
    {error}
    93 | ) : ( 94 | '' 95 | )} 96 |
    97 | Şifreni mi unuttun? 98 |
    99 |
    100 |
    101 | 102 | {'Hesabın yok mu? '} 103 | 104 | Kaydol 105 | 106 | 107 |
    108 |
    109 |
    110 | 132 | {auth?.user?.uid} 133 |
    134 |
    135 | ) 136 | } 137 | -------------------------------------------------------------------------------- /components/SignInScreen/styles.module.scss: -------------------------------------------------------------------------------- 1 | .signInPage { 2 | // display: flex; 3 | padding-top: 45px; 4 | justify-content: center; 5 | align-items: center; 6 | 7 | @media (max-width: 735px) { 8 | padding-top: 30px; 9 | } 10 | 11 | .mockups { 12 | display: none; 13 | } 14 | 15 | .signUpWrapper { 16 | width: 100%; 17 | max-width: 350px; 18 | margin-left: auto; 19 | margin-right: auto; 20 | display: block; 21 | 22 | .section { 23 | border: 1px solid var(--border-color); 24 | border-radius: 3px; 25 | text-align: center; 26 | background-color: var(--white); 27 | 28 | @media (max-width: 735px) { 29 | border: none; 30 | } 31 | 32 | .brand { 33 | display: flex; 34 | justify-content: center; 35 | margin: 22px auto 12px; 36 | 37 | img { 38 | width: 100%; 39 | height: 100%; 40 | max-width: 175px; 41 | max-height: 51px; 42 | object-fit: contain; 43 | } 44 | } 45 | .field { 46 | margin: 0 40px 6px 40px; 47 | position: relative; 48 | 49 | input { 50 | border: 1px solid var(--border-color); 51 | padding: 9px 0 7px 8px; 52 | width: 100%; 53 | border-radius: 3px; 54 | font-size: 12px; 55 | background-color: var(--input-background); 56 | outline: 0; 57 | } 58 | .loginBtn { 59 | width: 100%; 60 | padding: 5px 9px; 61 | background-color: var(--blue); 62 | outline: 0; 63 | border: 1px solid var(--blue); 64 | border-radius: 3px; 65 | color: var(--white); 66 | font-weight: 500; 67 | cursor: pointer; 68 | } 69 | 70 | .showOrHide { 71 | appearance: none; 72 | background-color: transparent; 73 | border: 0; 74 | cursor: pointer; 75 | font-weight: 500; 76 | outline: 0; 77 | position: absolute; 78 | right: 10px; 79 | top: 50%; 80 | transform: translateY(-50%); 81 | font-size: 13.3333px; 82 | } 83 | } 84 | 85 | .horizantalLine { 86 | text-transform: uppercase; 87 | height: 30px; 88 | font-size: 13px; 89 | font-weight: 500; 90 | color: var(--muted-text); 91 | position: relative; 92 | margin: 10px 40px; 93 | 94 | .line { 95 | height: 1.5px; 96 | width: 100%; 97 | left: 0; 98 | position: absolute; 99 | background-color: var(--muted-text); 100 | top: 50%; 101 | opacity: 0.3; 102 | transform: translateY(-50%); 103 | z-index: 0; 104 | } 105 | 106 | .text { 107 | position: absolute; 108 | z-index: 1; 109 | background-color: white; 110 | left: 50%; 111 | top: 50%; 112 | padding: 0 15px; 113 | transform: translateY(-50%) translateX(-50%); 114 | } 115 | } 116 | 117 | .facebookLogin { 118 | margin: 15px 0; 119 | display: flex; 120 | align-items: center; 121 | justify-content: center; 122 | 123 | img { 124 | width: 15px; 125 | height: 15px; 126 | margin-right: 5px; 127 | } 128 | a { 129 | text-decoration: none; 130 | font-weight: 500; 131 | color: #385185; 132 | font-size: 14px; 133 | } 134 | } 135 | .forgotPassword { 136 | font-size: 12px; 137 | margin-bottom: 15px; 138 | a { 139 | text-decoration: none; 140 | font-size: 12px; 141 | color: var(--text-color); 142 | } 143 | } 144 | } 145 | 146 | .notHaveAccounts { 147 | width: 100%; 148 | max-width: 350px; 149 | margin-left: auto; 150 | margin-right: auto; 151 | display: block; 152 | border: 1px solid var(--border-color); 153 | border-radius: 3px; 154 | text-align: center; 155 | background-color: var(--white); 156 | margin-top: 10px; 157 | padding: 20px 0; 158 | font-size: 14px; 159 | 160 | @media (max-width: 735px) { 161 | border: none; 162 | } 163 | 164 | a { 165 | text-decoration: none; 166 | color: var(--blue); 167 | font-weight: 500; 168 | } 169 | } 170 | } 171 | 172 | .signUpFooter { 173 | margin-top: 40px; 174 | width: 80%; 175 | margin-left: auto; 176 | margin-right: auto; 177 | display: flex; 178 | flex-wrap: wrap; 179 | justify-content: center; 180 | 181 | a { 182 | color: var(--muted-text); 183 | text-decoration: none; 184 | font-size: 12px; 185 | white-space: nowrap; 186 | margin-right: 15px; 187 | margin-bottom: 10px; 188 | 189 | &:last-child { 190 | margin-right: 0; 191 | } 192 | } 193 | 194 | .footerText { 195 | width: 100%; 196 | text-align: center; 197 | font-size: 12px; 198 | color: var(--muted-text); 199 | margin-top: 20px; 200 | } 201 | } 202 | } 203 | .passwordInput { 204 | padding-right: 50px !important; 205 | } 206 | .errorMessage { 207 | margin: 40px 10px; 208 | color: var(--red); 209 | font-weight: 400; 210 | font-size: 14px; 211 | } 212 | -------------------------------------------------------------------------------- /components/SignUpScreen/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import styles from './styles.module.scss' 3 | import Link from 'next/link' 4 | import { signUp } from '../../lib/db' 5 | 6 | export default function SignUpScreen() { 7 | const [email, setEmail] = useState('') 8 | const [fullName, setFullName] = useState('') 9 | const [username, setUsername] = useState('') 10 | const [password, setPassword] = useState('') 11 | const [error, setError] = useState('') 12 | 13 | const handleSubmitForm = async (e) => { 14 | e.preventDefault() 15 | signUp(email, password, username, fullName).then((res) => { 16 | if (res) { 17 | setError(res.message) 18 | } 19 | }) 20 | } 21 | 22 | return ( 23 |
    24 |
    25 |
    26 |
    handleSubmitForm(e)}> 27 |
    28 | 29 | 30 | 31 | 32 | 33 |
    34 |
    35 | Arkadaşlarının fotoğraf ve videolarını görmek için 36 | kaydol. 37 |
    38 |
    39 | 40 |
    41 |
    42 |
    ya da
    43 |
    44 |
    45 |
    46 | setEmail(e.target.value)} 51 | /> 52 |
    53 |
    54 | setFullName(e.target.value)} 60 | /> 61 |
    62 |
    63 | setUsername(e.target.value)} 69 | /> 70 |
    71 |
    72 | setPassword(e.target.value)} 77 | /> 78 |
    79 |
    80 | 87 |
    88 | {error ? ( 89 |
    {error}
    90 | ) : ( 91 | '' 92 | )} 93 |
    94 | Kaydolarak, Koşullar'ı,{' '} 95 | Veri İlkesi'ni ve{' '} 96 | Çerezler İlkesi'ni kabul etmiş 97 | olursun. 98 |
    99 |
    100 |
    101 | 102 | Hesabın var mı?{' '} 103 | 104 | Giriş yap 105 | 106 | 107 |
    108 |
    109 |
    110 | 125 |
    126 |
    127 |
    128 | ) 129 | } 130 | -------------------------------------------------------------------------------- /components/SignUpScreen/styles.module.scss: -------------------------------------------------------------------------------- 1 | .signUpPage { 2 | // display: flex; 3 | padding-top: 45px; 4 | justify-content: center; 5 | align-items: center; 6 | 7 | @media (max-width: 735px) { 8 | padding-top: 30px; 9 | } 10 | 11 | .signUpWrapper { 12 | width: 100%; 13 | max-width: 350px; 14 | margin-left: auto; 15 | margin-right: auto; 16 | display: block; 17 | 18 | form { 19 | border: 1px solid var(--border-color); 20 | border-radius: 3px; 21 | text-align: center; 22 | background-color: var(--white); 23 | 24 | @media (max-width: 735px) { 25 | border: none; 26 | } 27 | 28 | .brand { 29 | display: flex; 30 | justify-content: center; 31 | margin: 22px auto 12px; 32 | 33 | img { 34 | width: 100%; 35 | height: 100%; 36 | max-width: 175px; 37 | max-height: 51px; 38 | object-fit: contain; 39 | } 40 | } 41 | 42 | .description { 43 | margin: 15px 40px; 44 | font-weight: 500; 45 | color: var(--muted-text); 46 | } 47 | 48 | .facebookLoginBtnWrapper { 49 | margin: 0 40px; 50 | display: block; 51 | 52 | button { 53 | cursor: pointer; 54 | width: 100%; 55 | padding: 5px 9px; 56 | background-color: var(--blue); 57 | outline: 0; 58 | border: 1px solid var(--blue); 59 | border-radius: 3px; 60 | color: var(--white); 61 | font-weight: 500; 62 | } 63 | } 64 | .field { 65 | margin: 0 40px 6px 40px; 66 | position: relative; 67 | 68 | input { 69 | border: 1px solid var(--border-color); 70 | padding: 9px 0 7px 8px; 71 | width: 100%; 72 | border-radius: 3px; 73 | font-size: 12px; 74 | background-color: var(--input-background); 75 | outline: 0; 76 | line-height: 1.5; 77 | } 78 | 79 | .showOrHide { 80 | appearance: none; 81 | background-color: transparent; 82 | border: 0; 83 | cursor: pointer; 84 | font-weight: 500; 85 | outline: 0; 86 | position: absolute; 87 | right: 10px; 88 | top: 50%; 89 | transform: translateY(-50%); 90 | } 91 | .signUpBtn { 92 | width: 100%; 93 | padding: 5px 9px; 94 | background-color: var(--blue); 95 | outline: 0; 96 | border: 1px solid var(--blue); 97 | border-radius: 3px; 98 | color: var(--white); 99 | font-weight: 500; 100 | margin-top: 10px; 101 | cursor: pointer; 102 | } 103 | } 104 | 105 | .horizantalLine { 106 | text-transform: uppercase; 107 | height: 30px; 108 | font-size: 13px; 109 | font-weight: 500; 110 | color: var(--muted-text); 111 | position: relative; 112 | margin: 10px 40px; 113 | 114 | .line { 115 | height: 1.5px; 116 | width: 100%; 117 | left: 0; 118 | position: absolute; 119 | background-color: var(--muted-text); 120 | top: 50%; 121 | opacity: 0.3; 122 | transform: translateY(-50%); 123 | z-index: 0; 124 | } 125 | 126 | .text { 127 | position: absolute; 128 | z-index: 1; 129 | background-color: white; 130 | left: 50%; 131 | top: 50%; 132 | padding: 0 15px; 133 | transform: translateY(-50%) translateX(-50%); 134 | } 135 | } 136 | 137 | .terms { 138 | font-size: 12px; 139 | margin-bottom: 15px; 140 | margin-left: 40px; 141 | margin-right: 40px; 142 | margin-top: 20px; 143 | a { 144 | text-decoration: none; 145 | color: var(--text-color); 146 | font-weight: 500; 147 | } 148 | } 149 | } 150 | 151 | .doYouHaveAnAccount { 152 | width: 100%; 153 | max-width: 350px; 154 | margin-left: auto; 155 | margin-right: auto; 156 | display: block; 157 | border: 1px solid var(--border-color); 158 | border-radius: 3px; 159 | text-align: center; 160 | background-color: var(--white); 161 | margin-top: 10px; 162 | padding: 20px 0; 163 | font-size: 14px; 164 | 165 | @media (max-width: 735px) { 166 | border: none; 167 | } 168 | 169 | a { 170 | text-decoration: none; 171 | color: var(--blue); 172 | } 173 | } 174 | } 175 | 176 | .signUpFooter { 177 | margin-top: 40px; 178 | padding-bottom: 20px; 179 | width: 80%; 180 | margin-left: auto; 181 | margin-right: auto; 182 | display: flex; 183 | flex-wrap: wrap; 184 | justify-content: center; 185 | 186 | a { 187 | color: var(--muted-text); 188 | text-decoration: none; 189 | font-size: 12px; 190 | white-space: nowrap; 191 | margin-right: 15px; 192 | margin-bottom: 10px; 193 | 194 | &:last-child { 195 | margin-right: 0; 196 | } 197 | } 198 | 199 | .footerText { 200 | width: 100%; 201 | text-align: center; 202 | font-size: 12px; 203 | color: var(--muted-text); 204 | margin-top: 20px; 205 | } 206 | } 207 | } 208 | .errorMessage { 209 | margin: 40px 20px; 210 | color: var(--red); 211 | font-weight: 400; 212 | font-size: 14px; 213 | } 214 | -------------------------------------------------------------------------------- /components/StoriesBar/index.js: -------------------------------------------------------------------------------- 1 | import styles from './styles.module.scss' 2 | import StoryItem from '../StoryItem' 3 | 4 | export default function StoriesBar() { 5 | return ( 6 |
    7 |
    8 | 15 |
    16 |
    17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /components/StoriesBar/styles.module.scss: -------------------------------------------------------------------------------- 1 | .storiesBar { 2 | background-color: var(--white); 3 | border: 1px solid var(--border-color); 4 | border-radius: 3px; 5 | overflow-x: auto; 6 | overflow-y: hidden; 7 | @media (max-width: 599.98px) { 8 | border: 0; 9 | border-bottom: 1px solid var(--border-color); 10 | border-radius: 0; 11 | } 12 | 13 | .storiesInner { 14 | .stories { 15 | padding: 16px 4px; 16 | list-style-type: none; 17 | display: flex; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /components/StoryItem/index.js: -------------------------------------------------------------------------------- 1 | import UserImage from '../UserImage' 2 | import styles from './styles.module.scss' 3 | 4 | export default function StoryItem({ username = "owuzan", src = "owuzan.jpg" }) { 5 | return ( 6 |
  • 7 | 8 |

    {username}

    9 |
  • 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /components/StoryItem/styles.module.scss: -------------------------------------------------------------------------------- 1 | .storyItem { 2 | display: flex; 3 | flex-direction: column; 4 | margin-left: 14px; 5 | display: flex; 6 | color: var(--text); 7 | font-size: 12px; 8 | text-align: center; 9 | font-weight: 400; 10 | cursor: pointer; 11 | padding: 6px; 12 | 13 | p { 14 | margin-top: 3px; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /components/SugessionUser/index.js: -------------------------------------------------------------------------------- 1 | import UserImage from '../UserImage' 2 | import styles from './styles.module.scss' 3 | 4 | export default function SuggessionUser({ username = "owuzan", name = "Oğuzhan Yılmaz", src = "owuzan.jpg" }) { 5 | return ( 6 | <> 7 |
    8 | 9 |
    10 |

    {username}

    11 | {name} 12 |
    13 |
    14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /components/SugessionUser/styles.module.scss: -------------------------------------------------------------------------------- 1 | .suggesionUser { 2 | display: flex; 3 | align-items: center; 4 | justify-content: flex-start; 5 | 6 | .userMeta { 7 | margin-left: 12px; 8 | width: 141px; 9 | display: flex; 10 | flex-direction: column; 11 | p { 12 | margin: 0; 13 | font-weight: 500; 14 | font-size: 14px; 15 | 16 | a { 17 | text-decoration: none; 18 | color: inherit; 19 | 20 | &:hover { 21 | text-decoration: underline; 22 | } 23 | } 24 | } 25 | span { 26 | font-weight: 400; 27 | font-size: 12px; 28 | color: var(--muted-text); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /components/UserImage/index.js: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import styles from './styles.module.scss' 3 | 4 | export default function UserImage(props) { 5 | const src = props.src ?? '/user.jpg' 6 | const classes = classNames({ 7 | [styles.userImage]: true, 8 | [styles.story]: props?.type === 'story' ? true : false, 9 | [styles.active]: props?.type === 'active' ? true : false, 10 | }) 11 | return ( 12 |
    13 |
    14 | 15 |
    16 | 21 |
    22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /components/UserImage/styles.module.scss: -------------------------------------------------------------------------------- 1 | .userImage { 2 | display: inline-flex; 3 | font-size: 24px; 4 | width: 1em; 5 | height: 1em; 6 | position: relative; 7 | cursor: pointer; 8 | 9 | .imageWrapper { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | position: absolute; 14 | top: 0; 15 | right: 0; 16 | bottom: 0; 17 | left: 0; 18 | border-radius: 50%; 19 | 20 | img { 21 | width: 100%; 22 | height: 100%; 23 | border-radius: 50%; 24 | object-fit: cover; 25 | } 26 | } 27 | } 28 | 29 | .story { 30 | .imageWrapper { 31 | border-radius: 50%; 32 | top: -4px; 33 | right: -4px; 34 | bottom: -4px; 35 | left: -4px; 36 | background: conic-gradient( 37 | from 180deg at 50% 50%, 38 | #e03571 -44.74deg, 39 | #f9793a 0.68deg, 40 | #f79c4f 46.29deg, 41 | #f97e34 90.31deg, 42 | #e3455f 138.62deg, 43 | #d72b7e 180deg, 44 | #c12f91 227.75deg, 45 | #db297d 269.6deg, 46 | #e03571 315.26deg, 47 | #f9793a 360.68deg 48 | ); 49 | 50 | img { 51 | box-shadow: 0 0 0 2px var(--white); 52 | width: 1em; 53 | height: 1em; 54 | } 55 | } 56 | } 57 | 58 | .active { 59 | .imageWrapper { 60 | box-shadow: 0 0 0 3px var(--black); 61 | img { 62 | box-shadow: 0 0 0 2px var(--white); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /components/UserInfo/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.scss' 3 | import linkedText from '../../utility/linkedText' 4 | import Link from 'next/link' 5 | 6 | export default function UserInfo({ userData }) { 7 | return ( 8 |
    9 |

    {userData.name}

    10 |
    11 |

    12 | {linkedText(userData?.biography ? userData.biography : '')} 13 |

    14 |
    15 |
    16 |

    Burası test amaçlı yazılmıştır.

    17 |

    {linkedText('Var olan @owuzan hesabına git.')}

    18 |

    {linkedText('Var olan @ssezer hesabına git.')}

    19 |

    20 | {linkedText( 21 | 'Var olmayan @boylebirhesapyok hesabına git.' 22 | )} 23 |

    24 |

    25 | {linkedText( 26 | 'Route olan @direct linkine hesap olarak gitmeye çalış.' 27 | )} 28 |

    29 |
    30 |
    31 |
    32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /components/UserInfo/styles.module.scss: -------------------------------------------------------------------------------- 1 | .userProfileInfo { 2 | @media (max-width: 734.98px) { 3 | margin: 15px; 4 | } 5 | .userFullname { 6 | font-size: 16px; 7 | font-weight: 600; 8 | margin-bottom: 5px; 9 | } 10 | .userBiography { 11 | font-size: 16px; 12 | line-height: 1.5; 13 | 14 | a { 15 | color: var(--tag-blue); 16 | text-decoration: none; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /components/UserPost/styles.module.scss: -------------------------------------------------------------------------------- 1 | .postWrapper { 2 | border: 1px solid var(--border-color); 3 | border-radius: 3px; 4 | background-color: var(--white); 5 | margin-top: 30px; 6 | display: flex; 7 | flex-direction: column; 8 | @media (max-width: 599.98px) { 9 | margin: 0; 10 | margin-bottom: 10px; 11 | border: 0; 12 | background-color: var(--white); 13 | } 14 | 15 | svg { 16 | font-size: 24px; 17 | } 18 | 19 | &:last-child { 20 | margin-bottom: 0; 21 | } 22 | 23 | header { 24 | display: flex; 25 | justify-content: space-between; 26 | align-items: center; 27 | height: 60px; 28 | padding: 0 16px; 29 | .userInfo { 30 | display: flex; 31 | align-items: center; 32 | 33 | svg { 34 | font-size: 32px; 35 | } 36 | 37 | .userName { 38 | margin: 0; 39 | margin-left: 16px; 40 | color: var(--text); 41 | font-size: 14px; 42 | font-weight: 500; 43 | text-decoration: none; 44 | 45 | &:hover { 46 | text-decoration: underline; 47 | } 48 | } 49 | } 50 | } 51 | 52 | .postContent { 53 | .imageWrapper { 54 | position: relative; 55 | 56 | *::selection { 57 | background: transparent; 58 | } 59 | 60 | .heart { 61 | position: absolute; 62 | display: flex; 63 | justify-content: center; 64 | align-items: center; 65 | height: 100%; 66 | width: 100%; 67 | opacity: 0.3; 68 | svg { 69 | transform: scale(0); 70 | font-size: 70px; 71 | } 72 | 73 | svg path { 74 | fill: white; 75 | } 76 | 77 | &.heartAnimate { 78 | animation: likeAnimationOnImage 1s; 79 | svg { 80 | transform: scale(1); 81 | } 82 | } 83 | } 84 | img { 85 | display: block; 86 | width: 100%; 87 | max-height: 500px; 88 | object-fit: cover; 89 | } 90 | } 91 | 92 | .actionButtons { 93 | padding: 4px 6px 0; 94 | display: flex; 95 | align-items: center; 96 | justify-content: flex-start; 97 | 98 | button { 99 | appearance: none; 100 | background-color: transparent; 101 | border: 0; 102 | display: flex; 103 | justify-content: center; 104 | align-items: center; 105 | outline: 0; 106 | cursor: pointer; 107 | width: 40px; 108 | height: 40px; 109 | animation-duration: 300ms; 110 | color: inherit; 111 | } 112 | } 113 | 114 | .postInfo { 115 | padding: 0 16px; 116 | display: flex; 117 | flex-direction: column; 118 | font-size: 14px; 119 | 120 | .likeCount { 121 | font-weight: 500; 122 | padding: 1px 0; 123 | margin-bottom: 4px; 124 | &::selection { 125 | background: transparent; 126 | } 127 | } 128 | 129 | .postDescription { 130 | margin-bottom: 4px; 131 | a { 132 | font-weight: 500; 133 | text-decoration: none; 134 | color: var(--text); 135 | margin-right: 5px; 136 | 137 | &:hover { 138 | text-decoration: underline; 139 | } 140 | } 141 | span { 142 | } 143 | } 144 | 145 | ul.commentsList { 146 | list-style: none; 147 | padding: 0; 148 | margin: 0; 149 | 150 | .commentsCount, 151 | .postTime { 152 | color: var(--muted-text); 153 | } 154 | 155 | .postTime { 156 | text-transform: uppercase; 157 | font-size: 10px; 158 | } 159 | 160 | li { 161 | margin-bottom: 4px; 162 | 163 | a { 164 | color: var(--tag-blue); 165 | text-decoration: none; 166 | } 167 | span { 168 | margin-right: 5px; 169 | 170 | a { 171 | font-weight: 500; 172 | color: var(--text); 173 | text-decoration: none; 174 | } 175 | } 176 | } 177 | } 178 | } 179 | } 180 | 181 | .commentForm { 182 | padding-top: 5px; 183 | 184 | .formWrapper { 185 | border-top: 1px solid var(--border-light-color); 186 | padding: 0 16px; 187 | margin-top: 4px; 188 | 189 | form { 190 | display: flex; 191 | align-items: center; 192 | height: 56px; 193 | } 194 | 195 | input { 196 | all: unset; 197 | flex: 1; 198 | height: 100%; 199 | display: block; 200 | font-size: 14px; 201 | 202 | &::placeholder { 203 | color: var(--muted-text); 204 | } 205 | } 206 | 207 | button { 208 | all: unset; 209 | height: 100%; 210 | display: block; 211 | color: var(--blue); 212 | font-weight: 500; 213 | cursor: pointer; 214 | 215 | &:disabled { 216 | cursor: auto; 217 | opacity: 0.5; 218 | } 219 | } 220 | } 221 | } 222 | } 223 | .fillRed { 224 | animation-name: likeAnimation; 225 | } 226 | .fillRed svg path { 227 | fill: var(--red); 228 | transition: 300ms fill; 229 | } 230 | @keyframes likeAnimation { 231 | 0% { 232 | transform: scale(1); 233 | } 234 | 50% { 235 | transform: scale(1.2); 236 | } 237 | 100% { 238 | transform: scale(1); 239 | } 240 | } 241 | @keyframes likeAnimationOnImage { 242 | 0% { 243 | opacity: 1; 244 | transform: scale(0.5); 245 | } 246 | 25% { 247 | opacity: 1; 248 | transform: scale(1.1); 249 | } 250 | 50% { 251 | opacity: 1; 252 | transform: scale(1); 253 | } 254 | 75% { 255 | opacity: 1; 256 | transform: scale(1); 257 | } 258 | 100% { 259 | opacity: 0; 260 | transform: scale(0.5); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /components/UserPosts/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.scss' 3 | import Link from 'next/link' 4 | import { getUserPosts, getUserIdFromUsername } from '../../lib/db' 5 | import { useRouter } from 'next/router' 6 | import usePostsFormat from '../../hooks/usePostsFormat' 7 | 8 | const UserPosts = () => { 9 | const router = useRouter() 10 | const { username } = router.query 11 | const [postsList, setPostsList] = React.useState([]) 12 | 13 | React.useEffect(async () => { 14 | const getPosts = (username) => { 15 | return new Promise(async (resolve, reject) => { 16 | const id = await getUserIdFromUsername(username).then( 17 | (res) => res 18 | ) 19 | const userPosts = await getUserPosts(id) 20 | resolve(userPosts) 21 | }) 22 | } 23 | const list = await getPosts(username).then((res) => res) 24 | 25 | setPostsList(usePostsFormat(list)) 26 | }, [username]) 27 | 28 | return ( 29 |
    30 | {postsList.map((row, index) => { 31 | return ( 32 |
    33 | {row.map((column, index) => { 34 | return ( 35 |
    39 |
    40 | {Object.entries(column).length ? ( 41 | 42 | 43 |
    48 | 52 |
    53 |
    54 | 55 | ) : ( 56 | '' 57 | )} 58 |
    59 |
    60 | ) 61 | })} 62 |
    63 | ) 64 | })} 65 |
    66 | ) 67 | } 68 | export default UserPosts 69 | -------------------------------------------------------------------------------- /components/UserPosts/styles.module.scss: -------------------------------------------------------------------------------- 1 | .userPosts { 2 | --gap: 28px; 3 | display: flex; 4 | flex-direction: column; 5 | align-items: stretch; 6 | z-index: 10; 7 | width: 100%; 8 | height: 100%; 9 | 10 | img { 11 | object-fit: cover; 12 | width: 100%; 13 | height: 100%; 14 | } 15 | 16 | @media (max-width: 734.98px) { 17 | --gap: 2px; 18 | } 19 | 20 | .userPostsRow { 21 | display: flex; 22 | margin-bottom: var(--gap); 23 | 24 | .userPostWrapper { 25 | width: 100%; 26 | margin-right: var(--gap); 27 | 28 | &:last-child { 29 | margin-right: 0; 30 | } 31 | } 32 | 33 | .userPostColumn { 34 | position: relative; 35 | width: 100%; 36 | padding-bottom: 100%; 37 | overflow: hidden; 38 | 39 | a { 40 | position: absolute; 41 | top: 0; 42 | left: 0; 43 | bottom: 0; 44 | right: 0; 45 | } 46 | 47 | .userPost { 48 | height: 100%; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /components/UserStatistics/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './styles.module.scss' 3 | 4 | export default function UserStatistics(props) { 5 | const { postsCount, followersCount, followingsCount } = props.statistics 6 | return ( 7 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /components/UserStatistics/styles.module.scss: -------------------------------------------------------------------------------- 1 | .userStatistics { 2 | margin-bottom: 20px; 3 | list-style: none; 4 | display: flex; 5 | align-items: center; 6 | flex-wrap: nowrap; 7 | 8 | @media (max-width: 734.98px) { 9 | margin: 0; 10 | justify-content: space-between; 11 | max-width: 400px; 12 | margin: 0 40px 0 0px; 13 | } 14 | 15 | li { 16 | margin-right: 40px; 17 | display: flex; 18 | 19 | @media (max-width: 734.98px) { 20 | flex-direction: column; 21 | align-items: center; 22 | margin-right: 0; 23 | } 24 | 25 | &:last-child { 26 | margin-right: 0; 27 | } 28 | 29 | span { 30 | @media (max-width: 734.98px) { 31 | text-transform: capitalize; 32 | font-size: 14px; 33 | } 34 | 35 | &.count { 36 | font-weight: 500; 37 | margin-right: 5px; 38 | font-size: 16px; 39 | 40 | @media (max-width: 734.98px) { 41 | margin-right: 0; 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /hooks/usePostsFormat.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const usePostsFormat = (list) => { 4 | let rows = [], 5 | columns = [] 6 | list.map((post, index) => { 7 | index++ 8 | if (index % 3 == 0) { 9 | columns.push(post) 10 | rows.push(columns) 11 | columns = [] 12 | } else { 13 | columns.push(post) 14 | } 15 | }) 16 | const remaining = list.length % 3 17 | if (remaining) { 18 | let add = 3 - remaining 19 | for (let index = 0; index < add; index++) { 20 | columns.push({}) 21 | } 22 | rows.push(columns) 23 | } 24 | 25 | return rows 26 | } 27 | 28 | export default usePostsFormat 29 | -------------------------------------------------------------------------------- /hooks/useWindowSize.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | 3 | export default function useWindowSize() { 4 | const [windowSize, setWindowSize] = useState({ 5 | width: undefined, 6 | height: undefined, 7 | }); 8 | useEffect(() => { 9 | const handleResize = () => { 10 | setWindowSize({ 11 | width: window.innerWidth, 12 | height: window.innerHeight, 13 | }); 14 | } 15 | window.addEventListener("resize", handleResize); 16 | handleResize(); 17 | return () => window.removeEventListener("resize", handleResize); 18 | }, []); 19 | return windowSize; 20 | } 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /icons/AddPost.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgAddPost(props) { 4 | return ( 5 | 13 | 17 | 21 | 25 | 26 | ) 27 | } 28 | 29 | export default SvgAddPost 30 | -------------------------------------------------------------------------------- /icons/Back.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgBack(props) { 4 | return ( 5 | 13 | 17 | 18 | ) 19 | } 20 | 21 | export default SvgBack 22 | -------------------------------------------------------------------------------- /icons/Bookmark.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgBookmark(props) { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default SvgBookmark 29 | -------------------------------------------------------------------------------- /icons/BookmarkFill.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgBookmarkFill(props) { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default SvgBookmarkFill 29 | -------------------------------------------------------------------------------- /icons/Camera.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgCamera(props) { 4 | return ( 5 | 13 | 19 | 20 | ) 21 | } 22 | 23 | export default SvgCamera 24 | -------------------------------------------------------------------------------- /icons/Close.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgClose(props) { 4 | return ( 5 | 13 | 19 | 20 | ) 21 | } 22 | 23 | export default SvgClose 24 | -------------------------------------------------------------------------------- /icons/Comment.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgComment(props) { 4 | return ( 5 | 13 | 19 | 20 | ) 21 | } 22 | 23 | export default SvgComment 24 | -------------------------------------------------------------------------------- /icons/Emoji.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgEmoji(props) { 4 | return ( 5 | 13 | 17 | 21 | 22 | ) 23 | } 24 | 25 | export default SvgEmoji 26 | -------------------------------------------------------------------------------- /icons/Explore.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgExplore(props) { 4 | return ( 5 | 13 | 19 | 20 | ) 21 | } 22 | 23 | export default SvgExplore 24 | -------------------------------------------------------------------------------- /icons/ExploreFill.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgExploreFill(props) { 4 | return ( 5 | 13 | 19 | 20 | ) 21 | } 22 | 23 | export default SvgExploreFill 24 | -------------------------------------------------------------------------------- /icons/Home.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgHome(props) { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default SvgHome 29 | -------------------------------------------------------------------------------- /icons/HomeFill.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgHomeFill(props) { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default SvgHomeFill 29 | -------------------------------------------------------------------------------- /icons/Info.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgInfo(props) { 4 | return ( 5 | 13 | 17 | 21 | 25 | 26 | ) 27 | } 28 | 29 | export default SvgInfo 30 | -------------------------------------------------------------------------------- /icons/Like.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgLike(props) { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default SvgLike 29 | -------------------------------------------------------------------------------- /icons/LikeFill.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgLikeFill(props) { 4 | return ( 5 | 13 | 17 | 18 | ) 19 | } 20 | 21 | export default SvgLikeFill 22 | -------------------------------------------------------------------------------- /icons/Loader.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgLoader(props) { 4 | return ( 5 | 12 | 13 | 14 | 15 | 20 | 25 | 26 | 31 | 36 | 37 | 42 | 47 | 55 | 56 | 57 | ) 58 | } 59 | 60 | export default SvgLoader 61 | -------------------------------------------------------------------------------- /icons/Message.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgMessage(props) { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default SvgMessage 29 | -------------------------------------------------------------------------------- /icons/MessageFill.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgMessageFill(props) { 4 | return ( 5 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ) 26 | } 27 | 28 | export default SvgMessageFill 29 | -------------------------------------------------------------------------------- /icons/NewMessage.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgNewMessage(props) { 4 | return ( 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ) 25 | } 26 | 27 | export default SvgNewMessage 28 | -------------------------------------------------------------------------------- /icons/Options.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgOptions(props) { 4 | return ( 5 | 13 | 19 | 20 | ) 21 | } 22 | 23 | export default SvgOptions 24 | -------------------------------------------------------------------------------- /icons/Photo.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgPhoto(props) { 4 | return ( 5 | 13 | 17 | 18 | ) 19 | } 20 | 21 | export default SvgPhoto 22 | -------------------------------------------------------------------------------- /icons/Posts.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgPosts(props) { 4 | return ( 5 | 13 | 19 | 20 | ) 21 | } 22 | 23 | export default SvgPosts 24 | -------------------------------------------------------------------------------- /icons/Preferences.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgPreferences(props) { 4 | return ( 5 | 13 | 17 | 18 | ) 19 | } 20 | 21 | export default SvgPreferences 22 | -------------------------------------------------------------------------------- /icons/Search.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgSearch(props) { 4 | return ( 5 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ) 24 | } 25 | 26 | export default SvgSearch 27 | -------------------------------------------------------------------------------- /icons/Tagged.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgTagged(props) { 4 | return ( 5 | 13 | 17 | 18 | ) 19 | } 20 | 21 | export default SvgTagged 22 | -------------------------------------------------------------------------------- /icons/User.js: -------------------------------------------------------------------------------- 1 | import * as React from 'react' 2 | 3 | function SvgUser(props) { 4 | return ( 5 | 13 | 17 | 18 | ) 19 | } 20 | 21 | export default SvgUser 22 | -------------------------------------------------------------------------------- /icons/index.js: -------------------------------------------------------------------------------- 1 | export { default as AddPost } from './AddPost' 2 | export { default as Back } from './Back' 3 | export { default as Bookmark } from './Bookmark' 4 | export { default as BookmarkFill } from './BookmarkFill' 5 | export { default as Camera } from './Camera' 6 | export { default as Close } from './Close' 7 | export { default as Comment } from './Comment' 8 | export { default as Emoji } from './Emoji' 9 | export { default as Explore } from './Explore' 10 | export { default as ExploreFill } from './ExploreFill' 11 | export { default as Home } from './Home' 12 | export { default as HomeFill } from './HomeFill' 13 | export { default as Info } from './Info' 14 | export { default as Like } from './Like' 15 | export { default as LikeFill } from './LikeFill' 16 | export { default as Loader } from './Loader' 17 | export { default as Message } from './Message' 18 | export { default as MessageFill } from './MessageFill' 19 | export { default as NewMessage } from './NewMessage' 20 | export { default as Options } from './Options' 21 | export { default as Photo } from './Photo' 22 | export { default as Posts } from './Posts' 23 | export { default as Preferences } from './Preferences' 24 | export { default as Search } from './Search' 25 | export { default as Tagged } from './Tagged' 26 | export { default as User } from './User' -------------------------------------------------------------------------------- /lib/auth.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useContext, createContext } from 'react' 2 | import Router from 'next/router' 3 | import cookie from 'js-cookie' 4 | import firebase from './firebase' 5 | const authContext = createContext() 6 | export function AuthProvider({ children }) { 7 | const auth = useProvideAuth() 8 | return {children} 9 | } 10 | export const useAuth = () => { 11 | return useContext(authContext) 12 | } 13 | function useProvideAuth() { 14 | const [user, setUser] = useState(null) 15 | const [loading, setLoading] = useState(true) 16 | const handleUser = async (rawUser) => { 17 | if (rawUser) { 18 | const user = await formatUser(rawUser) 19 | const { token, ...userWithoutToken } = user 20 | setUser(user) 21 | cookie.set('instagram-clone-auth', true, { 22 | expires: 1, 23 | }) 24 | setLoading(false) 25 | return user 26 | } else { 27 | setUser(false) 28 | cookie.remove('instagram-clone-auth') 29 | setLoading(false) 30 | return false 31 | } 32 | } 33 | const signIn = (email, password) => { 34 | setLoading(true) 35 | return firebase 36 | .auth() 37 | .signInWithEmailAndPassword(email, password) 38 | .then((response) => { 39 | handleUser(response.user) 40 | Router.push('/') 41 | }) 42 | .catch((error) => { 43 | setLoading(false) 44 | return error 45 | }) 46 | } 47 | const signout = () => { 48 | Router.push('/') 49 | return firebase 50 | .auth() 51 | .signOut() 52 | .then(() => handleUser(false)) 53 | } 54 | useEffect(() => { 55 | const unsubscribe = firebase.auth().onIdTokenChanged(handleUser) 56 | return () => unsubscribe() 57 | }, []) 58 | return { 59 | user, 60 | loading, 61 | signIn, 62 | signout, 63 | } 64 | } 65 | const formatUser = async (user) => { 66 | return { 67 | id: user.uid, 68 | email: user.email, 69 | token: user.xa, 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/db.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import firebase from './firebase' 3 | import { useAuth } from './auth' 4 | const app = firebase.app() 5 | const firestore = firebase.firestore() 6 | const storageRef = firebase.storage().ref() 7 | 8 | /* -------------------------------------------------------------------------- */ 9 | /* Control Functions */ 10 | /* -------------------------------------------------------------------------- */ 11 | 12 | export const usernameExist = async (username) => { 13 | const query = firestore 14 | .collection('users') 15 | .where('username', '==', username) 16 | 17 | return await query.get().then((users) => { 18 | return users.docs.length ? true : false 19 | }) 20 | } 21 | 22 | export const searchUser = async (searchText) => { 23 | const query = firestore.collection('users') 24 | 25 | return await query.get().then((users) => { 26 | let result = [] 27 | users.docs.forEach((user) => { 28 | const data = user.data() 29 | if ( 30 | searchText.length > 0 && 31 | (data.username 32 | .toLowerCase() 33 | .includes(searchText.toLowerCase()) || 34 | data.name.toLowerCase().includes(searchText.toLowerCase())) 35 | ) { 36 | result.push(data) 37 | } 38 | }) 39 | return result 40 | }) 41 | } 42 | 43 | /* -------------------------------------------------------------------------- */ 44 | /* Insert Functions */ 45 | /* -------------------------------------------------------------------------- */ 46 | 47 | export const signUp = async (email, password, username, name) => { 48 | const isExistUsername = await usernameExist(username.trim()) 49 | if (!isExistUsername) { 50 | return firebase 51 | .auth() 52 | .createUserWithEmailAndPassword(email, password) 53 | .then((res) => { 54 | const user = res.user 55 | const id = user.uid 56 | return firestore.collection('users').doc(id).set({ 57 | username, 58 | email, 59 | name, 60 | createdAt: new Date(), 61 | }) 62 | }) 63 | .catch((error) => { 64 | return error 65 | }) 66 | } else { 67 | return { 68 | message: 69 | 'Bu kullanıcı adı alınamıyor. Lütfen başka bir kullanıcı adı dene.', 70 | } 71 | } 72 | 73 | // return firestore 74 | // .collection('users') 75 | // .doc(uid) 76 | // .set({ uid, ...data }, { merge: true }) 77 | } 78 | 79 | /* -------------------------------------------------------------------------- */ 80 | /* Select Functions */ 81 | /* -------------------------------------------------------------------------- */ 82 | 83 | export const getUserData = async (id) => { 84 | if (!id) { 85 | return false 86 | } 87 | const userData = await firestore 88 | .collection('users') 89 | .doc(id) 90 | .get() 91 | .then((user) => { 92 | return { 93 | id, 94 | ...user.data(), 95 | } 96 | }) 97 | .catch((error) => { 98 | console.log(error.message) 99 | }) 100 | return userData 101 | } 102 | 103 | export const getUserIdFromUsername = (username) => { 104 | return new Promise(async (resolve, reject) => { 105 | if (!username) { 106 | reject(false) 107 | } 108 | const userData = await firestore 109 | .collection('users') 110 | .where('username', '==', username) 111 | .get() 112 | if (userData.docs.length) { 113 | resolve(userData.docs[0].id) 114 | } 115 | reject(false) 116 | }) 117 | } 118 | 119 | /* -------------------------------------------------------------------------- */ 120 | /* Storage Functions */ 121 | /* -------------------------------------------------------------------------- */ 122 | 123 | export const uploadPost = (id, post) => { 124 | storageRef 125 | .child(`posts/${id}/${Date.now()}/${post.file.name}`) 126 | .put(post.file) 127 | .then(async (snapshot) => { 128 | const downloadURL = await snapshot.ref.getDownloadURL() 129 | const filePath = snapshot.ref.fullPath 130 | firestore.collection(`users/${id}/posts`).doc().set({ 131 | caption: post.caption, 132 | image: downloadURL, 133 | imageRef: filePath, 134 | time: post.time, 135 | }) 136 | return true 137 | }) 138 | } 139 | 140 | export const getUserPosts = async (id) => { 141 | const query = firestore 142 | .collection(`users/${id}/posts`) 143 | .orderBy('time', 'desc') 144 | .get() 145 | const posts = await query 146 | 147 | if (!posts.docs.length) { 148 | return [] 149 | } 150 | 151 | let userPosts = [] 152 | for (const post of posts.docs) { 153 | const postData = post.data() 154 | userPosts.push({ 155 | ...postData, 156 | id: post.id, 157 | }) 158 | } 159 | return userPosts 160 | } 161 | 162 | // export function createSite(data) { 163 | // const site = firestore.collection('sites').doc() 164 | // site.set(data) 165 | 166 | // return site 167 | // } 168 | 169 | // export async function deleteSite(id) { 170 | // firestore.collection('sites').doc(id).delete() 171 | // const snapshot = await firestore 172 | // .collection('feedback') 173 | // .where('siteId', '==', id) 174 | // .get() 175 | 176 | // const batch = firestore.batch() 177 | 178 | // snapshot.forEach((doc) => { 179 | // batch.delete(doc.ref) 180 | // }) 181 | 182 | // return batch.commit() 183 | // } 184 | 185 | // export async function updateSite(id, newValues) { 186 | // return firestore.collection('sites').doc(id).update(newValues) 187 | // } 188 | 189 | // export function createFeedback(data) { 190 | // return firestore.collection('feedback').add(data) 191 | // } 192 | 193 | // export function deleteFeedback(id) { 194 | // return firestore.collection('feedback').doc(id).delete() 195 | // } 196 | 197 | // export function updateFeedback(id, newValues) { 198 | // return firestore.collection('feedback').doc(id).update(newValues) 199 | // } 200 | 201 | // export async function createCheckoutSession(uid) { 202 | // const checkoutSessionRef = await firestore 203 | // .collection('users') 204 | // .doc(uid) 205 | // .collection('checkout_sessions') 206 | // .add({ 207 | // price: process.env.NEXT_PUBLIC_PRICE_ID, 208 | // allow_promotion_codes: true, 209 | // success_url: window.location.origin, 210 | // cancel_url: window.location.origin, 211 | // }) 212 | 213 | // checkoutSessionRef.onSnapshot(async (snap) => { 214 | // const { sessionId } = snap.data() 215 | 216 | // if (sessionId) { 217 | // const stripe = await getStripe() 218 | 219 | // stripe.redirectToCheckout({ sessionId }) 220 | // } 221 | // }) 222 | // } 223 | -------------------------------------------------------------------------------- /lib/firebase.js: -------------------------------------------------------------------------------- 1 | import firebase from 'firebase' 2 | import 'firebase/auth' 3 | import 'firebase/functions' 4 | import 'firebase/firestore' 5 | import 'firebase/storage' 6 | 7 | if (!firebase.apps.length) { 8 | firebase.initializeApp({ 9 | apiKey: process.env.FIREBASE_API_KEY, 10 | authDomain: process.env.FIREBASE_AUTH_DOMAIN, 11 | databaseURL: process.env.FIREBASE_DATABASE_URL, 12 | projectId: process.env.FIREBASE_PROJECT_ID, 13 | storageBucket: process.env.FIREBASE_STORAGE_BUCKET, 14 | messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID, 15 | appId: process.env.FIREBASE_APP_ID, 16 | }) 17 | } 18 | 19 | export default firebase 20 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | FIREBASE_API_KEY: 'AIzaSyD7pqsPi5LLq121Y5e4FbkI5RkPFW03bH4', 4 | FIREBASE_AUTH_DOMAIN: 'instagram-clone-45093.firebaseapp.com', 5 | FIREBASE_DATABASE_URL: 6 | 'https://instagram-clone-45093-default-rtdb.firebaseio.com', 7 | FIREBASE_PROJECT_ID: 'instagram-clone-45093', 8 | FIREBASE_STORAGE_BUCKET: 'instagram-clone-45093.appspot.com', 9 | FIREBASE_MESSAGING_SENDER_ID: '820550670430', 10 | FIREBASE_APP_ID: '1:820550670430:web:8aa8ca9925e5ca405bbccf', 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /next.config.template.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | FIREBASE_API_KEY: 'FIREBASE_API_KEY', 4 | FIREBASE_AUTH_DOMAIN: 'FIREBASE_AUTH_DOMAIN', 5 | FIREBASE_DATABASE_URL: 'FIREBASE_DATABASE_URL', 6 | FIREBASE_PROJECT_ID: 'FIREBASE_PROJECT_ID', 7 | FIREBASE_STORAGE_BUCKET: 'FIREBASE_STORAGE_BUCKET', 8 | FIREBASE_MESSAGING_SENDER_ID: 'FIREBASE_MESSAGING_SENDER_ID', 9 | FIREBASE_APP_ID: 'FIREBASE_APP_ID', 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-instragram-clone-test", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "svgtocomponent": "npx @svgr/cli -d icons svgs --icon --replace-attr-values #262626=currentColor" 10 | }, 11 | "dependencies": { 12 | "classnames": "^2.2.6", 13 | "firebase": "^8.2.1", 14 | "js-cookie": "^2.2.1", 15 | "next": "10.0.4", 16 | "react": "17.0.1", 17 | "react-dom": "17.0.1", 18 | "react-spinners": "^0.10.4", 19 | "react-timeago": "^5.2.0" 20 | }, 21 | "devDependencies": { 22 | "sass": "^1.32.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pages/404.js: -------------------------------------------------------------------------------- 1 | import NotFoundScreen from '../components/NotFoundScreen' 2 | 3 | export default function NotFoundPage() { 4 | return 5 | } 6 | -------------------------------------------------------------------------------- /pages/[username]/[[...index]].js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Profile from '../../components/Profile' 3 | import NotFoundScreen from '../../components/NotFoundScreen' 4 | import { useAuth } from '../../lib/auth' 5 | import { useRouter } from 'next/router' 6 | import Loader from '../../components/Loader' 7 | import { usernameExist } from '../../lib/db' 8 | 9 | const ProfilePage = () => { 10 | const router = useRouter() 11 | const { user, loading } = useAuth() 12 | const [isUserExist, setIsUserExist] = React.useState(false) 13 | 14 | const [userExistLoad, setUserExistLoad] = React.useState(true) 15 | 16 | React.useEffect(async () => { 17 | if (typeof router.query.username != 'undefined') { 18 | const query = await usernameExist(router.query.username) 19 | query ? setIsUserExist(true) : setIsUserExist(false) 20 | setUserExistLoad(false) 21 | } 22 | }, [router.query.username]) 23 | 24 | if (loading || userExistLoad) { 25 | return 26 | } else { 27 | if (!isUserExist || !user) { 28 | return 29 | } else { 30 | return 31 | } 32 | } 33 | } 34 | export default ProfilePage 35 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import '../styles/globals.scss' 2 | import AppHeader from '../components/AppHeader' 3 | import Head from 'next/head' 4 | import Container from '../components/Container' 5 | import { AuthProvider } from '../lib/auth' 6 | export default function Instagram({ Component, pageProps }) { 7 | return ( 8 | 9 | 10 | 11 | 15 | Instagram Clone App 16 | 17 | 18 | 19 | 20 | 21 | ) 22 | } 23 | -------------------------------------------------------------------------------- /pages/accounts/emailsignup.js: -------------------------------------------------------------------------------- 1 | import SignUpScreen from '../../components/SignUpScreen' 2 | import { useAuth } from '../../lib/auth' 3 | import Router from 'next/router' 4 | 5 | export default function SignUp() { 6 | const { user } = useAuth() 7 | if (user) { 8 | Router.push('/') 9 | } 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default (req, res) => { 4 | res.statusCode = 200 5 | res.json({ name: 'John Doe' }) 6 | } 7 | -------------------------------------------------------------------------------- /pages/direct/[[...index]].js: -------------------------------------------------------------------------------- 1 | import InboxScreen from '../../components/InboxScreen' 2 | import Loader from '../../components/Loader' 3 | import { useAuth } from '../../lib/auth' 4 | import { useRouter } from 'next/router' 5 | 6 | export default function direct() { 7 | const router = useRouter() 8 | const { user, loading } = useAuth() 9 | 10 | if (loading) { 11 | return 12 | } else { 13 | if (!user) { 14 | router.push('/') 15 | return <> 16 | } else { 17 | return 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import HomeLayout from '../components/HomeLayout' 2 | import SignInScreen from '../components/SignInScreen' 3 | import { useAuth } from '../lib/auth' 4 | import Loader from '../components/Loader' 5 | 6 | const Home = () => { 7 | const { user, loading } = useAuth() 8 | 9 | return ( 10 | <> 11 | {user ? : } 12 | {loading ? : ''} 13 | 14 | ) 15 | } 16 | export default Home 17 | -------------------------------------------------------------------------------- /public/betul.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/betul.jpg -------------------------------------------------------------------------------- /public/bill.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/bill.jpg -------------------------------------------------------------------------------- /public/elon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/elon.jpg -------------------------------------------------------------------------------- /public/erkan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/erkan.jpg -------------------------------------------------------------------------------- /public/erkan2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/erkan2.jpg -------------------------------------------------------------------------------- /public/facebook-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/facebook-logo.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/favicon.ico -------------------------------------------------------------------------------- /public/hasan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/hasan.jpg -------------------------------------------------------------------------------- /public/instagram-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/instagram-dark.png -------------------------------------------------------------------------------- /public/instagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/instagram.png -------------------------------------------------------------------------------- /public/ivana.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/ivana.jpg -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Instagram", 4 | // "icons": [ 5 | // { 6 | // "src": "favicon.ico", 7 | // "sizes": "64x64 32x32 24x24 16x16", 8 | // "type": "image/x-icon" 9 | // }, 10 | // { 11 | // "src": "logo192.png", 12 | // "type": "image/png", 13 | // "sizes": "192x192" 14 | // }, 15 | // { 16 | // "src": "logo512.png", 17 | // "type": "image/png", 18 | // "sizes": "512x512" 19 | // } 20 | // ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/mustafa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/mustafa.jpg -------------------------------------------------------------------------------- /public/owuzan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan.jpg -------------------------------------------------------------------------------- /public/owuzan/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/1.jpg -------------------------------------------------------------------------------- /public/owuzan/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/10.jpg -------------------------------------------------------------------------------- /public/owuzan/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/11.jpg -------------------------------------------------------------------------------- /public/owuzan/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/2.jpg -------------------------------------------------------------------------------- /public/owuzan/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/3.jpg -------------------------------------------------------------------------------- /public/owuzan/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/4.jpg -------------------------------------------------------------------------------- /public/owuzan/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/5.jpg -------------------------------------------------------------------------------- /public/owuzan/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/6.jpg -------------------------------------------------------------------------------- /public/owuzan/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/7.jpg -------------------------------------------------------------------------------- /public/owuzan/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/8.jpg -------------------------------------------------------------------------------- /public/owuzan/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/owuzan/9.jpg -------------------------------------------------------------------------------- /public/photo-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/photo-example.jpg -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/ronaldo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/ronaldo.jpg -------------------------------------------------------------------------------- /public/serdar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/serdar.jpg -------------------------------------------------------------------------------- /public/sign-up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/sign-up.png -------------------------------------------------------------------------------- /public/suleyman-example.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/suleyman-example.jpg -------------------------------------------------------------------------------- /public/suleyman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/suleyman.jpg -------------------------------------------------------------------------------- /public/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owuzan/next-instagram-clone/bfe0eee5c9d737a4bffff4ed9aef8dbbd3952434/public/user.jpg -------------------------------------------------------------------------------- /styles/globals.scss: -------------------------------------------------------------------------------- 1 | *, 2 | *::before, 3 | *::after { 4 | box-sizing: border-box; 5 | margin: 0; 6 | padding: 0; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | :root { 11 | --white: #ffffff; 12 | --background-color: #fafafa; 13 | --input-background: #fafafa; 14 | --border-color: #dbdbdb; 15 | --border-light-color: #efefef; 16 | --muted-text: #8e8e8e; 17 | --text: #262626; 18 | --blue: #0095f6; 19 | --tag-blue: #00376b; 20 | --black: #000000; 21 | --red: #ed4956; 22 | --button-text: var(--white); 23 | --other-message-background: var(--white); 24 | } 25 | html, 26 | body { 27 | height: 100%; 28 | background-color: var(--background-color); 29 | } 30 | body { 31 | #__next { 32 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; 33 | color: var(--text); 34 | min-height: 100vh; 35 | @media (max-width: 599.98px) { 36 | padding-bottom: 50px; 37 | padding-top: 50px; 38 | background-color: var(--white); 39 | } 40 | } 41 | #__next.dark { 42 | --white: #0c0c0c; 43 | --red: #ed4956; 44 | --background-color: #000000; 45 | --text: #fafafa; 46 | --muted-text: #989898; 47 | --other-message-background: #262626; 48 | --blue: #0095f6; 49 | --tag-blue: var(--blue); 50 | 51 | --border-color: #1d1d1d; 52 | --border-light-color: #131313; 53 | --input-background: #080808; 54 | 55 | --black: #ffffff; 56 | 57 | .contact-list .contact:hover:not(.active-contact) { 58 | background-color: #101010 !important; 59 | } 60 | } 61 | } 62 | .container { 63 | max-width: 940px; 64 | width: 100%; 65 | display: block; 66 | margin-left: auto; 67 | margin-right: auto; 68 | } 69 | button { 70 | font-family: inherit; 71 | white-space: nowrap; 72 | } 73 | .overflow-auto { 74 | overflow: auto !important; 75 | } 76 | -------------------------------------------------------------------------------- /svgs/AddPost.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /svgs/Back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /svgs/Bookmark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgs/BookmarkFill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgs/Camera.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/Close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /svgs/Comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/Emoji.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/Explore.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/ExploreFill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/Home.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgs/HomeFill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgs/Info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /svgs/Like.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgs/LikeFill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/Loader.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /svgs/Message.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgs/MessageFill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /svgs/NewMessage.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /svgs/Options.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/Photo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /svgs/Posts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /svgs/Preferences.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /svgs/Search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /svgs/Tagged.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /svgs/User.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /utility/follow.js: -------------------------------------------------------------------------------- 1 | import firebase from '../lib/firebase' 2 | 3 | const follow = (authId, userId) => { 4 | const firestore = firebase.firestore() 5 | firestore.collection(`users/${authId}/followings`).doc(userId).set({ 6 | time: new Date(), 7 | }) 8 | firestore.collection(`users/${userId}/followers`).doc(authId).set({ 9 | time: new Date(), 10 | }) 11 | } 12 | 13 | export default follow 14 | -------------------------------------------------------------------------------- /utility/isFollowing.js: -------------------------------------------------------------------------------- 1 | import firebase from '../lib/firebase' 2 | 3 | const isFollowing = async (authId, userId) => { 4 | const firestore = firebase.firestore() 5 | return await firestore 6 | .doc(`users/${authId}/followings/${userId}`) 7 | .get() 8 | .then((res) => res.exists) 9 | } 10 | 11 | export default isFollowing 12 | -------------------------------------------------------------------------------- /utility/linkedText.js: -------------------------------------------------------------------------------- 1 | import Link from 'next/link' 2 | 3 | export default function linkedText(text) { 4 | // FIXME En sona link eklendiği zaman başka karakter olmazsa çalışmıyor. 5 | 6 | const words = text.split(' ') 7 | let list = words.map((word, index) => { 8 | if (word.slice(0, 1) === '@') { 9 | return ( 10 | 11 | {word} 12 | 13 | ) 14 | } 15 | if (word.slice(0, 1) === '#') { 16 | return ( 17 | 18 | {word} 19 | 20 | ) 21 | } 22 | return word 23 | }) 24 | let temp = [] 25 | let final = [] 26 | let itemType = null 27 | const content = list.map((item, index) => { 28 | if (typeof item === 'object') { 29 | temp.length > 0 ? final.push(temp.join(' ') + ' ') : '' 30 | final.push(item) 31 | temp = [] 32 | itemType = 'object' 33 | } else { 34 | if (index == 0) { 35 | temp.push(item) 36 | } else { 37 | temp.push(' ' + item) 38 | } 39 | itemType = 'string' 40 | } 41 | if (list.length - 1 === index && itemType === 'string') { 42 | final.push(' ' + temp.join(' ')) 43 | return final 44 | } 45 | }) 46 | return content 47 | } 48 | -------------------------------------------------------------------------------- /utility/sendMessage.js: -------------------------------------------------------------------------------- 1 | import firebase from '../lib/firebase' 2 | 3 | const sendMessage = (authId, userId, message) => { 4 | const firestore = firebase.firestore() 5 | 6 | const time = new Date() 7 | // From 8 | firestore 9 | .collection(`users/${authId}/contacts/${userId}/messages`) 10 | .doc() 11 | .set({ 12 | me: true, 13 | message, 14 | seen: false, 15 | time, 16 | liked: false, 17 | }) 18 | .catch((error) => { 19 | console.log(error.message) 20 | return false 21 | }) 22 | firestore 23 | .collection(`users/${authId}/contacts`) 24 | .doc(userId) 25 | .set({ 26 | me: true, 27 | message, 28 | seen: false, 29 | time, 30 | liked: false, 31 | }) 32 | .catch((error) => { 33 | console.log(error.message) 34 | return false 35 | }) 36 | 37 | // To 38 | firestore 39 | .collection(`users/${userId}/contacts/${authId}/messages`) 40 | .doc() 41 | .set({ 42 | me: false, 43 | message, 44 | seen: false, 45 | time, 46 | liked: false, 47 | }) 48 | .catch((error) => { 49 | console.log(error.message) 50 | return false 51 | }) 52 | firestore 53 | .collection(`users/${userId}/contacts`) 54 | .doc(authId) 55 | .set({ 56 | me: false, 57 | message, 58 | seen: false, 59 | time, 60 | liked: false, 61 | }) 62 | .catch((error) => { 63 | console.log(error.message) 64 | return false 65 | }) 66 | 67 | return true 68 | } 69 | 70 | export default sendMessage 71 | -------------------------------------------------------------------------------- /utility/unfollow.js: -------------------------------------------------------------------------------- 1 | import firebase from '../lib/firebase' 2 | 3 | const unfollow = (authId, userId) => { 4 | const firestore = firebase.firestore() 5 | firestore.collection(`users/${authId}/followings`).doc(userId).delete() 6 | firestore.collection(`users/${userId}/followers`).doc(authId).delete() 7 | } 8 | 9 | export default unfollow 10 | --------------------------------------------------------------------------------