59 lines
1.2 KiB
Vue
59 lines
1.2 KiB
Vue
<script setup lang="ts">
|
|
import { ref, watchEffect } from 'vue';
|
|
|
|
const { grow, shrink, title, size = 16, ...direction } = defineProps<{
|
|
grow?:true;
|
|
shrink?:true;
|
|
title?:string;
|
|
size?:number;
|
|
} & { [Direction in 'h' | 'v']? : true }>()
|
|
|
|
const minSize = 0;
|
|
|
|
const measure = ref()
|
|
|
|
watchEffect(() => measure.value = {
|
|
size: `${Math.max(size, minSize)}px`,
|
|
margin: `${(size-Math.max(size, minSize))/2}px`
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div :class="[$style.spacer, grow && 'grow', title && $style['has-title']]">
|
|
<slot />
|
|
</div>
|
|
</template>
|
|
|
|
<style module lang="scss">
|
|
.spacer {
|
|
width: v-bind('direction.v ? 0 : measure.size');
|
|
height: v-bind('direction.h ? 0 : measure.size');
|
|
margin: v-bind('measure.margin');
|
|
flex-grow:v-bind('grow ? 1 : 0');
|
|
flex-shrink:v-bind('shrink ? 1 : 0');
|
|
transition:flex-grow .2s, flex-shrink .2s;
|
|
|
|
position: relative;
|
|
|
|
&.has-title::after {
|
|
position:absolute;
|
|
inset:calc(50% - 1em);
|
|
content:v-bind('`"${title}"`')
|
|
}
|
|
|
|
@if $docs {
|
|
animation: blink .7s 1;
|
|
@keyframes blink { 50% {
|
|
outline: 2px dashed var(--fw-secondary);
|
|
outline-offset: v-bind('measure.margin');
|
|
} }
|
|
&:hover {
|
|
animation-iteration-count: infinite;
|
|
}
|
|
}
|
|
@else {
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
</style>
|