├── nextbranches.md ├── app ├── favicon.ico ├── (auth) │ ├── sign-in │ │ └── page.tsx │ ├── sign-up │ │ └── page.tsx │ └── layout.tsx ├── (root) │ ├── posts │ │ └── [id] │ │ │ └── page.tsx │ ├── profile │ │ └── [id] │ │ │ ├── page.tsx │ │ │ ├── followers │ │ │ └── page.tsx │ │ │ └── following │ │ │ └── page.tsx │ ├── layout.tsx │ ├── (home) │ │ └── page.tsx │ ├── create-post │ │ └── page.tsx │ ├── edit-profile │ │ └── [id] │ │ │ └── page.tsx │ ├── edit-post │ │ └── [id] │ │ │ └── page.tsx │ ├── community │ │ └── page.tsx │ ├── collection │ │ └── page.tsx │ └── explore │ │ └── page.tsx └── layout.tsx ├── postcss.config.js ├── public ├── assets │ ├── icons │ │ ├── magnify.png │ │ ├── arrow.svg │ │ ├── liked.svg │ │ ├── jsm-arrow.svg │ │ ├── search.svg │ │ ├── search-colored.svg │ │ ├── loader.svg │ │ ├── add-square.svg │ │ ├── saved.svg │ │ ├── filter.svg │ │ ├── profile-placeholder.svg │ │ ├── posts.svg │ │ ├── error.svg │ │ ├── google.svg │ │ ├── like.svg │ │ ├── follow.svg │ │ ├── chat.svg │ │ ├── back.svg │ │ ├── share.svg │ │ ├── people.svg │ │ ├── home.svg │ │ ├── gallery-add.svg │ │ ├── add-post.svg │ │ ├── bookmark.svg │ │ ├── save.svg │ │ ├── delete.svg │ │ ├── edit.svg │ │ ├── file-upload.svg │ │ ├── logout.svg │ │ └── wallpaper.svg │ └── images │ │ ├── profile.png │ │ ├── ladunjexa.jpeg │ │ ├── site-logo.png │ │ ├── logo-colored.png │ │ ├── avatar-circle.svg │ │ └── logo-black.svg ├── vercel.svg └── next.svg ├── .eslintrc.json ├── components ├── shared │ ├── atoms │ │ ├── Loader.tsx │ │ └── Alert.tsx │ ├── layout │ │ ├── Bottombar.tsx │ │ ├── RightSidebar.tsx │ │ ├── Topbar.tsx │ │ └── LeftSidebar.tsx │ ├── Story.tsx │ ├── GridPostList.tsx │ ├── search │ │ ├── LocalSearchbar.tsx │ │ └── LocalResult.tsx │ ├── FileUploader.tsx │ └── PostStats.tsx ├── scenes │ ├── AllStories.tsx │ ├── AllUsers.tsx │ ├── SavedPosts.tsx │ ├── RecentPosts.tsx │ ├── Follows.tsx │ ├── Post.tsx │ └── Profile.tsx ├── ui │ ├── label.tsx │ ├── textarea.tsx │ ├── input.tsx │ ├── toaster.tsx │ ├── button.tsx │ ├── tabs.tsx │ ├── dialog.tsx │ ├── use-toast.ts │ ├── form.tsx │ └── toast.tsx ├── cards │ ├── FollowCard.tsx │ ├── PostCard.tsx │ └── UserCard.tsx └── forms │ ├── Post.tsx │ ├── Profile.tsx │ └── Auth.tsx ├── .vscode └── settings.json ├── components.json ├── .prettierrc ├── appwrite ├── conf │ └── index.ts ├── client.ts ├── actions │ ├── save.action.ts │ ├── user.action.ts │ └── post.action.ts └── env.ts ├── next.config.js ├── .gitignore ├── lib ├── react-query │ ├── Provider.tsx │ ├── QueryKeys.ts │ ├── queries │ │ ├── user.query.ts │ │ └── post.query.ts │ └── mutations │ │ ├── save.mutation.ts │ │ ├── post.mutation.ts │ │ └── user.mutation.ts ├── validations │ └── index.ts └── utils.ts ├── tsconfig.json ├── hooks └── useDebounce.ts ├── LICENSE ├── constants └── index.ts ├── types └── index.d.ts ├── package.json ├── tailwind.config.ts └── context └── AuthContext.tsx /nextbranches.md: -------------------------------------------------------------------------------- 1 | 028_loading 029_toast_notifications 030_seo_metadata 031_playground 2 | -------------------------------------------------------------------------------- /app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladunjexa/nextjs14-snapshot/HEAD/app/favicon.ico -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/assets/icons/magnify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladunjexa/nextjs14-snapshot/HEAD/public/assets/icons/magnify.png -------------------------------------------------------------------------------- /public/assets/images/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladunjexa/nextjs14-snapshot/HEAD/public/assets/images/profile.png -------------------------------------------------------------------------------- /public/assets/images/ladunjexa.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladunjexa/nextjs14-snapshot/HEAD/public/assets/images/ladunjexa.jpeg -------------------------------------------------------------------------------- /public/assets/images/site-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladunjexa/nextjs14-snapshot/HEAD/public/assets/images/site-logo.png -------------------------------------------------------------------------------- /public/assets/images/logo-colored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ladunjexa/nextjs14-snapshot/HEAD/public/assets/images/logo-colored.png -------------------------------------------------------------------------------- /app/(auth)/sign-in/page.tsx: -------------------------------------------------------------------------------- 1 | import Auth from '@/components/forms/Auth'; 2 | 3 | export default function Page() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /app/(auth)/sign-up/page.tsx: -------------------------------------------------------------------------------- 1 | import Auth from '@/components/forms/Auth'; 2 | 3 | export default function Page() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "standard", "plugin:tailwindcss/recommended", "prettier"], 3 | "ignorePatterns": ["/components/ui/*"] 4 | } 5 | -------------------------------------------------------------------------------- /public/assets/icons/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /components/shared/atoms/Loader.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | 3 | const Loader = ({otherClasses}: {otherClasses?: string}) => { 4 | return ( 5 |
6 | loader 7 |
8 | ); 9 | }; 10 | 11 | export default Loader; 12 | -------------------------------------------------------------------------------- /app/(root)/posts/[id]/page.tsx: -------------------------------------------------------------------------------- 1 | import Post from '@/components/scenes/Post'; 2 | 3 | import type {Metadata} from 'next'; 4 | 5 | export const metadata: Metadata = { 6 | title: 'Posts — SnapShot', 7 | }; 8 | 9 | type Props = { 10 | params: {id: string}; 11 | }; 12 | 13 | export default function Page({params}: Props) { 14 | return ; 15 | } 16 | -------------------------------------------------------------------------------- /app/(root)/profile/[id]/page.tsx: -------------------------------------------------------------------------------- 1 | import Profile from '@/components/scenes/Profile'; 2 | 3 | import type {Metadata} from 'next'; 4 | 5 | export const metadata: Metadata = { 6 | title: 'Profile — SnapShot', 7 | }; 8 | 9 | type Props = { 10 | params: {id: string}; 11 | }; 12 | 13 | export default function Page({params}: Props) { 14 | return ; 15 | } 16 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.eslint": true, 6 | "source.addMissingImports": true 7 | }, 8 | "[typescriptreact]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "svg.preview.background": "dark-transparent" 12 | } 13 | -------------------------------------------------------------------------------- /components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "app/globals.css", 9 | "baseColor": "slate", 10 | "cssVariables": true 11 | }, 12 | "aliases": { 13 | "components": "@/components", 14 | "utils": "@/lib/utils" 15 | } 16 | } -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/prettierrc", 3 | "arrowParens": "avoid", 4 | "bracketSpacing": false, 5 | "jsxBracketSameLine": false, 6 | "jsxSingleQuote": false, 7 | "printWidth": 100, 8 | "proseWrap": "always", 9 | "quoteProps": "as-needed", 10 | "semi": true, 11 | "singleQuote": true, 12 | "tabWidth": 2, 13 | "trailingComma": "es5", 14 | "useTabs": false 15 | } 16 | -------------------------------------------------------------------------------- /app/(root)/profile/[id]/followers/page.tsx: -------------------------------------------------------------------------------- 1 | import Follows from '@/components/scenes/Follows'; 2 | 3 | import type {Metadata} from 'next'; 4 | 5 | export const metadata: Metadata = { 6 | title: 'Followers — SnapShot', 7 | }; 8 | 9 | type Props = { 10 | params: {id: string}; 11 | }; 12 | 13 | export default function Page({params}: Props) { 14 | return ; 15 | } 16 | -------------------------------------------------------------------------------- /app/(root)/profile/[id]/following/page.tsx: -------------------------------------------------------------------------------- 1 | import Follows from '@/components/scenes/Follows'; 2 | 3 | import type {Metadata} from 'next'; 4 | 5 | export const metadata: Metadata = { 6 | title: 'Following — SnapShot', 7 | }; 8 | 9 | type Props = { 10 | params: {id: string}; 11 | }; 12 | 13 | export default function Page({params}: Props) { 14 | return ; 15 | } 16 | -------------------------------------------------------------------------------- /appwrite/conf/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | url, 3 | projectId, 4 | databaseId, 5 | storageId, 6 | userCollectionId, 7 | postCollectionId, 8 | saveCollectionId, 9 | } from '@/appwrite/env'; 10 | 11 | const appwriteConfig = { 12 | url, 13 | projectId, 14 | databaseId, 15 | storageId, 16 | userCollectionId, 17 | postCollectionId, 18 | saveCollectionId, 19 | }; 20 | 21 | export default appwriteConfig; 22 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | images: { 4 | remotePatterns: [ 5 | { 6 | protocol: 'https', 7 | hostname: 'cloud.appwrite.io', 8 | }, 9 | { 10 | protocol: 'http', 11 | hostname: 'cloud.appwrite.io', 12 | }, 13 | ], 14 | unoptimized: true, 15 | }, 16 | }; 17 | 18 | module.exports = nextConfig; 19 | -------------------------------------------------------------------------------- /public/assets/icons/liked.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /appwrite/client.ts: -------------------------------------------------------------------------------- 1 | import {Client, Account, Databases, Storage, Avatars} from 'appwrite'; 2 | 3 | import appwriteConfig from '@/appwrite/conf'; 4 | 5 | export const client = new Client(); 6 | 7 | client.setEndpoint(appwriteConfig.url).setProject(appwriteConfig.projectId); 8 | 9 | export const account = new Account(client); 10 | export const database = new Databases(client); 11 | export const storage = new Storage(client); 12 | export const avatars = new Avatars(client); 13 | export {ID} from 'appwrite'; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /public/assets/icons/jsm-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /public/assets/images/avatar-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/react-query/Provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import React, {useState} from 'react'; 4 | 5 | import {QueryClientProvider, QueryClient} from '@tanstack/react-query'; 6 | import {ReactQueryDevtools} from '@tanstack/react-query-devtools'; 7 | 8 | const showDevtools: boolean = true; 9 | 10 | export default function Provider({children}: {children: React.ReactNode}) { 11 | const [queryClient] = useState(() => new QueryClient()); 12 | 13 | return ( 14 | 15 | {showDevtools && } 16 | {children} 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /app/(root)/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import Bottombar from '@/components/shared/layout/Bottombar'; 4 | import LeftSidebar from '@/components/shared/layout/LeftSidebar'; 5 | import RightSidebar from '@/components/shared/layout/RightSidebar'; 6 | import Topbar from '@/components/shared/layout/Topbar'; 7 | 8 | export default function Layout({children}: {children: React.ReactNode}) { 9 | return ( 10 |
11 | 12 | 13 | 14 |
{children}
15 | 16 | 17 | 18 |
19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /lib/react-query/QueryKeys.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | 3 | enum QUERY_KEYS { 4 | // AUTH KEYS 5 | CREATE_USER_ACCOUNT = 'createUserAccount', 6 | 7 | // USER KEYS 8 | GET_CURRENT_USER = 'getCurrentUser', 9 | GET_USERS = 'getUsers', 10 | GET_USER_BY_ID = 'getUserById', 11 | 12 | // POST KEYS 13 | GET_POSTS = 'getPosts', 14 | GET_INFINITE_POSTS = 'getInfinitePosts', 15 | GET_RECENT_POSTS = 'getRecentPosts', 16 | GET_POST_BY_ID = 'getPostById', 17 | GET_USER_POSTS = 'getUserPosts', 18 | GET_FILE_PREVIEW = 'getFilePreview', 19 | 20 | // SEARCH KEYS 21 | SEARCH_POSTS = 'getSearchPosts', 22 | } 23 | 24 | export default QUERY_KEYS; 25 | -------------------------------------------------------------------------------- /app/(root)/(home)/page.tsx: -------------------------------------------------------------------------------- 1 | // import AllStories from '@/components/scenes/AllStories'; 2 | import RecentPosts from '@/components/scenes/RecentPosts'; 3 | 4 | import type {Metadata} from 'next'; 5 | 6 | export const metadata: Metadata = { 7 | title: 'Home — SnapShot', 8 | }; 9 | 10 | export default function Home() { 11 | return ( 12 |
13 |
14 |
15 | {/* */} 16 | 17 |

Feed

18 | 19 | 20 |
21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /app/(auth)/layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Image from 'next/image'; 3 | 4 | import type {Metadata} from 'next'; 5 | 6 | export const metadata: Metadata = { 7 | title: 'Auth — SnapShot', 8 | }; 9 | 10 | export default function Layout({children}: {children: React.ReactNode}) { 11 | return ( 12 | <> 13 |
{children}
14 | 15 | logo 22 | 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /public/assets/icons/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/icons/search-colored.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/assets/icons/loader.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "noEmit": true, 9 | "esModuleInterop": true, 10 | "module": "esnext", 11 | "moduleResolution": "bundler", 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "incremental": true, 16 | "plugins": [ 17 | { 18 | "name": "next" 19 | } 20 | ], 21 | "paths": { 22 | "@/*": ["./*"] 23 | } 24 | }, 25 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 26 | "exclude": ["node_modules"] 27 | } 28 | -------------------------------------------------------------------------------- /components/scenes/AllStories.tsx: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import Image from 'next/image'; 4 | 5 | import Story from '@/components/shared/Story'; 6 | 7 | const AllStories = () => { 8 | return ( 9 |
10 | 11 | {...Array(5).fill()} 12 |
13 | 19 |
20 |
21 | ); 22 | }; 23 | 24 | export default AllStories; 25 | -------------------------------------------------------------------------------- /app/(root)/create-post/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | 3 | import Post from '@/components/forms/Post'; 4 | 5 | import type {Metadata} from 'next'; 6 | 7 | export const metadata: Metadata = { 8 | title: 'Create Post — SnapShot', 9 | }; 10 | 11 | export default function Page() { 12 | return ( 13 |
14 |
15 |
16 | add 17 |

Create Post

18 |
19 | 20 | 21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /app/(root)/edit-profile/[id]/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | 3 | import Profile from '@/components/forms/Profile'; 4 | 5 | import type {Metadata} from 'next'; 6 | 7 | export const metadata: Metadata = { 8 | title: 'Edit Post — SnapShot', 9 | }; 10 | 11 | type Props = { 12 | params: {id: string}; 13 | }; 14 | 15 | export default function Page({params}: Props) { 16 | return ( 17 |
18 |
19 |
20 | add 21 |

Edit Profile

22 |
23 | 24 |
25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /app/(root)/edit-post/[id]/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | 3 | import Post from '@/components/forms/Post'; 4 | 5 | import type {Metadata} from 'next'; 6 | 7 | export const metadata: Metadata = { 8 | title: 'Edit Post — SnapShot', 9 | }; 10 | 11 | type Props = { 12 | params: {id: string}; 13 | }; 14 | 15 | export default function Page({params}: Props) { 16 | return ( 17 |
18 |
19 |
20 | add 21 |

Edit Post

22 |
23 | 24 | 25 |
26 |
27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client" 2 | 3 | import * as React from "react" 4 | import * as LabelPrimitive from "@radix-ui/react-label" 5 | import { cva, type VariantProps } from "class-variance-authority" 6 | 7 | import { cn } from "@/lib/utils" 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" 11 | ) 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )) 24 | Label.displayName = LabelPrimitive.Root.displayName 25 | 26 | export { Label } 27 | -------------------------------------------------------------------------------- /app/(root)/community/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | 3 | import AllUsers from '@/components/scenes/AllUsers'; 4 | 5 | import type {Metadata} from 'next'; 6 | 7 | export const metadata: Metadata = { 8 | title: 'Community — SnapShot', 9 | }; 10 | 11 | export default function Page() { 12 | return ( 13 |
14 |
15 |
16 | add 23 |

All Users

24 |
25 | 26 | 27 |
28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /app/(root)/collection/page.tsx: -------------------------------------------------------------------------------- 1 | import Image from 'next/image'; 2 | 3 | import SavedPosts from '@/components/scenes/SavedPosts'; 4 | 5 | import type {Metadata} from 'next'; 6 | 7 | export const metadata: Metadata = { 8 | title: 'Collection — SnapShot', 9 | }; 10 | 11 | export default function Page() { 12 | return ( 13 |
14 |
15 |
16 | add 23 |

Saved Posts

24 |
25 | 26 | 27 |
28 |
29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "@/lib/utils" 4 | 5 | export interface TextareaProps 6 | extends React.TextareaHTMLAttributes {} 7 | 8 | const Textarea = React.forwardRef( 9 | ({ className, ...props }, ref) => { 10 | return ( 11 |