Skip to content

Commit 02856ee

Browse files
committed
Game setup redesign
1 parent 735b2b9 commit 02856ee

File tree

15 files changed

+605
-155
lines changed

15 files changed

+605
-155
lines changed

modules/coreI18n/src/main/key.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1677,6 +1677,7 @@ object I18nKey:
16771677
val `minutesPerSide`: I18nKey = "minutesPerSide"
16781678
val `variant`: I18nKey = "variant"
16791679
val `variants`: I18nKey = "variants"
1680+
val `variantsDescription`: I18nKey = "variantsDescription"
16801681
val `timeControl`: I18nKey = "timeControl"
16811682
val `realTime`: I18nKey = "realTime"
16821683
val `correspondence`: I18nKey = "correspondence"
@@ -1747,6 +1748,7 @@ object I18nKey:
17471748
val `standard`: I18nKey = "standard"
17481749
val `customPosition`: I18nKey = "customPosition"
17491750
val `unlimited`: I18nKey = "unlimited"
1751+
val `unlimitedDesc`: I18nKey = "unlimitedDesc"
17501752
val `mode`: I18nKey = "mode"
17511753
val `casual`: I18nKey = "casual"
17521754
val `rated`: I18nKey = "rated"
@@ -1823,7 +1825,6 @@ object I18nKey:
18231825
val `pasteTheFenStringHere`: I18nKey = "pasteTheFenStringHere"
18241826
val `pasteThePgnStringHere`: I18nKey = "pasteThePgnStringHere"
18251827
val `orUploadPgnFile`: I18nKey = "orUploadPgnFile"
1826-
val `fromPosition`: I18nKey = "fromPosition"
18271828
val `continueFromHere`: I18nKey = "continueFromHere"
18281829
val `toStudy`: I18nKey = "toStudy"
18291830
val `importGame`: I18nKey = "importGame"
@@ -2994,6 +2995,8 @@ object I18nKey:
29942995
val `racingKingsTitle`: I18nKey = "variant:racingKingsTitle"
29952996
val `crazyhouse`: I18nKey = "variant:crazyhouse"
29962997
val `crazyhouseTitle`: I18nKey = "variant:crazyhouseTitle"
2998+
val `fromPosition`: I18nKey = "variant:fromPosition"
2999+
val `fromPositionTitle`: I18nKey = "variant:fromPositionTitle"
29973000

29983001
object video:
29993002
val `chessVideos`: I18nKey = "video:chessVideos"

translation/source/site.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@
205205
<string name="minutesPerSide">Minutes per side</string>
206206
<string name="variant">Variant</string>
207207
<string name="variants">Variants</string>
208+
<string name="variantsDescription">More ways to play</string>
208209
<string name="timeControl">Time control</string>
209210
<string name="realTime">Real time</string>
210211
<string name="correspondence">Correspondence</string>
@@ -299,6 +300,7 @@
299300
<string name="standard">Standard</string>
300301
<string name="customPosition">Custom position</string>
301302
<string name="unlimited">Unlimited</string>
303+
<string name="unlimitedDesc">Take all the time you need</string>
302304
<string name="mode">Mode</string>
303305
<string name="casual">Casual</string>
304306
<string name="rated">Rated</string>
@@ -427,7 +429,6 @@
427429
<string name="pasteTheFenStringHere">Paste the FEN text here</string>
428430
<string name="pasteThePgnStringHere">Paste the PGN text here</string>
429431
<string name="orUploadPgnFile">Or upload a PGN file</string>
430-
<string name="fromPosition">From position</string>
431432
<string name="continueFromHere">Continue from here</string>
432433
<string name="toStudy">Study</string>
433434
<string name="importGame">Import game</string>

translation/source/variant.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@
1818
<string name="racingKingsTitle">Get your king to the other side of the board to win.</string>
1919
<string name="crazyhouse">Crazyhouse</string>
2020
<string name="crazyhouseTitle">Captured pieces can be dropped back on the board instead of moving a piece.</string>
21+
<string name="fromPosition">From Position</string>
22+
<string name="fromPositionTitle">Standard chess from a custom position</string>
2123
</resources>

ui/@types/lichess/i18n.d.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3505,8 +3505,6 @@ interface I18n {
35053505
freeOnlineChess: string;
35063506
/** Friends */
35073507
friends: string;
3508-
/** From position */
3509-
fromPosition: string;
35103508
/** Game aborted */
35113509
gameAborted: string;
35123510
/** Game as GIF */
@@ -4475,6 +4473,8 @@ interface I18n {
44754473
unknownDueToRounding: string;
44764474
/** Unlimited */
44774475
unlimited: string;
4476+
/** Take all the time you need */
4477+
unlimitedDesc: string;
44784478
/** Unsubscribe */
44794479
unsubscribe: string;
44804480
/** Until */
@@ -4513,6 +4513,8 @@ interface I18n {
45134513
variantLoss: string;
45144514
/** Variants */
45154515
variants: string;
4516+
/** More ways to play */
4517+
variantsDescription: string;
45164518
/** Variant win */
45174519
variantWin: string;
45184520
/** Variation arrows let you navigate without using the move list. */
@@ -5867,6 +5869,10 @@ interface I18n {
58675869
crazyhouse: string;
58685870
/** Captured pieces can be dropped back on the board instead of moving a piece. */
58695871
crazyhouseTitle: string;
5872+
/** From Position */
5873+
fromPosition: string;
5874+
/** Standard chess from a custom position */
5875+
fromPositionTitle: string;
58705876
/** Horde */
58715877
horde: string;
58725878
/** One side has a large number of pawns, the other has a normal army. */

ui/lib/css/setup/_colorChoice.scss

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
.color-picker {
2-
--button-size: 40px;
32
--king-size: 32px;
43
&__button {
5-
width: 50px !important;
6-
height: var(--button-size) !important;
7-
padding: 4px 8px !important;
8-
94
i {
105
display: block;
116
width: var(--king-size);

ui/lib/src/setup/view/color.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,21 @@ export const blindModeColorPicker = (colorProp: ColorProp): VNode[] => [
1616
];
1717

1818
export const colorButtons = (colorProp: ColorProp): VNode =>
19-
hl('div.radio-pane', [
20-
i18n.site.youPlayAs,
19+
hl('div.config-group', [
20+
hl('div.label', i18n.site.side),
2121
hl(
22-
'group.radio.color-picker',
23-
colors.map(({ key, name }) => [
24-
hl(`input#color-picker-${key}`, {
25-
attrs: { name: 'color', type: 'radio', value: key, checked: key === colorProp() },
26-
on: { change: () => colorProp(key) },
27-
}),
28-
hl(
29-
`label.color-picker__button.${key}`,
30-
{ attrs: { title: name, for: `color-picker-${key}` } },
31-
hl('i'),
32-
),
33-
]),
22+
'group.radio.color-picker.color-cards',
23+
colors.map(({ key, name }) =>
24+
hl('div', [
25+
hl(`input#color-picker-${key}`, {
26+
attrs: { name: 'color', type: 'radio', value: key, checked: colorProp() === key },
27+
on: { change: () => colorProp(key) },
28+
}),
29+
hl(`label.card-radio`, { attrs: { for: `color-picker-${key}` } }, [
30+
hl('div.color-picker__button', { class: { [key]: true } }, hl('i')),
31+
hl('span.text', name),
32+
]),
33+
]),
34+
),
3435
),
3536
]);

ui/lib/src/setup/view/timeControl.ts

Lines changed: 121 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
// ui/lib/src/setup/view/timeControl.ts
12
import type { Prop } from '@/index';
23
import { hl, type VNode } from '@/view';
34
import type { InputValue } from '../interfaces';
45
import {
56
timeModes,
67
sliderTimes,
8+
sliderInitVal,
9+
timeVToTime,
710
incrementVToIncrement,
811
daysVToDays,
912
type TimeControl,
@@ -18,6 +21,35 @@ const showTime = (v: number) => {
1821
return v.toString();
1922
};
2023

24+
const PRESETS = {
25+
standard: [
26+
// Common non-default time controls.
27+
{ lim: 0.25, inc: 0 },
28+
{ lim: 0.5, inc: 0 },
29+
{ lim: 0, inc: 1 },
30+
{ lim: 1, inc: 1 },
31+
{ lim: 2, inc: 0 },
32+
{ lim: 8, inc: 0 },
33+
{ lim: 5, inc: 5 },
34+
{ lim: 10, inc: 3 },
35+
{ lim: 15, inc: 0 },
36+
],
37+
nonStandard: [
38+
// mirrors modules/pool/src/main/PoolList.scala
39+
{ lim: 1, inc: 0 },
40+
{ lim: 2, inc: 1 },
41+
{ lim: 3, inc: 0 },
42+
{ lim: 3, inc: 2 },
43+
{ lim: 5, inc: 0 },
44+
{ lim: 5, inc: 3 },
45+
{ lim: 10, inc: 0 },
46+
{ lim: 10, inc: 5 },
47+
{ lim: 15, inc: 10 },
48+
{ lim: 30, inc: 0 },
49+
{ lim: 30, inc: 20 },
50+
],
51+
};
52+
2153
const blindModeTimePickers = (tc: TimeControl) => {
2254
return [
2355
renderTimeModePicker(tc),
@@ -95,35 +127,95 @@ const inputRange = (min: number, max: number, prop: Prop<InputValue>, classes?:
95127
hl('input.range', {
96128
class: classes,
97129
attrs: { type: 'range', min, max, value: prop() },
130+
hook: {
131+
update: (_: VNode, vnode: VNode) => {
132+
const el = vnode.elm as HTMLInputElement;
133+
el.value = prop().toString();
134+
},
135+
},
98136
on: { input: (e: Event) => prop(parseFloat((e.target as HTMLInputElement).value)) },
99137
});
100138

101-
export const timePickerAndSliders = (tc: TimeControl, minimumTimeRequiredIfReal: number = 0): VNode =>
102-
hl(
103-
'div.config-group',
104-
site.blindMode
105-
? blindModeTimePickers(tc)
106-
: [
107-
renderTimeModePicker(tc),
108-
tc.mode() === 'realTime' &&
109-
hl('div.time-choice.range', [
110-
`${i18n.site.minutesPerSide}: `,
111-
hl('span', showTime(tc.time())),
112-
inputRange(0, 38, tc.timeV, {
113-
failure: !tc.realTimeValid(minimumTimeRequiredIfReal),
114-
}),
115-
]),
116-
tc.mode() === 'realTime'
117-
? hl('div.increment-choice.range', [
118-
`${i18n.site.incrementInSeconds}: `,
119-
hl('span', `${tc.increment()}`),
120-
inputRange(0, 30, tc.incrementV, { failure: !tc.realTimeValid(minimumTimeRequiredIfReal) }),
121-
])
122-
: tc.mode() === 'correspondence' &&
123-
hl('div.days-choice.range', [
124-
`${i18n.site.daysPerTurn}: `,
125-
hl('span', `${tc.days()}`),
126-
inputRange(1, 7, tc.daysV),
127-
]),
128-
],
129-
);
139+
export const timePickerAndSliders = (
140+
tc: TimeControl,
141+
minimumTimeRequiredIfReal: number = 0,
142+
variant?: string,
143+
gameType?: 'hook' | 'friend' | 'ai',
144+
): VNode => {
145+
if (site.blindMode) return hl('div.config-group', blindModeTimePickers(tc));
146+
147+
const activeMode = tc.mode();
148+
const showTabs = tc.canSelectMode();
149+
150+
const tabs = showTabs
151+
? hl(
152+
'div.tabs-horiz',
153+
tc.modes.map(mode =>
154+
hl(
155+
'span',
156+
{
157+
class: { active: activeMode === mode },
158+
on: { click: () => tc.mode(mode) },
159+
},
160+
timeModes.find(m => m.key === mode)?.name || mode,
161+
),
162+
),
163+
)
164+
: null;
165+
166+
let panelContent: VNode | null = null;
167+
168+
if (activeMode === 'realTime') {
169+
const isStandard = !variant || variant === 'standard' || variant === 'fromPosition';
170+
const currentPresets = gameType === 'hook' && isStandard ? PRESETS.standard : PRESETS.nonStandard;
171+
172+
panelContent = hl('div.time-panel', [
173+
hl(
174+
'div.presets',
175+
currentPresets.map(p =>
176+
hl(
177+
'button.preset-btn',
178+
{
179+
on: {
180+
click: () => {
181+
tc.timeV(sliderInitVal(p.lim, timeVToTime, 100, 9));
182+
tc.incrementV(sliderInitVal(p.inc, incrementVToIncrement, 100, 0));
183+
},
184+
},
185+
},
186+
`${showTime(p.lim)}+${p.inc}`,
187+
),
188+
),
189+
),
190+
hl('div.sliders-grid', [
191+
hl('div.slider-container', [
192+
hl('div.label-row', [
193+
hl('label', i18n.site.minutesPerSide),
194+
hl('span.val-box', showTime(tc.time())),
195+
]),
196+
inputRange(0, 38, tc.timeV, {
197+
failure: !tc.realTimeValid(minimumTimeRequiredIfReal),
198+
}),
199+
]),
200+
hl('div.slider-container', [
201+
hl('div.label-row', [
202+
hl('label', i18n.site.incrementInSeconds),
203+
hl('span.val-box', tc.increment().toString()),
204+
]),
205+
inputRange(0, 30, tc.incrementV, { failure: !tc.realTimeValid(minimumTimeRequiredIfReal) }),
206+
]),
207+
]),
208+
]);
209+
} else if (activeMode === 'correspondence') {
210+
panelContent = hl('div.time-panel', [
211+
hl('div.slider-container.full-width', [
212+
hl('div.label-row', [hl('label', i18n.site.daysPerTurn), hl('span.val-box', tc.days().toString())]),
213+
inputRange(1, 7, tc.daysV),
214+
]),
215+
]);
216+
} else if (activeMode === 'unlimited') {
217+
panelContent = hl('div.time-panel', i18n.site.unlimitedDesc);
218+
}
219+
220+
return hl('div.config-group.time-control-tabs', [tabs, panelContent]);
221+
};

0 commit comments

Comments
 (0)