diff --git a/prefs_page/README.md b/prefs_page/README.md new file mode 100644 index 0000000..74872fd --- /dev/null +++ b/prefs_page/README.md @@ -0,0 +1,50 @@ +# 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 +export default tseslint.config({ + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` +- Optionally add `...tseslint.configs.stylisticTypeChecked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: + +```js +// eslint.config.js +import react from 'eslint-plugin-react' + +export default tseslint.config({ + // Set the react version + settings: { react: { version: '18.3' } }, + plugins: { + // Add the react plugin + react, + }, + rules: { + // other rules... + // Enable its recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + }, +}) +``` diff --git a/prefs_page/index.html b/prefs_page/index.html new file mode 100644 index 0000000..ec5e6b7 --- /dev/null +++ b/prefs_page/index.html @@ -0,0 +1,13 @@ + + + + + + + Team preference + + +
+ + + diff --git a/prefs_page/package.json b/prefs_page/package.json new file mode 100644 index 0000000..a9c449e --- /dev/null +++ b/prefs_page/package.json @@ -0,0 +1,33 @@ +{ + "name": "prefs", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@emotion/react": "^11.13.3", + "@emotion/styled": "^11.13.0", + "@mui/icons-material": "^6.1.5", + "@mui/material": "^6.1.5", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@eslint/js": "^9.13.0", + "@types/react": "^18.3.11", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.3", + "eslint": "^9.13.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.13", + "globals": "^15.11.0", + "typescript": "~5.6.2", + "typescript-eslint": "^8.10.0", + "vite": "^5.4.9" + } +} diff --git a/prefs_page/public/logo.svg b/prefs_page/public/logo.svg new file mode 100644 index 0000000..f674658 --- /dev/null +++ b/prefs_page/public/logo.svg @@ -0,0 +1,55 @@ + + + + + + + + + + diff --git a/prefs_page/src/App.css b/prefs_page/src/App.css new file mode 100644 index 0000000..3800e3c --- /dev/null +++ b/prefs_page/src/App.css @@ -0,0 +1,14 @@ +#root { + max-width: 60vw; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/prefs_page/src/App.tsx b/prefs_page/src/App.tsx new file mode 100644 index 0000000..fc262ea --- /dev/null +++ b/prefs_page/src/App.tsx @@ -0,0 +1,204 @@ +import "./App.css"; +import names from "./players.json"; +import * as React from "react"; +import { Theme, useTheme } from "@mui/material/styles"; +import Box from "@mui/material/Box"; +import OutlinedInput from "@mui/material/OutlinedInput"; +import InputLabel from "@mui/material/InputLabel"; +import MenuItem from "@mui/material/MenuItem"; +import FormControl from "@mui/material/FormControl"; +import Select, { SelectChangeEvent } from "@mui/material/Select"; +import Chip from "@mui/material/Chip"; +import { + Alert, + Button, + Dialog, + DialogTitle, + FormHelperText, + Stack, +} from "@mui/material"; + +function getStyles(name: string, players: readonly string[], theme: Theme) { + return { + fontWeight: players.includes(name) + ? theme.typography.fontWeightMedium + : theme.typography.fontWeightRegular, + }; +} + +async function submit( + person: string, + players: string[], + setResponseStatus: (value: number) => void +) { + // console.log(JSON.stringify({ person: person, players: players })); + const response = await fetch("https://0124816.xyz/team/submit/", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ person: person, players: players }), + }); + setResponseStatus(response.status); +} + +type SubmitButtonProps = { + person: string; + players: string[]; +}; + +function SubmitButton(props: SubmitButtonProps) { + const [responseStatus, setResponseStatus] = React.useState(0); + + return ( +
+ + + thank you. please leave now. + +
+ ); +} + +type MultiSelectProps = { + person: string; + setPerson: (value: string) => void; + players: string[]; + setPlayers: (value: string[]) => void; +}; + +function MultipleSelectChip(props: MultiSelectProps) { + const ITEM_HEIGHT = 48; + const ITEM_PADDING_TOP = 8; + const MenuProps = { + PaperProps: { + style: { + maxHeight: ITEM_HEIGHT * 6.5 + ITEM_PADDING_TOP, + width: 250, + }, + }, + }; + const [alert, setAlert] = React.useState("none"); + const maxLimit = 9; + const theme = useTheme(); + + const handlePersonChange = ( + event: SelectChangeEvent + ) => { + const { + target: { value }, + } = event; + props.setPerson(value); + const index = props.players.indexOf(value); + if (index > -1) { + props.players.splice(index, 1); + } + props.setPlayers(props.players); + }; + + const handleChange = (event: SelectChangeEvent) => { + const { + target: { value }, + } = event; + if (value.length <= maxLimit) { + setAlert("none"); + props.setPlayers( + // On autofill we get a stringified value. + typeof value === "string" ? value.split(",") : value + ); + } else { + setAlert(""); + } + }; + + return ( + + + + who are you? + + + + + do not select more than {maxLimit} players + + + + players + + max. {maxLimit} + + + + ); +} + +function App() { + const [person, setPerson] = React.useState(""); + const [players, setPlayers] = React.useState([]); + + return ( + <> +

choose your best buddies for the Igloo

+
+ {MultipleSelectChip({ person, setPerson, players, setPlayers })} + {SubmitButton({ person, players })} +

now: click submit.

+
+

+ something not working? message me. +

+ + ); +} + +export default App; diff --git a/prefs_page/src/index.css b/prefs_page/src/index.css new file mode 100644 index 0000000..6119ad9 --- /dev/null +++ b/prefs_page/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/prefs_page/src/main.tsx b/prefs_page/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/prefs_page/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/prefs_page/src/vite-env.d.ts b/prefs_page/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/prefs_page/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/prefs_page/tsconfig.app.json b/prefs_page/tsconfig.app.json new file mode 100644 index 0000000..5a2def4 --- /dev/null +++ b/prefs_page/tsconfig.app.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/prefs_page/tsconfig.app.tsbuildinfo b/prefs_page/tsconfig.app.tsbuildinfo new file mode 100644 index 0000000..60a28f6 --- /dev/null +++ b/prefs_page/tsconfig.app.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts"],"version":"5.6.3"} \ No newline at end of file diff --git a/prefs_page/tsconfig.json b/prefs_page/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/prefs_page/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/prefs_page/tsconfig.node.json b/prefs_page/tsconfig.node.json new file mode 100644 index 0000000..9dad701 --- /dev/null +++ b/prefs_page/tsconfig.node.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "Bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/prefs_page/tsconfig.node.tsbuildinfo b/prefs_page/tsconfig.node.tsbuildinfo new file mode 100644 index 0000000..75ea001 --- /dev/null +++ b/prefs_page/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"root":["./vite.config.ts"],"version":"5.6.3"} \ No newline at end of file