diff --git a/packages/frontend/src/components/MkMarquee.vue b/packages/frontend/src/components/MkMarquee.vue deleted file mode 100644 index 4a89d21b92..0000000000 --- a/packages/frontend/src/components/MkMarquee.vue +++ /dev/null @@ -1,112 +0,0 @@ -<!-- -SPDX-FileCopyrightText: syuilo and misskey-project -SPDX-License-Identifier: AGPL-3.0-only ---> - -<script lang="ts"> -import { h, onMounted, onUnmounted, ref, watch } from 'vue'; - -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) { - const contentEl = ref<HTMLElement>(); - - function calc() { - if (contentEl.value == null) return; - const eachLength = contentEl.value.offsetWidth / props.repeat; - const factor = 3000; - const duration = props.duration / ((1 / eachLength) * factor); - - contentEl.value.style.animationDuration = `${duration}s`; - } - - watch(() => props.duration, calc); - - 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 { - overflow: clip; - animation-play-state: running; - - &:hover { - animation-play-state: paused; - } -} -.content { - display: inline-block; - white-space: nowrap; - animation-play-state: inherit; -} -.text { - display: inline-block; - animation-name: marquee; - animation-timing-function: linear; - animation-iteration-count: infinite; - animation-duration: inherit; - animation-play-state: inherit; -} -.paused .text { - animation-play-state: paused; -} -@keyframes marquee { - 0% { transform:translateX(0); } - 100% { transform:translateX(-100%); } -} -</style> diff --git a/packages/frontend/src/components/MkMarqueeText.vue b/packages/frontend/src/components/MkMarqueeText.vue new file mode 100644 index 0000000000..a2c365afe9 --- /dev/null +++ b/packages/frontend/src/components/MkMarqueeText.vue @@ -0,0 +1,89 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div :class="$style.wrap"> + <span + ref="contentEl" + :class="[$style.content, { + [$style.paused]: paused, + [$style.reverse]: reverse, + }]" + > + <span v-for="key in repeat" :key="key" :class="$style.text"> + <slot></slot> + </span> + </span> +</div> +</template> + +<script lang="ts" setup> +import { onMounted, useTemplateRef, watch } from 'vue'; + +const props = withDefaults(defineProps<{ + duration?: number; + repeat?: number; + paused?: boolean; + reverse?: boolean; +}>(), { + duration: 15, + repeat: 2, + paused: false, + reverse: false, +}); + +const contentEl = useTemplateRef('contentEl'); + +function calcDuration() { + if (contentEl.value == null) return; + const eachLength = contentEl.value.offsetWidth / props.repeat; + const factor = 3000; + const duration = props.duration / ((1 / eachLength) * factor); + contentEl.value.style.animationDuration = `${duration}s`; +} + +watch(() => props.duration, calcDuration); + +onMounted(calcDuration); +</script> + +<style lang="scss" module> +.wrap { + overflow: clip; + animation-play-state: running; + + &:hover { + animation-play-state: paused; + } +} + +.content { + display: inline-block; + white-space: nowrap; + animation-play-state: inherit; +} + +.text { + display: inline-block; + animation-name: marquee; + animation-timing-function: linear; + animation-iteration-count: infinite; + animation-duration: inherit; + animation-play-state: inherit; +} + +.paused .text { + animation-play-state: paused; +} + +.reverse .text { + animation-direction: reverse; +} + +@keyframes marquee { + 0% { transform: translateX(0); } + 100% { transform: translateX(-100%); } +} +</style> diff --git a/packages/frontend/src/pages/welcome.entrance.a.vue b/packages/frontend/src/pages/welcome.entrance.a.vue index d131c17340..c2cf937c71 100644 --- a/packages/frontend/src/pages/welcome.entrance.a.vue +++ b/packages/frontend/src/pages/welcome.entrance.a.vue @@ -17,13 +17,13 @@ SPDX-License-Identifier: AGPL-3.0-only <MkVisitorDashboard/> </div> <div v-if="instances && instances.length > 0" :class="$style.federation"> - <MarqueeText :duration="40"> + <MkMarqueeText :duration="40"> <MkA v-for="instance in instances" :key="instance.id" :class="$style.federationInstance" :to="`/instance-info/${instance.host}`" behavior="window"> <!--<MkInstanceCardMini :instance="instance"/>--> <img v-if="instance.iconUrl" :class="$style.federationInstanceIcon" :src="getInstanceIcon(instance)" alt=""/> <span class="_monospace">{{ instance.host }}</span> </MkA> - </MarqueeText> + </MkMarqueeText> </div> </div> </template> @@ -32,7 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { ref } from 'vue'; import * as Misskey from 'misskey-js'; import XTimeline from './welcome.timeline.vue'; -import MarqueeText from '@/components/MkMarquee.vue'; +import MkMarqueeText from '@/components/MkMarqueeText.vue'; import MkFeaturedPhotos from '@/components/MkFeaturedPhotos.vue'; import misskeysvg from '/client-assets/misskey.svg'; import { misskeyApiGet } from '@/utility/misskey-api.js'; diff --git a/packages/frontend/src/ui/_common_/statusbar-federation.vue b/packages/frontend/src/ui/_common_/statusbar-federation.vue index 16e72fa227..7248e8826b 100644 --- a/packages/frontend/src/ui/_common_/statusbar-federation.vue +++ b/packages/frontend/src/ui/_common_/statusbar-federation.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only :leaveToClass="$style.transition_change_leaveTo" mode="default" > - <MarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> + <MkMarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> <span v-for="instance in instances" :key="instance.id" :class="[$style.item, { [$style.colored]: colored }]" :style="{ background: colored ? instance.themeColor : null }"> <img :class="$style.icon" :src="getInstanceIcon(instance)" alt=""/> <MkA :to="`/instance-info/${instance.host}`" :class="$style.host" class="_monospace"> @@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only </MkA> <span></span> </span> - </MarqueeText> + </MkMarqueeText> </Transition> </template> <template v-else-if="display === 'oneByOne'"> @@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; import * as Misskey from 'misskey-js'; -import MarqueeText from '@/components/MkMarquee.vue'; +import MkMarqueeText from '@/components/MkMarqueeText.vue'; import { misskeyApi } from '@/utility/misskey-api.js'; import { useInterval } from '@@/js/use-interval.js'; import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js'; diff --git a/packages/frontend/src/ui/_common_/statusbar-rss.vue b/packages/frontend/src/ui/_common_/statusbar-rss.vue index 4da89a181e..7db0d5267d 100644 --- a/packages/frontend/src/ui/_common_/statusbar-rss.vue +++ b/packages/frontend/src/ui/_common_/statusbar-rss.vue @@ -13,11 +13,11 @@ SPDX-License-Identifier: AGPL-3.0-only :leaveToClass="$style.transition_change_leaveTo" mode="default" > - <MarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> + <MkMarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> <span v-for="item in items" :class="$style.item"> <a :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span :class="$style.divider"></span> </span> - </MarqueeText> + </MkMarqueeText> </Transition> </template> <template v-else-if="display === 'oneByOne'"> @@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; import * as Misskey from 'misskey-js'; -import MarqueeText from '@/components/MkMarquee.vue'; +import MkMarqueeText from '@/components/MkMarqueeText.vue'; import { useInterval } from '@@/js/use-interval.js'; import { shuffle } from '@/utility/shuffle.js'; diff --git a/packages/frontend/src/ui/_common_/statusbar-user-list.vue b/packages/frontend/src/ui/_common_/statusbar-user-list.vue index c5bee51162..13139a1064 100644 --- a/packages/frontend/src/ui/_common_/statusbar-user-list.vue +++ b/packages/frontend/src/ui/_common_/statusbar-user-list.vue @@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only :leaveToClass="$style.transition_change_leaveTo" mode="default" > - <MarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> + <MkMarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> <span v-for="note in notes" :key="note.id" :class="$style.item"> <img :class="$style.avatar" :src="note.user.avatarUrl" decoding="async"/> <MkA :class="$style.text" :to="notePage(note)"> @@ -21,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only </MkA> <span :class="$style.divider"></span> </span> - </MarqueeText> + </MkMarqueeText> </Transition> </template> <template v-else-if="display === 'oneByOne'"> @@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref, watch } from 'vue'; import * as Misskey from 'misskey-js'; -import MarqueeText from '@/components/MkMarquee.vue'; +import MkMarqueeText from '@/components/MkMarqueeText.vue'; import { misskeyApi } from '@/utility/misskey-api.js'; import { useInterval } from '@@/js/use-interval.js'; import { getNoteSummary } from '@/utility/get-note-summary.js'; diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue index b5be4d35c2..7fe7c6111a 100644 --- a/packages/frontend/src/widgets/WidgetRssTicker.vue +++ b/packages/frontend/src/widgets/WidgetRssTicker.vue @@ -15,11 +15,11 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <div v-else> <Transition :name="$style.change" mode="default" appear> - <MarqueeText :key="key" :duration="widgetProps.duration" :reverse="widgetProps.reverse"> + <MkMarqueeText :key="key" :duration="widgetProps.duration" :reverse="widgetProps.reverse"> <span v-for="item in items" :key="item.link" :class="$style.item"> <a :href="item.link" rel="nofollow noopener" target="_blank" :title="item.title">{{ item.title }}</a><span :class="$style.divider"></span> </span> - </MarqueeText> + </MkMarqueeText> </Transition> </div> </div> @@ -31,7 +31,7 @@ import { ref, watch, computed } from 'vue'; import * as Misskey from 'misskey-js'; import { useWidgetPropsManager } from './widget.js'; import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; -import MarqueeText from '@/components/MkMarquee.vue'; +import MarqueeText from '@/components/MkMarqueeText.vue'; import type { GetFormResultType } from '@/utility/form.js'; import MkContainer from '@/components/MkContainer.vue'; import { shuffle } from '@/utility/shuffle.js';