From 3fec0a94bd102d81db61efba7c3b8b8ce34c72e9 Mon Sep 17 00:00:00 2001 From: Varun Patil Date: Fri, 4 Aug 2023 18:49:28 -0700 Subject: [PATCH] cluster: new albums layout Signed-off-by: Varun Patil --- src/components/ClusterGrid.vue | 47 +++++++++++--- src/components/ClusterView.vue | 8 ++- src/components/frame/Cluster.vue | 103 +++++++++++++++++++++---------- 3 files changed, 114 insertions(+), 44 deletions(-) diff --git a/src/components/ClusterGrid.vue b/src/components/ClusterGrid.vue index b149ff1e..8eae2fcf 100644 --- a/src/components/ClusterGrid.vue +++ b/src/components/ClusterGrid.vue @@ -8,7 +8,8 @@ :items="clusters" :skipHover="true" :buffer="400" - :itemSize="itemSize" + :itemSize="height" + :itemSecondarySize="width" :gridItems="gridItems" @resize="resize" > @@ -18,7 +19,7 @@ @@ -60,8 +61,7 @@ export default defineComponent({ }, data: () => ({ - itemSize: 200, - gridItems: 5, + recyclerWidth: 300, }), mounted() { @@ -69,6 +69,40 @@ export default defineComponent({ }, computed: { + /** Height of the cluster */ + height() { + if (this.routeIsAlbums) { + // album view: add gap for text below album + return this.width + 42; + } + + return this.width; + }, + + /** Width of the cluster */ + width() { + // Restrict the number of columns between minCols and the size cap + return Math.floor(this.recyclerWidth / this.gridItems); + }, + + /** Number of items horizontally */ + gridItems() { + return Math.max(Math.floor(this.recyclerWidth / this.maxSize), this.minCols); + }, + + /** Classes list on cluster object */ + clusterClasses() { + return { + 'cluster--album': this.routeIsAlbums, + }; + }, + + /** Whether the clusters should show counters */ + counters() { + return !this.routeIsAlbums; + }, + + /** List of clusters to display */ clusters() { const items = [...this.items]; @@ -98,10 +132,7 @@ export default defineComponent({ }, resize() { - // Restrict the number of columns between minCols and the size cap - const w = (this.$refs.recycler).$el.clientWidth; - this.gridItems = Math.max(Math.floor(w / this.maxSize), this.minCols); - this.itemSize = Math.floor(w / this.gridItems); + this.recyclerWidth = (this.$refs.recycler).$el.clientWidth; }, }, }); diff --git a/src/components/ClusterView.vue b/src/components/ClusterView.vue index bc373122..e0db06a6 100644 --- a/src/components/ClusterView.vue +++ b/src/components/ClusterView.vue @@ -6,7 +6,7 @@ - + @@ -56,7 +56,11 @@ export default defineComponent({ }, minCols() { - return this.$route.name === 'albums' ? 2 : 3; + return this.routeIsAlbums ? 2 : 3; + }, + + maxSize() { + return this.routeIsAlbums ? 250 : 180; }, }, diff --git a/src/components/frame/Cluster.vue b/src/components/frame/Cluster.vue index c7a42af6..2ea1ba76 100644 --- a/src/components/frame/Cluster.vue +++ b/src/components/frame/Cluster.vue @@ -4,8 +4,8 @@ {{ data.count }}
- {{ title }} - {{ subtitle }} +
{{ title }}
+
{{ subtitle }}
@@ -87,8 +87,23 @@ export default defineComponent({ }, subtitle() { - if (this.album && this.album.user !== getCurrentUser()?.uid) { - return `(${this.album.user_display || this.album.user})`; + if (this.album) { + let text: string; + if (this.album.count === 0) { + text = this.t('memories', 'No items'); + } else { + text = this.n('memories', '{n} item', '{n} items', this.album.count, { n: this.album.count }); + } + + if (this.album.user !== getCurrentUser()?.uid) { + text += + ' / ' + + this.t('memories', 'Shared by {user}', { + user: this.album.user_display || this.album.user, + }); + } + + return text; } return ''; @@ -165,14 +180,6 @@ img { } .cluster { - // to use this option, the height must be set to a bit more - // than the width for the text; the image will then be forced - // to be square and the label will be outside. - &--circle { - height: unset; // from .fill-block - aspect-ratio: 1; - } - // Get rid of color of the bubble .count-bubble :deep .counter-bubble__counter { color: unset !important; @@ -187,9 +194,6 @@ $namemargin: 7px; width: calc(100% - 2 * #{$namemargin}); margin: $namemargin; - // 2px padding prevents the bottom of the text from being cut off - padding-bottom: 2px; - color: white; word-wrap: break-word; white-space: normal; @@ -198,31 +202,55 @@ $namemargin: 7px; line-height: 1.1em; // multiline ellipsis - display: -webkit-box; - -webkit-line-clamp: 5; - -webkit-box-orient: vertical; - overflow: hidden; + > .title { + display: -webkit-box; + -webkit-line-clamp: 5; + -webkit-box-orient: vertical; + overflow: hidden; + // 2px padding prevents the bottom of the text from being cut off + padding-bottom: 2px; + } + + // name is below the image .cluster--circle & { - -webkit-line-clamp: 2; margin: 0 $namemargin; min-height: 26px; // alignment - } - - > .subtitle { - font-size: 0.7em; - margin-top: 2px; - display: block; - } - - .cluster.error > &, - .cluster--circle & { color: unset; } + .cluster--circle &, + .cluster--album &, + .cluster.error & { + color: unset; + + > .title { + -webkit-line-clamp: 2; + } + } + + .cluster--album & { + text-align: start; + margin: 0; + padding: 0 12px; + min-height: 50px; + + > .subtitle { + color: var(--color-text-lighter); + font-size: 0.87em; + } + } + @media (max-width: 768px) { font-size: 0.9em; } + + > .subtitle { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } .count-bubble { @@ -239,6 +267,10 @@ $namemargin: 7px; padding: 2px; box-sizing: border-box; + .cluster--album & { + padding: 12px; + } + > .img-outer { position: relative; background-color: var(--color-background-dark); @@ -250,14 +282,17 @@ $namemargin: 7px; display: inline-block; cursor: pointer; - .cluster--rounded & { + .cluster--rounded &, + .cluster--album & { border-radius: 12px; // rounded corners } + .cluster--album &, .cluster--circle & { - // circle image - border-radius: 50%; height: unset; - aspect-ratio: 1; + aspect-ratio: 1; // force square + } + .cluster--circle & { + border-radius: 50%; // circle image } &.plus {