mirror of
https://github.com/hanzoai/vitest.git
synced 2026-10-30 14:46:34 +00:00
104 lines
2.2 KiB
Vue
104 lines
2.2 KiB
Vue
<script setup lang="ts">
|
|
import { Icon } from '@iconify/vue'
|
|
import { until, useElementVisibility } from '@vueuse/core'
|
|
import { computed, effectScope, onMounted, ref } from 'vue'
|
|
|
|
const el = ref<HTMLDivElement>()
|
|
const state = ref(0)
|
|
|
|
function reset() {
|
|
state.value = 0
|
|
setTimeout(() => {
|
|
state.value = Math.random() > 0.9 ? 2 : 1
|
|
if (state.value === 2) {
|
|
setTimeout(reset, 1000)
|
|
}
|
|
}, Math.round(Math.random() * 3000) + 400)
|
|
}
|
|
|
|
const color = computed(() => {
|
|
return {
|
|
'--vp-c-brand-1': state.value === 1
|
|
? 'var(--color-brand)'
|
|
: state.value === 2
|
|
? 'var(--vp-c-red-1)'
|
|
: 'var(--vp-c-yellow-1)',
|
|
} as any
|
|
})
|
|
|
|
const scope = effectScope()
|
|
|
|
const visibility = scope.run(() => useElementVisibility(el))
|
|
|
|
onMounted(async () => {
|
|
await until(visibility).toBe(true)
|
|
|
|
scope.stop()
|
|
reset()
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<li :style="color">
|
|
<div ref="el" class="icon-container">
|
|
<div class="icon-wrapper" :class="state ? 'flip' : ''">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 32 32" class="icon-spinner">
|
|
<circle cx="16" cy="16" r="13" fill="none" stroke="currentColor" stroke-width="2" stroke-dasharray="8 4" />
|
|
</svg>
|
|
</div>
|
|
<div class="icon-wrapper" :class="state === 2 ? '' : 'flip'">
|
|
<Icon icon="carbon:close-outline" class="icon-error" width="1.2em" height="1.2em" />
|
|
</div>
|
|
<div class="icon-wrapper" :class="state === 1 ? '' : 'flip'">
|
|
<Icon icon="carbon:checkmark-outline" class="icon-success" width="1.2em" height="1.2em" />
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<slot />
|
|
</div>
|
|
</li>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.icon-container {
|
|
position: relative;
|
|
width: 1.2em;
|
|
height: 1.2em;
|
|
flex: none;
|
|
margin-top: auto;
|
|
margin-bottom: auto;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
.icon-wrapper {
|
|
position: absolute;
|
|
transition: all 300ms;
|
|
}
|
|
|
|
.flip {
|
|
transform: rotateY(90deg);
|
|
}
|
|
|
|
.icon-spinner {
|
|
animation: spin 1s linear infinite;
|
|
color: var(--vp-c-yellow-1);
|
|
}
|
|
|
|
.icon-error {
|
|
color: var(--vp-c-red-1);
|
|
}
|
|
|
|
.icon-success {
|
|
color: var(--color-brand);
|
|
}
|
|
|
|
@keyframes spin {
|
|
from {
|
|
transform: rotate(0deg);
|
|
}
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
}
|
|
</style>
|