UI: Lazy loading and TG fixes (#77)
Reviewed-on: #77 Co-authored-by: Daniel Ponte <amigan@gmail.com> Co-committed-by: Daniel Ponte <amigan@gmail.com>
This commit is contained in:
parent
d95cda6b44
commit
b4cf5550d7
11 changed files with 291 additions and 55 deletions
|
@ -8,7 +8,7 @@
|
|||
<div class="centerNav"></div>
|
||||
<div class="rightNav">
|
||||
@if (auth.loggedIn) {
|
||||
<button class="ybtn">
|
||||
<button class="ybtn sbButton">
|
||||
<a (click)="logout()" class="logout">Logout</a>
|
||||
</button>
|
||||
}
|
||||
|
|
|
@ -1,30 +1,68 @@
|
|||
import { Routes } from '@angular/router';
|
||||
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { LoginComponent } from './login/login.component';
|
||||
import { TalkgroupsComponent } from './talkgroups/talkgroups.component';
|
||||
import { TalkgroupRecordComponent } from './talkgroups/talkgroup-record/talkgroup-record.component';
|
||||
import { CallsComponent } from './calls/calls.component';
|
||||
import { IncidentsComponent } from './incidents/incidents.component';
|
||||
import { AlertsComponent } from './alerts/alerts.component';
|
||||
import { ImportComponent } from './talkgroups/import/import.component';
|
||||
import { ExportComponent } from './talkgroups/export/export.component';
|
||||
import { AuthGuard } from './auth.guard';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: 'login', component: LoginComponent },
|
||||
{
|
||||
path: 'login',
|
||||
loadComponent: () =>
|
||||
import('./login/login.component').then((m) => m.LoginComponent),
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
canActivateChild: [AuthGuard],
|
||||
children: [
|
||||
{ path: '', component: HomeComponent, pathMatch: 'full' },
|
||||
{ path: 'talkgroups', component: TalkgroupsComponent },
|
||||
{ path: 'talkgroups/import', component: ImportComponent },
|
||||
{ path: 'talkgroups/export', component: ExportComponent },
|
||||
{ path: 'talkgroups/:sys/:tg', component: TalkgroupRecordComponent },
|
||||
{ path: 'calls', component: CallsComponent },
|
||||
{ path: 'incidents', component: IncidentsComponent },
|
||||
{ path: 'alerts', component: AlertsComponent },
|
||||
{
|
||||
path: '',
|
||||
loadComponent: () =>
|
||||
import('./home/home.component').then((m) => m.HomeComponent),
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'talkgroups',
|
||||
loadComponent: () =>
|
||||
import('./talkgroups/talkgroups.component').then(
|
||||
(m) => m.TalkgroupsComponent,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'talkgroups/import',
|
||||
loadComponent: () =>
|
||||
import('./talkgroups/import/import.component').then(
|
||||
(m) => m.ImportComponent,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'talkgroups/export',
|
||||
loadComponent: () =>
|
||||
import('./talkgroups/export/export.component').then(
|
||||
(m) => m.ExportComponent,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'talkgroups/:sys/:tg',
|
||||
loadComponent: () =>
|
||||
import(
|
||||
'./talkgroups/talkgroup-record/talkgroup-record.component'
|
||||
).then((m) => m.TalkgroupRecordComponent),
|
||||
},
|
||||
{
|
||||
path: 'calls',
|
||||
loadComponent: () =>
|
||||
import('./calls/calls.component').then((m) => m.CallsComponent),
|
||||
},
|
||||
{
|
||||
path: 'incidents',
|
||||
loadComponent: () =>
|
||||
import('./incidents/incidents.component').then(
|
||||
(m) => m.IncidentsComponent,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'alerts',
|
||||
loadComponent: () =>
|
||||
import('./alerts/alerts.component').then((m) => m.AlertsComponent),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
<div>
|
||||
<mat-form-field class="tagsField">
|
||||
<mat-label>Tags</mat-label>
|
||||
<mat-chip-grid #tagsChipGrid [formControl]="tagsControl">
|
||||
<mat-chip-grid #tagsChipGrid formControlName="tagsControl">
|
||||
@for (tag of tg.tags; track tag) {
|
||||
<mat-chip-row (removed)="removeTag(tag)">
|
||||
{{ tag }}
|
||||
|
@ -74,10 +74,25 @@
|
|||
}
|
||||
</mat-chip-grid>
|
||||
<input
|
||||
name="tag"
|
||||
placeholder="New tag..."
|
||||
[matChipInputFor]="tagsChipGrid"
|
||||
(matChipInputTokenEnd)="addTag($event)"
|
||||
(matChipInputTokenEnd)="addTagEv($event)"
|
||||
[matChipInputAddOnBlur]="false"
|
||||
[formControlName]="'tagInput'"
|
||||
#tagInput
|
||||
[matAutocomplete]="auto"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
#auto="matAutocomplete"
|
||||
(optionSelected)="selected($event)"
|
||||
(optionActivated)="activated($event)"
|
||||
>
|
||||
@for (tag of filteredTags(); track tag) {
|
||||
<mat-option [value]="tag">{{ tag }}</mat-option>
|
||||
}
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -88,6 +103,6 @@
|
|||
Rules:
|
||||
<alert-rule-builder [rules]="tg.alert_config" />
|
||||
</div>
|
||||
<button type="submit">Save</button>
|
||||
<button class="sbButton" type="submit">Save</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,33 @@
|
|||
import { Component, ChangeDetectionStrategy, inject } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
model,
|
||||
ChangeDetectionStrategy,
|
||||
Signal,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { toSignal } from '@angular/core/rxjs-interop';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import {
|
||||
Talkgroup,
|
||||
TalkgroupUpdate,
|
||||
IconMap,
|
||||
iconMapping,
|
||||
} from '../../talkgroup';
|
||||
import { COMMA, ENTER } from '@angular/cdk/keycodes';
|
||||
import { TalkgroupService } from '../talkgroups.service';
|
||||
import { AlertRuleBuilderComponent } from './alert-rule-builder/alert-rule-builder.component';
|
||||
import {
|
||||
MatAutocomplete,
|
||||
MatAutocompleteModule,
|
||||
MatAutocompleteSelectedEvent,
|
||||
MatAutocompleteActivatedEvent,
|
||||
} from '@angular/material/autocomplete';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { catchError, of } from 'rxjs';
|
||||
import { shareReplay } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import {
|
||||
ReactiveFormsModule,
|
||||
FormGroup,
|
||||
|
@ -35,22 +54,49 @@ import { MatIconModule } from '@angular/material/icon';
|
|||
MatCheckboxModule,
|
||||
MatChipsModule,
|
||||
MatIconModule,
|
||||
MatAutocompleteModule,
|
||||
],
|
||||
templateUrl: './talkgroup-record.component.html',
|
||||
styleUrl: './talkgroup-record.component.scss',
|
||||
// changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TalkgroupRecordComponent {
|
||||
tg!: Talkgroup;
|
||||
iconMapping: IconMap = iconMapping;
|
||||
tgService: TalkgroupService = inject(TalkgroupService);
|
||||
tagsControl = new FormControl<string[]>([]);
|
||||
|
||||
form!: FormGroup;
|
||||
allTags = <string[]>[];
|
||||
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
|
||||
readonly filteredTags = computed(() => {
|
||||
const currentTag = this.tagInputSig()?.toLowerCase() ?? '';
|
||||
return currentTag
|
||||
? this.allTags.filter((tag) => tag.toLowerCase().includes(currentTag))
|
||||
: this.allTags.slice();
|
||||
});
|
||||
readonly _allTags: Observable<string[]>;
|
||||
form = new FormGroup({
|
||||
name: new FormControl(''),
|
||||
alpha_tag: new FormControl(''),
|
||||
tg_group: new FormControl(''),
|
||||
frequency: new FormControl(0),
|
||||
alert: new FormControl(false),
|
||||
weight: new FormControl(0.0),
|
||||
icon: new FormControl(''),
|
||||
tagInput: new FormControl(''),
|
||||
tagsControl: new FormControl<string[]>([]),
|
||||
});
|
||||
tagInputSig = toSignal(
|
||||
this.form.get('tagInput')!.valueChanges.pipe(debounceTime(300)) ?? of(null),
|
||||
{},
|
||||
);
|
||||
@ViewChild('auto') autocomp!: MatAutocomplete;
|
||||
active: string | null = null;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
) {}
|
||||
) {
|
||||
this._allTags = this.tgService.allTags().pipe(shareReplay());
|
||||
}
|
||||
|
||||
removeTag(tag: string) {
|
||||
const idx = this.tg.tags.indexOf(tag);
|
||||
|
@ -63,17 +109,52 @@ export class TalkgroupRecordComponent {
|
|||
return [...this.tg.tags];
|
||||
}
|
||||
|
||||
addTag(event: MatChipInputEvent) {
|
||||
const value = (event.value || '').trim();
|
||||
|
||||
if (value) {
|
||||
this.tg.tags = [...this.tg.tags, value];
|
||||
addTagEv(event: MatChipInputEvent) {
|
||||
if (this.active != null) {
|
||||
// this is a hack
|
||||
this.addTag(this.active);
|
||||
this.active = null;
|
||||
event.chipInput!.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
const value = (event.value || '').trim();
|
||||
this.addTag(value);
|
||||
|
||||
event.chipInput!.clear();
|
||||
}
|
||||
|
||||
activated(event: MatAutocompleteActivatedEvent) {
|
||||
console.log('activated');
|
||||
this.active = event.option?.value;
|
||||
}
|
||||
|
||||
addTag(tag: string) {
|
||||
const idx = this.tg.tags.indexOf(tag);
|
||||
if (idx > -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tag) {
|
||||
this.tg.tags = [...this.tg.tags, tag];
|
||||
}
|
||||
}
|
||||
|
||||
selected(event: any) {
|
||||
let ev = event as MatAutocompleteSelectedEvent;
|
||||
this.addTag(ev.option.viewValue);
|
||||
ev.option.deselect();
|
||||
this.form.controls['tagInput'].reset();
|
||||
}
|
||||
|
||||
loadTags() {
|
||||
this._allTags.subscribe((event) => {
|
||||
this.allTags = event;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.loadTags();
|
||||
const sysId = this.route.snapshot.paramMap.get('sys');
|
||||
const tgId = this.route.snapshot.paramMap.get('tg');
|
||||
|
||||
|
@ -81,16 +162,15 @@ export class TalkgroupRecordComponent {
|
|||
.getTalkgroup(Number(sysId), Number(tgId))
|
||||
.subscribe((data: Talkgroup) => {
|
||||
this.tg = data;
|
||||
this.form = new FormGroup({
|
||||
name: new FormControl(this.tg.name),
|
||||
alpha_tag: new FormControl(this.tg.alpha_tag),
|
||||
tg_group: new FormControl(this.tg.tg_group),
|
||||
frequency: new FormControl(this.tg.frequency),
|
||||
alert: new FormControl(this.tg.alert),
|
||||
weight: new FormControl(this.tg.weight),
|
||||
icon: new FormControl(this.tg?.metadata?.icon ?? ''),
|
||||
});
|
||||
this.tagsControl.setValue(this.tg?.tags ?? []);
|
||||
this.form.controls['name'].setValue(this.tg.name);
|
||||
this.form.controls['alpha_tag'].setValue(this.tg.alpha_tag);
|
||||
this.form.controls['tg_group'].setValue(this.tg.tg_group);
|
||||
this.form.controls['frequency'].setValue(this.tg.frequency);
|
||||
this.form.controls['alert'].setValue(this.tg.alert);
|
||||
this.form.controls['weight'].setValue(this.tg.weight);
|
||||
this.form.controls['icon'].setValue(this.tg?.metadata?.icon ?? '');
|
||||
this.form.controls['tagInput'].setValue('');
|
||||
this.form.controls['tagsControl'].setValue(this.tg?.tags ?? []);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -118,11 +198,11 @@ export class TalkgroupRecordComponent {
|
|||
if (this.form.controls['weight'].dirty) {
|
||||
tgu.weight = Number(this.form.controls['weight'].value);
|
||||
}
|
||||
if (this.tagsControl.dirty) {
|
||||
tgu.tags = this.tagsControl.value;
|
||||
if (this.form.controls['tagsControl'].dirty) {
|
||||
tgu.tags = this.form.controls['tagsControl'].value;
|
||||
}
|
||||
if (this.form.controls['icon'].dirty) {
|
||||
let iv: string = this.form.controls['icon'].value;
|
||||
let iv: string = this.form.controls['icon'].value ?? '';
|
||||
if (tgu.metadata == null) {
|
||||
tgu.metadata = {};
|
||||
}
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
<div class="tableContainer">
|
||||
<table mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox
|
||||
(change)="$event ? masterToggle() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-checkbox
|
||||
(click)="$event.stopPropagation()"
|
||||
(change)="$event ? selection.toggle(row) : null"
|
||||
[checked]="selection.isSelected(row)"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</td>
|
||||
</ng-container>
|
||||
<ng-container matColumnDef="icon">
|
||||
<th mat-header-cell *matHeaderCellDef></th>
|
||||
<td mat-cell *matCellDef="let tg">
|
||||
|
|
|
@ -2,8 +2,10 @@ import {
|
|||
Component,
|
||||
inject,
|
||||
Pipe,
|
||||
Input,
|
||||
PipeTransform,
|
||||
output,
|
||||
ViewChild,
|
||||
input,
|
||||
} from '@angular/core';
|
||||
import { toObservable } from '@angular/core/rxjs-interop';
|
||||
|
@ -14,13 +16,17 @@ import { RouterModule, RouterLink } from '@angular/router';
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
||||
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||
import { MatPaginatorModule, PageEvent } from '@angular/material/paginator';
|
||||
import {
|
||||
MatPaginator,
|
||||
MatPaginatorModule,
|
||||
PageEvent,
|
||||
} from '@angular/material/paginator';
|
||||
import { PrefsService } from '../../prefs/prefs.service';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import {
|
||||
MatChipSelectionChange,
|
||||
MatChipsModule,
|
||||
} from '@angular/material/chips';
|
||||
import { MatChipsModule } from '@angular/material/chips';
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
|
||||
@Pipe({
|
||||
standalone: true,
|
||||
|
@ -60,6 +66,7 @@ export class SanitizeHtmlPipe implements PipeTransform {
|
|||
IconifyPipe,
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
MatCheckboxModule,
|
||||
MatChipsModule,
|
||||
],
|
||||
templateUrl: './talkgroup-table.component.html',
|
||||
|
@ -81,6 +88,7 @@ export class TalkgroupTableComponent {
|
|||
perPage: number = 25;
|
||||
count = 0;
|
||||
columns = [
|
||||
'select',
|
||||
'icon',
|
||||
'sysID',
|
||||
'sysName',
|
||||
|
@ -92,14 +100,30 @@ export class TalkgroupTableComponent {
|
|||
'learned',
|
||||
'edit',
|
||||
];
|
||||
selection = new SelectionModel<Talkgroup>(true, []);
|
||||
private resetPageSub!: Subscription;
|
||||
@Input() resetPage!: Observable<void>;
|
||||
@ViewChild('paginator') paginator!: MatPaginator;
|
||||
suppress = false;
|
||||
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
setPage(p: PageEvent) {
|
||||
this.switchPage.emit(p);
|
||||
// don't needlessly request page 0 if we were asked merely to reset the state of the control
|
||||
this.selection.clear();
|
||||
if (!this.suppress) {
|
||||
this.switchPage.emit(p);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.resetPageSub = this.resetPage.subscribe(() => {
|
||||
this.suppress = true;
|
||||
this.paginator.firstPage();
|
||||
this.selection.clear();
|
||||
this.suppress = false;
|
||||
});
|
||||
|
||||
this.perPage = this.prefsService.last.tgsPerPage;
|
||||
this.talkgroups$.subscribe((event) => {
|
||||
if (event != null) {
|
||||
|
@ -109,10 +133,26 @@ export class TalkgroupTableComponent {
|
|||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.resetPageSub.unsubscribe();
|
||||
}
|
||||
|
||||
searchChip(event: MouseEvent) {
|
||||
// not a fan of how this looks, but it works...
|
||||
this.changeFilter.emit(
|
||||
(event.target as Element).childNodes[0].textContent ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
isAllSelected() {
|
||||
const numSelected = this.selection.selected.length;
|
||||
const numRows = this.dataSource.data.length;
|
||||
return numSelected === numRows;
|
||||
}
|
||||
|
||||
masterToggle() {
|
||||
this.isAllSelected()
|
||||
? this.selection.clear()
|
||||
: this.dataSource.data.forEach((row) => this.selection.select(row));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,33 @@
|
|||
<div class="tgTools">
|
||||
<mat-form-field class="filterBox" subscriptSizing="dynamic">
|
||||
<mat-label>Filter</mat-label>
|
||||
<input matInput name="filter" type="search" autocomplete="off" [formControl]="filter" />
|
||||
<input
|
||||
matInput
|
||||
name="filter"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
[formControl]="filter"
|
||||
/>
|
||||
<button
|
||||
class="clearBtn"
|
||||
*ngIf="filter.value"
|
||||
matSuffix
|
||||
mat-icon-button
|
||||
(click)="filter.setValue('')"
|
||||
>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<div class="addTag"></div>
|
||||
<div class="impExp">
|
||||
<button [routerLink]="'/talkgroups/import'">Import</button>
|
||||
<button [routerLink]="'/talkgroups/export'">Export</button>
|
||||
<button class="sbButton" [routerLink]="'/talkgroups/import'">Import</button>
|
||||
<button class="sbButton" [routerLink]="'/talkgroups/export'">Export</button>
|
||||
</div>
|
||||
</div>
|
||||
<talkgroup-table
|
||||
*ngIf="tgs; else spinner"
|
||||
[talkgroups]="tgs"
|
||||
[resetPage]="pageReset.asObservable()"
|
||||
(switchPage)="switchPage($event)"
|
||||
(changeFilter)="changeFilter($event)"
|
||||
></talkgroup-table>
|
||||
|
|
|
@ -3,6 +3,10 @@ talkgroup-table {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.filterBox {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
talkgroups {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -10,6 +14,11 @@ talkgroups {
|
|||
height: 90%;
|
||||
}
|
||||
|
||||
.clearBtn {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.tgTools {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@ import { TalkgroupTableComponent } from './talkgroup-table/talkgroup-table.compo
|
|||
import { PageEvent } from '@angular/material/paginator';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { PrefsService } from '../prefs/prefs.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatInputModule, MatInput } from '@angular/material/input';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
|
||||
@Component({
|
||||
selector: 'talkgroups',
|
||||
|
@ -27,6 +29,7 @@ import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms';
|
|||
ReactiveFormsModule,
|
||||
FormsModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatIconModule,
|
||||
],
|
||||
templateUrl: './talkgroups.component.html',
|
||||
styleUrl: './talkgroups.component.scss',
|
||||
|
@ -43,6 +46,12 @@ export class TalkgroupsComponent {
|
|||
curPage = <PageEvent>{ pageIndex: 0, pageSize: this.perPage };
|
||||
constructor(private route: ActivatedRoute) {}
|
||||
|
||||
pageReset: Subject<void> = new Subject<void>();
|
||||
|
||||
resetPage() {
|
||||
this.pageReset.next();
|
||||
}
|
||||
|
||||
switchPage(p: PageEvent) {
|
||||
this.curPage = p;
|
||||
this.route.paramMap
|
||||
|
@ -84,6 +93,8 @@ export class TalkgroupsComponent {
|
|||
this.filter.setValue(f);
|
||||
}
|
||||
filterChange() {
|
||||
this.curPage.pageIndex = 0;
|
||||
this.resetPage();
|
||||
this.switchPage(this.curPage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ export class TalkgroupService {
|
|||
});
|
||||
}
|
||||
|
||||
allTags(): Observable<string[]> {
|
||||
return this.http.get<string[]>('/api/talkgroup/tags');
|
||||
}
|
||||
|
||||
exportTGs(
|
||||
type: string,
|
||||
sysID: number,
|
||||
|
|
|
@ -167,7 +167,7 @@ button.ybtn {
|
|||
text-shadow: 2px 2px 2px rgb(156, 156, 156);
|
||||
}
|
||||
|
||||
button {
|
||||
button.sbButton {
|
||||
border-radius: 3px;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
|
@ -199,3 +199,7 @@ body {
|
|||
.navItems {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
input {
|
||||
caret-color: var(--color-dark-fg) !important;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue