From 7bf58894761742d4da8e6f52ce113ea7327e7114 Mon Sep 17 00:00:00 2001
From: Joris
Date: Thu, 16 May 2019 09:40:02 +0200
Subject: Bootstrap
---
client/src/Main.scala | 15 +++++
client/src/model/FileRights.scala | 7 ++
client/src/model/Licence.scala | 8 +++
client/src/model/Pose.scala | 11 ++++
client/src/model/PoseCategory.scala | 18 +++++
client/src/model/Route.scala | 13 ++++
client/src/router/Router.scala | 105 ++++++++++++++++++++++++++++++
client/src/service/Licences.scala | 31 +++++++++
client/src/service/Poses.scala | 58 +++++++++++++++++
client/src/view/View.scala | 22 +++++++
client/src/view/index/Index.scala | 27 ++++++++
client/src/view/licence/LicencePage.scala | 24 +++++++
client/src/view/notFound/NotFound.scala | 12 ++++
13 files changed, 351 insertions(+)
create mode 100644 client/src/Main.scala
create mode 100644 client/src/model/FileRights.scala
create mode 100644 client/src/model/Licence.scala
create mode 100644 client/src/model/Pose.scala
create mode 100644 client/src/model/PoseCategory.scala
create mode 100644 client/src/model/Route.scala
create mode 100644 client/src/router/Router.scala
create mode 100644 client/src/service/Licences.scala
create mode 100644 client/src/service/Poses.scala
create mode 100644 client/src/view/View.scala
create mode 100644 client/src/view/index/Index.scala
create mode 100644 client/src/view/licence/LicencePage.scala
create mode 100644 client/src/view/notFound/NotFound.scala
(limited to 'client')
diff --git a/client/src/Main.scala b/client/src/Main.scala
new file mode 100644
index 0000000..e72c4a0
--- /dev/null
+++ b/client/src/Main.scala
@@ -0,0 +1,15 @@
+package yoga
+
+import mhtml.mount
+import org.scalajs.dom.document
+
+import yoga.view.View
+
+object Main {
+
+ def main(args: Array[String]): Unit = {
+ mount(document.body, View())
+ ()
+ }
+
+}
diff --git a/client/src/model/FileRights.scala b/client/src/model/FileRights.scala
new file mode 100644
index 0000000..3b91d37
--- /dev/null
+++ b/client/src/model/FileRights.scala
@@ -0,0 +1,7 @@
+package yoga.model
+
+final case class FileRights(
+ licence: Licence,
+ author: String,
+ modification: Option[String] = None
+)
diff --git a/client/src/model/Licence.scala b/client/src/model/Licence.scala
new file mode 100644
index 0000000..883d01d
--- /dev/null
+++ b/client/src/model/Licence.scala
@@ -0,0 +1,8 @@
+package yoga.model
+
+import java.net.URI
+
+final case class Licence(
+ name: String,
+ uri: URI
+)
diff --git a/client/src/model/Pose.scala b/client/src/model/Pose.scala
new file mode 100644
index 0000000..e073466
--- /dev/null
+++ b/client/src/model/Pose.scala
@@ -0,0 +1,11 @@
+package yoga.model
+
+import java.net.URI
+
+final case class Pose(
+ name: String,
+ otherNames: Seq[String] = Nil,
+ category: PoseCategory,
+ image: URI,
+ rights: FileRights
+)
diff --git a/client/src/model/PoseCategory.scala b/client/src/model/PoseCategory.scala
new file mode 100644
index 0000000..95eb974
--- /dev/null
+++ b/client/src/model/PoseCategory.scala
@@ -0,0 +1,18 @@
+package yoga.model
+
+import scala.collection.immutable.IndexedSeq
+
+import enumeratum.{ Enum, EnumEntry }
+
+sealed trait PoseCategory extends EnumEntry
+
+object PoseCategory extends Enum[PoseCategory] {
+
+ case object Standing extends PoseCategory
+ case object Balancing extends PoseCategory
+ case object Sitting extends PoseCategory
+ case object Reclining extends PoseCategory
+
+ val values: IndexedSeq[PoseCategory] = findValues
+
+}
diff --git a/client/src/model/Route.scala b/client/src/model/Route.scala
new file mode 100644
index 0000000..34cb1fc
--- /dev/null
+++ b/client/src/model/Route.scala
@@ -0,0 +1,13 @@
+package yoga.model
+
+import java.net.URI
+
+sealed trait Route
+
+case object Route {
+
+ case object Index extends Route
+ final case class Licence(uri: URI) extends Route
+ final object NotFound extends Route
+
+}
diff --git a/client/src/router/Router.scala b/client/src/router/Router.scala
new file mode 100644
index 0000000..60e5ef2
--- /dev/null
+++ b/client/src/router/Router.scala
@@ -0,0 +1,105 @@
+package yoga.router
+
+import scala.scalajs.js
+import scala.scalajs.js.URIUtils
+import scala.xml.Node
+import java.net.URI
+
+import mhtml.Var
+import org.scalajs.dom.raw.{ Element, Node => RawNode }
+import org.scalajs.dom.{ document, window, Event, MouseEvent }
+
+import yoga.model.Route
+import yoga.view.index.Index
+import yoga.view.licence.LicencePage
+import yoga.view.notFound.NotFound
+
+object Router {
+
+ private val route: Var[Route] = Var(parseRoute(Path.current()))
+
+ def render(): Node =
+
+ document.addEventListener("click", Handler.click)
+ window.addEventListener("popstate", Handler.popState)
+ }
+ mhtml-onumnount={ (n: RawNode) =>
+ document.removeEventListener("click", Handler.click)
+ window.removeEventListener("popstate", Handler.popState)
+ }
+ >
+ {route.map {
+ case Route.Index => Index()
+ case Route.Licence(uri) => LicencePage(uri)
+ case Route.NotFound => NotFound()
+ }}
+
+
+ object Path {
+
+ val index: String = "/"
+
+ def licence(uri: URI): String = s"/licence/${uri}"
+
+ def current(): String =
+ URIUtils.decodeURI(s"${window.location.pathname}${window.location.search}")
+
+ }
+
+ private def parseRoute(path: String): Route =
+ pathAndParams(path) match {
+ case (List(), _) => Route.Index
+ case (List("licence", uri), _) => Route.Licence(URI.create(uri))
+ case _ => Route.NotFound
+ }
+
+ private def pathAndParams(path: String): (List[String], List[String]) = {
+ println(path)
+ def splitPath(path: String) = path.split("/").drop(1).toList
+ path.split('?') match {
+ case Array(path) => (splitPath(path), Nil)
+ case Array(path, params) => (splitPath(path), params.split("&").toList)
+ }
+ }
+
+ private object Handler {
+
+ lazy val click: js.Function1[MouseEvent, Unit] =
+ routeTransitionOnAnchorClick { path =>
+ route := parseRoute(path)
+ window.history.pushState(null, "", path)
+ }
+
+ lazy val popState: js.Function1[Event, Unit] =
+ _ => route := parseRoute(Path.current())
+
+ }
+
+ private def routeTransitionOnAnchorClick(goTo: String => Unit)(event: MouseEvent): Unit =
+ if (event.button == 0)
+ Dom.findSelfOrParent("a", event.target.asInstanceOf[RawNode]) match {
+ case Some(node) =>
+ val elem = node.asInstanceOf[Element]
+ if (elem.getAttribute("data-nav") != "ignore") {
+ event.preventDefault()
+ val href = elem.getAttribute("href")
+ if (href != Path.current()) goTo(href)
+ }
+ case _ =>
+ }
+
+ private object Dom {
+
+ @annotation.tailrec
+ def findSelfOrParent(nodeName: String, current: RawNode): Option[RawNode] =
+ if (current.nodeName.toString.toLowerCase == nodeName.toLowerCase)
+ Some(current)
+ else if (current.parentNode == null)
+ None
+ else
+ findSelfOrParent(nodeName, current.parentNode)
+
+ }
+
+}
diff --git a/client/src/service/Licences.scala b/client/src/service/Licences.scala
new file mode 100644
index 0000000..77bfe5d
--- /dev/null
+++ b/client/src/service/Licences.scala
@@ -0,0 +1,31 @@
+package yoga.service
+
+import java.net.URI
+
+import yoga.model.Licence
+
+object Licences {
+
+ object CreativeCommons {
+
+ val attributionAlike_2_5: Licence =
+ Licence(
+ name = "Creative Commons Attribution 2.5 Generic",
+ uri = URI.create("https://creativecommons.org/licenses/by/2.5/deed.en")
+ )
+
+ val attributionAlike_3_0: Licence =
+ Licence(
+ name = "Creative Commons Attribution-Share Alike 3.0 Unported license",
+ uri = URI.create("https://creativecommons.org/licenses/by-sa/3.0/deed.en")
+ )
+
+ val attributionAlike_4_0: Licence =
+ Licence(
+ name = "Creative Commons Attribution 4.0 International license",
+ uri = URI.create("https://creativecommons.org/licenses/by/4.0/deed.en")
+ )
+
+ }
+
+}
diff --git a/client/src/service/Poses.scala b/client/src/service/Poses.scala
new file mode 100644
index 0000000..584c13c
--- /dev/null
+++ b/client/src/service/Poses.scala
@@ -0,0 +1,58 @@
+package yoga.service
+
+import java.net.URI
+
+import yoga.model.{ Pose, PoseCategory, FileRights }
+
+object Poses {
+
+ def values: Seq[Pose] = Seq(
+ Pose(
+ name = "Downward-Facing Dog",
+ category = PoseCategory.Standing,
+ image = URI.create("downward-facing-dog.jpg"),
+ rights = FileRights(
+ author = "Joseph RENGER",
+ licence = Licences.CreativeCommons.attributionAlike_3_0
+ )
+ ),
+ Pose(
+ name = "Downward-Facing Tree",
+ otherNames = Seq("Yoga Handstand"),
+ category = PoseCategory.Balancing,
+ image = URI.create("downward-facing-tree.jpg"),
+ rights = FileRights(
+ author = "Chiswick Chap",
+ licence = Licences.CreativeCommons.attributionAlike_4_0,
+ modification = Some("cropped 81 % horizontally, 9 % vertically using CropTool with precise mode.")
+ )
+ ),
+ // Pose(
+ // name = "Shooting bow",
+ // otherNames = Seq("Archer", "Bow and arrow"),
+ // category = PoseCategory.Sitting,
+ // image = URI.create("shooting-bow.jpg"),
+ // licence = Licences.CreativeCommons.attributionAlike_4_0
+ // ),
+ // Pose(
+ // name = "Ananta’s pose",
+ // otherNames = Seq("Vishnu’s Couch pose"),
+ // category = PoseCategory.Reclining,
+ // image = URI.create("ananta-pose.jpg"),
+ // licence = Licences.CreativeCommons.attributionAlike_4_0
+ // ),
+ // Pose(
+ // name = "Crescent Moon",
+ // category = PoseCategory.Standing,
+ // image = URI.create("crescent-moon.jpg"),
+ // licence = Licences.CreativeCommons.attributionAlike_3_0
+ // ),
+ // Pose(
+ // name = "Half moon",
+ // category = PoseCategory.Standing,
+ // image = URI.create("half-moon.jpg"),
+ // licence = Licences.CreativeCommons.attributionAlike_3_0
+ // )
+ )
+
+}
diff --git a/client/src/view/View.scala b/client/src/view/View.scala
new file mode 100644
index 0000000..5c79a71
--- /dev/null
+++ b/client/src/view/View.scala
@@ -0,0 +1,22 @@
+package yoga.view
+
+import scala.xml.Node
+
+import yoga.router.Router
+
+object View {
+
+ def apply(): Node =
+
+
+
+
+ {Router.render()}
+
+
+
+}
diff --git a/client/src/view/index/Index.scala b/client/src/view/index/Index.scala
new file mode 100644
index 0000000..29cb6ca
--- /dev/null
+++ b/client/src/view/index/Index.scala
@@ -0,0 +1,27 @@
+package yoga.view.index
+
+import scala.xml.Node
+
+import yoga.model.Pose
+import yoga.router.Router
+import yoga.service.Poses
+
+object Index {
+
+ def apply(): Node =
+
+ {Poses.values.map(renderPose)}
+
+
+ def renderPose(pose: Pose): Node =
+
+
+ {pose.name}
+
+
+
+
+
+
+
+}
diff --git a/client/src/view/licence/LicencePage.scala b/client/src/view/licence/LicencePage.scala
new file mode 100644
index 0000000..fc76522
--- /dev/null
+++ b/client/src/view/licence/LicencePage.scala
@@ -0,0 +1,24 @@
+package yoga.view.licence
+
+import java.net.URI
+import scala.xml.Node
+
+import yoga.service.Poses
+
+object LicencePage {
+
+ def apply(uri: URI): Node =
+
+ {Poses.values.find(_.image == uri).map { pose =>
+
+ }}
+
+
+}
diff --git a/client/src/view/notFound/NotFound.scala b/client/src/view/notFound/NotFound.scala
new file mode 100644
index 0000000..a877640
--- /dev/null
+++ b/client/src/view/notFound/NotFound.scala
@@ -0,0 +1,12 @@
+package yoga.view.notFound
+
+import scala.xml.Node
+
+object NotFound {
+
+ def apply(): Node =
+
+ Page not found
+
+
+}
--
cgit v1.2.3