166 lines
3.9 KiB
Vue
166 lines
3.9 KiB
Vue
<script setup lang="ts">
|
|
import ButtonSelector from "~/components/Common/ButtonSelector.vue";
|
|
import { promiseTimeout } from "@vueuse/core";
|
|
|
|
const { onRender } = useScreen();
|
|
|
|
const store = useContactStore();
|
|
const achievements = useAchievementsStore();
|
|
const confirmationModal = useConfirmationModal();
|
|
const { assets } = useAssets((a) => a.images.contact.bottomScreen.buttons);
|
|
|
|
const BUTTONS = {
|
|
git: {
|
|
position: [31, 32],
|
|
action: "open",
|
|
url: "https://git.pihkaal.me",
|
|
text: "git.pihkaal.me",
|
|
},
|
|
email: {
|
|
position: [31, 64],
|
|
action: "copy",
|
|
url: "hello@pihkaal.me",
|
|
text: "hello@pihkaal.me",
|
|
},
|
|
linkedin: {
|
|
position: [31, 96],
|
|
action: "open",
|
|
url: "https://linkedin.com/in/stevancorre/",
|
|
text: "/in/stevancorre/",
|
|
},
|
|
cv: {
|
|
position: [31, 128],
|
|
action: "open",
|
|
url: "https://pihkaal.me/cv",
|
|
text: "/cv",
|
|
},
|
|
} as const satisfies Record<
|
|
string,
|
|
{
|
|
position: [number, number];
|
|
action: "copy" | "open";
|
|
url: string;
|
|
text: string;
|
|
}
|
|
>;
|
|
|
|
const { selected, pressed, selectorPosition } = useButtonNavigation({
|
|
buttons: {
|
|
git: [26, 27, 202, 42],
|
|
email: [26, 59, 202, 42],
|
|
linkedin: [26, 91, 202, 42],
|
|
cv: [26, 123, 202, 42],
|
|
},
|
|
navigation: {
|
|
git: {
|
|
down: "email",
|
|
},
|
|
email: {
|
|
up: "git",
|
|
down: "linkedin",
|
|
},
|
|
linkedin: {
|
|
up: "email",
|
|
down: "cv",
|
|
},
|
|
cv: {
|
|
up: "linkedin",
|
|
},
|
|
},
|
|
initialButton: "git",
|
|
onActivate: (button) => handleActivateA(button),
|
|
disabled: computed(() => store.isIntro || store.isOutro),
|
|
selectorAnimation: {
|
|
duration: 0.075,
|
|
ease: "none",
|
|
},
|
|
});
|
|
|
|
const handleActivateA = async (button: typeof selected.value) => {
|
|
const { action, url } = BUTTONS[button];
|
|
const verb = $t(`contact.actions.${button}`);
|
|
if (action === "copy") {
|
|
try {
|
|
await navigator.clipboard.writeText(url);
|
|
store.pushNotification($t("contact.copiedToClipboard", { item: verb }));
|
|
} catch (error) {
|
|
console.error("Failed to copy to clipboard:", error);
|
|
}
|
|
} else {
|
|
confirmationModal.open({
|
|
text: $t("contact.openUrl", { url: url.replace(/^https?:\/\//, "") }),
|
|
onActivateA: async () => {
|
|
store.pushNotification($t("contact.opened", { item: verb }));
|
|
|
|
await promiseTimeout(100);
|
|
await navigateTo(url, { open: { target: "_blank " } });
|
|
await promiseTimeout(500);
|
|
|
|
if (button === "git") {
|
|
achievements.unlock("contact_git_visit");
|
|
}
|
|
},
|
|
});
|
|
}
|
|
};
|
|
|
|
const handleActivateB = () => {
|
|
if (store.isIntro || store.isOutro) return;
|
|
store.animateOutro();
|
|
};
|
|
|
|
onRender((ctx) => {
|
|
ctx.globalAlpha = store.isIntro
|
|
? store.intro.stage3Opacity
|
|
: store.outro.stage1Opacity;
|
|
|
|
ctx.textBaseline = "top";
|
|
ctx.font = "10px NDS10";
|
|
ctx.fillStyle = "#515151";
|
|
|
|
for (const [
|
|
buttonName,
|
|
{
|
|
text,
|
|
position: [x, y],
|
|
},
|
|
] of Object.entries(BUTTONS)) {
|
|
const button = buttonName as typeof selected.value;
|
|
const isPressed = pressed.value === button;
|
|
|
|
assets[isPressed ? "buttonPressed" : "button"].draw(ctx, x, y);
|
|
|
|
const pressedKey: `${typeof selected.value}Pressed` = `${button}Pressed`;
|
|
assets[isPressed ? pressedKey : button].draw(ctx, x + 1, y + 1);
|
|
|
|
ctx.fillText(text, x + 36, y + 11);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<ButtonSelector
|
|
:rect="selectorPosition"
|
|
:opacity="
|
|
store.isIntro ? store.intro.stage3Opacity : store.outro.stage1Opacity
|
|
"
|
|
/>
|
|
<CommonConfirmationModal />
|
|
<CommonButtons
|
|
:y-offset="
|
|
store.isIntro ? store.intro.barOffsetY : confirmationModal.buttonsYOffset
|
|
"
|
|
:opacity="
|
|
store.isIntro
|
|
? store.intro.stage3Opacity
|
|
: store.isOutro
|
|
? store.outro.stage2Opacity
|
|
: 1
|
|
"
|
|
:b-label="$t('common.quit')"
|
|
:a-label="$t(`contact.actions.${BUTTONS[selected].action}`)"
|
|
@activate-a="handleActivateA(selected)"
|
|
@activate-b="handleActivateB"
|
|
/>
|
|
</template>
|