-
Notifications
You must be signed in to change notification settings - Fork 191
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 9a7e4a6
Showing
12 changed files
with
301 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
dist | ||
aot | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
src | ||
node_modules | ||
.gitignore | ||
.npmignore | ||
tsconfig.json | ||
.idea | ||
aot |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "ionic2-super-tabs", | ||
"version": "0.1.0", | ||
"description": "", | ||
"main": "dist/index.js", | ||
"typings": "dist/index.d.ts", | ||
"scripts": { | ||
"build": "rm -rf aot dist && ngc", | ||
"copy:scss": "cd src && copyfiles '**/*.scss' ../dist" | ||
}, | ||
"author": "Ibby Hadeed <[email protected]>", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@angular/common": "2.4.8", | ||
"@angular/compiler": "2.4.8", | ||
"@angular/compiler-cli": "2.4.8", | ||
"@angular/core": "2.4.8", | ||
"@angular/forms": "^2.4.8", | ||
"@angular/http": "2.4.8", | ||
"@angular/platform-browser": "2.4.8", | ||
"@angular/platform-browser-dynamic": "2.4.8", | ||
"@angular/platform-server": "2.4.8", | ||
"copy": "^0.3.0", | ||
"copyfiles": "^1.2.0", | ||
"ionic-angular": "2.2.0", | ||
"ionicons": "3.0.0", | ||
"rxjs": "5.0.1", | ||
"sw-toolbox": "3.4.0", | ||
"typescript": "2.0.9", | ||
"zone.js": "0.7.2" | ||
} | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
super-tab { | ||
> ion-nav { | ||
position: static; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { Component, Input } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'super-tab', | ||
template: '' | ||
}) | ||
export class SuperTabComponent { | ||
|
||
@Input() | ||
tabRoot: any; | ||
|
||
@Input() | ||
title: string; | ||
|
||
@Input() | ||
icon: string; | ||
|
||
constructor() { | ||
console.log('Hello SuperTab Component'); | ||
} | ||
|
||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
super-tabs { | ||
|
||
ion-segment.segment.segment-md { | ||
ion-segment-button { | ||
border-bottom: 0; | ||
height: inherit; | ||
ion-icon { | ||
display: block; | ||
} | ||
} | ||
|
||
+ .slide { | ||
bottom: 0; | ||
position: absolute; | ||
z-index: 2; | ||
height: 2px; | ||
background: map_get($colors, light); | ||
&.ease { | ||
transition: left .25s ease-in; | ||
} | ||
} | ||
|
||
} | ||
|
||
ion-slides { | ||
text-align: inherit; | ||
font-size: inherit; | ||
ion-slide, ion-slide .slide-zoom, .swiper-slide { | ||
text-align: inherit; | ||
font-size: inherit; | ||
} | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import {Component, ContentChildren, Input, QueryList, ViewChild} from '@angular/core'; | ||
import {SuperTabComponent} from "../super-tab/super-tab"; | ||
import {Header, Platform, Slides} from "ionic-angular"; | ||
|
||
/* | ||
Generated class for the SuperTabs component. | ||
See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html | ||
for more info on Angular 2 Components. | ||
*/ | ||
@Component({ | ||
selector: 'super-tabs', | ||
template: ` | ||
<ion-header> | ||
<ion-navbar color="dark"> | ||
<ion-title>{{pageTitle}}</ion-title> | ||
</ion-navbar> | ||
<ion-toolbar color="dark"> | ||
<ion-segment color="light" [(ngModel)]="selectedTabIndex"> | ||
<ion-segment-button *ngFor="let tab of tabs; let i = index" [value]="i" (ionSelect)="onTabSelect(i)"> | ||
<ion-icon *ngIf="tab.icon" [name]="tab.icon"></ion-icon> | ||
{{tab.title}} | ||
</ion-segment-button> | ||
</ion-segment> | ||
<div class="slide" #slide [style.left]="slidePosition" [class.ease]="shouldSlideEase" [style.width]="slideWidth"></div> | ||
</ion-toolbar> | ||
</ion-header> | ||
<ion-slides [style.margin-top]="headerHeight + 'px'" [style.height]="slidesHeight + 'px'" (ionSlideDrag)="onDrag($event)" (ionSlideWillChange)="onSlideWillChange()" (ionSlideDidChange)="onSlideDidChange()" [initialSlide]="selectedTabIndex"> | ||
<ion-slide *ngFor="let tab of tabs"> | ||
<ion-nav [root]="tab.tabRoot"></ion-nav> | ||
</ion-slide> | ||
</ion-slides> | ||
` | ||
}) | ||
export class SuperTabsComponent { | ||
|
||
@ContentChildren(SuperTabComponent) superTabs: QueryList<SuperTabComponent>; | ||
|
||
tabs: SuperTabComponent[] = []; | ||
|
||
@ViewChild(Slides) slides: Slides; | ||
|
||
@ViewChild(Header) header: Header; | ||
headerHeight: number = 0; | ||
slidesHeight: number = 0; | ||
|
||
_selectedTabIndex = 0; | ||
@Input() | ||
set selectedTabIndex(val: number) { | ||
if (val >= this.tabs.length) { | ||
return; | ||
} | ||
this._selectedTabIndex = val; | ||
let slidePosition = val * this.slides.renderedWidth / this.tabs.length; | ||
this.slidePosition = slidePosition <= this.maxSlidePosition ? slidePosition + 'px' : this.maxSlidePosition + 'px'; | ||
this.pageTitle = this.tabs[this.selectedTabIndex].title; | ||
} | ||
|
||
get selectedTabIndex(): number { | ||
return this._selectedTabIndex; | ||
} | ||
|
||
maxSlidePosition: number; | ||
slidePosition = '0'; | ||
slideWidth = '0'; | ||
shouldSlideEase: boolean = false; | ||
pageTitle: string = ''; | ||
|
||
constructor(private platform: Platform) { | ||
console.log('Hello SuperTabs Component'); | ||
} | ||
|
||
/** | ||
* We listen to drag events to move the "slide" thingy along with the slides | ||
* // TODO figure out a way to reset the "slide" position after the user is done dragging. ATM it gets stuck if the user swipes partially without changing the tab. | ||
* @param ev | ||
*/ | ||
onDrag(ev: Slides) { | ||
if (ev._translate > 0) return; | ||
const percentage = Math.abs(ev._translate / ev._virtualSize); | ||
const singleSlideSize = ev._renderedSize; | ||
|
||
let slidePosition = percentage * singleSlideSize; | ||
|
||
if (slidePosition > this.maxSlidePosition) { | ||
slidePosition = this.maxSlidePosition; | ||
} | ||
|
||
this.slidePosition = slidePosition + 'px'; | ||
} | ||
|
||
/** | ||
* The slide will change because the user stopped dragging, or clicked on a segment button | ||
* Let's make sure the segment button is in alignment with the slides | ||
* Also, lets animate the "slide" element | ||
*/ | ||
onSlideWillChange() { | ||
if (this.slides.getActiveIndex() <= this.tabs.length) { | ||
this.shouldSlideEase = true; | ||
this.selectedTabIndex = this.slides.getActiveIndex(); | ||
} | ||
} | ||
|
||
/** | ||
* We need to disable animation after the slide is done changing | ||
* Any further movement should happen instantly as the user swipes through the tabs | ||
*/ | ||
onSlideDidChange() { | ||
this.shouldSlideEase = false; | ||
} | ||
|
||
/** | ||
* Runs when the user clicks on a segment button | ||
* @param index | ||
*/ | ||
onTabSelect(index: number) { | ||
if (index <= this.tabs.length) { | ||
this.slides.slideTo(index); | ||
} | ||
} | ||
|
||
ngAfterViewInit() { | ||
// take the tabs from the query and put them in a regular array to make life easier | ||
this.superTabs.forEach(tab => this.tabs.push(tab)); | ||
|
||
// set page title based on the selected page | ||
this.pageTitle = this.tabs[this.selectedTabIndex].title; | ||
|
||
// the width of the "slide", should be equal to the width of a single `ion-segment-button` | ||
// we'll just calculate it instead of querying for a segment button | ||
this.slideWidth = this.platform.width() / this.tabs.length + 'px'; | ||
|
||
// we need this to make sure the "slide" thingy doesn't move outside the screen | ||
this.maxSlidePosition = this.platform.width() - (this.platform.width() / this.tabs.length); | ||
|
||
// we waiting for 100ms just to give `ion-icon` some time to decide if they want to show up or not | ||
// if we check height immediately, we will get the height of the header without the icons | ||
setTimeout(this.setHeights.bind(this), 100); | ||
|
||
} | ||
|
||
/** | ||
* Sets the height of ion-slides and it's position from the top of the page | ||
*/ | ||
private setHeights() { | ||
this.headerHeight = this.header.getNativeElement().offsetHeight; | ||
this.slidesHeight = this.platform.height() - this.headerHeight; | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './components/super-tab/super-tab'; | ||
export * from './components/super-tabs/super-tabs'; | ||
export * from './super-tabs.module'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { NgModule } from '@angular/core'; | ||
import { IonicModule } from 'ionic-angular'; | ||
import {SuperTabComponent} from "./components/super-tab/super-tab"; | ||
import {SuperTabsComponent} from "./components/super-tabs/super-tabs"; | ||
|
||
@NgModule({ | ||
declarations: [ | ||
SuperTabComponent, | ||
SuperTabsComponent | ||
], | ||
imports: [ | ||
IonicModule | ||
], | ||
exports: [ | ||
SuperTabComponent, | ||
SuperTabsComponent | ||
] | ||
}) | ||
export class SuperTabsModule { } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"compilerOptions": { | ||
"module": "es2015", | ||
"target": "es5", | ||
"moduleResolution": "node", | ||
"sourceMap": true, | ||
"declaration": true, | ||
"noImplicitAny": false, | ||
"experimentalDecorators": true, | ||
"lib": [ | ||
"dom", | ||
"es2015" | ||
], | ||
"outDir": "dist" | ||
}, | ||
"exclude": [ | ||
"node_modules", | ||
"dist" | ||
], | ||
"angularCompilerOptions": { | ||
"genDir": "aot" | ||
} | ||
} |