diff --git a/client/package.json b/client/package.json index 0732496..0d32562 100644 --- a/client/package.json +++ b/client/package.json @@ -11,11 +11,16 @@ "dependencies": { "@headlessui/react": "^1.7.2", "@heroicons/react": "^2.0.11", + "@hookform/resolvers": "^2.9.8", + "@tanstack/react-query": "^4.7.2", + "axios": "^0.27.2", "clsx": "^1.2.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hook-form": "^7.36.1", "react-router-dom": "^6.4.1", - "tailwind-scrollbar": "^2.0.1" + "tailwind-scrollbar": "^2.0.1", + "zod": "^3.19.1" }, "devDependencies": { "@types/react": "^18.0.17", @@ -27,5 +32,6 @@ "tailwindcss": "^3.1.8", "typescript": "^4.6.4", "vite": "^3.1.0" - } + }, + "proxy": "http://localhost:5000" } \ No newline at end of file diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index 237de88..b745955 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -3,29 +3,39 @@ lockfileVersion: 5.4 specifiers: '@headlessui/react': ^1.7.2 '@heroicons/react': ^2.0.11 + '@hookform/resolvers': ^2.9.8 + '@tanstack/react-query': ^4.7.2 '@types/react': ^18.0.17 '@types/react-dom': ^18.0.6 '@vitejs/plugin-react': ^2.1.0 autoprefixer: ^10.4.12 + axios: ^0.27.2 clsx: ^1.2.1 postcss: ^8.4.16 prettier: ^2.7.1 react: ^18.2.0 react-dom: ^18.2.0 + react-hook-form: ^7.36.1 react-router-dom: ^6.4.1 tailwind-scrollbar: ^2.0.1 tailwindcss: ^3.1.8 typescript: ^4.6.4 vite: ^3.1.0 + zod: ^3.19.1 dependencies: '@headlessui/react': 1.7.2_biqbaboplfbrettd7655fr4n2y '@heroicons/react': 2.0.11_react@18.2.0 + '@hookform/resolvers': 2.9.8_react-hook-form@7.36.1 + '@tanstack/react-query': 4.7.2_biqbaboplfbrettd7655fr4n2y + axios: 0.27.2 clsx: 1.2.1 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 + react-hook-form: 7.36.1_react@18.2.0 react-router-dom: 6.4.1_biqbaboplfbrettd7655fr4n2y tailwind-scrollbar: 2.0.1_tailwindcss@3.1.8 + zod: 3.19.1 devDependencies: '@types/react': 18.0.21 @@ -344,6 +354,14 @@ packages: react: 18.2.0 dev: false + /@hookform/resolvers/2.9.8_react-hook-form@7.36.1: + resolution: {integrity: sha512-iVVjH0USq+1TqDdGkWe2M1x7Wn5OFPgVRo7CbWFsXTqqXqCaZtZcnzJu+UhljCWbthFWxWGXKLGYUDPZ04oVvQ==} + peerDependencies: + react-hook-form: ^7.0.0 + dependencies: + react-hook-form: 7.36.1_react@18.2.0 + dev: false + /@jridgewell/gen-mapping/0.1.1: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} @@ -405,6 +423,28 @@ packages: engines: {node: '>=14'} dev: false + /@tanstack/query-core/4.7.2: + resolution: {integrity: sha512-1zQuFsKShMhLY6rQYBEmkYiK9Zcb3lQcCVOTIgQcvliKIxPyZFaE/8LMtaITEEfgGF5qwYqHdm61+BUtpyNsrg==} + dev: false + + /@tanstack/react-query/4.7.2_biqbaboplfbrettd7655fr4n2y: + resolution: {integrity: sha512-4nJ0HxU2kxkaHZ/swJw39io3Bb3liiggJBsCCdFOydZOl8AJDRCor1E3GsOBrtn53HT01R9EIP4PY/6fyYdKsw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-native: '*' + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + dependencies: + '@tanstack/query-core': 4.7.2 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + use-sync-external-store: 1.2.0_react@18.2.0 + dev: false + /@types/prop-types/15.7.5: resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} dev: true @@ -478,6 +518,10 @@ packages: /arg/5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + /asynckit/0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + /autoprefixer/10.4.12_postcss@8.4.16: resolution: {integrity: sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==} engines: {node: ^10 || ^12 || >=14} @@ -494,6 +538,15 @@ packages: postcss-value-parser: 4.2.0 dev: true + /axios/0.27.2: + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + transitivePeerDependencies: + - debug + dev: false + /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -564,6 +617,13 @@ packages: /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + /combined-stream/1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + /convert-source-map/1.8.0: resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} dependencies: @@ -594,6 +654,11 @@ packages: /defined/1.0.0: resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==} + /delayed-stream/1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /detective/5.2.1: resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} engines: {node: '>=0.8.0'} @@ -854,6 +919,25 @@ packages: dependencies: to-regex-range: 5.0.1 + /follow-redirects/1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /form-data/4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fraction.js/4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: true @@ -970,6 +1054,18 @@ packages: braces: 3.0.2 picomatch: 2.3.1 + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} @@ -1099,6 +1195,15 @@ packages: scheduler: 0.23.0 dev: false + /react-hook-form/7.36.1_react@18.2.0: + resolution: {integrity: sha512-EbYYkCG2p8ywe7ikOH2l02lAFMrrrslZi1I8fqd8ifDGNAkhomHZQzQsP6ksvzrWBKntRe8b5L5L7Zsd+Gm02Q==} + engines: {node: '>=12.22.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 + dependencies: + react: 18.2.0 + dev: false + /react-refresh/0.14.0: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} @@ -1271,6 +1376,14 @@ packages: picocolors: 1.0.0 dev: true + /use-sync-external-store/1.2.0_react@18.2.0: + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -1308,3 +1421,7 @@ packages: /yaml/1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + + /zod/3.19.1: + resolution: {integrity: sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==} + dev: false diff --git a/client/src/App.tsx b/client/src/App.tsx index 47472e6..fb718ec 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,5 +1,6 @@ import { Routes, Route } from "react-router-dom"; import BrowseLayout from "./components/BrowseLayout"; +import CategoryPage from "./pages/CategoryPage"; import ChannelPage from "./pages/ChannelPage"; function App() { @@ -7,6 +8,7 @@ function App() { }> } /> + } /> Hi} /> diff --git a/client/src/components/Button.tsx b/client/src/components/Button.tsx index 65ef204..0b2b0c0 100644 --- a/client/src/components/Button.tsx +++ b/client/src/components/Button.tsx @@ -18,11 +18,7 @@ const getStyling = (variant?: ButtonVariants) => { } }; -const Button: FC = ({ - className, - variant, - ...rest -}: ButtonProps) => { +const Button: FC = ({ className, variant, ...rest }) => { return ( + + - -

- Creating an account allows you to participate in chat, follow - your favorite channels, and broadcast from your own channel. -

- - - - -

- By clicking Sign Up, you are agreeing to twitch-clone's{" "} - - Terms of Service - - . -

- + + @@ -110,20 +53,4 @@ const LoginModal: FC = ({ defaultPage, isOpen, onClose }) => { ); }; -interface LoginModalTabProps extends React.ComponentPropsWithoutRef<"p"> { - selected: boolean; -} - -const LoginModalTab: FC = ({ selected, ...rest }) => { - return ( -

- ); -}; - export default LoginModal; diff --git a/client/src/components/LoginModalTab.tsx b/client/src/components/LoginModalTab.tsx new file mode 100644 index 0000000..82c1fb4 --- /dev/null +++ b/client/src/components/LoginModalTab.tsx @@ -0,0 +1,20 @@ +import { FC } from "react"; +import clsx from "clsx"; + +interface LoginModalTabProps extends React.ComponentPropsWithoutRef<"p"> { + selected: boolean; +} + +const LoginModalTab: FC = ({ selected, ...rest }) => { + return ( +

+ ); +}; + +export default LoginModalTab; diff --git a/client/src/components/NavBar.tsx b/client/src/components/NavBar.tsx index 92ac784..c42ccb7 100644 --- a/client/src/components/NavBar.tsx +++ b/client/src/components/NavBar.tsx @@ -20,7 +20,7 @@ const NavBar: FC = () => { }; return ( -