fix(gallery): resolve image zoom stretching and add rich viewer features
deploy-chabokan / deploy (push) Canceled after 0s

This commit is contained in:
2026-08-30 11:25:31 +03:30
parent 7c56d2e66a
commit 195d0300a0
48 changed files with 2448 additions and 2163 deletions
+53 -74
View File
@@ -1,93 +1,72 @@
<!-- LoadingCheck.vue -->
<template>
<div class="inline-flex items-center justify-center">
<svg
:width="size"
:height="size"
viewBox="0 0 24 24"
class="transform transition-transform duration-500"
>
<circle
cx="12"
cy="12"
r="8"
fill="none"
stroke="currentColor"
stroke-width="2"
class="text-blue-500"
:style="circleStyle"
/>
<path
d="M8 12l3 3l5-5"
fill="none"
stroke="currentColor"
stroke-width="2"
class="text-green-500"
:style="checkStyle"
/>
</svg>
</div>
</template>
<script setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
const props = defineProps({
isComplete: {
type: Boolean,
default: false
},
size: {
type: Number,
default: 24
}
})
isComplete: {
type: Boolean,
default: false
},
size: {
type: Number,
default: 24
}
});
const dashOffset = ref(0)
let animationFrame = null
const dashOffset = ref(0);
let animationFrame = null;
const circleStyle = computed(() => ({
strokeDasharray: '60 60',
strokeDashoffset: props.isComplete ? '60' : String(dashOffset.value),
transition: props.isComplete ? 'all 0.2s ease-in-out' : 'none',
transformOrigin: 'center',
transform: `rotate(${props.isComplete ? -90 : 0}deg)`
}))
strokeDasharray: '60 60',
strokeDashoffset: props.isComplete ? '60' : String(dashOffset.value),
transition: props.isComplete ? 'all 0.2s ease-in-out' : 'none',
transformOrigin: 'center',
transform: `rotate(${props.isComplete ? -90 : 0}deg)`
}));
const checkStyle = computed(() => ({
opacity: props.isComplete ? 1 : 0,
strokeDasharray: 20,
strokeDashoffset: props.isComplete ? 0 : 20,
transition: 'all 0.3s ease-in-out',
transitionDelay: '0.2s'
}))
opacity: props.isComplete ? 1 : 0,
strokeDasharray: 20,
strokeDashoffset: props.isComplete ? 0 : 20,
transition: 'all 0.3s ease-in-out',
transitionDelay: '0.2s'
}));
let startTime = null
let startTime = null;
const animate = (timestamp) => {
if (!startTime) startTime = timestamp
dashOffset.value = (timestamp - startTime) / 10
animationFrame = requestAnimationFrame(animate)
}
if (!startTime) startTime = timestamp;
dashOffset.value = (timestamp - startTime) / 10;
animationFrame = requestAnimationFrame(animate);
};
watch(
() => props.isComplete,
(newValue) => {
if (newValue && animationFrame) {
cancelAnimationFrame(animationFrame)
animationFrame = null
() => props.isComplete,
(newValue) => {
if (newValue && animationFrame) {
cancelAnimationFrame(animationFrame);
animationFrame = null;
}
}
}
)
);
onMounted(() => {
if (!props.isComplete) {
animationFrame = requestAnimationFrame(animate)
}
})
if (!props.isComplete) {
animationFrame = requestAnimationFrame(animate);
}
});
onUnmounted(() => {
if (animationFrame) {
cancelAnimationFrame(animationFrame)
}
})
if (animationFrame) {
cancelAnimationFrame(animationFrame);
}
});
</script>
<template>
<div class="inline-flex items-center justify-center">
<svg :width="size" :height="size" viewBox="0 0 24 24" class="transform transition-transform duration-500">
<circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2" class="text-blue-500" :style="circleStyle" />
<path d="M8 12l3 3l5-5" fill="none" stroke="currentColor" stroke-width="2" class="text-green-500" :style="checkStyle" />
</svg>
</div>
</template>