schon/storefront/app/components/demo/ui/checkbox.vue
2026-02-27 21:59:51 +03:00

187 lines
No EOL
3.7 KiB
Vue

<template>
<label class="checkbox">
<input
:id="id"
type="checkbox"
:checked="modelValue"
@change="$emit('update:modelValue', ($event.target as HTMLInputElement).checked)"
/>
<span class="checkbox__box">
<span class="checkbox__mark"></span>
</span>
<span
class="checkbox__label"
:data-text="label"
>
{{ label }}
</span>
</label>
</template>
<script setup lang="ts">
const props = defineProps<{
label: string;
modelValue: boolean;
id: number;
}>();
defineEmits<{
'update:modelValue': [value: boolean]
}>();
</script>
<style lang="scss" scoped>
.checkbox {
width: fit-content;
display: flex;
align-items: center;
gap: 15px;
cursor: pointer;
user-select: none;
position: relative;
--glitch-anim-duration: 0.3s;
& input {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
&__box {
width: 1.5em;
height: 1.5em;
border: 2px solid $accentNeon;
position: relative;
transition: all 0.3s ease;
clip-path: polygon(
15% 0,
85% 0,
100% 15%,
100% 85%,
85% 100%,
15% 100%,
0 85%,
0 15%
);
}
&__mark {
position: absolute;
top: 50%;
left: 50%;
width: 60%;
height: 60%;
background-color: $accentNeon;
transform: translate(-50%, -50%) scale(0);
opacity: 0;
transition: all 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
clip-path: inherit;
}
&__label {
color: $white;
font-weight: 500;
font-size: 18px;
text-transform: uppercase;
position: relative;
transition:
color 0.3s ease,
text-shadow 0.3s ease;
}
}
.checkbox input:checked + .checkbox__box .checkbox__mark {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
animation: glitch-anim-checkbox var(--glitch-anim-duration) both;
}
.checkbox input:checked ~ .checkbox__label {
color: $accentNeon;
text-shadow: 0 0 8px $accentNeon;
}
.checkbox:hover .checkbox__box {
box-shadow: 0 0 10px $accentNeon;
}
.checkbox:hover .checkbox__label::before,
.checkbox:hover .checkbox__label::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #050505;
}
.checkbox:hover .checkbox__label::before {
color: #a855f7;
animation: glitch-anim-text var(--glitch-anim-duration)
cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
}
.checkbox:hover .checkbox__label::after {
color: $accentNeon;
animation: glitch-anim-text var(--glitch-anim-duration)
cubic-bezier(0.25, 0.46, 0.45, 0.94) reverse both;
}
@keyframes glitch-anim-checkbox {
0% {
transform: translate(-50%, -50%);
clip-path: inset(0 0 0 0);
}
20% {
transform: translate(calc(-50% - 3px), calc(-50% + 2px));
clip-path: inset(50% 0 20% 0);
}
40% {
transform: translate(calc(-50% + 2px), calc(-50% - 1px));
clip-path: inset(20% 0 60% 0);
}
60% {
transform: translate(calc(-50% - 2px), calc(-50% + 1px));
clip-path: inset(80% 0 5% 0);
}
80% {
transform: translate(calc(-50% + 2px), calc(-50% - 2px));
clip-path: inset(30% 0 45% 0);
}
100% {
transform: translate(-50%, -50%);
clip-path: inset(0 0 0 0);
}
}
@keyframes glitch-anim-text {
0% {
transform: translate(0);
clip-path: inset(0 0 0 0);
}
20% {
transform: translate(-3px, 2px);
clip-path: inset(50% 0 20% 0);
}
40% {
transform: translate(2px, -1px);
clip-path: inset(20% 0 60% 0);
}
60% {
transform: translate(-2px, 1px);
clip-path: inset(80% 0 5% 0);
}
80% {
transform: translate(2px, -2px);
clip-path: inset(30% 0 45% 0);
}
100% {
transform: translate(0);
clip-path: inset(0 0 0 0);
}
}
</style>