diff --git a/CHANGELOG.md b/CHANGELOG.md
index 611d5d986..1a911f63b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -88,6 +88,7 @@ You should also include the user name that made the change.
- Client: show bot warning on screen when logged in as bot account @syuilo
- Client: improve overall performance of client @syuilo
- Client: ui tweaks @syuilo
+- Client: clicker game @syuilo
### Bugfixes
- Server: 引用内の文章がnyaizeされてしまう問題を修正 @kabo2468
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 3445e5835..e42f9babe 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1361,6 +1361,7 @@ _widgets:
userList: "ユーザーリスト"
_userList:
chooseList: "リストを選択"
+ clicker: "クリッカー"
_cw:
hide: "隠す"
diff --git a/packages/frontend/assets/cookie.png b/packages/frontend/assets/cookie.png
new file mode 100644
index 000000000..4a7f04061
Binary files /dev/null and b/packages/frontend/assets/cookie.png differ
diff --git a/packages/frontend/src/components/MkClickerGame.vue b/packages/frontend/src/components/MkClickerGame.vue
new file mode 100644
index 000000000..6ae202cb6
--- /dev/null
+++ b/packages/frontend/src/components/MkClickerGame.vue
@@ -0,0 +1,70 @@
+
+
+
+
{{ number(cookies) }}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/frontend/src/components/MkPlusOneEffect.vue b/packages/frontend/src/components/MkPlusOneEffect.vue
new file mode 100644
index 000000000..6a09669a6
--- /dev/null
+++ b/packages/frontend/src/components/MkPlusOneEffect.vue
@@ -0,0 +1,69 @@
+
+
+ +1
+
+
+
+
+
+
diff --git a/packages/frontend/src/directives/click-anime.ts b/packages/frontend/src/directives/click-anime.ts
index 83ec08543..3d070177b 100644
--- a/packages/frontend/src/directives/click-anime.ts
+++ b/packages/frontend/src/directives/click-anime.ts
@@ -12,6 +12,9 @@ export default {
target.classList.add('_anime_bounce_standBy');
el.addEventListener('mousedown', () => {
+ target.classList.remove('_anime_bounce_ready');
+ target.classList.remove('_anime_bounce');
+
target.classList.add('_anime_bounce_standBy');
target.classList.add('_anime_bounce_ready');
diff --git a/packages/frontend/src/pages/clicker.vue b/packages/frontend/src/pages/clicker.vue
new file mode 100644
index 000000000..082a303e6
--- /dev/null
+++ b/packages/frontend/src/pages/clicker.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts
index 63c753de2..bfa4a3cea 100644
--- a/packages/frontend/src/router.ts
+++ b/packages/frontend/src/router.ts
@@ -460,6 +460,10 @@ export const routes = [{
path: '/timeline/antenna/:antennaId',
component: page(() => import('./pages/antenna-timeline.vue')),
loginRequired: true,
+}, {
+ path: '/clicker',
+ component: page(() => import('./pages/clicker.vue')),
+ loginRequired: true,
}, {
name: 'index',
path: '/',
diff --git a/packages/frontend/src/scripts/clicker-game.ts b/packages/frontend/src/scripts/clicker-game.ts
new file mode 100644
index 000000000..77206cc8e
--- /dev/null
+++ b/packages/frontend/src/scripts/clicker-game.ts
@@ -0,0 +1,46 @@
+import { ref, computed } from 'vue';
+import * as os from '@/os';
+
+type SaveData = {
+ gameVersion: number;
+ cookies: number;
+ clicked: number;
+};
+
+export const saveData = ref();
+export const ready = computed(() => saveData.value != null);
+
+let prev = '';
+
+export async function load() {
+ try {
+ saveData.value = await os.api('i/registry/get', {
+ scope: ['clickerGame'],
+ key: 'saveData',
+ });
+ } catch (err) {
+ if (err.code === 'NO_SUCH_KEY') {
+ saveData.value = {
+ gameVersion: 1,
+ cookies: 0,
+ clicked: 0,
+ };
+ save();
+ return;
+ }
+ throw err;
+ }
+}
+
+export async function save() {
+ const current = JSON.stringify(saveData.value);
+ if (current === prev) return;
+
+ await os.api('i/registry/set', {
+ scope: ['clickerGame'],
+ key: 'saveData',
+ value: saveData.value,
+ });
+
+ prev = current;
+}
diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts
index dfdf324bc..c3b22cd9e 100644
--- a/packages/frontend/src/ui/_common_/common.ts
+++ b/packages/frontend/src/ui/_common_/common.ts
@@ -41,6 +41,11 @@ export function openInstanceMenu(ev: MouseEvent) {
to: '/api-console',
text: 'API Console',
icon: 'ti ti-terminal-2',
+ }, {
+ type: 'link',
+ to: '/clicker',
+ text: '🍪👈',
+ icon: 'ti ti-cookie',
}],
}, null, {
type: 'parent',
diff --git a/packages/frontend/src/widgets/clicker.vue b/packages/frontend/src/widgets/clicker.vue
new file mode 100644
index 000000000..77d1777e9
--- /dev/null
+++ b/packages/frontend/src/widgets/clicker.vue
@@ -0,0 +1,44 @@
+
+
+ Clicker
+
+
+
+
+
diff --git a/packages/frontend/src/widgets/index.ts b/packages/frontend/src/widgets/index.ts
index 3966649da..eba4abd2f 100644
--- a/packages/frontend/src/widgets/index.ts
+++ b/packages/frontend/src/widgets/index.ts
@@ -25,6 +25,7 @@ export default function(app: App) {
app.component('MkwAiscriptApp', defineAsyncComponent(() => import('./aiscript-app.vue')));
app.component('MkwAichan', defineAsyncComponent(() => import('./aichan.vue')));
app.component('MkwUserList', defineAsyncComponent(() => import('./user-list.vue')));
+ app.component('MkwClicker', defineAsyncComponent(() => import('./clicker.vue')));
}
export const widgets = [
@@ -52,4 +53,5 @@ export const widgets = [
'aiscriptApp',
'aichan',
'userList',
+ 'clicker',
];