mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-03-15 11:12:22 +00:00
refactor: simplify favorites and mensa dashboard sections
This commit is contained in:
committed by
Rainer Killinger
parent
47565e51b0
commit
23bd5a431c
34
src/app/_helpers/rxjs/mutation-observer.ts
Normal file
34
src/app/_helpers/rxjs/mutation-observer.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Observable} from 'rxjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function fromMutationObserver(
|
||||||
|
target: Node,
|
||||||
|
options?: MutationObserverInit,
|
||||||
|
): Observable<MutationRecord[]> {
|
||||||
|
return new Observable(subscriber => {
|
||||||
|
const observer = new MutationObserver(mutations => {
|
||||||
|
subscriber.next(mutations);
|
||||||
|
});
|
||||||
|
observer.observe(target, options);
|
||||||
|
return () => {
|
||||||
|
observer.disconnect();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -50,6 +50,9 @@
|
|||||||
ion-content {
|
ion-content {
|
||||||
--background: var(--ion-color-light);
|
--background: var(--ion-color-light);
|
||||||
--padding-bottom: var(--spacing-xl);
|
--padding-bottom: var(--spacing-xl);
|
||||||
|
&::part(inner-scroll) {
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.schedule {
|
.schedule {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import {MomentModule} from 'ngx-moment';
|
|||||||
import {DataModule} from '../data/data.module';
|
import {DataModule} from '../data/data.module';
|
||||||
import {SettingsProvider} from '../settings/settings.provider';
|
import {SettingsProvider} from '../settings/settings.provider';
|
||||||
import {DashboardComponent} from './dashboard.component';
|
import {DashboardComponent} from './dashboard.component';
|
||||||
import {EditModalComponent} from './edit-modal/edit-modal.component';
|
|
||||||
import {SearchSectionComponent} from './sections/search-section/search-section.component';
|
import {SearchSectionComponent} from './sections/search-section/search-section.component';
|
||||||
import {NewsSectionComponent} from './sections/news-section/news-section.component';
|
import {NewsSectionComponent} from './sections/news-section/news-section.component';
|
||||||
import {MensaSectionComponent} from './sections/mensa-section/mensa-section.component';
|
import {MensaSectionComponent} from './sections/mensa-section/mensa-section.component';
|
||||||
@@ -46,7 +45,6 @@ const catalogRoutes: Routes = [
|
|||||||
*/
|
*/
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
EditModalComponent,
|
|
||||||
SearchSectionComponent,
|
SearchSectionComponent,
|
||||||
NewsSectionComponent,
|
NewsSectionComponent,
|
||||||
MensaSectionComponent,
|
MensaSectionComponent,
|
||||||
@@ -69,6 +67,5 @@ const catalogRoutes: Routes = [
|
|||||||
NewsModule,
|
NewsModule,
|
||||||
],
|
],
|
||||||
providers: [SettingsProvider, TranslatePipe],
|
providers: [SettingsProvider, TranslatePipe],
|
||||||
exports: [EditModalComponent],
|
|
||||||
})
|
})
|
||||||
export class DashboardModule {}
|
export class DashboardModule {}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
<!--
|
|
||||||
~ Copyright (C) 2022 StApps
|
|
||||||
~ This program is free software: you can redistribute it and/or modify it
|
|
||||||
~ under the terms of the GNU General Public License as published by the Free
|
|
||||||
~ Software Foundation, version 3.
|
|
||||||
~
|
|
||||||
~ This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
~ more details.
|
|
||||||
~
|
|
||||||
~ You should have received a copy of the GNU General Public License along with
|
|
||||||
~ this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<ion-header>
|
|
||||||
<ion-toolbar mode="ios">
|
|
||||||
<ion-title>{{ 'modal.settings' | translate | titlecase }}</ion-title>
|
|
||||||
<ion-button fill="clear" slot="start" (click)="dismissModal()">
|
|
||||||
{{ 'modal.DISMISS_CANCEL' | translate }}
|
|
||||||
</ion-button>
|
|
||||||
<ion-button fill="clear" slot="end" (click)="onSaveClick()">
|
|
||||||
<ion-label>{{ 'modal.DISMISS_CONFIRM' | translate }}</ion-label>
|
|
||||||
</ion-button>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>
|
|
||||||
<ion-content>
|
|
||||||
<ng-container [ngSwitch]="true">
|
|
||||||
<ion-reorder-group
|
|
||||||
*ngSwitchCase="type === types.CHECKBOXES"
|
|
||||||
disabled="false"
|
|
||||||
(ionItemReorder)="doReorder($event)"
|
|
||||||
>
|
|
||||||
<!-- Default reorder icon, end aligned items -->
|
|
||||||
<ion-item *ngFor="let item of items">
|
|
||||||
<ion-reorder slot="start"></ion-reorder>
|
|
||||||
<ion-label>{{ item.labelLocalized }}</ion-label>
|
|
||||||
<ion-toggle slot="end" [checked]="item.active" [(ngModel)]="item.active"></ion-toggle>
|
|
||||||
</ion-item>
|
|
||||||
</ion-reorder-group>
|
|
||||||
|
|
||||||
<ion-radio-group *ngSwitchCase="type === types.RADIOBOXES" [(ngModel)]="selectedValue">
|
|
||||||
<ion-list-header>
|
|
||||||
<ion-label>{{ 'dashboard.canteens.choose_favorite' | translate }}</ion-label>
|
|
||||||
</ion-list-header>
|
|
||||||
<ion-item *ngFor="let item of items">
|
|
||||||
<ion-label>{{ item.labelLocalized }}</ion-label>
|
|
||||||
<ion-radio slot="end" [value]="item.id"></ion-radio>
|
|
||||||
</ion-item>
|
|
||||||
</ion-radio-group>
|
|
||||||
</ng-container>
|
|
||||||
</ion-content>
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
:host {
|
|
||||||
--width: 100vw;
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2022 StApps
|
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
|
||||||
* Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with
|
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
import {Component, Input, OnInit, ViewChild} from '@angular/core';
|
|
||||||
import {IonReorderGroup, ModalController} from '@ionic/angular';
|
|
||||||
import {ItemReorderEventDetail} from '@ionic/core';
|
|
||||||
import {EditModalItem, EditModalTypeEnum} from './edit-modal-type.enum';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a modal window to sort and enable/disable menu items
|
|
||||||
*/
|
|
||||||
@Component({
|
|
||||||
selector: 'stapps-dashboard-edit-modal',
|
|
||||||
templateUrl: 'edit-modal.component.html',
|
|
||||||
styleUrls: ['edit-modal.component.scss'],
|
|
||||||
})
|
|
||||||
export class EditModalComponent implements OnInit {
|
|
||||||
@ViewChild(IonReorderGroup) reorderGroup: IonReorderGroup;
|
|
||||||
|
|
||||||
@Input() type: EditModalTypeEnum = EditModalTypeEnum.CHECKBOXES;
|
|
||||||
|
|
||||||
@Input() items: EditModalItem[];
|
|
||||||
|
|
||||||
@Input() selectedValue: string;
|
|
||||||
|
|
||||||
reorderedItems: EditModalItem[];
|
|
||||||
|
|
||||||
types = EditModalTypeEnum;
|
|
||||||
|
|
||||||
constructor(public modalController: ModalController) {}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.reorderedItems = this.items;
|
|
||||||
}
|
|
||||||
|
|
||||||
ionViewWillLeave() {
|
|
||||||
this.dismissModal();
|
|
||||||
}
|
|
||||||
|
|
||||||
doReorder(event: CustomEvent<ItemReorderEventDetail>) {
|
|
||||||
this.reorderedItems = event.detail.complete(this.reorderedItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
onSaveClick() {
|
|
||||||
this.modalController.dismiss({
|
|
||||||
items: this.reorderedItems,
|
|
||||||
selectedValue: this.selectedValue,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
dismissModal() {
|
|
||||||
this.modalController.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2022 StApps
|
* Copyright (C) 2023 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -12,14 +12,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import {animate, style, transition, trigger} from '@angular/animations';
|
||||||
|
|
||||||
export enum EditModalTypeEnum {
|
export const fadeAnimation = trigger('fade', [
|
||||||
CHECKBOXES,
|
transition(':enter', [style({opacity: '0'}), animate(250, style({opacity: '1'}))]),
|
||||||
RADIOBOXES,
|
]);
|
||||||
}
|
|
||||||
|
|
||||||
export interface EditModalItem {
|
|
||||||
id: unknown;
|
|
||||||
labelLocalized: string;
|
|
||||||
active: boolean;
|
|
||||||
}
|
|
||||||
28
src/app/modules/dashboard/mensa-filters.ts
Normal file
28
src/app/modules/dashboard/mensa-filters.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 StApps
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import {SCBuildingCategories, SCThings, SCThingWithCategories} from '@openstapps/core';
|
||||||
|
|
||||||
|
const mensaCategories = new Set<SCBuildingCategories>(['canteen', 'cafe', 'student canteen', 'restaurant']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export function isMensaThing(item: SCThings): boolean {
|
||||||
|
return (
|
||||||
|
(item as SCThingWithCategories<string, never>).categories?.some(category =>
|
||||||
|
mensaCategories.has(category as never),
|
||||||
|
) || false
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
<ion-button slot="button-end" fill="clear" color="medium" [routerLink]="['/favorites']">
|
<ion-button slot="button-end" fill="clear" color="medium" [routerLink]="['/favorites']">
|
||||||
<ion-icon slot="icon-only" name="search" size="24"></ion-icon>
|
<ion-icon slot="icon-only" name="search" size="24"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<simple-swiper *ngIf="(items | async)?.length; else noItems">
|
<simple-swiper *ngIf="items | async as items; else noItems" @fade>
|
||||||
<stapps-data-list-item
|
<stapps-data-list-item
|
||||||
*ngFor="let item of items | async"
|
*ngFor="let item of items"
|
||||||
[hideThumbnail]="true"
|
[hideThumbnail]="true"
|
||||||
[favoriteButton]="false"
|
[favoriteButton]="false"
|
||||||
[item]="item"
|
[item]="item"
|
||||||
|
|||||||
@@ -12,22 +12,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component, OnInit} from '@angular/core';
|
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {filter, map} from 'rxjs/operators';
|
||||||
import {AlertController, AnimationController} from '@ionic/angular';
|
|
||||||
import {combineLatest} from 'rxjs';
|
|
||||||
import {debounceTime, distinctUntilChanged, startWith, take} from 'rxjs/operators';
|
|
||||||
import {NGXLogger} from 'ngx-logger';
|
|
||||||
import {SCThings} from '@openstapps/core';
|
|
||||||
|
|
||||||
import {DataProvider} from '../../../data/data.provider';
|
|
||||||
import {DataRoutingService} from '../../../data/data-routing.service';
|
|
||||||
import {SearchPageComponent} from '../../../data/list/search-page.component';
|
|
||||||
import {PositionService} from '../../../map/position.service';
|
|
||||||
import {SettingsProvider} from '../../../settings/settings.provider';
|
|
||||||
import {FavoritesService} from '../../../favorites/favorites.service';
|
import {FavoritesService} from '../../../favorites/favorites.service';
|
||||||
import {ContextMenuService} from '../../../menu/context/context-menu.service';
|
import {fadeAnimation} from '../../fade.animation';
|
||||||
import {ConfigProvider} from '../../../config/config.provider';
|
import {isMensaThing} from '../../mensa-filters';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a section with meals of the chosen mensa
|
* Shows a section with meals of the chosen mensa
|
||||||
@@ -36,95 +25,14 @@ import {ConfigProvider} from '../../../config/config.provider';
|
|||||||
selector: 'stapps-favorites-section',
|
selector: 'stapps-favorites-section',
|
||||||
templateUrl: 'favorites-section.component.html',
|
templateUrl: 'favorites-section.component.html',
|
||||||
styleUrls: ['favorites-section.component.scss'],
|
styleUrls: ['favorites-section.component.scss'],
|
||||||
|
animations: [fadeAnimation],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class FavoritesSectionComponent extends SearchPageComponent implements OnInit {
|
export class FavoritesSectionComponent {
|
||||||
constructor(
|
items = this.favoritesService.favoriteThings$.pipe(
|
||||||
protected readonly alertController: AlertController,
|
map(favorites => favorites.filter(it => !isMensaThing(it))),
|
||||||
protected dataProvider: DataProvider,
|
filter(favorites => favorites.length > 0),
|
||||||
protected readonly contextMenuService: ContextMenuService,
|
|
||||||
protected readonly settingsProvider: SettingsProvider,
|
|
||||||
protected readonly logger: NGXLogger,
|
|
||||||
protected dataRoutingService: DataRoutingService,
|
|
||||||
protected router: Router,
|
|
||||||
route: ActivatedRoute,
|
|
||||||
positionService: PositionService,
|
|
||||||
private favoritesService: FavoritesService,
|
|
||||||
configProvider: ConfigProvider,
|
|
||||||
animationController: AnimationController,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
alertController,
|
|
||||||
dataProvider,
|
|
||||||
contextMenuService,
|
|
||||||
settingsProvider,
|
|
||||||
logger,
|
|
||||||
dataRoutingService,
|
|
||||||
router,
|
|
||||||
route,
|
|
||||||
positionService,
|
|
||||||
configProvider,
|
|
||||||
animationController,
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
async initialize() {
|
constructor(private favoritesService: FavoritesService) {}
|
||||||
this.subscriptions.push(
|
|
||||||
combineLatest([
|
|
||||||
this.queryTextChanged.pipe(
|
|
||||||
debounceTime(this.searchQueryDueTime),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
startWith(this.queryText),
|
|
||||||
),
|
|
||||||
this.favoritesService.favoritesChanged$,
|
|
||||||
]).subscribe(async () => {
|
|
||||||
await this.fetchAndUpdateItems();
|
|
||||||
this.queryChanged.next();
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches/updates the favorites (search page component's method override)
|
|
||||||
*/
|
|
||||||
async fetchAndUpdateItems() {
|
|
||||||
this.favoritesService
|
|
||||||
.search(this.queryText, this.filterQuery, this.sortQuery)
|
|
||||||
.pipe(take(1))
|
|
||||||
.subscribe(result => {
|
|
||||||
this.items = new Promise(resolve => {
|
|
||||||
resolve(result.data && result.data.filter(item => !this.isMensaThing(item)));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function as 'typeof' is not accessible in HTML
|
|
||||||
*
|
|
||||||
* @param item TODO
|
|
||||||
*/
|
|
||||||
isMensaThing(item: SCThings): boolean {
|
|
||||||
return (
|
|
||||||
this.hasCategories(item) &&
|
|
||||||
((item.categories as string[]).includes('canteen') ||
|
|
||||||
(item.categories as string[]).includes('cafe') ||
|
|
||||||
(item.categories as string[]).includes('student canteen') ||
|
|
||||||
(item.categories as string[]).includes('restaurant'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*
|
|
||||||
* @param item TODO
|
|
||||||
*/
|
|
||||||
hasCategories(item: SCThings): item is SCThings & {categories: string[]} {
|
|
||||||
return typeof (item as {categories: string[]}).categories !== 'undefined';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emit event that an item was selected
|
|
||||||
*/
|
|
||||||
notifySelect(item: SCThings) {
|
|
||||||
this.dataRoutingService.emitChildEvent(item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component, Input} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
|
||||||
import {SCDish, SCPlace, SCThings} from '@openstapps/core';
|
import {SCDish, SCPlace, SCThings} from '@openstapps/core';
|
||||||
import {PlaceMensaService} from '../../../data/types/place/special/mensa/place-mensa-service';
|
import {PlaceMensaService} from '../../../data/types/place/special/mensa/place-mensa-service';
|
||||||
import {animate, style, transition, trigger} from '@angular/animations';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import {fadeAnimation} from '../../fade.animation';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a section with meals of the chosen mensa
|
* Shows a section with meals of the chosen mensa
|
||||||
@@ -25,11 +25,8 @@ import moment from 'moment';
|
|||||||
selector: 'stapps-mensa-section-content',
|
selector: 'stapps-mensa-section-content',
|
||||||
templateUrl: 'mensa-section-content.component.html',
|
templateUrl: 'mensa-section-content.component.html',
|
||||||
styleUrls: ['mensa-section-content.component.scss'],
|
styleUrls: ['mensa-section-content.component.scss'],
|
||||||
animations: [
|
animations: [fadeAnimation],
|
||||||
trigger('fade', [
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
transition(':enter', [style({opacity: '0'}), animate('500ms ease', style({opacity: '1'}))]),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class MensaSectionContentComponent {
|
export class MensaSectionContentComponent {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<ion-item class="nothing-selected" lines="none">
|
<ion-item class="nothing-selected" lines="none">
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
{{ 'dashboard.canteens.no_favorite_prefix' | translate }}
|
{{ 'dashboard.canteens.no_favorite_prefix' | translate }}
|
||||||
<a (click)="onSectionEdit()">{{ 'dashboard.canteens.no_favorite_link' | translate }}</a>
|
<a [routerLink]="['/canteen']">{{ 'dashboard.canteens.no_favorite_link' | translate }}</a>
|
||||||
{{ 'dashboard.canteens.no_favorite_suffix' | translate }}
|
{{ 'dashboard.canteens.no_favorite_suffix' | translate }}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|||||||
@@ -12,23 +12,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component} from '@angular/core';
|
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||||
import {ActivatedRoute, Router} from '@angular/router';
|
import {map} from 'rxjs/operators';
|
||||||
import {AlertController, AnimationController, ModalController} from '@ionic/angular';
|
|
||||||
import {combineLatest, Subscription} from 'rxjs';
|
|
||||||
import {debounceTime, distinctUntilChanged, startWith, take} from 'rxjs/operators';
|
|
||||||
import {NGXLogger} from 'ngx-logger';
|
|
||||||
import {SCThings} from '@openstapps/core';
|
|
||||||
|
|
||||||
import {DataProvider} from '../../../data/data.provider';
|
|
||||||
import {DataRoutingService} from '../../../data/data-routing.service';
|
|
||||||
import {FoodDataListComponent} from '../../../data/list/food-data-list.component';
|
|
||||||
import {PositionService} from '../../../map/position.service';
|
|
||||||
import {SettingsProvider} from '../../../settings/settings.provider';
|
|
||||||
import {FavoritesService} from '../../../favorites/favorites.service';
|
import {FavoritesService} from '../../../favorites/favorites.service';
|
||||||
import {ContextMenuService} from '../../../menu/context/context-menu.service';
|
import {fadeAnimation} from '../../fade.animation';
|
||||||
import {ConfigProvider} from '../../../config/config.provider';
|
import {isMensaThing} from '../../mensa-filters';
|
||||||
import {animate, style, transition, trigger} from '@angular/animations';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a section with meals of the chosen mensa
|
* Shows a section with meals of the chosen mensa
|
||||||
@@ -37,107 +25,11 @@ import {animate, style, transition, trigger} from '@angular/animations';
|
|||||||
selector: 'stapps-mensa-section',
|
selector: 'stapps-mensa-section',
|
||||||
templateUrl: 'mensa-section.component.html',
|
templateUrl: 'mensa-section.component.html',
|
||||||
styleUrls: ['mensa-section.component.scss'],
|
styleUrls: ['mensa-section.component.scss'],
|
||||||
animations: [
|
animations: [fadeAnimation],
|
||||||
trigger('fade', [transition(':enter', [style({opacity: '0'}), animate(250, style({opacity: '1'}))])]),
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class MensaSectionComponent extends FoodDataListComponent {
|
export class MensaSectionComponent {
|
||||||
sub: Subscription;
|
items = this.favoritesService.favoriteThings$.pipe(map(favorites => favorites.filter(isMensaThing)));
|
||||||
|
|
||||||
constructor(
|
constructor(protected favoritesService: FavoritesService) {}
|
||||||
protected readonly alertController: AlertController,
|
|
||||||
protected dataProvider: DataProvider,
|
|
||||||
protected readonly contextMenuService: ContextMenuService,
|
|
||||||
protected readonly settingsProvider: SettingsProvider,
|
|
||||||
protected readonly logger: NGXLogger,
|
|
||||||
protected dataRoutingService: DataRoutingService,
|
|
||||||
protected router: Router,
|
|
||||||
route: ActivatedRoute,
|
|
||||||
protected positionService: PositionService,
|
|
||||||
public modalController: ModalController,
|
|
||||||
protected favoritesService: FavoritesService,
|
|
||||||
configProvider: ConfigProvider,
|
|
||||||
animationController: AnimationController,
|
|
||||||
) {
|
|
||||||
super(
|
|
||||||
alertController,
|
|
||||||
dataProvider,
|
|
||||||
contextMenuService,
|
|
||||||
settingsProvider,
|
|
||||||
logger,
|
|
||||||
dataRoutingService,
|
|
||||||
router,
|
|
||||||
route,
|
|
||||||
positionService,
|
|
||||||
configProvider,
|
|
||||||
animationController,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async initialize() {
|
|
||||||
super.initialize();
|
|
||||||
|
|
||||||
this.subscriptions.push(
|
|
||||||
combineLatest([
|
|
||||||
this.queryTextChanged.pipe(
|
|
||||||
debounceTime(this.searchQueryDueTime),
|
|
||||||
distinctUntilChanged(),
|
|
||||||
startWith(this.queryText),
|
|
||||||
),
|
|
||||||
this.favoritesService.favoritesChanged$,
|
|
||||||
]).subscribe(async query => {
|
|
||||||
this.queryText = query[0];
|
|
||||||
this.from = 0;
|
|
||||||
if (typeof this.filterQuery !== 'undefined' || this.queryText?.length > 0 || this.showDefaultData) {
|
|
||||||
await this.fetchAndUpdateItems();
|
|
||||||
this.queryChanged.next();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches/updates the favorites (search page component's method override)
|
|
||||||
*/
|
|
||||||
async fetchAndUpdateItems() {
|
|
||||||
this.favoritesService
|
|
||||||
.search(this.queryText, this.filterQuery, this.sortQuery)
|
|
||||||
.pipe(take(1))
|
|
||||||
.subscribe(result => {
|
|
||||||
this.items = new Promise(resolve => {
|
|
||||||
resolve(result.data && result.data.filter(item => this.isMensaThing(item)));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function as 'typeof' is not accessible in HTML
|
|
||||||
*
|
|
||||||
* @param item TODO
|
|
||||||
*/
|
|
||||||
isMensaThing(item: SCThings): boolean {
|
|
||||||
return (
|
|
||||||
this.hasCategories(item) &&
|
|
||||||
((item.categories as string[]).includes('canteen') ||
|
|
||||||
(item.categories as string[]).includes('cafe') ||
|
|
||||||
(item.categories as string[]).includes('student canteen') ||
|
|
||||||
(item.categories as string[]).includes('restaurant'))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO
|
|
||||||
*
|
|
||||||
* @param item TODO
|
|
||||||
*/
|
|
||||||
hasCategories(item: SCThings): item is SCThings & {categories: string[]} {
|
|
||||||
return typeof (item as {categories: string[]}).categories !== 'undefined';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action when user clicked edit to this section
|
|
||||||
*/
|
|
||||||
onSectionEdit() {
|
|
||||||
void this.router.navigate(['/canteen']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ simple-swiper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.more-news {
|
.more-news {
|
||||||
width: 128px;
|
|
||||||
font-size: var(--font-size-xl);
|
font-size: var(--font-size-xl);
|
||||||
--color: var(--ion-color-medium-tint);
|
--color: var(--ion-color-medium-tint);
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,9 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component} from '@angular/core';
|
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||||
import {NewsProvider} from '../../../news/news.provider';
|
import {NewsProvider} from '../../../news/news.provider';
|
||||||
import {SCMessage} from '@openstapps/core';
|
import {fadeAnimation} from '../../fade.animation';
|
||||||
import {animate, style, transition, trigger} from '@angular/animations';
|
|
||||||
import {Router} from '@angular/router';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a section with news
|
* Shows a section with news
|
||||||
@@ -25,21 +23,14 @@ import {Router} from '@angular/router';
|
|||||||
selector: 'stapps-news-section',
|
selector: 'stapps-news-section',
|
||||||
templateUrl: 'news-section.component.html',
|
templateUrl: 'news-section.component.html',
|
||||||
styleUrls: ['news-section.component.scss'],
|
styleUrls: ['news-section.component.scss'],
|
||||||
animations: [
|
animations: [fadeAnimation],
|
||||||
trigger('fade', [
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
transition(':enter', [
|
|
||||||
style({opacity: '0', transform: 'translateX(100px)'}),
|
|
||||||
animate('250ms ease', style({opacity: '1', transform: 'translateX(0)'})),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class NewsSectionComponent {
|
export class NewsSectionComponent {
|
||||||
news: Promise<SCMessage[]>;
|
news = this.newsProvider
|
||||||
|
|
||||||
constructor(readonly newsProvider: NewsProvider, readonly router: Router) {
|
|
||||||
this.news = this.newsProvider
|
|
||||||
.getCurrentFilters()
|
.getCurrentFilters()
|
||||||
|
// eslint-disable-next-line unicorn/prefer-top-level-await,unicorn/consistent-function-scoping
|
||||||
.then(filters => this.newsProvider.getList(5, 0, filters));
|
.then(filters => this.newsProvider.getList(5, 0, filters));
|
||||||
}
|
|
||||||
|
constructor(readonly newsProvider: NewsProvider) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<stapps-section title="{{ 'dashboard.navigation.item.search' | translate }}">
|
<stapps-section title="{{ 'dashboard.navigation.item.search' | translate }}">
|
||||||
<ion-searchbar
|
<ion-searchbar
|
||||||
[routerLink]="'/search'"
|
[routerLink]="['/search']"
|
||||||
[routerAnimation]="routeTransition"
|
[routerAnimation]="routeTransition"
|
||||||
class="stapps-searchbar ion-activatable ripple-parent"
|
class="stapps-searchbar ion-activatable ripple-parent"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -13,10 +13,7 @@
|
|||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {Router} from '@angular/router';
|
import {AnimationController} from '@ionic/angular';
|
||||||
import {Capacitor} from '@capacitor/core';
|
|
||||||
import {Keyboard} from '@capacitor/keyboard';
|
|
||||||
import {AnimationBuilder, AnimationController} from '@ionic/angular';
|
|
||||||
import {homePageSearchTransition} from './search-route-transition';
|
import {homePageSearchTransition} from './search-route-transition';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,29 +25,7 @@ import {homePageSearchTransition} from './search-route-transition';
|
|||||||
styleUrls: ['search-section.component.scss'],
|
styleUrls: ['search-section.component.scss'],
|
||||||
})
|
})
|
||||||
export class SearchSectionComponent {
|
export class SearchSectionComponent {
|
||||||
searchTerm = '';
|
routeTransition = homePageSearchTransition(this.animationController);
|
||||||
|
|
||||||
routeTransition: AnimationBuilder;
|
constructor(private animationController: AnimationController) {}
|
||||||
|
|
||||||
constructor(private router: Router, private animationController: AnimationController) {
|
|
||||||
this.routeTransition = homePageSearchTransition(this.animationController);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User submits search
|
|
||||||
*/
|
|
||||||
onSubmitSearch() {
|
|
||||||
this.router
|
|
||||||
.navigate(['/search'], {queryParams: {query: this.searchTerm}})
|
|
||||||
.then(() => this.hideKeyboard());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hides keyboard in native app environments
|
|
||||||
*/
|
|
||||||
hideKeyboard() {
|
|
||||||
if (Capacitor.isNativePlatform()) {
|
|
||||||
Keyboard.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ export class FavoritesService {
|
|||||||
// using debounce time 0 allows change detection to run through async suspension
|
// using debounce time 0 allows change detection to run through async suspension
|
||||||
favoritesChanged$ = this.favorites.pipe(debounceTime(0));
|
favoritesChanged$ = this.favorites.pipe(debounceTime(0));
|
||||||
|
|
||||||
|
favoriteThings$ = this.favoritesChanged$.pipe(map(favorite => [...favorite.values()].map(it => it.data)));
|
||||||
|
|
||||||
static getDataFromFavorites(items: SCFavorite[]) {
|
static getDataFromFavorites(items: SCFavorite[]) {
|
||||||
return items.map(item => item.data);
|
return items.map(item => item.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
*ngFor="let link of item.links"
|
*ngFor="let link of item.links"
|
||||||
[routerLink]="link.link"
|
[routerLink]="link.link"
|
||||||
[disabled]="link.needsAuth && !isLoggedIn"
|
[disabled]="link.needsAuth && !isLoggedIn"
|
||||||
|
[detail]="false"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<ion-icon [name]="link.icon" size="36" color="dark"></ion-icon>
|
<ion-icon [name]="link.icon" size="36" color="dark"></ion-icon>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
@use 'sass:math';
|
||||||
|
|
||||||
$width: 108px;
|
$width: 108px;
|
||||||
|
|
||||||
simple-swiper {
|
simple-swiper {
|
||||||
@@ -22,7 +24,7 @@ simple-swiper {
|
|||||||
@each $i in 7, 6, 5, 4, 3, 2, 1 {
|
@each $i in 7, 6, 5, 4, 3, 2, 1 {
|
||||||
$max: #{($width + 8px) * $i};
|
$max: #{($width + 8px) * $i};
|
||||||
@container (inline-size < #{$max}) {
|
@container (inline-size < #{$max}) {
|
||||||
--swiper-slide-width: #{100cqi / $i};
|
--swiper-slide-width: #{math.div(100cqi, $i)};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2022 StApps
|
* Copyright (C) 2023 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -13,12 +13,13 @@
|
|||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, HostBinding, Input} from '@angular/core';
|
import {ChangeDetectionStrategy, Component, HostBinding, Input} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'stapps-icon',
|
selector: 'stapps-icon',
|
||||||
templateUrl: 'icon.html',
|
templateUrl: 'icon.html',
|
||||||
styleUrls: ['icon.scss'],
|
styleUrls: ['icon.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class IconComponent {
|
export class IconComponent {
|
||||||
@HostBinding('style.--size')
|
@HostBinding('style.--size')
|
||||||
|
|||||||
@@ -25,14 +25,24 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
|
||||||
<ng-container *ngIf="swiper">
|
<ng-container *ngIf="swiper | async as swiper">
|
||||||
<ion-col size="auto" class="swiper-button">
|
<ion-col size="auto" class="swiper-button">
|
||||||
<ion-button fill="clear" color="medium" (click)="slidePrev()" [disabled]="false">
|
<ion-button
|
||||||
|
fill="clear"
|
||||||
|
color="medium"
|
||||||
|
(click)="swiper.scrollBy({left: -swiper.offsetWidth, behavior: 'smooth'})"
|
||||||
|
[disabled]="false"
|
||||||
|
>
|
||||||
<ion-icon size="24" slot="icon-only" name="chevron_left"></ion-icon>
|
<ion-icon size="24" slot="icon-only" name="chevron_left"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
<ion-col size="auto" class="swiper-button">
|
<ion-col size="auto" class="swiper-button">
|
||||||
<ion-button fill="clear" color="medium" (click)="slideNext()" [disabled]="false">
|
<ion-button
|
||||||
|
fill="clear"
|
||||||
|
color="medium"
|
||||||
|
(click)="swiper.scrollBy({left: swiper.offsetWidth, behavior: 'smooth'})"
|
||||||
|
[disabled]="false"
|
||||||
|
>
|
||||||
<ion-icon size="24" slot="icon-only" name="chevron_right"></ion-icon>
|
<ion-icon size="24" slot="icon-only" name="chevron_right"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ ion-col {
|
|||||||
}
|
}
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
|
transition: height 250ms ease;
|
||||||
display: block;
|
display: block;
|
||||||
padding: var(--spacing-sm) var(--spacing-md) var(--spacing-sm);
|
padding: var(--spacing-sm) var(--spacing-md) var(--spacing-sm);
|
||||||
--swiper-scroll-padding: var(--spacing-md);
|
--swiper-scroll-padding: var(--spacing-md);
|
||||||
|
|||||||
@@ -12,8 +12,11 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import {AfterContentInit, Component, Input, OnDestroy, ViewContainerRef} from '@angular/core';
|
import {AfterContentInit, ChangeDetectionStrategy, Component, Input, ViewContainerRef} from '@angular/core';
|
||||||
import {SCThings} from '@openstapps/core';
|
import {SCThings} from '@openstapps/core';
|
||||||
|
import {fromMutationObserver} from '../_helpers/rxjs/mutation-observer';
|
||||||
|
import {mergeMap, ReplaySubject, takeLast} from 'rxjs';
|
||||||
|
import {distinctUntilChanged, filter, map, startWith} from 'rxjs/operators';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a horizontal list of action chips
|
* Shows a horizontal list of action chips
|
||||||
@@ -22,50 +25,34 @@ import {SCThings} from '@openstapps/core';
|
|||||||
selector: 'stapps-section',
|
selector: 'stapps-section',
|
||||||
templateUrl: 'section.component.html',
|
templateUrl: 'section.component.html',
|
||||||
styleUrls: ['section.component.scss'],
|
styleUrls: ['section.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class SectionComponent implements AfterContentInit, OnDestroy {
|
export class SectionComponent implements AfterContentInit {
|
||||||
@Input() title = '';
|
@Input() title = '';
|
||||||
|
|
||||||
@Input() item?: SCThings;
|
@Input() item?: SCThings;
|
||||||
|
|
||||||
mutationObserver: MutationObserver;
|
nativeElement = new ReplaySubject<HTMLElement>(1);
|
||||||
|
|
||||||
swiper?: HTMLElement;
|
swiper = this.nativeElement.pipe(
|
||||||
|
takeLast(1),
|
||||||
|
mergeMap(element =>
|
||||||
|
fromMutationObserver(element, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true,
|
||||||
|
}).pipe(
|
||||||
|
startWith([]),
|
||||||
|
map(() => element.querySelector('simple-swiper') as HTMLElement),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
filter(element => !!element),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
constructor(readonly viewContainerRef: ViewContainerRef) {}
|
constructor(readonly viewContainerRef: ViewContainerRef) {}
|
||||||
|
|
||||||
ngAfterContentInit() {
|
ngAfterContentInit() {
|
||||||
this.mutationObserver = new MutationObserver(() => {
|
this.nativeElement.next(this.viewContainerRef.element.nativeElement);
|
||||||
const simpleSwiper = this.viewContainerRef.element.nativeElement.querySelector('simple-swiper');
|
this.nativeElement.complete();
|
||||||
if (!simpleSwiper) return;
|
|
||||||
|
|
||||||
this.swiper = simpleSwiper;
|
|
||||||
});
|
|
||||||
this.mutationObserver.observe(this.viewContainerRef.element.nativeElement, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
slideNext() {
|
|
||||||
if (this.swiper) {
|
|
||||||
this.swiper.scrollBy({
|
|
||||||
left: this.swiper.offsetWidth,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
slidePrev() {
|
|
||||||
if (this.swiper) {
|
|
||||||
this.swiper.scrollBy({
|
|
||||||
left: -this.swiper.offsetWidth,
|
|
||||||
behavior: 'smooth',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.mutationObserver.disconnect();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,12 @@
|
|||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Component, ContentChildren, ElementRef, ViewContainerRef} from '@angular/core';
|
import {ChangeDetectionStrategy, Component} from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'simple-swiper',
|
selector: 'simple-swiper',
|
||||||
templateUrl: 'simple-swiper.html',
|
templateUrl: 'simple-swiper.html',
|
||||||
styleUrls: ['simple-swiper.scss'],
|
styleUrls: ['simple-swiper.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class SimpleSwiperComponent {
|
export class SimpleSwiperComponent {}
|
||||||
constructor(readonly viewContainerRef: ViewContainerRef) {}
|
|
||||||
|
|
||||||
@ContentChildren('*') children: ElementRef<unknown>;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
gap: var(--swiper-gap, 0);
|
gap: var(--swiper-gap, 0);
|
||||||
|
|
||||||
&::ng-deep > *:not(ion-button) {
|
&::ng-deep > * {
|
||||||
contain: layout;
|
contain: layout;
|
||||||
scroll-snap-align: start;
|
scroll-snap-align: start;
|
||||||
scroll-margin-inline: var(--swiper-scroll-padding, 0);
|
scroll-margin-inline: var(--swiper-scroll-padding, 0);
|
||||||
|
|||||||
@@ -30,9 +30,10 @@ import {ThingTranslateModule} from '../translation/thing-translate.module';
|
|||||||
import {SimpleSwiperComponent} from './simple-swiper.component';
|
import {SimpleSwiperComponent} from './simple-swiper.component';
|
||||||
import {SearchbarAutofocusDirective} from './searchbar-autofocus.directive';
|
import {SearchbarAutofocusDirective} from './searchbar-autofocus.directive';
|
||||||
import {SectionComponent} from './section.component';
|
import {SectionComponent} from './section.component';
|
||||||
|
import {RouterModule} from '@angular/router';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [BrowserModule, IonicModule, TranslateModule, ThingTranslateModule.forChild()],
|
imports: [BrowserModule, IonicModule, TranslateModule, ThingTranslateModule.forChild(), RouterModule],
|
||||||
declarations: [
|
declarations: [
|
||||||
ElementSizeChangeDirective,
|
ElementSizeChangeDirective,
|
||||||
ArrayLastPipe,
|
ArrayLastPipe,
|
||||||
|
|||||||
Reference in New Issue
Block a user