feat: remove query based routing
This commit is contained in:
@@ -5,13 +5,25 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
const menusContext = inject<{
|
||||||
|
isSubmenuSelected: ComputedRef<boolean>;
|
||||||
|
selectedSubmenuParent: ComputedRef<string | null>;
|
||||||
|
}>("menusContext")!;
|
||||||
|
|
||||||
const { assets } = useAssets();
|
const { assets } = useAssets();
|
||||||
|
|
||||||
const isOpen = computed(() => settingsStore.isMenuOpen("clock"));
|
const isOpen = computed(
|
||||||
const isAnyOtherMenuOpen = computed(() =>
|
() => settingsStore.currentMenu === "clock" && settingsStore.menuExpanded,
|
||||||
settingsStore.isAnyOtherMenuOpen("clock"),
|
|
||||||
);
|
);
|
||||||
|
const isAnyOtherMenuOpen = computed(() => {
|
||||||
|
if (settingsStore.currentSubMenu) {
|
||||||
|
return !settingsStore.currentSubMenu.startsWith("clock");
|
||||||
|
}
|
||||||
|
if (menusContext.isSubmenuSelected.value) {
|
||||||
|
return menusContext.selectedSubmenuParent.value !== "clock";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
const animation = useMenuAnimation("clock", isOpen);
|
const animation = useMenuAnimation("clock", isOpen);
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,27 @@ import UserMenu from "./User/Menu.vue";
|
|||||||
import TouchScreenMenu from "./TouchScreen/Menu.vue";
|
import TouchScreenMenu from "./TouchScreen/Menu.vue";
|
||||||
import Selector from "~/components/Common/ButtonSelector.vue";
|
import Selector from "~/components/Common/ButtonSelector.vue";
|
||||||
|
|
||||||
|
const app = useAppStore();
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
|
||||||
|
type Menu = "options" | "clock" | "user" | "touchScreen";
|
||||||
|
|
||||||
|
const MAIN_MENUS: Menu[] = ["options", "clock", "user", "touchScreen"];
|
||||||
|
|
||||||
|
const isMainMenu = (button: string): button is Menu => {
|
||||||
|
return MAIN_MENUS.includes(button as Menu);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSubMenu = (button: string): boolean => {
|
||||||
|
return /^(options|clock|user|touchScreen)[A-Z]/.test(button);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getParentMenu = (submenu: string): Menu => {
|
||||||
|
const match = submenu.match(/^(options|clock|user|touchScreen)/);
|
||||||
|
if (!match?.[1]) throw new Error(`Invalid submenu: '${submenu}'`);
|
||||||
|
return match[1] as Menu;
|
||||||
|
};
|
||||||
|
|
||||||
const { selectedButton: selected, selectorPosition } = useButtonNavigation({
|
const { selectedButton: selected, selectorPosition } = useButtonNavigation({
|
||||||
buttons: {
|
buttons: {
|
||||||
options: [31, 119, 49, 49],
|
options: [31, 119, 49, 49],
|
||||||
@@ -35,13 +54,8 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({
|
|||||||
},
|
},
|
||||||
initialButton: "options",
|
initialButton: "options",
|
||||||
onButtonClick: (buttonName: string) => {
|
onButtonClick: (buttonName: string) => {
|
||||||
if (isSubmenu(buttonName)) {
|
if (isSubMenu(buttonName)) {
|
||||||
router.push({
|
settingsStore.openSubMenu(buttonName);
|
||||||
query: {
|
|
||||||
screen: "settings",
|
|
||||||
menu: buttonName,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
navigation: {
|
navigation: {
|
||||||
@@ -118,51 +132,27 @@ const { selectedButton: selected, selectorPosition } = useButtonNavigation({
|
|||||||
disabled: computed(() => settingsStore.currentSubMenu !== null),
|
disabled: computed(() => settingsStore.currentSubMenu !== null),
|
||||||
});
|
});
|
||||||
|
|
||||||
const isSubmenu = (buttonName: string) => {
|
const isSubmenuSelected = computed(() => isSubMenu(selected.value));
|
||||||
return (
|
const selectedSubmenuParent = computed(() =>
|
||||||
/^(options|clock|user|touchScreen)[A-Z]/.test(buttonName) &&
|
isSubmenuSelected.value ? getParentMenu(selected.value) : null,
|
||||||
!["options", "clock", "user", "touchScreen"].includes(buttonName)
|
);
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const router = useRouter();
|
provide("menusContext", {
|
||||||
|
isSubmenuSelected,
|
||||||
onBeforeRouteUpdate((to, from) => {
|
selectedSubmenuParent,
|
||||||
const fromMenu = from.query.menu?.toString();
|
|
||||||
const toMenu = to.query.menu?.toString();
|
|
||||||
|
|
||||||
if (!fromMenu && toMenu) {
|
|
||||||
settingsStore.setActiveMenu(selected.value);
|
|
||||||
} else if (fromMenu && !toMenu) {
|
|
||||||
if (fromMenu === "options" || fromMenu === "clock" || fromMenu === "user") {
|
|
||||||
selected.value = fromMenu;
|
|
||||||
settingsStore.setActiveMenu(null);
|
|
||||||
} else {
|
|
||||||
throw new Error("Unreachable");
|
|
||||||
}
|
|
||||||
} else if (fromMenu && toMenu) {
|
|
||||||
if (toMenu === "options" || toMenu === "clock" || toMenu === "user") {
|
|
||||||
settingsStore.setCurrentSubMenu(null);
|
|
||||||
settingsStore.setActiveMenu(selected.value);
|
|
||||||
} else {
|
|
||||||
settingsStore.setCurrentSubMenu(toMenu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
selected,
|
selected,
|
||||||
(newSelected) => {
|
(newSelected) => {
|
||||||
if (settingsStore.currentSubMenu === null) {
|
if (settingsStore.currentSubMenu === null) {
|
||||||
if (isSubmenu(newSelected)) {
|
if (isMainMenu(newSelected)) {
|
||||||
router.push({
|
settingsStore.openMenu(newSelected, false);
|
||||||
query: {
|
} else if (isSubMenu(newSelected)) {
|
||||||
screen: "settings",
|
const parentMenu = getParentMenu(newSelected);
|
||||||
menu: newSelected.split(/[A-Z]/)[0],
|
if (parentMenu) {
|
||||||
},
|
settingsStore.openMenu(parentMenu, true);
|
||||||
});
|
}
|
||||||
} else {
|
|
||||||
router.push({ query: { screen: "settings", menu: undefined } });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -186,6 +176,21 @@ const viewComponents: Record<string, Component> = {
|
|||||||
<TouchScreenMenu :x="177" :y="121" :opacity="1" />
|
<TouchScreenMenu :x="177" :y="121" :opacity="1" />
|
||||||
|
|
||||||
<Selector :rect="selectorPosition" :opacity="1" />
|
<Selector :rect="selectorPosition" :opacity="1" />
|
||||||
|
|
||||||
|
<CommonButtons
|
||||||
|
v-if="isSubmenuSelected"
|
||||||
|
:y-offset="0"
|
||||||
|
b-label="Go back"
|
||||||
|
a-label="Select"
|
||||||
|
@activate-b="selected = getParentMenu(selected)"
|
||||||
|
/>
|
||||||
|
<CommonButtons
|
||||||
|
v-else
|
||||||
|
:y-offset="0"
|
||||||
|
b-label="Quit"
|
||||||
|
a-label="Select"
|
||||||
|
@activate-b="app.navigateTo('home')"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<component :is="viewComponents[settingsStore.currentSubMenu]" v-else />
|
<component :is="viewComponents[settingsStore.currentSubMenu]" v-else />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,13 +5,25 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
const menusContext = inject<{
|
||||||
|
isSubmenuSelected: ComputedRef<boolean>;
|
||||||
|
selectedSubmenuParent: ComputedRef<string | null>;
|
||||||
|
}>("menusContext")!;
|
||||||
|
|
||||||
const { assets } = useAssets();
|
const { assets } = useAssets();
|
||||||
|
|
||||||
const isOpen = computed(() => settingsStore.isMenuOpen("options"));
|
const isOpen = computed(
|
||||||
const isAnyOtherMenuOpen = computed(() =>
|
() => settingsStore.currentMenu === "options" && settingsStore.menuExpanded,
|
||||||
settingsStore.isAnyOtherMenuOpen("options"),
|
|
||||||
);
|
);
|
||||||
|
const isAnyOtherMenuOpen = computed(() => {
|
||||||
|
if (settingsStore.currentSubMenu) {
|
||||||
|
return !settingsStore.currentSubMenu.startsWith("options");
|
||||||
|
}
|
||||||
|
if (menusContext.isSubmenuSelected.value) {
|
||||||
|
return menusContext.selectedSubmenuParent.value !== "options";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
const animation = useMenuAnimation("options", isOpen);
|
const animation = useMenuAnimation("options", isOpen);
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,23 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
const menusContext = inject<{
|
||||||
|
isSubmenuSelected: ComputedRef<boolean>;
|
||||||
|
selectedSubmenuParent: ComputedRef<string | null>;
|
||||||
|
}>("menusContext")!;
|
||||||
|
|
||||||
const { assets } = useAssets();
|
const { assets } = useAssets();
|
||||||
|
|
||||||
const isAnyOtherMenuOpen = computed(() =>
|
// TODO: i don't like this
|
||||||
settingsStore.isAnyOtherMenuOpen("touchScreen"),
|
const isAnyOtherMenuOpen = computed(() => {
|
||||||
);
|
if (settingsStore.currentSubMenu) {
|
||||||
|
return !settingsStore.currentSubMenu.startsWith("touchScreen");
|
||||||
|
}
|
||||||
|
if (menusContext.isSubmenuSelected.value) {
|
||||||
|
return menusContext.selectedSubmenuParent.value !== "touchScreen";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
useRender((ctx) => {
|
useRender((ctx) => {
|
||||||
if (isAnyOtherMenuOpen.value) {
|
if (isAnyOtherMenuOpen.value) {
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ const SPACING = 16;
|
|||||||
const ANIMATION_SPEED = 475;
|
const ANIMATION_SPEED = 475;
|
||||||
|
|
||||||
const app = useAppStore();
|
const app = useAppStore();
|
||||||
|
const store = useSettingsStore();
|
||||||
const { assets } = useAssets();
|
const { assets } = useAssets();
|
||||||
|
|
||||||
|
const originalSelectedCol = app.color.col;
|
||||||
|
const originalSelectedRow = app.color.row;
|
||||||
|
|
||||||
let selectedCol = app.color.col;
|
let selectedCol = app.color.col;
|
||||||
let selectedRow = app.color.row;
|
let selectedRow = app.color.row;
|
||||||
let selectorX = GRID_START_X + selectedCol * (CELL_SIZE + SPACING) - 4;
|
let selectorX = GRID_START_X + selectedCol * (CELL_SIZE + SPACING) - 4;
|
||||||
@@ -94,7 +98,32 @@ useRender((ctx, deltaTime) => {
|
|||||||
ctx.fillRect(192, 96, 32, 32);
|
ctx.fillRect(192, 96, 32, 32);
|
||||||
});
|
});
|
||||||
|
|
||||||
defineOptions({
|
const handleCancel = () => {
|
||||||
render: () => null,
|
select(originalSelectedCol, originalSelectedRow);
|
||||||
});
|
store.closeSubMenu();
|
||||||
|
};
|
||||||
|
|
||||||
|
const { open: openModal, close: closeModal } = useConfirmationModal();
|
||||||
|
|
||||||
|
const handleConfirm = () => {
|
||||||
|
app.save();
|
||||||
|
openModal({
|
||||||
|
text: "hey",
|
||||||
|
showButtons: false,
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
closeModal();
|
||||||
|
store.closeSubMenu();
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<CommonButtons
|
||||||
|
:y-offset="0"
|
||||||
|
b-label="Cancel"
|
||||||
|
a-label="Confirm"
|
||||||
|
@activate-b="handleCancel"
|
||||||
|
@activate-a="handleConfirm"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|||||||
@@ -5,13 +5,25 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
|
const menusContext = inject<{
|
||||||
|
isSubmenuSelected: ComputedRef<boolean>;
|
||||||
|
selectedSubmenuParent: ComputedRef<string | null>;
|
||||||
|
}>("menusContext")!;
|
||||||
|
|
||||||
const { assets } = useAssets();
|
const { assets } = useAssets();
|
||||||
|
|
||||||
const isOpen = computed(() => settingsStore.isMenuOpen("user"));
|
const isOpen = computed(
|
||||||
const isAnyOtherMenuOpen = computed(() =>
|
() => settingsStore.currentMenu === "user" && settingsStore.menuExpanded,
|
||||||
settingsStore.isAnyOtherMenuOpen("user"),
|
|
||||||
);
|
);
|
||||||
|
const isAnyOtherMenuOpen = computed(() => {
|
||||||
|
if (settingsStore.currentSubMenu) {
|
||||||
|
return !settingsStore.currentSubMenu.startsWith("user");
|
||||||
|
}
|
||||||
|
if (menusContext.isSubmenuSelected.value) {
|
||||||
|
return menusContext.selectedSubmenuParent.value !== "user";
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
const animation = useMenuAnimation("user", isOpen);
|
const animation = useMenuAnimation("user", isOpen);
|
||||||
|
|
||||||
|
|||||||
@@ -30,36 +30,24 @@ const mainNotification = computed(() => ({
|
|||||||
description: $t("settings.description"),
|
description: $t("settings.description"),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// TODO: this could be computed instead
|
||||||
|
const MENU_IMAGES: Record<string, HTMLImageElement> = {
|
||||||
|
options: assets.settings.topScreen.options.options,
|
||||||
|
clock: assets.settings.topScreen.clock.clock,
|
||||||
|
user: assets.settings.topScreen.user.user,
|
||||||
|
touchScreen: assets.settings.topScreen.touchScreen.touchScreen,
|
||||||
|
};
|
||||||
|
|
||||||
const menuNotification = computed(() => {
|
const menuNotification = computed(() => {
|
||||||
if (!store.currentMenu) return null;
|
if (!store.currentMenu || !store.menuExpanded) return null;
|
||||||
|
|
||||||
let image: HTMLImageElement | null = null;
|
|
||||||
let id = "";
|
|
||||||
|
|
||||||
if (/^options[A-Z]/.test(store.currentMenu)) {
|
|
||||||
image = assets.settings.topScreen.options.options;
|
|
||||||
id = "options";
|
|
||||||
} else if (/^clock[A-Z]/.test(store.currentMenu)) {
|
|
||||||
image = assets.settings.topScreen.clock.clock;
|
|
||||||
id = "clock";
|
|
||||||
} else if (/^user[A-Z]/.test(store.currentMenu)) {
|
|
||||||
image = assets.settings.topScreen.user.user;
|
|
||||||
id = "user";
|
|
||||||
} else if (/^touchScreen[A-Z]/.test(store.currentMenu)) {
|
|
||||||
image = assets.settings.topScreen.touchScreen.touchScreen;
|
|
||||||
id = "touchScreen";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!image) return null;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
image,
|
image: MENU_IMAGES[store.currentMenu]!,
|
||||||
title: $t(`settings.${id}.title`),
|
title: $t(`settings.${store.currentMenu}.title`),
|
||||||
description: $t(`settings.${id}.description`),
|
description: $t(`settings.${store.currentMenu}.description`),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: this could be computed instead
|
|
||||||
const IMAGES_MAP: Record<string, HTMLImageElement> = {
|
const IMAGES_MAP: Record<string, HTMLImageElement> = {
|
||||||
optionsStartUp: assets.settings.topScreen.options.startUp,
|
optionsStartUp: assets.settings.topScreen.options.startUp,
|
||||||
optionsLanguage: assets.settings.topScreen.options.language,
|
optionsLanguage: assets.settings.topScreen.options.language,
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ type ScreenInstance = InstanceType<typeof NDSScreen>;
|
|||||||
|
|
||||||
const { isReady } = useAssets();
|
const { isReady } = useAssets();
|
||||||
|
|
||||||
const route = useRoute();
|
const app = useAppStore();
|
||||||
const screen = computed(() => route.query.screen as string | undefined);
|
|
||||||
|
|
||||||
const topScreen = useTemplateRef<ScreenInstance>("topScreen");
|
const topScreen = useTemplateRef<ScreenInstance>("topScreen");
|
||||||
const bottomScreen = useTemplateRef<ScreenInstance>("bottomScreen");
|
const bottomScreen = useTemplateRef<ScreenInstance>("bottomScreen");
|
||||||
@@ -76,18 +75,18 @@ useKeyUp((key) => {
|
|||||||
<div :style="{ visibility: ENABLE_3D ? 'hidden' : 'visible' }">
|
<div :style="{ visibility: ENABLE_3D ? 'hidden' : 'visible' }">
|
||||||
<div>
|
<div>
|
||||||
<Screen ref="topScreen">
|
<Screen ref="topScreen">
|
||||||
<HomeTopScreen v-if="!screen" />
|
<HomeTopScreen v-if="app.screen === 'home'" />
|
||||||
<ContactTopScreen v-else-if="screen === 'contact'" />
|
<ContactTopScreen v-else-if="app.screen === 'contact'" />
|
||||||
<ProjectsTopScreen v-else-if="screen === 'projects'" />
|
<ProjectsTopScreen v-else-if="app.screen === 'projects'" />
|
||||||
<SettingsTopScreen v-else-if="screen === 'settings'" />
|
<SettingsTopScreen v-else-if="app.screen === 'settings'" />
|
||||||
</Screen>
|
</Screen>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Screen ref="bottomScreen">
|
<Screen ref="bottomScreen">
|
||||||
<HomeBottomScreen v-if="!screen" />
|
<HomeBottomScreen v-if="app.screen === 'home'" />
|
||||||
<ContactBottomScreen v-else-if="screen === 'contact'" />
|
<ContactBottomScreen v-else-if="app.screen === 'contact'" />
|
||||||
<ProjectsBottomScreen v-else-if="screen === 'projects'" />
|
<ProjectsBottomScreen v-else-if="app.screen === 'projects'" />
|
||||||
<SettingsBottomScreen v-else-if="screen === 'settings'" />
|
<SettingsBottomScreen v-else-if="app.screen === 'settings'" />
|
||||||
</Screen>
|
</Screen>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,36 +15,35 @@ const defaultSettings = (): Settings => ({
|
|||||||
color: { col: 0, row: 0 },
|
color: { col: 0, row: 0 },
|
||||||
});
|
});
|
||||||
|
|
||||||
const loadSettings = (): Settings => {
|
export const useAppStore = defineStore("app", {
|
||||||
|
state: () => {
|
||||||
|
let settings: Settings;
|
||||||
const stored = localStorage.getItem(STORAGE_ID);
|
const stored = localStorage.getItem(STORAGE_ID);
|
||||||
try {
|
try {
|
||||||
const result = settingsSchema.safeParse(JSON.parse(stored ?? ""));
|
settings = settingsSchema.parse(JSON.parse(stored ?? ""));
|
||||||
if (result.success) {
|
|
||||||
return result.data;
|
|
||||||
}
|
|
||||||
} catch {
|
} catch {
|
||||||
// JSON.parse failed
|
settings = defaultSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = defaultSettings();
|
return {
|
||||||
saveSettings(settings);
|
|
||||||
return settings;
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveSettings = (settings: Settings) => {
|
|
||||||
localStorage.setItem(STORAGE_ID, JSON.stringify(settings));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useAppStore = defineStore("app", {
|
|
||||||
state: () => ({
|
|
||||||
booted: false,
|
booted: false,
|
||||||
settings: loadSettings(),
|
settings,
|
||||||
}),
|
screen: "home" as AppScreen,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
setColor(col: number, row: number) {
|
setColor(col: number, row: number) {
|
||||||
this.settings.color = { col, row };
|
this.settings.color = { col, row };
|
||||||
},
|
},
|
||||||
|
|
||||||
|
navigateTo(screen: AppScreen) {
|
||||||
|
this.screen = screen;
|
||||||
|
},
|
||||||
|
|
||||||
|
save() {
|
||||||
|
localStorage.setItem(STORAGE_ID, JSON.stringify(this.settings));
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
|
|||||||
@@ -90,8 +90,9 @@ export const useContactStore = defineStore("contact", {
|
|||||||
const timeline = gsap.timeline({
|
const timeline = gsap.timeline({
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const router = useRouter();
|
this.isOutro = false;
|
||||||
router.push({ query: {} });
|
const app = useAppStore();
|
||||||
|
app.navigateTo("home");
|
||||||
}, 2000);
|
}, 2000);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,15 +54,15 @@ export const useHomeStore = defineStore("home", {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
animateOutro(to: "contact" | "projects" | "theme" | "settings" | "alarm") {
|
animateOutro(to: AppScreen) {
|
||||||
this.isOutro = true;
|
this.isOutro = true;
|
||||||
this.outro.animateTop = to !== "settings";
|
this.outro.animateTop = to !== "settings";
|
||||||
|
|
||||||
const timeline = gsap.timeline({
|
const timeline = gsap.timeline({
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.isOutro = true;
|
this.isOutro = true;
|
||||||
const router = useRouter();
|
const app = useAppStore();
|
||||||
router.push({ query: { screen: to } });
|
app.navigateTo(to);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -141,8 +141,9 @@ export const useProjectsStore = defineStore("projects", {
|
|||||||
ease: "none",
|
ease: "none",
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const router = useRouter();
|
this.isOutro = false;
|
||||||
router.push({ query: {} });
|
const app = useAppStore();
|
||||||
|
app.navigateTo("home");
|
||||||
}, 3000);
|
}, 3000);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,28 +1,25 @@
|
|||||||
|
type Menu = "options" | "clock" | "user" | "touchScreen";
|
||||||
|
|
||||||
export const useSettingsStore = defineStore("settings", {
|
export const useSettingsStore = defineStore("settings", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
currentMenu: null as string | null,
|
currentMenu: null as Menu | null,
|
||||||
currentSubMenu: null as string | null,
|
currentSubMenu: null as string | null,
|
||||||
|
menuExpanded: false,
|
||||||
}),
|
}),
|
||||||
getters: {
|
|
||||||
isMenuOpen: (state) => (menu: string) => {
|
|
||||||
if (!state.currentMenu) return false;
|
|
||||||
return new RegExp(`^${menu}[A-Z]`).test(state.currentMenu);
|
|
||||||
},
|
|
||||||
|
|
||||||
isAnyOtherMenuOpen: (state) => (excludeMenu: string) => {
|
|
||||||
if (!state.currentMenu) return false;
|
|
||||||
return ["options", "clock", "user", "touchScreen"]
|
|
||||||
.filter((m) => m !== excludeMenu)
|
|
||||||
.some((m) => new RegExp(`^${m}[A-Z]`).test(state.currentMenu!));
|
|
||||||
},
|
|
||||||
},
|
|
||||||
actions: {
|
actions: {
|
||||||
setActiveMenu(menu: string | null) {
|
openMenu(menu: Menu, expanded: boolean = false) {
|
||||||
this.currentMenu = menu;
|
this.currentMenu = menu;
|
||||||
|
this.menuExpanded = expanded;
|
||||||
|
this.currentSubMenu = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
setCurrentSubMenu(submenu: string | null) {
|
openSubMenu(submenu: string) {
|
||||||
this.currentSubMenu = submenu;
|
this.currentSubMenu = submenu;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
closeSubMenu() {
|
||||||
|
this.currentSubMenu = null;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
1
app/types/app.d.ts
vendored
Normal file
1
app/types/app.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
type AppScreen = "home" | "contact" | "projects" | "settings";
|
||||||
Reference in New Issue
Block a user