{"id":21486037,"url":"https://github.com/felipecastrosales/ui-twitter","last_synced_at":"2026-04-12T09:44:00.797Z","repository":{"id":255103649,"uuid":"848543836","full_name":"felipecastrosales/ui-twitter","owner":"felipecastrosales","description":"UI Twtter - Masterclass React with Rocketseat","archived":false,"fork":false,"pushed_at":"2024-09-28T13:38:11.000Z","size":40,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-17T10:11:19.102Z","etag":null,"topics":["clone","clone-website","phosphoricons","react","react-hooks","react-router","react-router-dom","reactjs","twitter","twitter-clone","ui","uiclone"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/felipecastrosales.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-28T00:39:07.000Z","updated_at":"2024-09-28T13:40:27.000Z","dependencies_parsed_at":"2024-09-15T06:48:07.910Z","dependency_job_id":"7fe3537d-6d28-4207-9557-0d19e914bf90","html_url":"https://github.com/felipecastrosales/ui-twitter","commit_stats":null,"previous_names":["felipecastrosales/ui-twitter"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/felipecastrosales/ui-twitter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecastrosales%2Fui-twitter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecastrosales%2Fui-twitter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecastrosales%2Fui-twitter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecastrosales%2Fui-twitter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/felipecastrosales","download_url":"https://codeload.github.com/felipecastrosales/ui-twitter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felipecastrosales%2Fui-twitter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264916028,"owners_count":23682957,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clone","clone-website","phosphoricons","react","react-hooks","react-router","react-router-dom","reactjs","twitter","twitter-clone","ui","uiclone"],"created_at":"2024-11-23T13:18:43.696Z","updated_at":"2026-04-12T09:43:55.737Z","avatar_url":"https://github.com/felipecastrosales.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Twitter UI Clone\n\nThis project is a Twitter UI clone built with React, TypeScript, and Vite. It aims to replicate some of the core features and design elements of Twitter's user interface.\n\n# Figma Design\nYou can view the design layout for this project on Figma:\n\n[Twitter UI Clone - Figma Design](https://www.figma.com/community/file/1202694130789327431)\n\n## Features\n\n- Home timeline\n- Tweet composition\n- Tweet display\n- Responsive design\n\n## Technologies Used\n\n- React 18.3.1\n- TypeScript\n- Vite\n- React Router\n- Phosphor Icons\n\n## Project Structure\n\nThe project follows a standard React application structure:\n\n- `src/`: Contains the main source code\n  - `components/`: Reusable React components\n  - `pages/`: Main page components\n  - `layouts/`: Layout components\n  - `assets/`: Static assets like images\n  - `global.css`: Global styles\n\n## Getting Started\n\n1. Clone the repository\n2. Install dependencies:\n   ```\n   npm install\n   ```\n3. Run the development server:\n   ```\n   npm run dev\n   ```\n\n## Available Scripts\n\n\n```6:11:package.json\n  \"scripts\": {\n    \"dev\": \"vite\",\n    \"build\": \"tsc -b \u0026\u0026 vite build\",\n    \"lint\": \"eslint .\",\n    \"preview\": \"vite preview\"\n  },\n```\n\n- `dev`: Runs the app in development mode\n- `build`: Builds the app for production\n- `lint`: Runs ESLint to check for code quality issues\n- `preview`: Previews the production build locally\n\n## Key Components\n\n### Timeline\n\nThe Timeline component displays a list of tweets and allows users to compose new tweets:\n\n```8:65:src/pages/Timeline.tsx\nexport function Timeline() {\n  const [newTweet, setNewTweet] = useState('')\n  const [tweets, setTweets] = useState([\n    'Hello, World!',\n    'This is a tweet!',\n    'This is another tweet!',\n  ])\n\n  function createNewTweet(event: FormEvent) {\n    event.preventDefault()\n\n    const tweet = newTweet\n    tweets.push(tweet)\n\n    setTweets([newTweet, ...tweets])\n    setNewTweet('')\n\n    console.log('New tweet:', tweet)\n    console.log('Tweets:', tweets)\n  }\n\n  function handleKeyDown(event: KeyboardEvent) {\n    if (event.key === 'Enter' \u0026\u0026 (event.metaKey || event.ctrlKey)) {\n      setTweets([newTweet, ...tweets])\n      setNewTweet('')\n    }\n  }\n\n  return (\n    \u003cmain className=\"timeline\"\u003e\n    \u003cHeader title={'Home'} /\u003e\n\n    \u003cform onSubmit={createNewTweet} className=\"new-tweet-form\"\u003e\n      \u003clabel htmlFor=\"tweet\"\u003e\n        \u003cimg src=\"https://github.com/felipecastrosales.png\" alt=\"Avatar\" /\u003e\n        \u003ctextarea\n          id=\"tweet\"\n          placeholder=\"What's happening?\"\n          value={newTweet}\n          onKeyDown={handleKeyDown}\n          onChange={(event) =\u003e {\n            setNewTweet(event.target.value)\n          }}\n        /\u003e\n      \u003c/label\u003e\n        \u003cbutton type=\"submit\"\u003eTweet\u003c/button\u003e\n    \u003c/form\u003e\n\n    \u003cSeparator /\u003e\n\n    {\n      tweets.map((tweet, index) =\u003e (\n        \u003cTweet key={index} content={tweet} /\u003e\n      ))\n    }\n  \u003c/main\u003e\n  )\n}\n```\n\n\n### Tweet\n\nThe Tweet component represents an individual tweet:\n\n```5:49:src/components/Tweet.tsx\ninterface TweetProps {\n  content: string;\n}\n\nexport function Tweet(\n  props: TweetProps,\n) {\n  return (\n    \u003cLink to='/status' className=\"tweet\"\u003e\n      \u003cimg src=\"https://github.com/felipecastrosales.png\" alt=\"Felipe Castro Sales\" /\u003e\n\n      \u003cdiv className=\"tweet-content\"\u003e\n        \u003cdiv className=\"tweet-content-header\"\u003e\n          \u003cstrong\u003eFelipe Castro Sales\u003c/strong\u003e\n          \u003cspan\u003e@felipecastrosales\u003c/span\u003e\n          \u003ctime\u003e1h\u003c/time\u003e\n        \u003c/div\u003e\n\n        \u003cp\u003e{props.content}\u003c/p\u003e\n\n        \u003cdiv className=\"tweet-content-footer\"\u003e\n          \u003cbutton type=\"button\"\u003e\n            \u003cChatCircle /\u003e\n            3\n          \u003c/button\u003e\n\n          \u003cbutton type=\"button\"\u003e\n            \u003cArrowsClockwise /\u003e\n            5\n          \u003c/button\u003e\n\n          \u003cbutton type=\"button\"\u003e\n            \u003cHeart /\u003e\n            10\n          \u003c/button\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/Link\u003e\n  );\n}\n```\n\n\n### Sidebar\n\nThe Sidebar component provides navigation and the tweet button:\n\n\n```8:53:src/components/Sidebar.tsx\nexport function Sidebar() {\n  return (\n    \u003caside className=\"sidebar\"\u003e\n    \u003cimg className=\"logo\" src={twitterLogo} alt=\"Twitter\" /\u003e\n    \u003cnav className=\"main-navigation\"\u003e\n      \u003cNavLink to=\"/\"\u003e\n        \u003cHouse weight=\"fill\" size={24} /\u003e\n        \u003cspan\u003eHome\u003c/span\u003e\n      \u003c/NavLink\u003e\n      \u003ca href=\"\"\u003e\n        \u003cHash/\u003e\n        \u003cspan\u003eExplore\u003c/span\u003e\n      \u003c/a\u003e\n      \u003ca href=\"\"\u003e\n        \u003cBell /\u003e\n        \u003cspan\u003eNotifications\u003c/span\u003e\n      \u003c/a\u003e\n      \u003ca href=\"\"\u003e\n        \u003cEnvelope /\u003e\n        \u003cspan\u003eMessages\u003c/span\u003e\n      \u003c/a\u003e\n      \u003ca href=\"\"\u003e\n        \u003cBookmarkSimple /\u003e\n        \u003cspan\u003eBookmarks\u003c/span\u003e\n      \u003c/a\u003e\n      \u003ca href=\"\"\u003e\n        \u003cFileText /\u003e\n        \u003cspan\u003eLists\u003c/span\u003e\n      \u003c/a\u003e\n      \u003ca href=\"\"\u003e\n        \u003cUser /\u003e\n        \u003cspan\u003eProfile\u003c/span\u003e\n      \u003c/a\u003e\n      \u003ca href=\"\"\u003e\n        \u003cDotsThreeCircle /\u003e\n        \u003cspan\u003eMore\u003c/span\u003e\n      \u003c/a\u003e\n    \u003c/nav\u003e\n\n    \u003cbutton className=\"new-tweet\" type=\"button\"\u003e\n      \u003cPencil weight=\"fill\" size={24} /\u003e\n      \u003cspan\u003eTweet\u003c/span\u003e\n    \u003c/button\u003e\n  \u003c/aside\u003e\n  );\n}\n```\n\n\n## Styling\n\nThe project uses CSS modules for component-specific styles and a global CSS file for common styles:\n\n\n```1:27:src/global.css\n* {\n  margin: 0;\n  padding: 0;\n  box-sizing: border-box;\n}\n\n:root {\n  --twitter-blue: #1da1f2;\n}\n\nbody {\n  color: #0f1419;\n  -webkit-font-smoothing: antialiased;\n}\n\nbody, input, textarea, button {\n  font: 400 1rem 'Roboto', sans-serif;\n}\n\nbutton {\n  cursor: pointer;\n}\n\na {\n  color: inherit;\n}\n\n```\n\n\n## Routing\n\nReact Router is used for navigation:\n\n\n```1:21:src/routes.tsx\nimport { createBrowserRouter } from \"react-router-dom\";\nimport { Timeline } from \"./pages/Timeline\";\nimport { Status } from \"./pages/Status\";\nimport { Default } from \"./layouts/Default\";\n\nexport const router = createBrowserRouter([\n  {\n    path: '/',\n    element: \u003cDefault /\u003e,\n    children: [\n      {\n        path: '/',\n        element: \u003cTimeline /\u003e,\n      },\n      {\n        path: '/status',\n        element: \u003cStatus /\u003e,\n      },\n    ]\n  }\n]);\n```\n\n\n## Development\n\nThis project uses ESLint for code quality and TypeScript for type checking. The configuration can be found in the `eslint.config.js` and `tsconfig.json` files.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipecastrosales%2Fui-twitter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffelipecastrosales%2Fui-twitter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelipecastrosales%2Fui-twitter/lists"}