feat(achievements): implement unlocking, saving and notification
This commit is contained in:
83
app/stores/achievements.ts
Normal file
83
app/stores/achievements.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
|
||||
const STORAGE_ID = "achievements";
|
||||
|
||||
export const ACHIEVEMENTS = [
|
||||
"boot",
|
||||
// projects
|
||||
"projects_visit",
|
||||
"projects_view_5",
|
||||
"projects_open_link",
|
||||
// gallery
|
||||
"gallery_visit",
|
||||
// contact
|
||||
"contact_visit",
|
||||
"contact_git_visit",
|
||||
// settings
|
||||
"settings_color_change",
|
||||
// snake
|
||||
"snake_play",
|
||||
"snake_score_40",
|
||||
// secrets
|
||||
"settings_color_try_all",
|
||||
"settings_language_try_all",
|
||||
"settings_visit_all",
|
||||
"contact_36_notifications",
|
||||
] as const;
|
||||
|
||||
export type Achievement = (typeof ACHIEVEMENTS)[number];
|
||||
|
||||
export const useAchievementsStore = defineStore("achievements", () => {
|
||||
const app = useAppStore();
|
||||
const { locale } = useI18n();
|
||||
|
||||
const storage = useLocalStorage(
|
||||
STORAGE_ID,
|
||||
{
|
||||
unlocked: [] as Achievement[],
|
||||
advancement: {
|
||||
colors: [app.color.hex],
|
||||
languages: [locale.value],
|
||||
visitedSettings: [] as string[],
|
||||
},
|
||||
},
|
||||
{ mergeDefaults: true },
|
||||
);
|
||||
|
||||
if (!storage.value.advancement.colors.includes(app.color.hex)) {
|
||||
storage.value.advancement.colors.push(app.color.hex);
|
||||
}
|
||||
if (!storage.value.advancement.languages.includes(locale.value)) {
|
||||
storage.value.advancement.languages.push(locale.value);
|
||||
}
|
||||
|
||||
const unlock = (name: Achievement) => {
|
||||
if (storage.value.unlocked.includes(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
storage.value.unlocked.push(name);
|
||||
return true;
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
storage.value = {
|
||||
unlocked: [],
|
||||
advancement: {
|
||||
colors: [app.color.hex],
|
||||
languages: [locale.value],
|
||||
visitedSettings: [],
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
achievements: computed(() => storage.value.unlocked),
|
||||
advancement: computed(() => storage.value.advancement),
|
||||
unlock,
|
||||
reset,
|
||||
isUnlocked: computed(
|
||||
() => (name: Achievement) => storage.value.unlocked.includes(name),
|
||||
),
|
||||
};
|
||||
});
|
||||
@@ -41,6 +41,22 @@ export const useAppStore = defineStore("app", {
|
||||
|
||||
navigateTo(screen: AppScreen) {
|
||||
this.screen = screen;
|
||||
|
||||
const achievements = useAchievementsStore();
|
||||
|
||||
switch (screen) {
|
||||
case "projects":
|
||||
achievements.unlock("projects_visit");
|
||||
break;
|
||||
|
||||
case "gallery":
|
||||
achievements.unlock("gallery_visit");
|
||||
break;
|
||||
|
||||
case "contact":
|
||||
achievements.unlock("contact_visit");
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
setCamera(camera: THREE.Camera) {
|
||||
|
||||
@@ -82,6 +82,11 @@ export const useContactStore = defineStore("contact", {
|
||||
{ notificationsYOffset: 20 },
|
||||
{ notificationsYOffset: 0, duration: 0.075 },
|
||||
);
|
||||
|
||||
if (this.notifications.length === 36) {
|
||||
const achievements = useAchievementsStore();
|
||||
achievements.unlock("contact_36_notifications");
|
||||
}
|
||||
},
|
||||
|
||||
animateOutro() {
|
||||
|
||||
@@ -68,7 +68,9 @@ export const useIntroStore = defineStore("intro", {
|
||||
})
|
||||
.call(() => {
|
||||
const app = useAppStore();
|
||||
const achievements = useAchievementsStore();
|
||||
app.booted = true;
|
||||
achievements.unlock("boot");
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -61,7 +61,11 @@ export const useProjectsStore = defineStore("projects", {
|
||||
|
||||
visitProject() {
|
||||
const link = this.projects[this.currentProject]?.link;
|
||||
if (link) navigateTo(link, { open: { target: "_blank" } });
|
||||
if (link) {
|
||||
navigateTo(link, { open: { target: "_blank" } });
|
||||
const achievements = useAchievementsStore();
|
||||
achievements.unlock("projects_open_link");
|
||||
}
|
||||
},
|
||||
|
||||
scrollProjects(direction: "left" | "right") {
|
||||
@@ -89,6 +93,13 @@ export const useProjectsStore = defineStore("projects", {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (this.currentProject >= 4) {
|
||||
setTimeout(() => {
|
||||
const achievements = useAchievementsStore();
|
||||
achievements.unlock("projects_view_5");
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: not used anymore
|
||||
|
||||
@@ -14,6 +14,17 @@ export const useSettingsStore = defineStore("settings", {
|
||||
|
||||
openSubMenu(submenu: SettingsSubMenu) {
|
||||
this.currentSubMenu = submenu;
|
||||
|
||||
const achievements = useAchievementsStore();
|
||||
if (!achievements.advancement.visitedSettings.includes(submenu)) {
|
||||
achievements.advancement.visitedSettings.push(submenu);
|
||||
}
|
||||
if (
|
||||
achievements.advancement.visitedSettings.length ===
|
||||
SETTINGS_SUB_MENUS.length
|
||||
) {
|
||||
achievements.unlock("settings_visit_all");
|
||||
}
|
||||
},
|
||||
|
||||
closeSubMenu() {
|
||||
|
||||
Reference in New Issue
Block a user