npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sd-masonry

v0.1.11

Published

Angular Component for organising child components in a masonry layout

Downloads

6

Readme

SdMasonry

This library was generated with Angular CLI version 10.0.14.

Angular Component for organising child components in a masonry layout

The masonry grid is hastily calculated using sdMasonryWidth and sdMasonryHeight on each item on an array that you provide. Much faster than working this out on the fly after render that you see on other masonry layout packages. From there, you may add as much or as little data you want to each item which will be passed to one of your own component to do with what you will.

Did I mention sd-masonry also flawlessly handles pagination. Simply add more items to your data object

Install

npm i sd-masonry

Usage

Import SdMasonryModule into your app's modules:

import { SdMasonryModule } from 'sd-masonry';

@NgModule({
  imports: [SdMasonryModule],
  ...
})

@Params

  • component: Component Class (required)
  • data: array (required)
  • maxGridGap: number (optional - default 10px)
  • maxTotalColCount: number (optional - default 10px)

<sd-masonry [component]="component" [data]="data" maxGridGap="0" maxTotalColCount="15"></sd-masonry>

maxGrigGap and maxTotalColCount will automatically reduce in size depending on the container size

Component Class

Your component will be passed each item in your data array above in the form of an item object. Your component will need to be ready to grab it - @Input() item

@Input() item: {sdMasonryWidth: number, sdMasonryHeight: number, ... };

Getting Started - A Walk-through

Start a new project ng new my-sd-masonry

replace app.component.ts with the following

import { Component, Input } from '@angular/core';  

@Component({  
    selector: 'app-root',  
    template: `<div style="margin: 40px 100px;"><sd-masonry [component]="component" [data]="data"></sd-masonry></div>`,  
})  
export class AppComponent {  
  
    /** Required by sd-masonry */  
    public component = ItemComponent; /** ItemComponent declared below */  
  
    /** Required by sd-masonry (id and url properties are only required by ItemComponent in this example) */
    public data: {sdMasonryWidth: number, sdMasonryHeight: number, id?: number, url?: string}[];  
  
    private page1 = [  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1500, id: 1, url: 'https://via.placeholder.com/1000x1500/947/000/?text=1+-+1000x1500' },  
        { sdMasonryWidth: 1512, sdMasonryHeight: 1006, id: 2, url: 'https://via.placeholder.com/1512x1006/69c/000/?text=2+-+1512x1006' },  
        { sdMasonryWidth: 1507, sdMasonryHeight: 1004, id: 3, url: 'https://via.placeholder.com/1507x1004/a5b/000/?text=3+-+1507x1004' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1500, id: 4, url: 'https://via.placeholder.com/1000x1500/3c2/000/?text=4+-+1000x1500' },  
        { sdMasonryWidth: 1086, sdMasonryHeight: 1629, id: 5, url: 'https://via.placeholder.com/1086x1629/ae4/000/?text=5+-+1086x1629' },  
        { sdMasonryWidth: 1376, sdMasonryHeight: 1720, id: 6, url: 'https://via.placeholder.com/1376x1720/5c7/000/?text=6+-+1376x1720' },  
        { sdMasonryWidth: 1488, sdMasonryHeight: 992, id: 7, url: 'https://via.placeholder.com/1488x992/dbd/000/?text=7+-+1488x992' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1351, id: 8, url: 'https://via.placeholder.com/1000x1351/c8b/000/?text=8+-+1000x1351' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1500, id: 9, url: 'https://via.placeholder.com/1000x1500/2b3/000/?text=9+-+1000x1500' },  
        { sdMasonryWidth: 1374, sdMasonryHeight: 917, id: 10, url: 'https://via.placeholder.com/1374x917/468/000/?text=10+-+1374x917' },  
        { sdMasonryWidth: 708, sdMasonryHeight: 1060, id: 11, url: 'https://via.placeholder.com/708x1060/2c7/000/?text=11+-+708x1060' },  
        { sdMasonryWidth: 1368, sdMasonryHeight: 912, id: 12, url: 'https://via.placeholder.com/1368x912/a3a/000/?text=12+-+1368x912' },  
        { sdMasonryWidth: 888, sdMasonryHeight: 1291, id: 13, url: 'https://via.placeholder.com/888x1291/7ec/000/?text=13+-+888x1291' },  
        { sdMasonryWidth: 912, sdMasonryHeight: 1368, id: 14, url: 'https://via.placeholder.com/912x1368/1e3/000/?text=14+-+912x1368' },  
        { sdMasonryWidth: 1693, sdMasonryHeight: 1123, id: 15, url: 'https://via.placeholder.com/1693x1123/989/000/?text=15+-+1693x1123' },  
        { sdMasonryWidth: 1326, sdMasonryHeight: 1988, id: 16, url: 'https://via.placeholder.com/1326x1988/583/000/?text=16+-+1326x1988' },  
        { sdMasonryWidth: 1200, sdMasonryHeight: 1500, id: 17, url: 'https://via.placeholder.com/1200x1500/b9e/000/?text=17+-+1200x1500' },  
        { sdMasonryWidth: 1734, sdMasonryHeight: 1771, id: 18, url: 'https://via.placeholder.com/1734x1771/889/000/?text=18+-+1734x1771' },  
        { sdMasonryWidth: 817, sdMasonryHeight: 561, id: 19, url: 'https://via.placeholder.com/817x561/a5a/000/?text=19+-+817x561' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1500, id: 20, url: 'https://via.placeholder.com/1000x1500/5bd/000/?text=20+-+1000x1500' },  
        { sdMasonryWidth: 931, sdMasonryHeight: 1396, id: 21, url: 'https://via.placeholder.com/931x1396/d69/000/?text=21+-+931x1396' },  
        { sdMasonryWidth: 1006, sdMasonryHeight: 1512, id: 22, url: 'https://via.placeholder.com/1006x1512/2bb/000/?text=22+-+1006x1512' },  
        { sdMasonryWidth: 1146, sdMasonryHeight: 764, id: 23, url: 'https://via.placeholder.com/1146x764/68e/000/?text=23+-+1146x764' },  
        { sdMasonryWidth: 1840, sdMasonryHeight: 1228, id: 24, url: 'https://via.placeholder.com/1840x1228/8bd/000/?text=24+-+1840x1228' },  
        { sdMasonryWidth: 750, sdMasonryHeight: 500, id: 25, url: 'https://via.placeholder.com/750x500/891/000/?text=25+-+750x500' },  
        { sdMasonryWidth: 1182, sdMasonryHeight: 1000, id: 26, url: 'https://via.placeholder.com/1182x1000/464/000/?text=26+-+1182x1000' },  
        { sdMasonryWidth: 1396, sdMasonryHeight: 2092, id: 27, url: 'https://via.placeholder.com/1396x2092/d5d/000/?text=27+-+1396x2092' },  
        { sdMasonryWidth: 666, sdMasonryHeight: 1000, id: 28, url: 'https://via.placeholder.com/666x1000/989/000/?text=28+-+666x1000' },  
        { sdMasonryWidth: 931, sdMasonryHeight: 698, id: 29, url: 'https://via.placeholder.com/931x698/6c6/000/?text=29+-+931x698' },  
        { sdMasonryWidth: 1023, sdMasonryHeight: 1535, id: 30, url: 'https://via.placeholder.com/1023x1535/122/000/?text=30+-+1023x1535' },  
    ];  
  
    private page2 = [  
        { sdMasonryWidth: 855, sdMasonryHeight: 1282, id: 31, url: 'https://via.placeholder.com/855x1282/89e/000/?text=31+-+855x1282' },  
        { sdMasonryWidth: 967, sdMasonryHeight: 1450, id: 32, url: 'https://via.placeholder.com/967x1450/752/000/?text=32+-+967x1450' },  
        { sdMasonryWidth: 1680, sdMasonryHeight: 1120, id: 33, url: 'https://via.placeholder.com/1680x1120/871/000/?text=33+-+1680x1120' },  
        { sdMasonryWidth: 1060, sdMasonryHeight: 708, id: 34, url: 'https://via.placeholder.com/1060x708/211/000/?text=34+-+1060x708' },  
        { sdMasonryWidth: 1500, sdMasonryHeight: 1000, id: 35, url: 'https://via.placeholder.com/1500x1000/6a8/000/?text=35+-+1500x1000' },  
        { sdMasonryWidth: 1015, sdMasonryHeight: 1522, id: 36, url: 'https://via.placeholder.com/1015x1522/137/000/?text=36+-+1015x1522' },  
        { sdMasonryWidth: 1252, sdMasonryHeight: 765, id: 37, url: 'https://via.placeholder.com/1252x765/1db/000/?text=37+-+1252x765' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1500, id: 38, url: 'https://via.placeholder.com/1000x1500/ec6/000/?text=38+-+1000x1500' },  
        { sdMasonryWidth: 864, sdMasonryHeight: 1296, id: 39, url: 'https://via.placeholder.com/864x1296/a9b/000/?text=39+-+864x1296' },  
        { sdMasonryWidth: 760, sdMasonryHeight: 760, id: 40, url: 'https://via.placeholder.com/760x760/77e/000/?text=40+-+760x760' },  
        { sdMasonryWidth: 1500, sdMasonryHeight: 1000, id: 41, url: 'https://via.placeholder.com/1500x1000/686/000/?text=41+-+1500x1000' },  
        { sdMasonryWidth: 966, sdMasonryHeight: 1296, id: 42, url: 'https://via.placeholder.com/966x1296/987/000/?text=42+-+966x1296' },  
        { sdMasonryWidth: 1152, sdMasonryHeight: 768, id: 43, url: 'https://via.placeholder.com/1152x768/214/000/?text=43+-+1152x768' },  
        { sdMasonryWidth: 1004, sdMasonryHeight: 1385, id: 44, url: 'https://via.placeholder.com/1004x1385/c6c/000/?text=44+-+1004x1385' },  
        { sdMasonryWidth: 1016, sdMasonryHeight: 677, id: 45, url: 'https://via.placeholder.com/1016x677/776/000/?text=45+-+1016x677' },  
        { sdMasonryWidth: 864, sdMasonryHeight: 1296, id: 46, url: 'https://via.placeholder.com/864x1296/2ec/000/?text=46+-+864x1296' },  
        { sdMasonryWidth: 526, sdMasonryHeight: 750, id: 47, url: 'https://via.placeholder.com/526x750/565/000/?text=47+-+526x750' },  
        { sdMasonryWidth: 600, sdMasonryHeight: 750, id: 48, url: 'https://via.placeholder.com/600x750/62e/000/?text=48+-+600x750' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1500, id: 49, url: 'https://via.placeholder.com/1000x1500/7a7/000/?text=49+-+1000x1500' },  
        { sdMasonryWidth: 1040, sdMasonryHeight: 1560, id: 50, url: 'https://via.placeholder.com/1040x1560/d16/000/?text=50+-+1040x1560' },  
        { sdMasonryWidth: 1040, sdMasonryHeight: 1560, id: 51, url: 'https://via.placeholder.com/1040x1560/e4a/000/?text=51+-+1040x1560' },  
        { sdMasonryWidth: 1040, sdMasonryHeight: 1560, id: 52, url: 'https://via.placeholder.com/1040x1560/6b4/000/?text=52+-+1040x1560' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1500, id: 53, url: 'https://via.placeholder.com/1000x1500/81e/000/?text=53+-+1000x1500' },  
        { sdMasonryWidth: 1120, sdMasonryHeight: 1680, id: 54, url: 'https://via.placeholder.com/1120x1680/7de/000/?text=54+-+1120x1680' },  
        { sdMasonryWidth: 722, sdMasonryHeight: 1084, id: 55, url: 'https://via.placeholder.com/722x1084/d96/000/?text=55+-+722x1084' },  
        { sdMasonryWidth: 1000, sdMasonryHeight: 1250, id: 56, url: 'https://via.placeholder.com/1000x1250/e5a/000/?text=56+-+1000x1250' },  
        { sdMasonryWidth: 945, sdMasonryHeight: 1417, id: 57, url: 'https://via.placeholder.com/945x1417/92b/000/?text=57+-+945x1417' },  
        { sdMasonryWidth: 912, sdMasonryHeight: 1283, id: 58, url: 'https://via.placeholder.com/912x1283/63c/000/?text=58+-+912x1283' },  
        { sdMasonryWidth: 1197, sdMasonryHeight: 1820, id: 59, url: 'https://via.placeholder.com/1197x1820/e6a/000/?text=59+-+1197x1820' },  
        { sdMasonryWidth: 987, sdMasonryHeight: 1480, id: 60, url: 'https://via.placeholder.com/987x1480/6de/000/?text=60+-+987x1480' },  
    ];  
  
    /**  
     * Populate this.data 
     */  
    constructor() {  
        this.data = this.page1; /** Loading in Page 1 */  
  
        setTimeout(() => {  
            this.data = this.data.concat(this.page2); /** Loading in Page 2 */  
        }, 5000);  
    }  
}  
  
  
/**  
 * Your own child component for each sd-masonry cell 
 */
@Component({  
    selector: 'app-item-image',  
    template: `<img [src]="item.url" [alt]="item.id">`,  
    styles: ['img { width: 100%; height: 100%; object-fit: cover; border-radius: 5px;}'],  
})  
export class ItemComponent {  
    @Input() item: {sdMasonryWidth: number, sdMasonryHeight: number, id?: number, url?: string};
}

Update app.module.ts to include SdMasonryModule and ItemComponent

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent, ItemComponent } from './app.component';
import { SdMasonryModule } from 'sd-masonry';

@NgModule({
  declarations: [
    AppComponent,
    ItemComponent
  ],
  entryComponents: [ItemComponent],
  imports: [
    BrowserModule,
    SdMasonryModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Output

Masonry Output Screen-shot

Animation Example

Why not try adding in your own animation to the mix? Just edit your ItemComponent like so :

import {animate, state, style, transition, trigger} from '@angular/animations';

// ...

@Component({
    selector: 'app-item-image',
    template: `<img [@scaleAnimation]="state" [src]="item.url" [alt]="item.masonryStyle">`,
    styles: ['img { width: 100%; height: 100%; object-fit: cover;}'],
    animations: [trigger('scaleAnimation', [
        state('beginning', style({transform: 'scale(0)', opacity: 0})),
            state('end', style({transform: 'scale(1)', opacity: 1})),
            transition('beginning => end', [animate('300ms')]),
        ])]
})
export class ItemComponent implements OnInit{

    @Input() item: {adMasonryWidth: number, sdMasonryHeight: number, id?: number, url?: string};
    public state = 'beginning';

    ngOnInit(): void {
        setTimeout(() => {
            this.state = 'end';
        }, Math.random() * 600);
    }
}

Remember to update app.module.ts to import the BrowserAnimationsModule

imports: [
    BrowserModule,
    SdMasonryModule,
    BrowserAnimationsModule
],

Upping the game

If you chose to include an id property, you'll also be able individually update an item's property, add a new item into the middle of the stack, and delete an item. Try updating your app.component.ts to the following

    private newItem = { sdMasonryWidth: 1368, sdMasonryHeight: 2739, id: 61, url: 'https://via.placeholder.com/966x1296/000/fff/?text=NEW+ITEM' };

    /**
     * Populate this.data
     */
    constructor() {

        const delay = 2000;
        let i = 2;

        /** Loading in Page 1 */
        this.data = this.page1;

        /** Change an item's properties (and dimensions) - changing background to red */
        setTimeout(() => {
            this.data = this.data.map(item => {
                if (item.id === 23) {
                    item.url = 'https://via.placeholder.com/146x430/f00/000/?text=23+-+146x430';
                    item.sdMasonryWidth = 146;
                    item.sdMasonryHeight = 430;
                }
                return item;
            });
        }, delay * i++);

        /** Add a new item randomly into the stack */
        setTimeout(() => {
            this.data.splice(12, 0, this.newItem);
            this.data = [].concat(this.data); /** sd-masonry uses ngOnChange(), so mutated data won't trigger that lifecycle event 😔 */
        }, delay * i++);

        /** Loading in Page 2 */
        setTimeout(() => {
            this.data = this.data.concat(this.page2);
        }, delay * i++);

        /** Now... Let's remove the item we just added */
        setTimeout(() => {
            this.data = this.data.filter((item, index) => index !== 12);
        }, delay * i++);
    }

Troubleshooting

If you're getting Ivy errors, you may need to update tsconfig.json or tsconfig.app.json with

  "angularCompilerOptions": {
    "enableIvy": false
  }

Further help

To get more help on the Angular CLI use ng help or go check out the Angular CLI README.