From ae2b3d1327c503a10cc9dcead8cdca954709f8f8 Mon Sep 17 00:00:00 2001 From: efim Date: Sun, 24 Sep 2023 13:37:39 +0000 Subject: [PATCH] feat: single country page, borders --- .../src/main/resources/public/output.css | 172 ++++++++++++++++++ .../src/main/resources/templates/country.html | 112 ++++++++++++ .../src/main/resources/templates/index.html | 2 +- .../src/main/scala/example/Country.scala | 6 +- .../src/main/scala/example/Routes.scala | 27 ++- 5 files changed, 311 insertions(+), 8 deletions(-) create mode 100644 16-countries-page-from-api/src/main/resources/templates/country.html 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 +
+
+
+
+

Border Countries:

+
+ France +
+
+
+ + 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")