css generalized 'tile' (ScheduleList, ScheduleEditor)

This commit is contained in:
Patrick Haßel 2024-09-11 13:47:26 +02:00
parent 0f91c35771
commit 8915d9a8d4
13 changed files with 335 additions and 390 deletions

View File

@ -1,28 +1,9 @@
import {prefix} from "../helpers";
export class Timestamp { export class Timestamp {
public readonly WEEKDAY: string[] = ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"];
public readonly dayName;
public readonly timeString;
public constructor( public constructor(
readonly date: Date, readonly date: Date,
) { ) {
const now = new Date(); // -
const minutes: string = prefix(this.date.getMinutes(), '0', 2);
if (date.getDate() === now.getDate()) {
this.dayName = "Heute";
this.timeString = date.getHours() + ":" + minutes;
} else if (date.getDate() === now.getDate() + 1) {
this.dayName = "Morgen";
this.timeString = date.getHours() + ":" + minutes;
} else {
this.dayName = this.WEEKDAY[date.getDay()];
this.timeString = date.getHours() + ":" + minutes;
}
} }
public static fromDateOrNull(date: Date | null): Timestamp | null { public static fromDateOrNull(date: Date | null): Timestamp | null {

View File

@ -0,0 +1,65 @@
import {Inject, Injectable, LOCALE_ID} from '@angular/core';
import {DatePipe} from "@angular/common";
import {Timestamp} from "./Timestamp";
@Injectable({
providedIn: 'root'
})
export class TimeService {
readonly datePipe: DatePipe = new DatePipe(this.locale);
private _now: Date = new Date();
constructor(
@Inject(LOCALE_ID) readonly locale: string,
) {
// -
}
get now(): Date {
return this._now;
}
relativeDate(timestamp: Timestamp | undefined) {
const date: Date = timestamp?.date;
if (date === undefined || date === null) {
return "";
}
const relativeName = this.relativeCalendarDaysName(date);
return relativeName + " " + this.datePipe.transform(date, 'HH:mm');
}
relativeCalendarDaysName(date: Date): string {
const prefix = this.relativeCalendarDaysPrefix(date);
const weekday = date.toLocaleDateString(this.locale, {weekday: 'long'});
return prefix + ", " + weekday;
}
private relativeCalendarDaysPrefix(date: Date): string {
const days = this.calendarDays(date);
if (days < -2) {
return "Vor " + -days + " Tagen";
} else if (days === -2) {
return "Vorgestern";
} else if (days === -1) {
return "Gestern";
} else if (days === 1) {
return "Morgen";
} else if (days === 2) {
return "Übermorgen";
} else if (days > 2) {
return "In " + days + " Tagen";
}
return "Heute";
}
private calendarDays(date: Date) {
const DAY_MS = 1000 * 60 * 60 * 24;
const aMidnight = new Date(this._now.getFullYear(), this._now.getMonth(), this._now.getDate());
const bMidnight = new Date(date.getFullYear(), date.getMonth(), date.getDate());
const milliseconds = bMidnight.getTime() - aMidnight.getTime();
return Math.floor(milliseconds / DAY_MS);
}
}

View File

@ -1,13 +1,17 @@
<ng-container *ngIf="schedule"> <ng-container *ngIf="schedule">
<div id="title"> <div id="title">
<app-text [initial]="schedule.title" (valueChange)="scheduleService.set(schedule, 'title', $event)"></app-text> <app-text [initial]="schedule.title" (valueChange)="scheduleService.set(schedule, 'title', $event)"></app-text>
</div> </div>
<div id="entries">
<div class="entry" *ngFor="let entry of schedule.entries; trackBy: ScheduleEntry.trackBy">
<div class="section"> <div class="tiles">
<div class="enabled">
<app-bool [value]="entry.enabled" (onChange)="entryService.set(entry, 'enabled', $event)"></app-bool> <div class="tile" *ngFor="let entry of schedule.entries; trackBy: ScheduleEntry.trackBy">
<div class="tileHead disabledBack" [class.enabledBack]="entry.executable" [class.skipBack]="entry.skip">
<div class="enabled" (click)="set(entry, 'enabled', !entry.enabled)">
<fa-icon *ngIf="entry.enabled" [icon]="faCheckCircle"></fa-icon>
<fa-icon *ngIf="!entry.enabled" [icon]="faCircle"></fa-icon>
</div> </div>
<div class="title"> <div class="title">
<select [ngModel]="entry.bulk?.id" (ngModelChange)="entryService.set(entry, 'bulk', $event)"> <select [ngModel]="entry.bulk?.id" (ngModelChange)="entryService.set(entry, 'bulk', $event)">
@ -17,7 +21,7 @@
</div> </div>
</div> </div>
<div class="section"> <div class="tileBodyFlex">
<div class="weekdays"> <div class="weekdays">
<div> <div>
<app-bool label="Mo" [value]="entry.monday" (onChange)="entryService.set(entry, 'monday', $event)"></app-bool> <app-bool label="Mo" [value]="entry.monday" (onChange)="entryService.set(entry, 'monday', $event)"></app-bool>
@ -56,8 +60,8 @@
</div> </div>
</div> </div>
<div class="section" *ngIf="entry.type === 'TIME'"> <div class="tileBodyFlex" *ngIf="entry.type === 'TIME'">
<div class="time"> <div class="flexFull time">
<button class="buttonPlus" (click)="dayMinuteAdd(entry, +60)">+</button> <button class="buttonPlus" (click)="dayMinuteAdd(entry, +60)">+</button>
<button class="buttonMinus" (click)="dayMinuteAdd(entry, -60)">-</button> <button class="buttonMinus" (click)="dayMinuteAdd(entry, -60)">-</button>
<input type="time" [ngModel]="entry.time" (ngModelChange)="timeFromString(entry, $event)"> <input type="time" [ngModel]="entry.time" (ngModelChange)="timeFromString(entry, $event)">
@ -66,8 +70,8 @@
</div> </div>
</div> </div>
<div class="section" *ngIf="entry.type === 'SUNRISE' || entry.type === 'SUNSET'"> <div class="tileBodyFlex" *ngIf="entry.type === 'SUNRISE' || entry.type === 'SUNSET'">
<div class="sun"> <div class="flexFull sun">
<div *ngFor="let zenith of getZenithEntries(entry.type); trackBy: trackByZenith"> <div *ngFor="let zenith of getZenithEntries(entry.type); trackBy: trackByZenith">
<app-bool [label]="zenith.title" [value]="entry.zenith === zenith.value" (onChange)="entryService.set(entry, 'zenith', zenith.value)"></app-bool> <app-bool [label]="zenith.title" [value]="entry.zenith === zenith.value" (onChange)="entryService.set(entry, 'zenith', zenith.value)"></app-bool>
</div> </div>
@ -77,37 +81,39 @@
</div> </div>
</div> </div>
<div class="section"> <div class="tileBodyFlex">
<div class="flexHalf"> <div class="flexHalf">
<div class="flexIcon"> <div class="flexIcon">
<img src="assets/dice.svg" alt="+/-" title="Zufallsabweichung +/-"> <img class="icon" src="assets/dice.svg" alt="+/-" title="Zufallsabweichung +/-">
</div> </div>
<div class="flexInput"> <div class="flexIconInput">
<app-duration [duration]="Duration.ofCode(entry.fuzzySeconds + 's')" [bgcolor]="entry.fuzzySeconds ? '#88c0ff' : 'white'" [min]="Duration.ofCode('')" (onChange)="entryService.set(entry, 'fuzzySeconds', $event.totalSeconds)"></app-duration> <app-duration [duration]="Duration.ofCode(entry.fuzzySeconds + 's')" [inputClass]="entry.fuzzySeconds ? 'fuzzyBack' : ''" [min]="Duration.ofCode('')" (onChange)="entryService.set(entry, 'fuzzySeconds', $event.totalSeconds)"></app-duration>
</div> </div>
</div> </div>
<div class="flexHalf"> <div class="flexHalf">
<div class="flexIcon"> <div class="flexIcon">
<img src="assets/skip.svg" alt="Überspringen"> <img class="icon" src="assets/skip.svg" alt="Überspringen">
</div> </div>
<div class="flexInput flexInputLast"> <div class="flexIconInput flexInputLast">
<input type="number" min="0" [class.skipBack]="entry.skip" [ngModel]="entry.skip" (ngModelChange)="entryService.set(entry, 'skip', $event || 0)"> <input type="number" min="0" [class.skipBack]="entry.skip" [ngModel]="entry.skip" (ngModelChange)="entryService.set(entry, 'skip', $event || 0)">
</div> </div>
</div> </div>
</div> </div>
<div class="section"> <div class="tileBodyFlex">
<div class="nextFuzzyTimestamp" [class.skipFont]="entry.skip" *ngIf="entry.executable"> <div class="flexFull timestamp" [class.skipFont]="entry.skip" *ngIf="entry.executable">
{{ relativeDate(entry.nextFuzzyTimestamp?.date) }} {{ timeService.relativeDate(entry.nextFuzzyTimestamp) }}
<span [class.fuzzyFont]="entry.fuzzySeconds" *ngIf="entry.fuzzySeconds"> <span [class.fuzzyFont]="entry.fuzzySeconds" *ngIf="entry.fuzzySeconds">
(eig: {{ entry.nextClearTimestamp.date | date:'HH:mm' }}) (eig: {{ entry.nextClearTimestamp.date | date:'HH:mm' }})
</span> </span>
</div> </div>
<div class="inactive" *ngIf="entry.todo"> <div class="flexFull inactive" *ngIf="entry.todo">
{{ entry.todo }} {{ entry.todo }}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</ng-container> </ng-container>

View File

@ -1,49 +1,15 @@
@import "../../../../config";
@time_input_width: 35%;
#title { #title {
margin: 0.5em; margin: @margin;
}
#entries {
margin-top: 0.5em;
margin-left: 0.5em;
img {
display: inline;
height: 1em;
vertical-align: top;
}
.entry {
margin-bottom: 0.5em;
margin-right: 0.5em;
height: 8.2em;
border-radius: 0.2em;
background-color: #ececec;
@media (min-width: 1001px) {
float: left;
width: 400px;
}
.section {
margin: 0.25em;
.enabled {
float: left;
width: 1.4em;
border-radius: 0.2em;
margin-right: 0.25em;
}
.title {
float: left;
padding: 0.1em;
width: calc(100% - 1.65em);
} }
.weekdays { .weekdays {
float: left; float: left;
width: 75%; width: 75%;
border-radius: 0.2em; border-radius: @border-radius;
div { div {
float: left; float: left;
@ -57,8 +23,8 @@
width: 25%; width: 25%;
._inner_ { ._inner_ {
margin-left: 0.25em; margin-left: @margin;
border-radius: 0.2em; border-radius: @border-radius;
div { div {
float: left; float: left;
@ -69,19 +35,26 @@
} }
.time { .time {
width: 50%; width: 100%;
button {
width: 16.25%;
}
input { input {
width: 35%; width: @time_input_width;
text-align: center;
margin-right: @margin;
} }
button {
width: calc(((100% - @time_input_width) - 4 * @margin) / 4);
margin-right: @margin;
}
button:last-child {
margin-right: 0;
}
} }
.sun { .sun {
border-radius: 0.2em;
div { div {
float: left; float: left;
@ -90,45 +63,11 @@
} }
.flexHalf { .timestamp {
float: left;
width: 50%;
display: flex;
align-items: center;
}
.flexIcon {
width: 2.5em;
text-align: center; text-align: center;
} }
.flexInput {
flex-grow: 1;
}
.nextFuzzyTimestamp {
text-align: center;
}
}
}
.skipBack {
background-color: #ffc059;
}
.skipFont {
color: #ff9a00;
}
.fuzzyFont {
color: #489dff;
}
.inactive { .inactive {
color: gray; color: gray;
text-align: center; text-align: center;
} }
}

View File

@ -1,4 +1,4 @@
import {Component, Inject, LOCALE_ID, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {ScheduleService} from "../../../api/schedule/schedule.service"; import {ScheduleService} from "../../../api/schedule/schedule.service";
import {Schedule} from "../../../api/schedule/Schedule"; import {Schedule} from "../../../api/schedule/Schedule";
import {ScheduleEntry} from "../../../api/schedule/entry/ScheduleEntry"; import {ScheduleEntry} from "../../../api/schedule/entry/ScheduleEntry";
@ -6,12 +6,13 @@ import {ScheduleEntryService} from "../../../api/schedule/entry/schedule-entry.s
import {ActivatedRoute, Router} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {Update} from "../../../api/Update"; import {Update} from "../../../api/Update";
import {NO_OP} from "../../../api/api.service"; import {NO_OP} from "../../../api/api.service";
import {DatePipe} from "@angular/common";
import {Duration} from "../../../api/Duration"; import {Duration} from "../../../api/Duration";
import {Bulk} from "../../../api/bulk/Bulk"; import {Bulk} from "../../../api/bulk/Bulk";
import {BulkService} from "../../../api/bulk/BulkService"; import {BulkService} from "../../../api/bulk/BulkService";
import {Zenith} from "../../../api/schedule/entry/Zenith"; import {Zenith} from "../../../api/schedule/entry/Zenith";
import {TimeService} from "../../../api/time.service";
import {faCheckCircle, faCircle} from "@fortawesome/free-regular-svg-icons";
const DAY_MINUTES: number = 24 * 60; const DAY_MINUTES: number = 24 * 60;
@ -22,8 +23,6 @@ const DAY_MINUTES: number = 24 * 60;
}) })
export class ScheduleEditorComponent implements OnInit { export class ScheduleEditorComponent implements OnInit {
protected readonly datePipe: DatePipe = new DatePipe(this.locale);
protected readonly ScheduleEntry = ScheduleEntry; protected readonly ScheduleEntry = ScheduleEntry;
protected readonly Schedule = Schedule; protected readonly Schedule = Schedule;
@ -54,7 +53,7 @@ export class ScheduleEditorComponent implements OnInit {
readonly scheduleService: ScheduleService, readonly scheduleService: ScheduleService,
readonly entryService: ScheduleEntryService, readonly entryService: ScheduleEntryService,
readonly bulkService: BulkService, readonly bulkService: BulkService,
@Inject(LOCALE_ID) private locale: string, readonly timeService: TimeService,
) { ) {
// - // -
} }
@ -87,7 +86,7 @@ export class ScheduleEditorComponent implements OnInit {
} }
delete(entry: ScheduleEntry): void { delete(entry: ScheduleEntry): void {
if (confirm("Eintrag \"" + entry.nextClearTimestamp?.timeString + " +/-" + entry.fuzzySeconds + "\" wirklich löschen?")) { if (confirm("Eintrag \"" + this.timeService.relativeDate(entry.nextClearTimestamp) + " +/-" + entry.fuzzySeconds + "\" wirklich löschen?")) {
this.entryService.delete(entry, NO_OP); this.entryService.delete(entry, NO_OP);
} }
} }
@ -100,46 +99,6 @@ export class ScheduleEditorComponent implements OnInit {
} }
} }
relativeDate(date: Date | undefined) {
if (date === undefined || date === null) {
return "";
}
const relativeName = this.relativeCalendarDaysName(date);
return relativeName + " " + this.datePipe.transform(date, 'HH:mm');
}
relativeCalendarDaysName(date: Date): string {
const prefix = this.relativeCalendarDaysPrefix(date);
const weekday = date.toLocaleDateString(this.locale, {weekday: 'long'});
return prefix + ", " + weekday;
}
private relativeCalendarDaysPrefix(date: Date): string {
const days = this.calendarDays(date);
if (days < -2) {
return "Vor " + -days + " Tagen";
} else if (days === -2) {
return "Vorgestern";
} else if (days === -1) {
return "Gestern";
} else if (days === 1) {
return "Morgen";
} else if (days === 2) {
return "Übermorgen";
} else if (days > 2) {
return "In " + days + " Tagen";
}
return "Heute";
}
private calendarDays(date: Date) {
const DAY_MS = 1000 * 60 * 60 * 24;
const aMidnight = new Date(this.now.getFullYear(), this.now.getMonth(), this.now.getDate());
const bMidnight = new Date(date.getFullYear(), date.getMonth(), date.getDate());
const milliseconds = bMidnight.getTime() - aMidnight.getTime();
return Math.floor(milliseconds / DAY_MS);
}
getZenithEntries(type: string): Zenith[] { getZenithEntries(type: string): Zenith[] {
if (type === 'SUNRISE') { if (type === 'SUNRISE') {
return this.ZENITH_ENTRIES.filter(zenith => zenith.sunrise); return this.ZENITH_ENTRIES.filter(zenith => zenith.sunrise);
@ -172,5 +131,7 @@ export class ScheduleEditorComponent implements OnInit {
this.entryService.set(entry, 'daySecond', newMinutes * 60); this.entryService.set(entry, 'daySecond', newMinutes * 60);
} }
protected readonly console = console; protected readonly faCheckCircle = faCheckCircle;
protected readonly faCircle = faCircle;
} }

View File

@ -1,59 +1,51 @@
<p> <div class="tiles">
<button (click)="create()">+ Hinzufügen</button>
</p>
<div class="schedules"> <div class="tile" *ngFor="let schedule of schedules; trackBy: Schedule.trackBy">
<div class="scheduleBox" *ngFor="let schedule of schedules; trackBy: Schedule.trackBy">
<div class="schedule" [class.scheduleEnabled]="schedule.enabled">
<div class="header" [class.skipActive]="schedule.next?.skip"> <div class="tileHead disabledBack" [class.enabledBack]="schedule.next" [class.skipBack]="schedule.next?.skip">
<div class="enabled" (click)="set(schedule, 'enabled', !schedule.enabled)" [class.true]="schedule.enabled" [class.false]="!schedule.enabled"> <div class="enabled" (click)="set(schedule, 'enabled', !schedule.enabled)">
<fa-icon *ngIf="schedule.enabled" [icon]="faCheckCircle"></fa-icon> <fa-icon *ngIf="schedule.enabled" [icon]="faCheckCircle"></fa-icon>
<fa-icon *ngIf="!schedule.enabled" [icon]="faCircle"></fa-icon> <fa-icon *ngIf="!schedule.enabled" [icon]="faCircle"></fa-icon>
</div> </div>
<div class="skip" (click)="skip(schedule.next)">
<img src="assets/skip.svg" [alt]="schedule.next?.skip">
{{ schedule.next?.skip }}
</div>
<div class="title" [routerLink]="['/Schedule', {id: schedule.id}]"> <div class="title" [routerLink]="['/Schedule', {id: schedule.id}]">
{{ schedule.title }} {{ schedule.title }}
</div> </div>
<div class="skip" (click)="skip(schedule.next)" *ngIf="schedule.next">
<img class="icon" src="assets/skip.svg" [alt]="'Über.'">{{ schedule.next?.skip }}
</div>
<div class="delete" (click)="delete(schedule)"> <div class="delete" (click)="delete(schedule)">
<fa-icon title="Löschen" [icon]="faTimes"></fa-icon> <fa-icon title="Löschen" [icon]="faTimes"></fa-icon>
</div> </div>
</div> </div>
<div class="timestampBox timestampBoxNext"> <div class="tileBody next">
<div class="timestampTimestamp"> <div class="timestamp">
<ng-container *ngIf="schedule.next">{{ schedule.next?.nextFuzzyTimestamp.dayName }}:&nbsp;{{ schedule.next?.nextFuzzyTimestamp.timeString }}</ng-container> <ng-container *ngIf="schedule.next">{{ timeService.relativeDate(schedule.next?.nextFuzzyTimestamp) }}</ng-container>
<ng-container *ngIf="!schedule.next">- - -</ng-container>
</div> </div>
<div class="timestampTitle"> <div class="bulk" [class.timestampBulkEmpty]="!schedule.next?.bulk" *ngIf="schedule.next?.bulk">
Nächste Ausführung:
</div>
<div class="timestampBulk" [class.timestampBulkEmpty]="!schedule.next?.bulk" *ngIf="schedule.next?.bulk" (click)="execute(schedule.next?.bulk)">
{{ schedule.next?.bulk?.name }} {{ schedule.next?.bulk?.name }}
<fa-icon [icon]="faPlayCircle" (click)="execute(schedule.next?.bulk)"></fa-icon>
</div> </div>
</div> </div>
<div class="timestampBox timestampBoxLast"> <div class="tileBody last">
<div class="timestampTitle"> <div class="timestamp">
Zuletzt: <ng-container *ngIf="schedule.last">{{ timeService.relativeDate(schedule.last?.lastFuzzyTimestamp) }}</ng-container>
</div>
<div class="timestampTimestamp">
<ng-container *ngIf="schedule.last">{{ schedule.last?.lastFuzzyTimestamp.dayName }}:&nbsp;{{ schedule.last?.lastFuzzyTimestamp.timeString }}</ng-container>
<ng-container *ngIf="!schedule.last">- - -</ng-container> <ng-container *ngIf="!schedule.last">- - -</ng-container>
</div> </div>
<div class="timestampBulk" [class.timestampBulkEmpty]="!schedule.last?.bulk" *ngIf="schedule.last?.bulk" (click)="execute(schedule.last?.bulk)"> <div class="bulk" [class.timestampBulkEmpty]="!schedule.last?.bulk" *ngIf="schedule.last?.bulk">
{{ schedule.last?.bulk?.name }} {{ schedule.last?.bulk?.name }}
<fa-icon [icon]="faPlayCircle" (click)="execute(schedule.last?.bulk)"></fa-icon>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<button (click)="create()">+ Hinzufügen</button>

View File

@ -1,134 +1,23 @@
.schedules { @import "../../../../config";
padding: 0.25em;
.scheduleBox {
.schedule {
margin: 0.25em;
border: 0.1em solid gray;
border-radius: 0.2em;
background-color: #FFF0F0;
.header {
border-bottom: 0.1em solid gray;
.enabled {
float: left;
padding: 0.5em;
}
.title {
float: left;
padding: 0.5em;
font-weight: bold;
}
.skip { .skip {
padding: 0.45em; float: right !important;
float: left;
img {
display: inline;
vertical-align: bottom;
height: 1.3em;
}
} }
.delete { .delete {
float: right; float: right !important;
padding: 0.5em;
} }
} .last {
.timestampBoxNext {
clear: left;
float: left;
width: 100%;
height: 4em;
border-bottom: 0.1em solid lightgray;
div {
float: left;
padding: 0.1em;
height: 2em;
}
.timestampTitle {
// -
}
.timestampTimestamp {
float: right;
text-align: right;
}
.timestampBulk {
clear: both;
float: right;
width: 100%;
text-align: right;
}
.timestampBulkEmpty {
clear: both;
float: right;
width: 100%;
text-align: right;
color: gray; color: gray;
font-size: 60%;
border-top: @border solid gray;
} }
} .timestamp {
.timestampBoxLast {
clear: left;
float: left; float: left;
width: 100%;
color: gray;
font-size: 80%;
div {
float: left;
padding: 0.1em;
height: 2em;
} }
.timestampTitle { .bulk {
width: 4em;
}
.timestampTimestamp {
text-align: right;
}
.timestampBulk {
float: right; float: right;
text-align: right;
}
.timestampBulkEmpty {
float: right;
text-align: right;
color: gray;
}
}
}
.scheduleEnabled {
background-color: #F0FFF0;
}
.skipActive {
background-color: orange;
}
@media (min-width: 1000px) {
float: left;
width: 400px;
}
}
} }

View File

@ -1,13 +1,14 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {ScheduleService} from "../../../api/schedule/schedule.service"; import {ScheduleService} from "../../../api/schedule/schedule.service";
import {Schedule} from "../../../api/schedule/Schedule"; import {Schedule} from "../../../api/schedule/Schedule";
import {faCheckCircle, faCircle, faTimesCircle} from '@fortawesome/free-regular-svg-icons'; import {faCheckCircle, faCircle, faPlayCircle, faTimesCircle} from '@fortawesome/free-regular-svg-icons';
import {NO_OP} from "../../../api/api.service"; import {NO_OP} from "../../../api/api.service";
import {Update} from "../../../api/Update"; import {Update} from "../../../api/Update";
import {ScheduleEntryService} from "../../../api/schedule/entry/schedule-entry.service"; import {ScheduleEntryService} from "../../../api/schedule/entry/schedule-entry.service";
import {ScheduleEntry} from "../../../api/schedule/entry/ScheduleEntry"; import {ScheduleEntry} from "../../../api/schedule/entry/ScheduleEntry";
import {Bulk} from "../../../api/bulk/Bulk"; import {Bulk} from "../../../api/bulk/Bulk";
import {BulkService} from "../../../api/bulk/BulkService"; import {BulkService} from "../../../api/bulk/BulkService";
import {TimeService} from "../../../api/time.service";
@Component({ @Component({
selector: 'app-schedule-list', selector: 'app-schedule-list',
@ -30,6 +31,7 @@ export class ScheduleListComponent implements OnInit {
readonly scheduleService: ScheduleService, readonly scheduleService: ScheduleService,
readonly entryService: ScheduleEntryService, readonly entryService: ScheduleEntryService,
readonly bulkService: BulkService, readonly bulkService: BulkService,
readonly timeService: TimeService,
) { ) {
// nothing // nothing
} }
@ -83,4 +85,5 @@ export class ScheduleListComponent implements OnInit {
} }
} }
protected readonly faPlayCircle = faPlayCircle;
} }

View File

@ -1 +1 @@
<input type="text" [(ngModel)]="code" (focus)="focus = true" (blur)="apply()" (keydown.enter)="apply()" (keydown.escape)="cancel()" [style.background-color]="bgcolor"> <input type="text" [class]="inputClass" [(ngModel)]="code" (focus)="focus = true" (blur)="apply()" (keydown.enter)="apply()" (keydown.escape)="cancel()">

View File

@ -23,7 +23,7 @@ export class DurationComponent implements OnInit {
} }
@Input() @Input()
bgcolor: string = ''; inputClass: string = '';
@Input() @Input()
min: Duration | undefined = undefined; min: Duration | undefined = undefined;

View File

@ -0,0 +1,36 @@
@margin: 0.5em;
@padding: 0.2em;
@border: 0.05em;
@border-radius: 0.2em;
.disabledFont {
color: gray;
}
.disabledBack {
background-color: gray;
}
.enabledFont {
color: #8fbc8f;
}
.enabledBack {
background-color: #8fbc8f;
}
.skipBack {
background-color: #ffc059;
}
.skipFont {
color: #ff9a00;
}
.fuzzyFont {
color: #489dff;
}
.fuzzyBack {
background-color: #88c0ff;
}

View File

@ -1,3 +1,7 @@
* {
box-sizing: border-box;
}
// font // font
body, input, select, button { body, input, select, button {
font-size: 5vw; font-size: 5vw;
@ -14,13 +18,12 @@ input, select, button {
border: none; border: none;
outline: none; outline: none;
padding: 0.1em; padding: 0.1em;
border-radius: 0.1em; border-radius: @border-radius;
box-sizing: border-box;
background-color: white;
} }
select { select {
margin-top: -0.1em; margin-top: -0.1em;
background-color: transparent;
} }
body { body {
@ -35,7 +38,6 @@ a {
div { div {
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
box-sizing: border-box;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
@ -159,3 +161,5 @@ table.vertical {
.buttonMinus { .buttonMinus {
background-color: #ef8787; background-color: #ef8787;
} }
@import "tile";

View File

@ -0,0 +1,69 @@
@import "config";
.tiles {
margin-top: @margin;
margin-left: @margin;
.tile {
border-radius: @border-radius;
margin-right: @margin;
margin-bottom: @margin;
background-color: #ececec;
@media (min-width: 1001px) {
width: 400px;
float: left;
}
.tileHead {
display: flex;
div {
float: left;
padding: @padding;
}
.title {
flex-grow: 1;
}
}
.tileBody {
padding: @padding;
}
.tileBodyFlex {
display: flex;
padding: @padding;
}
.icon {
display: inline;
vertical-align: bottom;
height: 1.1em;
}
}
.flexHalf {
width: 50%;
}
.flexIcon {
float: left;
width: 1.5em;
text-align: center;
}
.flexIconInput {
float: left;
width: calc(100% - 1.5em);
text-align: center;
}
.flexFull {
width: 100%;
}
}