From 97165fbaf5c108d3feb0046e6cf742b63b3d88e6 Mon Sep 17 00:00:00 2001
From: syuilo <syuilotan@yahoo.co.jp>
Date: Sat, 5 Dec 2020 18:18:37 +0900
Subject: [PATCH] =?UTF-8?q?=E3=83=88=E3=83=83=E3=83=97=E3=83=9A=E3=83=BC?=
 =?UTF-8?q?=E3=82=B8=E3=82=92=E5=BC=B7=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/client/pages/welcome.entrance.vue | 100 +++++++++++++++++++++++---
 src/client/ui/visitor/b.vue           |   6 ++
 src/server/api/endpoints/stats.ts     |  11 ++-
 3 files changed, 107 insertions(+), 10 deletions(-)

diff --git a/src/client/pages/welcome.entrance.vue b/src/client/pages/welcome.entrance.vue
index 2ce357e205..550d9fe6ec 100644
--- a/src/client/pages/welcome.entrance.vue
+++ b/src/client/pages/welcome.entrance.vue
@@ -1,9 +1,27 @@
 <template>
 <div class="rsqzvsbo _section" v-if="meta">
-	<h2># {{ $t('pinnedNotes') }}</h2>
-	<MkPagination :pagination="pagination" #default="{items}">
-		<XNote class="kmkqjgkl" v-for="note in items" :note="note" :key="note.id"/>
-	</MkPagination>
+	<div class="overview _monospace" v-if="stats">
+		<div class="stats">
+			<div><span>Users</span><span>{{ number(stats.originalUsersCount) }}</span></div>
+			<div><span>Notes</span><span>{{ number(stats.originalNotesCount) }}</span></div>
+			<div><span>Reactions</span><span>{{ number(stats.reactionsCount) }}</span></div>
+		</div>
+		<div class="tags">
+			<MkA class="tag" v-for="tag in tags" :to="`/tags/${encodeURIComponent(tag.tag)}`">#{{ tag.tag }}</MkA>
+		</div>
+	</div>
+	<template v-if="meta.pinnedClipId">
+		<h2># {{ $t('pinnedNotes') }}</h2>
+		<MkPagination :pagination="clipPagination" #default="{items}">
+			<XNote class="kmkqjgkl" v-for="note in items" :note="note" :key="note.id"/>
+		</MkPagination>
+	</template>
+	<template v-else>
+		<h2># {{ $t('featured') }}</h2>
+		<MkPagination :pagination="featuredPagination" #default="{items}">
+			<XNote class="kmkqjgkl" v-for="note in items" :note="note" :key="note.id"/>
+		</MkPagination>
+	</template>
 </div>
 </template>
 
@@ -17,6 +35,7 @@ import XNote from '@/components/note.vue';
 import MkPagination from '@/components/ui/pagination.vue';
 import { host, instanceName } from '@/config';
 import * as os from '@/os';
+import number from '@/filters/number';
 
 export default defineComponent({
 	components: {
@@ -30,13 +49,20 @@ export default defineComponent({
 			host: toUnicode(host),
 			instanceName,
 			meta: null,
-			pagination: {
+			stats: null,
+			tags: [],
+			clipPagination: {
 				endpoint: 'clips/notes',
 				limit: 10,
 				params: () => ({
 					clipId: this.meta.pinnedClipId,
 				})
 			},
+			featuredPagination: {
+				endpoint: 'notes/featured',
+				limit: 10,
+				offsetMode: true
+			},
 		};
 	},
 
@@ -48,6 +74,13 @@ export default defineComponent({
 		os.api('stats').then(stats => {
 			this.stats = stats;
 		});
+
+		os.api('hashtags/list', {
+			sort: '+mentionedLocalUsers',
+			limit: 8
+		}).then(tags => {
+			this.tags = tags;
+		});
 	},
 
 	methods: {
@@ -61,7 +94,9 @@ export default defineComponent({
 			os.popup(XSignupDialog, {
 				autoSet: true
 			}, {}, 'closed');
-		}
+		},
+
+		number
 	}
 });
 </script>
@@ -77,15 +112,64 @@ export default defineComponent({
 		padding: 8px 12px;
 		background: rgba(0, 0, 0, 0.5);
 	}
+
+	> .overview {
+		> .stats, > .tags {
+			display: inline-block;
+			vertical-align: top;
+			width: 530px;
+			padding: 32px;
+			margin: 16px;
+			box-sizing: border-box;
+
+			@media (max-width: 800px) {
+				display: block;
+				width: 100%;
+				margin: 12px 0;
+			}
+		}
+
+		> .stats {
+			background: var(--accent);
+			border-radius: 12px;
+			color: #fff;
+			font-size: 1.5em;
+
+			> div {
+				display: flex;
+
+				> span:first-child {
+					opacity: 0.7;
+					font-weight: bold;
+				}
+
+				> span:last-child {
+					margin-left: auto;
+				}
+			}
+		}
+
+		> .tags {
+			background: var(--panel);
+			border-radius: 12px;
+			color: var(--fg);
+			font-size: 1.5em;
+
+			> .tag {
+				margin-right: 1em;
+			}
+		}
+	}
 }
 
 .kmkqjgkl {
 	display: inline-block;
 	vertical-align: middle;
-	width: 600px;
+	width: 530px;
 	margin: 16px;
+	box-sizing: border-box;
 	text-align: left;
-	box-shadow: 0 6px 46px rgb(0 0 0 / 30%);
+	box-shadow: 0 6px 46px rgb(0 0 0 / 25%);
 	border-radius: 12px;
 
 	@media (max-width: 800px) {
diff --git a/src/client/ui/visitor/b.vue b/src/client/ui/visitor/b.vue
index 4f7a7f8956..efef2ade3c 100644
--- a/src/client/ui/visitor/b.vue
+++ b/src/client/ui/visitor/b.vue
@@ -1,5 +1,7 @@
 <template>
 <div class="mk-app" :style="{ backgroundImage: root ? `url(${ $store.state.instance.meta.backgroundImageUrl })` : 'none' }">
+	<a href="https://github.com/syuilo/misskey" target="_blank" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:var(--panel); color:var(--fg); position: fixed; z-index: 10; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a>
+
 	<div class="side" v-if="!narrow">
 		<XKanban class="kanban" full :transparent="root" :powered-by="root"/>
 	</div>
@@ -160,6 +162,10 @@ export default defineComponent({
 });
 </script>
 
+<style>
+.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}
+</style>
+
 <style lang="scss" scoped>
 .tray-enter-active,
 .tray-leave-active {
diff --git a/src/server/api/endpoints/stats.ts b/src/server/api/endpoints/stats.ts
index dab05c1675..955a791948 100644
--- a/src/server/api/endpoints/stats.ts
+++ b/src/server/api/endpoints/stats.ts
@@ -1,5 +1,5 @@
 import define from '../define';
-import { Notes, Users } from '../../../models';
+import { NoteReactions, Notes, Users } from '../../../models';
 import { federationChart, driveChart } from '../../../services/chart';
 
 export const meta = {
@@ -48,10 +48,13 @@ export const meta = {
 };
 
 export default define(meta, async () => {
-	const [notesCount,
+	const [
+		notesCount,
 		originalNotesCount,
 		usersCount,
 		originalUsersCount,
+		reactionsCount,
+		//originalReactionsCount,
 		instances,
 		driveUsageLocal,
 		driveUsageRemote
@@ -60,6 +63,8 @@ export default define(meta, async () => {
 		Notes.count({ where: { userHost: null }, cache: 3600000 }),
 		Users.count({ cache: 3600000 }),
 		Users.count({ where: { host: null }, cache: 3600000 }),
+		NoteReactions.count({ cache: 3600000 }), // 1 hour
+		//NoteReactions.count({ where: { userHost: null }, cache: 3600000 }),
 		federationChart.getChart('hour', 1, null).then(chart => chart.instance.total[0]),
 		driveChart.getChart('hour', 1, null).then(chart => chart.local.totalSize[0]),
 		driveChart.getChart('hour', 1, null).then(chart => chart.remote.totalSize[0]),
@@ -70,6 +75,8 @@ export default define(meta, async () => {
 		originalNotesCount,
 		usersCount,
 		originalUsersCount,
+		reactionsCount,
+		//originalReactionsCount,
 		instances,
 		driveUsageLocal,
 		driveUsageRemote