diff options
Diffstat (limited to 'src/main/scala/reading/component')
10 files changed, 109 insertions, 45 deletions
diff --git a/src/main/scala/reading/component/Index.scala b/src/main/scala/reading/component/Index.scala index 0105150..d6d1b6f 100644 --- a/src/main/scala/reading/component/Index.scala +++ b/src/main/scala/reading/component/Index.scala @@ -10,8 +10,8 @@ import reading.component.style.{ Index => IndexStyle } import reading.models.{ Book, Books, Filter } object Index { - def apply(initialFilters: Seq[Filter], initialDetail: Option[Book])(implicit ctx: Ctx.Owner): Frag = { - val filters: Var[Seq[Filter]] = Var(initialFilters) + def apply(initialFilters: Set[Filter], initialDetail: Option[Book])(implicit ctx: Ctx.Owner): Frag = { + val filters: Var[Set[Filter]] = Var(initialFilters) val books: Rx[Seq[Book]] = Rx(Filter.add(Books(), filters())) val search: Var[String] = Var("") val showFiltersMenu: Var[Boolean] = Var(false) diff --git a/src/main/scala/reading/component/index/BookDetail.scala b/src/main/scala/reading/component/index/BookDetail.scala index f532c02..e97a154 100644 --- a/src/main/scala/reading/component/index/BookDetail.scala +++ b/src/main/scala/reading/component/index/BookDetail.scala @@ -1,27 +1,32 @@ package reading.component.index -import scala.util.Random - +import rx._ import scalacss.Defaults._ import scalacss.ScalatagsCss._ import scalatags.JsDom.all._ import reading.component.index.style.{ BookDetail => BookStyle } import reading.component.widget.AnimateMethod -import reading.models.{ Book, Program, Filter } +import reading.models.{ Filter, Book, Program, Grade, Theme, GroupedTheme } import reading.Route +import reading.utils.RxUtils._ object BookDetail { - val componentId = s"books${Random.nextInt}" + val componentId = s"books-detail" def apply( - filters: Seq[Filter], + filters: Var[Set[Filter]], + detail: Var[Option[Book]], + search: Var[String], book: Book, parentId: String, onClose: => Unit + )( + implicit + ctx: Ctx.Owner ): Frag = { val titleParts = if (book.parts > 1) s", ${book.parts} volumes" else "" - val grades = book.programs.map(Program.grade(_)).distinct.sorted + val grades = book.programs.map(Grade.from(_)).distinct.sorted AnimateMethod.fadeIn(componentId) @@ -55,23 +60,33 @@ object BookDetail { BookStyle.definitions, grades.map { grade => - val programs = book.programs.filter(p => Program.grade(p) == grade).sorted + val programs = book.programs.filter(p => Grade.from(p) == grade).sorted val pp = grade.prettyPrint - definition(pp, pp, programs.map(p => s"« ${p.prettyPrint} »")) + val programFilters = programs.map { program => + (Filter(program), filters.map(addProgram(_, program))) + } + definition(filters, detail, search, pp, pp, programFilters, p => s"« $p »") }, if (book.themes.nonEmpty) { - definition("thème", "thèmes", book.themes.sorted.map(_.prettyPrint)) + val themeFilters = book.themes.sorted.map { theme => + (Filter(theme), filters.map(addTheme(_, theme))) + } + definition(filters, detail, search, "thème", "thèmes", themeFilters) }, if (book.genres.nonEmpty) { - definition("genre", "genres", book.genres.sorted.map(_.prettyPrint)) + val bookFilters = book.genres.sorted.map(Filter(_)).map(b => (b, filters.map(_ + b))) + definition(filters, detail, search, "genre", "genres", bookFilters) }, - definition("niveau", "niveaux", Seq(book.level.prettyPrint)) + { + val levelFilters = Seq(Filter(book.level)).map(b => (b, filters.map(_ + b))) + definition(filters, detail, search, "niveau", "niveaux", levelFilters) + } ), a( BookStyle.close, onclick := (() => onClose), - href := Route.url(Route.Books(filters)), + href := Rx(Route.url(Route.Books(filters()))), "Fermer" ) ) @@ -79,11 +94,48 @@ object BookDetail { ) } - private def definition(key: String, pluralKey: String, values: Seq[String]): Seq[Frag] = { - val term = if (values.length > 1) pluralKey else key + private def definition( + filters: Var[Set[Filter]], + detail: Var[Option[Book]], + search: Var[String], + term: String, + pluralTerm: String, + definitionFilters: Seq[(Filter, Rx[Set[Filter]])], + format: String => String = _.capitalize + )( + implicit + ctx: Ctx.Owner + ): Seq[Frag] = { + val sTerm = if (definitionFilters.length > 1) pluralTerm else term + Seq( - dt(BookStyle.definitionTerm, s"${term.capitalize} :"), - dd(BookStyle.definitionDescription, values.mkString(", ")) + dt(BookStyle.definitionTerm, s"${sTerm.capitalize} :"), + dd( + BookStyle.definitionDescription, + definitionFilters.map { + case (filter, newFilters) => + a( + BookStyle.definitionFilter, + href := Rx(Route.url(Route.Books(newFilters()))), + onclick := (() => FilterUtils.set(filters, detail, search, newFilters.now)), + format(filter.name) + ) + } + ) ) } + + private def addProgram(filters: Set[Filter], program: Program): Set[Filter] = { + val grade = Grade.from(program) + val otherGrades = Grade.values.filter(_ != grade).map(Filter(_)) + val otherPrograms = Program.values.filter(Grade.from(_) != grade).map(Filter(_)) + filters -- otherGrades -- otherPrograms + Filter(grade) + Filter(program) + } + + private def addTheme(filters: Set[Filter], theme: Theme): Set[Filter] = { + val groupedTheme = GroupedTheme.from(theme) + val otherGroupedThemes = GroupedTheme.values.filter(_ != groupedTheme).map(Filter(_)) + val otherThemes = Theme.values.filter(GroupedTheme.from(_) != groupedTheme).map(Filter(_)) + filters -- otherGroupedThemes -- otherThemes + Filter(groupedTheme) + Filter(theme) + } } diff --git a/src/main/scala/reading/component/index/Books.scala b/src/main/scala/reading/component/index/Books.scala index f15e2dc..14aac51 100644 --- a/src/main/scala/reading/component/index/Books.scala +++ b/src/main/scala/reading/component/index/Books.scala @@ -18,7 +18,7 @@ object Books { def apply( books: Rx[Seq[Book]], - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], showFiltersMenu: Var[Boolean] @@ -75,7 +75,10 @@ object Books { Rx { detail() match { case Some(book) => - BookDetail(filters.now, book, componentId, onClose = closeDetail(filters, detail)) + BookDetail(filters, detail, search, book, componentId, onClose = { + closeDetail(filters, detail) + Route.push(Route.Books(filters.now, None)) + }) case None => span("") } @@ -83,10 +86,9 @@ object Books { ) } - def closeDetail(filters: Var[Seq[Filter]], detail: Var[Option[Book]]): Unit = + def closeDetail(filters: Var[Set[Filter]], detail: Var[Option[Book]]): Unit = AnimateMethod.fadeOut(BookDetail.componentId, onEnd = { detail() = None - Route.push(Route.Books(filters.now, None)) AnimateMethod.fadeIn(componentId) }) } diff --git a/src/main/scala/reading/component/index/FilterUtils.scala b/src/main/scala/reading/component/index/FilterUtils.scala index 89f993a..c019513 100644 --- a/src/main/scala/reading/component/index/FilterUtils.scala +++ b/src/main/scala/reading/component/index/FilterUtils.scala @@ -7,7 +7,7 @@ import reading.Route object FilterUtils { def remove( - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], filter: Filter @@ -20,23 +20,22 @@ object FilterUtils { } def removeAll( - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String] ): Unit = { - filters() = Nil + filters() = Set() if (detail.now.nonEmpty) Books.closeDetail(filters, detail) search() = "" - Route.push(Route.Books(Nil)) + Route.push(Route.Books()) } - def add( - filters: Var[Seq[Filter]], + def set( + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], - filter: Filter + newFilters: Set[Filter] ): Unit = { - val newFilters = filter +: filters.now filters() = newFilters if (detail.now.nonEmpty) Books.closeDetail(filters, detail) search() = "" diff --git a/src/main/scala/reading/component/index/Filters.scala b/src/main/scala/reading/component/index/Filters.scala index 935e501..c300190 100644 --- a/src/main/scala/reading/component/index/Filters.scala +++ b/src/main/scala/reading/component/index/Filters.scala @@ -15,7 +15,7 @@ import reading.utils.RxUtils._ object Filters { def apply( - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], showFiltersMenu: Var[Boolean] @@ -23,7 +23,7 @@ object Filters { implicit ctx: Ctx.Owner ): Frag = { - val filtersCount: Rx[Int] = Rx(filters().length) + val filtersCount: Rx[Int] = Rx(filters().size) div( FiltersStyle.render, @@ -51,7 +51,7 @@ object Filters { "Effacer les filtres" ), - filters().sortBy(_.name).map { filter => + filters().toSeq.sortBy(_.name).map { filter => a( FiltersStyle.filter, onclick := (() => FilterUtils.remove(filters, detail, search, filter)), diff --git a/src/main/scala/reading/component/index/Header.scala b/src/main/scala/reading/component/index/Header.scala index 0809b0c..2d9504e 100644 --- a/src/main/scala/reading/component/index/Header.scala +++ b/src/main/scala/reading/component/index/Header.scala @@ -13,7 +13,7 @@ import reading.utils.RxUtils._ object Header { def apply( books: Rx[Seq[Book]], - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], showFiltersMenu: Var[Boolean] diff --git a/src/main/scala/reading/component/index/Menu.scala b/src/main/scala/reading/component/index/Menu.scala index 0ea6ca4..ec6c21f 100644 --- a/src/main/scala/reading/component/index/Menu.scala +++ b/src/main/scala/reading/component/index/Menu.scala @@ -14,7 +14,7 @@ import reading.utils.RxUtils._ object Menu { def apply( books: Rx[Seq[Book]], - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], showFiltersMenu: Var[Boolean] @@ -27,14 +27,14 @@ object Menu { Rx(if (showFiltersMenu()) MenuStyle.show else MenuStyle.empty), MenuStyle.menu, - Rx(header(showFiltersMenu, filters().length)), + Rx(header(showFiltersMenu, filters().size)), div( MenuStyle.groups, Rx { filters().find(_.kind == FilterKind.Grade) match { case Some(grade) => - val programs = Program.values.filter(p => Program.grade(p).toString() == grade.nonFormattedName).sorted + val programs = Program.values.filter(p => Grade.from(p).toString() == grade.nonFormattedName).sorted group(books, filters, detail, search, grade.name, grade.name, programs.map(Filter.apply(_)), Some(grade)) case None => group(books, filters, detail, search, "classe", "classes", Grade.values.sorted.map(Filter.apply(_))) @@ -43,7 +43,7 @@ object Menu { Rx { filters().find(_.kind == FilterKind.GroupedTheme) match { case Some(groupedTheme) => - val themes = Theme.values.filter(t => Theme.grouped(t).toString() == groupedTheme.nonFormattedName).sorted + val themes = Theme.values.filter(t => GroupedTheme.from(t).toString() == groupedTheme.nonFormattedName).sorted group(books, filters, detail, search, groupedTheme.name, groupedTheme.name, themes.map(Filter.apply(_)), Some(groupedTheme)) case None => group(books, filters, detail, search, "thème", "thèmes", GroupedTheme.values.sorted.map(Filter.apply(_))) @@ -66,7 +66,7 @@ object Menu { def group( books: Rx[Seq[Book]], - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], name: String, @@ -100,7 +100,7 @@ object Menu { if (parentFilter.isDefined) MenuStyle.activeFilter else "", if (filtersCount() > 1) pluralName else name, Rx { - val count = filters().filter(f => groupFilters.exists(f == _)).length + val count = filters().filter(f => groupFilters.exists(f == _)).size if (count > 0) span(MenuStyle.filterTitleCount, count) else span("") } ), @@ -109,7 +109,7 @@ object Menu { case (filter, count) => { val isActive = Filter.contains(filters(), filter) val route = Route.Books( - filters = if (isActive) Filter.remove(filters(), filter) else filter +: filters() + filters = if (isActive) Filter.remove(filters(), filter) else filters() + filter ) a( @@ -120,7 +120,7 @@ object Menu { if (isActive) FilterUtils.remove(filters, detail, search, filter) else - FilterUtils.add(filters, detail, search, filter)), + FilterUtils.set(filters, detail, search, filters.now + filter)), span( span(filter.name.capitalize), span(MenuStyle.filterCount, count) @@ -135,7 +135,7 @@ object Menu { def footer( books: Rx[Seq[Book]], - filters: Var[Seq[Filter]], + filters: Var[Set[Filter]], detail: Var[Option[Book]], search: Var[String], showFiltersMenu: Var[Boolean] diff --git a/src/main/scala/reading/component/index/style/BookDetail.scala b/src/main/scala/reading/component/index/style/BookDetail.scala index 2ce0632..eaad862 100644 --- a/src/main/scala/reading/component/index/style/BookDetail.scala +++ b/src/main/scala/reading/component/index/style/BookDetail.scala @@ -71,6 +71,15 @@ object BookDetail extends StyleSheet.Inline { lineHeight(1.4.em) ) + val definitionFilter = style( + &.hover(color(C.stiletto.value)), + &.not(_.lastChild).after( + content := "\",\"", + marginRight(5.px), + &.hover(color(C.black.value)) + ) + ) + val close = style( Button.simple, marginBottom(1.em) diff --git a/src/main/scala/reading/component/index/style/Books.scala b/src/main/scala/reading/component/index/style/Books.scala index a1f0374..808b937 100644 --- a/src/main/scala/reading/component/index/style/Books.scala +++ b/src/main/scala/reading/component/index/style/Books.scala @@ -21,7 +21,8 @@ object Books extends StyleSheet.Inline { ) val listParent = style( - overflowY.scroll + overflowY.scroll, + paddingTop(15.px) ) val list = style( diff --git a/src/main/scala/reading/component/index/style/Header.scala b/src/main/scala/reading/component/index/style/Header.scala index 10ce059..a871e9c 100644 --- a/src/main/scala/reading/component/index/style/Header.scala +++ b/src/main/scala/reading/component/index/style/Header.scala @@ -9,7 +9,8 @@ object Header extends StyleSheet.Inline { import dsl._ val header = style( - margin(30.px, 0.px) + marginTop(30.px), + marginBottom(20.px) ) val searchAndCount = style( |