Skip to content

Commit

Permalink
Add ionic tabs after shell integration as component
Browse files Browse the repository at this point in the history
Closes #106
  • Loading branch information
luiza-cicone authored and sinedied committed Aug 24, 2018
1 parent 96dd32f commit 9ddb56e
Show file tree
Hide file tree
Showing 22 changed files with 372 additions and 12 deletions.
2 changes: 2 additions & 0 deletions generators/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ module.exports = Generator.make({
options,
prompts,
prefixRules: Object.assign(Generator.defaultPrefixRules, {
'ionic-tabs': props => props.ui === 'ionic' && props.layout === 'tabs',
'ionic-side-menu': props => props.ui === 'ionic' && props.layout === 'side-menu',
'material-simple': props => props.ui === 'material' && props.layout === 'simple',
'material-side-menu': props => props.ui === 'material' && props.layout === 'side-menu',
raw: props => props.ui === 'raw'
Expand Down
34 changes: 22 additions & 12 deletions generators/app/prompts.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,28 @@ module.exports = [
type: 'list',
name: 'layout',
message: 'Which kind of layout do you want?',
choices: [
{
value: 'simple',
name: 'Simple responsive header bar (more website-oriented)'
},
{
value: 'side-menu',
name: 'Side menu with split panels (more app-oriented)'
}
],
when: props => props.ui === 'material',
default: 'simple'
choices: props => {
return [
{
value: 'simple',
name: 'Simple responsive header bar (more website-oriented)',
when: props.ui === 'material'
},
{
value: 'side-menu',
name: 'Side menu with split panels (more app-oriented)',
when: true
},
{
value: 'tabs',
name: 'Tabs menu (more app-oriented)',
when: props.ui === 'ionic'
}
]
.filter(choice => choice.when);
},
when: props => props.ui === 'material' || props.ui === 'ionic',
default: 'side-menu'
},
{
type: 'confirm',
Expand Down
6 changes: 6 additions & 0 deletions generators/app/templates/src/app/_app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ import { AboutModule } from './about/about.module';
<% if (props.auth) { -%>
import { LoginModule } from './login/login.module';
<% } -%>
<% if (props.layout === 'tabs') { -%>
import { SettingsModule } from './settings/settings.module';
<% } -%>
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

Expand All @@ -68,6 +71,9 @@ import { AppRoutingModule } from './app-routing.module';
CoreModule,
SharedModule,
HomeModule,
<% if (props.layout === 'tabs'){ -%>
SettingsModule,
<% } -%>
<% if (!props.lazy) { -%>
AboutModule,
<% } -%>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { extract } from '@app/core';
import { SettingsComponent } from '@app/settings/settings.component';
import { Shell } from '@app/shell/shell.service';

const routes: Routes = [
Shell.childRoutes([
{ path: 'settings', component: SettingsComponent, data: { title: extract('Settings') } }
])
];

@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: []
})
export class SettingsRoutingModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<ion-header>
<ion-navbar color="primary">
<ion-title><span translate>Settings</span></ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<% if (props.auth) { -%>
<div>
<div class="profile" text-center padding>
<ion-icon class="profile-icon" name="contact"></ion-icon>
<div class="profile-title">{{username}}</div>
</div>
</div>
<ion-list-header>
<ion-label translate>Account</ion-label>
</ion-list-header>
<button ion-item>
<ion-icon name="contact" item-start></ion-icon>
<ion-label translate>Profile</ion-label>
</button>
<ion-item (click)="logout()">
<ion-icon name="md-log-out" item-start></ion-icon>
<ion-label translate>Logout</ion-label>
</ion-item>
<% } -%>

<ion-list-header>
<ion-label translate>Preferences</ion-label>
</ion-list-header>
<button *ngIf="isWeb" ion-item (click)="changeLanguage()">
<ion-icon name="md-globe" item-start></ion-icon>
<ion-label translate>Change language</ion-label>
</button>
<ion-item>
<ion-icon name="notifications" item-start></ion-icon>
<ion-label translate>Notifications</ion-label>
<ion-toggle></ion-toggle>
</ion-item>

</ion-content>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@import "src/theme/theme-variables";

[ion-fixed] {
width: 100%;
height: 100%;
}

.profile {
background: color($colors, primary);
}

.profile-icon {
font-size: 6rem;
color: color-contrast($colors, primary);
}

.profile-title {
color: color-contrast($colors, primary);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { TranslateModule } from '@ngx-translate/core';
import { IonicModule } from 'ionic-angular';

import { SharedModule } from '@app/shared';
import { CoreModule } from '@app/core';
import { SettingsComponent } from './settings.component';

describe('SettingsComponent', () => {
let component: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule,
TranslateModule.forRoot(),
IonicModule.forRoot(SettingsComponent),
CoreModule,
SharedModule
],
declarations: [ SettingsComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(SettingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Component, OnInit } from '@angular/core';
import { ActionSheetController, AlertController, Platform } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core';
import { I18nService } from '@app/core/i18n.service';
<% if (props.auth) { -%>
import { AuthenticationService } from '@app/core/authentication/authentication.service';
<% } -%>
import { ActivatedRoute, Router } from '@angular/router';

@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
})
export class SettingsComponent implements OnInit {

constructor(private router: Router,
private activatedRoute: ActivatedRoute,
private translateService: TranslateService,
private platform: Platform,
private alertController: AlertController,
private actionSheetController: ActionSheetController,
<% if (props.auth) { -%>
private authenticationService: AuthenticationService,
<% } -%>
private i18nService: I18nService) { }

ngOnInit() { }

get isWeb(): boolean {
return !this.platform.is('cordova');
}

<% if (props.auth) { -%>
get username(): string | null {
const credentials = this.authenticationService.credentials;
return credentials ? credentials.username : null;
}

logout() {
this.authenticationService.logout()
.subscribe(() => this.router.navigate(['/login'], { replaceUrl: true }));
}
<% } -%>

changeLanguage() {
this.alertController
.create({
title: this.translateService.instant('Change language'),
inputs: this.i18nService.supportedLanguages.map(language => ({
type: 'radio',
label: language,
value: language,
checked: language === this.i18nService.language
})),
buttons: [
{
text: this.translateService.instant('Cancel'),
role: 'cancel'
},
{
text: this.translateService.instant('Ok'),
handler: language => {
this.i18nService.language = language;
}
}
]
})
.present();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { IonicModule } from 'ionic-angular';

import { SettingsRoutingModule } from './settings-routing.module';
import { SettingsComponent } from './settings.component';

@NgModule({
imports: [
CommonModule,
TranslateModule,
IonicModule,
SettingsRoutingModule
],
entryComponents: [
SettingsComponent
],
declarations: [
SettingsComponent
]
})
export class SettingsModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<ion-tabs #navTabs *ngIf="tabs" [selectedIndex]="selectedTabIndex" (ionChange)="onTabChange($event)">
<ion-tab *ngFor="let t of tabs" [root]="t.component" [tabTitle]="t.title | translate" [tabIcon]="t.icon"></ion-tab>
</ion-tabs>
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { Tab } from 'ionic-angular';
import { filter } from 'rxjs/operators';
import { findIndex } from 'lodash';
import { SettingsComponent } from '@app/settings/settings.component';
import { AboutComponent } from '@app/about/about.component';
import { HomeComponent } from '@app/home/home.component';
@Component({
selector: 'app-shell',
templateUrl: './shell.component.html',
styleUrls: ['./shell.component.scss']
})
export class ShellComponent implements OnInit {
tabs = [
{ component: HomeComponent, route: 'home', title: 'Home', icon: 'home' },
{ component: AboutComponent, route: 'about', title: 'About', icon: 'logo-angular' },
{ component: SettingsComponent, route: 'settings', title: 'Settings', icon: 'cog' }
];
selectedTabIndex: number;
subscription: any;
constructor(private router: Router,
private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.updateTab(this.activatedRoute);
// Bind Ionic navigation to Angular router events
this.subscription = this.router.events
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe(() => this.updateTab(this.activatedRoute));
}
onTabChange(selectedTab: Tab) {
this.router.navigate([this.tabs[selectedTab.index].route]);
}
private updateTab(route: ActivatedRoute) {
if (!route || !route.firstChild) {
return;
}
// First component should always be IonicApp
route = route.firstChild;
if (route && route.component === ShellComponent && route.firstChild) {
route = route.firstChild;
// Fixed the bug#19420 : route.component is undefined if module is lazy
// See: https://github.com/angular/angular/issues/19420
while (route.firstChild) {
route = route.firstChild;
}
// Fixed #19420 end
this.selectedTabIndex = findIndex(this.tabs, { route: route.routeConfig.path });
}
}
}
35 changes: 35 additions & 0 deletions generators/app/templates/src/app/shell/_shell.component.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,38 @@
<% if (props.ui === 'ionic') { -%>
<% if (props.layout === 'tabs') { -%>
$tabs-height: 8.2rem;

.tabs::ng-deep {
.content {
.scroll-content,
.fixed-content {
height: 100%;
}
}

@media (min-width: 768px) {
.tabbar {
height: 100%;
width: $tabs-height;
flex-direction: column;
justify-content: flex-start;

.tab-button {
width: 100%;
height: $tabs-height;
flex: 0 1 auto;
}
}

.header,
.content {
left: $tabs-height;
right: 0;
width: calc(100% - #{$tabs-height});
}
}
}
<% } else if (props.layout === 'side-menu') { -%>
@import "src/theme/theme-variables";

[ion-fixed] {
Expand All @@ -25,6 +59,7 @@
border-color: color-contrast($colors, primary);
color: color-contrast($colors, primary);
}
<% } -%>
<% } else if (props.ui === 'material') { -%>
<% if (props.layout === 'simple') { -%>
@import "src/theme/theme-variables";
Expand Down
Loading

0 comments on commit 9ddb56e

Please sign in to comment.