enzostvs HF staff victor HF staff commited on
Commit
bc2c276
·
verified ·
1 Parent(s): 49f34f2

- feat: Add resize functionality and logging for breakpoint (2c6c947770edd4b2f62b971f917d4b49a9b14464)
- toto (974e9f3b3d2fdde002506d66b3a43051b638f9cd)
- aider (dd0993f748a36b51efee9048a24a2d13d14c34cd)


Co-authored-by: Victor Mustar <[email protected]>

.gitignore CHANGED
@@ -22,4 +22,5 @@ dist-ssr
22
  *.njsproj
23
  *.sln
24
  *.sw?
25
- .env
 
 
22
  *.njsproj
23
  *.sln
24
  *.sw?
25
+ .env
26
+ .aider*
server.js CHANGED
@@ -218,10 +218,8 @@ app.post("/api/ask-ai", async (req, res) => {
218
  // Stream chunk to client
219
  let newChunk = chunk;
220
  if (chunk.includes("</html>")) {
221
- console.log("Chunk before replacement:", newChunk);
222
  // Replace everything after the last </html> tag with an empty string
223
  newChunk = newChunk.replace(/<\/html>[\s\S]*/, "</html>");
224
- console.log("Chunk after replacement:", newChunk);
225
  }
226
  completeResponse += newChunk;
227
  res.write(newChunk);
 
218
  // Stream chunk to client
219
  let newChunk = chunk;
220
  if (chunk.includes("</html>")) {
 
221
  // Replace everything after the last </html> tag with an empty string
222
  newChunk = newChunk.replace(/<\/html>[\s\S]*/, "</html>");
 
223
  }
224
  completeResponse += newChunk;
225
  res.write(newChunk);
src/components/App.tsx CHANGED
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
  import { useRef, useState } from "react";
3
  import Editor from "@monaco-editor/react";
4
  import classNames from "classnames";
@@ -7,7 +6,6 @@ import {
7
  useMount,
8
  useUnmount,
9
  useEvent,
10
- createBreakpoint,
11
  useLocalStorage,
12
  } from "react-use";
13
  import { toast } from "react-toastify";
@@ -20,15 +18,9 @@ import AskAI from "./ask-ai/ask-ai";
20
  import { Auth } from "../utils/types";
21
  import Preview from "./preview/preview";
22
 
23
- const useBreakpoint = createBreakpoint({
24
- md: 768,
25
- lg: 1024,
26
- });
27
 
28
  function App() {
29
- const breakpoint = useBreakpoint();
30
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
31
- const [htmlStorage, _, removeHtmlStorage] = useLocalStorage("html_content");
32
 
33
  const preview = useRef<HTMLDivElement>(null);
34
  const editor = useRef<HTMLDivElement>(null);
@@ -51,12 +43,47 @@ function App() {
51
  }
52
  };
53
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  const handleResize = (e: MouseEvent) => {
55
  if (!editor.current || !preview.current || !resizer.current) return;
 
 
 
 
 
56
  const editorWidth = e.clientX;
57
- const previewWidth = window.innerWidth - editorWidth - 4;
58
- editor.current.style.width = `${editorWidth}px`;
59
- preview.current.style.width = `${previewWidth}px`;
 
 
60
  };
61
 
62
  const handleMouseDown = () => {
@@ -71,6 +98,7 @@ function App() {
71
  document.removeEventListener("mouseup", handleMouseUp);
72
  };
73
 
 
74
  useEvent("beforeunload", (e) => {
75
  if (isAiWorking || html !== defaultHTML) {
76
  e.preventDefault();
@@ -78,34 +106,34 @@ function App() {
78
  }
79
  });
80
 
 
81
  useMount(() => {
 
82
  fetchMe();
 
 
83
  if (htmlStorage) {
84
  removeHtmlStorage();
85
  toast.warn("Previous HTML content restored from local storage.");
86
  }
87
- if (!editor.current || !preview.current) return;
88
 
89
- if (breakpoint === "lg") {
90
- // Set initial sizes
91
- const initialEditorWidth = window.innerWidth / 2;
92
- const initialPreviewWidth = window.innerWidth - initialEditorWidth - 4;
93
- editor.current.style.width = `${initialEditorWidth}px`;
94
- preview.current.style.width = `${initialPreviewWidth}px`;
95
- }
96
 
 
97
  if (!resizer.current) return;
98
  resizer.current.addEventListener("mousedown", handleMouseDown);
99
- window.addEventListener("resize", () => handleMouseDown);
100
  });
101
 
 
102
  useUnmount(() => {
103
  document.removeEventListener("mousemove", handleResize);
104
  document.removeEventListener("mouseup", handleMouseUp);
105
  if (resizer.current) {
106
  resizer.current.removeEventListener("mousedown", handleMouseDown);
107
  }
108
- window.removeEventListener("resize", () => handleMouseDown);
109
  });
110
 
111
  return (
 
 
1
  import { useRef, useState } from "react";
2
  import Editor from "@monaco-editor/react";
3
  import classNames from "classnames";
 
6
  useMount,
7
  useUnmount,
8
  useEvent,
 
9
  useLocalStorage,
10
  } from "react-use";
11
  import { toast } from "react-toastify";
 
18
  import { Auth } from "../utils/types";
19
  import Preview from "./preview/preview";
20
 
 
 
 
 
21
 
22
  function App() {
23
+ const [htmlStorage, , removeHtmlStorage] = useLocalStorage("html_content");
 
 
24
 
25
  const preview = useRef<HTMLDivElement>(null);
26
  const editor = useRef<HTMLDivElement>(null);
 
43
  }
44
  };
45
 
46
+ /**
47
+ * Resets the layout based on screen size
48
+ * - For desktop: Sets editor to 1/3 width and preview to 2/3
49
+ * - For mobile: Removes inline styles to let CSS handle it
50
+ */
51
+ const resetLayout = () => {
52
+ if (!editor.current || !preview.current) return;
53
+
54
+ // lg breakpoint is 1024px based on useBreakpoint definition and Tailwind defaults
55
+ if (window.innerWidth >= 1024) {
56
+ // Set initial 1/3 - 2/3 sizes for large screens, accounting for resizer width
57
+ const resizerWidth = resizer.current?.offsetWidth ?? 8; // w-2 = 0.5rem = 8px
58
+ const availableWidth = window.innerWidth - resizerWidth;
59
+ const initialEditorWidth = availableWidth / 3; // Editor takes 1/3 of space
60
+ const initialPreviewWidth = availableWidth - initialEditorWidth; // Preview takes 2/3
61
+ editor.current.style.width = `${initialEditorWidth}px`;
62
+ preview.current.style.width = `${initialPreviewWidth}px`;
63
+ } else {
64
+ // Remove inline styles for smaller screens, let CSS flex-col handle it
65
+ editor.current.style.width = '';
66
+ preview.current.style.width = '';
67
+ }
68
+ };
69
+
70
+ /**
71
+ * Handles resizing when the user drags the resizer
72
+ * Ensures minimum widths are maintained for both panels
73
+ */
74
  const handleResize = (e: MouseEvent) => {
75
  if (!editor.current || !preview.current || !resizer.current) return;
76
+
77
+ const resizerWidth = resizer.current.offsetWidth;
78
+ const minWidth = 100; // Minimum width for editor/preview
79
+ const maxWidth = window.innerWidth - resizerWidth - minWidth;
80
+
81
  const editorWidth = e.clientX;
82
+ const clampedEditorWidth = Math.max(minWidth, Math.min(editorWidth, maxWidth));
83
+ const calculatedPreviewWidth = window.innerWidth - clampedEditorWidth - resizerWidth;
84
+
85
+ editor.current.style.width = `${clampedEditorWidth}px`;
86
+ preview.current.style.width = `${calculatedPreviewWidth}px`;
87
  };
88
 
89
  const handleMouseDown = () => {
 
98
  document.removeEventListener("mouseup", handleMouseUp);
99
  };
100
 
101
+ // Prevent accidental navigation away when AI is working or content has changed
102
  useEvent("beforeunload", (e) => {
103
  if (isAiWorking || html !== defaultHTML) {
104
  e.preventDefault();
 
106
  }
107
  });
108
 
109
+ // Initialize component on mount
110
  useMount(() => {
111
+ // Fetch user data
112
  fetchMe();
113
+
114
+ // Restore content from storage if available
115
  if (htmlStorage) {
116
  removeHtmlStorage();
117
  toast.warn("Previous HTML content restored from local storage.");
118
  }
 
119
 
120
+ // Set initial layout based on window size
121
+ resetLayout();
 
 
 
 
 
122
 
123
+ // Attach event listeners
124
  if (!resizer.current) return;
125
  resizer.current.addEventListener("mousedown", handleMouseDown);
126
+ window.addEventListener("resize", resetLayout);
127
  });
128
 
129
+ // Clean up event listeners on unmount
130
  useUnmount(() => {
131
  document.removeEventListener("mousemove", handleResize);
132
  document.removeEventListener("mouseup", handleMouseUp);
133
  if (resizer.current) {
134
  resizer.current.removeEventListener("mousedown", handleMouseDown);
135
  }
136
+ window.removeEventListener("resize", resetLayout);
137
  });
138
 
139
  return (
src/components/login/login.tsx CHANGED
@@ -8,14 +8,12 @@ function Login({
8
  html?: string;
9
  children?: React.ReactNode;
10
  }) {
11
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
12
- const [_, setStorage] = useLocalStorage("html_content");
13
 
14
  const handleClick = () => {
15
  if (html !== defaultHTML) {
16
  setStorage(html);
17
  }
18
- console.log("store current HTML in local storage");
19
  };
20
 
21
  return (
 
8
  html?: string;
9
  children?: React.ReactNode;
10
  }) {
11
+ const [, setStorage] = useLocalStorage("html_content");
 
12
 
13
  const handleClick = () => {
14
  if (html !== defaultHTML) {
15
  setStorage(html);
16
  }
 
17
  };
18
 
19
  return (