From 42f3d9188bb1428ed4978ca0974f49e754d7f7d1 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sun, 22 Jan 2023 20:22:38 +0900
Subject: [PATCH] add a secret achievement

---
 locales/ja-JP.yml                             |   3 +
 .../backend/src/core/AchievementService.ts    |   1 +
 packages/frontend/src/pages/about-misskey.vue | 122 +++++++++++-------
 packages/frontend/src/scripts/achievements.ts |   8 +-
 4 files changed, 88 insertions(+), 46 deletions(-)

diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 57296b985..cd4438fde 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1105,6 +1105,9 @@ _achievements:
       title: "I Love Misskey"
       description: "\"I ❤ #Misskey\"を投稿した"
       flavor: "Misskeyを使ってくださりありがとうございます! by 開発チーム"
+    _foundTreasure:
+      title: "宝探し"
+      description: "隠されたお宝を発見した"
     _client30min:
       title: "ひとやすみ"
       description: "クライアントを起動してから30分以上経過した"
diff --git a/packages/backend/src/core/AchievementService.ts b/packages/backend/src/core/AchievementService.ts
index be763e462..2536ea34e 100644
--- a/packages/backend/src/core/AchievementService.ts
+++ b/packages/backend/src/core/AchievementService.ts
@@ -62,6 +62,7 @@ const ACHIEVEMENT_TYPES = [
 	'collectAchievements30',
 	'viewAchievements3min',
 	'iLoveMisskey',
+	'foundTreasure',
 	'client30min',
 	'noteDeletedWithin1min',
 	'postedAtLateNight',
diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue
index 1c3535a83..a6d4c6065 100644
--- a/packages/frontend/src/pages/about-misskey.vue
+++ b/packages/frontend/src/pages/about-misskey.vue
@@ -4,11 +4,14 @@
 	<div style="overflow: clip;">
 		<MkSpacer :content-max="600" :margin-min="20">
 			<div class="_gaps_m znqjceqz">
-				<div ref="containerEl" v-panel class="about" :class="{ playing: easterEggEngine != null }">
-					<img src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/>
-					<div class="misskey">Misskey</div>
-					<div class="version">v{{ version }}</div>
-					<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :is-reaction="false" :normal="true" :no-style="true"/></span>
+				<div v-panel class="about">
+					<div ref="containerEl" class="container" :class="{ playing: easterEggEngine != null }">
+						<img src="/client-assets/about-icon.png" alt="" class="icon" draggable="false" @load="iconLoaded" @click="gravity"/>
+						<div class="misskey">Misskey</div>
+						<div class="version">v{{ version }}</div>
+						<span v-for="emoji in easterEggEmojis" :key="emoji.id" class="emoji" :data-physics-x="emoji.left" :data-physics-y="emoji.top" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }"><MkEmoji class="emoji" :emoji="emoji.emoji" :is-reaction="false" :normal="true" :no-style="true"/></span>
+					</div>
+					<button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button>
 				</div>
 				<div style="text-align: center;">
 					{{ i18n.ts._aboutMisskey.about }}<br><a href="https://misskey-hub.net/docs/misskey.html" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a>
@@ -70,6 +73,8 @@ import { i18n } from '@/i18n';
 import { defaultStore } from '@/store';
 import * as os from '@/os';
 import { definePageMetadata } from '@/scripts/page-metadata';
+import { claimAchievement, claimedAchievements } from '@/scripts/achievements';
+import { $i } from '@/account';
 
 const patrons = [
 	'まっちゃとーにゅ',
@@ -152,6 +157,8 @@ const patrons = [
 	'pixeldesu',
 ];
 
+let thereIsTreasure = $ref($i && !claimedAchievements.includes('foundTreasure'));
+
 let easterEggReady = false;
 let easterEggEmojis = $ref([]);
 let easterEggEngine = $ref(null);
@@ -187,6 +194,11 @@ function iLoveMisskey() {
 	});
 }
 
+function getTreasure() {
+	thereIsTreasure = false;
+	claimAchievement('foundTreasure');
+}
+
 onBeforeUnmount(() => {
 	if (easterEggEngine) {
 		easterEggEngine.stop();
@@ -207,52 +219,72 @@ definePageMetadata({
 .znqjceqz {
 	> .about {
 		position: relative;
-		text-align: center;
-		padding: 16px;
 		border-radius: var(--radius);
 
-		&.playing {
-			&, * {
-				user-select: none;
-			}
-
-			* {
-				will-change: transform;
-			}
-
-			> .emoji {
-				visibility: visible;
-			}
-		}
-
-		> .icon {
-			display: block;
-			width: 80px;
-			margin: 0 auto;
-			border-radius: 16px;
-		}
-
-		> .misskey {
-			margin: 0.75em auto 0 auto;
-			width: max-content;
-		}
-
-		> .version {
-			margin: 0 auto;
-			width: max-content;
-			opacity: 0.5;
-		}
-
-		> .emoji {
+		> .treasure {
 			position: absolute;
-			top: 0;
+			top: 55px;
 			left: 0;
-			visibility: hidden;
+			right: 0;
+			margin: 0 auto;
+			width: min-content;
+
+			> .treasureImg {
+				width: 25px;
+				vertical-align: bottom;
+			}
+		}
+
+		> .container {
+			position: relative;
+			text-align: center;
+			padding: 16px;
+
+			&.playing {
+				&, * {
+					user-select: none;
+				}
+
+				* {
+					will-change: transform;
+				}
+
+				> .emoji {
+					visibility: visible;
+				}
+			}
+
+			> .icon {
+				display: block;
+				width: 80px;
+				margin: 0 auto;
+				border-radius: 16px;
+				position: relative;
+				z-index: 1;
+			}
+
+			> .misskey {
+				margin: 0.75em auto 0 auto;
+				width: max-content;
+			}
+
+			> .version {
+				margin: 0 auto;
+				width: max-content;
+				opacity: 0.5;
+			}
 
 			> .emoji {
-				pointer-events: none;
-				font-size: 24px;
-				width: 24px;
+				position: absolute;
+				top: 0;
+				left: 0;
+				visibility: hidden;
+
+				> .emoji {
+					pointer-events: none;
+					font-size: 24px;
+					width: 24px;
+				}
 			}
 		}
 	}
diff --git a/packages/frontend/src/scripts/achievements.ts b/packages/frontend/src/scripts/achievements.ts
index f511fce3e..53a921418 100644
--- a/packages/frontend/src/scripts/achievements.ts
+++ b/packages/frontend/src/scripts/achievements.ts
@@ -58,6 +58,7 @@ export const ACHIEVEMENT_TYPES = [
 	'collectAchievements30',
 	'viewAchievements3min',
 	'iLoveMisskey',
+	'foundTreasure',
 	'client30min',
 	'noteDeletedWithin1min',
 	'postedAtLateNight',
@@ -331,6 +332,11 @@ export const ACHIEVEMENT_BADGES = {
 		bg: 'linear-gradient(0deg, rgb(255 77 77), rgb(247 155 214))',
 		frame: 'silver',
 	},
+	'foundTreasure': {
+		img: '/fluent-emoji/1f3c6.png',
+		bg: 'linear-gradient(0deg, rgb(255 77 77), rgb(247 155 214))',
+		frame: 'gold',
+	},
 	'client30min': {
 		img: '/fluent-emoji/1f552.png',
 		bg: 'linear-gradient(0deg, rgb(220 223 225), rgb(172 192 207))',
@@ -437,7 +443,7 @@ export const ACHIEVEMENT_BADGES = {
 	frame: 'bronze' | 'silver' | 'gold' | 'platinum';
 }>;
 
-export const claimedAchievements = ($i && $i.achievements) ? $i.achievements.map(x => x.name) : [];
+export const claimedAchievements: typeof ACHIEVEMENT_TYPES[number][] = ($i && $i.achievements) ? $i.achievements.map(x => x.name) : [];
 
 const claimingQueue = new Set<string>();