164 lines
3.7 KiB
Vue
164 lines
3.7 KiB
Vue
<script setup lang="ts">
|
|
import gsap from "gsap";
|
|
|
|
const { onRender, onClick } = useScreen();
|
|
|
|
const { assets } = useAssets();
|
|
const store = useProjectsStore();
|
|
|
|
const TEXT_SLOW = 0.05;
|
|
const TEXT_FAST = 0.01;
|
|
const TEXT_Y = 151;
|
|
const YES_Y = 107;
|
|
const NO_Y = 123;
|
|
|
|
let selectedOption: "yes" | "no" = "yes";
|
|
const textProgress = ref(0);
|
|
let waitingForNdsARelease = false;
|
|
let timeline: gsap.core.Timeline | null = null;
|
|
|
|
const text = computed(() => {
|
|
const project = store.projects[store.currentProject]!;
|
|
return $t("projects.linkConformationPopup.text", {
|
|
url: project.link.replace(/^https?:\/\//, ""),
|
|
});
|
|
});
|
|
|
|
const animateText = (speed: number) => {
|
|
timeline?.kill();
|
|
const remaining = (1 - textProgress.value) * text.value.length;
|
|
timeline = gsap.timeline().to(textProgress, {
|
|
value: 1,
|
|
duration: remaining * speed,
|
|
ease: "none",
|
|
});
|
|
};
|
|
|
|
onMounted(() => {
|
|
animateText(TEXT_SLOW);
|
|
});
|
|
|
|
onUnmounted(() => timeline?.kill());
|
|
|
|
useKeyDown(({ key }) => {
|
|
if (!store.showConfirmationPopup) return;
|
|
|
|
if (textProgress.value < 1 && key === "NDS_A") {
|
|
waitingForNdsARelease = true;
|
|
animateText(TEXT_FAST);
|
|
return;
|
|
}
|
|
|
|
if (textProgress.value < 1 || waitingForNdsARelease) return;
|
|
|
|
switch (key) {
|
|
case "NDS_UP":
|
|
selectedOption = "yes";
|
|
break;
|
|
case "NDS_DOWN":
|
|
selectedOption = "no";
|
|
break;
|
|
case "NDS_A":
|
|
case "NDS_START":
|
|
setTimeout(() => {
|
|
if (selectedOption === "yes") store.visitProject();
|
|
store.showConfirmationPopup = false;
|
|
}, 5);
|
|
break;
|
|
case "NDS_B":
|
|
setTimeout(() => {
|
|
store.showConfirmationPopup = false;
|
|
}, 5);
|
|
break;
|
|
}
|
|
});
|
|
|
|
useKeyUp(({ key }) => {
|
|
if (store.showConfirmationPopup && key === "NDS_A") {
|
|
waitingForNdsARelease = false;
|
|
}
|
|
});
|
|
|
|
onClick((x, y) => {
|
|
if (
|
|
!store.showConfirmationPopup ||
|
|
textProgress.value < 1 ||
|
|
waitingForNdsARelease
|
|
)
|
|
return;
|
|
|
|
const ACTIVATION_DELAY = 50;
|
|
|
|
if (rectContains([198, 105, 50, 14], [x, y])) {
|
|
selectedOption = "yes";
|
|
setTimeout(() => {
|
|
store.visitProject();
|
|
store.showConfirmationPopup = false;
|
|
}, ACTIVATION_DELAY);
|
|
} else if (rectContains([198, 121, 50, 14], [x, y])) {
|
|
selectedOption = "no";
|
|
setTimeout(() => (store.showConfirmationPopup = false), ACTIVATION_DELAY);
|
|
}
|
|
});
|
|
|
|
const drawTextWithShadow = (
|
|
ctx: CanvasRenderingContext2D,
|
|
text: string,
|
|
x: number,
|
|
y: number,
|
|
) => {
|
|
ctx.fillStyle = "#a2a2aa";
|
|
ctx.fillText(text, x + 1, y);
|
|
ctx.fillText(text, x + 1, y + 1);
|
|
ctx.fillText(text, x, y + 1);
|
|
ctx.fillStyle = "#515159";
|
|
ctx.fillText(text, x, y);
|
|
};
|
|
|
|
onRender((ctx) => {
|
|
if (!store.showConfirmationPopup) return;
|
|
|
|
// frame
|
|
ctx.strokeStyle = "#0000007f";
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
|
|
|
// text
|
|
assets.images.projects.bottomScreen.popupTextBackground.draw(ctx, 2, 146);
|
|
ctx.font = "16px Pokemon DP Pro";
|
|
ctx.textBaseline = "top";
|
|
const displayedText = text.value.slice(
|
|
0,
|
|
Math.floor(textProgress.value * text.value.length),
|
|
);
|
|
drawTextWithShadow(ctx, displayedText, 15, TEXT_Y);
|
|
|
|
// choice box
|
|
if (textProgress.value >= 1) {
|
|
assets.images.projects.bottomScreen.popupChoiceBackground.draw(
|
|
ctx,
|
|
194,
|
|
98,
|
|
);
|
|
|
|
const y = selectedOption === "yes" ? YES_Y : NO_Y;
|
|
assets.images.projects.bottomScreen.popupSelector.draw(ctx, 200, y);
|
|
|
|
drawTextWithShadow(
|
|
ctx,
|
|
$t("projects.linkConformationPopup.yes").toUpperCase(),
|
|
207,
|
|
YES_Y - 3,
|
|
);
|
|
drawTextWithShadow(
|
|
ctx,
|
|
$t("projects.linkConformationPopup.no").toUpperCase(),
|
|
207,
|
|
NO_Y - 3,
|
|
);
|
|
}
|
|
});
|
|
|
|
defineOptions({ render: () => null });
|
|
</script>
|