Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Ember CSS Grid Masonry
import Component from '@glimmer/component';
export default class extends Component {
constructor() {
super(...arguments);
this.items = new Array(16);
}
}
import Component from '@glimmer/component';
export default class extends Component {
}
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { htmlSafe } from '@ember/template';
// The code in this component generates a random height
export default class extends Component {
@tracked height;
constructor() {
super(...arguments);
this.height = this.getRandomIntInclusive(50, 250);
}
get computedStyle() {
return htmlSafe(`height: ${this.height}px`);
}
getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
}
import Controller from '@ember/controller';
export default class ApplicationController extends Controller {
appName = 'Ember Twiddle';
}
import Modifier from 'ember-modifier';
export default class MasonryColumnsModifier extends Modifier {
get gridWidth() {
let gridStyle = getComputedStyle(this.element);
let paddingLeft = parseFloat(gridStyle.getPropertyValue('padding-left'));
let paddingRight = parseFloat(gridStyle.getPropertyValue('padding-right'));
return parseFloat(gridStyle.getPropertyValue('width')) - (paddingLeft + paddingRight);
}
get columnGap() {
let { columnGap } = this.args.named;
if (columnGap === 'auto') {
let possibleColumns = Math.floor(this.gridWidth / this.columnWidth);
let availableSpace = this.gridWidth - (this.columnWidth * possibleColumns);
return Math.floor(availableSpace / (possibleColumns - 1));
}
return parseFloat(columnGap);
}
get columnCount() {
let { columnCount } = this.args.named;
if (columnCount === 'auto') {
return Math.floor((this.gridWidth + this.columnGap)/(this.columnWidth + this.columnGap));
}
return parseFloat(this.args.named.columnCount);
}
get columnWidth() {
return parseFloat(this.args.named.columnWidth);
}
didReceiveArguments() {
this.configureColumns();
}
didInstall() {
this.resizeObserver = new ResizeObserver((entries) => {
this.configureColumns();
});
this.resizeObserver.observe(this.element);
}
configureColumns() {
this.element.style.gridTemplateColumns = `repeat(${this.columnCount}, ${this.columnWidth}px)`;
this.element.style.gridColumnGap = `${this.columnGap}px`;
}
}
import Modifier from 'ember-modifier';
export default class MasonryRowsModifier extends Modifier {
get rowGap() {
return parseFloat(this.args.named.rowGap);
}
didReceiveArguments() {
let numRows = Math.ceil(this.element.offsetHeight / 1) + this.rowGap;
this.element.style.gridRowEnd = `span ${numRows}`;
}
}
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
.masonry-demo {
position: relative;
width: 100%;
}
.masonry {
display: grid;
grid-auto-rows: 1px;
border: 1px solid gray;
box-sizing: border-box;
min-width: 100%;
}
.masonry-item {
}
.content {
background-color: lightgray;
border: 1px dashed black;
display: flex;
font-size: 45pt;
align-items: center;
justify-content: center;
}
<h1>Ember CSS Grid Masonry</h1>
<p>This demo implements a masonry layout with nothing but CSS Grid and Ember modifiers. Uncheck "Live Reload" in the upper right corner and click "Run Now" several times to see the grid adapt to different item sizes! Also, try changing some of the values in the template masonry-demo.hbs to customize the grid.</p>
<MasonryDemo/>
<div class="masonry-demo">
<MasonryGrid
@columnCount='auto'
@columnWidth=120
@columnGap='auto'
@rowGap=10
as |grid|
>
{{#each this.items as |item index|}}
<grid.Item>{{index}}</grid.Item>
{{/each}}
</MasonryGrid>
</div>
<div class="masonry"
{{masonry-columns
columnCount=@columnCount
columnWidth=@columnWidth
columnGap=@columnGap
}}
>
{{yield (hash Item=(component 'masonry-item' rowGap=@rowGap))}}
</div>
<div
class="masonry-item content"
style={{this.computedStyle}}
{{masonry-rows rowGap=@rowGap}}
>
{{yield}}
</div>
{
"version": "0.17.1",
"EmberENV": {
"FEATURES": {},
"_TEMPLATE_ONLY_GLIMMER_COMPONENTS": false,
"_APPLICATION_TEMPLATE_WRAPPER": true,
"_JQUERY_INTEGRATION": true
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js",
"ember": "3.18.1",
"ember-template-compiler": "3.18.1",
"ember-testing": "3.18.1"
},
"addons": {
"@glimmer/component": "1.0.0",
"ember-modifier": "2.1.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.