puzzle racer WIP
parent
c7cfc0c925
commit
be6e80dfa3
|
@ -24,14 +24,17 @@ final class RacerJson(stormJson: StormJson, sign: StormSign, lightUserSync: Ligh
|
|||
|
||||
// full race data
|
||||
def data(race: RacerRace, player: RacerPlayer) =
|
||||
Json.obj(
|
||||
"race" -> Json.obj(
|
||||
"id" -> race.id.value,
|
||||
"moves" -> race.moves
|
||||
),
|
||||
"player" -> player,
|
||||
"puzzles" -> race.puzzles
|
||||
) ++ state(race)
|
||||
Json
|
||||
.obj(
|
||||
"race" -> Json
|
||||
.obj(
|
||||
"id" -> race.id.value,
|
||||
"moves" -> race.moves
|
||||
)
|
||||
.add("alreadyStarted" -> race.hasStarted),
|
||||
"player" -> player,
|
||||
"puzzles" -> race.puzzles
|
||||
) ++ state(race)
|
||||
|
||||
// socket updates
|
||||
def state(race: RacerRace) = Json
|
||||
|
|
|
@ -40,6 +40,8 @@ case class RacerRace(
|
|||
|
||||
def startsInMillis = startsAt.map(d => d.getMillis - nowMillis)
|
||||
|
||||
def hasStarted = startsInMillis.pp.exists(_ <= 0)
|
||||
|
||||
lazy val moves = puzzles.foldLeft(0) { case (m, p) =>
|
||||
m + p.line.size / 2
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
.racer {
|
||||
&__countdown {
|
||||
@extend %box-radius, %popup-shadow, %flex-center-nowrap;
|
||||
background: $c-bg-zebra;
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 2em 3em;
|
||||
|
||||
&__lights {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: #3a3a3a;
|
||||
width: 60px;
|
||||
height: 160px;
|
||||
border-radius: 15px;
|
||||
margin-right: 2em;
|
||||
|
||||
light {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
border-radius: 100%;
|
||||
display: block;
|
||||
opacity: 0.3;
|
||||
transition: all 1s;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
&.red {
|
||||
background: $c-red;
|
||||
&.active {
|
||||
box-shadow: 0 0 2em $c-red, 0 0 4em $c-red;
|
||||
}
|
||||
}
|
||||
&.orange {
|
||||
background: $c-brag;
|
||||
&.active {
|
||||
box-shadow: 0 0 2em $c-brag, 0 0 4em $c-brag;
|
||||
}
|
||||
}
|
||||
&.green {
|
||||
background: $c-good;
|
||||
&.active {
|
||||
box-shadow: 0 0 2em $c-good, 0 0 4em $c-good;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__seconds {
|
||||
@extend %flex-center;
|
||||
font-family: 'storm';
|
||||
font-size: 8em;
|
||||
color: $c-font;
|
||||
margin-bottom: -0.23em;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
@import 'race';
|
||||
@import 'countdown';
|
||||
|
||||
.racer {
|
||||
&__race {
|
||||
|
@ -18,65 +19,19 @@
|
|||
'board side';
|
||||
}
|
||||
|
||||
&__countdown {
|
||||
@extend %box-radius, %popup-shadow, %flex-center-nowrap;
|
||||
background: $c-bg-zebra;
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 2em 3em;
|
||||
&__started {
|
||||
@extend %flex-column;
|
||||
|
||||
&__lights {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
background-color: #3a3a3a;
|
||||
width: 60px;
|
||||
height: 160px;
|
||||
border-radius: 15px;
|
||||
margin-right: 2em;
|
||||
justify-content: stretch;
|
||||
text-align: center;
|
||||
|
||||
light {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
border-radius: 100%;
|
||||
display: block;
|
||||
opacity: 0.3;
|
||||
transition: all 1s;
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
&.red {
|
||||
background: $c-red;
|
||||
&.active {
|
||||
box-shadow: 0 0 2em $c-red, 0 0 4em $c-red;
|
||||
}
|
||||
}
|
||||
&.orange {
|
||||
background: $c-brag;
|
||||
&.active {
|
||||
box-shadow: 0 0 2em $c-brag, 0 0 4em $c-brag;
|
||||
}
|
||||
}
|
||||
&.green {
|
||||
background: $c-good;
|
||||
&.active {
|
||||
box-shadow: 0 0 2em $c-good, 0 0 4em $c-good;
|
||||
}
|
||||
}
|
||||
}
|
||||
i {
|
||||
font-size: 15em;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
&__seconds {
|
||||
@extend %flex-center;
|
||||
font-family: 'storm';
|
||||
font-size: 8em;
|
||||
color: $c-font;
|
||||
margin-bottom: -0.23em;
|
||||
p {
|
||||
margin: 3em 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ export default class StormCtrl {
|
|||
lichess.socket = new lichess.StrongSocket(`/racer/${this.race.id}`, false);
|
||||
lichess.pubsub.on('socket.in.racerState', this.serverUpdate);
|
||||
this.startCountdown();
|
||||
console.log(this.race);
|
||||
}
|
||||
|
||||
serverUpdate = (data: UpdatableData) => {
|
||||
|
|
|
@ -25,6 +25,7 @@ export interface RacerData extends UpdatableData {
|
|||
export interface Race {
|
||||
id: string;
|
||||
moves: number;
|
||||
alreadyStarted?: boolean;
|
||||
}
|
||||
|
||||
export interface Player {
|
||||
|
|
|
@ -47,16 +47,20 @@ const chessground = (ctrl: RacerCtrl): VNode =>
|
|||
|
||||
const renderPlay = (ctrl: RacerCtrl): VNode[] => [
|
||||
renderRace(ctrl),
|
||||
h('div.puz-board.main-board', [
|
||||
chessground(ctrl),
|
||||
ctrl.promotion.view(),
|
||||
ctrl.countdownSeconds() ? renderCountdown(ctrl.countdownSeconds()) : undefined,
|
||||
]),
|
||||
h('div.puz-side', [
|
||||
ctrl.run.clock.startAt ? renderSolved(ctrl.run) : renderStart(),
|
||||
ctrl.isPlayer() ? renderClock(ctrl.run, ctrl.endNow) : renderJoin(ctrl),
|
||||
h('div.puz-side__table', [renderCombo(config)(ctrl.run)]),
|
||||
]),
|
||||
...(ctrl.race.alreadyStarted
|
||||
? [renderStarted()]
|
||||
: [
|
||||
h('div.puz-board.main-board', [
|
||||
chessground(ctrl),
|
||||
ctrl.promotion.view(),
|
||||
ctrl.countdownSeconds() ? renderCountdown(ctrl.countdownSeconds()) : undefined,
|
||||
]),
|
||||
h('div.puz-side', [
|
||||
ctrl.run.clock.startAt ? renderSolved(ctrl.run) : renderStart(),
|
||||
ctrl.isPlayer() ? renderClock(ctrl.run, ctrl.endNow) : renderJoin(ctrl),
|
||||
h('div.puz-side__table', [renderCombo(config)(ctrl.run)]),
|
||||
]),
|
||||
]),
|
||||
];
|
||||
|
||||
const renderCountdown = (seconds: number) =>
|
||||
|
@ -94,3 +98,16 @@ const renderStart = () =>
|
|||
'div.puz-side__top.puz-side__start',
|
||||
h('div.puz-side__start__text', [h('strong', 'Puzzle Racer'), h('span', 'Waiting to start')])
|
||||
);
|
||||
|
||||
const renderStarted = () =>
|
||||
h('div.racer__started.box.box-pad', [
|
||||
h('i', { attrs: { 'data-icon': '~' } }),
|
||||
h('p', 'This race has already started!'),
|
||||
h(
|
||||
'a.storm--dup__reload.button',
|
||||
{
|
||||
attrs: { href: '/racer' },
|
||||
},
|
||||
'New race'
|
||||
),
|
||||
]);
|
||||
|
|
Loading…
Reference in New Issue