[Update] Config Page: MessageFormat: Add ui, message format.
This commit is contained in:
@@ -211,6 +211,7 @@ config_page:
|
||||
|
||||
others:
|
||||
section_label_sounds: "Sounds"
|
||||
section_label_message_formats: "Message Formats"
|
||||
auto_clear_the_message_box:
|
||||
label: "Auto Clear Message box"
|
||||
send_only_translated_messages:
|
||||
@@ -231,6 +232,26 @@ config_page:
|
||||
label: "Send Received Message To VRChat"
|
||||
desc: "Send the message you received from the speaker's voice to VRChat's chatbox."
|
||||
|
||||
message_format_common:
|
||||
example_view:
|
||||
title: "Preview"
|
||||
original_translated: "Original + Translated"
|
||||
original_translated_multi: "Original + Translated (Multi-Translation)"
|
||||
translated_only_multi: "Translated Only (Multi-Translation)"
|
||||
translated_only: "Translated Only"
|
||||
original_only: "Original Only"
|
||||
settings:
|
||||
title: "Settings"
|
||||
original: "Original"
|
||||
translated: "Translated"
|
||||
for_multi_translation: For Multi-Translation
|
||||
send_message_format:
|
||||
label: "Message Format (Send)"
|
||||
desc: "You can change the decoration of the message you want to send."
|
||||
received_message_format:
|
||||
label: "Message Format (Speaker2Chatbox)"
|
||||
desc: "It will be used in Speaker2Chatbox for now."
|
||||
|
||||
hotkeys:
|
||||
toggle_vrct_visibility:
|
||||
label: "Toggle VRCT visibility"
|
||||
|
||||
@@ -211,6 +211,7 @@ config_page:
|
||||
|
||||
others:
|
||||
section_label_sounds: "サウンド"
|
||||
section_label_message_formats: "メッセージフォーマット"
|
||||
auto_clear_the_message_box:
|
||||
label: "送信後はメッセージ入力欄を空にする"
|
||||
send_only_translated_messages:
|
||||
@@ -230,6 +231,25 @@ config_page:
|
||||
send_received_message_to_vrc:
|
||||
label: "受信したメッセージをVRChatに送信する"
|
||||
desc: "スピーカーから聞き取り、文字起こしされたメッセージをVRChatに送信します。"
|
||||
message_format_common:
|
||||
example_view:
|
||||
title: "プレビュー"
|
||||
original_translated: "原文 + 翻訳"
|
||||
original_translated_multi: "原文 + 翻訳(多言語)"
|
||||
translated_only_multi: "翻訳のみ(多言語)"
|
||||
translated_only: "翻訳のみ"
|
||||
original_only: "原文のみ"
|
||||
settings:
|
||||
title: "設定"
|
||||
original: "原文"
|
||||
translated: "翻訳"
|
||||
for_multi_translation: 多言語翻訳用
|
||||
send_message_format:
|
||||
label: メッセージフォーマット(送信)
|
||||
desc: VRChatで相手に実際に見えるフォーマットを変更できます。
|
||||
received_message_format:
|
||||
label: メッセージフォーマット(Speaker2Chatbox)
|
||||
desc: 今のところ、Speaker2Chatboxで送信した時の表示に使われます。
|
||||
|
||||
hotkeys:
|
||||
toggle_vrct_visibility:
|
||||
|
||||
@@ -21,11 +21,11 @@ const _Entry = forwardRef((props, ref) => {
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.entry_container}>
|
||||
<div
|
||||
className={input_wrapper_class_names}
|
||||
style={{width: props.width || "20rem" }}
|
||||
className={styles.entry_container}
|
||||
style={{width: props.width || "100%" }}
|
||||
>
|
||||
<div className={input_wrapper_class_names}>
|
||||
<input
|
||||
ref={inputRef}
|
||||
text={props.text ? props.text : "text"}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
}
|
||||
|
||||
.entry_wrapper {
|
||||
width: 10rem;
|
||||
height: 100%;
|
||||
padding: 0.6rem;
|
||||
background-color: var(--dark_875_color);
|
||||
@@ -19,6 +18,7 @@
|
||||
height: 100%;
|
||||
font-size: 1.4rem;
|
||||
resize: none;
|
||||
font-family: Arial, sans-serif;
|
||||
&.is_disabled {
|
||||
color: var(--dark_500_color);
|
||||
pointer-events: none;
|
||||
|
||||
@@ -13,3 +13,4 @@ export { SwitchBox } from "./switch_box/SwitchBox";
|
||||
export { ThresholdComponent } from "./threshold_component/ThresholdComponent";
|
||||
export { WordFilter, WordFilterListToggleComponent } from "./word_filter/WordFilter";
|
||||
export { DownloadModels } from "./download_models/DownloadModels";
|
||||
export { MessageFormat } from "./message_format/MessageFormat";
|
||||
@@ -0,0 +1,295 @@
|
||||
import styles from "./MessageFormat.module.scss";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { _Entry } from "../_atoms/_entry/_Entry";
|
||||
import SwapImg from "@images/swap_icon.png";
|
||||
import ArrowLeftSvg from "@images/arrow_left.svg?react";
|
||||
import { useStore_IsBreakPoint } from "@store";
|
||||
import { useAppearance } from "@logics_configs";
|
||||
import { ui_configs } from "@ui_configs";
|
||||
import { ResetButton } from "@common_components";
|
||||
|
||||
const ENTRY_WIDTH = "8rem";
|
||||
|
||||
const EXAMPLE_TEXTS = {
|
||||
en: "Hello",
|
||||
ja: "こんにちは",
|
||||
ko: "안녕하세요",
|
||||
fr: "Bonjour",
|
||||
};
|
||||
|
||||
export const MessageFormat = (props) => {
|
||||
const { currentIsBreakPoint } = useStore_IsBreakPoint();
|
||||
const message_format_container_class = clsx(styles.container, {
|
||||
[styles.is_break_point]: currentIsBreakPoint.data,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={message_format_container_class}>
|
||||
<ExampleComponent
|
||||
format={props.variable.data}
|
||||
example_view_filter_variable={props.example_view_filter_variable}
|
||||
exampleViewFilterToggleFunction={props.exampleViewFilterToggleFunction}
|
||||
format_id={props.format_id}
|
||||
/>
|
||||
<div className={styles.border}></div>
|
||||
<InputComponent
|
||||
variable={props.variable.data}
|
||||
setFunction={props.setFunction}
|
||||
format_id={props.format_id}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ExampleComponent = ({ format, example_view_filter_variable, exampleViewFilterToggleFunction, format_id }) => {
|
||||
const { currentUiLanguage } = useAppearance();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
const locale_base_path = "config_page.others.message_format_common.example_view.";
|
||||
|
||||
const label_title = t(locale_base_path + "title");
|
||||
|
||||
const label_original_translated = t(locale_base_path + "original_translated");
|
||||
const label_original_translated_multi = t(locale_base_path + "original_translated_multi");
|
||||
const label_translated_only_multi = t(locale_base_path + "translated_only_multi");
|
||||
const label_translated_only = t(locale_base_path + "translated_only");
|
||||
const label_original_only = t(locale_base_path + "original_only");
|
||||
|
||||
const createExampleMessage = (id) => {
|
||||
// 言語順序を決定
|
||||
let example_text_order = [];
|
||||
switch (currentUiLanguage.data) {
|
||||
case "ja":
|
||||
example_text_order = ["ja", "en", "ko", "fr"];
|
||||
break;
|
||||
case "ko":
|
||||
example_text_order = ["ko", "ja", "en", "fr"];
|
||||
break;
|
||||
default: // en
|
||||
example_text_order = ["en", "ja", "ko", "fr"];
|
||||
break;
|
||||
}
|
||||
|
||||
const original = EXAMPLE_TEXTS[example_text_order[0]];
|
||||
const translations = example_text_order.slice(1).map(lang => EXAMPLE_TEXTS[lang]);
|
||||
|
||||
const originalPart = `${format.message.prefix}${original}${format.message.suffix}`;
|
||||
const translationSingle = `${format.translation.prefix}${translations[0]}${format.translation.suffix}`;
|
||||
const translationMulti = `${format.translation.prefix}${translations.join(format.translation.separator)}${format.translation.suffix}`;
|
||||
|
||||
switch (id) {
|
||||
case "original_translated":
|
||||
return format.translation_first
|
||||
? `${translationSingle}${format.separator}${originalPart}`
|
||||
: `${originalPart}${format.separator}${translationSingle}`;
|
||||
|
||||
case "original_only":
|
||||
return originalPart;
|
||||
|
||||
case "translated_only":
|
||||
return translationSingle;
|
||||
|
||||
case "translated_only_multi":
|
||||
return translationMulti;
|
||||
|
||||
case "original_translated_multi":
|
||||
return format.translation_first
|
||||
? `${translationMulti}${format.separator}${originalPart}`
|
||||
: `${originalPart}${format.separator}${translationMulti}`;
|
||||
|
||||
default:
|
||||
throw new Error(`Unexpected id: ${id}`);
|
||||
}
|
||||
};
|
||||
|
||||
const ExampleBox = ({label, example_text_id}) => {
|
||||
return (
|
||||
<div className={styles.example_wrapper}>
|
||||
<p className={styles.example_label}>{label}</p>
|
||||
<div className={styles.example_chatbox}>
|
||||
<p className={styles.example_text}>{createExampleMessage(example_text_id)}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
const svg_class_names = clsx(styles.arrow_left_svg, {
|
||||
[styles.to_down]: example_view_filter_variable[format_id] === "Simplified",
|
||||
[styles.to_up]: example_view_filter_variable[format_id] === "All"
|
||||
});
|
||||
|
||||
|
||||
const FilteredExampleBox = ({format_id, id}) => {
|
||||
if (format_id === "send" && id === "Simplified") {
|
||||
return (
|
||||
<>
|
||||
<ExampleBox label={label_original_translated} example_text_id="original_translated" />
|
||||
<ExampleBox label={label_original_translated_multi} example_text_id="original_translated_multi" />
|
||||
</>
|
||||
);
|
||||
} else if ( format_id === "send" && id === "All") {
|
||||
return (
|
||||
<>
|
||||
<ExampleBox label={label_original_translated} example_text_id="original_translated" />
|
||||
<ExampleBox label={label_original_translated_multi} example_text_id="original_translated_multi" />
|
||||
<ExampleBox label={label_translated_only_multi} example_text_id="translated_only_multi" />
|
||||
<ExampleBox label={label_translated_only} example_text_id="translated_only" />
|
||||
<ExampleBox label={label_original_only} example_text_id="original_only" />
|
||||
</>
|
||||
);
|
||||
|
||||
} else if (format_id === "received") {
|
||||
return (
|
||||
<>
|
||||
<ExampleBox label={label_original_translated} example_text_id="original_translated" />
|
||||
<ExampleBox label={label_original_only} example_text_id="original_only" />
|
||||
<ExampleBox label={label_translated_only} example_text_id="translated_only" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className={styles.example_container}>
|
||||
<p className={styles.section_title}>{label_title}</p>
|
||||
<div className={styles.example_view_container}>
|
||||
<FilteredExampleBox format_id={format_id} id={example_view_filter_variable[format_id]} />
|
||||
</div>
|
||||
{ format_id === "send" &&
|
||||
<div className={styles.show_more_container} onClick={() => exampleViewFilterToggleFunction(format_id)}>
|
||||
<ArrowLeftSvg className={svg_class_names}/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const InputComponent = ({id, variable, setFunction, format_id }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const locale_base_path = "config_page.others.message_format_common.settings.";
|
||||
const label_title = t(locale_base_path + "title");
|
||||
|
||||
const LABEL_ORIGINAL = t(locale_base_path + "original");
|
||||
const LABEL_TRANSLATED = t(locale_base_path + "translated");
|
||||
const LABEL_FOR_MULTI_TRANSLATION = t(locale_base_path + "for_multi_translation");
|
||||
|
||||
const replaceValue = (value) => {
|
||||
if (value === "") return "";
|
||||
|
||||
const replaced = value.replace(/\\n/g, "\n");
|
||||
return replaced;
|
||||
};
|
||||
|
||||
const handleChange = (parent_key, child_key) => (e) => {
|
||||
const rawValue = e.target.value;
|
||||
const parsedValue = replaceValue(rawValue);
|
||||
|
||||
if (child_key !== undefined) {
|
||||
setFunction({
|
||||
...variable,
|
||||
[parent_key]: {
|
||||
...variable[parent_key],
|
||||
[child_key]: parsedValue
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setFunction({
|
||||
...variable,
|
||||
[parent_key]: parsedValue
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const toUiValue = (v) => {
|
||||
if (typeof v === "string") {
|
||||
return v.replace(/\n/g, "\\n");
|
||||
}
|
||||
console.log("Empty");
|
||||
|
||||
return v ?? "";
|
||||
};
|
||||
|
||||
const resetFunction = () => {
|
||||
if (format_id === "send") {
|
||||
setFunction(ui_configs.send_message_format_parts);
|
||||
} else if (format_id === "received") {
|
||||
setFunction(ui_configs.received_message_format_parts);
|
||||
}
|
||||
};
|
||||
|
||||
const SwapButton = ({ variable, setFunction }) => {
|
||||
const swapMessageAndTranslate = () => {
|
||||
setFunction({ ...variable, translation_first: !variable.translation_first });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.swap_button_wrapper} onClick={swapMessageAndTranslate}>
|
||||
<p className={styles.swap_text}>{variable.translation_first ? LABEL_TRANSLATED : LABEL_ORIGINAL}</p>
|
||||
<img className={styles.swap_img} src={SwapImg} alt="Swap Icon" />
|
||||
<p className={styles.swap_text}>{variable.translation_first ? LABEL_ORIGINAL : LABEL_TRANSLATED}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.message_format_settings_container}>
|
||||
<p className={styles.section_title}>{label_title}</p>
|
||||
<div className={styles.message_format_settings_wrapper}>
|
||||
<div className={styles.swap_button_container}>
|
||||
<SwapButton variable={variable} setFunction={setFunction} />
|
||||
</div>
|
||||
{ !variable.translation_first ?
|
||||
<div className={styles.input_wrapper}>
|
||||
<div className={styles.input_contents}>
|
||||
<_Entry ui_variable={toUiValue(variable.message.prefix)} width={ENTRY_WIDTH} onChange={handleChange("message", "prefix")} />
|
||||
<p className={styles.preset_text}>{LABEL_ORIGINAL}</p>
|
||||
<_Entry ui_variable={toUiValue(variable.message.suffix)} width={ENTRY_WIDTH} onChange={handleChange("message", "suffix")} />
|
||||
</div>
|
||||
<div className={styles.input_contents}>
|
||||
<_Entry ui_variable={toUiValue(variable.separator)} width={ENTRY_WIDTH} onChange={handleChange("separator")} />
|
||||
</div>
|
||||
<div className={styles.input_contents}>
|
||||
<_Entry ui_variable={toUiValue(variable.translation.prefix)} width={ENTRY_WIDTH} onChange={handleChange("translation", "prefix")} />
|
||||
<p className={styles.preset_text}>{LABEL_TRANSLATED}</p>
|
||||
<_Entry ui_variable={toUiValue(variable.translation.suffix)} width={ENTRY_WIDTH} onChange={handleChange("translation", "suffix")} />
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className={styles.input_wrapper}>
|
||||
<div className={styles.input_contents}>
|
||||
<_Entry ui_variable={toUiValue(variable.translation.prefix)} width={ENTRY_WIDTH} onChange={handleChange("translation", "prefix")} />
|
||||
<p className={styles.preset_text}>{LABEL_TRANSLATED}</p>
|
||||
<_Entry ui_variable={toUiValue(variable.translation.suffix)} width={ENTRY_WIDTH} onChange={handleChange("translation", "suffix")} />
|
||||
</div>
|
||||
<div className={styles.input_contents}>
|
||||
<_Entry ui_variable={toUiValue(variable.separator)} width={ENTRY_WIDTH} onChange={handleChange("separator")} />
|
||||
</div>
|
||||
<div className={styles.input_contents}>
|
||||
<_Entry ui_variable={toUiValue(variable.message.prefix)} width={ENTRY_WIDTH} onChange={handleChange("message", "prefix")} />
|
||||
<p className={styles.preset_text}>{LABEL_ORIGINAL}</p>
|
||||
<_Entry ui_variable={toUiValue(variable.message.suffix)} width={ENTRY_WIDTH} onChange={handleChange("message", "suffix")} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{ format_id === "send" &&
|
||||
<div className={styles.multi_translation_input_wrapper}>
|
||||
<p className={styles.multi_translation_title}>{LABEL_FOR_MULTI_TRANSLATION}</p>
|
||||
<div className={styles.input_contents}>
|
||||
<p className={styles.preset_text}>{LABEL_TRANSLATED}</p>
|
||||
<_Entry ui_variable={toUiValue(variable.translation.separator)} width={ENTRY_WIDTH} onChange={handleChange("translation", "separator")} />
|
||||
<p className={styles.preset_text}>{LABEL_TRANSLATED}</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div className={styles.reset_button_wrapper}>
|
||||
<ResetButton onClickFunction={resetFunction}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,200 @@
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
gap: 2.6rem;
|
||||
padding-bottom: 2rem;
|
||||
margin: 1rem 0;
|
||||
&.is_break_point {
|
||||
flex-direction: column;
|
||||
gap: 2.2rem;
|
||||
align-items: center;
|
||||
.border {
|
||||
height: 0.1rem;
|
||||
width: 60%;
|
||||
margin: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.show_more_container {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
.example_container {
|
||||
gap: 0;
|
||||
}
|
||||
.message_format_settings_container {
|
||||
gap: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.border {
|
||||
height: auto;
|
||||
width: 0.1rem;
|
||||
background-color: var(--dark_800_color);
|
||||
margin: 3.2rem 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.section_title {
|
||||
font-size: 1.4rem;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.example_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2rem;
|
||||
min-width: 14rem;
|
||||
max-width: 34rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.example_view_container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.2rem;
|
||||
}
|
||||
|
||||
.example_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.example_label {
|
||||
font-size: 1.4rem;
|
||||
text-align: start;
|
||||
width: 100%;
|
||||
color: var(--dark_basic_text_color);
|
||||
}
|
||||
.example_chatbox {
|
||||
padding: 0.6rem;
|
||||
background-color: #3A4554;
|
||||
border-radius: 1rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.example_text {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.show_more_container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.6rem 0;
|
||||
cursor: pointer;
|
||||
border-radius: 0.6rem;
|
||||
&:hover {
|
||||
background-color: var(--dark_850_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
}
|
||||
|
||||
.arrow_left_svg {
|
||||
width: 2rem;
|
||||
color: var(--dark_450_color);
|
||||
&.to_down {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
&.to_up {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.message_format_settings_container {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.message_format_settings_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3.8rem;
|
||||
width: 34rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.swap_button_container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.swap_button_wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.8rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 0.4rem;
|
||||
background-color: var(--dark_850_color);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_800_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color);
|
||||
}
|
||||
}
|
||||
|
||||
.swap_text {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.swap_img {
|
||||
width: 2rem;
|
||||
}
|
||||
|
||||
|
||||
.input_wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1.8rem;
|
||||
}
|
||||
|
||||
.input_contents {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
color: var(--dark_basic_text_color);
|
||||
}
|
||||
|
||||
.preset_text {
|
||||
font-size: 1.6rem;
|
||||
text-align: center;
|
||||
flex-shrink: 0;
|
||||
color: var(--dark_basic_text_color);
|
||||
}
|
||||
|
||||
.multi_translation_input_wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
color: var(--dark_basic_text_color);
|
||||
}
|
||||
|
||||
.multi_translation_title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.reset_button_wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
WordFilter,
|
||||
WordFilterListToggleComponent,
|
||||
DownloadModels,
|
||||
MessageFormat,
|
||||
} from "../_components/";
|
||||
import { Checkbox } from "@common_components";
|
||||
|
||||
@@ -130,3 +131,16 @@ export const WordFilterContainer = (props) => (
|
||||
export const DownloadModelsContainer = (props) => (
|
||||
<CommonContainer Component={DownloadModels} {...props} />
|
||||
);
|
||||
|
||||
export const MessageFormatContainer = (props) => {
|
||||
return (
|
||||
<div className={clsx(styles.container, styles.flex_column)}>
|
||||
<div className={styles.label_only_section}>
|
||||
<LabelComponent label={props.label} desc={props.desc} />
|
||||
</div>
|
||||
<div className={styles.message_format_section}>
|
||||
<MessageFormat {...props}/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
|
||||
import {
|
||||
CheckboxContainer,
|
||||
MessageFormatContainer,
|
||||
} from "../_templates/Templates";
|
||||
|
||||
import {
|
||||
@@ -39,6 +40,11 @@ export const Others = () => {
|
||||
<SectionLabelComponent label="Speaker2Chatbox" />
|
||||
<SendReceivedMessageToVrcContainer />
|
||||
</div>
|
||||
<div>
|
||||
<SectionLabelComponent label={t("config_page.others.section_label_message_formats")} />
|
||||
<SendMessageFormatPartsContainer />
|
||||
<ReceivedMessageFormatPartsContainer />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -152,3 +158,47 @@ const SendReceivedMessageToVrcContainer = () => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const SendMessageFormatPartsContainer = () => {
|
||||
const { t } = useI18n();
|
||||
const {
|
||||
currentSendMessageFormatParts,
|
||||
setSendMessageFormatParts,
|
||||
currentMessageFormat_ExampleViewFilter,
|
||||
toggleMessageFormat_ExampleViewFilter,
|
||||
} = useOthers();
|
||||
|
||||
return (
|
||||
<MessageFormatContainer
|
||||
label={t("config_page.others.send_message_format.label")}
|
||||
desc={t("config_page.others.send_message_format.desc")}
|
||||
variable={currentSendMessageFormatParts}
|
||||
setFunction={setSendMessageFormatParts}
|
||||
example_view_filter_variable={currentMessageFormat_ExampleViewFilter.data}
|
||||
exampleViewFilterToggleFunction={toggleMessageFormat_ExampleViewFilter}
|
||||
format_id="send"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ReceivedMessageFormatPartsContainer = () => {
|
||||
const { t } = useI18n();
|
||||
const {
|
||||
currentReceivedMessageFormatParts,
|
||||
setReceivedMessageFormatParts,
|
||||
currentMessageFormat_ExampleViewFilter,
|
||||
toggleMessageFormat_ExampleViewFilter,
|
||||
} = useOthers();
|
||||
|
||||
return (
|
||||
<MessageFormatContainer
|
||||
label={t("config_page.others.received_message_format.label")}
|
||||
desc={t("config_page.others.received_message_format.desc")}
|
||||
variable={currentReceivedMessageFormatParts}
|
||||
setFunction={setReceivedMessageFormatParts}
|
||||
example_view_filter_variable={currentMessageFormat_ExampleViewFilter.data}
|
||||
exampleViewFilterToggleFunction={toggleMessageFormat_ExampleViewFilter}
|
||||
format_id="received"
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -14,12 +14,12 @@ import {
|
||||
SectionLabelComponent,
|
||||
} from "../_components/";
|
||||
|
||||
import { ResetButton } from "@common_components";
|
||||
|
||||
import {
|
||||
useVr,
|
||||
} from "@logics_configs";
|
||||
|
||||
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";
|
||||
@@ -528,13 +528,6 @@ const CommonSettingsContainer = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const ResetButton = ({onClickFunction}) => {
|
||||
return (
|
||||
<button className={styles.slider_reset_button} onClick={onClickFunction}>
|
||||
<RedoSvg className={styles.slider_reset_svg}/>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
const SendSampleTextToggleButton = () => {
|
||||
const { t } = useI18n();
|
||||
|
||||
@@ -301,34 +301,6 @@
|
||||
@include variable-button-wrapper(bottom, 50%, right, -60%, -45deg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.slider_reset_button {
|
||||
background-color: var(--dark_875_color);
|
||||
padding: 0.6rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0.4rem;
|
||||
flex-shrink: 0;
|
||||
&:hover {
|
||||
background-color: var(--dark_825_color);
|
||||
& .slider_reset_svg {
|
||||
color: var(--dark_200_color);
|
||||
}
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_925_color);
|
||||
}
|
||||
}
|
||||
|
||||
.slider_reset_svg {
|
||||
width: 1.4rem;
|
||||
color: var(--dark_550_color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.other_controls {
|
||||
margin-top: 6rem;
|
||||
display: flex;
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export { Checkbox } from "./checkbox/Checkbox";
|
||||
export { HomepageLinkButton } from "./homepage_link_button/HomepageLinkButton";
|
||||
export { ResetButton } from "./reset_button/ResetButton";
|
||||
10
src-ui/common_components/reset_button/ResetButton.jsx
Normal file
10
src-ui/common_components/reset_button/ResetButton.jsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import styles from "./ResetButton.module.scss";
|
||||
import RedoSvg from "@images/redo.svg?react";
|
||||
|
||||
export const ResetButton = ({ onClickFunction }) => {
|
||||
return (
|
||||
<button className={styles.reset_button} onClick={onClickFunction}>
|
||||
<RedoSvg className={styles.reset_svg}/>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
.reset_button {
|
||||
width: fit-content;
|
||||
background-color: var(--dark_875_color);
|
||||
padding: 0.6rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0.4rem;
|
||||
flex-shrink: 0;
|
||||
&:hover {
|
||||
background-color: var(--dark_825_color);
|
||||
& .reset_svg {
|
||||
color: var(--dark_200_color);
|
||||
}
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_925_color);
|
||||
}
|
||||
}
|
||||
|
||||
.reset_svg {
|
||||
width: 1.4rem;
|
||||
color: var(--dark_550_color);
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import {
|
||||
useStore_EnableSendMessageToVrc,
|
||||
useStore_EnableNotificationVrcSfx,
|
||||
useStore_EnableSendReceivedMessageToVrc,
|
||||
useStore_MessageFormat_ExampleViewFilter,
|
||||
useStore_SendMessageFormatParts,
|
||||
useStore_ReceivedMessageFormatParts,
|
||||
} from "@store";
|
||||
import { useStdoutToPython } from "@useStdoutToPython";
|
||||
import { useNotificationStatus } from "@logics_common";
|
||||
@@ -29,6 +32,12 @@ export const useOthers = () => {
|
||||
// Speaker2Chatbox
|
||||
// Send Received Message To VRC
|
||||
const { currentEnableSendReceivedMessageToVrc, updateEnableSendReceivedMessageToVrc, pendingEnableSendReceivedMessageToVrc } = useStore_EnableSendReceivedMessageToVrc();
|
||||
// Message Formats
|
||||
const { currentMessageFormat_ExampleViewFilter, updateMessageFormat_ExampleViewFilter, pendingMessageFormat_ExampleViewFilter } = useStore_MessageFormat_ExampleViewFilter();
|
||||
// Send
|
||||
const { currentSendMessageFormatParts, updateSendMessageFormatParts, pendingSendMessageFormatParts } = useStore_SendMessageFormatParts();
|
||||
// Received
|
||||
const { currentReceivedMessageFormatParts, updateReceivedMessageFormatParts, pendingReceivedMessageFormatParts } = useStore_ReceivedMessageFormatParts();
|
||||
|
||||
const { showNotification_SaveSuccess } = useNotificationStatus();
|
||||
|
||||
@@ -178,6 +187,53 @@ export const useOthers = () => {
|
||||
showNotification_SaveSuccess();
|
||||
};
|
||||
|
||||
// Message Formats
|
||||
// Send
|
||||
const getSendMessageFormatParts = () => {
|
||||
pendingSendMessageFormatParts();
|
||||
asyncStdoutToPython("/get/data/send_message_format_parts");
|
||||
};
|
||||
|
||||
const setSendMessageFormatParts = (message_format_parts) => {
|
||||
pendingSendMessageFormatParts();
|
||||
asyncStdoutToPython("/set/data/send_message_format_parts", message_format_parts);
|
||||
};
|
||||
|
||||
const setSuccessSendMessageFormatParts = (message_format_parts) => {
|
||||
updateSendMessageFormatParts(message_format_parts);
|
||||
showNotification_SaveSuccess();
|
||||
};
|
||||
|
||||
// Received
|
||||
const getReceivedMessageFormatParts = () => {
|
||||
pendingReceivedMessageFormatParts();
|
||||
asyncStdoutToPython("/get/data/received_message_format_parts");
|
||||
};
|
||||
|
||||
const setReceivedMessageFormatParts = (message_format_parts) => {
|
||||
pendingReceivedMessageFormatParts();
|
||||
asyncStdoutToPython("/set/data/received_message_format_parts", message_format_parts);
|
||||
};
|
||||
|
||||
const setSuccessReceivedMessageFormatParts = (message_format_parts) => {
|
||||
updateReceivedMessageFormatParts(message_format_parts);
|
||||
showNotification_SaveSuccess();
|
||||
};
|
||||
|
||||
|
||||
const toggleMessageFormat_ExampleViewFilter = (id) => {
|
||||
pendingMessageFormat_ExampleViewFilter();
|
||||
if (["send", "received"].includes(id) === false) return console.error(`id should be small case 'send' or 'received'. got id: ${id}`);
|
||||
|
||||
updateMessageFormat_ExampleViewFilter({
|
||||
...currentMessageFormat_ExampleViewFilter.data,
|
||||
[id]: currentMessageFormat_ExampleViewFilter.data[id] === "Simplified"
|
||||
? "All"
|
||||
: "Simplified"
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
// Auto Clear Message Input Box
|
||||
currentEnableAutoClearMessageInputBox,
|
||||
@@ -230,5 +286,22 @@ export const useOthers = () => {
|
||||
toggleEnableSendReceivedMessageToVrc,
|
||||
updateEnableSendReceivedMessageToVrc,
|
||||
setSuccessEnableSendReceivedMessageToVrc,
|
||||
|
||||
// Message Formats
|
||||
currentMessageFormat_ExampleViewFilter,
|
||||
toggleMessageFormat_ExampleViewFilter,
|
||||
// Send
|
||||
currentSendMessageFormatParts,
|
||||
updateSendMessageFormatParts,
|
||||
getSendMessageFormatParts,
|
||||
setSendMessageFormatParts,
|
||||
setSuccessSendMessageFormatParts,
|
||||
|
||||
// Received
|
||||
currentReceivedMessageFormatParts,
|
||||
updateReceivedMessageFormatParts,
|
||||
getReceivedMessageFormatParts,
|
||||
setReceivedMessageFormatParts,
|
||||
setSuccessReceivedMessageFormatParts,
|
||||
};
|
||||
};
|
||||
@@ -275,6 +275,12 @@ export const ROUTE_META_LIST = [
|
||||
{ endpoint: "/get/data/notification_vrc_sfx", ns: configs, hook_name: "useOthers", method_name: "updateEnableNotificationVrcSfx" },
|
||||
{ endpoint: "/set/enable/notification_vrc_sfx", ns: configs, hook_name: "useOthers", method_name: "setSuccessEnableNotificationVrcSfx" },
|
||||
{ endpoint: "/set/disable/notification_vrc_sfx", ns: configs, hook_name: "useOthers", method_name: "setSuccessEnableNotificationVrcSfx" },
|
||||
{ endpoint: "/set/disable/notification_vrc_sfx", ns: configs, hook_name: "useOthers", method_name: "setSuccessEnableNotificationVrcSfx" },
|
||||
|
||||
{ endpoint: "/get/data/send_message_format_parts", ns: configs, hook_name: "useOthers", method_name: "updateSendMessageFormatParts" },
|
||||
{ endpoint: "/set/data/send_message_format_parts", ns: configs, hook_name: "useOthers", method_name: "setSuccessSendMessageFormatParts" },
|
||||
{ endpoint: "/get/data/received_message_format_parts", ns: configs, hook_name: "useOthers", method_name: "updateReceivedMessageFormatParts" },
|
||||
{ endpoint: "/set/data/received_message_format_parts", ns: configs, hook_name: "useOthers", method_name: "setSuccessReceivedMessageFormatParts" },
|
||||
|
||||
// Hotkeys
|
||||
{ endpoint: "/get/data/hotkeys", ns: configs, hook_name: "useHotkeys", method_name: "updateHotkeys" },
|
||||
|
||||
@@ -274,6 +274,37 @@ export const { atomInstance: Atom_EnableVrcMicMuteSync, useHook: useStore_Enable
|
||||
export const { atomInstance: Atom_EnableSendMessageToVrc, useHook: useStore_EnableSendMessageToVrc } = createAtomWithHook(true, "EnableSendMessageToVrc");
|
||||
export const { atomInstance: Atom_EnableSendReceivedMessageToVrc, useHook: useStore_EnableSendReceivedMessageToVrc } = createAtomWithHook(false, "EnableSendReceivedMessageToVrc");
|
||||
export const { atomInstance: Atom_EnableNotificationVrcSfx, useHook: useStore_EnableNotificationVrcSfx } = createAtomWithHook(true, "EnableNotificationVrcSfx");
|
||||
export const { atomInstance: Atom_MessageFormat_ExampleViewFilter, useHook: useStore_MessageFormat_ExampleViewFilter } = createAtomWithHook({
|
||||
send: "Simplified",
|
||||
received: "Simplified",
|
||||
}, "MessageFormat_ExampleViewFilter");
|
||||
export const { atomInstance: Atom_SendMessageFormatParts, useHook: useStore_SendMessageFormatParts } = createAtomWithHook({
|
||||
message: {
|
||||
prefix: "",
|
||||
suffix: ""
|
||||
},
|
||||
separator: "\n",
|
||||
translation: {
|
||||
prefix: "",
|
||||
separator: "\n",
|
||||
suffix: ""
|
||||
},
|
||||
translation_first: false,
|
||||
}, "SendMessageFormatParts");
|
||||
export const { atomInstance: Atom_ReceivedMessageFormatParts, useHook: useStore_ReceivedMessageFormatParts } = createAtomWithHook({
|
||||
message: {
|
||||
prefix: "",
|
||||
suffix: ""
|
||||
},
|
||||
separator: "\n",
|
||||
translation: {
|
||||
prefix: "",
|
||||
separator: "\n",
|
||||
suffix: ""
|
||||
},
|
||||
translation_first: false,
|
||||
}, "ReceivedMessageFormatParts");
|
||||
|
||||
|
||||
// Hotkeys
|
||||
export const { atomInstance: Atom_Hotkeys, useHook: useStore_Hotkeys } = createAtomWithHook({
|
||||
|
||||
@@ -49,6 +49,33 @@ export const ui_configs = {
|
||||
tracker: "LeftHand",
|
||||
},
|
||||
|
||||
send_message_format_parts: {
|
||||
message: {
|
||||
prefix: "",
|
||||
suffix: ""
|
||||
},
|
||||
separator: "\n",
|
||||
translation: {
|
||||
prefix: "",
|
||||
separator: "\n",
|
||||
suffix: ""
|
||||
},
|
||||
translation_first: false,
|
||||
},
|
||||
received_message_format_parts: {
|
||||
message: {
|
||||
prefix: "",
|
||||
suffix: ""
|
||||
},
|
||||
separator: "\n",
|
||||
translation: {
|
||||
prefix: "",
|
||||
separator: "\n",
|
||||
suffix: ""
|
||||
},
|
||||
translation_first: false,
|
||||
},
|
||||
|
||||
selectable_ui_languages: [
|
||||
{id: "en", label: "English"},
|
||||
{id: "ja", label: "日本語"},
|
||||
|
||||
Reference in New Issue
Block a user