[Refactor] Move to src-ui/views and src-ui/logics structure.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import clsx from "clsx";
|
||||
|
||||
import styles from "./SidebarSection.module.scss";
|
||||
import { useStore_IsOpenedLanguageSelector } from "@store";
|
||||
import { useIsMainPageCompactMode } from "@logics_main";
|
||||
|
||||
import { Logo } from "./logo/Logo";
|
||||
import { MainFunctionSwitch } from "./main_function_switch/MainFunctionSwitch";
|
||||
import { LanguageSettings } from "./language_settings/LanguageSettings";
|
||||
import { OpenSettings } from "./open_settings/OpenSettings";
|
||||
|
||||
export const SidebarSection = () => {
|
||||
const { currentIsMainPageCompactMode } = useIsMainPageCompactMode();
|
||||
const container_class_name = clsx(styles.container, {
|
||||
[styles.is_compact_mode]: currentIsMainPageCompactMode.data
|
||||
});
|
||||
|
||||
const { currentIsOpenedLanguageSelector } = useStore_IsOpenedLanguageSelector();
|
||||
const scroll_container_class_names = clsx(styles.scroll_container, {
|
||||
[styles.is_opened]: (currentIsOpenedLanguageSelector.data.your_language === true || currentIsOpenedLanguageSelector.data.target_language === true)
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={container_class_name}>
|
||||
<Logo />
|
||||
<div className={scroll_container_class_names}>
|
||||
<MainFunctionSwitch />
|
||||
{!currentIsMainPageCompactMode.data && <LanguageSettings />}
|
||||
</div>
|
||||
<OpenSettings />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
.container {
|
||||
position: relative;
|
||||
min-width: 23rem;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--dark_850_color);
|
||||
&.is_compact_mode {
|
||||
min-width: auto;
|
||||
.scroll_container {
|
||||
// overflow-y: hidden;
|
||||
// width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll_container {
|
||||
width: calc(100% + 0.8rem);
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
margin-bottom: calc(2rem + 1.6rem + 2rem); // config button's sizes (svg + padding + margin).
|
||||
pointer-events: auto;
|
||||
z-index: 1;
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.8rem;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: var(--dark_888_color);
|
||||
border-radius: 0.4rem;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--dark_888_color);
|
||||
border-radius: 0.4rem;
|
||||
}
|
||||
|
||||
&.is_opened {
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--dark_800_color);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { useI18n } from "@useI18n";
|
||||
import styles from "./LanguageSettings.module.scss";
|
||||
import { PresetTabSelector } from "./preset_tab_selector/PresetTabSelector";
|
||||
import { LanguageSelectorOpenButton } from "./language_selector_open_button/LanguageSelectorOpenButton";
|
||||
import { LanguageSwapButton } from "./language_swap_button/LanguageSwapButton";
|
||||
import { TranslatorSelectorOpenButton } from "./translator_selector_open_button/TranslatorSelectorOpenButton";
|
||||
import { AddRemoveTargetLanguageButtons } from "./add_remove_target_language_buttons/AddRemoveTargetLanguageButtons";
|
||||
import { useStore_IsOpenedTranslatorSelector } from "@store";
|
||||
|
||||
export const LanguageSettings = () => {
|
||||
const { t } = useI18n();
|
||||
const { updateIsOpenedTranslatorSelector } = useStore_IsOpenedTranslatorSelector();
|
||||
const closeTranslatorSelector = () => updateIsOpenedTranslatorSelector(false);
|
||||
|
||||
return (
|
||||
<div className={styles.container} onMouseLeave={closeTranslatorSelector}>
|
||||
<p className={styles.title}>{t("main_page.language_settings")}</p>
|
||||
<PresetTabSelector />
|
||||
<PresetContainer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import MicSvg from "@images/mic.svg?react";
|
||||
import HeadphonesSvg from "@images/headphones.svg?react";
|
||||
import { useMainFunction } from "@logics_main";
|
||||
|
||||
const PresetContainer = () => {
|
||||
const { t } = useI18n();
|
||||
const { currentTranscriptionSendStatus, currentTranscriptionReceiveStatus } = useMainFunction();
|
||||
|
||||
const yourLanguageSettings = {
|
||||
TurnedOnSvgComponent: MicSvg,
|
||||
is_turned_on: currentTranscriptionSendStatus.data,
|
||||
};
|
||||
|
||||
const targetLanguageSettings = {
|
||||
TurnedOnSvgComponent: HeadphonesSvg,
|
||||
is_turned_on: currentTranscriptionReceiveStatus.data,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.preset_container}>
|
||||
<LanguageSelectorOpenButton {...yourLanguageSettings} selector_key="your_language" target_key="1"/>
|
||||
<LanguageSwapButton />
|
||||
<div className={styles.target_language_containers}>
|
||||
<LanguageSelectorOpenButton {...targetLanguageSettings} selector_key="target_language" target_key="1" />
|
||||
<LanguageSelectorOpenButton {...targetLanguageSettings} selector_key="target_language" target_key="2" />
|
||||
<LanguageSelectorOpenButton {...targetLanguageSettings} selector_key="target_language" target_key="3" />
|
||||
</div>
|
||||
<AddRemoveTargetLanguageButtons />
|
||||
<TranslatorSelectorOpenButton />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.4rem;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 0.8rem;
|
||||
color: var(--dark_400_color);
|
||||
}
|
||||
|
||||
.preset_container {
|
||||
width: 100%;
|
||||
padding-top: 0.8rem;
|
||||
background-color: var(--dark_800_color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.target_language_containers {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import clsx from "clsx";
|
||||
import styles from "./AddRemoveTargetLanguageButtons.module.scss";
|
||||
import RemoveSvg from "@images/remove.svg?react";
|
||||
import AddSvg from "@images/add.svg?react";
|
||||
|
||||
import { useLanguageSettings } from "@logics_main";
|
||||
|
||||
export const AddRemoveTargetLanguageButtons = () => {
|
||||
const {
|
||||
currentSelectedPresetTabNumber,
|
||||
// currentSelectedYourLanguages,
|
||||
currentSelectedTargetLanguages,
|
||||
removeTargetLanguage,
|
||||
addTargetLanguage,
|
||||
} = useLanguageSettings();
|
||||
|
||||
const remove_button_class = clsx(styles.remove_target_language_button, {
|
||||
[styles.is_disabled]: !currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]["2"].enable,
|
||||
});
|
||||
const add_button_class = clsx(styles.add_target_language_button, {
|
||||
[styles.is_disabled]: currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]["3"].enable,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.add_remove_target_language_container}>
|
||||
<div className={remove_button_class} onClick={removeTargetLanguage}>
|
||||
<RemoveSvg className={styles.remove_svg} />
|
||||
</div>
|
||||
<div className={add_button_class} onClick={addTargetLanguage}>
|
||||
<AddSvg className={styles.add_svg} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
.add_remove_target_language_container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.remove_target_language_button, .add_target_language_button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.6rem 1rem;
|
||||
cursor: pointer;
|
||||
background-color: var(--dark_825_color);
|
||||
&:hover {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color);
|
||||
}
|
||||
&.is_disabled {
|
||||
pointer-events: none;
|
||||
.remove_svg, .add_svg {
|
||||
color: var(--dark_700_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remove_target_language_button {
|
||||
border-radius: 0 0 0 0.4rem;
|
||||
|
||||
}
|
||||
.add_target_language_button {
|
||||
border-radius: 0 0 0.4rem 0;
|
||||
}
|
||||
|
||||
.remove_svg, .add_svg {
|
||||
width: 0.8rem;
|
||||
color: var(--dark_200_color);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useI18n } from "@useI18n";
|
||||
import clsx from "clsx";
|
||||
import styles from "./LanguageSelectorOpenButton.module.scss";
|
||||
import ArrowLeftSvg from "@images/arrow_left.svg?react";
|
||||
import { useStore_IsOpenedLanguageSelector } from "@store";
|
||||
import {
|
||||
useLanguageSettings,
|
||||
} from "@logics_main";
|
||||
|
||||
export const LanguageSelectorOpenButton = ({ TurnedOnSvgComponent, is_turned_on, selector_key, target_key }) => {
|
||||
const { t } = useI18n();
|
||||
const { updateIsOpenedLanguageSelector, currentIsOpenedLanguageSelector } = useStore_IsOpenedLanguageSelector();
|
||||
|
||||
const {
|
||||
currentSelectedPresetTabNumber,
|
||||
currentSelectedYourLanguages,
|
||||
currentSelectedTargetLanguages,
|
||||
} = useLanguageSettings();
|
||||
|
||||
const toggleSelector = () => {
|
||||
if (currentIsOpenedLanguageSelector.data[selector_key] === true && currentIsOpenedLanguageSelector.data.target_key === target_key) { // Close Language Selector
|
||||
updateIsOpenedLanguageSelector({ your_language: false, target_language: false, target_key: "1" });
|
||||
} else { // Open Language Selector
|
||||
updateIsOpenedLanguageSelector({
|
||||
your_language: selector_key === "your_language",
|
||||
target_language: selector_key === "target_language",
|
||||
target_key: target_key,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const arrow_class_names = clsx(styles.arrow_left_svg, {
|
||||
[styles.reverse]: (currentIsOpenedLanguageSelector.data[selector_key] === true && currentIsOpenedLanguageSelector.data.target_key === target_key),
|
||||
});
|
||||
|
||||
const category_class_names = clsx(styles.category_svg, {
|
||||
[styles.is_turned_on]: is_turned_on,
|
||||
});
|
||||
|
||||
const getVariable = (target_selector_key) => {
|
||||
if (target_selector_key === "your_language") return currentSelectedYourLanguages.data[currentSelectedPresetTabNumber.data];
|
||||
if (target_selector_key === "target_language") return currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data];
|
||||
};
|
||||
|
||||
const getTitle = (target_selector_key) => {
|
||||
if (target_selector_key === "your_language") return t("main_page.your_language");
|
||||
if (target_selector_key === "target_language") {
|
||||
if (currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data]["2"].enable === false) return t("main_page.target_language");
|
||||
return `${t("main_page.target_language")} ${target_key}`;
|
||||
}
|
||||
};
|
||||
|
||||
const title = getTitle(selector_key);
|
||||
|
||||
if (getVariable(selector_key)[target_key].enable === false) return null;
|
||||
|
||||
const language_text = getVariable(selector_key)[target_key].language ?? "Loading...";
|
||||
const country_text = getVariable(selector_key)[target_key].country ?? "Loading...";
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.title_container}>
|
||||
<TurnedOnSvgComponent className={category_class_names} />
|
||||
<p className={styles.title}>{title}</p>
|
||||
</div>
|
||||
<div className={styles.dropdown_menu_container} onClick={toggleSelector}>
|
||||
<p className={styles.selected_language}>{language_text}</p>
|
||||
<p className={styles.selected_language}>({country_text})</p>
|
||||
<ArrowLeftSvg className={arrow_class_names} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
background-color: var(--dark_825_color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0.8rem;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
.title_container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.category_svg {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 1.2rem;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 1.4rem;
|
||||
color: var(--dark_400_color);
|
||||
display: none;
|
||||
&.is_turned_on {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 1.6rem;
|
||||
color: var(--dark_400_color);
|
||||
}
|
||||
|
||||
.dropdown_menu_container {
|
||||
position: relative;
|
||||
background-color: var(--dark_888_color);
|
||||
width: 100%;
|
||||
padding: 0.4rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0.4rem;
|
||||
gap: 0.2rem;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color);
|
||||
}
|
||||
}
|
||||
|
||||
.selected_language {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.arrow_left_svg {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin: 0 0.2rem;
|
||||
transform: rotate(180deg);
|
||||
width: 1.6rem;
|
||||
&.reverse {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { useI18n } from "@useI18n";
|
||||
|
||||
import styles from "./LanguageSwapButton.module.scss";
|
||||
|
||||
import NarrowArrowDownSvg from "@images/narrow_arrow_down.svg?react";
|
||||
import { useLanguageSettings } from "@logics_main";
|
||||
|
||||
export const LanguageSwapButton = () => {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const { t } = useI18n();
|
||||
const { swapSelectedLanguages } = useLanguageSettings();
|
||||
|
||||
const label = isHovered
|
||||
? t("main_page.swap_button_label")
|
||||
: t("main_page.translate_each_other_label");
|
||||
|
||||
const labelClassName = clsx(styles["label"], {
|
||||
[styles["is_hovered"]]: isHovered
|
||||
});
|
||||
|
||||
const handleMouseEnter = () => setIsHovered(true);
|
||||
const handleMouseLeave = () => setIsHovered(false);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div
|
||||
className={styles.swap_button_wrapper}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={swapSelectedLanguages}
|
||||
>
|
||||
<NarrowArrowDownSvg className={clsx(styles.narrow_arrow_down_svg, styles.reverse)} />
|
||||
<p className={labelClassName}>{label}</p>
|
||||
<NarrowArrowDownSvg className={styles.narrow_arrow_down_svg} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.swap_button_wrapper {
|
||||
width: auto;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0.8rem 2rem;
|
||||
padding: 0.4rem 0.8rem;
|
||||
border-radius: 0.6rem;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_750_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_850_color);
|
||||
}
|
||||
}
|
||||
|
||||
.narrow_arrow_down_svg {
|
||||
width: 1.6rem;
|
||||
color: var(--dark_500_color);
|
||||
&.reverse {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 1.2rem;
|
||||
color: var(--dark_500_color);
|
||||
&.is_hovered {
|
||||
color: var(--dark_200_color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import styles from "./PresetTabSelector.module.scss";
|
||||
|
||||
export const PresetTabSelector = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Tab preset_number={"1"} />
|
||||
<Tab preset_number={"2"} />
|
||||
<Tab preset_number={"3"} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import clsx from "clsx";
|
||||
|
||||
import { useLanguageSettings } from "@logics_main";
|
||||
|
||||
const Tab = (props) => {
|
||||
const { currentSelectedPresetTabNumber, setSelectedPresetTabNumber } = useLanguageSettings();
|
||||
const onclickFunction = () => {
|
||||
setSelectedPresetTabNumber(props.preset_number);
|
||||
};
|
||||
|
||||
const class_names = clsx(styles.tab_container, {
|
||||
[styles.is_selected]: (currentSelectedPresetTabNumber.data === props.preset_number) ? true : false
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={class_names} onClick={onclickFunction}>
|
||||
<p className={styles.tab_number}>{props.preset_number}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tab_container {
|
||||
height: 3rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0.6rem 0.6rem 0 0;
|
||||
color: var(--dark_600_color);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_825_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
&.is_selected {
|
||||
background-color: var(--dark_800_color);
|
||||
color: var(--dark_200_color);
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.tab_number {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import { useI18n } from "@useI18n";
|
||||
import { updateLabelsById } from "@utils";
|
||||
import styles from "./TranslatorSelectorOpenButton.module.scss";
|
||||
import { TranslatorSelector } from "./translator_selector/TranslatorSelector";
|
||||
import { useStore_IsOpenedTranslatorSelector } from "@store";
|
||||
import { useLanguageSettings } from "@logics_main";
|
||||
import WarningSvg from "@images/warning.svg?react";
|
||||
|
||||
export const TranslatorSelectorOpenButton = () => {
|
||||
const { t } = useI18n();
|
||||
const {
|
||||
currentSelectedYourLanguages,
|
||||
currentSelectedTargetLanguages,
|
||||
currentSelectedPresetTabNumber,
|
||||
currentTranslationEngines,
|
||||
currentSelectedTranslationEngines,
|
||||
} = useLanguageSettings();
|
||||
|
||||
// const new_labels = [
|
||||
// {id: "CTranslate2", label: "AI\nCTranslate2"}
|
||||
// ];
|
||||
|
||||
const translation_engines = currentTranslationEngines.data;
|
||||
// const translation_engines = updateLabelsById(currentTranslationEngines.data, new_labels);
|
||||
|
||||
const selected_engine_id = currentSelectedTranslationEngines.data[currentSelectedPresetTabNumber.data];
|
||||
|
||||
const checkIsSelectedSameLanguage = () => {
|
||||
const your_language_data = currentSelectedYourLanguages.data[currentSelectedPresetTabNumber.data];
|
||||
const target_language_data = currentSelectedTargetLanguages.data[currentSelectedPresetTabNumber.data];
|
||||
|
||||
const yourLanguage = your_language_data["1"];
|
||||
const yourLanguageName = yourLanguage.language;
|
||||
const yourCountry = yourLanguage.country;
|
||||
|
||||
let is_selected_same_language = false;
|
||||
|
||||
for (const key in target_language_data) {
|
||||
const targetLanguage = target_language_data[key];
|
||||
|
||||
if (targetLanguage.enable) {
|
||||
const targetLanguageName = targetLanguage.language;
|
||||
const targetCountry = targetLanguage.country;
|
||||
|
||||
if (yourLanguageName === targetLanguageName && yourCountry === targetCountry) {
|
||||
is_selected_same_language = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return is_selected_same_language;
|
||||
};
|
||||
|
||||
const is_selected_same_language = checkIsSelectedSameLanguage();
|
||||
|
||||
const getSelectedLabel = () => {
|
||||
|
||||
const selected_engine = translation_engines.find(
|
||||
d => d.id === selected_engine_id
|
||||
);
|
||||
return selected_engine?.label;
|
||||
};
|
||||
|
||||
const is_loading = currentTranslationEngines.state === "pending";
|
||||
const selected_label = is_loading ? "Loading..." : getSelectedLabel();
|
||||
|
||||
|
||||
const { currentIsOpenedTranslatorSelector, updateIsOpenedTranslatorSelector} = useStore_IsOpenedTranslatorSelector();
|
||||
|
||||
const openTranslatorSelector = () => {
|
||||
updateIsOpenedTranslatorSelector(!currentIsOpenedTranslatorSelector.data);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.translator_selector_button} onClick={openTranslatorSelector}>
|
||||
<p className={styles.label}>{t("main_page.translator")}:</p>
|
||||
<p className={styles.label}>{selected_label}</p>
|
||||
{is_selected_same_language
|
||||
? <WarningSvg className={styles.warning_svg}/>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
{currentIsOpenedTranslatorSelector.data &&
|
||||
<TranslatorSelector
|
||||
selected_id={selected_engine_id}
|
||||
translation_engines={translation_engines}
|
||||
is_selected_same_language={is_selected_same_language}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.translator_selector_button {
|
||||
position: relative;
|
||||
width: auto;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
margin: 0.4rem;
|
||||
padding: 0.6rem 0;
|
||||
border-radius: 0.6rem;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color);
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 1.2rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.warning_svg {
|
||||
margin-left: 0.2rem;
|
||||
padding-bottom: 0.2rem;
|
||||
width: 1.8rem;
|
||||
color: var(--warning_color);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import clsx from "clsx";
|
||||
import styles from "./TranslatorSelector.module.scss";
|
||||
import { useI18n } from "@useI18n";
|
||||
|
||||
import { chunkArray } from "@utils";
|
||||
import { useStore_IsOpenedTranslatorSelector } from "@store";
|
||||
import { useLanguageSettings } from "@logics_main";
|
||||
|
||||
export const TranslatorSelector = ({selected_id, translation_engines, is_selected_same_language}) => {
|
||||
const { t } = useI18n();
|
||||
const columns = chunkArray(translation_engines, 2);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.relative_container}>
|
||||
<div className={styles.wrapper}>
|
||||
{columns.map((column, column_index) => (
|
||||
<div className={styles.column_wrapper} key={`column_${column_index}`}>
|
||||
{column.map(({ id, label, is_available, is_default }) => (
|
||||
<TranslatorBox
|
||||
key={id}
|
||||
id={id}
|
||||
label={label}
|
||||
is_available={is_available}
|
||||
is_default={is_default}
|
||||
is_selected={(id === selected_id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{is_selected_same_language ?
|
||||
<div className={styles.is_selected_same_language_wrapper}>
|
||||
<p className={styles.is_selected_same_language_text}>
|
||||
{t("main_page.translator_selector.is_selected_same_language", {
|
||||
your_language: t("main_page.your_language"),
|
||||
target_language: t("main_page.target_language"),
|
||||
ctranslate2: "CTranslate2",
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const TranslatorBox = (props) => {
|
||||
const { t } = useI18n();
|
||||
const { setSelectedTranslationEngines} = useLanguageSettings();
|
||||
const { updateIsOpenedTranslatorSelector} = useStore_IsOpenedTranslatorSelector();
|
||||
|
||||
const box_class_name = clsx(
|
||||
styles.box,
|
||||
{ [styles.is_selected]: props.is_selected },
|
||||
{ [styles.is_available]: props.is_available }
|
||||
);
|
||||
const label_default_class_name = clsx(
|
||||
styles.label_default,
|
||||
{ [styles.is_selected]: props.is_selected },
|
||||
);
|
||||
|
||||
const selectTranslator = () => {
|
||||
if (props.is_selected === false) {
|
||||
setSelectedTranslationEngines(props.id);
|
||||
}
|
||||
updateIsOpenedTranslatorSelector(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={box_class_name} onClick={selectTranslator}>
|
||||
<p className={styles.translator_name}>{props.label}</p>
|
||||
{props.is_default && <p className={label_default_class_name}>{t("main_page.translator_label_default")}</p>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
.container {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
width: 100%;
|
||||
height: 26rem;
|
||||
background-color: var(--dark_1000_color_dd);
|
||||
backdrop-filter: blur(0.1rem);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.relative_container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1.4rem;
|
||||
}
|
||||
|
||||
.column_wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1.2rem;
|
||||
}
|
||||
|
||||
$box_size: 6.2rem;
|
||||
.box {
|
||||
position: relative;
|
||||
width: 9.4rem;
|
||||
height: $box_size;
|
||||
background-color: var(--dark_875_color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
white-space: pre-wrap;
|
||||
text-align: center;
|
||||
border-radius: 0.2rem;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_825_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color);
|
||||
outline: 0.1rem solid var(--primary_300_color);
|
||||
}
|
||||
&.is_selected {
|
||||
outline: 0.2rem solid var(--primary_300_color);
|
||||
}
|
||||
&:not(.is_available) {
|
||||
pointer-events: none;
|
||||
background-color: var(--dark_950_color);
|
||||
& .translator_name {
|
||||
color: var(--dark_600_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.translator_name {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.label_default {
|
||||
background-color: var(--dark_875_color);
|
||||
outline: 0.1rem solid var(--dark_1000_color);
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 1.2rem;
|
||||
position: absolute;
|
||||
top: -0.8rem;
|
||||
right: -0.8rem;
|
||||
pointer-events: none;
|
||||
&.is_selected {
|
||||
outline: 0.1rem solid var(--primary_300_color);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.is_selected_same_language_wrapper {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--dark_1000_color_66);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: start;
|
||||
pointer-events: none;
|
||||
padding: 4rem 1rem;
|
||||
}
|
||||
|
||||
.is_selected_same_language_text {
|
||||
font-size: 1.4rem;
|
||||
text-align: center;
|
||||
text-wrap: balance;
|
||||
}
|
||||
23
src-ui/views/app/main_page/sidebar_section/logo/Logo.jsx
Normal file
23
src-ui/views/app/main_page/sidebar_section/logo/Logo.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import styles from "./Logo.module.scss";
|
||||
|
||||
export const Logo = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<LogoBox />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
import vrct_logo from "@images/vrct_logo_for_dark_mode.png";
|
||||
import chato_img from "@images/chato_white.png";
|
||||
import { useIsMainPageCompactMode } from "@logics_main";
|
||||
|
||||
export const LogoBox = () => {
|
||||
const { currentIsMainPageCompactMode } = useIsMainPageCompactMode();
|
||||
if (currentIsMainPageCompactMode.data === true) {
|
||||
return <img src={chato_img} className={styles.logo_chato} alt="VRCT logo chato" />;
|
||||
} else {
|
||||
return <img src={vrct_logo} className={styles.logo} alt="VRCT logo" />;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
.container {
|
||||
height: var(--main_page_topbar_height);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 12rem;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.logo_chato {
|
||||
width: 2rem;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { useI18n } from "@useI18n";
|
||||
import clsx from "clsx";
|
||||
import styles from "./MainFunctionSwitch.module.scss";
|
||||
import TranslationSvg from "@images/translation.svg?react";
|
||||
import MicSvg from "@images/mic.svg?react";
|
||||
import HeadphonesSvg from "@images/headphones.svg?react";
|
||||
import ForegroundSvg from "@images/foreground.svg?react";
|
||||
import {
|
||||
useIsMainPageCompactMode,
|
||||
useMainFunction,
|
||||
} from "@logics_main";
|
||||
|
||||
export const MainFunctionSwitch = () => {
|
||||
const { t } = useI18n();
|
||||
|
||||
const {
|
||||
toggleTranslation, currentTranslationStatus,
|
||||
toggleTranscriptionSend, currentTranscriptionSendStatus,
|
||||
toggleTranscriptionReceive, currentTranscriptionReceiveStatus,
|
||||
toggleForeground, currentForegroundStatus,
|
||||
} = useMainFunction();
|
||||
|
||||
|
||||
const switch_items = [
|
||||
{
|
||||
switch_id: "translation",
|
||||
label: t("main_page.translation"),
|
||||
SvgComponent: TranslationSvg,
|
||||
currentState: currentTranslationStatus,
|
||||
toggleFunction: toggleTranslation,
|
||||
},
|
||||
{
|
||||
switch_id: "transcription_send",
|
||||
label: t("main_page.transcription_send"),
|
||||
SvgComponent: MicSvg,
|
||||
currentState: currentTranscriptionSendStatus,
|
||||
toggleFunction: toggleTranscriptionSend,
|
||||
},
|
||||
{
|
||||
switch_id: "transcription_receive",
|
||||
label: t("main_page.transcription_receive"),
|
||||
SvgComponent: HeadphonesSvg,
|
||||
currentState: currentTranscriptionReceiveStatus,
|
||||
toggleFunction: toggleTranscriptionReceive,
|
||||
},
|
||||
{
|
||||
switch_id: "foreground",
|
||||
label: t("main_page.foreground"),
|
||||
SvgComponent: ForegroundSvg,
|
||||
currentState: currentForegroundStatus,
|
||||
toggleFunction: toggleForeground,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{switch_items.map(item => (
|
||||
<SwitchContainer
|
||||
key={item.switch_id}
|
||||
switch_id={item.switch_id}
|
||||
switchLabel={item.label}
|
||||
currentState={item.currentState}
|
||||
toggleFunction={item.toggleFunction}
|
||||
SvgComponent={item.SvgComponent}
|
||||
>
|
||||
</SwitchContainer>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
export const SwitchContainer = ({ switchLabel, switch_id, children, currentState, toggleFunction, SvgComponent }) => {
|
||||
const [is_hovered, setIsHovered] = useState(false);
|
||||
const [is_mouse_down, setIsMouseDown] = useState(false);
|
||||
|
||||
const { currentIsMainPageCompactMode } = useIsMainPageCompactMode();
|
||||
|
||||
const getClassNames = (baseClass) => clsx(baseClass, {
|
||||
[styles.is_compact_mode]: currentIsMainPageCompactMode.data,
|
||||
[styles.is_active]: (currentState.data === true),
|
||||
[styles.is_pending]: (currentState.state === "pending"),
|
||||
[styles.is_hovered]: is_hovered,
|
||||
[styles.is_mouse_down]: is_mouse_down,
|
||||
});
|
||||
|
||||
const onMouseEnter = () => setIsHovered(true);
|
||||
const onMouseLeave = () => setIsHovered(false);
|
||||
const onMouseDown = () => setIsMouseDown(true);
|
||||
const onMouseUp = () => setIsMouseDown(false);
|
||||
|
||||
return (
|
||||
<div className={getClassNames(styles.switch_container)}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
onMouseDown={onMouseDown}
|
||||
onMouseUp={onMouseUp}
|
||||
onClick={toggleFunction}
|
||||
>
|
||||
<div className={styles.label_wrapper}>
|
||||
<SvgComponent className={getClassNames(styles.switch_svg)} />
|
||||
<p className={getClassNames(styles.switch_label)}>{switchLabel}</p>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
<div className={getClassNames(styles.toggle_control)}>
|
||||
<span className={getClassNames(styles.control)}></span>
|
||||
</div>
|
||||
|
||||
<div className={getClassNames(styles.switch_indicator)}></div>
|
||||
{(currentState.state === "pending")
|
||||
? <span className={styles.loader}></span>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
@import "@scss_mixins";
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 0.1rem;
|
||||
}
|
||||
|
||||
.switch_container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1.6rem 1.4rem;
|
||||
background-color: var(--dark_825_color);
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_800_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
&.is_compact_mode {
|
||||
padding: 1.5rem;
|
||||
justify-content: center;
|
||||
}
|
||||
&.is_pending {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.label_wrapper {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
$pending_label_color: var(--dark_500_color);
|
||||
.switch_label {
|
||||
font-size: 1.4rem;
|
||||
&.is_compact_mode {
|
||||
display: none;
|
||||
}
|
||||
&.is_pending {
|
||||
color: $pending_label_color;
|
||||
}
|
||||
}
|
||||
|
||||
.switch_svg {
|
||||
width: 1.8rem;
|
||||
&.is_pending {
|
||||
color: $pending_label_color;
|
||||
}
|
||||
&:not(.is_compact_mode) {
|
||||
width: 1.6rem;
|
||||
color: var(--dark_350_color);
|
||||
}
|
||||
}
|
||||
|
||||
.switch_indicator {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0.4rem;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 0.2rem;
|
||||
height: 2.6rem;
|
||||
border-radius: 0.1rem;
|
||||
background-color: var(--primary_300_color);
|
||||
display: none;
|
||||
&.is_compact_mode.is_active {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.loader {
|
||||
@include loader(2rem, 0.2rem, left, 50%);
|
||||
}
|
||||
|
||||
.toggle_control {
|
||||
// @include toggle_control_styles;
|
||||
@include toggle_control_styles($toggle_width: 3.6rem, $toggle_height: 1.4rem);
|
||||
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
align-items: center;
|
||||
&.is_compact_mode {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import styles from "./OpenSettings.module.scss";
|
||||
import { useIsOpenedConfigPage } from "@logics_common";
|
||||
import ConfigurationSvg from "@images/configuration.svg?react";
|
||||
|
||||
export const OpenSettings = () => {
|
||||
const { setIsOpenedConfigPage } = useIsOpenedConfigPage();
|
||||
|
||||
const openConfigPage = () => {
|
||||
setIsOpenedConfigPage(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.open_config_page_button} onClick={openConfigPage}>
|
||||
<ConfigurationSvg className={styles.configuration_svg} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
.container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: var(--dark_850_color);
|
||||
}
|
||||
|
||||
.open_config_page_button {
|
||||
width: auto;
|
||||
margin: 1rem;
|
||||
padding: 0.8rem 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-radius: 0.6rem;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_800_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_875_color);
|
||||
}
|
||||
}
|
||||
|
||||
.configuration_svg {
|
||||
width: 2rem;
|
||||
color: var(--dark_500_color);
|
||||
}
|
||||
Reference in New Issue
Block a user