-
{{ 'name' | thingTranslate: item }}
+
{{ 'name' | thingTranslate: item }}
diff --git a/src/app/modules/data/types/dish/dish-list-item.html b/src/app/modules/data/types/dish/dish-list-item.html
index 5d5f5817..30e19772 100644
--- a/src/app/modules/data/types/dish/dish-list-item.html
+++ b/src/app/modules/data/types/dish/dish-list-item.html
@@ -2,8 +2,8 @@
-
{{ 'name' | thingTranslate: item }}
-
+ {{ 'name' | thingTranslate: item }}
+
{{ 'description' | thingTranslate: item }}
{{ 'categories' | thingTranslate: item | join: ', ' }}
diff --git a/src/app/modules/data/types/event/event-list-item.html b/src/app/modules/data/types/event/event-list-item.html
index 30b02e82..a1a66915 100644
--- a/src/app/modules/data/types/event/event-list-item.html
+++ b/src/app/modules/data/types/event/event-list-item.html
@@ -2,18 +2,22 @@
-
{{ item.name }}
-
{{ item.description }}
-
{{ item.academicTerms[0].name }}
+
{{ item.name }}
+
{{ item.description }}
+
+ {{ item.academicTerms[0].name }}
+
{{ item.type }} ({{ item.categories.join(', ') }})
- {{ item.name }}
- {{ item.description }}
- {{ item.academicTerms[0].name }}
+ {{ item.name }}
+ {{ item.description }}
+
+ {{ item.academicTerms[0].name }}
+
{{ item.type }}
diff --git a/src/app/modules/data/types/favorite/favorite-list-item.html b/src/app/modules/data/types/favorite/favorite-list-item.html
index 9e4f76bb..3b018797 100644
--- a/src/app/modules/data/types/favorite/favorite-list-item.html
+++ b/src/app/modules/data/types/favorite/favorite-list-item.html
@@ -2,11 +2,11 @@
-
+
{{ 'name' | thingTranslate: item }}:
{{ 'name' | thingTranslate: item.data }}
-
-
+
+
@@ -44,7 +47,7 @@
{{ item.name }}
+ >{{ item.name }}
diff --git a/src/app/modules/data/types/message/message-detail-content.scss b/src/app/modules/data/types/message/message-detail-content.scss
index aff5a181..13622255 100644
--- a/src/app/modules/data/types/message/message-detail-content.scss
+++ b/src/app/modules/data/types/message/message-detail-content.scss
@@ -36,4 +36,10 @@
margin: 0 auto;
}
}
+
+ .date-published {
+ --ion-card-color: var(--ion-color-medium-shade);
+ text-transform: uppercase;
+ font-weight: var(--font-weight-semi-bold);
+ }
}
diff --git a/src/app/modules/data/types/message/message-list-item.html b/src/app/modules/data/types/message/message-list-item.html
index 0132c6f1..27d43f43 100644
--- a/src/app/modules/data/types/message/message-list-item.html
+++ b/src/app/modules/data/types/message/message-list-item.html
@@ -2,7 +2,7 @@
-
{{ 'name' | thingTranslate: item }}
+
{{ 'name' | thingTranslate: item }}
-
{{ 'name' | thingTranslate: item }}
-
+ {{ 'name' | thingTranslate: item }}
+
{{ 'description' | thingTranslate: item }}
{{ 'type' | thingTranslate: item }}
diff --git a/src/app/modules/data/types/person/person-list-item.html b/src/app/modules/data/types/person/person-list-item.html
index 9578abf1..c6b68007 100644
--- a/src/app/modules/data/types/person/person-list-item.html
+++ b/src/app/modules/data/types/person/person-list-item.html
@@ -2,10 +2,10 @@
-
+
{{ 'name' | thingTranslate: item }}
, {{ item.honorificPrefix }}
-
+
{{
diff --git a/src/app/modules/data/types/place/place-detail-content.component.ts b/src/app/modules/data/types/place/place-detail-content.component.ts
index 6ffa1e62..324c2644 100644
--- a/src/app/modules/data/types/place/place-detail-content.component.ts
+++ b/src/app/modules/data/types/place/place-detail-content.component.ts
@@ -38,6 +38,8 @@ export class PlaceDetailContentComponent implements OnInit {
*/
@Input() item: SCBuilding | SCRoom | SCPointOfInterest | SCFloor;
+ @Input() openAsModal = false;
+
/**
* Does it have valid location or not (for showing in in a map widget)
*/
diff --git a/src/app/modules/data/types/place/place-detail-content.html b/src/app/modules/data/types/place/place-detail-content.html
index 0f676725..c8aa8255 100644
--- a/src/app/modules/data/types/place/place-detail-content.html
+++ b/src/app/modules/data/types/place/place-detail-content.html
@@ -1,5 +1,6 @@
diff --git a/src/app/modules/data/types/place/place-list-item.html b/src/app/modules/data/types/place/place-list-item.html
index d4146272..11a2cac3 100644
--- a/src/app/modules/data/types/place/place-list-item.html
+++ b/src/app/modules/data/types/place/place-list-item.html
@@ -2,12 +2,10 @@
-
{{ 'name' | thingTranslate: item }}
+
{{ 'name' | thingTranslate: item }}
-
-
- {{ item.openingHours | openingHours }}
-
+
+ {{ item.openingHours | openingHours }}
{
- void this.router.navigate(['data-detail', item.uid]);
- }),
- );
+ if (!this.openAsModal) {
+ this.subscriptions.push(
+ this.dataRoutingService.itemSelectListener().subscribe(item => {
+ void this.router.navigate(['/data-detail', item.uid]);
+ }),
+ );
+ }
}
/**
diff --git a/src/app/modules/data/types/place/special/mensa/place-mensa.html b/src/app/modules/data/types/place/special/mensa/place-mensa.html
index 600f417e..e03e70f7 100644
--- a/src/app/modules/data/types/place/special/mensa/place-mensa.html
+++ b/src/app/modules/data/types/place/special/mensa/place-mensa.html
@@ -16,10 +16,27 @@
diff --git a/src/app/modules/data/types/semester/semester-list-item.html b/src/app/modules/data/types/semester/semester-list-item.html
index 863a2d23..4390753a 100644
--- a/src/app/modules/data/types/semester/semester-list-item.html
+++ b/src/app/modules/data/types/semester/semester-list-item.html
@@ -2,8 +2,8 @@
-
{{ 'name' | thingTranslate: item }}
-
+ {{ 'name' | thingTranslate: item }}
+
{{ item.startDate | dateFormat }} -
diff --git a/src/app/modules/data/types/video/video-list-item.html b/src/app/modules/data/types/video/video-list-item.html
index 863a039c..abfe344e 100644
--- a/src/app/modules/data/types/video/video-list-item.html
+++ b/src/app/modules/data/types/video/video-list-item.html
@@ -2,8 +2,8 @@
-
{{ 'name' | thingTranslate: item }}
-
+ {{ 'name' | thingTranslate: item }}
+
-
+
-
-
+
{{ 'feedback.page.TITLE' | translate }}
diff --git a/src/app/modules/feedback/feedback.module.ts b/src/app/modules/feedback/feedback.module.ts
index 044accaf..5a39cf35 100644
--- a/src/app/modules/feedback/feedback.module.ts
+++ b/src/app/modules/feedback/feedback.module.ts
@@ -20,6 +20,7 @@ import {FeedbackPageComponent} from './feedback-page.component';
import {RouterModule, Routes} from '@angular/router';
import {TranslateModule} from '@ngx-translate/core';
import {MarkdownModule} from 'ngx-markdown';
+import {UtilModule} from '../../util/util.module';
const feedbackRoutes: Routes = [
{
@@ -36,6 +37,7 @@ const feedbackRoutes: Routes = [
RouterModule.forChild(feedbackRoutes),
TranslateModule,
MarkdownModule,
+ UtilModule,
],
declarations: [FeedbackPageComponent],
})
diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail-content.html b/src/app/modules/hebis/hebis-detail/hebis-detail-content.html
index 5d1287a1..14cb9475 100644
--- a/src/app/modules/hebis/hebis-detail/hebis-detail-content.html
+++ b/src/app/modules/hebis/hebis-detail/hebis-detail-content.html
@@ -14,7 +14,7 @@
-
+
diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail.html b/src/app/modules/hebis/hebis-detail/hebis-detail.html
index 75859e20..02e1f449 100644
--- a/src/app/modules/hebis/hebis-detail/hebis-detail.html
+++ b/src/app/modules/hebis/hebis-detail/hebis-detail.html
@@ -1,31 +1,48 @@
+
+
-
+
-
-
+
{{ 'data.detail.TITLE' | translate }}
-
-
-
+
+
+
{{ 'data.detail.COULD_NOT_CONNECT' | translate }}
-
-
+
+
{{ 'data.detail.NOT_FOUND' | translate }}
diff --git a/src/app/modules/hebis/hebis-routing.module.ts b/src/app/modules/hebis/hebis-routing.module.ts
index 338e7d47..48764484 100644
--- a/src/app/modules/hebis/hebis-routing.module.ts
+++ b/src/app/modules/hebis/hebis-routing.module.ts
@@ -19,6 +19,7 @@ import {HebisSearchPageComponent} from './list/hebis-search-page.component';
const hebisRoutes: Routes = [
{path: 'hebis-search', component: HebisSearchPageComponent},
+ {path: 'hebis-search/:term', component: HebisSearchPageComponent},
{path: 'hebis-detail/:uid', component: HebisDetailComponent},
];
diff --git a/src/app/modules/hebis/list/hebis-search-page.component.ts b/src/app/modules/hebis/list/hebis-search-page.component.ts
index 054d4e9b..ee2a7ca1 100644
--- a/src/app/modules/hebis/list/hebis-search-page.component.ts
+++ b/src/app/modules/hebis/list/hebis-search-page.component.ts
@@ -13,7 +13,7 @@
* this program. If not, see
.
*/
import {Component, Input, OnInit, OnDestroy} from '@angular/core';
-import {Router} from '@angular/router';
+import {ActivatedRoute, Router} from '@angular/router';
import {AlertController} from '@ionic/angular';
import {NGXLogger} from 'ngx-logger';
import {combineLatest} from 'rxjs';
@@ -24,6 +24,7 @@ import {DataRoutingService} from '../../data/data-routing.service';
import {SearchPageComponent} from '../../data/list/search-page.component';
import {HebisDataProvider} from '../hebis-data.provider';
import {PositionService} from '../../map/position.service';
+import {ConfigProvider} from '../../config/config.provider';
/**
* HebisSearchPageComponent queries things and shows list of things as search results and filter as context menu
@@ -31,6 +32,7 @@ import {PositionService} from '../../map/position.service';
@Component({
selector: 'stapps-hebissearch-page',
templateUrl: 'hebis-search-page.html',
+ styleUrls: ['../../data/list/search-page.scss'],
})
export class HebisSearchPageComponent
extends SearchPageComponent
@@ -56,7 +58,9 @@ export class HebisSearchPageComponent
* @param logger An angular logger
* @param dataRoutingService DataRoutingService
* @param router Router
+ * @param route Active Route
* @param positionService PositionService
+ * @param configProvider ConfigProvider
*/
constructor(
protected readonly alertController: AlertController,
@@ -66,7 +70,9 @@ export class HebisSearchPageComponent
protected readonly logger: NGXLogger,
protected dataRoutingService: DataRoutingService,
protected router: Router,
+ route: ActivatedRoute,
protected positionService: PositionService,
+ configProvider: ConfigProvider,
) {
super(
alertController,
@@ -76,7 +82,9 @@ export class HebisSearchPageComponent
logger,
dataRoutingService,
router,
+ route,
positionService,
+ configProvider,
);
}
diff --git a/src/app/modules/hebis/list/hebis-search-page.html b/src/app/modules/hebis/list/hebis-search-page.html
index f02ee4e0..fc548e71 100644
--- a/src/app/modules/hebis/list/hebis-search-page.html
+++ b/src/app/modules/hebis/list/hebis-search-page.html
@@ -1,19 +1,19 @@
-
-
+
-
-
-
-
-
-
-
+
+ {{ 'hebisSearch.title' | translate }}
+
+
+
+
+ {{ 'search.type' | translate }}
+
+ {{
+ 'hebisSearch.type' | translate
+ }}
+
+
diff --git a/src/app/modules/library/account/account.page.html b/src/app/modules/library/account/account.page.html
index 0e89587c..6c46c2f3 100644
--- a/src/app/modules/library/account/account.page.html
+++ b/src/app/modules/library/account/account.page.html
@@ -1,8 +1,10 @@
-
+
-
-
+
{{ 'library.account.title' | translate | titlecase }}
@@ -18,11 +20,11 @@
- {{ 'library.account.pages.profile.title' | translate | titlecase }}
- {{ 'library.account.pages.holds.title' | translate | titlecase }}
@@ -30,7 +32,7 @@
>{{ 'library.account.pages.checked_out.title' | translate | titlecase }}
- {{ 'library.account.pages.fines.title' | translate | titlecase }}
diff --git a/src/app/modules/library/account/checked-out/checked-out-page.html b/src/app/modules/library/account/checked-out/checked-out-page.html
index 8aecccb7..86744fbe 100644
--- a/src/app/modules/library/account/checked-out/checked-out-page.html
+++ b/src/app/modules/library/account/checked-out/checked-out-page.html
@@ -1,8 +1,10 @@
-
+
-
-
+
{{
'library.account.pages.checked_out.title' | translate | titlecase
diff --git a/src/app/modules/library/account/fines/fines-page.html b/src/app/modules/library/account/fines/fines-page.html
index bcbe5a13..41e532e1 100644
--- a/src/app/modules/library/account/fines/fines-page.html
+++ b/src/app/modules/library/account/fines/fines-page.html
@@ -1,8 +1,10 @@
-
+
-
-
+
{{
'library.account.pages.fines.title' | translate | titlecase
diff --git a/src/app/modules/library/account/holds-and-reservations/holds-and-reservations-page.html b/src/app/modules/library/account/holds-and-reservations/holds-and-reservations-page.html
index 2176be45..45e6f448 100644
--- a/src/app/modules/library/account/holds-and-reservations/holds-and-reservations-page.html
+++ b/src/app/modules/library/account/holds-and-reservations/holds-and-reservations-page.html
@@ -1,8 +1,10 @@
-
+
-
-
+
{{
'library.account.pages.holds.title' | translate | titlecase
diff --git a/src/app/modules/library/account/profile/profile-page.html b/src/app/modules/library/account/profile/profile-page.html
index 32a5a182..52674166 100644
--- a/src/app/modules/library/account/profile/profile-page.html
+++ b/src/app/modules/library/account/profile/profile-page.html
@@ -1,8 +1,10 @@
-
+
-
-
+
{{
'library.account.pages.profile.title' | translate | titlecase
diff --git a/src/app/modules/library/library.module.ts b/src/app/modules/library/library.module.ts
index 3b89d5e6..6f25a311 100644
--- a/src/app/modules/library/library.module.ts
+++ b/src/app/modules/library/library.module.ts
@@ -16,6 +16,7 @@ import {ProtectedRoutes} from '../auth/protected.routes';
import {MomentModule} from 'ngx-moment';
import {FeeItemComponent} from './account/elements/fee-item/fee-item.component';
import {DataModule} from '../data/data.module';
+import {UtilModule} from '../../util/util.module';
const routes: ProtectedRoutes | Routes = [
{
@@ -59,6 +60,7 @@ const routes: ProtectedRoutes | Routes = [
TranslateModule,
MomentModule,
DataModule,
+ UtilModule,
],
declarations: [
LibraryAccountPageComponent,
diff --git a/src/app/modules/map/item/map-item.component.html b/src/app/modules/map/item/map-item.component.html
index 7090ffa9..c1995b30 100644
--- a/src/app/modules/map/item/map-item.component.html
+++ b/src/app/modules/map/item/map-item.component.html
@@ -8,6 +8,7 @@
trigger="show-more"
[presentingElement]="routerOutlet.nativeEl"
swipeToClose="true"
+ class="modal-large"
>
@@ -15,36 +16,35 @@
+
+
+
-
-
-
-
-
- {{ $any(item).inPlace.name }},
- {{ address.streetAddress }}, {{ address.addressLocality }}
-
-
-
-
- More
-
-
-
-
-
-
-
-
-
+
+
+ {{ $any(item).inPlace.name }},
+ {{ address.streetAddress }}, {{ address.addressLocality }}
+
+
+ {{
+ 'map.page.buttons.MORE' | translate
+ }}
+
+
+
+
+
+
diff --git a/src/app/modules/map/item/map-item.component.scss b/src/app/modules/map/item/map-item.component.scss
index e8941db6..3c542e64 100644
--- a/src/app/modules/map/item/map-item.component.scss
+++ b/src/app/modules/map/item/map-item.component.scss
@@ -1,8 +1,57 @@
-ion-col:nth-child(2) {
- display: flex;
- justify-content: flex-end;
+@import '../../../../theme/util/mixins';
- ion-button {
- margin-top: auto;
+:host {
+ display: block;
+ max-width: 100%;
+
+ ion-card {
+ padding: 0;
+ overflow: visible;
+
+ ion-card-header{
+ padding: 0;
+ border-bottom: var(--border-width-default) solid var(--border-color-default);
+
+ stapps-data-list-item {
+ --ion-margin: 0;
+
+ &::ng-deep ion-item {
+ --padding-start: 0;
+ --padding-end: 0;
+
+ ion-label {
+ white-space: break-spaces;
+ }
+ }
+ }
+
+ .close {
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ z-index: 1;
+ --padding-top: 0;
+ --padding-bottom: 0;
+ --padding-start: 0;
+ --padding-end: 0;
+
+ ion-icon {
+ width: 30px;
+ height: 30px;
+ }
+ }
+ }
+
+ ion-card-content {
+ padding: var(--spacing-md);
+ display: flex;
+ flex-direction: row;
+
+ #show-more-button {
+ text-transform: uppercase;
+ margin-left: auto;
+ }
+ }
}
+
}
diff --git a/src/app/modules/map/item/map-item.component.ts b/src/app/modules/map/item/map-item.component.ts
index 6a9c116c..856339ab 100644
--- a/src/app/modules/map/item/map-item.component.ts
+++ b/src/app/modules/map/item/map-item.component.ts
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see .
*/
-import {Component, Input} from '@angular/core';
+import {Component, EventEmitter, Input, Output} from '@angular/core';
import {SCPlace} from '@openstapps/core';
import {IonRouterOutlet} from '@ionic/angular';
@@ -27,5 +27,15 @@ export class MapItemComponent {
*/
@Input() item: SCPlace;
+ // eslint-disable-next-line @angular-eslint/no-output-on-prefix
+ @Output() onClose = new EventEmitter();
+
constructor(readonly routerOutlet: IonRouterOutlet) {}
+
+ /**
+ * Action when edit is clicked
+ */
+ onCloseClick() {
+ this.onClose.emit();
+ }
}
diff --git a/src/app/modules/map/map.module.ts b/src/app/modules/map/map.module.ts
index 4e40eea7..366a1749 100644
--- a/src/app/modules/map/map.module.ts
+++ b/src/app/modules/map/map.module.ts
@@ -33,6 +33,7 @@ import {MapListModalComponent} from './page/modals/map-list-modal.component';
import {MapSingleModalComponent} from './page/modals/map-single-modal.component';
import {MapItemComponent} from './item/map-item.component';
import {NgModule} from '@angular/core';
+import {UtilModule} from '../../util/util.module';
/**
* Initializes the default area to show in advance (before components are initialized)
@@ -78,6 +79,7 @@ const mapRoutes: Routes = [
DataModule,
FormsModule,
ThingTranslateModule,
+ UtilModule,
],
providers: [
Geolocation,
diff --git a/src/app/modules/map/map.provider.ts b/src/app/modules/map/map.provider.ts
index 21fd37b7..ebc80b0f 100644
--- a/src/app/modules/map/map.provider.ts
+++ b/src/app/modules/map/map.provider.ts
@@ -76,7 +76,7 @@ export class MapProvider {
? `
`
- : ' ',
+ : ' ',
iconSize: [iconSize, iconSize],
}),
zIndexOffset: 1000,
diff --git a/src/app/modules/map/page/map-page.component.ts b/src/app/modules/map/page/map-page.component.ts
index 12d5fa38..c647f7fd 100644
--- a/src/app/modules/map/page/map-page.component.ts
+++ b/src/app/modules/map/page/map-page.component.ts
@@ -13,6 +13,7 @@
* this program. If not, see .
*/
import {Location} from '@angular/common';
+import {trigger, style, animate, transition} from '@angular/animations';
import {
ChangeDetectorRef,
Component,
@@ -59,6 +60,24 @@ import {Capacitor} from '@capacitor/core';
styleUrls: ['./map-page.scss'],
templateUrl: './map-page.html',
providers: [ContextMenuService],
+ animations: [
+ trigger('fadeInOut', [
+ transition(':enter', [
+ style({transform: 'translateY(200%)', opacity: 0}),
+ animate(
+ '500ms ease-in-out',
+ style({transform: 'translateY(0%)', opacity: 1}),
+ ),
+ ]),
+ transition(':leave', [
+ style({transform: 'translateY(0%)', opacity: 1}),
+ animate(
+ '500ms ease-in-out',
+ style({transform: 'translateY(200%)', opacity: 0}),
+ ),
+ ]),
+ ]),
+ ],
})
export class MapPageComponent {
/**
@@ -242,13 +261,17 @@ export class MapPageComponent {
/**
* Fetches items with set query configuration
*
+ * @param fetchAll Should fetch all items
* @param animate Should the fly animation be used
*/
- async fetchAndUpdateItems(animate?: boolean): Promise {
+ async fetchAndUpdateItems(
+ fetchAll = false,
+ animate?: boolean,
+ ): Promise {
try {
const result = await this.mapProvider.searchPlaces(
this.filterQuery,
- this.queryText,
+ fetchAll ? '' : this.queryText,
);
if (result.data.length === 0) {
const alert = await this.alertController.create({
@@ -353,7 +376,7 @@ export class MapPageComponent {
this.subscriptions.push(
this.contextMenuService.filterQueryChanged$.subscribe(query => {
this.filterQuery = query;
- this.fetchAndUpdateItems(true);
+ this.fetchAndUpdateItems(false, true);
}),
);
@@ -414,7 +437,7 @@ export class MapPageComponent {
*/
async resetView() {
this.location.go('/map');
- await this.fetchAndUpdateItems();
+ await this.fetchAndUpdateItems(this.items.length > 0);
this.ref.detectChanges();
}
@@ -437,7 +460,7 @@ export class MapPageComponent {
*/
searchStringChanged(queryText?: string) {
this.queryText = queryText || '';
- void this.fetchAndUpdateItems(true);
+ void this.fetchAndUpdateItems(false, true);
}
/**
@@ -451,7 +474,7 @@ export class MapPageComponent {
this.distance = this.positionService.getDistance(this.items[0].geo.point);
this.addToMap(this.items, true);
this.ref.detectChanges();
- const url = this.router.createUrlTree([[], uid]).toString();
+ const url = this.router.createUrlTree(['/map', uid]).toString();
this.location.go(url);
// center the selected place
this.focus(geoJSON(this.items[0].geo.point).getBounds().getCenter());
diff --git a/src/app/modules/map/page/map-page.html b/src/app/modules/map/page/map-page.html
index 05ebcc1d..08bd3c99 100644
--- a/src/app/modules/map/page/map-page.html
+++ b/src/app/modules/map/page/map-page.html
@@ -16,31 +16,39 @@
-
+
+
-
+ {{ 'map.page.TITLE' | translate }}
+
+
-
-
-
+
-
+
@@ -61,6 +69,7 @@
1"
+ [@fadeInOut]
color="light"
shape="round"
size="small"
@@ -79,21 +88,24 @@
>
-
+
1"
+ [@fadeInOut]
color="light"
shape="round"
size="small"
@@ -112,10 +124,10 @@
>
-
+
diff --git a/src/app/modules/map/page/map-page.scss b/src/app/modules/map/page/map-page.scss
index d64f3efc..d66465de 100644
--- a/src/app/modules/map/page/map-page.scss
+++ b/src/app/modules/map/page/map-page.scss
@@ -1,22 +1,3 @@
-ion-header {
- ion-toolbar {
- --background: transparent;
- --ion-color-base: transparent;
-
- ion-buttons {
- ion-back-button::part(native), ion-menu-button::part(native) {
- box-shadow: var(--map-box-shadow);
- //padding: 2px;
- }
- }
- }
- ion-searchbar {
- --background: white;
- // important for iOS
- --box-shadow: var(--map-box-shadow);
- }
-}
-
ion-content {
// fixes the unexpected issue that the content is not fullscreen (behind the header)
position: absolute;
@@ -24,12 +5,13 @@ ion-content {
width: 100%;
height: 100%;
}
+ & > div {
+ overflow: hidden;
+ }
}
-ion-back-button, ion-menu-button {
- --background: white;
- --background-hover: whitesmoke;
- --background-focused: whitesmoke;
+ion-toolbar:first-of-type {
+ padding: 0 var(--spacing-md) var(--spacing-xs);
}
::ng-deep {
@@ -50,14 +32,20 @@ ion-back-button, ion-menu-button {
}
div.floating-content {
- display: grid;
+ display: block;
position: absolute;
- bottom: 15px;
+ left: 0;
+ right: 0;
+ bottom: 0;
z-index: 1000;
width: 100%;
- padding: 0 20px;
+ padding: 0 var(--spacing-md) 8vh;
justify-content: center;
+ ion-card {
+ margin: 0;
+ }
+
div.map-buttons {
display: flex;
justify-content: flex-end;
@@ -67,7 +55,7 @@ ion-back-button, ion-menu-button {
width: 550px;
position: center;
justify-self: center;
- margin: 2px;
+ margin: var(--spacing-sm) auto;
}
}
}
diff --git a/src/app/modules/map/page/modals/map-list.html b/src/app/modules/map/page/modals/map-list.html
index 2715b706..7da284ee 100644
--- a/src/app/modules/map/page/modals/map-list.html
+++ b/src/app/modules/map/page/modals/map-list.html
@@ -15,7 +15,7 @@
-
+
{{ 'map.modals.list.TITLE' | translate }}
{{
diff --git a/src/app/modules/map/page/modals/map-single.html b/src/app/modules/map/page/modals/map-single.html
index 99140ef4..118a7b0f 100644
--- a/src/app/modules/map/page/modals/map-single.html
+++ b/src/app/modules/map/page/modals/map-single.html
@@ -1,5 +1,5 @@
-
+
{{ 'map.modals.single.TITLE' | translate }}
{{
@@ -9,5 +9,8 @@
-
+
diff --git a/src/app/modules/map/page/modals/map-single.scss b/src/app/modules/map/page/modals/map-single.scss
index e69de29b..4cef8a0c 100644
--- a/src/app/modules/map/page/modals/map-single.scss
+++ b/src/app/modules/map/page/modals/map-single.scss
@@ -0,0 +1,4 @@
+:host {
+ display: flex;
+ flex-direction: column;
+}
diff --git a/src/app/modules/map/widget/map-widget.component.ts b/src/app/modules/map/widget/map-widget.component.ts
index a3dd5540..550d8d3a 100644
--- a/src/app/modules/map/widget/map-widget.component.ts
+++ b/src/app/modules/map/widget/map-widget.component.ts
@@ -13,6 +13,7 @@
* this program. If not, see .
*/
import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core';
+import {Router} from '@angular/router';
import {SCPlace} from '@openstapps/core';
import {geoJSON, Map, MapOptions, tileLayer} from 'leaflet';
import {MapProvider} from '../map.provider';
@@ -46,6 +47,13 @@ export class MapWidgetComponent implements OnInit {
*/
@Input() place: SCPlace;
+ /**
+ * Indicates if the expand button should be visible
+ */
+ showExpandButton = true;
+
+ constructor(private router: Router) {}
+
/**
* Prepare the map
*/
@@ -69,6 +77,9 @@ export class MapWidgetComponent implements OnInit {
zoom: 16,
zoomControl: false,
};
+ if (this.router) {
+ this.showExpandButton = !this.router.url.startsWith('/map');
+ }
}
/**
diff --git a/src/app/modules/map/widget/map-widget.html b/src/app/modules/map/widget/map-widget.html
index c3f7dd81..026be7a8 100644
--- a/src/app/modules/map/widget/map-widget.html
+++ b/src/app/modules/map/widget/map-widget.html
@@ -5,13 +5,13 @@
#mapContainer
[leafletOptions]="options"
>
-
+
+
-
{{ i + hoursRange.from }}:00
-
+
+
+
+ {{ i + hoursRange.from }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/modules/schedule/page/calendar-view.scss b/src/app/modules/schedule/page/calendar-view.scss
index d8da0377..40ab8523 100644
--- a/src/app/modules/schedule/page/calendar-view.scss
+++ b/src/app/modules/schedule/page/calendar-view.scss
@@ -12,71 +12,3 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see
.
*/
-
-.header-swiper {
- width: 100%;
- height: 100%;
-}
-
-.header {
- position: relative;
-
- .left-button, .right-button {
- position: absolute;
- top: 0;
- bottom: 0;
- margin: auto;
- z-index: 5;
- }
-
- .left-button {
- left: 0;
- }
-
- .right-button {
- right: 0;
- }
-}
-
-// phantom element
-.phantom {
- position: absolute;
- visibility: hidden;
- height: 0 !important;
-}
-
-.day-labels {
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: center;
- align-items: center;
-
- ion-button {
- width: 100%;
- height: 100%;
-
- text-transform: none;
- ion-label {
- overflow: visible !important;
- }
- }
-}
-
-.hour-lines {
- top: 0;
- position: absolute;
- display: flex;
- flex-direction: row;
- width: 100%;
-
- ion-label {
- padding: 0 20px 20px;
- }
-
- .horizontal-line {
- width: 100%;
- top: 0;
- border-top: 1px solid #dbdbdb;
- }
-}
diff --git a/src/app/modules/schedule/page/components/calendar-component.html b/src/app/modules/schedule/page/components/calendar-component.html
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/modules/schedule/page/components/calendar-component.scss b/src/app/modules/schedule/page/components/calendar-component.scss
new file mode 100644
index 00000000..590a3a5c
--- /dev/null
+++ b/src/app/modules/schedule/page/components/calendar-component.scss
@@ -0,0 +1,123 @@
+/*!
+ * 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
.
+ */
+
+$header-height: 50px;
+$hours-width: 40px;
+
+.header {
+ height: $header-height;
+ background-color: var(--ion-color-light);
+ position: relative;
+
+ .left-button, .right-button {
+ color: var(--ion-color-medium-shade);
+ position: absolute;
+ z-index: 99;
+ height: 100%;
+ margin: 0;
+ --padding-start: 0;
+ --padding-end: 0;
+ }
+ .left-button {
+ left: 0;
+ padding: 0 var(--spacing-sm);
+ }
+ .right-button {
+ right: 0;
+ padding: 0 var(--spacing-sm);
+ }
+
+ .day-labels {
+ ion-button {
+ width: unset;
+ color: var(--ion-color-light-contrast);
+ overflow: visible !important;
+ }
+ }
+
+ .header-swiper {
+ background-color: var(--ion-color-light);
+ }
+}
+
+.full-height {
+ height: 100%;
+}
+
+.day-labels {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ ion-button {
+ width: 100%;
+ height: 100%;
+
+ text-transform: none;
+ ion-label {
+ overflow: visible !important;
+ }
+ }
+}
+
+ion-content {
+ overflow-y: auto;
+}
+
+.schedule-wrapper {
+ display: grid;
+ grid-template-columns: 40px calc(100% - 40px); // swiper.js can't calculate width when using 1fr instead of 100%
+ height: 100%;
+
+ .hours-wrapper {
+ z-index: 100;
+ background-color: var(--ion-color-primary-contrast);
+
+ .hour-lines {
+ width: 40px;
+ height: 70px;
+ border-right: 1px solid var(--ion-color-light);
+ text-align: center;
+ top: 0;
+ position: absolute;
+ font-weight: var(--font-weight-bold);
+ background-color: var(--calender-background-color);
+ }
+ }
+
+ .infinite-swiper-wrapper {
+ width: 100%;
+ }
+}
+
+.date-header {
+ border-bottom: 1px solid var(--calender-date-line-gray);
+ padding: var(--spacing-sm) auto;
+ height: fit-content;
+ font-weight: var(--font-weight-bold);
+ text-transform: uppercase;
+ text-align: center;
+}
+
+.day-labels > ion-button[disabled] {
+ opacity: 1;
+}
+
+
+div {
+ height: 100%;
+}
diff --git a/src/app/modules/schedule/page/components/calendar.component.ts b/src/app/modules/schedule/page/components/calendar.component.ts
new file mode 100644
index 00000000..da242f5f
--- /dev/null
+++ b/src/app/modules/schedule/page/components/calendar.component.ts
@@ -0,0 +1,264 @@
+/*
+ * 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
.
+ */
+import {Component, Input, OnDestroy, OnInit} from '@angular/core';
+import {ActivatedRoute} from '@angular/router';
+import {SCISO8601Date, SCUuid} from '@openstapps/core';
+import moment, {Moment} from 'moment';
+import {
+ materialFade,
+ materialManualFade,
+ materialSharedAxisX,
+} from '../../../../animation/material-motion';
+import {ScheduleProvider} from '../../../calendar/schedule.provider';
+import {ScheduleEvent, ScheduleResponsiveBreakpoint} from '../schema/schema';
+import {SwiperComponent} from 'swiper/angular';
+import {InfiniteSwiperComponent} from '../grid/infinite-swiper.component';
+import {IonDatetime} from '@ionic/angular';
+import {Subscription} from 'rxjs';
+import {CalendarService} from '../../../calendar/calendar.service';
+
+/**
+ * Component that displays the schedule
+ */
+@Component({
+ selector: 'stapps-calendar-component',
+ templateUrl: 'calendar-component.html',
+ styleUrls: ['calendar-component.scss'],
+ animations: [materialFade, materialSharedAxisX, materialManualFade],
+})
+export class CalendarComponent implements OnInit, OnDestroy {
+ /**
+ * The day that the schedule started out on
+ */
+ @Input() baselineDate: Moment;
+
+ /**
+ * Range of date of the slides shown on screen.
+ */
+ dateRange: {
+ startDate: string;
+ endDate: string;
+ } = {
+ startDate: '',
+ endDate: '',
+ };
+
+ calendarServiceSubscription: Subscription;
+
+ prevHeaderIndex = 0;
+
+ /**
+ * Hours for grid
+ */
+ @Input() hours: number[];
+
+ /**
+ * Range of hours to display
+ */
+ @Input() readonly hoursRange = {
+ from: 5,
+ to: 22,
+ };
+
+ todaySlideIndex: number;
+
+ initialSlideIndex?: Promise
;
+
+ /**
+ * Layout of the schedule
+ */
+ @Input() layout: ScheduleResponsiveBreakpoint;
+
+ /**
+ * Route fragment
+ */
+ routeFragment = 'schedule/calendar';
+
+ /**
+ * Vertical scale of the schedule (distance between hour lines)
+ */
+ @Input() scale = 70;
+
+ /**
+ * unix -> (uid -> event)
+ */
+ @Input() testSchedule: Record> =
+ {};
+
+ /**
+ * UUIDs
+ */
+ @Input() uuids: SCUuid[];
+
+ /**
+ * UUID subscription
+ */
+ uuidSubscription: Subscription;
+
+ @Input() useInfiniteSwiper = true;
+
+ @Input() weekDates: Array;
+
+ constructor(
+ protected readonly activatedRoute: ActivatedRoute,
+ protected readonly calendarService: CalendarService,
+ protected readonly scheduleProvider: ScheduleProvider,
+ ) {}
+
+ ngOnInit() {
+ this.onInit();
+ }
+
+ ngOnDestroy() {
+ this.onDestroy();
+ }
+
+ onInit() {
+ this.dateRange.startDate = this.calculateDateFromIndex(0, 0, 'DD.MM.YY');
+ this.dateRange.endDate = this.calculateDateFromIndex(
+ 0,
+ this.layout.days - 1,
+ 'DD.MM.YY',
+ );
+
+ let dayString: string | number | null =
+ this.activatedRoute.snapshot.paramMap.get('date');
+ if (dayString == undefined || dayString === 'now') {
+ const fragments = window.location.href.split('/');
+ const urlFragment: string = fragments[fragments.length - 1] ?? '';
+
+ dayString = /^\d{4}-\d{2}-\d{2}$/.test(urlFragment)
+ ? urlFragment
+ : moment.now();
+ }
+
+ this.baselineDate = moment(dayString).startOf('day');
+
+ this.initialSlideIndex = new Promise(resolve => {
+ this.uuidSubscription = this.scheduleProvider.uuids$.subscribe(
+ async result => {
+ this.uuids = result;
+ resolve(await this.loadEvents());
+ },
+ );
+ });
+ }
+
+ onDestroy() {
+ this.uuidSubscription.unsubscribe();
+ if (this.calendarServiceSubscription) {
+ this.calendarServiceSubscription.unsubscribe();
+ }
+ }
+
+ /**
+ * Get date from baseline date and index of current slide.
+ *
+ * @param index number
+ * @param delta number - is added to index
+ * @param dateFormat string
+ */
+ calculateDateFromIndex(index: number, delta = 0, dateFormat = 'YYYY-MM-DD') {
+ return moment(this.baselineDate)
+ .add(index + delta, 'days')
+ .format(dateFormat);
+ }
+
+ /**
+ * Change page
+ */
+ onPageChange(index: number) {
+ this.setDateRange(index);
+
+ window.history.replaceState(
+ {},
+ '',
+ `${this.routeFragment}/${this.calculateDateFromIndex(index)}`,
+ );
+ }
+
+ setDateRange(index: number) {
+ this.dateRange.startDate = this.calculateDateFromIndex(
+ index,
+ 0,
+ 'DD.MM.YY',
+ );
+ this.dateRange.endDate = this.calculateDateFromIndex(
+ index,
+ this.layout.days - 1,
+ 'DD.MM.YY',
+ );
+ }
+
+ onHeaderSwipe(index: number, infiniteController: InfiniteSwiperComponent) {
+ if (index < this.prevHeaderIndex) {
+ infiniteController?.pageBackwards();
+ }
+ if (index > this.prevHeaderIndex) {
+ infiniteController?.pageForward();
+ }
+ this.prevHeaderIndex = index;
+ }
+
+ syncSwiper(self: SwiperComponent, other: SwiperComponent) {
+ other.swiperRef.slideTo(self.swiperRef.activeIndex);
+ }
+
+ presentDatePopover(
+ mainSwiper: InfiniteSwiperComponent,
+ headerSwiper: InfiniteSwiperComponent,
+ index: number,
+ popoverDateTime: IonDatetime,
+ ) {
+ const nextIndex =
+ moment(popoverDateTime.value).diff(this.baselineDate, 'days') -
+ headerSwiper.virtualIndex -
+ index;
+
+ mainSwiper.goToIndex(nextIndex).then(() => {
+ this.setDateRange(nextIndex);
+ });
+ popoverDateTime.confirm(true);
+ }
+
+ /**
+ * Load events
+ */
+ async loadEvents(): Promise {
+ const dateSeries = await this.scheduleProvider.getDateSeries(this.uuids);
+
+ this.testSchedule = {};
+
+ for (const series of dateSeries.dates) {
+ for (const date of series.dates) {
+ const index = moment(date)
+ .startOf('day')
+ .diff(this.baselineDate, 'days');
+
+ // fall back to default
+ (this.testSchedule[index] ?? (this.testSchedule[index] = {}))[
+ series.uid
+ ] = {
+ dateSeries: series,
+ time: {
+ start: moment(date).hours(),
+ duration: series.duration,
+ },
+ };
+ }
+ }
+ return this.todaySlideIndex;
+ }
+}
diff --git a/src/app/modules/schedule/page/grid/infinite-swiper.component.ts b/src/app/modules/schedule/page/grid/infinite-swiper.component.ts
index 711e0407..7161e510 100644
--- a/src/app/modules/schedule/page/grid/infinite-swiper.component.ts
+++ b/src/app/modules/schedule/page/grid/infinite-swiper.component.ts
@@ -73,6 +73,8 @@ export class InfiniteSwiperComponent
@Output() indexChange = new EventEmitter();
+ @Output() indexChangeStart = new EventEmitter();
+
slidesArray: number[];
@ViewChild('swiper', {static: true})
@@ -158,6 +160,12 @@ export class InfiniteSwiperComponent
this.indexChange.emit(this.virtualIndex);
this.preventControllerCallback = false;
});
+
+ this.swiper.on('slideChangeTransitionStart', swiper => {
+ this.indexChangeStart.emit(
+ this.virtualIndex + swiper.activeIndex - swiper.previousIndex,
+ );
+ });
}
clearSlides() {
diff --git a/src/app/modules/schedule/page/grid/infinite-swiper.scss b/src/app/modules/schedule/page/grid/infinite-swiper.scss
index 47cd69aa..a61126e4 100644
--- a/src/app/modules/schedule/page/grid/infinite-swiper.scss
+++ b/src/app/modules/schedule/page/grid/infinite-swiper.scss
@@ -17,3 +17,7 @@
height: 100%;
width: 100%;
}
+
+.swiper, .swiper-wrapper, .swiper-slide {
+ overflow: unset;
+}
diff --git a/src/app/modules/schedule/page/grid/range-overlap.ts b/src/app/modules/schedule/page/grid/range-overlap.ts
index ea09699c..2357398c 100644
--- a/src/app/modules/schedule/page/grid/range-overlap.ts
+++ b/src/app/modules/schedule/page/grid/range-overlap.ts
@@ -51,11 +51,18 @@ function within(a: number, b: number, c: number): boolean {
return a > b && a < c;
}
+/**
+ *
+ */
+function equals(start1: number, end1: number, start2: number, end2: number) {
+ return start1 === start2 && end1 === end2;
+}
+
/**
*
*/
function hasOverlap(a1: number, b1: number, a2: number, b2: number): boolean {
- return within(a1, a2, b2) || within(b1, a2, b2);
+ return within(a1, a2, b2) || within(b1, a2, b2) || equals(a1, b1, a2, b2);
}
/**
diff --git a/src/app/modules/schedule/page/grid/schedule-card.component.ts b/src/app/modules/schedule/page/grid/schedule-card.component.ts
index 19c66b01..f1be8c60 100644
--- a/src/app/modules/schedule/page/grid/schedule-card.component.ts
+++ b/src/app/modules/schedule/page/grid/schedule-card.component.ts
@@ -26,6 +26,12 @@ import {ScheduleEvent} from '../schema/schema';
styleUrls: ['../../../data/list/data-list-item.scss', 'schedule-card.scss'],
})
export class ScheduleCardComponent implements OnInit {
+ cardColor = {
+ isBlack: false,
+ isBlue: false,
+ isDefault: false,
+ };
+
/**
* The hour from which on the schedule is displayed
*/
@@ -56,6 +62,11 @@ export class ScheduleCardComponent implements OnInit {
*/
@Input() scheduleEvent: ScheduleEvent;
+ /**
+ * Card shows the name of the place the event takes place
+ */
+ @Input() showPlaceName = false;
+
/**
* The title of the event
*/
@@ -67,8 +78,8 @@ export class ScheduleCardComponent implements OnInit {
* Get the note text
*/
getNote(): string | undefined {
- return 'categories' in this.scheduleEvent.dateSeries.event
- ? this.scheduleEvent.dateSeries.event.categories?.join(', ')
+ return this.scheduleEvent?.dateSeries?.name
+ ? this.scheduleEvent.dateSeries.name
: undefined;
}
@@ -80,6 +91,27 @@ export class ScheduleCardComponent implements OnInit {
this.height = moment.duration(this.scheduleEvent.time.duration).asHours();
this.title = this.scheduleEvent.dateSeries.event.name;
+
+ this.cardColor = {
+ isBlack: false,
+ isBlue: false,
+ isDefault: false,
+ };
+
+ switch (
+ 'categories' in this.scheduleEvent.dateSeries.event
+ ? this.scheduleEvent.dateSeries.event?.categories[0]
+ : ''
+ ) {
+ case 'lecture':
+ this.cardColor.isBlue = true;
+ break;
+ case 'exercise':
+ this.cardColor.isBlack = true;
+ break;
+ default:
+ this.cardColor.isDefault = true;
+ }
}
/**
diff --git a/src/app/modules/schedule/page/grid/schedule-card.html b/src/app/modules/schedule/page/grid/schedule-card.html
index a8baa1e5..2f4f4d2f 100644
--- a/src/app/modules/schedule/page/grid/schedule-card.html
+++ b/src/app/modules/schedule/page/grid/schedule-card.html
@@ -13,41 +13,30 @@
~ this program. If not, see .
-->
+
{{
- this.scheduleEvent.dateSeries.event.name
- | nullishCoalesce: this.scheduleEvent.dateSeries.name
+ this.scheduleEvent?.dateSeries?.event?.name
+ | nullishCoalesce: this.scheduleEvent?.dateSeries?.name
}}
-
-
-
- {{ 'schedule.card.forEach' | translate }}
- {{
- scheduleEvent.dateSeries.repeatFrequency
- | durationLocalized: true
- | sentencecase
- }}
- {{ 'schedule.card.until' | translate }}
- {{
- scheduleEvent.dateSeries.dates | last | amDateFormat: 'DD. MMM YYYY'
- }}
-
-
{{ getNote() }}
+ {{
+ scheduleEvent?.dateSeries?.inPlace?.name
+ }}
-
diff --git a/src/app/modules/schedule/page/grid/schedule-card.scss b/src/app/modules/schedule/page/grid/schedule-card.scss
index 3eb7c5a9..31b659d9 100644
--- a/src/app/modules/schedule/page/grid/schedule-card.scss
+++ b/src/app/modules/schedule/page/grid/schedule-card.scss
@@ -1,13 +1,84 @@
ion-card {
width: inherit;
z-index: 2;
+ margin-left: 0;
+ margin-right: 0;
+ border-radius: 0;
+
+ &.blueCard {
+ --background: var(--calender-blue-card);
+
+ ion-card-title, ion-card-subtitle span, ion-card-content ion-note, ion-card-content ion-text {
+ color: var(--ion-color-primary-contrast);
+ }
+
+ &:after {
+ background: linear-gradient(rgba(var(--calender-blue-card-rgb), 0%), rgba(var(--calender-blue-card-rgb), 100%));
+ }
+ }
+ &.blackCard {
+ --background: var(--calender-black-card);
+
+ ion-card-title, ion-card-subtitle span, ion-card-content ion-note, ion-card-content ion-text {
+ color: var(--ion-color-primary-contrast);
+ }
+
+ &:after {
+ background: linear-gradient(rgba(var(--calender-black-card-rgb), 0%), rgba(var(--calender-black-card-rgb), 100%));
+ }
+ }
+ &.defaultCard {
+ --background: var(--calender-default-card);
+
+ ion-card-title, ion-card-subtitle span, ion-card-content ion-note, ion-card-content ion-text {
+ color: var(--ion-color-light-contrast);
+ }
+
+ &:after {
+ background: linear-gradient(rgba(var(--calender-light-card-rgb), 0%), rgba(var(--calender-light-card-rgb), 100%));
+ }
+ }
+
+ &:after {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ height: 33%;
+ width: 100%;
+ background: linear-gradient(rgba(var(--calender-blue-card-rgb), 0%), rgba(var(--calender-blue-card-rgb), 100%));
+ }
ion-card-header {
height: available;
+ padding-bottom: var(--spacing-xs);
ion-card-title {
overflow-wrap: break-word;
}
+
+ ion-card-subtitle {
+ display: flex;
+ ion-icon.icon-white {
+ color: var(--ion-color-primary-contrast);
+ margin-right: var(--spacing-xs);
+ }
+ }
+ }
+
+ ion-card-header, ion-card-title, ion-card-subtitle span, ion-card-content ion-note {
+ font-size: var(--font-size-sm);
+ font-weight: var(--font-weight-bold);
+ font-family: var(--headline-font-family);
+ text-overflow: ellipsis;
+ }
+
+ ion-card-content .place-name {
+ display: block;
+ font-family: var(--headline-font-family);
+ }
+
+ ion-card-content .place-name {
+ display: block;
}
div {
diff --git a/src/app/modules/schedule/page/grid/schedule-cursor.html b/src/app/modules/schedule/page/grid/schedule-cursor.html
index 06048b32..76fcfd90 100644
--- a/src/app/modules/schedule/page/grid/schedule-cursor.html
+++ b/src/app/modules/schedule/page/grid/schedule-cursor.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/app/modules/schedule/page/grid/schedule-cursor.scss b/src/app/modules/schedule/page/grid/schedule-cursor.scss
index 422c14d5..6e016687 100644
--- a/src/app/modules/schedule/page/grid/schedule-cursor.scss
+++ b/src/app/modules/schedule/page/grid/schedule-cursor.scss
@@ -21,7 +21,7 @@ div {
flex-direction: row;
width: 100%;
top: 4px;
- z-index: 0;
+ z-index: 2;
div {
width: 100%;
@@ -33,7 +33,7 @@ div {
margin-right: 16px;
margin-top: 8px;
height: 2px;
- border-top: 2px solid var(--ion-color-primary);
+ border-top: 2px solid var(--ion-color-danger);
margin-block-start: 0;
margin-block-end: 0;
}
@@ -45,7 +45,7 @@ div {
top: -3px;
border-radius: 50% 0 50% 50%;
transform: rotateZ(45deg);
- background-color: var(--ion-color-primary);
+ background-color: var(--ion-color-danger);
}
}
}
diff --git a/src/app/modules/schedule/page/grid/schedule-day.component.ts b/src/app/modules/schedule/page/grid/schedule-day.component.ts
index 50830880..31046728 100644
--- a/src/app/modules/schedule/page/grid/schedule-day.component.ts
+++ b/src/app/modules/schedule/page/grid/schedule-day.component.ts
@@ -12,9 +12,13 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see
.
*/
-import {Component, Input} from '@angular/core';
+import {Component, HostListener, Input, OnInit} from '@angular/core';
import moment from 'moment';
-import {Range, ScheduleEvent} from '../schema/schema';
+import {
+ Range,
+ ScheduleEvent,
+ ScheduleResponsiveBreakpoint,
+} from '../schema/schema';
import {ScheduleProvider} from '../../../calendar/schedule.provider';
import {SCISO8601Duration, SCUuid} from '@openstapps/core';
import {materialFade} from '../../../../animation/material-motion';
@@ -26,7 +30,7 @@ import {groupRangeOverlaps} from './range-overlap';
styleUrls: ['schedule-day.scss'],
animations: [materialFade],
})
-export class ScheduleDayComponent {
+export class ScheduleDayComponent implements OnInit {
@Input() day: moment.Moment;
@Input() hoursRange: Range
;
@@ -37,6 +41,10 @@ export class ScheduleDayComponent {
@Input() frequencies?: SCISO8601Duration[];
+ @Input() layout: ScheduleResponsiveBreakpoint;
+
+ @Input() isLeftmost = false;
+
dateSeriesGroups?: ScheduleEvent[][];
@Input() set dateSeries(value: Record) {
@@ -52,8 +60,28 @@ export class ScheduleDayComponent {
).map(it => it.elements);
}
+ dateFormat = 'dd';
+
constructor(protected readonly scheduleProvider: ScheduleProvider) {}
+ ngOnInit() {
+ this.determineDateFormat();
+ }
+
+ @HostListener('window:resize', ['$event'])
+ _onResize() {
+ this.determineDateFormat();
+ }
+
+ private determineDateFormat() {
+ this.dateFormat =
+ this.layout &&
+ window.innerWidth > 1024 &&
+ window.innerWidth <= this.layout?.until
+ ? 'dddd'
+ : 'dd';
+ }
+
// TODO: backend bug results in the wrong date series being returned
/* async fetchDateSeries(): Promise {
const dateSeries = await this.scheduleProvider.getDateSeries(
diff --git a/src/app/modules/schedule/page/grid/schedule-day.html b/src/app/modules/schedule/page/grid/schedule-day.html
index cd97ad40..f20e5aea 100644
--- a/src/app/modules/schedule/page/grid/schedule-day.html
+++ b/src/app/modules/schedule/page/grid/schedule-day.html
@@ -12,7 +12,10 @@
~ You should have received a copy of the GNU General Public License along with
~ this program. If not, see .
-->
-
+
+
-
.
*/
-.schedule-card {
- overflow: hidden;
-}
-
-div {
- height: 100%;
- width: 100%;
-}
-
-.horizontal-group {
- position: absolute;
- top: 13px;
- left: 0;
- grid-column: 1;
- grid-row: 1;
- width: 100%;
-
- box-sizing: border-box;
- max-width: inherit;
-
- display: flex;
- flex-direction: row;
- align-items: flex-start;
-}
-
-.vertical-line {
- position: absolute;
- top: 0;
- left: 0;
- width: 1px;
- height: 100%;
- background-color: #dbdbdb;
+:host {
+ .day-wrapper {
+ border-left: 1px solid var(--calender-date-line-gray);
+ border-right: 1px solid var(--calender-date-line-gray);
+
+ &.leftmost {
+ border-left: unset;
+ }
+
+ .day-header {
+ position: sticky;
+ top: 0;
+ left: 0;
+ height: fit-content;
+ padding: var(--spacing-md);
+ border-bottom: 2px solid var(--ion-color-light);
+ font-size: var(--font-size-md);
+ font-weight: var(--font-weight-bold);
+ text-align: center;
+ text-transform: uppercase;
+ background-color: var(--ion-color-primary-contrast);
+ z-index: 3;
+
+ &.leftmost {
+ border-left: 1px solid var(--ion-color-light);
+ }
+ }
+ }
+
+ .schedule-card {
+ overflow: hidden;
+ }
+
+ div {
+ height: 100%;
+ width: 100%;
+ }
+
+ .horizontal-group {
+ position: absolute;
+ top: 10px;
+ left: 0;
+ grid-column: 1;
+ grid-row: 1;
+ width: 100%;
+
+ box-sizing: border-box;
+ max-width: inherit;
+
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ }
+
+ .vertical-line {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 1px;
+ height: 100%;
+ background-color: var(--calender-date-line-gray);
+ }
}
diff --git a/src/app/modules/schedule/page/modal/modal-event-creator.html b/src/app/modules/schedule/page/modal/modal-event-creator.html
index 943976a7..643d8208 100644
--- a/src/app/modules/schedule/page/modal/modal-event-creator.html
+++ b/src/app/modules/schedule/page/modal/modal-event-creator.html
@@ -13,7 +13,7 @@
~ this program. If not, see
.
-->
-
+
{{
'schedule.addEventModal.addEvent' | translate | titlecase
}}
@@ -29,5 +29,7 @@
[showDrawer]="false"
[forcedFilter]="filter"
[itemRouting]="false"
+ [showTopToolbar]="false"
+ [showNavigation]="false"
>
diff --git a/src/app/modules/schedule/page/modal/modal-event-creator.scss b/src/app/modules/schedule/page/modal/modal-event-creator.scss
index 7facf36d..2e12b0b8 100644
--- a/src/app/modules/schedule/page/modal/modal-event-creator.scss
+++ b/src/app/modules/schedule/page/modal/modal-event-creator.scss
@@ -1,3 +1,10 @@
+:host {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 20%;
+}
+
ion-button {
ion-label {
color: var(--ion-color-light);
diff --git a/src/app/modules/schedule/page/schedule-page.component.ts b/src/app/modules/schedule/page/schedule-page.component.ts
index f86eba7c..d4b5fff4 100644
--- a/src/app/modules/schedule/page/schedule-page.component.ts
+++ b/src/app/modules/schedule/page/schedule-page.component.ts
@@ -16,6 +16,7 @@ import {
AfterViewInit,
Component,
HostListener,
+ Input,
OnInit,
ViewChild,
} from '@angular/core';
@@ -25,6 +26,8 @@ import {IonRouterOutlet} from '@ionic/angular';
import {SharedAxisChoreographer} from '../../../animation/animation-choreographer';
import {materialSharedAxisX} from '../../../animation/material-motion';
import {ScheduleResponsiveBreakpoint} from './schema/schema';
+import {CalendarService} from '../../calendar/calendar.service';
+import moment from 'moment';
/**
* This needs to be sorted by break point low -> high
@@ -34,7 +37,7 @@ import {ScheduleResponsiveBreakpoint} from './schema/schema';
const responsiveConfig: ScheduleResponsiveBreakpoint[] = [
{
until: 768,
- days: 1,
+ days: 3,
startOf: 'day',
},
{
@@ -69,6 +72,10 @@ export class SchedulePageComponent implements OnInit, AfterViewInit {
*/
actualSegmentValue?: string | null;
+ /**
+ * Trigger event to go to today in calendar component
+ */
+
/**
* Layout
*/
@@ -76,18 +83,25 @@ export class SchedulePageComponent implements OnInit, AfterViewInit {
this.currentWindowWidth,
);
- /**
- * Vertical scale of the schedule (distance between hour lines)
- */
- scale = 60;
-
@ViewChild('segment') segmentView!: HTMLIonSegmentElement;
+ /**
+ * Show the navigation drawer
+ */
+ @Input() showDrawer = true;
+
+ /**
+ * Search value from search bar
+ */
+ queryText: string;
+
/**
* Choreographer for the tab switching
*/
tabChoreographer: SharedAxisChoreographer;
+ isModalOpen = false;
+
/**
* Amount of days that should be shown according to current display width
*/
@@ -104,22 +118,36 @@ export class SchedulePageComponent implements OnInit, AfterViewInit {
constructor(
private readonly activatedRoute: ActivatedRoute,
+ private calendarService: CalendarService,
readonly routerOutlet: IonRouterOutlet,
private router: Router,
private location: Location,
) {}
ngOnInit() {
- this.tabChoreographer = new SharedAxisChoreographer(
- this.activatedRoute.snapshot.paramMap.get('mode'),
- ['calendar', 'recurring', 'single'],
- );
+ this.onInit();
+ }
+
+ /**
+ * ngOnInit is not reliably called after first navigation to app/schedule. This leads to URL and segmentView being out of sync.
+ * ionViewWillEnter is called on second, third, ... navigation to app/schedule
+ */
+ ionViewWillEnter() {
+ this.onInit();
+ this.segmentView.value = this.tabChoreographer.currentValue;
}
ngAfterViewInit() {
this.segmentView.value = this.tabChoreographer.currentValue;
}
+ onInit() {
+ this.tabChoreographer = new SharedAxisChoreographer(
+ this.activatedRoute.snapshot.paramMap.get('mode'),
+ ['calendar', 'recurring', 'single'],
+ );
+ }
+
/**
* Resize callback
*
@@ -144,9 +172,21 @@ export class SchedulePageComponent implements OnInit, AfterViewInit {
*/
onSegmentChange() {
const url = this.router
- .createUrlTree([[], this.segmentView.value])
+ .createUrlTree([[], 'schedule', this.segmentView.value])
.toString();
this.location.go(url);
this.tabChoreographer.changeViewForState(this.segmentView.value);
}
+
+ onTodayClick() {
+ this.calendarService.emitGoToDate(moment().startOf('day'));
+ }
+
+ onFABClick() {
+ this.isModalOpen = true;
+ }
+
+ onModalDismiss() {
+ this.isModalOpen = false;
+ }
}
diff --git a/src/app/modules/schedule/page/schedule-page.html b/src/app/modules/schedule/page/schedule-page.html
index 350b6093..8d5b6c38 100644
--- a/src/app/modules/schedule/page/schedule-page.html
+++ b/src/app/modules/schedule/page/schedule-page.html
@@ -14,13 +14,35 @@
-->
-
+
-
-
+
-
-
+ {{
+ 'schedule.calendar' | translate | titlecase
+ }}
+ {{
+ 'schedule.recurring' | translate | titlecase
+ }}
+ {{
+ 'schedule.single' | translate | titlecase
+ }}
+
+
+ {{ 'schedule.view.today' | translate | uppercase }}
+
+
+
+
+
{{ 'schedule.calendar' | translate }}
@@ -34,35 +56,43 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
diff --git a/src/app/modules/schedule/page/schedule-page.scss b/src/app/modules/schedule/page/schedule-page.scss
index 6aa3458a..dfc23470 100644
--- a/src/app/modules/schedule/page/schedule-page.scss
+++ b/src/app/modules/schedule/page/schedule-page.scss
@@ -13,6 +13,49 @@
* this program. If not, see .
*/
+ion-header {
+ ion-toolbar {
+ ion-back-button {
+ --padding-start: 0;
+ --padding-end: var(--spacing-lg);
+ }
+
+ &.tabs-toolbar {
+ --min-height: 44px;
+ }
+
+ ion-segment.tabs {
+ position: absolute;
+ bottom: 0;
+ min-height: unset;
+ margin-left: 15%;
+ margin-right: 15%;
+ max-width: 70%;
+ left: 50%;
+ transform: translateX(-50%);
+
+ @media (max-width: 420px) {
+ width: 300px;
+ max-width: unset;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ ion-segment-button {
+ min-height: 44px;
+
+ ion-label {
+ line-height: unset;
+ margin: var(--spacing-sm) 0;
+ }
+ }
+ }
+ }
+}
+
+ion-content {
+ --background: var(--ion-color-light);
+}
div {
height: 100%;
diff --git a/src/app/modules/schedule/page/schedule-single-events.component.ts b/src/app/modules/schedule/page/schedule-single-events.component.ts
index 26ee98f3..71c2c37a 100644
--- a/src/app/modules/schedule/page/schedule-single-events.component.ts
+++ b/src/app/modules/schedule/page/schedule-single-events.component.ts
@@ -90,7 +90,9 @@ export class ScheduleSingleEventsComponent implements OnInit, OnDestroy {
// tslint:disable-next-line:no-magic-numbers
.minute() /
60,
+ startAsString: moment(date).format('LT'),
duration: event.duration,
+ endAsString: moment(date).add(event.duration).format('LT'),
},
},
})),
@@ -118,9 +120,10 @@ export class ScheduleSingleEventsComponent implements OnInit, OnDestroy {
);
// TODO: replace with filter
- return ScheduleSingleEventsComponent.groupDateSeriesToDays(
+ const test = ScheduleSingleEventsComponent.groupDateSeriesToDays(
dateSeries.dates.filter(it => !it.repeatFrequency),
);
+ return test;
}
/**
diff --git a/src/app/modules/schedule/page/schedule-single-events.html b/src/app/modules/schedule/page/schedule-single-events.html
index 958262b8..2b35893a 100644
--- a/src/app/modules/schedule/page/schedule-single-events.html
+++ b/src/app/modules/schedule/page/schedule-single-events.html
@@ -5,14 +5,21 @@
{{ day[0].day | amDateFormat: 'LL' }}
-
- {{ event.event.dateSeries.dates[0] | amDateFormat: 'HH:mm' }}
-
+
+
+ {{ event.event.time.startAsString }}
+
+
+ {{
+ event.event.time.endAsString
+ }}
+
diff --git a/src/app/modules/schedule/page/schedule-single-events.scss b/src/app/modules/schedule/page/schedule-single-events.scss
index 0b6c1487..4172f74c 100644
--- a/src/app/modules/schedule/page/schedule-single-events.scss
+++ b/src/app/modules/schedule/page/schedule-single-events.scss
@@ -1,17 +1,35 @@
-ion-content {
- height: 100%;
-}
+:host {
+ ion-content {
+ height: 100%;
+ }
-.hour-label {
- width: fit-content;
-}
+ .hour-wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-right: var(--spacing-md);
-.day-label {
- padding: 16px;
- font-size: large;
- font-weight: bold;
-}
+ .hour-label {
+ width: fit-content;
+ display: inline-block;
+ text-align: center;
+ }
+ .hour-line {
+ width: 1px;
+ height: 20px;
+ border-left: 1px solid var(--ion-color-primary);
+ margin: var(--spacing-xs) 0;
+ }
+ }
-.event-card {
- width: 100%
+ .day-label {
+ padding: 16px;
+ font-size: large;
+ font-weight: bold;
+ }
+
+ .event-card {
+ width: 100%;
+ max-width: 600px;
+ }
}
diff --git a/src/app/modules/schedule/page/schedule-single-events.spec.ts b/src/app/modules/schedule/page/schedule-single-events.spec.ts
index b395dc3b..3562ae20 100644
--- a/src/app/modules/schedule/page/schedule-single-events.spec.ts
+++ b/src/app/modules/schedule/page/schedule-single-events.spec.ts
@@ -46,7 +46,11 @@ describe('ScheduleSingleEvents', () => {
dateSeries: series as SCDateSeries,
time: {
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'),
},
},
};
diff --git a/src/app/modules/schedule/page/schedule-view.component.ts b/src/app/modules/schedule/page/schedule-view.component.ts
index ff334c31..8a1e0e8d 100644
--- a/src/app/modules/schedule/page/schedule-view.component.ts
+++ b/src/app/modules/schedule/page/schedule-view.component.ts
@@ -12,18 +12,27 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see .
*/
-import {Component} from '@angular/core';
+import {
+ AfterViewInit,
+ Component,
+ Input,
+ OnDestroy,
+ OnInit,
+ ViewChild,
+} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
-import {Platform} from '@ionic/angular';
-import moment from 'moment';
-import {DateFormatPipe} from 'ngx-moment';
+import moment, {Moment} from 'moment';
import {
materialFade,
materialManualFade,
materialSharedAxisX,
} from '../../../animation/material-motion';
import {ScheduleProvider} from '../../calendar/schedule.provider';
-import {CalendarViewComponent} from './calendar-view.component';
+import {SCISO8601Date, SCUuid} from '@openstapps/core';
+import {ScheduleEvent, ScheduleResponsiveBreakpoint} from './schema/schema';
+import {CalendarService} from '../../calendar/calendar.service';
+import {CalendarComponent} from './components/calendar.component';
+import {IonDatetime} from '@ionic/angular';
import {SwiperComponent} from 'swiper/angular';
/**
@@ -32,49 +41,105 @@ import {SwiperComponent} from 'swiper/angular';
@Component({
selector: 'stapps-schedule-view',
templateUrl: 'schedule-view.html',
- styleUrls: ['calendar-view.scss', 'schedule-view.scss'],
+ styleUrls: ['schedule-view.scss', './components/calendar-component.scss'],
animations: [materialFade, materialSharedAxisX, materialManualFade],
})
-export class ScheduleViewComponent extends CalendarViewComponent {
+export class ScheduleViewComponent
+ extends CalendarComponent
+ implements OnInit, AfterViewInit, OnDestroy
+{
+ @ViewChild('mainSwiper') mainSwiper: SwiperComponent;
+
+ @ViewChild('headerSwiper') headerSwiper: SwiperComponent;
+
+ /**
+ * The day that the schedule started out on
+ */
+ baselineDate: Moment;
+
+ /**
+ * Hours for grid
+ */
+ readonly hours: number[];
+
+ /**
+ * Range of hours to display
+ */
+ @Input() readonly hoursRange = {
+ from: 5,
+ to: 22,
+ };
+
+ /**
+ * Layout of the schedule
+ */
+ @Input() layout: ScheduleResponsiveBreakpoint;
+
+ schedule: Record> = {};
+
+ /**
+ * unix -> (uid -> event)
+ */
+ @Input() testSchedule: Record> =
+ {};
+
/**
* Route Fragment
*/
// @Override
routeFragment = 'schedule/recurring';
+ // start at sunday
weekDates = Array.from({length: 7}).map(
- /* eslint-disable-next-line unicorn/consistent-function-scoping */
- (_, i) => moment(new Date(2022, 0, 2 + i)), // 02/01/2022 is a Sunday
+ // eslint-disable-next-line unicorn/consistent-function-scoping
+ (_, i) =>
+ moment()
+ .startOf('week')
+ .add(i - 1, 'days'),
);
constructor(
- scheduleProvider: ScheduleProvider,
activatedRoute: ActivatedRoute,
- datePipe: DateFormatPipe,
- platform: Platform,
+ calendarService: CalendarService,
+ scheduleProvider: ScheduleProvider,
) {
- super(scheduleProvider, activatedRoute, datePipe, platform);
- }
-
- syncSwiper(self: SwiperComponent, other: SwiperComponent) {
- other.swiperRef.slideTo(self.swiperRef.activeIndex);
+ super(activatedRoute, calendarService, scheduleProvider);
+ const hoursAmount = this.hoursRange.to - this.hoursRange.from + 1;
+ this.hours = [...Array.from({length: hoursAmount}).keys()];
}
/**
- * Determine displayed dates according to display size
+ * Initialize
*/
- // @Override
- determineDisplayDates() {
- // let's boldly assume that we at least display one day
-
- const out = [moment(moment.now()).startOf(this.layout.startOf)];
- for (let i = 1; i < this.layout.days; i++) {
- out.push(out[0].clone().add(i, 'day'));
+ ngOnInit() {
+ super.onInit();
+ if (this.calendarServiceSubscription) {
+ this.calendarServiceSubscription.unsubscribe();
}
+ this.calendarServiceSubscription =
+ this.calendarService.goToDateClicked.subscribe(() => {
+ this.slideToToday();
+ });
+ }
- this.displayDates = [out];
+ ngAfterViewInit() {
+ this.slideToToday();
+ }
- // void this.mainSlides.slideTo(this.mode === 'schedule' ? 0 : 1, 0, false);
+ /**
+ * OnDestroy
+ */
+ ngOnDestroy(): void {
+ super.onDestroy();
+ }
+
+ /**
+ * Slide today into view.
+ */
+ slideToToday() {
+ const todayIndex = Number(moment().startOf('week').format('d')) + 1;
+ this.mainSwiper?.swiperRef.slideTo(todayIndex);
+ this.setDateRange(todayIndex);
}
/**
@@ -113,4 +178,15 @@ export class ScheduleViewComponent extends CalendarViewComponent {
return this.todaySlideIndex;
}
+
+ presentScheduleDatePopover(index: number, popoverDateTime: IonDatetime) {
+ const nextIndex =
+ moment(popoverDateTime.value).diff(this.baselineDate, 'days') -
+ this.headerSwiper.swiperRef.realIndex -
+ index;
+
+ this.mainSwiper.swiperRef.slideTo(nextIndex);
+ this.setDateRange(nextIndex);
+ popoverDateTime.confirm(true);
+ }
}
diff --git a/src/app/modules/schedule/page/schedule-view.html b/src/app/modules/schedule/page/schedule-view.html
index f95ffc3b..de538b76 100644
--- a/src/app/modules/schedule/page/schedule-view.html
+++ b/src/app/modules/schedule/page/schedule-view.html
@@ -6,72 +6,101 @@
~
~ 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
+ ~ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licens for
~ more details.
~
~ You should have received a copy of the GNU General Public License along with
~ this program. If not, see .
-->
-
-
-
-
+
-
+
+ {{ dateRange.startDate }} - {{ dateRange.endDate }}
+
+
+
+
+
+
+
+
+
+
+
+
-
{{ i + hoursRange.from }}:00
-
+
+
+
+ {{ i + hoursRange.from }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/modules/schedule/page/schedule-view.scss b/src/app/modules/schedule/page/schedule-view.scss
index 6398e1a9..72433d07 100644
--- a/src/app/modules/schedule/page/schedule-view.scss
+++ b/src/app/modules/schedule/page/schedule-view.scss
@@ -13,18 +13,6 @@
* this program. If not, see
.
*/
-.full-height {
- height: 100%;
-}
-
-.day-labels > ion-button[disabled] {
- opacity: 1;
-}
-
-.day-labels {
- ion-button {
- ion-label {
- overflow: visible !important;
- }
- }
+.swiper, .swiper-wrapper, .swiper-slide {
+ overflow: unset;
}
diff --git a/src/app/modules/schedule/page/schema/schema.ts b/src/app/modules/schedule/page/schema/schema.ts
index 92fd9488..faafb114 100644
--- a/src/app/modules/schedule/page/schema/schema.ts
+++ b/src/app/modules/schedule/page/schema/schema.ts
@@ -19,6 +19,8 @@ import {unitOfTime} from 'moment';
interface DateRange {
duration: SCISO8601Duration;
start: number;
+ startAsString?: string;
+ endAsString?: string;
}
export interface Range
{
diff --git a/src/app/modules/schedule/schedule.module.ts b/src/app/modules/schedule/schedule.module.ts
index 341a903b..da3369ea 100644
--- a/src/app/modules/schedule/schedule.module.ts
+++ b/src/app/modules/schedule/schedule.module.ts
@@ -36,6 +36,7 @@ import {ScheduleDayComponent} from './page/grid/schedule-day.component';
import {ThingTranslateModule} from '../../translation/thing-translate.module';
import {InfiniteSwiperComponent} from './page/grid/infinite-swiper.component';
import {FileOpener} from '@ionic-native/file-opener/ngx';
+import {CalendarComponent} from './page/components/calendar.component';
const settingsRoutes: Routes = [
{path: 'schedule', redirectTo: 'schedule/calendar/now'},
@@ -51,6 +52,7 @@ const settingsRoutes: Routes = [
*/
@NgModule({
declarations: [
+ CalendarComponent,
CalendarViewComponent,
ModalEventCreatorComponent,
ScheduleCardComponent,
diff --git a/src/app/modules/settings/item/settings-item.html b/src/app/modules/settings/item/settings-item.html
index 1bb980b3..e5b75d77 100644
--- a/src/app/modules/settings/item/settings-item.html
+++ b/src/app/modules/settings/item/settings-item.html
@@ -12,7 +12,7 @@
{{ vals.name }}
diff --git a/src/app/modules/settings/page/calendar-sync-settings.html b/src/app/modules/settings/page/calendar-sync-settings.html
index 0748719d..298279e7 100644
--- a/src/app/modules/settings/page/calendar-sync-settings.html
+++ b/src/app/modules/settings/page/calendar-sync-settings.html
@@ -66,7 +66,7 @@
(click)="syncCalendar(true)"
>
Sync Now
-
+
@@ -97,7 +97,7 @@
{{
'settings.calendar.export.backup' | translate
}}
-
+
{{
diff --git a/src/app/modules/settings/page/settings-page.html b/src/app/modules/settings/page/settings-page.html
index 12b36dff..ca0c6c3f 100644
--- a/src/app/modules/settings/page/settings-page.html
+++ b/src/app/modules/settings/page/settings-page.html
@@ -1,8 +1,10 @@
-
+
-
-
+
{{ 'settings.title' | translate | titlecase }}
@@ -43,6 +45,6 @@
(click)="presentResetAlert()"
>
{{ 'settings.resetSettings' | translate }}
-
+
diff --git a/src/app/modules/settings/settings.module.ts b/src/app/modules/settings/settings.module.ts
index 03c4f57f..dcc41454 100644
--- a/src/app/modules/settings/settings.module.ts
+++ b/src/app/modules/settings/settings.module.ts
@@ -33,6 +33,7 @@ import {ScheduleSyncService} from '../background/schedule/schedule-sync.service'
import {CalendarService} from '../calendar/calendar.service';
import {CalendarModule} from '../calendar/calendar.module';
import {BackgroundModule} from '../background/background.module';
+import {UtilModule} from '../../util/util.module';
const settingsRoutes: Routes = [
{path: 'settings', component: SettingsPageComponent},
@@ -58,6 +59,7 @@ const settingsRoutes: Routes = [
TranslateModule.forChild(),
ThingTranslateModule.forChild(),
RouterModule.forChild(settingsRoutes),
+ UtilModule,
],
providers: [
ScheduleSyncService,
diff --git a/src/app/translation/i18n.spec.ts b/src/app/translation/i18n.spec.ts
index c6e7e105..b957a42e 100644
--- a/src/app/translation/i18n.spec.ts
+++ b/src/app/translation/i18n.spec.ts
@@ -28,6 +28,10 @@ const exceptions = new Set([
'ejournal',
'backup',
'export',
+ 'dashboard',
+ 'home',
+ 'email',
+ 'logins',
]);
const languages = [
diff --git a/src/app/util/daytime-key.pipe.ts b/src/app/util/daytime-key.pipe.ts
new file mode 100644
index 00000000..5aa8f6e6
--- /dev/null
+++ b/src/app/util/daytime-key.pipe.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 .
+ */
+
+import {Injectable, Pipe, PipeTransform} from '@angular/core';
+import moment from 'moment';
+
+/**
+ * Return the extended translation key by the current daytime key
+ */
+@Injectable()
+@Pipe({
+ name: 'daytimeKey',
+})
+export class DaytimeKeyPipe implements PipeTransform {
+ /**
+ * Transform
+ */
+ transform(translationKey: string): string {
+ const hour = Number.parseInt(moment().format('HH'), 10);
+ let key = '';
+ if (hour >= 5 && hour <= 10) {
+ key = 'morning';
+ } else if (hour >= 11 && hour <= 18) {
+ key = 'day';
+ } else if (hour >= 19 && hour <= 23) {
+ key = 'evening';
+ } else {
+ key = 'night';
+ }
+
+ return `${translationKey}_${key}`;
+ }
+}
diff --git a/src/app/util/ion-back-button.directive.ts b/src/app/util/ion-back-button.directive.ts
new file mode 100644
index 00000000..aca2f7fb
--- /dev/null
+++ b/src/app/util/ion-back-button.directive.ts
@@ -0,0 +1,59 @@
+import {Directive, HostListener, Input, Optional} from '@angular/core';
+import {
+ AnimationBuilder,
+ Config,
+ IonBackButtonDelegate,
+ IonRouterOutlet,
+ NavController,
+} from '@ionic/angular';
+
+/**
+ * Overrides the default ion-back-button directive.
+ *
+ * @see https://github.com/ionic-team/ionic-framework/blob/main/angular/src/directives/navigation/ion-back-button.ts
+ */
+@Directive({
+ selector: 'ion-back-button',
+})
+export class IonBackButtonOverrideDirective {
+ @Input()
+ defaultHref: string | undefined | null;
+
+ @Input()
+ routerAnimation?: AnimationBuilder;
+
+ constructor(
+ @Optional() private routerOutlet: IonRouterOutlet,
+ private navCtrl: NavController,
+ private config: Config,
+ private ionBackButton: IonBackButtonDelegate,
+ ) {
+ this.ionBackButton.onClick = () => {
+ // Override default onClick to prevent double execution and errors
+ };
+ }
+
+ @HostListener('click', ['$event'])
+ onClick(event: Event): void {
+ const defaultHref =
+ this.defaultHref || this.config.get('backButtonDefaultHref');
+
+ // Handle back via angular navCtrl.back()
+ // (which is animated, instead of location.back)
+ if (defaultHref === '..') {
+ this.navCtrl.back();
+ } else if (this.routerOutlet?.canGoBack()) {
+ this.navCtrl.setDirection(
+ 'back',
+ undefined,
+ undefined,
+ this.routerAnimation,
+ );
+ this.routerOutlet.pop();
+ event.preventDefault();
+ } else if (defaultHref != undefined) {
+ this.navCtrl.navigateBack(defaultHref, {animation: this.routerAnimation});
+ event.preventDefault();
+ }
+ }
+}
diff --git a/src/app/util/next-date-in-list.pipe.ts b/src/app/util/next-date-in-list.pipe.ts
new file mode 100644
index 00000000..17efc92b
--- /dev/null
+++ b/src/app/util/next-date-in-list.pipe.ts
@@ -0,0 +1,41 @@
+/*
+ * 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 .
+ */
+
+import {Injectable, Pipe, PipeTransform} from '@angular/core';
+import moment from 'moment';
+
+/**
+ * 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
+})
+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 || '';
+ }
+}
diff --git a/src/app/util/util.module.ts b/src/app/util/util.module.ts
index c0ad4a6a..a357d840 100644
--- a/src/app/util/util.module.ts
+++ b/src/app/util/util.module.ts
@@ -18,7 +18,10 @@ 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 {IonBackButtonOverrideDirective} from './ion-back-button.directive';
@NgModule({
declarations: [
@@ -27,6 +30,9 @@ import {LazyPipe} from './lazy.pipe';
NullishCoalescingPipe,
LazyPipe,
DateFromIndexPipe,
+ DaytimeKeyPipe,
+ NextDateInListPipe,
+ IonBackButtonOverrideDirective,
],
exports: [
ArrayLastPipe,
@@ -34,6 +40,9 @@ import {LazyPipe} from './lazy.pipe';
NullishCoalescingPipe,
LazyPipe,
DateFromIndexPipe,
+ DaytimeKeyPipe,
+ NextDateInListPipe,
+ IonBackButtonOverrideDirective,
],
})
export class UtilModule {}
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 9fab6acf..41c4a277 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -1,10 +1,14 @@
{
"ok": "Ok",
"abort": "Abbrechen",
+ "save": "Speichern",
+ "back" : "Zurück",
"export": "Exportieren",
"share": "Teilen",
+ "timeSuffix": "Uhr",
"modal": {
- "DISMISS": "Schließen"
+ "DISMISS": "Schließen",
+ "settings": "Einstellungen"
},
"app": {
"ui": {
@@ -16,6 +20,13 @@
"UNKNOWN": "Unbekannter Fehler."
}
},
+ "tabs": {
+ "home": "Home",
+ "canteens": "Mensa",
+ "schedule": "Studium",
+ "map": "Karte",
+ "profile": "Profil"
+ },
"assessments": {
"TITLE": "Noten",
"courseOfStudyAssessments": {
@@ -45,6 +56,47 @@
"opening_soon": "Öffnet"
}
},
+ "dashboard": {
+ "header": {
+ "title_morning": "Guten Morgen",
+ "title_day": "Guten Tag",
+ "title_evening": "Guten Abend",
+ "title_night": "Hallo"
+ },
+ "navigation": {
+ "title": "Dashboard",
+ "item": {
+ "catalog": "Vorlesungsv.",
+ "canteen": "Mensa",
+ "map": "Campus",
+ "settings": "Einstellungen",
+ "search": "Suche"
+ }
+ },
+ "news": {
+ "title": "Aktuelles",
+ "moreNews": "Mehr Nachrichten"
+ },
+ "schedule": {
+ "title": "Nächste Einheit",
+ "noEvent": "Kein Eintrag gefunden",
+ "noEventLink": "Jetzt Termine im Stundenplan hinzufügen."
+ },
+ "canteens": {
+ "title": "Deine Mensa",
+ "no_favorite_prefix": "Du hast noch keine Mensa als deinen Favoriten markiert. Nutze die",
+ "no_favorite_link": "Übersicht der Mensen",
+ "no_favorite_suffix": "um einen Favorit zu wählen.",
+ "choose_favorite": "Wähle einen Favorit",
+ "no_dishes_available": "Aktuell sind keine Gerichte verfügbar."
+ },
+ "favorites": {
+ "title": "Deine Favoriten",
+ "no_favorite_prefix": "Du hast noch keine Favoriten markiert. Nutze die",
+ "no_favorite_link": "Suche",
+ "no_favorite_suffix": "um Favoriten zu wählen."
+ }
+ },
"data": {
"REFRESH_ACTION": "Aktualisieren",
"REFRESHING": "Aktualisierung läuft...",
@@ -268,16 +320,24 @@
}
},
"news": {
- "title": "Aktuelles"
+ "title": "Aktuelles",
+ "publishedOn": "News vom"
+ },
+ "canteens": {
+ "title": "Mensa"
},
"search": {
+ "title": "Universal Suche",
+ "type": "Suche",
"search_bar": {
- "placeholder": "Suche ..."
+ "placeholder": "Suche nach News, Räumen, Personen ..."
},
"instruction": "Starte oben zu tippen, um Veranstaltungen, Veranstaltungstermine, Personen, Orte, Essen und mehr zu finden ...",
"nothing_found": "Keine Ergebnisse"
},
"hebisSearch": {
+ "title": "Bibliothekssuche",
+ "type": "Bibliothek",
"search_bar": {
"placeholder": "Suche ..."
},
@@ -334,6 +394,9 @@
}
}
},
+ "view": {
+ "today": "Heute"
+ },
"recurring": "Stundenplan",
"calendar": "Kalender",
"single": "Einzeltermine",
@@ -354,6 +417,9 @@
},
"profile": {
"title": "Profil",
+ "titleLogins": "Logins",
+ "titleCourses": "Meine Kurse",
+ "role_guest": "Gastnutzer",
"buttons": {
"default": {
"log_in": "Login",
@@ -365,7 +431,14 @@
}
},
"userInfo": {
- "studentId": "Matrikelnr."
+ "studentId": "Matrikelnr.",
+ "username": "Nutzer Name",
+ "email": "Email",
+ "logInPrompt": "Bitte loggen Sie sich ein, um Ihre Nutzerdaten sehen zu können."
+ },
+ "courses": {
+ "today": "Heute",
+ "no_courses": "Heute stehen keine Termine mehr an."
}
},
"settings": {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 9d31fcbf..aaf12186 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -1,10 +1,14 @@
{
"ok": "Ok",
"abort": "Abort",
+ "save": "Save",
+ "back" : "back",
"export": "Export",
"share": "Share",
+ "timeSuffix": "",
"modal": {
- "DISMISS": "Close"
+ "DISMISS": "Close",
+ "settings": "Settings"
},
"app": {
"ui": {
@@ -16,6 +20,13 @@
"UNKNOWN": "Unknown problem."
}
},
+ "tabs": {
+ "home": "Home",
+ "canteens": "Canteens",
+ "schedule": "Study",
+ "map": "Map",
+ "profile": "Profile"
+ },
"assessments": {
"TITLE": "Grades",
"courseOfStudyAssessments": {
@@ -45,6 +56,47 @@
"opening_soon": "Opens"
}
},
+ "dashboard": {
+ "header": {
+ "title_morning": "Good Morning",
+ "title_day": "Good Day",
+ "title_evening": "Good Evening",
+ "title_night": "Hello"
+ },
+ "navigation": {
+ "title": "Dashboard",
+ "item": {
+ "catalog": "Course Catalog",
+ "canteen": "Canteens",
+ "map": "Map",
+ "settings": "Settings",
+ "search": "Search"
+ }
+ },
+ "news": {
+ "title": "News",
+ "moreNews": "More News"
+ },
+ "schedule": {
+ "title": "Next Unit",
+ "noEvent": "No entry found",
+ "noEventLink": "Add appointments to the timetable now."
+ },
+ "canteens": {
+ "title": "Your canteen",
+ "no_favorite_prefix": "You haven't yet marked a canteen as your favorite. Use the",
+ "no_favorite_link": "overview of the canteens",
+ "no_favorite_suffix": "to mark a favorite.",
+ "choose_favorite": "Mark a favorite",
+ "no_dishes_available": "There are currently no dishes available."
+ },
+ "favorites": {
+ "title": "Your favorites",
+ "no_favorite_prefix": "You have not yet marked any favorites. Use the",
+ "no_favorite_link": "Search",
+ "no_favorite_suffix": "to choose favorites."
+ }
+ },
"data": {
"REFRESH_ACTION": "Refresh",
"REFRESHING": "Refreshing...",
@@ -268,16 +320,24 @@
}
},
"news": {
- "title": "News"
+ "title": "News",
+ "publishedOn": "News of"
+ },
+ "canteens": {
+ "title": "Canteens"
},
"search": {
+ "title": "Universal Search",
+ "type": "Search",
"search_bar": {
- "placeholder": "Search ..."
+ "placeholder": "Search for news, rooms, persons ..."
},
"instruction": "Start typing above to find events, persons, places, food and more ...",
"nothing_found": "No results"
},
"hebisSearch": {
+ "title": "Library Search",
+ "type": "Library",
"search_bar": {
"placeholder": "Search ..."
},
@@ -334,6 +394,9 @@
}
}
},
+ "view": {
+ "today": "Today"
+ },
"recurring": "Recurring",
"calendar": "Calendar",
"single": "Single Events",
@@ -354,6 +417,9 @@
},
"profile": {
"title": "Profile",
+ "titleLogins": "Logins",
+ "titleCourses": "My Courses",
+ "role_guest": "guest user",
"buttons": {
"default": {
"log_in": "Log In",
@@ -365,7 +431,14 @@
}
},
"userInfo": {
- "studentId": "Matriculation Nr."
+ "studentId": "Matriculation Nr.",
+ "username": "Username",
+ "email": "Email",
+ "logInPrompt": "Please log in to view your user data."
+ },
+ "courses": {
+ "today": "Today",
+ "no_courses": "There are no more appointments scheduled today."
}
},
"settings": {
diff --git a/src/assets/imgs/profile-card-head.jpeg b/src/assets/imgs/profile-card-head.jpeg
new file mode 100644
index 00000000..df9b4360
Binary files /dev/null and b/src/assets/imgs/profile-card-head.jpeg differ
diff --git a/src/assets/imgs/uni-frankfurt/goethe.jpeg b/src/assets/imgs/uni-frankfurt/goethe.jpeg
new file mode 100644
index 00000000..df9b4360
Binary files /dev/null and b/src/assets/imgs/uni-frankfurt/goethe.jpeg differ
diff --git a/src/assets/imgs/uni-frankfurt/logo.svg b/src/assets/imgs/uni-frankfurt/logo.svg
new file mode 100644
index 00000000..d2e0cbc2
--- /dev/null
+++ b/src/assets/imgs/uni-frankfurt/logo.svg
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/tabler-icons/arrow-loop-left.svg b/src/assets/tabler-icons/arrow-loop-left.svg
index bc1cbcaa..70ea7929 100644
--- a/src/assets/tabler-icons/arrow-loop-left.svg
+++ b/src/assets/tabler-icons/arrow-loop-left.svg
@@ -1,7 +1,7 @@
-
+
diff --git a/src/assets/tabler-icons/arrow-loop-right.svg b/src/assets/tabler-icons/arrow-loop-right.svg
index 351fac07..4f69ae6b 100644
--- a/src/assets/tabler-icons/arrow-loop-right.svg
+++ b/src/assets/tabler-icons/arrow-loop-right.svg
@@ -1,7 +1,7 @@
-
+
diff --git a/src/assets/tabler-icons/brand-vk.svg b/src/assets/tabler-icons/brand-vk.svg
index 1ecee228..d7e81e3f 100644
--- a/src/assets/tabler-icons/brand-vk.svg
+++ b/src/assets/tabler-icons/brand-vk.svg
@@ -1,6 +1,8 @@
-
+
+
+
diff --git a/src/assets/tabler-icons/bulb-off.svg b/src/assets/tabler-icons/bulb-off.svg
index 86b1433b..68e79900 100644
--- a/src/assets/tabler-icons/bulb-off.svg
+++ b/src/assets/tabler-icons/bulb-off.svg
@@ -1,9 +1,7 @@
-
-
-
-
+
+
diff --git a/src/assets/tabler-icons/cardboards.svg b/src/assets/tabler-icons/cardboards.svg
index 490074bd..4b0cd7bb 100644
--- a/src/assets/tabler-icons/cardboards.svg
+++ b/src/assets/tabler-icons/cardboards.svg
@@ -1,8 +1,8 @@
-
-
-
+
+
+
diff --git a/src/assets/tabler-icons/cloud.svg b/src/assets/tabler-icons/cloud.svg
index a5345f6d..1bda7e15 100644
--- a/src/assets/tabler-icons/cloud.svg
+++ b/src/assets/tabler-icons/cloud.svg
@@ -1,6 +1,6 @@
-
+
diff --git a/src/assets/tabler-icons/currency-bath.svg b/src/assets/tabler-icons/currency-bath.svg
new file mode 100644
index 00000000..4051da0e
--- /dev/null
+++ b/src/assets/tabler-icons/currency-bath.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/tabler-icons/device-mobile-rotated.svg b/src/assets/tabler-icons/device-mobile-rotated.svg
index 491d7758..6c9bc749 100644
--- a/src/assets/tabler-icons/device-mobile-rotated.svg
+++ b/src/assets/tabler-icons/device-mobile-rotated.svg
@@ -1,8 +1,10 @@
-
-
-
+
+
+
+
+
diff --git a/src/assets/tabler-icons/device-mobile-vibration.svg b/src/assets/tabler-icons/device-mobile-vibration.svg
index d0ea731e..a53750a5 100644
--- a/src/assets/tabler-icons/device-mobile-vibration.svg
+++ b/src/assets/tabler-icons/device-mobile-vibration.svg
@@ -1,9 +1,9 @@
-
-
+
+
-
+
diff --git a/src/assets/tabler-icons/device-mobile.svg b/src/assets/tabler-icons/device-mobile.svg
index 378e2053..667bd813 100644
--- a/src/assets/tabler-icons/device-mobile.svg
+++ b/src/assets/tabler-icons/device-mobile.svg
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/assets/tabler-icons/directions.svg b/src/assets/tabler-icons/directions.svg
index 819c6e71..b036bfab 100644
--- a/src/assets/tabler-icons/directions.svg
+++ b/src/assets/tabler-icons/directions.svg
@@ -1,11 +1,10 @@
-
-
-
-
-
-
+
+
+
+
+
diff --git a/src/assets/tabler-icons/edit.svg b/src/assets/tabler-icons/edit.svg
index 07540044..316a8a8d 100644
--- a/src/assets/tabler-icons/edit.svg
+++ b/src/assets/tabler-icons/edit.svg
@@ -1,8 +1,8 @@
-
-
-
+
+
+
diff --git a/src/assets/tabler-icons/eraser.svg b/src/assets/tabler-icons/eraser.svg
index 36a2cc5a..1e4ff1e8 100644
--- a/src/assets/tabler-icons/eraser.svg
+++ b/src/assets/tabler-icons/eraser.svg
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/assets/tabler-icons/file-download.svg b/src/assets/tabler-icons/file-download.svg
index 942b215a..1f5d958a 100644
--- a/src/assets/tabler-icons/file-download.svg
+++ b/src/assets/tabler-icons/file-download.svg
@@ -2,8 +2,8 @@
-
-
+
+
diff --git a/src/assets/tabler-icons/file-upload.svg b/src/assets/tabler-icons/file-upload.svg
index f86ab859..f062fd80 100644
--- a/src/assets/tabler-icons/file-upload.svg
+++ b/src/assets/tabler-icons/file-upload.svg
@@ -2,8 +2,8 @@
-
-
+
+
diff --git a/src/assets/tabler-icons/hammer.svg b/src/assets/tabler-icons/hammer.svg
index cd517425..63942ebf 100644
--- a/src/assets/tabler-icons/hammer.svg
+++ b/src/assets/tabler-icons/hammer.svg
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/assets/tabler-icons/hanger.svg b/src/assets/tabler-icons/hanger.svg
index 59fdc04c..7c88b1f4 100644
--- a/src/assets/tabler-icons/hanger.svg
+++ b/src/assets/tabler-icons/hanger.svg
@@ -1,6 +1,6 @@
-
+
diff --git a/src/assets/tabler-icons/heart-broken.svg b/src/assets/tabler-icons/heart-broken.svg
index 0afc1847..79fa2b93 100644
--- a/src/assets/tabler-icons/heart-broken.svg
+++ b/src/assets/tabler-icons/heart-broken.svg
@@ -1,7 +1,7 @@
-
-
+
+
diff --git a/src/assets/tabler-icons/heart.svg b/src/assets/tabler-icons/heart.svg
index 8747966f..56211a9b 100644
--- a/src/assets/tabler-icons/heart.svg
+++ b/src/assets/tabler-icons/heart.svg
@@ -1,6 +1,6 @@
-
+
diff --git a/src/assets/tabler-icons/letters-case.svg b/src/assets/tabler-icons/letters-case.svg
new file mode 100644
index 00000000..e8e16df8
--- /dev/null
+++ b/src/assets/tabler-icons/letters-case.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/assets/tabler-icons/miliraty-award.svg b/src/assets/tabler-icons/miliraty-award.svg
new file mode 100644
index 00000000..53c2cd79
--- /dev/null
+++ b/src/assets/tabler-icons/miliraty-award.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/src/assets/tabler-icons/plug.svg b/src/assets/tabler-icons/plug.svg
index 6ea4a764..63c4b2d5 100644
--- a/src/assets/tabler-icons/plug.svg
+++ b/src/assets/tabler-icons/plug.svg
@@ -1,9 +1,9 @@
-
-
-
-
+
+
+
+
diff --git a/src/assets/tabler-icons/smart-home.svg b/src/assets/tabler-icons/smart-home.svg
index b340c22a..7c3e1cc8 100644
--- a/src/assets/tabler-icons/smart-home.svg
+++ b/src/assets/tabler-icons/smart-home.svg
@@ -1,6 +1,7 @@
+
diff --git a/src/assets/tabler-icons/test-pipe.svg b/src/assets/tabler-icons/test-pipe.svg
index 0b7b3d61..14c00e6b 100644
--- a/src/assets/tabler-icons/test-pipe.svg
+++ b/src/assets/tabler-icons/test-pipe.svg
@@ -1,9 +1,8 @@
-
-
-
-
+
+
+
diff --git a/src/assets/tabler-icons/vector-beizer-2.svg b/src/assets/tabler-icons/vector-beizer-2.svg
new file mode 100644
index 00000000..1697d014
--- /dev/null
+++ b/src/assets/tabler-icons/vector-beizer-2.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/global.scss b/src/global.scss
index 984392f2..51255ffc 100644
--- a/src/global.scss
+++ b/src/global.scss
@@ -37,7 +37,7 @@ ion-item {
font-weight: bold;
}
ion-thumbnail {
- background: var(--placeholder-gray);
+ background: transparent;
--size: 36px;
display: flex;
align-items: center;
diff --git a/src/index.html b/src/index.html
index 7046d987..c39e6c12 100644
--- a/src/index.html
+++ b/src/index.html
@@ -24,7 +24,7 @@
-
+
diff --git a/src/theme/_fonts.scss b/src/theme/_fonts.scss
new file mode 100644
index 00000000..f6ac0dbe
--- /dev/null
+++ b/src/theme/_fonts.scss
@@ -0,0 +1,37 @@
+@font-face {
+ font-family: 'Barlow';
+ src: url('../assets/fonts/barlow/Barlow-Regular.ttf');
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: 'Barlow';
+ src: url('../assets/fonts/barlow/Barlow-SemiBold.ttf');
+ font-weight: 700;
+ font-style: normal;
+}
+@font-face {
+ font-family: 'Barlow';
+ src: url('../assets/fonts/barlow/Barlow-Bold.ttf');
+ font-weight: 800;
+ font-style: normal;
+}
+@font-face {
+ font-family: 'Barlow Condensed';
+ src: url('../assets/fonts/barlow_condensed/BarlowCondensed-Regular.ttf');
+ font-weight: 400;
+ font-style: normal;
+}
+@font-face {
+ font-family: 'Barlow Condensed';
+ src: url('../assets/fonts/barlow_condensed/BarlowCondensed-SemiBold.ttf');
+ font-weight: 700;
+ font-style: normal;
+}
+@font-face {
+ font-family: 'Barlow Condensed';
+ src: url('../assets/fonts/barlow_condensed/BarlowCondensed-Bold.ttf');
+ font-weight: 800;
+ font-style: normal;
+}
+
diff --git a/src/theme/common/_helper.scss b/src/theme/common/_helper.scss
new file mode 100644
index 00000000..418e274f
--- /dev/null
+++ b/src/theme/common/_helper.scss
@@ -0,0 +1,11 @@
+.no-padding-right {
+ padding-right: 0 !important;
+}
+
+.display-flex {
+ display: flex;
+}
+
+.clickable {
+ cursor: pointer;
+}
diff --git a/src/theme/common/_ion-button.scss b/src/theme/common/_ion-button.scss
new file mode 100644
index 00000000..338e9e69
--- /dev/null
+++ b/src/theme/common/_ion-button.scss
@@ -0,0 +1,42 @@
+
+
+app-root {
+ // Change default border radius
+ ion-buttons ion-button.button,
+ .button {
+ &:not(.button-round) {
+ --border-radius: var(--border-radius-default);
+ }
+ }
+
+ .button {
+ font-size: var(--font-size-sm);
+ font-weight: var(--font-weight-semi-bold);
+ --padding-top: var(--spacing-sm);
+ --padding-bottom: var(--spacing-sm);
+ height: auto;
+
+
+ // Add default border, so buttons have the same size
+ &:not([fill='outline'])::part(native) {
+ border: var(--border-width-default) solid transparent;
+ }
+
+ &[fill='outline']::part(native) {
+ border: var(--border-width-default) solid rgba(var(--ion-color-primary-contrast-rgb), 0.2);
+ }
+
+ &.button-active {
+ font-weight: var(--font-weight-bold);
+ --background: var(--ion-color-tertiary);
+
+ ion-icon {
+ color: var(--ion-color-secondary);
+ }
+ }
+ }
+
+ ion-menu-button.button {
+ font-size: var(--font-size-lg);
+ }
+}
diff --git a/src/theme/common/_ion-header.scss b/src/theme/common/_ion-header.scss
new file mode 100644
index 00000000..b08d3731
--- /dev/null
+++ b/src/theme/common/_ion-header.scss
@@ -0,0 +1,5 @@
+app-root ion-header[class*='header-'] {
+ &:after {
+ background-image: unset;
+ }
+}
diff --git a/src/theme/common/_ion-img.scss b/src/theme/common/_ion-img.scss
new file mode 100644
index 00000000..5d088c38
--- /dev/null
+++ b/src/theme/common/_ion-img.scss
@@ -0,0 +1,5 @@
+app-root {
+ ion-thumbnail {
+ background: transparent;
+ }
+}
diff --git a/src/theme/common/_ion-input.scss b/src/theme/common/_ion-input.scss
new file mode 100644
index 00000000..2838c006
--- /dev/null
+++ b/src/theme/common/_ion-input.scss
@@ -0,0 +1,40 @@
+$icon-size: 23px;
+
+app-root ion-searchbar[class*='sc-ion-searchbar-'] {
+ --border-radius: var(--border-radius-default);
+ padding-top: 0;
+ padding-bottom: 0;
+ height: 38px;
+
+ &.filterable {
+ padding-left: 0;
+ padding-right: 0;
+ --box-shadow: none;
+ position: relative;
+
+ ion-menu-button {
+ position: absolute;
+ right: 5px;
+ z-index: 1;
+ }
+
+ .searchbar-clear-button {
+ right: 45px;
+ }
+ }
+
+ ion-icon.searchbar-search-icon {
+ width: $icon-size;
+ height: $icon-size;
+ top: 50%;
+ transform: translateY(-50%);
+ left: var(--spacing-sm);
+ color: var(--ion-color-medium-shade);
+ }
+
+ input.searchbar-input {
+ padding-top: var(--spacing-xs);
+ padding-bottom: var(--spacing-xs);
+ padding-left: calc(var(--spacing-lg) + #{$icon-size});
+ }
+}
diff --git a/src/theme/common/_ion-modal.scss b/src/theme/common/_ion-modal.scss
new file mode 100644
index 00000000..596253bb
--- /dev/null
+++ b/src/theme/common/_ion-modal.scss
@@ -0,0 +1,12 @@
+@import '../../theme/util/mixins';
+
+ion-modal {
+ &.modal-large {
+ --height: 100%;
+
+ @include ion-md-up {
+ --height: 70vh;
+ --max-height: 800px;
+ }
+ }
+}
diff --git a/src/theme/common/_ion-popover.scss b/src/theme/common/_ion-popover.scss
new file mode 100644
index 00000000..ff60da92
--- /dev/null
+++ b/src/theme/common/_ion-popover.scss
@@ -0,0 +1,4 @@
+.sc-ion-popover-ios-h,
+.sc-ion-popover-md-h {
+ --width: 98vw
+}
diff --git a/src/theme/common/_ion-refresher.scss b/src/theme/common/_ion-refresher.scss
new file mode 100644
index 00000000..d3e9d9ef
--- /dev/null
+++ b/src/theme/common/_ion-refresher.scss
@@ -0,0 +1,13 @@
+
+ion-refresher {
+ background-color: var(--ion-color-primary);
+ text-transform: uppercase;
+
+ .refresher-pulling-icon,
+ .refresher-pulling-text,
+ .refresher-refreshing-text {
+ font-size: var(--font-size-xs);
+ font-weight: var(--font-weight-semi-bold);
+ --ion-text-color: var(--ion-color-primary-contrast);
+ }
+}
diff --git a/src/theme/common/_ion-toolbar.scss b/src/theme/common/_ion-toolbar.scss
new file mode 100644
index 00000000..caeb7328
--- /dev/null
+++ b/src/theme/common/_ion-toolbar.scss
@@ -0,0 +1,53 @@
+app-root ion-toolbar.in-toolbar {
+ --background: var(--ion-color-primary);
+ --border-color: var(--ion-color-primary);
+ --color: var(--ion-color-primary-contrast);
+ --ion-toolbar-color: var(--ion-color-primary-contrast);
+ --min-height: unset;
+ --padding-start: 0;
+ --padding-end: 0;
+ --padding-top: 0;
+ --padding-bottom: 0;
+ --opacity: 1;
+ padding: 0 var(--spacing-md) var(--spacing-md);
+
+ &:last-of-type {
+ padding-bottom: var(--spacing-md);
+ --padding-top: 0;
+ --padding-bottom: 0;
+ }
+
+ ion-searchbar {
+ padding-left: 0;
+ padding-right: 0;
+ --box-shadow: none;
+ }
+
+ ion-menu-button.filter {
+ --padding-start: var(--spacing-lg);
+ --padding-end: var(--spacing-lg);
+
+ ion-icon {
+ margin-right: var(--spacing-md);
+ font-size: var(--font-size-lg);
+ }
+ }
+
+ ion-title {
+ font-weight: var(--font-weight-black);
+ font-size: var(--font-size-lg);
+ text-transform: uppercase;
+ }
+
+ ion-button {
+ text-transform: uppercase;
+ }
+ ion-menu-button {
+ width: auto;
+ }
+
+ ion-back-button {
+ --icon-margin-end: var(--spacing-xs);
+ height: 42px; // this prevents the back button to become a .x px value
+ }
+}
diff --git a/src/theme/common/_swiper.scss b/src/theme/common/_swiper.scss
new file mode 100644
index 00000000..560da9da
--- /dev/null
+++ b/src/theme/common/_swiper.scss
@@ -0,0 +1,38 @@
+@import '../../theme/util/mixins';
+
+.swiper.card-swiper {
+ overflow: visible;
+ padding-right: var(--spacing-lg);
+
+ .swiper-slide {
+ display: flex;
+ flex-direction: column;
+ height: auto; // required for same height of cards
+
+
+ a {
+ color: var(--ion-color-text);
+ text-decoration: none;
+ }
+ }
+ .swiper-button-prev, .swiper-button-next {
+ --swiper-navigation-size: 20px;
+ top: calc(-1 * var(--spacing-xxl));
+ transform: translateY(0%);
+ font-weight: var(--font-weight-black);
+ color: var(--ion-color-dark);
+
+ @include ion-md-down {
+ display: none;
+ }
+ }
+
+ .swiper-button-prev {
+ right: 30px;
+ left: auto;
+ }
+
+ .swiper-button-next {
+ right: 0;
+ }
+}
diff --git a/src/theme/common/_typo.scss b/src/theme/common/_typo.scss
new file mode 100644
index 00000000..b2709bb7
--- /dev/null
+++ b/src/theme/common/_typo.scss
@@ -0,0 +1,14 @@
+body app-root {
+ .title,
+ .title-sub,
+ .title[class*='sc-ion-label'],
+ .title-sub[class*='sc-ion-label'] {
+ font-size: var(--font-size-md);
+ font-weight: var(--font-weight-semi-bold);
+ // TODO Condensed Font
+ }
+
+ .title-sub {
+ color: var(--ion-color-primary);
+ }
+}
diff --git a/src/theme/common/_typography.scss b/src/theme/common/_typography.scss
new file mode 100644
index 00000000..71af95b7
--- /dev/null
+++ b/src/theme/common/_typography.scss
@@ -0,0 +1,3 @@
+a {
+ cursor: pointer;
+}
diff --git a/src/theme/components/_card.scss b/src/theme/components/_card.scss
new file mode 100644
index 00000000..3379e3a1
--- /dev/null
+++ b/src/theme/components/_card.scss
@@ -0,0 +1,21 @@
+.card {
+ box-shadow: var(--shadow-cards);
+ background-color: var(--ion-color-primary-contrast);
+ border-radius: var(--border-radius-default);
+ padding: var(--spacing-md);
+ font-size: var(--font-size-sm);
+ font-weight: var(--font-weight-bold);
+ text-align: left;
+ display: block;
+ height: 100%;
+ transition: transform 250ms ease-in-out,
+ box-shadow 250ms ease-in-out;
+}
+
+a.card,
+.card.clickable {
+ &:hover {
+ transform: translate(-5px, -5px);
+ box-shadow: var(--shadow-cards-hover);
+ }
+}
diff --git a/src/theme/components/_section.scss b/src/theme/components/_section.scss
new file mode 100644
index 00000000..5c8a06d4
--- /dev/null
+++ b/src/theme/components/_section.scss
@@ -0,0 +1,12 @@
+.section-headline {
+ font-size: var(--font-size-lg);
+ font-weight: var(--font-weight-black);
+ font-stretch: condensed;
+ text-transform: uppercase;
+ margin-bottom: var(--spacing-xs);
+
+ width: 100%;
+ display: flex;
+ flex-direction: revert;
+ justify-content: space-between;
+}
diff --git a/src/theme/configs/goethe-uni-frankfurt.scss b/src/theme/configs/goethe-uni-frankfurt.scss
new file mode 100644
index 00000000..a1d80a74
--- /dev/null
+++ b/src/theme/configs/goethe-uni-frankfurt.scss
@@ -0,0 +1,137 @@
+:root {
+ --ion-color-primary: #00618F;
+ --ion-color-primary-rgb: 0,97,143;
+ --ion-color-primary-contrast: #ffffff;
+ --ion-color-primary-contrast-rgb: 255,255,255;
+ --ion-color-primary-shade: #00557e;
+ --ion-color-primary-tint: #1a719a;
+
+ --ion-color-secondary: #2fd2f5;
+ --ion-color-secondary-rgb: 47,210,245;
+ --ion-color-secondary-contrast: #000000;
+ --ion-color-secondary-contrast-rgb: 0,0,0;
+ --ion-color-secondary-shade: #29b9d8;
+ --ion-color-secondary-tint: #44d7f6;
+
+ --ion-color-tertiary: #00334d;
+ --ion-color-tertiary-rgb: 0,51,77;
+ --ion-color-tertiary-contrast: #ffffff;
+ --ion-color-tertiary-contrast-rgb: 255,255,255;
+ --ion-color-tertiary-shade: #002d44;
+ --ion-color-tertiary-tint: #1a475f;
+
+ --ion-color-success: #2dd36f;
+ --ion-color-success-rgb: 45,211,111;
+ --ion-color-success-contrast: #000000;
+ --ion-color-success-contrast-rgb: 0,0,0;
+ --ion-color-success-shade: #28ba62;
+ --ion-color-success-tint: #42d77d;
+
+ --ion-color-warning: #ffc409;
+ --ion-color-warning-rgb: 255,196,9;
+ --ion-color-warning-contrast: #000000;
+ --ion-color-warning-contrast-rgb: 0,0,0;
+ --ion-color-warning-shade: #e0ac08;
+ --ion-color-warning-tint: #ffca22;
+
+ --ion-color-danger: #eb445a;
+ --ion-color-danger-rgb: 235,68,90;
+ --ion-color-danger-contrast: #ffffff;
+ --ion-color-danger-contrast-rgb: 255,255,255;
+ --ion-color-danger-shade: #cf3c4f;
+ --ion-color-danger-tint: #ed576b;
+
+ --ion-color-medium: #d1d2d3;
+ --ion-color-medium-rgb: 209,210,211;
+ --ion-color-medium-contrast: #000000;
+ --ion-color-medium-contrast-rgb: 0,0,0;
+ --ion-color-medium-shade: #b8b9ba;
+ --ion-color-medium-tint: #d6d7d7;
+
+ --ion-color-light: #ebedec;
+ --ion-color-light-rgb: 235,237,236;
+ --ion-color-light-contrast: #000000;
+ --ion-color-light-contrast-rgb: 0,0,0;
+ --ion-color-light-shade: #cfd1d0;
+ --ion-color-light-tint: #edefee;
+
+
+ --ion-color-text: #000;
+ --ion-color-field-bg: #fff;
+ --ion-color-light-icon: #e6e6e6;
+
+
+ --linear-gradient: linear-gradient(135deg, var(--ion-color-primary-shade), var(--ion-color-tertiary));
+
+
+ // Shadows
+ --shadow-default: 0px 0px 10px 4px #ddd;
+ --shadow-cards: 0 0 8px 1px #ddd;
+ --shadow-cards-hover: 5px 5px 8px 4px #ccc;
+ --shadow-profile-card: 0 2px 6px 6px rgba(0,0,0,0.06),
+ 0 4px 5px 12px rgba(0,0,0,0.04),
+ 0 5px 6px 20px rgba(0,0,0,0.02);
+
+
+ // Fonts
+ --ion-font-family: "Barlow",Helvetica,Arial,sans-serif;
+ --headline-font-family: "Barlow Condensed",Helvetica,Arial,sans-serif;
+
+ --font-size-xxs: 10px;
+ --font-size-xs: 12px;
+ --font-size-sm: 14px;
+ --font-size-md: 16px;
+ --font-size-lg: 20px;
+ --font-size-xl: 24px;
+
+ --font-weight-thin: 200;
+ --font-weight-regular: 400;
+ --font-weight-semi-bold: 700;
+ --font-weight-bold: 800;
+ --font-weight-black: 900;
+
+ // Spacing
+ --spacing-xs: 4px;
+ --spacing-sm: 8px;
+ --spacing-md: 12px;
+ --spacing-lg: 16px;
+ --spacing-xl: 20px;
+ --spacing-xxl: 24px;
+
+ --border-color-default: #dedd;
+ --border-width-default: 1px;
+ --border-radius-default: 8px;
+
+ --header-spacing-bottom: 70px;
+
+ --icon-stroke-width: 1.2;
+
+ --tablet-top-bar-height: 100px;
+
+ --ion-tabbar-height: 50px;
+
+}
+
+html, body {
+ font-family: var(--ion-font-family);
+ background-color: var(--ion-color-primary);
+}
+
+@import "~swiper/css/navigation";
+
+// Import all other styles
+@import '../fonts';
+@import '../common/typo';
+@import '../common/helper';
+@import '../common/ion-button';
+@import '../common/ion-header';
+@import '../common/ion-input';
+@import '../common/ion-modal';
+@import '../common/ion-popover';
+@import '../common/ion-refresher';
+@import '../common/ion-toolbar';
+@import '../common/swiper';
+@import '../common/typography';
+
+@import '../components/card';
+@import '../components/section';
diff --git a/src/theme/util/_mixins.scss b/src/theme/util/_mixins.scss
new file mode 100644
index 00000000..526dc21f
--- /dev/null
+++ b/src/theme/util/_mixins.scss
@@ -0,0 +1,58 @@
+
+/**
+ * Breakpoints copied from node_modules/@ionic/angular/css/display.css
+ */
+
+@mixin ion-sm-up {
+ @media (min-width: 576px) {
+ @content
+ }
+}
+@mixin ion-sm-down {
+ @media (max-width: 575.98px) {
+ @content
+ }
+}
+@mixin ion-md-up {
+ @media (min-width: 768px) {
+ @content
+ }
+}
+@mixin ion-md-down {
+ @media (max-width: 767.98px) {
+ @content
+ }
+}
+@mixin ion-lg-up {
+ @media (min-width: 992px) {
+ @content
+ }
+}
+@mixin ion-lg-down {
+ @media (max-width: 991.98px) {
+ @content
+ }
+}
+@mixin ion-xl-up {
+ @media (min-width: 1200px) {
+ @content
+ }
+}
+@mixin ion-xl-down {
+ @media (max-width: 1199.98px) {
+ @content
+ }
+}
+
+@mixin phoneLandscape {
+ @media (max-height: 500px) and (orientation: landscape) {
+ @content
+ }
+}
+
+
+@mixin phonePortraitSmall {
+ @media (max-height: 700px) and (orientation: portrait) {
+ @content
+ }
+}
diff --git a/src/theme/variables.scss b/src/theme/variables.scss
index 89fc398d..c5a6cf80 100644
--- a/src/theme/variables.scss
+++ b/src/theme/variables.scss
@@ -77,6 +77,17 @@
/** StApps **/
--placeholder-gray: #F1F0ED;
+ --calender-date-line-gray: #dbdbdb;
+ --calender-background-color: #fff;
+ --calender-background-color-rgb: 255, 255, 255;
+ --calender-blue-card: var(--ion-color-primary-tint);
+ --calender-blue-card-rgb: 26, 113, 154;
+ --calender-black-card: #000000;
+ --calender-black-card-rgb: 0, 0, 0;
+ --calender-default-card: var(--ion-color-light);
/** Change the colors of the toolbar and the toolbar text here **/
--map-box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+
}
+
+@import 'configs/goethe-uni-frankfurt';
diff --git a/tsconfig.app.json b/tsconfig.app.json
index 60471b68..8556d7ec 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -1,11 +1,12 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
- "outDir": "../out-tsc/app",
+ "outDir": "../out-tsc/app"
},
"files": [
"src/main.ts",
- "src/polyfills.ts"
+ "src/polyfills.ts",
+ "src/app/modules/dashboard/sections/navigation-section/menu-item.interface.ts"
],
"include": [
"src/**/*.d.ts"