upend/ui/src/components/Marquee.vue

77 lines
1.4 KiB
Vue

<template>
<div
class="marquee"
:class="{ overflowed }"
:style="`--shift-width: ${shiftWidth}`"
ref="root"
>
<div class="inner" ref="inner">
<slot></slot>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref } from "vue";
export default defineComponent({
name: "Marquee",
setup() {
const root = ref<HTMLDivElement | null>(null);
const inner = ref<HTMLDivElement | null>(null);
const overflowed = ref(false);
const shiftWidth = ref("unset");
onMounted(() => {
const resizeObserver = new ResizeObserver(() => {
overflowed.value = root.value!.scrollWidth > root.value!.clientWidth;
shiftWidth.value = `-${
inner.value!.clientWidth - root.value!.clientWidth
}px`;
});
resizeObserver.observe(inner.value!);
});
return {
root,
inner,
overflowed,
shiftWidth,
};
},
});
</script>
<style scoped lang="scss">
.marquee {
line-height: 1;
overflow: hidden;
}
.inner {
white-space: nowrap;
display: inline-block;
}
</style>
<style lang="scss">
.overflowed .inner {
animation: marquee 12s ease-in-out infinite;
--padding: .5em;
}
@keyframes marquee {
0% {
transform: translateX(var(--padding));
}
50% {
transform: translateX(calc(var(--shift-width) - var(--padding)));
}
100% {
transform: translateX(var(--padding));
}
}
</style>