mirror of
https://github.com/lichess-org/lila.git
synced 2026-05-26 13:51:00 +00:00
Merge branch 'master' into broadcast-infinite-scroll-15353
This commit is contained in:
@@ -84,7 +84,7 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env):
|
||||
env.relay.api.tourCreate(setup).flatMap { tour =>
|
||||
negotiate(
|
||||
Redirect(routes.RelayRound.form(tour.id)).flashSuccess,
|
||||
JsonOk(env.relay.jsonView(tour.withRounds(Nil), withUrls = true))
|
||||
JsonOk(env.relay.jsonView(tour.withRounds(Nil)))
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -170,7 +170,7 @@ final class RelayTour(env: Env, apiC: => Api) extends LilaController(env):
|
||||
env.relay.api
|
||||
.withRounds(tour)
|
||||
.map: trs =>
|
||||
Ok(env.relay.jsonView(trs, withUrls = true))
|
||||
Ok(env.relay.jsonView(trs))
|
||||
|
||||
def pgn(id: RelayTourId) = OpenOrScoped(): ctx ?=>
|
||||
Found(env.relay.api.tourById(id)): tour =>
|
||||
|
||||
@@ -388,14 +388,17 @@ final class User(
|
||||
}
|
||||
|
||||
val userLoginsFu = env.security.userLogins(user, nbOthers)
|
||||
val others = for
|
||||
val othersAndLogins = for
|
||||
userLogins <- userLoginsFu
|
||||
appeals <- env.appeal.api.byUserIds(user.id :: userLogins.otherUserIds)
|
||||
data <- loginsTableData(user, userLogins, nbOthers)
|
||||
yield views.user.mod.otherUsers(me, user, data, appeals)
|
||||
yield (views.user.mod.otherUsers(me, user, data, appeals), data)
|
||||
|
||||
val identification = userLoginsFu.map: logins =>
|
||||
isGranted(_.ViewPrintNoIP).so(views.user.mod.identification(logins))
|
||||
val identification = isGranted(_.ViewPrintNoIP).so:
|
||||
for
|
||||
logins <- userLoginsFu
|
||||
others <- othersAndLogins
|
||||
yield views.user.mod.identification(logins, others._2.othersPartiallyLoaded)
|
||||
|
||||
val kaladin = isGranted(_.MarkEngine).so(env.irwin.kaladinApi.get(user).map {
|
||||
_.flatMap(_.response).so(views.irwin.kaladin.report)
|
||||
@@ -426,7 +429,7 @@ final class User(
|
||||
.merge(modZoneSegment(reportLog, "reportLog", user))
|
||||
.merge(modZoneSegment(prefs, "prefs", user))
|
||||
.merge(modZoneSegment(rageSit, "rageSit", user))
|
||||
.merge(modZoneSegment(others, "others", user))
|
||||
.merge(modZoneSegment(othersAndLogins.map(_._1), "others", user))
|
||||
.merge(modZoneSegment(identification, "identification", user))
|
||||
.merge(modZoneSegment(kaladin, "kaladin", user))
|
||||
.merge(modZoneSegment(irwin, "irwin", user))
|
||||
|
||||
@@ -19,7 +19,7 @@ def notFound(msg: Option[String])(using Context) =
|
||||
),
|
||||
div(cls := "game")(
|
||||
iframe(
|
||||
src := assetUrl(s"vendor/ChessPursuit/bin-release/index.html"),
|
||||
src := staticAssetUrl(s"vendor/ChessPursuit/bin-release/index.html"),
|
||||
st.frameborder := 0,
|
||||
widthA := 400,
|
||||
heightA := 500,
|
||||
|
||||
@@ -24,10 +24,10 @@ object page:
|
||||
raw(s"""<meta name="theme-color" content="${ctx.pref.themeColor}">""")
|
||||
|
||||
private def boardPreload(using ctx: Context) = frag(
|
||||
preload(assetUrl(s"images/board/${ctx.pref.currentTheme.file}"), "image", crossorigin = false),
|
||||
preload(staticAssetUrl(s"images/board/${ctx.pref.currentTheme.file}"), "image", crossorigin = false),
|
||||
ctx.pref.is3d.option(
|
||||
preload(
|
||||
assetUrl(s"images/staunton/board/${ctx.pref.currentTheme3d.file}"),
|
||||
staticAssetUrl(s"images/staunton/board/${ctx.pref.currentTheme3d.file}"),
|
||||
"image",
|
||||
crossorigin = false
|
||||
)
|
||||
@@ -74,7 +74,7 @@ object page:
|
||||
content := p.openGraph.fold(trans.site.siteDescription.txt())(o => o.description),
|
||||
name := "description"
|
||||
),
|
||||
link(rel := "mask-icon", href := assetUrl("logo/lichess.svg"), attr("color") := "black"),
|
||||
link(rel := "mask-icon", href := staticAssetUrl("logo/lichess.svg"), attr("color") := "black"),
|
||||
favicons,
|
||||
(!p.robots || !netConfig.crawlable).option:
|
||||
raw("""<meta content="noindex, nofollow" name="robots">""")
|
||||
@@ -90,12 +90,12 @@ object page:
|
||||
fontPreload,
|
||||
boardPreload,
|
||||
manifests,
|
||||
jsLicense,
|
||||
p.withHrefLangs.map(hrefLangs),
|
||||
sitePreload(
|
||||
p.modules ++ p.pageModule.so(module => jsPageModule(module.name)),
|
||||
isInquiry = ctx.data.inquiry.isDefined
|
||||
),
|
||||
lichessFontFaceCss,
|
||||
(ctx.pref.bg === lila.pref.Pref.Bg.SYSTEM).so(systemThemeScript(ctx.nonce))
|
||||
),
|
||||
st.body(
|
||||
|
||||
@@ -33,8 +33,8 @@ object home:
|
||||
.css("lobby")
|
||||
.graph(
|
||||
OpenGraph(
|
||||
image = assetUrl("logo/lichess-tile-wide.png").some,
|
||||
twitterImage = assetUrl("logo/lichess-tile.png").some,
|
||||
image = staticAssetUrl("logo/lichess-tile-wide.png").some,
|
||||
twitterImage = staticAssetUrl("logo/lichess-tile.png").some,
|
||||
title = "The best free, adless Chess server",
|
||||
url = netBaseUrl.value,
|
||||
description = trans.site.siteDescription.txt()
|
||||
|
||||
@@ -109,7 +109,7 @@ object mod:
|
||||
tr(
|
||||
th(
|
||||
pluralize("linked user", userLogins.otherUsers.size),
|
||||
(max < 1000 || othersWithEmail.others.sizeIs >= max).option(
|
||||
(max < 1000 || othersPartiallyLoaded).option(
|
||||
frag(
|
||||
nbsp,
|
||||
a(cls := "more-others")("Load more")
|
||||
@@ -211,7 +211,10 @@ object mod:
|
||||
case email => frag(email)
|
||||
}
|
||||
|
||||
def identification(logins: UserLogins)(using ctx: Context, renderIp: RenderIp): Frag =
|
||||
def identification(logins: UserLogins, othersPartiallyLoaded: Boolean)(using
|
||||
ctx: Context,
|
||||
renderIp: RenderIp
|
||||
): Frag =
|
||||
val canIpBan = Granter.opt(_.IpBan)
|
||||
val canFpBan = Granter.opt(_.PrintBan)
|
||||
val canLocate = Granter.opt(_.Admin)
|
||||
@@ -301,7 +304,7 @@ object mod:
|
||||
button(
|
||||
cls := List(
|
||||
"button button-empty" -> true,
|
||||
"button-discouraging" -> (ip.alts.cleans > 0)
|
||||
"button-discouraging" -> (ip.alts.cleans > 0 || othersPartiallyLoaded)
|
||||
),
|
||||
href := routes.Mod.singleIpBan(!ip.blocked, ip.ip.value.value)
|
||||
)("BAN")
|
||||
@@ -335,7 +338,7 @@ object mod:
|
||||
button(
|
||||
cls := List(
|
||||
"button button-empty" -> true,
|
||||
"button-discouraging" -> (fp.alts.cleans > 0)
|
||||
"button-discouraging" -> (fp.alts.cleans > 0 || othersPartiallyLoaded)
|
||||
),
|
||||
href := routes.Mod.printBan(!fp.banned, fp.fp.value.value)
|
||||
)("BAN")
|
||||
|
||||
@@ -26,8 +26,8 @@ object page:
|
||||
Page(s"${u.username} : ${trans.activity.activity.txt()}")
|
||||
.graph(
|
||||
OpenGraph(
|
||||
image = assetUrl("logo/lichess-tile-wide.png").some,
|
||||
twitterImage = assetUrl("logo/lichess-tile.png").some,
|
||||
image = staticAssetUrl("logo/lichess-tile-wide.png").some,
|
||||
twitterImage = staticAssetUrl("logo/lichess-tile.png").some,
|
||||
title = u.titleUsernameWithBestRating,
|
||||
url = s"$netBaseUrl${routes.User.show(u.username).url}",
|
||||
description = ui.describeUser(u)
|
||||
|
||||
@@ -153,7 +153,7 @@ final class PostUi(helpers: Helpers, bits: ForumBits):
|
||||
else r.key
|
||||
}
|
||||
)(
|
||||
img(src := assetUrl(s"images/emoji/$r.png"), alt := r.key),
|
||||
img(src := staticAssetUrl(s"images/emoji/$r.png"), alt := r.key),
|
||||
(size > 0).option(size)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -11,13 +11,9 @@ final class TwoFactorUi(helpers: Helpers, ui: AccountUi):
|
||||
import trans.{ tfa as trt }
|
||||
import ui.AccountPage
|
||||
|
||||
private val qrCode = raw:
|
||||
"""<div style="width: 276px; height: 276px; padding: 10px; background: white; margin: 2em auto;"><div id="qrcode" style="width: 256px; height: 256px;"></div></div>"""
|
||||
|
||||
def setup(form: Form[?])(using Context)(using me: Me) =
|
||||
ui.AccountPage(s"${me.username} - ${trt.twoFactorAuth.txt()}", "twofactor")
|
||||
.iife(iifeModule("javascripts/vendor/qrcode.min.js"))
|
||||
.iife(iifeModule("javascripts/twofactor.form.js")):
|
||||
.js(EsmInit("bits.twofactor")):
|
||||
div(cls := "twofactor box box-pad")(
|
||||
h1(cls := "box__top")(trt.twoFactorAuth()),
|
||||
standardFlash,
|
||||
@@ -39,10 +35,10 @@ final class TwoFactorUi(helpers: Helpers, ui: AccountUi):
|
||||
p(strong("iOS"), " : ", a(href := "https://2fas.com/")("2FAS"))
|
||||
),
|
||||
div(cls := "form-group")(trt.scanTheCode()),
|
||||
qrCode,
|
||||
canvas(id := "qrcode"),
|
||||
div(cls := "form-group"):
|
||||
trt.ifYouCannotScanEnterX:
|
||||
span(style := "background:black;color:black;")(form("secret").value.orZero: String)
|
||||
span(cls := "redacted")(form("secret").value.orZero: String)
|
||||
,
|
||||
div(cls := "form-group explanation")(trt.enterPassword()),
|
||||
form3.hidden(form("secret")),
|
||||
|
||||
@@ -52,17 +52,17 @@ final class JsonView(
|
||||
.add("ongoing" -> (r.hasStarted && !r.finished))
|
||||
.add("startsAt" -> r.startsAt.orElse(r.startedAt))
|
||||
|
||||
def apply(trs: RelayTour.WithRounds, withUrls: Boolean = false): JsObject =
|
||||
def apply(trs: RelayTour.WithRounds): JsObject =
|
||||
Json
|
||||
.obj(
|
||||
"tour" -> Json
|
||||
.toJsObject(trs.tour)
|
||||
.add("markup" -> trs.tour.markup.map(markup(trs.tour)))
|
||||
.add("url" -> withUrls.option(s"$baseUrl${trs.tour.path}"))
|
||||
.add("url" -> s"$baseUrl${trs.tour.path}".some)
|
||||
.add("teamTable" -> trs.tour.teamTable)
|
||||
.add("leaderboard" -> trs.tour.autoLeaderboard),
|
||||
"rounds" -> trs.rounds.map: round =>
|
||||
if withUrls then withUrl(round.withTour(trs.tour), withTour = false) else apply(round)
|
||||
withUrl(round.withTour(trs.tour), withTour = false)
|
||||
)
|
||||
|
||||
def apply(round: RelayRound): JsObject = Json.toJsObject(round)
|
||||
|
||||
@@ -52,7 +52,7 @@ final class RelayTourUi(helpers: Helpers, ui: RelayUi):
|
||||
Page(trc.liveBroadcasts.txt())
|
||||
.css("relay.index")
|
||||
.js(infiniteScrollEsmInit):
|
||||
main(cls := "relay-index page-menu")(div(cls := "page-menu__content box box-pad")(body))
|
||||
main(cls := "relay-index page-menu")(menu, div(cls := "page-menu__content box box-pad")(body))
|
||||
|
||||
def search(pager: Paginator[WithLastRound], query: String)(using Context) =
|
||||
listLayout(trc.liveBroadcasts.txt(), pageMenu("index"))(
|
||||
|
||||
@@ -249,3 +249,4 @@ object UserLogins:
|
||||
def withUsers[V: UserIdOf](users: List[V]) = copy(
|
||||
othersWithEmail = othersWithEmail.withUsers(users)
|
||||
)
|
||||
def othersPartiallyLoaded = othersWithEmail.others.sizeIs >= max
|
||||
|
||||
@@ -13,11 +13,9 @@ trait AssetHelper:
|
||||
def manifest: AssetManifest
|
||||
def assetBaseUrl: AssetBaseUrl
|
||||
def assetUrl(path: String): String
|
||||
def infiniteScrollEsmInit: EsmInit
|
||||
def captchaEsmInit: EsmInit
|
||||
def safeJsonValue(jsValue: JsValue): SafeJsonStr
|
||||
|
||||
val load = "site.asset.loadEsm"
|
||||
private val load = "site.asset.loadEsm"
|
||||
|
||||
given Conversion[EsmInit, EsmList] with
|
||||
def apply(esmInit: EsmInit): EsmList = List(Some(esmInit))
|
||||
@@ -33,6 +31,9 @@ trait AssetHelper:
|
||||
def jsPageModule(key: String): EsmInit =
|
||||
EsmInit(key, embedJsUnsafeLoadThen(s"site.asset.loadPageEsm('$key')"))
|
||||
|
||||
val infiniteScrollEsmInit: EsmInit = jsModuleInit("bits.infiniteScroll")
|
||||
val captchaEsmInit: EsmInit = EsmInit("bits.captcha")
|
||||
|
||||
// load iife scripts in <head> and defer
|
||||
def iifeModule(path: String): Frag = script(deferAttr, src := assetUrl(path))
|
||||
|
||||
|
||||
@@ -220,7 +220,7 @@ final class VideoUi(helpers: Helpers)(using NetDomain):
|
||||
ts.sortBy(_.tag).map { t =>
|
||||
a(cls := "tag", href := s"${routes.Video.index}?tags=${t.tag}")(
|
||||
t.tag.capitalize,
|
||||
em(t.nb)
|
||||
em(" " + t.nb)
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -52,11 +52,9 @@ trait AssetFullHelper:
|
||||
manifest.deps(keys).map { dep =>
|
||||
script(tpe := "module", src := staticAssetUrl(s"compiled/$dep"))
|
||||
}
|
||||
def roundNvuiTag(using ctx: Context) = ctx.blind.option(EsmInit("round.nvui"))
|
||||
lazy val infiniteScrollEsmInit: EsmInit = jsModuleInit("bits.infiniteScroll")
|
||||
lazy val captchaEsmInit: EsmInit = EsmInit("bits.captcha")
|
||||
lazy val cashTag: Frag = iifeModule("javascripts/vendor/cash.min.js")
|
||||
lazy val chessgroundTag: Frag = script(tpe := "module", src := assetUrl("npm/chessground.min.js"))
|
||||
def roundNvuiTag(using ctx: Context) = ctx.blind.option(EsmInit("round.nvui"))
|
||||
lazy val cashTag: Frag = iifeModule("javascripts/vendor/cash.min.js")
|
||||
lazy val chessgroundTag: Frag = script(tpe := "module", src := assetUrl("npm/chessground.min.js"))
|
||||
|
||||
def basicCsp(using ctx: Context): ContentSecurityPolicy =
|
||||
val sockets = socketDomains.map { x => s"wss://$x${(!ctx.req.secure).so(s" ws://$x")}" }
|
||||
|
||||
@@ -35,7 +35,6 @@ final class layout(helpers: Helpers, assetHelper: lila.web.ui.AssetFullHelper)(
|
||||
)(nonce)
|
||||
def pieceSprite(name: String): Frag =
|
||||
link(id := "piece-sprite", href := assetUrl(s"piece-css/$name.css"), rel := "stylesheet")
|
||||
|
||||
val noTranslate = raw("""<meta name="google" content="notranslate">""")
|
||||
|
||||
def preload(href: String, as: String, crossorigin: Boolean, tpe: Option[String] = None) =
|
||||
@@ -46,13 +45,13 @@ final class layout(helpers: Helpers, assetHelper: lila.web.ui.AssetFullHelper)(
|
||||
def fontPreload(using ctx: Context) = frag(
|
||||
preload(assetUrl("font/lichess.woff2"), "font", crossorigin = true, "font/woff2".some),
|
||||
preload(
|
||||
assetUrl("font/noto-sans-v14-latin-regular.woff2"),
|
||||
staticAssetUrl("font/noto-sans-v14-latin-regular.woff2"),
|
||||
"font",
|
||||
crossorigin = true,
|
||||
"font/woff2".some
|
||||
),
|
||||
(!ctx.pref.pieceNotationIsLetter).option(
|
||||
preload(assetUrl("font/lichess.chess.woff2"), "font", crossorigin = true, "font/woff2".some)
|
||||
preload(staticAssetUrl("font/lichess.chess.woff2"), "font", crossorigin = true, "font/woff2".some)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -93,7 +92,7 @@ final class layout(helpers: Helpers, assetHelper: lila.web.ui.AssetFullHelper)(
|
||||
|
||||
def botImage =
|
||||
img(
|
||||
src := assetUrl("images/icons/bot.png"),
|
||||
src := staticAssetUrl("images/icons/bot.png"),
|
||||
title := "Robot chess",
|
||||
style := "display:inline;width:34px;height:34px;vertical-align:top;margin-right:5px;vertical-align:text-top"
|
||||
)
|
||||
@@ -101,20 +100,14 @@ final class layout(helpers: Helpers, assetHelper: lila.web.ui.AssetFullHelper)(
|
||||
val manifests = raw:
|
||||
"""<link rel="manifest" href="/manifest.json"><meta name="twitter:site" content="@lichess">"""
|
||||
|
||||
val jsLicense = raw("""<link rel="jslicense" href="/source">""")
|
||||
|
||||
val favicons = raw:
|
||||
List(512, 256, 192, 128, 64)
|
||||
.map: px =>
|
||||
s"""<link rel="icon" type="image/png" href="${assetUrl(
|
||||
s"logo/lichess-favicon-$px.png"
|
||||
)}" sizes="${px}x$px">"""
|
||||
s"""<link rel="icon" type="image/png" href="$assetBaseUrl/assets/logo/lichess-favicon-$px.png" sizes="${px}x$px">"""
|
||||
.mkString(
|
||||
"",
|
||||
"",
|
||||
s"""<link id="favicon" rel="icon" type="image/png" href="${assetUrl(
|
||||
"logo/lichess-favicon-32.png"
|
||||
)}" sizes="32x32">"""
|
||||
s"""<link id="favicon" rel="icon" type="image/png" href="$assetBaseUrl/assets/logo/lichess-favicon-32.png" sizes="32x32">"""
|
||||
)
|
||||
def blindModeForm(using ctx: Context) = raw:
|
||||
s"""<form id="blind-mode" action="${routes.Main.toggleBlindMode}" method="POST"><input type="hidden" name="enable" value="${
|
||||
@@ -218,6 +211,15 @@ final class layout(helpers: Helpers, assetHelper: lila.web.ui.AssetFullHelper)(
|
||||
private val spaceRegex = """\s{2,}+""".r
|
||||
def spaceless(html: String) = raw(spaceRegex.replaceAllIn(html.replace("\\n", ""), ""))
|
||||
|
||||
val lichessFontFaceCss = spaceless:
|
||||
s"""<style>@font-face {
|
||||
font-family: 'lichess';
|
||||
font-display: block;
|
||||
src:
|
||||
url('${assetUrl("font/lichess.woff2")}') format('woff2'),
|
||||
url('${assetUrl("font/lichess.woff")}') format('woff');
|
||||
}</style>"""
|
||||
|
||||
def bottomHtml(using ctx: Context) = frag(
|
||||
ctx.me
|
||||
.exists(_.enabled.yes)
|
||||
|
||||
Generated
+129
@@ -70,6 +70,9 @@ importers:
|
||||
'@types/debounce-promise':
|
||||
specifier: ^3.1.9
|
||||
version: 3.1.9
|
||||
'@types/sortablejs':
|
||||
specifier: ^1.15.8
|
||||
version: 1.15.8
|
||||
'@types/yaireo__tagify':
|
||||
specifier: 4.17.5
|
||||
version: 4.17.5
|
||||
@@ -115,6 +118,9 @@ importers:
|
||||
snabbdom:
|
||||
specifier: 3.5.1
|
||||
version: 3.5.1
|
||||
sortablejs:
|
||||
specifier: ^1.15.2
|
||||
version: 1.15.2
|
||||
tree:
|
||||
specifier: workspace:*
|
||||
version: link:../tree
|
||||
@@ -139,6 +145,9 @@ importers:
|
||||
'@types/fnando__sparkline':
|
||||
specifier: ^0.3.7
|
||||
version: 0.3.7
|
||||
'@types/qrcode':
|
||||
specifier: ^1.5.5
|
||||
version: 1.5.5
|
||||
'@types/yaireo__tagify':
|
||||
specifier: 4.17.5
|
||||
version: 4.17.5
|
||||
@@ -175,6 +184,9 @@ importers:
|
||||
prop-types:
|
||||
specifier: ^15.8.1
|
||||
version: 15.8.1
|
||||
qrcode:
|
||||
specifier: ^1.5.3
|
||||
version: 1.5.3
|
||||
tablesort:
|
||||
specifier: ^5.3.0
|
||||
version: 5.3.0
|
||||
@@ -1179,12 +1191,18 @@ packages:
|
||||
'@types/prop-types@15.7.12':
|
||||
resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==}
|
||||
|
||||
'@types/qrcode@1.5.5':
|
||||
resolution: {integrity: sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==}
|
||||
|
||||
'@types/react@18.2.74':
|
||||
resolution: {integrity: sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==}
|
||||
|
||||
'@types/semver@7.5.8':
|
||||
resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==}
|
||||
|
||||
'@types/sortablejs@1.15.8':
|
||||
resolution: {integrity: sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==}
|
||||
|
||||
'@types/stack-utils@2.0.3':
|
||||
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
|
||||
|
||||
@@ -1488,6 +1506,9 @@ packages:
|
||||
resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
cliui@6.0.0:
|
||||
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
|
||||
|
||||
cliui@8.0.1:
|
||||
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1559,6 +1580,10 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
|
||||
decamelize@1.2.0:
|
||||
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
dedent@1.5.1:
|
||||
resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==}
|
||||
peerDependencies:
|
||||
@@ -1585,6 +1610,9 @@ packages:
|
||||
resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
|
||||
dijkstrajs@1.0.3:
|
||||
resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1615,6 +1643,9 @@ packages:
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
encode-utf8@1.0.3:
|
||||
resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==}
|
||||
|
||||
error-ex@1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
|
||||
@@ -2334,6 +2365,10 @@ packages:
|
||||
resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
pngjs@5.0.0:
|
||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
|
||||
prelude-ls@1.2.1:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@@ -2385,6 +2420,11 @@ packages:
|
||||
pure-rand@6.1.0:
|
||||
resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
|
||||
|
||||
qrcode@1.5.3:
|
||||
resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
@@ -2402,6 +2442,9 @@ packages:
|
||||
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
require-main-filename@2.0.0:
|
||||
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||
|
||||
resolve-cwd@3.0.0:
|
||||
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2458,6 +2501,9 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
set-blocking@2.0.0:
|
||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2496,6 +2542,9 @@ packages:
|
||||
resolution: {integrity: sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==}
|
||||
engines: {node: '>=8.3.0'}
|
||||
|
||||
sortablejs@1.15.2:
|
||||
resolution: {integrity: sha512-FJF5jgdfvoKn1MAKSdGs33bIqLi3LmsgVTliuX6iITj834F+JRQZN90Z93yql8h0K2t0RwDPBmxwlbZfDcxNZA==}
|
||||
|
||||
source-map-support@0.5.13:
|
||||
resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
|
||||
|
||||
@@ -2703,11 +2752,18 @@ packages:
|
||||
resolution: {integrity: sha512-1AQO+d4ElfVSXyzNVTOewgGT/tAomwwztX/6e3totvyyzXPvXIIuUUjAmyZGbKBKbZOXauuJooZm3g6IuFuiNQ==}
|
||||
engines: {node: '>=6.0.0', npm: '>=3.10.0'}
|
||||
|
||||
which-module@2.0.1:
|
||||
resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}
|
||||
|
||||
which@2.0.2:
|
||||
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||
engines: {node: '>= 8'}
|
||||
hasBin: true
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2731,6 +2787,9 @@ packages:
|
||||
resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==}
|
||||
engines: {node: '>=4.0'}
|
||||
|
||||
y18n@4.0.3:
|
||||
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
|
||||
|
||||
y18n@5.0.8:
|
||||
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -2745,10 +2804,18 @@ packages:
|
||||
resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==}
|
||||
engines: {node: '>= 14'}
|
||||
|
||||
yargs-parser@18.1.3:
|
||||
resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
yargs-parser@21.1.1:
|
||||
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
yargs@15.4.1:
|
||||
resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
yargs@17.7.2:
|
||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -3322,6 +3389,10 @@ snapshots:
|
||||
|
||||
'@types/prop-types@15.7.12': {}
|
||||
|
||||
'@types/qrcode@1.5.5':
|
||||
dependencies:
|
||||
'@types/node': 20.12.2
|
||||
|
||||
'@types/react@18.2.74':
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.12
|
||||
@@ -3329,6 +3400,8 @@ snapshots:
|
||||
|
||||
'@types/semver@7.5.8': {}
|
||||
|
||||
'@types/sortablejs@1.15.8': {}
|
||||
|
||||
'@types/stack-utils@2.0.3': {}
|
||||
|
||||
'@types/web@0.0.142': {}
|
||||
@@ -3670,6 +3743,12 @@ snapshots:
|
||||
slice-ansi: 5.0.0
|
||||
string-width: 7.1.0
|
||||
|
||||
cliui@6.0.0:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
|
||||
cliui@8.0.1:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
@@ -3735,6 +3814,8 @@ snapshots:
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
decamelize@1.2.0: {}
|
||||
|
||||
dedent@1.5.1: {}
|
||||
|
||||
deep-is@0.1.4: {}
|
||||
@@ -3747,6 +3828,8 @@ snapshots:
|
||||
|
||||
diff-sequences@29.6.3: {}
|
||||
|
||||
dijkstrajs@1.0.3: {}
|
||||
|
||||
dir-glob@3.0.1:
|
||||
dependencies:
|
||||
path-type: 4.0.0
|
||||
@@ -3769,6 +3852,8 @@ snapshots:
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
encode-utf8@1.0.3: {}
|
||||
|
||||
error-ex@1.3.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.2.1
|
||||
@@ -4673,6 +4758,8 @@ snapshots:
|
||||
dependencies:
|
||||
find-up: 4.1.0
|
||||
|
||||
pngjs@5.0.0: {}
|
||||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prettier@3.0.2: {}
|
||||
@@ -4741,6 +4828,13 @@ snapshots:
|
||||
|
||||
pure-rand@6.1.0: {}
|
||||
|
||||
qrcode@1.5.3:
|
||||
dependencies:
|
||||
dijkstrajs: 1.0.3
|
||||
encode-utf8: 1.0.3
|
||||
pngjs: 5.0.0
|
||||
yargs: 15.4.1
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
react-is@16.13.1: {}
|
||||
@@ -4753,6 +4847,8 @@ snapshots:
|
||||
|
||||
require-directory@2.1.1: {}
|
||||
|
||||
require-main-filename@2.0.0: {}
|
||||
|
||||
resolve-cwd@3.0.0:
|
||||
dependencies:
|
||||
resolve-from: 5.0.0
|
||||
@@ -4798,6 +4894,8 @@ snapshots:
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
|
||||
set-blocking@2.0.0: {}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
@@ -4829,6 +4927,8 @@ snapshots:
|
||||
|
||||
snabbdom@3.5.1: {}
|
||||
|
||||
sortablejs@1.15.2: {}
|
||||
|
||||
source-map-support@0.5.13:
|
||||
dependencies:
|
||||
buffer-from: 1.1.2
|
||||
@@ -5006,10 +5106,18 @@ snapshots:
|
||||
dependencies:
|
||||
sdp: 3.2.0
|
||||
|
||||
which-module@2.0.1: {}
|
||||
|
||||
which@2.0.2:
|
||||
dependencies:
|
||||
isexe: 2.0.0
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
wrap-ansi@7.0.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
@@ -5036,6 +5144,8 @@ snapshots:
|
||||
|
||||
xmlbuilder@11.0.1: {}
|
||||
|
||||
y18n@4.0.3: {}
|
||||
|
||||
y18n@5.0.8: {}
|
||||
|
||||
yallist@3.1.1: {}
|
||||
@@ -5044,8 +5154,27 @@ snapshots:
|
||||
|
||||
yaml@2.3.4: {}
|
||||
|
||||
yargs-parser@18.1.3:
|
||||
dependencies:
|
||||
camelcase: 5.3.1
|
||||
decamelize: 1.2.0
|
||||
|
||||
yargs-parser@21.1.1: {}
|
||||
|
||||
yargs@15.4.1:
|
||||
dependencies:
|
||||
cliui: 6.0.0
|
||||
decamelize: 1.2.0
|
||||
find-up: 4.1.0
|
||||
get-caller-file: 2.0.5
|
||||
require-directory: 2.1.1
|
||||
require-main-filename: 2.0.0
|
||||
set-blocking: 2.0.0
|
||||
string-width: 4.2.3
|
||||
which-module: 2.0.1
|
||||
y18n: 4.0.3
|
||||
yargs-parser: 18.1.3
|
||||
|
||||
yargs@17.7.2:
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
$(function () {
|
||||
var issuer = window.location.host; // lichess.org
|
||||
var user = document.body.dataset.user;
|
||||
var secret = $('input[name=secret]').val();
|
||||
new QRCode(document.getElementById('qrcode'), {
|
||||
text: 'otpauth://totp/' + issuer + ':' + user + '?secret=' + secret + '&issuer=' + issuer,
|
||||
});
|
||||
});
|
||||
-2
File diff suppressed because one or more lines are too long
-16
File diff suppressed because one or more lines are too long
Vendored
+8
-5
@@ -39,7 +39,7 @@ interface Site {
|
||||
removeCssPath(path: string): void;
|
||||
jsModule(name: string): string;
|
||||
loadIife(path: string, opts?: AssetUrlOpts): Promise<void>;
|
||||
loadEsm<T, ModuleOpts = any>(name: string, opts?: { init?: ModuleOpts; url?: AssetUrlOpts }): Promise<T>;
|
||||
loadEsm<T>(name: string, opts?: EsmModuleOpts): Promise<T>;
|
||||
userComplete(opts: UserCompleteOpts): Promise<UserComplete>;
|
||||
};
|
||||
idleTimer(delay: number, onIdle: () => void, onWakeUp: () => void): void;
|
||||
@@ -89,6 +89,11 @@ interface Site {
|
||||
manifest: { css: Record<string, string>; js: Record<string, string> };
|
||||
}
|
||||
|
||||
interface EsmModuleOpts extends AssetUrlOpts {
|
||||
init?: any;
|
||||
npm?: boolean;
|
||||
}
|
||||
|
||||
interface LichessLog {
|
||||
(...args: any[]): Promise<void>;
|
||||
clear(): Promise<void>;
|
||||
@@ -190,9 +195,8 @@ interface Cookie {
|
||||
|
||||
interface AssetUrlOpts {
|
||||
documentOrigin?: boolean;
|
||||
sameDomain?: boolean;
|
||||
noVersion?: boolean;
|
||||
version?: string;
|
||||
pathOnly?: boolean;
|
||||
version?: false | string;
|
||||
}
|
||||
|
||||
type Timeout = ReturnType<typeof setTimeout>;
|
||||
@@ -311,7 +315,6 @@ interface Window {
|
||||
readonly Stripe: any;
|
||||
readonly Textcomplete: any;
|
||||
readonly UserComplete: any;
|
||||
readonly Sortable: any;
|
||||
readonly Tagify: unknown;
|
||||
readonly paypalOrder: unknown;
|
||||
readonly paypalSubscription: unknown;
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
.player {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-inline-start: 10px;
|
||||
margin: 0 1em;
|
||||
}
|
||||
|
||||
.no-square {
|
||||
@@ -65,8 +65,9 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.instruction > * {
|
||||
display: block;
|
||||
.instruction {
|
||||
@extend %flex-column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.instruction > strong {
|
||||
@@ -75,6 +76,7 @@
|
||||
}
|
||||
|
||||
.choices {
|
||||
@extend %flex-between;
|
||||
line-height: 1.6em;
|
||||
margin: 5px 0 -5px 0;
|
||||
}
|
||||
|
||||
@@ -46,10 +46,8 @@ $span-width: 1.7em;
|
||||
}
|
||||
|
||||
.sortable-ghost {
|
||||
opacity: 0.7;
|
||||
|
||||
&,
|
||||
.status {
|
||||
span {
|
||||
background: $c-secondary !important;
|
||||
color: $c-over !important;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"dependencies": {
|
||||
"@badrap/result": "^0.2.13",
|
||||
"@types/debounce-promise": "^3.1.9",
|
||||
"@types/sortablejs": "^1.15.8",
|
||||
"@types/yaireo__tagify": "4.17.5",
|
||||
"@yaireo/tagify": "4.17.9",
|
||||
"ceval": "workspace:*",
|
||||
@@ -31,6 +32,7 @@
|
||||
"prop-types": "^15.8.1",
|
||||
"shepherd.js": "^11.2.0",
|
||||
"snabbdom": "3.5.1",
|
||||
"sortablejs": "^1.15.2",
|
||||
"tree": "workspace:*"
|
||||
},
|
||||
"lichess": {
|
||||
@@ -42,7 +44,8 @@
|
||||
"src/plugins/analyse.study.tour.ts"
|
||||
],
|
||||
"sync": {
|
||||
"node_modules/@yaireo/tagify/dist/tagify.min.js": "public/npm/tagify"
|
||||
"node_modules/@yaireo/tagify/dist/tagify.min.js": "public/npm/tagify",
|
||||
"node_modules/sortablejs/modular/sortable.esm.js": "public/npm"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import StudyCtrl from './studyCtrl';
|
||||
import { opposite } from 'chessops/util';
|
||||
import { fenColor } from 'common/miniBoard';
|
||||
import { initialFen } from 'chess';
|
||||
import type Sortable from 'sortablejs';
|
||||
|
||||
/* read-only interface for external use */
|
||||
export class StudyChapters {
|
||||
@@ -166,15 +167,13 @@ export function view(ctrl: StudyCtrl): VNode {
|
||||
}
|
||||
vData.count = newCount;
|
||||
if (canContribute && newCount > 1 && !vData.sortable) {
|
||||
const makeSortable = () => {
|
||||
vData.sortable = window.Sortable.create(el, {
|
||||
site.asset.loadEsm<typeof Sortable>('sortable.esm', { npm: true }).then(s => {
|
||||
vData.sortable = s.create(el, {
|
||||
draggable: '.draggable',
|
||||
handle: 'ontouchstart' in window ? 'span' : undefined,
|
||||
onSort: () => ctrl.chapters.sort(vData.sortable.toArray()),
|
||||
});
|
||||
};
|
||||
if (window.Sortable) makeSortable();
|
||||
else site.asset.loadIife('javascripts/vendor/Sortable.min.js').then(makeSortable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +200,7 @@ export function view(ctrl: StudyCtrl): VNode {
|
||||
update(vnode);
|
||||
},
|
||||
destroy: vnode => {
|
||||
const sortable = vnode.data!.li!.sortable;
|
||||
const sortable: Sortable = vnode.data!.li!.sortable;
|
||||
if (sortable) sortable.destroy();
|
||||
},
|
||||
},
|
||||
|
||||
@@ -284,11 +284,8 @@ export function renderControls(ctrl: AnalyseCtrl) {
|
||||
else if (action === 'explorer') ctrl.toggleExplorer();
|
||||
else if (action === 'practice') ctrl.togglePractice();
|
||||
else if (action === 'menu') ctrl.actionMenu.toggle();
|
||||
else if (action === 'analysis' && ctrl.studyPractice) {
|
||||
if (!window.open(ctrl.studyPractice.analysisUrl(), '_blank', 'noopener')) {
|
||||
window.location.href = ctrl.studyPractice.analysisUrl(); //safari
|
||||
}
|
||||
}
|
||||
else if (action === 'analysis' && ctrl.studyPractice)
|
||||
window.open(ctrl.studyPractice.analysisUrl(), '_blank', 'noopener');
|
||||
}, ctrl.redraw),
|
||||
),
|
||||
},
|
||||
|
||||
@@ -35,8 +35,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.twofactor ol li {
|
||||
list-style: decimal;
|
||||
.twofactor {
|
||||
canvas {
|
||||
display: block;
|
||||
margin: 2em auto;
|
||||
}
|
||||
.redacted {
|
||||
background: black;
|
||||
color: black;
|
||||
font-family: monospace;
|
||||
}
|
||||
}
|
||||
|
||||
.oauth {
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
@media (max-width: at-most($x-small)) {
|
||||
#jslicense-labels1 {
|
||||
max-width: 100vw;
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,6 @@
|
||||
font-size: 1.4em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
input {
|
||||
text-indent: 23px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-menu__menu {
|
||||
@@ -210,6 +206,7 @@
|
||||
@include mq-subnav-top {
|
||||
background: $c-accent;
|
||||
color: $c-over;
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,8 +247,7 @@
|
||||
|
||||
em {
|
||||
font-weight: bold;
|
||||
opacity: 0.6;
|
||||
color: $c-brag;
|
||||
color: $c-accent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,3 @@
|
||||
@import '../../../common/css/component/slist';
|
||||
@import '../../../common/css/component/markdown';
|
||||
@import '../page';
|
||||
@import '../source';
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fnando/sparkline": "^0.3.10",
|
||||
"@toast-ui/editor": "3.1.7",
|
||||
"@textcomplete/core": "^0.1.13",
|
||||
"@textcomplete/textarea": "^0.1.13",
|
||||
"@toast-ui/editor": "3.1.7",
|
||||
"@types/debounce-promise": "^3.1.6",
|
||||
"@types/fnando__sparkline": "^0.3.7",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@types/yaireo__tagify": "4.17.5",
|
||||
"@types/zxcvbn": "^4.4.4",
|
||||
"@yaireo/tagify": "4.17.9",
|
||||
@@ -34,6 +35,7 @@
|
||||
"flatpickr": "^4.6.13",
|
||||
"lichess-pgn-viewer": "^2.1.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"qrcode": "^1.5.3",
|
||||
"tablesort": "^5.3.0",
|
||||
"zxcvbn": "^4.4.2"
|
||||
},
|
||||
@@ -73,6 +75,7 @@
|
||||
"src/bits.teamBattleForm.ts",
|
||||
"src/bits.tourForm.ts",
|
||||
"src/bits.tvGames.ts",
|
||||
"src/bits.twofactor.ts",
|
||||
"src/bits.ublog.ts",
|
||||
"src/bits.ublogForm.ts",
|
||||
"src/bits.user.ts",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import QRCode from 'qrcode';
|
||||
|
||||
const issuer = window.location.host; // lichess.org
|
||||
const secret = $('input[name=secret]').val();
|
||||
|
||||
QRCode.toCanvas(
|
||||
document.getElementById('qrcode'),
|
||||
`otpauth://totp/${issuer}:${document.body.dataset.user}?secret=${secret}&issuer=${issuer}`,
|
||||
{
|
||||
width: 320,
|
||||
},
|
||||
);
|
||||
@@ -31,7 +31,7 @@ export class SimpleEngine implements CevalEngine {
|
||||
this.protocol.compute(work);
|
||||
|
||||
if (!this.worker) {
|
||||
this.worker = new Worker(site.asset.url(this.url, { sameDomain: true }));
|
||||
this.worker = new Worker(site.asset.url(this.url, { pathOnly: true }));
|
||||
this.worker.addEventListener('message', e => this.protocol.received(e.data), true);
|
||||
this.worker.addEventListener(
|
||||
'error',
|
||||
|
||||
@@ -69,7 +69,7 @@ export class StockfishWebEngine implements CevalEngine {
|
||||
if (storedBuffer && storedBuffer.byteLength > 128 * 1024) return storedBuffer;
|
||||
const req = new XMLHttpRequest();
|
||||
|
||||
req.open('get', site.asset.url(`lifat/nnue/${nnueFilename}`, { noVersion: true }), true);
|
||||
req.open('get', site.asset.url(`lifat/nnue/${nnueFilename}`, { version: false }), true);
|
||||
req.responseType = 'arraybuffer';
|
||||
req.onprogress = e => this.status?.({ download: { bytes: e.loaded, total: e.total } });
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ export class ThreadedEngine implements CevalEngine {
|
||||
printErr: (msg: string) => this.onError(new Error(msg)),
|
||||
onError: this.onError,
|
||||
locateFile: (path: string) =>
|
||||
site.asset.url(`${root}/${path}`, { version, sameDomain: path.endsWith('.worker.js') }),
|
||||
site.asset.url(`${root}/${path}`, { version, pathOnly: path.endsWith('.worker.js') }),
|
||||
wasmMemory: sharedWasmMemory(this.info.minMem!),
|
||||
});
|
||||
|
||||
|
||||
@@ -4,14 +4,6 @@
|
||||
|
||||
/* Icon fonts */
|
||||
|
||||
@font-face {
|
||||
font-family: 'lichess';
|
||||
font-display: block;
|
||||
src:
|
||||
local-font('lichess.woff2') format('woff2'),
|
||||
local-font('lichess.woff') format('woff');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Noto Chess';
|
||||
font-display: block;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
overflow-y: scroll;
|
||||
overflow: auto clip;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0 !important;
|
||||
|
||||
@@ -7,10 +7,6 @@ cg-board {
|
||||
left: 0;
|
||||
user-select: none;
|
||||
line-height: 0;
|
||||
|
||||
.manipulable & {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
cg-board::before {
|
||||
@@ -129,10 +125,14 @@ piece {
|
||||
background-size: cover;
|
||||
z-index: z('cg__piece');
|
||||
will-change: transform;
|
||||
pointer-events: none;
|
||||
|
||||
.manipulable & {
|
||||
cursor: pointer;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
cursor: move;
|
||||
cursor: grabbing;
|
||||
z-index: z('cg__piece.dragging') !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ function notify(msg: string | (() => string)) {
|
||||
storage.set('' + Date.now());
|
||||
if ($.isFunction(msg)) msg = msg();
|
||||
const notification = new Notification('lichess.org', {
|
||||
icon: site.asset.url('logo/lichess-favicon-256.png', { noVersion: true }),
|
||||
icon: site.asset.url('logo/lichess-favicon-256.png', { version: false }),
|
||||
body: msg,
|
||||
});
|
||||
notification.onclick = () => window.focus();
|
||||
|
||||
@@ -144,7 +144,7 @@ export class BackgroundCtrl extends PaneCtrl {
|
||||
|
||||
const gallery = this.data.gallery!;
|
||||
const cols = window.matchMedia('(min-width: 650px)').matches ? 4 : 2;
|
||||
const montageUrl = site.asset.url(gallery[`montage${cols}`], { noVersion: true });
|
||||
const montageUrl = site.asset.url(gallery[`montage${cols}`], { version: false });
|
||||
const width =
|
||||
cols * (160 + 2) + (gallery.images.length > cols * 4 ? elementScrollBarWidthSlowGuess() : 0);
|
||||
|
||||
@@ -154,7 +154,7 @@ export class BackgroundCtrl extends PaneCtrl {
|
||||
'div#images-grid',
|
||||
{ attrs: { style: `background-image: url(${montageUrl});` } },
|
||||
gallery.images.map(img => {
|
||||
const assetUrl = site.asset.url(img, { noVersion: true });
|
||||
const assetUrl = site.asset.url(img, { version: false });
|
||||
const divClass = this.data.image.endsWith(assetUrl) ? '.selected' : '';
|
||||
return h(`div#${urlId(assetUrl)}${divClass}`, { hook: bind('click', () => setImg(assetUrl)) });
|
||||
}),
|
||||
|
||||
+14
-16
@@ -3,13 +3,12 @@ import { memoize } from 'common';
|
||||
|
||||
export const baseUrl = memoize(() => document.body.getAttribute('data-asset-url') || '');
|
||||
|
||||
const version = memoize(() => document.body.getAttribute('data-asset-version'));
|
||||
const assetVersion = memoize(() => document.body.getAttribute('data-asset-version'));
|
||||
|
||||
export const url = (path: string, opts: AssetUrlOpts = {}) => {
|
||||
opts = opts || {};
|
||||
const base = opts.documentOrigin ? window.location.origin : opts.sameDomain ? '' : baseUrl(),
|
||||
v = opts.version || version();
|
||||
return `${base}/assets${opts.noVersion ? '' : '/_' + v}/${path}`;
|
||||
const base = opts.documentOrigin ? window.location.origin : opts.pathOnly ? '' : baseUrl();
|
||||
const version = opts.version === false ? '' : `/_${opts.version ?? assetVersion()}`;
|
||||
return `${base}/assets${version}/${path}`;
|
||||
};
|
||||
|
||||
// bump flairs version if a flair is changed only (not added or removed)
|
||||
@@ -17,7 +16,7 @@ export const flairSrc = (flair: Flair) => url(`flair/img/${flair}.webp`, { versi
|
||||
|
||||
export const loadCss = (href: string, key?: string): Promise<void> => {
|
||||
return new Promise(resolve => {
|
||||
href = url(href, { noVersion: true });
|
||||
href = url(href, { version: false });
|
||||
if (document.head.querySelector(`link[href="${href}"]`)) return resolve();
|
||||
|
||||
const el = document.createElement('link');
|
||||
@@ -36,10 +35,10 @@ export const loadCssPath = async (key: string): Promise<void> => {
|
||||
|
||||
export const removeCssPath = (key: string) => $(`head > link[data-css-key="${key}"]`).remove();
|
||||
|
||||
export const jsModule = (name: string) => {
|
||||
export const jsModule = (name: string, prefix: string = 'compiled/') => {
|
||||
if (name.endsWith('.js')) name = name.slice(0, -3);
|
||||
const hash = site.manifest.js[name];
|
||||
return `compiled/${name}${hash ? `.${hash}` : ''}.js`;
|
||||
return `${prefix}${name}${hash ? `.${hash}` : ''}.js`;
|
||||
};
|
||||
|
||||
const scriptCache = new Map<string, Promise<void>>();
|
||||
@@ -49,17 +48,16 @@ export const loadIife = (u: string, opts: AssetUrlOpts = {}): Promise<void> => {
|
||||
return scriptCache.get(u)!;
|
||||
};
|
||||
|
||||
export async function loadEsm<T, ModuleOpts = any>(
|
||||
name: string,
|
||||
opts?: { init?: ModuleOpts; url?: AssetUrlOpts },
|
||||
): Promise<T> {
|
||||
const urlOpts = opts?.url?.version ? opts?.url : { ...opts?.url, noVersion: true };
|
||||
const module = await import(url(jsModule(name), urlOpts));
|
||||
return module.initModule ? module.initModule(opts?.init) : module.default(opts?.init);
|
||||
export async function loadEsm<T>(name: string, opts: EsmModuleOpts = {}): Promise<T> {
|
||||
opts = { ...opts, version: opts.version ?? false };
|
||||
|
||||
const module = await import(url(opts.npm ? jsModule(name, 'npm/') : jsModule(name), opts));
|
||||
const initializer = module.initModule ?? module.default;
|
||||
return opts.npm && !opts.init ? initializer : initializer(opts.init);
|
||||
}
|
||||
|
||||
export const loadPageEsm = async (name: string) => {
|
||||
const modulePromise = import(url(jsModule(name), { noVersion: true }));
|
||||
const modulePromise = import(url(jsModule(name), { version: false }));
|
||||
const dataScript = document.getElementById('page-init-data');
|
||||
const opts = dataScript && JSON.parse(dataScript.innerHTML);
|
||||
dataScript?.remove();
|
||||
|
||||
+2
-2
@@ -208,7 +208,7 @@ export const mic = new (class implements Voice.Microphone {
|
||||
}
|
||||
this.broadcast('Loading...');
|
||||
|
||||
const modelUrl = site.asset.url(models.get(this.lang)!, { noVersion: true });
|
||||
const modelUrl = site.asset.url(models.get(this.lang)!, { version: false });
|
||||
const downloadAsync = this.downloadModel(`/vosk/${modelUrl.replace(/[\W]/g, '_')}`);
|
||||
const audioAsync = this.initAudio();
|
||||
|
||||
@@ -263,7 +263,7 @@ export const mic = new (class implements Voice.Microphone {
|
||||
if ((await voskStore.count(`${emscriptenPath}/extracted.ok`)) > 0) return;
|
||||
const modelBlob: ArrayBuffer | undefined = await new Promise((resolve, reject) => {
|
||||
this.download = new XMLHttpRequest();
|
||||
this.download.open('GET', site.asset.url(models.get(this.lang)!, { noVersion: true }), true);
|
||||
this.download.open('GET', site.asset.url(models.get(this.lang)!, { version: false }), true);
|
||||
this.download.responseType = 'arraybuffer';
|
||||
this.download.onerror = _ => reject('Failed. See console');
|
||||
this.download.onabort = _ => reject('Aborted');
|
||||
|
||||
@@ -4,7 +4,7 @@ import { storage } from './storage';
|
||||
export default async function () {
|
||||
if (!('serviceWorker' in navigator && 'Notification' in window && 'PushManager' in window)) return;
|
||||
const workerUrl = new URL(
|
||||
assetUrl(jsModule('serviceWorker'), { sameDomain: true }),
|
||||
assetUrl(jsModule('serviceWorker'), { pathOnly: true }),
|
||||
self.location.href, // eslint-disable-line no-restricted-globals
|
||||
);
|
||||
workerUrl.searchParams.set('asset-url', document.body.getAttribute('data-asset-url')!);
|
||||
|
||||
Reference in New Issue
Block a user