From 797616a9f8aec4d1362ef9e53b3782327a0079cc Mon Sep 17 00:00:00 2001 From: Joris Date: Wed, 21 Dec 2016 20:04:26 +0100 Subject: Add period and difficulty --- src/main/scala/reading/Books.scala | 32 ++++++++++----- src/main/scala/reading/component/index/Books.scala | 12 +++++- .../scala/reading/component/index/Filters.scala | 7 +++- .../reading/component/index/FiltersMenu.scala | 48 ++++++++++++---------- .../reading/component/index/style/Books.scala | 12 +++++- .../reading/component/index/style/Filters.scala | 12 +++++- .../component/index/style/FiltersMenu.scala | 4 ++ src/main/scala/reading/component/style/Color.scala | 2 - .../scala/reading/component/widget/Cross.scala | 20 +++++++++ .../reading/component/widget/style/Cross.scala | 31 ++++++++++++++ src/main/scala/reading/models/Book.scala | 5 ++- src/main/scala/reading/models/Difficulty.scala | 22 ++++++++++ src/main/scala/reading/models/Filter.scala | 11 +++++ src/main/scala/reading/models/Period.scala | 21 ++++++++++ 14 files changed, 196 insertions(+), 43 deletions(-) create mode 100644 src/main/scala/reading/component/widget/Cross.scala create mode 100644 src/main/scala/reading/component/widget/style/Cross.scala create mode 100644 src/main/scala/reading/models/Difficulty.scala create mode 100644 src/main/scala/reading/models/Period.scala (limited to 'src') diff --git a/src/main/scala/reading/Books.scala b/src/main/scala/reading/Books.scala index 743d06c..29c26d2 100644 --- a/src/main/scala/reading/Books.scala +++ b/src/main/scala/reading/Books.scala @@ -1,42 +1,52 @@ package reading -import reading.models.{Book, Theme, Genre}, Theme._, Genre._ +import reading.models.{Book, Period, Theme, Genre}, Period._, Theme._, Genre._ object Books { def apply(): Seq[Book] = Seq( Book( - title = "Les Dix petits nègres", + title = "Les Dix petits nègres", author = "Agatha Christie", + period = Siecle20, genres = Seq(Policier), - themes = Seq(Peur) + themes = Seq(Peur), + pages = 250 ), Book( - title = "Le Joueur", + title = "Le Joueur", author = "Fiódor Dostoyevski", + period = Siecle19, genres = Seq(), - themes = Seq(Peur) + themes = Seq(Peur), + pages = 170 ), Book( - title = "Voyage au bout de la nuit", + title = "Voyage au bout de la nuit", author = "Céline", + period = Siecle20, genres = Seq(), - themes = Seq(Peur) + themes = Seq(Peur), + pages = 380 ), Book( - title = "Le Petit Prince", + title = "Le Petit Prince", author = "Antoine de Saint Exupéry", + period = Siecle19, genres = Seq(Policier), - themes = Seq(Amitie) + themes = Seq(Amitie), + pages = 130 ), Book( - title = "Les Frères Karamazov", + title = "Les Frères Karamazov", author = "Fiódor Dostoyevski", + period = Siecle19, genres = Seq(), - themes = Seq(Famille) + themes = Seq(Famille), + pages = 850 ) ) } diff --git a/src/main/scala/reading/component/index/Books.scala b/src/main/scala/reading/component/index/Books.scala index ef0f413..39c0e67 100644 --- a/src/main/scala/reading/component/index/Books.scala +++ b/src/main/scala/reading/component/index/Books.scala @@ -23,13 +23,21 @@ object Books { BooksStyle.book, div(BooksStyle.title, book.title), div(BooksStyle.author, book.author), + div( + BooksStyle.period, + s"période: ${book.period}" + ), div( BooksStyle.genres, - span(s"genre: ${book.genres.mkString(", ")}") + s"genre: ${book.genres.mkString(", ")}" ), div( BooksStyle.themes, - span(s"thème: ${book.themes.mkString(", ")}") + s"thème: ${book.themes.mkString(", ")}" + ), + div( + BooksStyle.pages, + s"${book.pages} pages" ) ) } diff --git a/src/main/scala/reading/component/index/Filters.scala b/src/main/scala/reading/component/index/Filters.scala index 1d9cc93..50b2f0e 100644 --- a/src/main/scala/reading/component/index/Filters.scala +++ b/src/main/scala/reading/component/index/Filters.scala @@ -8,6 +8,8 @@ import scalacss.Defaults._ import scalacss.ScalatagsCss._ import reading.component.index.style.{Filters => FiltersStyle} +import reading.component.widget.Cross +import reading.component.style.Col import reading.models.Filter import reading.utils.{RxTag, RxAttr} @@ -22,10 +24,11 @@ object Filters { FiltersStyle.filters, filters().sortBy(_.name).map { filter => - button( + div( FiltersStyle.filter, RxAttr(onclick, Rx(() => filters() = filters().filter(!Filter.equals(_, filter)))), - filter.name + span(FiltersStyle.name, filter.name), + Cross(15.px, Col.white) ) } ) diff --git a/src/main/scala/reading/component/index/FiltersMenu.scala b/src/main/scala/reading/component/index/FiltersMenu.scala index 880c3e7..81220e3 100644 --- a/src/main/scala/reading/component/index/FiltersMenu.scala +++ b/src/main/scala/reading/component/index/FiltersMenu.scala @@ -8,41 +8,47 @@ import scalacss.Defaults._ import scalacss.ScalatagsCss._ import reading.component.index.style.{FiltersMenu => FiltersMenuStyle} -import reading.models.{Book, Filter, Genre, Theme, FilterFactory} +import reading.models.{Book, Filter, Period, Genre, Theme, Difficulty} import reading.utils.{RxTag, RxAttr} object FiltersMenu { def apply(books: Rx[Seq[Book]], filters: Var[Seq[Filter]]): Frag = div( FiltersMenuStyle.render, - group(books, filters, "Genre", Genre.values), - group(books, filters, "Theme", Theme.values) + FiltersMenuStyle.groups, + group(books, filters, "Période", Period.values.map(Filter.apply(_))), + group(books, filters, "Genre", Genre.values.map(Filter.apply(_))), + group(books, filters, "Theme", Theme.values.map(Filter.apply(_))), + group(books, filters, "Difficulté", Difficulty.filters) ) - def group[T: FilterFactory](books: Rx[Seq[Book]], filters: Var[Seq[Filter]], name: String, groupFilters: Seq[T]): Frag = { + def group(books: Rx[Seq[Book]], filters: Var[Seq[Filter]], name: String, groupFilters: Seq[Filter]): Frag = { val filtersWithCount = Rx { groupFilters - .filter(filter => !Filter.contains(filters(), Filter(filter))) - .map(filter => (filter, Book.filter(books(), Filter(filter) +: filters()).length)) + .filter(filter => !Filter.contains(filters(), filter)) + .map(filter => (filter, Book.filter(books(), filter +: filters()).length)) .filter(_._2 > 0) } - div( - FiltersMenuStyle.group, - - div(FiltersMenuStyle.groupTitle, name), - - RxTag { implicit context => + RxTag { implicit context => + if(filtersWithCount().isEmpty) + span("") + else div( - filtersWithCount().map { case (filter, count) => - button( - FiltersMenuStyle.filter, - RxAttr(onclick, Rx(() => filters() = Filter(filter) +: filters())), - span(s"${filter.toString} ($count)") - ) - } + FiltersMenuStyle.group, + + div(FiltersMenuStyle.groupTitle, name), + + div( + filtersWithCount().map { case (filter, count) => + button( + FiltersMenuStyle.filter, + RxAttr(onclick, Rx(() => filters() = filter +: filters())), + span(s"${filter.name} ($count)") + ) + } + ) ) - } - ) + } } } diff --git a/src/main/scala/reading/component/index/style/Books.scala b/src/main/scala/reading/component/index/style/Books.scala index fa97849..c023e66 100644 --- a/src/main/scala/reading/component/index/style/Books.scala +++ b/src/main/scala/reading/component/index/style/Books.scala @@ -17,7 +17,7 @@ object Books extends StyleSheet.Inline { val title = style( display.inlineBlock, fontWeight.bold, - marginBottom(10.px), + marginBottom(15.px), marginRight(10.px), color(Col.congoBrown) ) @@ -26,12 +26,22 @@ object Books extends StyleSheet.Inline { display.inlineBlock ) + val period = style( + marginLeft(20.px), + marginBottom(10.px) + ) + val genres = style( marginLeft(20.px), marginBottom(10.px) ) val themes = style( + marginLeft(20.px), + marginBottom(10.px) + ) + + val pages = style( marginLeft(20.px) ) } diff --git a/src/main/scala/reading/component/index/style/Filters.scala b/src/main/scala/reading/component/index/style/Filters.scala index c2d0aaf..5ca9dfe 100644 --- a/src/main/scala/reading/component/index/style/Filters.scala +++ b/src/main/scala/reading/component/index/style/Filters.scala @@ -13,9 +13,17 @@ object Filters extends StyleSheet.Inline { ) val filter = style( + display.flex, + alignItems.center, backgroundColor(Col.gray), color(Col.white), - padding(5.px, 10.px), - marginRight(10.px) + padding(10.px), + marginRight(10.px), + borderRadius(2.px), + &.hover(cursor.pointer) + ) + + val name = style( + marginRight(5.px) ) } diff --git a/src/main/scala/reading/component/index/style/FiltersMenu.scala b/src/main/scala/reading/component/index/style/FiltersMenu.scala index 9fd50f0..7168e1b 100644 --- a/src/main/scala/reading/component/index/style/FiltersMenu.scala +++ b/src/main/scala/reading/component/index/style/FiltersMenu.scala @@ -7,6 +7,10 @@ import reading.component.style.Col object FiltersMenu extends StyleSheet.Inline { import dsl._ + val groups = style( + width(250.px) + ) + val group = style( marginBottom(30.px) ) diff --git a/src/main/scala/reading/component/style/Color.scala b/src/main/scala/reading/component/style/Color.scala index b9f9cf4..0d13158 100644 --- a/src/main/scala/reading/component/style/Color.scala +++ b/src/main/scala/reading/component/style/Color.scala @@ -10,7 +10,5 @@ object Col extends StyleSheet.Inline { val white = c"#FFFFFF" val gray = c"#7E7E7E" val eastBay = c"#505080" - val tawnyPort = c"#7F2447" - val cosmic = c"#683649" val congoBrown = c"#57363E" } diff --git a/src/main/scala/reading/component/widget/Cross.scala b/src/main/scala/reading/component/widget/Cross.scala new file mode 100644 index 0000000..8692aeb --- /dev/null +++ b/src/main/scala/reading/component/widget/Cross.scala @@ -0,0 +1,20 @@ +package reading.component.widget + +import scalatags.JsDom.all._ +import scalacss.Defaults._ +import scalacss.ScalatagsCss._ +import scalacss.internal.ValueT, ValueT.Color + +import reading.component.widget.style.{Cross => CrossStyle} + +object Cross { + def apply(size: String, color: ValueT[Color]): HtmlTag = + div( + CrossStyle.render, + CrossStyle.cross, + width := size, + height := size, + div(CrossStyle.line1, backgroundColor := color.value), + div(CrossStyle.line2, backgroundColor := color.value) + ) +} diff --git a/src/main/scala/reading/component/widget/style/Cross.scala b/src/main/scala/reading/component/widget/style/Cross.scala new file mode 100644 index 0000000..1d96958 --- /dev/null +++ b/src/main/scala/reading/component/widget/style/Cross.scala @@ -0,0 +1,31 @@ +package reading.component.widget.style + +import scalacss.Defaults._ + +object Cross extends StyleSheet.Inline { + import dsl._ + + val cross = style( + position.relative + ) + + val line1 = style( + content := "\"\"", + position.absolute, + left(40.%%), + width(20.%%), + height(100.%%), + + transform := "rotate(45deg)" + ) + + val line2 = style( + content := "\"\"", + position.absolute, + left(40.%%), + width(20.%%), + height(100.%%), + + transform := "rotate(-45deg)" + ) +} diff --git a/src/main/scala/reading/models/Book.scala b/src/main/scala/reading/models/Book.scala index b856b7d..7c4bf8a 100644 --- a/src/main/scala/reading/models/Book.scala +++ b/src/main/scala/reading/models/Book.scala @@ -3,13 +3,14 @@ package reading.models case class Book ( title: String, author: String, + period: Period, genres: Seq[Genre], - themes: Seq[Theme] + themes: Seq[Theme], + pages: Int ) extends Ordered[Book] { def compare(that: Book) = { def formatTitle(title: String) = title.toLowerCase.replaceAll("^les ", "").replaceAll("^le ", "") - formatTitle(this.title).compare(formatTitle(that.title)) } } diff --git a/src/main/scala/reading/models/Difficulty.scala b/src/main/scala/reading/models/Difficulty.scala new file mode 100644 index 0000000..aade5f5 --- /dev/null +++ b/src/main/scala/reading/models/Difficulty.scala @@ -0,0 +1,22 @@ +package reading.models + +object Difficulty { + val filters: Seq[Filter] = + Seq( + new Filter { + def filter(book: Book): Boolean = book.pages < 200 + val kind: FilterKind = DifficultyKind + def name: String = "facile" + }, + new Filter { + def filter(book: Book): Boolean = book.pages >= 200 && book.pages < 400 + val kind: FilterKind = DifficultyKind + def name: String = "moyen" + }, + new Filter { + def filter(book: Book): Boolean = book.pages > 400 + val kind: FilterKind = DifficultyKind + def name: String = "difficile" + } + ) +} diff --git a/src/main/scala/reading/models/Filter.scala b/src/main/scala/reading/models/Filter.scala index c4836bb..5e96cf9 100644 --- a/src/main/scala/reading/models/Filter.scala +++ b/src/main/scala/reading/models/Filter.scala @@ -7,8 +7,10 @@ trait Filter { } sealed trait FilterKind +case object PeriodKind extends FilterKind case object ThemeKind extends FilterKind case object GenreKind extends FilterKind +case object DifficultyKind extends FilterKind object Filter { def apply[T](in: T)(implicit filterFactory: FilterFactory[T]): Filter = @@ -26,6 +28,15 @@ trait FilterFactory[T] { } object FilterFactory { + implicit object PeriodFilter extends FilterFactory[Period] { + def create(period: Period): Filter = + new Filter { + def filter(book: Book): Boolean = book.period == period + val kind: FilterKind = PeriodKind + val name: String = period.toString() + } + } + implicit object ThemeFilter extends FilterFactory[Theme] { def create(theme: Theme): Filter = new Filter { diff --git a/src/main/scala/reading/models/Period.scala b/src/main/scala/reading/models/Period.scala new file mode 100644 index 0000000..0dfa3bf --- /dev/null +++ b/src/main/scala/reading/models/Period.scala @@ -0,0 +1,21 @@ +package reading.models + +import enumeratum._ + +sealed trait Period extends EnumEntry { + import Period._ + + override def toString(): String = this match { + case Louis14 => "Louis XIV" + case Siecle19 => "19ème siècle" + case Siecle20 => "20ème siècle" + } +} + +object Period extends Enum[Period] { + val values = findValues + + case object Louis14 extends Period + case object Siecle19 extends Period + case object Siecle20 extends Period +} -- cgit v1.2.3