mirror of
https://github.com/sqlchat/sqlchat.git
synced 2025-07-29 18:23:25 +08:00
chore: update responsible connection sidebar style
This commit is contained in:
@ -1,8 +1,9 @@
|
|||||||
|
import { Drawer } from "@mui/material";
|
||||||
import { head } from "lodash-es";
|
import { head } from "lodash-es";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useConversationStore, useConnectionStore, useLayoutStore } from "@/store";
|
import { useConversationStore, useConnectionStore, useLayoutStore, ResponsiveWidth } from "@/store";
|
||||||
import { Conversation, Connection } from "@/types";
|
import { Conversation, Connection } from "@/types";
|
||||||
import Select from "./kit/Select";
|
import Select from "./kit/Select";
|
||||||
import Icon from "./Icon";
|
import Icon from "./Icon";
|
||||||
@ -40,6 +41,25 @@ const ConnectionSidebar = () => {
|
|||||||
conversation.databaseName === currentConnectionCtx?.database?.name
|
conversation.databaseName === currentConnectionCtx?.database?.name
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleWindowResize = () => {
|
||||||
|
if (window.innerWidth < ResponsiveWidth.sm) {
|
||||||
|
layoutStore.toggleSidebar(false);
|
||||||
|
layoutStore.setIsMobileView(true);
|
||||||
|
} else {
|
||||||
|
layoutStore.toggleSidebar(true);
|
||||||
|
layoutStore.setIsMobileView(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleWindowResize();
|
||||||
|
window.addEventListener("resize", handleWindowResize);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("resize", handleWindowResize);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentConnectionCtx?.connection) {
|
if (currentConnectionCtx?.connection) {
|
||||||
setIsRequestingDatabase(true);
|
setIsRequestingDatabase(true);
|
||||||
@ -112,7 +132,9 @@ const ConnectionSidebar = () => {
|
|||||||
|
|
||||||
const handleConversationSelect = (conversation: Conversation) => {
|
const handleConversationSelect = (conversation: Conversation) => {
|
||||||
conversationStore.setCurrentConversation(conversation);
|
conversationStore.setCurrentConversation(conversation);
|
||||||
layoutStore.toggleSidebar(false);
|
if (layoutStore.isMobileView) {
|
||||||
|
layoutStore.toggleSidebar(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditConversationTitle = (conversation: Conversation) => {
|
const handleEditConversationTitle = (conversation: Conversation) => {
|
||||||
@ -132,8 +154,11 @@ const ConnectionSidebar = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<aside className="drawer-side">
|
<Drawer
|
||||||
<label htmlFor="connection-drawer" className="drawer-overlay"></label>
|
variant={layoutStore.isMobileView ? "temporary" : "persistent"}
|
||||||
|
open={layoutStore.showSidebar}
|
||||||
|
onClose={() => layoutStore.toggleSidebar(false)}
|
||||||
|
>
|
||||||
<div className="w-80 h-full overflow-y-hidden border-r flex flex-row justify-start items-start">
|
<div className="w-80 h-full overflow-y-hidden border-r flex flex-row justify-start items-start">
|
||||||
<div className="w-16 h-full bg-gray-200 pl-2 py-4 pt-6 flex flex-col justify-between items-center">
|
<div className="w-16 h-full bg-gray-200 pl-2 py-4 pt-6 flex flex-col justify-between items-center">
|
||||||
<div className="w-full flex flex-col justify-start items-start">
|
<div className="w-full flex flex-col justify-start items-start">
|
||||||
@ -258,7 +283,7 @@ const ConnectionSidebar = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</Drawer>
|
||||||
|
|
||||||
{createPortal(
|
{createPortal(
|
||||||
<CreateConnectionModal
|
<CreateConnectionModal
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useConversationStore } from "@/store";
|
import { useConversationStore, useLayoutStore } from "@/store";
|
||||||
import Icon from "../Icon";
|
import Icon from "../Icon";
|
||||||
import GitHubStarBadge from "../GitHubStarBadge";
|
import GitHubStarBadge from "../GitHubStarBadge";
|
||||||
|
|
||||||
@ -9,6 +9,7 @@ interface Props {
|
|||||||
|
|
||||||
const Header = (props: Props) => {
|
const Header = (props: Props) => {
|
||||||
const { className } = props;
|
const { className } = props;
|
||||||
|
const layoutStore = useLayoutStore();
|
||||||
const conversationStore = useConversationStore();
|
const conversationStore = useConversationStore();
|
||||||
const currentConversation = conversationStore.currentConversation;
|
const currentConversation = conversationStore.currentConversation;
|
||||||
const title = currentConversation?.title || "SQL Chat";
|
const title = currentConversation?.title || "SQL Chat";
|
||||||
@ -24,9 +25,12 @@ const Header = (props: Props) => {
|
|||||||
} w-full flex flex-row justify-between items-center lg:grid lg:grid-cols-3 py-1 border-b z-1 transition-all duration-300`}
|
} w-full flex flex-row justify-between items-center lg:grid lg:grid-cols-3 py-1 border-b z-1 transition-all duration-300`}
|
||||||
>
|
>
|
||||||
<div className="ml-2 flex justify-start items-center">
|
<div className="ml-2 flex justify-start items-center">
|
||||||
<label htmlFor="connection-drawer" className="w-8 h-8 p-1 mr-1 block lg:hidden rounded-md cursor-pointer hover:bg-gray-100">
|
<button
|
||||||
|
className="w-8 h-8 p-1 mr-1 block lg:hidden rounded-md cursor-pointer hover:bg-gray-100"
|
||||||
|
onClick={() => layoutStore.toggleSidebar()}
|
||||||
|
>
|
||||||
<Icon.IoIosMenu className="text-gray-600 w-full h-auto" />
|
<Icon.IoIosMenu className="text-gray-600 w-full h-auto" />
|
||||||
</label>
|
</button>
|
||||||
<span className="w-auto text-left block lg:hidden">{title}</span>
|
<span className="w-auto text-left block lg:hidden">{title}</span>
|
||||||
<GitHubStarBadge className="hidden lg:flex ml-2" />
|
<GitHubStarBadge className="hidden lg:flex ml-2" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
useMessageStore,
|
useMessageStore,
|
||||||
useConnectionStore,
|
useConnectionStore,
|
||||||
useSettingStore,
|
useSettingStore,
|
||||||
|
useLayoutStore,
|
||||||
} from "@/store";
|
} from "@/store";
|
||||||
import { CreatorRole, Message } from "@/types";
|
import { CreatorRole, Message } from "@/types";
|
||||||
import { countTextTokens, generateUUID } from "@/utils";
|
import { countTextTokens, generateUUID } from "@/utils";
|
||||||
@ -23,6 +24,7 @@ const MAX_TOKENS = 4000;
|
|||||||
|
|
||||||
const ConversationView = () => {
|
const ConversationView = () => {
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
const layoutStore = useLayoutStore();
|
||||||
const connectionStore = useConnectionStore();
|
const connectionStore = useConnectionStore();
|
||||||
const conversationStore = useConversationStore();
|
const conversationStore = useConversationStore();
|
||||||
const messageStore = useMessageStore();
|
const messageStore = useMessageStore();
|
||||||
@ -207,9 +209,11 @@ const ConversationView = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main
|
<div
|
||||||
ref={conversationViewRef}
|
ref={conversationViewRef}
|
||||||
className="drawer-content relative w-full h-full max-h-full flex flex-col justify-start items-start overflow-y-auto bg-white"
|
className={`${
|
||||||
|
layoutStore.showSidebar && "sm:pl-80"
|
||||||
|
} relative w-full h-full max-h-full flex flex-col justify-start items-start overflow-y-auto bg-white transition-all duration-300`}
|
||||||
>
|
>
|
||||||
<div className="sticky top-0 z-1 bg-white w-full flex flex-col justify-start items-start">
|
<div className="sticky top-0 z-1 bg-white w-full flex flex-col justify-start items-start">
|
||||||
<DataStorageBanner />
|
<DataStorageBanner />
|
||||||
@ -225,7 +229,7 @@ const ConversationView = () => {
|
|||||||
<div className="sticky bottom-0 w-full max-w-4xl py-2 px-4 sm:px-8 mx-auto bg-white bg-opacity-80 backdrop-blur">
|
<div className="sticky bottom-0 w-full max-w-4xl py-2 px-4 sm:px-8 mx-auto bg-white bg-opacity-80 backdrop-blur">
|
||||||
<MessageTextarea disabled={lastMessage?.status === "LOADING"} sendMessage={sendMessageToCurrentConversation} />
|
<MessageTextarea disabled={lastMessage?.status === "LOADING"} sendMessage={sendMessageToCurrentConversation} />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ import { NextPage } from "next";
|
|||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
import Script from "next/script";
|
import Script from "next/script";
|
||||||
import React, { useEffect } from "react";
|
import React from "react";
|
||||||
import { ResponsiveWidth, useLayoutStore } from "@/store";
|
|
||||||
|
|
||||||
// Use dynamic import to avoid page hydrated.
|
// Use dynamic import to avoid page hydrated.
|
||||||
// reference: https://github.com/pmndrs/zustand/issues/1145#issuecomment-1316431268
|
// reference: https://github.com/pmndrs/zustand/issues/1145#issuecomment-1316431268
|
||||||
@ -18,25 +17,6 @@ const QueryDrawer = dynamic(() => import("@/components/QueryDrawer"), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const IndexPage: NextPage = () => {
|
const IndexPage: NextPage = () => {
|
||||||
const layoutStore = useLayoutStore();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleWindowResize = () => {
|
|
||||||
if (window.innerWidth < ResponsiveWidth.lg) {
|
|
||||||
layoutStore.toggleSidebar(false);
|
|
||||||
} else {
|
|
||||||
layoutStore.toggleSidebar(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleWindowResize();
|
|
||||||
window.addEventListener("resize", handleWindowResize);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("resize", handleWindowResize);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Head>
|
<Head>
|
||||||
@ -53,17 +33,9 @@ const IndexPage: NextPage = () => {
|
|||||||
|
|
||||||
<h1 className="sr-only">SQL Chat</h1>
|
<h1 className="sr-only">SQL Chat</h1>
|
||||||
|
|
||||||
<main className="drawer drawer-mobile w-full h-full">
|
<main className="w-full h-full flex flex-row">
|
||||||
<input
|
|
||||||
id="connection-drawer"
|
|
||||||
type="checkbox"
|
|
||||||
className="drawer-toggle"
|
|
||||||
checked={layoutStore.showSidebar}
|
|
||||||
onChange={(e) => layoutStore.toggleSidebar(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<ConversationView />
|
|
||||||
{/* Render sidebar after chatview to prevent z-index problem */}
|
|
||||||
<ConnectionSidebar />
|
<ConnectionSidebar />
|
||||||
|
<ConversationView />
|
||||||
<QueryDrawer />
|
<QueryDrawer />
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
@ -4,16 +4,18 @@ import { create } from "zustand";
|
|||||||
// reference: https://tailwindcss.com/docs/responsive-design
|
// reference: https://tailwindcss.com/docs/responsive-design
|
||||||
export enum ResponsiveWidth {
|
export enum ResponsiveWidth {
|
||||||
sm = 640,
|
sm = 640,
|
||||||
lg = 1024,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LayoutState {
|
interface LayoutState {
|
||||||
showSidebar: boolean;
|
showSidebar: boolean;
|
||||||
|
isMobileView: boolean;
|
||||||
toggleSidebar: (show?: boolean) => void;
|
toggleSidebar: (show?: boolean) => void;
|
||||||
|
setIsMobileView: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useLayoutStore = create<LayoutState>()((set) => ({
|
export const useLayoutStore = create<LayoutState>()((set) => ({
|
||||||
showSidebar: true,
|
showSidebar: true,
|
||||||
|
isMobileView: false,
|
||||||
toggleSidebar: (show) => {
|
toggleSidebar: (show) => {
|
||||||
if (isUndefined(show)) {
|
if (isUndefined(show)) {
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
@ -27,4 +29,10 @@ export const useLayoutStore = create<LayoutState>()((set) => ({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setIsMobileView: (value) => {
|
||||||
|
set((state) => ({
|
||||||
|
...state,
|
||||||
|
isMobileView: value,
|
||||||
|
}));
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
Reference in New Issue
Block a user