mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 01:10:14 +01:00
style(Nav): improve Nav transition for open/close (#652)
* Revert "Animated sidebar (#649)"
This reverts commit dd19323280.
* in progress
* style(Nav): improve transition for Nav
This commit is contained in:
parent
dd19323280
commit
15987abe0a
5 changed files with 74 additions and 124 deletions
|
|
@ -12,7 +12,7 @@ export default function MobileNav({ setNavVisible }) {
|
||||||
<div className="fixed left-0 right-0 top-0 z-10 flex items-center border-b border-white/20 bg-gray-800 pl-1 pt-1 text-gray-200 sm:pl-3 md:hidden">
|
<div className="fixed left-0 right-0 top-0 z-10 flex items-center border-b border-white/20 bg-gray-800 pl-1 pt-1 text-gray-200 sm:pl-3 md:hidden">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="-ml-0.5 -mt-0.5 inline-flex h-10 w-10 items-center justify-center rounded-md hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white dark:hover:text-white"
|
className="-ml-0.5 -mt-0.5 inline-flex h-10 w-10 items-center justify-center rounded-md hover:text-gray-900 focus:outline-none focus:ring-0 focus:ring-inset focus:ring-white dark:hover:text-white"
|
||||||
onClick={() => setNavVisible((prev) => !prev)}
|
onClick={() => setNavVisible((prev) => !prev)}
|
||||||
>
|
>
|
||||||
<span className="sr-only">Open sidebar</span>
|
<span className="sr-only">Open sidebar</span>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useGetConversationsQuery, useSearchQuery } from '@librechat/data-provider';
|
import { useGetConversationsQuery, useSearchQuery } from '@librechat/data-provider';
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
|
|
@ -7,33 +6,12 @@ import Conversations from '../Conversations';
|
||||||
import NavLinks from './NavLinks';
|
import NavLinks from './NavLinks';
|
||||||
import NewChat from './NewChat';
|
import NewChat from './NewChat';
|
||||||
import Pages from '../Conversations/Pages';
|
import Pages from '../Conversations/Pages';
|
||||||
import Panel from '../svg/Panel';
|
import { Panel, Spinner } from '~/components';
|
||||||
import Spinner from '../svg/Spinner';
|
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
import store from '~/store';
|
import store from '~/store';
|
||||||
import { useAuthContext } from '~/hooks/AuthContext';
|
import { useAuthContext } from '~/hooks/AuthContext';
|
||||||
import useDebounce from '~/hooks/useDebounce';
|
import useDebounce from '~/hooks/useDebounce';
|
||||||
|
|
||||||
// import resolveConfig from 'tailwindcss/resolveConfig';
|
|
||||||
// const tailwindConfig = import('../../../tailwind.config.cjs');
|
|
||||||
// const fullConfig = resolveConfig(tailwindConfig);
|
|
||||||
|
|
||||||
// export const getBreakpointValue = (value) =>
|
|
||||||
// +fullConfig.theme.screens[value].slice(0, fullConfig.theme.screens[value].indexOf('px'));
|
|
||||||
|
|
||||||
// export const getCurrentBreakpoint = () => {
|
|
||||||
// let currentBreakpoint;
|
|
||||||
// let biggestBreakpointValue = 0;
|
|
||||||
// for (const breakpoint of Object.keys(fullConfig.theme.screens)) {
|
|
||||||
// const breakpointValue = getBreakpointValue(breakpoint);
|
|
||||||
// if (breakpointValue > biggestBreakpointValue && window.innerWidth >= breakpointValue) {
|
|
||||||
// biggestBreakpointValue = breakpointValue;
|
|
||||||
// currentBreakpoint = breakpoint;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return currentBreakpoint;
|
|
||||||
// };
|
|
||||||
|
|
||||||
export default function Nav({ navVisible, setNavVisible }) {
|
export default function Nav({ navVisible, setNavVisible }) {
|
||||||
const [isHovering, setIsHovering] = useState(false);
|
const [isHovering, setIsHovering] = useState(false);
|
||||||
const { isAuthenticated } = useAuthContext();
|
const { isAuthenticated } = useAuthContext();
|
||||||
|
|
@ -140,34 +118,13 @@ export default function Nav({ navVisible, setNavVisible }) {
|
||||||
if (!isSearching) {
|
if (!isSearching) {
|
||||||
getConversationsQuery.refetch();
|
getConversationsQuery.refetch();
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [pageNumber, conversationId, refreshConversationsHint]);
|
}, [pageNumber, conversationId, refreshConversationsHint]);
|
||||||
|
|
||||||
const toggleNavVisible = () => {
|
const toggleNavVisible = () => {
|
||||||
setNavVisible((prev) => !prev);
|
setNavVisible((prev) => !prev);
|
||||||
};
|
};
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// let currentBreakpoint = getCurrentBreakpoint();
|
|
||||||
// if (currentBreakpoint === 'sm') {
|
|
||||||
// setNavVisible(false);
|
|
||||||
// } else {
|
|
||||||
// setNavVisible(true);
|
|
||||||
// }
|
|
||||||
// }, [conversationId, setNavVisible]);
|
|
||||||
|
|
||||||
const isMobile = () => {
|
|
||||||
const userAgent = typeof window.navigator === 'undefined' ? '' : navigator.userAgent;
|
|
||||||
const mobileRegex =
|
|
||||||
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i;
|
|
||||||
return mobileRegex.test(userAgent);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (isMobile()) {
|
|
||||||
setNavVisible(false);
|
|
||||||
}
|
|
||||||
}, [conversationId, setNavVisible]);
|
|
||||||
|
|
||||||
const containerClasses =
|
const containerClasses =
|
||||||
getConversationsQuery.isLoading && pageNumber === 1
|
getConversationsQuery.isLoading && pageNumber === 1
|
||||||
? 'flex flex-col gap-2 text-gray-100 text-sm h-full justify-center items-center'
|
? 'flex flex-col gap-2 text-gray-100 text-sm h-full justify-center items-center'
|
||||||
|
|
@ -176,69 +133,74 @@ export default function Nav({ navVisible, setNavVisible }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className={
|
className="nav active dark flex-shrink-0 overflow-x-hidden bg-gray-900 transition-all duration-200 ease-in-out"
|
||||||
'nav dark bg-gray-900 transition-all duration-500 md:inset-y-0' +
|
style={{
|
||||||
(navVisible ? ' active' : '')
|
width: navVisible ? '260px' : '0px',
|
||||||
}
|
visibility: navVisible ? 'visible' : 'hidden',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex h-full min-h-0 flex-col ">
|
<div className="h-full w-[260px]">
|
||||||
<div className="scrollbar-trigger relative flex h-full w-full flex-1 items-start border-white/20">
|
<div className="flex h-full min-h-0 flex-col ">
|
||||||
<nav className="relative flex h-full flex-1 flex-col space-y-1 p-2">
|
<div className="scrollbar-trigger relative flex h-full w-full flex-1 items-start border-white/20">
|
||||||
<div className="mb-2 flex h-11 flex-row">
|
<nav className="relative flex h-full flex-1 flex-col space-y-1 p-2">
|
||||||
<NewChat />
|
<div className="mb-2 flex h-11 flex-row">
|
||||||
<button
|
<NewChat />
|
||||||
type="button"
|
<button
|
||||||
className={cn(
|
type="button"
|
||||||
'nav-close-button inline-flex h-11 w-11 items-center justify-center rounded-md border border-white/20 text-white hover:bg-gray-500/10',
|
className={cn(
|
||||||
)}
|
'nav-close-button inline-flex h-11 w-11 items-center justify-center rounded-md border border-white/20 text-white hover:bg-gray-500/10',
|
||||||
onClick={toggleNavVisible}
|
)}
|
||||||
>
|
onClick={toggleNavVisible}
|
||||||
<span className="sr-only">Close sidebar</span>
|
>
|
||||||
<Panel open={false} />
|
<span className="sr-only">Close sidebar</span>
|
||||||
</button>
|
<Panel open={false} />
|
||||||
</div>
|
</button>
|
||||||
<div
|
|
||||||
className={`flex-1 flex-col overflow-y-auto ${
|
|
||||||
isHovering ? '' : 'scrollbar-transparent'
|
|
||||||
} border-b border-white/20`}
|
|
||||||
onMouseEnter={() => setIsHovering(true)}
|
|
||||||
onMouseLeave={() => setIsHovering(false)}
|
|
||||||
ref={containerRef}
|
|
||||||
>
|
|
||||||
<div className={containerClasses}>
|
|
||||||
{(getConversationsQuery.isLoading && pageNumber === 1) || isFetching ? (
|
|
||||||
<Spinner />
|
|
||||||
) : (
|
|
||||||
<Conversations
|
|
||||||
conversations={conversations}
|
|
||||||
conversationId={conversationId}
|
|
||||||
moveToTop={moveToTop}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Pages
|
|
||||||
pageNumber={pageNumber}
|
|
||||||
pages={pages}
|
|
||||||
nextPage={nextPage}
|
|
||||||
previousPage={previousPage}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div
|
||||||
<NavLinks clearSearch={clearSearch} isSearchEnabled={isSearchEnabled} />
|
className={`flex-1 flex-col overflow-y-auto ${
|
||||||
</nav>
|
isHovering ? '' : 'scrollbar-transparent'
|
||||||
|
} border-b border-white/20`}
|
||||||
|
onMouseEnter={() => setIsHovering(true)}
|
||||||
|
onMouseLeave={() => setIsHovering(false)}
|
||||||
|
ref={containerRef}
|
||||||
|
>
|
||||||
|
<div className={containerClasses}>
|
||||||
|
{(getConversationsQuery.isLoading && pageNumber === 1) || isFetching ? (
|
||||||
|
<Spinner />
|
||||||
|
) : (
|
||||||
|
<Conversations
|
||||||
|
conversations={conversations}
|
||||||
|
conversationId={conversationId}
|
||||||
|
moveToTop={moveToTop}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Pages
|
||||||
|
pageNumber={pageNumber}
|
||||||
|
pages={pages}
|
||||||
|
nextPage={nextPage}
|
||||||
|
previousPage={previousPage}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NavLinks clearSearch={clearSearch} isSearchEnabled={isSearchEnabled} />
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!navVisible && (
|
{!navVisible && (
|
||||||
<button
|
<div className="absolute left-2 top-2 z-10 hidden md:inline-block">
|
||||||
type="button"
|
<button
|
||||||
className="nav-open-button fixed left-2 top-0.5 z-10 mt-1 flex h-11 w-11 cursor-pointer items-center gap-3 rounded-md border border-black/10 bg-white p-3 text-sm text-gray-900 transition-colors duration-200 hover:bg-gray-50 dark:border-white/20 dark:bg-gray-800 dark:text-gray-100 dark:hover:bg-gray-700"
|
type="button"
|
||||||
onClick={toggleNavVisible}
|
className="nav-open-button flex h-11 cursor-pointer items-center gap-3 rounded-md border border-black/10 bg-white p-3 text-sm text-black transition-colors duration-200 hover:bg-gray-50 dark:border-white/20 dark:bg-gray-800 dark:hover:bg-gray-700"
|
||||||
>
|
onClick={toggleNavVisible}
|
||||||
<div className="flex items-center justify-center">
|
>
|
||||||
<span className="sr-only">Open sidebar</span>
|
<div className="flex items-center justify-center">
|
||||||
<Panel open={true} />
|
<span className="sr-only">Open sidebar</span>
|
||||||
</div>
|
<Panel open={true} />
|
||||||
</button>
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={'nav-mask' + (navVisible ? ' active' : '')} onClick={toggleNavVisible}></div>
|
<div className={'nav-mask' + (navVisible ? ' active' : '')} onClick={toggleNavVisible}></div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
export { default as Plugin } from './Plugin';
|
export { default as Plugin } from './Plugin';
|
||||||
export { default as GPTIcon } from './GPTIcon';
|
export { default as GPTIcon } from './GPTIcon';
|
||||||
export { default as CogIcon } from './CogIcon';
|
export { default as CogIcon } from './CogIcon';
|
||||||
|
export { default as Panel } from './Panel';
|
||||||
export { default as Spinner } from './Spinner';
|
export { default as Spinner } from './Spinner';
|
||||||
export { default as MessagesSquared } from './MessagesSquared';
|
export { default as MessagesSquared } from './MessagesSquared';
|
||||||
export { default as StopGeneratingIcon } from './StopGeneratingIcon';
|
export { default as StopGeneratingIcon } from './StopGeneratingIcon';
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,6 @@
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-open-button {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-close-button {
|
.nav-close-button {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
@ -15,11 +10,9 @@
|
||||||
.nav {
|
.nav {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 40;
|
z-index: 40;
|
||||||
left: calc(-100%);
|
|
||||||
top: 0;
|
top: 0;
|
||||||
width: calc(100% - 60px);
|
|
||||||
|
|
||||||
max-width: 260px;
|
/* max-width: 260px; */
|
||||||
|
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
@ -27,20 +20,10 @@
|
||||||
|
|
||||||
.nav.active {
|
.nav.active {
|
||||||
position: relative;
|
position: relative;
|
||||||
animation: nav-open 1000ms ease-in-out forwards;
|
|
||||||
left: 0;
|
left: 0;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes nav-open {
|
|
||||||
0% {
|
|
||||||
width: 0%;
|
|
||||||
}
|
|
||||||
100%{
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-mask.active {
|
.nav-mask.active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
|
@ -48,9 +31,9 @@
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.nav {
|
.nav {
|
||||||
width: calc(100% - 60px);
|
width: calc(100% - 10px) ;
|
||||||
|
transition: all 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-mask {
|
.nav-mask {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 35;
|
z-index: 35;
|
||||||
|
|
@ -62,9 +45,14 @@
|
||||||
padding-left: 420px;
|
padding-left: 420px;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
transition: all 0.5s;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-open-button {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.nav-mask.active {
|
.nav-mask.active {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
|
@ -72,7 +60,6 @@
|
||||||
|
|
||||||
.nav.active {
|
.nav.active {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
animation: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue