changed component folders

This commit is contained in:
Mamalizz
2025-01-14 18:49:23 +03:30
parent 857a770401
commit 4e97761782
31 changed files with 24 additions and 612 deletions
+138
View File
@@ -0,0 +1,138 @@
<script setup lang="ts">
// types
type Props = {
status?: "success" | "error" | "idle";
modelValue: never[];
autofocus?: boolean;
disabled?: boolean;
}
// props
const props = withDefaults(defineProps<Props>(), {
status: "idle"
});
const { modelValue, disabled, status } = toRefs(props);
// state
const { $gsap: gsap } = useNuxtApp();
// emit
const emit = defineEmits(["complete", "update:modelValue"]);
// state
const currentOtpCode = ref([]);
// methods
const handleChange = () => {
emit("update:modelValue", currentOtpCode.value);
};
const handleComplete = () => {
emit("update:modelValue", currentOtpCode.value);
emit("complete", currentOtpCode.value);
};
const playStatusAnimation = () => {
const inputCount = 6;
const duration = 0.100;
let statusColor = {
border : "",
bg : ""
};
if (status.value === "success") {
statusColor.border = "var(--color-success-500)";
statusColor.bg = "var(--color-success-50)";
} else if (status.value === "error") {
statusColor.border = "var(--color-danger-500)";
statusColor.bg = "var(--color-danger-50)";
}
let index = 0;
const animate = (index: number) => {
setTimeout(() => {
gsap.to(`#otp-input-${index}`, {
borderColor: statusColor.border,
backgroundColor: statusColor.bg,
scale: 1.2,
duration: duration / 2
});
gsap.to(`#otp-input-${index}`, {
scale: 1,
duration: duration / 2,
delay: duration
});
setTimeout(() => {
gsap.to(`#otp-input-${index}`, {
borderColor: "black",
backgroundColor: "var(--color-slate-50)"
});
}, (inputCount + 1) * duration * 3000);
}, index * duration * 500);
};
while (index < 6) {
animate(index);
index++;
}
};
// watch
watch(() => modelValue.value, (value) => {
currentOtpCode.value = value;
});
watch(() => disabled.value, (value) => {
if (!value) {
const otpInputFirst = document.querySelector("#otp-input-0") as HTMLInputElement;
setTimeout(() => {
otpInputFirst.focus();
}, 100);
}
});
watch(() => status.value, (value) => {
if (value !== "idle") {
playStatusAnimation();
}
});
</script>
<template>
<div>
<PinInputRoot
:disabled="disabled"
v-bind="$attrs"
type="number"
v-model="currentOtpCode"
placeholder="_"
class="flex gap-4 items-center justify-center mt-1"
@change="handleChange"
@complete="handleComplete"
otp
>
<PinInputInput
v-for="(id, index) in 6"
:id="`otp-input-${index}`"
:key="id"
:index="index"
:autofocus="autofocus ? index === 0 ? true : 'off' : 'off'"
class="disabled:text-slate-400 focus-within:border-black transition-all size-16 bg-slate-50 typo-label-lg rounded-lg text-center border-[1.5px] border-slate-200 outline-none"
/>
</PinInputRoot>
</div>
</template>