From 699f24f3dcdb156838eb70602885c0b2cdd02cbc Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Mon, 20 Jun 2022 17:38:49 +0900
Subject: refactor(client): Refine routing (#8846)

---
 packages/client/src/pages/admin/queue.vue | 57 +++++++++++++++++--------------
 1 file changed, 31 insertions(+), 26 deletions(-)

(limited to 'packages/client/src/pages/admin/queue.vue')

diff --git a/packages/client/src/pages/admin/queue.vue b/packages/client/src/pages/admin/queue.vue
index 656b18199f..c2865525ab 100644
--- a/packages/client/src/pages/admin/queue.vue
+++ b/packages/client/src/pages/admin/queue.vue
@@ -1,24 +1,28 @@
 <template>
-<MkSpacer :content-max="800">
-	<XQueue :connection="connection" domain="inbox">
-		<template #title>In</template>
-	</XQueue>
-	<XQueue :connection="connection" domain="deliver">
-		<template #title>Out</template>
-	</XQueue>
-	<MkButton danger @click="clear()"><i class="fas fa-trash-alt"></i> {{ i18n.ts.clearQueue }}</MkButton>
-</MkSpacer>
+<MkStickyContainer>
+	<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
+	<MkSpacer :content-max="800">
+		<XQueue :connection="connection" domain="inbox">
+			<template #title>In</template>
+		</XQueue>
+		<XQueue :connection="connection" domain="deliver">
+			<template #title>Out</template>
+		</XQueue>
+		<MkButton danger @click="clear()"><i class="fas fa-trash-alt"></i> {{ i18n.ts.clearQueue }}</MkButton>
+	</MkSpacer>
+</MkStickyContainer>
 </template>
 
 <script lang="ts" setup>
 import { markRaw, onMounted, onBeforeUnmount, nextTick } from 'vue';
-import MkButton from '@/components/ui/button.vue';
 import XQueue from './queue.chart.vue';
+import XHeader from './_header_.vue';
+import MkButton from '@/components/ui/button.vue';
 import * as os from '@/os';
 import { stream } from '@/stream';
-import * as symbols from '@/symbols';
 import * as config from '@/config';
 import { i18n } from '@/i18n';
+import { definePageMetadata } from '@/scripts/page-metadata';
 
 const connection = markRaw(stream.useChannel('queueStats'));
 
@@ -38,7 +42,7 @@ onMounted(() => {
 	nextTick(() => {
 		connection.send('requestLog', {
 			id: Math.random().toString().substr(2, 8),
-			length: 200
+			length: 200,
 		});
 	});
 });
@@ -47,19 +51,20 @@ onBeforeUnmount(() => {
 	connection.dispose();
 });
 
-defineExpose({
-	[symbols.PAGE_INFO]: {
-		title: i18n.ts.jobQueue,
-		icon: 'fas fa-clipboard-list',
-		bg: 'var(--bg)',
-		actions: [{
-			asFullButton: true,
-			icon: 'fas fa-up-right-from-square',
-			text: i18n.ts.dashboard,
-			handler: () => {
-				window.open(config.url + '/queue', '_blank');
-			},
-		}],
-	}
+const headerActions = $computed(() => [{
+	asFullButton: true,
+	icon: 'fas fa-up-right-from-square',
+	text: i18n.ts.dashboard,
+	handler: () => {
+		window.open(config.url + '/queue', '_blank');
+	},
+}]);
+
+const headerTabs = $computed(() => []);
+
+definePageMetadata({
+	title: i18n.ts.jobQueue,
+	icon: 'fas fa-clipboard-list',
+	bg: 'var(--bg)',
 });
 </script>
-- 
cgit v1.2.3-freya


From 0248a2a98926d47bf10ada8446393cb6fe0e0238 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 25 Jun 2022 23:01:40 +0900
Subject: enhance(client): improve control panel

---
 packages/client/src/components/queue-chart.vue     | 232 ----------
 .../client/src/pages/admin/overview.federation.vue | 105 +++++
 .../src/pages/admin/overview.queue-chart.vue       | 213 ++++++++++
 packages/client/src/pages/admin/overview.vue       | 469 ++++++++++++++++-----
 .../client/src/pages/admin/queue.chart.chart.vue   | 181 ++++++++
 packages/client/src/pages/admin/queue.chart.vue    | 142 +++++--
 packages/client/src/pages/admin/queue.vue          |  35 +-
 7 files changed, 985 insertions(+), 392 deletions(-)
 delete mode 100644 packages/client/src/components/queue-chart.vue
 create mode 100644 packages/client/src/pages/admin/overview.federation.vue
 create mode 100644 packages/client/src/pages/admin/overview.queue-chart.vue
 create mode 100644 packages/client/src/pages/admin/queue.chart.chart.vue

(limited to 'packages/client/src/pages/admin/queue.vue')

diff --git a/packages/client/src/components/queue-chart.vue b/packages/client/src/components/queue-chart.vue
deleted file mode 100644
index 7bb548cf06..0000000000
--- a/packages/client/src/components/queue-chart.vue
+++ /dev/null
@@ -1,232 +0,0 @@
-<template>
-<canvas ref="chartEl"></canvas>
-</template>
-
-<script lang="ts">
-import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
-import {
-	Chart,
-	ArcElement,
-	LineElement,
-	BarElement,
-	PointElement,
-	BarController,
-	LineController,
-	CategoryScale,
-	LinearScale,
-	TimeScale,
-	Legend,
-	Title,
-	Tooltip,
-	SubTitle,
-	Filler,
-} from 'chart.js';
-import number from '@/filters/number';
-import * as os from '@/os';
-import { defaultStore } from '@/store';
-
-Chart.register(
-	ArcElement,
-	LineElement,
-	BarElement,
-	PointElement,
-	BarController,
-	LineController,
-	CategoryScale,
-	LinearScale,
-	TimeScale,
-	Legend,
-	Title,
-	Tooltip,
-	SubTitle,
-	Filler,
-);
-
-const alpha = (hex, a) => {
-	const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!;
-	const r = parseInt(result[1], 16);
-	const g = parseInt(result[2], 16);
-	const b = parseInt(result[3], 16);
-	return `rgba(${r}, ${g}, ${b}, ${a})`;
-};
-
-export default defineComponent({
-	props: {
-		domain: {
-			type: String,
-			required: true,
-		},
-		connection: {
-			required: true,
-		},
-	},
-
-	setup(props) {
-		const chartEl = ref<HTMLCanvasElement>(null);
-
-		const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
-
-		// フォントカラー
-		Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
-
-		onMounted(() => {
-			const chartInstance = new Chart(chartEl.value, {
-				type: 'line',
-				data: {
-					labels: [],
-					datasets: [{
-						label: 'Process',
-						pointRadius: 0,
-						tension: 0,
-						borderWidth: 2,
-						borderJoinStyle: 'round',
-						borderColor: '#00E396',
-						backgroundColor: alpha('#00E396', 0.1),
-						data: []
-					}, {
-						label: 'Active',
-						pointRadius: 0,
-						tension: 0,
-						borderWidth: 2,
-						borderJoinStyle: 'round',
-						borderColor: '#00BCD4',
-						backgroundColor: alpha('#00BCD4', 0.1),
-						data: []
-					}, {
-						label: 'Waiting',
-						pointRadius: 0,
-						tension: 0,
-						borderWidth: 2,
-						borderJoinStyle: 'round',
-						borderColor: '#FFB300',
-						backgroundColor: alpha('#FFB300', 0.1),
-						yAxisID: 'y2',
-						data: []
-					}, {
-						label: 'Delayed',
-						pointRadius: 0,
-						tension: 0,
-						borderWidth: 2,
-						borderJoinStyle: 'round',
-						borderColor: '#E53935',
-						borderDash: [5, 5],
-						fill: false,
-						yAxisID: 'y2',
-						data: []
-					}],
-				},
-				options: {
-					aspectRatio: 2.5,
-					layout: {
-						padding: {
-							left: 16,
-							right: 16,
-							top: 16,
-							bottom: 8,
-						},
-					},
-					scales: {
-						x: {
-							grid: {
-								display: true,
-								color: gridColor,
-								borderColor: 'rgb(0, 0, 0, 0)',
-							},
-							ticks: {
-								display: false,
-								maxTicksLimit: 10
-							},
-						},
-						y: {
-							min: 0,
-							stack: 'queue',
-							stackWeight: 2,
-							grid: {
-								color: gridColor,
-								borderColor: 'rgb(0, 0, 0, 0)',
-							},
-						},
-						y2: {
-							min: 0,
-							offset: true,
-							stack: 'queue',
-							stackWeight: 1,
-							grid: {
-								color: gridColor,
-								borderColor: 'rgb(0, 0, 0, 0)',
-							},
-						},
-					},
-					interaction: {
-						intersect: false,
-					},
-					plugins: {
-						legend: {
-							position: 'bottom',
-							labels: {
-								boxWidth: 16,
-							},
-						},
-						tooltip: {
-							mode: 'index',
-							animation: {
-								duration: 0,
-							},
-						},
-					},
-				},
-			});
-
-			const onStats = (stats) => {
-				chartInstance.data.labels.push('');
-				chartInstance.data.datasets[0].data.push(stats[props.domain].activeSincePrevTick);
-				chartInstance.data.datasets[1].data.push(stats[props.domain].active);
-				chartInstance.data.datasets[2].data.push(stats[props.domain].waiting);
-				chartInstance.data.datasets[3].data.push(stats[props.domain].delayed);
-				if (chartInstance.data.datasets[0].data.length > 200) {
-					chartInstance.data.labels.shift();
-					chartInstance.data.datasets[0].data.shift();
-					chartInstance.data.datasets[1].data.shift();
-					chartInstance.data.datasets[2].data.shift();
-					chartInstance.data.datasets[3].data.shift();
-				}
-				chartInstance.update();
-			};
-
-			const onStatsLog = (statsLog) => {
-				for (const stats of [...statsLog].reverse()) {
-					chartInstance.data.labels.push('');
-					chartInstance.data.datasets[0].data.push(stats[props.domain].activeSincePrevTick);
-					chartInstance.data.datasets[1].data.push(stats[props.domain].active);
-					chartInstance.data.datasets[2].data.push(stats[props.domain].waiting);
-					chartInstance.data.datasets[3].data.push(stats[props.domain].delayed);
-					if (chartInstance.data.datasets[0].data.length > 200) {
-						chartInstance.data.labels.shift();
-						chartInstance.data.datasets[0].data.shift();
-						chartInstance.data.datasets[1].data.shift();
-						chartInstance.data.datasets[2].data.shift();
-						chartInstance.data.datasets[3].data.shift();
-					}
-				}
-				chartInstance.update();
-			};
-
-			props.connection.on('stats', onStats);
-			props.connection.on('statsLog', onStatsLog);
-
-			onUnmounted(() => {
-				props.connection.off('stats', onStats);
-				props.connection.off('statsLog', onStatsLog);
-			});
-		});
-
-		return {
-			chartEl,
-		};
-	},
-});
-</script>
-
-<style lang="scss" scoped>
-
-</style>
diff --git a/packages/client/src/pages/admin/overview.federation.vue b/packages/client/src/pages/admin/overview.federation.vue
new file mode 100644
index 0000000000..6709c30c64
--- /dev/null
+++ b/packages/client/src/pages/admin/overview.federation.vue
@@ -0,0 +1,105 @@
+<template>
+<div class="wbrkwale">
+	<MkLoading v-if="fetching"/>
+	<transition-group v-else tag="div" :name="$store.state.animation ? 'chart' : ''" class="instances">
+		<div v-for="(instance, i) in instances" :key="instance.id" class="instance">
+			<img v-if="instance.iconUrl" :src="instance.iconUrl" alt=""/>
+			<div class="body">
+				<a class="a" :href="'https://' + instance.host" target="_blank" :title="instance.host">{{ instance.name ?? instance.host }}</a>
+				<p>{{ instance.host }}</p>
+			</div>
+			<MkMiniChart class="chart" :src="charts[i].requests.received"/>
+		</div>
+	</transition-group>
+</div>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted, ref } from 'vue';
+import MkMiniChart from '@/components/mini-chart.vue';
+import * as os from '@/os';
+
+const instances = ref([]);
+const charts = ref([]);
+const fetching = ref(true);
+
+const fetch = async () => {
+	const fetchedInstances = await os.api('federation/instances', {
+		sort: '+lastCommunicatedAt',
+		limit: 5,
+	});
+	const fetchedCharts = await Promise.all(fetchedInstances.map(i => os.apiGet('charts/instance', { host: i.host, limit: 16, span: 'hour' })));
+	instances.value = fetchedInstances;
+	charts.value = fetchedCharts;
+	fetching.value = false;
+};
+
+let intervalId;
+
+onMounted(() => {
+	fetch();
+	intervalId = window.setInterval(fetch, 1000 * 60);
+});
+
+onUnmounted(() => {
+	window.clearInterval(intervalId);
+});
+</script>
+
+<style lang="scss" scoped>
+.wbrkwale {
+	> .instances {
+		.chart-move {
+			transition: transform 1s ease;
+		}
+
+		> .instance {
+			display: flex;
+			align-items: center;
+			padding: 16px 20px;
+
+			&:not(:last-child) {
+				border-bottom: solid 0.5px var(--divider);
+			}
+
+			> img {
+				display: block;
+				width: 34px;
+				height: 34px;
+				object-fit: cover;
+				border-radius: 4px;
+				margin-right: 12px;
+			}
+
+			> .body {
+				flex: 1;
+				overflow: hidden;
+				font-size: 0.9em;
+				color: var(--fg);
+				padding-right: 8px;
+
+				> .a {
+					display: block;
+					width: 100%;
+					white-space: nowrap;
+					overflow: hidden;
+					text-overflow: ellipsis;
+				}
+
+				> p {
+					margin: 0;
+					font-size: 75%;
+					opacity: 0.7;
+					white-space: nowrap;
+					overflow: hidden;
+					text-overflow: ellipsis;
+				}
+			}
+
+			> .chart {
+				height: 30px;
+			}
+		}
+	}
+}
+</style>
diff --git a/packages/client/src/pages/admin/overview.queue-chart.vue b/packages/client/src/pages/admin/overview.queue-chart.vue
new file mode 100644
index 0000000000..646d1ac2f3
--- /dev/null
+++ b/packages/client/src/pages/admin/overview.queue-chart.vue
@@ -0,0 +1,213 @@
+<template>
+<canvas ref="chartEl"></canvas>
+</template>
+
+<script lang="ts" setup>
+import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
+import {
+	Chart,
+	ArcElement,
+	LineElement,
+	BarElement,
+	PointElement,
+	BarController,
+	LineController,
+	CategoryScale,
+	LinearScale,
+	TimeScale,
+	Legend,
+	Title,
+	Tooltip,
+	SubTitle,
+	Filler,
+} from 'chart.js';
+import number from '@/filters/number';
+import * as os from '@/os';
+import { defaultStore } from '@/store';
+import { useChartTooltip } from '@/scripts/use-chart-tooltip';
+
+Chart.register(
+	ArcElement,
+	LineElement,
+	BarElement,
+	PointElement,
+	BarController,
+	LineController,
+	CategoryScale,
+	LinearScale,
+	TimeScale,
+	Legend,
+	Title,
+	Tooltip,
+	SubTitle,
+	Filler,
+);
+
+const props = defineProps<{
+	domain: string;
+	connection: any;
+}>();
+
+const alpha = (hex, a) => {
+	const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!;
+	const r = parseInt(result[1], 16);
+	const g = parseInt(result[2], 16);
+	const b = parseInt(result[3], 16);
+	return `rgba(${r}, ${g}, ${b}, ${a})`;
+};
+
+const chartEl = ref<HTMLCanvasElement>(null);
+
+const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
+
+// フォントカラー
+Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
+
+const { handler: externalTooltipHandler } = useChartTooltip();
+
+let chartInstance: Chart;
+
+const onStats = (stats) => {
+	chartInstance.data.labels.push('');
+	chartInstance.data.datasets[0].data.push(stats[props.domain].activeSincePrevTick);
+	chartInstance.data.datasets[1].data.push(stats[props.domain].active);
+	chartInstance.data.datasets[2].data.push(stats[props.domain].waiting);
+	chartInstance.data.datasets[3].data.push(stats[props.domain].delayed);
+	if (chartInstance.data.datasets[0].data.length > 200) {
+		chartInstance.data.labels.shift();
+		chartInstance.data.datasets[0].data.shift();
+		chartInstance.data.datasets[1].data.shift();
+		chartInstance.data.datasets[2].data.shift();
+		chartInstance.data.datasets[3].data.shift();
+	}
+	chartInstance.update();
+};
+
+const onStatsLog = (statsLog) => {
+	for (const stats of [...statsLog].reverse()) {
+		chartInstance.data.labels.push('');
+		chartInstance.data.datasets[0].data.push(stats[props.domain].activeSincePrevTick);
+		chartInstance.data.datasets[1].data.push(stats[props.domain].active);
+		chartInstance.data.datasets[2].data.push(stats[props.domain].waiting);
+		chartInstance.data.datasets[3].data.push(stats[props.domain].delayed);
+		if (chartInstance.data.datasets[0].data.length > 200) {
+			chartInstance.data.labels.shift();
+			chartInstance.data.datasets[0].data.shift();
+			chartInstance.data.datasets[1].data.shift();
+			chartInstance.data.datasets[2].data.shift();
+			chartInstance.data.datasets[3].data.shift();
+		}
+	}
+	chartInstance.update();
+};
+
+onMounted(() => {
+	chartInstance = new Chart(chartEl.value, {
+		type: 'line',
+		data: {
+			labels: [],
+			datasets: [{
+				label: 'Process',
+				pointRadius: 0,
+				tension: 0.3,
+				borderWidth: 2,
+				borderJoinStyle: 'round',
+				borderColor: '#00E396',
+				backgroundColor: alpha('#00E396', 0.1),
+				data: [],
+			}, {
+				label: 'Active',
+				pointRadius: 0,
+				tension: 0.3,
+				borderWidth: 2,
+				borderJoinStyle: 'round',
+				borderColor: '#00BCD4',
+				backgroundColor: alpha('#00BCD4', 0.1),
+				data: [],
+			}, {
+				label: 'Waiting',
+				pointRadius: 0,
+				tension: 0.3,
+				borderWidth: 2,
+				borderJoinStyle: 'round',
+				borderColor: '#FFB300',
+				backgroundColor: alpha('#FFB300', 0.1),
+				data: [],
+			}, {
+				label: 'Delayed',
+				pointRadius: 0,
+				tension: 0.3,
+				borderWidth: 2,
+				borderJoinStyle: 'round',
+				borderColor: '#E53935',
+				borderDash: [5, 5],
+				fill: false,
+				data: [],
+			}],
+		},
+		options: {
+			aspectRatio: 2.5,
+			layout: {
+				padding: {
+					left: 0,
+					right: 8,
+					top: 0,
+					bottom: 0,
+				},
+			},
+			scales: {
+				x: {
+					grid: {
+						display: false,
+					},
+					ticks: {
+						display: false,
+						maxTicksLimit: 10,
+					},
+				},
+				y: {
+					min: 0,
+					grid: {
+						display: false,
+					},
+					ticks: {
+						display: false,
+					},
+				},
+			},
+			interaction: {
+				intersect: false,
+			},
+			plugins: {
+				legend: {
+					display: false,
+				},
+				tooltip: {
+					enabled: false,
+					mode: 'index',
+					animation: {
+						duration: 0,
+					},
+					external: externalTooltipHandler,
+				},
+			},
+		},
+	});
+
+	props.connection.on('stats', onStats);
+	props.connection.on('statsLog', onStatsLog);
+
+	props.connection.send('requestLog', {
+		id: Math.random().toString().substr(2, 8),
+	});
+});
+
+onUnmounted(() => {
+	props.connection.off('stats', onStats);
+	props.connection.off('statsLog', onStatsLog);
+});
+</script>
+
+<style lang="scss" scoped>
+
+</style>
diff --git a/packages/client/src/pages/admin/overview.vue b/packages/client/src/pages/admin/overview.vue
index f81f6104c7..22d9d72a70 100644
--- a/packages/client/src/pages/admin/overview.vue
+++ b/packages/client/src/pages/admin/overview.vue
@@ -1,92 +1,318 @@
 <template>
-<div v-size="{ max: [740] }" class="edbbcaef">
-	<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" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="usersComparedToThePrevDay"><template #before>(</template><template #after>)</template></MkNumberDiff>
+<MkSpacer :content-max="900">
+	<div ref="rootEl" v-size="{ max: [740] }" class="edbbcaef">
+		<div class="left">
+			<div v-if="stats" class="container stats">
+				<div class="title">Stats</div>
+				<div class="body">
+					<div class="number _panel">
+						<div class="label">Users</div>
+						<div class="value _monospace">
+							{{ number(stats.originalUsersCount) }}
+							<MkNumberDiff v-if="usersComparedToThePrevDay != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="usersComparedToThePrevDay"><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" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="notesComparedToThePrevDay"><template #before>(</template><template #after>)</template></MkNumberDiff>
+						</div>
+					</div>
+				</div>
 			</div>
-		</div>
-		<div class="number _panel">
-			<div class="label">Notes</div>
-			<div class="value _monospace">
-				{{ number(stats.originalNotesCount) }}
-				<MkNumberDiff v-if="notesComparedToThePrevDay != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="notesComparedToThePrevDay"><template #before>(</template><template #after>)</template></MkNumberDiff>
-			</div>
-		</div>
-	</div>
 
-	<MkContainer :foldable="true" class="charts">
-		<template #header><i class="fas fa-chart-bar"></i>{{ i18n.ts.charts }}</template>
-		<div style="padding: 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>
+			<div class="container queue">
+				<div class="title">Job queue</div>
+				<div class="body deliver">
+					<div class="title">Deliver</div>
+					<XQueueChart :connection="queueStatsConnection" domain="deliver"/>
+				</div>
+				<div class="body inbox">
+					<div class="title">Inbox</div>
+					<XQueueChart :connection="queueStatsConnection" domain="inbox"/>
+				</div>
+			</div>
 
-	<!--<XMetrics/>-->
+			<!--<XMetrics/>-->
 
-	<MkFolder style="margin: var(--margin)">
-		<template #header><i class="fas fa-info-circle"></i> {{ i18n.ts.info }}</template>
-		<div class="cfcdecdf">
-			<div class="number _panel">
-				<div class="label">Misskey</div>
-				<div class="value _monospace">{{ version }}</div>
+			<div class="container env">
+				<div class="title">Enviroment</div>
+				<div class="body">
+					<div class="number _panel">
+						<div class="label">Misskey</div>
+						<div class="value _monospace">{{ version }}</div>
+					</div>
+					<div v-if="serverInfo" class="number _panel">
+						<div class="label">Node.js</div>
+						<div class="value _monospace">{{ serverInfo.node }}</div>
+					</div>
+					<div v-if="serverInfo" class="number _panel">
+						<div class="label">PostgreSQL</div>
+						<div class="value _monospace">{{ serverInfo.psql }}</div>
+					</div>
+					<div v-if="serverInfo" class="number _panel">
+						<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>
 			</div>
-			<div v-if="serverInfo" class="number _panel">
-				<div class="label">Node.js</div>
-				<div class="value _monospace">{{ serverInfo.node }}</div>
-			</div>
-			<div v-if="serverInfo" class="number _panel">
-				<div class="label">PostgreSQL</div>
-				<div class="value _monospace">{{ serverInfo.psql }}</div>
-			</div>
-			<div v-if="serverInfo" class="number _panel">
-				<div class="label">Redis</div>
-				<div class="value _monospace">{{ serverInfo.redis }}</div>
+		</div>
+		<div class="right">
+			<div class="container charts">
+				<div class="title">Active users</div>
+				<div class="body">
+					<canvas ref="chartEl"></canvas>
+				</div>
 			</div>
-			<div class="number _panel">
-				<div class="label">Vue</div>
-				<div class="value _monospace">{{ vueVersion }}</div>
+			<div class="container federation">
+				<div class="title">Active instances</div>
+				<div class="body">
+					<XFederation/>
+				</div>
 			</div>
 		</div>
-	</MkFolder>
-</div>
+	</div>
+</MkSpacer>
 </template>
 
 <script lang="ts" setup>
 import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } from 'vue';
+import {
+	Chart,
+	ArcElement,
+	LineElement,
+	BarElement,
+	PointElement,
+	BarController,
+	LineController,
+	CategoryScale,
+	LinearScale,
+	TimeScale,
+	Legend,
+	Title,
+	Tooltip,
+	SubTitle,
+	Filler,
+} from 'chart.js';
+import { enUS } from 'date-fns/locale';
+import tinycolor from 'tinycolor2';
+import MagicGrid from 'magic-grid';
 import XMetrics from './metrics.vue';
+import XFederation from './overview.federation.vue';
+import XQueueChart from './overview.queue-chart.vue';
 import MkInstanceStats from '@/components/instance-stats.vue';
 import MkNumberDiff from '@/components/number-diff.vue';
-import MkContainer from '@/components/ui/container.vue';
-import MkFolder from '@/components/ui/folder.vue';
-import MkQueueChart from '@/components/queue-chart.vue';
 import { version, url } from '@/config';
 import number from '@/filters/number';
 import * as os from '@/os';
 import { stream } from '@/stream';
 import { i18n } from '@/i18n';
 import { definePageMetadata } from '@/scripts/page-metadata';
+import 'chartjs-adapter-date-fns';
+import { defaultStore } from '@/store';
+import { useChartTooltip } from '@/scripts/use-chart-tooltip';
 
+Chart.register(
+	ArcElement,
+	LineElement,
+	BarElement,
+	PointElement,
+	BarController,
+	LineController,
+	CategoryScale,
+	LinearScale,
+	TimeScale,
+	Legend,
+	Title,
+	Tooltip,
+	SubTitle,
+	Filler,
+	//gradient,
+);
+
+const rootEl = $ref<HTMLElement>();
+const chartEl = $ref<HTMLCanvasElement>(null);
 let stats: any = $ref(null);
 let serverInfo: any = $ref(null);
 let usersComparedToThePrevDay: any = $ref(null);
 let notesComparedToThePrevDay: any = $ref(null);
 const queueStatsConnection = markRaw(stream.useChannel('queueStats'));
+const now = new Date();
+let chartInstance: Chart = null;
+const chartLimit = 30;
+
+const { handler: externalTooltipHandler } = useChartTooltip();
+
+async function renderChart() {
+	if (chartInstance) {
+		chartInstance.destroy();
+	}
+
+	const getDate = (ago: number) => {
+		const y = now.getFullYear();
+		const m = now.getMonth();
+		const d = now.getDate();
+
+		return new Date(y, m, d - ago);
+	};
+
+	const format = (arr) => {
+		return arr.map((v, i) => ({
+			x: getDate(i).getTime(),
+			y: v,
+		}));
+	};
+
+	const raw = await os.api('charts/active-users', { limit: chartLimit, span: 'day' });
+
+	const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
+	const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
+
+	// フォントカラー
+	Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
+
+	const color = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--accent'));
+
+	chartInstance = new Chart(chartEl, {
+		type: 'bar',
+		data: {
+			//labels: new Array(props.limit).fill(0).map((_, i) => getDate(i).toLocaleString()).slice().reverse(),
+			datasets: [{
+				parsing: false,
+				label: 'a',
+				data: format(raw.readWrite).slice().reverse(),
+				tension: 0.3,
+				pointRadius: 0,
+				borderWidth: 0,
+				borderJoinStyle: 'round',
+				borderRadius: 3,
+				backgroundColor: color,
+				/*gradient: props.bar ? undefined : {
+					backgroundColor: {
+						axis: 'y',
+						colors: {
+							0: alpha(x.color ? x.color : getColor(i), 0),
+							[maxes[i]]: alpha(x.color ? x.color : getColor(i), 0.2),
+						},
+					},
+				},*/
+				barPercentage: 0.9,
+				categoryPercentage: 0.9,
+				clip: 8,
+			}],
+		},
+		options: {
+			aspectRatio: 2.5,
+			layout: {
+				padding: {
+					left: 0,
+					right: 8,
+					top: 0,
+					bottom: 0,
+				},
+			},
+			scales: {
+				x: {
+					type: 'time',
+					stacked: true,
+					offset: false,
+					time: {
+						stepSize: 1,
+						unit: 'month',
+					},
+					grid: {
+						display: false,
+					},
+					ticks: {
+						display: false,
+					},
+					adapters: {
+						date: {
+							locale: enUS,
+						},
+					},
+					min: getDate(chartLimit).getTime(),
+				},
+				y: {
+					position: 'left',
+					stacked: true,
+					grid: {
+						display: false,
+					},
+					ticks: {
+						display: false,
+						//mirror: true,
+					},
+				},
+			},
+			interaction: {
+				intersect: false,
+				mode: 'index',
+			},
+			elements: {
+				point: {
+					hoverRadius: 5,
+					hoverBorderWidth: 2,
+				},
+			},
+			animation: false,
+			plugins: {
+				legend: {
+					display: false,
+				},
+				tooltip: {
+					enabled: false,
+					mode: 'index',
+					animation: {
+						duration: 0,
+					},
+					external: externalTooltipHandler,
+				},
+				//gradient,
+			},
+		},
+		plugins: [{
+			id: 'vLine',
+			beforeDraw(chart, args, options) {
+				if (chart.tooltip._active && chart.tooltip._active.length) {
+					const activePoint = chart.tooltip._active[0];
+					const ctx = chart.ctx;
+					const x = activePoint.element.x;
+					const topY = chart.scales.y.top;
+					const bottomY = chart.scales.y.bottom;
+
+					ctx.save();
+					ctx.beginPath();
+					ctx.moveTo(x, bottomY);
+					ctx.lineTo(x, topY);
+					ctx.lineWidth = 1;
+					ctx.strokeStyle = vLineColor;
+					ctx.stroke();
+					ctx.restore();
+				}
+			},
+		}],
+	});
+}
+
+onMounted(async () => {
+	/*
+	const magicGrid = new MagicGrid({
+		container: rootEl,
+		static: true,
+		animate: true,
+	});
+
+	magicGrid.listen();
+	*/
+
+	renderChart();
 
-onMounted(async () => {	
 	os.api('stats', {}).then(statsResponse => {
 		stats = statsResponse;
 
@@ -128,63 +354,108 @@ definePageMetadata({
 
 <style lang="scss" scoped>
 .edbbcaef {
-	.cfcdecdf {
-		display: grid;
-		grid-gap: 8px;
-		grid-template-columns: repeat(auto-fill,minmax(150px,1fr));
+	display: flex;
 
-		> .number {
-			padding: 12px 16px;
+	> .left, > .right {
+		box-sizing: border-box;
+		width: 50%;
 
-			> .label {
-				opacity: 0.7;
-				font-size: 0.8em;
-			}
+		> .container {
+			margin: 32px 0;
 
-			> .value {
-				font-weight: bold;
+			> .title {
 				font-size: 1.2em;
+				font-weight: bold;
+				margin-bottom: 16px;
+			}
 
-				> .diff {
-					font-size: 0.8em;
+			&.stats {
+				> .body {
+					display: grid;
+					grid-gap: 16px;
+					grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+
+					> .number {
+						padding: 14px 20px;
+
+						> .label {
+							opacity: 0.7;
+							font-size: 0.8em;
+						}
+
+						> .value {
+							font-weight: bold;
+							font-size: 1.5em;
+
+							> .diff {
+								font-size: 0.8em;
+							}
+						}
+					}
 				}
 			}
-		}
-	}
 
-	> .charts {
-		margin: var(--margin);
-	}
+			&.env {
+				> .body {
+					display: grid;
+					grid-gap: 16px;
+					grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
 
-	> .queue {
-		margin: var(--margin);
-		display: flex;
+					> .number {
+						padding: 14px 20px;
 
-		> .deliver,
-		> .inbox {
-			flex: 1;
-			width: 50%;
+						> .label {
+							opacity: 0.7;
+							font-size: 0.8em;
+						}
 
-			&:not(:first-child) {
-				margin-left: var(--margin);
+						> .value {
+							font-size: 1.2em;
+						}
+					}
+				}
+			}
+
+			&.charts {
+				> .body {
+					padding: 32px;
+					background: var(--panel);
+					border-radius: var(--radius);
+				}
+			}
+
+			&.federation {
+				> .body {
+					background: var(--panel);
+					border-radius: var(--radius);
+					overflow: clip;
+				}
 			}
-		}
-	}
 
-	&.max-width_740px {
-		> .queue {
-			display: block;
+			&.queue {
+				> .body {
+					padding: 32px;
+					background: var(--panel);
+					border-radius: var(--radius);
 
-			> .deliver,
-			> .inbox {
-				width: 100%;
+					&:not(:last-child) {
+						margin-bottom: 16px;
+					}
 
-				&:not(:first-child) {
-					margin-top: var(--margin);
-					margin-left: 0;
+					> .title {
+
+					}
 				}
 			}
 		}
 	}
+
+	> .left {
+		padding-right: 16px;
+	}
+
+	> .right {
+		padding-left: 16px;
+	}
 }
 </style>
diff --git a/packages/client/src/pages/admin/queue.chart.chart.vue b/packages/client/src/pages/admin/queue.chart.chart.vue
new file mode 100644
index 0000000000..dbfaf6caa4
--- /dev/null
+++ b/packages/client/src/pages/admin/queue.chart.chart.vue
@@ -0,0 +1,181 @@
+<template>
+<canvas ref="chartEl"></canvas>
+</template>
+
+<script lang="ts" setup>
+import { watch, onMounted, onUnmounted, ref } from 'vue';
+import {
+	Chart,
+	ArcElement,
+	LineElement,
+	BarElement,
+	PointElement,
+	BarController,
+	LineController,
+	CategoryScale,
+	LinearScale,
+	TimeScale,
+	Legend,
+	Title,
+	Tooltip,
+	SubTitle,
+	Filler,
+} from 'chart.js';
+import number from '@/filters/number';
+import * as os from '@/os';
+import { defaultStore } from '@/store';
+import { useChartTooltip } from '@/scripts/use-chart-tooltip';
+
+Chart.register(
+	ArcElement,
+	LineElement,
+	BarElement,
+	PointElement,
+	BarController,
+	LineController,
+	CategoryScale,
+	LinearScale,
+	TimeScale,
+	Legend,
+	Title,
+	Tooltip,
+	SubTitle,
+	Filler,
+);
+
+const props = defineProps<{
+	type: string;
+}>();
+
+const alpha = (hex, a) => {
+	const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)!;
+	const r = parseInt(result[1], 16);
+	const g = parseInt(result[2], 16);
+	const b = parseInt(result[3], 16);
+	return `rgba(${r}, ${g}, ${b}, ${a})`;
+};
+
+const chartEl = ref<HTMLCanvasElement>(null);
+
+const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
+
+// フォントカラー
+Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
+
+const { handler: externalTooltipHandler } = useChartTooltip();
+
+let chartInstance: Chart;
+
+function setData(values) {
+	if (chartInstance == null) return;
+	for (const value of values) {
+		chartInstance.data.labels.push('');
+		chartInstance.data.datasets[0].data.push(value);
+		if (chartInstance.data.datasets[0].data.length > 200) {
+			chartInstance.data.labels.shift();
+			chartInstance.data.datasets[0].data.shift();
+		}
+	}
+	chartInstance.update();
+}
+
+function pushData(value) {
+	if (chartInstance == null) return;
+	chartInstance.data.labels.push('');
+	chartInstance.data.datasets[0].data.push(value);
+	if (chartInstance.data.datasets[0].data.length > 200) {
+		chartInstance.data.labels.shift();
+		chartInstance.data.datasets[0].data.shift();
+	}
+	chartInstance.update();
+}
+
+const label =
+	props.type === 'process' ? 'Process' :
+	props.type === 'active' ? 'Active' :
+	props.type === 'delayed' ? 'Delayed' :
+	props.type === 'waiting' ? 'Waiting' :
+	'?' as never;
+
+const color =
+	props.type === 'process' ? '#00E396' :
+	props.type === 'active' ? '#00BCD4' :
+	props.type === 'delayed' ? '#E53935' :
+	props.type === 'waiting' ? '#FFB300' :
+	'?' as never;
+
+onMounted(() => {
+	chartInstance = new Chart(chartEl.value, {
+		type: 'line',
+		data: {
+			labels: [],
+			datasets: [{
+				label: label,
+				pointRadius: 0,
+				tension: 0.3,
+				borderWidth: 2,
+				borderJoinStyle: 'round',
+				borderColor: color,
+				backgroundColor: alpha(color, 0.1),
+				data: [],
+			}],
+		},
+		options: {
+			aspectRatio: 2.5,
+			layout: {
+				padding: {
+					left: 0,
+					right: 8,
+					top: 0,
+					bottom: 0,
+				},
+			},
+			scales: {
+				x: {
+					grid: {
+						display: true,
+						color: gridColor,
+						borderColor: 'rgb(0, 0, 0, 0)',
+					},
+					ticks: {
+						display: false,
+						maxTicksLimit: 10,
+					},
+				},
+				y: {
+					min: 0,
+					grid: {
+						color: gridColor,
+						borderColor: 'rgb(0, 0, 0, 0)',
+					},
+				},
+			},
+			interaction: {
+				intersect: false,
+			},
+			plugins: {
+				legend: {
+					display: false,
+				},
+				tooltip: {
+					enabled: false,
+					mode: 'index',
+					animation: {
+						duration: 0,
+					},
+					external: externalTooltipHandler,
+				},
+			},
+		},
+	});
+});
+
+defineExpose({
+	setData,
+	pushData,
+});
+</script>
+
+<style lang="scss" scoped>
+
+</style>
diff --git a/packages/client/src/pages/admin/queue.chart.vue b/packages/client/src/pages/admin/queue.chart.vue
index be63830bdd..c213037b65 100644
--- a/packages/client/src/pages/admin/queue.chart.vue
+++ b/packages/client/src/pages/admin/queue.chart.vue
@@ -1,80 +1,148 @@
 <template>
-<div class="_debobigegoItem">
-	<div class="_debobigegoLabel"><slot name="title"></slot></div>
-	<div class="_debobigegoPanel pumxzjhg">
-		<div class="_table status">
-			<div class="_row">
-				<div class="_cell"><div class="_label">Process</div>{{ number(activeSincePrevTick) }}</div>
-				<div class="_cell"><div class="_label">Active</div>{{ number(active) }}</div>
-				<div class="_cell"><div class="_label">Waiting</div>{{ number(waiting) }}</div>
-				<div class="_cell"><div class="_label">Delayed</div>{{ number(delayed) }}</div>
-			</div>
+<div class="pumxzjhg">
+	<div class="_table status">
+		<div class="_row">
+			<div class="_cell"><div class="_label">Process</div>{{ number(activeSincePrevTick) }}</div>
+			<div class="_cell"><div class="_label">Active</div>{{ number(active) }}</div>
+			<div class="_cell"><div class="_label">Waiting</div>{{ number(waiting) }}</div>
+			<div class="_cell"><div class="_label">Delayed</div>{{ number(delayed) }}</div>
+		</div>
+	</div>
+	<div class="charts">
+		<div class="chart">
+			<div class="title">Process</div>
+			<XChart ref="chartProcess" type="process"/>
 		</div>
-		<div class="">
-			<MkQueueChart :domain="domain" :connection="connection"/>
+		<div class="chart">
+			<div class="title">Active</div>
+			<XChart ref="chartActive" type="active"/>
 		</div>
-		<div class="jobs">
-			<div v-if="jobs.length > 0">
-				<div v-for="job in jobs" :key="job[0]">
-					<span>{{ job[0] }}</span>
-					<span style="margin-left: 8px; opacity: 0.7;">({{ number(job[1]) }} jobs)</span>
-				</div>
+		<div class="chart">
+			<div class="title">Delayed</div>
+			<XChart ref="chartDelayed" type="delayed"/>
+		</div>
+		<div class="chart">
+			<div class="title">Waiting</div>
+			<XChart ref="chartWaiting" type="waiting"/>
+		</div>
+	</div>
+	<div class="jobs">
+		<div v-if="jobs.length > 0">
+			<div v-for="job in jobs" :key="job[0]">
+				<span>{{ job[0] }}</span>
+				<span style="margin-left: 8px; opacity: 0.7;">({{ number(job[1]) }} jobs)</span>
 			</div>
-			<span v-else style="opacity: 0.5;">{{ $ts.noJobs }}</span>
 		</div>
+		<span v-else style="opacity: 0.5;">{{ $ts.noJobs }}</span>
 	</div>
 </div>
 </template>
 
 <script lang="ts" setup>
-import { onMounted, onUnmounted, ref } from 'vue';
+import { markRaw, onMounted, onUnmounted, ref } from 'vue';
+import XChart from './queue.chart.chart.vue';
 import number from '@/filters/number';
-import MkQueueChart from '@/components/queue-chart.vue';
 import * as os from '@/os';
+import { stream } from '@/stream';
+
+const connection = markRaw(stream.useChannel('queueStats'));
 
 const activeSincePrevTick = ref(0);
 const active = ref(0);
-const waiting = ref(0);
 const delayed = ref(0);
+const waiting = ref(0);
 const jobs = ref([]);
+let chartProcess = $ref<InstanceType<typeof XChart>>();
+let chartActive = $ref<InstanceType<typeof XChart>>();
+let chartDelayed = $ref<InstanceType<typeof XChart>>();
+let chartWaiting = $ref<InstanceType<typeof XChart>>();
 
 const props = defineProps<{
-	domain: string,
-	connection: any,
+	domain: string;
 }>();
 
+const onStats = (stats) => {
+	activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
+	active.value = stats[props.domain].active;
+	delayed.value = stats[props.domain].delayed;
+	waiting.value = stats[props.domain].waiting;
+
+	chartProcess.pushData(stats[props.domain].activeSincePrevTick);
+	chartActive.pushData(stats[props.domain].active);
+	chartDelayed.pushData(stats[props.domain].delayed);
+	chartWaiting.pushData(stats[props.domain].waiting);
+};
+
+const onStatsLog = (statsLog) => {
+	const dataProcess = [];
+	const dataActive = [];
+	const dataDelayed = [];
+	const dataWaiting = [];
+
+	for (const stats of [...statsLog].reverse()) {
+		dataProcess.push(stats[props.domain].activeSincePrevTick);
+		dataActive.push(stats[props.domain].active);
+		dataDelayed.push(stats[props.domain].delayed);
+		dataWaiting.push(stats[props.domain].waiting);
+	}
+
+	chartProcess.setData(dataProcess);
+	chartActive.setData(dataActive);
+	chartDelayed.setData(dataDelayed);
+	chartWaiting.setData(dataWaiting);
+};
+
 onMounted(() => {
 	os.api(props.domain === 'inbox' ? 'admin/queue/inbox-delayed' : props.domain === 'deliver' ? 'admin/queue/deliver-delayed' : null, {}).then(result => {
 		jobs.value = result;
 	});
 
-	const onStats = (stats) => {
-		activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
-		active.value = stats[props.domain].active;
-		waiting.value = stats[props.domain].waiting;
-		delayed.value = stats[props.domain].delayed;
-	};
-
-	props.connection.on('stats', onStats);
-
-	onUnmounted(() => {
-		props.connection.off('stats', onStats);
+	connection.on('stats', onStats);
+	connection.on('statsLog', onStatsLog);
+	connection.send('requestLog', {
+		id: Math.random().toString().substr(2, 8),
+		length: 200,
 	});
 });
+
+onUnmounted(() => {
+	connection.off('stats', onStats);
+	connection.off('statsLog', onStatsLog);
+	connection.dispose();
+});
 </script>
 
 <style lang="scss" scoped>
 .pumxzjhg {
 	> .status {
 		padding: 16px;
-		border-bottom: solid 0.5px var(--divider);
+	}
+
+	> .charts {
+		display: grid;
+		grid-template-columns: 1fr 1fr;
+		gap: 16px;
+
+		> .chart {
+			min-width: 0;
+			padding: 16px;
+			background: var(--panel);
+			border-radius: var(--radius);
+
+			> .title {
+				margin-bottom: 8px;
+			}
+		}
 	}
 
 	> .jobs {
+		margin-top: 16px;
 		padding: 16px;
-		border-top: solid 0.5px var(--divider);
 		max-height: 180px;
 		overflow: auto;
+		background: var(--panel);
+		border-radius: var(--radius);
 	}
+
 }
 </style>
diff --git a/packages/client/src/pages/admin/queue.vue b/packages/client/src/pages/admin/queue.vue
index c2865525ab..d091fe647c 100644
--- a/packages/client/src/pages/admin/queue.vue
+++ b/packages/client/src/pages/admin/queue.vue
@@ -1,14 +1,9 @@
 <template>
 <MkStickyContainer>
-	<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
+	<template #header><XHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
 	<MkSpacer :content-max="800">
-		<XQueue :connection="connection" domain="inbox">
-			<template #title>In</template>
-		</XQueue>
-		<XQueue :connection="connection" domain="deliver">
-			<template #title>Out</template>
-		</XQueue>
-		<MkButton danger @click="clear()"><i class="fas fa-trash-alt"></i> {{ i18n.ts.clearQueue }}</MkButton>
+		<XQueue v-if="tab === 'deliver'" domain="deliver"/>
+		<XQueue v-else-if="tab === 'inbox'" domain="inbox"/>
 	</MkSpacer>
 </MkStickyContainer>
 </template>
@@ -19,12 +14,11 @@ import XQueue from './queue.chart.vue';
 import XHeader from './_header_.vue';
 import MkButton from '@/components/ui/button.vue';
 import * as os from '@/os';
-import { stream } from '@/stream';
 import * as config from '@/config';
 import { i18n } from '@/i18n';
 import { definePageMetadata } from '@/scripts/page-metadata';
 
-const connection = markRaw(stream.useChannel('queueStats'));
+let tab = $ref('deliver');
 
 function clear() {
 	os.confirm({
@@ -38,19 +32,6 @@ function clear() {
 	});
 }
 
-onMounted(() => {
-	nextTick(() => {
-		connection.send('requestLog', {
-			id: Math.random().toString().substr(2, 8),
-			length: 200,
-		});
-	});
-});
-
-onBeforeUnmount(() => {
-	connection.dispose();
-});
-
 const headerActions = $computed(() => [{
 	asFullButton: true,
 	icon: 'fas fa-up-right-from-square',
@@ -60,7 +41,13 @@ const headerActions = $computed(() => [{
 	},
 }]);
 
-const headerTabs = $computed(() => []);
+const headerTabs = $computed(() => [{
+	key: 'deliver',
+	title: 'Deliver',
+}, {
+	key: 'inbox',
+	title: 'Inbox',
+}]);
 
 definePageMetadata({
 	title: i18n.ts.jobQueue,
-- 
cgit v1.2.3-freya


From ded0f6f0dfd68f448d3026163c76d9fcb83eb4f9 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 2 Jul 2022 14:00:37 +0900
Subject: refactor(client): refactoring

---
 packages/client/src/components/page-window.vue     |  1 +
 packages/client/src/pages/about-misskey.vue        |  1 -
 packages/client/src/pages/about.vue                |  1 -
 packages/client/src/pages/admin-file.vue           |  1 -
 packages/client/src/pages/admin/abuses.vue         |  1 -
 packages/client/src/pages/admin/ads.vue            |  1 -
 packages/client/src/pages/admin/announcements.vue  |  1 -
 packages/client/src/pages/admin/database.vue       |  1 -
 packages/client/src/pages/admin/email-settings.vue |  1 -
 packages/client/src/pages/admin/emojis.vue         |  1 -
 packages/client/src/pages/admin/files.vue          |  1 -
 packages/client/src/pages/admin/index.vue          |  1 -
 packages/client/src/pages/admin/instance-block.vue |  1 -
 packages/client/src/pages/admin/integrations.vue   |  1 -
 packages/client/src/pages/admin/object-storage.vue |  1 -
 packages/client/src/pages/admin/other-settings.vue |  1 -
 packages/client/src/pages/admin/overview.vue       |  1 -
 packages/client/src/pages/admin/proxy-account.vue  |  1 -
 packages/client/src/pages/admin/queue.vue          |  1 -
 packages/client/src/pages/admin/relays.vue         |  1 -
 packages/client/src/pages/admin/security.vue       |  1 -
 packages/client/src/pages/admin/settings.vue       |  1 -
 packages/client/src/pages/admin/users.vue          |  1 -
 packages/client/src/pages/announcements.vue        |  1 -
 packages/client/src/pages/antenna-timeline.vue     | 47 +++++++++++-----------
 packages/client/src/pages/channel-editor.vue       |  2 -
 packages/client/src/pages/channel.vue              |  1 -
 packages/client/src/pages/channels.vue             |  1 -
 packages/client/src/pages/clip.vue                 |  1 -
 packages/client/src/pages/drive.vue                |  1 -
 packages/client/src/pages/explore.vue              |  1 -
 packages/client/src/pages/favorites.vue            |  1 -
 packages/client/src/pages/follow-requests.vue      |  1 -
 packages/client/src/pages/gallery/edit.vue         |  2 -
 packages/client/src/pages/gallery/index.vue        |  1 -
 packages/client/src/pages/gallery/post.vue         |  1 -
 packages/client/src/pages/instance-info.vue        |  1 -
 packages/client/src/pages/messaging/index.vue      |  1 -
 packages/client/src/pages/my-antennas/create.vue   |  1 -
 packages/client/src/pages/my-antennas/index.vue    |  1 -
 packages/client/src/pages/my-clips/index.vue       |  1 -
 packages/client/src/pages/my-lists/index.vue       |  1 -
 packages/client/src/pages/my-lists/list.vue        |  1 -
 packages/client/src/pages/not-found.vue            |  1 -
 packages/client/src/pages/note.vue                 |  1 -
 packages/client/src/pages/notifications.vue        |  1 -
 .../client/src/pages/page-editor/page-editor.vue   |  3 +-
 packages/client/src/pages/pages.vue                |  1 -
 packages/client/src/pages/preview.vue              |  1 -
 packages/client/src/pages/reset-password.vue       |  1 -
 packages/client/src/pages/search.vue               |  1 -
 packages/client/src/pages/settings/accounts.vue    |  1 -
 packages/client/src/pages/settings/api.vue         |  1 -
 packages/client/src/pages/settings/apps.vue        |  1 -
 packages/client/src/pages/settings/custom-css.vue  |  1 -
 packages/client/src/pages/settings/deck.vue        |  1 -
 .../client/src/pages/settings/delete-account.vue   |  1 -
 packages/client/src/pages/settings/drive.vue       |  1 -
 packages/client/src/pages/settings/email.vue       |  1 -
 packages/client/src/pages/settings/general.vue     |  1 -
 .../client/src/pages/settings/import-export.vue    |  1 -
 packages/client/src/pages/settings/index.vue       |  1 -
 packages/client/src/pages/settings/integration.vue |  1 -
 packages/client/src/pages/settings/menu.vue        |  1 -
 packages/client/src/pages/settings/mute-block.vue  |  1 -
 .../client/src/pages/settings/notifications.vue    |  1 -
 packages/client/src/pages/settings/other.vue       |  1 -
 .../client/src/pages/settings/plugin.install.vue   |  1 -
 packages/client/src/pages/settings/plugin.vue      |  1 -
 packages/client/src/pages/settings/privacy.vue     |  1 -
 packages/client/src/pages/settings/profile.vue     |  1 -
 packages/client/src/pages/settings/reaction.vue    |  1 -
 packages/client/src/pages/settings/security.vue    |  1 -
 packages/client/src/pages/settings/sounds.vue      |  1 -
 .../client/src/pages/settings/theme.install.vue    |  1 -
 .../client/src/pages/settings/theme.manage.vue     |  1 -
 packages/client/src/pages/settings/theme.vue       |  1 -
 .../client/src/pages/settings/webhook.edit.vue     |  1 -
 packages/client/src/pages/settings/webhook.new.vue |  1 -
 packages/client/src/pages/settings/webhook.vue     |  1 -
 packages/client/src/pages/settings/word-mute.vue   |  1 -
 packages/client/src/pages/tag.vue                  |  1 -
 packages/client/src/pages/theme-editor.vue         |  1 -
 packages/client/src/pages/timeline.vue             |  1 -
 packages/client/src/pages/user-info.vue            |  1 -
 packages/client/src/pages/user-list-timeline.vue   |  1 -
 packages/client/src/pages/user/followers.vue       |  1 -
 packages/client/src/pages/user/following.vue       |  1 -
 packages/client/src/pages/user/index.vue           |  1 -
 packages/client/src/ui/universal.vue               |  2 +-
 90 files changed, 27 insertions(+), 114 deletions(-)

(limited to 'packages/client/src/pages/admin/queue.vue')

diff --git a/packages/client/src/components/page-window.vue b/packages/client/src/components/page-window.vue
index 886f480bfb..5b06c7718c 100644
--- a/packages/client/src/components/page-window.vue
+++ b/packages/client/src/components/page-window.vue
@@ -139,5 +139,6 @@ defineExpose({
 <style lang="scss" scoped>
 .yrolvcoq {
 	min-height: 100%;
+	background: var(--bg);
 }
 </style>
diff --git a/packages/client/src/pages/about-misskey.vue b/packages/client/src/pages/about-misskey.vue
index ba85860cda..fd7b5f936d 100644
--- a/packages/client/src/pages/about-misskey.vue
+++ b/packages/client/src/pages/about-misskey.vue
@@ -204,7 +204,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.aboutMisskey,
 	icon: null,
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/about.vue b/packages/client/src/pages/about.vue
index 683f7446b8..e482c4ca6d 100644
--- a/packages/client/src/pages/about.vue
+++ b/packages/client/src/pages/about.vue
@@ -131,7 +131,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: i18n.ts.instanceInfo,
 	icon: 'fas fa-info-circle',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/admin-file.vue b/packages/client/src/pages/admin-file.vue
index 402e9502d2..7bfbed35f0 100644
--- a/packages/client/src/pages/admin-file.vue
+++ b/packages/client/src/pages/admin-file.vue
@@ -117,7 +117,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: file ? i18n.ts.file + ': ' + file.name : i18n.ts.file,
 	icon: 'fas fa-file',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/admin/abuses.vue b/packages/client/src/pages/admin/abuses.vue
index 2b6dadf7c6..59d457dde7 100644
--- a/packages/client/src/pages/admin/abuses.vue
+++ b/packages/client/src/pages/admin/abuses.vue
@@ -87,7 +87,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.abuseReports,
 	icon: 'fas fa-exclamation-circle',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/admin/ads.vue b/packages/client/src/pages/admin/ads.vue
index 05557469e7..21feafc0bb 100644
--- a/packages/client/src/pages/admin/ads.vue
+++ b/packages/client/src/pages/admin/ads.vue
@@ -116,7 +116,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.ads,
 	icon: 'fas fa-audio-description',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/admin/announcements.vue b/packages/client/src/pages/admin/announcements.vue
index 025897d093..5107c2f302 100644
--- a/packages/client/src/pages/admin/announcements.vue
+++ b/packages/client/src/pages/admin/announcements.vue
@@ -102,7 +102,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.announcements,
 	icon: 'fas fa-broadcast-tower',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/admin/database.vue b/packages/client/src/pages/admin/database.vue
index b9c5f9e393..ca8718ef63 100644
--- a/packages/client/src/pages/admin/database.vue
+++ b/packages/client/src/pages/admin/database.vue
@@ -29,6 +29,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.database,
 	icon: 'fas fa-database',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/email-settings.vue b/packages/client/src/pages/admin/email-settings.vue
index c0ff94fad2..46cfd3db72 100644
--- a/packages/client/src/pages/admin/email-settings.vue
+++ b/packages/client/src/pages/admin/email-settings.vue
@@ -122,6 +122,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.emailServer,
 	icon: 'fas fa-envelope',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/emojis.vue b/packages/client/src/pages/admin/emojis.vue
index 868472ac9c..4d847daa54 100644
--- a/packages/client/src/pages/admin/emojis.vue
+++ b/packages/client/src/pages/admin/emojis.vue
@@ -292,7 +292,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: i18n.ts.customEmojis,
 	icon: 'fas fa-laugh',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/admin/files.vue b/packages/client/src/pages/admin/files.vue
index 1d037fc4e4..dd309180a7 100644
--- a/packages/client/src/pages/admin/files.vue
+++ b/packages/client/src/pages/admin/files.vue
@@ -110,7 +110,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => ({
 	title: i18n.ts.files,
 	icon: 'fas fa-cloud',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/admin/index.vue b/packages/client/src/pages/admin/index.vue
index d967a081b7..f0ac5b3fc9 100644
--- a/packages/client/src/pages/admin/index.vue
+++ b/packages/client/src/pages/admin/index.vue
@@ -41,7 +41,6 @@ const router = useRouter();
 const indexInfo = {
 	title: i18n.ts.controlPanel,
 	icon: 'fas fa-cog',
-	bg: 'var(--bg)',
 	hideHeader: true,
 };
 
diff --git a/packages/client/src/pages/admin/instance-block.vue b/packages/client/src/pages/admin/instance-block.vue
index 1aec151abb..6d479e8f0d 100644
--- a/packages/client/src/pages/admin/instance-block.vue
+++ b/packages/client/src/pages/admin/instance-block.vue
@@ -47,6 +47,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.instanceBlocking,
 	icon: 'fas fa-ban',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/integrations.vue b/packages/client/src/pages/admin/integrations.vue
index d407d440b9..9964426a68 100644
--- a/packages/client/src/pages/admin/integrations.vue
+++ b/packages/client/src/pages/admin/integrations.vue
@@ -53,6 +53,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.integration,
 	icon: 'fas fa-share-alt',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/object-storage.vue b/packages/client/src/pages/admin/object-storage.vue
index 450fd134e1..5cc3018532 100644
--- a/packages/client/src/pages/admin/object-storage.vue
+++ b/packages/client/src/pages/admin/object-storage.vue
@@ -144,6 +144,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.objectStorage,
 	icon: 'fas fa-cloud',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/other-settings.vue b/packages/client/src/pages/admin/other-settings.vue
index 59b3503c3c..ee4e8edba0 100644
--- a/packages/client/src/pages/admin/other-settings.vue
+++ b/packages/client/src/pages/admin/other-settings.vue
@@ -40,6 +40,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.other,
 	icon: 'fas fa-cogs',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/overview.vue b/packages/client/src/pages/admin/overview.vue
index f44bba27fd..316cf04f14 100644
--- a/packages/client/src/pages/admin/overview.vue
+++ b/packages/client/src/pages/admin/overview.vue
@@ -468,7 +468,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.dashboard,
 	icon: 'fas fa-tachometer-alt',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/admin/proxy-account.vue b/packages/client/src/pages/admin/proxy-account.vue
index 0c5bb1bc9f..0951d26c24 100644
--- a/packages/client/src/pages/admin/proxy-account.vue
+++ b/packages/client/src/pages/admin/proxy-account.vue
@@ -58,6 +58,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.proxyAccount,
 	icon: 'fas fa-ghost',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/queue.vue b/packages/client/src/pages/admin/queue.vue
index d091fe647c..6ccb464d17 100644
--- a/packages/client/src/pages/admin/queue.vue
+++ b/packages/client/src/pages/admin/queue.vue
@@ -52,6 +52,5 @@ const headerTabs = $computed(() => [{
 definePageMetadata({
 	title: i18n.ts.jobQueue,
 	icon: 'fas fa-clipboard-list',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/relays.vue b/packages/client/src/pages/admin/relays.vue
index 1ca4f2df09..42347c0e7d 100644
--- a/packages/client/src/pages/admin/relays.vue
+++ b/packages/client/src/pages/admin/relays.vue
@@ -78,7 +78,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.relays,
 	icon: 'fas fa-globe',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/admin/security.vue b/packages/client/src/pages/admin/security.vue
index 65b08565cd..ec11e42a7d 100644
--- a/packages/client/src/pages/admin/security.vue
+++ b/packages/client/src/pages/admin/security.vue
@@ -74,6 +74,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.security,
 	icon: 'fas fa-lock',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/settings.vue b/packages/client/src/pages/admin/settings.vue
index a5767cc2c2..496eb46ea4 100644
--- a/packages/client/src/pages/admin/settings.vue
+++ b/packages/client/src/pages/admin/settings.vue
@@ -258,6 +258,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.general,
 	icon: 'fas fa-cog',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/admin/users.vue b/packages/client/src/pages/admin/users.vue
index 3b70679a45..fc2ab3ea00 100644
--- a/packages/client/src/pages/admin/users.vue
+++ b/packages/client/src/pages/admin/users.vue
@@ -135,7 +135,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => ({
 	title: i18n.ts.users,
 	icon: 'fas fa-users',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/announcements.vue b/packages/client/src/pages/announcements.vue
index 9afaa7fd1f..aeb85b6557 100644
--- a/packages/client/src/pages/announcements.vue
+++ b/packages/client/src/pages/announcements.vue
@@ -47,7 +47,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.announcements,
 	icon: 'fas fa-broadcast-tower',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/antenna-timeline.vue b/packages/client/src/pages/antenna-timeline.vue
index 29b6066fc9..831ced4eac 100644
--- a/packages/client/src/pages/antenna-timeline.vue
+++ b/packages/client/src/pages/antenna-timeline.vue
@@ -1,17 +1,20 @@
 <template>
-<div ref="rootEl" v-hotkey.global="keymap" v-size="{ min: [800] }" class="tqmomfks">
-	<div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
-	<div class="tl _block">
-		<XTimeline
-			ref="tlEl" :key="antennaId"
-			class="tl"
-			src="antenna"
-			:antenna="antennaId"
-			:sound="true"
-			@queue="queueUpdated"
-		/>
+<MkStickyContainer>
+	<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
+	<div ref="rootEl" v-hotkey.global="keymap" v-size="{ min: [800] }" class="tqmomfks">
+		<div v-if="queue > 0" class="new"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
+		<div class="tl _block">
+			<XTimeline
+				ref="tlEl" :key="antennaId"
+				class="tl"
+				src="antenna"
+				:antenna="antennaId"
+				:sound="true"
+				@queue="queueUpdated"
+			/>
+		</div>
 	</div>
-</div>
+</MkStickyContainer>
 </template>
 
 <script lang="ts" setup>
@@ -68,23 +71,21 @@ watch(() => props.antennaId, async () => {
 	});
 }, { immediate: true });
 
-const headerActions = $computed(() => []);
+const headerActions = $computed(() => antenna ? [{
+	icon: 'fas fa-calendar-alt',
+	text: i18n.ts.jumpToSpecifiedDate,
+	handler: timetravel,
+}, {
+	icon: 'fas fa-cog',
+	text: i18n.ts.settings,
+	handler: settings,
+}] : []);
 
 const headerTabs = $computed(() => []);
 
 definePageMetadata(computed(() => antenna ? {
 	title: antenna.name,
 	icon: 'fas fa-satellite',
-	bg: 'var(--bg)',
-	actions: [{
-		icon: 'fas fa-calendar-alt',
-		text: i18n.ts.jumpToSpecifiedDate,
-		handler: timetravel,
-	}, {
-		icon: 'fas fa-cog',
-		text: i18n.ts.settings,
-		handler: settings,
-	}],
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/channel-editor.vue b/packages/client/src/pages/channel-editor.vue
index 2065bd6689..0fa1f69518 100644
--- a/packages/client/src/pages/channel-editor.vue
+++ b/packages/client/src/pages/channel-editor.vue
@@ -111,11 +111,9 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => props.channelId ? {
 	title: i18n.ts._channel.edit,
 	icon: 'fas fa-satellite-dish',
-	bg: 'var(--bg)',
 } : {
 	title: i18n.ts._channel.create,
 	icon: 'fas fa-satellite-dish',
-	bg: 'var(--bg)',
 }));
 </script>
 
diff --git a/packages/client/src/pages/channel.vue b/packages/client/src/pages/channel.vue
index 003ad5cce9..1443a9b644 100644
--- a/packages/client/src/pages/channel.vue
+++ b/packages/client/src/pages/channel.vue
@@ -80,7 +80,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => channel ? {
 	title: channel.name,
 	icon: 'fas fa-satellite-dish',
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/channels.vue b/packages/client/src/pages/channels.vue
index c48a64a1e7..63612bc57f 100644
--- a/packages/client/src/pages/channels.vue
+++ b/packages/client/src/pages/channels.vue
@@ -75,6 +75,5 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: i18n.ts.channel,
 	icon: 'fas fa-satellite-dish',
-	bg: 'var(--bg)',
 })));
 </script>
diff --git a/packages/client/src/pages/clip.vue b/packages/client/src/pages/clip.vue
index ce21b4c809..608e4ba7ee 100644
--- a/packages/client/src/pages/clip.vue
+++ b/packages/client/src/pages/clip.vue
@@ -102,7 +102,6 @@ const headerActions = $computed(() => clip && isOwned ? [{
 definePageMetadata(computed(() => clip ? {
 	title: clip.name,
 	icon: 'fas fa-paperclip',
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/drive.vue b/packages/client/src/pages/drive.vue
index c7bc31135c..988a1bf3df 100644
--- a/packages/client/src/pages/drive.vue
+++ b/packages/client/src/pages/drive.vue
@@ -20,7 +20,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => ({
 	title: folder ? folder.name : i18n.ts.drive,
 	icon: 'fas fa-cloud',
-	bg: 'var(--bg)',
 	hideHeader: true,
 })));
 </script>
diff --git a/packages/client/src/pages/explore.vue b/packages/client/src/pages/explore.vue
index c59fb639d4..981660cbfe 100644
--- a/packages/client/src/pages/explore.vue
+++ b/packages/client/src/pages/explore.vue
@@ -87,6 +87,5 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: i18n.ts.explore,
 	icon: 'fas fa-hashtag',
-	bg: 'var(--bg)',
 })));
 </script>
diff --git a/packages/client/src/pages/favorites.vue b/packages/client/src/pages/favorites.vue
index 6efca4c221..6f75d68def 100644
--- a/packages/client/src/pages/favorites.vue
+++ b/packages/client/src/pages/favorites.vue
@@ -38,7 +38,6 @@ const pagingComponent = ref<InstanceType<typeof MkPagination>>();
 definePageMetadata({
 	title: i18n.ts.favorites,
 	icon: 'fas fa-star',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/follow-requests.vue b/packages/client/src/pages/follow-requests.vue
index e6f9a9a5d9..f21c68c4c7 100644
--- a/packages/client/src/pages/follow-requests.vue
+++ b/packages/client/src/pages/follow-requests.vue
@@ -65,7 +65,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => ({
 	title: i18n.ts.followRequests,
 	icon: 'fas fa-user-clock',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/gallery/edit.vue b/packages/client/src/pages/gallery/edit.vue
index 1de8328fea..f8a5d54f71 100644
--- a/packages/client/src/pages/gallery/edit.vue
+++ b/packages/client/src/pages/gallery/edit.vue
@@ -116,11 +116,9 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => props.postId ? {
 	title: i18n.ts.edit,
 	icon: 'fas fa-pencil-alt',
-	bg: 'var(--bg)',
 } : {
 	title: i18n.ts.postToGallery,
 	icon: 'fas fa-pencil-alt',
-	bg: 'var(--bg)',
 }));
 </script>
 
diff --git a/packages/client/src/pages/gallery/index.vue b/packages/client/src/pages/gallery/index.vue
index 1eb6ce22f8..6b406af742 100644
--- a/packages/client/src/pages/gallery/index.vue
+++ b/packages/client/src/pages/gallery/index.vue
@@ -122,7 +122,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata({
 	title: i18n.ts.gallery,
 	icon: 'fas fa-icons',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/gallery/post.vue b/packages/client/src/pages/gallery/post.vue
index 6651c3e28f..e16ccc3150 100644
--- a/packages/client/src/pages/gallery/post.vue
+++ b/packages/client/src/pages/gallery/post.vue
@@ -149,7 +149,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => post ? {
 	title: post.title,
 	avatar: post.user,
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/instance-info.vue b/packages/client/src/pages/instance-info.vue
index 83f3354df1..b97ebb3e3d 100644
--- a/packages/client/src/pages/instance-info.vue
+++ b/packages/client/src/pages/instance-info.vue
@@ -215,7 +215,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata({
 	title: props.host,
 	icon: 'fas fa-server',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/messaging/index.vue b/packages/client/src/pages/messaging/index.vue
index bf9ac056cf..7df4c846fb 100644
--- a/packages/client/src/pages/messaging/index.vue
+++ b/packages/client/src/pages/messaging/index.vue
@@ -159,7 +159,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.messaging,
 	icon: 'fas fa-comments',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/my-antennas/create.vue b/packages/client/src/pages/my-antennas/create.vue
index e792834a89..dc10bece81 100644
--- a/packages/client/src/pages/my-antennas/create.vue
+++ b/packages/client/src/pages/my-antennas/create.vue
@@ -38,7 +38,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.manageAntennas,
 	icon: 'fas fa-satellite',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/my-antennas/index.vue b/packages/client/src/pages/my-antennas/index.vue
index 2cdb26031f..70e444da52 100644
--- a/packages/client/src/pages/my-antennas/index.vue
+++ b/packages/client/src/pages/my-antennas/index.vue
@@ -34,7 +34,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.manageAntennas,
 	icon: 'fas fa-satellite',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/my-clips/index.vue b/packages/client/src/pages/my-clips/index.vue
index 6434b0c004..ac5a3578f8 100644
--- a/packages/client/src/pages/my-clips/index.vue
+++ b/packages/client/src/pages/my-clips/index.vue
@@ -69,7 +69,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.clip,
 	icon: 'fas fa-paperclip',
-	bg: 'var(--bg)',
 	action: {
 		icon: 'fas fa-plus',
 		handler: create,
diff --git a/packages/client/src/pages/my-lists/index.vue b/packages/client/src/pages/my-lists/index.vue
index 411826a950..03b638151e 100644
--- a/packages/client/src/pages/my-lists/index.vue
+++ b/packages/client/src/pages/my-lists/index.vue
@@ -46,7 +46,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.manageLists,
 	icon: 'fas fa-list-ul',
-	bg: 'var(--bg)',
 	action: {
 		icon: 'fas fa-plus',
 		handler: create,
diff --git a/packages/client/src/pages/my-lists/list.vue b/packages/client/src/pages/my-lists/list.vue
index 6e76c4a7d5..5bc0bf41dd 100644
--- a/packages/client/src/pages/my-lists/list.vue
+++ b/packages/client/src/pages/my-lists/list.vue
@@ -120,7 +120,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => list ? {
 	title: list.name,
 	icon: 'fas fa-list-ul',
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/not-found.vue b/packages/client/src/pages/not-found.vue
index 955fbbccfd..a819cce961 100644
--- a/packages/client/src/pages/not-found.vue
+++ b/packages/client/src/pages/not-found.vue
@@ -18,6 +18,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.notFound,
 	icon: 'fas fa-exclamation-triangle',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/note.vue b/packages/client/src/pages/note.vue
index 852b821573..7c936cc629 100644
--- a/packages/client/src/pages/note.vue
+++ b/packages/client/src/pages/note.vue
@@ -132,7 +132,6 @@ definePageMetadata(computed(() => note ? {
 		title: i18n.t('noteOf', { user: note.user.name }),
 		text: note.text,
 	},
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/notifications.vue b/packages/client/src/pages/notifications.vue
index 3df1a3f17f..acf338c2c2 100644
--- a/packages/client/src/pages/notifications.vue
+++ b/packages/client/src/pages/notifications.vue
@@ -91,6 +91,5 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: i18n.ts.notifications,
 	icon: 'fas fa-bell',
-	bg: 'var(--bg)',
 })));
 </script>
diff --git a/packages/client/src/pages/page-editor/page-editor.vue b/packages/client/src/pages/page-editor/page-editor.vue
index c38286c1d3..3ce48e89f4 100644
--- a/packages/client/src/pages/page-editor/page-editor.vue
+++ b/packages/client/src/pages/page-editor/page-editor.vue
@@ -439,8 +439,7 @@ definePageMetadata(computed(() => {
 	return {
 		title: title,
 		icon: 'fas fa-pencil-alt',
-		bg: 'var(--bg)',
-	};
+		};
 }));
 </script>
 
diff --git a/packages/client/src/pages/pages.vue b/packages/client/src/pages/pages.vue
index 16aeae2f56..62c675e41e 100644
--- a/packages/client/src/pages/pages.vue
+++ b/packages/client/src/pages/pages.vue
@@ -77,7 +77,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: i18n.ts.pages,
 	icon: 'fas fa-sticky-note',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/preview.vue b/packages/client/src/pages/preview.vue
index cba7589a38..8f211081dd 100644
--- a/packages/client/src/pages/preview.vue
+++ b/packages/client/src/pages/preview.vue
@@ -17,7 +17,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => ({
 	title: i18n.ts.preview,
 	icon: 'fas fa-eye',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/reset-password.vue b/packages/client/src/pages/reset-password.vue
index 39a1191caf..10c41f2d21 100644
--- a/packages/client/src/pages/reset-password.vue
+++ b/packages/client/src/pages/reset-password.vue
@@ -51,7 +51,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.resetPassword,
 	icon: 'fas fa-lock',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/search.vue b/packages/client/src/pages/search.vue
index 25fef7af50..404b9e3dbd 100644
--- a/packages/client/src/pages/search.vue
+++ b/packages/client/src/pages/search.vue
@@ -34,6 +34,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => ({
 	title: i18n.t('searchWith', { q: props.query }),
 	icon: 'fas fa-search',
-	bg: 'var(--bg)',
 })));
 </script>
diff --git a/packages/client/src/pages/settings/accounts.vue b/packages/client/src/pages/settings/accounts.vue
index 47b816243f..d1e71c4548 100644
--- a/packages/client/src/pages/settings/accounts.vue
+++ b/packages/client/src/pages/settings/accounts.vue
@@ -109,7 +109,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.accounts,
 	icon: 'fas fa-users',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/api.vue b/packages/client/src/pages/settings/api.vue
index d94862712e..b8a2dedb5a 100644
--- a/packages/client/src/pages/settings/api.vue
+++ b/packages/client/src/pages/settings/api.vue
@@ -42,6 +42,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: 'API',
 	icon: 'fas fa-key',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/apps.vue b/packages/client/src/pages/settings/apps.vue
index 673e91fe6b..10ecbc795d 100644
--- a/packages/client/src/pages/settings/apps.vue
+++ b/packages/client/src/pages/settings/apps.vue
@@ -67,7 +67,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.installedApps,
 	icon: 'fas fa-plug',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/custom-css.vue b/packages/client/src/pages/settings/custom-css.vue
index 3e032be257..d5000d3973 100644
--- a/packages/client/src/pages/settings/custom-css.vue
+++ b/packages/client/src/pages/settings/custom-css.vue
@@ -42,6 +42,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.customCss,
 	icon: 'fas fa-code',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/deck.vue b/packages/client/src/pages/settings/deck.vue
index 295357377e..b1cf8a8cc9 100644
--- a/packages/client/src/pages/settings/deck.vue
+++ b/packages/client/src/pages/settings/deck.vue
@@ -73,6 +73,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.deck,
 	icon: 'fas fa-columns',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/delete-account.vue b/packages/client/src/pages/settings/delete-account.vue
index a587c32998..3c4ea716ce 100644
--- a/packages/client/src/pages/settings/delete-account.vue
+++ b/packages/client/src/pages/settings/delete-account.vue
@@ -48,6 +48,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts._accountDelete.accountDelete,
 	icon: 'fas fa-exclamation-triangle',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/drive.vue b/packages/client/src/pages/settings/drive.vue
index 73c0384f1f..cec2dc4d5f 100644
--- a/packages/client/src/pages/settings/drive.vue
+++ b/packages/client/src/pages/settings/drive.vue
@@ -101,7 +101,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.drive,
 	icon: 'fas fa-cloud',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/email.vue b/packages/client/src/pages/settings/email.vue
index 8b67ff34dd..e575af6d6b 100644
--- a/packages/client/src/pages/settings/email.vue
+++ b/packages/client/src/pages/settings/email.vue
@@ -107,6 +107,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.email,
 	icon: 'fas fa-envelope',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/general.vue b/packages/client/src/pages/settings/general.vue
index e7339af14e..74fa0bc926 100644
--- a/packages/client/src/pages/settings/general.vue
+++ b/packages/client/src/pages/settings/general.vue
@@ -186,6 +186,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.general,
 	icon: 'fas fa-cogs',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/import-export.vue b/packages/client/src/pages/settings/import-export.vue
index 49d8a80b38..d48dab9f8d 100644
--- a/packages/client/src/pages/settings/import-export.vue
+++ b/packages/client/src/pages/settings/import-export.vue
@@ -155,7 +155,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.importAndExport,
 	icon: 'fas fa-boxes',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/index.vue b/packages/client/src/pages/settings/index.vue
index 8143298cc5..8e445a77d7 100644
--- a/packages/client/src/pages/settings/index.vue
+++ b/packages/client/src/pages/settings/index.vue
@@ -42,7 +42,6 @@ const props = withDefaults(defineProps<{
 const indexInfo = {
 	title: i18n.ts.settings,
 	icon: 'fas fa-cog',
-	bg: 'var(--bg)',
 	hideHeader: true,
 };
 const INFO = ref(indexInfo);
diff --git a/packages/client/src/pages/settings/integration.vue b/packages/client/src/pages/settings/integration.vue
index 7de151040e..ccb02e08a2 100644
--- a/packages/client/src/pages/settings/integration.vue
+++ b/packages/client/src/pages/settings/integration.vue
@@ -95,6 +95,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.integration,
 	icon: 'fas fa-share-alt',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/menu.vue b/packages/client/src/pages/settings/menu.vue
index 1b4d8799c8..076654c105 100644
--- a/packages/client/src/pages/settings/menu.vue
+++ b/packages/client/src/pages/settings/menu.vue
@@ -83,6 +83,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.menu,
 	icon: 'fas fa-list-ul',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/mute-block.vue b/packages/client/src/pages/settings/mute-block.vue
index d8cb286626..397a0c815c 100644
--- a/packages/client/src/pages/settings/mute-block.vue
+++ b/packages/client/src/pages/settings/mute-block.vue
@@ -57,6 +57,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.muteAndBlock,
 	icon: 'fas fa-ban',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/notifications.vue b/packages/client/src/pages/settings/notifications.vue
index 494a3eebe0..d2a363965a 100644
--- a/packages/client/src/pages/settings/notifications.vue
+++ b/packages/client/src/pages/settings/notifications.vue
@@ -56,6 +56,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.notifications,
 	icon: 'fas fa-bell',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/other.vue b/packages/client/src/pages/settings/other.vue
index 283d87a066..52ef4d401f 100644
--- a/packages/client/src/pages/settings/other.vue
+++ b/packages/client/src/pages/settings/other.vue
@@ -41,6 +41,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.other,
 	icon: 'fas fa-ellipsis-h',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/plugin.install.vue b/packages/client/src/pages/settings/plugin.install.vue
index 7ff55e9d83..a4cab4b7a4 100644
--- a/packages/client/src/pages/settings/plugin.install.vue
+++ b/packages/client/src/pages/settings/plugin.install.vue
@@ -120,6 +120,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts._plugin.install,
 	icon: 'fas fa-download',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/plugin.vue b/packages/client/src/pages/settings/plugin.vue
index 75cf42bb89..8e773b7990 100644
--- a/packages/client/src/pages/settings/plugin.vue
+++ b/packages/client/src/pages/settings/plugin.vue
@@ -90,7 +90,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.plugins,
 	icon: 'fas fa-plug',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/privacy.vue b/packages/client/src/pages/settings/privacy.vue
index 4d509efe28..be9e34cdfb 100644
--- a/packages/client/src/pages/settings/privacy.vue
+++ b/packages/client/src/pages/settings/privacy.vue
@@ -96,6 +96,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.privacy,
 	icon: 'fas fa-lock-open',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/profile.vue b/packages/client/src/pages/settings/profile.vue
index b662de9e3d..6b60148df5 100644
--- a/packages/client/src/pages/settings/profile.vue
+++ b/packages/client/src/pages/settings/profile.vue
@@ -183,7 +183,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.profile,
 	icon: 'fas fa-user',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/reaction.vue b/packages/client/src/pages/settings/reaction.vue
index d0fdf835cf..382e1b081e 100644
--- a/packages/client/src/pages/settings/reaction.vue
+++ b/packages/client/src/pages/settings/reaction.vue
@@ -131,7 +131,6 @@ definePageMetadata({
 		icon: 'fas fa-eye',
 		handler: preview,
 	},
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/security.vue b/packages/client/src/pages/settings/security.vue
index 57880ef3dd..eb3efa9afb 100644
--- a/packages/client/src/pages/settings/security.vue
+++ b/packages/client/src/pages/settings/security.vue
@@ -104,7 +104,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.security,
 	icon: 'fas fa-lock',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/sounds.vue b/packages/client/src/pages/settings/sounds.vue
index bb23257d7a..f29c9eb049 100644
--- a/packages/client/src/pages/settings/sounds.vue
+++ b/packages/client/src/pages/settings/sounds.vue
@@ -131,6 +131,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.sounds,
 	icon: 'fas fa-music',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/theme.install.vue b/packages/client/src/pages/settings/theme.install.vue
index 6a863ed9e6..2994d8fb1a 100644
--- a/packages/client/src/pages/settings/theme.install.vue
+++ b/packages/client/src/pages/settings/theme.install.vue
@@ -76,6 +76,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts._theme.install,
 	icon: 'fas fa-download',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/theme.manage.vue b/packages/client/src/pages/settings/theme.manage.vue
index 68cbf3c353..9d28b4a316 100644
--- a/packages/client/src/pages/settings/theme.manage.vue
+++ b/packages/client/src/pages/settings/theme.manage.vue
@@ -74,6 +74,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts._theme.manage,
 	icon: 'fas fa-folder-open',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/theme.vue b/packages/client/src/pages/settings/theme.vue
index d4c23e07b0..6e7a5ff3a3 100644
--- a/packages/client/src/pages/settings/theme.vue
+++ b/packages/client/src/pages/settings/theme.vue
@@ -152,7 +152,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.theme,
 	icon: 'fas fa-palette',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/settings/webhook.edit.vue b/packages/client/src/pages/settings/webhook.edit.vue
index d3cf5d7b79..618250958b 100644
--- a/packages/client/src/pages/settings/webhook.edit.vue
+++ b/packages/client/src/pages/settings/webhook.edit.vue
@@ -86,6 +86,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: 'Edit webhook',
 	icon: 'fas fa-bolt',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/webhook.new.vue b/packages/client/src/pages/settings/webhook.new.vue
index 508c0d78be..fa96c5fa4b 100644
--- a/packages/client/src/pages/settings/webhook.new.vue
+++ b/packages/client/src/pages/settings/webhook.new.vue
@@ -78,6 +78,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: 'Create new webhook',
 	icon: 'fas fa-bolt',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/webhook.vue b/packages/client/src/pages/settings/webhook.vue
index 50739e2fd1..ef9b9b56f7 100644
--- a/packages/client/src/pages/settings/webhook.vue
+++ b/packages/client/src/pages/settings/webhook.vue
@@ -49,6 +49,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: 'Webhook',
 	icon: 'fas fa-bolt',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/settings/word-mute.vue b/packages/client/src/pages/settings/word-mute.vue
index c6af0e7661..5fee7cd35a 100644
--- a/packages/client/src/pages/settings/word-mute.vue
+++ b/packages/client/src/pages/settings/word-mute.vue
@@ -124,6 +124,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.wordMute,
 	icon: 'fas fa-comment-slash',
-	bg: 'var(--bg)',
 });
 </script>
diff --git a/packages/client/src/pages/tag.vue b/packages/client/src/pages/tag.vue
index d63864ed5c..406eb1c988 100644
--- a/packages/client/src/pages/tag.vue
+++ b/packages/client/src/pages/tag.vue
@@ -28,6 +28,5 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => ({
 	title: props.tag,
 	icon: 'fas fa-hashtag',
-	bg: 'var(--bg)',
 })));
 </script>
diff --git a/packages/client/src/pages/theme-editor.vue b/packages/client/src/pages/theme-editor.vue
index 3525543531..cec3833594 100644
--- a/packages/client/src/pages/theme-editor.vue
+++ b/packages/client/src/pages/theme-editor.vue
@@ -224,7 +224,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata({
 	title: i18n.ts.themeEditor,
 	icon: 'fas fa-palette',
-	bg: 'var(--bg)',
 });
 </script>
 
diff --git a/packages/client/src/pages/timeline.vue b/packages/client/src/pages/timeline.vue
index 004c29c56b..40eb85ff43 100644
--- a/packages/client/src/pages/timeline.vue
+++ b/packages/client/src/pages/timeline.vue
@@ -151,7 +151,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: i18n.ts.timeline,
 	icon: src === 'local' ? 'fas fa-comments' : src === 'social' ? 'fas fa-share-alt' : src === 'global' ? 'fas fa-globe' : 'fas fa-home',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/user-info.vue b/packages/client/src/pages/user-info.vue
index b3292290ea..cfea2637b7 100644
--- a/packages/client/src/pages/user-info.vue
+++ b/packages/client/src/pages/user-info.vue
@@ -309,7 +309,6 @@ const headerTabs = $computed(() => [{
 definePageMetadata(computed(() => ({
 	title: user ? acct(user) : i18n.ts.userInfo,
 	icon: 'fas fa-info-circle',
-	bg: 'var(--bg)',
 })));
 </script>
 
diff --git a/packages/client/src/pages/user-list-timeline.vue b/packages/client/src/pages/user-list-timeline.vue
index 07d5a166e9..593db1dea7 100644
--- a/packages/client/src/pages/user-list-timeline.vue
+++ b/packages/client/src/pages/user-list-timeline.vue
@@ -79,7 +79,6 @@ const headerTabs = $computed(() => []);
 definePageMetadata(computed(() => list ? {
 	title: list.name,
 	icon: 'fas fa-list-ul',
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/user/followers.vue b/packages/client/src/pages/user/followers.vue
index 3feec15e4a..c0c0e01d7f 100644
--- a/packages/client/src/pages/user/followers.vue
+++ b/packages/client/src/pages/user/followers.vue
@@ -54,7 +54,6 @@ definePageMetadata(computed(() => user ? {
 	subtitle: i18n.ts.followers,
 	userName: user,
 	avatar: user,
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/user/following.vue b/packages/client/src/pages/user/following.vue
index 0c6bb1c9f4..d1753fe7d5 100644
--- a/packages/client/src/pages/user/following.vue
+++ b/packages/client/src/pages/user/following.vue
@@ -54,7 +54,6 @@ definePageMetadata(computed(() => user ? {
 	subtitle: i18n.ts.following,
 	userName: user,
 	avatar: user,
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/pages/user/index.vue b/packages/client/src/pages/user/index.vue
index bd1bb11a5b..99c3413882 100644
--- a/packages/client/src/pages/user/index.vue
+++ b/packages/client/src/pages/user/index.vue
@@ -103,7 +103,6 @@ definePageMetadata(computed(() => user ? {
 	share: {
 		title: user.name,
 	},
-	bg: 'var(--bg)',
 } : null));
 </script>
 
diff --git a/packages/client/src/ui/universal.vue b/packages/client/src/ui/universal.vue
index 41d59342bd..3614f7de53 100644
--- a/packages/client/src/ui/universal.vue
+++ b/packages/client/src/ui/universal.vue
@@ -234,7 +234,7 @@ const wallpaper = localStorage.getItem('wallpaper') != null;
 	> .contents {
 		width: 100%;
 		min-width: 0;
-		background: var(--panel);
+		background: var(--bg);
 
 		> main {
 			min-width: 0;
-- 
cgit v1.2.3-freya

