personal opening explorer UI WIP
parent
ca36d40fce
commit
b1a398b66d
|
@ -94,6 +94,7 @@ final class Env(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val explorerEndpoint = config.get[String]("explorer.endpoint")
|
val explorerEndpoint = config.get[String]("explorer.endpoint")
|
||||||
|
val explorer3Endpoint = config.get[String]("explorer.endpoint3")
|
||||||
val tablebaseEndpoint = config.get[String]("explorer.tablebase.endpoint")
|
val tablebaseEndpoint = config.get[String]("explorer.tablebase.endpoint")
|
||||||
|
|
||||||
val appVersionDate = config.getOptional[String]("app.version.date")
|
val appVersionDate = config.getOptional[String]("app.version.date")
|
||||||
|
|
|
@ -84,7 +84,8 @@ trait AssetHelper { self: I18nHelper with SecurityHelper =>
|
||||||
}
|
}
|
||||||
ContentSecurityPolicy(
|
ContentSecurityPolicy(
|
||||||
defaultSrc = List("'self'", assets),
|
defaultSrc = List("'self'", assets),
|
||||||
connectSrc = "'self'" :: assets :: sockets ::: env.explorerEndpoint :: env.tablebaseEndpoint :: Nil,
|
connectSrc =
|
||||||
|
"'self'" :: assets :: sockets ::: env.explorerEndpoint :: env.tablebaseEndpoint :: env.explorer3Endpoint :: Nil,
|
||||||
styleSrc = List("'self'", "'unsafe-inline'", assets),
|
styleSrc = List("'self'", "'unsafe-inline'", assets),
|
||||||
frameSrc = List("'self'", assets, "https://www.youtube.com", "https://player.twitch.tv"),
|
frameSrc = List("'self'", assets, "https://www.youtube.com", "https://player.twitch.tv"),
|
||||||
workerSrc = List("'self'", assets),
|
workerSrc = List("'self'", assets),
|
||||||
|
|
|
@ -40,6 +40,7 @@ object Environment
|
||||||
def apiVersion = lila.api.Mobile.Api.currentVersion
|
def apiVersion = lila.api.Mobile.Api.currentVersion
|
||||||
|
|
||||||
def explorerEndpoint = env.explorerEndpoint
|
def explorerEndpoint = env.explorerEndpoint
|
||||||
|
def explorer3Endpoint = env.explorer3Endpoint
|
||||||
def tablebaseEndpoint = env.tablebaseEndpoint
|
def tablebaseEndpoint = env.tablebaseEndpoint
|
||||||
|
|
||||||
def isChatPanicEnabled = env.chat.panic.enabled
|
def isChatPanicEnabled = env.chat.panic.enabled
|
||||||
|
|
|
@ -94,14 +94,11 @@ object replay {
|
||||||
embedJsUnsafeLoadThen(s"""LichessAnalyse.boot(${safeJsonValue(
|
embedJsUnsafeLoadThen(s"""LichessAnalyse.boot(${safeJsonValue(
|
||||||
Json
|
Json
|
||||||
.obj(
|
.obj(
|
||||||
"data" -> data,
|
"data" -> data,
|
||||||
"i18n" -> jsI18n(),
|
"i18n" -> jsI18n(),
|
||||||
"userId" -> ctx.userId,
|
"userId" -> ctx.userId,
|
||||||
"chat" -> chatJson,
|
"chat" -> chatJson,
|
||||||
"explorer" -> Json.obj(
|
"explorer" -> views.html.board.bits.explorerEndpoints
|
||||||
"endpoint" -> explorerEndpoint,
|
|
||||||
"tablebaseEndpoint" -> tablebaseEndpoint
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.add("hunter" -> isGranted(_.Hunter))
|
.add("hunter" -> isGranted(_.Hunter))
|
||||||
)})""")
|
)})""")
|
||||||
|
|
|
@ -42,6 +42,12 @@ object bits {
|
||||||
)
|
)
|
||||||
.add("fen" -> fen)
|
.add("fen" -> fen)
|
||||||
|
|
||||||
|
val explorerEndpoints = Json.obj(
|
||||||
|
"endpoint" -> explorerEndpoint,
|
||||||
|
"endpoint3" -> explorer3Endpoint,
|
||||||
|
"tablebaseEndpoint" -> tablebaseEndpoint
|
||||||
|
)
|
||||||
|
|
||||||
private val i18nKeyes = List(
|
private val i18nKeyes = List(
|
||||||
trans.setTheBoard,
|
trans.setTheBoard,
|
||||||
trans.boardEditor,
|
trans.boardEditor,
|
||||||
|
|
|
@ -28,13 +28,10 @@ object userAnalysis {
|
||||||
analyseNvuiTag,
|
analyseNvuiTag,
|
||||||
embedJsUnsafe(s"""lichess.userAnalysis=${safeJsonValue(
|
embedJsUnsafe(s"""lichess.userAnalysis=${safeJsonValue(
|
||||||
Json.obj(
|
Json.obj(
|
||||||
"data" -> data,
|
"data" -> data,
|
||||||
"i18n" -> userAnalysisI18n(withForecast = withForecast),
|
"i18n" -> userAnalysisI18n(withForecast = withForecast),
|
||||||
"explorer" -> Json.obj(
|
"explorer" -> bits.explorerEndpoints,
|
||||||
"endpoint" -> explorerEndpoint,
|
"wiki" -> pov.game.variant.standard
|
||||||
"tablebaseEndpoint" -> tablebaseEndpoint
|
|
||||||
),
|
|
||||||
"wiki" -> pov.game.variant.standard
|
|
||||||
)
|
)
|
||||||
)}""")
|
)}""")
|
||||||
),
|
),
|
||||||
|
|
|
@ -165,7 +165,8 @@ object userAnalysisI18n {
|
||||||
trans.maybeIncludeMoreGamesFromThePreferencesMenu,
|
trans.maybeIncludeMoreGamesFromThePreferencesMenu,
|
||||||
trans.winPreventedBy50MoveRule,
|
trans.winPreventedBy50MoveRule,
|
||||||
trans.lossSavedBy50MoveRule,
|
trans.lossSavedBy50MoveRule,
|
||||||
trans.allSet
|
trans.allSet,
|
||||||
|
trans.study.searchByUsername
|
||||||
).map(_.key)
|
).map(_.key)
|
||||||
|
|
||||||
private val forecastTranslations: Vector[MessageKey] = Vector(
|
private val forecastTranslations: Vector[MessageKey] = Vector(
|
||||||
|
|
|
@ -26,10 +26,7 @@ object show {
|
||||||
"study" -> data.study,
|
"study" -> data.study,
|
||||||
"data" -> data.analysis,
|
"data" -> data.analysis,
|
||||||
"i18n" -> board.userAnalysisI18n(),
|
"i18n" -> board.userAnalysisI18n(),
|
||||||
"explorer" -> Json.obj(
|
"explorer" -> views.html.board.bits.explorerEndpoints
|
||||||
"endpoint" -> explorerEndpoint,
|
|
||||||
"tablebaseEndpoint" -> tablebaseEndpoint
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)}""")
|
)}""")
|
||||||
),
|
),
|
||||||
|
|
|
@ -44,10 +44,7 @@ object show {
|
||||||
localMod = ctx.userId.??(rt.study.canContribute)
|
localMod = ctx.userId.??(rt.study.canContribute)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
"explorer" -> Json.obj(
|
"explorer" -> views.html.board.bits.explorerEndpoints,
|
||||||
"endpoint" -> explorerEndpoint,
|
|
||||||
"tablebaseEndpoint" -> tablebaseEndpoint
|
|
||||||
),
|
|
||||||
"socketUrl" -> views.html.study.show.socketUrl(rt.study.id.value),
|
"socketUrl" -> views.html.study.show.socketUrl(rt.study.id.value),
|
||||||
"socketVersion" -> socketVersion.value
|
"socketVersion" -> socketVersion.value
|
||||||
)
|
)
|
||||||
|
|
|
@ -43,10 +43,7 @@ object show {
|
||||||
localMod = ctx.userId exists s.canContribute
|
localMod = ctx.userId exists s.canContribute
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
"explorer" -> Json.obj(
|
"explorer" -> views.html.board.bits.explorerEndpoints,
|
||||||
"endpoint" -> explorerEndpoint,
|
|
||||||
"tablebaseEndpoint" -> tablebaseEndpoint
|
|
||||||
),
|
|
||||||
"socketUrl" -> socketUrl(s.id.value),
|
"socketUrl" -> socketUrl(s.id.value),
|
||||||
"socketVersion" -> socketVersion.value
|
"socketVersion" -> socketVersion.value
|
||||||
)
|
)
|
||||||
|
|
|
@ -324,6 +324,7 @@ streamer {
|
||||||
}
|
}
|
||||||
explorer {
|
explorer {
|
||||||
endpoint = "https://explorer.lichess.ovh"
|
endpoint = "https://explorer.lichess.ovh"
|
||||||
|
endpoint3 = "https://explorer.lichess.ovh"
|
||||||
internal_endpoint = "http://explorer.lichess.ovh"
|
internal_endpoint = "http://explorer.lichess.ovh"
|
||||||
tablebase = {
|
tablebase = {
|
||||||
endpoint = "https://tablebase.lichess.ovh"
|
endpoint = "https://tablebase.lichess.ovh"
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
@import 'layout';
|
@import 'layout';
|
||||||
@import 'tools';
|
@import 'tools';
|
||||||
@import 'action-menu';
|
@import 'action-menu';
|
||||||
@import 'explorer';
|
@import 'explorer/explorer';
|
||||||
@import 'training';
|
@import 'training';
|
||||||
@import 'practice';
|
@import 'practice';
|
||||||
@import 'fork';
|
@import 'fork';
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
.explorer__config {
|
||||||
|
section {
|
||||||
|
margin: 0.4em $block-gap 0 $block-gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
section.save {
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 0 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
|
display: block;
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choices {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
button {
|
||||||
|
@extend %metal;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: 5px 0;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
@include transition;
|
||||||
|
|
||||||
|
border: $border;
|
||||||
|
border-width: 1px 0 1px 1px;
|
||||||
|
text-transform: capitalize;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
@extend %box-radius-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
@extend %box-radius-right;
|
||||||
|
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
@extend %metal-hover;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-pressed='true'] {
|
||||||
|
background: $c-secondary;
|
||||||
|
color: $c-secondary-over;
|
||||||
|
text-shadow: 1px 0 0 rgba(0, 0, 0, 0.5);
|
||||||
|
font-weight: bold;
|
||||||
|
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2) inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
@extend %flex-center;
|
||||||
|
margin-top: 1em;
|
||||||
|
.user-link {
|
||||||
|
@extend %box-radius;
|
||||||
|
font-size: 1.3em;
|
||||||
|
padding-right: 1em;
|
||||||
|
|
||||||
|
background: mix($c-primary, $c-bg-box, 12%);
|
||||||
|
padding: 0.2em 0.6em;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__player__choice {
|
||||||
|
> div {
|
||||||
|
// for user complete
|
||||||
|
overflow: visible !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
// for user complete
|
||||||
|
overflow: visible !important;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
padding-top: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
@import './config';
|
||||||
|
|
||||||
.explorer-box {
|
.explorer-box {
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 2.5 1 0px;
|
flex: 2.5 1 0px;
|
||||||
|
@ -291,61 +293,4 @@
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.config {
|
|
||||||
section {
|
|
||||||
margin: 0.4em $block-gap 0 $block-gap;
|
|
||||||
}
|
|
||||||
|
|
||||||
section.save {
|
|
||||||
text-align: center;
|
|
||||||
padding: 15px 0 10px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-weight: bold;
|
|
||||||
display: block;
|
|
||||||
line-height: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.choices {
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
button {
|
|
||||||
@extend %metal;
|
|
||||||
flex-grow: 1;
|
|
||||||
padding: 5px 0;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
@include transition;
|
|
||||||
|
|
||||||
border: $border;
|
|
||||||
border-width: 1px 0 1px 1px;
|
|
||||||
text-transform: capitalize;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
@extend %box-radius-left;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
@extend %box-radius-right;
|
|
||||||
|
|
||||||
border-right-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
@extend %metal-hover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&[aria-pressed='true'] {
|
|
||||||
background: $c-secondary;
|
|
||||||
color: $c-secondary-over;
|
|
||||||
text-shadow: 1px 0 0 rgba(0, 0, 0, 0.5);
|
|
||||||
font-weight: bold;
|
|
||||||
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2) inset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,9 +1,10 @@
|
||||||
import { h, VNode } from 'snabbdom';
|
import { h, VNode } from 'snabbdom';
|
||||||
import { prop } from 'common';
|
import { prop } from 'common';
|
||||||
import { bind, dataIcon } from 'common/snabbdom';
|
import { bind, dataIcon, onInsert } from 'common/snabbdom';
|
||||||
import { storedProp, storedJsonProp, StoredJsonProp } from 'common/storage';
|
import { storedProp, storedJsonProp, StoredJsonProp } from 'common/storage';
|
||||||
import { Game } from '../interfaces';
|
import { Game } from '../interfaces';
|
||||||
import { ExplorerDb, ExplorerSpeed, ExplorerConfigData, ExplorerConfigCtrl } from './interfaces';
|
import { ExplorerDb, ExplorerSpeed, ExplorerConfigData, ExplorerConfigCtrl } from './interfaces';
|
||||||
|
import { snabModal } from 'common/modal';
|
||||||
|
|
||||||
const allSpeeds: ExplorerSpeed[] = ['bullet', 'blitz', 'rapid', 'classical'];
|
const allSpeeds: ExplorerSpeed[] = ['bullet', 'blitz', 'rapid', 'classical'];
|
||||||
const allRatings = [1600, 1800, 2000, 2200, 2500];
|
const allRatings = [1600, 1800, 2000, 2200, 2500];
|
||||||
|
@ -11,11 +12,11 @@ const allRatings = [1600, 1800, 2000, 2200, 2500];
|
||||||
export function controller(game: Game, onClose: () => void, trans: Trans, redraw: () => void): ExplorerConfigCtrl {
|
export function controller(game: Game, onClose: () => void, trans: Trans, redraw: () => void): ExplorerConfigCtrl {
|
||||||
const variant = game.variant.key === 'fromPosition' ? 'standard' : game.variant.key;
|
const variant = game.variant.key === 'fromPosition' ? 'standard' : game.variant.key;
|
||||||
|
|
||||||
const available: ExplorerDb[] = ['lichess'];
|
const available: ExplorerDb[] = ['lichess', 'player'];
|
||||||
if (variant === 'standard') available.unshift('masters');
|
if (variant === 'standard') available.unshift('masters');
|
||||||
|
|
||||||
const data: ExplorerConfigData = {
|
const data: ExplorerConfigData = {
|
||||||
open: prop(false),
|
open: prop(true),
|
||||||
db: {
|
db: {
|
||||||
available,
|
available,
|
||||||
selected:
|
selected:
|
||||||
|
@ -33,6 +34,10 @@ export function controller(game: Game, onClose: () => void, trans: Trans, redraw
|
||||||
available: allSpeeds,
|
available: allSpeeds,
|
||||||
selected: storedJsonProp<ExplorerSpeed[]>('explorer.speed', () => allSpeeds),
|
selected: storedJsonProp<ExplorerSpeed[]>('explorer.speed', () => allSpeeds),
|
||||||
},
|
},
|
||||||
|
playerName: {
|
||||||
|
open: prop(false),
|
||||||
|
value: storedProp<string | undefined>('explorer.player.name', document.body.dataset['user'] || ''),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleMany = function <T>(c: StoredJsonProp<T[]>, value: T) {
|
const toggleMany = function <T>(c: StoredJsonProp<T[]>, value: T) {
|
||||||
|
@ -68,69 +73,30 @@ export function controller(game: Game, onClose: () => void, trans: Trans, redraw
|
||||||
}
|
}
|
||||||
|
|
||||||
export function view(ctrl: ExplorerConfigCtrl): VNode[] {
|
export function view(ctrl: ExplorerConfigCtrl): VNode[] {
|
||||||
const d = ctrl.data;
|
|
||||||
return [
|
return [
|
||||||
h('section.db', [
|
h('section.db', [
|
||||||
h('label', ctrl.trans.noarg('database')),
|
h('label', ctrl.trans.noarg('database')),
|
||||||
h(
|
h(
|
||||||
'div.choices',
|
'div.choices',
|
||||||
d.db.available.map(function (s) {
|
ctrl.data.db.available.map(s =>
|
||||||
return h(
|
h(
|
||||||
'button',
|
'button',
|
||||||
{
|
{
|
||||||
attrs: {
|
attrs: {
|
||||||
'aria-pressed': `${d.db.selected() === s}`,
|
'aria-pressed': `${ctrl.data.db.selected() === s}`,
|
||||||
},
|
},
|
||||||
hook: bind('click', _ => ctrl.toggleDb(s), ctrl.redraw),
|
hook: bind('click', _ => ctrl.toggleDb(s), ctrl.redraw),
|
||||||
},
|
},
|
||||||
s
|
s
|
||||||
);
|
)
|
||||||
})
|
)
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
d.db.selected() === 'masters'
|
ctrl.data.db.selected() === 'masters'
|
||||||
? h('div.masters.message', [
|
? masterDb(ctrl)
|
||||||
h('i', { attrs: dataIcon('') }),
|
: ctrl.data.db.selected() === 'lichess'
|
||||||
h('p', ctrl.trans('masterDbExplanation', 2200, '1952', '2019')),
|
? lichessDb(ctrl)
|
||||||
])
|
: playerDb(ctrl),
|
||||||
: h('div', [
|
|
||||||
h('section.rating', [
|
|
||||||
h('label', ctrl.trans.noarg('averageElo')),
|
|
||||||
h(
|
|
||||||
'div.choices',
|
|
||||||
d.rating.available.map(function (r) {
|
|
||||||
return h(
|
|
||||||
'button',
|
|
||||||
{
|
|
||||||
attrs: {
|
|
||||||
'aria-pressed': `${d.rating.selected().includes(r)}`,
|
|
||||||
},
|
|
||||||
hook: bind('click', _ => ctrl.toggleRating(r), ctrl.redraw),
|
|
||||||
},
|
|
||||||
r.toString()
|
|
||||||
);
|
|
||||||
})
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
h('section.speed', [
|
|
||||||
h('label', ctrl.trans.noarg('timeControl')),
|
|
||||||
h(
|
|
||||||
'div.choices',
|
|
||||||
d.speed.available.map(function (s) {
|
|
||||||
return h(
|
|
||||||
'button',
|
|
||||||
{
|
|
||||||
attrs: {
|
|
||||||
'aria-pressed': `${d.speed.selected().includes(s)}`,
|
|
||||||
},
|
|
||||||
hook: bind('click', _ => ctrl.toggleSpeed(s), ctrl.redraw),
|
|
||||||
},
|
|
||||||
s
|
|
||||||
);
|
|
||||||
})
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
h(
|
h(
|
||||||
'section.save',
|
'section.save',
|
||||||
h(
|
h(
|
||||||
|
@ -144,3 +110,108 @@ export function view(ctrl: ExplorerConfigCtrl): VNode[] {
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const playerDb = (ctrl: ExplorerConfigCtrl) => {
|
||||||
|
const name = ctrl.data.playerName.value();
|
||||||
|
return h('div.player-db', [
|
||||||
|
ctrl.data.playerName.open() ? playerModal(ctrl) : undefined,
|
||||||
|
h('section.name', [
|
||||||
|
name
|
||||||
|
? h(
|
||||||
|
'span.user-link.ulpt',
|
||||||
|
{
|
||||||
|
hook: onInsert(lichess.powertip.manualUser),
|
||||||
|
attrs: { 'data-href': `/@/${name}` },
|
||||||
|
},
|
||||||
|
name
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
h(
|
||||||
|
`button.${name ? 'button-link' : 'button'}`,
|
||||||
|
{
|
||||||
|
hook: bind('click', () => ctrl.data.playerName.open(true), ctrl.redraw),
|
||||||
|
},
|
||||||
|
name ? 'Change' : 'Select a Lichess player'
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const playerModal = (ctrl: ExplorerConfigCtrl) => {
|
||||||
|
return snabModal({
|
||||||
|
class: 'explorer__config__player__choice',
|
||||||
|
onClose() {
|
||||||
|
ctrl.data.playerName.open(false);
|
||||||
|
ctrl.redraw();
|
||||||
|
},
|
||||||
|
content: [
|
||||||
|
h('h2', 'Personal opening explorer'),
|
||||||
|
h('div.input-wrapper', [
|
||||||
|
h('input', {
|
||||||
|
attrs: { placeholder: ctrl.trans.noarg('searchByUsername') },
|
||||||
|
hook: onInsert<HTMLInputElement>(input =>
|
||||||
|
lichess.userComplete().then(uac => {
|
||||||
|
uac({
|
||||||
|
input,
|
||||||
|
tag: 'span',
|
||||||
|
onSelect(v) {
|
||||||
|
// input.value = v.name;
|
||||||
|
ctrl.data.playerName.value(v.name);
|
||||||
|
ctrl.data.playerName.open(false);
|
||||||
|
ctrl.redraw();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
input.focus();
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const masterDb = (ctrl: ExplorerConfigCtrl) =>
|
||||||
|
h('div.masters.message', [
|
||||||
|
h('i', { attrs: dataIcon('') }),
|
||||||
|
h('p', ctrl.trans('masterDbExplanation', 2200, '1952', '2019')),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const lichessDb = (ctrl: ExplorerConfigCtrl) =>
|
||||||
|
h('div', [
|
||||||
|
h('section.rating', [
|
||||||
|
h('label', ctrl.trans.noarg('averageElo')),
|
||||||
|
h(
|
||||||
|
'div.choices',
|
||||||
|
ctrl.data.rating.available.map(r =>
|
||||||
|
h(
|
||||||
|
'button',
|
||||||
|
{
|
||||||
|
attrs: {
|
||||||
|
'aria-pressed': `${ctrl.data.rating.selected().includes(r)}`,
|
||||||
|
},
|
||||||
|
hook: bind('click', _ => ctrl.toggleRating(r), ctrl.redraw),
|
||||||
|
},
|
||||||
|
r.toString()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
h('section.speed', [
|
||||||
|
h('label', ctrl.trans.noarg('timeControl')),
|
||||||
|
h(
|
||||||
|
'div.choices',
|
||||||
|
ctrl.data.speed.available.map(s =>
|
||||||
|
h(
|
||||||
|
'button',
|
||||||
|
{
|
||||||
|
attrs: {
|
||||||
|
'aria-pressed': `${ctrl.data.speed.selected().includes(s)}`,
|
||||||
|
},
|
||||||
|
hook: bind('click', _ => ctrl.toggleSpeed(s), ctrl.redraw),
|
||||||
|
},
|
||||||
|
s
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
|
|
@ -78,7 +78,12 @@ export default function (root: AnalyseCtrl, opts: ExplorerOpts, allow: boolean):
|
||||||
? xhr.tablebase(opts.tablebaseEndpoint, effectiveVariant, fen)
|
? xhr.tablebase(opts.tablebaseEndpoint, effectiveVariant, fen)
|
||||||
: xhr.opening({
|
: xhr.opening({
|
||||||
endpoint: opts.endpoint,
|
endpoint: opts.endpoint,
|
||||||
|
endpoint3: opts.endpoint3,
|
||||||
db: config.data.db.selected() as ExplorerDb,
|
db: config.data.db.selected() as ExplorerDb,
|
||||||
|
personal: {
|
||||||
|
player: config.data.playerName.value(),
|
||||||
|
color: root.getOrientation(),
|
||||||
|
},
|
||||||
variant: effectiveVariant,
|
variant: effectiveVariant,
|
||||||
rootFen: root.nodeList[0].fen,
|
rootFen: root.nodeList[0].fen,
|
||||||
play: root.nodeList.slice(1).map(s => s.uci!),
|
play: root.nodeList.slice(1).map(s => s.uci!),
|
||||||
|
@ -180,6 +185,7 @@ export default function (root: AnalyseCtrl, opts: ExplorerOpts, allow: boolean):
|
||||||
return xhr
|
return xhr
|
||||||
.opening({
|
.opening({
|
||||||
endpoint: opts.endpoint,
|
endpoint: opts.endpoint,
|
||||||
|
endpoint3: opts.endpoint3,
|
||||||
db: 'masters',
|
db: 'masters',
|
||||||
rootFen: fen,
|
rootFen: fen,
|
||||||
play: [],
|
play: [],
|
||||||
|
|
|
@ -426,7 +426,7 @@ export default function (ctrl: AnalyseCtrl): VNode | undefined {
|
||||||
{
|
{
|
||||||
class: {
|
class: {
|
||||||
loading,
|
loading,
|
||||||
config: configOpened,
|
explorer__config: configOpened,
|
||||||
reduced: !configOpened && (!!explorer.failing() || explorer.movesAway() > 2),
|
reduced: !configOpened && (!!explorer.failing() || explorer.movesAway() > 2),
|
||||||
},
|
},
|
||||||
hook: {
|
hook: {
|
||||||
|
|
|
@ -3,7 +3,12 @@ import * as xhr from 'common/xhr';
|
||||||
|
|
||||||
interface OpeningXhrOpts {
|
interface OpeningXhrOpts {
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
|
endpoint3: string;
|
||||||
db: ExplorerDb;
|
db: ExplorerDb;
|
||||||
|
personal?: {
|
||||||
|
player: string;
|
||||||
|
color: Color;
|
||||||
|
};
|
||||||
rootFen: Fen;
|
rootFen: Fen;
|
||||||
play: string[];
|
play: string[];
|
||||||
fen: Fen;
|
fen: Fen;
|
||||||
|
@ -14,7 +19,8 @@ interface OpeningXhrOpts {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function opening(opts: OpeningXhrOpts): Promise<OpeningData> {
|
export function opening(opts: OpeningXhrOpts): Promise<OpeningData> {
|
||||||
const url = new URL(opts.db === 'lichess' ? '/lichess' : '/master', opts.endpoint);
|
const endpoint = opts.db == 'player' ? opts.endpoint3 : opts.endpoint;
|
||||||
|
const url = new URL(opts.db === 'lichess' ? '/lichess' : opts.db == 'player' ? '/personal' : '/master', endpoint);
|
||||||
const params = url.searchParams;
|
const params = url.searchParams;
|
||||||
params.set('fen', opts.rootFen);
|
params.set('fen', opts.rootFen);
|
||||||
params.set('play', opts.play.join(','));
|
params.set('play', opts.play.join(','));
|
||||||
|
@ -23,6 +29,11 @@ export function opening(opts: OpeningXhrOpts): Promise<OpeningData> {
|
||||||
if (opts.speeds) for (const speed of opts.speeds) params.append('speeds[]', speed);
|
if (opts.speeds) for (const speed of opts.speeds) params.append('speeds[]', speed);
|
||||||
if (opts.ratings) for (const rating of opts.ratings) params.append('ratings[]', rating.toString());
|
if (opts.ratings) for (const rating of opts.ratings) params.append('ratings[]', rating.toString());
|
||||||
}
|
}
|
||||||
|
if (opts.db === 'player' && opts.personal) {
|
||||||
|
params.set('player', opts.personal.player);
|
||||||
|
params.set('color', opts.personal.color);
|
||||||
|
// params.set('update', 'true');
|
||||||
|
}
|
||||||
if (!opts.withGames) {
|
if (!opts.withGames) {
|
||||||
params.set('topGames', '0');
|
params.set('topGames', '0');
|
||||||
params.set('recentGames', '0');
|
params.set('recentGames', '0');
|
||||||
|
|
|
@ -6,12 +6,17 @@ export interface Hovering {
|
||||||
uci: Uci;
|
uci: Uci;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExplorerDb = 'lichess' | 'masters';
|
export type ExplorerDb = 'lichess' | 'masters' | 'player';
|
||||||
|
|
||||||
export type ExplorerSpeed = 'bullet' | 'blitz' | 'rapid' | 'classical';
|
export type ExplorerSpeed = 'bullet' | 'blitz' | 'rapid' | 'classical';
|
||||||
|
|
||||||
|
export interface PlayerOpts {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ExplorerOpts {
|
export interface ExplorerOpts {
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
|
endpoint3: string;
|
||||||
tablebaseEndpoint: string;
|
tablebaseEndpoint: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +34,10 @@ export interface ExplorerConfigData {
|
||||||
available: ExplorerSpeed[];
|
available: ExplorerSpeed[];
|
||||||
selected: StoredJsonProp<ExplorerSpeed[]>;
|
selected: StoredJsonProp<ExplorerSpeed[]>;
|
||||||
};
|
};
|
||||||
|
playerName: {
|
||||||
|
open: Prop<boolean>;
|
||||||
|
value: StoredProp<string>;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExplorerConfigCtrl {
|
export interface ExplorerConfigCtrl {
|
||||||
|
|
Loading…
Reference in New Issue