From 4f04421cb3091fa6302ada179e02aadad0533607 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sun, 24 Oct 2021 04:03:07 +0900
Subject: [PATCH] refactor clinet

---
 src/client/components/global/header.vue       |   9 +-
 .../components/global/sticky-container.vue    |  74 ++++
 src/client/components/index.ts                |   2 +
 src/client/components/modal-page-window.vue   |   9 +-
 src/client/components/page-window.vue         |   5 +-
 src/client/pages/admin/ads.vue                |  82 ++---
 src/client/pages/admin/announcements.vue      |  45 +--
 src/client/pages/admin/emojis.vue             |   9 +-
 src/client/pages/admin/index.vue              |  16 +-
 src/client/pages/admin/overview.vue           | 124 ++++---
 src/client/pages/admin/users.vue              |   9 +-
 src/client/pages/announcements.vue            |  34 +-
 src/client/pages/emojis.vue                   |  12 +-
 src/client/pages/explore.vue                  |  11 +-
 src/client/pages/favorites.vue                |  14 +-
 src/client/pages/featured.vue                 |  12 +-
 src/client/pages/federation.vue               | 186 +++++-----
 src/client/pages/mentions.vue                 |  12 +-
 src/client/pages/messages.vue                 |  10 +-
 src/client/pages/messaging/index.vue          |  77 ++---
 src/client/pages/my-lists/index.vue           |  26 +-
 src/client/pages/my-lists/list.vue            |  55 ++-
 src/client/pages/notifications.vue            |  24 +-
 src/client/pages/page-editor/page-editor.vue  | 134 ++++----
 src/client/pages/page.vue                     | 110 +++---
 src/client/pages/pages.vue                    |  63 ++--
 src/client/pages/search.vue                   |  13 +-
 src/client/pages/settings/index.vue           |   1 +
 src/client/pages/timeline.vue                 |  36 +-
 src/client/pages/user/index.vue               | 323 +++++++++---------
 src/client/ui/deck/main-column.vue            |  17 +-
 src/client/ui/default.vue                     |  17 +-
 src/client/ui/universal.vue                   |  17 +-
 33 files changed, 745 insertions(+), 843 deletions(-)
 create mode 100644 src/client/components/global/sticky-container.vue

diff --git a/src/client/components/global/header.vue b/src/client/components/global/header.vue
index 2bf490c98a..526db07fd3 100644
--- a/src/client/components/global/header.vue
+++ b/src/client/components/global/header.vue
@@ -2,8 +2,8 @@
 <div class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick" ref="el">
 	<template v-if="info">
 		<div class="titleContainer" @click="showTabsPopup" v-if="!hideTitle">
-			<i v-if="info.icon" class="icon" :class="info.icon"></i>
-			<MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
+			<MkAvatar v-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
+			<i v-else-if="info.icon" class="icon" :class="info.icon"></i>
 
 			<div class="title">
 				<MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="title"/>
@@ -162,11 +162,6 @@ export default defineComponent({
 				onUnmounted(() => {
 					ro.disconnect();
 				});
-				setTimeout(() => {
-					const currentStickyTop = getComputedStyle(el.value.parentElement).getPropertyValue('--stickyTop') || '0px';
-					el.value.style.setProperty('--stickyTop', currentStickyTop);
-					el.value.parentElement.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${el.value.offsetHeight}px)`);
-				}, 100); // レンダリング順序の関係で親のstickyTopの設定が少し遅れることがあるため
 			}
 		});
 
diff --git a/src/client/components/global/sticky-container.vue b/src/client/components/global/sticky-container.vue
new file mode 100644
index 0000000000..859b2c1d73
--- /dev/null
+++ b/src/client/components/global/sticky-container.vue
@@ -0,0 +1,74 @@
+<template>
+<div ref="rootEl">
+	<slot name="header"></slot>
+	<div ref="bodyEl">
+		<slot></slot>
+	</div>
+</div>
+</template>
+
+<script lang="ts">
+import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
+
+export default defineComponent({
+	props: {
+		autoSticky: {
+			type: Boolean,
+			required: false,
+			default: false,
+		},
+	},
+
+	setup(props, context) {
+		const rootEl = ref<HTMLElement>(null);
+		const bodyEl = ref<HTMLElement>(null);
+
+		const calc = () => {
+			const currentStickyTop = getComputedStyle(rootEl.value).getPropertyValue('--stickyTop') || '0px';
+
+			const header = rootEl.value.children[0];
+			if (header === bodyEl.value) {
+				bodyEl.value.style.setProperty('--stickyTop', currentStickyTop);
+			} else {
+				bodyEl.value.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${header.offsetHeight}px)`);
+
+				if (props.autoSticky) {
+					header.style.setProperty('--stickyTop', currentStickyTop);
+					header.style.position = 'sticky';
+					header.style.top = 'var(--stickyTop)';
+					header.style.zIndex = '1';
+				}
+			}
+		};
+
+		onMounted(() => {
+			calc();
+
+			const observer = new MutationObserver(() => {
+				setTimeout(() => {
+					calc();
+				}, 100);
+			});
+
+			observer.observe(rootEl.value, {
+				attributes: false,
+				childList: true,
+				subtree: false,
+			});
+
+			onUnmounted(() => {
+				observer.disconnect();
+			});
+		});
+
+		return {
+			rootEl,
+			bodyEl,
+		};
+	},
+});
+</script>
+
+<style lang="scss" module>
+
+</style>
diff --git a/src/client/components/index.ts b/src/client/components/index.ts
index ecf66ea0e8..2340b228f8 100644
--- a/src/client/components/index.ts
+++ b/src/client/components/index.ts
@@ -15,6 +15,7 @@ import error from './global/error.vue';
 import ad from './global/ad.vue';
 import header from './global/header.vue';
 import spacer from './global/spacer.vue';
+import stickyContainer from './global/sticky-container.vue';
 
 export default function(app: App) {
 	app.component('I18n', i18n);
@@ -32,4 +33,5 @@ export default function(app: App) {
 	app.component('MkAd', ad);
 	app.component('MkHeader', header);
 	app.component('MkSpacer', spacer);
+	app.component('MkStickyContainer', stickyContainer);
 }
diff --git a/src/client/components/modal-page-window.vue b/src/client/components/modal-page-window.vue
index 621119294e..e47d3dc62c 100644
--- a/src/client/components/modal-page-window.vue
+++ b/src/client/components/modal-page-window.vue
@@ -11,9 +11,12 @@
 			<button class="_button" @click="$refs.modal.close()"><i class="fas fa-times"></i></button>
 		</div>
 		<div class="body">
-			<keep-alive>
-				<component :is="component" v-bind="props" :ref="changePage"/>
-			</keep-alive>
+			<MkStickyContainer>
+				<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
+				<keep-alive>
+					<component :is="component" v-bind="props" :ref="changePage"/>
+				</keep-alive>
+			</MkStickyContainer>
 		</div>
 	</div>
 </MkModal>
diff --git a/src/client/components/page-window.vue b/src/client/components/page-window.vue
index 2b77a214c5..bc7c5b7a19 100644
--- a/src/client/components/page-window.vue
+++ b/src/client/components/page-window.vue
@@ -17,7 +17,10 @@
 		<button v-if="history.length > 0" class="_button" @click="back()" v-tooltip="$ts.goBack"><i class="fas fa-arrow-left"></i></button>
 	</template>
 	<div class="yrolvcoq">
-		<component :is="component" v-bind="props" :ref="changePage"/>
+		<MkStickyContainer>
+			<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
+			<component :is="component" v-bind="props" :ref="changePage"/>
+		</MkStickyContainer>
 	</div>
 </XWindow>
 </template>
diff --git a/src/client/pages/admin/ads.vue b/src/client/pages/admin/ads.vue
index e776f99a4c..4d39bb4e40 100644
--- a/src/client/pages/admin/ads.vue
+++ b/src/client/pages/admin/ads.vue
@@ -1,45 +1,42 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="uqshojas">
-		<section class="_card _gap ads" v-for="ad in ads">
-			<div class="_content ad">
-				<MkAd v-if="ad.url" :specify="ad"/>
-				<MkInput v-model="ad.url" type="url">
-					<template #label>URL</template>
-				</MkInput>
-				<MkInput v-model="ad.imageUrl">
-					<template #label>{{ $ts.imageUrl }}</template>
-				</MkInput>
-				<div style="margin: 32px 0;">
-					<MkRadio v-model="ad.place" value="square">square</MkRadio>
-					<MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio>
-					<MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio>
-				</div>
-				<!--
-				<div style="margin: 32px 0;">
-					{{ $ts.priority }}
-					<MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio>
-					<MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio>
-					<MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio>
-				</div>
-				-->
-				<MkInput v-model="ad.ratio" type="number">
-					<template #label>{{ $ts.ratio }}</template>
-				</MkInput>
-				<MkInput v-model="ad.expiresAt" type="date">
-					<template #label>{{ $ts.expiration }}</template>
-				</MkInput>
-				<MkTextarea v-model="ad.memo">
-					<template #label>{{ $ts.memo }}</template>
-				</MkTextarea>
-				<div class="buttons">
-					<MkButton class="button" inline @click="save(ad)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
-					<MkButton class="button" inline @click="remove(ad)" danger><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
-				</div>
+<div class="uqshojas">
+	<section class="_card _gap ads" v-for="ad in ads">
+		<div class="_content ad">
+			<MkAd v-if="ad.url" :specify="ad"/>
+			<MkInput v-model="ad.url" type="url">
+				<template #label>URL</template>
+			</MkInput>
+			<MkInput v-model="ad.imageUrl">
+				<template #label>{{ $ts.imageUrl }}</template>
+			</MkInput>
+			<div style="margin: 32px 0;">
+				<MkRadio v-model="ad.place" value="square">square</MkRadio>
+				<MkRadio v-model="ad.place" value="horizontal">horizontal</MkRadio>
+				<MkRadio v-model="ad.place" value="horizontal-big">horizontal-big</MkRadio>
 			</div>
-		</section>
-	</div>
+			<!--
+			<div style="margin: 32px 0;">
+				{{ $ts.priority }}
+				<MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio>
+				<MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio>
+				<MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio>
+			</div>
+			-->
+			<MkInput v-model="ad.ratio" type="number">
+				<template #label>{{ $ts.ratio }}</template>
+			</MkInput>
+			<MkInput v-model="ad.expiresAt" type="date">
+				<template #label>{{ $ts.expiration }}</template>
+			</MkInput>
+			<MkTextarea v-model="ad.memo">
+				<template #label>{{ $ts.memo }}</template>
+			</MkTextarea>
+			<div class="buttons">
+				<MkButton class="button" inline @click="save(ad)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
+				<MkButton class="button" inline @click="remove(ad)" danger><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
+			</div>
+		</div>
+	</section>
 </div>
 </template>
 
@@ -68,11 +65,6 @@ export default defineComponent({
 				title: this.$ts.ads,
 				icon: 'fas fa-audio-description',
 				bg: 'var(--bg)',
-			},
-			header: {
-				title: this.$ts.ads,
-				icon: 'fas fa-audio-description',
-				bg: 'var(--bg)',
 				actions: [{
 					asFullButton: true,
 					icon: 'fas fa-plus',
diff --git a/src/client/pages/admin/announcements.vue b/src/client/pages/admin/announcements.vue
index 78637c095a..4ace515b0b 100644
--- a/src/client/pages/admin/announcements.vue
+++ b/src/client/pages/admin/announcements.vue
@@ -1,27 +1,23 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-
-	<div class="ztgjmzrw">
-		<section class="_card _gap announcements" v-for="announcement in announcements">
-			<div class="_content announcement">
-				<MkInput v-model="announcement.title">
-					<template #label>{{ $ts.title }}</template>
-				</MkInput>
-				<MkTextarea v-model="announcement.text">
-					<template #label>{{ $ts.text }}</template>
-				</MkTextarea>
-				<MkInput v-model="announcement.imageUrl">
-					<template #label>{{ $ts.imageUrl }}</template>
-				</MkInput>
-				<p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p>
-				<div class="buttons">
-					<MkButton class="button" inline @click="save(announcement)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
-					<MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
-				</div>
+<div class="ztgjmzrw">
+	<section class="_card _gap announcements" v-for="announcement in announcements">
+		<div class="_content announcement">
+			<MkInput v-model="announcement.title">
+				<template #label>{{ $ts.title }}</template>
+			</MkInput>
+			<MkTextarea v-model="announcement.text">
+				<template #label>{{ $ts.text }}</template>
+			</MkTextarea>
+			<MkInput v-model="announcement.imageUrl">
+				<template #label>{{ $ts.imageUrl }}</template>
+			</MkInput>
+			<p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p>
+			<div class="buttons">
+				<MkButton class="button" inline @click="save(announcement)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
+				<MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
 			</div>
-		</section>
-	</div>
+		</div>
+	</section>
 </div>
 </template>
 
@@ -48,11 +44,6 @@ export default defineComponent({
 				title: this.$ts.announcements,
 				icon: 'fas fa-broadcast-tower',
 				bg: 'var(--bg)',
-			},
-			header: {
-				title: this.$ts.announcements,
-				icon: 'fas fa-broadcast-tower',
-				bg: 'var(--bg)',
 				actions: [{
 					asFullButton: true,
 					icon: 'fas fa-plus',
diff --git a/src/client/pages/admin/emojis.vue b/src/client/pages/admin/emojis.vue
index 4cd34b046d..80e0e00ba9 100644
--- a/src/client/pages/admin/emojis.vue
+++ b/src/client/pages/admin/emojis.vue
@@ -1,7 +1,5 @@
 <template>
 <div class="ogwlenmc">
-	<MkHeader :info="header"/>
-
 	<div class="local" v-if="tab === 'local'">
 		<MkInput v-model="query" :debounce="true" type="search" style="margin: var(--margin);">
 			<template #prefix><i class="fas fa-search"></i></template>
@@ -71,12 +69,7 @@ export default defineComponent({
 
 	data() {
 		return {
-			[symbols.PAGE_INFO]: {
-				title: this.$ts.customEmojis,
-				icon: 'fas fa-laugh',
-				bg: 'var(--bg)',
-			},
-			header: computed(() => ({
+			[symbols.PAGE_INFO]: computed(() => ({
 				title: this.$ts.customEmojis,
 				icon: 'fas fa-laugh',
 				bg: 'var(--bg)',
diff --git a/src/client/pages/admin/index.vue b/src/client/pages/admin/index.vue
index f18c634959..07d407764b 100644
--- a/src/client/pages/admin/index.vue
+++ b/src/client/pages/admin/index.vue
@@ -13,7 +13,10 @@
 		<MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu>
 	</div>
 	<div class="main">
-		<component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/>
+		<MkStickyContainer>
+			<template #header><MkHeader v-if="childInfo && !childInfo.hideHeader" :info="childInfo"/></template>
+			<component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/>
+		</MkStickyContainer>
 	</div>
 </div>
 </template>
@@ -41,6 +44,10 @@ export default defineComponent({
 		MkInfo,
 	},
 
+	provide: {
+		shouldOmitHeaderTitle: false,
+	},
+
 	props: {
 		initialPage: {
 			type: String,
@@ -50,17 +57,19 @@ export default defineComponent({
 
 	setup(props, context) {
 		const indexInfo = {
-			title: i18n.locale.instance,
+			title: i18n.locale.controlPanel,
 			icon: 'fas fa-cog',
 			bg: 'var(--bg)',
+			hideHeader: true,
 		};
 		const INFO = ref(indexInfo);
+		const childInfo = ref(null);
 		const page = ref(props.initialPage);
 		const narrow = ref(false);
 		const view = ref(null);
 		const el = ref(null);
 		const onInfo = (viewInfo) => {
-			INFO.value = viewInfo;
+			childInfo.value = viewInfo;
 		};
 		const pageProps = ref({});
 
@@ -315,6 +324,7 @@ export default defineComponent({
 			view,
 			el,
 			onInfo,
+			childInfo,
 			pageProps,
 			component,
 			invite,
diff --git a/src/client/pages/admin/overview.vue b/src/client/pages/admin/overview.vue
index 4e761f0217..ced200351e 100644
--- a/src/client/pages/admin/overview.vue
+++ b/src/client/pages/admin/overview.vue
@@ -1,71 +1,67 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-
-	<div class="edbbcaef" v-size="{ max: [740] }">
-		<div v-if="stats" class="cfcdecdf" style="margin: var(--margin)">
-			<div class="number _panel">
-				<div class="label">Users</div>
-				<div class="value _monospace">
-					{{ number(stats.originalUsersCount) }}
-					<MkNumberDiff v-if="usersComparedToThePrevDay != null" class="diff" :value="usersComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff>
-				</div>
-			</div>
-			<div class="number _panel">
-				<div class="label">Notes</div>
-				<div class="value _monospace">
-					{{ number(stats.originalNotesCount) }}
-					<MkNumberDiff v-if="notesComparedToThePrevDay != null" class="diff" :value="notesComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff>
-				</div>
+<div class="edbbcaef" v-size="{ max: [740] }">
+	<div v-if="stats" class="cfcdecdf" style="margin: var(--margin)">
+		<div class="number _panel">
+			<div class="label">Users</div>
+			<div class="value _monospace">
+				{{ number(stats.originalUsersCount) }}
+				<MkNumberDiff v-if="usersComparedToThePrevDay != null" class="diff" :value="usersComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff>
 			</div>
 		</div>
-
-		<MkContainer :foldable="true" class="charts">
-			<template #header><i class="fas fa-chart-bar"></i>{{ $ts.charts }}</template>
-			<div style="padding-top: 12px;">
-				<MkInstanceStats :chart-limit="500" :detailed="true"/>
+		<div class="number _panel">
+			<div class="label">Notes</div>
+			<div class="value _monospace">
+				{{ number(stats.originalNotesCount) }}
+				<MkNumberDiff v-if="notesComparedToThePrevDay != null" class="diff" :value="notesComparedToThePrevDay" v-tooltip="$ts.dayOverDayChanges"><template #before>(</template><template #after>)</template></MkNumberDiff>
 			</div>
-		</MkContainer>
-
-		<div class="queue">
-			<MkContainer :foldable="true" :thin="true" class="deliver">
-				<template #header>Queue: deliver</template>
-				<MkQueueChart :connection="queueStatsConnection" domain="deliver"/>
-			</MkContainer>
-			<MkContainer :foldable="true" :thin="true" class="inbox">
-				<template #header>Queue: inbox</template>
-				<MkQueueChart :connection="queueStatsConnection" domain="inbox"/>
-			</MkContainer>
 		</div>
-
-			<!--<XMetrics/>-->
-
-		<MkFolder style="margin: var(--margin)">
-			<template #header><i class="fas fa-info-circle"></i> {{ $ts.info }}</template>
-			<div class="cfcdecdf">
-				<div class="number _panel">
-					<div class="label">Misskey</div>
-					<div class="value _monospace">{{ version }}</div>
-				</div>
-				<div class="number _panel" v-if="serverInfo">
-					<div class="label">Node.js</div>
-					<div class="value _monospace">{{ serverInfo.node }}</div>
-				</div>
-				<div class="number _panel" v-if="serverInfo">
-					<div class="label">PostgreSQL</div>
-					<div class="value _monospace">{{ serverInfo.psql }}</div>
-				</div>
-				<div class="number _panel" v-if="serverInfo">
-					<div class="label">Redis</div>
-					<div class="value _monospace">{{ serverInfo.redis }}</div>
-				</div>
-				<div class="number _panel">
-					<div class="label">Vue</div>
-					<div class="value _monospace">{{ vueVersion }}</div>
-				</div>
-			</div>
-		</MkFolder>
 	</div>
+
+	<MkContainer :foldable="true" class="charts">
+		<template #header><i class="fas fa-chart-bar"></i>{{ $ts.charts }}</template>
+		<div style="padding-top: 12px;">
+			<MkInstanceStats :chart-limit="500" :detailed="true"/>
+		</div>
+	</MkContainer>
+
+	<div class="queue">
+		<MkContainer :foldable="true" :thin="true" class="deliver">
+			<template #header>Queue: deliver</template>
+			<MkQueueChart :connection="queueStatsConnection" domain="deliver"/>
+		</MkContainer>
+		<MkContainer :foldable="true" :thin="true" class="inbox">
+			<template #header>Queue: inbox</template>
+			<MkQueueChart :connection="queueStatsConnection" domain="inbox"/>
+		</MkContainer>
+	</div>
+
+		<!--<XMetrics/>-->
+
+	<MkFolder style="margin: var(--margin)">
+		<template #header><i class="fas fa-info-circle"></i> {{ $ts.info }}</template>
+		<div class="cfcdecdf">
+			<div class="number _panel">
+				<div class="label">Misskey</div>
+				<div class="value _monospace">{{ version }}</div>
+			</div>
+			<div class="number _panel" v-if="serverInfo">
+				<div class="label">Node.js</div>
+				<div class="value _monospace">{{ serverInfo.node }}</div>
+			</div>
+			<div class="number _panel" v-if="serverInfo">
+				<div class="label">PostgreSQL</div>
+				<div class="value _monospace">{{ serverInfo.psql }}</div>
+			</div>
+			<div class="number _panel" v-if="serverInfo">
+				<div class="label">Redis</div>
+				<div class="value _monospace">{{ serverInfo.redis }}</div>
+			</div>
+			<div class="number _panel">
+				<div class="label">Vue</div>
+				<div class="value _monospace">{{ vueVersion }}</div>
+			</div>
+		</div>
+	</MkFolder>
 </div>
 </template>
 
@@ -107,10 +103,6 @@ export default defineComponent({
 				icon: 'fas fa-tachometer-alt',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.dashboard,
-				icon: 'fas fa-tachometer-alt',
-			},
 			version,
 			vueVersion,
 			url,
diff --git a/src/client/pages/admin/users.vue b/src/client/pages/admin/users.vue
index f7f9306b70..37a54d2de3 100644
--- a/src/client/pages/admin/users.vue
+++ b/src/client/pages/admin/users.vue
@@ -1,7 +1,5 @@
 <template>
 <div class="lknzcolw">
-	<MkHeader :info="header"/>
-
 	<div class="users">
 		<div class="inputs">
 			<MkSelect v-model="sort" style="flex: 1;">
@@ -90,11 +88,6 @@ export default defineComponent({
 				title: this.$ts.users,
 				icon: 'fas fa-users',
 				bg: 'var(--bg)',
-			},
-			header: {
-				title: this.$ts.users,
-				icon: 'fas fa-users',
-				bg: 'var(--bg)',
 				actions: [{
 					icon: 'fas fa-search',
 					text: this.$ts.search,
@@ -109,7 +102,7 @@ export default defineComponent({
 					icon: 'fas fa-search',
 					text: this.$ts.lookup,
 					handler: this.lookupUser
-				}]
+				}],
 			},
 			sort: '+createdAt',
 			state: 'all',
diff --git a/src/client/pages/announcements.vue b/src/client/pages/announcements.vue
index 6a0cbd67ba..327fa9b1f6 100644
--- a/src/client/pages/announcements.vue
+++ b/src/client/pages/announcements.vue
@@ -1,20 +1,17 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="_section">
-		<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content">
-			<section class="_card announcement _gap" v-for="(announcement, i) in items" :key="announcement.id">
-				<div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
-				<div class="_content">
-					<Mfm :text="announcement.text"/>
-					<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
-				</div>
-				<div class="_footer" v-if="$i && !announcement.isRead">
-					<MkButton @click="read(items, announcement, i)" primary><i class="fas fa-check"></i> {{ $ts.gotIt }}</MkButton>
-				</div>
-			</section>
-		</MkPagination>
-	</div>
+<div class="_section">
+	<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content">
+		<section class="_card announcement _gap" v-for="(announcement, i) in items" :key="announcement.id">
+			<div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
+			<div class="_content">
+				<Mfm :text="announcement.text"/>
+				<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
+			</div>
+			<div class="_footer" v-if="$i && !announcement.isRead">
+				<MkButton @click="read(items, announcement, i)" primary><i class="fas fa-check"></i> {{ $ts.gotIt }}</MkButton>
+			</div>
+		</section>
+	</MkPagination>
 </div>
 </template>
 
@@ -38,11 +35,6 @@ export default defineComponent({
 				icon: 'fas fa-broadcast-tower',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.announcements,
-				icon: 'fas fa-broadcast-tower',
-				bg: 'var(--bg)',
-			},
 			pagination: {
 				endpoint: 'announcements',
 				limit: 10,
diff --git a/src/client/pages/emojis.vue b/src/client/pages/emojis.vue
index d61fd25d3c..8918de2338 100644
--- a/src/client/pages/emojis.vue
+++ b/src/client/pages/emojis.vue
@@ -1,9 +1,6 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div :class="$style.root">
-		<XCategory v-if="tab === 'category'"/>
-	</div>
+<div :class="$style.root">
+	<XCategory v-if="tab === 'category'"/>
 </div>
 </template>
 
@@ -25,11 +22,6 @@ export default defineComponent({
 				icon: 'fas fa-laugh',
 				bg: 'var(--bg)',
 			})),
-			header: computed(() => ({
-				title: this.$ts.customEmojis,
-				icon: 'fas fa-laugh',
-				bg: 'var(--bg)',
-			})),
 			tab: 'category',
 		}
 	},
diff --git a/src/client/pages/explore.vue b/src/client/pages/explore.vue
index 6f304877b7..a77b4e53c3 100644
--- a/src/client/pages/explore.vue
+++ b/src/client/pages/explore.vue
@@ -1,7 +1,5 @@
 <template>
 <div>
-	<MkHeader :info="header"/>
-
 	<MkSpacer :content-max="1200">
 		<div class="lznhrdub">
 			<div v-if="tab === 'local'">
@@ -110,13 +108,7 @@ export default defineComponent({
 
 	data() {
 		return {
-			[symbols.PAGE_INFO]: {
-				title: this.$ts.explore,
-				icon: 'fas fa-hashtag',
-				bg: 'var(--bg)',
-			},
-			tab: 'local',
-			header: computed(() => ({
+			[symbols.PAGE_INFO]: computed(() => ({
 				title: this.$ts.explore,
 				icon: 'fas fa-hashtag',
 				bg: 'var(--bg)',
@@ -134,6 +126,7 @@ export default defineComponent({
 					onClick: () => { this.tab = 'search'; },
 				},]
 			})),
+			tab: 'local',
 			pinnedUsers: { endpoint: 'pinned-users' },
 			popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: {
 				state: 'alive',
diff --git a/src/client/pages/favorites.vue b/src/client/pages/favorites.vue
index bed78d1dbe..f13723c2d1 100644
--- a/src/client/pages/favorites.vue
+++ b/src/client/pages/favorites.vue
@@ -1,10 +1,7 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="jmelgwjh">
-		<div class="body">
-			<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
-		</div>
+<div class="jmelgwjh">
+	<div class="body">
+		<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
 	</div>
 </div>
 </template>
@@ -28,11 +25,6 @@ export default defineComponent({
 				icon: 'fas fa-star',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.favorites,
-				icon: 'fas fa-star',
-				bg: 'var(--bg)',
-			},
 			pagination: {
 				endpoint: 'i/favorites',
 				limit: 10,
diff --git a/src/client/pages/featured.vue b/src/client/pages/featured.vue
index 5d8da54541..afe3d62638 100644
--- a/src/client/pages/featured.vue
+++ b/src/client/pages/featured.vue
@@ -1,9 +1,6 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="_section">
-		<XNotes class="_content" ref="notes" :pagination="pagination" @before="before" @after="after"/>
-	</div>
+<div class="_section">
+	<XNotes class="_content" ref="notes" :pagination="pagination" @before="before" @after="after"/>
 </div>
 </template>
 
@@ -25,11 +22,6 @@ export default defineComponent({
 				icon: 'fas fa-fire-alt',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.featured,
-				icon: 'fas fa-fire-alt',
-				bg: 'var(--bg)',
-			},
 			pagination: {
 				endpoint: 'notes/featured',
 				limit: 10,
diff --git a/src/client/pages/federation.vue b/src/client/pages/federation.vue
index ae0aed4cc7..eae6a05367 100644
--- a/src/client/pages/federation.vue
+++ b/src/client/pages/federation.vue
@@ -1,98 +1,95 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="taeiyria">
-		<div class="query">
-			<MkInput v-model="host" :debounce="true" class="">
-				<template #prefix><i class="fas fa-search"></i></template>
-				<template #label>{{ $ts.host }}</template>
-			</MkInput>
-			<div class="_inputSplit">
-				<MkSelect v-model="state">
-					<template #label>{{ $ts.state }}</template>
-					<option value="all">{{ $ts.all }}</option>
-					<option value="federating">{{ $ts.federating }}</option>
-					<option value="subscribing">{{ $ts.subscribing }}</option>
-					<option value="publishing">{{ $ts.publishing }}</option>
-					<option value="suspended">{{ $ts.suspended }}</option>
-					<option value="blocked">{{ $ts.blocked }}</option>
-					<option value="notResponding">{{ $ts.notResponding }}</option>
-				</MkSelect>
-				<MkSelect v-model="sort">
-					<template #label>{{ $ts.sort }}</template>
-					<option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option>
-					<option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+notes">{{ $ts.notes }} ({{ $ts.descendingOrder }})</option>
-					<option value="-notes">{{ $ts.notes }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+users">{{ $ts.users }} ({{ $ts.descendingOrder }})</option>
-					<option value="-users">{{ $ts.users }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+following">{{ $ts.following }} ({{ $ts.descendingOrder }})</option>
-					<option value="-following">{{ $ts.following }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+followers">{{ $ts.followers }} ({{ $ts.descendingOrder }})</option>
-					<option value="-followers">{{ $ts.followers }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+caughtAt">{{ $ts.registeredAt }} ({{ $ts.descendingOrder }})</option>
-					<option value="-caughtAt">{{ $ts.registeredAt }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.descendingOrder }})</option>
-					<option value="-lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+driveUsage">{{ $ts.driveUsage }} ({{ $ts.descendingOrder }})</option>
-					<option value="-driveUsage">{{ $ts.driveUsage }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.descendingOrder }})</option>
-					<option value="-driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.ascendingOrder }})</option>
-				</MkSelect>
-			</div>
+<div class="taeiyria">
+	<div class="query">
+		<MkInput v-model="host" :debounce="true" class="">
+			<template #prefix><i class="fas fa-search"></i></template>
+			<template #label>{{ $ts.host }}</template>
+		</MkInput>
+		<div class="_inputSplit">
+			<MkSelect v-model="state">
+				<template #label>{{ $ts.state }}</template>
+				<option value="all">{{ $ts.all }}</option>
+				<option value="federating">{{ $ts.federating }}</option>
+				<option value="subscribing">{{ $ts.subscribing }}</option>
+				<option value="publishing">{{ $ts.publishing }}</option>
+				<option value="suspended">{{ $ts.suspended }}</option>
+				<option value="blocked">{{ $ts.blocked }}</option>
+				<option value="notResponding">{{ $ts.notResponding }}</option>
+			</MkSelect>
+			<MkSelect v-model="sort">
+				<template #label>{{ $ts.sort }}</template>
+				<option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option>
+				<option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+notes">{{ $ts.notes }} ({{ $ts.descendingOrder }})</option>
+				<option value="-notes">{{ $ts.notes }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+users">{{ $ts.users }} ({{ $ts.descendingOrder }})</option>
+				<option value="-users">{{ $ts.users }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+following">{{ $ts.following }} ({{ $ts.descendingOrder }})</option>
+				<option value="-following">{{ $ts.following }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+followers">{{ $ts.followers }} ({{ $ts.descendingOrder }})</option>
+				<option value="-followers">{{ $ts.followers }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+caughtAt">{{ $ts.registeredAt }} ({{ $ts.descendingOrder }})</option>
+				<option value="-caughtAt">{{ $ts.registeredAt }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.descendingOrder }})</option>
+				<option value="-lastCommunicatedAt">{{ $ts.lastCommunication }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+driveUsage">{{ $ts.driveUsage }} ({{ $ts.descendingOrder }})</option>
+				<option value="-driveUsage">{{ $ts.driveUsage }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.descendingOrder }})</option>
+				<option value="-driveFiles">{{ $ts.driveFilesCount }} ({{ $ts.ascendingOrder }})</option>
+			</MkSelect>
 		</div>
-
-		<MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state">
-			<div class="dqokceoi">
-				<MkA class="instance" v-for="instance in items" :key="instance.id" :to="`/instance-info/${instance.host}`">
-					<div class="host"><img :src="instance.faviconUrl">{{ instance.host }}</div>
-					<div class="table">
-						<div class="cell">
-							<div class="key">{{ $ts.registeredAt }}</div>
-							<div class="value"><MkTime :time="instance.caughtAt"/></div>
-						</div>
-						<div class="cell">
-							<div class="key">{{ $ts.software }}</div>
-							<div class="value">{{ instance.softwareName || `(${$ts.unknown})` }}</div>
-						</div>
-						<div class="cell">
-							<div class="key">{{ $ts.version }}</div>
-							<div class="value">{{ instance.softwareVersion || `(${$ts.unknown})` }}</div>
-						</div>
-						<div class="cell">
-							<div class="key">{{ $ts.users }}</div>
-							<div class="value">{{ instance.usersCount }}</div>
-						</div>
-						<div class="cell">
-							<div class="key">{{ $ts.notes }}</div>
-							<div class="value">{{ instance.notesCount }}</div>
-						</div>
-						<div class="cell">
-							<div class="key">{{ $ts.sent }}</div>
-							<div class="value"><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></div>
-						</div>
-						<div class="cell">
-							<div class="key">{{ $ts.received }}</div>
-							<div class="value"><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></div>
-						</div>
-					</div>
-					<div class="footer">
-						<span class="status" :class="getStatus(instance)">{{ getStatus(instance) }}</span>
-						<span class="pubSub">
-							<span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span>
-							<span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span>
-							<span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span>
-							<span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span>
-						</span>
-						<span class="right">
-							<span class="latestStatus">{{ instance.latestStatus || '-' }}</span>
-							<span class="lastCommunicatedAt"><MkTime :time="instance.lastCommunicatedAt"/></span>
-						</span>
-					</div>
-				</MkA>
-			</div>
-		</MkPagination>
 	</div>
+
+	<MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state">
+		<div class="dqokceoi">
+			<MkA class="instance" v-for="instance in items" :key="instance.id" :to="`/instance-info/${instance.host}`">
+				<div class="host"><img :src="instance.faviconUrl">{{ instance.host }}</div>
+				<div class="table">
+					<div class="cell">
+						<div class="key">{{ $ts.registeredAt }}</div>
+						<div class="value"><MkTime :time="instance.caughtAt"/></div>
+					</div>
+					<div class="cell">
+						<div class="key">{{ $ts.software }}</div>
+						<div class="value">{{ instance.softwareName || `(${$ts.unknown})` }}</div>
+					</div>
+					<div class="cell">
+						<div class="key">{{ $ts.version }}</div>
+						<div class="value">{{ instance.softwareVersion || `(${$ts.unknown})` }}</div>
+					</div>
+					<div class="cell">
+						<div class="key">{{ $ts.users }}</div>
+						<div class="value">{{ instance.usersCount }}</div>
+					</div>
+					<div class="cell">
+						<div class="key">{{ $ts.notes }}</div>
+						<div class="value">{{ instance.notesCount }}</div>
+					</div>
+					<div class="cell">
+						<div class="key">{{ $ts.sent }}</div>
+						<div class="value"><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></div>
+					</div>
+					<div class="cell">
+						<div class="key">{{ $ts.received }}</div>
+						<div class="value"><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></div>
+					</div>
+				</div>
+				<div class="footer">
+					<span class="status" :class="getStatus(instance)">{{ getStatus(instance) }}</span>
+					<span class="pubSub">
+						<span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span>
+						<span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span>
+						<span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span>
+						<span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span>
+					</span>
+					<span class="right">
+						<span class="latestStatus">{{ instance.latestStatus || '-' }}</span>
+						<span class="lastCommunicatedAt"><MkTime :time="instance.lastCommunicatedAt"/></span>
+					</span>
+				</div>
+			</MkA>
+		</div>
+	</MkPagination>
 </div>
 </template>
 
@@ -122,11 +119,6 @@ export default defineComponent({
 				icon: 'fas fa-globe',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.federation,
-				icon: 'fas fa-globe',
-				bg: 'var(--bg)',
-			},
 			host: '',
 			state: 'federating',
 			sort: '+pubSub',
diff --git a/src/client/pages/mentions.vue b/src/client/pages/mentions.vue
index e1d2f096e1..00c6a3d4d0 100644
--- a/src/client/pages/mentions.vue
+++ b/src/client/pages/mentions.vue
@@ -1,9 +1,6 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="_section">
-		<XNotes class="_content" :pagination="pagination" @before="before()" @after="after()"/>
-	</div>
+<div class="_section">
+	<XNotes class="_content" :pagination="pagination" @before="before()" @after="after()"/>
 </div>
 </template>
 
@@ -25,11 +22,6 @@ export default defineComponent({
 				icon: 'fas fa-at',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.mentions,
-				icon: 'fas fa-at',
-				bg: 'var(--bg)',
-			},
 			pagination: {
 				endpoint: 'notes/mentions',
 				limit: 10,
diff --git a/src/client/pages/messages.vue b/src/client/pages/messages.vue
index f4c68daab9..15cd9546be 100644
--- a/src/client/pages/messages.vue
+++ b/src/client/pages/messages.vue
@@ -1,9 +1,6 @@
 <template>
 <div>
-	<MkHeader :info="header"/>
-	<div>
-		<XNotes :pagination="pagination" @before="before()" @after="after()"/>
-	</div>
+	<XNotes :pagination="pagination" @before="before()" @after="after()"/>
 </div>
 </template>
 
@@ -25,11 +22,6 @@ export default defineComponent({
 				icon: 'fas fa-envelope',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.directNotes,
-				icon: 'fas fa-envelope',
-				bg: 'var(--bg)',
-			},
 			pagination: {
 				endpoint: 'notes/mentions',
 				limit: 10,
diff --git a/src/client/pages/messaging/index.vue b/src/client/pages/messaging/index.vue
index b3e0b6edd0..5b4fd51e55 100644
--- a/src/client/pages/messaging/index.vue
+++ b/src/client/pages/messaging/index.vue
@@ -1,45 +1,41 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
+<MkSpacer :content-max="800">
+	<div class="yweeujhr" v-size="{ max: [400] }">
+		<MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton>
 
-	<MkSpacer :content-max="800">
-		<div class="yweeujhr" v-size="{ max: [400] }">
-			<MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton>
-
-			<div class="history" v-if="messages.length > 0">
-				<MkA v-for="(message, i) in messages"
-					class="message _block"
-					:class="{ isMe: isMe(message), isRead: message.groupId ? message.reads.includes($i.id) : message.isRead }"
-					:to="message.groupId ? `/my/messaging/group/${message.groupId}` : `/my/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
-					:data-index="i"
-					:key="message.id"
-					v-anim="i"
-				>
-					<div>
-						<MkAvatar class="avatar" :user="message.groupId ? message.user : isMe(message) ? message.recipient : message.user" :show-indicator="true"/>
-						<header v-if="message.groupId">
-							<span class="name">{{ message.group.name }}</span>
-							<MkTime :time="message.createdAt" class="time"/>
-						</header>
-						<header v-else>
-							<span class="name"><MkUserName :user="isMe(message) ? message.recipient : message.user"/></span>
-							<span class="username">@{{ acct(isMe(message) ? message.recipient : message.user) }}</span>
-							<MkTime :time="message.createdAt" class="time"/>
-						</header>
-						<div class="body">
-							<p class="text"><span class="me" v-if="isMe(message)">{{ $ts.you }}:</span>{{ message.text }}</p>
-						</div>
+		<div class="history" v-if="messages.length > 0">
+			<MkA v-for="(message, i) in messages"
+				class="message _block"
+				:class="{ isMe: isMe(message), isRead: message.groupId ? message.reads.includes($i.id) : message.isRead }"
+				:to="message.groupId ? `/my/messaging/group/${message.groupId}` : `/my/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
+				:data-index="i"
+				:key="message.id"
+				v-anim="i"
+			>
+				<div>
+					<MkAvatar class="avatar" :user="message.groupId ? message.user : isMe(message) ? message.recipient : message.user" :show-indicator="true"/>
+					<header v-if="message.groupId">
+						<span class="name">{{ message.group.name }}</span>
+						<MkTime :time="message.createdAt" class="time"/>
+					</header>
+					<header v-else>
+						<span class="name"><MkUserName :user="isMe(message) ? message.recipient : message.user"/></span>
+						<span class="username">@{{ acct(isMe(message) ? message.recipient : message.user) }}</span>
+						<MkTime :time="message.createdAt" class="time"/>
+					</header>
+					<div class="body">
+						<p class="text"><span class="me" v-if="isMe(message)">{{ $ts.you }}:</span>{{ message.text }}</p>
 					</div>
-				</MkA>
-			</div>
-			<div class="_fullinfo" v-if="!fetching && messages.length == 0">
-				<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
-				<div>{{ $ts.noHistory }}</div>
-			</div>
-			<MkLoading v-if="fetching"/>
+				</div>
+			</MkA>
 		</div>
-	</MkSpacer>
-</div>
+		<div class="_fullinfo" v-if="!fetching && messages.length == 0">
+			<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
+			<div>{{ $ts.noHistory }}</div>
+		</div>
+		<MkLoading v-if="fetching"/>
+	</div>
+</MkSpacer>
 </template>
 
 <script lang="ts">
@@ -62,11 +58,6 @@ export default defineComponent({
 				icon: 'fas fa-comments',
 				bg: 'var(--bg)',
 			},
-			header: {
-				title: this.$ts.messaging,
-				icon: 'fas fa-comments',
-				bg: 'var(--bg)',
-			},
 			fetching: true,
 			moreFetching: false,
 			messages: [],
diff --git a/src/client/pages/my-lists/index.vue b/src/client/pages/my-lists/index.vue
index b0e9bf9d54..687e9e630e 100644
--- a/src/client/pages/my-lists/index.vue
+++ b/src/client/pages/my-lists/index.vue
@@ -1,16 +1,13 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="qkcjvfiv">
-		<MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton>
+<div class="qkcjvfiv">
+	<MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton>
 
-		<MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list">
-			<MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`">
-				<div class="name">{{ list.name }}</div>
-				<MkAvatars :user-ids="list.userIds"/>
-			</MkA>
-		</MkPagination>
-	</div>
+	<MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list">
+		<MkA v-for="list in items" :key="list.id" class="list _panel" :to="`/my/lists/${ list.id }`">
+			<div class="name">{{ list.name }}</div>
+			<MkAvatars :user-ids="list.userIds"/>
+		</MkA>
+	</MkPagination>
 </div>
 </template>
 
@@ -35,15 +32,10 @@ export default defineComponent({
 				title: this.$ts.manageLists,
 				icon: 'fas fa-list-ul',
 				bg: 'var(--bg)',
-			},
-			header: {
-				title: this.$ts.manageLists,
-				icon: 'fas fa-list-ul',
-				bg: 'var(--bg)',
 				action: {
 					icon: 'fas fa-plus',
 					handler: this.create
-				}
+				},
 			},
 			pagination: {
 				endpoint: 'users/lists/list',
diff --git a/src/client/pages/my-lists/list.vue b/src/client/pages/my-lists/list.vue
index 27c979bc88..049d370b4e 100644
--- a/src/client/pages/my-lists/list.vue
+++ b/src/client/pages/my-lists/list.vue
@@ -1,37 +1,34 @@
 <template>
-<div>
-	<MkHeader v-if="header" :info="header"/>
-	<div class="mk-list-page">
-		<transition name="zoom" mode="out-in">
-			<div v-if="list" class="_section">
-				<div class="_content">
-					<MkButton inline @click="addUser()">{{ $ts.addUser }}</MkButton>
-					<MkButton inline @click="renameList()">{{ $ts.rename }}</MkButton>
-					<MkButton inline @click="deleteList()">{{ $ts.delete }}</MkButton>
-				</div>
+<div class="mk-list-page">
+	<transition name="zoom" mode="out-in">
+		<div v-if="list" class="_section">
+			<div class="_content">
+				<MkButton inline @click="addUser()">{{ $ts.addUser }}</MkButton>
+				<MkButton inline @click="renameList()">{{ $ts.rename }}</MkButton>
+				<MkButton inline @click="deleteList()">{{ $ts.delete }}</MkButton>
 			</div>
-		</transition>
+		</div>
+	</transition>
 
-		<transition name="zoom" mode="out-in">
-			<div v-if="list" class="_section members _gap">
-				<div class="_title">{{ $ts.members }}</div>
-				<div class="_content">
-					<div class="users">
-						<div class="user _panel" v-for="user in users" :key="user.id">
-							<MkAvatar :user="user" class="avatar" :show-indicator="true"/>
-							<div class="body">
-								<MkUserName :user="user" class="name"/>
-								<MkAcct :user="user" class="acct"/>
-							</div>
-							<div class="action">
-								<button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button>
-							</div>
+	<transition name="zoom" mode="out-in">
+		<div v-if="list" class="_section members _gap">
+			<div class="_title">{{ $ts.members }}</div>
+			<div class="_content">
+				<div class="users">
+					<div class="user _panel" v-for="user in users" :key="user.id">
+						<MkAvatar :user="user" class="avatar" :show-indicator="true"/>
+						<div class="body">
+							<MkUserName :user="user" class="name"/>
+							<MkAcct :user="user" class="acct"/>
+						</div>
+						<div class="action">
+							<button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button>
 						</div>
 					</div>
 				</div>
 			</div>
-		</transition>
-	</div>
+		</div>
+	</transition>
 </div>
 </template>
 
@@ -53,10 +50,6 @@ export default defineComponent({
 				title: this.list.name,
 				icon: 'fas fa-list-ul',
 			} : null),
-			header: computed(() => this.list ? {
-				title: this.list.name,
-				icon: 'fas fa-list-ul',
-			} : null),
 			list: null,
 			users: [],
 		};
diff --git a/src/client/pages/notifications.vue b/src/client/pages/notifications.vue
index 049d057d02..8d6adec48d 100644
--- a/src/client/pages/notifications.vue
+++ b/src/client/pages/notifications.vue
@@ -1,12 +1,9 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<MkSpacer :content-max="800">
-		<div class="clupoqwt">
-			<XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
-		</div>
-	</MkSpacer>
-</div>
+<MkSpacer :content-max="800">
+	<div class="clupoqwt">
+		<XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
+	</div>
+</MkSpacer>
 </template>
 
 <script lang="ts">
@@ -24,14 +21,7 @@ export default defineComponent({
 
 	data() {
 		return {
-			[symbols.PAGE_INFO]: {
-				title: this.$ts.notifications,
-				icon: 'fas fa-bell',
-				bg: 'var(--bg)',
-			},
-			tab: 'all',
-			includeTypes: null,
-			header: computed(() => ({
+			[symbols.PAGE_INFO]: computed(() => ({
 				title: this.$ts.notifications,
 				icon: 'fas fa-bell',
 				bg: 'var(--bg)',
@@ -57,6 +47,8 @@ export default defineComponent({
 					onClick: () => { this.tab = 'unread'; },
 				},]
 			})),
+			tab: 'all',
+			includeTypes: null,
 		};
 	},
 
diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue
index e04039e634..aefcc14564 100644
--- a/src/client/pages/page-editor/page-editor.vue
+++ b/src/client/pages/page-editor/page-editor.vue
@@ -1,82 +1,78 @@
 <template>
 <div>
-	<MkHeader :info="header"/>
+	<div class="jqqmcavi" style="margin: 16px;">
+		<MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton>
+		<MkButton inline @click="save" primary class="button" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
+		<MkButton inline @click="duplicate" class="button" v-if="pageId"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton>
+		<MkButton inline @click="del" class="button" v-if="pageId && !readonly" danger><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
+	</div>
 
-	<div class="_root">
-		<div class="jqqmcavi" style="margin: 16px;">
-			<MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton>
-			<MkButton inline @click="save" primary class="button" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
-			<MkButton inline @click="duplicate" class="button" v-if="pageId"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton>
-			<MkButton inline @click="del" class="button" v-if="pageId && !readonly" danger><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
-		</div>
+	<div v-if="tab === 'settings'">
+		<div style="padding: 16px;" class="_formRoot">
+			<MkInput v-model="title" class="_formBlock">
+				<template #label>{{ $ts._pages.title }}</template>
+			</MkInput>
 
-		<div v-if="tab === 'settings'">
-			<div style="padding: 16px;" class="_formRoot">
-				<MkInput v-model="title" class="_formBlock">
-					<template #label>{{ $ts._pages.title }}</template>
-				</MkInput>
+			<MkInput v-model="summary" class="_formBlock">
+				<template #label>{{ $ts._pages.summary }}</template>
+			</MkInput>
 
-				<MkInput v-model="summary" class="_formBlock">
-					<template #label>{{ $ts._pages.summary }}</template>
-				</MkInput>
+			<MkInput v-model="name" class="_formBlock">
+				<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
+				<template #label>{{ $ts._pages.url }}</template>
+			</MkInput>
 
-				<MkInput v-model="name" class="_formBlock">
-					<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
-					<template #label>{{ $ts._pages.url }}</template>
-				</MkInput>
+			<MkSwitch v-model="alignCenter" class="_formBlock">{{ $ts._pages.alignCenter }}</MkSwitch>
 
-				<MkSwitch v-model="alignCenter" class="_formBlock">{{ $ts._pages.alignCenter }}</MkSwitch>
+			<MkSelect v-model="font" class="_formBlock">
+				<template #label>{{ $ts._pages.font }}</template>
+				<option value="serif">{{ $ts._pages.fontSerif }}</option>
+				<option value="sans-serif">{{ $ts._pages.fontSansSerif }}</option>
+			</MkSelect>
 
-				<MkSelect v-model="font" class="_formBlock">
-					<template #label>{{ $ts._pages.font }}</template>
-					<option value="serif">{{ $ts._pages.fontSerif }}</option>
-					<option value="sans-serif">{{ $ts._pages.fontSansSerif }}</option>
-				</MkSelect>
+			<MkSwitch v-model="hideTitleWhenPinned" class="_formBlock">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch>
 
-				<MkSwitch v-model="hideTitleWhenPinned" class="_formBlock">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch>
-
-				<div class="eyeCatch">
-					<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton>
-					<div v-else-if="eyeCatchingImage">
-						<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/>
-						<MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton>
-					</div>
+			<div class="eyeCatch">
+				<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton>
+				<div v-else-if="eyeCatchingImage">
+					<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/>
+					<MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton>
 				</div>
 			</div>
 		</div>
+	</div>
 
-		<div v-else-if="tab === 'contents'">
-			<div style="padding: 16px;">
-				<XBlocks class="content" v-model="content" :hpml="hpml"/>
+	<div v-else-if="tab === 'contents'">
+		<div style="padding: 16px;">
+			<XBlocks class="content" v-model="content" :hpml="hpml"/>
 
-				<MkButton @click="add()" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
-			</div>
+			<MkButton @click="add()" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
 		</div>
+	</div>
 
-		<div v-else-if="tab === 'variables'">
-			<div class="qmuvgica">
-				<XDraggable tag="div" class="variables" v-show="variables.length > 0" v-model="variables" item-key="name" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
-					<template #item="{element}">
-						<XVariable
-							:modelValue="element"
-							:removable="true"
-							@remove="() => removeVariable(element)"
-							:hpml="hpml"
-							:name="element.name"
-							:title="element.name"
-							:draggable="true"
-						/>
-					</template>
-				</XDraggable>
+	<div v-else-if="tab === 'variables'">
+		<div class="qmuvgica">
+			<XDraggable tag="div" class="variables" v-show="variables.length > 0" v-model="variables" item-key="name" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
+				<template #item="{element}">
+					<XVariable
+						:modelValue="element"
+						:removable="true"
+						@remove="() => removeVariable(element)"
+						:hpml="hpml"
+						:name="element.name"
+						:title="element.name"
+						:draggable="true"
+					/>
+				</template>
+			</XDraggable>
 
-				<MkButton @click="addVariable()" class="add" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
-			</div>
+			<MkButton @click="addVariable()" class="add" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
 		</div>
+	</div>
 
-		<div v-else-if="tab === 'script'">
-			<div>
-				<MkTextarea class="_code" v-model="script"/>
-			</div>
+	<div v-else-if="tab === 'script'">
+		<div>
+			<MkTextarea class="_code" v-model="script"/>
 		</div>
 	</div>
 </div>
@@ -131,21 +127,6 @@ export default defineComponent({
 	data() {
 		return {
 			[symbols.PAGE_INFO]: computed(() => {
-				let title = this.$ts._pages.newPage;
-				if (this.initPageId) {
-					title = this.$ts._pages.editPage;
-				}
-				else if (this.initPageName && this.initUser) {
-					title = this.$ts._pages.readPage;
-				}
-				return {
-					title: title,
-					icon: 'fas fa-pencil-alt',
-					bg: 'var(--bg)',
-				};
-			}),
-			tab: 'settings',
-			header: computed(() => {
 				let title = this.$ts._pages.newPage;
 				if (this.initPageId) {
 					title = this.$ts._pages.editPage;
@@ -177,9 +158,10 @@ export default defineComponent({
 						title: this.$ts.script,
 						icon: 'fas fa-code',
 						onClick: () => { this.tab = 'script'; },
-					}]
+					}],
 				};
 			}),
+			tab: 'settings',
 			author: this.$i,
 			readonly: false,
 			page: null,
diff --git a/src/client/pages/page.vue b/src/client/pages/page.vue
index b8d7507363..3ea687a35d 100644
--- a/src/client/pages/page.vue
+++ b/src/client/pages/page.vue
@@ -1,65 +1,61 @@
 <template>
 <div>
-	<MkHeader :info="header"/>
-
-	<div class="_root">
-		<transition name="fade" mode="out-in">
-			<div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }">
-				<div class="_block main">
-					<!--
-					<div class="header">
-						<h1>{{ page.title }}</h1>
+	<transition name="fade" mode="out-in">
+		<div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }">
+			<div class="_block main">
+				<!--
+				<div class="header">
+					<h1>{{ page.title }}</h1>
+				</div>
+				-->
+				<div class="banner">
+					<img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/>
+				</div>
+				<div class="content">
+					<XPage :page="page"/>
+				</div>
+				<div class="actions">
+					<div class="like">
+						<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
+						<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
 					</div>
-					-->
-					<div class="banner">
-						<img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/>
-					</div>
-					<div class="content">
-						<XPage :page="page"/>
-					</div>
-					<div class="actions">
-						<div class="like">
-							<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
-							<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
-						</div>
-						<div class="other">
-							<button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button>
-							<button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button>
-						</div>
-					</div>
-					<div class="user">
-						<MkAvatar :user="page.user" class="avatar"/>
-						<div class="name">
-							<MkUserName :user="page.user" style="display: block;"/>
-							<MkAcct :user="page.user"/>
-						</div>
-						<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
-					</div>
-					<div class="links">
-						<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA>
-						<template v-if="$i && $i.id === page.userId">
-							<MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA>
-							<button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button>
-							<button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button>
-						</template>
+					<div class="other">
+						<button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button>
+						<button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button>
 					</div>
 				</div>
-				<div class="footer">
-					<div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
-					<div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
+				<div class="user">
+					<MkAvatar :user="page.user" class="avatar"/>
+					<div class="name">
+						<MkUserName :user="page.user" style="display: block;"/>
+						<MkAcct :user="page.user"/>
+					</div>
+					<MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
+				</div>
+				<div class="links">
+					<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA>
+					<template v-if="$i && $i.id === page.userId">
+						<MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA>
+						<button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button>
+						<button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button>
+					</template>
 				</div>
-				<MkAd :prefer="['horizontal', 'horizontal-big']"/>
-				<MkContainer :max-height="300" :foldable="true" class="other">
-					<template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template>
-					<MkPagination :pagination="otherPostsPagination" #default="{items}">
-						<MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/>
-					</MkPagination>
-				</MkContainer>
 			</div>
-			<MkError v-else-if="error" @retry="fetch()"/>
-			<MkLoading v-else/>
-		</transition>
-	</div>
+			<div class="footer">
+				<div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
+				<div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
+			</div>
+			<MkAd :prefer="['horizontal', 'horizontal-big']"/>
+			<MkContainer :max-height="300" :foldable="true" class="other">
+				<template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template>
+				<MkPagination :pagination="otherPostsPagination" #default="{items}">
+					<MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/>
+				</MkPagination>
+			</MkContainer>
+		</div>
+		<MkError v-else-if="error" @retry="fetch()"/>
+		<MkLoading v-else/>
+	</transition>
 </div>
 </template>
 
@@ -101,10 +97,6 @@ export default defineComponent({
 			[symbols.PAGE_INFO]: computed(() => this.page ? {
 				title: computed(() => this.page.title || this.page.name),
 				avatar: this.page.user,
-			} : null),
-			header: computed(() => this.page ? {
-				title: computed(() => this.page.title || this.page.name),
-				avatar: this.page.user,
 				path: `/@${this.page.user.username}/pages/${this.page.name}`,
 				share: {
 					title: this.page.title || this.page.name,
diff --git a/src/client/pages/pages.vue b/src/client/pages/pages.vue
index 8300e8a6e4..6963682592 100644
--- a/src/client/pages/pages.vue
+++ b/src/client/pages/pages.vue
@@ -1,37 +1,33 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
+<MkSpacer>
+	<!-- TODO: MkHeaderに統合 -->
+	<MkTab v-model="tab" v-if="$i">
+		<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option>
+		<option value="my"><i class="fas fa-edit"></i> {{ $ts._pages.my }}</option>
+		<option value="liked"><i class="fas fa-heart"></i> {{ $ts._pages.liked }}</option>
+	</MkTab>
 
-	<MkSpacer>
-		<!-- TODO: MkHeaderに統合 -->
-		<MkTab v-model="tab" v-if="$i">
-			<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option>
-			<option value="my"><i class="fas fa-edit"></i> {{ $ts._pages.my }}</option>
-			<option value="liked"><i class="fas fa-heart"></i> {{ $ts._pages.liked }}</option>
-		</MkTab>
-
-		<div class="_section">
-			<div class="rknalgpo _content" v-if="tab === 'featured'">
-				<MkPagination :pagination="featuredPagesPagination" #default="{items}">
-					<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
-				</MkPagination>
-			</div>
-
-			<div class="rknalgpo _content my" v-if="tab === 'my'">
-				<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
-				<MkPagination :pagination="myPagesPagination" #default="{items}">
-					<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
-				</MkPagination>
-			</div>
-
-			<div class="rknalgpo _content" v-if="tab === 'liked'">
-				<MkPagination :pagination="likedPagesPagination" #default="{items}">
-					<MkPagePreview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/>
-				</MkPagination>
-			</div>
+	<div class="_section">
+		<div class="rknalgpo _content" v-if="tab === 'featured'">
+			<MkPagination :pagination="featuredPagesPagination" #default="{items}">
+				<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
+			</MkPagination>
 		</div>
-	</MkSpacer>
-</div>
+
+		<div class="rknalgpo _content my" v-if="tab === 'my'">
+			<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
+			<MkPagination :pagination="myPagesPagination" #default="{items}">
+				<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
+			</MkPagination>
+		</div>
+
+		<div class="rknalgpo _content" v-if="tab === 'liked'">
+			<MkPagination :pagination="likedPagesPagination" #default="{items}">
+				<MkPagePreview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/>
+			</MkPagination>
+		</div>
+	</div>
+</MkSpacer>
 </template>
 
 <script lang="ts">
@@ -52,11 +48,6 @@ export default defineComponent({
 				title: this.$ts.pages,
 				icon: 'fas fa-sticky-note',
 				bg: 'var(--bg)',
-			},
-			header: {
-				title: this.$ts.pages,
-				icon: 'fas fa-sticky-note',
-				bg: 'var(--bg)',
 				actions: [{
 					icon: 'fas fa-plus',
 					text: this.$ts.create,
diff --git a/src/client/pages/search.vue b/src/client/pages/search.vue
index fec138726f..8cf4d32a8f 100644
--- a/src/client/pages/search.vue
+++ b/src/client/pages/search.vue
@@ -1,10 +1,7 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<div class="_section">
-		<div class="_content">
-			<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
-		</div>
+<div class="_section">
+	<div class="_content">
+		<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
 	</div>
 </div>
 </template>
@@ -26,10 +23,6 @@ export default defineComponent({
 				title: computed(() => this.$t('searchWith', { q: this.$route.query.q })),
 				icon: 'fas fa-search',
 			},
-			header: {
-				title: computed(() => this.$t('searchWith', { q: this.$route.query.q })),
-				icon: 'fas fa-search',
-			},
 			pagination: {
 				endpoint: 'notes/search',
 				limit: 10,
diff --git a/src/client/pages/settings/index.vue b/src/client/pages/settings/index.vue
index d9f827a3ca..5a396b6a6b 100644
--- a/src/client/pages/settings/index.vue
+++ b/src/client/pages/settings/index.vue
@@ -41,6 +41,7 @@ export default defineComponent({
 			title: i18n.locale.settings,
 			icon: 'fas fa-cog',
 			bg: 'var(--bg)',
+			hideHeader: true,
 		};
 		const INFO = ref(indexInfo);
 		const page = ref(props.initialPage);
diff --git a/src/client/pages/timeline.vue b/src/client/pages/timeline.vue
index dfabcbf84b..7b17d585f8 100644
--- a/src/client/pages/timeline.vue
+++ b/src/client/pages/timeline.vue
@@ -1,21 +1,18 @@
 <template>
-<div v-hotkey.global="keymap">
-	<MkHeader :info="header"/>
-	<div class="cmuxhskf" v-size="{ min: [800] }">
-		<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/>
-		<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/>
+<div class="cmuxhskf" v-size="{ min: [800] }" v-hotkey.global="keymap">
+	<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/>
+	<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/>
 
-		<div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
-		<div class="tl _block">
-			<XTimeline ref="tl" class="tl"
-				:key="src"
-				:src="src"
-				:sound="true"
-				@before="before()"
-				@after="after()"
-				@queue="queueUpdated"
-			/>
-		</div>
+	<div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
+	<div class="tl _block">
+		<XTimeline ref="tl" class="tl"
+			:key="src"
+			:src="src"
+			:sound="true"
+			@before="before()"
+			@after="after()"
+			@queue="queueUpdated"
+		/>
 	</div>
 </div>
 </template>
@@ -46,11 +43,6 @@ export default defineComponent({
 				title: this.$ts.timeline,
 				icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home',
 				bg: 'var(--bg)',
-			})),
-			header: computed(() => ({
-				title: this.$ts.timeline,
-				icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home',
-				bg: 'var(--bg)',
 				actions: [{
 					icon: 'fas fa-list-ul',
 					text: this.$ts.lists,
@@ -92,7 +84,7 @@ export default defineComponent({
 					icon: 'fas fa-globe',
 					iconOnly: true,
 					onClick: () => { this.src = 'global'; this.saveSrc(); },
-				}]
+				}],
 			})),
 		};
 	},
diff --git a/src/client/pages/user/index.vue b/src/client/pages/user/index.vue
index 996e613866..d5dc244b4b 100644
--- a/src/client/pages/user/index.vue
+++ b/src/client/pages/user/index.vue
@@ -1,34 +1,123 @@
 <template>
-<div>
-	<MkHeader :info="header"/>
-	<transition name="fade" mode="out-in">
-		<div class="ftskorzw wide" v-if="user && narrow === false">
-			<MkRemoteCaution v-if="user.host != null" :href="user.url"/>
+<transition name="fade" mode="out-in">
+	<div class="ftskorzw wide" v-if="user && narrow === false">
+		<MkRemoteCaution v-if="user.host != null" :href="user.url"/>
 
-			<div class="banner-container" :style="style">
-				<div class="banner" ref="banner" :style="style"></div>
+		<div class="banner-container" :style="style">
+			<div class="banner" ref="banner" :style="style"></div>
+		</div>
+		<div class="contents">
+			<div class="side _forceContainerFull_">
+				<MkAvatar class="avatar" :user="user" :disable-preview="true" :show-indicator="true"/>
+				<div class="name">
+					<MkUserName :user="user" :nowrap="false" class="name"/>
+					<MkAcct :user="user" :detail="true" class="acct"/>
+				</div>
+				<div class="followed" v-if="$i && $i.id != user.id && user.isFollowed"><span>{{ $ts.followsYou }}</span></div>
+				<div class="status">
+					<MkA :to="userPage(user)" :class="{ active: page === 'index' }">
+						<b>{{ number(user.notesCount) }}</b>
+						<span>{{ $ts.notes }}</span>
+					</MkA>
+					<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
+						<b>{{ number(user.followingCount) }}</b>
+						<span>{{ $ts.following }}</span>
+					</MkA>
+					<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
+						<b>{{ number(user.followersCount) }}</b>
+						<span>{{ $ts.followers }}</span>
+					</MkA>
+				</div>
+				<div class="description">
+					<Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i" :custom-emojis="user.emojis"/>
+					<p v-else class="empty">{{ $ts.noAccountDescription }}</p>
+				</div>
+				<div class="fields system">
+					<dl class="field" v-if="user.location">
+						<dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ $ts.location }}</dt>
+						<dd class="value">{{ user.location }}</dd>
+					</dl>
+					<dl class="field" v-if="user.birthday">
+						<dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ $ts.birthday }}</dt>
+						<dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ $t('yearsOld', { age }) }})</dd>
+					</dl>
+					<dl class="field">
+						<dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ $ts.registeredDate }}</dt>
+						<dd class="value">{{ new Date(user.createdAt).toLocaleString() }} (<MkTime :time="user.createdAt"/>)</dd>
+					</dl>
+				</div>
+				<div class="fields" v-if="user.fields.length > 0">
+					<dl class="field" v-for="(field, i) in user.fields" :key="i">
+						<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>
+				<XActivity :user="user" :key="user.id" class="_gap"/>
+				<XPhotos :user="user" :key="user.id" class="_gap"/>
 			</div>
-			<div class="contents">
-				<div class="side _forceContainerFull_">
-					<MkAvatar class="avatar" :user="user" :disable-preview="true" :show-indicator="true"/>
-					<div class="name">
-						<MkUserName :user="user" :nowrap="false" class="name"/>
-						<MkAcct :user="user" :detail="true" class="acct"/>
+			<div class="main">
+				<div class="actions">
+					<button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
+					<MkFollowButton v-if="!$i || $i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
+				</div>
+				<template v-if="page === 'index'">
+					<div v-if="user.pinnedNotes.length > 0" class="_gap">
+						<XNote v-for="note in user.pinnedNotes" class="note _gap" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :pinned="true"/>
 					</div>
-					<div class="followed" v-if="$i && $i.id != user.id && user.isFollowed"><span>{{ $ts.followsYou }}</span></div>
-					<div class="status">
-						<MkA :to="userPage(user)" :class="{ active: page === 'index' }">
-							<b>{{ number(user.notesCount) }}</b>
-							<span>{{ $ts.notes }}</span>
-						</MkA>
-						<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
-							<b>{{ number(user.followingCount) }}</b>
-							<span>{{ $ts.following }}</span>
-						</MkA>
-						<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
-							<b>{{ number(user.followersCount) }}</b>
-							<span>{{ $ts.followers }}</span>
-						</MkA>
+					<div class="_gap">
+						<XUserTimeline :user="user"/>
+					</div>
+				</template>
+				<XFollowList v-else-if="page === 'following'" type="following" :user="user" class="_gap"/>
+				<XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_gap"/>
+				<XClips v-else-if="page === 'clips'" :user="user" class="_gap"/>
+				<XPages v-else-if="page === 'pages'" :user="user" class="_gap"/>
+			</div>
+		</div>
+	</div>
+	<MkSpacer v-else-if="user && narrow === true" :content-max="800">
+		<div class="ftskorzw narrow" v-size="{ max: [500] }">
+			<!-- TODO -->
+			<!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSuspended }}</div> -->
+			<!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSilenced }}</div> -->
+
+			<div class="profile">
+				<MkRemoteCaution v-if="user.host != null" :href="user.url" class="warn"/>
+
+				<div class="_block main" :key="user.id">
+					<div class="banner-container" :style="style">
+						<div class="banner" ref="banner" :style="style"></div>
+						<div class="fade"></div>
+						<div class="title">
+							<MkUserName class="name" :user="user" :nowrap="true"/>
+							<div class="bottom">
+								<span class="username"><MkAcct :user="user" :detail="true" /></span>
+								<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
+								<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
+								<span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
+								<span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
+							</div>
+						</div>
+						<span class="followed" v-if="$i && $i.id != user.id && user.isFollowed">{{ $ts.followsYou }}</span>
+						<div class="actions" v-if="$i">
+							<button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
+							<MkFollowButton v-if="$i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/>
+						</div>
+					</div>
+					<MkAvatar class="avatar" :user="user" :disable-preview="true" :show-indicator="true"/>
+					<div class="title">
+						<MkUserName :user="user" :nowrap="false" class="name"/>
+						<div class="bottom">
+							<span class="username"><MkAcct :user="user" :detail="true" /></span>
+							<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
+							<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
+							<span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
+							<span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
+						</div>
 					</div>
 					<div class="description">
 						<Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i" :custom-emojis="user.emojis"/>
@@ -58,141 +147,49 @@
 							</dd>
 						</dl>
 					</div>
-					<XActivity :user="user" :key="user.id" class="_gap"/>
-					<XPhotos :user="user" :key="user.id" class="_gap"/>
-				</div>
-				<div class="main">
-					<div class="actions">
-						<button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
-						<MkFollowButton v-if="!$i || $i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
+					<div class="status">
+						<MkA :to="userPage(user)" :class="{ active: page === 'index' }" v-click-anime>
+							<b>{{ number(user.notesCount) }}</b>
+							<span>{{ $ts.notes }}</span>
+						</MkA>
+						<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }" v-click-anime>
+							<b>{{ number(user.followingCount) }}</b>
+							<span>{{ $ts.following }}</span>
+						</MkA>
+						<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }" v-click-anime>
+							<b>{{ number(user.followersCount) }}</b>
+							<span>{{ $ts.followers }}</span>
+						</MkA>
 					</div>
-					<template v-if="page === 'index'">
-						<div v-if="user.pinnedNotes.length > 0" class="_gap">
-							<XNote v-for="note in user.pinnedNotes" class="note _gap" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :pinned="true"/>
-						</div>
-						<div class="_gap">
-							<XUserTimeline :user="user"/>
-						</div>
-					</template>
-					<XFollowList v-else-if="page === 'following'" type="following" :user="user" class="_gap"/>
-					<XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_gap"/>
-					<XClips v-else-if="page === 'clips'" :user="user" class="_gap"/>
-					<XPages v-else-if="page === 'pages'" :user="user" class="_gap"/>
 				</div>
 			</div>
+
+			<div class="contents">
+				<template v-if="page === 'index'">
+					<div>
+						<div v-if="user.pinnedNotes.length > 0" class="_gap">
+							<XNote v-for="note in user.pinnedNotes" class="note _block" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :pinned="true"/>
+						</div>
+						<MkInfo v-else-if="$i && $i.id === user.id">{{ $ts.userPagePinTip }}</MkInfo>
+						<XPhotos :user="user" :key="user.id"/>
+						<XActivity :user="user" :key="user.id"/>
+					</div>
+					<div>
+						<XUserTimeline :user="user"/>
+					</div>
+				</template>
+				<XFollowList v-else-if="page === 'following'" type="following" :user="user" class="_content _gap"/>
+				<XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_content _gap"/>
+				<XReactions v-else-if="page === 'reactions'" :user="user" class="_gap"/>
+				<XClips v-else-if="page === 'clips'" :user="user" class="_gap"/>
+				<XPages v-else-if="page === 'pages'" :user="user" class="_gap"/>
+				<XGallery v-else-if="page === 'gallery'" :user="user" class="_gap"/>
+			</div>
 		</div>
-		<MkSpacer v-else-if="user && narrow === true" :content-max="800">
-			<div class="ftskorzw narrow" v-size="{ max: [500] }">
-				<!-- TODO -->
-				<!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSuspended }}</div> -->
-				<!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSilenced }}</div> -->
-
-				<div class="profile">
-					<MkRemoteCaution v-if="user.host != null" :href="user.url" class="warn"/>
-
-					<div class="_block main" :key="user.id">
-						<div class="banner-container" :style="style">
-							<div class="banner" ref="banner" :style="style"></div>
-							<div class="fade"></div>
-							<div class="title">
-								<MkUserName class="name" :user="user" :nowrap="true"/>
-								<div class="bottom">
-									<span class="username"><MkAcct :user="user" :detail="true" /></span>
-									<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
-									<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
-									<span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
-									<span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
-								</div>
-							</div>
-							<span class="followed" v-if="$i && $i.id != user.id && user.isFollowed">{{ $ts.followsYou }}</span>
-							<div class="actions" v-if="$i">
-								<button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
-								<MkFollowButton v-if="$i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/>
-							</div>
-						</div>
-						<MkAvatar class="avatar" :user="user" :disable-preview="true" :show-indicator="true"/>
-						<div class="title">
-							<MkUserName :user="user" :nowrap="false" class="name"/>
-							<div class="bottom">
-								<span class="username"><MkAcct :user="user" :detail="true" /></span>
-								<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
-								<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
-								<span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
-								<span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
-							</div>
-						</div>
-						<div class="description">
-							<Mfm v-if="user.description" :text="user.description" :is-note="false" :author="user" :i="$i" :custom-emojis="user.emojis"/>
-							<p v-else class="empty">{{ $ts.noAccountDescription }}</p>
-						</div>
-						<div class="fields system">
-							<dl class="field" v-if="user.location">
-								<dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ $ts.location }}</dt>
-								<dd class="value">{{ user.location }}</dd>
-							</dl>
-							<dl class="field" v-if="user.birthday">
-								<dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ $ts.birthday }}</dt>
-								<dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ $t('yearsOld', { age }) }})</dd>
-							</dl>
-							<dl class="field">
-								<dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ $ts.registeredDate }}</dt>
-								<dd class="value">{{ new Date(user.createdAt).toLocaleString() }} (<MkTime :time="user.createdAt"/>)</dd>
-							</dl>
-						</div>
-						<div class="fields" v-if="user.fields.length > 0">
-							<dl class="field" v-for="(field, i) in user.fields" :key="i">
-								<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">
-							<MkA :to="userPage(user)" :class="{ active: page === 'index' }" v-click-anime>
-								<b>{{ number(user.notesCount) }}</b>
-								<span>{{ $ts.notes }}</span>
-							</MkA>
-							<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }" v-click-anime>
-								<b>{{ number(user.followingCount) }}</b>
-								<span>{{ $ts.following }}</span>
-							</MkA>
-							<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }" v-click-anime>
-								<b>{{ number(user.followersCount) }}</b>
-								<span>{{ $ts.followers }}</span>
-							</MkA>
-						</div>
-					</div>
-				</div>
-
-				<div class="contents">
-					<template v-if="page === 'index'">
-						<div>
-							<div v-if="user.pinnedNotes.length > 0" class="_gap">
-								<XNote v-for="note in user.pinnedNotes" class="note _block" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :pinned="true"/>
-							</div>
-							<MkInfo v-else-if="$i && $i.id === user.id">{{ $ts.userPagePinTip }}</MkInfo>
-							<XPhotos :user="user" :key="user.id"/>
-							<XActivity :user="user" :key="user.id"/>
-						</div>
-						<div>
-							<XUserTimeline :user="user"/>
-						</div>
-					</template>
-					<XFollowList v-else-if="page === 'following'" type="following" :user="user" class="_content _gap"/>
-					<XFollowList v-else-if="page === 'followers'" type="followers" :user="user" class="_content _gap"/>
-					<XReactions v-else-if="page === 'reactions'" :user="user" class="_gap"/>
-					<XClips v-else-if="page === 'clips'" :user="user" class="_gap"/>
-					<XPages v-else-if="page === 'pages'" :user="user" class="_gap"/>
-					<XGallery v-else-if="page === 'gallery'" :user="user" class="_gap"/>
-				</div>
-			</div>
-		</MkSpacer>
-		<MkError v-else-if="error" @retry="fetch()"/>
-		<MkLoading v-else/>
-	</transition>
-</div>
+	</MkSpacer>
+	<MkError v-else-if="error" @retry="fetch()"/>
+	<MkLoading v-else/>
+</transition>
 </template>
 
 <script lang="ts">
@@ -250,14 +247,6 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: computed(() => this.user ? {
 				icon: 'fas fa-user',
-				title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`,
-				path: `/@${this.user.username}`,
-				share: {
-					title: this.user.name,
-				},
-				bg: 'var(--bg)',
-			} : null),
-			header: computed(() => this.user ? {
 				title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`,
 				subtitle: `@${getAcct(this.user)}`,
 				userName: this.user,
@@ -292,7 +281,7 @@ export default defineComponent({
 					title: this.$ts.gallery,
 					icon: 'fas fa-icons',
 					onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/gallery'); },
-				}]
+				}],
 			} : null),
 			user: null,
 			error: null,
diff --git a/src/client/ui/deck/main-column.vue b/src/client/ui/deck/main-column.vue
index 591897bba7..8e36caa3ce 100644
--- a/src/client/ui/deck/main-column.vue
+++ b/src/client/ui/deck/main-column.vue
@@ -7,13 +7,16 @@
 		</template>
 	</template>
 
-	<router-view v-slot="{ Component }">
-		<transition>
-			<keep-alive :include="['timeline']">
-				<component :is="Component" :ref="changePage" @contextmenu.stop="onContextmenu"/>
-			</keep-alive>
-		</transition>
-	</router-view>
+	<MkStickyContainer>
+		<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
+		<router-view v-slot="{ Component }">
+			<transition>
+				<keep-alive :include="['timeline']">
+					<component :is="Component" :ref="changePage" @contextmenu.stop="onContextmenu"/>
+				</keep-alive>
+			</transition>
+		</router-view>
+	</MkStickyContainer>
 </XColumn>
 </template>
 
diff --git a/src/client/ui/default.vue b/src/client/ui/default.vue
index 0f0773e415..792aa197ad 100644
--- a/src/client/ui/default.vue
+++ b/src/client/ui/default.vue
@@ -14,13 +14,16 @@
 
 		<main class="main" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
 			<div class="content">
-				<router-view v-slot="{ Component }">
-					<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
-						<keep-alive :include="['timeline']">
-							<component :is="Component" :ref="changePage"/>
-						</keep-alive>
-					</transition>
-				</router-view>
+				<MkStickyContainer>
+					<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
+					<router-view v-slot="{ Component }">
+						<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
+							<keep-alive :include="['timeline']">
+								<component :is="Component" :ref="changePage"/>
+							</keep-alive>
+						</transition>
+					</router-view>
+				</MkStickyContainer>
 			</div>
 		</main>
 
diff --git a/src/client/ui/universal.vue b/src/client/ui/universal.vue
index 7c25d71bb3..e79ad80f61 100644
--- a/src/client/ui/universal.vue
+++ b/src/client/ui/universal.vue
@@ -5,13 +5,16 @@
 	<div class="contents" ref="contents" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
 		<main ref="main">
 			<div class="content">
-				<router-view v-slot="{ Component }">
-					<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
-						<keep-alive :include="['timeline']">
-							<component :is="Component" :ref="changePage"/>
-						</keep-alive>
-					</transition>
-				</router-view>
+				<MkStickyContainer>
+					<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
+					<router-view v-slot="{ Component }">
+						<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
+							<keep-alive :include="['timeline']">
+								<component :is="Component" :ref="changePage"/>
+							</keep-alive>
+						</transition>
+					</router-view>
+				</MkStickyContainer>
 			</div>
 			<div class="spacer"></div>
 		</main>