Merge branch 'master' into broadcast-infinite-scroll-15353

This commit is contained in:
Thibault Duplessis
2024-05-22 09:14:49 +02:00
committed by GitHub
43 changed files with 269 additions and 160 deletions
+2 -2
View File
@@ -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 =>
+8 -5
View File
@@ -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))
+1 -1
View File
@@ -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,
+4 -4
View File
@@ -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(
+2 -2
View File
@@ -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()
+7 -4
View File
@@ -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")
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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)
)
)
+3 -7
View File
@@ -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")),
+3 -3
View File
@@ -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)
+1 -1
View File
@@ -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
+4 -3
View File
@@ -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))
+1 -1
View File
@@ -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")}" }
+14 -12
View File
@@ -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)
+129
View File
@@ -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
-8
View File
@@ -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,
});
});
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+8 -5
View File
@@ -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;
+5 -3
View File
@@ -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;
}
+1 -3
View File
@@ -46,10 +46,8 @@ $span-width: 1.7em;
}
.sortable-ghost {
opacity: 0.7;
&,
.status {
span {
background: $c-secondary !important;
color: $c-over !important;
}
+4 -1
View File
@@ -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"
}
}
}
+5 -6
View File
@@ -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();
},
},
+2 -5
View File
@@ -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),
),
},
+10 -2
View File
@@ -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 {
-8
View File
@@ -1,8 +0,0 @@
@media (max-width: at-most($x-small)) {
#jslicense-labels1 {
max-width: 100vw;
display: block;
overflow-x: auto;
white-space: nowrap;
}
}
+2 -6
View File
@@ -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;
}
}
}
-1
View File
@@ -2,4 +2,3 @@
@import '../../../common/css/component/slist';
@import '../../../common/css/component/markdown';
@import '../page';
@import '../source';
+4 -1
View File
@@ -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",
+12
View File
@@ -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,
},
);
+1 -1
View File
@@ -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',
+1 -1
View File
@@ -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 } });
+1 -1
View File
@@ -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!),
});
-8
View File
@@ -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;
+1 -1
View File
@@ -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;
+6 -6
View File
@@ -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;
}
+1 -1
View File
@@ -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();
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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');
+1 -1
View File
@@ -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')!);