feat(settings): number input animation

This commit is contained in:
2026-02-06 13:10:59 +01:00
parent 04a5a36305
commit 3bd114ccde

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
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
"#ba4900": "#fbe3d3", // maroon "#ba4900": "#fbe3d3", // maroon
@@ -78,6 +80,48 @@ const downImage = computed(() => {
const squareWidth = computed(() => upImage.value.rect.width); const squareWidth = computed(() => upImage.value.rect.width);
const SLIDE_OFFSET = 96;
const SLIDE_DURATION = 0.25;
const ARROW_SLIDE_DELAY = 0.15;
const ARROW_SLIDE_DURATION = 0.15;
const animation = reactive({
offsetY: SLIDE_OFFSET,
opacity: 0,
upArrowOffsetY: ARROW_IMAGE_HEIGHT,
downArrowOffsetY: -ARROW_IMAGE_HEIGHT,
});
const animateIntro = async () => {
await gsap
.timeline()
.to(animation, { offsetY: 0, duration: SLIDE_DURATION, ease: "none" }, 0)
.to(animation, { opacity: 1, duration: SLIDE_DURATION, ease: "none" }, 0)
.to(
animation,
{ upArrowOffsetY: 0, duration: ARROW_SLIDE_DURATION, ease: "none" },
SLIDE_DURATION + ARROW_SLIDE_DELAY,
)
.to(
animation,
{ downArrowOffsetY: 0, duration: ARROW_SLIDE_DURATION, ease: "none" },
SLIDE_DURATION + ARROW_SLIDE_DELAY,
);
};
const animateOutro = async () => {
await gsap
.timeline()
.to(
animation,
{ offsetY: SLIDE_OFFSET, duration: SLIDE_DURATION, ease: "none" },
0,
)
.to(animation, { opacity: 0, duration: SLIDE_DURATION, ease: "none" }, 0);
};
defineExpose({ animateIntro, animateOutro });
const increase = () => { const increase = () => {
const newValue = value.value + 1; const newValue = value.value + 1;
value.value = newValue > props.max ? props.min : newValue; value.value = newValue > props.max ? props.min : newValue;
@@ -89,8 +133,16 @@ const decrease = () => {
}; };
onRender((ctx) => { onRender((ctx) => {
// arrow up ctx.globalAlpha = animation.opacity;
upImage.value.draw(ctx, props.x, Y); ctx.translate(0, animation.offsetY);
// arrow up (clipped to area above the number square)
ctx.save();
ctx.beginPath();
ctx.rect(props.x, 0, squareWidth.value, Y + ARROW_IMAGE_HEIGHT);
ctx.clip();
upImage.value.draw(ctx, props.x, Y + animation.upArrowOffsetY);
ctx.restore();
// outline // outline
ctx.fillStyle = "#515151"; ctx.fillStyle = "#515151";
@@ -123,8 +175,22 @@ onRender((ctx) => {
Y + ARROW_IMAGE_HEIGHT + Math.floor((SQUARE_HEIGHT - 39) / 2), Y + ARROW_IMAGE_HEIGHT + Math.floor((SQUARE_HEIGHT - 39) / 2),
); );
// arrow down // arrow down (clipped to area below the number square)
downImage.value.draw(ctx, props.x, Y + ARROW_IMAGE_HEIGHT + SQUARE_HEIGHT); ctx.save();
ctx.beginPath();
ctx.rect(
props.x,
Y + ARROW_IMAGE_HEIGHT + SQUARE_HEIGHT,
squareWidth.value,
ARROW_IMAGE_HEIGHT,
);
ctx.clip();
downImage.value.draw(
ctx,
props.x,
Y + ARROW_IMAGE_HEIGHT + SQUARE_HEIGHT + animation.downArrowOffsetY,
);
ctx.restore();
// title // title
ctx.font = "10px NDS10"; ctx.font = "10px NDS10";