diff --git a/client/.eslintrc.cjs b/client/.eslintrc.cjs new file mode 100644 index 0000000..ed16f94 --- /dev/null +++ b/client/.eslintrc.cjs @@ -0,0 +1,17 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + 'plugin:storybook/recommended', + 'eslint-config-prettier', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], + }, +} diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/client/.prettierignore b/client/.prettierignore new file mode 100644 index 0000000..54ab352 --- /dev/null +++ b/client/.prettierignore @@ -0,0 +1,6 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +node_modules/* \ No newline at end of file diff --git a/client/.prettierrc b/client/.prettierrc new file mode 100644 index 0000000..07e60f4 --- /dev/null +++ b/client/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": false, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 160, + "endOfLine": "auto" +} \ No newline at end of file diff --git a/client/.storybook/main.ts b/client/.storybook/main.ts new file mode 100644 index 0000000..6d68d18 --- /dev/null +++ b/client/.storybook/main.ts @@ -0,0 +1,19 @@ +import type { StorybookConfig } from "@storybook/react-vite"; + +const config: StorybookConfig = { + stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], + addons: [ + "@storybook/addon-links", + "@storybook/addon-essentials", + "@storybook/addon-onboarding", + "@storybook/addon-interactions", + ], + framework: { + name: "@storybook/react-vite", + options: {}, + }, + docs: { + autodocs: "tag", + }, +}; +export default config; diff --git a/client/.storybook/preview.ts b/client/.storybook/preview.ts new file mode 100644 index 0000000..ff58bbd --- /dev/null +++ b/client/.storybook/preview.ts @@ -0,0 +1,15 @@ +import type { Preview } from "@storybook/react"; + +const preview: Preview = { + parameters: { + actions: { argTypesRegex: "^on[A-Z].*" }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + }, +}; + +export default preview; diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..1ebe379 --- /dev/null +++ b/client/README.md @@ -0,0 +1,27 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, +``` + +- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` +- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list diff --git a/client/index.html b/client/index.html new file mode 100644 index 0000000..516c8aa --- /dev/null +++ b/client/index.html @@ -0,0 +1,13 @@ + + + + + + + GBS + + +
+ + + diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..46b4321 --- /dev/null +++ b/client/package.json @@ -0,0 +1,48 @@ +{ + "name": "client", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite --host 0.0.0.0 --port 3000", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview", + "storybook": "storybook dev -p 6006", + "build-storybook": "storybook build" + }, + "dependencies": { + "hls.js": "1.4.12", + "react": "18.2.0", + "react-dom": "18.2.0", + "recoil": "0.7.7", + "styled-components": "6.1.1" + }, + "devDependencies": { + "@storybook/addon-essentials": "^7.5.3", + "@storybook/addon-interactions": "^7.5.3", + "@storybook/addon-links": "^7.5.3", + "@storybook/addon-onboarding": "^1.0.8", + "@storybook/blocks": "^7.5.3", + "@storybook/react": "^7.5.3", + "@storybook/react-vite": "^7.5.3", + "@storybook/testing-library": "^0.2.2", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitejs/plugin-react": "^4.0.3", + "eslint": "^8.53.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-import": "^2.29.0", + "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.3", + "eslint-plugin-storybook": "^0.6.15", + "prettier": "^3.0.3", + "storybook": "^7.5.3", + "typescript": "^5.0.2", + "vite": "^4.4.5" + } +} diff --git a/client/public/vite.svg b/client/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/client/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx new file mode 100644 index 0000000..50962fb --- /dev/null +++ b/client/src/App.tsx @@ -0,0 +1,11 @@ +import HlsPlayer from './components/hls' + +function App() { + return ( + <> + + + ) +} + +export default App diff --git a/client/src/assets/react.svg b/client/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/client/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/components/hls/index.tsx b/client/src/components/hls/index.tsx new file mode 100644 index 0000000..a8142c6 --- /dev/null +++ b/client/src/components/hls/index.tsx @@ -0,0 +1,32 @@ +import { useEffect, useRef } from 'react'; +import Hls from 'hls.js'; + +const HlsPlayer = () => { + const videoSrc = 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'; + const videoRef = useRef(null); + + useEffect(() => { + const video = videoRef.current; + let hls:Hls; + + if (video) { + if (video.canPlayType('application/vnd.apple.mpegurl')) { + video.src = videoSrc; + } else if (Hls.isSupported()) { + hls = new Hls(); + hls.loadSource(videoSrc); + hls.attachMedia(video); + } + + return () => { + if (hls) { + hls.destroy(); + } + }; + } + }, []); + + return