feat: update components

This commit is contained in:
2023-11-15 20:43:36 +01:00
parent 4833155721
commit 0a5cf19b8a
137 changed files with 960 additions and 885 deletions
+1 -1
View File
@@ -19,6 +19,6 @@
"test": "npx prettier --config index.json --check \"test/*.js\""
},
"peerDependencies": {
"prettier": "3.0.3"
"prettier": "3.1.0"
}
}
+1 -2
View File
@@ -17,11 +17,10 @@ module.exports = {
...require('@openstapps/prettier-config'),
overrides: [
{
files: 'src/**/*.html',
files: ['*.html'],
options: {
parser: 'angular',
},
},
],
ignorePath: ['.prettierignore', '../../.gitignore'],
};
-1
View File
@@ -184,7 +184,6 @@
"typescript": "5.2.2",
"webpack-bundle-analyzer": "4.7.0"
},
"prettier": "@openstapps/prettier-config",
"cordova": {
"plugins": {},
"platforms": [
@@ -49,7 +49,10 @@ export class SharedAxisChoreographer<T> {
*/
currentValue: T;
constructor(initialValue: T, readonly pages?: T[]) {
constructor(
initialValue: T,
readonly pages?: T[],
) {
this.currentValue = initialValue;
this.expectedValue = initialValue;
}
@@ -31,7 +31,10 @@ export class AboutPageComponent implements OnInit {
version = packageJson.version;
constructor(private readonly route: ActivatedRoute, private readonly configProvider: ConfigProvider) {}
constructor(
private readonly route: ActivatedRoute,
private readonly configProvider: ConfigProvider,
) {}
async ngOnInit() {
const route = this.route.snapshot.url.map(it => it.path).join('/');
@@ -14,8 +14,12 @@
-->
<ion-label [color]="passed ? undefined : 'danger'"
>{{ (_item.grade | isNumeric) ? (_item.grade | numberLocalized :
'minimumFractionDigits:1,maximumFractionDigits:1') : '' }} {{ 'status' | thingTranslate : _item | titlecase
}}, {{ 'attempt' | propertyNameTranslate : _item }} {{ _item.attempt }}
>{{
(_item.grade | isNumeric)
? (_item.grade | numberLocalized: 'minimumFractionDigits:1,maximumFractionDigits:1')
: ''
}}
{{ 'status' | thingTranslate: _item | titlecase }}, {{ 'attempt' | propertyNameTranslate: _item }}
{{ _item.attempt }}
</ion-label>
<ion-note> {{ _item.ects }} {{ 'ects' | propertyNameTranslate: _item }}</ion-note>
@@ -16,8 +16,10 @@
<ion-card>
<ion-card-content>
<ion-note *ngIf="item.courseOfStudy as courseOfStudy">
{{ $any('courseOfStudy' | propertyNameTranslate : item) | titlecase }}: {{ 'name' | thingTranslate :
$any(courseOfStudy) }} ({{ 'academicDegree' | thingTranslate : $any(courseOfStudy) }})
{{ $any('courseOfStudy' | propertyNameTranslate: item) | titlecase }}:
{{ 'name' | thingTranslate: $any(courseOfStudy) }} ({{
'academicDegree' | thingTranslate: $any(courseOfStudy)
}})
</ion-note>
</ion-card-content>
</ion-card>
@@ -22,7 +22,10 @@ import {AuthHelperService} from './auth-helper.service';
providedIn: 'root',
})
export class AuthGuardService implements CanActivate {
constructor(private authHelper: AuthHelperService, private router: Router) {}
constructor(
private authHelper: AuthHelperService,
private router: Router,
) {}
public async canActivate(route: ActivatedProtectedRouteSnapshot, _state: RouterStateSnapshot) {
if (route.queryParamMap.get('token')) {
@@ -134,9 +134,9 @@ export class ScheduleSyncService {
private formatChanges(changes: ChangesOf<SCDateSeries, DateSeriesRelevantData>): string[] {
return changes.changes.map(
change =>
`${
this.translator.translator.translatedPropertyNames<SCDateSeries>(SCThingType.DateSeries)?.[change]
}: ${formatRelevantKeys[change](
`${this.translator.translator.translatedPropertyNames<SCDateSeries>(SCThingType.DateSeries)?.[
change
]}: ${formatRelevantKeys[change](
changes.new[change] as never,
this.dateFormatPipe,
this.durationFormatPipe,
@@ -47,9 +47,9 @@
<div class="horizontal-flex">
<ion-item lines="none">
<ion-checkbox [(ngModel)]="includeCancelled"
>{{ 'schedule.toCalendar.reviewModal.INCLUDE_CANCELLED' | translate }}</ion-checkbox
>
<ion-checkbox [(ngModel)]="includeCancelled">{{
'schedule.toCalendar.reviewModal.INCLUDE_CANCELLED' | translate
}}</ion-checkbox>
</ion-item>
</div>
<div class="horizontal-flex">
@@ -38,7 +38,10 @@ export class CalendarService {
calendarName = 'StApps';
// eslint-disable-next-line @typescript-eslint/no-empty-function
constructor(readonly calendar: Calendar, private readonly configProvider: ConfigProvider) {
constructor(
readonly calendar: Calendar,
private readonly configProvider: ConfigProvider,
) {
this.calendarName = (this.configProvider.getValue('name') as string) ?? 'StApps';
}
@@ -13,7 +13,18 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Component, DestroyRef, inject, Input, ViewChild} from '@angular/core';
import {IonRouterOutlet, ModalController} from '@ionic/angular/standalone';
import {
IonButton,
IonChip,
IonContent,
IonFooter,
IonIcon,
IonLabel,
IonRouterOutlet,
IonSkeletonText,
IonToolbar,
ModalController,
} from '@ionic/angular/standalone';
import {SCDateSeries, SCThing, SCThingType, SCUuid} from '@openstapps/core';
import {Subscription} from 'rxjs';
import {ScheduleProvider} from '../../../calendar/schedule.provider';
@@ -26,6 +37,11 @@ import {AddEventStates, AddEventStatesMap} from './add-event-action-chip.config'
import {EditEventSelectionComponent} from '../edit-event-selection.component';
import {AddEventReviewModalComponent} from '../../../calendar/add-event-review-modal.component';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {AsyncPipe, NgIf, TitleCasePipe} from '@angular/common';
import {DataModule} from '../../data.module';
import {TranslateModule} from '@ngx-translate/core';
import {EditModalComponent} from '../../../../util/edit-modal.component';
import {IonContentParallaxDirective} from '../../../../util/ion-content-parallax.directive';
/**
* Shows a horizontal list of action chips
@@ -33,8 +49,26 @@ import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
@Component({
selector: 'stapps-add-event-action-chip',
templateUrl: 'add-event-action-chip.html',
styleUrls: ['add-event-action-chip.scss'],
styleUrl: 'add-event-action-chip.scss',
animations: [chipSkeletonTransition, chipTransition],
standalone: true,
imports: [
IonChip,
AsyncPipe,
NgIf,
DataModule,
IonContent,
IonIcon,
IonLabel,
TranslateModule,
EditModalComponent,
IonFooter,
IonToolbar,
IonButton,
IonSkeletonText,
TitleCasePipe,
IonContentParallaxDirective,
],
})
export class AddEventActionChipComponent {
/**
@@ -14,6 +14,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Component, Input} from '@angular/core';
import {IonChip, IonIcon} from '@ionic/angular/standalone';
import {SCThing} from '@openstapps/core';
/**
@@ -22,6 +23,8 @@ import {SCThing} from '@openstapps/core';
@Component({
selector: 'stapps-locate-action-chip',
templateUrl: 'locate-action-chip.html',
standalone: true,
imports: [IonChip, IonIcon],
})
export class LocateActionChipComponent {
/**
@@ -18,7 +18,8 @@ import {SCPlaceWithoutReferences, SCThings} from '@openstapps/core';
@Component({
selector: 'stapps-navigate-action-chip',
templateUrl: 'navigate-action-chip.html',
styleUrls: ['navigate-action-chip.scss'],
styleUrl: 'navigate-action-chip.scss',
standalone: true,
})
export class NavigateActionChipComponent {
place: SCPlaceWithoutReferences;
@@ -31,9 +31,11 @@
(ionChange)="modified.emit(); frequency.click()"
>
<ion-list-header>
{{ frequency.children[0].item.repeatFrequency ? (frequency.children[0].item.repeatFrequency |
durationLocalized: true | sentencecase) : ('data.chips.add_events.popover.SINGLE' | translate |
titlecase) }}
{{
frequency.children[0].item.repeatFrequency
? (frequency.children[0].item.repeatFrequency | durationLocalized: true | sentencecase)
: ('data.chips.add_events.popover.SINGLE' | translate | titlecase)
}}
</ion-list-header>
</ion-checkbox>
</ion-item>
@@ -44,13 +46,13 @@
>
<ng-container *ngIf="date.item.dates.length > 1; else single_event">
<ion-text>
{{ date.item.dates[0] | amDateFormat: 'dddd, LT' }} - {{ date.item.dates[0] | amAdd:
date.item.duration | amDateFormat: 'LT' }}
{{ date.item.dates[0] | amDateFormat: 'dddd, LT' }} -
{{ date.item.dates[0] | amAdd: date.item.duration | amDateFormat: 'LT' }}
</ion-text>
<br />
<ion-text>
{{ date.item.dates[0] | amDateFormat: 'LL' }} - {{ date.item.dates[date.item.dates.length - 1] |
amDateFormat: 'LL' }}
{{ date.item.dates[0] | amDateFormat: 'LL' }} -
{{ date.item.dates[date.item.dates.length - 1] | amDateFormat: 'LL' }}
</ion-text>
</ng-container>
<ng-template #single_event>
@@ -44,7 +44,10 @@ export class TreeNode<T extends TreeNode<any> | SelectionValue> {
*/
parent?: TreeNode<TreeNode<T>>;
constructor(readonly children: T[], readonly ref: ChangeDetectorRef) {
constructor(
readonly children: T[],
readonly ref: ChangeDetectorRef,
) {
this.updateParents();
this.accumulateApplyValues();
}
@@ -29,10 +29,13 @@ async function delay(ms: number): Promise<void> {
* ['a', 'b', 'c'] => {0: 'a', 1: 'b', 2: 'c'}
*/
export function arrayToIndexMap<T>(array: T[]): Record<number, T> {
return array.reduce((previous, current, index) => {
return array.reduce(
(previous, current, index) => {
previous[index] = current;
return previous;
}, {} as Record<number, T>);
},
{} as Record<number, T>,
);
}
interface OngoingQuery {
@@ -231,6 +231,7 @@ import {VideoListItemComponent} from './types/video/video-list-item.component';
BookDetailContentComponent,
PeriodicalDetailContentComponent,
TitleCardComponent,
EditEventSelectionComponent,
],
})
export class DataModule {}
@@ -12,24 +12,48 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCAcademicPriceGroup, SCThingThatCanBeOfferedOffer} from '@openstapps/core';
import {
IonCard,
IonCardContent,
IonCardHeader,
IonCol,
IonGrid,
IonIcon,
IonRow,
IonText,
} from '@ionic/angular/standalone';
import {RouterLink} from '@angular/router';
import {ThingTranslateModule} from '../../../translation/thing-translate.module';
import {TranslateModule} from '@ngx-translate/core';
import {CurrencyPipe, KeyValuePipe, TitleCasePipe} from '@angular/common';
import {FormatPipeModule, ParseIsoPipeModule} from 'ngx-date-fns';
/**
* TODO
*/
@Component({
selector: 'stapps-offers-detail',
templateUrl: 'offers-detail.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
IonCard,
IonCardHeader,
IonCardContent,
IonGrid,
IonRow,
IonCol,
IonIcon,
RouterLink,
ThingTranslateModule,
TranslateModule,
TitleCasePipe,
ParseIsoPipeModule,
FormatPipeModule,
IonText,
CurrencyPipe,
KeyValuePipe,
],
})
export class OffersDetailComponent {
/**
* TODO
*/
objectKeys = Object.keys;
/**
* TODO
*/
@Input() offers: Array<SCThingThatCanBeOfferedOffer<SCAcademicPriceGroup>>;
}
@@ -16,7 +16,7 @@
<ion-card>
<ion-card-header>{{ 'data.detail.offers.TITLE' | translate | titlecase }}</ion-card-header>
<ion-card-content>
<div *ngFor="let offer of offers">
@for (offer of offers; track $index) {
<ion-grid>
<ion-row>
<ion-col>
@@ -26,24 +26,18 @@
</a>
</ion-col>
<ion-col>
<span
*ngIf="offer.availabilityRange.gt ? offer.availabilityRange.gt : offer.availabilityRange.gte"
>
{{ (offer.availabilityRange.gt ? offer.availabilityRange.gt : offer.availabilityRange.gte) |
amDateFormat : 'll' }}
</span>
@if (offer.availabilityRange.gt ? offer.availabilityRange.gt : offer.availabilityRange.gt) {
{{
(offer.availabilityRange.gt ? offer.availabilityRange.gt : offer.availabilityRange.gte)
| dfnsParseIso
| dfnsFormat: 'PP'
}}
}
</ion-col>
</ion-row>
</ion-grid>
<ion-grid *ngIf="offer.prices && offer.availability !== 'out of stock'">
<ion-row *ngFor="let group of objectKeys(offer.prices)">
<ion-col *ngIf="group !== 'default'">{{ 'data.detail.offers.' + group | translate }} </ion-col>
<ion-col *ngIf="group !== 'default'" width-20 text-right>
<p>{{ offer.prices[group] | currency : 'EUR' : 'symbol' : undefined : 'de' }}</p>
</ion-col>
</ion-row>
</ion-grid>
<ion-grid *ngIf="offer.availability === 'out of stock'">
@if (offer.availability === 'out of stock') {
<ion-grid>
<ion-row>
<ion-col></ion-col>
<ion-col width-20 text-right>
@@ -53,6 +47,20 @@
</ion-col>
</ion-row>
</ion-grid>
</div>
} @else if (offer.prices) {
<ion-grid>
@for (group of offer.prices | keyvalue) {
<ion-row>
@if (group[0] !== 'default') {
<ion-col>{{ 'data.detail.offers.' + group[0] | translate }} </ion-col>
<ion-col width-20 text-right>
<p>{{ offer.prices[group[0]] | currency: 'EUR' : 'symbol' : '' : 'de' }}</p>
</ion-col>
}
</ion-row>
}
</ion-grid>
}
}
</ion-card-content>
</ion-card>
@@ -12,21 +12,21 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCAcademicPriceGroup, SCThingThatCanBeOfferedOffer} from '@openstapps/core';
import {SettingsProvider} from '../../settings/settings.provider';
import {IonIcon, IonText} from '@ionic/angular/standalone';
import {CurrencyPipe} from '@angular/common';
import {TranslateModule} from '@ngx-translate/core';
/**
* TODO
*/
@Component({
selector: 'stapps-offers-in-list',
templateUrl: 'offers-in-list.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [IonText, CurrencyPipe, TranslateModule, IonIcon],
})
export class OffersInListComponent {
/**
* TODO
*/
@Input() set offers(it: Array<SCThingThatCanBeOfferedOffer<SCAcademicPriceGroup>>) {
this._offers = it;
this.price = it[0].prices?.default;
@@ -14,15 +14,24 @@
-->
<div>
<ion-text *ngIf="price && !soldOut" style="white-space: nowrap">
<h2>{{ price | currency : 'EUR' : 'symbol' : undefined : 'de' }}</h2>
</ion-text>
<ion-text *ngIf="soldOut" color="danger" class="sold-out" style="white-space: nowrap">
@if (soldOut) {
<ion-text color="danger" class="sold-out" [style.white-space]="'nowrap'">
<h2>{{ 'data.detail.offers.sold_out' | translate }}</h2>
</ion-text>
<p *ngIf="_offers[0].inPlace && !soldOut" class="place" style="white-space: nowrap">
<ion-icon name="pin_drop"></ion-icon>{{ _offers[0].inPlace.name }}<span *ngIf="_offers.length > 1"
>...</span
>
} @else {
@if (price) {
<ion-text [style.white-space]="'nowrap'">
<h2>{{ price | currency: 'EUR' : 'symbol' : '' : 'de' }}</h2>
</ion-text>
}
@if (_offers[0].inPlace) {
<p class="place" style="white-space: nowrap">
<ion-icon name="pin_drop"></ion-icon>
{{ _offers[0].inPlace.name }}
@if (_offers.length > 1) {
...
}
</p>
}
}
</div>
@@ -12,19 +12,30 @@
* 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} from '@angular/core';
import {SCThingOrigin} from '@openstapps/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCThingRemoteOrigin, SCThingUserOrigin} from '@openstapps/core';
import {IonCard, IonCardContent, IonCardHeader} from '@ionic/angular/standalone';
import {RouterLink} from '@angular/router';
import {TranslateModule} from '@ngx-translate/core';
import {TitleCasePipe} from '@angular/common';
import {FormatPipeModule, ParseIsoPipeModule} from 'ngx-date-fns';
/**
* TODO
*/
@Component({
selector: 'stapps-origin-detail',
templateUrl: 'origin-detail.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
IonCard,
IonCardHeader,
IonCardContent,
RouterLink,
TranslateModule,
TitleCasePipe,
ParseIsoPipeModule,
FormatPipeModule,
],
})
export class OriginDetailComponent {
/**
* TODO
*/
@Input() origin: SCThingOrigin;
@Input() origin: SCThingUserOrigin | SCThingRemoteOrigin;
}
@@ -13,54 +13,74 @@
~ this program. If not, see <https://www.gnu.org/licenses/>.
-->
<ion-card *ngIf="origin.type === 'user'">
@if (origin.type === 'user') {
<ion-card>
<ion-card-header
>{{ 'data.types.origin.TITLE' | translate | titlecase }}: {{ 'data.types.origin.USER' | translate |
titlecase }}</ion-card-header
>{{ 'data.types.origin.TITLE' | translate | titlecase }}:
{{ 'data.types.origin.USER' | translate | titlecase }}</ion-card-header
>
<ion-card-content>
<p>
{{ 'data.types.origin.detail.CREATED' | translate | titlecase }}: {{ origin.created | amDateFormat :
'll' }}
{{ 'data.types.origin.detail.CREATED' | translate | titlecase }}:
{{ origin.created | dfnsParseIso | dfnsFormat: 'PP' }}
</p>
<p *ngIf="origin.updated">
{{ 'data.types.origin.detail.UPDATED' | translate | titlecase }}: {{ origin.updated | amDateFormat :
'll' }}
@if (origin.updated) {
<p>
{{ 'data.types.origin.detail.UPDATED' | translate | titlecase }}:
{{ origin.updated | dfnsParseIso | dfnsFormat: 'PP' }}
</p>
<p *ngIf="origin.modified">
{{ 'data.types.origin.detail.MODIFIED' | translate | titlecase }}: {{ origin.modified | amDateFormat :
'll' }}
}
@if (origin.modified) {
<p>
{{ 'data.types.origin.detail.MODIFIED' | translate | titlecase }}:
{{ origin.modified | dfnsParseIso | dfnsFormat: 'PP' }}
</p>
<p *ngIf="origin.name">{{ 'data.types.origin.detail.MAINTAINER' | translate }}: {{ origin.name }}</p>
<p *ngIf="origin.maintainer">
}
@if (origin.name) {
<p>{{ 'data.types.origin.detail.MAINTAINER' | translate }}: {{ origin.name }}</p>
}
@if (origin.maintainer) {
<p>
{{ 'data.types.origin.detail.MAINTAINER' | translate }}:
<a [routerLink]="['/data-detail', origin.maintainer.uid]">{{ origin.maintainer.name }}</a>
</p>
}
</ion-card-content>
</ion-card>
<ion-card *ngIf="origin.type === 'remote'">
} @else if (origin.type === 'remote') {
<ion-card>
<ion-card-header
>{{ 'data.types.origin.TITLE' | translate | titlecase }}: {{ 'data.types.origin.REMOTE' | translate |
titlecase }}</ion-card-header
>{{ 'data.types.origin.TITLE' | translate | titlecase }}:
{{ 'data.types.origin.REMOTE' | translate | titlecase }}</ion-card-header
>
<ion-card-content>
<p>
{{ 'data.types.origin.detail.INDEXED' | translate | titlecase }}: {{ origin.indexed | amDateFormat :
'll' }}
{{ 'data.types.origin.detail.INDEXED' | translate | titlecase }}:
{{ origin.indexed | dfnsParseIso | dfnsFormat: 'PP' }}
</p>
<p *ngIf="origin.modified">
{{ 'data.types.origin.detail.MODIFIED' | translate | titlecase }}: {{ origin.modified | amDateFormat :
'll' }}
@if (origin.modified) {
<p>
{{ 'data.types.origin.detail.MODIFIED' | translate | titlecase }}:
{{ origin.modified | dfnsParseIso | dfnsFormat: 'PP' }}
</p>
<p *ngIf="origin.name">{{ 'data.types.origin.detail.MAINTAINER' | translate }}: {{ origin.name }}</p>
<p *ngIf="origin.maintainer">
}
@if (origin.name) {
<p>{{ 'data.types.origin.detail.MAINTAINER' | translate }}: {{ origin.name }}</p>
}
@if (origin.maintainer) {
<p>
{{ 'data.types.origin.detail.MAINTAINER' | translate | titlecase }}:
<a [routerLink]="['/data-detail', origin.maintainer.uid]">{{ origin.maintainer.name }}</a>
</p>
<p *ngIf="origin.responsibleEntity">
}
@if (origin.responsibleEntity) {
<p>
{{ 'data.types.origin.detail.RESPONSIBLE' | translate | titlecase }}:
<a [routerLink]="['/data-detail', origin.responsibleEntity.uid]">{{ origin.responsibleEntity.name }}</a>
<a [routerLink]="['/data-detail', origin.responsibleEntity.uid]">{{
origin.responsibleEntity.name
}}</a>
</p>
}
</ion-card-content>
</ion-card>
}
@@ -12,19 +12,17 @@
* 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} from '@angular/core';
import {SCThingOrigin} from '@openstapps/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCThingRemoteOrigin, SCThingUserOrigin} from '@openstapps/core';
import {ThingTranslateModule} from '../../../translation/thing-translate.module';
/**
* TODO
*/
@Component({
selector: 'stapps-origin-in-list',
templateUrl: 'origin-in-list.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [ThingTranslateModule],
})
export class OriginInListComponent {
/**
* TODO
*/
@Input() origin: SCThingOrigin;
@Input() origin: SCThingUserOrigin | SCThingRemoteOrigin;
}
@@ -1,7 +1,7 @@
<div *ngIf="origin.type === 'user'">
<p>{{ origin.created | dateFormat }}</p>
</div>
<div *ngIf="origin.type === 'remote'">
<p>{{ origin.indexed | dateFormat }}</p>
</div>
<p>
@if (origin.type === 'user') {
{{ origin.created | dateFormat }}
} @else if (origin.type === 'remote') {
{{ origin.indexed | dateFormat }}
}
</p>
@@ -51,7 +51,10 @@ export class StappsRatingComponent {
this.dish.next(value);
}
constructor(readonly elementRef: ElementRef, readonly ratingProvider: RatingProvider) {}
constructor(
readonly elementRef: ElementRef,
readonly ratingProvider: RatingProvider,
) {}
@HostListener('document:mousedown', ['$event'])
clickOutside(event: MouseEvent) {
@@ -12,49 +12,33 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCThingWithoutReferences} from '@openstapps/core';
import {IonCard, IonCardContent, IonCardHeader} from '@ionic/angular/standalone';
import {MarkdownComponent} from 'ngx-markdown';
import {RouterLink} from '@angular/router';
import {ThingTranslateModule} from '../../../translation/thing-translate.module';
/**
* TODO
*/
@Component({
selector: 'stapps-simple-card',
templateUrl: 'simple-card.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [IonCard, IonCardHeader, IonCardContent, MarkdownComponent, RouterLink, ThingTranslateModule],
})
export class SimpleCardComponent {
/**
* TODO
*/
areThings = false;
/**
* TODO
*/
@Input() content: string | string[] | SCThingWithoutReferences[];
/**
* TODO
*/
@Input() isMarkdown = false;
/**
* TODO
*/
@Input() title: string;
/**
* TODO
*/
// eslint-disable-next-line class-methods-use-this
isString(data: unknown): data is string {
return typeof data === 'string';
}
/**
* TODO
*/
// eslint-disable-next-line class-methods-use-this
isThing(something: unknown): something is SCThingWithoutReferences {
// bypass the 'type' field check because of translated values
return typeof something === 'object';
@@ -16,25 +16,25 @@
<ion-card>
<ion-card-header>{{ title }}</ion-card-header>
<ion-card-content>
<ng-container *ngIf="isString(content); then text; else list"> </ng-container>
<ng-template #text>
<ng-container *ngIf="isMarkdown; else plainText">
@if (isString(content)) {
@if (isMarkdown) {
<markdown [data]="content"></markdown>
</ng-container>
<ng-template #plainText>
} @else {
<p>{{ content }}</p>
</ng-template>
</ng-template>
<ng-template #list>
<ng-container *ngIf="isThing(content[0]); then thingList; else textList"> </ng-container>
<ng-template #thingList>
<a [routerLink]="['/data-detail', thing.uid]" *ngFor="let thing of content">
}
} @else {
@if (isThing(content[0])) {
@for (thing of content; track thing) {
<a [routerLink]="['/data-detail', thing.uid]">
<p>{{ 'name' | thingTranslate: thing }}</p>
</a>
</ng-template>
<ng-template #textList>
<p *ngFor="let text of content">{{ text }}</p>
</ng-template>
</ng-template>
}
}
}
@else {
@for (text of content; track text) {
<p>{{ text }}</p>
}
}
</ion-card-content>
</ion-card>
@@ -12,7 +12,16 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {
IonCol,
IonGrid,
IonItem,
IonNote,
IonRow,
IonSkeletonText,
IonThumbnail,
} from '@ionic/angular/standalone';
/**
* A placeholder to show when a list item is being loaded
@@ -20,7 +29,9 @@ import {Component, Input} from '@angular/core';
@Component({
selector: 'stapps-skeleton-list-item',
templateUrl: 'skeleton-list-item.html',
styleUrls: ['skeleton-list-item.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [IonItem, IonThumbnail, IonSkeletonText, IonGrid, IonRow, IonCol, IonNote],
})
export class SkeletonListItemComponent {
@Input() hideThumbnail = false;
@@ -1,18 +1,20 @@
<ion-item>
<ion-thumbnail *ngIf="!hideThumbnail" slot="start" class="ion-margin-end">
@if (!hideThumbnail) {
<ion-thumbnail slot="start" class="ion-margin-end">
<ion-skeleton-text animated></ion-skeleton-text>
</ion-thumbnail>
}
<ion-grid>
<ion-row>
<ion-col>
<h2 class="name">
<ion-skeleton-text animated style="width: 80%"></ion-skeleton-text>
<ion-skeleton-text animated [style.width.%]="80"></ion-skeleton-text>
</h2>
<p>
<ion-skeleton-text animated style="width: 80%"></ion-skeleton-text>
<ion-skeleton-text animated [style.width.%]="80"></ion-skeleton-text>
</p>
<ion-note>
<ion-skeleton-text animated style="width: 20%"></ion-skeleton-text>
<ion-skeleton-text animated [style.width.%]="80"></ion-skeleton-text>
</ion-note>
</ion-col>
</ion-row>
@@ -12,7 +12,8 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component} from '@angular/core';
import {IonSegmentButton, IonSkeletonText} from '@ionic/angular/standalone';
/**
* TODO
@@ -20,5 +21,8 @@ import {Component} from '@angular/core';
@Component({
selector: 'stapps-skeleton-segment-button',
templateUrl: 'skeleton-segment-button.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [IonSegmentButton, IonSkeletonText],
})
export class SkeletonSegmentComponent {}
@@ -1,3 +1,3 @@
<ion-segment-button>
<ion-skeleton-text animated style="width: 85%"></ion-skeleton-text>
<ion-skeleton-text animated [style.width.%]="85"></ion-skeleton-text>
</ion-segment-button>
@@ -12,7 +12,8 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {IonCard, IonCardContent, IonCardHeader, IonSkeletonText} from '@ionic/angular/standalone';
/**
* A placeholder to show when a simple card is being loaded
@@ -20,6 +21,9 @@ import {Component, Input} from '@angular/core';
@Component({
selector: 'stapps-skeleton-simple-card',
templateUrl: 'skeleton-simple-card.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [IonCard, IonCardHeader, IonSkeletonText, IonCardContent],
})
export class SkeletonSimpleCardComponent {
/**
@@ -1,14 +1,14 @@
<ion-card>
<ion-card-header *ngIf="title">
<ion-skeleton-text animated style="width: 15%"></ion-skeleton-text>
@if (title) {
<ion-card-header>
<ion-skeleton-text animated [style.width.%]="15"></ion-skeleton-text>
</ion-card-header>
}
<ion-card-content>
<p>
<ion-skeleton-text
*ngFor="let line of [].constructor(lines)"
animated
style="width: 85%"
></ion-skeleton-text>
@for (line of [].constructor(lines); track line) {
<ion-skeleton-text animated [style.width.%]="85"></ion-skeleton-text>
}
</p>
</ion-card-content>
</ion-card>
@@ -13,9 +13,28 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Component, ElementRef, HostListener, Input, OnChanges, OnInit, ViewChild} from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
ElementRef,
HostListener,
Input,
OnChanges,
OnInit,
ViewChild,
} from '@angular/core';
import {SCThings} from '@openstapps/core';
import {SCIcon} from '../../../util/ion-icon/icon';
import {
IonButton,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonIcon,
} from '@ionic/angular/standalone';
import {OpeningHoursComponent} from '../../../util/opening-hours.component';
import {ThingTranslateModule} from '../../../translation/thing-translate.module';
const AccordionButtonState = {
collapsed: SCIcon`expand_more`,
@@ -24,8 +43,20 @@ const AccordionButtonState = {
@Component({
selector: 'stapps-title-card',
templateUrl: './title-card.component.html',
styleUrls: ['./title-card.component.scss'],
templateUrl: 'title-card.html',
styleUrl: 'title-card.scss',
changeDetection: ChangeDetectionStrategy.Default,
standalone: true,
imports: [
IonCard,
IonCardHeader,
IonCardTitle,
IonCardContent,
OpeningHoursComponent,
IonButton,
IonIcon,
ThingTranslateModule,
],
})
export class TitleCardComponent implements OnInit, OnChanges {
/**
@@ -16,34 +16,35 @@
<ion-card-header>
<ion-card-title>
<h1>
<ng-container *ngIf="$any(item).honorificPrefix">{{
'honorificPrefix' | thingTranslate : item
}}</ng-container>
@if (item.honorificPrefix) {
{{ 'honorificPrefix' | thingTranslate: item }}
}
{{ 'name' | thingTranslate: item }}
<ng-container *ngIf="$any(item).honorificSuffix">{{
'honorificSuffix' | thingTranslate : item
}}</ng-container>
@if (item.honorificSuffix) {
{{ 'honorificSuffix' | thingTranslate: item }}
}
</h1>
</ion-card-title>
</ion-card-header>
<ion-card-content>
<div *ngIf="$any(item).openingHours" class="opening-hours">
@if (item.openingHours) {
<div class="opening-hours">
<stapps-opening-hours [openingHours]="item.openingHours"></stapps-opening-hours>
</div>
}
<!-- TODO obviously this is bad style. Tbd where to put the differentiation. Job Postings always have a description, but it's going to be shown in `stapps-job-posting-detail-content` anyways, no need to repeat here. For this view, I would use other fields of the schema.org JobPosting like the `ThingWithCategory.category` -->
<div *ngIf="item.description && item.type !== 'job posting'" class="description">
@if (item.description && item.type !== 'job posting') {
<div class="description">
<div class="text-accordion" [style.-webkit-line-clamp]="descriptionLinesToDisplay" #accordionTextArea>
{{ 'description' | thingTranslate: item }}
</div>
</div>
}
<!-- TODO see above -->
<ion-button
expand="full"
fill="clear"
*ngIf="item.description && item.type !== 'job posting' && buttonShown"
(click)="toggleDescriptionAccordion()"
>
@if (item.description && item.type !== 'job posting' && buttonShown) {
<ion-button expand="full" fill="clear" (click)="toggleDescriptionAccordion()">
<ion-icon [name]="buttonState" size="large"></ion-icon>
</ion-button>
}
</ion-card-content>
</ion-card>
@@ -53,7 +53,10 @@ export class SimpleDataListComponent implements OnInit {
destroy$ = inject(DestroyRef);
constructor(protected router: Router, private readonly dataRoutingService: DataRoutingService) {}
constructor(
protected router: Router,
private readonly dataRoutingService: DataRoutingService,
) {}
ngOnInit(): void {
if (!this.autoRouting) return;
@@ -22,9 +22,9 @@
></ng-container>
</ng-container>
</ion-list>
<ion-label class="empty-list-message" *ngIf="emptyListMessage && items.length === 0"
>{{ emptyListMessage }}</ion-label
>
<ion-label class="empty-list-message" *ngIf="emptyListMessage && items.length === 0">{{
emptyListMessage
}}</ion-label>
</ng-container>
<ng-template #loading>
<ion-list>
@@ -12,7 +12,7 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCArticle} from '@openstapps/core';
/**
@@ -21,6 +21,8 @@ import {SCArticle} from '@openstapps/core';
@Component({
selector: 'stapps-article-content',
templateUrl: 'article-content.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class ArticleContentComponent {
/**
@@ -64,8 +64,8 @@
<ion-card-header>{{ 'publications' | propertyNameTranslate: item | sentencecase }}</ion-card-header>
<ion-card-content>
<p *ngFor="let publication of item.publications">
{{ publication.locations | join : ', ' }} {{ publication.locations && publication.publisher ? ':' : ''
}} {{ publication.publisher }}
{{ publication.locations | join: ', ' }}
{{ publication.locations && publication.publisher ? ':' : '' }} {{ publication.publisher }}
</p>
</ion-card-content>
</ion-card>
@@ -12,9 +12,8 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCArticle} from '@openstapps/core';
import {DataListItemComponent} from '../../list/data-list-item.component';
/**
* TODO
@@ -22,8 +21,10 @@ import {DataListItemComponent} from '../../list/data-list-item.component';
@Component({
selector: 'stapps-article-item',
templateUrl: 'article-list-item.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class ArticleListItemComponent extends DataListItemComponent {
export class ArticleListItemComponent {
/**
* TODO
*/
@@ -18,15 +18,15 @@
<ion-col>
<h2 class="name">{{ 'name' | thingTranslate: item }}</h2>
<p>
<ng-container *ngFor="let author of item.authors">
{{ 'name' | thingTranslate : author }}</ng-container
<ng-container *ngFor="let author of item.authors"> {{ 'name' | thingTranslate: author }}</ng-container
><ng-container *ngIf="item.authors && item.authors && item.firstPublished">,&nbsp;</ng-container>
<ng-container *ngIf="item.firstPublished && !item.lastPublished; else dateRange"
>{{ item.firstPublished }}</ng-container
<ng-container *ngIf="item.firstPublished && !item.lastPublished; else dateRange">{{
item.firstPublished
}}</ng-container
><ng-template #dateRange
><ng-container *ngIf="item.firstPublished && item.lastPublished"
>{{ [item.firstPublished, item.lastPublished] | join : ' - ' }}</ng-container
></ng-template
><ng-container *ngIf="item.firstPublished && item.lastPublished">{{
[item.firstPublished, item.lastPublished] | join: ' - '
}}</ng-container></ng-template
>
</p>
<ion-note> {{ 'categories' | thingTranslate: item }} </ion-note>
@@ -12,7 +12,7 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCBook} from '@openstapps/core';
/**
@@ -21,6 +21,8 @@ import {SCBook} from '@openstapps/core';
@Component({
selector: 'stapps-book-detail-content',
templateUrl: 'book-detail-content.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class BookDetailContentComponent {
/**
@@ -75,8 +75,8 @@
<ion-card-header>{{ 'publications' | propertyNameTranslate: item | sentencecase }}</ion-card-header>
<ion-card-content>
<p *ngFor="let publication of item.publications">
{{ publication.locations | join : ', ' }} {{ publication.locations && publication.publisher ? ':' : ''
}} {{ publication.publisher }}
{{ publication.locations | join: ', ' }}
{{ publication.locations && publication.publisher ? ':' : '' }} {{ publication.publisher }}
</p>
</ion-card-content>
</ion-card>
@@ -12,9 +12,8 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCBook} from '@openstapps/core';
import {DataListItemComponent} from '../../list/data-list-item.component';
/**
* TODO
@@ -22,8 +21,10 @@ import {DataListItemComponent} from '../../list/data-list-item.component';
@Component({
selector: 'stapps-book-list-item',
templateUrl: 'book-list-item.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class BookListItemComponent extends DataListItemComponent {
export class BookListItemComponent {
/**
* TODO
*/
@@ -18,15 +18,15 @@
<ion-col>
<h2 class="name">{{ 'name' | thingTranslate: item }}</h2>
<p>
<ng-container *ngFor="let author of item.authors">
{{ 'name' | thingTranslate : author }}</ng-container
<ng-container *ngFor="let author of item.authors"> {{ 'name' | thingTranslate: author }}</ng-container
><ng-container *ngIf="item.authors && item.authors && item.firstPublished">,&nbsp;</ng-container>
<ng-container *ngIf="item.firstPublished && !item.lastPublished; else dateRange"
>{{ item.firstPublished }}</ng-container
<ng-container *ngIf="item.firstPublished && !item.lastPublished; else dateRange">{{
item.firstPublished
}}</ng-container
><ng-template #dateRange
><ng-container *ngIf="item.firstPublished && item.lastPublished"
>{{ [item.firstPublished, item.lastPublished] | join : ' - ' }}</ng-container
></ng-template
><ng-container *ngIf="item.firstPublished && item.lastPublished">{{
[item.firstPublished, item.lastPublished] | join: ' - '
}}</ng-container></ng-template
>
</p>
<ion-note> {{ 'categories' | thingTranslate: item }} </ion-note>
@@ -12,19 +12,18 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core';
import {SCCatalog, SCThings} from '@openstapps/core';
import {DataProvider} from '../../data.provider';
@Component({
selector: 'stapps-catalog-detail-content',
templateUrl: 'catalog-detail-content.html',
styleUrls: ['catalog-detail-content.scss'],
styleUrl: 'catalog-detail-content.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class CatalogDetailContentComponent implements OnInit {
/**
* SCCatalog to display
*/
@Input() item: SCCatalog;
items: Promise<SCThings[]>;
@@ -12,9 +12,11 @@
* 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} from '@angular/core';
import {ChangeDetectionStrategy, Component, Input} from '@angular/core';
import {SCCatalog} from '@openstapps/core';
import {DataListItemComponent} from '../../list/data-list-item.component';
import {IonCol, IonGrid, IonLabel, IonRow} from '@ionic/angular/standalone';
import {ThingTranslateModule} from '../../../../translation/thing-translate.module';
/**
* TODO
@@ -22,6 +24,9 @@ import {DataListItemComponent} from '../../list/data-list-item.component';
@Component({
selector: 'stapps-catalog-list-item',
templateUrl: 'catalog-list-item.html',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [IonGrid, IonRow, IonCol, IonLabel, ThingTranslateModule],
})
export class CatalogListItemComponent extends DataListItemComponent {
/**
@@ -3,7 +3,9 @@
<ion-col>
<div class="ion-text-wrap">
<ion-label class="title"> {{ 'name' | thingTranslate: item }}</ion-label>
<p *ngIf="item.academicTerm" class="title-sub">{{ item.academicTerm.name }}</p>
@if (item.academicTerm) {
<p class="title-sub">{{ item.academicTerm.name }}</p>
}
</div>
</ion-col>
</ion-row>
@@ -20,11 +20,32 @@ import {map} from 'rxjs/operators';
import {DataRoutingService} from '../../data-routing.service';
import {Router} from '@angular/router';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {AsyncPipe, TitleCasePipe} from '@angular/common';
import {IonCard, IonCardContent, IonCardHeader, IonChip, IonIcon, IonLabel} from '@ionic/angular/standalone';
import {TranslateModule} from '@ngx-translate/core';
import {ThingTranslateModule} from '../../../../translation/thing-translate.module';
import {MomentModule} from 'ngx-moment';
import {MapWidgetComponent} from '../../../map/widget/map-widget.component';
@Component({
selector: 'stapps-date-series-detail-content',
templateUrl: 'date-series-detail-content.html',
styleUrls: ['date-series-detail-content.scss'],
styleUrl: 'date-series-detail-content.scss',
standalone: true,
imports: [
AsyncPipe,
IonChip,
IonIcon,
IonLabel,
TranslateModule,
ThingTranslateModule,
TitleCasePipe,
MomentModule,
MapWidgetComponent,
IonCardHeader,
IonCardContent,
IonCard,
],
})
export class DateSeriesDetailContentComponent implements OnInit {
@Input() item: SCDateSeries;
@@ -57,10 +57,12 @@
<stapps-data-list-item [item]="$any(item.event)"></stapps-data-list-item>
</ion-card-content>
</ion-card>
<ion-card *ngIf="item.inPlace">
@if (item.inPlace) {
<ion-card>
<ion-card-header> {{ 'inPlace' | propertyNameTranslate: item | titlecase }} </ion-card-header>
<ion-card-content>
<stapps-data-list-item [item]="$any(item.inPlace)"></stapps-data-list-item>
</ion-card-content>
</ion-card>
}
<stapps-map-widget *ngIf="item.inPlace?.geo" [place]="item.inPlace"></stapps-map-widget>
@@ -22,17 +22,17 @@
<ion-icon name="calendar_today"></ion-icon>
<span *ngIf="item.dates[0] && item.dates[item.dates.length - 1]">
<span *ngIf="item.repeatFrequency">
{{ item.repeatFrequency | durationLocalized : true | sentencecase }}, {{ item.dates[0] |
dateFormat : 'weekday:long' }}
{{ item.repeatFrequency | durationLocalized: true | sentencecase }},
{{ item.dates[0] | dateFormat: 'weekday:long' }}
</span>
<span>
({{ item.dates[0] | dateFormat }} - {{ item.dates[item.dates.length - 1] | dateFormat }})
</span>
</span>
</p>
<ion-note *ngIf="item.event.type === 'academic event'"
>{{ 'categories' | thingTranslate : item.event | join : ', ' }}</ion-note
>
<ion-note *ngIf="item.event.type === 'academic event'">{{
'categories' | thingTranslate: item.event | join: ', '
}}</ion-note>
</div>
</ion-col>
<ion-col width-20 text-right>
@@ -39,9 +39,9 @@
[content]="item.majors"
></stapps-simple-card>
<ion-card *ngIf="item.catalogs">
<ion-card-header
>{{ $any('superCatalogs' | propertyNameTranslate : 'catalog') | titlecase }}</ion-card-header
>
<ion-card-header>{{
$any('superCatalogs' | propertyNameTranslate: 'catalog') | titlecase
}}</ion-card-header>
<ion-card-content>
<event-route-path
*ngFor="let item of item.catalogs"
@@ -20,9 +20,9 @@
[itemsBeforeCollapse]="itemsBeforeCollapse"
>
<ion-breadcrumb *ngFor="let item of items">
<ion-label class="crumb-label" *ngIf="item" [routerLink]="['/data-detail', item.uid]"
>{{ 'name' | thingTranslate : $any(item) }}</ion-label
>
<ion-label class="crumb-label" *ngIf="item" [routerLink]="['/data-detail', item.uid]">{{
'name' | thingTranslate: $any(item)
}}</ion-label>
</ion-breadcrumb>
</ion-breadcrumbs>
<ion-popover #popover>
@@ -62,8 +62,8 @@
<ion-card-header>{{ 'publications' | propertyNameTranslate: item | sentencecase }}</ion-card-header>
<ion-card-content>
<p *ngFor="let publication of item.publications">
{{ publication.locations | join : ', ' }} {{ publication.locations && publication.publisher ? ':' : ''
}} {{ publication.publisher }}
{{ publication.locations | join: ', ' }}
{{ publication.locations && publication.publisher ? ':' : '' }} {{ publication.publisher }}
</p>
</ion-card-content>
</ion-card>
@@ -18,15 +18,15 @@
<ion-col>
<h2 class="name">{{ 'name' | thingTranslate: item }}</h2>
<p>
<ng-container *ngFor="let author of item.authors">
{{ 'name' | thingTranslate : author }}</ng-container
<ng-container *ngFor="let author of item.authors"> {{ 'name' | thingTranslate: author }}</ng-container
><ng-container *ngIf="item.authors && item.authors && item.firstPublished">,&nbsp;</ng-container>
<ng-container *ngIf="item.firstPublished && !item.lastPublished; else dateRange"
>{{ item.firstPublished }}</ng-container
<ng-container *ngIf="item.firstPublished && !item.lastPublished; else dateRange">{{
item.firstPublished
}}</ng-container
><ng-template #dateRange
><ng-container *ngIf="item.firstPublished && item.lastPublished"
>{{ [item.firstPublished, item.lastPublished] | join : ' - ' }}</ng-container
></ng-template
><ng-container *ngIf="item.firstPublished && item.lastPublished">{{
[item.firstPublished, item.lastPublished] | join: ' - '
}}</ng-container></ng-template
>
</p>
<ion-note> {{ 'categories' | thingTranslate: item }} </ion-note>
@@ -26,7 +26,10 @@ import {SettingsProvider} from '../../../../../settings/settings.provider';
providedIn: 'root',
})
export class PlaceMensaService {
constructor(private dataProvider: DataProvider, readonly settingsProvider: SettingsProvider) {}
constructor(
private dataProvider: DataProvider,
readonly settingsProvider: SettingsProvider,
) {}
/**
* Fetches all dishes for this building
@@ -39,10 +42,13 @@ export class PlaceMensaService {
Array.from({length: days})
.map((_, i) => i)
.map(i => moment().add(i, 'days').toISOString())
.reduce((accumulator, item) => {
.reduce(
(accumulator, item) => {
accumulator[item] = item;
return accumulator;
}, {} as Record<SCISO8601Date, SCISO8601Date>),
},
{} as Record<SCISO8601Date, SCISO8601Date>,
),
date => ({
filter: {
arguments: {
@@ -18,12 +18,12 @@
<ng-container *ngIf="(dishes | json) !== '{}'; else empty">
<ion-segment [(ngModel)]="selectedDay" mode="md">
<ion-segment-button *ngFor="let day of dishes | keyvalue" [value]="day.key">
<ion-label class="ion-hide-sm-down"
>{{ day.key | dateFormat : 'weekday:long,month:numeric,day:numeric' }}</ion-label
>
<ion-label class="ion-hide-sm-up"
>{{ day.key | dateFormat : 'weekday:short,month:numeric,day:numeric' }}</ion-label
>
<ion-label class="ion-hide-sm-down">{{
day.key | dateFormat: 'weekday:long,month:numeric,day:numeric'
}}</ion-label>
<ion-label class="ion-hide-sm-up">{{
day.key | dateFormat: 'weekday:short,month:numeric,day:numeric'
}}</ion-label>
</ion-segment-button>
</ion-segment>
<ng-container [ngSwitch]="selectedDay">
@@ -33,8 +33,10 @@
<ng-container *ngFor="let section of date.value | keyvalue">
<ion-list-header *ngIf="section.value[0].menuSection" lines="inset">
<ion-label class="title">
{{ 'data.types.dish.detail.' + section.value[0].menuSection.name | translate | titlecase
}} {{ section.value[0].menuSection.servingHours }}
{{
'data.types.dish.detail.' + section.value[0].menuSection.name | translate | titlecase
}}
{{ section.value[0].menuSection.servingHours }}
</ion-label>
</ion-list-header>
<ng-container *ngFor="let dish of section.value; index as j">
@@ -20,7 +20,5 @@
' - ' +
('eventsEndDate' | propertyNameTranslate: item | titlecase)
"
[content]="
(item.eventsStartDate | amDateFormat : 'll') + ' - ' + (item.eventsEndDate | amDateFormat : 'll')
"
[content]="(item.eventsStartDate | amDateFormat: 'll') + ' - ' + (item.eventsEndDate | amDateFormat: 'll')"
></stapps-simple-card>
@@ -10,8 +10,8 @@
></stapps-long-inline-text>
</p>
<p *ngIf="item.duration">
{{ 'duration' | propertyNameTranslate : item | titlecase }}: {{ item.duration | amDuration :
'seconds' }}
{{ 'duration' | propertyNameTranslate: item | titlecase }}:
{{ item.duration | amDuration: 'seconds' }}
</p>
<ion-note>{{ 'type' | thingTranslate: item }}</ion-note>
</div>
@@ -44,12 +44,12 @@
interface="popover"
required="true"
>
<ion-select-option value="Comment"
>{{ 'feedback.form.type.values.comment' | translate }}</ion-select-option
>
<ion-select-option value="Bug"
>{{ 'feedback.form.type.values.bug' | translate }}</ion-select-option
>
<ion-select-option value="Comment">{{
'feedback.form.type.values.comment' | translate
}}</ion-select-option>
<ion-select-option value="Bug">{{
'feedback.form.type.values.bug' | translate
}}</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
@@ -91,9 +91,9 @@
</ion-item>
<ion-item lines="none">
<ion-label
><a style="display: contents" [routerLink]="['/about/privacy']"
>{{ 'feedback.form.termsAgree.1' | translate }}</a
></ion-label
><a style="display: contents" [routerLink]="['/about/privacy']">{{
'feedback.form.termsAgree.1' | translate
}}</a></ion-label
>
</ion-item>
<ion-item>
@@ -110,9 +110,9 @@
<ion-card>
<ion-card-title>
<ion-button expand="block" fill="clear" (click)="toggleShowMetaData()">
<ng-container *ngIf="!showMetaData; else hide"
>{{ 'feedback.form.protocolData.show' | translate }}</ng-container
>
<ng-container *ngIf="!showMetaData; else hide">{{
'feedback.form.protocolData.show' | translate
}}</ng-container>
<ng-template #hide>{{ 'feedback.form.protocolData.hide' | translate }}</ng-template>
</ion-button>
</ion-card-title>
@@ -24,26 +24,26 @@
<ion-content>
<p *ngIf="name; else loading">
{{ 'library.account.greeting' | translate }} {{ name | firstLastName }}! {{
'library.account.login.success' | translate }}
{{ 'library.account.greeting' | translate }} {{ name | firstLastName }}!
{{ 'library.account.login.success' | translate }}
</p>
<ng-template #loading>
<p><ion-skeleton-text animated style="width: 80%"></ion-skeleton-text></p>
</ng-template>
<ion-item [routerLink]="['profile']">
<ion-icon name="account_circle" slot="start"></ion-icon>{{ 'library.account.pages.profile.title' |
translate | titlecase }}
<ion-icon name="account_circle" slot="start"></ion-icon
>{{ 'library.account.pages.profile.title' | translate | titlecase }}
</ion-item>
<ion-item [routerLink]="['holds']">
<ion-icon name="collections_bookmark" slot="start"></ion-icon>{{ 'library.account.pages.holds.title' |
translate | titlecase }}
<ion-icon name="collections_bookmark" slot="start"></ion-icon
>{{ 'library.account.pages.holds.title' | translate | titlecase }}
</ion-item>
<ion-item [routerLink]="['checked-out']">
<ion-icon name="book" slot="start"></ion-icon>{{ 'library.account.pages.checked_out.title' | translate |
titlecase }}
<ion-icon name="book" slot="start"></ion-icon
>{{ 'library.account.pages.checked_out.title' | translate | titlecase }}
</ion-item>
<ion-item [routerLink]="['fines']">
<ion-icon name="request_quote" slot="start"></ion-icon>{{ 'library.account.pages.fines.title' | translate
| titlecase }}
<ion-icon name="request_quote" slot="start"></ion-icon
>{{ 'library.account.pages.fines.title' | translate | titlecase }}
</ion-item>
</ion-content>
@@ -37,8 +37,9 @@
{{ 'library.account.pages.profile.values.unlimited' | translate }}
</ng-container>
<ng-template #exactDate>
{{ 'library.account.pages.profile.values.expires' | translate }}:&nbsp;{{ patron[property] |
amDateFormat : 'll' }}
{{ 'library.account.pages.profile.values.expires' | translate }}:&nbsp;{{
patron[property] | amDateFormat: 'll'
}}
</ng-template>
</ng-template>
</ion-col>
@@ -56,7 +56,9 @@
<div>
<ion-list-header class="h3">
<ion-label>
<span *ngIf="facet.info.onlyOnType"><b>{{ facet.info.onlyOnType | titlecase }}</b> / </span>
<span *ngIf="facet.info.onlyOnType"
><b>{{ facet.info.onlyOnType | titlecase }}</b> /
</span>
{{ facet.info.field | titlecase }}
</ion-label>
</ion-list-header>
@@ -78,9 +80,12 @@
}"
class="filter-item-label"
>
({{ bucket.count }}) {{ facet.field === 'type' ? (getTranslatedPropertyValue($any(bucket.key),
'type') | titlecase) : (getTranslatedPropertyValue(facet.onlyOnType, facet.field, bucket.key)
| titlecase) }}
({{ bucket.count }})
{{
facet.field === 'type'
? (getTranslatedPropertyValue($any(bucket.key), 'type') | titlecase)
: (getTranslatedPropertyValue(facet.onlyOnType, facet.field, bucket.key) | titlecase)
}}
</ion-checkbox>
</ion-item>
<ion-button
@@ -38,7 +38,8 @@
<ion-icon slot="end" [name]="category.icon"></ion-icon>
<ion-label> {{ category.translations[language].title | titlecase }} </ion-label>
</ion-item>
} @for (item of category.items; track item) {
}
@for (item of category.items; track item) {
<ion-item [rootLink]="item.route" [redirectedFrom]="item.route">
<ion-icon slot="end" [name]="item.icon"></ion-icon>
<ion-label> {{ item.translations[language].title | titlecase }} </ion-label>
@@ -22,7 +22,10 @@ import {NGXLogger} from 'ngx-logger';
providedIn: 'root',
})
export class NavigationService {
constructor(private configProvider: ConfigProvider, private logger: NGXLogger) {}
constructor(
private configProvider: ConfigProvider,
private logger: NGXLogger,
) {}
async getMenu() {
let menu: SCAppConfigurationMenuCategory[] = [];
@@ -37,7 +37,10 @@ import {SettingsProvider} from '../settings/settings.provider';
providedIn: 'root',
})
export class NewsProvider {
constructor(private dataProvider: DataProvider, private settingsProvider: SettingsProvider) {}
constructor(
private dataProvider: DataProvider,
private settingsProvider: SettingsProvider,
) {}
async getCurrentSettings(): Promise<SCSetting[]> {
const settings: SCSetting[] = [];
@@ -45,11 +45,16 @@
</ion-row>
</ion-grid>
<div class="news-grid">
@if (!news) { @for (skeleton of [1, 2, 3, 4, 5]; track skeleton) {
@if (!news) {
@for (skeleton of [1, 2, 3, 4, 5]; track skeleton) {
<stapps-skeleton-news-item></stapps-skeleton-news-item>
} } @if (news.length > 0) { @for (item of news; track item) {
}
}
@if (news.length > 0) {
@for (item of news; track item) {
<stapps-news-item [item]="item"></stapps-news-item>
} }
}
}
</div>
@if (news.length === 0) {
<ion-label class="centered-message-container">
@@ -21,9 +21,12 @@
<ion-item slot="header">
<!-- TODO: when using date-fns, use https://date-fns.org/v2.30.0/docs/formatRelative -->
<ion-label
>{{ myCoursesDay[0] | amDateFormat: 'dddd, ll' }} - {{ ('profile.courses.' + (myCoursesDay[1].length
=== 0 ? 'NO' : myCoursesDay[1].length === 1 ? 'ONE' : 'MANY' ) + '_EVENT') | translate: {count:
myCoursesDay[1].length} }}</ion-label
>{{ myCoursesDay[0] | amDateFormat: 'dddd, ll' }} -
{{
'profile.courses.' +
(myCoursesDay[1].length === 0 ? 'NO' : myCoursesDay[1].length === 1 ? 'ONE' : 'MANY') +
'_EVENT' | translate: {count: myCoursesDay[1].length}
}}</ion-label
>
<ion-icon class="ion-accordion-toggle-icon" name="expand_more"></ion-icon>
</ion-item>
@@ -34,8 +37,8 @@
<ng-container *ngFor="let myCourse of myCoursesDay[1]">
<ion-item-group>
<ion-item-divider
>{{myCourse.startTime | amDateFormat: 'LT'}} - {{myCourse.endTime | amDateFormat:
'LT'}}</ion-item-divider
>{{ myCourse.startTime | amDateFormat: 'LT' }} -
{{ myCourse.endTime | amDateFormat: 'LT' }}</ion-item-divider
>
<stapps-data-list-item
[listItemChipInteraction]="false"
@@ -25,14 +25,15 @@
>
<ion-card-header mode="md">
<ion-card-title>
{{ this.scheduleEvent?.dateSeries?.event?.name | nullishCoalesce : this.scheduleEvent?.dateSeries?.name
{{
this.scheduleEvent?.dateSeries?.event?.name | nullishCoalesce: this.scheduleEvent?.dateSeries?.name
}}
</ion-card-title>
</ion-card-header>
<ion-card-content>
<ion-note> {{ getNote() }} </ion-note>
<ion-text *ngIf="showPlaceName" class="place-name"
>{{ scheduleEvent?.dateSeries?.inPlace?.name }}</ion-text
>
<ion-text *ngIf="showPlaceName" class="place-name">{{
scheduleEvent?.dateSeries?.inPlace?.name
}}</ion-text>
</ion-card-content>
</ion-card>
@@ -46,7 +46,9 @@ describe('ScheduleSingleEvents', () => {
start: time.hour() + time.minute() / 60,
startAsString: moment(time).format('LT'),
duration: series.duration as string,
endAsString: moment(time).add(series.duration?.[index]).format('LT'),
endAsString: moment(time)
.add(series.duration?.[index])
.format('LT'),
},
},
};
@@ -197,7 +197,10 @@ export class SettingsProvider {
* @param storage TODO
* @param configProvider TODO
*/
constructor(private readonly storage: StorageProvider, private readonly configProvider: ConfigProvider) {
constructor(
private readonly storage: StorageProvider,
private readonly configProvider: ConfigProvider,
) {
this.categoriesOrder = [];
this.settingsCache = {};
}
@@ -330,9 +333,8 @@ export class SettingsProvider {
if (await this.storage.has(STORAGE_KEY_SETTING_VALUES)) {
// get setting values from StorageProvider into settingsCache
const valuesContainer: SettingValuesContainer = await this.storage.get<SettingValuesContainer>(
STORAGE_KEY_SETTING_VALUES,
);
const valuesContainer: SettingValuesContainer =
await this.storage.get<SettingValuesContainer>(STORAGE_KEY_SETTING_VALUES);
// iterate through keys of categories
for (const categoryKey of Object.keys(this.settingsCache)) {
// iterate through setting keys of category
@@ -384,9 +386,8 @@ export class SettingsProvider {
*/
public async saveSettingValues(): Promise<void> {
if (await this.storage.has(STORAGE_KEY_SETTING_VALUES)) {
const savedSettingsValues: SettingValuesContainer = await this.storage.get<SettingValuesContainer>(
STORAGE_KEY_SETTING_VALUES,
);
const savedSettingsValues: SettingValuesContainer =
await this.storage.get<SettingValuesContainer>(STORAGE_KEY_SETTING_VALUES);
const cacheSettingsValues = this.getSettingValuesFromCache();
const mergedSettingValues = deepMerge(savedSettingsValues, cacheSettingsValues);
await this.storage.put<SettingValuesContainer>(STORAGE_KEY_SETTING_VALUES, mergedSettingValues);
@@ -1,34 +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 {Injectable, Pipe, PipeTransform} from '@angular/core';
/**
* Get the last value of an array
*/
@Injectable()
@Pipe({
name: 'last',
pure: true,
})
export class ArrayLastPipe implements PipeTransform {
/**
* Transform
*/
// tslint:disable-next-line:prefer-function-over-method
transform<T>(value: T[]): T | undefined {
return value.at(-1);
}
}
@@ -1,27 +0,0 @@
/*
* Copyright (C) 2021 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 {Pipe, PipeTransform} from '@angular/core';
import {Moment} from 'moment';
@Pipe({
name: 'dateFromIndex',
pure: true,
})
export class DateFromIndexPipe implements PipeTransform {
transform(index: number, baseline: Moment): Moment {
return baseline.clone().add(index, 'days');
}
}
@@ -1,38 +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 {Injectable, Pipe, PipeTransform} from '@angular/core';
import moment, {Moment, unitOfTime} from 'moment';
/**
* Get the last value of an array
*/
@Injectable()
@Pipe({
name: 'dateIsThis',
pure: false, // pure pipe can break in some change detection scenarios,
// specifically, on the calendar view it causes it to stay true even when you navigate
})
export class DateIsThisPipe implements PipeTransform {
/**
* Transform
*/
// tslint:disable-next-line:prefer-function-over-method
transform(value: Moment | string | number, granularity: unitOfTime.StartOf): boolean {
return (
typeof value === 'string' ? moment(value) : typeof value === 'number' ? moment.unix(value) : value
).isSame(moment(moment.now()), granularity);
}
}
@@ -22,6 +22,7 @@ import moment from 'moment';
@Injectable()
@Pipe({
name: 'daytimeKey',
standalone: true,
})
export class DaytimeKeyPipe implements PipeTransform {
/**
@@ -28,6 +28,7 @@ import {TranslatePipe} from '@ngx-translate/core';
@Component({
selector: 'stapps-edit-modal',
templateUrl: 'edit-modal.html',
standalone: true,
})
export class EditModalComponent {
@ContentChild(TemplateRef) content: TemplateRef<unknown>;
@@ -48,7 +49,7 @@ export class EditModalComponent {
) {}
present() {
this.modal.present();
void this.modal.present();
this.pendingChanges = false;
}
+3 -3
View File
@@ -19,9 +19,9 @@
<ion-toolbar>
<ion-title>{{ 'modal.TITLE_EDIT' | translate }}</ion-title>
<ion-buttons slot="end">
<ion-button (click)="save.emit(); dismiss(true)"
>{{ 'modal.DISMISS_CONFIRM' | translate }}</ion-button
>
<ion-button (click)="save.emit(); dismiss(true)">{{
'modal.DISMISS_CONFIRM' | translate
}}</ion-button>
</ion-buttons>
<ion-buttons slot="start">
<ion-button (click)="dismiss(true)">{{ 'modal.DISMISS_CANCEL' | translate }}</ion-button>
@@ -17,6 +17,7 @@ import {Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output} f
@Directive({
selector: '[elementSizeChange]',
standalone: true,
})
export class ElementSizeChangeDirective implements OnInit, OnDestroy {
@Output()
@@ -101,7 +101,10 @@ export class InternetConnectionService {
private readonly errors = new Set<unknown>();
constructor(private readonly logger: NGXLogger, private readonly router: Router) {}
constructor(
private readonly logger: NGXLogger,
private readonly router: Router,
) {}
/**
* Retry all failed http requests
@@ -73,6 +73,7 @@ type IonicColor =
*/
@Directive({
selector: 'ion-content[parallax]',
standalone: true,
})
export class IonContentParallaxDirective implements OnInit, OnDestroy {
@HostBinding('style.--parallax-content-size.px') @Input() parallaxSize = 230;
+4 -1
View File
@@ -22,7 +22,10 @@
height: 100%;
font-size: inherit;
font-variation-settings: 'wght' var(--weight), 'GRAD' var(--grade), 'FILL' var(--fill);
font-variation-settings:
'wght' var(--weight),
'GRAD' var(--grade),
'FILL' var(--fill);
transition: all 0.2s ease-in-out;
}
+1
View File
@@ -21,6 +21,7 @@ import {get} from '@openstapps/collection-utils';
@Pipe({
name: 'lazyThing',
pure: true,
standalone: true,
})
export class LazyPipe implements PipeTransform {
constructor(private readonly dataProvider: DataProvider) {}
@@ -13,29 +13,16 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Injectable, Pipe, PipeTransform} from '@angular/core';
import moment from 'moment';
import {Pipe, PipeTransform} from '@angular/core';
/**
* Get the last value of an array
*/
@Injectable()
@Pipe({
name: 'nextDateInList',
pure: false, // pure pipe can break in some change detection scenarios,
// specifically, on the calendar view it causes it to stay true even when you navigate
pure: true,
standalone: true,
})
export class NextDateInListPipe implements PipeTransform {
/**
* Transform
*/
// tslint:disable-next-line:prefer-function-over-method
transform(dates: string[]): string {
const nextDate = dates
.sort((a, b) => moment(a).unix() - moment(b).unix())
.find(date => {
return moment(date).unix() > moment().unix();
});
return nextDate || '';
// ISO8601 can be sorted alphabetically
return [...dates].sort()[0] || '';
}
}
@@ -22,6 +22,7 @@ import {Injectable, Pipe, PipeTransform} from '@angular/core';
@Pipe({
name: 'nullishCoalesce',
pure: true,
standalone: true,
})
export class NullishCoalescingPipe implements PipeTransform {
/**
@@ -20,8 +20,9 @@ import {map, startWith} from 'rxjs/operators';
@Component({
selector: 'stapps-opening-hours',
templateUrl: 'opening-hours.html',
styleUrls: ['opening-hours.scss'],
styleUrl: 'opening-hours.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class OpeningHoursComponent {
@ContentChild(TemplateRef) content: TemplateRef<unknown>;
+15 -5
View File
@@ -18,15 +18,25 @@
{{ openingHours.statusName | translate }}
</ion-badge>
<ng-template #blank>{{ openingHours.statusName | translate }}</ng-template>
<ng-container *ngIf="openingHours.statusText; else nextChange"> {{openingHours.statusText}} </ng-container>
<ng-container *ngIf="openingHours.statusText; else nextChange">
{{ openingHours.statusText }}
</ng-container>
<ng-template #nextChange>
<ng-container *ngIf="showNextChange && openingHours.nextChangeSoon">
{{ ('common.openingHours.' + openingHours.nextChangeAction + '_soon') | translate: {duration:
(openingHours.nextChangeSoon | async | dfnsFormatDistanceToNowStrict: {unit: 'minute'})} }}
{{
'common.openingHours.' + openingHours.nextChangeAction + '_soon'
| translate
: {
duration:
(openingHours.nextChangeSoon | async | dfnsFormatDistanceToNowStrict: ({unit: 'minute'}))
}
}}
</ng-container>
<ng-container *ngIf="showNextChange && !openingHours.nextChangeSoon">
{{ ('common.openingHours.' + openingHours.nextChangeAction) | translate: {date: openingHours.nextChange
| dfnsFormatRelativeToNow} }}
{{
'common.openingHours.' + openingHours.nextChangeAction
| translate: {date: openingHours.nextChange | dfnsFormatRelativeToNow}
}}
</ng-container>
</ng-template>
</div>
@@ -18,6 +18,7 @@ import {IonSearchbar} from '@ionic/angular/standalone';
@Directive({
selector: 'ion-searchbar[autofocus]',
standalone: true,
})
export class SearchbarAutofocusDirective implements AfterViewInit {
@Input() autofocus = true;
@@ -17,7 +17,8 @@ import {ChangeDetectionStrategy, Component} from '@angular/core';
@Component({
selector: 'simple-swiper',
templateUrl: 'simple-swiper.html',
styleUrls: ['simple-swiper.scss'],
styleUrl: 'simple-swiper.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
})
export class SimpleSwiperComponent {}
-82
View File
@@ -1,82 +0,0 @@
/*
* 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 {NgModule} from '@angular/core';
import {ArrayLastPipe} from './array-last.pipe';
import {DateIsThisPipe} from './date-is-today.pipe';
import {NullishCoalescingPipe} from './nullish-coalecing.pipe';
import {DateFromIndexPipe} from './date-from-index.pipe';
import {DaytimeKeyPipe} from './daytime-key.pipe';
import {LazyPipe} from './lazy.pipe';
import {NextDateInListPipe} from './next-date-in-list.pipe';
import {EditModalComponent} from './edit-modal.component';
import {BrowserModule} from '@angular/platform-browser';
import {TranslateModule} from '@ngx-translate/core';
import {ElementSizeChangeDirective} from './element-size-change.directive';
import {OpeningHoursComponent} from './opening-hours.component';
import {ThingTranslateModule} from '../translation/thing-translate.module';
import {SimpleSwiperComponent} from './simple-swiper.component';
import {SearchbarAutofocusDirective} from './searchbar-autofocus.directive';
import {RouterModule} from '@angular/router';
import {IonContentParallaxDirective} from './ion-content-parallax.directive';
import {FormatDistanceToNowStrictPipeModule, FormatRelativeToNowPipeModule} from 'ngx-date-fns';
import {IonButton, IonButtons, IonHeader, IonModal, IonTitle, IonToolbar} from '@ionic/angular/standalone';
@NgModule({
imports: [
BrowserModule,
TranslateModule,
ThingTranslateModule.forChild(),
RouterModule,
FormatRelativeToNowPipeModule,
FormatDistanceToNowStrictPipeModule,
IonModal,
IonHeader,
IonToolbar,
IonTitle,
IonButtons,
IonButton,
],
declarations: [
IonContentParallaxDirective,
ElementSizeChangeDirective,
ArrayLastPipe,
DateIsThisPipe,
NullishCoalescingPipe,
LazyPipe,
DateFromIndexPipe,
DaytimeKeyPipe,
NextDateInListPipe,
EditModalComponent,
OpeningHoursComponent,
SimpleSwiperComponent,
SearchbarAutofocusDirective,
],
exports: [
IonContentParallaxDirective,
ElementSizeChangeDirective,
ArrayLastPipe,
DateIsThisPipe,
NullishCoalescingPipe,
LazyPipe,
DateFromIndexPipe,
DaytimeKeyPipe,
NextDateInListPipe,
EditModalComponent,
OpeningHoursComponent,
SimpleSwiperComponent,
SearchbarAutofocusDirective,
],
})
export class UtilModule {}
+1 -1
View File
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
+3 -1
View File
@@ -27,7 +27,9 @@
border-radius: var(--border-radius-default);
box-shadow: var(--shadow-cards);
transition: transform 250ms ease-in-out, box-shadow 250ms ease-in-out;
transition:
transform 250ms ease-in-out,
box-shadow 250ms ease-in-out;
}
@media (hover: hover) {
+70 -70
View File
@@ -217,7 +217,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -234,8 +234,8 @@ importers:
specifier: 1.3.5
version: 1.3.5
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
sinon:
specifier: 15.0.4
version: 15.0.4
@@ -332,7 +332,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -346,8 +346,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -458,7 +458,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -472,8 +472,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -573,7 +573,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -584,8 +584,8 @@ importers:
specifier: 2.2.0
version: 2.2.0(mocha@10.2.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
sinon:
specifier: 15.0.4
version: 15.0.4
@@ -627,13 +627,13 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
configuration/eslint-config:
dependencies:
@@ -651,7 +651,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -672,8 +672,8 @@ importers:
configuration/prettier-config:
dependencies:
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
configuration/projectmanagement:
dependencies:
@@ -758,7 +758,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -769,8 +769,8 @@ importers:
specifier: 2.2.0
version: 2.2.0(mocha@10.2.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -848,7 +848,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -862,8 +862,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -935,13 +935,13 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
tsup:
specifier: 7.2.0
version: 7.2.0(ts-node@10.9.1)(typescript@5.2.2)
@@ -1260,7 +1260,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -1310,8 +1310,8 @@ importers:
specifier: 25.0.1
version: 25.0.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
stylelint:
specifier: 15.10.1
version: 15.10.1
@@ -1419,7 +1419,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -1430,8 +1430,8 @@ importers:
specifier: 2.2.0
version: 2.2.0(mocha@10.2.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
traverse:
specifier: 0.6.7
version: 0.6.7
@@ -1540,7 +1540,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -1554,8 +1554,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -1612,7 +1612,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -1623,8 +1623,8 @@ importers:
specifier: 2.2.0
version: 2.2.0(mocha@10.2.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -1721,7 +1721,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -1732,8 +1732,8 @@ importers:
specifier: 2.2.0
version: 2.2.0(mocha@10.2.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
source-map-support:
specifier: 0.5.21
version: 0.5.21
@@ -1818,7 +1818,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -1832,8 +1832,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -1900,7 +1900,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -1911,8 +1911,8 @@ importers:
specifier: 2.2.0
version: 2.2.0(mocha@10.2.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -1991,7 +1991,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -2005,8 +2005,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -2061,13 +2061,13 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -2149,7 +2149,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -2163,8 +2163,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -2243,7 +2243,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -2254,8 +2254,8 @@ importers:
specifier: 2.2.0
version: 2.2.0(mocha@10.2.0)
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
ts-node:
specifier: 10.9.1
version: 10.9.1(@types/node@18.15.3)(typescript@5.2.2)
@@ -2334,7 +2334,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -2348,8 +2348,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
typedoc:
specifier: 0.25.3
version: 0.25.3(typescript@5.2.2)
@@ -2422,7 +2422,7 @@ importers:
version: 46.8.2(eslint@8.53.0)
eslint-plugin-prettier:
specifier: 5.0.1
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3)
version: 5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0)
eslint-plugin-unicorn:
specifier: 49.0.0
version: 49.0.0(eslint@8.53.0)
@@ -2436,8 +2436,8 @@ importers:
specifier: 13.3.1
version: 13.3.1
prettier:
specifier: 3.0.3
version: 3.0.3
specifier: 3.1.0
version: 3.1.0
typedoc:
specifier: 0.25.3
version: 0.25.3(typescript@5.2.2)
@@ -11921,7 +11921,7 @@ packages:
transitivePeerDependencies:
- supports-color
/eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.0.3):
/eslint-plugin-prettier@5.0.1(eslint-config-prettier@9.0.0)(eslint@8.53.0)(prettier@3.1.0):
resolution: {integrity: sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==}
engines: {node: ^14.18.0 || >=16.0.0}
peerDependencies:
@@ -11937,7 +11937,7 @@ packages:
dependencies:
eslint: 8.53.0
eslint-config-prettier: 9.0.0(eslint@8.53.0)
prettier: 3.0.3
prettier: 3.1.0
prettier-linter-helpers: 1.0.0
synckit: 0.8.5
@@ -17235,8 +17235,8 @@ packages:
hasBin: true
dev: true
/prettier@3.0.3:
resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==}
/prettier@3.1.0:
resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==}
engines: {node: '>=14'}
hasBin: true