chore: update responsible connection sidebar style

This commit is contained in:
Steven
2023-04-07 20:04:23 +08:00
parent 8ca20535ef
commit 84413b7201
5 changed files with 56 additions and 43 deletions

View File

@ -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

View File

@ -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>

View File

@ -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>
); );
}; };

View File

@ -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>

View File

@ -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,
}));
},
})); }));