diff --git a/src/client/components/ui/container.vue b/src/client/components/ui/container.vue index 427421af7d..ef90a348b4 100644 --- a/src/client/components/ui/container.vue +++ b/src/client/components/ui/container.vue @@ -16,8 +16,11 @@ @leave="leave" @after-leave="afterLeave" > - <div v-show="showBody"> + <div v-show="showBody" class="content" :class="{ omitted }" ref="content"> <slot></slot> + <button v-if="omitted" class="fade _button" @click="() => { ignoreOmit = true; omitted = false; }"> + <span>{{ $ts.showMore }}</span> + </button> </div> </transition> </div> @@ -54,10 +57,17 @@ export default defineComponent({ required: false, default: false }, + maxHeight: { + type: Number, + required: false, + default: null + }, }, data() { return { showBody: this.expanded, + omitted: null, + ignoreOmit: false, faAngleUp, faAngleDown }; }, @@ -73,6 +83,19 @@ export default defineComponent({ }, { immediate: true }); + + this.$el.style.setProperty('--maxHeight', this.maxHeight + 'px'); + + const calcOmit = () => { + if (this.omitted || this.ignoreOmit || this.maxHeight == null) return; + const height = this.$refs.content.offsetHeight; + this.omitted = height > this.maxHeight; + }; + + calcOmit(); + new ResizeObserver((entries, observer) => { + calcOmit(); + }).observe(this.$refs.content); }, methods: { toggleContent(show: boolean) { @@ -127,7 +150,7 @@ export default defineComponent({ display: flex; flex-direction: column; - > div { + > .content { overflow: auto; } } @@ -169,12 +192,35 @@ export default defineComponent({ } } - > div { - > ::v-deep(._content) { - padding: 24px; + > .content { + &.omitted { + position: relative; + max-height: var(--maxHeight); + overflow: hidden; - & + ._content { - border-top: solid 0.5px var(--divider); + > .fade { + display: block; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 64px; + background: linear-gradient(0deg, var(--panel), var(--X15)); + + > span { + display: inline-block; + background: var(--panel); + padding: 6px 10px; + font-size: 0.8em; + border-radius: 999px; + box-shadow: 0 2px 6px rgb(0 0 0 / 20%); + } + + &:hover { + > span { + background: var(--panelHighlight); + } + } } } } @@ -187,10 +233,7 @@ export default defineComponent({ } } - > div { - > ::v-deep(._content) { - padding: 16px; - } + > .content { } } } diff --git a/src/client/pages/user/index.photos.vue b/src/client/pages/user/index.photos.vue index 54796bccbc..b5493fd9f2 100644 --- a/src/client/pages/user/index.photos.vue +++ b/src/client/pages/user/index.photos.vue @@ -1,5 +1,5 @@ <template> -<MkContainer> +<MkContainer :max-height="300"> <template #header><Fa :icon="faImage" style="margin-right: 0.5em;"/>{{ $ts.images }}</template> <div class="ujigsodd"> <MkLoading v-if="fetching"/> @@ -8,6 +8,7 @@ class="img" :style="`background-image: url(${thumbnail(image.file)})`" :to="notePage(image.note)" + :key="image.id" ></MkA> </div> <p class="empty" v-if="!fetching && images.length == 0">{{ $ts.nothing }}</p> @@ -52,16 +53,14 @@ export default defineComponent({ userId: this.user.id, fileType: image, excludeNsfw: this.$store.state.nsfw !== 'ignore', - limit: 9, + limit: 10, }).then(notes => { for (const note of notes) { for (const file of note.files) { - if (this.images.length < 9) { - this.images.push({ - note, - file - }); - } + this.images.push({ + note, + file + }); } } this.fetching = false; @@ -83,19 +82,15 @@ export default defineComponent({ padding: 8px; > .stream { - display: flex; - justify-content: center; - flex-wrap: wrap; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + grid-gap: 6px; > .img { - flex: 1 1 33%; - width: 33%; - height: 90px; - box-sizing: border-box; + height: 128px; background-position: center center; background-size: cover; background-clip: content-box; - border: solid 2px transparent; border-radius: 6px; } }