diff --git a/16-countries-page-from-api/src/main/resources/public/output.css b/16-countries-page-from-api/src/main/resources/public/output.css
index 4a374d7..43a843e 100644
--- a/16-countries-page-from-api/src/main/resources/public/output.css
+++ b/16-countries-page-from-api/src/main/resources/public/output.css
@@ -540,6 +540,10 @@ video {
margin-top: 0.25rem;
}
+.-mb-4 {
+ margin-bottom: -1rem;
+}
+
.block {
display: block;
}
@@ -576,6 +580,42 @@ video {
height: 350px;
}
+.h-32 {
+ height: 8rem;
+}
+
+.h-28 {
+ height: 7rem;
+}
+
+.h-36 {
+ height: 9rem;
+}
+
+.h-52 {
+ height: 13rem;
+}
+
+.h-56 {
+ height: 14rem;
+}
+
+.h-60 {
+ height: 15rem;
+}
+
+.h-10 {
+ height: 2.5rem;
+}
+
+.h-8 {
+ height: 2rem;
+}
+
+.h-9 {
+ height: 2.25rem;
+}
+
.w-16 {
width: 4rem;
}
@@ -592,6 +632,10 @@ video {
width: 100%;
}
+.w-20 {
+ width: 5rem;
+}
+
.flex-grow {
flex-grow: 1;
}
@@ -602,6 +646,10 @@ video {
appearance: none;
}
+.grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
.flex-row {
flex-direction: row;
}
@@ -634,6 +682,22 @@ video {
gap: 2.5rem;
}
+.gap-2 {
+ gap: 0.5rem;
+}
+
+.gap-y-8 {
+ row-gap: 2rem;
+}
+
+.gap-y-9 {
+ row-gap: 2.25rem;
+}
+
+.gap-y-10 {
+ row-gap: 2.5rem;
+}
+
.space-y-1 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
@@ -652,6 +716,12 @@ video {
margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
}
+.space-y-2 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
+}
+
.rounded-lg {
border-radius: 0.5rem;
}
@@ -660,6 +730,10 @@ video {
border-radius: 0.375rem;
}
+.rounded {
+ border-radius: 0.25rem;
+}
+
.rounded-t-lg {
border-top-left-radius: 0.5rem;
border-top-right-radius: 0.5rem;
@@ -679,6 +753,16 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
+.bg-blue-400 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(96 165 250 / var(--tw-bg-opacity));
+}
+
+.bg-red-300 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(252 165 165 / var(--tw-bg-opacity));
+}
+
.p-8 {
padding: 2rem;
}
@@ -698,15 +782,57 @@ video {
padding-right: 1.5rem;
}
+.py-10 {
+ padding-top: 2.5rem;
+ padding-bottom: 2.5rem;
+}
+
+.py-3 {
+ padding-top: 0.75rem;
+ padding-bottom: 0.75rem;
+}
+
+.py-2 {
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+}
+
+.px-5 {
+ padding-left: 1.25rem;
+ padding-right: 1.25rem;
+}
+
.pb-8 {
padding-bottom: 2rem;
}
+.pt-2 {
+ padding-top: 0.5rem;
+}
+
+.pb-10 {
+ padding-bottom: 2.5rem;
+}
+
+.text-center {
+ text-align: center;
+}
+
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
+.text-3xl {
+ font-size: 1.875rem;
+ line-height: 2.25rem;
+}
+
+.text-lg {
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+}
+
.font-bold {
font-weight: 700;
}
@@ -735,6 +861,52 @@ video {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
+.shadow-xl {
+ --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
+ --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
+}
+
+.drop-shadow-xl {
+ --tw-drop-shadow: drop-shadow(0 20px 13px rgb(0 0 0 / 0.03)) drop-shadow(0 8px 5px rgb(0 0 0 / 0.08));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
+.drop-shadow-\[0_0_15px_rgba\(0\2c 0\2c 0\2c 0\.25\)\] {
+ --tw-drop-shadow: drop-shadow(0 0 15px rgba(0,0,0,0.25));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
+.drop-shadow-\[0_0_25px_rgba\(0\2c 0\2c 0\2c 0\.25\)\] {
+ --tw-drop-shadow: drop-shadow(0 0 25px rgba(0,0,0,0.25));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
+.drop-shadow {
+ --tw-drop-shadow: drop-shadow(0 1px 2px rgb(0 0 0 / 0.1)) drop-shadow(0 1px 1px rgb(0 0 0 / 0.06));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
+.drop-shadow-\[0_0_15px_rgba\(0\2c 0\2c 0\2c 0\.75\)\] {
+ --tw-drop-shadow: drop-shadow(0 0 15px rgba(0,0,0,0.75));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
+.drop-shadow-\[0_0_5px_rgba\(0\2c 0\2c 0\2c 0\.75\)\] {
+ --tw-drop-shadow: drop-shadow(0 0 5px rgba(0,0,0,0.75));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
+.drop-shadow-\[0_0_3px_rgba\(0\2c 0\2c 0\2c 0\.75\)\] {
+ --tw-drop-shadow: drop-shadow(0 0 3px rgba(0,0,0,0.75));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
+.drop-shadow-\[0_0_3px_rgba\(0\2c 0\2c 0\2c 0\.5\)\] {
+ --tw-drop-shadow: drop-shadow(0 0 3px rgba(0,0,0,0.5));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+}
+
html {
font-size: 14px;
}
diff --git a/16-countries-page-from-api/src/main/resources/templates/country.html b/16-countries-page-from-api/src/main/resources/templates/country.html
new file mode 100644
index 0000000..eaca234
--- /dev/null
+++ b/16-countries-page-from-api/src/main/resources/templates/country.html
@@ -0,0 +1,112 @@
+
+
+
+
+
+ Exploring countries
+
+
+
+
+
+
+
+
+
+
+
+ Where in the world?
+ Dark Mode
+
+
+
+
+
+
+ Germany
+
+
+
+
+
- Native name:
+ - Belgie
+
+
+
- Population:
+ -
+ 81,771,900
+
+
+
+
- Region:
+ - Europe
+
+
+
- Sub Region:
+ - Western Europe
+
+
+
- Capital:
+ - Berlin
+
+
+
+
+
+
- Top Level Domain:
+ - .be
+
+
+
- Currencies:
+
+ -
+ Euro
+
+
+
+
- Languages:
+ -
+ Dutch, French, German
+
+
+
+
+
+
+
diff --git a/16-countries-page-from-api/src/main/resources/templates/index.html b/16-countries-page-from-api/src/main/resources/templates/index.html
index 5043fe8..fdeb2a7 100644
--- a/16-countries-page-from-api/src/main/resources/templates/index.html
+++ b/16-countries-page-from-api/src/main/resources/templates/index.html
@@ -1,5 +1,5 @@
-
+
diff --git a/16-countries-page-from-api/src/main/scala/example/Country.scala b/16-countries-page-from-api/src/main/scala/example/Country.scala
index 4d59c28..5fc314e 100644
--- a/16-countries-page-from-api/src/main/scala/example/Country.scala
+++ b/16-countries-page-from-api/src/main/scala/example/Country.scala
@@ -1,6 +1,7 @@
package example
import upickle.default._
+import scala.jdk.CollectionConverters._
final case class Country(
name: String,
@@ -15,7 +16,10 @@ final case class Country(
currencies: List[Currency] = List.empty,
languages: List[Language],
borders: List[String] = List.empty,
-) derives ReadWriter
+) derives ReadWriter {
+ def currenciesView = currencies.map(_.name).asJava
+ def languagesView = languages.map(_.name).asJava
+}
final case class Currency(
code: String,
diff --git a/16-countries-page-from-api/src/main/scala/example/Routes.scala b/16-countries-page-from-api/src/main/scala/example/Routes.scala
index ea4c047..602ee94 100644
--- a/16-countries-page-from-api/src/main/scala/example/Routes.scala
+++ b/16-countries-page-from-api/src/main/scala/example/Routes.scala
@@ -13,10 +13,9 @@ case class Routes(countries: List[Country])(implicit
log: cask.Logger
) extends cask.Routes {
- /**
- * initializing thymeleaf template engine
- * which finds and renders html templates by name
- */
+ /** initializing thymeleaf template engine which finds and renders html
+ * templates by name
+ */
def buildTemplateEngine(): TemplateEngine = {
val templateResolver = new ClassLoaderTemplateResolver()
templateResolver.setTemplateMode(TemplateMode.HTML)
@@ -37,7 +36,7 @@ case class Routes(countries: List[Country])(implicit
val regions = countries.map(_.region).distinct.sorted.asJava
val selectedCountries = region match {
- case None => countries
+ case None => countries
case Some(selectedRegion) => countries.filter(_.region == selectedRegion)
}
@@ -55,7 +54,23 @@ case class Routes(countries: List[Country])(implicit
@cask.get("/country")
def getCountryPage(countryName: String) = {
- s"counrty $countryName was requested"
+ val context = new Context()
+ countries.find(_.name == countryName) match {
+ case Some(selectedCountry) =>
+ context.setVariable("country", selectedCountry)
+ val borderCountries = countries
+ .filter(c => selectedCountry.borders.contains(c.alpha3Code))
+ .map(_.name).asJava
+
+ context.setVariable("borderCountries", borderCountries)
+
+ val countryPage = engine.process("country", context)
+ Response(
+ countryPage,
+ headers = Seq("Content-Type" -> "text/html; charset=utf-8")
+ )
+ case None => Response("", 400)
+ }
}
@cask.post("/do-thing")