Last active
September 18, 2019 06:08
-
-
Save Stradivario/0a45703a6609ddcd7ecb9e14d903064f to your computer and use it in GitHub Desktop.
Reactive flex grid lit component
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
import { html, Component, LitElement, css, property, async, TemplateResult } from '@rxdi/lit-html'; | |
import { Inject } from '@rxdi/core'; | |
import { map, switchMap } from 'rxjs/operators'; | |
import { combineLatest, of, Observable, isObservable, from } from 'rxjs'; | |
import { ResponsiveService } from '@rxdi/ui-components/services'; | |
/** | |
* @customElement flex-grid | |
*/ | |
@Component({ | |
selector: 'flex-grid', | |
style: css` | |
.flex { | |
display: flex; | |
} | |
.spacer { | |
flex: 1 3 auto; | |
} | |
.center { | |
margin: 0 auto | |
} | |
`, | |
template(this: GridComponent) { | |
return html` | |
${async( | |
from(isObservable(this.$items) ? this.$items : of(this.$items)) | |
.pipe( | |
map(items => (items.length ? items : Array.from(Array(this.fill).keys()))), | |
switchMap(c => | |
combineLatest(of(c), this.responsive.width.pipe(map(width => this.calculateColumns(width)))) | |
), | |
switchMap(([c, columns]) => combineLatest([of(c), of(this.calculateRows(c.length, columns)), of(columns)])) | |
) | |
.pipe( | |
map( | |
([components, rows, columns]) => html` | |
${Array.from(Array(rows).keys()).map( | |
i => html` | |
<div class="flex" style="margin-bottom: 30px;"> | |
${this.calculateTemplateColumns(components, i, columns)} | |
</div> | |
` | |
)} | |
` | |
) | |
) | |
)} | |
`; | |
}, | |
}) | |
export class GridComponent extends LitElement { | |
@Inject(ResponsiveService) | |
private responsive: ResponsiveService; | |
@property({ type: Number }) | |
fill: number; | |
@property({ attribute: false }) | |
$items: Observable<any[]> | any[] = of([]); | |
@property() | |
template: (item: any) => TemplateResult; | |
private calculateColumns(width: number) { | |
let columns: number; | |
if (width < 700) { | |
columns = 1; | |
} else if (width < 1000) { | |
columns = 2; | |
} else if (width < 1450) { | |
columns = 3; | |
} else if (width > 1450) { | |
columns = 4; | |
} | |
return columns; | |
} | |
private calculateRows(itemsLength: number, columns: number) { | |
return Math.round(itemsLength / columns) + 2; | |
} | |
private calculateTemplateColumns(items: any[], index: number, columns: number) { | |
const calculated = index * columns; | |
const offset = calculated - columns; | |
return html` | |
<div class="flex center"> | |
${items.length | |
? html` | |
${items.slice(offset, calculated).map(item => this.getTemplate(item))} | |
` | |
: 'No components found'} | |
</div> | |
`; | |
} | |
private getTemplate(item: any) { | |
return html` | |
${this.template ? this.template(item) : html`${item}`} | |
<span class="spacer"></span> | |
`; | |
} | |
} | |
// Usage | |
import { html, Component, LitElement, css } from '@rxdi/lit-html'; | |
import { MainView } from '../shared/styles/margin-top'; | |
import { Inject } from '@rxdi/core'; | |
import { UIComponentsService } from '../core/services/ui-components/ui-components.service'; | |
import { IComponentsType } from '../app.interface'; | |
import { COMPONENTS_DATA } from '../shared/grid/data'; | |
import { of } from 'rxjs'; | |
/** | |
* @customElement ui-components-component | |
*/ | |
@Component({ | |
selector: 'ui-components-component', | |
style: css` | |
${MainView} | |
h4 { | |
color: black; | |
margin-bottom: 0px; | |
} | |
`, | |
template(this: UiComponentsComponent) { | |
return html` | |
<div style="color: #324044;width: 100%; height: 100%;background-color: #f1f5f7"> | |
<div class="container"> | |
<div style="margin: 75px auto; padding: 25px; "> | |
<h1>Browse collections</h1> | |
<h3>72 Collections</h3> | |
<flex-grid | |
.$items=${[ | |
html`<p>2222</p>` | |
]} | |
></flex-grid> | |
<flex-grid | |
.$items=${this.uiComponentsService.$components} | |
.template=${(component: IComponentsType) => html` | |
<div style="margin-right: 15px;"> | |
<card-component style="cursor: pointer"> | |
<div style="width: 280px; height: 250px; text-align: center; padding: 15px; "> | |
<h4>${component.namespace}</h4> | |
<p>${component.items} Items</p> | |
<p> | |
${component.description} | |
</p> | |
<spacer-component></spacer-component> | |
<div class="flex"> | |
<span class="spacer"></span> | |
<div> | |
<p style=" margin: 0px;"> | |
<img style="width: 40px;" src="https://graphql-server.com/assets/images/logo.png" /> | |
</p> | |
</div> | |
<div> | |
<p style="margin: 10px 0 0 0; font-size: 13px; color: #027cb1">${component.owner}</p> | |
</div> | |
<span class="spacer"></span> | |
</div> | |
</div> | |
</card-component> | |
</div> | |
`} | |
> | |
</flex-grid> | |
</div> | |
</div> | |
</div> | |
`; | |
}, | |
}) | |
export class UiComponentsComponent extends LitElement { | |
@Inject(UIComponentsService) | |
private uiComponentsService: UIComponentsService; | |
interval; | |
OnInit() { | |
this.interval = setInterval(() => { | |
COMPONENTS_DATA.push({ | |
description: ` | |
An evolving set of free, open source web components for building mobile and desktop web | |
applications in modern browsers. | |
`, | |
id: '1', | |
items: 51, | |
namespace: '2', | |
owner: 'HTMLELements', | |
}); | |
this.uiComponentsService.loadComponents(COMPONENTS_DATA); | |
}, 2000); | |
} | |
OnDestroy() { | |
clearInterval(this.interval); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment