From c95da270191293b8171f4f1197ef609905a9b911 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 26 Dec 2022 08:40:13 +0900
Subject: [PATCH] enhance(client): use container queries if available to
 improve perf

---
 CHANGELOG.md                                  |  1 +
 .../client/src/components/MkContainer.vue     | 11 +++
 .../src/components/MkDateSeparatedList.vue    |  2 +
 packages/client/src/components/MkNote.vue     | 18 +++--
 .../client/src/components/MkNoteDetailed.vue  | 68 +++++++++++++++++++
 .../client/src/components/MkNotePreview.vue   | 20 ++++++
 .../client/src/components/MkNoteSimple.vue    | 20 ++++++
 packages/client/src/components/MkNoteSub.vue  | 10 +++
 .../client/src/components/MkNotification.vue  | 14 ++++
 packages/client/src/components/MkPostForm.vue | 57 ++++++++++++++++
 .../client/src/components/MkUrlPreview.vue    | 67 ++++++++++++++++++
 packages/client/src/components/MkWidgets.vue  |  2 +
 .../client/src/components/global/MkSpacer.vue |  1 +
 packages/client/src/directives/size.ts        |  8 +++
 .../client/src/pages/antenna-timeline.vue     |  7 ++
 packages/client/src/pages/messaging/index.vue | 24 +++++++
 .../messaging/messaging-room.message.vue      | 35 +++++++++-
 packages/client/src/pages/page.vue            |  2 +-
 .../client/src/pages/user-list-timeline.vue   |  7 ++
 packages/client/src/pages/user/home.vue       | 52 ++++++++++++++
 20 files changed, 420 insertions(+), 6 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e38d7e63c..13c2876a82 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,7 @@ You should also include the user name that made the change.
 - Client: Implement the button to subscribe push notification @tamaina
 - Client: Implement the toggle to or not to close push notifications when notifications or messages are read @tamaina
 - Client: show Unicode emoji tooltip with its name in MkReactionsViewer.reaction @saschanaz
+- Client: improve overall performance of client @syuilo
 
 ### Bugfixes
 - Server: 引用内の文章がnyaizeされてしまう問題を修正 @kabo2468
diff --git a/packages/client/src/components/MkContainer.vue b/packages/client/src/components/MkContainer.vue
index c097946c19..6d4d5be2bc 100644
--- a/packages/client/src/components/MkContainer.vue
+++ b/packages/client/src/components/MkContainer.vue
@@ -246,6 +246,17 @@ export default defineComponent({
 	}
 }
 
+@container (max-width: 380px) {
+	.ukygtjoj {
+		> header {
+			> .title {
+				padding: 8px 10px;
+				font-size: 0.9em;
+			}
+		}
+	}
+}
+
 ._forceContainerFull_ .ukygtjoj {
 	> header {
 		> .title {
diff --git a/packages/client/src/components/MkDateSeparatedList.vue b/packages/client/src/components/MkDateSeparatedList.vue
index 68903f3526..1f88bdf137 100644
--- a/packages/client/src/components/MkDateSeparatedList.vue
+++ b/packages/client/src/components/MkDateSeparatedList.vue
@@ -108,6 +108,8 @@ export default defineComponent({
 
 <style lang="scss">
 .sqadhkmv {
+	container-type: inline-size;
+
 	> *:empty {
 		display: none;
 	}
diff --git a/packages/client/src/components/MkNote.vue b/packages/client/src/components/MkNote.vue
index 1feb161ada..a4100e1f2c 100644
--- a/packages/client/src/components/MkNote.vue
+++ b/packages/client/src/components/MkNote.vue
@@ -433,6 +433,8 @@ function readPromo() {
 			min-width: 0;
 
 			> .body {
+				container-type: inline-size;
+
 				> .cw {
 					cursor: default;
 					display: block;
@@ -573,8 +575,10 @@ function readPromo() {
 	> .reply {
 		border-top: solid 0.5px var(--divider);
 	}
+}
 
-	&.max-width_500px {
+@container (max-width: 500px) {
+	.tkcbzcuz {
 		font-size: 0.9em;
 
 		> .article {
@@ -584,8 +588,10 @@ function readPromo() {
 			}
 		}
 	}
+}
 
-	&.max-width_450px {
+@container (max-width: 450px) {
+	.tkcbzcuz {
 		> .renote {
 			padding: 8px 16px 0 16px;
 		}
@@ -605,8 +611,10 @@ function readPromo() {
 			}
 		}
 	}
+}
 
-	&.max-width_350px {
+@container (max-width: 350px) {
+	.tkcbzcuz {
 		> .article {
 			> .main {
 				> .footer {
@@ -619,8 +627,10 @@ function readPromo() {
 			}
 		}
 	}
+}
 
-	&.max-width_300px {
+@container (max-width: 300px) {
+	.tkcbzcuz {
 		> .article {
 			> .avatar {
 				width: 44px;
diff --git a/packages/client/src/components/MkNoteDetailed.vue b/packages/client/src/components/MkNoteDetailed.vue
index 8269906bb0..7ce8e039d9 100644
--- a/packages/client/src/components/MkNoteDetailed.vue
+++ b/packages/client/src/components/MkNoteDetailed.vue
@@ -444,6 +444,8 @@ if (appearNote.replyId) {
 
 		> .main {
 			> .body {
+				container-type: inline-size;
+
 				> .cw {
 					cursor: default;
 					display: block;
@@ -601,6 +603,72 @@ if (appearNote.replyId) {
 	}
 }
 
+@container (max-width: 500px) {
+	.lxwezrsl {
+		font-size: 0.9em;
+	}
+}
+
+@container (max-width: 450px) {
+	.lxwezrsl {
+		> .renote {
+			padding: 8px 16px 0 16px;
+		}
+
+		> .article {
+			padding: 16px;
+
+			> .header {
+				> .avatar {
+					width: 50px;
+					height: 50px;
+				}
+			}
+		}
+	}
+}
+
+@container (max-width: 350px) {
+	.lxwezrsl {
+		> .article {
+			> .main {
+				> .footer {
+					> .button {
+						&:not(:last-child) {
+							margin-right: 18px;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+@container (max-width: 300px) {
+	.lxwezrsl {
+		font-size: 0.825em;
+
+		> .article {
+			> .header {
+				> .avatar {
+					width: 50px;
+					height: 50px;
+				}
+			}
+
+			> .main {
+				> .footer {
+					> .button {
+						&:not(:last-child) {
+							margin-right: 12px;
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
 .muted {
 	padding: 8px;
 	text-align: center;
diff --git a/packages/client/src/components/MkNotePreview.vue b/packages/client/src/components/MkNotePreview.vue
index a78b499654..0c81059091 100644
--- a/packages/client/src/components/MkNotePreview.vue
+++ b/packages/client/src/components/MkNotePreview.vue
@@ -89,4 +89,24 @@ const props = defineProps<{
 		}
 	}
 }
+
+@container (min-width: 350px) {
+	.fefdfafb {
+		> .avatar {
+			margin: 0 10px 0 0;
+			width: 44px;
+			height: 44px;
+		}
+	}
+}
+
+@container (min-width: 500px) {
+	.fefdfafb {
+		> .avatar {
+			margin: 0 12px 0 0;
+			width: 48px;
+			height: 48px;
+		}
+	}
+}
 </style>
diff --git a/packages/client/src/components/MkNoteSimple.vue b/packages/client/src/components/MkNoteSimple.vue
index 1bbbe0e1a6..96d29831d2 100644
--- a/packages/client/src/components/MkNoteSimple.vue
+++ b/packages/client/src/components/MkNoteSimple.vue
@@ -96,4 +96,24 @@ const showContent = $ref(false);
 		}
 	}
 }
+
+@container (min-width: 350px) {
+	.yohlumlk {
+		> .avatar {
+			margin: 0 10px 0 0;
+			width: 44px;
+			height: 44px;
+		}
+	}
+}
+
+@container (min-width: 500px) {
+	.yohlumlk {
+		> .avatar {
+			margin: 0 12px 0 0;
+			width: 48px;
+			height: 48px;
+		}
+	}
+}
 </style>
diff --git a/packages/client/src/components/MkNoteSub.vue b/packages/client/src/components/MkNoteSub.vue
index 95b6b71be9..d03ce7c434 100644
--- a/packages/client/src/components/MkNoteSub.vue
+++ b/packages/client/src/components/MkNoteSub.vue
@@ -127,4 +127,14 @@ if (props.detail) {
 		padding: 10px 0 0 16px;
 	}
 }
+
+@container (max-width: 450px) {
+	.wrpstxzv {
+		padding: 14px 16px;
+
+		&.children {
+			padding: 10px 0 0 8px;
+		}
+	}
+}
 </style>
diff --git a/packages/client/src/components/MkNotification.vue b/packages/client/src/components/MkNotification.vue
index 82965212f3..8b8d3f452d 100644
--- a/packages/client/src/components/MkNotification.vue
+++ b/packages/client/src/components/MkNotification.vue
@@ -306,4 +306,18 @@ useTooltip(reactionRef, (showing) => {
 		}
 	}
 }
+
+@container (max-width: 600px) {
+	.qglefbjs {
+		padding: 16px;
+		font-size: 0.9em;
+	}
+}
+
+@container (max-width: 500px) {
+	.qglefbjs {
+		padding: 12px;
+		font-size: 0.85em;
+	}
+}
 </style>
diff --git a/packages/client/src/components/MkPostForm.vue b/packages/client/src/components/MkPostForm.vue
index eb302ccc96..f79e5a32cd 100644
--- a/packages/client/src/components/MkPostForm.vue
+++ b/packages/client/src/components/MkPostForm.vue
@@ -990,4 +990,61 @@ onMounted(() => {
 		}
 	}
 }
+
+@container (max-width: 500px) {
+	.gafaadew {
+		> header {
+			height: 50px;
+
+			> .cancel {
+				width: 50px;
+				line-height: 50px;
+			}
+
+			> .right {
+				> .text-count {
+					line-height: 50px;
+				}
+
+				> .submit {
+					margin: 8px;
+				}
+			}
+		}
+
+		> .form {
+			> .to-specified {
+				padding: 6px 16px;
+			}
+
+			> .cw,
+			> .hashtags,
+			> .text {
+				padding: 0 16px;
+			}
+
+			> .text {
+				min-height: 80px;
+			}
+
+			> footer {
+				padding: 0 8px 8px 8px;
+			}
+		}
+	}
+}
+
+@container (max-width: 310px) {
+	.gafaadew {
+		> .form {
+			> footer {
+				> button {
+					font-size: 14px;
+					width: 44px;
+					height: 44px;
+				}
+			}
+		}
+	}
+}
 </style>
diff --git a/packages/client/src/components/MkUrlPreview.vue b/packages/client/src/components/MkUrlPreview.vue
index ac03559bea..b2d16ddb01 100644
--- a/packages/client/src/components/MkUrlPreview.vue
+++ b/packages/client/src/components/MkUrlPreview.vue
@@ -313,4 +313,71 @@ onUnmounted(() => {
 		}
 	}
 }
+
+@container (max-width: 400px) {
+	.mk-url-preview {
+		> .link {
+			font-size: 12px;
+
+			> .thumbnail {
+				height: 80px;
+			}
+
+			> article {
+				padding: 12px;
+			}
+		}
+	}
+}
+
+@container (max-width: 350px) {
+	.mk-url-preview {
+		> .link {
+			font-size: 10px;
+
+			> .thumbnail {
+				height: 70px;
+			}
+
+			> article {
+				padding: 8px;
+
+				> header {
+					margin-bottom: 4px;
+				}
+
+				> footer {
+					margin-top: 4px;
+
+					> img {
+						width: 12px;
+						height: 12px;
+					}
+				}
+			}
+
+			&.compact {
+				> .thumbnail {
+					position: absolute;
+					width: 56px;
+					height: 100%;
+				}
+
+				> article {
+					left: 56px;
+					width: calc(100% - 56px);
+					padding: 4px;
+
+					> header {
+						margin-bottom: 2px;
+					}
+
+					> footer {
+						margin-top: 2px;
+					}
+				}
+			}
+		}
+	}
+}
 </style>
diff --git a/packages/client/src/components/MkWidgets.vue b/packages/client/src/components/MkWidgets.vue
index a0c77f91a9..fff89117ce 100644
--- a/packages/client/src/components/MkWidgets.vue
+++ b/packages/client/src/components/MkWidgets.vue
@@ -111,6 +111,8 @@ function onContextmenu(widget: Widget, ev: MouseEvent) {
 
 <style lang="scss" scoped>
 .vjoppmmu {
+	container-type: inline-size;
+
 	> header {
 		margin: 16px 0;
 
diff --git a/packages/client/src/components/global/MkSpacer.vue b/packages/client/src/components/global/MkSpacer.vue
index 53adf07771..c7d53f2ee7 100644
--- a/packages/client/src/components/global/MkSpacer.vue
+++ b/packages/client/src/components/global/MkSpacer.vue
@@ -72,5 +72,6 @@ onUnmounted(() => {
 
 .content {
 	margin: 0 auto;
+	container-type: inline-size;
 }
 </style>
diff --git a/packages/client/src/directives/size.ts b/packages/client/src/directives/size.ts
index c8f446e3a8..b514f4e38b 100644
--- a/packages/client/src/directives/size.ts
+++ b/packages/client/src/directives/size.ts
@@ -15,6 +15,8 @@ type ClassOrder = {
 	remove: string[];
 };
 
+const isContainerQueriesSupported = ('container' in document.documentElement.style);
+
 const cache = new Map<string, ClassOrder>();
 
 function getClassOrder(width: number, queue: Value): ClassOrder {
@@ -78,6 +80,8 @@ function calc(el: Element) {
 
 export default {
 	mounted(src, binding, vn) {
+		if (isContainerQueriesSupported) return;
+
 		const resize = new ResizeObserver((entries, observer) => {
 			calc(src);
 		});
@@ -93,11 +97,15 @@ export default {
 	},
 
 	updated(src, binding, vn) {
+		if (isContainerQueriesSupported) return;
+
 		mountings.set(src, Object.assign({}, mountings.get(src), { value: binding.value }));
 		calc(src);
 	},
 
 	unmounted(src, binding, vn) {
+		if (isContainerQueriesSupported) return;
+
 		const info = mountings.get(src);
 		if (!info) return;
 		info.resize.disconnect();
diff --git a/packages/client/src/pages/antenna-timeline.vue b/packages/client/src/pages/antenna-timeline.vue
index 592131b2a8..0b2c284c99 100644
--- a/packages/client/src/pages/antenna-timeline.vue
+++ b/packages/client/src/pages/antenna-timeline.vue
@@ -118,4 +118,11 @@ definePageMetadata(computed(() => antenna ? {
 		margin: 0 auto;
 	}
 }
+
+@container (min-width: 800px) {
+	.tqmomfks {
+		max-width: 800px;
+		margin: 0 auto;
+	}
+}
 </style>
diff --git a/packages/client/src/pages/messaging/index.vue b/packages/client/src/pages/messaging/index.vue
index b4cec5f5e9..0d30998330 100644
--- a/packages/client/src/pages/messaging/index.vue
+++ b/packages/client/src/pages/messaging/index.vue
@@ -300,4 +300,28 @@ definePageMetadata({
 		}
 	}
 }
+
+@container (max-width: 400px) {
+	.yweeujhr {
+		> .history {
+			> .message {
+				&:not(.isMe):not(.isRead) {
+					> div {
+						background-image: none;
+						border-left: solid 4px #3aa2dc;
+					}
+				}
+
+				> div {
+					padding: 16px;
+					font-size: 0.9em;
+
+					> .avatar {
+						margin: 0 12px 0 0;
+					}
+				}
+			}
+		}
+	}
+}
 </style>
diff --git a/packages/client/src/pages/messaging/messaging-room.message.vue b/packages/client/src/pages/messaging/messaging-room.message.vue
index e7cf54a066..dbf0e37b73 100644
--- a/packages/client/src/pages/messaging/messaging-room.message.vue
+++ b/packages/client/src/pages/messaging/messaging-room.message.vue
@@ -2,7 +2,7 @@
 <div v-size="{ max: [400, 500] }" class="thvuemwp" :class="{ isMe }">
 	<MkAvatar class="avatar" :user="message.user" :show-indicator="true"/>
 	<div class="content">
-		<div class="balloon" :class="{ noText: message.text == null }" >
+		<div class="balloon" :class="{ noText: message.text == null }">
 			<button v-if="isMe" class="delete-button" :title="$ts.delete" @click="del">
 				<img src="/client-assets/remove.png" alt="Delete"/>
 			</button>
@@ -331,4 +331,37 @@ function del(): void {
 		}
 	}
 }
+
+@container (max-width: 400px) {
+	.thvuemwp {
+		> .avatar {
+			width: 48px;
+			height: 48px;
+		}
+
+		> .content {
+			> .balloon {
+				> .content {
+					> .text {
+						font-size: 0.9em;
+					}
+				}
+			}
+		}
+	}
+}
+
+@container (max-width: 500px) {
+	.thvuemwp {
+		> .content {
+			> .balloon {
+				> .content {
+					> .text {
+						padding: 8px 16px;
+					}
+				}
+			}
+		}
+	}
+}
 </style>
diff --git a/packages/client/src/pages/page.vue b/packages/client/src/pages/page.vue
index 7072b8ef03..a95bfe485c 100644
--- a/packages/client/src/pages/page.vue
+++ b/packages/client/src/pages/page.vue
@@ -3,7 +3,7 @@
 	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
 	<MkSpacer :content-max="700">
 		<transition :name="$store.state.animation ? 'fade' : ''" mode="out-in">
-			<div v-if="page" :key="page.id" v-size="{ max: [450] }" class="xcukqgmh">
+			<div v-if="page" :key="page.id" class="xcukqgmh">
 				<div class="_block main">
 					<!--
 				<div class="header">
diff --git a/packages/client/src/pages/user-list-timeline.vue b/packages/client/src/pages/user-list-timeline.vue
index aa5c078ab4..fdb3167375 100644
--- a/packages/client/src/pages/user-list-timeline.vue
+++ b/packages/client/src/pages/user-list-timeline.vue
@@ -111,4 +111,11 @@ definePageMetadata(computed(() => list ? {
 		margin: 0 auto;
 	}
 }
+
+@container (min-width: 800px) {
+	.eqqrhokj {
+		max-width: 800px;
+		margin: 0 auto;
+	}
+}
 </style>
diff --git a/packages/client/src/pages/user/home.vue b/packages/client/src/pages/user/home.vue
index 55d0aa89a6..43c1b37e1d 100644
--- a/packages/client/src/pages/user/home.vue
+++ b/packages/client/src/pages/user/home.vue
@@ -475,4 +475,56 @@ onUnmounted(() => {
 		}
 	}
 }
+
+@container (max-width: 500px) {
+	.ftskorzw {
+		> .main {
+			> .profile > .main {
+				> .banner-container {
+					height: 140px;
+
+					> .fade {
+						display: none;
+					}
+
+					> .title {
+						display: none;
+					}
+				}
+
+				> .title {
+					display: block;
+				}
+
+				> .avatar {
+					top: 90px;
+					left: 0;
+					right: 0;
+					width: 92px;
+					height: 92px;
+					margin: auto;
+				}
+
+				> .description {
+					padding: 16px;
+					text-align: center;
+				}
+
+				> .fields {
+					padding: 16px;
+				}
+
+				> .status {
+					padding: 16px;
+				}
+			}
+
+			> .contents {
+				> .nav {
+					font-size: 80%;
+				}
+			}
+		}
+	}
+}
 </style>