diff --git a/client/src/components/Radio/Radio.scss b/client/src/components/Radio/Radio.scss new file mode 100644 index 0000000..4d87859 --- /dev/null +++ b/client/src/components/Radio/Radio.scss @@ -0,0 +1,33 @@ +@import 'styles/variables'; +@import 'styles/helpers'; + +.Radio { + display: block; + position: relative; + + &__Label { + color: $color-black; + padding-left: $spacing-large; + } + + &__Input + &__Label::before { + border: $border-regular solid $color-black; + border-radius: 50%; + content: ''; + display: block; + height: $spacing-regular; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); + width: $spacing-regular; + } + + &__Input:checked + &__Label::before { + background: $color-black; + } + + &__Input:focus + &__Label::before { + @include focusStyles(); + } +} diff --git a/client/src/components/Radio/Radio.tsx b/client/src/components/Radio/Radio.tsx new file mode 100644 index 0000000..743a519 --- /dev/null +++ b/client/src/components/Radio/Radio.tsx @@ -0,0 +1,38 @@ +import React, { FC, InputHTMLAttributes, ChangeEvent } from 'react' +import classnames from 'classnames' + +import './Radio.scss' + +export interface RadioProps extends InputHTMLAttributes { + label: string + checked: boolean + value: string + onChange: (event: ChangeEvent) => void + className?: string +} + +const Radio: FC = ({ + label, + checked, + value, + onChange, + className, + ...other +}) => { + const classes = classnames(className, 'Radio') + return ( + + ) +} + +export default Radio diff --git a/client/src/components/Radio/index.ts b/client/src/components/Radio/index.ts new file mode 100644 index 0000000..8d29209 --- /dev/null +++ b/client/src/components/Radio/index.ts @@ -0,0 +1,2 @@ +export * from './Radio' +export { default } from './Radio' diff --git a/client/src/containers/Settings/Settings.scss b/client/src/containers/Settings/Settings.scss new file mode 100644 index 0000000..1db9ff5 --- /dev/null +++ b/client/src/containers/Settings/Settings.scss @@ -0,0 +1,32 @@ +@import 'styles/variables'; + +.Settings { + h2 { + margin-bottom: $spacing-regular; + } + + legend { + margin-bottom: $spacing-small; + } + + &__Field { + & + & { + display: flex; + flex-wrap: wrap; + margin-top: $spacing-large; + + > label { + flex-basis: 100%; + margin-bottom: $spacing-small; + } + } + + label + label { + margin-top: $spacing-small; + } + + [type='number'] { + margin-right: $spacing-small; + } + } +} diff --git a/client/src/containers/Settings/Settings.tsx b/client/src/containers/Settings/Settings.tsx new file mode 100644 index 0000000..90f84e0 --- /dev/null +++ b/client/src/containers/Settings/Settings.tsx @@ -0,0 +1,94 @@ +import React, { Component, ChangeEvent } from 'react' + +import Radio from '../../components/Radio' +import { Settings as SettingsType } from '../../types/Settings' +import { Difficulty } from '../../types/Difficulty' +import './Settings.scss' + +const difficulties = [ + { value: Difficulty.EASY, label: 'Facile' }, + { value: Difficulty.MEDIUM, label: 'Intermédiaire' }, + { value: Difficulty.HARD, label: 'Difficile' } +] + +export interface SettingsProps { + settings: SettingsType + className?: string +} + +export interface SettingsState { + difficulty: string + roundsToWin: string + cardSpeed: string +} + +class Settings extends Component { + state: SettingsState = { + difficulty: this.props.settings.difficulty, + roundsToWin: this.props.settings.roundsToWin.toString(), + cardSpeed: this.props.settings.cardSpeed.toString() + } + + handleDifficultyChange = (e: ChangeEvent) => { + this.setState({ + difficulty: e.target.value + }) + } + + handleRoundsToWinChange = (e: ChangeEvent) => { + this.setState({ + roundsToWin: e.target.value + }) + } + + handleCardSpeedChange = (e: ChangeEvent) => { + this.setState({ + cardSpeed: e.target.value + }) + } + + render() { + return ( +
+

Paramètres de la partie

+
+ Niveau de difficulté + {difficulties.map(({ value, label }) => ( + + ))} +
+ +
+ + + manches de jeu. +
+ +
+ + + secondes entre chaque carte. +
+
+ ) + } +} + +export default Settings diff --git a/client/src/containers/Settings/index.ts b/client/src/containers/Settings/index.ts new file mode 100644 index 0000000..f2a67c8 --- /dev/null +++ b/client/src/containers/Settings/index.ts @@ -0,0 +1,2 @@ +export * from './Settings' +export { default } from './Settings' diff --git a/client/src/pages/Lobby/Lobby.tsx b/client/src/pages/Lobby/Lobby.tsx index 1f42e77..2923524 100644 --- a/client/src/pages/Lobby/Lobby.tsx +++ b/client/src/pages/Lobby/Lobby.tsx @@ -1,11 +1,13 @@ import React, { FC, useEffect, useState } from 'react' import axios, { AxiosResponse } from 'axios' +import moment from 'moment' import { RouteComponentProps } from '@reach/router' -import { Game } from '../../types/Game' -import * as moment from 'moment' import connectToGameHub from '../../utils/signalrConnector' - +import { Game } from '../../types/Game' +import { Settings as SettingsType } from '../../types/Settings' +import { Difficulty } from '../../types/Difficulty' +import Settings from '../../containers/Settings' import './Lobby.scss' import PlayerBox from '../../components/PlayerBox' @@ -48,10 +50,17 @@ const Lobby: FC = (props: LobbyProps) => { return game.players && game.players[0].id === playerId } + const defaultSettings: SettingsType = { + difficulty: Difficulty.EASY, + roundsToWin: 10, + cardSpeed: 1.5 + } + return (
{game && ( <> +

Details de la partie ({game.id})

{`Créé ${moment.utc(game.creationDate).fromNow()}`}

diff --git a/client/src/styles/_helpers.scss b/client/src/styles/_helpers.scss index 5b02215..946ccc5 100644 --- a/client/src/styles/_helpers.scss +++ b/client/src/styles/_helpers.scss @@ -1,6 +1,23 @@ // Custom focus styles -*:focus { +@mixin focusStyles { outline: 0; box-shadow: 0 0 0 0.2rem rgba($color-primary, 0.75); transition: box-shadow 0.25s; } + +// Apply focus styles +*:focus { + @include focusStyles(); +} + +// Visually hide element +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} diff --git a/client/src/styles/_reset.scss b/client/src/styles/_reset.scss index f519737..32b66c2 100644 --- a/client/src/styles/_reset.scss +++ b/client/src/styles/_reset.scss @@ -60,3 +60,10 @@ textarea, select { font: inherit; } + +/* Remove ugly fieldset styles */ +fieldset { + border: 0; + margin: 0; + padding: 0; +} diff --git a/client/src/styles/_typography.scss b/client/src/styles/_typography.scss index 5bdbc5a..4afb89f 100644 --- a/client/src/styles/_typography.scss +++ b/client/src/styles/_typography.scss @@ -9,3 +9,15 @@ h1 { font-size: $font-size-larger; font-weight: $font-weight-bold; } + +h2 { + font-size: $font-size-large; + font-weight: $font-weight-medium; +} + +label, +legend { + color: $color-black-70; + font-size: $font-size-regular; + font-weight: $font-weight-medium; +} diff --git a/client/src/styles/_variables.scss b/client/src/styles/_variables.scss index de89905..f13d2d0 100644 --- a/client/src/styles/_variables.scss +++ b/client/src/styles/_variables.scss @@ -9,6 +9,7 @@ $spacing-larger: $base-spacing * 8; $color-primary: #cfcfcf; $color-white: #ffffff; $color-black: #050505; +$color-black-70: rgba($color-black, 0.7); $radius-regular: 0.3125rem; @@ -22,4 +23,5 @@ $font-size-large: 1.75rem; $font-size-larger: 2.25rem; $font-weight-bold: 700; +$font-weight-medium: 500; $font-weight-regular: 400; diff --git a/client/src/types/Difficulty.ts b/client/src/types/Difficulty.ts new file mode 100644 index 0000000..38b76a2 --- /dev/null +++ b/client/src/types/Difficulty.ts @@ -0,0 +1,5 @@ +export enum Difficulty { + EASY = 'Easy', + MEDIUM = 'Medium', + HARD = 'Hard' +} diff --git a/client/src/types/Settings.ts b/client/src/types/Settings.ts new file mode 100644 index 0000000..7f1bd74 --- /dev/null +++ b/client/src/types/Settings.ts @@ -0,0 +1,7 @@ +import { Difficulty } from './Difficulty' + +export interface Settings { + difficulty: Difficulty + roundsToWin: number + cardSpeed: number +}