diff --git a/src-ui/app/config_page/setting_section/setting_box/about_vrct/poster_showcase_contents/poster_showcase_worlds_contents/PosterShowcaseWorldsContents.jsx b/src-ui/app/config_page/setting_section/setting_box/about_vrct/poster_showcase_contents/poster_showcase_worlds_contents/PosterShowcaseWorldsContents.jsx index e51c8ea5..4d2044e1 100644 --- a/src-ui/app/config_page/setting_section/setting_box/about_vrct/poster_showcase_contents/poster_showcase_worlds_contents/PosterShowcaseWorldsContents.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/about_vrct/poster_showcase_contents/poster_showcase_worlds_contents/PosterShowcaseWorldsContents.jsx @@ -37,7 +37,7 @@ export const PosterShowcaseWorldsContents = () => { ); if (poster.x_post_num !== null) { return ( - + {content} ); diff --git a/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.jsx b/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.jsx index 6c80beb2..4115b667 100644 --- a/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.jsx @@ -1,10 +1,10 @@ -import { useEffect, useRef, useState, useCallback } from "react"; +import { useEffect, useRef } from "react"; import { useI18n } from "@useI18n"; import { usePlugins } from "@logics_configs"; import styles from "./Plugins.module.scss"; import { PluginsControlComponent } from "./plugins_control_component/PluginsControlComponent"; import { useNotificationStatus } from "@logics_common"; -import ExternalLink from "@images/external_link.svg?react"; +import { HomepageLinkButton } from "@common_components"; export const Plugins = () => { const { @@ -125,55 +125,4 @@ const PluginDownloadContainer = () => { })} ); -}; - -const HomepageLinkButton = ({ homepage_link, speed = 40 /* px/s */ }) => { - const containerRef = useRef(null); - const textRef = useRef(null); - const [inlineStyle, setInlineStyle] = useState({}); - - const handleMouseEnter = useCallback(() => { - const container = containerRef.current; - const text = textRef.current; - if (!container || !text) return; - const overflow = text.scrollWidth - container.clientWidth; - if (overflow > 0) { - const duration = overflow / speed; - setInlineStyle({ - transform: `translateX(-${overflow}px)`, - transition: `transform ${duration}s linear`, - }); - } - }, [speed]); - - const handleMouseLeave = useCallback(() => { - setInlineStyle({ - transform: 'translateX(0)', - transition: 'transform 0.3s ease-out', - }); - }, []); - - return ( -
- -
-

- {homepage_link} -

-
- -
-
- ); }; \ No newline at end of file diff --git a/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.module.scss b/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.module.scss index 2ad924bc..05c49046 100644 --- a/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.module.scss +++ b/src-ui/app/config_page/setting_section/setting_box/plugins/Plugins.module.scss @@ -56,45 +56,4 @@ // overflow: hidden; // white-space: nowrap; // text-overflow: ellipsis; -// } - -.open_homepage_button_wrapper { - width: 100%; -} - -.open_homepage_button { - padding: 0.6rem 0; - display: flex; - align-items: center; - gap: 1rem; - cursor: pointer; - text-decoration: none; - &:hover .external_link_svg { - color: var(--dark_200_color); - } - &:hover .open_homepage_text { - border-bottom: 0.1rem solid var(--dark_500_color); - } -} - -.text_container { - position: relative; - overflow: hidden; - flex: 1; /* テキスト部分をアイコンまで伸ばす */ -} - -.open_homepage_text { - margin: 0; /* pタグのデフォルトマージン除去 */ - font-size: 1.4rem; - color: var(--sent_400_color); - white-space: nowrap; - display: inline-block; - transform: translateX(0); - border-bottom: 0.1rem solid var(--sent_400_color); -} - -.external_link_svg { - flex-shrink: 0; - width: 1.6rem; - color: var(--dark_500_color); -} \ No newline at end of file +// } \ No newline at end of file diff --git a/src-ui/app/others/snackbar_controller/SnackbarController.jsx b/src-ui/app/others/snackbar_controller/SnackbarController.jsx index 60edac1f..d2197e1b 100644 --- a/src-ui/app/others/snackbar_controller/SnackbarController.jsx +++ b/src-ui/app/others/snackbar_controller/SnackbarController.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect, useState, isValidElement } from "react"; import { ToastContainer, toast, cssTransition } from "react-toastify"; import clsx from "clsx"; diff --git a/src-ui/common_components/homepage_link_button/HomepageLinkButton.jsx b/src-ui/common_components/homepage_link_button/HomepageLinkButton.jsx new file mode 100644 index 00000000..b68f235f --- /dev/null +++ b/src-ui/common_components/homepage_link_button/HomepageLinkButton.jsx @@ -0,0 +1,54 @@ +import ExternalLink from "@images/external_link.svg?react"; +import styles from "./HomepageLinkButton.module.scss"; +import { useRef, useState, useCallback } from "react"; + +export const HomepageLinkButton = ({ homepage_link, speed = 40 /* px/s */ }) => { + const containerRef = useRef(null); + const textRef = useRef(null); + const [inlineStyle, setInlineStyle] = useState({}); + + const handleMouseEnter = useCallback(() => { + const container = containerRef.current; + const text = textRef.current; + if (!container || !text) return; + const overflow = text.scrollWidth - container.clientWidth; + if (overflow > 0) { + const duration = overflow / speed; + setInlineStyle({ + transform: `translateX(-${overflow}px)`, + transition: `transform ${duration}s linear`, + }); + } + }, [speed]); + + const handleMouseLeave = useCallback(() => { + setInlineStyle({ + transform: 'translateX(0)', + transition: 'transform 0.3s ease-out', + }); + }, []); + + return ( +
+ +
+

+ {homepage_link} +

+
+ +
+
+ ); +}; \ No newline at end of file diff --git a/src-ui/common_components/homepage_link_button/HomepageLinkButton.module.scss b/src-ui/common_components/homepage_link_button/HomepageLinkButton.module.scss new file mode 100644 index 00000000..888d8a6f --- /dev/null +++ b/src-ui/common_components/homepage_link_button/HomepageLinkButton.module.scss @@ -0,0 +1,39 @@ +.open_homepage_button_wrapper { + width: 100%; +} + +.open_homepage_button { + padding: 0.6rem 0; + display: flex; + align-items: center; + gap: 1rem; + cursor: pointer; + text-decoration: none; + &:hover .external_link_svg { + color: var(--dark_200_color); + } + &:hover .open_homepage_text { + border-bottom: 0.1rem solid var(--dark_500_color); + } +} + +.text_container { + position: relative; + overflow: hidden; +} + +.open_homepage_text { + margin: 0; /* pタグのデフォルトマージン除去 */ + font-size: 1.4rem; + color: var(--sent_400_color); + white-space: nowrap; + display: inline-block; + transform: translateX(0); + border-bottom: 0.1rem solid var(--sent_400_color); +} + +.external_link_svg { + flex-shrink: 0; + width: 1.6rem; + color: var(--dark_500_color); +} \ No newline at end of file diff --git a/src-ui/common_components/index.js b/src-ui/common_components/index.js index 244dff53..177161eb 100644 --- a/src-ui/common_components/index.js +++ b/src-ui/common_components/index.js @@ -1 +1,2 @@ -export { Checkbox } from "./checkbox/Checkbox"; \ No newline at end of file +export { Checkbox } from "./checkbox/Checkbox"; +export { HomepageLinkButton } from "./homepage_link_button/HomepageLinkButton"; \ No newline at end of file diff --git a/src-ui/logics/common/useIsVrctAvailable.js b/src-ui/logics/common/useIsVrctAvailable.js deleted file mode 100644 index 569a0210..00000000 --- a/src-ui/logics/common/useIsVrctAvailable.js +++ /dev/null @@ -1,21 +0,0 @@ -import { useStore_IsVrctAvailable } from "@store"; -import { useNotificationStatus } from "@logics_common"; - -export const useIsVrctAvailable = () => { - const { currentIsVrctAvailable, updateIsVrctAvailable } = useStore_IsVrctAvailable(); - const { showNotification_Success, showNotification_Error } = useNotificationStatus(); - - const handleAiModelsAvailability = (is_ai_models_available) => { - if (is_ai_models_available === false) { - updateIsVrctAvailable(false); - showNotification_Error("AI models have not been detected. Check the network connection and restart VRCT (it will download automatically, normally).", { hide_duration: null }); - } - }; - - return { - currentIsVrctAvailable, - updateIsVrctAvailable, - - handleAiModelsAvailability, - }; -}; \ No newline at end of file diff --git a/src-ui/logics/common/useIsVrctAvailable.jsx b/src-ui/logics/common/useIsVrctAvailable.jsx new file mode 100644 index 00000000..613f0a61 --- /dev/null +++ b/src-ui/logics/common/useIsVrctAvailable.jsx @@ -0,0 +1,33 @@ +import { useStore_IsVrctAvailable } from "@store"; +import { useNotificationStatus } from "@logics_common"; +import { HomepageLinkButton } from "@common_components"; + +export const useIsVrctAvailable = () => { + const { currentIsVrctAvailable, updateIsVrctAvailable } = useStore_IsVrctAvailable(); + const { showNotification_Success, showNotification_Error } = useNotificationStatus(); + + const handleAiModelsAvailability = (is_ai_models_available) => { + if (is_ai_models_available === false) { + updateIsVrctAvailable(false); + const ErrorComponent = () => { + return ( +
+

AI models have not been detected. Check the network connection and restart VRCT (it will download automatically, normally).

+

If this error occurs frequently, try the following:

+ +
+ ); + }; + showNotification_Error(ErrorComponent, { hide_duration: null }); + } + }; + + return { + currentIsVrctAvailable, + updateIsVrctAvailable, + + handleAiModelsAvailability, + }; +}; \ No newline at end of file