-
Notifications
You must be signed in to change notification settings - Fork 358
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(media-queries): service & directives (#22)
* first draft on media service/directive * modified comments and little fixes * media docs/demo (first draft) * fixed unit test * update(cards): href for -prod routes - for link styles * update(media): change name to Media Queries - update description
- Loading branch information
1 parent
9712754
commit 341f56e
Showing
15 changed files
with
542 additions
and
2 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
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
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 @@ | ||
export { MediaDemoComponent } from './media.component'; |
134 changes: 134 additions & 0 deletions
134
src/app/components/components/media/media.component.html
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,134 @@ | ||
<md-card> | ||
<md-card-title>Media Queries</md-card-title> | ||
<md-card-subtitle>Responsive service & directive (for attributes)</md-card-subtitle> | ||
<md-divider></md-divider> | ||
<md-card-content> | ||
<p>Media Queries:</p> | ||
<md-list> | ||
<template let-demo let-last="demo" ngFor [ngForOf]="mediaDemo"> | ||
<a md-list-item layout-align="row"> | ||
<h3 [tdMediaToggle]="demo.query" [mediaStyles]="{color: 'red'}" [mediaAttributes]="{title: 'It matches!!!'}" md-line> {{demo.query}}</h3> | ||
<p md-line> matches: {{demo.value}} </p> | ||
</a> | ||
<md-divider *ngIf="!last"></md-divider> | ||
</template> | ||
</md-list> | ||
</md-card-content> | ||
</md-card> | ||
<md-card> | ||
<md-card-title>TdMediaService</md-card-title> | ||
<md-card-subtitle>How to use this service</md-card-subtitle> | ||
<md-divider></md-divider> | ||
<md-card-content> | ||
<h2><code>TdMediaService</code></h2> | ||
<p>This service is designed to provide basic media query evaluation for responsive applications.</p> | ||
<p>It has pre-programmed support for media queries that match the layout | ||
<a href="https://material.google.com/layout/responsive-ui.html" target="_blank">breakpoints</a>: | ||
</p> | ||
<md-list> | ||
<template let-bpoint let-last="bpoint" ngFor [ngForOf]="mediaBreakpoints"> | ||
<a md-list-item layout-align="row"> | ||
<h3 md-line> {{bpoint.breakpoint}}</h3> | ||
<p md-line> {{bpoint.query}} </p> | ||
</a> | ||
<md-divider *ngIf="!last"></md-divider> | ||
</template> | ||
</md-list> | ||
<h3>Methods:</h3> | ||
<p>The <code>TdMediaService</code> service has {{mediaServiceMethods.length}} properties:</p> | ||
<md-list> | ||
<template let-attr let-last="attr" ngFor [ngForOf]="mediaServiceMethods"> | ||
<a md-list-item layout-align="row"> | ||
<h3 md-line> {{attr.name}}: <span>{{attr.type}}</span></h3> | ||
<p md-line> {{attr.description}} </p> | ||
</a> | ||
<md-divider *ngIf="!last"></md-divider> | ||
</template> | ||
</md-list> | ||
<h3>Example:</h3> | ||
<p>Typescript:</p> | ||
<td-highlight lang="typescript"> | ||
<![CDATA[ | ||
import { Component, NgZone, OnInit, OnDestroy } from '@angular/core'; | ||
import { TdMediaService } from '@covalent/core'; | ||
import { Subscription } from 'rxjs/Subscription'; | ||
... | ||
providers: [ TdMediaService ] | ||
}) | ||
export class Demo implements OnInit, OnDestroy { | ||
isSmallScreen: boolean = false; | ||
private _querySubscription: Subscription; | ||
|
||
constructor(private _mediaService: TdMediaService, private _ngZone: NgZone) { | ||
} | ||
|
||
checkScreen(): void { | ||
this._ngZone.run(() => { | ||
this.isSmallScreen = this._mediaService.query('sm'); // or '(min-width: 960px) and (max-width: 1279px)' | ||
}); | ||
} | ||
|
||
watchScreen(): void { | ||
this._querySubscription = this._mediaService.registerQuery('sm').subscribe((matches: boolean) => { | ||
this._ngZone.run(() => { | ||
this.isSmallScreen = matches; | ||
}); | ||
}); | ||
} | ||
|
||
ngOnInit(): void { | ||
this.watchScreen(); | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this._querySubscription.unsubscribe(); | ||
} | ||
} | ||
]]> | ||
</td-highlight> | ||
<p>Note: Always unsubscribe from [Observable] objects when not using them anymore.</p> | ||
<p>A good way of doing it is in the <code>ngOnDestroy</code> component life-cycle hook provided by the [OnDestroy] interface.</p> | ||
</md-card-content> | ||
</md-card> | ||
<md-card> | ||
<md-card-title>TdMediaToggleDirective</md-card-title> | ||
<md-card-subtitle>How to use this directive</md-card-subtitle> | ||
<md-divider></md-divider> | ||
<md-card-content> | ||
<h2><code>tdMediaToggle</code></h2> | ||
<p>Simply add the <code>tdMediaToggle</code> attibute with a "media query" value to the element you want to modify depending on screen size.</p> | ||
<h3>Properties:</h3> | ||
<p>The <code>tdMediaToggle</code> directive has {{mediaAttrs.length}} properties:</p> | ||
<md-list> | ||
<template let-attr let-last="attr" ngFor [ngForOf]="mediaAttrs"> | ||
<a md-list-item layout-align="row"> | ||
<h3 md-line> {{attr.name}}: <span>{{attr.type}}</span></h3> | ||
<p md-line> {{attr.description}} </p> | ||
</a> | ||
<md-divider *ngIf="!last"></md-divider> | ||
</template> | ||
</md-list> | ||
<h3>Example:</h3> | ||
<p>HTML:</p> | ||
<td-highlight lang="html"> | ||
<![CDATA[ | ||
<div tdMediaToggle="sm" [mediaClasses]="['classOne', 'classTwo']" | ||
[mediaAttributes]="{title: 'tooltip'}" [mediaStyles]="{color: 'red'}"> | ||
... | ||
</div> | ||
]]> | ||
</td-highlight> | ||
<p>Typescript:</p> | ||
<td-highlight lang="typescript"> | ||
<![CDATA[ | ||
import { TdMediaToggleDirective, TdMediaService } from '@covalent/core'; | ||
... | ||
directives: [ TdMediaToggleDirective ], | ||
providers: [ TdMediaService ] | ||
}) | ||
export class Demo { | ||
} | ||
]]> | ||
</td-highlight> | ||
</md-card-content> | ||
</md-card> |
Empty file.
51 changes: 51 additions & 0 deletions
51
src/app/components/components/media/media.component.spec.ts
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,51 @@ | ||
import { | ||
beforeEach, | ||
addProviders, | ||
describe, | ||
expect, | ||
it, | ||
inject, | ||
} from '@angular/core/testing'; | ||
import { ComponentFixture, TestComponentBuilder } from '@angular/compiler/testing'; | ||
import { Component, DebugElement } from '@angular/core'; | ||
import { By } from '@angular/platform-browser'; | ||
import { MediaDemoComponent } from './media.component'; | ||
import { TdMediaService } from '../../../../platform/core'; | ||
|
||
describe('Component: MediaDemo', () => { | ||
let builder: TestComponentBuilder; | ||
|
||
beforeEach(() => { | ||
addProviders([ | ||
MediaDemoComponent, | ||
TdMediaService, | ||
]); | ||
}); | ||
|
||
beforeEach(inject([TestComponentBuilder], function (tcb: TestComponentBuilder): void { | ||
builder = tcb; | ||
})); | ||
|
||
it('should inject the component', inject([MediaDemoComponent], (component: MediaDemoComponent) => { | ||
expect(component).toBeTruthy(); | ||
})); | ||
|
||
it('should create the component', inject([], () => { | ||
return builder.createAsync(MediaDemoTestControllerComponent) | ||
.then((fixture: ComponentFixture<any>) => { | ||
let query: DebugElement = fixture.debugElement.query(By.directive(MediaDemoComponent)); | ||
expect(query).toBeTruthy(); | ||
expect(query.componentInstance).toBeTruthy(); | ||
}); | ||
})); | ||
}); | ||
|
||
@Component({ | ||
directives: [MediaDemoComponent], | ||
selector: 'td-test', | ||
template: ` | ||
<td-media-demo></td-media-demo> | ||
`, | ||
}) | ||
class MediaDemoTestControllerComponent { | ||
} |
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,164 @@ | ||
import { Component, OnInit, NgZone, OnDestroy } from '@angular/core'; | ||
import { Subscription } from 'rxjs/Subscription'; | ||
|
||
import { MD_CARD_DIRECTIVES } from '@angular2-material/card'; | ||
import { MD_LIST_DIRECTIVES } from '@angular2-material/list'; | ||
import { MdButton } from '@angular2-material/button'; | ||
import { MD_INPUT_DIRECTIVES } from '@angular2-material/input'; | ||
|
||
import { TdMediaToggleDirective, TdMediaService } from '../../../../platform/core'; | ||
import { TdHighlightComponent } from '../../../../platform/highlight'; | ||
|
||
@Component({ | ||
directives: [ | ||
MD_CARD_DIRECTIVES, | ||
MD_LIST_DIRECTIVES, | ||
MdButton, | ||
MD_INPUT_DIRECTIVES, | ||
TdMediaToggleDirective, | ||
TdHighlightComponent, | ||
], | ||
moduleId: module.id, | ||
selector: 'td-media-demo', | ||
styleUrls: [ 'media.component.css' ], | ||
templateUrl: 'media.component.html', | ||
}) | ||
export class MediaDemoComponent implements OnInit, OnDestroy { | ||
|
||
private _subcriptions: Subscription[] = []; | ||
|
||
mediaDemo: any[] = [{ | ||
query: 'xs', | ||
value: false, | ||
}, { | ||
query: 'gt-xs', | ||
value: false, | ||
}, { | ||
query: 'sm', | ||
value: false, | ||
}, { | ||
query: 'gt-sm', | ||
value: false, | ||
}, { | ||
query: 'md', | ||
value: false, | ||
}, { | ||
query: 'gt-gm', | ||
value: false, | ||
}, { | ||
query: 'lg', | ||
value: false, | ||
}, { | ||
query: 'gt-lg', | ||
value: false, | ||
}, { | ||
query: 'xl', | ||
value: false, | ||
}, { | ||
query: 'landscape', | ||
value: false, | ||
}, { | ||
query: 'portrait', | ||
value: false, | ||
}, { | ||
query: 'print', | ||
value: false, | ||
}, { | ||
query: '(max-width: 800px)', | ||
value: false, | ||
}, { | ||
query: '(min-width: 700px)', | ||
value: false, | ||
}]; | ||
|
||
mediaServiceMethods: Object[] = [{ | ||
description: `Used to evaluate whether a given media query is true or false given the | ||
current device's screen / window size.`, | ||
name: 'query', | ||
type: 'function(query: string)', | ||
}, { | ||
description: `Registers a media query and returns an [Observable] that will re-evaluate and | ||
return if the given media query matches on window resize.`, | ||
name: 'registerQuery', | ||
type: 'function(query: string)', | ||
}]; | ||
|
||
mediaBreakpoints: Object[] = [{ | ||
breakpoint: 'xs', | ||
query: '(max-width: 599px)', | ||
}, { | ||
breakpoint: 'gt-xs', | ||
query: '(min-width: 600px)', | ||
}, { | ||
breakpoint: 'sm', | ||
query: '(min-width: 600px) and (max-width: 959px)', | ||
}, { | ||
breakpoint: 'gt-sm', | ||
query: '(min-width: 960px)', | ||
}, { | ||
breakpoint: 'md', | ||
query: '(min-width: 960px) and (max-width: 1279px)', | ||
}, { | ||
breakpoint: 'gt-gm', | ||
query: '(min-width: 1280px)', | ||
}, { | ||
breakpoint: 'lg', | ||
query: '(min-width: 1280px) and (max-width: 1919px)', | ||
}, { | ||
breakpoint: 'gt-lg', | ||
query: '(min-width: 1920px)', | ||
}, { | ||
breakpoint: 'xl', | ||
query: '(min-width: 1920px)', | ||
}, { | ||
breakpoint: 'landscape', | ||
query: 'landscape', | ||
}, { | ||
breakpoint: 'portrait', | ||
query: 'portrait', | ||
}, { | ||
breakpoint: 'print', | ||
query: 'print', | ||
}]; | ||
|
||
mediaAttrs: Object[] = [{ | ||
description: `Media query used to evaluate screen/window size. | ||
Toggles attributes, classes and styles if media query is matched.`, | ||
name: 'tdMediaToggle', | ||
type: 'string', | ||
}, { | ||
description: 'Attributes to be toggled when media query matches', | ||
name: 'mediaAttributes?', | ||
type: '{[key: string]: string}', | ||
}, { | ||
description: 'CSS Classes to be toggled when media query matches', | ||
name: 'mediaClasses?', | ||
type: 'string[]', | ||
}, { | ||
description: 'CSS Styles to be toggled when media query matches', | ||
name: 'mediaStyles?', | ||
type: '{[key: string]: string}', | ||
}]; | ||
|
||
constructor(private _mediaService: TdMediaService, private _ngZone: NgZone) { } | ||
|
||
ngOnInit(): void { | ||
for (let demoObj of this.mediaDemo) { | ||
this._ngZone.run(() => { | ||
demoObj.value = this._mediaService.query(demoObj.query); | ||
}); | ||
this._subcriptions.push(this._mediaService.registerQuery(demoObj.query).subscribe((matches: boolean) => { | ||
this._ngZone.run(() => { | ||
demoObj.value = matches; | ||
}); | ||
})); | ||
} | ||
} | ||
|
||
ngOnDestroy(): void { | ||
this._subcriptions.forEach((subs: Subscription) => { | ||
subs.unsubscribe(); | ||
}); | ||
} | ||
|
||
} |
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
Oops, something went wrong.