V3 von Brett her + constraints update
This commit is contained in:
parent
afbced61e3
commit
23e042b90c
16 changed files with 323 additions and 78 deletions
|
@ -25,6 +25,11 @@ object ScheduleRepository : Repository<Schedule> {
|
|||
return parser.parse(json, Schedule.serializer())
|
||||
}
|
||||
|
||||
suspend fun getUpcoming(count: Int = 8): List<Schedule> {
|
||||
val json = repositoryGet("$prefix/api/schedule/upcoming?count=$count") ?: return emptyList()
|
||||
return parser.parse(json, Schedule.serializer().list)
|
||||
}
|
||||
|
||||
override suspend fun create(model: Schedule): Long {
|
||||
return repositoryPost("$prefix/api/schedules", Message.json.stringify(Schedule.serializer(), model))
|
||||
?: throw IllegalStateException("Cannot create model!")
|
||||
|
|
|
@ -1,38 +1,51 @@
|
|||
package de.kif.frontend.views.board
|
||||
|
||||
import com.soywiz.klock.DateFormat
|
||||
import com.soywiz.klock.DateTimeTz
|
||||
import com.soywiz.klock.KlockLocale
|
||||
import com.soywiz.klock.format
|
||||
import com.soywiz.klock.locale.german
|
||||
import de.kif.frontend.views.overview.getByClassOrCreate
|
||||
import de.westermann.kwebview.interval
|
||||
import de.westermann.kwebview.iterator
|
||||
import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.HTMLSpanElement
|
||||
import org.w3c.dom.get
|
||||
import kotlin.browser.document
|
||||
import kotlin.js.Date
|
||||
|
||||
fun initBoard() {
|
||||
//val boardSchedules = document.getElementsByClassName("board-schedules")[0] as HTMLElement
|
||||
val dateView = document.getElementsByClassName("board-header-date")[0] as HTMLElement
|
||||
//val referenceTime = boardSchedules.dataset["reference"]?.toLongOrNull() ?: 0L
|
||||
val dateContainer = document.getElementsByClassName("board-header-date")[0] as HTMLElement
|
||||
|
||||
/*
|
||||
val timeView = dateContainer.getByClassOrCreate<HTMLSpanElement>("board-header-date-time")
|
||||
val dateView = dateContainer.getByClassOrCreate<HTMLSpanElement>("board-header-date-date")
|
||||
|
||||
val initTime = Date.now().toLong()
|
||||
val referenceInitTime = dateContainer.dataset["now"]?.toLongOrNull() ?: initTime
|
||||
val diff = initTime - referenceInitTime
|
||||
|
||||
|
||||
val boardRunning = document.getElementsByClassName("board-running")[0] as HTMLElement
|
||||
val scheduleList = mutableListOf<BoardSchedule>()
|
||||
|
||||
for (bs in boardSchedules.getElementsByClassName("board-schedule").iterator()) {
|
||||
for (bs in boardRunning.getElementsByClassName("board-schedule").iterator()) {
|
||||
scheduleList += BoardSchedule(bs)
|
||||
}
|
||||
*/
|
||||
|
||||
interval(1000) {
|
||||
val now = Date.now().toLong() + diff
|
||||
|
||||
val currentTime = Date().let {
|
||||
it.getHours().toString().padStart(2, '0') + ":" + it.getMinutes().toString().padStart(2, '0')
|
||||
}
|
||||
val dt = DateTimeTz.fromUnixLocal(now)
|
||||
|
||||
timeView.textContent = DateFormat("HH:mm")
|
||||
.withLocale(KlockLocale.german)
|
||||
.format(dt)
|
||||
|
||||
dateView.textContent = DateFormat("EEEE, d. MMMM y")
|
||||
.withLocale(KlockLocale.german)
|
||||
.format(dt)
|
||||
|
||||
dateView.innerText = currentTime
|
||||
|
||||
/*
|
||||
val now = referenceTime - currentTime / 1000
|
||||
scheduleList.forEach { it.updateTime(now) }
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,36 @@
|
|||
package de.kif.frontend.views.board
|
||||
|
||||
import de.kif.common.formatDateTime
|
||||
import de.kif.common.formatTimeDiff
|
||||
import de.kif.common.model.Schedule
|
||||
import de.kif.frontend.views.overview.getByClassOrCreate
|
||||
import de.westermann.kwebview.View
|
||||
import org.w3c.dom.HTMLDivElement
|
||||
import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.HTMLSpanElement
|
||||
import org.w3c.dom.get
|
||||
import kotlin.js.Date
|
||||
|
||||
class BoardSchedule(
|
||||
view: HTMLElement
|
||||
) : View(view) {
|
||||
private val roomView = view.getByClassOrCreate<HTMLSpanElement>("board-schedule-room")
|
||||
private val timeView = view.getByClassOrCreate<HTMLSpanElement>("board-schedule-time")
|
||||
private val colorView = view.getByClassOrCreate<HTMLSpanElement>("board-schedule-color")
|
||||
private val nameView = view.getByClassOrCreate<HTMLSpanElement>("board-schedule-name")
|
||||
private val colorView = view.getByClassOrCreate<HTMLDivElement>("board-schedule-color")
|
||||
private val timeView = view.getByClassOrCreate<HTMLDivElement>("board-schedule-time")
|
||||
private val nameView = view.getByClassOrCreate<HTMLDivElement>("board-schedule-name")
|
||||
private val roomView = view.getByClassOrCreate<HTMLDivElement>("board-schedule-room")
|
||||
|
||||
private var time: Long = timeView.dataset["time"]?.toLongOrNull() ?: 0L
|
||||
private val schedule: Long = view.dataset["id"]?.toLongOrNull() ?: 0L
|
||||
private val startTime: Long = timeView.dataset["startTime"]?.toLongOrNull() ?: 0L
|
||||
private val endTime: Long = timeView.dataset["endTime"]?.toLongOrNull() ?: 0L
|
||||
|
||||
fun updateTime(now: Long) {
|
||||
//console.log(time.toString(), now.toString())
|
||||
timeView.textContent = Schedule.timeDifferenceToString(time + now)
|
||||
timeView.textContent = if (startTime >= now) {
|
||||
"Start in ${formatTimeDiff(startTime - now)}"
|
||||
} else {
|
||||
"Ende in ${formatTimeDiff(endTime - now)}"
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ class Calendar(calendar: HTMLElement) : View(calendar) {
|
|||
for ((s, l) in errors.map) {
|
||||
for (entry in body.calendarEntries) {
|
||||
if (entry.scheduleId == s) {
|
||||
entry.error = l.isNotEmpty()
|
||||
entry.setError(l)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package de.kif.frontend.views.calendar
|
||||
|
||||
import de.kif.common.CALENDAR_GRID_WIDTH
|
||||
import de.kif.common.ConstraintError
|
||||
import de.kif.common.model.Schedule
|
||||
import de.kif.common.model.WorkGroup
|
||||
import de.westermann.kwebview.iterator
|
||||
|
@ -38,7 +39,7 @@ class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : Vie
|
|||
var length = dataset["length"]?.toIntOrNull() ?: 0
|
||||
|
||||
var pending by classList.property("pending")
|
||||
var error by classList.property("error")
|
||||
private var error by classList.property("error")
|
||||
private var nextScroll = 0.0
|
||||
|
||||
private val editable: Boolean
|
||||
|
@ -172,6 +173,7 @@ class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : Vie
|
|||
}
|
||||
|
||||
private val calendarTools = if (editable) CalendarTools(this) else null
|
||||
private val calendarErrors = if (editable) CalendarErrors() else null
|
||||
|
||||
init {
|
||||
onMouseDown { event ->
|
||||
|
@ -207,6 +209,9 @@ class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : Vie
|
|||
calendarTools.update(s)
|
||||
}
|
||||
}
|
||||
if (calendarErrors != null) {
|
||||
html.appendChild(calendarErrors.html)
|
||||
}
|
||||
}
|
||||
|
||||
fun load(schedule: Schedule) {
|
||||
|
@ -263,6 +268,11 @@ class CalendarEntry(private val calendar: CalendarBody, view: HTMLElement) : Vie
|
|||
nameView.textContent = workGroup.name
|
||||
}
|
||||
|
||||
fun setError(errors: List<ConstraintError>) {
|
||||
error = errors.isNotEmpty()
|
||||
calendarErrors?.setErrors(errors)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(calendar: CalendarBody, schedule: Schedule): CalendarEntry {
|
||||
val entry = CalendarEntry(calendar, createHtmlView())
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package de.kif.frontend.views.calendar
|
||||
|
||||
import de.kif.common.ConstraintError
|
||||
import de.kif.common.model.Room
|
||||
import de.kif.common.model.Schedule
|
||||
import de.kif.frontend.launch
|
||||
import de.kif.frontend.repository.ScheduleRepository
|
||||
import de.westermann.kwebview.View
|
||||
import de.westermann.kwebview.ViewCollection
|
||||
import de.westermann.kwebview.components.*
|
||||
|
||||
class CalendarErrors() : ViewCollection<TextView>() {
|
||||
|
||||
fun setErrors(errors: List<ConstraintError>) {
|
||||
clear()
|
||||
|
||||
for (error in errors) {
|
||||
textView(error.reason)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@
|
|||
}
|
||||
|
||||
&:last-child {
|
||||
width: 30%;
|
||||
width: 29%;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@
|
|||
}
|
||||
|
||||
.board-content {
|
||||
top: 8rem !important;
|
||||
top: 9rem !important;
|
||||
bottom: 0;
|
||||
height: auto !important;
|
||||
}
|
||||
|
@ -59,15 +59,22 @@
|
|||
}
|
||||
|
||||
.board-running {
|
||||
column-count: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.board-schedule {
|
||||
line-height: 1.3rem;
|
||||
line-height: 2rem;
|
||||
height: 2rem;
|
||||
min-width: 10rem;
|
||||
display: flex;
|
||||
border-bottom: solid 1px var(--table-border-color)
|
||||
border-bottom: solid 1px var(--table-border-color);
|
||||
width: calc(50% - 1rem);
|
||||
margin-left: 1rem;
|
||||
|
||||
&:nth-last-child(1), &:nth-last-child(2) {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.board-schedule-color {
|
||||
|
@ -76,25 +83,33 @@
|
|||
span {
|
||||
display: block;
|
||||
background-color: var(--primary-color);
|
||||
width: 0.8rem;
|
||||
height: 0.8rem;
|
||||
border-radius: 100%;
|
||||
margin-top: 0.1rem;
|
||||
width: 0.5rem;
|
||||
height: 1rem;
|
||||
margin-top: 0.5rem;
|
||||
margin-left: 0.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.board-schedule-time {
|
||||
width: 7rem;
|
||||
color: var(--text-secondary-color)
|
||||
width: 8rem;
|
||||
color: var(--text-secondary-color);
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.board-schedule-name {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.board-schedule-room {
|
||||
width: 4rem;
|
||||
width: 8rem;
|
||||
text-align: right;
|
||||
color: var(--text-secondary-color)
|
||||
color: var(--text-secondary-color);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.board-calendar {
|
||||
|
@ -108,10 +123,12 @@
|
|||
.calendar-table-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.calendar-row {
|
||||
width: 100% !important;
|
||||
height: 0.7rem !important;
|
||||
}
|
||||
|
||||
.calendar-cell {
|
||||
&:not(:first-child) {
|
||||
flex-grow: 1;
|
||||
|
@ -119,6 +136,7 @@
|
|||
flex-basis: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-entry::after {
|
||||
content: none;
|
||||
}
|
||||
|
@ -128,13 +146,25 @@
|
|||
position: absolute;
|
||||
line-height: 2rem;
|
||||
font-size: 2rem;
|
||||
top: 50%;
|
||||
margin-top: -1rem;
|
||||
top: 0;
|
||||
left: 8rem;
|
||||
padding: 1.8rem 0;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.board-header-date-time {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.board-header-date-date {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.board-twitter {
|
||||
& > * {
|
||||
margin-top: -1px !important;
|
||||
}
|
||||
& > * {
|
||||
margin-top: -1px !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -611,3 +611,30 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-errors {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
margin-top: 0.2rem;
|
||||
left: 0;
|
||||
background-color: var(--background-primary-color);
|
||||
color: var(--text-secondary-color);
|
||||
border-radius: $border-radius;
|
||||
display: none;
|
||||
z-index: 10;
|
||||
width: max-content;
|
||||
|
||||
border: solid 1px var(--input-border-color);
|
||||
box-shadow: 0 0.1rem 0.2rem var(--shadow-color);
|
||||
|
||||
span {
|
||||
display: block;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-entry.error {
|
||||
.calendar-errors {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
display: none;
|
||||
position: absolute;
|
||||
background-color: var(--background-secondary-color);
|
||||
z-index: 5;
|
||||
z-index: 10;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
|
@ -106,6 +106,7 @@
|
|||
&:hover {
|
||||
.menu-content {
|
||||
display: block;
|
||||
border-bottom: solid 1px var(--table-border-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +122,7 @@
|
|||
position: static;
|
||||
background-color: transparent;
|
||||
z-index: unset;
|
||||
border-bottom: none !important;
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
height: calc(33.3333% - 1rem);
|
||||
overflow: hidden;
|
||||
border-bottom: solid 2px var(--input-border-color);
|
||||
position: relative;
|
||||
|
||||
&:first-child {
|
||||
height: calc(33.3333% + 2rem);
|
||||
|
@ -50,6 +51,7 @@
|
|||
|
||||
.calendar-body {
|
||||
display: flex;
|
||||
width: calc(100vw - 9.6rem);
|
||||
}
|
||||
|
||||
.calendar-row {
|
||||
|
@ -64,12 +66,27 @@
|
|||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
line-height: 2rem;
|
||||
width: 100%;
|
||||
width: 100% !important;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 0 !important;
|
||||
span {
|
||||
padding-left: 0.2rem;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-header {
|
||||
.calendar-cell {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
span {
|
||||
padding: 0 0.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,9 +94,34 @@
|
|||
.wall-calendar {
|
||||
margin-top: 0 !important;
|
||||
height: 100% !important;
|
||||
width: calc(100% - 2.4rem);
|
||||
margin-left: 2.4rem;
|
||||
|
||||
.calendar-table {
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wall-name {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 2.4rem;
|
||||
height: 100%;
|
||||
border-right: solid 1px var(--table-border-color);
|
||||
|
||||
span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
transform: rotate(-90deg);
|
||||
width: 10rem;
|
||||
line-height: 2.4rem;
|
||||
text-align: center;
|
||||
transform-origin: center;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -5rem;
|
||||
margin-top: -1.2rem;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue