Implement the rest of gameplay, no game status yet
This commit is contained in:
parent
7e0ba5431a
commit
23285b89b0
@ -8,19 +8,31 @@ const EMPTY_SPACE = '-'
|
||||
interface CardTokenProps {
|
||||
card: Card | null
|
||||
onSelect: () => void
|
||||
isSelected: boolean
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export default function BoardSlot(props: CardTokenProps): JSX.Element {
|
||||
const {onSelect, card} = props
|
||||
const {onSelect, card, isSelected, disabled} = props
|
||||
|
||||
if (card == null) {
|
||||
if (card === null || card.type === -1) {
|
||||
return (
|
||||
<button>
|
||||
<button
|
||||
type="button"
|
||||
className={`board-slot${isSelected ? ' selected' : ''}`}
|
||||
onClick={onSelect}
|
||||
disabled={disabled}
|
||||
>
|
||||
<span>{EMPTY_SPACE}</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<CardToken onSelect={onSelect} cardKey={card.id} />
|
||||
<CardToken
|
||||
onSelect={onSelect}
|
||||
cardKey={card.type}
|
||||
isSelected={isSelected}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -3,11 +3,19 @@ import React from 'react'
|
||||
import type { GameHandle, Selection } from './types.ts'
|
||||
import BoardSlot from './BoardSlot.tsx'
|
||||
import CardToken from './cards/Card.tsx'
|
||||
import {isAttackSelection, isMoveSelection, isPlayCardSelection} from './selection.tsx'
|
||||
import {
|
||||
isAttackSelection,
|
||||
isMoveSelection,
|
||||
isPlayCardSelection,
|
||||
isAlly,
|
||||
isBoard,
|
||||
isHand,
|
||||
} from './selection.tsx'
|
||||
|
||||
type GameProps = GameHandle
|
||||
|
||||
export default function Game({
|
||||
export default function Game(props: GameProps): JSX.Element {
|
||||
const {
|
||||
team,
|
||||
board,
|
||||
player,
|
||||
@ -19,6 +27,7 @@ export default function Game({
|
||||
canDraw,
|
||||
hasDrawn,
|
||||
gameStatus,
|
||||
drawChoices,
|
||||
startTurn,
|
||||
endTurn,
|
||||
startDraw,
|
||||
@ -26,11 +35,12 @@ export default function Game({
|
||||
attackCard,
|
||||
moveCard,
|
||||
playCard,
|
||||
}: GameProps): JSX.Element {
|
||||
getView,
|
||||
} = props
|
||||
const [selection, setSelection] = React.useState<Selection | null>(null)
|
||||
|
||||
function selectCard(nextSelection: Selection): void {
|
||||
if (!selection) {
|
||||
if (selection === null) {
|
||||
setSelection(nextSelection)
|
||||
} else {
|
||||
if (isAttackSelection(selection, nextSelection)) {
|
||||
@ -44,11 +54,27 @@ export default function Game({
|
||||
}
|
||||
}
|
||||
|
||||
function selectTurnButton(): void {
|
||||
React.useEffect(() => {
|
||||
if (currentTurn === team) {
|
||||
startTurn()
|
||||
}
|
||||
}, [currentTurn, startTurn])
|
||||
|
||||
React.useEffect(() => {
|
||||
const intervalId = setInterval(
|
||||
() => {
|
||||
getView()
|
||||
},
|
||||
1000,
|
||||
)
|
||||
return () => {
|
||||
clearInterval(intervalId)
|
||||
}
|
||||
}, [getView])
|
||||
|
||||
const enemyBoard = team === 1 ? board.scourge : board.sentinal
|
||||
const allyBoard = team === 1 ? board.sentinal : board.scourge
|
||||
const isMyTurn = currentTurn === team
|
||||
|
||||
return (
|
||||
<div className="game-container">
|
||||
@ -58,19 +84,20 @@ export default function Game({
|
||||
<p>Life: {enemyLife}</p>
|
||||
<p>Deck: {enemyDeckSize}</p>
|
||||
</div>
|
||||
<p>Turn: {currentTurn}</p>
|
||||
{canDraw && <p>Drawing phase...</p>}
|
||||
{hasDrawn && <p>Action phase...</p>}
|
||||
<button onClick={selectTurnButton}>End/Start Turn</button>
|
||||
<div>
|
||||
<p>{isMyTurn ? 'My' : 'Enemy'} Turn</p>
|
||||
{isMyTurn && canDraw && <button type="button" onClick={startDraw}>Start Draw</button>}
|
||||
{isMyTurn && hasDrawn && <button type="button" onClick={endTurn}>End Turn</button>}
|
||||
</div>
|
||||
<div className="player-info">
|
||||
<p>Life: {player.life}</p>
|
||||
<p>Deck: {deck.length}</p>
|
||||
<p>Deck: {deck.cards.length}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="game-board">
|
||||
<div className="hand">
|
||||
{Array(enemyHandSize).fill(null).map(() => (
|
||||
<CardToken cardKey={null} />
|
||||
<CardToken cardKey={null} isSelected={false} disabled />
|
||||
))}
|
||||
</div>
|
||||
<div className="fighter-area enemy">
|
||||
@ -78,6 +105,12 @@ export default function Game({
|
||||
<BoardSlot
|
||||
card={card ?? null}
|
||||
onSelect={() => selectCard({target: 'opponent', type: 'board', index})}
|
||||
isSelected={
|
||||
selection
|
||||
? !isAlly(selection) && isBoard(selection) && selection.index === index
|
||||
: false
|
||||
}
|
||||
disabled={!(currentTurn === team && hasDrawn)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
@ -86,14 +119,55 @@ export default function Game({
|
||||
<BoardSlot
|
||||
card={card ?? null}
|
||||
onSelect={() => selectCard({target: 'ally', type: 'board', index})}
|
||||
isSelected={
|
||||
selection
|
||||
? isAlly(selection) && isBoard(selection) && selection.index === index
|
||||
: false
|
||||
}
|
||||
disabled={!(currentTurn === team && hasDrawn)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{drawChoices.length > 0 && (
|
||||
<React.Fragment>
|
||||
<div className="draw-choices">
|
||||
{drawChoices.map((card, index) => (
|
||||
<CardToken
|
||||
cardKey={card.type === -1 ? null : card.type}
|
||||
onSelect={() => selectCard({target: 'ally', type: 'draws', index})}
|
||||
isSelected={
|
||||
selection
|
||||
? selection.type === 'draws' && selection.index === index
|
||||
: false
|
||||
}
|
||||
disabled={false}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={
|
||||
() => selection && selection.type === 'draws' && commitDraw(selection.index)
|
||||
}
|
||||
disabled={selection?.type !== 'draws'}
|
||||
>
|
||||
Draw Card
|
||||
</button>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)}
|
||||
<div className="hand">
|
||||
{player.hand.map((card, index) => (
|
||||
<CardToken
|
||||
cardKey={card.id}
|
||||
cardKey={card.type === -1 ? null : card.type}
|
||||
onSelect={() => selectCard({target: 'ally', type: 'hand', index})}
|
||||
isSelected={
|
||||
selection
|
||||
? isAlly(selection) && isHand(selection) && selection.index === index
|
||||
: false
|
||||
}
|
||||
disabled={!(isMyTurn && hasDrawn)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@ import Loading from '../components/Loading.tsx'
|
||||
|
||||
import {
|
||||
AsyncHandle,
|
||||
Card,
|
||||
FighterArea,
|
||||
GameState,
|
||||
GameAction,
|
||||
@ -14,19 +15,69 @@ import {
|
||||
import useServerSocket from './useServerSocket.ts'
|
||||
import Game from './Game.tsx'
|
||||
|
||||
function reducer(state: GameState, action: GameAction): GameState {
|
||||
interface GameClientState extends GameState {
|
||||
isDrawing: boolean
|
||||
}
|
||||
|
||||
type GameClientAction = GameAction
|
||||
|
||||
function reducer(state: GameClientState, action: GameClientAction): GameClientState {
|
||||
switch (action.type) {
|
||||
case 'update-state': {
|
||||
return {...action.state, team: state.team}
|
||||
return {...state, ...action.state}
|
||||
}
|
||||
case 'set-player': {
|
||||
case 'set-player-team': {
|
||||
return {...state, team: action.team}
|
||||
}
|
||||
case 'play-card': {
|
||||
const nextHand = [
|
||||
...state.player.hand.slice(0, action.handIndex),
|
||||
...state.player.hand.slice(action.handIndex + 1),
|
||||
]
|
||||
return {
|
||||
...state,
|
||||
player: { ...state.player, hand: nextHand },
|
||||
}
|
||||
}
|
||||
case 'receive-cards': {
|
||||
// first, i can draw and i am not yet drawing
|
||||
// scry N cards from the deck
|
||||
if (state.canDraw && !state.isDrawing) {
|
||||
return {
|
||||
...state,
|
||||
isDrawing: true,
|
||||
drawChoices: action.cards,
|
||||
}
|
||||
}
|
||||
// then, i am drawing, i can still draw, and I haven't yet drawn.
|
||||
// i draw a card into my hand
|
||||
if (state.canDraw && state.isDrawing && !state.hasDrawn) {
|
||||
return {
|
||||
...state,
|
||||
drawChoices: [],
|
||||
player: {
|
||||
...state.player,
|
||||
hand: action.cards
|
||||
},
|
||||
isDrawing: false,
|
||||
hasDrawn: true,
|
||||
}
|
||||
}
|
||||
// then, i am no longer drawing and cannot draw. this is the board.
|
||||
const team = state.team === 1 ? 'sentinal' : 'scourge' as const
|
||||
return {
|
||||
...state,
|
||||
board: {
|
||||
...state.board,
|
||||
[team]: action.cards,
|
||||
},
|
||||
}
|
||||
}
|
||||
default: return state
|
||||
}
|
||||
}
|
||||
|
||||
const initialState: GameState = {
|
||||
const initialState: GameClientState = {
|
||||
board: {
|
||||
sentinal: Array(4).fill(undefined) as FighterArea,
|
||||
scourge: Array(4).fill(undefined) as FighterArea,
|
||||
@ -38,7 +89,9 @@ const initialState: GameState = {
|
||||
life: 0,
|
||||
ready: false,
|
||||
},
|
||||
deck: [],
|
||||
deck: {
|
||||
cards: []
|
||||
},
|
||||
team: 1,
|
||||
enemyLife: 0,
|
||||
enemyDeckSize: 0,
|
||||
@ -47,17 +100,20 @@ const initialState: GameState = {
|
||||
canDraw: false,
|
||||
hasDrawn: false,
|
||||
gameStatus: 0,
|
||||
isDrawing: false,
|
||||
drawChoices: [],
|
||||
}
|
||||
|
||||
export default function GameClient(): JSX.Element {
|
||||
const [state, dispatch] = React.useReducer(reducer, initialState)
|
||||
|
||||
const handleGameUpdate = React.useCallback((data: Record<string, unknown>) => {
|
||||
console.log(data)
|
||||
const handleGameUpdate = React.useCallback((action: GameAction) => {
|
||||
dispatch(action)
|
||||
}, [])
|
||||
|
||||
const socketHandle = useServerSocket(handleGameUpdate)
|
||||
|
||||
const {team} = state
|
||||
const gameHandle = React.useMemo<AsyncHandle<GameCommandAPI>>(
|
||||
() => {
|
||||
if (socketHandle.status !== 'connected') return socketHandle
|
||||
@ -69,6 +125,7 @@ export default function GameClient(): JSX.Element {
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 's',
|
||||
cmd: 'b',
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
startTurn: () => {
|
||||
@ -76,6 +133,7 @@ export default function GameClient(): JSX.Element {
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 's',
|
||||
cmd: 's',
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
endTurn: () => {
|
||||
@ -83,6 +141,7 @@ export default function GameClient(): JSX.Element {
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 's',
|
||||
cmd: 'e',
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
getView: () => {
|
||||
@ -90,6 +149,7 @@ export default function GameClient(): JSX.Element {
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 's',
|
||||
cmd: 'g',
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
startDraw: () => {
|
||||
@ -97,20 +157,25 @@ export default function GameClient(): JSX.Element {
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 'a',
|
||||
cmd: 's',
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
commitDraw: (cardIndex: number) => {
|
||||
if (socketHandle.status !== 'connected') return
|
||||
// dispatch({type})
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 'a',
|
||||
cmd: `d ${cardIndex}`,
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
playCard: (handIndex: number, positionIndex: number) => {
|
||||
if (socketHandle.status !== 'connected') return
|
||||
dispatch({ type: 'play-card', handIndex })
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 'a',
|
||||
cmd: `p ${handIndex} ${positionIndex}`,
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
moveCard: (positionFrom: number, positionTo: number) => {
|
||||
@ -118,6 +183,7 @@ export default function GameClient(): JSX.Element {
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 'a',
|
||||
cmd: `m ${positionFrom} ${positionTo}`,
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
attackCard: (positionFrom: number, positionTo: number) => {
|
||||
@ -125,23 +191,22 @@ export default function GameClient(): JSX.Element {
|
||||
socketHandle.handle.sendGameCommand({
|
||||
type: 'a',
|
||||
cmd: `a ${positionFrom} ${positionTo}`,
|
||||
player_id: team,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
[socketHandle, state],
|
||||
[socketHandle, team],
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (gameHandle.status !== 'connected') return
|
||||
gameHandle.handle.readyPlayer()
|
||||
if (state?.team === 1) gameHandle.handle.startTurn()
|
||||
}, [gameHandle, state?.team])
|
||||
}, [gameHandle, team])
|
||||
|
||||
switch (gameHandle.status) {
|
||||
case 'connected': {
|
||||
if (!state) return <Loading />
|
||||
return <Game {...state} {...gameHandle.handle} />
|
||||
}
|
||||
case 'not-connected':
|
||||
|
@ -9,21 +9,30 @@ const EMPTY_SPACE = '-'
|
||||
interface CardTokenProps {
|
||||
cardKey: CardKey | null
|
||||
onSelect?: () => void
|
||||
isSelected: boolean
|
||||
disabled: boolean
|
||||
}
|
||||
|
||||
export default function CardToken(props: CardTokenProps): JSX.Element {
|
||||
const {onSelect, cardKey} = props
|
||||
|
||||
const {onSelect, cardKey, isSelected, disabled} = props
|
||||
if (cardKey == null) {
|
||||
return (
|
||||
<div className={`card-button card-back${isSelected ? ' selected' : ''}`}>
|
||||
<div>
|
||||
<span>{EMPTY_SPACE}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<button onClick={onSelect}>
|
||||
<button
|
||||
type="button"
|
||||
className={`card-button${isSelected ? ' selected' : ''}`}
|
||||
onClick={onSelect}
|
||||
disabled={disabled}
|
||||
>
|
||||
<img
|
||||
className="card-image"
|
||||
src={getCardSrc(cardKey)}
|
||||
alt={getCardAlt(cardKey)}
|
||||
/>
|
||||
|
@ -2,8 +2,8 @@ import type {CardKey} from '../types.ts'
|
||||
|
||||
const cardPaths: Record<CardKey, string> = {
|
||||
0: 'joker.png',
|
||||
1: 'sp_2.png',
|
||||
2: 'sp_14.png',
|
||||
1: 'sp_14.png',
|
||||
2: 'sp_2.png',
|
||||
3: 'sp_3.png',
|
||||
4: 'sp_4.png',
|
||||
5: 'sp_5.png',
|
||||
|
@ -1,17 +1,21 @@
|
||||
import type {Selection} from './types.ts'
|
||||
|
||||
function isAlly(selection: Selection): boolean {
|
||||
export function isAlly(selection: Selection): boolean {
|
||||
return selection.target === 'ally'
|
||||
}
|
||||
|
||||
function isHand(selection: Selection): boolean {
|
||||
export function isHand(selection: Selection): boolean {
|
||||
return selection.type === 'hand'
|
||||
}
|
||||
|
||||
function isBoard(selection: Selection): boolean {
|
||||
export function isBoard(selection: Selection): boolean {
|
||||
return selection.type === 'board'
|
||||
}
|
||||
|
||||
export function isDrawSelection(selection: Selection): boolean {
|
||||
return selection.type === 'draws'
|
||||
}
|
||||
|
||||
export function isPlayCardSelection(first: Selection, second: Selection): boolean {
|
||||
const isMyHand = isAlly(first) && isHand(first)
|
||||
const targetsMyBoard = isAlly(second) && isBoard(second)
|
||||
|
@ -11,10 +11,10 @@ export type AsyncHandle<T> =
|
||||
export type CardKey = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
|
||||
|
||||
export interface Card {
|
||||
type: number
|
||||
type: CardKey | -1
|
||||
basePower: number
|
||||
power: number
|
||||
id: CardKey
|
||||
id: string
|
||||
counters: number
|
||||
owner: number
|
||||
position: number
|
||||
@ -36,6 +36,7 @@ export interface Player {
|
||||
life: number
|
||||
ready: boolean
|
||||
}
|
||||
export type Team = 1 | 2
|
||||
|
||||
interface TeamEnumMap {
|
||||
1: 'sentinal'
|
||||
@ -55,8 +56,10 @@ interface GameStatusMap {
|
||||
export interface GameState {
|
||||
board: Board
|
||||
player: Player
|
||||
deck: Card[]
|
||||
team: 1 | 2
|
||||
deck: {
|
||||
cards: Card[]
|
||||
}
|
||||
team: Team
|
||||
enemyLife: number
|
||||
enemyDeckSize: number
|
||||
enemyHandSize: number
|
||||
@ -64,11 +67,14 @@ export interface GameState {
|
||||
canDraw: boolean
|
||||
hasDrawn: boolean
|
||||
gameStatus: keyof GameStatusMap
|
||||
drawChoices: Card[]
|
||||
}
|
||||
|
||||
export type GameAction =
|
||||
| { type: 'set-player'; team: 1 | 2}
|
||||
| { type: 'set-player-team'; team: Team}
|
||||
| { type: 'receive-cards'; cards: Card[]}
|
||||
| { type: 'update-state'; state: Omit<GameState, 'team'> }
|
||||
| { type: 'play-card', handIndex: number }
|
||||
|
||||
export interface GameCommandAPI {
|
||||
readyPlayer: () => void
|
||||
@ -106,13 +112,13 @@ export interface CommandVariantParamMap {
|
||||
}
|
||||
|
||||
export interface GameCommand {
|
||||
playerId: string
|
||||
type: GameCommandEnum,
|
||||
player_id: Team
|
||||
type: GameCommandEnum
|
||||
cmd: string // "<Variant> <VariantParam1> <VariantParam2> ..."
|
||||
}
|
||||
|
||||
type SelectionTarget = 'ally' | 'opponent'
|
||||
type SelectionType = 'hand' | 'board'
|
||||
type SelectionType = 'hand' | 'board' | 'draws'
|
||||
|
||||
export interface Selection {
|
||||
target: SelectionTarget
|
||||
|
@ -75,7 +75,7 @@ function reducer(state: GameSocketSessionState, action: Action): GameSocketSessi
|
||||
const initialState: GameSocketSessionState = {status: 'connecting'}
|
||||
|
||||
interface SocketHandle {
|
||||
sendGameCommand: (command: Omit<GameCommand, 'playerId'>) => void
|
||||
sendGameCommand: (command: GameCommand) => void
|
||||
}
|
||||
|
||||
export default function useServerSocket(
|
||||
@ -98,18 +98,49 @@ export default function useServerSocket(
|
||||
return
|
||||
}
|
||||
case 'joined p1': {
|
||||
onUpdate({ type: 'set-player', team: 1 })
|
||||
onUpdate({ type: 'set-player-team', team: 1 })
|
||||
dispatch ({ type: 'join-game' })
|
||||
return
|
||||
}
|
||||
case 'joined p2': {
|
||||
onUpdate({ type: 'set-player', team: 2 })
|
||||
onUpdate({ type: 'set-player-team', team: 2 })
|
||||
dispatch ({ type: 'join-game' })
|
||||
return
|
||||
}
|
||||
default: break;
|
||||
case 'played': {
|
||||
switch (data.game_result.result_type) {
|
||||
case 'a': {
|
||||
const result = data.game_result.action_result
|
||||
if (result) onUpdate({
|
||||
type: 'receive-cards',
|
||||
cards: result.cards,
|
||||
})
|
||||
return
|
||||
}
|
||||
case 's': {
|
||||
const result = data.game_result.state_result
|
||||
if (result) onUpdate({
|
||||
type: 'update-state',
|
||||
state: {
|
||||
board: result.board,
|
||||
player: result.player,
|
||||
deck: result.deck,
|
||||
enemyLife: result.enemy_life,
|
||||
enemyDeckSize: result.enemy_deck_size,
|
||||
enemyHandSize: result.enemy_hand_size,
|
||||
currentTurn: result.current_turn,
|
||||
canDraw: result.can_draw,
|
||||
hasDrawn: result.has_drawn,
|
||||
gameStatus: result.game_status,
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
default: return
|
||||
}
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
onUpdate(data)
|
||||
}, [onUpdate])
|
||||
|
||||
const onOpen = React.useCallback(() => {
|
||||
@ -141,16 +172,13 @@ export default function useServerSocket(
|
||||
sendJsonMessage(message)
|
||||
}, [sendJsonMessage])
|
||||
|
||||
const sendGameCommand = React.useCallback((gameCommand: Omit<GameCommand, 'playerId'>) => {
|
||||
const sendGameCommand = React.useCallback((gameCommand: GameCommand) => {
|
||||
if (state.status !== 'in-game') return
|
||||
sendJson({
|
||||
player_id: MY_ID,
|
||||
match_id: state.matchId,
|
||||
command: 'play',
|
||||
game_command: {
|
||||
...gameCommand,
|
||||
playerId: state.playerId,
|
||||
},
|
||||
game_command: gameCommand,
|
||||
})
|
||||
}, [state, sendJson])
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
* {
|
||||
font-family: sans-serif;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@ -151,6 +152,7 @@ h2 {
|
||||
.game-sidebar {
|
||||
flex: 0 0 auto;
|
||||
width: 10em;
|
||||
padding: 1em;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -162,7 +164,6 @@ h2 {
|
||||
}
|
||||
|
||||
.player-info {
|
||||
margin: 1em;
|
||||
padding: 1em;
|
||||
background-color: #c4c4c4;
|
||||
color: #000000;
|
||||
@ -187,3 +188,40 @@ h2 {
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.board-slot {
|
||||
width: 5em;
|
||||
height: 7em;
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
.card-button {
|
||||
width: 10em;
|
||||
height: 14em;
|
||||
margin: 0 1em;
|
||||
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.card-button:disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.card-back {
|
||||
background: grey;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
||||
.selected {
|
||||
box-shadow: 0px 0px 8px 4px rgba(245, 194, 10, 0.5);
|
||||
}
|
||||
|
||||
.card-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
import { Router } from 'oak'
|
||||
|
||||
function handleSocket(socket: WebSocket) {
|
||||
console.log(socket)
|
||||
}
|
||||
|
||||
const apiRouter = new Router()
|
||||
|
||||
apiRouter
|
||||
.get('/api/ws', async (context) => {
|
||||
if (!context.isUpgradable) throw new Error('Context not upgradable.')
|
||||
const ws = await context.upgrade()
|
||||
handleSocket(ws)
|
||||
})
|
||||
.get('/api/hello', (context) => {
|
||||
context.response.body = "Hello world!";
|
||||
})
|
||||
|
||||
export default apiRouter
|
@ -1,9 +1,5 @@
|
||||
import { Application, Status } from 'oak'
|
||||
|
||||
//// import any necessary wasm file here
|
||||
// import init from '~/common/wasm.js'
|
||||
|
||||
import apiRouter from './routes/api.ts'
|
||||
import staticRouter from './routes/static.tsx'
|
||||
|
||||
const app = new Application()
|
||||
@ -28,9 +24,6 @@ app.use((ctx, next) => {
|
||||
return next()
|
||||
})
|
||||
|
||||
app.use(apiRouter.routes())
|
||||
app.use(apiRouter.allowedMethods())
|
||||
|
||||
app.use(staticRouter.routes())
|
||||
app.use(staticRouter.allowedMethods())
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user