Files
pihkaal-me/app/components/Projects/TopScreen/Project.vue

160 lines
3.8 KiB
Vue

<script setup lang="ts">
const { onRender } = useScreen();
const store = useProjectsStore();
const { assets } = useAssets();
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);
};
onRender((ctx) => {
assets.images.projects.topScreen.background.draw(ctx, 0, 0);
ctx.textBaseline = "top";
ctx.font = "16px Pokemon DP Pro";
const project = store.projects[store.currentProject];
if (!project) return;
const thumbnailCenterX = 52;
const thumbnailCenterY = 104;
const thumbnailSpacing = 104;
ctx.save();
ctx.beginPath();
ctx.rect(0, 56, 104, 101);
ctx.clip();
// draw previous - current - next
for (let i = store.currentProject - 1; i <= store.currentProject + 1; i++) {
if (i < 0 || i >= store.projects.length) continue;
const offsetFromCurrent = i - store.currentProject;
// TODO: project.id should be typed from useAssets, shouldn't be just a string
const thumbnailImage =
assets.images.projects.pokemons[
store.projects[i]!.id as keyof typeof assets.images.projects.pokemons
]!;
thumbnailImage.draw(
ctx,
Math.floor(
thumbnailCenterX +
offsetFromCurrent * thumbnailSpacing -
thumbnailImage.rect.width / 2 +
store.offsetX,
),
Math.floor(thumbnailCenterY - thumbnailImage.rect.height / 2),
);
}
ctx.restore();
// text
drawTextWithShadow(ctx, "white", project.title.toUpperCase(), 23, 23);
drawTextWithShadow(ctx, "black", project.scope, 12, 39);
drawTextWithShadow2Lines(
ctx,
project.description,
8,
159,
90,
"white",
"black",
);
const { actualBoundingBoxRight: textWidth } = ctx.measureText(
project.summary,
);
drawTextWithShadow(
ctx,
"black",
project.summary,
Math.floor(185 - textWidth / 2),
17,
);
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 - 2);
textY += 16;
}
}
drawTextWithShadow2Lines(
ctx,
project.technologies.join(", "),
111,
159,
145,
"black",
"black",
);
ctx.fillStyle = `rgba(0, 0, 0, ${store.isIntro ? store.intro.fadeOpacity : store.isOutro ? store.outro.fadeOpacity : 0})`;
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
});
defineOptions({
render: () => null,
});
</script>