From 370d47233173ba56626e51d8fc3d6f61fc3c1eb7 Mon Sep 17 00:00:00 2001 From: Thibault Duplessis Date: Thu, 26 Nov 2015 19:07:24 +0700 Subject: [PATCH] coach filters UI --- .gitmodules | 3 + app/views/coach/index.scala.html | 8 +- modules/coach/src/main/CoachApi.scala | 5 +- modules/coach/src/main/Dimension.scala | 4 +- public/stylesheets/coach.css | 396 ++----------------------- public/vendor/multiple-select | 1 + ui/coach/src/ctrl.js | 1 + ui/coach/src/form.js | 56 ++++ ui/coach/src/view.js | 33 +-- 9 files changed, 101 insertions(+), 406 deletions(-) create mode 160000 public/vendor/multiple-select create mode 100644 ui/coach/src/form.js diff --git a/.gitmodules b/.gitmodules index 5669ed1083..f7fbc4d7ba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "public/vendor/ChessPursuit"] path = public/vendor/ChessPursuit url = https://github.com/ornicar/ChessPursuit +[submodule "public/vendor/multiple-select"] + path = public/vendor/multiple-select + url = https://github.com/wenzhixin/multiple-select diff --git a/app/views/coach/index.scala.html b/app/views/coach/index.scala.html index b099fc8ffd..1fe27644aa 100644 --- a/app/views/coach/index.scala.html +++ b/app/views/coach/index.scala.html @@ -2,6 +2,7 @@ @moreJs = { @highchartsLatestTag +@jsAt("vendor/multiple-select/multiple-select.js") @jsAt(s"compiled/lichess.coach${isProd??(".min")}.js") @embedJs { $(function() { @@ -14,9 +15,14 @@ userId: "@u.id" } } +@moreCss = { +@cssTag("coach.css") +@cssVendorTag("multiple-select/multiple-select.css") +} + @coach.layout(u, title = s"${u.username} coach", moreJs = moreJs, -moreCss = cssTag("coach.css")) { +moreCss = moreCss) {
} diff --git a/modules/coach/src/main/CoachApi.scala b/modules/coach/src/main/CoachApi.scala index a0353d354d..b9b853780f 100644 --- a/modules/coach/src/main/CoachApi.scala +++ b/modules/coach/src/main/CoachApi.scala @@ -35,9 +35,8 @@ final class CoachApi(coll: Coll) { } Answer( question, - clusters |> - postProcess(question) |> - postSort(question)) + clusters |> postProcess(question) |> postSort(question) + ) } } diff --git a/modules/coach/src/main/Dimension.scala b/modules/coach/src/main/Dimension.scala index 09ed8839c9..299c293015 100644 --- a/modules/coach/src/main/Dimension.scala +++ b/modules/coach/src/main/Dimension.scala @@ -66,9 +66,9 @@ object Dimension { case Phase => toJson(v.id, v.name) case Result => toJson(v.id, v.name) case Color => toJson(v.name, v.name) - case Opening => toJson(v.eco, v.name) + case Opening => toJson(v.eco, v.ecoName) case OpponentStrength => toJson(v.id, v.name) - case PieceRole => toJson(v.name, v.name) + case PieceRole => toJson(v.name, v.toString) } } } diff --git a/public/stylesheets/coach.css b/public/stylesheets/coach.css index aa0a87f7eb..89c3363f77 100644 --- a/public/stylesheets/coach.css +++ b/public/stylesheets/coach.css @@ -1,384 +1,40 @@ -#coach_side { - margin-top: 20px; - margin-left: -30px; - width: 241px; +#coach { + /* position: relative; */ } -@media (max-width: 1070px) { - #coach_side { - margin-left: 0; - width: 211px; - } + +#coach .filters { + position: absolute; + top: 80px; + left: -260px; + width: 240px; } -#coach_side .navigation { - text-transform: capitalize; - margin-bottom: 20px; -} -#coach_side .navigation a { + +#coach .ms-parent { display: block; - padding: 5px 10px 5px 5px; - border-left: 2px solid transparent; - transition: background 0.13s, border 0.13s; + margin-top: 10px; } -div.content_box_top { - padding: 20px; - border-bottom: 1px solid #CCC; - min-height: 60px; -} -div.content_box_top h1 { - padding: 0!important; -} -div.content_box_top .over { - transition: opacity 0.3s; -} -div.content_box_top.loading .over { - opacity: 0.5; -} -.coach_main .loader { - margin: 100px auto; - font-size: 22px; -} -.coach_main .top { - height: 450px; - box-sizing: border-box; - padding-top: 20px; - position: relative; -} -.coach_main .result-bar { - width: 100%; - white-space: nowrap; - overflow: hidden; - line-height: 0; -} -.coach_main .result-bar > div { - display: inline-block; - height: 100%; - transition: 0.3s; - color: #fff; - font-size: 14px; - line-height: 30px; - text-indent: 20px; - box-shadow: 2px 2px 9px rgba(0, 0, 0, 0.25) inset; -} -.coach_main .result-bar .nbWin { - background-color: #759900; -} -.coach_main .result-bar .nbDraw { - text-indent: 5px; - background-color: #d59120; -} -.coach_main .result-bar .nbLoss { - background-color: #dc322f; -} -.coach_main table.selector { - margin-top: 20px; - user-select: none; - -webkit-user-select: none; - -moz-user-select: none; -} -.coach_main table.selector thead th { - cursor: pointer; -} -.coach_main table.selector thead th::before { - margin-right: 3px; - opacity: 0.8; -} -.coach_main table.selector .name, -.coach_main table.selector .progress { - font-weight: bold; -} -.coach_main table.selector tbody tr { - cursor: pointer; -} -.coach_main table.selector tbody tr.hover, -.coach_main table.selector tbody tr:hover { - background: rgba(191, 231, 255, 0.7); -} -.coach_main table.selector tbody tr.active { - background: rgba(196, 210, 149, 0.7); -} -.coach_main table.selector .result-bar { - width: 100px; - opacity: 0.7; - border-radius: 9px; -} -.coach_main table.selector .result-bar > div { - line-height: 18px; - font-size: 0; -} -.coach_main .nodata p { - text-align: center; - line-height: 450px; -} -.coach_main .inspect { - padding: 45px 20px 20px 20px; -} -.coach_main .top > .to { - position: absolute; - font-size: 30px; - opacity: 0.5; - transition: 0.13s; - user-select: none; - -webkit-user-select: none; - -moz-user-select: none; -} -.coach_main .top > .to:hover { - opacity: 0.9; -} -.coach_main .top > .back { - top: 38px; - right: 10px; -} -.coach_main .top > .to.prev, -.coach_main .top > .to.next { - top: 180px; - padding: 30px 10px; -} -.coach_main .top > .to.prev { - left: -55px; -} -.coach_main .top > .to.next { - right: -55px; -} -.coach_main .inspect h2 strong { - font-size: 2em; -} -.coach_main .inspect h2 em { - font-size: 1.7em; - font-style: italic; - margin-left: 10px; -} -.coach_main .inspect h2 .progress { - font-size: 1.7em; - margin-left: 10px; -} -.coach_main .inspect .baseline { - margin-top: 5px; - font-size: 16px; -} -.coach_main .inspect .result-bar { - position: absolute; +#coach .ms-parent > * { + position: absoule; top: 0; left: 0; } -.coach_main .inspect .main { - white-space: nowrap; -} -.coach_main .inspect .main .progress { - float: left; - font-size: 4em; - line-height: 60px; - margin: 0 20px 0 -5px; -} -.coach_main .inspect .main .progress > span { - font-weight: bold; -} -.cube { - float: right; - position: relative; - width: 400px; - height: 48px; - -webkit-transform-style: preserve-3d; - -moz-transform-style: preserve-3d; - -ms-transform-style: preserve-3d; - -o-transform-style: preserve-3d; - transform-style: preserve-3d; - -webkit-perspective: 320px; - -moz-perspective: 320px; - -ms-perspective: 320px; - -o-perspective: 320px; - perspective: 320px; - margin-top: 2px; - user-select: none; - -webkit-user-select: none; - -moz-user-select: none; -} -.cube .dates { - margin-top: 56px; - text-align: center; - transition: opacity 0.3s; -} -.loading .cube .dates { - opacity: 0.6; -} -/* positions */ - -.cube .a, -.cube .b, -.cube .c, -.cube .d { - position: absolute; - width: 100%; - height: 100%; - left: 0; - z-index: 222; -} -.cube .a:before, -.cube .b:before, -.cube .c:before, -.cube .d:before, -.cube .a:after, -.cube .b:after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 400px; - height: 48px; -} -.cube .a:before, -.cube .b:before, -.cube .c:before, -.cube .d:before { - z-index: 111; -} -.cube .a:after, -.cube .b:after { - z-index: 333; -} -.cube .b { - top: 0; - -webkit-transform: rotateX(75deg) translateY(-48px); - -moz-transform: rotateX(75deg) translateY(-48px); - -o-transform: rotateX(75deg) translateY(-48px); - -ms-transform: rotateX(75deg) translateY(-48px); - transform: rotateX(75deg) translateY(-48px); - -webkit-transform-origin: 0 0; - -moz-transform-origin: 0 0; - -o-transform-origin: 0 0; - -ms-transform-origin: 0 0; - transform-origin: 0 0; -} -.cube .c { - top: 0; - -webkit-transform: rotateX(75deg); - -moz-transform: rotateX(75deg); - -o-transform: rotateX(75deg); - -ms-transform: rotateX(75deg); - transform: rotateX(75deg); - -webkit-transform-origin: 100% 100%; - -moz-transform-origin: 100% 100%; - -o-transform-origin: 100% 100%; - -ms-transform-origin: 100% 100%; - transform-origin: 100% 100%; -} -.cube .d { - -webkit-transform: translateZ(-48px) translateY(-12px); - -moz-transform: translateZ(-48px) translateY(-12px); - -o-transform: translateZ(-48px) translateY(-12px); - -ms-transform: translateZ(-48px) translateY(-12px); - transform: translateZ(-48px) translateY(-12px); -} -/* colors */ - -.cube .a div, -.cube .b div, -.cube .c div, -.cube .d div { - background-repeat: no-repeat; - background-size: 100% 100%; - background-position: 0 0; - width: 100%; - height: 100%; - transition: background 0.5s, opacity 1s; +#coach .ms-choice { + padding: 5px 10px; } -.cube .a div, -.cube .b div { - background-color: rgba(142, 186, 43, 0.8); +#coach .ms-drop { + margin-left: 100%; } -.cube .c div, -.cube .d div { - background-color: rgba(142, 186, 43, 0.5); +#coach .ms-drop ul { + padding: 0; } -.loading .cube .a div, -.loading .cube .b div { - background-color: rgba(240, 177, 73, 0.8); - opacity: 0.6; - color: #d59120; - box-shadow: 0 2px 2px rgba(240, 177, 73, 0.8); -} -.loading .cube .c div, -.loading .cube .d div { - background-color: rgba(240, 177, 73, 0.5); - opacity: 0.6; -} -.cube .c:before { - box-shadow: 0 24px 16px -16px rgba(0, 0, 0, 0.4), 0 32px 12px -18px rgba(0, 0, 0, 0.25); -} -.cube .a:before, -.cube .b:before, -.cube .c:before, -.cube .d:before { - background-color: rgba(0, 0, 0, 0.05); -} -.cube .a:after { - background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.07)), to(rgba(0, 0, 0, 0))); - background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0)); - background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0)); - background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0)); - background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.07), rgba(0, 0, 0, 0)); -} -.cube .b:after { - background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0.1)), to(rgba(255, 255, 255, 0.25))); - background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25)); - background-image: -moz-linear-gradient(top, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25)); - background-image: -o-linear-gradient(top, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25)); - background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25)); -} -.cube .slider { - position: absolute; - width: 94%; - left: 3%; - top: 21.6px; - margin: 0; - z-index: 999; -} -.cube .ui-slider { - height: 5px; - border: none; - background: rgba(0, 0, 0, 0.1); - box-shadow: 0 2px 2px rgba(255, 255, 255, 0.25), inset 0 1px 3px rgba(0, 0, 0, 0.3); -} -.cube .ui-slider:before, -.cube .ui-slider:after { - content: 'IIIIIIIIIII'; - position: absolute; - left: 2px; - width: 100%; - font-family: 'Roboto'; - font-weight: 300; - font-size: 1.2rem; - color: rgba(0, 0, 0, 0.3); - letter-spacing: 32px; - text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.2); -} -.cube .ui-slider:before { - top: -1.4rem; -} -.cube .ui-slider:after { - bottom: -1.4rem; -} -.cube .ui-slider-range { - background: transparent!important; -} -.cube .ui-slider .ui-slider-handle { - top: -6.4px; - width: 20.8px; - height: 16px; - margin-left: -12px; - padding-left: 4px; - border: none; - background: rgba(255, 255, 255, 0.7); - border-radius: 2px; - text-align: center; - font-size: 1em; - line-height: 16px; - color: rgba(0, 0, 0, 0.5); - letter-spacing: 3px; +#coach .ms-drop ul > li label { + padding: 4px 8px; cursor: pointer; - text-shadow: 1px 1px 2px rgba(255, 255, 255, 1); - box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3); } -.cube .ui-slider .ui-slider-handle:focus { - outline: none; +#coach .ms-drop ul > li label:hover { + background: #f0f0f0; +} +#coach .ms-drop ul > li label input { + margin-right: 5px; } diff --git a/public/vendor/multiple-select b/public/vendor/multiple-select new file mode 160000 index 0000000000..0e7962a3e1 --- /dev/null +++ b/public/vendor/multiple-select @@ -0,0 +1 @@ +Subproject commit 0e7962a3e1b919687e9c706be757d9cb5ddeb231 diff --git a/ui/coach/src/ctrl.js b/ui/coach/src/ctrl.js index 0fa3519a06..af9767ade2 100644 --- a/ui/coach/src/ctrl.js +++ b/ui/coach/src/ctrl.js @@ -9,6 +9,7 @@ module.exports = function(env) { this.vm = { metric: env.ui.metrics[0], dimension: env.ui.dimensions[0], + filters: {}, answer: null }; diff --git a/ui/coach/src/form.js b/ui/coach/src/form.js new file mode 100644 index 0000000000..201cc6c61c --- /dev/null +++ b/ui/coach/src/form.js @@ -0,0 +1,56 @@ +var m = require('mithril'); + +module.exports = { + filters: function(ctrl) { + return m('div.filters', [ + m('p', 'Filter results by:'), + ctrl.ui.dimensions.map(function(dimension) { + return m('select', { + multiple: true, + config: function(e) { + $(e).multipleSelect({ + placeholder: dimension.name, + width: '240px', + selectAll: false, + filter: dimension.key === 'opening' + }); + } + }, dimension.values.map(function(value) { + var selected = ctrl.vm.filters[dimension.key]; + return m('option', { + value: value.key, + selected: selected && selected.indexOf(value.key) !== -1 + }, value.name); + })); + }) + ]); + }, + axis: function(ctrl) { + return m('div.axis-form', [ + 'Examine ', + m('select.metric', { + onchange: function(e) { + ctrl.setMetric(e.target.value); + } + }, ctrl.ui.metrics.map(function(y) { + return m('option', { + value: y.key, + disabled: !ctrl.validCombination(ctrl.vm.dimension, y), + selected: ctrl.vm.metric.key === y.key + }, y.name); + })), + ' by ', + m('select.dimension', { + onchange: function(e) { + ctrl.setDimension(e.target.value); + } + }, ctrl.ui.dimensions.map(function(x) { + return m('option', { + value: x.key, + disabled: !ctrl.validCombination(x, ctrl.vm.metric), + selected: ctrl.vm.dimension.key === x.key + }, x.name); + })) + ]); + } +}; diff --git a/ui/coach/src/view.js b/ui/coach/src/view.js index bbe2e064c0..d30f0b52e4 100644 --- a/ui/coach/src/view.js +++ b/ui/coach/src/view.js @@ -1,40 +1,13 @@ var m = require('mithril'); var chart = require('./chart'); - -function axisForm(ctrl) { - return m('div.xy-form', [ - 'Examine ', - m('select.metric', { - onchange: function(e) { - ctrl.setMetric(e.target.value); - } - }, ctrl.ui.metrics.map(function(y) { - return m('option', { - value: y.key, - disabled: !ctrl.validCombination(ctrl.vm.dimension, y), - selected: ctrl.vm.metric.key === y.key - }, y.name); - })), - ' by ', - m('select.dimension', { - onchange: function(e) { - ctrl.setDimension(e.target.value); - } - }, ctrl.ui.dimensions.map(function(x) { - return m('option', { - value: x.key, - disabled: !ctrl.validCombination(x, ctrl.vm.metric), - selected: ctrl.vm.dimension.key === x.key - }, x.name); - })) - ]); -} +var form = require('./form'); module.exports = function(ctrl) { return m('div', { class: ctrl.vm.answer ? '' : 'loading', }, [ - axisForm(ctrl), + form.filters(ctrl), + form.axis(ctrl), chart(ctrl) ]); };