feat: display projects as pokemons in pokemon platinum
This commit is contained in:
@@ -1,33 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "/assets/images/projects/bottom-screen/background.webp";
|
||||
import VISIT_DISABLED_IMAGE from "/assets/images/projects/bottom-screen/visit-disabled.webp";
|
||||
import BACKGROUND_IMAGE from "~/assets/images/projects/bottom-screen/background.webp";
|
||||
|
||||
const store = useProjectsStore();
|
||||
|
||||
const [backgroundImage, visitDisabledImage] = useImages(
|
||||
BACKGROUND_IMAGE,
|
||||
VISIT_DISABLED_IMAGE,
|
||||
);
|
||||
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
|
||||
if (store.projects[store.currentProject]?.url === null) {
|
||||
ctx.drawImage(visitDisabledImage!, 144, 172);
|
||||
}
|
||||
});
|
||||
|
||||
const QUIT_BUTTON: Rect = [31, 172, 80, 18];
|
||||
const OK_BUTTON: Rect = [144, 172, 80, 18];
|
||||
|
||||
useScreenClick((x, y) => {
|
||||
if (rectContains(QUIT_BUTTON, [x, y])) {
|
||||
// TODO: outro
|
||||
} else if (rectContains(OK_BUTTON, [x, y])) {
|
||||
store.visitProject();
|
||||
}
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
render: () => null,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import Background from "./Background.vue";
|
||||
import Projects from "./Projects.vue";
|
||||
import Buttons from "./Buttons.vue";
|
||||
|
||||
const store = useProjectsStore();
|
||||
|
||||
@@ -13,5 +13,5 @@ onMounted(async () => {
|
||||
<template>
|
||||
<Background />
|
||||
|
||||
<Projects v-if="!store.loading" />
|
||||
<Buttons v-if="!store.loading" />
|
||||
</template>
|
||||
|
||||
56
app/components/Projects/BottomScreen/Buttons.vue
Normal file
56
app/components/Projects/BottomScreen/Buttons.vue
Normal file
@@ -0,0 +1,56 @@
|
||||
<script setup lang="ts">
|
||||
const store = useProjectsStore();
|
||||
|
||||
const PREV_BUTTON: Point = [36, 100];
|
||||
const QUIT_BUTTON: Point = [88, 156];
|
||||
const LINK_BUTTON: Point = [168, 156];
|
||||
const NEXT_BUTTON: Point = [220, 100];
|
||||
|
||||
const CLICK_RADIUS = 22;
|
||||
|
||||
const circleContains = (
|
||||
[cx, cy]: Point,
|
||||
[x, y]: Point,
|
||||
radius: number,
|
||||
): boolean => Math.sqrt(Math.pow(x - cx, 2) + Math.pow(y - cy, 2)) < radius;
|
||||
|
||||
useScreenClick((x, y) => {
|
||||
const project = store.projects[store.currentProject];
|
||||
if (circleContains(PREV_BUTTON, [x, y], CLICK_RADIUS)) {
|
||||
store.scrollProjects("left");
|
||||
} else if (circleContains(NEXT_BUTTON, [x, y], CLICK_RADIUS)) {
|
||||
store.scrollProjects("right");
|
||||
} else if (circleContains(QUIT_BUTTON, [x, y], CLICK_RADIUS)) {
|
||||
throw new Error("quit");
|
||||
} else if (
|
||||
circleContains(LINK_BUTTON, [x, y], CLICK_RADIUS) &&
|
||||
project?.link
|
||||
) {
|
||||
// TODO: show confirmation popup before opening the link, like "you are about to navigate to [...]"
|
||||
store.visitProject();
|
||||
}
|
||||
});
|
||||
|
||||
useScreenMouseWheel((dy) => {
|
||||
if (dy > 0) {
|
||||
store.scrollProjects("right");
|
||||
} else if (dy < 0) {
|
||||
store.scrollProjects("left");
|
||||
}
|
||||
});
|
||||
|
||||
useKeyDown((key) => {
|
||||
switch (key) {
|
||||
case "ArrowLeft":
|
||||
store.scrollProjects("left");
|
||||
break;
|
||||
case "ArrowRight":
|
||||
store.scrollProjects("right");
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
render: () => null,
|
||||
});
|
||||
</script>
|
||||
@@ -1,85 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import SELECTOR_IMAGE from "/assets/images/projects/bottom-screen/selector.webp";
|
||||
import PROJECT_SQUARE_IMAGE from "/assets/images/projects/bottom-screen/project-square.webp";
|
||||
|
||||
const store = useProjectsStore();
|
||||
|
||||
const [selectorImage, projectSquareImage, ...projectThumbnails] = useImages(
|
||||
SELECTOR_IMAGE,
|
||||
PROJECT_SQUARE_IMAGE,
|
||||
...store.projects.map((x) => x.thumbnail),
|
||||
);
|
||||
|
||||
const getBounds = () => ({
|
||||
startIndex: Math.max(store.currentProject - 3, 0),
|
||||
endIndex: Math.min(store.currentProject + 3 + 1, store.projects.length),
|
||||
});
|
||||
|
||||
useRender((ctx) => {
|
||||
const { startIndex, endIndex } = getBounds();
|
||||
|
||||
for (let i = startIndex; i < endIndex; i += 1) {
|
||||
const offsetFromCenter = i - store.currentProject;
|
||||
const x = 101 + 69 * offsetFromCenter + store.offsetX;
|
||||
|
||||
ctx.drawImage(projectSquareImage!, x, 81);
|
||||
ctx.drawImage(projectThumbnails[i]!, x + 7, 88);
|
||||
}
|
||||
|
||||
ctx.drawImage(selectorImage!, 96, 76);
|
||||
|
||||
ctx.font = "10px NDS10";
|
||||
|
||||
const lines = store.projects[store.currentProject]!.description.split("\\n");
|
||||
const textY = lines.length === 1 ? 35 : 28;
|
||||
for (let i = 0; i < lines.length; i += 1) {
|
||||
const { actualBoundingBoxRight: width } = ctx.measureText(lines[i]!);
|
||||
ctx.fillText(lines[i]!, Math.floor(128 - width / 2), textY + 15 * i);
|
||||
}
|
||||
});
|
||||
|
||||
useKeyDown((key) => {
|
||||
switch (key) {
|
||||
case "ArrowLeft":
|
||||
store.scrollProjects("left");
|
||||
break;
|
||||
case "ArrowRight":
|
||||
store.scrollProjects("right");
|
||||
break;
|
||||
case "Enter":
|
||||
case " ":
|
||||
store.visitProject();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
useScreenMouseWheel((dy) => {
|
||||
if (dy > 0) {
|
||||
store.scrollProjects("right");
|
||||
} else if (dy < 0) {
|
||||
store.scrollProjects("left");
|
||||
}
|
||||
});
|
||||
|
||||
useScreenClick((x, y) => {
|
||||
const { startIndex, endIndex } = getBounds();
|
||||
|
||||
for (let i = startIndex; i < endIndex; i += 1) {
|
||||
const offsetFromCenter = i - store.currentProject;
|
||||
const rectX = 101 + 69 * offsetFromCenter + store.offsetX;
|
||||
|
||||
if (rectContains([rectX, 81, 54, 54], [x, y])) {
|
||||
if (i === store.currentProject) {
|
||||
store.visitProject();
|
||||
} else {
|
||||
store.scrollToProject(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
render: () => null,
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user