Skip to content

Commit f0dc06d

Browse files
committed
Optimize page load
1 parent 2ad2c42 commit f0dc06d

26 files changed

+277
-75
lines changed

build.scala

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//> using dep com.monovore::decline-effect::2.6.0
44
//> using dep org.graalvm.js:js:25.0.2
55
//> using dep org.webjars.npm:katex:0.16.28
6+
//> using dep org.webjars.npm:fortawesome__fontawesome-free:7.1.0
67
//> using dep pink.cozydev::protosearch-laika:0.0-fdae301-SNAPSHOT
78
//> using repository https://central.sonatype.com/repository/maven-snapshots
89
//> using option -deprecation
@@ -11,6 +12,7 @@ import cats.effect.*
1112
import cats.syntax.all.*
1213
import com.monovore.decline.Opts
1314
import com.monovore.decline.effect.CommandIOApp
15+
import java.io.FileNotFoundException
1416

1517
// Welcome to the typelevel.org build script!
1618
// This script builds the site and can serve it locally for previewing.
@@ -116,7 +118,9 @@ object LaikaBuild {
116118
LaikaCustomizations.Directives,
117119
LaikaCustomizations.RssExtensions
118120
)
119-
.withConfigValue(LinkValidation.Global(excluded = Seq(Path.Root / "blog" / "feed.rss")))
121+
.withConfigValue(
122+
LinkValidation.Global(excluded = Seq(Path.Root / "blog" / "feed.rss"))
123+
)
120124
.withConfigValue(LaikaKeys.siteBaseURL, "https://typelevel.org/")
121125
.parallel[IO]
122126
.withTheme(theme)
@@ -180,7 +184,7 @@ object LaikaCustomizations {
180184
val link = h.options.id.map { id =>
181185
SpanLink
182186
.internal(RelativePath.CurrentDocument(id))(
183-
Literal("", Styles("fas", "fa-link", "fa-sm"))
187+
RawContent(NonEmptySet.of("html"), Icons("fa-link"))
184188
)
185189
.withOptions(
186190
Styles("anchor-link")
@@ -248,6 +252,14 @@ object LaikaCustomizations {
248252
.leftMap(_.message)
249253
.map(TemplateSpanSequence(_))
250254
}
255+
},
256+
TemplateDirectives.create("svg") {
257+
import TemplateDirectives.dsl.*
258+
attribute(0).as[String].map { icon =>
259+
TemplateElement(
260+
RawContent(NonEmptySet.of("html", "rss"), Icons(icon))
261+
)
262+
}
251263
}
252264
)
253265

@@ -329,6 +341,36 @@ object LaikaCustomizations {
329341
}
330342
}
331343
}
344+
345+
val Icons = {
346+
def loadFaIcon(prefix: String, name: String) = {
347+
val resourcePath =
348+
"/META-INF/resources/webjars/fortawesome__fontawesome-free/7.1.0"
349+
val inputStream =
350+
getClass.getResourceAsStream(s"$resourcePath/svgs/$prefix/$name.svg")
351+
String(inputStream.readAllBytes())
352+
}
353+
354+
Map(
355+
// brands
356+
"fa-bluesky" -> loadFaIcon("brands", "bluesky"),
357+
"fa-discord" -> loadFaIcon("brands", "discord"),
358+
"fa-github" -> loadFaIcon("brands", "github"),
359+
"fa-linkedin" -> loadFaIcon("brands", "linkedin"),
360+
"fa-mastodon" -> loadFaIcon("brands", "mastodon"),
361+
"fa-youtube" -> loadFaIcon("brands", "youtube"),
362+
// solids
363+
"fa-book" -> loadFaIcon("solid", "book"),
364+
"fa-envelope" -> loadFaIcon("solid", "envelope"),
365+
"fa-globe" -> loadFaIcon("solid", "globe"),
366+
"fa-hand-holding-heart" -> loadFaIcon("solid", "hand-holding-heart"),
367+
"fa-link" -> loadFaIcon("solid", "link"),
368+
"fa-magnifying-glass" -> loadFaIcon("solid", "magnifying-glass"),
369+
"fa-person-chalkboard" -> loadFaIcon("solid", "person-chalkboard"),
370+
"fa-puzzle-piece" -> loadFaIcon("solid", "puzzle-piece"),
371+
"fa-square-rss" -> loadFaIcon("solid", "square-rss")
372+
)
373+
}
332374
}
333375

334376
object KaTeX {
@@ -338,7 +380,7 @@ object KaTeX {
338380
private def loadKaTeX(): String = {
339381
val resourcePath = "/META-INF/resources/webjars/katex/0.16.28/dist/katex.js"
340382
val inputStream = getClass.getResourceAsStream(resourcePath)
341-
new String(inputStream.readAllBytes())
383+
String(inputStream.readAllBytes())
342384
}
343385

344386
private lazy val katex = {
@@ -352,7 +394,11 @@ object KaTeX {
352394

353395
def apply(latex: String, displayMode: Boolean = false): String =
354396
synchronized {
355-
val options = Map("throwOnError" -> true, "strict" -> true, "displayMode" -> displayMode)
397+
val options = Map(
398+
"throwOnError" -> true,
399+
"strict" -> true,
400+
"displayMode" -> displayMode
401+
)
356402
katex.invokeMember("renderToString", latex, options.asJava).asString
357403
}
358404

src/blog/algebraic-api-design.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${battermann}
33
date: "2019-02-06"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# Algebraic API Design - Types, Functions, Properties

src/blog/blog.template.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<span class="bulma-icon-text bulma-has-text-light">
77
Blog
88
<a class="bulma-icon bulma-has-text-current" href="@:target(feed.rss)">
9-
<i class="fas fa-square-rss"></i>
9+
@:svg(fa-square-rss)
1010
</a>
1111
</span>
1212
</p>

src/blog/deriving-instances-1.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${larsrh}
33
date: "2013-06-24"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# Deriving Type Class Instances

src/blog/equivalence-vs-equality.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${TomasMikula}
33
date: "2017-04-02"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# Equivalence versus Equality

src/blog/existential-inside.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${S11001001}
33
date: "2016-01-28"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# It’s existential on the inside
@@ -81,7 +82,7 @@ cases, `duzzle` among them, this is one where the caller determines
8182
the type.
8283

8384
We’ve [discussed](method-equiv.md) how you can
84-
prove that `duzzle` *<sub><small>m</small></sub>* `duzzle2`, in a
85+
prove that `duzzle` @:math \equiv_{m} @:@ `duzzle2`, in a
8586
previous post. Now, it’s time to see why.
8687

8788
## Type parameters are parameters
@@ -118,7 +119,7 @@ PList[([A], PList[A])] // “paired”
118119
## The `duzzle`s are currying
119120

120121
With these two models, we can finally get to the bottom of
121-
`duzzle` *<sub><small>m</small></sub>* `duzzle2`. Here are their
122+
`duzzle` @:math \equiv_{m} @:@ `duzzle2`. Here are their
122123
types, rewritten in the forms we’ve just seen.
123124

124125
```scala

src/blog/libra.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${zainabali}
33
date: "2017-06-13"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# Compile time dimensional analysis with Libra
@@ -27,8 +28,8 @@ This is actually a form of dimensional analysis. We're mentally assigning the d
2728

2829
### Why is it important?
2930

30-
Ignoring the laws can result in serious problems.
31-
Take the Mars Climate Orbiter, a $200 million space probe which successfully reached Mars after a year long voyage, but suddenly crashed into the Martian atmosphere on arrival. Most components on the orbiter were using metric units, however a single component was sending instructions in Imperial units. The other components did not detect this, and instead began a sudden descent causing the orbiter to burn up. This was a simple unit conversion error! It was a basic mistake that could have been easily avoided. It should have been picked up during testing, or in the runtime validation layer.
31+
Ignoring the laws can result in serious problems.
32+
Take the Mars Climate Orbiter, a $200 million space probe which successfully reached Mars after a year long voyage, but suddenly crashed into the Martian atmosphere on arrival. Most components on the orbiter were using metric units, however a single component was sending instructions in Imperial units. The other components did not detect this, and instead began a sudden descent causing the orbiter to burn up. This was a simple unit conversion error! It was a basic mistake that could have been easily avoided. It should have been picked up during testing, or in the runtime validation layer.
3233

3334
In fact, it could even have been caught at compile time.
3435

@@ -42,21 +43,21 @@ We'll begin by working through our calculation in doubles before adding compile
4243

4344
The star that we're aiming for is Alpha Librae. This is pretty far, so we can only send one very small person. We have been given the following quantities to work with:
4445

45-
- rocket mass of a small person - 40kg
46-
- fuel mass of a lot of fuel - 10<sup>4</sup>kg
47-
- exhaust speed of a decent fuel - 10<sup>6</sup>ms<sup>-1</sup>
48-
- distance to Alpha Librae - 77 ly
46+
- rocket mass of a small person - @:math 40 \text{kg} @:@
47+
- fuel mass of a lot of fuel - @:math 10^4 \text{kg} @:@
48+
- exhaust speed of a decent fuel - @:math 10^6 \text{ms}^{-1} @:@
49+
- distance to Alpha Librae - @:math 77 \text{ly} @:@
4950

5051
We want to calculate when the rocket will arrive.
5152

5253
To do so, we're going to make use of a formula known as the *Ideal Rocket Equation*.
5354
This calculates the speed of a rocket in ideal conditions.
54-
55+
5556
```scala
5657
val rocketSpeed = exhaustSpeed * log((rocketMass + fuelMass) / rocketMass)
5758
```
5859
Once we have the speed, we can work out the travel time.
59-
60+
6061
```scala
6162
val time = distance / rocketSpeed
6263
```
@@ -92,7 +93,7 @@ case class Quantity[A](value: Double)
9293

9394

9495

95-
96+
9697
```scala
9798
type Kilogram
9899
type Metre
@@ -104,7 +105,7 @@ type Year
104105
```
105106

106107
We can create quantities:
107-
108+
108109
```scala
109110
val rocketMass = Quantity[Kilogram](40.0)
110111
val fuelMass = Quantity[Kilogram](10000.0)
@@ -196,13 +197,13 @@ type Dimensionless
196197
And we'll need to write instances for all combinations of dimensions.
197198

198199
```scala
199-
implicit val kgDivideKg: Divide.Aux[Kilogram, Kilogram, Dimensionless] =
200+
implicit val kgDivideKg: Divide.Aux[Kilogram, Kilogram, Dimensionless] =
200201
new Divide[Kilogram, Kilogram] { type Out = Dimensionless }
201202

202-
implicit val lyDivideC: Divide.Aux[LightYear, C, Year] =
203+
implicit val lyDivideC: Divide.Aux[LightYear, C, Year] =
203204
new Divide[LightYear, C] { type Out = Year }
204-
205-
implicit val lyDivideMps: Divide.Aux[LightYear, MetresPerSecond, LightYearSecondsPerMetre] =
205+
206+
implicit val lyDivideMps: Divide.Aux[LightYear, MetresPerSecond, LightYearSecondsPerMetre] =
206207
new Divide[LightYear, MetresPerSecond] { type Out = LightYearSecondsPerMetre }
207208

208209
implicit val mpsDivideC: Divide.Aux[MetresPerSecond, C, MetresPerSecondPerC] =
@@ -348,7 +349,7 @@ implicit def baseCase: Invert.Aux[HNil, HNil] = new Invert[HNil] { type Out = HN
348349
The inductive case assumes that the tail has an instance, and derives an instance for the head by negating the exponent:
349350

350351
```scala
351-
implicit def inductiveCase[D, Exp <: XInt, NExp <: XInt, Tail <: HList,
352+
implicit def inductiveCase[D, Exp <: XInt, NExp <: XInt, Tail <: HList,
352353
OutTail <: HList](
353354
implicit negateEv: OpInt.Aux[Negate[Exp], NExp],
354355
tailEv: Invert.Aux[Tail, OutTail]
@@ -398,13 +399,13 @@ We can define the inductive case using the following logic:
398399
4. Look for a typeclass instance for the left list tail and the remaining elements in the right list
399400

400401
```scala
401-
implicit def inductiveCase[D, R <: HList, LExp <: XInt , RExp <: XInt,
402+
implicit def inductiveCase[D, R <: HList, LExp <: XInt , RExp <: XInt,
402403
OutExp <: XInt, RTail <: HList, LTail <: HList, OutTail <: HList](
403404
implicit pickEv: Selector.Aux[R, D, RExp],
404405
addEv: OpInt.Aux[LExp + RExp, OutExp],
405406
filterEv: FilterNot.Aux[R, FieldType[D, RExp], RTail],
406407
tailEv: Multiply.Aux[LTail, RTail, OutTail]
407-
): Multiply.Aux[FieldType[D, LExp] :: LTail, R, FieldType[D, OutExp] :: OutTail] =
408+
): Multiply.Aux[FieldType[D, LExp] :: LTail, R, FieldType[D, OutExp] :: OutTail] =
408409
new Multiply[FieldType[D, LExp] :: LTail, R] {
409410
type Out = FieldType[D, OutExp] :: OutTail
410411
}
@@ -428,7 +429,7 @@ Dividing a numerator by a denominator is as simple as inverting the denominator
428429
We can write this in a single non-inductive instance:
429430

430431
```scala
431-
implicit def divide[L <: HList, R <: HList, RInverted <: HList,
432+
implicit def divide[L <: HList, R <: HList, RInverted <: HList,
432433
Divided <: HList](
433434
implicit invertEv: Invert.Aux[R, RInverted],
434435
multiplyEv: Multiply.Aux[L, RInverted, Divided]
@@ -486,7 +487,7 @@ And we finished with compile time dimensional analysis:
486487

487488
```scala
488489
val rocketSpeed = 1000000.0.mps * log(((40.0.kg +10000.0.kg) /40.0.kg).value)
489-
val speedConversion = 300000000.0.mps / 1.c
490+
val speedConversion = 300000000.0.mps / 1.c
490491
val speedInC = rocketSpeed / speedConversion
491492
val time = 77.0.ly / speedInC
492493
//time: Quantity[FieldType[Year, 1] :: HNil] = Quantity(4180.65274634)
@@ -500,8 +501,8 @@ All we need to provide for the business logic of our rocket launch problem are t
500501
We could roll this out to any other problem. Let's say we wanted to do a currency conversion between `GBP` and `DKK`:
501502

502503
```scala
503-
val exchangeRate: Quantity[FieldType[DKK, 1] :: FieldType[GBP, -1] :: HNil] =
504-
currentExchangeRate()
504+
val exchangeRate: Quantity[FieldType[DKK, 1] :: FieldType[GBP, -1] :: HNil] =
505+
currentExchangeRate()
505506
Val krone: Quantity[FieldType[DKK, 1] :: HNil] = 10.gbp * exchangeRate
506507
```
507508

src/blog/method-equiv.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${S11001001}
33
date: "2015-07-16"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# When are two methods alike?

src/blog/minicheck.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${larsrh}
33
date: "2016-10-17"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# Let's build ourselves a small ScalaCheck

src/blog/nested-existentials.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
author: ${S11001001}
33
date: "2015-07-27"
44
tags: [technical]
5+
katex: true
56
%}
67

78
# Nested existentials
@@ -167,7 +168,7 @@ condition satisfied by either `PList[PList[_]]` or its equivalent
167168
reasoning; we have written the definition of `PList` in a
168169
way that scalac assumes that such a method may exist. You can
169170
determine the consequences yourself by adding the
170-
`lookAt</code> method to <code>PList`, repeating the
171+
`lookAt` method to `PList`, repeating the
171172
above substitution for `PList`, and thinking about the
172173
meaning of the resulting `def lookAt(x:
173174
PList[E] forSome {type E}): Unit`.
@@ -393,5 +394,3 @@ full of compiler errors, especially when allowing for mutation and
393394
impure functions.
394395

395396
*This article was tested with Scala 2.11.7 and Java 1.8.0_45.*
396-
397-
[e]: /todo/README.md

0 commit comments

Comments
 (0)