浏览代码

fix: #522 resizable side bar

Yidadaa 1 年之前
父节点
当前提交
6ae61c5357
共有 4 个文件被更改,包括 89 次插入4 次删除
  1. 3 0
      app/components/button.module.scss
  2. 25 3
      app/components/home.module.scss
  3. 59 1
      app/components/home.tsx
  4. 2 0
      app/store/app.ts

+ 3 - 0
app/components/button.module.scss

@@ -49,4 +49,7 @@
 .icon-button-text {
   margin-left: 5px;
   font-size: 12px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
 }

+ 25 - 3
app/components/home.module.scss

@@ -48,6 +48,27 @@
   display: flex;
   flex-direction: column;
   box-shadow: inset -2px 0px 2px 0px rgb(0, 0, 0, 0.05);
+  position: relative;
+  transition: width ease 0.1s;
+}
+
+.sidebar-drag {
+  $width: 10px;
+
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 100%;
+  width: $width;
+  background-color: var(--black);
+  cursor: ew-resize;
+  opacity: 0;
+  transition: all ease 0.3s;
+
+  &:hover,
+  &:active {
+    opacity: 0.2;
+  }
 }
 
 .window-content {
@@ -177,10 +198,11 @@
   margin-top: 8px;
 }
 
-.chat-item-count {
-}
-
+.chat-item-count,
 .chat-item-date {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
 }
 
 .sidebar-tail {

+ 59 - 1
app/components/home.tsx

@@ -2,7 +2,13 @@
 
 require("../polyfill");
 
-import { useState, useEffect } from "react";
+import {
+  useState,
+  useEffect,
+  useRef,
+  useCallback,
+  MouseEventHandler,
+} from "react";
 
 import { IconButton } from "./button";
 import styles from "./home.module.scss";
@@ -24,6 +30,7 @@ import { Chat } from "./chat";
 import dynamic from "next/dynamic";
 import { REPO_URL } from "../constant";
 import { ErrorBoundary } from "./error";
+import { useDebounce } from "use-debounce";
 
 export function Loading(props: { noLogo?: boolean }) {
   return (
@@ -75,6 +82,49 @@ function useSwitchTheme() {
   }, [config.theme]);
 }
 
+function useDragSideBar() {
+  const limit = (x: number) => Math.min(500, Math.max(220, x));
+
+  const chatStore = useChatStore();
+  const startX = useRef(0);
+  const startDragWidth = useRef(chatStore.config.sidebarWidth ?? 300);
+  const lastUpdateTime = useRef(Date.now());
+
+  const handleMouseMove = useRef((e: MouseEvent) => {
+    if (Date.now() < lastUpdateTime.current + 100) {
+      return;
+    }
+    lastUpdateTime.current = Date.now();
+    const d = e.clientX - startX.current;
+    const nextWidth = limit(startDragWidth.current + d);
+    chatStore.updateConfig((config) => (config.sidebarWidth = nextWidth));
+  });
+
+  const handleMouseUp = useRef(() => {
+    startDragWidth.current = chatStore.config.sidebarWidth ?? 300;
+    window.removeEventListener("mousemove", handleMouseMove.current);
+    window.removeEventListener("mouseup", handleMouseUp.current);
+  });
+
+  const onDragMouseDown = (e: MouseEvent) => {
+    startX.current = e.clientX;
+
+    window.addEventListener("mousemove", handleMouseMove.current);
+    window.addEventListener("mouseup", handleMouseUp.current);
+  };
+
+  useEffect(() => {
+    document.documentElement.style.setProperty(
+      "--sidebar-width",
+      `${limit(chatStore.config.sidebarWidth ?? 300)}px`,
+    );
+  }, [chatStore.config.sidebarWidth]);
+
+  return {
+    onDragMouseDown,
+  };
+}
+
 const useHasHydrated = () => {
   const [hasHydrated, setHasHydrated] = useState<boolean>(false);
 
@@ -101,6 +151,9 @@ function _Home() {
   const [openSettings, setOpenSettings] = useState(false);
   const config = useChatStore((state) => state.config);
 
+  // drag side bar
+  const { onDragMouseDown } = useDragSideBar();
+
   useSwitchTheme();
 
   if (loading) {
@@ -174,6 +227,11 @@ function _Home() {
             />
           </div>
         </div>
+
+        <div
+          className={styles["sidebar-drag"]}
+          onMouseDown={(e) => onDragMouseDown(e as any)}
+        ></div>
       </div>
 
       <div className={styles["window-content"]}>

+ 2 - 0
app/store/app.ts

@@ -53,6 +53,7 @@ export interface ChatConfig {
   theme: Theme;
   tightBorder: boolean;
   sendPreviewBubble: boolean;
+  sidebarWidth: number;
 
   disablePromptHint: boolean;
 
@@ -141,6 +142,7 @@ const DEFAULT_CONFIG: ChatConfig = {
   theme: Theme.Auto as Theme,
   tightBorder: false,
   sendPreviewBubble: true,
+  sidebarWidth: 300,
 
   disablePromptHint: false,