From ef83670716cc93f84c95e03d2a00377352d27d5b Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 2 Jul 2022 21:28:04 +0900
Subject: [PATCH] enhance(client): better marquee component

---
 packages/client/package.json                  |  1 -
 packages/client/src/components/marquee.vue    | 97 +++++++++++++++++++
 .../client/src/pages/welcome.entrance.a.vue   |  2 +-
 packages/client/src/widgets/rss-marquee.vue   |  2 +-
 packages/client/yarn.lock                     | 15 +--
 5 files changed, 100 insertions(+), 17 deletions(-)
 create mode 100644 packages/client/src/components/marquee.vue

diff --git a/packages/client/package.json b/packages/client/package.json
index 5a087a2970..b810abd08a 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -76,7 +76,6 @@
 		"vanilla-tilt": "1.7.2",
 		"vite": "3.0.0-beta.5",
 		"vue": "3.2.37",
-		"vue-marquee-text-component": "2.0.1",
 		"vue-prism-editor": "2.0.0-alpha.2",
 		"vuedraggable": "4.0.1",
 		"websocket": "1.0.34",
diff --git a/packages/client/src/components/marquee.vue b/packages/client/src/components/marquee.vue
new file mode 100644
index 0000000000..2fd76a54f0
--- /dev/null
+++ b/packages/client/src/components/marquee.vue
@@ -0,0 +1,97 @@
+<script lang="ts">
+import { h, onMounted, onUnmounted, ref } 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();
+
+		function calc() {
+			const eachLength = contentEl.value.offsetWidth / props.repeat;
+			const factor = 3000;
+			const duration = props.duration / ((1 / eachLength) * factor);
+
+			contentEl.value.style.animationDuration = `${duration}s`;
+		}
+
+		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;
+}
+.content {
+	display: inline-block;
+	white-space: nowrap;
+}
+.text {
+	display: inline-block;
+	animation-name: marquee;
+	animation-timing-function: linear;
+	animation-iteration-count: infinite;
+	animation-duration: inherit;
+}
+.paused .text {
+	animation-play-state: paused;
+}
+@keyframes marquee {
+	0% { transform:translateX(0); }
+	100% { transform:translateX(-100%); }
+}
+</style>
diff --git a/packages/client/src/pages/welcome.entrance.a.vue b/packages/client/src/pages/welcome.entrance.a.vue
index b78a37eab0..8ff7d9057f 100644
--- a/packages/client/src/pages/welcome.entrance.a.vue
+++ b/packages/client/src/pages/welcome.entrance.a.vue
@@ -47,8 +47,8 @@
 <script lang="ts" setup>
 import { } from 'vue';
 import { toUnicode } from 'punycode/';
-import MarqueeText from 'vue-marquee-text-component';
 import XTimeline from './welcome.timeline.vue';
+import MarqueeText from '@/components/marquee.vue';
 import XSigninDialog from '@/components/signin-dialog.vue';
 import XSignupDialog from '@/components/signup-dialog.vue';
 import MkButton from '@/components/ui/button.vue';
diff --git a/packages/client/src/widgets/rss-marquee.vue b/packages/client/src/widgets/rss-marquee.vue
index d96eadb4e0..2f92c09f38 100644
--- a/packages/client/src/widgets/rss-marquee.vue
+++ b/packages/client/src/widgets/rss-marquee.vue
@@ -18,8 +18,8 @@
 
 <script lang="ts" setup>
 import { onMounted, onUnmounted, ref, watch } from 'vue';
-import MarqueeText from 'vue-marquee-text-component';
 import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
+import MarqueeText from '@/components/marquee.vue';
 import { GetFormResultType } from '@/scripts/form';
 import * as os from '@/os';
 import MkContainer from '@/components/ui/container.vue';
diff --git a/packages/client/yarn.lock b/packages/client/yarn.lock
index e5f2e31d7f..a7b46b70d0 100644
--- a/packages/client/yarn.lock
+++ b/packages/client/yarn.lock
@@ -1221,11 +1221,6 @@ content-disposition@0.5.4:
   dependencies:
     safe-buffer "5.2.1"
 
-core-js@^3.18.0:
-  version "3.23.3"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.23.3.tgz#3b977612b15da6da0c9cc4aec487e8d24f371112"
-  integrity sha512-oAKwkj9xcWNBAvGbT//WiCdOMpb9XQG92/Fe3ABFM/R16BsHgePG00mFOgKf7IsCtfj8tA1kHtf/VwErhriz5Q==
-
 core-util-is@1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -4250,20 +4245,12 @@ vue-eslint-parser@^9.0.1:
     lodash "^4.17.21"
     semver "^7.3.6"
 
-vue-marquee-text-component@2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/vue-marquee-text-component/-/vue-marquee-text-component-2.0.1.tgz#62691df195f755471fa9bdc9b1969f836a922b9a"
-  integrity sha512-dbeRwDY5neOJcWZrDFU2tJMhPSsxN25ZpNYeZdt0jkseg1MbyGKzrfEH9nrCFZRkEfqhxG+ukyzwVwR9US5sTQ==
-  dependencies:
-    core-js "^3.18.0"
-    vue "^3.2.19"
-
 vue-prism-editor@2.0.0-alpha.2:
   version "2.0.0-alpha.2"
   resolved "https://registry.yarnpkg.com/vue-prism-editor/-/vue-prism-editor-2.0.0-alpha.2.tgz#aa53a88efaaed628027cbb282c2b1d37fc7c5c69"
   integrity sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==
 
-vue@3.2.37, vue@^3.2.19:
+vue@3.2.37:
   version "3.2.37"
   resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e"
   integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==