[Update] Migrate to tauri-app(Web UI)
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import clsx from "clsx";
|
||||
|
||||
import styles from "./SidebarSection.module.scss";
|
||||
import { useIsCompactMode } from "@store";
|
||||
|
||||
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 { currentIsCompactMode } = useIsCompactMode();
|
||||
const container_class_name = clsx(styles["container"], {
|
||||
[styles["is_compact_mode"]]: currentIsCompactMode
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={container_class_name}>
|
||||
<Logo />
|
||||
<MainFunctionSwitch />
|
||||
{!currentIsCompactMode && <LanguageSettings />}
|
||||
<OpenSettings />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import styles from "./LanguageSettings.module.scss";
|
||||
|
||||
import { PresetSelectTabs } from "./preset_select_tabs/PresetSelectTabs";
|
||||
import { LanguageSelectorOpenButton } from "./language_selector_open_button/LanguageSelectorOpenButton";
|
||||
import { LanguageSwapButton } from "./language_swap_button/LanguageSwapButton";
|
||||
import { TranslatorSelectorOpenButton } from "./translator_selector_open_button/TranslatorSelectorOpenButton";
|
||||
import { useOpenedTranslatorSelector } from "@store";
|
||||
|
||||
export const LanguageSettings = () => {
|
||||
const { updateOpenedTranslatorSelector} = useOpenedTranslatorSelector();
|
||||
const closeTranslatorSelector = () => updateOpenedTranslatorSelector(false);
|
||||
|
||||
return (
|
||||
<div className={styles.container} onMouseLeave={closeTranslatorSelector} >
|
||||
<p className={styles.title}>Language Settings</p>
|
||||
<PresetSelectTabs />
|
||||
<PresetContainer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
import MicSvg from "@images/mic.svg?react";
|
||||
import HeadphonesSvg from "@images/headphones.svg?react";
|
||||
import { useIsOpenedLanguageSelector } from "@store";
|
||||
import { useMainFunction } from "@logics/useMainFunction";
|
||||
|
||||
const PresetContainer = () => {
|
||||
const { t } = useTranslation();
|
||||
const { updateIsOpenedLanguageSelector, currentIsOpenedLanguageSelector } = useIsOpenedLanguageSelector();
|
||||
|
||||
const {
|
||||
currentState_TranscriptionSend,
|
||||
currentState_TranscriptionReceive,
|
||||
} = useMainFunction();
|
||||
|
||||
|
||||
const closeLanguageSelector = () => {
|
||||
updateIsOpenedLanguageSelector({
|
||||
your_language: false,
|
||||
target_language: false,
|
||||
});
|
||||
};
|
||||
|
||||
const toggleYourLanguageSelector = () => {
|
||||
if (currentIsOpenedLanguageSelector.your_language === true) {
|
||||
closeLanguageSelector();
|
||||
} else {
|
||||
updateIsOpenedLanguageSelector({
|
||||
your_language: true,
|
||||
target_language: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const toggleTargetLanguageSelector = () => {
|
||||
if (currentIsOpenedLanguageSelector.target_language === true) {
|
||||
closeLanguageSelector();
|
||||
} else {
|
||||
updateIsOpenedLanguageSelector({
|
||||
your_language: false,
|
||||
target_language: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleLanguageSelectorClick = (selector) => {
|
||||
if (selector === "your_language") {
|
||||
toggleYourLanguageSelector();
|
||||
} else if (selector === "target_language") {
|
||||
toggleTargetLanguageSelector();
|
||||
}
|
||||
};
|
||||
|
||||
const your_language_settings = {
|
||||
title: t("main_window.your_language"),
|
||||
is_opened: currentIsOpenedLanguageSelector.your_language,
|
||||
onClickFunction: () => handleLanguageSelectorClick("your_language"),
|
||||
TurnedOnSvgComponent: <MicSvg />,
|
||||
is_turned_on: currentState_TranscriptionSend.data,
|
||||
};
|
||||
|
||||
const target_language_settings = {
|
||||
title: t("main_window.target_language"),
|
||||
is_opened: currentIsOpenedLanguageSelector.target_language,
|
||||
onClickFunction: () => handleLanguageSelectorClick("target_language"),
|
||||
TurnedOnSvgComponent: <HeadphonesSvg />,
|
||||
is_turned_on: currentState_TranscriptionReceive.data,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.preset_container}>
|
||||
<LanguageSelectorOpenButton {...your_language_settings} />
|
||||
<LanguageSwapButton />
|
||||
<LanguageSelectorOpenButton {...target_language_settings} />
|
||||
<TranslatorSelectorOpenButton />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
.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;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import clsx from "clsx";
|
||||
import styles from "./LanguageSelectorOpenButton.module.scss";
|
||||
import ArrowLeftSvg from "@images/arrow_left.svg?react";
|
||||
import { useSvg } from "@utils/useSvg";
|
||||
export const LanguageSelectorOpenButton = (props) => {
|
||||
|
||||
const toggleLanguageSelector = () => {
|
||||
props.onClickFunction();
|
||||
};
|
||||
|
||||
const class_names = clsx(styles["arrow_left_svg"], {
|
||||
[styles["reverse"]]: props.is_opened
|
||||
});
|
||||
|
||||
const SvgComponent = useSvg(props.TurnedOnSvgComponent,
|
||||
{className: clsx(styles["category_svg"], {
|
||||
[styles["is_turned_on"]]: props.is_turned_on
|
||||
})}
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.title_container}>
|
||||
{SvgComponent}
|
||||
<p className={styles.title}>{props.title}</p>
|
||||
</div>
|
||||
<div className={styles.dropdown_menu_container} onClick={toggleLanguageSelector}>
|
||||
<p className={styles.selected_language}>Japanese</p>
|
||||
<p className={styles.selected_language}>(Japan)</p>
|
||||
<ArrowLeftSvg className={class_names} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
.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.2rem 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;
|
||||
color: var(--dark_basic_text_color);
|
||||
}
|
||||
|
||||
.arrow_left_svg {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin: 0 0.2rem;
|
||||
transform: rotate(180deg);
|
||||
width: 1.6rem;
|
||||
color: var(--dark_basic_text_color);
|
||||
&.reverse {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { useState } from "react";
|
||||
import clsx from "clsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import styles from "./LanguageSwapButton.module.scss";
|
||||
|
||||
import NarrowArrowDownSvg from "@images/narrow_arrow_down.svg?react";
|
||||
|
||||
export const LanguageSwapButton = () => {
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const label = isHovered
|
||||
? t("main_window.swap_button_label")
|
||||
: t("main_window.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}
|
||||
>
|
||||
<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_basic_text_color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import styles from "./PresetSelectTabs.module.scss";
|
||||
|
||||
export const PresetSelectTabs = () => {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Tab preset_number={1} />
|
||||
<Tab preset_number={2} />
|
||||
<Tab preset_number={3} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import clsx from "clsx";
|
||||
|
||||
import { useSelectedTab } from "@store";
|
||||
|
||||
const Tab = (props) => {
|
||||
const { updateSelectedTab, currentSelectedTab } = useSelectedTab();
|
||||
const onclickFunction = () => {
|
||||
updateSelectedTab(props.preset_number);
|
||||
};
|
||||
|
||||
const class_names = clsx(styles["tab_container"], {
|
||||
[styles["is_selected"]]: (currentSelectedTab === 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_basic_text_color);
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.tab_number {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import styles from "./TranslatorSelectorOpenButton.module.scss";
|
||||
import { TranslatorSelector } from "./translator_selector/TranslatorSelector";
|
||||
import { useTranslatorList, useSelectedTranslator, useOpenedTranslatorSelector } from "@store";
|
||||
|
||||
export const TranslatorSelectorOpenButton = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentSelectedTranslator } = useSelectedTranslator();
|
||||
const { currentTranslatorList } = useTranslatorList();
|
||||
const currentTranslator = currentTranslatorList.find(
|
||||
translator_data => translator_data.translator_key === currentSelectedTranslator
|
||||
);
|
||||
|
||||
const { currentOpenedTranslatorSelector, updateOpenedTranslatorSelector} = useOpenedTranslatorSelector();
|
||||
|
||||
const openTranslatorSelector = () => updateOpenedTranslatorSelector(!currentOpenedTranslatorSelector);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.translator_selector_button} onClick={openTranslatorSelector}>
|
||||
<p className={styles.label}>{t("main_window.translator")}</p>
|
||||
<p className={styles.label}>{currentTranslator?.translator_name}</p>
|
||||
</div>
|
||||
{currentOpenedTranslatorSelector && <TranslatorSelector />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.translator_selector_button {
|
||||
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;
|
||||
color: var(--dark_basic_text_color);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import styles from "./TranslatorSelector.module.scss";
|
||||
import { chunkArray } from "@utils/chunkArray";
|
||||
|
||||
import { useTranslatorList, useSelectedTranslator, useOpenedTranslatorSelector } from "@store";
|
||||
export const TranslatorSelector = () => {
|
||||
const { currentTranslatorList } = useTranslatorList();
|
||||
const columns = chunkArray(currentTranslatorList, 2);
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.wrapper}>
|
||||
{columns.map((column, column_index) => (
|
||||
<div className={styles.column_wrapper} key={`column_${column_index}`}>
|
||||
{column.map(({ translator_key, translator_name, is_available }) => (
|
||||
<TranslatorBox
|
||||
key={translator_key}
|
||||
translator_id={translator_key}
|
||||
translator_name={translator_name}
|
||||
is_available={is_available}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
import clsx from "clsx";
|
||||
const TranslatorBox = (props) => {
|
||||
const { currentSelectedTranslator, updateSelectedTranslator} = useSelectedTranslator();
|
||||
const { updateOpenedTranslatorSelector} = useOpenedTranslatorSelector();
|
||||
|
||||
const box_class_name = clsx(
|
||||
styles.box,
|
||||
{ [styles["is_selected"]]: (currentSelectedTranslator === props.translator_id) ? true : false },
|
||||
{ [styles["is_available"]]: (props.is_available === true) ? true : false }
|
||||
);
|
||||
|
||||
const selectTranslator = () => {
|
||||
updateSelectedTranslator(props.translator_id);
|
||||
updateOpenedTranslatorSelector(false);
|
||||
};
|
||||
return (
|
||||
<div className={box_class_name} onClick={selectTranslator}>
|
||||
<p className={styles.translator_name}>{props.translator_name}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
.container {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
width: 100%;
|
||||
height: 26rem;
|
||||
padding: 1rem;
|
||||
background-color: (#000000dd);
|
||||
// background-color: (var(--dark_875_color) + 80);
|
||||
backdrop-filter: blur(0.1rem);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.column_wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
$box_size: 6.8rem;
|
||||
.box {
|
||||
width: $box_size;
|
||||
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.6rem;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: var(--dark_825_color);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--dark_900_color);
|
||||
border: 0.1rem solid var(--primary_300_color);
|
||||
}
|
||||
&.is_selected {
|
||||
border: 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;
|
||||
}
|
||||
23
src-ui/windows/main_window/sidebar_section/logo/Logo.jsx
Normal file
23
src-ui/windows/main_window/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 { useIsCompactMode } from "@store";
|
||||
|
||||
export const LogoBox = () => {
|
||||
const { currentIsCompactMode } = useIsCompactMode();
|
||||
if (currentIsCompactMode === 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,18 @@
|
||||
.container {
|
||||
height: var(--main_window_topbar_height);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 12rem;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.logo_chato {
|
||||
width: 2rem;
|
||||
height: auto;
|
||||
margin: auto;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
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 { useIsCompactMode } from "@store";
|
||||
|
||||
import { useMainFunction } from "@logics/useMainFunction";
|
||||
|
||||
export const MainFunctionSwitch = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {
|
||||
toggleTranslation, currentState_Translation,
|
||||
toggleTranscriptionSend, currentState_TranscriptionSend,
|
||||
toggleTranscriptionReceive, currentState_TranscriptionReceive,
|
||||
toggleForeground, currentState_Foreground,
|
||||
} = useMainFunction();
|
||||
|
||||
|
||||
const switch_items = [
|
||||
{
|
||||
switch_id: "translation",
|
||||
label: t("main_window.translation"),
|
||||
SvgComponent: TranslationSvg,
|
||||
currentState: currentState_Translation,
|
||||
toggleFunction: toggleTranslation,
|
||||
},
|
||||
{
|
||||
switch_id: "transcription_send",
|
||||
label: t("main_window.transcription_send"),
|
||||
SvgComponent: MicSvg,
|
||||
currentState: currentState_TranscriptionSend,
|
||||
toggleFunction: toggleTranscriptionSend,
|
||||
},
|
||||
{
|
||||
switch_id: "transcription_receive",
|
||||
label: t("main_window.transcription_receive"),
|
||||
SvgComponent: HeadphonesSvg,
|
||||
currentState: currentState_TranscriptionReceive,
|
||||
toggleFunction: toggleTranscriptionReceive,
|
||||
},
|
||||
{
|
||||
switch_id: "foreground",
|
||||
label: t("main_window.foreground"),
|
||||
SvgComponent: ForegroundSvg,
|
||||
currentState: currentState_Foreground,
|
||||
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 { currentIsCompactMode } = useIsCompactMode();
|
||||
|
||||
const getClassNames = (baseClass) => clsx(baseClass, {
|
||||
[styles.is_compact_mode]: currentIsCompactMode,
|
||||
[styles.is_active]: (currentState.data === true),
|
||||
[styles.is_loading]: (currentState.state === "loading"),
|
||||
[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 === "loading")
|
||||
? <span className={styles.loader}></span>
|
||||
: null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,88 @@
|
||||
@import "@scss_mixins";
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 0.1rem;
|
||||
}
|
||||
|
||||
.switch_container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
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;
|
||||
}
|
||||
&.is_loading {
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.label_wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
gap: 0.8rem;
|
||||
}
|
||||
|
||||
$basic_label_color: var(--dark_basic_text_color);
|
||||
$loading_label_color: var(--dark_500_color);
|
||||
.switch_label {
|
||||
font-size: 1.4rem;
|
||||
color: $basic_label_color;
|
||||
&.is_compact_mode {
|
||||
display: none;
|
||||
}
|
||||
&.is_loading {
|
||||
color: $loading_label_color;
|
||||
}
|
||||
}
|
||||
|
||||
.switch_svg {
|
||||
width: 1.8rem;
|
||||
color: $basic_label_color;
|
||||
&.is_loading {
|
||||
color: $loading_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;
|
||||
&.is_compact_mode {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import styles from "./OpenSettings.module.scss";
|
||||
import ConfigurationSvg from "@images/configuration.svg?react";
|
||||
|
||||
import { useWindow } from "@utils/useWindow";
|
||||
|
||||
export const OpenSettings = () => {
|
||||
const { createConfigWindow } = useWindow();
|
||||
|
||||
const openConfigWindow = () => {
|
||||
createConfigWindow();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.open_config_window_button} onClick={openConfigWindow}>
|
||||
<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_window_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