feat(settings/clock/achievements): intro and outro animation
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SettingsBottomScreenNumberInput as NumberInput } from "#components";
|
import { SettingsBottomScreenNumberInput as NumberInput } from "#components";
|
||||||
import { ICONS } from "~/utils/icons";
|
import { ICONS } from "~/utils/icons";
|
||||||
|
import gsap from "gsap";
|
||||||
|
|
||||||
const APP_COLOR_TO_FONT_COLOR: Record<string, string> = {
|
const APP_COLOR_TO_FONT_COLOR: Record<string, string> = {
|
||||||
"#61829a": "#fbfbfb", // cyan
|
"#61829a": "#fbfbfb", // cyan
|
||||||
@@ -32,7 +33,68 @@ const achievements = useAchievementsStore();
|
|||||||
const achievementsScreen = useAchievementsScreen();
|
const achievementsScreen = useAchievementsScreen();
|
||||||
const confirmationModal = useConfirmationModal();
|
const confirmationModal = useConfirmationModal();
|
||||||
|
|
||||||
const handleCancel = () => {
|
const SLIDE_OFFSET = 96;
|
||||||
|
const SLIDE_DURATION = 0.25;
|
||||||
|
const ARROW_SLIDE_DELAY = 0.15;
|
||||||
|
const ARROW_SLIDE_DURATION = 0.15;
|
||||||
|
const VIEW_ALL_OFFSET = -20;
|
||||||
|
|
||||||
|
const animation = reactive({
|
||||||
|
offsetY: SLIDE_OFFSET,
|
||||||
|
opacity: 0,
|
||||||
|
viewAllOffsetY: VIEW_ALL_OFFSET,
|
||||||
|
});
|
||||||
|
|
||||||
|
const obtainedRef =
|
||||||
|
useTemplateRef<InstanceType<typeof NumberInput>>("obtained");
|
||||||
|
const totalRef = useTemplateRef<InstanceType<typeof NumberInput>>("total");
|
||||||
|
|
||||||
|
const animateIntro = async () => {
|
||||||
|
await Promise.all([
|
||||||
|
obtainedRef.value?.animateIntro(),
|
||||||
|
totalRef.value?.animateIntro(),
|
||||||
|
gsap
|
||||||
|
.timeline()
|
||||||
|
.to(animation, { offsetY: 0, duration: SLIDE_DURATION, ease: "none" }, 0)
|
||||||
|
.to(animation, { opacity: 1, duration: SLIDE_DURATION, ease: "none" }, 0)
|
||||||
|
.to(
|
||||||
|
animation,
|
||||||
|
{ viewAllOffsetY: 0, duration: ARROW_SLIDE_DURATION, ease: "none" },
|
||||||
|
SLIDE_DURATION + ARROW_SLIDE_DELAY,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const animateOutro = async () => {
|
||||||
|
await Promise.all([
|
||||||
|
obtainedRef.value?.animateOutro(),
|
||||||
|
totalRef.value?.animateOutro(),
|
||||||
|
gsap
|
||||||
|
.timeline()
|
||||||
|
.to(
|
||||||
|
animation,
|
||||||
|
{
|
||||||
|
viewAllOffsetY: VIEW_ALL_OFFSET,
|
||||||
|
duration: ARROW_SLIDE_DURATION,
|
||||||
|
ease: "none",
|
||||||
|
},
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.to(
|
||||||
|
animation,
|
||||||
|
{ offsetY: SLIDE_OFFSET, duration: SLIDE_DURATION, ease: "none" },
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
.to(animation, { opacity: 0, duration: SLIDE_DURATION, ease: "none" }, 0),
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
animateIntro();
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleCancel = async () => {
|
||||||
|
await animateOutro();
|
||||||
store.closeSubMenu();
|
store.closeSubMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,6 +128,8 @@ onRender((ctx) => {
|
|||||||
assets.images.home.topScreen.background.draw(ctx, 0, 0);
|
assets.images.home.topScreen.background.draw(ctx, 0, 0);
|
||||||
|
|
||||||
// slash divider
|
// slash divider
|
||||||
|
ctx.globalAlpha = animation.opacity;
|
||||||
|
ctx.translate(0, animation.offsetY);
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
ctx.fillStyle = "#515151";
|
ctx.fillStyle = "#515151";
|
||||||
ctx.fillRect(7 * 16 - 1, 4 * 16 - 1, 16 * 3 + 1, 16 * 3 + 1);
|
ctx.fillRect(7 * 16 - 1, 4 * 16 - 1, 16 * 3 + 1, 16 * 3 + 1);
|
||||||
@@ -80,6 +144,8 @@ onRender((ctx) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
onRender((ctx) => {
|
onRender((ctx) => {
|
||||||
|
ctx.translate(0, animation.viewAllOffsetY);
|
||||||
|
|
||||||
achievementAssets.viewAllButton.draw(ctx, 127, 2);
|
achievementAssets.viewAllButton.draw(ctx, 127, 2);
|
||||||
achievementAssets.smallTrophy.draw(ctx, 131, 6);
|
achievementAssets.smallTrophy.draw(ctx, 131, 6);
|
||||||
|
|
||||||
@@ -100,6 +166,7 @@ onRender((ctx) => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NumberInput
|
<NumberInput
|
||||||
|
ref="obtained"
|
||||||
:model-value="achievements.unlocked.length"
|
:model-value="achievements.unlocked.length"
|
||||||
:title="$t('settings.clock.achievements.obtained')"
|
:title="$t('settings.clock.achievements.obtained')"
|
||||||
:x="4 * 16 - 1"
|
:x="4 * 16 - 1"
|
||||||
@@ -108,6 +175,7 @@ onRender((ctx) => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<NumberInput
|
<NumberInput
|
||||||
|
ref="total"
|
||||||
:model-value="ACHIEVEMENTS.length"
|
:model-value="ACHIEVEMENTS.length"
|
||||||
:title="$t('settings.clock.achievements.total')"
|
:title="$t('settings.clock.achievements.total')"
|
||||||
:x="9 * 16 - 1"
|
:x="9 * 16 - 1"
|
||||||
|
|||||||
Reference in New Issue
Block a user