aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/reading/component/index
diff options
context:
space:
mode:
authorJoris2017-02-24 09:44:16 +0100
committerJoris2017-02-24 09:44:16 +0100
commitf1de0dd7632eb29a40ea1f5cf136ab43ee945926 (patch)
tree0e9045ffad0925afeaa6b8cbf07a6e0ff50f38d2 /src/main/scala/reading/component/index
parent626d5ee7ea4ea4f90637e453e0dc488fc6b1a19e (diff)
downloadreading-f1de0dd7632eb29a40ea1f5cf136ab43ee945926.tar.gz
reading-f1de0dd7632eb29a40ea1f5cf136ab43ee945926.tar.bz2
reading-f1de0dd7632eb29a40ea1f5cf136ab43ee945926.zip
Add search field
Diffstat (limited to 'src/main/scala/reading/component/index')
-rw-r--r--src/main/scala/reading/component/index/BookDetail.scala11
-rw-r--r--src/main/scala/reading/component/index/Books.scala11
-rw-r--r--src/main/scala/reading/component/index/FilterUtils.scala39
-rw-r--r--src/main/scala/reading/component/index/Header.scala48
-rw-r--r--src/main/scala/reading/component/index/Menu.scala160
-rw-r--r--src/main/scala/reading/component/index/style/BookDetail.scala4
-rw-r--r--src/main/scala/reading/component/index/style/Header.scala12
-rw-r--r--src/main/scala/reading/component/index/style/Menu.scala26
8 files changed, 207 insertions, 104 deletions
diff --git a/src/main/scala/reading/component/index/BookDetail.scala b/src/main/scala/reading/component/index/BookDetail.scala
index 7df771b..c42029f 100644
--- a/src/main/scala/reading/component/index/BookDetail.scala
+++ b/src/main/scala/reading/component/index/BookDetail.scala
@@ -8,7 +8,7 @@ import reading.component.index.style.{ BookDetail => BookStyle }
import reading.models.{ Program, Book }
object BookDetail {
- def apply(book: Book): HtmlTag =
+ def apply(book: Book): Frag =
div(
BookStyle.render,
BookStyle.detail,
@@ -20,6 +20,8 @@ object BookDetail {
),
div(
+ BookStyle.items,
+
if (book.programs.nonEmpty) {
item("classe", book.programs.map(Program.grade(_).prettyPrint).distinct.sorted)
},
@@ -33,11 +35,14 @@ object BookDetail {
item("genre", book.genres.sorted.map(_.prettyPrint))
},
book.period.map { period =>
- item("période", Seq(period.prettyPrint))
- }
+ item("période", period.prettyPrint)
+ },
+ item("niveau", book.level.prettyPrint)
)
)
+ private def item(key: String, value: String): Frag = item(key, Seq(value))
+
private def item(key: String, values: Seq[String]): Frag =
div(
BookStyle.item,
diff --git a/src/main/scala/reading/component/index/Books.scala b/src/main/scala/reading/component/index/Books.scala
index 20b308d..c22639f 100644
--- a/src/main/scala/reading/component/index/Books.scala
+++ b/src/main/scala/reading/component/index/Books.scala
@@ -1,7 +1,6 @@
package reading.component.index
import rx._
-import Ctx.Owner.Unsafe._
import scalatags.JsDom.all._
import scalacss.Defaults._
@@ -10,16 +9,16 @@ import scalacss.ScalatagsCss._
import reading.component.index.style.{ Books => BooksStyle }
import reading.component.widget.Modal
import reading.models.{ Book }
-import reading.utils.{ RxTag, RxAttr }
+import reading.utils.RxUtils._
object Books {
- def apply(books: Rx[Seq[Book]]): Frag = {
+ def apply(books: Rx[Seq[Book]])(implicit ctx: Ctx.Owner): Frag = {
val focus: Var[Option[Book]] = Var(None)
div(
BooksStyle.render,
- RxTag { implicit context =>
+ Rx {
div(
div(
BooksStyle.books,
@@ -31,13 +30,13 @@ object Books {
BooksStyle.cover,
src := s"cover/${book.title}.jpg",
alt := s"${book.title}, ${book.author}",
- RxAttr(onclick, Rx(() => focus() = Some(book)))
+ onclick := (() => focus() = Some(book))
)
)
}
),
- RxTag { implicit context =>
+ Rx {
focus() match {
case Some(book) => Modal(onClose = focus() = None)(BookDetail(book))
case None => span("")
diff --git a/src/main/scala/reading/component/index/FilterUtils.scala b/src/main/scala/reading/component/index/FilterUtils.scala
new file mode 100644
index 0000000..d4b24e4
--- /dev/null
+++ b/src/main/scala/reading/component/index/FilterUtils.scala
@@ -0,0 +1,39 @@
+package reading.component.index
+
+import rx._
+
+import reading.models._
+import reading.Route
+
+object FilterUtils {
+ def remove(
+ filters: Var[Seq[Filter]],
+ search: Var[String],
+ filter: Filter
+ ): Unit = {
+ val newFilters = Filter.remove(filters.now, filter)
+ filters() = newFilters
+ search() = ""
+ Route.push(Route.Books(newFilters))
+ }
+
+ def removeAll(
+ filters: Var[Seq[Filter]],
+ search: Var[String]
+ ): Unit = {
+ filters() = Nil
+ search() = ""
+ Route.push(Route.Books(Nil))
+ }
+
+ def add(
+ filters: Var[Seq[Filter]],
+ search: Var[String],
+ filter: Filter
+ ): Unit = {
+ val newFilters = filter +: filters.now
+ filters() = newFilters
+ search() = ""
+ Route.push(Route.Books(newFilters))
+ }
+}
diff --git a/src/main/scala/reading/component/index/Header.scala b/src/main/scala/reading/component/index/Header.scala
index cf078ad..50d520e 100644
--- a/src/main/scala/reading/component/index/Header.scala
+++ b/src/main/scala/reading/component/index/Header.scala
@@ -1,32 +1,39 @@
package reading.component.index
import rx._
-import Ctx.Owner.Unsafe._
import scalatags.JsDom.all._
import scalacss.Defaults._
import scalacss.ScalatagsCss._
import reading.component.index.style.{ Header => HeaderStyle }
-import reading.component.widget.Cross
+import reading.component.widget.{ Cross, Input }
import reading.component.style.{ Color => C }
-import reading.models.Filter
-import reading.Route
-import reading.utils.{ RxTag, RxAttr }
+import reading.models.{ Book, Filter }
+import reading.utils.RxUtils._
object Header {
- def apply(filters: Var[Seq[Filter]], showFiltersMenu: Var[Boolean], booksCount: Rx[Int]): Frag = {
+ def apply(
+ books: Rx[Seq[Book]],
+ filters: Var[Seq[Filter]],
+ search: Var[String],
+ showFiltersMenu: Var[Boolean]
+ )(
+ implicit
+ ctx: Ctx.Owner
+ ): Frag = {
val filtersCount: Rx[Int] = Rx(filters().length)
+ val booksCount: Rx[Int] = books.map(_.length)
div(
HeaderStyle.render,
HeaderStyle.header,
- RxTag { implicit context =>
+ Rx {
div(
div(
HeaderStyle.showFiltersMenu,
- RxAttr(onclick, Rx(() => showFiltersMenu() = true)),
+ onclick := (() => showFiltersMenu() = true),
"Filtrer",
if (filtersCount() > 0) span(HeaderStyle.filtersCount, filtersCount()) else span("")
),
@@ -39,14 +46,14 @@ object Header {
div(
HeaderStyle.clear,
- RxAttr(onclick, Rx(() => updateFilters(filters, Nil))),
+ onclick := (() => FilterUtils.removeAll(filters, search)),
"Effacer les filtres"
),
filters().sortBy(_.name).map { filter =>
div(
HeaderStyle.filter,
- RxAttr(onclick, Rx(() => updateFilters(filters, Filter.remove(filters(), filter)))),
+ onclick := (() => FilterUtils.remove(filters, search, filter)),
span(HeaderStyle.name, filter.name.capitalize),
Cross(15.px, C.black.value)
)
@@ -55,17 +62,16 @@ object Header {
)
},
- RxTag { implicit context =>
- div(
- HeaderStyle.booksCount,
- span(s"${booksCount()} livre${if (booksCount() > 1) "s" else ""}")
- )
- }
+ div(
+ HeaderStyle.searchAndCount,
+ Input(HeaderStyle.search, search, "Rechercher"),
+ Rx {
+ div(
+ HeaderStyle.booksCount,
+ span(s"${booksCount()} livre${if (booksCount() > 1) "s" else ""}")
+ )
+ }
+ )
)
}
-
- private def updateFilters(filters: Var[Seq[Filter]], newFilters: Seq[Filter]): Unit = {
- filters() = newFilters
- Route.push(Route.Books(newFilters))
- }
}
diff --git a/src/main/scala/reading/component/index/Menu.scala b/src/main/scala/reading/component/index/Menu.scala
index a0aabd1..4c118bd 100644
--- a/src/main/scala/reading/component/index/Menu.scala
+++ b/src/main/scala/reading/component/index/Menu.scala
@@ -1,7 +1,6 @@
package reading.component.index
import rx._
-import Ctx.Owner.Unsafe._
import scalatags.JsDom.all._
import scalacss.Defaults._
@@ -9,45 +8,60 @@ import scalacss.ScalatagsCss._
import reading.component.index.style.{ Menu => MenuStyle }
import reading.models._
-import reading.utils.{ RxTag, RxAttr }
-import reading.Route
+import reading.utils.RxUtils._
object Menu {
- def apply(books: Rx[Seq[Book]], filters: Var[Seq[Filter]], showFiltersMenu: Var[Boolean]): Frag =
- RxTag { implicit context =>
+ def apply(
+ books: Rx[Seq[Book]],
+ filters: Var[Seq[Filter]],
+ search: Var[String],
+ showFiltersMenu: Var[Boolean]
+ )(
+ implicit
+ ctx: Ctx.Owner
+ ): Frag =
+ div(
+ MenuStyle.render,
+ Rx(if (showFiltersMenu()) MenuStyle.show else MenuStyle.empty),
+ MenuStyle.menu,
+
+ div(MenuStyle.background),
+
div(
- MenuStyle.render,
- if (showFiltersMenu()) MenuStyle.show else "",
- MenuStyle.menu,
+ MenuStyle.content,
- header(showFiltersMenu, filters().length),
+ Rx(header(showFiltersMenu, filters().length)),
div(
MenuStyle.groups,
- filters().find(_.kind == FilterKind.Grade) match {
- case Some(grade) => {
- val programs = Program.values.filter(p => Program.grade(p).toString() == grade.nonFormattedName)
- group(books, filters, grade.name, programs.map(Filter.apply(_)), Some(grade))
+ Rx {
+ filters().find(_.kind == FilterKind.Grade) match {
+ case Some(grade) =>
+ val programs = Program.values.filter(p => Program.grade(p).toString() == grade.nonFormattedName)
+ group(books, filters, search, grade.name, programs.map(Filter.apply(_)), Some(grade))
+ case None =>
+ group(books, filters, search, "Classe", Grade.values.map(Filter.apply(_)))
}
- case None => group(books, filters, "Classe", Grade.values.map(Filter.apply(_)))
},
- filters().find(_.kind == FilterKind.GroupedTheme) match {
- case Some(groupedTheme) => {
- val themes = Theme.values.filter(t => Theme.groupedTheme(t).toString() == groupedTheme.nonFormattedName)
- group(books, filters, groupedTheme.name, themes.map(Filter.apply(_)), Some(groupedTheme))
+ Rx {
+ filters().find(_.kind == FilterKind.GroupedTheme) match {
+ case Some(groupedTheme) =>
+ val themes = Theme.values.filter(t => Theme.groupedTheme(t).toString() == groupedTheme.nonFormattedName)
+ group(books, filters, search, groupedTheme.name, themes.map(Filter.apply(_)), Some(groupedTheme))
+ case None =>
+ group(books, filters, search, "Theme", GroupedTheme.values.map(Filter.apply(_)))
}
- case None => group(books, filters, "Theme", GroupedTheme.values.map(Filter.apply(_)))
},
- group(books, filters, "Genre", Genre.values.sorted.map(Filter.apply(_))),
- group(books, filters, "Niveau", Level.values.map(Filter.apply(_))),
- group(books, filters, "Période", Period.values.map(Filter.apply(_)))
+ group(books, filters, search, "Genre", Genre.values.sorted.map(Filter.apply(_))),
+ group(books, filters, search, "Niveau", Level.values.map(Filter.apply(_))),
+ group(books, filters, search, "Période", Period.values.map(Filter.apply(_)))
),
- footer(Rx(books().length), filters, showFiltersMenu)
+ footer(books, filters, search, showFiltersMenu)
)
- }
+ )
- def header(showFiltersMenu: Var[Boolean], count: Int): HtmlTag =
+ def header(showFiltersMenu: Var[Boolean], count: Int): Frag =
div(
MenuStyle.header,
"Filtrer",
@@ -57,78 +71,84 @@ object Menu {
def group(
books: Rx[Seq[Book]],
filters: Var[Seq[Filter]],
+ search: Var[String],
name: String,
groupFilters: Seq[Filter],
parentFilter: Option[Filter] = None
)(
implicit
- context: Ctx.Data
+ ctx: Ctx.Owner
): Frag = {
val filtersWithCount = Rx {
groupFilters
- .map(filter => (filter, Book.filter(books(), Seq(filter)).length))
+ .map(filter => (filter, Filter.add(books(), filter).length))
.filter(_._2 > 0)
}
- if (filtersWithCount().isEmpty)
- span("")
- else
- div(
- MenuStyle.filterGroup,
+ Rx {
+ if (filtersWithCount().isEmpty)
+ span("")
+ else
div(
- MenuStyle.filterTitle,
- parentFilter.map { filter =>
- RxAttr(onclick, Rx(() => updateFilters(filters, Filter.remove(filters(), filter))))
- }.getOrElse(""),
- if (parentFilter.isDefined) MenuStyle.activeFilter else "",
- name,
- RxTag { implicit context =>
- val count = filters().filter(f => groupFilters.exists(Filter.equals(f, _))).length
- if (count > 0) span(MenuStyle.filterTitleCount, count) else span("")
- }
- ),
- div(
- filtersWithCount().map {
- case (filter, count) => {
- val isActive = Filter.contains(filters(), filter)
+ div(
+ MenuStyle.filterTitle,
+ parentFilter.map { filter =>
+ onclick := (() => FilterUtils.remove(filters, search, filter))
+ }.getOrElse(""),
+ if (parentFilter.isDefined) MenuStyle.activeFilter else "",
+ name,
+ Rx {
+ val count = filters().filter(f => groupFilters.exists(f == _)).length
+ if (count > 0) span(MenuStyle.filterTitleCount, count) else span("")
+ }
+ ),
+ div(
+ filtersWithCount().map {
+ case (filter, count) => {
+ val isActive = Filter.contains(filters(), filter)
- button(
- MenuStyle.filter,
- if (isActive) MenuStyle.activeFilter else "",
- RxAttr(onclick, Rx(() => updateFilters(
- filters,
- if (isActive) Filter.remove(filters(), filter) else filter +: filters()
- ))),
- span(
- span(filter.name.capitalize),
- span(MenuStyle.filterCount, count)
+ button(
+ MenuStyle.filter,
+ if (isActive) MenuStyle.activeFilter else "",
+ onclick := (() =>
+ if (isActive)
+ FilterUtils.remove(filters, search, filter)
+ else
+ FilterUtils.add(filters, search, filter)),
+ span(
+ span(filter.name.capitalize),
+ span(MenuStyle.filterCount, count)
+ )
)
- )
+ }
}
- }
+ )
)
- )
- }
-
- private def updateFilters(filters: Var[Seq[Filter]], newFilters: Seq[Filter]): Unit = {
- filters() = newFilters
- Route.push(Route.Books(newFilters))
+ }
}
- def footer(bookCount: Rx[Int], filters: Var[Seq[Filter]], showFiltersMenu: Var[Boolean]): HtmlTag =
+ def footer(
+ books: Rx[Seq[Book]],
+ filters: Var[Seq[Filter]],
+ search: Var[String],
+ showFiltersMenu: Var[Boolean]
+ )(
+ implicit
+ ctx: Ctx.Owner
+ ): Frag =
div(
MenuStyle.footer,
div(
MenuStyle.clear,
- RxAttr(onclick, Rx(() => filters() = Nil)),
+ onclick := (() => FilterUtils.removeAll(filters, search)),
"Effacer"
),
div(
MenuStyle.returnToBooks,
- RxAttr(onclick, Rx(() => showFiltersMenu() = false)),
+ onclick := (() => showFiltersMenu() = false),
"Afficher",
- RxTag { implicit context =>
- span(MenuStyle.bookCount, bookCount())
+ Rx {
+ span(MenuStyle.bookCount, books().length)
}
)
)
diff --git a/src/main/scala/reading/component/index/style/BookDetail.scala b/src/main/scala/reading/component/index/style/BookDetail.scala
index e8f970e..f432fda 100644
--- a/src/main/scala/reading/component/index/style/BookDetail.scala
+++ b/src/main/scala/reading/component/index/style/BookDetail.scala
@@ -18,6 +18,10 @@ object BookDetail extends StyleSheet.Inline {
marginBottom(30.px)
)
+ val items = style(
+ marginBottom(25.px)
+ )
+
val item = style(
lineHeight(25.px),
margin(0.px, 15.px, 15.px),
diff --git a/src/main/scala/reading/component/index/style/Header.scala b/src/main/scala/reading/component/index/style/Header.scala
index 2260c91..2eb6eb2 100644
--- a/src/main/scala/reading/component/index/style/Header.scala
+++ b/src/main/scala/reading/component/index/style/Header.scala
@@ -66,6 +66,18 @@ object Header extends StyleSheet.Inline {
height(15.px)
)
+ val searchAndCount = style(
+ display.flex,
+ flexWrap.wrap,
+ alignItems.center,
+ Media.mobile(justifyContent.center)
+ )
+
+ val search = style(
+ Media.mobile(display.none),
+ Media.desktop(marginRight(30.px))
+ )
+
val booksCount = style(
fontSize(20.px),
color(C.gray.value),
diff --git a/src/main/scala/reading/component/index/style/Menu.scala b/src/main/scala/reading/component/index/style/Menu.scala
index 12b0646..dd74039 100644
--- a/src/main/scala/reading/component/index/style/Menu.scala
+++ b/src/main/scala/reading/component/index/style/Menu.scala
@@ -10,9 +10,27 @@ object Menu extends StyleSheet.Inline {
val menu = style(
Media.mobile(display.none),
- color(C.white.value),
+ Media.desktop(
+ color(C.white.value),
+ position.relative,
+ width(280.px)
+ )
+ )
+
+ val background = style(
+ Media.desktop(
+ position.fixed,
+ width(280.px),
+ height(100.%%),
+ backgroundColor(C.englishWalnut.value),
+ boxShadow := "4px 0px 6px -1px rgba(0, 0, 0, 0.2)"
+ )
+ )
+
+ val content = style(
position.relative,
- width(280.px)
+ width(100.%%),
+ height(100.%%)
)
val header = style(
@@ -50,6 +68,8 @@ object Menu extends StyleSheet.Inline {
)
)
+ val empty = style()
+
val groups = style(
Media.mobile(
height :=! "calc(100% - 120px)",
@@ -57,8 +77,6 @@ object Menu extends StyleSheet.Inline {
)
)
- val filterGroup = style()
-
val filterTitle = style(
Commons.filter(),
minHeight(50.px),