diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..963354f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "printWidth": 120 +} diff --git a/package.json b/package.json index 4667c95..9f6b8da 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,12 @@ "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", "@types/react-redux": "^7.1.7", + "axios": "^0.21.1", + "classnames": "^2.2.6", "react": "^17.0.2", "react-dom": "^17.0.2", "react-redux": "^7.2.0", + "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", "typescript": "~3.8.2" }, @@ -38,5 +41,9 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/classnames": "^2.2.11", + "@types/react-router-dom": "^5.1.7" } } diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 355c49b..0000000 --- a/src/App.css +++ /dev/null @@ -1,39 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-float infinite 3s ease-in-out; - } -} - -.App-header { - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); -} - -.App-link { - color: rgb(112, 76, 182); -} - -@keyframes App-logo-float { - 0% { - transform: translateY(0); - } - 50% { - transform: translateY(10px) - } - 100% { - transform: translateY(0px) - } -} diff --git a/src/App.test.tsx b/src/App.test.tsx deleted file mode 100644 index 27f1965..0000000 --- a/src/App.test.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import { Provider } from 'react-redux'; -import { store } from './app/store'; -import App from './App'; - -test('renders learn react link', () => { - const { getByText } = render( - - - - ); - - expect(getByText(/learn/i)).toBeInTheDocument(); -}); diff --git a/src/App.tsx b/src/App.tsx deleted file mode 100644 index 2dc188f..0000000 --- a/src/App.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import logo from './logo.svg'; -import { Counter } from './features/counter/Counter'; -import './App.css'; - -function App() { - return ( -
-
- logo - -

- Edit src/App.tsx and save to reload. -

- - Learn - - React - - , - - Redux - - , - - Redux Toolkit - - , and - - React Redux - - -
-
- ); -} - -export default App; diff --git a/src/app/App.css b/src/app/App.css new file mode 100644 index 0000000..2877950 --- /dev/null +++ b/src/app/App.css @@ -0,0 +1,9 @@ +.app { + min-height: 100vh; + /* Why did I put linear gradient? Because every bg I found looks like sh*t */ + background-image: linear-gradient(217deg, rgba(255, 0, 0, 0.6), rgba(255, 0, 0, 0) 70.71%), + linear-gradient(127deg, rgba(0, 255, 0, 0.6), rgba(0, 255, 0, 0) 70.71%), + linear-gradient(336deg, rgba(0, 0, 255, 0.6), rgba(0, 0, 255, 0) 70.71%), + url("assets/bigstock-poker-table-background-26587844-2-1.jpg"); + background-size: cover; +} diff --git a/src/app/App.test.tsx b/src/app/App.test.tsx new file mode 100644 index 0000000..c55e803 --- /dev/null +++ b/src/app/App.test.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { render } from "@testing-library/react"; +import { Provider } from "react-redux"; +import { store } from "./store"; +import App from "./App"; + +test("renders learn react link", () => { + const { getByText } = render( + + + + ); + + expect(getByText(/learn/i)).toBeInTheDocument(); +}); diff --git a/src/app/App.tsx b/src/app/App.tsx new file mode 100644 index 0000000..2bdbce5 --- /dev/null +++ b/src/app/App.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +function App() { + return ( +
+ +
+ ); +} + +export default App; diff --git a/src/app/store.ts b/src/app/store.ts index 078cca0..2a5b012 100644 --- a/src/app/store.ts +++ b/src/app/store.ts @@ -1,16 +1,8 @@ -import { configureStore, ThunkAction, Action } from '@reduxjs/toolkit'; -import counterReducer from '../features/counter/counterSlice'; +import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit"; export const store = configureStore({ - reducer: { - counter: counterReducer, - }, + reducer: {}, }); export type RootState = ReturnType; -export type AppThunk = ThunkAction< - ReturnType, - RootState, - unknown, - Action ->; +export type AppThunk = ThunkAction>; diff --git a/src/assets/1.jpg b/src/assets/1.jpg new file mode 100644 index 0000000..ce85d0e Binary files /dev/null and b/src/assets/1.jpg differ diff --git a/src/assets/7f89c1ae58a1fb6a01e026367807a87b.jpg b/src/assets/7f89c1ae58a1fb6a01e026367807a87b.jpg new file mode 100644 index 0000000..574cd89 Binary files /dev/null and b/src/assets/7f89c1ae58a1fb6a01e026367807a87b.jpg differ diff --git a/src/assets/bigstock-poker-table-background-26587844-2-1.jpg b/src/assets/bigstock-poker-table-background-26587844-2-1.jpg new file mode 100644 index 0000000..59e71eb Binary files /dev/null and b/src/assets/bigstock-poker-table-background-26587844-2-1.jpg differ diff --git a/src/assets/istockphoto-96655837-612x612.jpg b/src/assets/istockphoto-96655837-612x612.jpg new file mode 100644 index 0000000..191402f Binary files /dev/null and b/src/assets/istockphoto-96655837-612x612.jpg differ diff --git a/src/assets/poker-table-background-green-color_47243-1094.jpg b/src/assets/poker-table-background-green-color_47243-1094.jpg new file mode 100644 index 0000000..a78c5ca Binary files /dev/null and b/src/assets/poker-table-background-green-color_47243-1094.jpg differ diff --git a/src/features/Board/Board.module.css b/src/features/Board/Board.module.css new file mode 100644 index 0000000..128f807 --- /dev/null +++ b/src/features/Board/Board.module.css @@ -0,0 +1,80 @@ +.board { + display: grid; + align-items: center; + min-height: 100vh; + max-width: 1440px; + margin-left: auto; + margin-right: auto; + animation: fadeIn 1s forwards; +} + +/* Last child is discard pile. - this is the moment where I started hating css modules */ +.board > :last-child { + place-self: center; +} + +.threePlayer > :last-child { + grid-row: 1; + grid-column: 2; +} + +.twoPlayer { + grid-template-rows: repeat(3, 1fr); + justify-content: center; +} + +.twoPlayer :nth-child(1) { + grid-row: 3; +} + +.threePlayer { + grid-template-columns: repeat(3, 1fr); + grid-template-rows: repeat(2, 1fr); +} + +.threePlayer :nth-child(1) { + grid-row: 2; + grid-column: 2; +} + +.threePlayer :nth-child(3) { + grid-column: 3; +} + +.fourPlayer { + grid-template-columns: 1fr 2fr 1fr; + grid-template-rows: 1fr 2fr 1fr; +} + +.fourPlayer :nth-child(1) { + grid-column: 2; + grid-row: 3; +} + +.fourPlayer :nth-child(2) { + grid-row: 2; +} + +.fourPlayer :nth-child(3) { + grid-column: 2; +} + +.fourPlayer :nth-child(4) { + grid-column: 3; + grid-row: 2; +} + +.fourPlayer > :last-child { + grid-column: 2; + grid-row: 2; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} diff --git a/src/features/Board/Board.tsx b/src/features/Board/Board.tsx new file mode 100644 index 0000000..493056b --- /dev/null +++ b/src/features/Board/Board.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import styles from "./Board.module.css"; + +export function Board({ playerCount, children }: React.PropsWithChildren<{ playerCount: number }>) { + const getBoardVariant = (variant: string) =>
{children}
; + switch (playerCount) { + case 2: + return getBoardVariant(styles.twoPlayer); + case 3: + return getBoardVariant(styles.threePlayer); + case 4: + return getBoardVariant(styles.fourPlayer); + default: + throw new Error("Invalid number of players"); + } +} diff --git a/src/features/counter/Counter.module.css b/src/features/counter/Counter.module.css deleted file mode 100644 index 6c2b58f..0000000 --- a/src/features/counter/Counter.module.css +++ /dev/null @@ -1,74 +0,0 @@ -.row { - display: flex; - align-items: center; - justify-content: center; -} - -.row:not(:last-child) { - margin-bottom: 16px; -} - -.value { - font-size: 78px; - padding-left: 16px; - padding-right: 16px; - margin-top: 2px; - font-family: 'Courier New', Courier, monospace; -} - -.button { - appearance: none; - background: none; - font-size: 32px; - padding-left: 12px; - padding-right: 12px; - outline: none; - border: 2px solid transparent; - color: rgb(112, 76, 182); - padding-bottom: 4px; - cursor: pointer; - background-color: rgba(112, 76, 182, 0.1); - border-radius: 2px; - transition: all 0.15s; -} - -.textbox { - font-size: 32px; - padding: 2px; - width: 64px; - text-align: center; - margin-right: 8px; -} - -.button:hover, .button:focus { - border: 2px solid rgba(112, 76, 182, 0.4); -} - -.button:active { - background-color: rgba(112, 76, 182, 0.2); -} - -.asyncButton { - composes: button; - position: relative; - margin-left: 8px; -} - -.asyncButton:after { - content: ""; - background-color: rgba(112, 76, 182, 0.15); - display: block; - position: absolute; - width: 100%; - height: 100%; - left: 0; - top: 0; - opacity: 0; - transition: width 1s linear, opacity 0.5s ease 1s; -} - -.asyncButton:active:after { - width: 0%; - opacity: 1; - transition: 0s -} diff --git a/src/features/counter/Counter.tsx b/src/features/counter/Counter.tsx deleted file mode 100644 index 2ca6ed0..0000000 --- a/src/features/counter/Counter.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import React, { useState } from 'react'; -import { useSelector, useDispatch } from 'react-redux'; -import { - decrement, - increment, - incrementByAmount, - incrementAsync, - selectCount, -} from './counterSlice'; -import styles from './Counter.module.css'; - -export function Counter() { - const count = useSelector(selectCount); - const dispatch = useDispatch(); - const [incrementAmount, setIncrementAmount] = useState('2'); - - return ( -
-
- - {count} - -
-
- setIncrementAmount(e.target.value)} - /> - - -
-
- ); -} diff --git a/src/features/counter/counterSlice.ts b/src/features/counter/counterSlice.ts deleted file mode 100644 index f9ee20a..0000000 --- a/src/features/counter/counterSlice.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { AppThunk, RootState } from '../../app/store'; - -interface CounterState { - value: number; -} - -const initialState: CounterState = { - value: 0, -}; - -export const counterSlice = createSlice({ - name: 'counter', - initialState, - reducers: { - increment: state => { - // Redux Toolkit allows us to write "mutating" logic in reducers. It - // doesn't actually mutate the state because it uses the Immer library, - // which detects changes to a "draft state" and produces a brand new - // immutable state based off those changes - state.value += 1; - }, - decrement: state => { - state.value -= 1; - }, - // Use the PayloadAction type to declare the contents of `action.payload` - incrementByAmount: (state, action: PayloadAction) => { - state.value += action.payload; - }, - }, -}); - -export const { increment, decrement, incrementByAmount } = counterSlice.actions; - -// The function below is called a thunk and allows us to perform async logic. It -// can be dispatched like a regular action: `dispatch(incrementAsync(10))`. This -// will call the thunk with the `dispatch` function as the first argument. Async -// code can then be executed and other actions can be dispatched -export const incrementAsync = (amount: number): AppThunk => dispatch => { - setTimeout(() => { - dispatch(incrementByAmount(amount)); - }, 1000); -}; - -// The function below is called a selector and allows us to select a value from -// the state. Selectors can also be defined inline where they're used instead of -// in the slice file. For example: `useSelector((state: RootState) => state.counter.value)` -export const selectCount = (state: RootState) => state.counter.value; - -export default counterSlice.reducer; diff --git a/src/index.css b/src/index.css index bd5bd6d..d50bafc 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1,93 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", + "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; +} + +html { + box-sizing: border-box; + font-size: 16px; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body, +h1, +h2, +h3, +h4, +h5, +h6, +p, +ol, +ul { + margin: 0; + padding: 0; + font-weight: normal; +} + +ol, +ul { + list-style: none; +} + +img { + max-width: 100%; + height: auto; +} + +button { + padding: 0; + border: none; + background-color: transparent; +} + +code { + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; +} + +.text-error { + font-size: 18px; + color: #ff3333; +} + +.text-gold { + color: #ffd700; +} + +.text-white { + color: #ffffff; +} + +.text-info { + color: #17a2b8; + font-weight: bold; + text-shadow: 2px 2px 5px #000000; +} + +.text-center { + text-align: center; +} + +.py-2 { + padding-top: 8px; + padding-bottom: 8px; +} + +.pb-2 { + padding-bottom: 8px; +} + +.flex { + display: flex; } diff --git a/src/index.tsx b/src/index.tsx index ca43bac..879b42c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; -import App from './App'; +import App from './app/App'; import { store } from './app/store'; import { Provider } from 'react-redux'; import * as serviceWorker from './serviceWorker'; diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 9e96334..0000000 --- a/src/logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tsconfig.json b/tsconfig.json index 7b1d3c6..bf09654 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,9 +18,10 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react" + "jsx": "react", + "baseUrl": "src" }, "include": [ "src" ] -} +} \ No newline at end of file