Skip to content

Commit 0d26e7f

Browse files
authored
Backport "Feat: Add a custom icon" to LTS (#19070)
Backports #17241 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 4df236c + 4f03d10 commit 0d26e7f

File tree

6 files changed

+117
-18
lines changed

6 files changed

+117
-18
lines changed

scaladoc/resources/dotty_res/styles/theme/components/button/icon-button.css

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,50 @@
533533
content: url("../../../../images/icon-buttons/gitter/dark/selected.svg");
534534
}
535535

536+
/* custom button */
537+
538+
.icon-button.custom-dark{
539+
display: none;
540+
}
541+
542+
.icon-button.custom::after {
543+
content: "";
544+
background-image: var(--bgimage);
545+
background-repeat: no-repeat;
546+
background-position: center;
547+
background-size: contain;
548+
display: block;
549+
max-width: 100%;
550+
max-height: 100%;
551+
}
552+
553+
.theme-dark .icon-button.custom-dark{
554+
display: unset;
555+
}
556+
557+
.theme-dark .icon-button.custom-dark::after{
558+
content: "";
559+
background-image: var(--bgimage-dark);
560+
background-repeat: no-repeat;
561+
background-position: center;
562+
background-size: contain;
563+
display: block;
564+
max-width: 100%;
565+
max-height: 100%;
566+
}
567+
568+
.theme-dark .icon-button.custom{
569+
display: none;
570+
}
571+
572+
.icon-button.custom:hover{
573+
opacity: 0.8;
574+
}
575+
576+
.icon-button.custom-dark:hover{
577+
opacity: 0.8;
578+
}
579+
536580
/* copy button */
537581

538582
.icon-button.copy-button::after {
@@ -830,4 +874,4 @@
830874

831875
.theme-dark .documentableElement .ar.icon-button.expanded.selected::after {
832876
content: url("../../../../images/icon-buttons/arrow-down/dark/selected.svg");
833-
}
877+
}

scaladoc/resources/dotty_res/styles/theme/layout/footer.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
display: none;
6565
}
6666

67-
#footer.mobile-footer .text-mobile {
67+
#footer.mobile-footer .text-mobile {
6868
display: flex;
6969
width: 100%;
7070
justify-content: center;
@@ -78,5 +78,5 @@
7878
#footer.mobile-footer > .text-mobile {
7979
display: flex;
8080
}
81-
81+
8282
}

scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class ScaladocSettings extends SettingGroup with AllScalaSettings:
4343

4444
val socialLinks: Setting[List[String]] =
4545
MultiStringSetting("-social-links", "social-links",
46-
"Links to social sites. '[github|twitter|gitter|discord]::link' syntax is used.")
46+
"Links to social sites. '[github|twitter|gitter|discord]::link' or 'custom::link::light_icon_file_name[::dark_icon_file_name]' syntax is used. For custom links, the icons must be present in '_assets/images/'")
4747

4848
val deprecatedSkipPackages: Setting[List[String]] =
4949
MultiStringSetting("-skip-packages", "packages", "Deprecated, please use `-skip-by-id` or `-skip-by-regex`")

scaladoc/src/dotty/tools/scaladoc/SocialLinks.scala

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ enum SocialLinks(val url: String, val className: String):
55
case Twitter(tUrl: String) extends SocialLinks(tUrl, "twitter")
66
case Gitter(gUrl: String) extends SocialLinks(gUrl, "gitter")
77
case Discord(dUrl: String) extends SocialLinks(dUrl, "discord")
8+
case Custom(cUrl: String, lightIcon: String, darkIcon: String) extends SocialLinks(cUrl, "custom")
89

910
object SocialLinks:
11+
val LowercaseNamePattern = "^[a-z]+$".r
12+
1013
def parse(s: String): Either[String, SocialLinks] =
1114
val errorPrefix = s"Social links arg $s is invalid: "
1215
val splitted = s.split("::")
13-
splitted.head match {
16+
17+
splitted.head.toLowerCase match {
1418
case "github" if splitted.size == 2 => Right(Github(splitted(1)))
1519
case "github" => Left(errorPrefix + "For 'github' arg expected one argument: url")
1620
case "twitter" if splitted.size == 2 => Right(Twitter(splitted(1)))
@@ -19,5 +23,8 @@ object SocialLinks:
1923
case "gitter" => Left(errorPrefix + "For 'gitter' arg expected one argument: url")
2024
case "discord" if splitted.size == 2 => Right(Discord(splitted(1)))
2125
case "discord" => Left(errorPrefix + "For 'discord' arg expected one argument: url")
26+
case LowercaseNamePattern() if splitted.size == 4 => Right(Custom(splitted(1), splitted(2), splitted(3)))
27+
case LowercaseNamePattern() if splitted.size == 3 => Right(Custom(splitted(1), splitted(2), splitted(2)))
28+
case LowercaseNamePattern() => Left(errorPrefix + "For the 'custom' link, a minimum of two arguments is expected: URL, light icon file name, [dark icon file name]")
2229
case _ => Left(errorPrefix)
2330
}

scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,14 @@ class HtmlRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: Do
166166
def icon(link: SocialLinks) = link.className
167167
args.socialLinks.map { link =>
168168
a(href := link.url) (
169-
button(cls := s"icon-button ${icon(link)}")
169+
link match
170+
case SocialLinks.Custom(_, lightIcon, darkIcon) =>
171+
Seq(
172+
button(cls := s"icon-button ${icon(link)}", style := s"--bgimage:url(../../../../images/$lightIcon)"),
173+
button(cls := s"icon-button ${icon(link)}-dark", style := s"--bgimage-dark:url(../../../../images/$darkIcon)")
174+
)
175+
case _ =>
176+
button(cls := s"icon-button ${icon(link)}")
170177
)
171178
}
172179

@@ -308,18 +315,7 @@ class HtmlRenderer(rootPackage: Member, members: Map[DRI, Member])(using ctx: Do
308315
"Generated with"
309316
),
310317
div(cls := "right-container")(
311-
a(href := "https://github.com/lampepfl/dotty") (
312-
button(cls := "icon-button gh")
313-
),
314-
a(href := "https://twitter.com/scala_lang") (
315-
button(cls := "icon-button twitter")
316-
),
317-
a(href := "https://discord.com/invite/scala") (
318-
button(cls := "icon-button discord"),
319-
),
320-
a(href := "https://gitter.im/scala/scala") (
321-
button(cls := "icon-button gitter"),
322-
),
318+
socialLinks,
323319
div(cls := "text")(textFooter)
324320
),
325321
div(cls := "text-mobile")(textFooter)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package dotty.tools.scaladoc
2+
3+
import org.junit.Test
4+
import org.junit.Assert._
5+
import dotty.tools.scaladoc.SocialLinks
6+
7+
class SocialLinksTest:
8+
9+
@Test def githubLink(): Unit =
10+
val githubLink = "github::https://github.com/test"
11+
val expected = SocialLinks.Github("https://github.com/test")
12+
assertEquals(expected, SocialLinks.parse(githubLink).getOrElse(null))
13+
14+
@Test def twitterLink(): Unit =
15+
val twitterLink = "twitter::https://twitter.com/test"
16+
val expected = SocialLinks.Twitter("https://twitter.com/test")
17+
assertEquals(expected, SocialLinks.parse(twitterLink).getOrElse(null))
18+
19+
@Test def gitterLink(): Unit =
20+
val gitterLink = "gitter::https://gitter.im/test"
21+
val expected = SocialLinks.Gitter("https://gitter.im/test")
22+
assertEquals(expected, SocialLinks.parse(gitterLink).getOrElse(null))
23+
24+
@Test def discordLink(): Unit =
25+
val discordLink = "discord::https://discord.gg/test"
26+
val expected = SocialLinks.Discord("https://discord.gg/test")
27+
assertEquals(expected, SocialLinks.parse(discordLink).getOrElse(null))
28+
29+
@Test def customLinkLight(): Unit =
30+
val customLink = "namecustom::https://custom.com/test::custom"
31+
val expected = SocialLinks.Custom("https://custom.com/test", "custom", "custom")
32+
assertEquals(expected, SocialLinks.parse(customLink).getOrElse(null))
33+
34+
@Test def customLinkLightAndDark(): Unit =
35+
val customLink = "namecustom::https://custom.com/test::custom::custom-dark"
36+
val expected = SocialLinks.Custom("https://custom.com/test", "custom", "custom-dark")
37+
assertEquals(expected, SocialLinks.parse(customLink).getOrElse(null))
38+
39+
@Test def customLinkUpper(): Unit =
40+
val customLink = "Namecustom::https://custom.com/test::custom"
41+
val expected = SocialLinks.Custom("https://custom.com/test", "custom", "custom")
42+
assertEquals(expected, SocialLinks.parse(customLink).getOrElse(null))
43+
44+
@Test def parseRegexError(): Unit =
45+
val regexErrorLink = "nameCustom3::https://custom.com/test::custom::custom-dark::custom"
46+
val expected = s"Social links arg $regexErrorLink is invalid: "
47+
assertEquals(expected, SocialLinks.parse(regexErrorLink).left.getOrElse(null))
48+
49+
@Test def parseLinkWithError(): Unit =
50+
val errorLink = "namecustom::https://custom.com/test::custom::custom-dark::custom"
51+
val expected = s"Social links arg $errorLink is invalid: For the 'custom' link, a minimum of two arguments is expected: URL, light icon file name, [dark icon file name]"
52+
assertEquals(expected, SocialLinks.parse(errorLink).left.getOrElse(null))

0 commit comments

Comments
 (0)