Merge branch 'develop' into gpu_error

This commit is contained in:
Sakamoto Shiina
2025-06-06 15:59:06 +09:00
21 changed files with 723 additions and 122 deletions

View File

@@ -29,8 +29,8 @@ common_warning:
main_page: main_page:
translation: "翻訳" translation: "翻訳"
transcription_send: "音声認識 マイク" transcription_send: "マイク入力"
transcription_receive: "音声認識 スピーカー" transcription_receive: "聞き取り"
foreground: "最前面固定" foreground: "最前面固定"
language_settings: "言語設定" language_settings: "言語設定"
@@ -134,7 +134,7 @@ config_page:
ctranslate2_compute_device: ctranslate2_compute_device:
label: "AI翻訳 {{ctranslate2}} の処理デバイス" label: "AI翻訳 {{ctranslate2}} の処理デバイス"
deepl_auth_key: deepl_auth_key:
label: "DeepL API 認証キー" label: "DeepL APIキーの登録"
desc: "使用の際は、メイン画面にある {{translator}} をDeepL_APIに変更してください。\n※対応していない言語もあります。" desc: "使用の際は、メイン画面にある {{translator}} をDeepL_APIに変更してください。\n※対応していない言語もあります。"
open_auth_key_webpage: "DeepLアカウントページを開く" open_auth_key_webpage: "DeepLアカウントページを開く"
save: "保存" save: "保存"

14
package-lock.json generated
View File

@@ -28,6 +28,7 @@
"react-error-boundary": "5.0.0", "react-error-boundary": "5.0.0",
"react-i18next": "15.5.1", "react-i18next": "15.5.1",
"react-resizable-layout": "0.7.2", "react-resizable-layout": "0.7.2",
"react-toastify": "11.0.5",
"sass": "1.79.4", "sass": "1.79.4",
"semver": "7.7.1" "semver": "7.7.1"
}, },
@@ -5534,6 +5535,19 @@
"react-dom": ">=17.0.0" "react-dom": ">=17.0.0"
} }
}, },
"node_modules/react-toastify": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz",
"integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==",
"license": "MIT",
"dependencies": {
"clsx": "^2.1.1"
},
"peerDependencies": {
"react": "^18 || ^19",
"react-dom": "^18 || ^19"
}
},
"node_modules/react-transition-group": { "node_modules/react-transition-group": {
"version": "4.4.5", "version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",

View File

@@ -43,6 +43,7 @@
"react-error-boundary": "5.0.0", "react-error-boundary": "5.0.0",
"react-i18next": "15.5.1", "react-i18next": "15.5.1",
"react-resizable-layout": "0.7.2", "react-resizable-layout": "0.7.2",
"react-toastify": "11.0.5",
"sass": "1.79.4", "sass": "1.79.4",
"semver": "7.7.1" "semver": "7.7.1"
}, },

View File

@@ -989,7 +989,7 @@ class Config:
def init_config(self): def init_config(self):
# Read Only # Read Only
self._VERSION = "3.1.2" self._VERSION = "3.2.0"
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
self._PATH_LOCAL = os_path.dirname(sys.executable) self._PATH_LOCAL = os_path.dirname(sys.executable)
else: else:

View File

@@ -24,8 +24,8 @@
--error_bc_color: #bb4448; --error_bc_color: #bb4448;
--error_bc_active_color: #9c3938; --error_bc_active_color: #9c3938;
--success_bc_color: #368777; --success_bc_color: #368777;
--waring_color: #cb944f; --warning_color: #cb944f;
--waring_bc_color: #cf7b1b; --warning_bc_color: #cf7b1b;
--dark_basic_text_color: #f2f2f2; --dark_basic_text_color: #f2f2f2;
--dark_100_color: #f5f7fb; --dark_100_color: #f5f7fb;

View File

@@ -4,44 +4,107 @@ import MUI_Slider from "@mui/material/Slider";
import clsx from "clsx"; import clsx from "clsx";
export const Slider = (props) => { export const Slider = (props) => {
const location = props.valueLabelDisplayLocation || "top";
const sliderSx = {
color: "var(--dark_700_color)",
"& .MuiSlider-thumb": {
backgroundColor: "var(--primary_600_color)",
"&:hover, &.Mui-focusVisible, &.Mui-active": {
boxShadow: `0 0 0 0.8rem var(--primary_600_color_44)`,
},
"& .MuiSlider-valueLabel": {
position: "absolute",
backgroundColor: "var(--dark_800_color)",
width: "fit-content",
minWidth: "4.8rem",
padding: "0.4rem 0.8rem",
lineHeight: "1.15",
"& .MuiSlider-valueLabelLabel": {
fontSize: "1.4rem",
},
...(location === "top" && {
top: "-110%",
left: "50%",
transform: "translate(-50%, -50%) scale(0)",
transformOrigin: "bottom center",
"&.MuiSlider-valueLabelOpen": {
transform: "translate(-50%, -50%) scale(1)",
},
"&::before": {
bottom: "0%",
left: "50%",
},
}),
...(location === "right" && {
top: "50%",
left: "150%",
transform: "translate(0, -50%) scale(0)",
transformOrigin: "left center",
"&.MuiSlider-valueLabelOpen": {
transform: "translate(0, -50%) scale(1)",
},
"&::before": {
bottom: "50%",
left: "0",
},
}),
...(location === "left" && {
// top: "50%",
// right: "50%",
// transform: "translate(-50%, -50%) scale(0)",
// transformOrigin: "bottom center",
// "&.MuiSlider-valueLabelOpen": {
// transform: "translate(-50%, -50%) scale(1)",
// },
// "&::before": {
// bottom: "50%",
// left: "100%",
// },
}),
},
},
"& .MuiSlider-markLabel": {
fontSize: "1.4rem",
color: "var(--dark_550_color)",
whiteSpace: "nowrap",
},
"& .MuiSlider-markLabelActive": {
color: "var(--primary_300_color)",
},
};
return ( return (
<div className={clsx(styles.container, props.className, {[styles.no_padding]: props.no_padding || props.is_break_point})}> <div
className={clsx(
styles.container,
props.className,
{ [styles.no_padding]: props.no_padding || props.is_break_point }
)}
>
<MUI_Slider <MUI_Slider
aria-label="Default" aria-label="Default"
valueLabelDisplay="auto" // valueLabelDisplay="on"
valueLabelDisplay={props.valueLabelDisplay ? props.valueLabelDisplay : "auto"}
value={props.variable} value={props.variable}
step={props.step} step={props.step}
min={Number(props.min)} min={Number(props.min)}
max={Number(props.max)} max={Number(props.max)}
onChange={(_e, value) => props.onchangeFunction(value)} onChange={(_e, value) => props.onchangeFunction(value)}
onChangeCommitted={(_e, value) => props.onchangeCommittedFunction ? props.onchangeCommittedFunction(value) : null} onChangeCommitted={(_e, value) =>
props.onchangeCommittedFunction ? props.onchangeCommittedFunction(value) : null
}
onMouseEnter={(event) =>
props.onMouseEnterFunction ? props.onMouseEnterFunction(event) : null
}
onMouseLeave={(event) =>
props.onMouseLeaveFunction ? props.onMouseLeaveFunction(event) : null
}
marks={props.marks} marks={props.marks}
track={props.track} track={props.track}
orientation={props.orientation} orientation={props.orientation}
valueLabelFormat={`${props.valueLabelFormat ? props.valueLabelFormat : props.variable}`} valueLabelFormat={`${props.valueLabelFormat ? props.valueLabelFormat : props.variable}`}
sx={{ sx={sliderSx}
color: "var(--dark_700_color)",
"& .MuiSlider-thumb": {
backgroundColor: "var(--primary_600_color)",
"&:hover, &.Mui-focusVisible, &.Mui-active": {
boxShadow: `0 0 0 0.8rem var(--primary_600_color_44)`,
},
"& .MuiSlider-valueLabel": {
fontSize: "1.4rem",
backgroundColor: "var(--dark_800_color)",
padding: "0.6rem 1rem",
lineHeight: "1.15",
},
},
"& .MuiSlider-markLabel": {
fontSize: "1.4rem",
color: "var(--dark_550_color)",
whiteSpace: "nowrap",
},
"& .MuiSlider-markLabelActive": {
color: "var(--primary_300_color)",
},
}}
/> />
</div> </div>
); );

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import clsx from "clsx"; import clsx from "clsx";
import styles from "./Vr.module.scss"; import styles from "./Vr.module.scss";
@@ -25,6 +25,10 @@ import {
import RedoSvg from "@images/redo.svg?react"; import RedoSvg from "@images/redo.svg?react";
import SquareSvg from "@images/square.svg?react";
import TriangleSvg from "@images/triangle.svg?react";
import { randomIntMinMax } from "@utils";
export const Vr = () => { export const Vr = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const [is_opened_small_settings, setIsOpenedSmallSettings] = useState(true); const [is_opened_small_settings, setIsOpenedSmallSettings] = useState(true);
@@ -147,7 +151,7 @@ const OverlaySettingsContainer = ({
) : ( ) : (
<RotationControls settings={settings} onchangeFunction={onchangeFunction} ui_configs={ui_configs} default_ui_configs={default_ui_configs} selectFunction={selectFunction}/> <RotationControls settings={settings} onchangeFunction={onchangeFunction} ui_configs={ui_configs} default_ui_configs={default_ui_configs} selectFunction={selectFunction}/>
)} )}
<SendSampleTextToggleButton /> <SendSampleTextToggleButton />
</div> </div>
<OtherControls settings={settings} onchangeFunction={onchangeFunction} ui_configs={ui_configs} /> <OtherControls settings={settings} onchangeFunction={onchangeFunction} ui_configs={ui_configs} />
<RadioButtonContainer <RadioButtonContainer
@@ -187,9 +191,34 @@ const PageSwitcherContainer = (props) => {
); );
}; };
const PositionControls = ({settings, onchangeFunction, selectFunction, ui_configs, default_ui_configs}) => {
export const PositionControls = ({ settings, onchangeFunction, selectFunction, ui_configs, default_ui_configs }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const {
variable_display: x_variable_display,
is_max: is_max_position_x,
is_min: is_min_position_x,
countUp: countUpPositionX,
countDown: countDownPositionX,
} = useVariableControl("x_pos", settings, onchangeFunction, ui_configs);
const {
variable_display: y_variable_display,
is_max: is_max_position_y,
is_min: is_min_position_y,
countUp: countUpPositionY,
countDown: countDownPositionY,
} = useVariableControl("y_pos", settings, onchangeFunction, ui_configs);
const {
variable_display: z_variable_display,
is_max: is_max_position_z,
is_min: is_min_position_z,
countUp: countUpPositionZ,
countDown: countDownPositionZ,
} = useVariableControl("z_pos", settings, onchangeFunction, ui_configs);
return ( return (
<div className={styles.position_controls}> <div className={styles.position_controls}>
<div className={styles.position_wrapper}> <div className={styles.position_wrapper}>
@@ -205,8 +234,18 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
min={ui_configs.x_pos.min} min={ui_configs.x_pos.min}
max={ui_configs.x_pos.max} max={ui_configs.x_pos.max}
onchangeFunction={(value) => onchangeFunction("x_pos", value)} onchangeFunction={(value) => onchangeFunction("x_pos", value)}
valueLabelDisplay={x_variable_display}
valueLabelDisplayLocation="top"
/>
<AdjustButtonContainer
wrapper_class_name={styles.x_position_button_wrapper}
is_max={is_max_position_x}
is_min={is_min_position_x}
countUp={countUpPositionX}
countDown={countDownPositionX}
/> />
</div> </div>
<div className={styles.position_wrapper}> <div className={styles.position_wrapper}>
<p className={clsx(styles.slider_label, styles.y_position_label)}> <p className={clsx(styles.slider_label, styles.y_position_label)}>
{t("config_page.vr.y_position")} {t("config_page.vr.y_position")}
@@ -221,8 +260,18 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
max={ui_configs.y_pos.max} max={ui_configs.y_pos.max}
onchangeFunction={(value) => onchangeFunction("y_pos", value)} onchangeFunction={(value) => onchangeFunction("y_pos", value)}
orientation="vertical" orientation="vertical"
valueLabelDisplay={y_variable_display}
valueLabelDisplayLocation="right"
/>
<AdjustButtonContainer
wrapper_class_name={styles.y_position_button_wrapper}
is_max={is_max_position_y}
is_min={is_min_position_y}
countUp={countUpPositionY}
countDown={countDownPositionY}
/> />
</div> </div>
<div className={styles.position_wrapper}> <div className={styles.position_wrapper}>
<p className={clsx(styles.slider_label, styles.z_position_label)}> <p className={clsx(styles.slider_label, styles.z_position_label)}>
{t("config_page.vr.z_position")} {t("config_page.vr.z_position")}
@@ -237,69 +286,162 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
max={ui_configs.z_pos.max} max={ui_configs.z_pos.max}
onchangeFunction={(value) => onchangeFunction("z_pos", value)} onchangeFunction={(value) => onchangeFunction("z_pos", value)}
orientation="vertical" orientation="vertical"
valueLabelDisplay={z_variable_display}
valueLabelDisplayLocation="left"
/>
<AdjustButtonContainer
wrapper_class_name={styles.z_position_button_wrapper}
is_max={is_max_position_z}
is_min={is_min_position_z}
countUp={countUpPositionZ}
countDown={countDownPositionZ}
/> />
</div> </div>
</div> </div>
); );
}; };
const RotationControls = ({settings, onchangeFunction, selectFunction, default_ui_configs}) => { export const RotationControls = ({ settings, onchangeFunction, selectFunction, ui_configs, default_ui_configs }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const {
variable_display: x_variable_display,
is_max: is_max_rotation_x,
is_min: is_min_rotation_x,
countUp: countUpRotationX,
countDown: countDownRotationX,
} = useVariableControl("x_rotation", settings, onchangeFunction, ui_configs);
const {
variable_display: y_variable_display,
is_max: is_max_rotation_y,
is_min: is_min_rotation_y,
countUp: countUpRotationY,
countDown: countDownRotationY,
} = useVariableControl("y_rotation", settings, onchangeFunction, ui_configs);
const {
variable_display: z_variable_display,
is_max: is_max_rotation_z,
is_min: is_min_rotation_z,
countUp: countUpRotationZ,
countDown: countDownRotationZ,
} = useVariableControl("z_rotation", settings, onchangeFunction, ui_configs);
return ( return (
<div className={styles.rotation_controls}> <div className={styles.rotation_controls}>
<div className={styles.rotation_wrapper}> <div className={styles.rotation_wrapper}>
<p className={clsx(styles.slider_label, styles.x_rotation_label)}> <p className={clsx(styles.slider_label, styles.x_rotation_label)}>
{t("config_page.vr.x_rotation")} {t("config_page.vr.x_rotation")}
<ResetButton onClickFunction={() => selectFunction("x_rotation", default_ui_configs.y_pos)} /> <ResetButton onClickFunction={() => selectFunction("x_rotation", default_ui_configs.x_rotation)} />
</p> </p>
<Slider <Slider
className={styles.x_rotation_slider} className={styles.x_rotation_slider}
no_padding={true} no_padding={true}
variable={-settings.x_rotation} variable={-settings.x_rotation}
valueLabelFormat={settings.x_rotation} valueLabelFormat={settings.x_rotation}
step={5} step={ui_configs.x_rotation.step}
min={-180} min={ui_configs.x_rotation.min}
max={180} max={ui_configs.x_rotation.max}
onchangeFunction={(value) => onchangeFunction("x_rotation", -value)} onchangeFunction={(value) => onchangeFunction("x_rotation", -value)}
orientation="vertical" orientation="vertical"
valueLabelDisplay={x_variable_display}
valueLabelDisplayLocation="right"
/>
<AdjustButtonContainer
wrapper_class_name={styles.x_rotation_button_wrapper}
is_max={is_min_rotation_x}
is_min={is_max_rotation_x}
countUp={countDownRotationX}
countDown={countUpRotationX}
/> />
</div> </div>
<div className={styles.rotation_wrapper}> <div className={styles.rotation_wrapper}>
<p className={clsx(styles.slider_label, styles.y_rotation_label)}> <p className={clsx(styles.slider_label, styles.y_rotation_label)}>
{t("config_page.vr.y_rotation")} {t("config_page.vr.y_rotation")}
<ResetButton onClickFunction={() => selectFunction("y_rotation", default_ui_configs.y_pos)} /> <ResetButton onClickFunction={() => selectFunction("y_rotation", default_ui_configs.y_rotation)} />
</p> </p>
<Slider <Slider
className={styles.y_rotation_slider} className={styles.y_rotation_slider}
no_padding={true} no_padding={true}
variable={settings.y_rotation} variable={settings.y_rotation}
step={5} step={ui_configs.y_rotation.step}
min={-180} min={ui_configs.y_rotation.min}
max={180} max={ui_configs.y_rotation.max}
onchangeFunction={(value) => onchangeFunction("y_rotation", value)} onchangeFunction={(value) => onchangeFunction("y_rotation", value)}
valueLabelDisplay={y_variable_display}
valueLabelDisplayLocation="top"
/>
<AdjustButtonContainer
wrapper_class_name={styles.y_rotation_button_wrapper}
is_max={is_max_rotation_y}
is_min={is_min_rotation_y}
countUp={countUpRotationY}
countDown={countDownRotationY}
/> />
</div> </div>
<div className={styles.rotation_wrapper}> <div className={styles.rotation_wrapper}>
<p className={clsx(styles.slider_label, styles.z_rotation_label)}> <p className={clsx(styles.slider_label, styles.z_rotation_label)}>
{t("config_page.vr.z_rotation")} {t("config_page.vr.z_rotation")}
<ResetButton onClickFunction={() => selectFunction("z_rotation", default_ui_configs.y_pos)} /> <ResetButton onClickFunction={() => selectFunction("z_rotation", default_ui_configs.z_rotation)} />
</p> </p>
<Slider <Slider
className={styles.z_rotation_slider} className={styles.z_rotation_slider}
no_padding={true} no_padding={true}
variable={settings.z_rotation} variable={settings.z_rotation}
step={5} step={ui_configs.z_rotation.step}
min={-180} min={ui_configs.z_rotation.min}
max={180} max={ui_configs.z_rotation.max}
onchangeFunction={(value) => onchangeFunction("z_rotation", value)} onchangeFunction={(value) => onchangeFunction("z_rotation", value)}
orientation="vertical" orientation="vertical"
valueLabelDisplay={z_variable_display}
valueLabelDisplayLocation="left"
/>
<AdjustButtonContainer
wrapper_class_name={styles.z_rotation_button_wrapper}
is_max={is_max_rotation_z}
is_min={is_min_rotation_z}
countUp={countUpRotationZ}
countDown={countDownRotationZ}
/> />
</div> </div>
</div> </div>
); );
}; };
const AdjustButtonContainer = ({ wrapper_class_name, is_max, is_min, countUp, countDown }) => {
return (
<div className={wrapper_class_name}>
<div
className={clsx(
styles.button_wrapper,
{
[styles.is_disabled]: is_max,
[styles.up]: true,
}
)}
onClick={countUp}
>
<TriangleSvg className={styles.adjust_button_triangle_svg} />
</div>
<div
className={clsx(
styles.button_wrapper,
{
[styles.is_disabled]: is_min,
}
)}
onClick={countDown}
>
<TriangleSvg className={styles.adjust_button_triangle_svg} />
</div>
</div>
);
};
const OtherControls = ({settings, onchangeFunction, ui_configs}) => { const OtherControls = ({settings, onchangeFunction, ui_configs}) => {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -393,10 +535,6 @@ const ResetButton = ({onClickFunction}) => {
); );
}; };
import SquareSvg from "@images/square.svg?react";
import TriangleSvg from "@images/triangle.svg?react";
import { randomIntMinMax } from "@utils";
const SendSampleTextToggleButton = () => { const SendSampleTextToggleButton = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { sendTextToOverlay } = useSendTextToOverlay(); const { sendTextToOverlay } = useSendTextToOverlay();
@@ -445,4 +583,58 @@ const SendSampleTextToggleButton = () => {
<p className={styles.sample_text_button_label}>{label}</p> <p className={styles.sample_text_button_label}>{label}</p>
</div> </div>
); );
};
const useVariableControl = (key, settings, onchangeFunction, ui_configs) => {
const [variable_display, setVariableDisplay] = useState("auto");
const [is_max, setIsMax] = useState(settings[key] >= ui_configs[key].max);
const [is_min, setIsMin] = useState(settings[key] <= ui_configs[key].min);
const timerRef = useRef();
useEffect(() => {
return () => {
clearTimeout(timerRef.current);
};
}, []);
const triggerDisplay = () => {
setVariableDisplay("on");
clearTimeout(timerRef.current);
timerRef.current = setTimeout(() => {
setVariableDisplay("auto");
}, 2000);
};
useEffect(() => {
setIsMax(settings[key] >= ui_configs[key].max);
setIsMin(settings[key] <= ui_configs[key].min);
}, [settings[key]]);
const countUp = () => {
if (is_max) return;
const step = ui_configs[key].step;
const new_value = parseFloat((settings[key] + step).toFixed(2));
onchangeFunction(key, new_value);
triggerDisplay();
};
const countDown = () => {
if (is_min) return;
const step = ui_configs[key].step;
const new_value = parseFloat((settings[key] - step).toFixed(2));
onchangeFunction(key, new_value);
triggerDisplay();
};
return {
variable_display,
is_max,
is_min,
countUp,
countDown,
};
}; };

View File

@@ -16,7 +16,7 @@
justify-content: center; justify-content: center;
width: 100%; width: 100%;
max-width: 56rem; max-width: 56rem;
gap: 2rem; gap: 4rem;
} }
.controller_type_switch { .controller_type_switch {
@@ -58,12 +58,13 @@
.sample_text_button_wrapper { .sample_text_button_wrapper {
position: absolute; position: absolute;
bottom: 0; bottom: -12%;
left: -74%; left: -80%;
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
// transform: translate(-50%, -50%);
} }
.sample_text_button { .sample_text_button {
background-color: var(--dark_850_color); background-color: var(--dark_850_color);
@@ -121,20 +122,20 @@
} }
.x_position_label { .x_position_label {
position: absolute; position: absolute;
bottom: -4.6rem; bottom: -5rem;
right: -46%; right: -46%;
justify-content: end; justify-content: end;
} }
.y_position_label { .y_position_label {
position: absolute; position: absolute;
top: -44%; bottom: 110%;
left: 10%; right: 119%;
justify-content: start; justify-content: end;
} }
.z_position_label { .z_position_label {
position: absolute; position: absolute;
top: 30%; top: 14%;
left: 80%; left: 110%;
} }
.x_position_slider { .x_position_slider {
@@ -155,14 +156,84 @@
.z_position_slider { .z_position_slider {
position: absolute; position: absolute;
bottom: 61%; bottom: 80%;
left: 61%; left: 88%;
transform: translate(50%,50%) rotate(45deg); transform: translate(50%,50%) rotate(45deg);
width: 0%; width: 0%;
height: 100%; height: 100%;
} }
%variable-button {
width: 3.8rem;
border-radius: 0.4rem;
aspect-ratio: 1.2 / 1;
background-color: var(--dark_850_color);
display: flex;
justify-content: center;
align-items: center;
font-size: 1.6rem;
cursor: pointer;
&:hover {
background-color: var(--primary_500_color);
}
&:active {
background-color: var(--primary_600_color);
}
&.is_disabled {
pointer-events: none;
background-color: var(--dark_875_color);
& .adjust_button_triangle_svg {
color: var(--dark_800_color);
}
}
}
@mixin variable-button-wrapper($vertical-pos, $vertical-value, $horizontal-pos, $horizontal-value, $rotate: 0deg) {
position: absolute;
#{$vertical-pos}: $vertical-value;
#{$horizontal-pos}: $horizontal-value;
display: flex;
gap: 1.6rem;
flex-direction: column;
transform: translate(-50%) rotate($rotate);
}
.button_wrapper {
@extend %variable-button;
&.up .adjust_button_triangle_svg {
transform: rotate(0deg);
}
&:not(.up) .adjust_button_triangle_svg {
transform: rotate(180deg);
}
&.is_disabled {
pointer-events: none;
color: var(--dark_875_color);
}
}
.adjust_button_triangle_svg {
width: 1.8rem;
color: var(--dark_400_color);
}
.y_position_button_wrapper {
@include variable-button-wrapper(top, 30%, left, -26%);
}
.x_position_button_wrapper {
@include variable-button-wrapper(bottom, -38%, left, 46%, 90deg);
}
.z_position_button_wrapper {
@include variable-button-wrapper(bottom, 26%, right, -4%, 45deg);
}
// .rotation_controls { // .rotation_controls {
@@ -175,19 +246,20 @@
.x_rotation_label { .x_rotation_label {
position: absolute; position: absolute;
top: -44%; bottom: 110%;
left: 10%; right: 119%;
justify-content: end;
} }
.y_rotation_label { .y_rotation_label {
position: absolute; position: absolute;
bottom: -4.6rem; bottom: -5rem;
right: -46%; right: -46%;
justify-content: end; justify-content: end;
} }
.z_rotation_label { .z_rotation_label {
position: absolute; position: absolute;
top: -10%; top: -20%;
right: -110%; right: -100%;
} }
.x_rotation_slider { .x_rotation_slider {
@@ -216,6 +288,21 @@
} }
.x_rotation_button_wrapper {
@include variable-button-wrapper(top, 30%, left, -26%);
}
.y_rotation_button_wrapper {
@include variable-button-wrapper(bottom, -38%, left, 46%, 90deg);
}
.z_rotation_button_wrapper {
@include variable-button-wrapper(bottom, 50%, right, -60%, -45deg);
}
.slider_reset_button { .slider_reset_button {
background-color: var(--dark_875_color); background-color: var(--dark_875_color);
padding: 0.6rem; padding: 0.6rem;

View File

@@ -65,6 +65,7 @@ const ErrorContainer = ({error}) => {
); );
}; };
// Duplicated
const CloseButtonContainer = () => { const CloseButtonContainer = () => {
const { asyncCloseApp } = useWindow(); const { asyncCloseApp } = useWindow();
return ( return (

View File

@@ -72,6 +72,7 @@
// Duplicated
.close_button_wrapper { .close_button_wrapper {
position: absolute; position: absolute;
top: 0; top: 0;

View File

@@ -31,5 +31,5 @@
margin-left: 0.2rem; margin-left: 0.2rem;
padding-bottom: 0.2rem; padding-bottom: 0.2rem;
width: 1.8rem; width: 1.8rem;
color: var(--waring_color); color: var(--warning_color);
} }

View File

@@ -59,7 +59,7 @@ export const UpdateModal = () => {
</div> </div>
<div className={styles.cuda_section}> <div className={styles.cuda_section}>
<div className={styles.button_wrapper}> <div className={styles.button_wrapper}>
<button className={cuda_accept_button_class_name} onClick={onClickUpdateSoftware_CUDA}>CUDA (GPU)</button> <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} {!is_cpu_version ? <CurrentVersionLabel is_latest_version_already={is_latest_version_already} is_cuda={true}/> : null}
</div> </div>
<div className={styles.version_desc_container}> <div className={styles.version_desc_container}>
@@ -85,7 +85,7 @@ const VersionDescComponent = (props) => {
return ( return (
<div className={styles.version_desc_wrapper}> <div className={styles.version_desc_wrapper}>
<div className={styles.version_desc_point}></div> <div className={styles.version_desc_point}></div>
<p className={styles.version_desc}>{props.desc}</p> <p className={styles.version_desc}>{`- ${props.desc}`}</p>
</div> </div>
); );
}; };

View File

@@ -54,7 +54,7 @@
.warning_svg { .warning_svg {
padding-bottom: 0.4rem; padding-bottom: 0.4rem;
width: 2.4rem; width: 2.4rem;
color: var(--waring_color); color: var(--warning_color);
flex-shrink: 0; flex-shrink: 0;
} }

View File

@@ -0,0 +1,112 @@
:root {
--toastify-color-light: #fff;
--toastify-color-dark: var(--dark_950_color);
--toastify-color-info: var(--sent_400_color);
--toastify-color-success: var(--primary_400_color);
--toastify-color-warning: var(--warning_bc_color);
--toastify-color-error: var(--error_bc_color);
--toastify-color-transparent: rgba(255, 255, 255, 0.7);
--toastify-icon-color-info: var(--toastify-color-info);
--toastify-icon-color-success: var(--toastify-color-success);
--toastify-icon-color-warning: var(--toastify-color-warning);
--toastify-icon-color-error: var(--toastify-color-error);
--toastify-container-width: fit-content;
--toastify-toast-width: 32rem;
--toastify-toast-offset: 1.6rem;
--toastify-toast-top: max(var(--toastify-toast-offset), env(safe-area-inset-top));
--toastify-toast-right: max(var(--toastify-toast-offset), env(safe-area-inset-right));
--toastify-toast-left: max(var(--toastify-toast-offset), env(safe-area-inset-left));
--toastify-toast-bottom: max(var(--toastify-toast-offset), env(safe-area-inset-bottom));
--toastify-toast-background: #fff;
--toastify-toast-padding: 1.4rem;
--toastify-toast-min-height: 6.4rem;
--toastify-toast-max-height: 80rem;
--toastify-toast-bd-radius: 0.6rem;
--toastify-toast-shadow: .0 0.4rem 1.2rem rgba(0, 0, 0, 0.1);
--toastify-font-family: var(--font_family);
--toastify-z-index: 9999;
--toastify-text-color-light: #757575;
--toastify-text-color-dark: var(--dark_basic_text_color);
/* Used only for colored theme */
--toastify-text-color-info: var(--dark_basic_text_color);
--toastify-text-color-success: var(--dark_basic_text_color);
--toastify-text-color-warning: var(--dark_basic_text_color);
--toastify-text-color-error: var(--dark_basic_text_color);
--toastify-spinner-color: #616161;
--toastify-spinner-color-empty-area: #e0e0e0;
--toastify-color-progress-light: linear-gradient(to right, #4cd964, #5ac8fa, #007aff, #34aadc, #5856d6, #ff2d55);
--toastify-color-progress-dark: #bb86fc;
--toastify-color-progress-info: var(--toastify-color-info);
--toastify-color-progress-success: var(--toastify-color-success);
--toastify-color-progress-warning: var(--toastify-color-warning);
--toastify-color-progress-error: var(--toastify-color-error);
/* used to control the opacity of the progress trail */
--toastify-color-progress-bgo: 0.2;
}
.Toastify__toast {
// --------------------------------------------------------
// Default Settings
// --------------------------------------------------------
position: relative;
touch-action: none;
// width: var(--toastify-toast-width);
min-height: var(--toastify-toast-min-height);
box-sizing: border-box;
margin-bottom: 1rem;
// padding: var(--toastify-toast-padding);
border-radius: 0.6rem;
box-shadow: none;
max-height: var(--toastify-toast-max-height);
// font-family: "Yu Gothic UI";
// font-family: var(--toastify-font-family);
// z-index: 0;
// display: flex;
// flex: 1 auto;
// align-items: center;
word-break: break-word;
// --------------------------------------------------------
// --------------------------------------------------------
// Comment out above and override. Commented out is just for memorization.
overflow: hidden;
display: flex;
justify-content: start;
align-items: center;
font-size: 1.4rem;
width: fit-content;
max-width: 50vw;
padding-right: 4rem;
background-color: var(--dark_950_color);
gap: 0.6rem;
}
.Toastify__progress-bar--wrp {
height: 0.4rem;
}
.Toastify__progress-bar--success {
background: var(--success_bc_color);
}
.Toastify__progress-bar--warning {
background: var(--warning_bc_color);
}
.Toastify__progress-bar--error {
background: var(--error_bc_color);
}
.Toastify__toast-icon {
width: fit-content;
max-width: 2.8rem;
min-width: 2.8rem;
justify-content: center;
align-items: center;
}

View File

@@ -1,46 +1,114 @@
import React, { useEffect, useState } from "react";
import { ToastContainer, toast, Bounce } from "react-toastify";
import clsx from "clsx"; import clsx from "clsx";
import Snackbar from "@mui/material/Snackbar";
import Slide from "@mui/material/Slide";
import "./ReactToastifyOverrideClass.scss";
import styles from "./SnackbarController.module.scss"; import styles from "./SnackbarController.module.scss";
import XMarkSvg from "@images/cancel.svg?react";
import WarningSvg from "@images/warning.svg?react";
import MegaphoneSvg from "@images/megaphone.svg?react";
import CheckMarkSvg from "@images/check_mark.svg?react";
import ErrorSvg from "@images/error.svg?react";
import { useNotificationStatus } from "@logics_common"; import { useNotificationStatus } from "@logics_common";
export const SnackbarController = () => { export const SnackbarController = () => {
const { currentNotificationStatus, closeNotification } = useNotificationStatus(); const { currentNotificationStatus, closeNotification } = useNotificationStatus();
const [containerKey, setContainerKey] = useState(0);
const handleClose = (event, reason) => {
closeNotification(event, reason);
};
const snackbar_classname = clsx(styles.snackbar_content, {
[styles.is_success]: currentNotificationStatus.data.status === "success",
[styles.is_warning]: currentNotificationStatus.data.status === "warning",
[styles.is_error]: currentNotificationStatus.data.status === "error",
});
const settings = currentNotificationStatus.data; const settings = currentNotificationStatus.data;
let hide_duration = 5000; const snackbar_classname = clsx(
if (settings.options?.hide_duration === null) hide_duration = null; styles.snackbar_content,
if (Number(settings.options?.hide_duration)) hide_duration = settings.options.hide_duration; {
[styles.is_success]: settings.status === "success",
[styles.is_warning]: settings.status === "warning",
[styles.is_error]: settings.status === "error",
}
);
let hideDuration = 5000;
if (settings.options?.hide_duration === null) {
hideDuration = false;
} else if (Number(settings.options?.hide_duration)) {
hideDuration = Number(settings.options?.hide_duration);
}
useEffect(() => {
if (!settings.is_open) return;
const message_text = settings.message;
if (toast.isActive(message_text)) {
setContainerKey(prevKey => prevKey + 1);
setTimeout(() => {
toast(message_text, {
toastId: message_text,
type: settings.status,
autoClose: hideDuration,
transition: Bounce,
toastClassName: snackbar_classname,
progressClassName: styles.toast_progress,
closeButton: <CloseButtonContainer />,
onClose: () => {
closeNotification();
},
});
}, 50);
} else {
toast(message_text, {
toastId: message_text,
type: settings.status,
autoClose: hideDuration,
transition: Bounce,
toastClassName: snackbar_classname,
progressClassName: styles.toast_progress,
closeButton: <CloseButtonContainer />,
onClose: () => {
closeNotification();
},
});
}
}, [settings, hideDuration, closeNotification, snackbar_classname]);
return ( return (
<div> <ToastContainer
<Snackbar key={containerKey}
open={settings.is_open} position="bottom-left"
onClose={handleClose} transition={Bounce}
TransitionComponent={SlideTransition} hideProgressBar={false}
key={settings.key} newestOnTop={false}
autoHideDuration={hide_duration} closeOnClick={false}
> pauseOnFocusLoss={false}
<div className={snackbar_classname}> draggable={false}
<p className={styles.snackbar_message}>{settings.message}</p> pauseOnHover={true}
</div> theme="dark"
</Snackbar> icon={({ type }) => {
</div> switch (type) {
case "info":
return <MegaphoneSvg className={styles.megaphone_svg} />;
case "error":
return <ErrorSvg className={styles.error_svg} />;
case "success":
return <CheckMarkSvg className={styles.check_mark_svg} />;
case "warning":
return <WarningSvg className={styles.warning_svg} />;
default:
return null;
}
}}
/>
); );
}; };
const SlideTransition = (props) => { const CloseButtonContainer = ({ closeToast }) => {
return <Slide {...props} direction="up" />; return (
}; <button className={styles.close_button_wrapper} onClick={closeToast}>
<div className={styles.close_button}>
<XMarkSvg className={styles.x_mark_svg} />
</div>
</button>
);
};

View File

@@ -1,19 +1,75 @@
.snackbar_content { .snackbar_content {
width: 100%; position: relative;
height: 100%; padding: 1.2rem 1.6rem;
padding: 2rem; border-radius: 0.8rem;
color: #fff; font-size: 1.4rem;
&.is_success { box-shadow: 0 0.2rem 0.8rem rgba(0, 0, 0, 0.5);
background-color: var(--success_bc_color);
}
&.is_warning {
background-color: var(--waring_bc_color);
}
&.is_error {
background-color: var(--error_bc_color);
}
} }
.snackbar_message { // .is_success {
font-size: 1.4rem; // background-color: var(--success_bc_color);
// }
// .is_warning {
// background-color: var(--warning_bc_color);
// }
// .is_error {
// background-color: var(--error_bc_color);
// }
.megaphone_svg {
color: var(--dark_200_color);
width: 2.4rem;
}
.error_svg {
color: var(--error_bc_color);
width: 2.4rem;
}
.check_mark_svg {
color: var(--primary_400_color);
width: 2rem;
}
.warning_svg {
color: var(--warning_color);
width: 2.4rem;
}
// Duplicated (Customized)
.close_button_wrapper {
position: absolute;
top: 0;
left: 100%;
transform: translate(-50%, -50%) rotate(45deg);
display: flex;
justify-content: center;
align-items: end;
width: 5.6rem;
aspect-ratio: 1 / 1;
&:hover {
background-color: var(--error_bc_color);
& .x_mark_svg {
color: var(--dark_200_color);
transform: rotate(45deg);
}
}
&:active {
background-color: var(--error_bc_active_color);
}
transition: all 0.1s ease;
}
.close_button {
// width: 100%;
// height: 100%;
}
.x_mark_svg {
width: 2rem;
transform: rotate(-45deg);
color: var(--dark_700_color);
transition: transform 0.3s ease;
} }

View File

@@ -71,7 +71,7 @@ const AnnouncementsContainer = () => {
}; };
// Duplicated
const CloseButtonContainer = () => { const CloseButtonContainer = () => {
const { asyncCloseApp } = useWindow(); const { asyncCloseApp } = useWindow();

View File

@@ -67,7 +67,7 @@
} }
// Duplicated
.close_button_wrapper { .close_button_wrapper {
position: absolute; position: absolute;
top: 0; top: 0;

1
src-ui/assets/error.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm-1.31 7.526c-.099-.807.528-1.526 1.348-1.526.771 0 1.377.676 1.28 1.451l-.757 6.053c-.035.283-.276.496-.561.496s-.526-.213-.562-.496l-.748-5.978zm1.31 10.724c-.69 0-1.25-.56-1.25-1.25s.56-1.25 1.25-1.25 1.25.56 1.25 1.25-.56 1.25-1.25 1.25z"/></svg>

After

Width:  |  Height:  |  Size: 468 B

View File

@@ -35,8 +35,7 @@ export const useNotificationStatus = () => {
}); });
}; };
const closeNotification = (event, reason) => { const closeNotification = () => {
if (reason === "clickaway") return;
updateNotificationStatus((prev) => ({ updateNotificationStatus((prev) => ({
...prev.data, ...prev.data,
is_open: false, is_open: false,

View File

@@ -7,12 +7,18 @@ export const ui_configs = {
x_pos: { step: 0.05, min: -0.5, max: 0.5 }, x_pos: { step: 0.05, min: -0.5, max: 0.5 },
y_pos: { step: 0.05, min: -0.8, max: 0.8 }, y_pos: { step: 0.05, min: -0.8, max: 0.8 },
z_pos: { step: 0.05, min: -0.5, max: 1.5 }, z_pos: { step: 0.05, min: -0.5, max: 1.5 },
x_rotation: { min: -180, max: 180, step: 5 },
y_rotation: { min: -180, max: 180, step: 5 },
z_rotation: { min: -180, max: 180, step: 5 },
ui_scaling: { step: 10, min: 40, max: 200 }, ui_scaling: { step: 10, min: 40, max: 200 },
}, },
overlay_large_log: { overlay_large_log: {
x_pos: { step: 0.05, min: -0.5, max: 0.5 }, x_pos: { step: 0.05, min: -0.5, max: 0.5 },
y_pos: { step: 0.05, min: -0.8, max: 0.8 }, y_pos: { step: 0.05, min: -0.8, max: 0.8 },
z_pos: { step: 0.05, min: -0.5, max: 1.5 }, z_pos: { step: 0.05, min: -0.5, max: 1.5 },
x_rotation: { min: -180, max: 180, step: 5 },
y_rotation: { min: -180, max: 180, step: 5 },
z_rotation: { min: -180, max: 180, step: 5 },
ui_scaling: { step: 10, min: 40, max: 200 }, ui_scaling: { step: 10, min: 40, max: 200 },
}, },