diff --git a/app/views/account/profile.scala.html b/app/views/account/profile.scala.html index 57df3a9964..6708f69a88 100644 --- a/app/views/account/profile.scala.html +++ b/app/views/account/profile.scala.html @@ -40,6 +40,13 @@ evenMoreCss =cssTag("material.form.css")) { } } + @base.form.group(form("links"), Html("Social media links ")) { + +

+ Such as Twitter, Facebook, Github, Chess.com, ...
+ One URL per line. +

+ } @errMsg(form) @base.form.submit() diff --git a/app/views/user/show/header.scala.html b/app/views/user/show/header.scala.html index 1bacb287d1..cfb94959f8 100644 --- a/app/views/user/show/header.scala.html +++ b/app/views/user/show/header.scala.html @@ -169,9 +169,14 @@ case _ => {

@trans.tpTimeSpentOnTV(showPeriod(tvPeriod))

} } -
+ +
@info.teamIds.sorted.map { t => - @teamLink(t) + @teamLink(t, withIcon = false) }
diff --git a/modules/user/src/main/DataForm.scala b/modules/user/src/main/DataForm.scala index 06cfd2c258..5ce2870930 100644 --- a/modules/user/src/main/DataForm.scala +++ b/modules/user/src/main/DataForm.scala @@ -20,7 +20,8 @@ object DataForm { "lastName" -> nameField, "fideRating" -> optional(number(min = 600, max = 3000)), "uscfRating" -> optional(number(min = 600, max = 3000)), - "ecfRating" -> optional(number(min = 0, max = 300)) + "ecfRating" -> optional(number(min = 0, max = 300)), + "links" -> optional(nonEmptyText(maxLength = 3000)) )(Profile.apply)(Profile.unapply)) def profileOf(user: User) = profile fill user.profileOrDefault diff --git a/modules/user/src/main/Links.scala b/modules/user/src/main/Links.scala new file mode 100644 index 0000000000..ade4a8d1d2 --- /dev/null +++ b/modules/user/src/main/Links.scala @@ -0,0 +1,45 @@ +package lila.user + +object Links { + + def make(text: String): List[Link] = text.lines.toList.map(_.trim) flatMap toLink + + private val UrlRegex = """^(?:http[s]?:\/\/)?(.+)/.+""".r + + private def toLink(line: String): Option[Link] = line match { + case UrlRegex(domain) => Link( + site = Link.Site.allKnown find { site => + site.domains.contains(domain) + } getOrElse Link.Site.Other(domain), + url = + if (line startsWith "http") line + else s"https://$line" + ).some + case _ => none + } +} + +case class Link(site: Link.Site, url: String) + +object Link { + + sealed abstract class Site(val name: String, val domains: List[String]) + object Site { + case object Twitter extends Site("Twitter", List("twitter.com")) + case object Facebook extends Site("Facebook", List("facebook.com")) + case object YouTube extends Site("YouTube", List("youtube.com")) + case object Twitch extends Site("Twitch", List("twitch.com")) + case object Github extends Site("Github", List("github.com")) + case object ChessCom extends Site("Chess.com", List("chess.com")) + case object Chess24 extends Site("Chess24", List("chess24.com")) + case object GameKnot extends Site("GameKnot", List("gameknot.com")) + case object ChessTempo extends Site("ChessTempo", List("chesstempo.com")) + case object ChessCube extends Site("ChessCube", List("chesscube.com")) + case class Other(domain: String) extends Site(domain, List(domain)) + + val allKnown: List[Site] = List( + Twitter, Facebook, YouTube, Twitch, Github, + ChessCom, Chess24, GameKnot, ChessTempo, ChessCube + ) + } +} diff --git a/modules/user/src/main/Profile.scala b/modules/user/src/main/Profile.scala index 1b07aacc96..f625a5623a 100644 --- a/modules/user/src/main/Profile.scala +++ b/modules/user/src/main/Profile.scala @@ -8,7 +8,8 @@ case class Profile( lastName: Option[String] = None, fideRating: Option[Int] = None, uscfRating: Option[Int] = None, - ecfRating: Option[Int] = None + ecfRating: Option[Int] = None, + links: Option[String] = None ) { def nonEmptyRealName = List(ne(firstName), ne(lastName)).flatten match { @@ -31,6 +32,8 @@ case class Profile( 100 * c.count(_.isDefined) / c.size } + def actualLinks: List[Link] = links ?? Links.make + import Profile.OfficialRating def officialRating: Option[OfficialRating] = @@ -47,5 +50,6 @@ object Profile { val default = Profile() - private[user] val profileBSONHandler = reactivemongo.bson.Macros.handler[Profile] + import reactivemongo.bson.Macros + private[user] val profileBSONHandler = Macros.handler[Profile] } diff --git a/public/stylesheets/user-show.css b/public/stylesheets/user-show.css index 96fbb485b0..6f11fbb66a 100644 --- a/public/stylesheets/user-show.css +++ b/public/stylesheets/user-show.css @@ -299,17 +299,23 @@ div.sub_ratings h3 { .user_show .bio, .user_show .stats, .user_show .tournament_points, +.user_show .social_links, .user_show .teams { display: block; margin-top: 16px; } +.user_show .col2 { + display: flex; + flex-flow: row wrap; + line-height: 1.7em; +} +.user_show .col2 > a { + flex: 0 0 50%; + color: #3893E8!important; +} .user_show .bio { font-style: italic; } -.user_show .teams a { - display: block; - margin: 5px 0; -} .user_show div.games { padding-top: 10px; }