base on Twitter clone built in Next.js + TypeScript + Tailwind CSS using Cloud Firestore and Storage <br /> ![](/.github/assets/presentation.png) <p align="center"> Twitter clone built in Next.js + TypeScript + Tailwind CSS using Cloud Firestore and Storage </p> ## Preview 🎬 https://user-images.githubusercontent.com/55032197/201472767-9db0177a-79b5-4913-8666-1744102b0ad7.mp4 ## Features ✨ - Authentication with Firebase Authentication - Strongly typed React components with TypeScript - Users can add tweets, like, retweet, and reply - Users can delete tweets, add a tweet to bookmarks, and pin their tweet - Users can add images and GIFs to tweet - Users can follow and unfollow other users - Users can see their and other followers and the following list - Users can see all users and the trending list - Realtime update likes, retweets, and user profile - Realtime trending data from Twitter API - User can edit their profile - Responsive design for mobile, tablet, and desktop - Users can customize the site color scheme and color background - All images uploads are stored on Firebase Cloud Storage ## Tech 🛠 - [Next.js](https://nextjs.org) - [TypeScript](https://www.typescriptlang.org) - [Tailwind CSS](https://tailwindcss.com) - [Firebase](https://firebase.google.com) - [SWR](https://swr.vercel.app) - [Headless UI](https://headlessui.com) - [React Hot Toast](https://react-hot-toast.com) - [Framer Motion](https://framer.com) ## Development 💻 Here are the steps to run the project locally. 1. Clone the repository ```bash git clone https://github.com/ccrsxx/twitter-clone.git ``` 1. Install dependencies ```bash npm i ``` 1. Create a Firebase project and select the web app 1. Add your Firebase config to `.env.development`. Note that `NEXT_PUBLIC_MEASUREMENT_ID` is optional 1. Make sure you have enabled the following Firebase services: - Authentication. Enable the Google sign-in method. - Cloud Firestore. Create a database and set its location to your nearest region. - Cloud Storage. Create a storage bucket. 1. Install Firebase CLI globally ```bash npm i -g firebase-tools ``` 1. Log in to Firebase ```bash firebase login ``` 1. Get your project ID ```bash firebase projects:list ``` 1. Select your project ID ```bash firebase use your-project-id ``` 1. At this point, you have two choices. Either run this project using the Firebase on the cloud or locally using emulator. 1. Using the Firebase Cloud Backend: 1. Deploy Firestore rules, Firestore indexes, and Cloud Storage rules ```bash firebase deploy --except functions ``` 1. Run the project ```bash npm run dev ``` 1. Using Firebase Local Emulator: 1. Install [Java JDK version 11 or higher](https://jdk.java.net/) before proceeding. This is required to run the emulators. 1. Set the environment variable `NEXT_PUBLIC_USE_EMULATOR` to `true` in `.env.development`. This will make the app use the emulators instead of the cloud backend. 1. At this point, you can run the following command to have a fully functional Twitter clone running locally: ```bash npm run dev:emulators ``` > **_Note_**: When you deploy Firestore indexes rules, it might take a few minutes to complete. So before the indexes are enabled, you will get an error when you fetch the data from Firestore.<br><br>You can check the status of your Firestore indexes with the link below, replace `your-project-id` with your project ID: https://console.firebase.google.com/u/0/project/your-project-id/firestore/indexes Optional: - If you want to get trending data from Twitter API, you need to create a Twitter developer account and get your API keys. Then add your API keys to `.env.development`. I hope Elon Musk doesn't make this API paid 😅. - If you want to make the user stats synced with the deleted tweets, you need to enable the Cloud Functions for Firebase. Then deploy the Cloud Functions. ", Assign "at most 3 tags" to the expected json: {"id":"2239","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"