2023-07-27 14:31:52 +09:00
|
|
|
<!--
|
2024-02-14 00:59:27 +09:00
|
|
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
2023-07-27 14:31:52 +09:00
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
-->
|
|
|
|
|
2022-07-02 21:28:04 +09:00
|
|
|
<script lang="ts">
|
2022-07-02 22:07:04 +09:00
|
|
|
import { h, onMounted, onUnmounted, ref, watch } from 'vue';
|
2022-07-02 21:28:04 +09:00
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'MarqueeText',
|
|
|
|
props: {
|
|
|
|
duration: {
|
|
|
|
type: Number,
|
|
|
|
default: 15,
|
|
|
|
},
|
|
|
|
repeat: {
|
|
|
|
type: Number,
|
|
|
|
default: 2,
|
|
|
|
},
|
|
|
|
paused: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
reverse: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
setup(props) {
|
2023-12-26 14:19:35 +09:00
|
|
|
const contentEl = ref<HTMLElement>();
|
2022-07-02 21:28:04 +09:00
|
|
|
|
|
|
|
function calc() {
|
2024-01-30 19:53:53 +09:00
|
|
|
if (contentEl.value == null) return;
|
2022-07-02 21:28:04 +09:00
|
|
|
const eachLength = contentEl.value.offsetWidth / props.repeat;
|
|
|
|
const factor = 3000;
|
|
|
|
const duration = props.duration / ((1 / eachLength) * factor);
|
|
|
|
|
|
|
|
contentEl.value.style.animationDuration = `${duration}s`;
|
|
|
|
}
|
|
|
|
|
2022-07-02 22:07:04 +09:00
|
|
|
watch(() => props.duration, calc);
|
|
|
|
|
2022-07-02 21:28:04 +09:00
|
|
|
onMounted(() => {
|
|
|
|
calc();
|
|
|
|
});
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
|
|
contentEl,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
render({
|
|
|
|
$slots, $style, $props: {
|
|
|
|
duration, repeat, paused, reverse,
|
|
|
|
},
|
|
|
|
}) {
|
|
|
|
return h('div', { class: [$style.wrap] }, [
|
|
|
|
h('span', {
|
|
|
|
ref: 'contentEl',
|
|
|
|
class: [
|
|
|
|
paused
|
|
|
|
? $style.paused
|
|
|
|
: undefined,
|
|
|
|
$style.content,
|
|
|
|
],
|
|
|
|
}, Array(repeat).fill(
|
|
|
|
h('span', {
|
|
|
|
class: $style.text,
|
|
|
|
style: {
|
|
|
|
animationDirection: reverse
|
|
|
|
? 'reverse'
|
|
|
|
: undefined,
|
|
|
|
},
|
|
|
|
}, $slots.default()),
|
|
|
|
)),
|
|
|
|
]);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" module>
|
|
|
|
.wrap {
|
2022-07-13 21:41:06 +09:00
|
|
|
overflow: clip;
|
2022-07-05 16:16:13 +09:00
|
|
|
animation-play-state: running;
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
animation-play-state: paused;
|
|
|
|
}
|
2022-07-02 21:28:04 +09:00
|
|
|
}
|
|
|
|
.content {
|
|
|
|
display: inline-block;
|
|
|
|
white-space: nowrap;
|
2022-07-05 16:16:13 +09:00
|
|
|
animation-play-state: inherit;
|
2022-07-02 21:28:04 +09:00
|
|
|
}
|
|
|
|
.text {
|
|
|
|
display: inline-block;
|
|
|
|
animation-name: marquee;
|
|
|
|
animation-timing-function: linear;
|
|
|
|
animation-iteration-count: infinite;
|
|
|
|
animation-duration: inherit;
|
2022-07-05 16:16:13 +09:00
|
|
|
animation-play-state: inherit;
|
2022-07-02 21:28:04 +09:00
|
|
|
}
|
|
|
|
.paused .text {
|
|
|
|
animation-play-state: paused;
|
|
|
|
}
|
|
|
|
@keyframes marquee {
|
|
|
|
0% { transform:translateX(0); }
|
|
|
|
100% { transform:translateX(-100%); }
|
|
|
|
}
|
|
|
|
</style>
|