Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow a user to make sticky blog posts #16736

Merged
merged 16 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/views/coach.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def show(
)(using ctx: Context) = ui.show(
c,
studies = studies.map(s => st.article(cls := "study")(views.study.bits.widget(s, h3))),
posts = posts.map(views.ublog.ui.card(_))
posts = posts.map(p => views.ublog.ui.card(p, showSticky = p.isSticky.getOrElse(false)))
)

def edit(c: lila.coach.Coach.WithUser, form: Form[?])(using ctx: Context) =
Expand Down
2 changes: 1 addition & 1 deletion app/views/user/show/header.scala
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ object header:
,
(ctx.kid.no && info.ublog.so(_.latests).nonEmpty).option(
div(cls := "user-show__blog ublog-post-cards")(
info.ublog.so(_.latests).map(views.ublog.ui.card(_))
info.ublog.so(_.latests).map(p => views.ublog.ui.card(p, showSticky = p.isSticky.getOrElse(false)))
)
),
div(cls := "angles number-menu number-menu--tabs menu-box-pop")(
Expand Down
2 changes: 2 additions & 0 deletions modules/coreI18n/src/main/key.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2761,6 +2761,8 @@ object I18nKey:
val `createBlogDiscussionHelp`: I18nKey = "ublog:createBlogDiscussionHelp"
val `publishOnYourBlog`: I18nKey = "ublog:publishOnYourBlog"
val `publishHelp`: I18nKey = "ublog:publishHelp"
val `stickyPost`: I18nKey = "ublog:stickyPost"
val `stickyPostHelp`: I18nKey = "ublog:stickyPostHelp"
val `xPublishedY`: I18nKey = "ublog:xPublishedY"
val `thisPostIsPublished`: I18nKey = "ublog:thisPostIsPublished"
val `thisIsADraft`: I18nKey = "ublog:thisIsADraft"
Expand Down
27 changes: 23 additions & 4 deletions modules/ublog/src/main/UblogApi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,29 @@ final class UblogApi(

def latestPosts(blogId: UblogBlog.Id, nb: Int): Fu[List[UblogPost.PreviewPost]] =
colls.post
.find($doc("blog" -> blogId, "live" -> true), previewPostProjection.some)
.sort($doc("lived.at" -> -1))
.cursor[UblogPost.PreviewPost](ReadPref.sec)
.list(nb)
.aggregateList(maxDocs = nb, _.sec): framework =>
import framework.*
Match($doc("blog" -> blogId, "live" -> true)) -> List(
AddFields(
$doc(
"isSticky" -> $doc(
"$cond" -> $doc(
"if" -> $doc("$ne" -> $arr($doc("$type" -> "$sticky"), "missing")),
yafred marked this conversation as resolved.
Show resolved Hide resolved
"then" -> "$sticky",
"else" -> false
)
)
)
),
Sort(Descending("isSticky"), Descending("lived.at")),
Project($doc(previewPostProjection)),
yafred marked this conversation as resolved.
Show resolved Hide resolved
Limit(nb)
)
.map: docs =>
for
doc <- docs
post <- doc.asOpt[UblogPost.PreviewPost]
yield post

def userBlogPreviewFor(user: User, nb: Int)(using me: Option[Me]): Fu[Option[UblogPost.BlogPreview]] =
val blogId = UblogBlog.Id.User(user.id)
Expand Down
15 changes: 8 additions & 7 deletions modules/ublog/src/main/UblogBsonHandlers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ private object UblogBsonHandlers:
val lightPostProjection = $doc("title" -> true)
val previewPostProjection =
$doc(
"blog" -> true,
"title" -> true,
"intro" -> true,
"image" -> true,
"created" -> true,
"lived" -> true,
"topics" -> true
"blog" -> true,
"title" -> true,
"intro" -> true,
"image" -> true,
"created" -> true,
"lived" -> true,
"topics" -> true,
"isSticky" -> true
)
5 changes: 5 additions & 0 deletions modules/ublog/src/main/UblogForm.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ final class UblogForm(val captcher: CaptchaApi, langList: LangList):
"topics" -> optional(text),
"live" -> boolean,
"discuss" -> boolean,
"sticky" -> boolean,
"gameId" -> of[GameId],
"move" -> text
)(UblogPostData.apply)(unapply)
Expand All @@ -40,6 +41,7 @@ final class UblogForm(val captcher: CaptchaApi, langList: LangList):
topics = post.topics.mkString(", ").some,
live = post.live,
discuss = ~post.discuss,
sticky = ~post.sticky,
gameId = GameId(""),
move = ""
)
Expand All @@ -56,6 +58,7 @@ object UblogForm:
topics: Option[String],
live: Boolean,
discuss: Boolean,
sticky: Boolean,
gameId: GameId,
move: String
) extends WithCaptcha:
Expand All @@ -72,6 +75,7 @@ object UblogForm:
image = none,
live = false,
discuss = Option(false),
sticky = Option(false),
created = UblogPost.Recorded(user.id, nowInstant),
updated = none,
lived = none,
Expand All @@ -92,6 +96,7 @@ object UblogForm:
topics = topics.so(UblogTopic.fromStrList),
live = live,
discuss = Option(discuss),
sticky = Option(sticky),
updated = UblogPost.Recorded(user.id, nowInstant).some,
lived = prev.lived.orElse(live.option(UblogPost.Recorded(user.id, nowInstant)))
)
Expand Down
2 changes: 2 additions & 0 deletions modules/ublog/src/main/UblogPost.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ case class UblogPost(
topics: List[UblogTopic],
live: Boolean,
discuss: Option[Boolean],
sticky: Option[Boolean],
created: UblogPost.Recorded,
updated: Option[UblogPost.Recorded],
lived: Option[UblogPost.Recorded],
Expand Down Expand Up @@ -73,6 +74,7 @@ object UblogPost:
created: Recorded,
updated: Option[Recorded],
lived: Option[Recorded],
isSticky: Option[Boolean],
topics: List[UblogTopic]
) extends BasePost

Expand Down
7 changes: 7 additions & 0 deletions modules/ublog/src/main/ui/UblogFormUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ final class UblogFormUi(helpers: Helpers, ui: UblogUi)(
help = trans.ublog.publishHelp().some,
half = true
)
),
form3.split(
form3.checkbox(
form("sticky"),
trans.ublog.stickyPost(),
help = trans.ublog.stickyPostHelp().some
)
)
)
,
Expand Down
13 changes: 9 additions & 4 deletions modules/ublog/src/main/ui/UblogUi.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,22 @@ final class UblogUi(helpers: Helpers, atomUi: AtomUi)(picfitUrl: lila.core.misc.
post: UblogPost.BasePost,
makeUrl: UblogPost.BasePost => Call = urlOfPost,
showAuthor: ShowAt = ShowAt.none,
showIntro: Boolean = true
showIntro: Boolean = true,
showSticky: Boolean = false
)(using Context) =
val clsSticky = if showSticky then "ublog-post-card--sticky" else ""
a(
cls := s"ublog-post-card ublog-post-card--link ublog-post-card--by-${post.created.by}",
cls := s"ublog-post-card ublog-post-card--link ublog-post-card--by-${post.created.by} $clsSticky",
href := makeUrl(post)
)(
span(cls := "ublog-post-card__top")(
thumbnail(post, _.Size.Small)(cls := "ublog-post-card__image"),
post.lived.map { live => semanticDate(live.at)(cls := "ublog-post-card__over-image") },
post.lived.map { live => semanticDate(live.at)(cls := s"ublog-post-card__over-image")() },
showAuthor match
case ShowAt.none => emptyFrag
case ShowAt.none =>
if showSticky then
span(dataIcon := Icon.Star, cls := "user-link ublog-post-card__over-image pos-top")
else emptyFrag
case showAt =>
userIdSpanMini(post.created.by)(cls := s"ublog-post-card__over-image pos-$showAt")
),
Expand Down
2 changes: 2 additions & 0 deletions translation/source/ublog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
<string name="createBlogDiscussionHelp">A forum topic will be created for people to comment on your post</string>
<string name="publishOnYourBlog">Publish on your blog</string>
<string name="publishHelp">If checked, the post will be listed on your blog. If not, it will be private, in your draft posts</string>
<string name="stickyPost" comment="Label for the toggle that can make this blog post sticky.">Sticky post</string>
<string name="stickyPostHelp">If checked, this post will be listed first in your profile recent posts.</string>
<plurals name="publishedNbBlogPosts">
<item quantity="one">Published a blog post</item>
<item quantity="other">Published %s blog posts</item>
Expand Down
6 changes: 6 additions & 0 deletions ui/bits/css/ublog/_card.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
0 0 20px $c-link;
}

&--sticky {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i know it's everywhere in our code, but using parent selector to glue names is bad for searchability, which means it is just bad.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's just an opinion, i'm not suggesting you rewrite all of our scss here! 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeap, I just copied the &--link above

I think I'll leave it like that for the time being.
Is there a discussion somewhere about the best practices to adopt when working with scss ?

box-shadow:
0 0 5px $c-secondary,
0 0 20px $c-secondary;
}

&__top {
display: block;
position: relative;
Expand Down
Loading