update dependencies, improve views
This commit is contained in:
parent
b602564781
commit
94b8792de8
@ -121,5 +121,8 @@
|
||||
}
|
||||
}
|
||||
}},
|
||||
"defaultProject": "bstlboard-angular"
|
||||
"defaultProject": "bstlboard-angular",
|
||||
"cli": {
|
||||
"analytics": false
|
||||
}
|
||||
}
|
||||
|
11756
package-lock.json
generated
11756
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
61
package.json
61
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "bstlboard",
|
||||
"version": "0.0.0",
|
||||
"version": "1.5.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
@ -11,44 +11,43 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular-material-components/datetime-picker": "^7.0.1",
|
||||
"@angular/animations": "^13.3.3",
|
||||
"@angular/cdk": "^13.3.2",
|
||||
"@angular/common": "^13.3.3",
|
||||
"@angular/compiler": "^13.3.3",
|
||||
"@angular/core": "^13.3.3",
|
||||
"@angular/flex-layout": "^13.0.0-beta.38",
|
||||
"@angular/forms": "^13.3.3",
|
||||
"@angular/material": "^13.3.2",
|
||||
"@angular/material-moment-adapter": "^13.3.2",
|
||||
"@angular/platform-browser": "^13.3.3",
|
||||
"@angular/platform-browser-dynamic": "^13.3.3",
|
||||
"@angular/router": "^13.3.3",
|
||||
"@angular/service-worker": "^13.3.3",
|
||||
"moment": "^2.29.2",
|
||||
"rxjs": "~7.5.5",
|
||||
"tslib": "^2.3.1",
|
||||
"zone.js": "~0.11.5"
|
||||
"@angular-material-components/datetime-picker": "^9.0.0",
|
||||
"@angular/animations": "^15.0.2",
|
||||
"@angular/cdk": "^15.0.1",
|
||||
"@angular/common": "^15.0.2",
|
||||
"@angular/compiler": "^15.0.2",
|
||||
"@angular/core": "^15.0.2",
|
||||
"@angular/forms": "^15.0.2",
|
||||
"@angular/material": "^15.0.1",
|
||||
"@angular/material-moment-adapter": "^15.0.1",
|
||||
"@angular/platform-browser": "^15.0.2",
|
||||
"@angular/platform-browser-dynamic": "^15.0.2",
|
||||
"@angular/router": "^15.0.2",
|
||||
"@angular/service-worker": "^15.0.2",
|
||||
"moment": "^2.29.4",
|
||||
"rxjs": "~7.6.0",
|
||||
"tslib": "^2.4.1",
|
||||
"zone.js": "~0.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^13.3.2",
|
||||
"@angular/cli": "^13.3.2",
|
||||
"@angular/compiler-cli": "^13.3.3",
|
||||
"@angular/localize": "^13.3.3",
|
||||
"@types/jasmine": "^4.0.2",
|
||||
"@angular-devkit/build-angular": "^15.0.2",
|
||||
"@angular/cli": "^15.0.2",
|
||||
"@angular/compiler-cli": "^15.0.2",
|
||||
"@angular/localize": "^15.0.2",
|
||||
"@types/jasmine": "^4.3.1",
|
||||
"@types/jasminewd2": "^2.0.10",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/node": "^18.11.11",
|
||||
"codelyzer": "^6.0.2",
|
||||
"jasmine-core": "~4.1.0",
|
||||
"jasmine-core": "~4.5.0",
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "^6.3.18",
|
||||
"karma": "^6.4.1",
|
||||
"karma-chrome-launcher": "~3.1.1",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.3",
|
||||
"karma-jasmine": "~5.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.7.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "^2.0.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~10.7.0",
|
||||
"ts-node": "~10.9.1",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.6.3"
|
||||
"typescript": "~4.8.4"
|
||||
}
|
||||
}
|
@ -25,32 +25,32 @@ import { UiMain } from './ui/main/main.ui';
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '', component: UiMain, children: [
|
||||
{ path: '', component: PageView, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'login', component: PageLogin, canActivate: [ AnonymousGuard ] },
|
||||
{ path: 'search', component: PageSearch, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'moderation/comments', component: PageModerationComments, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'moderation/entries', component: PageModerationEntries, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'bookmarks', component: PageBookmarks, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'settings', component: PageSettings, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'submit', component: PageEntryEdit, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'e/:id', component: PageEntry, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'e/:id/edit', component: PageEntryEdit, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'c/:id', component: PageComment, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'u/:username', component: PageUser, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'u/c/:username', component: PageUserComments, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'u/e/:username', component: PageUserEntries, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: '', component: PageView, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'login', component: PageLogin, canActivate: [AnonymousGuard] },
|
||||
{ path: 'search', component: PageSearch, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'moderation/comments', component: PageModerationComments, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'moderation/entries', component: PageModerationEntries, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'bookmarks', component: PageBookmarks, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'settings', component: PageSettings, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'submit', component: PageEntryEdit, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'e/:id', component: PageEntry, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'e/:id/edit', component: PageEntryEdit, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'c/:id', component: PageComment, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'u/:username', component: PageUser, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'u/c/:username', component: PageUserComments, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'u/e/:username', component: PageUserEntries, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'unavailable', component: PageUnavailable },
|
||||
{ path: 'v', component: PageViewEdit, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'v/:name', component: PageView, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'v/:name/edit', component: PageViewEdit, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: 'v/:name/:username', component: PageView, canActivate: [ AuthenticatedGuard ] },
|
||||
{ path: '**', component: PageNotFound, pathMatch: 'full', canActivate: [ AuthUpdateGuard ] },
|
||||
{ path: 'v', component: PageViewEdit, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'v/:name', component: PageView, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'v/:name/edit', component: PageViewEdit, canActivate: [AuthenticatedGuard] },
|
||||
{ path: 'v/:name/:username', component: PageView, canActivate: [AuthenticatedGuard] },
|
||||
{ path: '**', component: PageNotFound, pathMatch: 'full', canActivate: [AuthUpdateGuard] },
|
||||
]
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [ RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload', relativeLinkResolution: 'legacy' }) ],
|
||||
exports: [ RouterModule ]
|
||||
imports: [RouterModule.forRoot(routes, { onSameUrlNavigation: 'reload' })],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
|
@ -43,7 +43,6 @@ import {MatPaginatorModule} from '@angular/material/paginator';
|
||||
import {MatSortModule} from '@angular/material/sort';
|
||||
import {MatTableModule} from '@angular/material/table';
|
||||
import {MatMomentDateModule} from '@angular/material-moment-adapter';
|
||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||
|
||||
import {
|
||||
NgxMatDatetimePickerModule,
|
||||
@ -91,7 +90,6 @@ import {
|
||||
MatSortModule,
|
||||
MatTableModule,
|
||||
MatMomentDateModule,
|
||||
FlexLayoutModule,
|
||||
NgxMatDatetimePickerModule,
|
||||
NgxMatNativeDateModule,
|
||||
NgxMatTimepickerModule
|
||||
@ -132,7 +130,6 @@ import {
|
||||
MatPaginatorModule,
|
||||
MatSortModule,
|
||||
MatTableModule,
|
||||
FlexLayoutModule,
|
||||
NgxMatDatetimePickerModule,
|
||||
NgxMatNativeDateModule,
|
||||
NgxMatTimepickerModule
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
<ui-commentform [target]="entry.id" (replyCommentEvent)="replyCallback($event)"></ui-commentform>
|
||||
|
||||
<ui-comments #comments [target]="entry.id" [subcomments]="true"></ui-comments>
|
||||
<ui-comments #comments [target]="entry.id" [subcomments]="true" class="scroll-container"></ui-comments>
|
||||
</ng-container>
|
||||
</div>
|
@ -1,4 +1,4 @@
|
||||
<div fxLayout="column" fxFlexFill>
|
||||
<div class="flex column fill">
|
||||
<div class="container">
|
||||
<mat-card *ngIf="externals && externals.length > 0" class="box">
|
||||
<mat-card-content>
|
||||
@ -7,7 +7,7 @@
|
||||
{{'login.external.invalid' | i18n}}
|
||||
</mat-error>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<mat-card-actions class="flex wrap">
|
||||
<a class="external-login" (click)="externalLogin(client)" *ngFor="let client of externals"
|
||||
mat-raised-button color="accent">{{'login.external.client' | i18n:client.id}}</a>
|
||||
<mat-slide-toggle [(ngModel)]="autologin">
|
||||
@ -50,7 +50,7 @@
|
||||
</mat-card>
|
||||
</form>
|
||||
</div>
|
||||
<span fxFlexOffset="auto"></span>
|
||||
<span class="spacer"></span>
|
||||
<div class="container" *ngIf="!internalLogin">
|
||||
<small>
|
||||
<a href="javascript:" (click)="internalLogin = true;">{{'login.local' | i18n}}</a>
|
||||
|
@ -4,7 +4,8 @@ mat-form-field {
|
||||
|
||||
a.external-login {
|
||||
margin: 15px 0;
|
||||
display: block;
|
||||
flex-basis: 100%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.box {
|
||||
|
@ -1,7 +1,7 @@
|
||||
<div class="container">
|
||||
<mat-progress-bar *ngIf="!comments || !comments.content" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<div *ngIf="comments && comments.content" fxLayout="column" fxFlexFill class="comments">
|
||||
<div *ngIf="comments && comments.content" class="comments flex column fill">
|
||||
<ng-container *ngFor="let comment of comments.content; let i = index">
|
||||
<mat-divider class="divider" *ngIf="i > 0"></mat-divider>
|
||||
<ui-comment class="comment" [comment]="comment" [subcomments]="false" [parentLink]="true" [change]="boundRefresh">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div fxLayout="column" fxFlexFill>
|
||||
<div class="container">
|
||||
<mat-form-field appearance="fill">
|
||||
<div class="flex column fill">
|
||||
<div class="container flex wrap">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>{{'search.query' | i18n}}</mat-label>
|
||||
<input matInput [formControl]="searchFormControl">
|
||||
</mat-form-field>
|
||||
@ -24,7 +24,8 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-select placeholder="{{'search.byDate' | i18n}}" [value]="byDate" (selectionChange)="byDate = $event.value; refresh()">
|
||||
<mat-select placeholder="{{'search.byDate' | i18n}}" [value]="byDate"
|
||||
(selectionChange)="byDate = $event.value; refresh()">
|
||||
<mat-select-trigger>
|
||||
<mat-icon>{{'search.byDate.' + byDate + '.icon' | i18n}}</mat-icon> {{'search.byDate.' +
|
||||
byDate | i18n}}
|
||||
@ -59,7 +60,7 @@
|
||||
|
||||
<mat-progress-bar *ngIf="!results || !results.content && !results.error" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<div *ngIf="results && results.error" fxLayout="column" fxFlexFill>
|
||||
<div *ngIf="results && results.error" class="flex column fill">
|
||||
<mat-card class="accent box">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ 'search.error.' + results.error.status | i18n}}</mat-card-title>
|
||||
@ -73,8 +74,8 @@
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<div class="results" *ngIf="results" fxLayout="column">
|
||||
<mat-list *ngIf="results.content">
|
||||
<ng-container *ngIf="results">
|
||||
<mat-list *ngIf="results.content" class="scroll-container">
|
||||
<ng-container *ngFor="let result of results.content; let i = index">
|
||||
<mat-divider *ngIf="i > 0"></mat-divider>
|
||||
<mat-list-item>
|
||||
@ -94,10 +95,9 @@
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
<span fxFlexOffset="auto" fxFlexOffset.xs="none"></span>
|
||||
<span class="spacer"></span>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [pageIndex]="results.number" [length]="results.totalElements"
|
||||
[pageSize]="results.size" (page)="update && update($event)" showFirstLastButtons>
|
||||
</mat-paginator>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
</div>
|
@ -1,13 +1,12 @@
|
||||
.results {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
mat-list mat-list-item {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
mat-form-field {
|
||||
margin-right: 15px;
|
||||
flex-basis: 0;
|
||||
flex-grow: 1;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.container {
|
||||
@ -58,4 +57,4 @@ ui-tagspicker {
|
||||
@media screen and (min-width: 992px) {
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
@ -10,20 +10,20 @@ import { SettingsService } from 'src/app/services/settings.service';
|
||||
@Component({
|
||||
selector: 'page-search',
|
||||
templateUrl: './search.page.html',
|
||||
styleUrls: [ './search.page.scss' ]
|
||||
styleUrls: ['./search.page.scss']
|
||||
})
|
||||
export class PageSearch implements OnInit {
|
||||
|
||||
searchFormControl = new FormControl();
|
||||
pageSizeOptions: number[] = [ 1, 2, 3, 4, 5, 10, 15, 30, 50, 100 ];
|
||||
pageSizeOptions: number[] = [1, 2, 3, 4, 5, 10, 15, 30, 50, 100];
|
||||
results: any;
|
||||
asc: boolean = false;
|
||||
byDate: boolean = false;
|
||||
settings: any;
|
||||
settingsSubscription: Subscription;
|
||||
boundRefresh: Function;
|
||||
types: string[] = [ 'all', 'entry', 'comment' ];
|
||||
searchType: string = this.types[ 1 ];
|
||||
types: string[] = ['all', 'entry', 'comment'];
|
||||
searchType: string = this.types[1];
|
||||
|
||||
constructor(
|
||||
private searchService: SearchService,
|
||||
@ -33,10 +33,16 @@ export class PageSearch implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.boundRefresh = this.refresh.bind(this);
|
||||
this.asc = this.route.snapshot.queryParamMap.get('asc') == 'true';
|
||||
this.byDate = this.route.snapshot.queryParamMap.get('byDate') == 'true';
|
||||
this.searchType = this.route.snapshot.queryParamMap.get('type') || this.types[ 1 ];
|
||||
this.searchFormControl.setValue(this.route.snapshot.queryParamMap.get('q'));
|
||||
|
||||
this.route.queryParams.subscribe({
|
||||
next: (params) => {
|
||||
this.asc = params['asc'] == 'true';
|
||||
this.byDate = params['byDate'] == 'true';
|
||||
this.searchType = params['type'] || this.types[1];
|
||||
this.searchFormControl.setValue(params['q']);
|
||||
}
|
||||
})
|
||||
|
||||
this.searchFormControl.valueChanges.pipe(
|
||||
debounceTime(300)).subscribe((value: string) => {
|
||||
this.refresh();
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
<mat-progress-bar *ngIf="!comments || !comments.content" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<div *ngIf="comments && comments.content" fxLayout="column" fxFlexFill class="comments">
|
||||
<div *ngIf="comments && comments.content" class="comments flex column fill">
|
||||
<p>{{'user.commentsBy' | i18n}}<a routerLink="/u/{{username}}">{{username}}</a></p>
|
||||
<ng-container *ngFor="let comment of comments.content; let i = index">
|
||||
<mat-divider class="divider" *ngIf="i > 0"></mat-divider>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div fxLayout="column" fxFlexFill>
|
||||
<div class="flex column fill">
|
||||
<div class="container">
|
||||
<p>{{'user.entriesBy' | i18n}}<a routerLink="/u/{{username}}">{{username}}</a></p>
|
||||
</div>
|
||||
<page-entries [fetch]="boundFetch" fxFlex="grow"></page-entries>
|
||||
<page-entries [fetch]="boundFetch" class="grow"></page-entries>
|
||||
</div>
|
@ -65,13 +65,13 @@
|
||||
</section>
|
||||
|
||||
</mat-card-content>
|
||||
<mat-card-actions fxLayout="row wrap" fxFlexFill>
|
||||
<mat-card-actions class="flex wrap fill">
|
||||
<button *ngIf="!working" mat-raised-button color="primary" [disabled]="form.invalid">
|
||||
<mat-icon>save</mat-icon> {{ (view.id ? 'views.update' : 'views.create') | i18n}}
|
||||
</button>
|
||||
<a mat-button color="primary" routerLink="/v/{{view.name}}" *ngIf="view.id">{{ 'views.goTo' |
|
||||
i18n}}</a>
|
||||
<span fxFlexOffset="auto" fxFlexOffset.xs="none"></span>
|
||||
<span class="spacer"></span>
|
||||
<a mat-raised-button color="warn" *ngIf="!working && view.id" (click)="deleteView()">
|
||||
<mat-icon>delete</mat-icon> {{
|
||||
'views.delete' |
|
||||
|
@ -1,9 +1,10 @@
|
||||
<mat-progress-bar *ngIf="!comments || !comments.content" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
<div *ngIf="comments && comments.content" fxLayout="column" fxFlexFill class="comments">
|
||||
<div *ngIf="comments && comments.content" class="comments flex column fill">
|
||||
<ng-container *ngFor="let comment of comments.content; let i = index">
|
||||
<mat-divider class="divider" *ngIf="i > 0"></mat-divider>
|
||||
<ui-comment class="comment" [comment]="comment" [change]="boundRefresh" [subcomments]="subcomments" [ignore]="ignore" [parentLink]="parentLink"></ui-comment>
|
||||
<ui-comment class="comment" [comment]="comment" [change]="boundRefresh" [subcomments]="subcomments"
|
||||
[ignore]="ignore" [parentLink]="parentLink"></ui-comment>
|
||||
</ng-container>
|
||||
|
||||
<mat-list *ngIf="comments.totalElements == 0 && !parent">
|
||||
|
@ -1,7 +1,7 @@
|
||||
<mat-progress-bar *ngIf="!entries || !entries.content && !entries.error" mode="indeterminate"></mat-progress-bar>
|
||||
|
||||
|
||||
<div *ngIf="entries && entries.error" fxLayout="column" fxFlexFill>
|
||||
<div *ngIf="entries && entries.error" class="flex column fill">
|
||||
<mat-card class="accent box">
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{ 'entries.error.' + entries.error.status | i18n}}</mat-card-title>
|
||||
@ -15,8 +15,8 @@
|
||||
</mat-card>
|
||||
</div>
|
||||
|
||||
<div *ngIf="entries" fxLayout="column" fxFlexFill>
|
||||
<mat-list *ngIf="entries.content">
|
||||
<div *ngIf="entries" class="flex column fill">
|
||||
<mat-list *ngIf="entries.content" class="scroll-container">
|
||||
<ng-container *ngFor="let entry of entries.content; let i = index">
|
||||
<mat-divider *ngIf="i > 0"></mat-divider>
|
||||
<mat-list-item class="entry-item">
|
||||
@ -33,15 +33,15 @@
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
|
||||
<span fxFlexOffset="auto"></span>
|
||||
<span class="spacer"></span>
|
||||
|
||||
<div class="mat-paginator" fxLayout="row" fxLayout.xs="column" fxLayoutAlign.xs="start start">
|
||||
<div class="mat-mdc-paginator flex">
|
||||
<div *ngIf="filter" class="filter-container">
|
||||
<a mat-icon-button mat-button (click)="filterOpen=!filterOpen" title="{{'entries.filter' | i18n}}"
|
||||
<a mat-icon-button (click)="filterOpen=!filterOpen" title="{{'entries.filter' | i18n}}"
|
||||
[color]="filterOpen ? 'accent' : 'primary'">
|
||||
<mat-icon>filter_alt</mat-icon>
|
||||
</a>
|
||||
<div *ngIf="filterOpen" fxLayout="row wrap">
|
||||
<div *ngIf="filterOpen" class="flex">
|
||||
<ui-tagspicker [(model)]="tags" placeholder="{{'entries.filter.tags' | i18n}}" [change]="boundTagsPickerChange">
|
||||
</ui-tagspicker>
|
||||
|
||||
@ -87,7 +87,7 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<span fxFlexOffset="auto" fxFlexOffset.xs="none"></span>
|
||||
<span class="spacer"></span>
|
||||
<mat-paginator [pageSizeOptions]="pageSizeOptions" [pageIndex]="entries.number" [length]="entries.totalElements"
|
||||
[pageSize]="entries.size" (page)="update && update($event)" showFirstLastButtons>
|
||||
</mat-paginator>
|
||||
|
@ -31,9 +31,9 @@
|
||||
<mat-slide-toggle [checked]="darkTheme">
|
||||
{{'darkTheme' | i18n}}
|
||||
</mat-slide-toggle>
|
||||
</a>
|
||||
</a>
|
||||
<mat-divider *ngIf="authenticated"></mat-divider>
|
||||
<a *ngIf="authenticated" routerLink="/settings" routerLinkActive="active" mat-menu-item>
|
||||
<a *ngIf="authenticated" routerLink="/settings" routerLinkActive="active" mat-menu-item>
|
||||
<mat-icon>tune</mat-icon> {{'settings' | i18n}}
|
||||
</a>
|
||||
<mat-divider *ngIf="authenticated"></mat-divider>
|
||||
@ -51,21 +51,31 @@
|
||||
<ui-viewmenu *ngIf="authenticated"></ui-viewmenu>
|
||||
<mat-divider *ngIf="moderator"></mat-divider>
|
||||
<a *ngIf="moderator" routerLink="/moderation/entries" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>report</mat-icon> {{'moderation.entries' | i18n}}
|
||||
<mat-icon matListItemIcon>report</mat-icon>
|
||||
<span>{{'moderation.entries' | i18n}}</span>
|
||||
</a>
|
||||
<a *ngIf="moderator" routerLink="/moderation/comments" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>feedback</mat-icon> {{'moderation.comments' | i18n}}
|
||||
<mat-icon matListItemIcon>feedback</mat-icon>
|
||||
<span>{{'moderation.comments' | i18n}}</span>
|
||||
</a>
|
||||
<mat-divider *ngIf="authenticated"></mat-divider>
|
||||
<a *ngIf="authenticated" routerLink="/bookmarks" routerLinkActive="active" mat-list-item>
|
||||
<mat-icon>bookmarks</mat-icon> {{'bookmarks' | i18n}}
|
||||
<mat-icon matListItemIcon>bookmarks</mat-icon>
|
||||
<span>{{'bookmarks' | i18n}}</span>
|
||||
</a>
|
||||
<mat-divider *ngIf="authenticated"></mat-divider>
|
||||
<a (click)="openExternal('https://wiki.bstly.de/services/bstlboard#faq','_blank')" routerLinkActive="active"
|
||||
mat-list-item>
|
||||
<mat-icon>help</mat-icon> {{'page.faq' | i18n}}
|
||||
<mat-icon matListItemIcon>help</mat-icon>
|
||||
<span>{{'page.faq' | i18n}}</span>
|
||||
</a>
|
||||
</mat-nav-list>
|
||||
|
||||
<mat-form-field *ngIf="authenticated">
|
||||
<input matInput type="text" (change)="search($event.target && $event.target.value || undefined, $event)"
|
||||
placeholder="{{'search' | i18n}}">
|
||||
</mat-form-field>
|
||||
|
||||
<span class="spacer"></span>
|
||||
<mat-nav-list>
|
||||
<mat-divider></mat-divider>
|
||||
@ -83,4 +93,4 @@
|
||||
<mat-sidenav-content>
|
||||
<router-outlet></router-outlet>
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
</mat-sidenav-container>
|
@ -13,7 +13,7 @@ import { SettingsService } from '../../services/settings.service';
|
||||
@Component({
|
||||
selector: 'ui-main',
|
||||
templateUrl: './main.ui.html',
|
||||
styleUrls: [ './main.ui.scss' ]
|
||||
styleUrls: ['./main.ui.scss']
|
||||
})
|
||||
export class UiMain {
|
||||
|
||||
@ -91,6 +91,13 @@ export class UiMain {
|
||||
}
|
||||
}
|
||||
|
||||
search(text, event) {
|
||||
if (text) {
|
||||
this.router.navigate(["search"], { queryParams: { q: text } });
|
||||
}
|
||||
event.target.value = '';
|
||||
}
|
||||
|
||||
toggleDarkTheme() {
|
||||
this.darkTheme = !this.darkTheme;
|
||||
|
||||
@ -112,7 +119,7 @@ export class UiMain {
|
||||
logout() {
|
||||
localStorage.removeItem("bstlboard.autologin");
|
||||
this.authService.logout().subscribe(data => {
|
||||
this.router.navigate([ "" ]).then(() => {
|
||||
this.router.navigate([""]).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
})
|
||||
@ -131,7 +138,7 @@ export class UiMain {
|
||||
window.open(url, target);
|
||||
}
|
||||
|
||||
@HostListener('window:resize', [ '$event' ])
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onResize(event) {
|
||||
if (event.target.innerWidth < 768) {
|
||||
this.opened = false;
|
||||
@ -142,14 +149,14 @@ export class UiMain {
|
||||
|
||||
touchEvents(): void {
|
||||
fromEvent(document, 'touchstart').subscribe((event: TouchEvent) => {
|
||||
if (event.touches[ 0 ]) {
|
||||
this.touchStartX = event.touches[ 0 ].screenX;
|
||||
if (event.touches[0]) {
|
||||
this.touchStartX = event.touches[0].screenX;
|
||||
}
|
||||
})
|
||||
|
||||
fromEvent(document, 'touchmove').subscribe((event: TouchEvent) => {
|
||||
if (event.touches[ 0 ]) {
|
||||
this.touchX = event.touches[ 0 ].screenX;
|
||||
if (event.touches[0]) {
|
||||
this.touchX = event.touches[0].screenX;
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,16 +1,16 @@
|
||||
<mat-form-field>
|
||||
<mat-chip-list #tagList>
|
||||
<mat-chip *ngFor="let tag of tags" [removable]="true" (removed)="removeTag(tag)">
|
||||
<mat-chip-grid #tagList>
|
||||
<mat-chip-row *ngFor="let tag of tags" [removable]="true" (removed)="removeTag(tag)">
|
||||
<mat-icon inline="true">tag</mat-icon>{{tag}}
|
||||
<button matChipRemove>
|
||||
<mat-icon>cancel</mat-icon>
|
||||
</button>
|
||||
</mat-chip>
|
||||
</mat-chip-row>
|
||||
<input *ngIf="max == 0 || !tags || tags.length < max" #tagsInput placeholder="{{placeholder}}"
|
||||
[formControl]="searchFormControl" [matAutocomplete]="auto" [matChipInputFor]="tagList"
|
||||
[matChipInputSeparatorKeyCodes]="separatorKeysCodes" (matChipInputTokenEnd)="addInputTag($event)">
|
||||
<mat-hint *ngIf="max > 1" align="end">{{tags && tags.length || 0}}/{{max}}</mat-hint>
|
||||
</mat-chip-list>
|
||||
</mat-chip-grid>
|
||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="addOptionTag($event)">
|
||||
<mat-option *ngFor="let option of searchTags | async" [value]="option">
|
||||
<mat-icon inline="true">tag</mat-icon>{{option}}
|
||||
|
@ -1,20 +1,17 @@
|
||||
<ng-container *ngIf="settings">
|
||||
<ng-container *ngFor="let view of views">
|
||||
<mat-divider *ngIf="view.divider"></mat-divider>
|
||||
<mat-list-item>
|
||||
<a routerLink="/v/{{view.name}}" routerLinkActive="active" class="link">
|
||||
<mat-icon>{{'sorting.' + view.sorting + '.icon' | i18n}}</mat-icon> {{'sorting.' + view.name | i18nEmpty}}
|
||||
</a>
|
||||
<small>
|
||||
<a routerLink="/v/{{view.name}}/edit" matTooltip="{{'views.edit' | i18n}}" color="primary" class="edit">
|
||||
<mat-icon inline="true">tune</mat-icon>
|
||||
</a>
|
||||
<a routerLink="/v/{{view.name}}" routerLinkActive="active" class="link" mat-list-item>
|
||||
<mat-icon matListItemIcon>{{'sorting.' + view.sorting + '.icon' | i18n}}</mat-icon>
|
||||
<span>{{'sorting.' + view.name | i18nEmpty}}</span>
|
||||
<small color="primary" class="edit" matTooltip="{{'views.edit' | i18n}}" (click)="edit(view.name, $event)">
|
||||
<mat-icon inline="true">tune</mat-icon>
|
||||
</small>
|
||||
</mat-list-item>
|
||||
</a>
|
||||
</ng-container>
|
||||
<mat-divider></mat-divider>
|
||||
<a *ngIf="views.length < settings.maxViews" routerLink="/v" routerLinkActive="active" mat-list-item
|
||||
title="{{'views.add' | i18n}}">
|
||||
<mat-icon style="margin: 0 auto;">add</mat-icon>
|
||||
</a>
|
||||
</ng-container>
|
||||
</ng-container>
|
@ -2,23 +2,26 @@ mat-form-field {
|
||||
display: block;
|
||||
}
|
||||
|
||||
mat-list-item {
|
||||
a.link {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.link {
|
||||
|
||||
a.edit {
|
||||
position: relative;
|
||||
|
||||
.edit {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
mat-list-item:hover {
|
||||
a.edit {
|
||||
.link:hover {
|
||||
.edit {
|
||||
opacity: 0.6;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a.edit:hover {
|
||||
.edit:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { SettingsService } from 'src/app/services/settings.service';
|
||||
import { ViewService } from 'src/app/services/view.service';
|
||||
@ -6,7 +7,7 @@ import { ViewService } from 'src/app/services/view.service';
|
||||
@Component({
|
||||
selector: 'ui-viewmenu',
|
||||
templateUrl: 'viewmenu.ui.html',
|
||||
styleUrls: [ './viewmenu.ui.scss' ]
|
||||
styleUrls: ['./viewmenu.ui.scss']
|
||||
})
|
||||
export class UiViewMenu implements OnInit {
|
||||
|
||||
@ -15,7 +16,7 @@ export class UiViewMenu implements OnInit {
|
||||
settings: any;
|
||||
settingsSubscription: Subscription;
|
||||
|
||||
constructor(private viewService: ViewService, private settingsService: SettingsService) {
|
||||
constructor(private viewService: ViewService, private settingsService: SettingsService, private router: Router) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -28,5 +29,11 @@ export class UiViewMenu implements OnInit {
|
||||
})
|
||||
}
|
||||
|
||||
edit(name, event) {
|
||||
this.router.navigateByUrl('/v/' + name + '/edit');
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,15 +15,15 @@
|
||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
||||
// hue. Available color palettes: https://material.io/design/color/
|
||||
$light-theme: mat.define-light-theme((color: (primary: $light-primary,
|
||||
accent: $light-accent,
|
||||
warn: $light-warn,
|
||||
)));
|
||||
accent: $light-accent,
|
||||
warn: $light-warn,
|
||||
)));
|
||||
|
||||
// Define an alternate dark theme.
|
||||
$dark-theme: mat.define-dark-theme((color: (primary: $dark-primary,
|
||||
accent: $light-accent,
|
||||
warn: $light-warn,
|
||||
)));
|
||||
accent: $light-accent,
|
||||
warn: $light-warn,
|
||||
)));
|
||||
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ $dark-theme: mat.define-dark-theme((color: (primary: $dark-primary,
|
||||
|
||||
a {
|
||||
color: $primary;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
@ -82,7 +83,8 @@ body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
|
||||
}
|
||||
|
||||
app-root, ui-main {
|
||||
app-root,
|
||||
ui-main {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
display: flex;
|
||||
@ -148,6 +150,33 @@ qrcode canvas {
|
||||
max-width: 400px !important;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex !important;
|
||||
|
||||
&.column {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&.wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&.fill {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
@ -10,10 +10,10 @@
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "es2015",
|
||||
"module": "es2020",
|
||||
"target": "es2022",
|
||||
"module": "es2022",
|
||||
"lib": [
|
||||
"es2018",
|
||||
"es2022",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user