diff --git a/locales/ja.yml b/locales/ja.yml
index b8d70695..a9a6901b 100644
--- a/locales/ja.yml
+++ b/locales/ja.yml
@@ -29,8 +29,8 @@ common_warning:
main_page:
translation: "翻訳"
- transcription_send: "音声認識 マイク"
- transcription_receive: "音声認識 スピーカー"
+ transcription_send: "マイク入力"
+ transcription_receive: "聞き取り"
foreground: "最前面固定"
language_settings: "言語設定"
@@ -134,7 +134,7 @@ config_page:
ctranslate2_compute_device:
label: "AI翻訳 {{ctranslate2}} の処理デバイス"
deepl_auth_key:
- label: "DeepL API 認証キー"
+ label: "DeepL APIキーの登録"
desc: "使用の際は、メイン画面にある {{translator}} をDeepL_APIに変更してください。\n※対応していない言語もあります。"
open_auth_key_webpage: "DeepLアカウントページを開く"
save: "保存"
diff --git a/package-lock.json b/package-lock.json
index f131d4a8..cbe6e142 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,6 +28,7 @@
"react-error-boundary": "5.0.0",
"react-i18next": "15.5.1",
"react-resizable-layout": "0.7.2",
+ "react-toastify": "11.0.5",
"sass": "1.79.4",
"semver": "7.7.1"
},
@@ -5534,6 +5535,19 @@
"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": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
diff --git a/package.json b/package.json
index a2d9030f..c15471e5 100644
--- a/package.json
+++ b/package.json
@@ -43,6 +43,7 @@
"react-error-boundary": "5.0.0",
"react-i18next": "15.5.1",
"react-resizable-layout": "0.7.2",
+ "react-toastify": "11.0.5",
"sass": "1.79.4",
"semver": "7.7.1"
},
diff --git a/src-python/config.py b/src-python/config.py
index cfeeec51..64c09440 100644
--- a/src-python/config.py
+++ b/src-python/config.py
@@ -989,7 +989,7 @@ class Config:
def init_config(self):
# Read Only
- self._VERSION = "3.1.2"
+ self._VERSION = "3.2.0"
if getattr(sys, 'frozen', False):
self._PATH_LOCAL = os_path.dirname(sys.executable)
else:
diff --git a/src-ui/app/_index_css/variables.css b/src-ui/app/_index_css/variables.css
index ca2beca1..3ae80370 100644
--- a/src-ui/app/_index_css/variables.css
+++ b/src-ui/app/_index_css/variables.css
@@ -24,8 +24,8 @@
--error_bc_color: #bb4448;
--error_bc_active_color: #9c3938;
--success_bc_color: #368777;
- --waring_color: #cb944f;
- --waring_bc_color: #cf7b1b;
+ --warning_color: #cb944f;
+ --warning_bc_color: #cf7b1b;
--dark_basic_text_color: #f2f2f2;
--dark_100_color: #f5f7fb;
diff --git a/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx b/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx
index 8f61d725..827c0253 100644
--- a/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx
+++ b/src-ui/app/config_page/setting_section/setting_box/_components/slider/Slider.jsx
@@ -4,44 +4,107 @@ import MUI_Slider from "@mui/material/Slider";
import clsx from "clsx";
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 (
-
+
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}
track={props.track}
orientation={props.orientation}
valueLabelFormat={`${props.valueLabelFormat ? props.valueLabelFormat : props.variable}`}
- sx={{
- 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)",
- },
- }}
+ sx={sliderSx}
/>
);
diff --git a/src-ui/app/config_page/setting_section/setting_box/vr/Vr.jsx b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.jsx
index 06920712..b145bb44 100644
--- a/src-ui/app/config_page/setting_section/setting_box/vr/Vr.jsx
+++ b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.jsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from "react";
+import React, { useState, useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import clsx from "clsx";
import styles from "./Vr.module.scss";
@@ -25,6 +25,10 @@ import {
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 = () => {
const { t } = useTranslation();
const [is_opened_small_settings, setIsOpenedSmallSettings] = useState(true);
@@ -147,7 +151,7 @@ const OverlaySettingsContainer = ({
) : (
)}
-
+
{
);
};
-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 {
+ 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 (
@@ -205,8 +234,18 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
min={ui_configs.x_pos.min}
max={ui_configs.x_pos.max}
onchangeFunction={(value) => onchangeFunction("x_pos", value)}
+ valueLabelDisplay={x_variable_display}
+ valueLabelDisplayLocation="top"
+ />
+
+
{t("config_page.vr.y_position")}
@@ -221,8 +260,18 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
max={ui_configs.y_pos.max}
onchangeFunction={(value) => onchangeFunction("y_pos", value)}
orientation="vertical"
+ valueLabelDisplay={y_variable_display}
+ valueLabelDisplayLocation="right"
+ />
+
+
{t("config_page.vr.z_position")}
@@ -237,69 +286,162 @@ const PositionControls = ({settings, onchangeFunction, selectFunction, ui_config
max={ui_configs.z_pos.max}
onchangeFunction={(value) => onchangeFunction("z_pos", value)}
orientation="vertical"
+ valueLabelDisplay={z_variable_display}
+ valueLabelDisplayLocation="left"
+ />
+
);
};
-const RotationControls = ({settings, onchangeFunction, selectFunction, default_ui_configs}) => {
+export const RotationControls = ({ settings, onchangeFunction, selectFunction, ui_configs, default_ui_configs }) => {
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 (
{t("config_page.vr.x_rotation")}
- selectFunction("x_rotation", default_ui_configs.y_pos)} />
+ selectFunction("x_rotation", default_ui_configs.x_rotation)} />
onchangeFunction("x_rotation", -value)}
orientation="vertical"
+ valueLabelDisplay={x_variable_display}
+ valueLabelDisplayLocation="right"
+ />
+
+
{t("config_page.vr.y_rotation")}
- selectFunction("y_rotation", default_ui_configs.y_pos)} />
+ selectFunction("y_rotation", default_ui_configs.y_rotation)} />
onchangeFunction("y_rotation", value)}
+ valueLabelDisplay={y_variable_display}
+ valueLabelDisplayLocation="top"
+ />
+
+
{t("config_page.vr.z_rotation")}
- selectFunction("z_rotation", default_ui_configs.y_pos)} />
+ selectFunction("z_rotation", default_ui_configs.z_rotation)} />
onchangeFunction("z_rotation", value)}
orientation="vertical"
+ valueLabelDisplay={z_variable_display}
+ valueLabelDisplayLocation="left"
+ />
+
);
};
+const AdjustButtonContainer = ({ wrapper_class_name, is_max, is_min, countUp, countDown }) => {
+ return (
+
+ );
+};
+
+
const OtherControls = ({settings, onchangeFunction, ui_configs}) => {
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 { t } = useTranslation();
const { sendTextToOverlay } = useSendTextToOverlay();
@@ -445,4 +583,58 @@ const SendSampleTextToggleButton = () => {
{label}
);
+};
+
+
+
+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,
+ };
};
\ No newline at end of file
diff --git a/src-ui/app/config_page/setting_section/setting_box/vr/Vr.module.scss b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.module.scss
index 35798530..9d0963e8 100644
--- a/src-ui/app/config_page/setting_section/setting_box/vr/Vr.module.scss
+++ b/src-ui/app/config_page/setting_section/setting_box/vr/Vr.module.scss
@@ -16,7 +16,7 @@
justify-content: center;
width: 100%;
max-width: 56rem;
- gap: 2rem;
+ gap: 4rem;
}
.controller_type_switch {
@@ -58,12 +58,13 @@
.sample_text_button_wrapper {
position: absolute;
- bottom: 0;
- left: -74%;
+ bottom: -12%;
+ left: -80%;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
+ // transform: translate(-50%, -50%);
}
.sample_text_button {
background-color: var(--dark_850_color);
@@ -121,20 +122,20 @@
}
.x_position_label {
position: absolute;
- bottom: -4.6rem;
+ bottom: -5rem;
right: -46%;
justify-content: end;
}
.y_position_label {
position: absolute;
- top: -44%;
- left: 10%;
- justify-content: start;
+ bottom: 110%;
+ right: 119%;
+ justify-content: end;
}
.z_position_label {
position: absolute;
- top: 30%;
- left: 80%;
+ top: 14%;
+ left: 110%;
}
.x_position_slider {
@@ -155,14 +156,84 @@
.z_position_slider {
position: absolute;
- bottom: 61%;
- left: 61%;
+ bottom: 80%;
+ left: 88%;
transform: translate(50%,50%) rotate(45deg);
width: 0%;
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 {
@@ -175,19 +246,20 @@
.x_rotation_label {
position: absolute;
- top: -44%;
- left: 10%;
+ bottom: 110%;
+ right: 119%;
+ justify-content: end;
}
.y_rotation_label {
position: absolute;
- bottom: -4.6rem;
+ bottom: -5rem;
right: -46%;
justify-content: end;
}
.z_rotation_label {
position: absolute;
- top: -10%;
- right: -110%;
+ top: -20%;
+ right: -100%;
}
.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 {
background-color: var(--dark_875_color);
padding: 0.6rem;
diff --git a/src-ui/app/error_boundary/AppErrorBoundary.jsx b/src-ui/app/error_boundary/AppErrorBoundary.jsx
index 4aeb34a2..37a1cc23 100644
--- a/src-ui/app/error_boundary/AppErrorBoundary.jsx
+++ b/src-ui/app/error_boundary/AppErrorBoundary.jsx
@@ -65,6 +65,7 @@ const ErrorContainer = ({error}) => {
);
};
+// Duplicated
const CloseButtonContainer = () => {
const { asyncCloseApp } = useWindow();
return (
diff --git a/src-ui/app/error_boundary/AppErrorBoundary.module.scss b/src-ui/app/error_boundary/AppErrorBoundary.module.scss
index 2abb2710..2ff85390 100644
--- a/src-ui/app/error_boundary/AppErrorBoundary.module.scss
+++ b/src-ui/app/error_boundary/AppErrorBoundary.module.scss
@@ -72,6 +72,7 @@
+// Duplicated
.close_button_wrapper {
position: absolute;
top: 0;
diff --git a/src-ui/app/main_page/sidebar_section/language_settings/translator_selector_open_button/TranslatorSelectorOpenButton.module.scss b/src-ui/app/main_page/sidebar_section/language_settings/translator_selector_open_button/TranslatorSelectorOpenButton.module.scss
index 6549c5b3..ed8a1ab7 100644
--- a/src-ui/app/main_page/sidebar_section/language_settings/translator_selector_open_button/TranslatorSelectorOpenButton.module.scss
+++ b/src-ui/app/main_page/sidebar_section/language_settings/translator_selector_open_button/TranslatorSelectorOpenButton.module.scss
@@ -31,5 +31,5 @@
margin-left: 0.2rem;
padding-bottom: 0.2rem;
width: 1.8rem;
- color: var(--waring_color);
+ color: var(--warning_color);
}
\ No newline at end of file
diff --git a/src-ui/app/modal_controller/update_modal/UpdateModal.jsx b/src-ui/app/modal_controller/update_modal/UpdateModal.jsx
index c35a240c..dd8f0f43 100644
--- a/src-ui/app/modal_controller/update_modal/UpdateModal.jsx
+++ b/src-ui/app/modal_controller/update_modal/UpdateModal.jsx
@@ -59,7 +59,7 @@ export const UpdateModal = () => {
-
+
{!is_cpu_version ? : null}
@@ -85,7 +85,7 @@ const VersionDescComponent = (props) => {
return (
-
{props.desc}
+
{`- ${props.desc}`}
);
};
diff --git a/src-ui/app/modal_controller/update_modal/plugins_compatibility_list/PluginCompatibilityList.module.scss b/src-ui/app/modal_controller/update_modal/plugins_compatibility_list/PluginCompatibilityList.module.scss
index 0b439619..a82112e1 100644
--- a/src-ui/app/modal_controller/update_modal/plugins_compatibility_list/PluginCompatibilityList.module.scss
+++ b/src-ui/app/modal_controller/update_modal/plugins_compatibility_list/PluginCompatibilityList.module.scss
@@ -54,7 +54,7 @@
.warning_svg {
padding-bottom: 0.4rem;
width: 2.4rem;
- color: var(--waring_color);
+ color: var(--warning_color);
flex-shrink: 0;
}
diff --git a/src-ui/app/snackbar_controller/ReactToastifyOverrideClass.scss b/src-ui/app/snackbar_controller/ReactToastifyOverrideClass.scss
new file mode 100644
index 00000000..75ad8e19
--- /dev/null
+++ b/src-ui/app/snackbar_controller/ReactToastifyOverrideClass.scss
@@ -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;
+}
\ No newline at end of file
diff --git a/src-ui/app/snackbar_controller/SnackbarController.jsx b/src-ui/app/snackbar_controller/SnackbarController.jsx
index e503e695..28bd6325 100644
--- a/src-ui/app/snackbar_controller/SnackbarController.jsx
+++ b/src-ui/app/snackbar_controller/SnackbarController.jsx
@@ -1,46 +1,114 @@
+import React, { useEffect, useState } from "react";
+import { ToastContainer, toast, Bounce } from "react-toastify";
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 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";
export const SnackbarController = () => {
const { currentNotificationStatus, closeNotification } = useNotificationStatus();
-
- 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 [containerKey, setContainerKey] = useState(0);
const settings = currentNotificationStatus.data;
- let hide_duration = 5000;
- if (settings.options?.hide_duration === null) hide_duration = null;
- if (Number(settings.options?.hide_duration)) hide_duration = settings.options.hide_duration;
+ const snackbar_classname = clsx(
+ styles.snackbar_content,
+ {
+ [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:
,
+ 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:
,
+ onClose: () => {
+ closeNotification();
+ },
+ });
+ }
+ }, [settings, hideDuration, closeNotification, snackbar_classname]);
return (
-
+
{
+ switch (type) {
+ case "info":
+ return ;
+ case "error":
+ return ;
+ case "success":
+ return ;
+ case "warning":
+ return ;
+ default:
+ return null;
+ }
+ }}
+ />
);
};
-const SlideTransition = (props) => {
- return ;
-};
+const CloseButtonContainer = ({ closeToast }) => {
+ return (
+
+ );
+};
\ No newline at end of file
diff --git a/src-ui/app/snackbar_controller/SnackbarController.module.scss b/src-ui/app/snackbar_controller/SnackbarController.module.scss
index 075e4419..ebb18798 100644
--- a/src-ui/app/snackbar_controller/SnackbarController.module.scss
+++ b/src-ui/app/snackbar_controller/SnackbarController.module.scss
@@ -1,19 +1,75 @@
.snackbar_content {
- width: 100%;
- height: 100%;
- padding: 2rem;
- color: #fff;
- &.is_success {
- background-color: var(--success_bc_color);
- }
- &.is_warning {
- background-color: var(--waring_bc_color);
- }
- &.is_error {
- background-color: var(--error_bc_color);
- }
+ position: relative;
+ padding: 1.2rem 1.6rem;
+ border-radius: 0.8rem;
+ font-size: 1.4rem;
+ box-shadow: 0 0.2rem 0.8rem rgba(0, 0, 0, 0.5);
}
-.snackbar_message {
- font-size: 1.4rem;
+// .is_success {
+// 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;
}
\ No newline at end of file
diff --git a/src-ui/app/splash_component/SplashComponent.jsx b/src-ui/app/splash_component/SplashComponent.jsx
index 2943bad0..809f917c 100644
--- a/src-ui/app/splash_component/SplashComponent.jsx
+++ b/src-ui/app/splash_component/SplashComponent.jsx
@@ -71,7 +71,7 @@ const AnnouncementsContainer = () => {
};
-
+// Duplicated
const CloseButtonContainer = () => {
const { asyncCloseApp } = useWindow();
diff --git a/src-ui/app/splash_component/SplashComponent.module.scss b/src-ui/app/splash_component/SplashComponent.module.scss
index f279b21b..bae69063 100644
--- a/src-ui/app/splash_component/SplashComponent.module.scss
+++ b/src-ui/app/splash_component/SplashComponent.module.scss
@@ -67,7 +67,7 @@
}
-
+// Duplicated
.close_button_wrapper {
position: absolute;
top: 0;
diff --git a/src-ui/assets/error.svg b/src-ui/assets/error.svg
new file mode 100644
index 00000000..4842a2a7
--- /dev/null
+++ b/src-ui/assets/error.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src-ui/logics/common/useNotificationStatus.js b/src-ui/logics/common/useNotificationStatus.js
index f4aab3ed..c623d091 100644
--- a/src-ui/logics/common/useNotificationStatus.js
+++ b/src-ui/logics/common/useNotificationStatus.js
@@ -35,8 +35,7 @@ export const useNotificationStatus = () => {
});
};
- const closeNotification = (event, reason) => {
- if (reason === "clickaway") return;
+ const closeNotification = () => {
updateNotificationStatus((prev) => ({
...prev.data,
is_open: false,
diff --git a/src-ui/ui_configs.js b/src-ui/ui_configs.js
index d6ef28eb..915d6a6b 100644
--- a/src-ui/ui_configs.js
+++ b/src-ui/ui_configs.js
@@ -7,12 +7,18 @@ export const ui_configs = {
x_pos: { step: 0.05, min: -0.5, max: 0.5 },
y_pos: { step: 0.05, min: -0.8, max: 0.8 },
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 },
},
overlay_large_log: {
x_pos: { step: 0.05, min: -0.5, max: 0.5 },
y_pos: { step: 0.05, min: -0.8, max: 0.8 },
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 },
},