From 0225711b63c49c8921bb7a9db6e891b76a0950a3 Mon Sep 17 00:00:00 2001
From: Freeplay <Freeplay@duck.com>
Date: Thu, 27 Apr 2023 08:16:25 -0400
Subject: [PATCH] add additional information & show more button in user preview
 popup

---
 .../client/src/components/MkUserPreview.vue   | 133 +++++++++++++++++-
 1 file changed, 132 insertions(+), 1 deletion(-)

diff --git a/packages/client/src/components/MkUserPreview.vue b/packages/client/src/components/MkUserPreview.vue
index 956dececb..1e6db1442 100644
--- a/packages/client/src/components/MkUserPreview.vue
+++ b/packages/client/src/components/MkUserPreview.vue
@@ -46,7 +46,7 @@
 					/></MkA>
 					<p class="username"><MkAcct :user="user" /></p>
 				</div>
-				<div class="description">
+				<div class="description" :class="{ collapsed: isLong && collapsed }">
 					<Mfm
 						v-if="user.description"
 						:text="user.description"
@@ -55,6 +55,45 @@
 						:custom-emojis="user.emojis"
 					/>
 				</div>
+				<button
+					v-if="isLong && collapsed"
+					class="fade _button"
+					@click.stop="collapsed = false"
+				>
+					<span>{{ i18n.ts.showMore }}</span>
+				</button>
+				<button
+					v-if="isLong && !collapsed"
+					class="showLess _button"
+					@click.stop="collapsed = true"
+				>
+					<span>{{ i18n.ts.showLess }}</span>
+				</button>
+				<div v-if="user.fields.length > 0" class="fields">
+					<dl
+						v-for="(field, i) in user.fields"
+						:key="i"
+						class="field"
+					>
+						<dt class="name">
+							<Mfm
+								:text="field.name"
+								:plain="true"
+								:custom-emojis="user.emojis"
+								:colored="false"
+							/>
+						</dt>
+						<dd class="value">
+							<Mfm
+								:text="field.value"
+								:author="user"
+								:i="$i"
+								:custom-emojis="user.emojis"
+								:colored="false"
+							/>
+						</dd>
+					</dl>
+				</div>
 				<div class="status">
 					<div>
 						<p>{{ i18n.ts.notes }}</p>
@@ -110,9 +149,14 @@ let user = $ref<misskey.entities.UserDetailed | null>(null);
 let top = $ref(0);
 let left = $ref(0);
 
+
+let isLong = $ref(false);
+let collapsed = $ref(!isLong);
+
 onMounted(() => {
 	if (typeof props.q === "object") {
 		user = props.q;
+		isLong = (user.description.split("\n").length > 9 || user.description.length > 400);
 	} else {
 		const query = props.q.startsWith("@")
 			? Acct.parse(props.q.substr(1))
@@ -121,8 +165,10 @@ onMounted(() => {
 		os.api("users/show", query).then((res) => {
 			if (!props.showing) return;
 			user = res;
+			isLong = (user.description.split("\n").length > 9 || user.description.length > 400);
 		});
 	}
+	
 
 	const rect = props.source.getBoundingClientRect();
 	const x =
@@ -219,6 +265,88 @@ onMounted(() => {
 			padding: 0 16px;
 			font-size: 0.8em;
 			color: var(--fg);
+			&.collapsed {
+				position: relative;
+				max-height: calc(9em + 50px);
+				mask: linear-gradient(black calc(100% - 64px), transparent);
+				-webkit-mask: linear-gradient(
+					black calc(100% - 64px),
+					transparent
+				);
+			}
+		}
+		:deep(.fade) {
+			position: relative;
+			display: block;
+			width: 100%;
+			margin-top: -2.5em;
+			z-index: 2;
+			> span {
+				display: inline-block;
+				background: var(--panel);
+				padding: 0.4em 1em;
+				font-size: 0.8em;
+				border-radius: 999px;
+				box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
+			}
+			&:hover {
+				> span {
+					background: var(--panelHighlight);
+				}
+			}
+		}
+		:deep(.showLess) {
+			width: 100%;
+			margin-top: 1em;
+			position: sticky;
+			bottom: var(--stickyBottom);
+
+			> span {
+				display: inline-block;
+				background: var(--panel);
+				padding: 6px 10px;
+				font-size: 0.8em;
+				border-radius: 999px;
+				box-shadow: 0 0 7px 7px var(--bg);
+			}
+		}
+
+		> .fields {
+			padding: 0 16px;
+			font-size: .8em;
+			margin-top: 1em;
+
+			> .field {
+				display: flex;
+				padding: 0;
+				margin: 0;
+				align-items: center;
+
+				&:not(:last-child) {
+					margin-bottom: 8px;
+				}
+
+				:deep(span) {
+					white-space: nowrap !important;
+				}
+
+				> .name {
+					width: 30%;
+					overflow: hidden;
+					white-space: nowrap;
+					text-overflow: ellipsis;
+					font-weight: bold;
+					text-align: center;
+				}
+
+				> .value {
+					width: 70%;
+					overflow: hidden;
+					white-space: nowrap;
+					text-overflow: ellipsis;
+					margin: 0;
+				}
+			}
 		}
 
 		> .status {
@@ -237,6 +365,9 @@ onMounted(() => {
 				> span {
 					font-size: 1em;
 					color: var(--accent);
+					:global(span) {
+						white-space: nowrap;
+					}
 				}
 			}
 		}