class design
This commit is contained in:
parent
16e6d86ed1
commit
1f7d91b653
|
@ -113,7 +113,9 @@ final class Clas(
|
||||||
|
|
||||||
def edit(id: String) = Secure(_.Teacher) { implicit ctx => me =>
|
def edit(id: String) = Secure(_.Teacher) { implicit ctx => me =>
|
||||||
WithClass(me, id) { _ => clas =>
|
WithClass(me, id) { _ => clas =>
|
||||||
Ok(html.clas.clas.edit(clas, env.clas.forms.edit(clas))).fuccess
|
env.clas.api.student.activeWithUsers(clas) map { students =>
|
||||||
|
Ok(html.clas.clas.edit(clas, students, env.clas.forms.edit(clas)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +125,10 @@ final class Clas(
|
||||||
.edit(clas)
|
.edit(clas)
|
||||||
.bindFromRequest()(ctx.body)
|
.bindFromRequest()(ctx.body)
|
||||||
.fold(
|
.fold(
|
||||||
err => BadRequest(html.clas.clas.edit(clas, err)).fuccess,
|
err =>
|
||||||
|
env.clas.api.student.activeWithUsers(clas) map { students =>
|
||||||
|
BadRequest(html.clas.clas.edit(clas, students, err))
|
||||||
|
},
|
||||||
data =>
|
data =>
|
||||||
env.clas.api.clas.update(clas, data) map { clas =>
|
env.clas.api.clas.update(clas, data) map { clas =>
|
||||||
Redirect(routes.Clas.show(clas.id.value)).flashSuccess
|
Redirect(routes.Clas.show(clas.id.value)).flashSuccess
|
||||||
|
|
|
@ -5,7 +5,7 @@ import play.api.data.Form
|
||||||
import lila.api.Context
|
import lila.api.Context
|
||||||
import lila.app.templating.Environment._
|
import lila.app.templating.Environment._
|
||||||
import lila.app.ui.ScalatagsTemplate._
|
import lila.app.ui.ScalatagsTemplate._
|
||||||
import lila.clas.Clas
|
import lila.clas.{ Clas, Student }
|
||||||
import lila.clas.ClasForm.ClasData
|
import lila.clas.ClasForm.ClasData
|
||||||
import controllers.routes
|
import controllers.routes
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ object clas {
|
||||||
h1("Lichess Classes"),
|
h1("Lichess Classes"),
|
||||||
a(
|
a(
|
||||||
href := routes.Clas.form,
|
href := routes.Clas.form,
|
||||||
cls := "new button button-green button-empty",
|
cls := "new button button-empty",
|
||||||
title := "New Class",
|
title := "New Class",
|
||||||
dataIcon := "O"
|
dataIcon := "O"
|
||||||
)
|
)
|
||||||
|
@ -86,10 +86,9 @@ object clas {
|
||||||
innerForm(form, none)
|
innerForm(form, none)
|
||||||
)
|
)
|
||||||
|
|
||||||
def edit(c: lila.clas.Clas, form: Form[ClasData])(implicit ctx: Context) =
|
def edit(c: lila.clas.Clas, students: List[Student.WithUser], form: Form[ClasData])(implicit ctx: Context) =
|
||||||
bits.layout(c.name, Left(c withStudents Nil))(
|
teacherDashboard.layout(c, students, "edit")(
|
||||||
cls := "box-pad",
|
div(cls := "box-pad")(
|
||||||
h1("Edit ", c.name),
|
|
||||||
innerForm(form, c.some),
|
innerForm(form, c.some),
|
||||||
hr,
|
hr,
|
||||||
c.isActive option postForm(
|
c.isActive option postForm(
|
||||||
|
@ -102,6 +101,7 @@ object clas {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private def innerForm(form: Form[ClasData], clas: Option[Clas])(implicit ctx: Context) =
|
private def innerForm(form: Form[ClasData], clas: Option[Clas])(implicit ctx: Context) =
|
||||||
postForm(cls := "form3", action := clas.fold(routes.Clas.create())(c => routes.Clas.update(c.id.value)))(
|
postForm(cls := "form3", action := clas.fold(routes.Clas.create())(c => routes.Clas.update(c.id.value)))(
|
||||||
|
|
|
@ -10,20 +10,17 @@ import lila.common.String.html.richText
|
||||||
|
|
||||||
object teacherDashboard {
|
object teacherDashboard {
|
||||||
|
|
||||||
private def dashboard(
|
private[clas] def layout(
|
||||||
c: Clas,
|
c: Clas,
|
||||||
students: List[Student.WithUser],
|
students: List[Student.WithUser],
|
||||||
active: String
|
active: String
|
||||||
)(modifiers: Modifier*)(implicit ctx: Context) =
|
)(modifiers: Modifier*)(implicit ctx: Context) =
|
||||||
bits.layout(c.name, Left(c withStudents students.map(_.student)))(
|
bits.layout(c.name, Left(c withStudents students.map(_.student)))(
|
||||||
cls := "clas-show dashboard dashboard-teacher",
|
cls := s"clas-show dashboard dashboard-teacher dashboard-teacher-$active",
|
||||||
|
div(cls := "clas-show__top")(
|
||||||
div(cls := "box__top")(
|
div(cls := "box__top")(
|
||||||
h1(dataIcon := "f", cls := "text")(c.name),
|
h1(dataIcon := "f", cls := "text")(c.name),
|
||||||
div(cls := "box__top__actions")(
|
div(cls := "box__top__actions")(
|
||||||
a(
|
|
||||||
href := routes.Clas.edit(c.id.value),
|
|
||||||
cls := "button button-empty"
|
|
||||||
)("Edit"),
|
|
||||||
a(
|
a(
|
||||||
href := routes.Clas.studentForm(c.id.value),
|
href := routes.Clas.studentForm(c.id.value),
|
||||||
cls := "button button-green text",
|
cls := "button button-green text",
|
||||||
|
@ -31,7 +28,18 @@ object teacherDashboard {
|
||||||
)("Add student")
|
)("Add student")
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
div(cls := "box__pad")(
|
st.nav(cls := "dashboard-nav")(
|
||||||
|
a(cls := active.active("overview"), href := routes.Clas.show(c.id.value))("Overview"),
|
||||||
|
a(
|
||||||
|
cls := active.active("progress"),
|
||||||
|
href := routes.Clas.progress(c.id.value, PerfType.Blitz.key, 7)
|
||||||
|
)(
|
||||||
|
"Progress"
|
||||||
|
),
|
||||||
|
a(cls := active.active("edit"), href := routes.Clas.edit(c.id.value))("Edit"),
|
||||||
|
a(cls := active.active("archived"), href := routes.Clas.archived(c.id.value))("Archived")
|
||||||
|
)
|
||||||
|
),
|
||||||
standardFlash(),
|
standardFlash(),
|
||||||
c.archived map { archived =>
|
c.archived map { archived =>
|
||||||
div(cls := "clas-show__archived archived")(
|
div(cls := "clas-show__archived archived")(
|
||||||
|
@ -43,15 +51,7 @@ object teacherDashboard {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
),
|
|
||||||
st.nav(cls := "dashboard-nav tabs-horiz")(
|
|
||||||
a(cls := active.active("overview"), href := routes.Clas.show(c.id.value))("Overview"),
|
|
||||||
a(cls := active.active("progress"), href := routes.Clas.progress(c.id.value, PerfType.Blitz.key, 7))(
|
|
||||||
"Progress"
|
|
||||||
),
|
|
||||||
a(cls := active.active("archived"), href := routes.Clas.archived(c.id.value))("Archived")
|
|
||||||
),
|
|
||||||
modifiers
|
modifiers
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ object teacherDashboard {
|
||||||
c: Clas,
|
c: Clas,
|
||||||
students: List[Student.WithUser]
|
students: List[Student.WithUser]
|
||||||
)(implicit ctx: Context) =
|
)(implicit ctx: Context) =
|
||||||
dashboard(c, students, "overview")(
|
layout(c, students, "overview")(
|
||||||
div(cls := "clas-show__overview")(
|
div(cls := "clas-show__overview")(
|
||||||
c.desc.trim.nonEmpty option div(cls := "clas-desc")(richText(c.desc)),
|
c.desc.trim.nonEmpty option div(cls := "clas-desc")(richText(c.desc)),
|
||||||
clas.teachers(c)
|
clas.teachers(c)
|
||||||
|
@ -74,7 +74,7 @@ object teacherDashboard {
|
||||||
c: Clas,
|
c: Clas,
|
||||||
students: List[Student.WithUser]
|
students: List[Student.WithUser]
|
||||||
)(implicit ctx: Context) =
|
)(implicit ctx: Context) =
|
||||||
dashboard(c, students.filter(_.student.isActive), "archived") {
|
layout(c, students.filter(_.student.isActive), "archived") {
|
||||||
val archived = students.filter(_.student.isArchived)
|
val archived = students.filter(_.student.isArchived)
|
||||||
if (archived.isEmpty)
|
if (archived.isEmpty)
|
||||||
p(cls := "box__pad students__empty")("No archived students.")
|
p(cls := "box__pad students__empty")("No archived students.")
|
||||||
|
@ -87,7 +87,7 @@ object teacherDashboard {
|
||||||
students: List[Student.WithUser],
|
students: List[Student.WithUser],
|
||||||
progress: ClasProgress
|
progress: ClasProgress
|
||||||
)(implicit ctx: Context) =
|
)(implicit ctx: Context) =
|
||||||
dashboard(c, students, "progress")(
|
layout(c, students, "progress")(
|
||||||
div(cls := "progress")(
|
div(cls := "progress")(
|
||||||
div(cls := "progress-perf")(
|
div(cls := "progress-perf")(
|
||||||
label("Variant"),
|
label("Variant"),
|
||||||
|
|
|
@ -17,6 +17,12 @@
|
||||||
%box-radius-bottom {
|
%box-radius-bottom {
|
||||||
border-radius: 0 0 $box-radius-size $box-radius-size;
|
border-radius: 0 0 $box-radius-size $box-radius-size;
|
||||||
}
|
}
|
||||||
|
%box-radius-top-left {
|
||||||
|
border-radius: $box-radius-size 0 0 0;
|
||||||
|
}
|
||||||
|
%box-radius-top-right {
|
||||||
|
border-radius: 0 $box-radius-size 0 0;
|
||||||
|
}
|
||||||
%box-shadow {
|
%box-shadow {
|
||||||
@include box-shadow;
|
@include box-shadow;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
$c-tabs-active: $c-accent !default;
|
||||||
|
|
||||||
.tabs-horiz {
|
.tabs-horiz {
|
||||||
@extend %flex-center-nowrap, %page-text;
|
@extend %flex-center-nowrap, %page-text;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -6,7 +8,7 @@
|
||||||
@include breakpoint($mq-not-xx-small) {
|
@include breakpoint($mq-not-xx-small) {
|
||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
}
|
}
|
||||||
span, > a {
|
span {
|
||||||
@extend %roboto;
|
@extend %roboto;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -21,7 +23,7 @@
|
||||||
}
|
}
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: '';
|
||||||
background: fade-out($c-accent, .3);
|
background: fade-out($c-tabs-active, .3);
|
||||||
height: 2px;
|
height: 2px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 96%;
|
width: 96%;
|
||||||
|
@ -37,7 +39,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
color: $c-accent;
|
color: $c-tabs-active;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.unread {
|
.unread {
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
$clas-color: rgb(127, 90, 240);
|
$c-clas: rgb(127, 90, 240);
|
||||||
|
|
||||||
|
$c-font-clas: mix($c-font-clear, $c-clas, 30%);
|
||||||
|
$c-bg-clas: $c-clas;
|
||||||
|
$c-bg-clas-over: white;
|
||||||
|
$c-bg-clas-over-dim: mix($c-bg-clas-over, $c-bg-clas, 80%);
|
||||||
|
|
||||||
%archived {
|
%archived {
|
||||||
@extend %box-radius, %flex-between;
|
@extend %box-radius, %flex-between;
|
||||||
|
@ -13,6 +18,12 @@ $clas-color: rgb(127, 90, 240);
|
||||||
@include breakpoint($mq-medium) {
|
@include breakpoint($mq-medium) {
|
||||||
max-width: 15vw;
|
max-width: 15vw;
|
||||||
}
|
}
|
||||||
|
&.active {
|
||||||
|
color: $c-font-clas;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
background: $c-clas;
|
||||||
|
}
|
||||||
&.student {
|
&.student {
|
||||||
em {
|
em {
|
||||||
@extend %roboto;
|
@extend %roboto;
|
||||||
|
@ -21,12 +32,6 @@ $clas-color: rgb(127, 90, 240);
|
||||||
@include breakpoint($mq-subnav-side) {
|
@include breakpoint($mq-subnav-side) {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: .4rem 2vw .4rem .8rem;
|
padding: .4rem 2vw .4rem .8rem;
|
||||||
&.active {
|
|
||||||
color: $clas-color;
|
|
||||||
}
|
|
||||||
&::after {
|
|
||||||
background: $clas-color;
|
|
||||||
}
|
|
||||||
em {
|
em {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -37,7 +42,12 @@ $clas-color: rgb(127, 90, 240);
|
||||||
|
|
||||||
.clas-index {
|
.clas-index {
|
||||||
.box__top {
|
.box__top {
|
||||||
|
background: $c-bg-clas;
|
||||||
|
&, a {
|
||||||
|
color: $c-bg-clas-over;
|
||||||
|
}
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
|
h1 { margin: 0 }
|
||||||
}
|
}
|
||||||
.new::before {
|
.new::before {
|
||||||
font-size: 3em;
|
font-size: 3em;
|
||||||
|
@ -53,7 +63,7 @@ $clas-color: rgb(127, 90, 240);
|
||||||
position: relative;
|
position: relative;
|
||||||
@include transition();
|
@include transition();
|
||||||
&::before {
|
&::before {
|
||||||
color: mix($c-link, $c-bg-box, 80%);
|
color: mix($c-clas, $c-bg-box, 80%);
|
||||||
font-size: 5em;
|
font-size: 5em;
|
||||||
margin-right: .4em;
|
margin-right: .4em;
|
||||||
@include transition();
|
@include transition();
|
||||||
|
@ -62,9 +72,9 @@ $clas-color: rgb(127, 90, 240);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background: mix($c-link, $c-bg-box, 10%);
|
background: mix($c-clas, $c-bg-box, 10%);
|
||||||
&::before {
|
&::before {
|
||||||
color: mix($c-link, $c-bg-box, 100%);
|
color: mix($c-clas, $c-bg-box, 100%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.overlay {
|
.overlay {
|
||||||
|
@ -72,7 +82,7 @@ $clas-color: rgb(127, 90, 240);
|
||||||
}
|
}
|
||||||
h3 {
|
h3 {
|
||||||
@include fluid-size('font-size', 23px, 35px);
|
@include fluid-size('font-size', 23px, 35px);
|
||||||
color: $c-link;
|
color: $c-clas;
|
||||||
}
|
}
|
||||||
p {
|
p {
|
||||||
margin: .5em 0 0 0;
|
margin: .5em 0 0 0;
|
||||||
|
@ -88,6 +98,13 @@ $clas-color: rgb(127, 90, 240);
|
||||||
|
|
||||||
.clas-show {
|
.clas-show {
|
||||||
|
|
||||||
|
&__top {
|
||||||
|
background: $c-bg-clas;
|
||||||
|
&, a, .button, .title {
|
||||||
|
color: $c-bg-clas-over;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__overview {
|
&__overview {
|
||||||
@extend %box-padding;
|
@extend %box-padding;
|
||||||
background: $c-bg-zebra;
|
background: $c-bg-zebra;
|
||||||
|
@ -100,12 +117,11 @@ $clas-color: rgb(127, 90, 240);
|
||||||
|
|
||||||
.dashboard {
|
.dashboard {
|
||||||
|
|
||||||
.tabs-horiz a {
|
.flash {
|
||||||
letter-spacing: normal;
|
margin: 0;
|
||||||
font-size: 1.1em;
|
&__content {
|
||||||
color: $c-font;
|
padding: 2em var(--box-padding);
|
||||||
&.active {
|
border-radius: 0;
|
||||||
color: $c-accent;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +157,39 @@ $clas-color: rgb(127, 90, 240);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-nav {
|
||||||
|
@extend %flex-center-nowrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-end;
|
||||||
|
@include breakpoint($mq-not-xx-small) {
|
||||||
|
font-size: .9em;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
@extend %box-radius-top;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
text-align: center;
|
||||||
|
padding: 1.2em 0 .8em 0;
|
||||||
|
&:first-child {
|
||||||
|
@extend %box-radius-top-right;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
@extend %box-radius-top-left;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background: mix($c-bg-zebra, $c-clas, 20%);
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
background: $c-bg-zebra;
|
||||||
|
color: $c-font-clas;
|
||||||
|
font-weight: bold;
|
||||||
|
.dashboard-teacher-edit &,
|
||||||
|
.dashboard-teacher-archived & {
|
||||||
|
background: $c-bg-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-student {
|
&-student {
|
||||||
.teachers {
|
.teachers {
|
||||||
margin-bottom: 2em;
|
margin-bottom: 2em;
|
||||||
|
@ -170,6 +219,9 @@ $clas-color: rgb(127, 90, 240);
|
||||||
}
|
}
|
||||||
&-choices {
|
&-choices {
|
||||||
@extend %flex-center, %box-neat-force;
|
@extend %flex-center, %box-neat-force;
|
||||||
|
@if $theme-dark {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
background: $c-bg-box;
|
background: $c-bg-box;
|
||||||
}
|
}
|
||||||
|
@ -178,13 +230,13 @@ $clas-color: rgb(127, 90, 240);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: .7em;
|
padding: .7em;
|
||||||
color: $c-good;
|
color: $c-clas;
|
||||||
&:hover {
|
&:hover {
|
||||||
background: mix($c-bg-box, $c-good, 70%);
|
background: mix($c-bg-box, $c-clas, 70%);
|
||||||
color: $c-font-clear;
|
color: $c-font-clear;
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
background: $c-good;
|
background: $c-clas;
|
||||||
color: $c-good-over;
|
color: $c-good-over;
|
||||||
}
|
}
|
||||||
border-right: 1px solid $c-border;
|
border-right: 1px solid $c-border;
|
||||||
|
@ -213,22 +265,18 @@ $clas-color: rgb(127, 90, 240);
|
||||||
|
|
||||||
.student-show {
|
.student-show {
|
||||||
|
|
||||||
$top-background: $clas-color;
|
|
||||||
$top-font: white;
|
|
||||||
$top-font-dim: mix($top-font, $top-background, 80%);
|
|
||||||
|
|
||||||
padding-bottom: 3em;
|
padding-bottom: 3em;
|
||||||
|
|
||||||
&__top {
|
&__top {
|
||||||
padding: calc(5vh - 1rem) var(--box-padding);
|
padding: calc(5vh - 1rem) var(--box-padding);
|
||||||
background: $top-background;
|
background: $c-bg-clas;
|
||||||
margin-bottom: 3em;
|
margin-bottom: 3em;
|
||||||
&, a, .button, .title {
|
&, a, .button, .title {
|
||||||
color: $top-font;
|
color: $c-bg-clas-over;
|
||||||
}
|
}
|
||||||
a:not(.button) {
|
a:not(.button) {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-bottom: 1px dotted $top-font-dim;
|
border-bottom: 1px dotted $c-bg-clas-over-dim;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
@extend %flex-center;
|
@extend %flex-center;
|
||||||
|
@ -236,14 +284,14 @@ $clas-color: rgb(127, 90, 240);
|
||||||
&::before {
|
&::before {
|
||||||
font-size: 2.5em;
|
font-size: 2.5em;
|
||||||
margin-right: .4em;
|
margin-right: .4em;
|
||||||
color: $top-font-dim;
|
color: $c-bg-clas-over-dim;
|
||||||
}
|
}
|
||||||
strong {
|
strong {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
em {
|
em {
|
||||||
@extend %roboto;
|
@extend %roboto;
|
||||||
color: $top-font-dim;
|
color: $c-bg-clas-over-dim;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__meta {
|
&__meta {
|
||||||
|
|
|
@ -2,6 +2,5 @@
|
||||||
@import '../../../common/css/form/form3';
|
@import '../../../common/css/form/form3';
|
||||||
@import '../../../common/css/component/slist';
|
@import '../../../common/css/component/slist';
|
||||||
@import '../../../common/css/component/tablesort';
|
@import '../../../common/css/component/tablesort';
|
||||||
@import '../../../common/css/component/tabs-horiz';
|
|
||||||
@import '../user/activity';
|
@import '../user/activity';
|
||||||
@import '../clas';
|
@import '../clas';
|
||||||
|
|
Loading…
Reference in a new issue