Skip to content

Commit f12f1bb

Browse files
committed
Merge branch 'release/1.0.10'
2 parents bbca440 + 9b4f2ff commit f12f1bb

File tree

17 files changed

+468
-95
lines changed

17 files changed

+468
-95
lines changed

โ€Ž.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ jobs:
2828
2929
# 3. Clean up Old Images
3030
- name: Remove Dangling Images
31-
run: docker image prune -a -f
31+
run: docker image prune -f

โ€Žclient/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# 1. Node.js 20 ๊ธฐ๋ฐ˜ ๋นŒ๋“œ ์ด๋ฏธ์ง€
2-
FROM node:20
2+
FROM node:20 AS build
33
WORKDIR /app
44

55
# 2. ๋ชจ๋…ธ๋ ˆํฌ ๋ฃจํŠธ์—์„œ ํ•„์š”ํ•œ ํŒŒ์ผ ๋ณต์‚ฌ

โ€Žclient/src/apis/ai.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,15 @@ import { unAuthorizationFetch } from "./axios";
33

44
// TODO ์‹คํŒจ ์‹œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ
55
export const useCreateAIDocumentMutation = (onSuccess: () => void) => {
6-
const fetcher = ({ text }: { text: string }) => unAuthorizationFetch.post("/ai", { text });
6+
const fetcher = ({
7+
clientId,
8+
workspaceId,
9+
message,
10+
}: {
11+
clientId: number | null;
12+
workspaceId: string | undefined;
13+
message: string;
14+
}) => unAuthorizationFetch.post("/ai/chat", { clientId, workspaceId, message });
715

816
return useMutation({
917
mutationFn: fetcher,

โ€Žclient/src/components/Toast/Toast.style.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const ToastWrapper = css({
1212
color: "white",
1313
backgroundColor: "gray.700",
1414
boxShadow: "lg",
15+
overflow: "hidden",
1516
// overflow: "hidden", // progress bar๊ฐ€ ๋„˜์น˜์ง€ ์•Š๋„๋ก
1617
transition: "all",
1718
transitionDuration: "300ms",

โ€Žclient/src/components/Toast/Toast.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ export const Toast = ({ message, duration = 3000, onClose }: ToastProps) => {
4848
animate={{ width: "100%" }}
4949
transition={{ duration: duration / 1000, ease: "easeOut" }}
5050
className={ToastProgress}
51+
style={{
52+
backgroundColor: message === "์˜ฌ๋ฐ”๋ฅธ ๋ช…๋ น์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”" ? "#E25D68" : "#6293E5",
53+
}}
5154
/>
5255

5356
<span className="text-sm">{message}</span>

โ€Žclient/src/features/ai/AIButton.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { useState, useRef, useEffect } from "react";
2+
import { useToastStore } from "@src/stores/useToastStore";
23
import * as style from "./AIButton.style";
34
import { AIModal } from "./AIModal";
45

56
export const AIButton = () => {
67
const [isOpen, setIsOpen] = useState(false);
78
const modalRef = useRef<HTMLDivElement>(null);
8-
9+
const { addToast } = useToastStore();
910
const handleClose = () => {
1011
setIsOpen(false);
12+
addToast("AI ๋ฌธ์„œ ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
1113
};
1214

1315
useEffect(() => {
@@ -24,7 +26,7 @@ export const AIButton = () => {
2426
}, []);
2527

2628
return (
27-
<div className={style.floatingButtonContainer}>
29+
<div className={style.floatingButtonContainer} data-onboarding="ai-button">
2830
<div ref={modalRef}>
2931
{isOpen && <AIModal onCloseButton={handleClose} />}
3032
<button onClick={() => setIsOpen((prev) => !prev)} className={style.buttonContainer}>

โ€Žclient/src/features/ai/AIModal.style.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export const inputContainer = css({
2121
backgroundColor: "white/80",
2222
});
2323

24+
export const inputWrapper = css({
25+
position: "relative",
26+
flex: 1,
27+
});
28+
2429
export const inputBox = css({
2530
outline: "none",
2631
width: "full",
@@ -29,8 +34,25 @@ export const inputBox = css({
2934

3035
export const iconBox = css({
3136
display: "flex",
37+
position: "relative",
3238
justifyContent: "center",
3339
alignItems: "center",
3440
width: "36px",
41+
transition: "filter 0.3s ease",
3542
cursor: "pointer",
43+
"&:hover": {
44+
scale: 1.1,
45+
},
46+
});
47+
export const loadingOverlay = css({
48+
display: "flex",
49+
zIndex: 10,
50+
position: "absolute",
51+
top: 0,
52+
left: 0,
53+
right: 0,
54+
bottom: 0,
55+
justifyContent: "center",
56+
alignItems: "center",
57+
backgroundColor: "rgba(255, 255, 255, 0.8)",
3658
});

โ€Žclient/src/features/ai/AIModal.tsx

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1-
import { useState, KeyboardEvent } from "react";
21
import { motion } from "framer-motion";
3-
import * as style from "./AIModal.style";
4-
import { animation } from "./AiModal.animation";
2+
import { useState, KeyboardEvent } from "react";
53
import { FaLocationArrow } from "react-icons/fa";
64
import { useCreateAIDocumentMutation } from "@src/apis/ai";
5+
import { LoadingSpinner } from "@src/components/lotties/LoadingSpinner";
6+
import { useSocketStore } from "@src/stores/useSocketStore";
7+
import { useToastStore } from "@src/stores/useToastStore";
8+
import * as style from "./AIModal.style";
9+
import { animation } from "./AiModal.animation";
710

811
export const AIModal = ({ onCloseButton }: { onCloseButton: () => void }) => {
9-
const [text, setText] = useState("");
10-
const { mutate: createAIDocument } = useCreateAIDocumentMutation(onCloseButton);
12+
const { clientId, workspace } = useSocketStore();
13+
const [message, setMessage] = useState("");
14+
const { mutate: createAIDocument, status } = useCreateAIDocumentMutation(onCloseButton);
15+
const isLoading = status === "pending";
1116

17+
const { addToast } = useToastStore();
1218
const handleSubmit = () => {
13-
createAIDocument({ text });
19+
if (!message.trim()) {
20+
addToast("์˜ฌ๋ฐ”๋ฅธ ๋ช…๋ น์„ ์ž‘์„ฑํ•ด์ฃผ์„ธ์š”");
21+
return;
22+
}
23+
if (!isLoading) {
24+
createAIDocument({ clientId, workspaceId: workspace?.id, message });
25+
}
1426
};
1527

1628
const handleKeyPress = (e: KeyboardEvent<HTMLInputElement>) => {
@@ -27,15 +39,24 @@ export const AIModal = ({ onCloseButton }: { onCloseButton: () => void }) => {
2739
>
2840
<div className={style.popoverContainer}>
2941
<div className={style.inputContainer}>
30-
<input
31-
type="text"
32-
value={text}
33-
onChange={(e) => setText(e.target.value)}
34-
onKeyPress={handleKeyPress}
35-
placeholder="๋ฌธ์„œ ์ž‘์„ฑํ•ด์ค˜"
36-
className={style.inputBox}
37-
/>
38-
<div className={style.iconBox} onClick={handleSubmit}>
42+
<div className={style.inputWrapper}>
43+
<input
44+
type="message"
45+
value={message}
46+
onChange={(e) => setMessage(e.target.value)}
47+
onKeyPress={handleKeyPress}
48+
placeholder="๋ฌธ์„œ ์ž‘์„ฑํ•ด์ค˜"
49+
className={style.inputBox}
50+
disabled={isLoading}
51+
/>
52+
{isLoading && (
53+
<div className={style.loadingOverlay}>
54+
<LoadingSpinner size={50} />
55+
</div>
56+
)}
57+
</div>
58+
<div className={style.iconBox} onClick={!isLoading ? handleSubmit : undefined}>
59+
{isLoading && <div className={style.loadingOverlay}></div>}
3960
<FaLocationArrow />
4061
</div>
4162
</div>

โ€Žclient/src/features/editor/utils/domSyncUtils.ts

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -188,76 +188,6 @@ const nodesAreEqual = (node1: Node, node2: Node): boolean => {
188188
return false;
189189
};
190190

191-
// export const setInnerHTML = ({ element, block }: SetInnerHTMLProps): void => {
192-
// const chars = block.crdt.LinkedList.spread();
193-
// if (chars.length === 0) {
194-
// element.innerHTML = "";
195-
// return;
196-
// }
197-
198-
// // ๊ฐ ์œ„์น˜๋ณ„ ๋ชจ๋“  ์ ์šฉ๋œ ์Šคํƒ€์ผ์„ ์ถ”์ 
199-
// const positionStyles: TextStyleState[] = chars.map((char) => {
200-
// const styleSet = new Set<string>();
201-
202-
// // ํ˜„์žฌ ๋ฌธ์ž์˜ ์Šคํƒ€์ผ ์ˆ˜์ง‘
203-
// char.style.forEach((style) => styleSet.add(TEXT_STYLES[style]));
204-
205-
// return {
206-
// styles: styleSet,
207-
// color: char.color,
208-
// backgroundColor: char.backgroundColor,
209-
// };
210-
// });
211-
212-
// let html = "";
213-
// let currentState: TextStyleState = {
214-
// styles: new Set<string>(),
215-
// color: "black",
216-
// backgroundColor: "transparent",
217-
// };
218-
// let spanOpen = false;
219-
220-
// chars.forEach((char, index) => {
221-
// const targetState = positionStyles[index];
222-
223-
// // ์Šคํƒ€์ผ, ์ƒ‰์ƒ, ๋ฐฐ๊ฒฝ์ƒ‰ ๋ณ€๊ฒฝ ํ™•์ธ
224-
// const styleChanged =
225-
// !setsEqual(currentState.styles, targetState.styles) ||
226-
// currentState.color !== targetState.color ||
227-
// currentState.backgroundColor !== targetState.backgroundColor;
228-
229-
// // ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฉด ํ˜„์žฌ span ํƒœ๊ทธ ๋‹ซ๊ธฐ
230-
// if (styleChanged && spanOpen) {
231-
// html += "</span>";
232-
// spanOpen = false;
233-
// }
234-
235-
// // ์ƒˆ๋กœ์šด ์Šคํƒ€์ผ ์กฐํ•ฉ์œผ๋กœ span ํƒœ๊ทธ ์—ด๊ธฐ
236-
// if (styleChanged) {
237-
// const className = getClassNames(targetState);
238-
// html += `<span class="${className}" style="white-space: pre;">`;
239-
// spanOpen = true;
240-
// }
241-
242-
// // ํ…์ŠคํŠธ ์ถ”๊ฐ€
243-
// html += sanitizeText(char.value);
244-
245-
// // ๋‹ค์Œ ๋ฌธ์ž๋กœ ๋„˜์–ด๊ฐ€๊ธฐ ์ „์— ํ˜„์žฌ ์ƒํƒœ ์—…๋ฐ์ดํŠธ
246-
// currentState = targetState;
247-
248-
// // ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์ด๊ณ  span์ด ์—ด๋ ค์žˆ์œผ๋ฉด ๋‹ซ๊ธฐ
249-
// if (index === chars.length - 1 && spanOpen) {
250-
// html += "</span>";
251-
// spanOpen = false;
252-
// }
253-
// });
254-
255-
// // DOM ์—…๋ฐ์ดํŠธ
256-
// if (element.innerHTML !== html) {
257-
// element.innerHTML = html;
258-
// }
259-
// };
260-
261191
// Set ๋น„๊ต ํ—ฌํผ ํ•จ์ˆ˜
262192
const setsEqual = (a: Set<string>, b: Set<string>): boolean => {
263193
if (a.size !== b.size) return false;

โ€Žclient/src/features/workSpace/components/OnboardingOverlay.style.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const overlayContainer = css({
99
export const highlightBox = css({
1010
position: "absolute",
1111
borderColor: "rgba(168, 85, 247, 0.5)", // purple-400 with 50% opacity
12-
borderRadius: "xl",
12+
borderRadius: "0",
1313
borderWidth: "2px",
1414
backgroundColor: "rgba(255, 255, 255, 0.1)",
1515
pointerEvents: "none",

0 commit comments

Comments
ย (0)