feat: display projects as pokemons in pokemon platinum
This commit is contained in:
134
app/components/Projects/TopScreen/Project.vue
Normal file
134
app/components/Projects/TopScreen/Project.vue
Normal file
@@ -0,0 +1,134 @@
|
||||
<script setup lang="ts">
|
||||
import BACKGROUND_IMAGE from "~/assets/images/projects/top-screen/background.webp";
|
||||
|
||||
const store = useProjectsStore();
|
||||
|
||||
const [backgroundImage, ...projectImages] = useImages(
|
||||
BACKGROUND_IMAGE,
|
||||
...store.projects.map((project) => `/images/projects/${project.id}.webp`),
|
||||
);
|
||||
|
||||
const drawTextWithShadow = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
color: "white" | "black",
|
||||
text: string,
|
||||
x: number,
|
||||
y: number,
|
||||
) => {
|
||||
ctx.fillStyle = color === "white" ? "#505050" : "#a8b8b8";
|
||||
ctx.fillText(text, x + 1, y + 0);
|
||||
ctx.fillText(text, x + 1, y + 1);
|
||||
ctx.fillText(text, x + 0, y + 1);
|
||||
|
||||
ctx.fillStyle = color === "white" ? "#f8f8f8" : "#101820";
|
||||
ctx.fillText(text, x, y);
|
||||
};
|
||||
|
||||
const drawTextWithShadow2Lines = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
text: string,
|
||||
x: number,
|
||||
y: number,
|
||||
maxWidth: number,
|
||||
line1Color: "white" | "black",
|
||||
line2Color: "white" | "black",
|
||||
) => {
|
||||
const { actualBoundingBoxRight: textWidth } = ctx.measureText(text);
|
||||
|
||||
if (textWidth <= maxWidth) {
|
||||
drawTextWithShadow(ctx, line1Color, text, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
const words = text.split(" ");
|
||||
let firstLine = "";
|
||||
let secondLine = "";
|
||||
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
const testLine = firstLine + (firstLine ? " " : "") + words[i];
|
||||
const { actualBoundingBoxRight: testWidth } = ctx.measureText(testLine);
|
||||
|
||||
if (testWidth > maxWidth && firstLine) {
|
||||
secondLine = words.slice(i).join(" ");
|
||||
break;
|
||||
}
|
||||
firstLine = testLine;
|
||||
}
|
||||
|
||||
drawTextWithShadow(ctx, line1Color, firstLine, x, y);
|
||||
drawTextWithShadow(ctx, line2Color, secondLine, x, y + 16);
|
||||
};
|
||||
|
||||
useRender((ctx) => {
|
||||
ctx.drawImage(backgroundImage!, 0, 0);
|
||||
|
||||
ctx.textBaseline = "hanging";
|
||||
ctx.font = "16px Pokemon DP Pro";
|
||||
|
||||
const project = store.projects[store.currentProject];
|
||||
if (!project) return;
|
||||
|
||||
// image
|
||||
const projectImage = projectImages[store.currentProject]!;
|
||||
ctx.drawImage(
|
||||
projectImage,
|
||||
Math.floor(52 - projectImage.width / 2),
|
||||
Math.floor(104 - projectImage.height / 2),
|
||||
);
|
||||
|
||||
// text
|
||||
drawTextWithShadow(ctx, "white", project.title.toUpperCase(), 23, 25);
|
||||
drawTextWithShadow(ctx, "black", project.scope, 12, 41);
|
||||
|
||||
drawTextWithShadow2Lines(
|
||||
ctx,
|
||||
project.description,
|
||||
8,
|
||||
161,
|
||||
90,
|
||||
"white",
|
||||
"black",
|
||||
);
|
||||
|
||||
const { actualBoundingBoxRight: textWidth } = ctx.measureText(
|
||||
project.summary,
|
||||
);
|
||||
drawTextWithShadow(
|
||||
ctx,
|
||||
"black",
|
||||
project.summary,
|
||||
Math.floor(185 - textWidth / 2),
|
||||
19,
|
||||
);
|
||||
|
||||
let textY = 35;
|
||||
for (let i = 0; i < project.tasks.length; i += 1) {
|
||||
const lines = project.tasks[i]!.split("\\n");
|
||||
|
||||
ctx.fillStyle = i % 2 === 0 ? "#6870d8" : "#8890f8";
|
||||
ctx.fillRect(106, textY - 1, 150, lines.length * 16);
|
||||
|
||||
ctx.fillStyle = i % 2 === 0 ? "#8890f8" : "#b0b8d0";
|
||||
ctx.fillRect(105, textY - 1, 1, lines.length * 16);
|
||||
|
||||
for (let j = 0; j < lines.length; j += 1) {
|
||||
drawTextWithShadow(ctx, "white", lines[j]!, 118, textY);
|
||||
textY += 16;
|
||||
}
|
||||
}
|
||||
|
||||
drawTextWithShadow2Lines(
|
||||
ctx,
|
||||
project.technologies.join(", "),
|
||||
111,
|
||||
161,
|
||||
145,
|
||||
"black",
|
||||
"black",
|
||||
);
|
||||
});
|
||||
|
||||
defineOptions({
|
||||
render: () => null,
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user