diff --git a/frontend/src/app/components/masonry/masonry.component.html b/frontend/src/app/components/masonry/masonry.component.html index 6dbc743..a6cb881 100644 --- a/frontend/src/app/components/masonry/masonry.component.html +++ b/frontend/src/app/components/masonry/masonry.component.html @@ -1 +1,3 @@ - + +
+
diff --git a/frontend/src/app/components/masonry/masonry.component.scss b/frontend/src/app/components/masonry/masonry.component.scss index e69de29..1c3c4e9 100644 --- a/frontend/src/app/components/masonry/masonry.component.scss +++ b/frontend/src/app/components/masonry/masonry.component.scss @@ -0,0 +1,11 @@ +:host { + display: flex; + flex-direction: row; +} + +.column { + display: flex; + flex-grow: 1; + flex-basis: 0; + flex-direction: column; +} diff --git a/frontend/src/app/components/masonry/masonry.component.ts b/frontend/src/app/components/masonry/masonry.component.ts index 97d3e90..953a1c4 100644 --- a/frontend/src/app/components/masonry/masonry.component.ts +++ b/frontend/src/app/components/masonry/masonry.component.ts @@ -3,13 +3,15 @@ import { Component, ContentChildren, ElementRef, - OnChanges, - OnInit, + Input, + OnDestroy, QueryList, - SimpleChanges, - ViewChild, + ViewChildren } from '@angular/core'; import { AutoUnsubscribe } from 'ngx-auto-unsubscribe-decorator'; +import { combineLatest, Subscription } from 'rxjs'; +import { RemoveChildren } from 'src/app/util/remove-children'; +import { Throttle } from 'src/app/util/throttle'; import { MasonryItemDirective } from './masonry-item.directive'; @Component({ @@ -17,9 +19,17 @@ import { MasonryItemDirective } from './masonry-item.directive'; templateUrl: './masonry.component.html', styleUrls: ['./masonry.component.scss'], }) -export class MasonryComponent implements AfterViewInit { +export class MasonryComponent implements AfterViewInit, OnDestroy { + @Input('columns') column_count: number = 1; + @Input('update-speed') update_speed: number = 200; + @ContentChildren(MasonryItemDirective) - content: QueryList; + private content: QueryList; + + @ViewChildren('column') + private columns: QueryList>; + + private sizesSubscription: Subscription | null = null; ngAfterViewInit(): void { this.subscribeContent(); @@ -27,8 +37,58 @@ export class MasonryComponent implements AfterViewInit { @AutoUnsubscribe() private subscribeContent() { - return this.content.changes.subscribe((items) => { - console.log('a', items.toArray()); - }); + return this.content.changes.subscribe( + (items: QueryList) => { + const sizes = items.map((i) => i.getSize()); + + if (this.sizesSubscription) { + this.sizesSubscription.unsubscribe(); + } + + this.sizesSubscription = combineLatest(sizes) + .pipe(Throttle(this.update_speed)) + .subscribe((output) => { + this.resortItems(items); + }); + + this.resortItems(items); + } + ); + } + + private resortItems(items: QueryList) { + const itemsArray = items.toArray(); + const columnsArray = this.columns.map((c) => c.nativeElement); + + for (let i = 0; i < columnsArray.length; i++) { + RemoveChildren(columnsArray[i]); + } + + const columnSizes = columnsArray.map((c) => 0); + + for (let i = 0; i < itemsArray.length; i++) { + const item = itemsArray[i]; + + let smallestColumn = 0; + let smallestColumnSize = columnSizes[0]; + for (let j = 1; j < columnSizes.length; j++) { + let better_j = (j + i) % columnSizes.length; + + if (columnSizes[better_j] <= smallestColumnSize) { + smallestColumn = better_j; + smallestColumnSize = columnSizes[better_j]; + } + } + + columnsArray[smallestColumn].appendChild(item.getElement()); + columnSizes[smallestColumn] += + item.getLastSize()?.contentRect.height ?? 0; + } + } + + ngOnDestroy() { + if (this.sizesSubscription) { + this.sizesSubscription.unsubscribe(); + } } } diff --git a/frontend/src/app/routes/images/images.component.html b/frontend/src/app/routes/images/images.component.html index 2daa283..6924587 100644 --- a/frontend/src/app/routes/images/images.component.html +++ b/frontend/src/app/routes/images/images.component.html @@ -1,5 +1,5 @@ - -
+ +
Image by you @@ -21,35 +21,6 @@
-
-
-
- - - Image by you - - Uploaded {{ image.created | amTimeAgo }} - - - - - - - - - -
-
-
-