diff --git a/modules/relay/src/main/RelayApi.scala b/modules/relay/src/main/RelayApi.scala
index 5b78503b105b..95488cbe1a13 100644
--- a/modules/relay/src/main/RelayApi.scala
+++ b/modules/relay/src/main/RelayApi.scala
@@ -69,7 +69,7 @@ final class RelayApi(
targetRound <- officialTarget(rt.round)
yield (
rt.round,
- nav.copy(round = rt.round.id.some, sourceRound = sourceRound, targetRound = targetRound)
+ nav.copy(roundId = rt.round.id.some, sourceRound = sourceRound, targetRound = targetRound)
)
def formNavigation(tour: RelayTour): Fu[ui.FormNavigation] = for
diff --git a/modules/relay/src/main/RelayRound.scala b/modules/relay/src/main/RelayRound.scala
index a9c72981da34..c655e1ae1798 100644
--- a/modules/relay/src/main/RelayRound.scala
+++ b/modules/relay/src/main/RelayRound.scala
@@ -118,6 +118,9 @@ object RelayRound:
case Url(url: URL) extends Upstream
case Urls(urls: List[URL]) extends Upstream
case Ids(ids: List[GameId]) extends Upstream
+ def isUrl = this match
+ case Url(_) => true
+ case _ => false
def lcc: Option[Lcc] = this match
case Url(url) =>
url.toString match
diff --git a/modules/relay/src/main/ui/FormUi.scala b/modules/relay/src/main/ui/FormUi.scala
index ab02c8facdc9..90df6140cf80 100644
--- a/modules/relay/src/main/ui/FormUi.scala
+++ b/modules/relay/src/main/ui/FormUi.scala
@@ -11,13 +11,18 @@ case class FormNavigation(
group: Option[RelayGroup.WithTours],
tour: RelayTour,
rounds: List[RelayRound],
- round: Option[RelayRoundId],
+ roundId: Option[RelayRoundId],
sourceRound: Option[RelayRound.WithTour] = none,
targetRound: Option[RelayRound.WithTour] = none,
newRound: Boolean = false
):
def tourWithGroup = RelayTour.WithGroupTours(tour, group)
def tourWithRounds = RelayTour.WithRounds(tour, rounds)
+ def round = roundId.flatMap(id => rounds.find(_.id == id))
+ def featurableRound = round
+ .ifTrue(targetRound.isEmpty)
+ .filter: r =>
+ r.sync.upstream.forall(up => up.isUrl && !up.hasLcc)
final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
import helpers.{ *, given }
@@ -40,7 +45,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
nav.rounds.map: r =>
a(
href := routes.RelayRound.edit(r.id),
- cls := List("subnav__subitem text" -> true, "active" -> nav.round.has(r.id)),
+ cls := List("subnav__subitem text" -> true, "active" -> nav.roundId.has(r.id)),
dataIcon := (
if r.finished then Icon.Checkmark
else if r.hasStarted then Icon.DiscBig
@@ -106,7 +111,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
)
),
standardFlash,
- inner(form, routes.RelayRound.create(nav.tour.id), nav.tour, round = none)
+ inner(form, routes.RelayRound.create(nav.tour.id), nav)
)
def edit(
@@ -126,7 +131,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
strong(a(href := tr.path, cls := "text", dataIcon := Icon.RadioTower)(tr.fullName)),
"."
),
- inner(form, routes.RelayRound.update(r.id), nav.tour, round = r.some, nav.sourceRound),
+ inner(form, routes.RelayRound.update(r.id), nav),
div(cls := "relay-form__actions")(
postForm(action := routes.RelayRound.reset(r.id))(
submitButton(
@@ -147,15 +152,13 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
private def inner(
form: Form[RelayRoundForm.Data],
url: play.api.mvc.Call,
- t: RelayTour,
- round: Option[RelayRound],
- sourceRound: Option[RelayRound.WithTour] = none
+ nav: FormNavigation
)(using ctx: Context) =
- val lccWarning = round
+ val lccWarning = nav.round
.flatMap(_.sync.upstream)
.exists(_.hasLcc)
- .option(
- flashMessage("box")(
+ .option:
+ flashMessage("box relay-form__lcc-deprecated")(
p(strong("Please use the ", a(href := broadcasterUrl)("Lichess Broadcaster App"))),
p(
"LiveChessCloud support is deprecated and will be removed soon.",
@@ -163,12 +166,22 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
"If you need help, please contact us at broadcast@lichess.org."
)
)
- )
+ val contactUsForOfficial = nav.featurableRound.isDefined
+ .option:
+ flashMessage("box relay-form__contact-us")(
+ p(
+ "Is this a tournament you organize? Do you want Lichess to feature it on the ",
+ a(href := routes.RelayTour.index(1))("broadcast page"),
+ "?"
+ ),
+ p(trans.contact.sendEmailAt("broadcast@lichess.org"))
+ )
+ .pp
postForm(cls := "form3", action := url)(
(!Granter.opt(_.StudyAdmin)).option:
div(cls := "form-group")(
div(cls := "form-group")(ui.howToUse),
- (round.isEmpty && t.createdAt.isBefore(nowInstant.minusMinutes(1))).option:
+ (nav.round.isEmpty && nav.tour.createdAt.isBefore(nowInstant.minusMinutes(1))).option:
p(dataIcon := Icon.InfoCircle, cls := "text"):
trb.theNewRoundHelp()
)
@@ -189,13 +202,13 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
"Where do the games come from?"
)(form3.select(_, RelayRoundForm.sourceTypes)),
div(cls := "relay-form__sync relay-form__sync-url")(
- lccWarning,
+ lccWarning.orElse(contactUsForOfficial),
form3.group(
form("syncUrl"),
trb.sourceSingleUrl(),
help = trb.sourceUrlHelp().some
)(form3.input(_)),
- sourceRound.map: source =>
+ nav.sourceRound.map: source =>
flashMessage("round-push")(
"Getting real-time updates from ",
strong(a(href := source.path)(source.fullName)),
@@ -235,6 +248,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
half = false
)(form3.input(_))(cls := "relay-form__sync relay-form__sync-ids none"),
div(cls := "form-group relay-form__sync relay-form__sync-push none")(
+ contactUsForOfficial,
p(
"Send your local games to Lichess using the ",
a(href := broadcasterUrl)("Lichess Broadcaster App"),
@@ -280,7 +294,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
)(form3.input(_))
)
),
- form3.fieldset("Advanced", toggle = round.exists(r => r.sync.delay.isDefined).some)(
+ form3.fieldset("Advanced", toggle = nav.round.exists(r => r.sync.delay.isDefined).some)(
form3.split(
form3.group(
form("delay"),
@@ -323,7 +337,7 @@ final class FormUi(helpers: Helpers, ui: RelayUi, tourUi: RelayTourUi):
)
),
form3.actions(
- a(href := routes.RelayTour.show(t.slug, t.id))(trans.site.cancel()),
+ a(href := routes.RelayTour.show(nav.tour.slug, nav.tour.id))(trans.site.cancel()),
form3.submit(trans.site.apply())
)
)
diff --git a/modules/web/src/main/ui/contact.scala b/modules/web/src/main/ui/contact.scala
index 05dab2c9c2b7..50e12a301cec 100644
--- a/modules/web/src/main/ui/contact.scala
+++ b/modules/web/src/main/ui/contact.scala
@@ -222,18 +222,6 @@ object contact:
)
)
),
- Leaf(
- "broadcast",
- wantBroadcastTournament(),
- frag(
- p(a(href := routes.RelayTour.help)(learnHowToMakeBroadcasts()), "."),
- p(
- contactAboutOfficialBroadcasts(),
- " ",
- sendEmailAt(contactEmailLink("broadcast@lichess.org"))
- )
- )
- ),
frag(
p(doNotMessageModerators()),
p(sendAppealTo(a(href := routes.Appeal.home)(routes.Appeal.home.url))),
diff --git a/translation/source/contact.xml b/translation/source/contact.xml
index 40c918c23816..58165b14468f 100644
--- a/translation/source/contact.xml
+++ b/translation/source/contact.xml
@@ -55,9 +55,7 @@
In certain circumstances when playing against a bot account, a rated game may not award points if it is determined that the player is abusing the bot for rating points.
Error page
If you faced an error page, you may report it:
- I want to broadcast a tournament
Learn how to make your own broadcasts on Lichess
- You can also contact the broadcast team about official broadcasts.
Appeal for a ban or IP restriction
Engine or cheat mark
You may send an appeal to %s.
diff --git a/ui/bits/css/relay/_form.scss b/ui/bits/css/relay/_form.scss
index 1e239316b9ad..d0868ef5073c 100644
--- a/ui/bits/css/relay/_form.scss
+++ b/ui/bits/css/relay/_form.scss
@@ -29,7 +29,7 @@
}
}
-.flash-box {
+.relay-form__lcc-deprecated {
border: 5px solid $m-brag_bg--mix-70;
&::before {
@@ -39,6 +39,16 @@
}
}
+.relay-form__contact-us.flash-box {
+ border: 5px solid $m-secondary_bg--mix-70;
+
+ &::before {
+ color: $c-secondary;
+ content: $licon-UploadCloud;
+ font-size: 4em;
+ }
+}
+
.flash-round-push {
border: 5px solid $c-good;
background: $c-bg-box;