Feat/improve mobile display (#843)
* Ok 1 * Finished * Fix PR * Fix PR * Fix desktop * Fix * Fix absolute listen click outside * console.log * Fix according to code review --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -4,6 +4,7 @@ import { useRecoilValue } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import { AutosizeTextInput } from '@/ui/input/components/AutosizeTextInput';
|
||||
import { CommentThread, useCreateCommentMutation } from '~/generated/graphql';
|
||||
import { isNonEmptyString } from '~/utils/isNonEmptyString';
|
||||
@ -38,7 +39,10 @@ const StyledCommentActionBar = styled.div`
|
||||
border-top: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
display: flex;
|
||||
padding: 16px 24px 16px 48px;
|
||||
width: calc(${({ theme }) => theme.rightDrawerWidth} - 48px - 24px);
|
||||
width: calc(
|
||||
${({ theme }) => (useIsMobile() ? '100%' : theme.rightDrawerWidth)} - 48px -
|
||||
24px
|
||||
);
|
||||
`;
|
||||
|
||||
const StyledThreadCommentTitle = styled.div`
|
||||
|
||||
@ -12,7 +12,7 @@ import { CompanyChip } from '@/companies/components/CompanyChip';
|
||||
import { useFilteredSearchCompanyQuery } from '@/companies/queries';
|
||||
import { PersonChip } from '@/people/components/PersonChip';
|
||||
import { useFilteredSearchPeopleQuery } from '@/people/queries';
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
import { usePreviousHotkeyScope } from '@/ui/hotkey/hooks/usePreviousHotkeyScope';
|
||||
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
|
||||
import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope';
|
||||
@ -194,7 +194,7 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
|
||||
placement: 'bottom-start',
|
||||
});
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [refs.floating, refs.domReference],
|
||||
callback: () => {
|
||||
exitEditMode();
|
||||
|
||||
@ -9,6 +9,7 @@ import { CommentThreadTypeDropdown } from '@/activities/components/CommentThread
|
||||
import { GET_COMMENT_THREAD } from '@/activities/queries';
|
||||
import { PropertyBox } from '@/ui/editable-field/property-box/components/PropertyBox';
|
||||
import { PropertyBoxItem } from '@/ui/editable-field/property-box/components/PropertyBoxItem';
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import { IconArrowUpRight } from '@/ui/icon/index';
|
||||
import {
|
||||
useGetCommentThreadQuery,
|
||||
@ -43,7 +44,8 @@ const StyledTopContainer = styled.div`
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-bottom: ${({ theme }) =>
|
||||
useIsMobile() ? 'none' : `1px solid ${theme.border.color.medium}`};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
@ -187,7 +189,6 @@ export function CommentThread({
|
||||
onChange={updateTitleFromBody}
|
||||
/>
|
||||
</StyledUpperPartContainer>
|
||||
|
||||
{showComment && (
|
||||
<CommentThreadComments
|
||||
commentThread={{
|
||||
|
||||
@ -7,6 +7,7 @@ import { useOpenCommentThreadRightDrawer } from '@/activities/hooks/useOpenComme
|
||||
import { useOpenCreateCommentThreadDrawer } from '@/activities/hooks/useOpenCreateCommentThreadDrawer';
|
||||
import { CommentableEntity } from '@/activities/types/CommentableEntity';
|
||||
import { CommentThreadForDrawer } from '@/activities/types/CommentThreadForDrawer';
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import { IconNotes } from '@/ui/icon/index';
|
||||
import {
|
||||
ActivityType,
|
||||
@ -23,21 +24,26 @@ import { OverflowingTextWithTooltip } from '../../../ui/tooltip/OverflowingTextW
|
||||
const StyledMainContainer = styled.div`
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
border-top: ${({ theme }) =>
|
||||
useIsMobile() ? `1px solid ${theme.border.color.medium}` : 'none'};
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const StyledTimelineContainer = styled.div`
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
justify-content: flex-start;
|
||||
overflow-y: auto;
|
||||
|
||||
padding: 12px 16px 12px 16px;
|
||||
`;
|
||||
|
||||
@ -175,9 +181,13 @@ const StyledTooltip = styled(Tooltip)`
|
||||
const StyledTopActionBar = styled.div`
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
backdrop-filter: blur(5px);
|
||||
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
|
||||
border-top-right-radius: 8px;
|
||||
backdrop-filter: ${() => (useIsMobile() ? 'none' : `blur(5px)`)};
|
||||
|
||||
border-bottom: ${({ theme }) =>
|
||||
useIsMobile() ? 'none' : `1px solid ${theme.border.color.medium}`};
|
||||
|
||||
border-top-right-radius: ${() => (useIsMobile() ? 'none' : `8px`)};
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
left: 0px;
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { Command } from 'cmdk';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
|
||||
export const StyledDialog = styled(Command.Dialog)`
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
@ -13,8 +15,9 @@ export const StyledDialog = styled(Command.Dialog)`
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
position: fixed;
|
||||
top: 30%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
transform: ${() =>
|
||||
useIsMobile() ? 'translateX(-49.5%)' : 'translateX(-50%)'};
|
||||
width: ${() => (useIsMobile() ? 'calc(100% - 40px)' : '100%')};
|
||||
z-index: 1000;
|
||||
`;
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
} from '@/ui/icon/index';
|
||||
import NavItem from '@/ui/navbar/components/NavItem';
|
||||
import NavTitle from '@/ui/navbar/components/NavTitle';
|
||||
import SubNavbar from '@/ui/navbar/components/SubNavbar';
|
||||
import SubMenuNavbar from '@/ui/navbar/components/SubMenuNavbar';
|
||||
|
||||
export function SettingsNavbar() {
|
||||
const theme = useTheme();
|
||||
@ -24,62 +24,60 @@ export function SettingsNavbar() {
|
||||
}, [signOut]);
|
||||
|
||||
return (
|
||||
<SubNavbar backButtonTitle="Settings">
|
||||
<>
|
||||
<NavTitle label="User" />
|
||||
<NavItem
|
||||
label="Profile"
|
||||
to="/settings/profile"
|
||||
icon={<IconUser size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/profile').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavItem
|
||||
label="Experience"
|
||||
to="/settings/profile/experience"
|
||||
icon={<IconColorSwatch size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/profile/experience').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavTitle label="Workspace" />
|
||||
<NavItem
|
||||
label="Members"
|
||||
to="/settings/workspace-members"
|
||||
icon={<IconUsers size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/workspace-members').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavItem
|
||||
label="General"
|
||||
to="/settings/workspace"
|
||||
icon={<IconSettings size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/workspace').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavTitle label="Other" />
|
||||
<NavItem
|
||||
label="Logout"
|
||||
onClick={handleLogout}
|
||||
icon={<IconLogout size={theme.icon.size.md} />}
|
||||
danger={true}
|
||||
/>
|
||||
</>
|
||||
</SubNavbar>
|
||||
<SubMenuNavbar backButtonTitle="Settings">
|
||||
<NavTitle label="User" />
|
||||
<NavItem
|
||||
label="Profile"
|
||||
to="/settings/profile"
|
||||
icon={<IconUser size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/profile').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavItem
|
||||
label="Experience"
|
||||
to="/settings/profile/experience"
|
||||
icon={<IconColorSwatch size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/profile/experience').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavTitle label="Workspace" />
|
||||
<NavItem
|
||||
label="Members"
|
||||
to="/settings/workspace-members"
|
||||
icon={<IconUsers size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/workspace-members').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavItem
|
||||
label="General"
|
||||
to="/settings/workspace"
|
||||
icon={<IconSettings size={theme.icon.size.md} />}
|
||||
active={
|
||||
!!useMatch({
|
||||
path: useResolvedPath('/settings/workspace').pathname,
|
||||
end: true,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<NavTitle label="Other" />
|
||||
<NavItem
|
||||
label="Logout"
|
||||
onClick={handleLogout}
|
||||
icon={<IconLogout size={theme.icon.size.md} />}
|
||||
danger={true}
|
||||
/>
|
||||
</SubMenuNavbar>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { ReactElement, useRef } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
|
||||
import { overlayBackground } from '@/ui/themes/effects';
|
||||
|
||||
@ -43,7 +43,7 @@ export function BoardCardEditableFieldEditMode({
|
||||
}: OwnProps) {
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [wrapperRef],
|
||||
callback: () => {
|
||||
onExit();
|
||||
|
||||
@ -7,7 +7,7 @@ import { DropdownMenu } from '@/ui/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSelectableItem } from '@/ui/dropdown/components/DropdownMenuSelectableItem';
|
||||
import DropdownButton from '@/ui/filter-n-sort/components/DropdownButton';
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
|
||||
import { BoardColumnEditTitleMenu } from './BoardColumnEditTitleMenu';
|
||||
|
||||
@ -35,7 +35,7 @@ export function BoardColumnMenu({
|
||||
const [openMenu, setOpenMenu] = useState('actions');
|
||||
const boardColumnMenuRef = useRef(null);
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [boardColumnMenuRef],
|
||||
callback: onClose,
|
||||
});
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
|
||||
|
||||
import { EditableFieldHotkeyScope } from '../types/EditableFieldHotkeyScope';
|
||||
@ -12,7 +12,7 @@ export function useRegisterCloseFieldHandlers(
|
||||
) {
|
||||
const { closeEditableField, isFieldInEditMode } = useEditableField();
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [wrapperRef],
|
||||
callback: () => {
|
||||
if (isFieldInEditMode) {
|
||||
|
||||
@ -2,7 +2,7 @@ import { useRef } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { DropdownMenu } from '../../dropdown/components/DropdownMenu';
|
||||
import { useListenClickOutsideArrayOfRef } from '../../hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '../../hooks/useListenClickOutside';
|
||||
|
||||
export const StyledDropdownMenuContainer = styled.ul`
|
||||
position: absolute;
|
||||
@ -19,7 +19,7 @@ export function DropdownMenuContainer({
|
||||
}) {
|
||||
const dropdownRef = useRef(null);
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [dropdownRef],
|
||||
callback: () => {
|
||||
onClose?.();
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { useRef } from 'react';
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { useListenClickOutsideArrayOfRef } from '../useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '../useListenClickOutside';
|
||||
|
||||
const onOutsideClick = jest.fn();
|
||||
|
||||
function TestComponentDomMode() {
|
||||
const buttonRef = useRef(null);
|
||||
const buttonRef2 = useRef(null);
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [buttonRef, buttonRef2],
|
||||
callback: onOutsideClick,
|
||||
});
|
||||
@ -22,7 +22,7 @@ function TestComponentDomMode() {
|
||||
);
|
||||
}
|
||||
|
||||
test('useListenClickOutsideArrayOfRef hook works in dom mode', async () => {
|
||||
test('useListenClickOutside hook works in dom mode', async () => {
|
||||
const { getByText } = render(<TestComponentDomMode />);
|
||||
const inside = getByText('Inside');
|
||||
const inside2 = getByText('Inside 2');
|
||||
|
||||
7
front/src/modules/ui/hooks/useIsMobile.ts
Normal file
7
front/src/modules/ui/hooks/useIsMobile.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { useMediaQuery } from 'react-responsive';
|
||||
|
||||
import { MOBILE_VIEWPORT } from '@/ui/themes/themes';
|
||||
|
||||
export function useIsMobile() {
|
||||
return useMediaQuery({ query: `(max-width: ${MOBILE_VIEWPORT}px)` });
|
||||
}
|
||||
@ -5,7 +5,7 @@ export enum ClickOutsideMode {
|
||||
dom = 'dom',
|
||||
}
|
||||
|
||||
export function useListenClickOutsideArrayOfRef<T extends Element>({
|
||||
export function useListenClickOutside<T extends Element>({
|
||||
refs,
|
||||
callback,
|
||||
mode = ClickOutsideMode.dom,
|
||||
@ -37,9 +37,13 @@ export function useListenClickOutsideArrayOfRef<T extends Element>({
|
||||
const { x, y, width, height } = ref.current.getBoundingClientRect();
|
||||
|
||||
const clientX =
|
||||
'clientX' in event ? event.clientX : event.touches[0].clientX;
|
||||
'clientX' in event
|
||||
? event.clientX
|
||||
: event.changedTouches[0].clientX;
|
||||
const clientY =
|
||||
'clientY' in event ? event.clientY : event.touches[0].clientY;
|
||||
'clientY' in event
|
||||
? event.clientY
|
||||
: event.changedTouches[0].clientY;
|
||||
|
||||
if (
|
||||
clientX < x ||
|
||||
@ -1,5 +1,3 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { AnimatePresence, LayoutGroup } from 'framer-motion';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
@ -11,10 +9,9 @@ import { CommandMenu } from '@/command-menu/components/CommandMenu';
|
||||
import { NavbarAnimatedContainer } from '@/ui/navbar/components/NavbarAnimatedContainer';
|
||||
import { MOBILE_VIEWPORT } from '@/ui/themes/themes';
|
||||
import { AppNavbar } from '~/AppNavbar';
|
||||
import { useIsMatchingLocation } from '~/hooks/useIsMatchingLocation';
|
||||
import { CompaniesMockMode } from '~/pages/companies/CompaniesMockMode';
|
||||
|
||||
import { AppPath } from '../../../types/AppPath';
|
||||
import { useAutoNavigateOnboarding } from '../hooks/useAutoNavigateOnboarding';
|
||||
import { isNavbarOpenedState } from '../states/isNavbarOpenedState';
|
||||
|
||||
const StyledLayout = styled.div`
|
||||
@ -46,72 +43,30 @@ type OwnProps = {
|
||||
};
|
||||
|
||||
export function DefaultLayout({ children }: OwnProps) {
|
||||
const navigate = useNavigate();
|
||||
const isMatchingLocation = useIsMatchingLocation();
|
||||
useAutoNavigateOnboarding();
|
||||
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
||||
useEffect(() => {
|
||||
const isMachinOngoingUserCreationRoute =
|
||||
isMatchingLocation(AppPath.SignUp) ||
|
||||
isMatchingLocation(AppPath.SignIn) ||
|
||||
isMatchingLocation(AppPath.Invite) ||
|
||||
isMatchingLocation(AppPath.Verify);
|
||||
|
||||
const isMatchingOnboardingRoute =
|
||||
isMatchingLocation(AppPath.SignUp) ||
|
||||
isMatchingLocation(AppPath.SignIn) ||
|
||||
isMatchingLocation(AppPath.Invite) ||
|
||||
isMatchingLocation(AppPath.Verify) ||
|
||||
isMatchingLocation(AppPath.CreateWorkspace) ||
|
||||
isMatchingLocation(AppPath.CreateProfile);
|
||||
|
||||
if (
|
||||
onboardingStatus === OnboardingStatus.OngoingUserCreation &&
|
||||
!isMachinOngoingUserCreationRoute
|
||||
) {
|
||||
navigate(AppPath.SignIn);
|
||||
} else if (
|
||||
onboardingStatus === OnboardingStatus.OngoingWorkspaceCreation &&
|
||||
!isMatchingLocation(AppPath.CreateWorkspace)
|
||||
) {
|
||||
navigate(AppPath.CreateWorkspace);
|
||||
} else if (
|
||||
onboardingStatus === OnboardingStatus.OngoingProfileCreation &&
|
||||
!isMatchingLocation(AppPath.CreateProfile)
|
||||
) {
|
||||
navigate(AppPath.CreateProfile);
|
||||
} else if (
|
||||
onboardingStatus === OnboardingStatus.Completed &&
|
||||
isMatchingOnboardingRoute
|
||||
) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [onboardingStatus, navigate, isMatchingLocation]);
|
||||
|
||||
return (
|
||||
<StyledLayout>
|
||||
<>
|
||||
<CommandMenu />
|
||||
<NavbarAnimatedContainer>
|
||||
<AppNavbar />
|
||||
</NavbarAnimatedContainer>
|
||||
<MainContainer>
|
||||
{onboardingStatus &&
|
||||
onboardingStatus !== OnboardingStatus.Completed ? (
|
||||
<>
|
||||
<CompaniesMockMode />
|
||||
<AnimatePresence mode="wait">
|
||||
<LayoutGroup>
|
||||
<AuthModal>{children}</AuthModal>
|
||||
</LayoutGroup>
|
||||
</AnimatePresence>
|
||||
</>
|
||||
) : (
|
||||
<>{children}</>
|
||||
)}
|
||||
</MainContainer>
|
||||
</>
|
||||
<CommandMenu />
|
||||
<NavbarAnimatedContainer>
|
||||
<AppNavbar />
|
||||
</NavbarAnimatedContainer>
|
||||
<MainContainer>
|
||||
{onboardingStatus && onboardingStatus !== OnboardingStatus.Completed ? (
|
||||
<>
|
||||
<CompaniesMockMode />
|
||||
<AnimatePresence mode="wait">
|
||||
<LayoutGroup>
|
||||
<AuthModal>{children}</AuthModal>
|
||||
</LayoutGroup>
|
||||
</AnimatePresence>
|
||||
</>
|
||||
) : (
|
||||
<>{children}</>
|
||||
)}
|
||||
</MainContainer>
|
||||
</StyledLayout>
|
||||
);
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ type LeftContainerProps = {
|
||||
|
||||
const StyledLeftContainer = styled.div<LeftContainerProps>`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
11
front/src/modules/ui/layout/components/ShowPageContainer.tsx
Normal file
11
front/src/modules/ui/layout/components/ShowPageContainer.tsx
Normal file
@ -0,0 +1,11 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
|
||||
export const ShowPageContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: ${() => (useIsMobile() ? 'column' : 'row')};
|
||||
gap: ${({ theme }) => (useIsMobile() ? theme.spacing(3) : '0')};
|
||||
height: 100%;
|
||||
width: ${() => (useIsMobile() ? `calc(100% - 2px);` : '100%')};
|
||||
`;
|
||||
@ -12,7 +12,7 @@ const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export function NoTopBarContainer({ children }: OwnProps) {
|
||||
export function SubMenuTopBarContainer({ children }: OwnProps) {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<RightDrawerContainer topMargin={16}>{children}</RightDrawerContainer>
|
||||
@ -0,0 +1,52 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useIsMatchingLocation } from '../../../../hooks/useIsMatchingLocation';
|
||||
import { useOnboardingStatus } from '../../../auth/hooks/useOnboardingStatus';
|
||||
import { OnboardingStatus } from '../../../auth/utils/getOnboardingStatus';
|
||||
import { AppPath } from '../../../types/AppPath';
|
||||
|
||||
export function useAutoNavigateOnboarding() {
|
||||
const navigate = useNavigate();
|
||||
const isMatchingLocation = useIsMatchingLocation();
|
||||
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
|
||||
useEffect(() => {
|
||||
const isMachinOngoingUserCreationRoute =
|
||||
isMatchingLocation(AppPath.SignUp) ||
|
||||
isMatchingLocation(AppPath.SignIn) ||
|
||||
isMatchingLocation(AppPath.Invite) ||
|
||||
isMatchingLocation(AppPath.Verify);
|
||||
|
||||
const isMatchingOnboardingRoute =
|
||||
isMatchingLocation(AppPath.SignUp) ||
|
||||
isMatchingLocation(AppPath.SignIn) ||
|
||||
isMatchingLocation(AppPath.Invite) ||
|
||||
isMatchingLocation(AppPath.Verify) ||
|
||||
isMatchingLocation(AppPath.CreateWorkspace) ||
|
||||
isMatchingLocation(AppPath.CreateProfile);
|
||||
|
||||
if (
|
||||
onboardingStatus === OnboardingStatus.OngoingUserCreation &&
|
||||
!isMachinOngoingUserCreationRoute
|
||||
) {
|
||||
navigate(AppPath.SignIn);
|
||||
} else if (
|
||||
onboardingStatus === OnboardingStatus.OngoingWorkspaceCreation &&
|
||||
!isMatchingLocation(AppPath.CreateWorkspace)
|
||||
) {
|
||||
navigate(AppPath.CreateWorkspace);
|
||||
} else if (
|
||||
onboardingStatus === OnboardingStatus.OngoingProfileCreation &&
|
||||
!isMatchingLocation(AppPath.CreateProfile)
|
||||
) {
|
||||
navigate(AppPath.CreateProfile);
|
||||
} else if (
|
||||
onboardingStatus === OnboardingStatus.Completed &&
|
||||
isMatchingOnboardingRoute
|
||||
) {
|
||||
navigate('/');
|
||||
}
|
||||
}, [onboardingStatus, navigate, isMatchingLocation]);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
export function useIsSubNavbarDisplayed() {
|
||||
export function useIsSubMenuNavbarDisplayed() {
|
||||
const currentPath = useLocation().pathname;
|
||||
return currentPath.match(/\/settings\//g) !== null;
|
||||
}
|
||||
@ -1,13 +1,23 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
|
||||
export const ShowPageLeftContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
border-bottom-left-radius: 8px;
|
||||
border-right: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-right: 1px solid
|
||||
${({ theme }) => {
|
||||
const isMobile = useIsMobile();
|
||||
return !isMobile ? theme.border.color.medium : 0;
|
||||
}};
|
||||
border-top-left-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
padding: 0px ${({ theme }) => theme.spacing(3)};
|
||||
width: 320px;
|
||||
width: ${({ theme }) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return isMobile ? `calc(100% - ${theme.spacing(6)})` : '320px';
|
||||
}};
|
||||
`;
|
||||
|
||||
@ -1,12 +1,16 @@
|
||||
import { ReactNode, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { IconButton } from '@/ui/button/components/IconButton';
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import { IconChevronLeft, IconPlus } from '@/ui/icon/index';
|
||||
import NavCollapseButton from '@/ui/navbar/components/NavCollapseButton';
|
||||
|
||||
import { navbarIconSize } from '../../../navbar/constants';
|
||||
import { OverflowingTextWithTooltip } from '../../../tooltip/OverflowingTextWithTooltip';
|
||||
import { isNavbarOpenedState } from '../../states/isNavbarOpenedState';
|
||||
|
||||
export const TOP_BAR_MIN_HEIGHT = 40;
|
||||
|
||||
@ -20,6 +24,7 @@ const TopBarContainer = styled.div`
|
||||
justify-content: space-between;
|
||||
min-height: ${TOP_BAR_MIN_HEIGHT}px;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
padding-left: 0;
|
||||
padding-right: ${({ theme }) => theme.spacing(3)};
|
||||
`;
|
||||
|
||||
@ -37,10 +42,22 @@ const TitleContainer = styled.div`
|
||||
max-width: 50%;
|
||||
`;
|
||||
|
||||
const TopBarButtonContainer = styled.div`
|
||||
margin-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const BackIconButton = styled(IconButton)`
|
||||
margin-right: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledTopBarIconTitleContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
title: string;
|
||||
hasBackButton?: boolean;
|
||||
@ -57,21 +74,38 @@ export function TopBar({
|
||||
const navigate = useNavigate();
|
||||
const navigateBack = useCallback(() => navigate(-1), [navigate]);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
const isNavbarOpened = useRecoilValue(isNavbarOpenedState);
|
||||
|
||||
const showNavCollapseButton = isMobile || !isNavbarOpened;
|
||||
|
||||
const iconSize = useIsMobile()
|
||||
? navbarIconSize.mobile
|
||||
: navbarIconSize.desktop;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TopBarContainer>
|
||||
<StyledLeftContainer>
|
||||
<NavCollapseButton hideIfOpen={true} />
|
||||
{hasBackButton && (
|
||||
<BackIconButton
|
||||
icon={<IconChevronLeft size={16} />}
|
||||
onClick={navigateBack}
|
||||
/>
|
||||
{showNavCollapseButton && (
|
||||
<TopBarButtonContainer>
|
||||
<NavCollapseButton direction="right" />
|
||||
</TopBarButtonContainer>
|
||||
)}
|
||||
{icon}
|
||||
<TitleContainer data-testid="top-bar-title">
|
||||
<OverflowingTextWithTooltip text={title} />
|
||||
</TitleContainer>
|
||||
{hasBackButton && (
|
||||
<TopBarButtonContainer>
|
||||
<BackIconButton
|
||||
icon={<IconChevronLeft size={iconSize} />}
|
||||
onClick={navigateBack}
|
||||
/>
|
||||
</TopBarButtonContainer>
|
||||
)}
|
||||
<StyledTopBarIconTitleContainer>
|
||||
{icon}
|
||||
<TitleContainer data-testid="top-bar-title">
|
||||
<OverflowingTextWithTooltip text={title} />
|
||||
</TitleContainer>
|
||||
</StyledTopBarIconTitleContainer>
|
||||
</StyledLeftContainer>
|
||||
{onAddButtonClick && (
|
||||
<IconButton
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import NavCollapseButton from '@/ui/navbar/components/NavCollapseButton';
|
||||
|
||||
const TitleAndCollapseContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
@ -22,7 +20,6 @@ type OwnProps = {
|
||||
export function TopTitle({ title }: OwnProps) {
|
||||
return (
|
||||
<TitleAndCollapseContainer>
|
||||
<NavCollapseButton hideIfOpen={true} hideOnDesktop={true} />
|
||||
<TitleContainer data-testid="top-bar-title">{title}</TitleContainer>
|
||||
</TitleAndCollapseContainer>
|
||||
);
|
||||
|
||||
@ -4,11 +4,11 @@ import NavItemsContainer from './NavItemsContainer';
|
||||
import NavWorkspaceButton from './NavWorkspaceButton';
|
||||
|
||||
type OwnProps = {
|
||||
children: JSX.Element;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: ${({ theme }) => theme.leftNavBarWidth};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export default function MainNavbar({ children }: OwnProps) {
|
||||
|
||||
@ -5,8 +5,6 @@ import { useRecoilState } from 'recoil';
|
||||
import { IconChevronLeft } from '@/ui/icon/index';
|
||||
import { isNavbarSwitchingSizeState } from '@/ui/layout/states/isNavbarSwitchingSizeState';
|
||||
|
||||
import NavCollapseButton from './NavCollapseButton';
|
||||
|
||||
type OwnProps = {
|
||||
title: string;
|
||||
};
|
||||
@ -50,7 +48,6 @@ export default function NavBackButton({ title }: OwnProps) {
|
||||
<IconChevronLeft />
|
||||
<span>{title}</span>
|
||||
</IconAndButtonContainer>
|
||||
<NavCollapseButton hideOnDesktop={true} />
|
||||
</StyledContainer>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import {
|
||||
IconLayoutSidebarLeftCollapse,
|
||||
IconLayoutSidebarRightCollapse,
|
||||
} from '@/ui/icon';
|
||||
import { isNavbarOpenedState } from '@/ui/layout/states/isNavbarOpenedState';
|
||||
import { MOBILE_VIEWPORT } from '@/ui/themes/themes';
|
||||
|
||||
const CollapseButton = styled.button<{ hideOnDesktop: boolean | undefined }>`
|
||||
import { navbarIconSize } from '../constants';
|
||||
|
||||
const CollapseButton = styled.button`
|
||||
align-items: center;
|
||||
background: inherit;
|
||||
border: 0;
|
||||
@ -25,46 +27,33 @@ const CollapseButton = styled.button<{ hideOnDesktop: boolean | undefined }>`
|
||||
justify-content: center;
|
||||
|
||||
padding: 0;
|
||||
|
||||
user-select: none;
|
||||
|
||||
width: 32px;
|
||||
|
||||
${(props) =>
|
||||
props.hideOnDesktop &&
|
||||
`@media (min-width: ${MOBILE_VIEWPORT}px) {
|
||||
display:none;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
type CollapseButtonProps = {
|
||||
hideIfOpen?: boolean;
|
||||
hideIfClosed?: boolean;
|
||||
hideOnDesktop?: boolean;
|
||||
direction?: 'left' | 'right';
|
||||
};
|
||||
|
||||
export default function NavCollapseButton({
|
||||
hideIfOpen,
|
||||
hideOnDesktop,
|
||||
direction = 'left',
|
||||
}: CollapseButtonProps) {
|
||||
const [isNavOpen, setIsNavOpen] = useRecoilState(isNavbarOpenedState);
|
||||
|
||||
const iconSize = useIsMobile()
|
||||
? navbarIconSize.mobile
|
||||
: navbarIconSize.desktop;
|
||||
|
||||
return (
|
||||
<>
|
||||
{isNavOpen && !hideIfOpen && (
|
||||
<CollapseButton
|
||||
onClick={() => setIsNavOpen(!isNavOpen)}
|
||||
hideOnDesktop={hideOnDesktop}
|
||||
>
|
||||
<IconLayoutSidebarLeftCollapse size={16} />
|
||||
{direction === 'left' ? (
|
||||
<CollapseButton onClick={() => setIsNavOpen(!isNavOpen)}>
|
||||
<IconLayoutSidebarLeftCollapse size={iconSize} />
|
||||
</CollapseButton>
|
||||
)}
|
||||
{!isNavOpen && (
|
||||
<CollapseButton
|
||||
onClick={() => setIsNavOpen(!isNavOpen)}
|
||||
hideOnDesktop={hideOnDesktop}
|
||||
>
|
||||
<IconLayoutSidebarRightCollapse size={16} />
|
||||
) : (
|
||||
<CollapseButton onClick={() => setIsNavOpen(!isNavOpen)}>
|
||||
<IconLayoutSidebarRightCollapse size={iconSize} />
|
||||
</CollapseButton>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import { MOBILE_VIEWPORT } from '@/ui/themes/themes';
|
||||
|
||||
import { isNavbarOpenedState } from '../../layout/states/isNavbarOpenedState';
|
||||
|
||||
type OwnProps = {
|
||||
label: string;
|
||||
to?: string;
|
||||
@ -79,21 +83,25 @@ const StyledSoonPill = styled.div`
|
||||
|
||||
function NavItem({ label, icon, to, onClick, active, danger, soon }: OwnProps) {
|
||||
const navigate = useNavigate();
|
||||
const [, setIsNavbarOpened] = useRecoilState(isNavbarOpenedState);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
function handleItemClick() {
|
||||
if (isMobile) {
|
||||
setIsNavbarOpened(false);
|
||||
}
|
||||
|
||||
const onItemClick = () => {
|
||||
if (onClick) {
|
||||
onClick();
|
||||
return;
|
||||
}
|
||||
if (to) {
|
||||
} else if (to) {
|
||||
navigate(to);
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledItem
|
||||
onClick={onItemClick}
|
||||
onClick={handleItemClick}
|
||||
active={active}
|
||||
aria-selected={active}
|
||||
danger={danger}
|
||||
|
||||
@ -65,7 +65,7 @@ function NavWorkspaceButton() {
|
||||
></StyledLogo>
|
||||
<StyledName>{currentWorkspace?.displayName ?? 'Twenty'}</StyledName>
|
||||
</LogoAndNameContainer>
|
||||
<NavCollapseButton />
|
||||
<NavCollapseButton direction="left" />
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,10 +3,12 @@ import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { useIsSubNavbarDisplayed } from '@/ui/layout/hooks/useIsSubNavbarDisplayed';
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import { useIsSubMenuNavbarDisplayed } from '@/ui/layout/hooks/useIsSubMenuNavbarDisplayed';
|
||||
import { isNavbarOpenedState } from '@/ui/layout/states/isNavbarOpenedState';
|
||||
import { isNavbarSwitchingSizeState } from '@/ui/layout/states/isNavbarSwitchingSizeState';
|
||||
import { MOBILE_VIEWPORT } from '@/ui/themes/themes';
|
||||
|
||||
import { leftNavbarWidth, leftSubMenuNavbarWidth } from '../constants';
|
||||
|
||||
const StyledNavbarContainer = styled(motion.div)`
|
||||
align-items: end;
|
||||
@ -15,35 +17,37 @@ const StyledNavbarContainer = styled(motion.div)`
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
width: ${(props) =>
|
||||
useRecoilValue(isNavbarOpenedState)
|
||||
? `calc(100% - ` + props.theme.spacing(4) + `)`
|
||||
: '0'};
|
||||
}
|
||||
`;
|
||||
|
||||
type NavbarProps = {
|
||||
children: React.ReactNode;
|
||||
layout?: string;
|
||||
};
|
||||
|
||||
export function NavbarAnimatedContainer({ children, layout }: NavbarProps) {
|
||||
export function NavbarAnimatedContainer({ children }: NavbarProps) {
|
||||
const isMenuOpened = useRecoilValue(isNavbarOpenedState);
|
||||
const [, setIsNavbarSwitchingSize] = useRecoilState(
|
||||
isNavbarSwitchingSizeState,
|
||||
);
|
||||
const isSubNavbarDisplayed = useIsSubNavbarDisplayed();
|
||||
const isInSubMenu = useIsSubMenuNavbarDisplayed();
|
||||
const theme = useTheme();
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const leftBarWidth = isInSubMenu
|
||||
? isMobile
|
||||
? leftSubMenuNavbarWidth.mobile
|
||||
: leftSubMenuNavbarWidth.desktop
|
||||
: isMobile
|
||||
? leftNavbarWidth.mobile
|
||||
: leftNavbarWidth.desktop;
|
||||
|
||||
return (
|
||||
<StyledNavbarContainer
|
||||
onAnimationComplete={() => {
|
||||
setIsNavbarSwitchingSize(false);
|
||||
}}
|
||||
animate={{
|
||||
width: isMenuOpened ? (isSubNavbarDisplayed ? '520px' : '220px') : '0',
|
||||
width: isMenuOpened ? leftBarWidth : '0',
|
||||
opacity: isMenuOpened ? 1 : 0,
|
||||
}}
|
||||
transition={{
|
||||
|
||||
@ -1,21 +1,25 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
|
||||
import { leftNavbarWidth } from '../constants';
|
||||
|
||||
import NavBackButton from './NavBackButton';
|
||||
import NavItemsContainer from './NavItemsContainer';
|
||||
|
||||
type OwnProps = {
|
||||
children: JSX.Element;
|
||||
children: React.ReactNode;
|
||||
backButtonTitle: string;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: ${({ theme }) => theme.spacing(6)};
|
||||
width: 220px;
|
||||
padding-top: ${({ theme }) => theme.spacing(2)};
|
||||
width: ${({ theme }) => (useIsMobile() ? '100%' : leftNavbarWidth.desktop)};
|
||||
`;
|
||||
|
||||
export default function SubNavbar({ children, backButtonTitle }: OwnProps) {
|
||||
export default function SubMenuNavbar({ children, backButtonTitle }: OwnProps) {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<NavBackButton title={backButtonTitle} />
|
||||
14
front/src/modules/ui/navbar/constants/index.ts
Normal file
14
front/src/modules/ui/navbar/constants/index.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export const leftNavbarWidth = {
|
||||
mobile: 'calc(100% - 16px)',
|
||||
desktop: '220px',
|
||||
};
|
||||
|
||||
export const leftSubMenuNavbarWidth = {
|
||||
mobile: 'calc(100% - 16px)',
|
||||
desktop: '520px',
|
||||
};
|
||||
|
||||
export const navbarIconSize = {
|
||||
mobile: 18,
|
||||
desktop: 16,
|
||||
};
|
||||
@ -6,7 +6,7 @@ import { DropdownMenuItem } from '@/ui/dropdown/components/DropdownMenuItem';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSearch } from '@/ui/dropdown/components/DropdownMenuSearch';
|
||||
import { DropdownMenuSeparator } from '@/ui/dropdown/components/DropdownMenuSeparator';
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
import { IconPlus } from '@/ui/icon';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
@ -46,7 +46,7 @@ export function SingleEntitySelect<
|
||||
|
||||
const showCreateButton = isDefined(onCreate) && searchFilter !== '';
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [containerRef],
|
||||
callback: () => {
|
||||
onCancel?.();
|
||||
|
||||
@ -5,13 +5,15 @@ import { motion } from 'framer-motion';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { Key } from 'ts-key-enum';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
import {
|
||||
ClickOutsideMode,
|
||||
useListenClickOutsideArrayOfRef,
|
||||
} from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
useListenClickOutside,
|
||||
} from '@/ui/hooks/useListenClickOutside';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { useScopedHotkeys } from '../../hotkey/hooks/useScopedHotkeys';
|
||||
import { leftNavbarWidth } from '../../navbar/constants';
|
||||
import { useRightDrawer } from '../hooks/useRightDrawer';
|
||||
import { isRightDrawerExpandedState } from '../states/isRightDrawerExpandedState';
|
||||
import { isRightDrawerOpenState } from '../states/isRightDrawerOpenState';
|
||||
@ -51,7 +53,7 @@ export function RightDrawer() {
|
||||
|
||||
const rightDrawerRef = useRef(null);
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [rightDrawerRef],
|
||||
callback: () => closeRightDrawer(),
|
||||
mode: ClickOutsideMode.absolute,
|
||||
@ -66,16 +68,22 @@ export function RightDrawer() {
|
||||
[setIsRightDrawerOpen],
|
||||
);
|
||||
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const rightDrawerWidthExpanded = `calc(100% - ${
|
||||
theme.leftNavBarWidth
|
||||
leftNavbarWidth.desktop
|
||||
} - ${theme.spacing(2)})`;
|
||||
|
||||
const rightDrawerWidth = isRightDrawerOpen
|
||||
? isRightDrawerExpanded
|
||||
? isMobile
|
||||
? '100%'
|
||||
: isRightDrawerExpanded
|
||||
? rightDrawerWidthExpanded
|
||||
: theme.rightDrawerWidth
|
||||
: '0';
|
||||
|
||||
console.log(rightDrawerWidth);
|
||||
|
||||
if (!isDefined(rightDrawerPage)) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useIsMobile } from '@/ui/hooks/useIsMobile';
|
||||
|
||||
import { RightDrawerTopBarCloseButton } from './RightDrawerTopBarCloseButton';
|
||||
import { RightDrawerTopBarExpandButton } from './RightDrawerTopBarExpandButton';
|
||||
|
||||
@ -20,10 +22,12 @@ const StyledRightDrawerTopBar = styled.div`
|
||||
`;
|
||||
|
||||
export function RightDrawerTopBar() {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<StyledRightDrawerTopBar>
|
||||
<RightDrawerTopBarCloseButton />
|
||||
<RightDrawerTopBarExpandButton />
|
||||
{!isMobile && <RightDrawerTopBarExpandButton />}
|
||||
</StyledRightDrawerTopBar>
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import styled from '@emotion/styled';
|
||||
|
||||
import { TableColumn } from '@/people/table/components/peopleColumns';
|
||||
import { SelectedSortType, SortType } from '@/ui/filter-n-sort/types/interface';
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
|
||||
import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
|
||||
import { TableHeader } from '../table-header/components/TableHeader';
|
||||
@ -90,7 +90,7 @@ export function EntityTable<SortField>({
|
||||
|
||||
const leaveTableFocus = useLeaveTableFocus();
|
||||
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [tableBodyRef],
|
||||
callback: () => {
|
||||
leaveTableFocus();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
|
||||
import { useListenClickOutside } from '@/ui/hooks/useListenClickOutside';
|
||||
import { useScopedHotkeys } from '@/ui/hotkey/hooks/useScopedHotkeys';
|
||||
|
||||
import { useMoveSoftFocus } from '../../hooks/useMoveSoftFocus';
|
||||
@ -14,7 +14,7 @@ export function useRegisterCloseCellHandlers(
|
||||
) {
|
||||
const { closeEditableCell } = useEditableCell();
|
||||
const { isCurrentCellInEditMode } = useCurrentCellEditMode();
|
||||
useListenClickOutsideArrayOfRef({
|
||||
useListenClickOutside({
|
||||
refs: [wrapperRef],
|
||||
callback: (event) => {
|
||||
if (isCurrentCellInEditMode) {
|
||||
|
||||
@ -37,7 +37,6 @@ const common = {
|
||||
checkboxColumnWidth: '32px',
|
||||
},
|
||||
rightDrawerWidth: '500px',
|
||||
leftNavBarWidth: '220px',
|
||||
clickableElementBackgroundTransition: 'background 0.1s ease',
|
||||
lastLayerZIndex: 2147483647,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user