mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-20 16:42:56 +00:00
feat: add map module
This commit is contained in:
@@ -36,44 +36,46 @@ import {DataProvider} from './data.provider';
|
||||
import {DataDetailContentComponent} from './detail/data-detail-content.component';
|
||||
import {DataDetailComponent} from './detail/data-detail.component';
|
||||
import {AddressDetailComponent} from './elements/address-detail.component';
|
||||
import {LongInlineTextComponent} from './elements/long-inline-text.component';
|
||||
import {OffersDetailComponent} from './elements/offers-detail.component';
|
||||
import {OffersInListComponent} from './elements/offers-in-list.component';
|
||||
import {OriginDetailComponent} from './elements/origin-detail.component';
|
||||
import {OriginInListComponent} from './elements/origin-in-list.component';
|
||||
import {SimpleCardComponent} from './elements/simple-card.component';
|
||||
import {SkeletonListItemComponent} from './elements/skeleton-list-item.component';
|
||||
import {SkeletonSegmentComponent} from './elements/skeleton-segment-button.component';
|
||||
import {SkeletonSimpleCardComponent} from './elements/skeleton-simple-card.component';
|
||||
import {DataListItemComponent} from './list/data-list-item.component';
|
||||
import {DataListComponent} from './list/data-list.component';
|
||||
import {FoodDataListComponent} from './list/food-data-list.component';
|
||||
import {SearchPageComponent} from './list/search-page.component';
|
||||
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
|
||||
import {ArticleDetailContentComponent} from './types/article/article-detail-content.component';
|
||||
import {ArticleListItemComponent} from './types/article/article-list-item.component';
|
||||
import {CatalogDetailContentComponent} from './types/catalog/catalog-detail-content.component';
|
||||
import {CatalogListItemComponent} from './types/catalog/catalog-list-item.component';
|
||||
import {DateSeriesDetailContentComponent} from './types/date-series/date-series-detail-content.component';
|
||||
import {DateSeriesListItemComponent} from './types/date-series/date-series-list-item.component';
|
||||
import {DishDetailContentComponent} from './types/dish/dish-detail-content.component';
|
||||
import {DishListItemComponent} from './types/dish/dish-list-item.component';
|
||||
import {EventDetailContentComponent} from './types/event/event-detail-content.component';
|
||||
import {EventListItemComponent} from './types/event/event-list-item.component';
|
||||
import {FavoriteDetailContentComponent} from './types/favorite/favorite-detail-content.component';
|
||||
import {FavoriteListItemComponent} from './types/favorite/favorite-list-item.component';
|
||||
import {MessageDetailContentComponent} from './types/message/message-detail-content.component';
|
||||
import {MessageListItemComponent} from './types/message/message-list-item.component';
|
||||
import {OrganizationDetailContentComponent} from './types/organization/organization-detail-content.component';
|
||||
import {OrganizationListItemComponent} from './types/organization/organization-list-item.component';
|
||||
import {PersonDetailContentComponent} from './types/person/person-detail-content.component';
|
||||
import {PersonListItemComponent} from './types/person/person-list-item.component';
|
||||
import {PlaceDetailContentComponent} from './types/place/place-detail-content.component';
|
||||
import {PlaceListItemComponent} from './types/place/place-list-item.component';
|
||||
import {PlaceMensaDetailComponent} from './types/place/special/mensa/place-mensa-detail.component';
|
||||
import {SemesterDetailContentComponent} from './types/semester/semester-detail-content.component';
|
||||
import {SemesterListItemComponent} from './types/semester/semester-list-item.component';
|
||||
import {VideoDetailContentComponent} from './types/video/video-detail-content.component';
|
||||
import {MapWidgetComponent} from '../map/widget/map-widget.component';
|
||||
import {LeafletModule} from '@asymmetrik/ngx-leaflet';
|
||||
import {ArticleListItemComponent} from './types/article/article-list-item.component';
|
||||
import {SkeletonSimpleCardComponent} from './elements/skeleton-simple-card.component';
|
||||
import {CatalogListItemComponent} from './types/catalog/catalog-list-item.component';
|
||||
import {DataListItemComponent} from './list/data-list-item.component';
|
||||
import {DateSeriesListItemComponent} from './types/date-series/date-series-list-item.component';
|
||||
import {DishListItemComponent} from './types/dish/dish-list-item.component';
|
||||
import {FavoriteListItemComponent} from './types/favorite/favorite-list-item.component';
|
||||
import {LongInlineTextComponent} from './elements/long-inline-text.component';
|
||||
import {MessageListItemComponent} from './types/message/message-list-item.component';
|
||||
import {OrganizationListItemComponent} from './types/organization/organization-list-item.component';
|
||||
import {PersonListItemComponent} from './types/person/person-list-item.component';
|
||||
import {SemesterListItemComponent} from './types/semester/semester-list-item.component';
|
||||
import {SkeletonListItemComponent} from './elements/skeleton-list-item.component';
|
||||
import {SkeletonSegmentComponent} from './elements/skeleton-segment-button.component';
|
||||
import {VideoListItemComponent} from './types/video/video-list-item.component';
|
||||
|
||||
/**
|
||||
@@ -81,17 +83,19 @@ import {VideoListItemComponent} from './types/video/video-list-item.component';
|
||||
*/
|
||||
@NgModule({
|
||||
declarations: [
|
||||
ActionChipListComponent,
|
||||
AddEventActionChipComponent,
|
||||
AddEventPopoverComponent,
|
||||
OffersDetailComponent,
|
||||
OffersInListComponent,
|
||||
AddressDetailComponent,
|
||||
ArticleDetailContentComponent,
|
||||
ArticleListItemComponent,
|
||||
SimpleCardComponent,
|
||||
SkeletonSimpleCardComponent,
|
||||
CatalogDetailContentComponent,
|
||||
CatalogListItemComponent,
|
||||
DataDetailComponent,
|
||||
DataDetailContentComponent,
|
||||
DataIconPipe,
|
||||
FoodDataListComponent,
|
||||
DataListComponent,
|
||||
DataListItemComponent,
|
||||
DateSeriesDetailContentComponent,
|
||||
@@ -102,13 +106,10 @@ import {VideoListItemComponent} from './types/video/video-list-item.component';
|
||||
EventListItemComponent,
|
||||
FavoriteDetailContentComponent,
|
||||
FavoriteListItemComponent,
|
||||
FoodDataListComponent,
|
||||
LocateActionChipComponent,
|
||||
LongInlineTextComponent,
|
||||
MapWidgetComponent,
|
||||
MessageDetailContentComponent,
|
||||
MessageListItemComponent,
|
||||
OffersDetailComponent,
|
||||
OffersInListComponent,
|
||||
OrganizationDetailContentComponent,
|
||||
OrganizationListItemComponent,
|
||||
OriginDetailComponent,
|
||||
@@ -121,20 +122,22 @@ import {VideoListItemComponent} from './types/video/video-list-item.component';
|
||||
SearchPageComponent,
|
||||
SemesterDetailContentComponent,
|
||||
SemesterListItemComponent,
|
||||
SimpleCardComponent,
|
||||
SkeletonListItemComponent,
|
||||
SkeletonSegmentComponent,
|
||||
SkeletonSimpleCardComponent,
|
||||
VideoDetailContentComponent,
|
||||
VideoListItemComponent,
|
||||
DataIconPipe,
|
||||
ActionChipListComponent,
|
||||
AddEventActionChipComponent,
|
||||
LocateActionChipComponent,
|
||||
],
|
||||
entryComponents: [DataListComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
DataRoutingModule,
|
||||
FormsModule,
|
||||
HttpClientModule,
|
||||
IonicModule.forRoot(),
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
DataRoutingModule,
|
||||
HttpClientModule,
|
||||
LeafletModule,
|
||||
MarkdownModule.forRoot(),
|
||||
MenuModule,
|
||||
MomentModule.forRoot({
|
||||
@@ -148,5 +151,15 @@ import {VideoListItemComponent} from './types/video/video-list-item.component';
|
||||
ThingTranslateModule.forChild(),
|
||||
],
|
||||
providers: [DataProvider, DataFacetsProvider, Network, StAppsWebHttpClient],
|
||||
exports: [
|
||||
DataListComponent,
|
||||
DataListItemComponent,
|
||||
DataDetailComponent,
|
||||
SkeletonSimpleCardComponent,
|
||||
SkeletonListItemComponent,
|
||||
DataIconPipe,
|
||||
PlaceListItemComponent,
|
||||
DataDetailContentComponent,
|
||||
],
|
||||
})
|
||||
export class DataModule {}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
<ion-item class="ion-text-wrap" lines="inset">
|
||||
<ion-thumbnail slot="start" class="ion-margin-end">
|
||||
<ion-icon color="medium" [attr.name]="item.type | dataIcon"></ion-icon>
|
||||
</ion-thumbnail>
|
||||
<ion-grid>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="ion-text-wrap">
|
||||
<h2 class="name">{{ item.name }}</h2>
|
||||
<ion-note>{{ item.type }}</ion-note>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-item>
|
||||
<stapps-simple-card
|
||||
*ngIf="item.description"
|
||||
[title]="'Description'"
|
||||
|
||||
@@ -38,24 +38,6 @@
|
||||
<stapps-skeleton-simple-card></stapps-skeleton-simple-card>
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<ion-item class="ion-text-wrap" lines="inset">
|
||||
<ion-thumbnail slot="start" class="ion-margin-end">
|
||||
<ion-icon
|
||||
color="medium"
|
||||
[attr.name]="item.type | dataIcon"
|
||||
></ion-icon>
|
||||
</ion-thumbnail>
|
||||
<ion-grid *ngSwitchDefault>
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<div class="ion-text-wrap">
|
||||
<h2 class="name">{{ item.name }}</h2>
|
||||
<ion-note>{{ item.type }}</ion-note>
|
||||
</div>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
</ion-item>
|
||||
<stapps-data-detail-content [item]="item"></stapps-data-detail-content>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -15,4 +15,18 @@
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
ion-note {
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
li {
|
||||
list-style-type: none;
|
||||
display: inline;
|
||||
}
|
||||
li:not(:first-child):before {
|
||||
content: " • ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,15 +2,23 @@ import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {DataListComponent} from './data-list.component';
|
||||
import {TranslateModule} from '@ngx-translate/core';
|
||||
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {ConfigProvider} from '../../config/config.provider';
|
||||
|
||||
describe('DataListComponent', () => {
|
||||
let component: DataListComponent;
|
||||
let fixture: ComponentFixture<DataListComponent>;
|
||||
let configProviderMock: jasmine.SpyObj<ConfigProvider>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
configProviderMock = jasmine.createSpyObj('ConfigProvider', {
|
||||
getValue: () => Promise.resolve({lat: 123, lng: 123}),
|
||||
});
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [DataListComponent],
|
||||
imports: [TranslateModule.forRoot()],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
providers: [{provide: ConfigProvider, useValue: configProviderMock}],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<stapps-context></stapps-context>
|
||||
<stapps-context contentId="data-list"></stapps-context>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
@@ -13,7 +13,9 @@
|
||||
<ion-searchbar
|
||||
(ngModelChange)="searchStringChanged($event)"
|
||||
[(ngModel)]="queryText"
|
||||
></ion-searchbar>
|
||||
showClearButton="always"
|
||||
>
|
||||
</ion-searchbar>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import {DataProvider} from '../../data.provider';
|
||||
*/
|
||||
@Component({
|
||||
providers: [DataProvider],
|
||||
styleUrls: ['place-detail-content.scss'],
|
||||
selector: 'stapps-place-detail-content',
|
||||
templateUrl: 'place-detail-content.html',
|
||||
})
|
||||
@@ -41,7 +42,9 @@ export class PlaceDetailContentComponent {
|
||||
*
|
||||
* @param item TODO
|
||||
*/
|
||||
// tslint:disable-next-line:completed-docs prefer-function-over-method
|
||||
hasCategories(item: SCThings): item is SCThings & {categories: string[]} {
|
||||
// tslint:disable-next-line:completed-docs
|
||||
return typeof (item as {categories: string[]}).categories !== 'undefined';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<stapps-place-mensa-detail-content
|
||||
[item]="item"
|
||||
[language]="language"
|
||||
*ngIf="isMensaThing(item)"
|
||||
></stapps-place-mensa-detail-content>
|
||||
<ng-container *ngIf="item.type !== 'floor'">
|
||||
@@ -26,8 +25,9 @@
|
||||
}}</a>
|
||||
</ion-card-content>
|
||||
</ion-card>
|
||||
<stapps-address-detail
|
||||
*ngIf="item.inPlace && item.inPlace.address"
|
||||
[address]="item.inPlace.address"
|
||||
></stapps-address-detail>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="item.type !== 'floor'">
|
||||
<ion-card *ngIf="item.geo" class="map-widget">
|
||||
<stapps-map-widget [place]="item" expandable="true"></stapps-map-widget>
|
||||
</ion-card>
|
||||
</ng-container>
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
ion-card.map-widget {
|
||||
height: 300px;
|
||||
width: auto;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019 StApps
|
||||
* Copyright (C) 2019-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.
|
||||
@@ -14,18 +14,55 @@
|
||||
*/
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {SCBuilding, SCFloor, SCPointOfInterest, SCRoom} from '@openstapps/core';
|
||||
import {DataListItemComponent} from '../../list/data-list-item.component';
|
||||
import {PositionService} from '../../../map/position.service';
|
||||
|
||||
type placeTypes = (SCBuilding | SCRoom | SCPointOfInterest | SCFloor) & {
|
||||
distance?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* Provide information if a place is a floor
|
||||
*
|
||||
* @param place A place to check
|
||||
*/
|
||||
function isSCFloor(place: placeTypes): place is SCFloor {
|
||||
return place.type === 'floor';
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a place as a list item
|
||||
*/
|
||||
@Component({
|
||||
selector: 'stapps-place-list-item',
|
||||
templateUrl: 'place-list-item.html',
|
||||
})
|
||||
export class PlaceListItemComponent extends DataListItemComponent {
|
||||
export class PlaceListItemComponent {
|
||||
/**
|
||||
* TODO
|
||||
* Item getter
|
||||
*/
|
||||
@Input() item: SCBuilding | SCRoom | SCPointOfInterest | SCFloor;
|
||||
get item(): placeTypes {
|
||||
return this._item;
|
||||
}
|
||||
|
||||
/**
|
||||
* An item to show (setter is used as there were issues assigning the distance to the right place in a list)
|
||||
*/
|
||||
@Input() set item(item: placeTypes) {
|
||||
this._item = item;
|
||||
if (!isSCFloor(item)) {
|
||||
this.distance = this.positionService.getDistance(item.geo.point);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An item to show
|
||||
*/
|
||||
private _item: placeTypes;
|
||||
|
||||
/**
|
||||
* Distance in meters
|
||||
*/
|
||||
distance?: number;
|
||||
|
||||
constructor(private positionService: PositionService) {}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,15 @@
|
||||
<p *ngIf="item.description">
|
||||
{{ 'description' | thingTranslate: item }}
|
||||
</p>
|
||||
<ion-note>{{ 'type' | thingTranslate: item }} </ion-note>
|
||||
<ion-note>
|
||||
<ul>
|
||||
<li>{{ 'type' | thingTranslate: item }}</li>
|
||||
<li *ngIf="distance">
|
||||
<ion-icon name="walk"></ion-icon
|
||||
>{{ distance | numberLocalized: '1.0-0' }} m
|
||||
</li>
|
||||
</ul>
|
||||
</ion-note>
|
||||
</div>
|
||||
</ion-col>
|
||||
<ion-col width-20 text-right *ngIf="item.type !== 'building'">
|
||||
|
||||
Reference in New Issue
Block a user