[Update] Migrate to tauri-app(Web UI)

This commit is contained in:
Sakamoto Shiina
2024-07-25 01:01:22 +09:00
parent 25899b63da
commit ebd1a8d70d
342 changed files with 14616 additions and 13428 deletions

View File

@@ -0,0 +1,34 @@
import { useResizable } from "react-resizable-layout";
import styles from "./MessageContainer.module.scss";
import { LogBox } from "./log_box/LogBox";
import { MessageInputBox } from "./message_input_box/MessageInputBox";
export const MessageContainer = () => {
const { position, separatorProps } = useResizable({
axis: "y",
reverse: true
});
return (
<div className={styles.container}>
<LogBox />
<Separator
dir={"horizontal"}
{...separatorProps}
/>
<div className={styles.message_box_resize_wrapper} style={ { height: `${(position / 10) - 1.5 }rem` } }>
<MessageInputBox />
</div>
</div>
);
};
const Separator = ({ ...props }) => {
return (
<div tabIndex={0} className={styles.separator} {...props}>
<span className={styles.separator_line}></span>
</div>
);
};

View File

@@ -0,0 +1,36 @@
.container {
height: 0%;
display: flex;
flex-direction: column;
flex: 1;
padding: 0 1.6rem 1rem 1.6rem;
}
.separator {
position: relative;
width: 100%;
height: 0.8rem;
cursor: row-resize;
flex-shrink: 0;
&:hover {
& .separator_line {
background-color: var(--primary_300_color);
}
}
}
.separator_line {
position: absolute;
bottom: 0%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 50%;
width: 99%;
transition: background-color .15s ease-out;
}
.message_box_resize_wrapper {
height: 10rem;
min-height: 3.8rem;
max-height: 80%;
}

View File

@@ -0,0 +1,47 @@
import { useEffect, useLayoutEffect, useRef, useState } from "react";
import styles from "./LogBox.module.scss";
import { useMessageLogs, store } from "@store";
import { MessageContainer } from "./message_container/MessageContainer";
import { scrollToBottom } from "@logics/scrollToBottom";
export const LogBox = () => {
const { currentMessageLogs } = useMessageLogs();
const log_container_ref = useRef(null);
const [is_scrolling, setIsScrolling] = useState(false);
useLayoutEffect(() => {
store.log_box_ref = log_container_ref;
if (!is_scrolling) {
scrollToBottom(store.log_box_ref, true);
}
}, [currentMessageLogs]);
useEffect(() => {
const handleScroll = () => {
const element = log_container_ref.current;
const currentScrollTop = element.scrollTop;
const at_bottom = element.scrollHeight - currentScrollTop === element.clientHeight;
if (at_bottom) {
setIsScrolling(false);
} else {
setIsScrolling(true);
}
};
const element = log_container_ref.current;
element.addEventListener("scroll", handleScroll);
return () => {
element.removeEventListener("scroll", handleScroll);
};
}, []);
return (
<div id="log_container" className={styles.container} ref={log_container_ref}>
{currentMessageLogs.map(message_data => (
<MessageContainer key={message_data.id} {...message_data} />
))}
</div>
);
};

View File

@@ -0,0 +1,13 @@
.container {
height: 100%;
width: 100%;
flex: 1;
background-color: var(--dark_900_color);
overflow: auto;
border-radius: 0.8rem;
padding: 1rem;
}
.text {
overflow-wrap: break-word;
}

View File

@@ -0,0 +1,44 @@
import { useTranslation } from "react-i18next";
import clsx from "clsx";
import styles from "./MessageContainer.module.scss";
export const MessageContainer = ({ messages, status, category, created_at }) => {
const { t } = useTranslation();
const is_translated_exist = messages.translated.length >= 1;
const is_pending = status === "pending";
const is_sent_message = category === "sent";
const category_text = is_sent_message ? t("main_window.textbox_tab_sent") : t("main_window.textbox_tab_received");
const message_type_class_name = clsx({
[styles.sent_message]: is_sent_message,
[styles.received_message]: !is_sent_message,
});
return (
<div className={clsx(styles.container, message_type_class_name)}>
<div className={clsx(styles.info_box, message_type_class_name)}>
<p className={styles.time}>{created_at}</p>
<p className={clsx(styles.category, message_type_class_name)}>{category_text}</p>
{is_sent_message && is_pending && <span className={styles.loader}></span>}
</div>
<div className={clsx(styles.message_box, message_type_class_name)}>
{is_translated_exist
? <WithTranslatedMessages messages={messages} />
: <p className={styles.message_main}>{messages.original}</p>
}
</div>
</div>
);
};
const WithTranslatedMessages = ({ messages }) => {
return (
<>
<p className={styles.message_second}>{messages.original}</p>
{messages.translated.map((message, index) => (
<p key={index} className={styles.message_main}>{message}</p>
))}
</>
);
};

View File

@@ -0,0 +1,70 @@
@import "@scss_mixins";
.container {
margin-bottom: 1rem;
width: 100%;
flex-direction: column;
display: flex;
justify-content: center;
&.sent_message {
align-items: end;
}
&.received_message {
align-items: start;
}
}
.info_box {
position: relative;
display: flex;
gap: 0.8rem;
justify-content: center;
&.sent_message {
align-items: end;
}
&.received_message {
flex-flow: row-reverse;
align-items: start;
}
}
.loader {
@include loader(0.8rem, 0.1rem, left, -1rem);
}
.time {
font-size: 1rem;
color: var(--dark_600_color);
}
.category {
font-size: 1rem;
&.sent_message {
color: var(--sent_400_color);
}
&.received_message {
align-items: start;
color: var(--received_300_color);
}
}
.message_box {
display: flex;
flex-direction: column;
&.sent_message {
align-items: end;
}
&.received_message {
align-items: start;
}
}
.message_main {
color: var(--dark_basic_text_color);
font-size: 1.4rem;
}
.message_second {
color: var(--dark_450_color);
font-size: 1rem;
}

View File

@@ -0,0 +1,45 @@
import { useState } from "react";
import styles from "./MessageInputBox.module.scss";
import SendMessageSvg from "@images/send_message.svg?react";
import { useMessage } from "@logics/useMessage";
import { store } from "@store";
import { scrollToBottom } from "@logics/scrollToBottom";
export const MessageInputBox = () => {
const [inputValue, setInputValue] = useState("");
const { sendMessage } = useMessage();
const onSubmitFunction = (e) => {
e.preventDefault();
sendMessage(inputValue);
setTimeout(() => {
scrollToBottom(store.log_box_ref);
}, 10);
};
const onChangeFunction = (e) => {
setInputValue(e.currentTarget.value);
};
return (
<div className={styles.container}>
<div className={styles.message_box_wrapper}>
<textarea
className={styles.message_box_input_area}
onChange={onChangeFunction}
placeholder="Input Textfield"
/>
</div>
<button
className={styles.message_send_button}
type="button"
onClick={onSubmitFunction}
>
<SendMessageSvg className={styles.message_send_icon} />
</button>
</div>
);
};

View File

@@ -0,0 +1,45 @@
.container {
height: 100%;
display: flex;
flex-direction: row;
}
.message_box_wrapper {
width: 100%;
height: 100%;
margin-right: 1rem;
padding: 0.8rem;
background-color: var(--dark_875_color);
border: 0.1rem solid var(--dark_750_color);
border-radius: 0.4rem;
}
.message_box_input_area {
width: 100%;
height: 100%;
font-size: 1.6rem;
resize: none;
}
.message_send_button {
display: flex;
justify-content: center;
align-items: center;
max-width: 10rem;
height: 100%;
font-size: 1.2rem;
background-color: var(--dark_850_color);
border-radius: 0.4rem;
aspect-ratio: 1 / 1;
&:hover {
background-color: var(--dark_825_color);
}
&:active {
background-color: var(--dark_900_color);
}
}
.message_send_icon {
width: 2rem;
color: var(--dark_400_color);
}