107 lines
2.6 KiB
Vue
107 lines
2.6 KiB
Vue
<script setup lang="ts">
|
|
import gsap from "gsap";
|
|
import type { Achievement } from "~/stores/achievements";
|
|
|
|
const { onRender } = useScreen();
|
|
const achievements = useAchievementsStore();
|
|
const { assets } = useAssets();
|
|
|
|
const queue = ref<Achievement[]>([]);
|
|
const currentAchievement = ref<Achievement | null>(null);
|
|
const x = ref(LOGICAL_WIDTH);
|
|
const isAnimating = ref(false);
|
|
|
|
const PADDING = 4;
|
|
const LOGO_SIZE = assets.images.achievements.notificationLogo.rect.height;
|
|
const NOTIF_WIDTH = 120;
|
|
const NOTIF_HEIGHT = LOGO_SIZE + PADDING * 2;
|
|
const NOTIF_Y = 3;
|
|
const NOTIF_X_VISIBLE = LOGICAL_WIDTH - NOTIF_WIDTH;
|
|
const TEXT_X_OFFSET = LOGO_SIZE + PADDING * 2;
|
|
const LINE_HEIGHT = 8;
|
|
|
|
achievements.$onAction(({ name, args, after }) => {
|
|
if (name === "unlock") {
|
|
after((wasUnlocked) => {
|
|
if (wasUnlocked) {
|
|
queue.value.push(args[0]);
|
|
processQueue();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
const processQueue = () => {
|
|
if (isAnimating.value || queue.value.length === 0) return;
|
|
|
|
const next = queue.value.shift();
|
|
if (!next) return;
|
|
|
|
currentAchievement.value = next;
|
|
isAnimating.value = true;
|
|
|
|
gsap
|
|
.timeline()
|
|
.to(x, {
|
|
value: NOTIF_X_VISIBLE,
|
|
duration: 0.3,
|
|
ease: "power2.out",
|
|
})
|
|
.to(
|
|
x,
|
|
{
|
|
value: LOGICAL_WIDTH,
|
|
duration: 0.3,
|
|
ease: "power2.in",
|
|
},
|
|
"+=2.5",
|
|
)
|
|
.call(() => {
|
|
currentAchievement.value = null;
|
|
isAnimating.value = false;
|
|
processQueue();
|
|
});
|
|
};
|
|
|
|
onRender((ctx) => {
|
|
if (!currentAchievement.value) return;
|
|
|
|
const logo = assets.images.achievements.notificationLogo;
|
|
|
|
// shadow
|
|
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
|
|
ctx.fillRect(x.value + 1, NOTIF_Y + 1, NOTIF_WIDTH, NOTIF_HEIGHT);
|
|
|
|
// border
|
|
ctx.fillStyle = "#282828";
|
|
ctx.fillRect(x.value, NOTIF_Y, NOTIF_WIDTH, 1); // Top
|
|
ctx.fillRect(x.value, NOTIF_Y, 1, NOTIF_HEIGHT); // Left
|
|
ctx.fillRect(x.value, NOTIF_Y + NOTIF_HEIGHT - 1, NOTIF_WIDTH, 1); // Bottom
|
|
|
|
// background
|
|
ctx.fillStyle = "#fafafa";
|
|
ctx.fillRect(x.value + 1, NOTIF_Y + 1, NOTIF_WIDTH - 1, NOTIF_HEIGHT - 2);
|
|
|
|
// logo
|
|
logo.draw(ctx, x.value + PADDING, NOTIF_Y + PADDING);
|
|
|
|
// text (1 or 2 lines)
|
|
ctx.font = "7px NDS7";
|
|
ctx.fillStyle = "#282828";
|
|
|
|
const lines = $t(`achievements.${currentAchievement.value}`).split("\n");
|
|
const textY =
|
|
lines.length === 1 ? NOTIF_Y + PADDING + 4 : NOTIF_Y + PADDING + 1;
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
ctx.fillText(
|
|
lines[i]!,
|
|
x.value + TEXT_X_OFFSET,
|
|
textY + i * LINE_HEIGHT + 7,
|
|
);
|
|
}
|
|
}, 200);
|
|
|
|
defineOptions({ render: () => null });
|
|
</script>
|