Merge branch 'master' of github.com:ornicar/lila
* 'master' of github.com:ornicar/lila: tweak relation caches show full list of friends remove timeline entries about people following me Revert "no longer send follow to friends timelines" no longer send follow to friends timelines ublog post image alt & credit analyse/embed/css: button cursor: pointer analyse/embed/css: Fix zh layout on mobile Prettier broadcast: Fix error URL ublog: Translate follow button properly css: Reduce page h2 line-height css: Make .button display: inline-block ublog/css: Prevent linebreak inside view count Fix zulip chat panic link Make shepherd close button visible Fix shepherd themes being swapped
This commit is contained in:
commit
2fe175294e
|
@ -117,8 +117,9 @@ final class Relation(
|
||||||
OptionFuResult(env.user.repo named username) { user =>
|
OptionFuResult(env.user.repo named username) { user =>
|
||||||
RelatedPager(api.followingPaginatorAdapter(user.id), page) flatMap { pag =>
|
RelatedPager(api.followingPaginatorAdapter(user.id), page) flatMap { pag =>
|
||||||
negotiate(
|
negotiate(
|
||||||
html = api countFollowers user.id map { nbFollowers =>
|
html = {
|
||||||
Ok(html.relation.bits.following(user, pag, nbFollowers))
|
if (ctx is user) Ok(html.relation.bits.friends(user, pag)).fuccess
|
||||||
|
else ctx.me.fold(notFound)(me => Redirect(routes.Relation.following(me.username)).fuccess)
|
||||||
},
|
},
|
||||||
api = _ => Ok(jsonRelatedPaginator(pag)).fuccess
|
api = _ => Ok(jsonRelatedPaginator(pag)).fuccess
|
||||||
)
|
)
|
||||||
|
@ -129,19 +130,16 @@ final class Relation(
|
||||||
|
|
||||||
def followers(username: String, page: Int) =
|
def followers(username: String, page: Int) =
|
||||||
Open { implicit ctx =>
|
Open { implicit ctx =>
|
||||||
Reasonable(page, 20) {
|
|
||||||
OptionFuResult(env.user.repo named username) { user =>
|
|
||||||
RelatedPager(api.followersPaginatorAdapter(user.id), page) flatMap { pag =>
|
|
||||||
negotiate(
|
negotiate(
|
||||||
html = api countFollowing user.id map { nbFollowing =>
|
html = notFound,
|
||||||
Ok(html.relation.bits.followers(user, pag, nbFollowing))
|
api = _ =>
|
||||||
},
|
Reasonable(page, 20) {
|
||||||
api = _ => Ok(jsonRelatedPaginator(pag)).fuccess
|
RelatedPager(api.followersPaginatorAdapter(UserModel normalize username), page) flatMap { pag =>
|
||||||
|
Ok(jsonRelatedPaginator(pag)).fuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def apiFollowing(name: String) = apiRelation(name, Direction.Following)
|
def apiFollowing(name: String) = apiRelation(name, Direction.Following)
|
||||||
|
|
||||||
|
|
|
@ -512,7 +512,7 @@ final class User(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sequenceFu
|
.sequenceFu
|
||||||
} yield html.user.opponents(me, relateds)
|
} yield html.relation.bits.opponents(me, relateds)
|
||||||
}
|
}
|
||||||
|
|
||||||
def perfStat(username: String, perfKey: String) =
|
def perfStat(username: String, perfKey: String) =
|
||||||
|
|
|
@ -1,44 +1,23 @@
|
||||||
package views.html.relation
|
package views.html.relation
|
||||||
|
|
||||||
|
import controllers.routes
|
||||||
import play.api.mvc.Call
|
import play.api.mvc.Call
|
||||||
|
|
||||||
import lila.api.Context
|
import lila.api.Context
|
||||||
import lila.app.templating.Environment._
|
import lila.app.templating.Environment._
|
||||||
import lila.app.ui.ScalatagsTemplate._
|
import lila.app.ui.ScalatagsTemplate._
|
||||||
import lila.common.paginator.Paginator
|
import lila.common.paginator.Paginator
|
||||||
|
import lila.game.FavoriteOpponents
|
||||||
import lila.relation.Related
|
import lila.relation.Related
|
||||||
import lila.user.User
|
import lila.user.User
|
||||||
|
|
||||||
import controllers.routes
|
|
||||||
|
|
||||||
object bits {
|
object bits {
|
||||||
|
|
||||||
def followers(u: User, pag: Paginator[Related], nbFollowing: Int)(implicit ctx: Context) =
|
def friends(u: User, pag: Paginator[Related])(implicit ctx: Context) =
|
||||||
layout(s"${u.username} • ${trans.nbFollowers.pluralSameTxt(pag.nbResults)}")(
|
layout(s"${u.username} • ${trans.friends.txt()}")(
|
||||||
div(cls := "box__top")(
|
h1(
|
||||||
h1(userLink(u, withOnline = false)),
|
a(href := routes.User.show(u.username), dataIcon := "", cls := "text"),
|
||||||
div(cls := "actions")(
|
trans.friends()
|
||||||
trans.nbFollowers.pluralSame(pag.nbResults),
|
|
||||||
" ",
|
|
||||||
amp,
|
|
||||||
" ",
|
|
||||||
a(href := routes.Relation.following(u.username))(trans.nbFollowing.pluralSame(nbFollowing))
|
|
||||||
)
|
|
||||||
),
|
|
||||||
pagTable(pag, routes.Relation.followers(u.username))
|
|
||||||
)
|
|
||||||
|
|
||||||
def following(u: User, pag: Paginator[Related], nbFollowers: Int)(implicit ctx: Context) =
|
|
||||||
layout(s"${u.username} • ${trans.nbFollowing.pluralSameTxt(pag.nbResults)}")(
|
|
||||||
div(cls := "box__top")(
|
|
||||||
h1(userLink(u, withOnline = false)),
|
|
||||||
div(cls := "actions")(
|
|
||||||
trans.nbFollowing.pluralSame(pag.nbResults),
|
|
||||||
" ",
|
|
||||||
amp,
|
|
||||||
" ",
|
|
||||||
a(href := routes.Relation.followers(u.username))(trans.nbFollowers.pluralSame(nbFollowers))
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
pagTable(pag, routes.Relation.following(u.username))
|
pagTable(pag, routes.Relation.following(u.username))
|
||||||
)
|
)
|
||||||
|
@ -54,6 +33,38 @@ object bits {
|
||||||
pagTable(pag, routes.Relation.blocks())
|
pagTable(pag, routes.Relation.blocks())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def opponents(u: User, sugs: List[lila.relation.Related])(implicit ctx: Context) =
|
||||||
|
layout(s"${u.username} • ${trans.favoriteOpponents.txt()}")(
|
||||||
|
h1(
|
||||||
|
a(href := routes.User.show(u.username), dataIcon := "", cls := "text"),
|
||||||
|
trans.favoriteOpponents(),
|
||||||
|
" (",
|
||||||
|
trans.nbGames.pluralSame(FavoriteOpponents.gameLimit),
|
||||||
|
")"
|
||||||
|
),
|
||||||
|
table(cls := "slist")(
|
||||||
|
tbody(
|
||||||
|
if (sugs.nonEmpty) sugs.map { r =>
|
||||||
|
tr(
|
||||||
|
td(userLink(r.user)),
|
||||||
|
td(showBestPerf(r.user)),
|
||||||
|
td(
|
||||||
|
r.nbGames.filter(_ > 0).map { nbGames =>
|
||||||
|
a(href := s"${routes.User.games(u.username, "search")}?players.b=${r.user.username}")(
|
||||||
|
trans.nbGames.plural(nbGames, nbGames.localize)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
td(
|
||||||
|
views.html.relation.actions(r.user.id, r.relation, followable = r.followable, blocked = false)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else tr(td(trans.none()))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def layout(title: String)(content: Modifier*)(implicit ctx: Context) =
|
def layout(title: String)(content: Modifier*)(implicit ctx: Context) =
|
||||||
views.html.base.layout(
|
views.html.base.layout(
|
||||||
title = title,
|
title = title,
|
||||||
|
@ -71,7 +82,7 @@ object bits {
|
||||||
tr(cls := "paginated")(
|
tr(cls := "paginated")(
|
||||||
td(userLink(r.user)),
|
td(userLink(r.user)),
|
||||||
td(showBestPerf(r.user)),
|
td(showBestPerf(r.user)),
|
||||||
td(trans.nbGames.pluralSame(r.user.count.game)),
|
td(trans.nbGames.plural(r.user.count.game, r.user.count.game.localize)),
|
||||||
td(actions(r.user.id, relation = r.relation, followable = r.followable, blocked = false))
|
td(actions(r.user.id, relation = r.relation, followable = r.followable, blocked = false))
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -26,7 +26,7 @@ object form {
|
||||||
) {
|
) {
|
||||||
main(cls := "page-menu page-small")(
|
main(cls := "page-menu page-small")(
|
||||||
views.html.blog.bits.menu(none, "mine".some),
|
views.html.blog.bits.menu(none, "mine".some),
|
||||||
div(cls := "page-menu__content box box-pad ublog-post-form")(
|
div(cls := "page-menu__content box ublog-post-form")(
|
||||||
standardFlash(),
|
standardFlash(),
|
||||||
h1(trans.ublog.newPost()),
|
h1(trans.ublog.newPost()),
|
||||||
etiquette,
|
etiquette,
|
||||||
|
@ -43,7 +43,7 @@ object form {
|
||||||
) {
|
) {
|
||||||
main(cls := "page-menu page-small")(
|
main(cls := "page-menu page-small")(
|
||||||
views.html.blog.bits.menu(none, "mine".some),
|
views.html.blog.bits.menu(none, "mine".some),
|
||||||
div(cls := "page-menu__content box box-pad ublog-post-form")(
|
div(cls := "page-menu__content box ublog-post-form")(
|
||||||
standardFlash(),
|
standardFlash(),
|
||||||
div(cls := "box__top")(
|
div(cls := "box__top")(
|
||||||
h1(
|
h1(
|
||||||
|
@ -108,17 +108,24 @@ object form {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def formImage(post: UblogPost) = postView.thumbnail(post, _.Small)
|
def formImage(post: UblogPost) =
|
||||||
|
postView.thumbnail(post, _.Small)(cls := post.image.isDefined.option("user-image"))
|
||||||
|
|
||||||
private def inner(form: Form[UblogPostData], post: Either[User, UblogPost], captcha: Option[Captcha])(
|
private def inner(form: Form[UblogPostData], post: Either[User, UblogPost], captcha: Option[Captcha])(
|
||||||
implicit ctx: Context
|
implicit ctx: Context
|
||||||
) =
|
) =
|
||||||
postForm(
|
postForm(
|
||||||
cls := "form3",
|
cls := "form3 ublog-post-form__main",
|
||||||
action := post.fold(_ => routes.Ublog.create, p => routes.Ublog.update(p.id.value))
|
action := post.fold(_ => routes.Ublog.create, p => routes.Ublog.update(p.id.value))
|
||||||
)(
|
)(
|
||||||
form3.globalError(form),
|
form3.globalError(form),
|
||||||
post.isRight option form3.split(
|
post.toOption.map { p =>
|
||||||
|
frag(
|
||||||
|
form3.split(
|
||||||
|
form3.group(form("imageAlt"), trans.ublog.imageAlt(), half = true)(form3.input(_)),
|
||||||
|
form3.group(form("imageCredit"), trans.ublog.imageCredit(), half = true)(form3.input(_))
|
||||||
|
)(cls := s"ublog-post-form__image-text ${p.image.isDefined ?? "visible"}"),
|
||||||
|
form3.split(
|
||||||
form3.checkbox(
|
form3.checkbox(
|
||||||
form("live"),
|
form("live"),
|
||||||
trans.ublog.publishOnYourBlog(),
|
trans.ublog.publishOnYourBlog(),
|
||||||
|
@ -133,7 +140,9 @@ object form {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
),
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
form3.group(form("title"), trans.ublog.postTitle())(form3.input(_)(autofocus)),
|
form3.group(form("title"), trans.ublog.postTitle())(form3.input(_)(autofocus)),
|
||||||
form3.group(form("intro"), trans.ublog.postIntro())(form3.input(_)(autofocus)),
|
form3.group(form("intro"), trans.ublog.postIntro())(form3.input(_)(autofocus)),
|
||||||
form3.group(
|
form3.group(
|
||||||
|
|
|
@ -44,7 +44,12 @@ object post {
|
||||||
main(cls := "page-menu page-small")(
|
main(cls := "page-menu page-small")(
|
||||||
views.html.blog.bits.menu(none, (if (ctx is user) "mine" else "community").some),
|
views.html.blog.bits.menu(none, (if (ctx is user) "mine" else "community").some),
|
||||||
div(cls := "page-menu__content box box-pad ublog-post")(
|
div(cls := "page-menu__content box box-pad ublog-post")(
|
||||||
post.image.isDefined option thumbnail(post, _.Large)(cls := "ublog-post__image"),
|
post.image.map { image =>
|
||||||
|
frag(
|
||||||
|
thumbnail(post, _.Large)(cls := "ublog-post__image"),
|
||||||
|
image.credit.map { p(cls := "ublog-post__image-credit")(_) }
|
||||||
|
)
|
||||||
|
},
|
||||||
ctx.is(user) || isGranted(_.ModerateBlog) option standardFlash(),
|
ctx.is(user) || isGranted(_.ModerateBlog) option standardFlash(),
|
||||||
h1(cls := "ublog-post__title")(post.title),
|
h1(cls := "ublog-post__title")(post.title),
|
||||||
div(cls := "ublog-post__meta")(
|
div(cls := "ublog-post__meta")(
|
||||||
|
@ -135,15 +140,15 @@ object post {
|
||||||
)
|
)
|
||||||
)(
|
)(
|
||||||
List(
|
List(
|
||||||
("yes", trans.following, routes.Relation.unfollow _, ""),
|
("yes", trans.unfollowX, routes.Relation.unfollow _, ""),
|
||||||
("no", trans.follow, routes.Relation.follow _, "")
|
("no", trans.followX, routes.Relation.follow _, "")
|
||||||
).map { case (role, text, route, icon) =>
|
).map { case (role, text, route, icon) =>
|
||||||
button(
|
button(
|
||||||
cls := s"ublog-post__follow__$role button button-big",
|
cls := s"ublog-post__follow__$role button button-big",
|
||||||
dataIcon := icon,
|
dataIcon := icon,
|
||||||
dataRel := route(user.id)
|
dataRel := route(user.id)
|
||||||
)(
|
)(
|
||||||
span(cls := "button-label")(text.txt(), " ", user.titleUsername)
|
span(cls := "button-label")(text(user.titleUsername))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -191,12 +196,13 @@ object post {
|
||||||
img(
|
img(
|
||||||
cls := "ublog-post-image",
|
cls := "ublog-post-image",
|
||||||
widthA := size(UblogPost.thumbnail).width,
|
widthA := size(UblogPost.thumbnail).width,
|
||||||
heightA := size(UblogPost.thumbnail).height
|
heightA := size(UblogPost.thumbnail).height,
|
||||||
|
alt := post.image.flatMap(_.alt)
|
||||||
)(src := url(post, size))
|
)(src := url(post, size))
|
||||||
|
|
||||||
def url(post: UblogPost.BasePost, size: UblogPost.thumbnail.SizeSelector) =
|
def url(post: UblogPost.BasePost, size: UblogPost.thumbnail.SizeSelector) =
|
||||||
post.image match {
|
post.image match {
|
||||||
case Some(image) => UblogPost.thumbnail(picfitUrl, image, size)
|
case Some(image) => UblogPost.thumbnail(picfitUrl, image.id, size)
|
||||||
case _ => assetUrl("images/user-blog-default.png")
|
case _ => assetUrl("images/user-blog-default.png")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
package views.html
|
|
||||||
package user
|
|
||||||
|
|
||||||
import lila.api.Context
|
|
||||||
import lila.app.templating.Environment._
|
|
||||||
import lila.app.ui.ScalatagsTemplate._
|
|
||||||
import lila.user.User
|
|
||||||
import lila.game.FavoriteOpponents
|
|
||||||
|
|
||||||
import controllers.routes
|
|
||||||
|
|
||||||
object opponents {
|
|
||||||
def apply(u: User, sugs: List[lila.relation.Related])(implicit ctx: Context) =
|
|
||||||
relation.bits.layout(s"${u.username} • ${trans.favoriteOpponents.txt()}")(
|
|
||||||
h1(
|
|
||||||
a(href := routes.User.show(u.username), dataIcon := "", cls := "text"),
|
|
||||||
trans.favoriteOpponents(),
|
|
||||||
" (",
|
|
||||||
trans.nbGames.pluralSame(FavoriteOpponents.gameLimit),
|
|
||||||
")"
|
|
||||||
),
|
|
||||||
table(cls := "slist")(
|
|
||||||
tbody(
|
|
||||||
if (sugs.nonEmpty) sugs.map { r =>
|
|
||||||
tr(
|
|
||||||
td(userLink(r.user)),
|
|
||||||
td(showBestPerf(r.user)),
|
|
||||||
td(
|
|
||||||
r.nbGames.filter(_ > 0).map { nbGames =>
|
|
||||||
a(href := s"${routes.User.games(u.username, "search")}?players.b=${r.user.username}")(
|
|
||||||
trans.nbGames.pluralSame(nbGames)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
td(relation.actions(r.user.id, r.relation, followable = r.followable, blocked = false))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else tr(td(trans.none()))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -48,9 +48,6 @@ object header {
|
||||||
),
|
),
|
||||||
div(cls := "user-show__social")(
|
div(cls := "user-show__social")(
|
||||||
div(cls := "number-menu")(
|
div(cls := "number-menu")(
|
||||||
a(cls := "nm-item", href := routes.Relation.followers(u.username))(
|
|
||||||
splitNumber(trans.nbFollowers.pluralSame(info.nbFollowers))
|
|
||||||
),
|
|
||||||
u.noBot option a(
|
u.noBot option a(
|
||||||
href := routes.UserTournament.path(u.username, "recent"),
|
href := routes.UserTournament.path(u.username, "recent"),
|
||||||
cls := "nm-item tournament_stats",
|
cls := "nm-item tournament_stats",
|
||||||
|
@ -232,6 +229,8 @@ object header {
|
||||||
trans.profileCompletion(s"${profile.completionPercent}%")
|
trans.profileCompletion(s"${profile.completionPercent}%")
|
||||||
),
|
),
|
||||||
br,
|
br,
|
||||||
|
a(href := routes.Relation.following(u.username))(trans.friends()),
|
||||||
|
br,
|
||||||
a(href := routes.User.opponents)(trans.favoriteOpponents())
|
a(href := routes.User.opponents)(trans.favoriteOpponents())
|
||||||
),
|
),
|
||||||
u.playTime.map { playTime =>
|
u.playTime.map { playTime =>
|
||||||
|
|
3
bin/mongodb/ublog-image.js
Normal file
3
bin/mongodb/ublog-image.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
db.ublog_post
|
||||||
|
.find({ image: { $exists: 1 } }, { image: 1 })
|
||||||
|
.forEach(p => db.ublog_post.update({ _id: p._id }, { $set: { image: { id: p.image } } }));
|
|
@ -161,7 +161,7 @@ final class PersonalDataExport(
|
||||||
"title" -> post.title,
|
"title" -> post.title,
|
||||||
"intro" -> post.intro,
|
"intro" -> post.intro,
|
||||||
"body" -> post.markdown,
|
"body" -> post.markdown,
|
||||||
"image" -> post.image.??(lila.ublog.UblogPost.thumbnail(picfitUrl, _, _.Large)),
|
"image" -> post.image.??(i => lila.ublog.UblogPost.thumbnail(picfitUrl, i.id, _.Large)),
|
||||||
"topics" -> post.topics.map(_.value).mkString(", ")
|
"topics" -> post.topics.map(_.value).mkString(", ")
|
||||||
).map { case (k, v) =>
|
).map { case (k, v) =>
|
||||||
s"$k: $v"
|
s"$k: $v"
|
||||||
|
|
|
@ -277,6 +277,8 @@ val `favoriteOpponents` = new I18nKey("favoriteOpponents")
|
||||||
val `follow` = new I18nKey("follow")
|
val `follow` = new I18nKey("follow")
|
||||||
val `following` = new I18nKey("following")
|
val `following` = new I18nKey("following")
|
||||||
val `unfollow` = new I18nKey("unfollow")
|
val `unfollow` = new I18nKey("unfollow")
|
||||||
|
val `followX` = new I18nKey("followX")
|
||||||
|
val `unfollowX` = new I18nKey("unfollowX")
|
||||||
val `block` = new I18nKey("block")
|
val `block` = new I18nKey("block")
|
||||||
val `blocked` = new I18nKey("blocked")
|
val `blocked` = new I18nKey("blocked")
|
||||||
val `unblock` = new I18nKey("unblock")
|
val `unblock` = new I18nKey("unblock")
|
||||||
|
@ -2281,6 +2283,8 @@ val `noPostsInThisBlogYet` = new I18nKey("ublog:noPostsInThisBlogYet")
|
||||||
val `noDrafts` = new I18nKey("ublog:noDrafts")
|
val `noDrafts` = new I18nKey("ublog:noDrafts")
|
||||||
val `latestBlogPosts` = new I18nKey("ublog:latestBlogPosts")
|
val `latestBlogPosts` = new I18nKey("ublog:latestBlogPosts")
|
||||||
val `uploadAnImageForYourPost` = new I18nKey("ublog:uploadAnImageForYourPost")
|
val `uploadAnImageForYourPost` = new I18nKey("ublog:uploadAnImageForYourPost")
|
||||||
|
val `imageAlt` = new I18nKey("ublog:imageAlt")
|
||||||
|
val `imageCredit` = new I18nKey("ublog:imageCredit")
|
||||||
val `publishedNbBlogPosts` = new I18nKey("ublog:publishedNbBlogPosts")
|
val `publishedNbBlogPosts` = new I18nKey("ublog:publishedNbBlogPosts")
|
||||||
val `nbViews` = new I18nKey("ublog:nbViews")
|
val `nbViews` = new I18nKey("ublog:nbViews")
|
||||||
val `viewAllNbPosts` = new I18nKey("ublog:viewAllNbPosts")
|
val `viewAllNbPosts` = new I18nKey("ublog:viewAllNbPosts")
|
||||||
|
|
|
@ -87,7 +87,7 @@ final class IrcApi(
|
||||||
|
|
||||||
def chatPanic(mod: Holder, v: Boolean): Funit =
|
def chatPanic(mod: Holder, v: Boolean): Funit =
|
||||||
zulip(_.mod.log, "chat panic")(
|
zulip(_.mod.log, "chat panic")(
|
||||||
s":stop: ${markdown.modLink(mod.user)} ${if (v) "enabled" else "disabled"} ${markdown.lichessLink("mod/chat-panic", " Chat Panic")}"
|
s":stop: ${markdown.modLink(mod.user)} ${if (v) "enabled" else "disabled"} ${markdown.lichessLink("/mod/chat-panic", " Chat Panic")}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def garbageCollector(msg: String): Funit =
|
def garbageCollector(msg: String): Funit =
|
||||||
|
|
|
@ -80,9 +80,8 @@ final class RelationApi(
|
||||||
def fetchAreFriends(u1: ID, u2: ID): Fu[Boolean] =
|
def fetchAreFriends(u1: ID, u2: ID): Fu[Boolean] =
|
||||||
fetchFollows(u1, u2) >>& fetchFollows(u2, u1)
|
fetchFollows(u1, u2) >>& fetchFollows(u2, u1)
|
||||||
|
|
||||||
private val countFollowingCache = cacheApi[ID, Int](8192, "relation.count.following") {
|
private val countFollowingCache = cacheApi[ID, Int](8_192, "relation.count.following") {
|
||||||
_.expireAfterAccess(10 minutes)
|
_.maximumSize(8_192)
|
||||||
.maximumSize(32768)
|
|
||||||
.buildAsyncFuture { userId =>
|
.buildAsyncFuture { userId =>
|
||||||
coll.countSel($doc("u1" -> userId, "r" -> Follow))
|
coll.countSel($doc("u1" -> userId, "r" -> Follow))
|
||||||
}
|
}
|
||||||
|
@ -92,9 +91,8 @@ final class RelationApi(
|
||||||
|
|
||||||
def reachedMaxFollowing(userId: ID): Fu[Boolean] = countFollowingCache get userId map (config.maxFollow <=)
|
def reachedMaxFollowing(userId: ID): Fu[Boolean] = countFollowingCache get userId map (config.maxFollow <=)
|
||||||
|
|
||||||
private val countFollowersCache = cacheApi[ID, Int](131_072, "relation.count.followers") {
|
private val countFollowersCache = cacheApi[ID, Int](32_768, "relation.count.followers") {
|
||||||
_.expireAfterAccess(10 minutes)
|
_.maximumSize(32_768)
|
||||||
.maximumSize(131_072)
|
|
||||||
.buildAsyncFuture { userId =>
|
.buildAsyncFuture { userId =>
|
||||||
coll.secondaryPreferred.countSel($doc("u2" -> userId, "r" -> Follow))
|
coll.secondaryPreferred.countSel($doc("u2" -> userId, "r" -> Follow))
|
||||||
}
|
}
|
||||||
|
@ -147,7 +145,7 @@ final class RelationApi(
|
||||||
repo.follow(u1, u2) >> limitFollow(u1) >>- {
|
repo.follow(u1, u2) >> limitFollow(u1) >>- {
|
||||||
countFollowersCache.update(u2, 1 +)
|
countFollowersCache.update(u2, 1 +)
|
||||||
countFollowingCache.update(u1, prev => (prev + 1) atMost config.maxFollow.value)
|
countFollowingCache.update(u1, prev => (prev + 1) atMost config.maxFollow.value)
|
||||||
timeline ! Propagate(FollowUser(u1, u2)).toFriendsOf(u1).toUsers(List(u2))
|
timeline ! Propagate(FollowUser(u1, u2)).toFriendsOf(u1)
|
||||||
Bus.publish(lila.hub.actorApi.relation.Follow(u1, u2), "relation")
|
Bus.publish(lila.hub.actorApi.relation.Follow(u1, u2), "relation")
|
||||||
lila.mon.relation.follow.increment().unit
|
lila.mon.relation.follow.increment().unit
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ object JsonView {
|
||||||
"log" -> s.log.events
|
"log" -> s.log.events
|
||||||
) ++
|
) ++
|
||||||
s.upstream.?? {
|
s.upstream.?? {
|
||||||
case RelayRound.Sync.UpstreamUrl(url) => Json.obj("url" -> url)
|
case url: RelayRound.Sync.UpstreamUrl => Json.obj("url" -> url.withRound.url)
|
||||||
case RelayRound.Sync.UpstreamIds(ids) => Json.obj("ids" -> ids)
|
case RelayRound.Sync.UpstreamIds(ids) => Json.obj("ids" -> ids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,10 +110,10 @@ final class UblogApi(
|
||||||
|
|
||||||
def uploadImage(user: User, post: UblogPost, picture: PicfitApi.FilePart): Fu[UblogPost] =
|
def uploadImage(user: User, post: UblogPost, picture: PicfitApi.FilePart): Fu[UblogPost] =
|
||||||
for {
|
for {
|
||||||
image <- picfitApi
|
pic <- picfitApi.uploadFile(imageRel(post), picture, userId = user.id)
|
||||||
.uploadFile(imageRel(post), picture, userId = user.id)
|
image = post.image.fold(UblogImage(pic.id))(_.copy(id = pic.id))
|
||||||
_ <- colls.post.update.one($id(post.id), $set("image" -> image.id))
|
_ <- colls.post.updateField($id(post.id), "image", image)
|
||||||
} yield post.copy(image = image.id.some)
|
} yield post.copy(image = image.some)
|
||||||
|
|
||||||
def deleteImage(post: UblogPost): Fu[UblogPost] =
|
def deleteImage(post: UblogPost): Fu[UblogPost] =
|
||||||
picfitApi.deleteByRel(imageRel(post)) >>
|
picfitApi.deleteByRel(imageRel(post)) >>
|
||||||
|
|
|
@ -25,6 +25,7 @@ private object UblogBsonHandlers {
|
||||||
.afterRead(_.filter(t => UblogTopic.exists(t.value)))
|
.afterRead(_.filter(t => UblogTopic.exists(t.value)))
|
||||||
implicit val langBsonHandler = stringAnyValHandler[Lang](_.code, Lang.apply)
|
implicit val langBsonHandler = stringAnyValHandler[Lang](_.code, Lang.apply)
|
||||||
implicit val recordedBSONHandler = Macros.handler[Recorded]
|
implicit val recordedBSONHandler = Macros.handler[Recorded]
|
||||||
|
implicit val imageBSONHandler = Macros.handler[UblogImage]
|
||||||
implicit val likesBSONHandler = intAnyValHandler[Likes](_.value, Likes)
|
implicit val likesBSONHandler = intAnyValHandler[Likes](_.value, Likes)
|
||||||
implicit val viewsBSONHandler = intAnyValHandler[Views](_.value, Views)
|
implicit val viewsBSONHandler = intAnyValHandler[Views](_.value, Views)
|
||||||
implicit val rankBSONHandler = dateIsoHandler[Rank](Iso[DateTime, Rank](Rank, _.value))
|
implicit val rankBSONHandler = dateIsoHandler[Rank](Iso[DateTime, Rank](Rank, _.value))
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class UblogForm(markup: UblogMarkup, val captcher: lila.hub.actors.Captche
|
||||||
"title" -> cleanNonEmptyText(minLength = 3, maxLength = 80),
|
"title" -> cleanNonEmptyText(minLength = 3, maxLength = 80),
|
||||||
"intro" -> cleanNonEmptyText(minLength = 0, maxLength = 1_000),
|
"intro" -> cleanNonEmptyText(minLength = 0, maxLength = 1_000),
|
||||||
"markdown" -> cleanNonEmptyText(minLength = 0, maxLength = 100_000).verifying(markdownImage.constraint),
|
"markdown" -> cleanNonEmptyText(minLength = 0, maxLength = 100_000).verifying(markdownImage.constraint),
|
||||||
|
"imageAlt" -> optional(cleanNonEmptyText(minLength = 3, maxLength = 200)),
|
||||||
|
"imageCredit" -> optional(cleanNonEmptyText(minLength = 3, maxLength = 200)),
|
||||||
"language" -> optional(stringIn(LangList.popularNoRegion.map(_.code).toSet)),
|
"language" -> optional(stringIn(LangList.popularNoRegion.map(_.code).toSet)),
|
||||||
"topics" -> optional(text),
|
"topics" -> optional(text),
|
||||||
"live" -> boolean,
|
"live" -> boolean,
|
||||||
|
@ -37,6 +39,8 @@ final class UblogForm(markup: UblogMarkup, val captcher: lila.hub.actors.Captche
|
||||||
title = post.title,
|
title = post.title,
|
||||||
intro = post.intro,
|
intro = post.intro,
|
||||||
markdown = post.markdown,
|
markdown = post.markdown,
|
||||||
|
imageAlt = post.image.flatMap(_.alt),
|
||||||
|
imageCredit = post.image.flatMap(_.credit),
|
||||||
language = post.language.code.some,
|
language = post.language.code.some,
|
||||||
topics = post.topics.map(_.value).mkString(", ").some,
|
topics = post.topics.map(_.value).mkString(", ").some,
|
||||||
live = post.live,
|
live = post.live,
|
||||||
|
@ -52,6 +56,8 @@ object UblogForm {
|
||||||
title: String,
|
title: String,
|
||||||
intro: String,
|
intro: String,
|
||||||
markdown: String,
|
markdown: String,
|
||||||
|
imageAlt: Option[String],
|
||||||
|
imageCredit: Option[String],
|
||||||
language: Option[String],
|
language: Option[String],
|
||||||
topics: Option[String],
|
topics: Option[String],
|
||||||
live: Boolean,
|
live: Boolean,
|
||||||
|
@ -84,6 +90,9 @@ object UblogForm {
|
||||||
title = title,
|
title = title,
|
||||||
intro = intro,
|
intro = intro,
|
||||||
markdown = markdown,
|
markdown = markdown,
|
||||||
|
image = prev.image.map { i =>
|
||||||
|
i.copy(alt = imageAlt, credit = imageCredit)
|
||||||
|
},
|
||||||
language = LangList.removeRegion(realLanguage | prev.language),
|
language = LangList.removeRegion(realLanguage | prev.language),
|
||||||
topics = topics ?? UblogTopic.fromStrList,
|
topics = topics ?? UblogTopic.fromStrList,
|
||||||
live = live,
|
live = live,
|
||||||
|
|
|
@ -13,7 +13,7 @@ case class UblogPost(
|
||||||
intro: String,
|
intro: String,
|
||||||
markdown: String,
|
markdown: String,
|
||||||
language: Lang,
|
language: Lang,
|
||||||
image: Option[PicfitImage.Id],
|
image: Option[UblogImage],
|
||||||
topics: List[UblogTopic],
|
topics: List[UblogTopic],
|
||||||
live: Boolean,
|
live: Boolean,
|
||||||
created: UblogPost.Recorded,
|
created: UblogPost.Recorded,
|
||||||
|
@ -28,6 +28,8 @@ case class UblogPost(
|
||||||
def indexable = live && topics.exists(t => UblogTopic.chessExists(t.value))
|
def indexable = live && topics.exists(t => UblogTopic.chessExists(t.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class UblogImage(id: PicfitImage.Id, alt: Option[String] = None, credit: Option[String] = None)
|
||||||
|
|
||||||
object UblogPost {
|
object UblogPost {
|
||||||
|
|
||||||
case class Id(value: String) extends AnyVal with StringValue
|
case class Id(value: String) extends AnyVal with StringValue
|
||||||
|
@ -50,7 +52,7 @@ object UblogPost {
|
||||||
val blog: UblogBlog.Id
|
val blog: UblogBlog.Id
|
||||||
val title: String
|
val title: String
|
||||||
val intro: String
|
val intro: String
|
||||||
val image: Option[PicfitImage.Id]
|
val image: Option[UblogImage]
|
||||||
val created: Recorded
|
val created: Recorded
|
||||||
val lived: Option[Recorded]
|
val lived: Option[Recorded]
|
||||||
def id = _id
|
def id = _id
|
||||||
|
@ -62,7 +64,7 @@ object UblogPost {
|
||||||
blog: UblogBlog.Id,
|
blog: UblogBlog.Id,
|
||||||
title: String,
|
title: String,
|
||||||
intro: String,
|
intro: String,
|
||||||
image: Option[PicfitImage.Id],
|
image: Option[UblogImage],
|
||||||
created: Recorded,
|
created: Recorded,
|
||||||
lived: Option[Recorded]
|
lived: Option[Recorded]
|
||||||
) extends BasePost
|
) extends BasePost
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
function loadShepherd(f) {
|
function loadShepherd(f) {
|
||||||
var theme = 'shepherd-theme-' + ($('body').hasClass('dark') ? 'default' : 'dark');
|
var theme = 'shepherd-theme-' + ($('body').hasClass('dark') ? 'dark' : 'default');
|
||||||
lichess.loadCss('vendor/shepherd/dist/css/' + theme + '.css');
|
lichess.loadCss('vendor/' + theme + '.css');
|
||||||
lichess.loadScript('vendor/shepherd/dist/js/tether.js', { noVersion: true }).then(function () {
|
lichess.loadScript('vendor/shepherd/dist/js/tether.js', { noVersion: true }).then(function () {
|
||||||
lichess.loadScript('vendor/shepherd/dist/js/shepherd.min.js', { noVersion: true }).then(function () {
|
lichess.loadScript('vendor/shepherd/dist/js/shepherd.min.js', { noVersion: true }).then(function () {
|
||||||
f(theme);
|
f(theme);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
function loadShepherd(f) {
|
function loadShepherd(f) {
|
||||||
if (typeof Shepherd === 'undefined' || Shepherd.activeTour === null) {
|
if (typeof Shepherd === 'undefined' || Shepherd.activeTour === null) {
|
||||||
var theme = 'shepherd-theme-' + ($('body').hasClass('dark') ? 'default' : 'dark');
|
var theme = 'shepherd-theme-' + ($('body').hasClass('dark') ? 'dark' : 'default');
|
||||||
lichess.loadCss('vendor/shepherd/dist/css/' + theme + '.css');
|
lichess.loadCss('vendor/' + theme + '.css');
|
||||||
lichess.loadScript('vendor/shepherd/dist/js/tether.js', { noVersion: true }).then(function () {
|
lichess.loadScript('vendor/shepherd/dist/js/tether.js', { noVersion: true }).then(function () {
|
||||||
lichess.loadScript('vendor/shepherd/dist/js/shepherd.min.js', { noVersion: true }).then(function () {
|
lichess.loadScript('vendor/shepherd/dist/js/shepherd.min.js', { noVersion: true }).then(function () {
|
||||||
f(theme);
|
f(theme);
|
||||||
|
|
213
public/vendor/shepherd-theme-dark.css
vendored
Normal file
213
public/vendor/shepherd-theme-dark.css
vendored
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/* https://raw.githubusercontent.com/shipshapecode/shepherd/e3ed0fcbf5c31137ece409d3ad6fea4e264ca1cc/dist/css/shepherd-theme-dark.css */
|
||||||
|
.shepherd-element, .shepherd-element:after, .shepherd-element:before, .shepherd-element *, .shepherd-element *:after, .shepherd-element *:before {
|
||||||
|
box-sizing: border-box; }
|
||||||
|
|
||||||
|
.shepherd-element {
|
||||||
|
position: absolute;
|
||||||
|
display: none; }
|
||||||
|
.shepherd-element.shepherd-open {
|
||||||
|
display: block; }
|
||||||
|
|
||||||
|
.shepherd-element.shepherd-theme-dark {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content {
|
||||||
|
border-radius: 5px;
|
||||||
|
position: relative;
|
||||||
|
font-family: inherit;
|
||||||
|
background: #232323;
|
||||||
|
color: #eee;
|
||||||
|
padding: 1em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
line-height: 1.5em; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 16px;
|
||||||
|
border-style: solid;
|
||||||
|
pointer-events: none; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content {
|
||||||
|
margin-bottom: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content:before {
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -16px;
|
||||||
|
border-top-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content {
|
||||||
|
margin-top: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content:before {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -16px;
|
||||||
|
border-bottom-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content {
|
||||||
|
margin-right: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content:before {
|
||||||
|
left: 100%;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -16px;
|
||||||
|
border-left-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content {
|
||||||
|
margin-left: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content:before {
|
||||||
|
right: 100%;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -16px;
|
||||||
|
border-right-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content {
|
||||||
|
margin-top: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content:before {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 16px;
|
||||||
|
border-bottom-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content {
|
||||||
|
margin-top: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content:before {
|
||||||
|
bottom: 100%;
|
||||||
|
right: 16px;
|
||||||
|
border-bottom-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content {
|
||||||
|
margin-bottom: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content:before {
|
||||||
|
top: 100%;
|
||||||
|
left: 16px;
|
||||||
|
border-top-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content {
|
||||||
|
margin-bottom: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content:before {
|
||||||
|
top: 100%;
|
||||||
|
right: 16px;
|
||||||
|
border-top-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content {
|
||||||
|
margin-right: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before {
|
||||||
|
top: 16px;
|
||||||
|
left: 100%;
|
||||||
|
border-left-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content {
|
||||||
|
margin-left: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before {
|
||||||
|
top: 16px;
|
||||||
|
right: 100%;
|
||||||
|
border-right-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content {
|
||||||
|
margin-right: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before {
|
||||||
|
bottom: 16px;
|
||||||
|
left: 100%;
|
||||||
|
border-left-color: #232323; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content {
|
||||||
|
margin-left: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before {
|
||||||
|
bottom: 16px;
|
||||||
|
right: 100%;
|
||||||
|
border-right-color: #232323; }
|
||||||
|
|
||||||
|
.shepherd-element.shepherd-theme-dark {
|
||||||
|
z-index: 9999;
|
||||||
|
max-width: 24em;
|
||||||
|
font-size: 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-center.shepherd-has-title .shepherd-content:before, .shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom.shepherd-has-title .shepherd-content:before, .shepherd-element.shepherd-theme-dark.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom.shepherd-has-title .shepherd-content:before {
|
||||||
|
border-bottom-color: #303030; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-has-title .shepherd-content header {
|
||||||
|
background: #303030;
|
||||||
|
padding: 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-has-title .shepherd-content header a.shepherd-cancel-link {
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-dark.shepherd-has-cancel-link .shepherd-content header h3 {
|
||||||
|
float: left; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content {
|
||||||
|
box-shadow: 0 0 1em rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content * {
|
||||||
|
font-size: inherit; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content header {
|
||||||
|
*zoom: 1;
|
||||||
|
border-radius: 5px 5px 0 0; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content header:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content header h3 {
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1;
|
||||||
|
font-weight: normal; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content header a.shepherd-cancel-link {
|
||||||
|
float: right;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.25em;
|
||||||
|
line-height: .8em;
|
||||||
|
font-weight: normal;
|
||||||
|
color: white;
|
||||||
|
opacity: 0.6;
|
||||||
|
position: relative;
|
||||||
|
top: .1em;
|
||||||
|
padding: .8em;
|
||||||
|
margin-bottom: -.8em; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content header a.shepherd-cancel-link:hover {
|
||||||
|
opacity: 1; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content .shepherd-text {
|
||||||
|
padding: 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content .shepherd-text p {
|
||||||
|
margin: 0 0 .5em 0;
|
||||||
|
line-height: 1.3em; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content .shepherd-text p:last-child {
|
||||||
|
margin-bottom: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content footer {
|
||||||
|
padding: 0 1em 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content footer .shepherd-buttons {
|
||||||
|
text-align: right;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content footer .shepherd-buttons li {
|
||||||
|
display: inline;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content footer .shepherd-buttons li .shepherd-button {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
*vertical-align: auto;
|
||||||
|
*zoom: 1;
|
||||||
|
*display: inline;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 0;
|
||||||
|
margin: 0 .5em 0 0;
|
||||||
|
font-family: inherit;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .1em;
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 1em;
|
||||||
|
padding: .75em 2em;
|
||||||
|
background: #3288e6;
|
||||||
|
color: #fff; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content footer .shepherd-buttons li .shepherd-button.shepherd-button-secondary {
|
||||||
|
background: #eee;
|
||||||
|
color: #888; }
|
||||||
|
.shepherd-element.shepherd-theme-dark .shepherd-content footer .shepherd-buttons li:last-child .shepherd-button {
|
||||||
|
margin-right: 0; }
|
||||||
|
|
||||||
|
.shepherd-start-tour-button.shepherd-theme-dark {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
*vertical-align: auto;
|
||||||
|
*zoom: 1;
|
||||||
|
*display: inline;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 0;
|
||||||
|
margin: 0 .5em 0 0;
|
||||||
|
font-family: inherit;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .1em;
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 1em;
|
||||||
|
padding: .75em 2em;
|
||||||
|
background: #3288e6;
|
||||||
|
color: #fff; }
|
213
public/vendor/shepherd-theme-default.css
vendored
Normal file
213
public/vendor/shepherd-theme-default.css
vendored
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/* https://raw.githubusercontent.com/shipshapecode/shepherd/e3ed0fcbf5c31137ece409d3ad6fea4e264ca1cc/dist/css/shepherd-theme-default.css */
|
||||||
|
.shepherd-element, .shepherd-element:after, .shepherd-element:before, .shepherd-element *, .shepherd-element *:after, .shepherd-element *:before {
|
||||||
|
box-sizing: border-box; }
|
||||||
|
|
||||||
|
.shepherd-element {
|
||||||
|
position: absolute;
|
||||||
|
display: none; }
|
||||||
|
.shepherd-element.shepherd-open {
|
||||||
|
display: block; }
|
||||||
|
|
||||||
|
.shepherd-element.shepherd-theme-default {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content {
|
||||||
|
border-radius: 5px;
|
||||||
|
position: relative;
|
||||||
|
font-family: inherit;
|
||||||
|
background: #f6f6f6;
|
||||||
|
color: #444;
|
||||||
|
padding: 1em;
|
||||||
|
font-size: 1.1em;
|
||||||
|
line-height: 1.5em; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-color: transparent;
|
||||||
|
border-width: 16px;
|
||||||
|
border-style: solid;
|
||||||
|
pointer-events: none; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content {
|
||||||
|
margin-bottom: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-center .shepherd-content:before {
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -16px;
|
||||||
|
border-top-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content {
|
||||||
|
margin-top: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-center .shepherd-content:before {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -16px;
|
||||||
|
border-bottom-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content {
|
||||||
|
margin-right: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-right.shepherd-element-attached-middle .shepherd-content:before {
|
||||||
|
left: 100%;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -16px;
|
||||||
|
border-left-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content {
|
||||||
|
margin-left: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-left.shepherd-element-attached-middle .shepherd-content:before {
|
||||||
|
right: 100%;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -16px;
|
||||||
|
border-right-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content {
|
||||||
|
margin-top: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom .shepherd-content:before {
|
||||||
|
bottom: 100%;
|
||||||
|
left: 16px;
|
||||||
|
border-bottom-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content {
|
||||||
|
margin-top: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom .shepherd-content:before {
|
||||||
|
bottom: 100%;
|
||||||
|
right: 16px;
|
||||||
|
border-bottom-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content {
|
||||||
|
margin-bottom: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-top .shepherd-content:before {
|
||||||
|
top: 100%;
|
||||||
|
left: 16px;
|
||||||
|
border-top-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content {
|
||||||
|
margin-bottom: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-top .shepherd-content:before {
|
||||||
|
top: 100%;
|
||||||
|
right: 16px;
|
||||||
|
border-top-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content {
|
||||||
|
margin-right: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before {
|
||||||
|
top: 16px;
|
||||||
|
left: 100%;
|
||||||
|
border-left-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content {
|
||||||
|
margin-left: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before {
|
||||||
|
top: 16px;
|
||||||
|
right: 100%;
|
||||||
|
border-right-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content {
|
||||||
|
margin-right: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-right.shepherd-target-attached-left .shepherd-content:before {
|
||||||
|
bottom: 16px;
|
||||||
|
left: 100%;
|
||||||
|
border-left-color: #f6f6f6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content {
|
||||||
|
margin-left: 16px; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-bottom.shepherd-element-attached-left.shepherd-target-attached-right .shepherd-content:before {
|
||||||
|
bottom: 16px;
|
||||||
|
right: 100%;
|
||||||
|
border-right-color: #f6f6f6; }
|
||||||
|
|
||||||
|
.shepherd-element.shepherd-theme-default {
|
||||||
|
z-index: 9999;
|
||||||
|
max-width: 24em;
|
||||||
|
font-size: 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-center.shepherd-has-title .shepherd-content:before, .shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-right.shepherd-target-attached-bottom.shepherd-has-title .shepherd-content:before, .shepherd-element.shepherd-theme-default.shepherd-element-attached-top.shepherd-element-attached-left.shepherd-target-attached-bottom.shepherd-has-title .shepherd-content:before {
|
||||||
|
border-bottom-color: #e6e6e6; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-has-title .shepherd-content header {
|
||||||
|
background: #e6e6e6;
|
||||||
|
padding: 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-has-title .shepherd-content header a.shepherd-cancel-link {
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-default.shepherd-has-cancel-link .shepherd-content header h3 {
|
||||||
|
float: left; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content {
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.17);
|
||||||
|
padding: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content * {
|
||||||
|
font-size: inherit; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content header {
|
||||||
|
*zoom: 1;
|
||||||
|
border-radius: 5px 5px 0 0; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content header:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content header h3 {
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1;
|
||||||
|
font-weight: normal; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content header a.shepherd-cancel-link {
|
||||||
|
float: right;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.25em;
|
||||||
|
line-height: .8em;
|
||||||
|
font-weight: normal;
|
||||||
|
color: black;
|
||||||
|
opacity: 0.6;
|
||||||
|
position: relative;
|
||||||
|
top: .1em;
|
||||||
|
padding: .8em;
|
||||||
|
margin-bottom: -.8em; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content header a.shepherd-cancel-link:hover {
|
||||||
|
opacity: 1; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content .shepherd-text {
|
||||||
|
padding: 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content .shepherd-text p {
|
||||||
|
margin: 0 0 .5em 0;
|
||||||
|
line-height: 1.3em; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content .shepherd-text p:last-child {
|
||||||
|
margin-bottom: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content footer {
|
||||||
|
padding: 0 1em 1em; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content footer .shepherd-buttons {
|
||||||
|
text-align: right;
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content footer .shepherd-buttons li {
|
||||||
|
display: inline;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content footer .shepherd-buttons li .shepherd-button {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
*vertical-align: auto;
|
||||||
|
*zoom: 1;
|
||||||
|
*display: inline;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 0;
|
||||||
|
margin: 0 .5em 0 0;
|
||||||
|
font-family: inherit;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .1em;
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 1em;
|
||||||
|
padding: .75em 2em;
|
||||||
|
background: #3288e6;
|
||||||
|
color: #fff; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content footer .shepherd-buttons li .shepherd-button.shepherd-button-secondary {
|
||||||
|
background: #eee;
|
||||||
|
color: #888; }
|
||||||
|
.shepherd-element.shepherd-theme-default .shepherd-content footer .shepherd-buttons li:last-child .shepherd-button {
|
||||||
|
margin-right: 0; }
|
||||||
|
|
||||||
|
.shepherd-start-tour-button.shepherd-theme-default {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
*vertical-align: auto;
|
||||||
|
*zoom: 1;
|
||||||
|
*display: inline;
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 0;
|
||||||
|
margin: 0 .5em 0 0;
|
||||||
|
font-family: inherit;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .1em;
|
||||||
|
font-size: .8em;
|
||||||
|
line-height: 1em;
|
||||||
|
padding: .75em 2em;
|
||||||
|
background: #3288e6;
|
||||||
|
color: #fff; }
|
|
@ -382,6 +382,8 @@ computer analysis, game chat and shareable URL.</string>
|
||||||
<string name="follow">Follow</string>
|
<string name="follow">Follow</string>
|
||||||
<string name="following">Following</string>
|
<string name="following">Following</string>
|
||||||
<string name="unfollow">Unfollow</string>
|
<string name="unfollow">Unfollow</string>
|
||||||
|
<string name="followX">Follow %s</string>
|
||||||
|
<string name="unfollowX">Unfollow %s</string>
|
||||||
<string name="block">Block</string>
|
<string name="block">Block</string>
|
||||||
<string name="blocked">Blocked</string>
|
<string name="blocked">Blocked</string>
|
||||||
<string name="unblock">Unblock</string>
|
<string name="unblock">Unblock</string>
|
||||||
|
|
|
@ -31,4 +31,6 @@
|
||||||
<item quantity="other">View all %s posts</item>
|
<item quantity="other">View all %s posts</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="uploadAnImageForYourPost">Upload an image for your post</string>
|
<string name="uploadAnImageForYourPost">Upload an image for your post</string>
|
||||||
|
<string name="imageAlt">Image alternative text</string>
|
||||||
|
<string name="imageCredit">Image credit</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -42,3 +42,7 @@ cg-board {
|
||||||
padding: 2em 4em;
|
padding: 2em 4em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
|
@ -33,8 +33,10 @@
|
||||||
&.gamebook-play {
|
&.gamebook-play {
|
||||||
@media (min-width: 400px) and (min-aspect-ratio: 1/1) {
|
@media (min-width: 400px) and (min-aspect-ratio: 1/1) {
|
||||||
grid-template-columns: minmax(200px, calc(100vh - 2.5rem)) minmax(200px, 1fr);
|
grid-template-columns: minmax(200px, calc(100vh - 2.5rem)) minmax(200px, 1fr);
|
||||||
grid-template-rows: auto 2.5rem;
|
grid-template-rows: auto 3rem;
|
||||||
grid-template-areas: 'board tools' 'board controls';
|
grid-template-areas:
|
||||||
|
'board tools'
|
||||||
|
'board controls';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,11 +57,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.analyse.variant-crazyhouse {
|
.analyse.variant-crazyhouse {
|
||||||
grid-template-rows: 60px auto 2.5rem 60px;
|
grid-template-areas:
|
||||||
|
'pocket-top'
|
||||||
|
'board'
|
||||||
|
'pocket-bot'
|
||||||
|
'tools'
|
||||||
|
'controls';
|
||||||
|
grid-template-rows: auto 100vw auto 1fr 3rem;
|
||||||
|
height: calc(100vh - 2.5rem);
|
||||||
|
|
||||||
body.supports-max-content & {
|
@media (min-width: 400px) and (min-aspect-ratio: 1/1) {
|
||||||
grid-template-rows: max-content auto 2.5rem max-content;
|
grid-template-rows: auto 1fr 3rem auto;
|
||||||
|
grid-template-areas:
|
||||||
|
'board pocket-top'
|
||||||
|
'board tools'
|
||||||
|
'board controls'
|
||||||
|
'board pocket-bot';
|
||||||
}
|
}
|
||||||
|
|
||||||
grid-template-areas: 'board pocket-top' 'board tools' 'board controls' 'board pocket-bot';
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
@include transition;
|
@include transition;
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,10 @@
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin: 1.3em 0 0.5em 0;
|
margin: 1.8em 0 0.5em 0;
|
||||||
border-bottom: 1px solid $c-brag;
|
border-bottom: 1px solid $c-brag;
|
||||||
line-height: 2.5em;
|
line-height: 1.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
p,
|
p,
|
||||||
|
@ -32,7 +33,8 @@
|
||||||
@extend %roboto;
|
@extend %roboto;
|
||||||
|
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
line-height: 2.5em;
|
line-height: 1.5em;
|
||||||
|
margin-top: 1.3em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
|
|
|
@ -1,6 +1,35 @@
|
||||||
@import 'flash';
|
@import 'flash';
|
||||||
|
|
||||||
.ublog-post-form {
|
.ublog-post-form {
|
||||||
|
padding-bottom: 5vh;
|
||||||
|
|
||||||
|
&__main .form-split,
|
||||||
|
&__main > .form-group,
|
||||||
|
&__main .form-actions,
|
||||||
|
&__delete .form-actions,
|
||||||
|
&__image {
|
||||||
|
padding-left: var(--box-padding);
|
||||||
|
padding-right: var(--box-padding);
|
||||||
|
}
|
||||||
|
&__image {
|
||||||
|
background: $c-bg-zebra;
|
||||||
|
padding-top: 5vh;
|
||||||
|
}
|
||||||
|
&__image-text {
|
||||||
|
background: $c-bg-zebra;
|
||||||
|
margin-bottom: 5vh;
|
||||||
|
border-bottom: $border;
|
||||||
|
font-size: 0.9em;
|
||||||
|
.form-group {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.visible {
|
||||||
|
height: auto;
|
||||||
|
.form-group {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.ublog-post-image {
|
.ublog-post-image {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
@ -13,10 +42,8 @@
|
||||||
}
|
}
|
||||||
&__image {
|
&__image {
|
||||||
.form-group {
|
.form-group {
|
||||||
text-align: center;
|
|
||||||
@extend %flex-column;
|
@extend %flex-column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
@extend %box-neat;
|
@extend %box-neat;
|
||||||
|
|
|
@ -52,9 +52,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin-top: 1.3em;
|
margin-top: 1.8em;
|
||||||
border-bottom: 1px solid $c-brag;
|
border-bottom: 1px solid $c-brag;
|
||||||
line-height: 2.5em;
|
line-height: 1.5em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
|
|
|
@ -77,10 +77,18 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&__views {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
&__image {
|
&__image {
|
||||||
@extend %box-neat-force;
|
@extend %box-neat-force;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
&-credit {
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: $c-font-dim;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&__intro {
|
&__intro {
|
||||||
@extend %break-word;
|
@extend %break-word;
|
||||||
|
|
|
@ -3,8 +3,6 @@ import exportLichessGlobals from './site.lichess.globals';
|
||||||
exportLichessGlobals();
|
exportLichessGlobals();
|
||||||
|
|
||||||
export default function (opts: any) {
|
export default function (opts: any) {
|
||||||
document.body.classList.toggle('supports-max-content', !!window.chrome);
|
|
||||||
|
|
||||||
window.LichessAnalyse.start({
|
window.LichessAnalyse.start({
|
||||||
...opts,
|
...opts,
|
||||||
socketSend: () => {},
|
socketSend: () => {},
|
||||||
|
|
|
@ -28,11 +28,16 @@ const setupTopics = (el: HTMLTextAreaElement) =>
|
||||||
});
|
});
|
||||||
|
|
||||||
const setupImage = (form: HTMLFormElement) => {
|
const setupImage = (form: HTMLFormElement) => {
|
||||||
|
const showText = () =>
|
||||||
|
$('.ublog-post-form__image-text').toggleClass('visible', $('.ublog-post-image').hasClass('user-image'));
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
const replace = (html: string) => $(form).find('.ublog-post-image').replaceWith(html);
|
const replace = (html: string) => $(form).find('.ublog-post-image').replaceWith(html);
|
||||||
const wrap = (html: string) => '<div class="ublog-post-image">' + html + '</div>';
|
const wrap = (html: string) => '<div class="ublog-post-image">' + html + '</div>';
|
||||||
xhr.formToXhr(form).then(
|
xhr.formToXhr(form).then(
|
||||||
html => replace(html),
|
html => {
|
||||||
|
replace(html);
|
||||||
|
showText();
|
||||||
|
},
|
||||||
err => replace(wrap(`<bad>${err}</bad>`))
|
err => replace(wrap(`<bad>${err}</bad>`))
|
||||||
);
|
);
|
||||||
replace(wrap(spinner));
|
replace(wrap(spinner));
|
||||||
|
@ -40,6 +45,7 @@ const setupImage = (form: HTMLFormElement) => {
|
||||||
};
|
};
|
||||||
$(form).on('submit', submit);
|
$(form).on('submit', submit);
|
||||||
$(form).find('input[name="image"]').on('change', submit);
|
$(form).find('input[name="image"]').on('change', submit);
|
||||||
|
showText();
|
||||||
};
|
};
|
||||||
|
|
||||||
const setupMarkdownEditor = (el: HTMLTextAreaElement) => {
|
const setupMarkdownEditor = (el: HTMLTextAreaElement) => {
|
||||||
|
|
Loading…
Reference in a new issue