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;
}