[Refactor] Organize files.

This commit is contained in:
Sakamoto Shiina
2025-06-10 20:36:16 +09:00
parent 66e9fc9126
commit f229d9ec95
29 changed files with 25 additions and 16 deletions

View File

@@ -0,0 +1,34 @@
import styles from "./ModalController.module.scss";
import { useStore_OpenedQuickSetting } from "@store";
import { Vr, VrcMicMuteSyncContainer, Plugins } from "@setting_box";
import { UpdateModal } from "./update_modal/UpdateModal";
export const ModalController = () => {
const { currentOpenedQuickSetting, updateOpenedQuickSetting } = useStore_OpenedQuickSetting();
if (currentOpenedQuickSetting.data === "") return null;
return (
<div className={styles.container}>
<div className={styles.bg_onclick_close_area} onClick={() => updateOpenedQuickSetting("")}></div>
<div className={styles.wrapper}>
<QuickSettingsController />
</div>
</div>
);
};
const QuickSettingsController = () => {
const { currentOpenedQuickSetting, updateOpenedQuickSetting } = useStore_OpenedQuickSetting();
switch (currentOpenedQuickSetting.data) {
case "plugins":
return <Plugins />;
case "vrc_mic_mute_sync":
return <VrcMicMuteSyncContainer />;
case "overlay":
return <Vr />;
case "update_software":
return <UpdateModal />;
default:
return null;
}
};

View File

@@ -0,0 +1,29 @@
.container {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.bg_onclick_close_area {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--dark_550_color_22);
backdrop-filter: blur(0.2rem);
}
.wrapper {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
overflow-y: auto;
background-color: var(--dark_900_color);
width: 80%;
height: 96%;
padding: 2rem;
border-radius: 0.6rem;
}

View File

@@ -0,0 +1,100 @@
import clsx from "clsx";
import styles from "./UpdateModal.module.scss";
import { useTranslation } from "react-i18next";
import { useStore_OpenedQuickSetting } from "@store";
import { usePlugins } from "@logics_configs";
import {
useComputeMode,
useUpdateSoftware,
useIsSoftwareUpdating,
useSoftwareVersion,
} from "@logics_common";
import { PluginCompatibilityList } from "./plugins_compatibility_list/PluginCompatibilityList";
export const UpdateModal = () => {
const { t } = useTranslation();
const { updateOpenedQuickSetting } = useStore_OpenedQuickSetting();
const { updateSoftware, updateSoftware_CUDA } = useUpdateSoftware();
const { updateIsSoftwareUpdating } = useIsSoftwareUpdating();
const { currentComputeMode } = useComputeMode();
const { currentLatestSoftwareVersionInfo } = useSoftwareVersion();
const { isAnyPluginEnabled } = usePlugins();
const is_latest_version_already = currentLatestSoftwareVersionInfo.data.is_update_available === false;
const is_cpu_version = currentComputeMode.data === "cpu";
const onClickUpdateSoftware = () => {
updateIsSoftwareUpdating(true);
updateSoftware();
}
const onClickUpdateSoftware_CUDA = () => {
updateIsSoftwareUpdating(true);
updateSoftware_CUDA();
}
const cpu_accept_button_class_name = clsx(styles.accept_button, {
[styles.current_compute_version]: is_cpu_version,
[styles.is_latest_version_already]: is_latest_version_already,
})
const cuda_accept_button_class_name = clsx(styles.accept_button, {
[styles.current_compute_version]: !is_cpu_version,
[styles.is_latest_version_already]: is_latest_version_already,
})
return (
<div className={styles.container}>
<div className={styles.wrapper}>
<div className={styles.update_section_wrapper}>
{isAnyPluginEnabled() && <PluginCompatibilityList />}
<div className={styles.update_section}>
<div className={styles.cpu_section}>
<div className={styles.button_wrapper}>
<button className={cpu_accept_button_class_name} onClick={onClickUpdateSoftware}>CPU</button>
{is_cpu_version ? <CurrentVersionLabel is_latest_version_already={is_latest_version_already} /> : null}
</div>
<div className={styles.version_desc_container}>
<VersionDescComponent desc={t("update_modal.cpu_desc")} />
</div>
</div>
<div className={styles.cuda_section}>
<div className={styles.button_wrapper}>
<button className={cuda_accept_button_class_name} onClick={onClickUpdateSoftware_CUDA}>CUDA (CPU/GPU)</button>
{!is_cpu_version ? <CurrentVersionLabel is_latest_version_already={is_latest_version_already} is_cuda={true}/> : null}
</div>
<div className={styles.version_desc_container}>
<VersionDescComponent desc={t("update_modal.cuda_desc")} />
<VersionDescComponent desc={t("update_modal.cuda_compare_cpu_desc")} />
<VersionDescComponent desc={t("update_modal.cuda_disk_space_desc", {size: "5GB"})} />
</div>
</div>
<p className={styles.update_desc}>{t("update_modal.download_latest_and_restart")}</p>
</div>
</div>
<div className={styles.button_wrapper}>
<button className={styles.deny_button} onClick={() => updateOpenedQuickSetting("")} >{t("update_modal.close_modal")}</button>
</div>
</div>
</div>
);
};
const VersionDescComponent = (props) => {
return (
<div className={styles.version_desc_wrapper}>
<div className={styles.version_desc_point}></div>
<p className={styles.version_desc}>{`- ${props.desc}`}</p>
</div>
);
};
const CurrentVersionLabel = (props) => {
const { t } = useTranslation();
if (props.is_latest_version_already) {
return <p className={clsx(styles.current_version_label, {[styles.is_cuda]: props.is_cuda})}>{t("update_modal.is_latest_version_already")}</p>;
}
return <p className={clsx(styles.current_version_label, {[styles.is_cuda]: props.is_cuda})}>{t("update_modal.is_current_compute_device")}</p>;
};

View File

@@ -0,0 +1,156 @@
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: safe center;
align-items: center;
gap: 2.4rem;
}
.wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 8rem;
}
.update_section_wrapper {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 4rem;
}
.update_section {
border: 0.1rem solid var(--dark_600_color);
border-radius: 0.4rem;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
gap: 4rem;
padding: 6rem 2rem;
position: relative;
}
.update_desc {
position: absolute;
top: 100%;
transform: translateY(-50%);
font-size: 1.4rem;
background-color: var(--dark_900_color);
padding: 0 2.8rem;
text-align: center;
font-weight: 400;
}
.cpu_section, .cuda_section {
width: 100%;
display: flex;
justify-content: start;
align-items: center;
gap: 3rem;
}
.button_wrapper {
display: flex;
width: 16rem;
justify-content: space-between;
position: relative;
flex-shrink: 0;
}
.deny_button, .accept_button {
font-size: 1.6rem;
padding: 1rem;
min-width: 10rem;
flex: 1;
max-width: 20rem;
text-align: center;
border-radius: 0.4rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.accept_button {
background-color: var(--primary_700_color);
position: relative;
overflow: visible;
&:hover {
background-color: var(--primary_450_color);
}
&:active {
background-color: var(--primary_600_color);
}
&.current_compute_version {
&::after {
content: "";
position: absolute;
top: -1rem;
right: -1rem;
bottom: -1rem;
left: -1rem;
border: 0.1rem solid var(--primary_400_color);
border-radius: 0.4rem;
}
&.is_latest_version_already {
background-color: var(--dark_825_color);
pointer-events: none;
}
}
}
.deny_button {
background-color: var(--dark_825_color);
&:hover {
background-color: var(--dark_800_color);
}
&:active {
background-color: var(--dark_850_color);
}
}
.current_version_label {
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
margin: 0 0 0.4rem 0;
font-size: 1.2rem;
width: max-content;
height: max-content;
background-color: var(--dark_900_color);
padding: 0 1rem;
font-weight: 300;
&.is_cuda {
top: 100%;
margin: 0.4rem 0 0 0;
}
}
.version_desc_container {
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.version_desc_wrapper {
display: flex;
align-items: center;
gap: 0.6rem;
}
.version_desc_point {
width: 0.3rem;
border-radius: 50%;
aspect-ratio: 1 / 1;
}
.version_desc {
font-size: 1.4rem;
max-width: 48rem;
// text-align: center;
font-weight: 300;
}

View File

@@ -0,0 +1,78 @@
import { useEffect } from "react";
import styles from "./PluginCompatibilityList.module.scss";
import { usePlugins } from "@logics_configs";
import CheckMarkSvg from "@images/check_mark.svg?react";
import XSvg from "@images/x_mark.svg?react";
import WarningSvg from "@images/warning.svg?react";
export const PluginCompatibilityList = () => {
const {
enabledPluginsList,
asyncFetchPluginsInfo,
currentFetchedPluginsInfo,
} = usePlugins();
useEffect(() => {
asyncFetchPluginsInfo();
}, []);
// ダウンロード済みのもの
const downloaded_plugin = enabledPluginsList().filter(p => p.is_downloaded);
const compatible_plugins_list = [];
const incompatible_plugins_list = [];
for (const p of downloaded_plugin) {
if (!p.downloaded_plugin_info?.is_plugin_supported_latest_vrct && !p.latest_plugin_info?.is_plugin_supported_latest_vrct) {
// プラグイン最新版でも、VRCT最新版VRCTアプデ後に非対応のもの
incompatible_plugins_list.push(p);
} else {
// 現プラグイン or 最新版が、VRCT最新版VRCTアプデ後に対応しているもの
compatible_plugins_list.push(p);
}
}
const is_any_incompatible_plugin = incompatible_plugins_list.length > 0;
const is_any_compatible_plugin = compatible_plugins_list.length > 0;
if (!is_any_incompatible_plugin && !is_any_compatible_plugin) return null; // This is just for safety.
// Duplicate
const is_failed_to_fetch = currentFetchedPluginsInfo.state === "error";
const is_fetching = currentFetchedPluginsInfo.state === "pending";
return (
<div className={styles.container}>
<p className={styles.title}>使用中プラグインの互換性チェック</p>
{is_failed_to_fetch && <p>Failed to fetch plugins data</p>}
{is_fetching && <p>Fetching plugins data...</p>}
<div className={styles.plugins_compatibility_container}>
{incompatible_plugins_list.map(plugin => {
const target_data = plugin.downloaded_plugin_info;
return <PluginContainer key={target_data.plugin_id} target_data={target_data} is_compatible={false}/>;
})}
{compatible_plugins_list.map(plugin => {
const target_data = plugin.downloaded_plugin_info;
return <PluginContainer key={target_data.plugin_id} target_data={target_data} is_compatible={true} />;
})}
</div>
{is_any_incompatible_plugin &&
<div className={styles.warning_container}>
<WarningSvg className={styles.warning_svg}/>
<p className={styles.warning_text}>VRCT最新バージョンで互換性のないプラグインはアップデート後に無効化されます引き続き使用したい場合は各プラグインの更新を待ってください</p>
</div>
}
</div>
);
};
const PluginContainer = ({ target_data, is_compatible }) => {
return (
<div className={styles.plugin_box}>
<p className={clsx(styles.plugin_label, {[styles.is_compatible]: is_compatible})} >{target_data.title}</p>
{is_compatible
? <CheckMarkSvg className={styles.check_mark_svg}/>
: <XSvg className={styles.x_svg}/>
}
</div>
);
};

View File

@@ -0,0 +1,63 @@
.container {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 1rem;
}
.title {
font-size: 1.6rem;
}
.plugins_compatibility_container {
display: flex;
justify-content: center;
align-items: center;
gap: 0.2rem 1rem;
flex-wrap: wrap;
}
.plugin_box {
display: flex;
justify-content: center;
align-items: center;
padding: 0.4rem 0.6rem;
gap: 0.6rem;
}
.plugin_label {
font-size: 1.4rem;
color: var(--error_bc_color);
&.is_compatible {
color: var(--primary_300_color);
}
}
.check_mark_svg {
width: 1.8rem;
color: var(--primary_300_color);
}
.x_svg {
width: 1.8rem;
color: var(--error_bc_color);
}
.warning_container {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
}
.warning_svg {
padding-bottom: 0.4rem;
width: 2.4rem;
color: var(--warning_color);
flex-shrink: 0;
}
.warning_text {
font-size: 1.2rem;
}