diff --git a/packages/frontend/src/components/MkOmit.vue b/packages/frontend/src/components/MkOmit.vue new file mode 100644 index 0000000000..5a834c9800 --- /dev/null +++ b/packages/frontend/src/components/MkOmit.vue @@ -0,0 +1,72 @@ +<template> +<div ref="content" :class="[$style.content, { [$style.omitted]: omitted }]"> + <slot></slot> + <button v-if="omitted" :class="$style.fade" class="_button" @click="() => { ignoreOmit = true; omitted = false; }"> + <span :class="$style.fadeLabel">{{ $ts.showMore }}</span> + </button> +</div> +</template> + +<script lang="ts" setup> +import { nextTick, onMounted } from 'vue'; + +const props = withDefaults(defineProps<{ + maxHeight: number; +}>(), { + maxHeight: 200, +}); + +let content = $ref<HTMLElement>(); +let omitted = $ref(false); +let ignoreOmit = $ref(false); + +onMounted(() => { + const calcOmit = () => { + if (omitted || ignoreOmit) return; + omitted = content.offsetHeight > props.maxHeight; + }; + + calcOmit(); + new ResizeObserver((entries, observer) => { + calcOmit(); + }).observe(content); +}); +</script> + +<style lang="scss" module> +.content { + --stickyTop: 0px; + + &.omitted { + position: relative; + max-height: v-bind("props.maxHeight + 'px'"); + overflow: hidden; + + > .fade { + display: block; + position: absolute; + z-index: 10; + bottom: 0; + left: 0; + width: 100%; + height: 64px; + background: linear-gradient(0deg, var(--panel), var(--X15)); + + > .fadeLabel { + 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 { + > .fadeLabel { + background: var(--panelHighlight); + } + } + } + } +} +</style> diff --git a/packages/frontend/src/pages/user/home.vue b/packages/frontend/src/pages/user/home.vue index e30adf4473..b629ba7a0f 100644 --- a/packages/frontend/src/pages/user/home.vue +++ b/packages/frontend/src/pages/user/home.vue @@ -42,8 +42,10 @@ <span v-for="role in user.roles" :key="role.id" v-tooltip="role.description" class="role" :style="{ '--color': role.color }">{{ role.name }}</span> </div> <div class="description"> - <Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i"/> - <p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p> + <MkOmit> + <Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i"/> + <p v-else class="empty">{{ i18n.ts.noAccountDescription }}</p> + </MkOmit> </div> <div class="fields system"> <dl v-if="user.location" class="field"> @@ -119,6 +121,7 @@ import MkContainer from '@/components/MkContainer.vue'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; import MkRemoteCaution from '@/components/MkRemoteCaution.vue'; import MkTab from '@/components/MkTab.vue'; +import MkOmit from '@/components/MkOmit.vue'; import MkInfo from '@/components/MkInfo.vue'; import { getScrollPosition } from '@/scripts/scroll'; import { getUserMenu } from '@/scripts/get-user-menu';