122 lines
2.8 KiB
Vue
122 lines
2.8 KiB
Vue
<script setup lang="ts">
|
|
// TODO: buttons should take in account opacity
|
|
|
|
import Background from "./Background.vue";
|
|
import Buttons from "./Buttons.vue";
|
|
import ButtonSelector from "~/components/Common/ButtonSelector.vue";
|
|
import Bars from "./Bars.vue";
|
|
|
|
const store = useContactStore();
|
|
const { open: openModal, state: modalState } = useConfirmationModal();
|
|
|
|
const ACTIONS = {
|
|
github: ["Open", "Github profile", "https://github.com/pihkaal"],
|
|
email: ["Copy", "Email", "hello@pihkaal.me"],
|
|
website: ["Copy", "Website link", "https://pihkaal.me"],
|
|
cv: ["Open", "CV", "https://pihkaal.me/cv"],
|
|
} as const satisfies Record<
|
|
string,
|
|
[action: "Copy" | "Open", verb: string, content: string]
|
|
>;
|
|
|
|
const { selectedButton, selectorPosition } = useButtonNavigation({
|
|
buttons: {
|
|
github: [26, 27, 202, 42],
|
|
email: [26, 59, 202, 42],
|
|
website: [26, 91, 202, 42],
|
|
cv: [26, 123, 202, 42],
|
|
},
|
|
navigation: {
|
|
github: {
|
|
down: "email",
|
|
},
|
|
email: {
|
|
up: "github",
|
|
down: "website",
|
|
},
|
|
website: {
|
|
up: "email",
|
|
down: "cv",
|
|
},
|
|
cv: {
|
|
up: "website",
|
|
},
|
|
},
|
|
initialButton: "github",
|
|
onButtonClick: async (button) => {
|
|
actionateButton(button);
|
|
},
|
|
});
|
|
|
|
const actionateButton = async (button: (typeof selectedButton)["value"]) => {
|
|
const [action, verb, content] = ACTIONS[button];
|
|
if (action === "Copy") {
|
|
try {
|
|
await navigator.clipboard.writeText(content);
|
|
store.pushNotification(`${verb} copied to clipboard`);
|
|
} catch (error) {
|
|
console.error("Failed to copy to clipboard:", error);
|
|
}
|
|
} else {
|
|
const url = content.replace(/^https?:\/\//, "");
|
|
openModal(`Open ${url}?`, async () => {
|
|
store.pushNotification(`${verb} opened`);
|
|
await sleep(100);
|
|
await navigateTo(content, { open: { target: "_blank " } });
|
|
});
|
|
}
|
|
};
|
|
|
|
const QUIT_BUTTON: Rect = [31, 172, 80, 18];
|
|
const OK_BUTTON: Rect = [144, 172, 80, 18];
|
|
|
|
useScreenClick((x, y) => {
|
|
if (modalState.value.isOpen) {
|
|
return;
|
|
}
|
|
|
|
if (rectContains(QUIT_BUTTON, [x, y])) {
|
|
store.animateOutro();
|
|
} else if (rectContains(OK_BUTTON, [x, y])) {
|
|
actionateButton(selectedButton.value);
|
|
}
|
|
});
|
|
|
|
useKeyDown((key) => {
|
|
if (modalState.value.isOpen) return;
|
|
|
|
switch (key) {
|
|
case "NDS_B":
|
|
store.animateOutro();
|
|
break;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<Background />
|
|
|
|
<Buttons />
|
|
<ButtonSelector
|
|
:rect="selectorPosition"
|
|
:opacity="
|
|
store.isIntro ? store.intro.stage3Opacity : store.outro.stage1Opacity
|
|
"
|
|
/>
|
|
|
|
<Bars />
|
|
<CommonConfirmationModal />
|
|
<CommonButtons
|
|
:y-offset="
|
|
store.isIntro
|
|
? store.intro.bottomBarY - (SCREEN_HEIGHT - 24)
|
|
: modalState.buttonsYOffset
|
|
"
|
|
:opacity="
|
|
store.isIntro ? store.intro.stage3Opacity : store.outro.stage2Opacity
|
|
"
|
|
b-label="Quit"
|
|
:a-label="ACTIONS[selectedButton][0]"
|
|
/>
|
|
</template>
|