Scroll behavior part 2 (#1304)
* Fix layout issues introduced by scroll behavior * Complete scrollbar work
This commit is contained in:
@ -1,12 +1,10 @@
|
||||
import React from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { ActivityCreateButton } from '@/activities/components/ActivityCreateButton';
|
||||
import { useOpenCreateActivityDrawer } from '@/activities/hooks/useOpenCreateActivityDrawer';
|
||||
import { ActivityForDrawer } from '@/activities/types/ActivityForDrawer';
|
||||
import { ActivityTargetableEntity } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { IconCircleDot } from '@/ui/icon';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import {
|
||||
ActivityType,
|
||||
@ -14,7 +12,7 @@ import {
|
||||
useGetActivitiesByTargetsQuery,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
import { TimelineActivity } from './TimelineActivity';
|
||||
import { TimelineItemsContainer } from './TimelineItemsContainer';
|
||||
|
||||
const StyledMainContainer = styled.div`
|
||||
align-items: flex-start;
|
||||
@ -22,26 +20,12 @@ const StyledMainContainer = styled.div`
|
||||
border-top: ${({ theme }) =>
|
||||
useIsMobile() ? `1px solid ${theme.border.color.medium}` : 'none'};
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const StyledTimelineContainer = styled.div`
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
justify-content: flex-start;
|
||||
overflow-y: ${() => (useIsMobile() ? 'none' : 'auto')};
|
||||
|
||||
padding: ${({ theme }) => theme.spacing(3)} ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledTimelineEmptyContainer = styled.div`
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
@ -85,17 +69,7 @@ const StyledTopActionBar = styled.div`
|
||||
top: 0px;
|
||||
`;
|
||||
|
||||
const StyledStartIcon = styled.div`
|
||||
align-self: flex-start;
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
display: flex;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
`;
|
||||
|
||||
export function Timeline({ entity }: { entity: ActivityTargetableEntity }) {
|
||||
const theme = useTheme();
|
||||
|
||||
const { data: queryResult, loading } = useGetActivitiesByTargetsQuery({
|
||||
variables: {
|
||||
activityTargetIds: [entity.id],
|
||||
@ -136,14 +110,7 @@ export function Timeline({ entity }: { entity: ActivityTargetableEntity }) {
|
||||
onTaskClick={() => openCreateActivity(ActivityType.Task, [entity])}
|
||||
/>
|
||||
</StyledTopActionBar>
|
||||
<StyledTimelineContainer>
|
||||
{activities.map((activity) => (
|
||||
<TimelineActivity key={activity.id} activity={activity} />
|
||||
))}
|
||||
<StyledStartIcon>
|
||||
<IconCircleDot size={theme.icon.size.lg} />
|
||||
</StyledStartIcon>
|
||||
</StyledTimelineContainer>
|
||||
<TimelineItemsContainer activities={activities} />
|
||||
</StyledMainContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { ActivityForDrawer } from '@/activities/types/ActivityForDrawer';
|
||||
import { IconCircleDot } from '@/ui/icon';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
|
||||
import { TimelineActivity } from './TimelineActivity';
|
||||
|
||||
const StyledTimelineContainer = styled.div`
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(1)};
|
||||
justify-content: flex-start;
|
||||
|
||||
padding: ${({ theme }) => theme.spacing(3)} ${({ theme }) => theme.spacing(4)};
|
||||
`;
|
||||
|
||||
const StyledStartIcon = styled.div`
|
||||
align-self: flex-start;
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
display: flex;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
`;
|
||||
|
||||
const StyledScrollWrapper = styled(ScrollWrapper)``;
|
||||
|
||||
export type TimelineItemsContainerProps = {
|
||||
activities: ActivityForDrawer[];
|
||||
};
|
||||
|
||||
export function TimelineItemsContainer({
|
||||
activities,
|
||||
}: TimelineItemsContainerProps) {
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<StyledScrollWrapper>
|
||||
<StyledTimelineContainer>
|
||||
{activities.map((activity) => (
|
||||
<TimelineActivity key={activity.id} activity={activity} />
|
||||
))}
|
||||
<StyledStartIcon>
|
||||
<IconCircleDot size={theme.icon.size.lg} />
|
||||
</StyledStartIcon>
|
||||
</StyledTimelineContainer>
|
||||
</StyledScrollWrapper>
|
||||
);
|
||||
}
|
||||
@ -29,6 +29,7 @@ const StyledListContainer = styled.div`
|
||||
align-items: flex-start;
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-radius: ${({ theme }) => theme.spacing(1)};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
|
||||
@ -14,8 +14,7 @@ import { BoardColumnIdContext } from '@/ui/board/contexts/BoardColumnIdContext';
|
||||
import { SelectedSortType } from '@/ui/filter-n-sort/types/interface';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
|
||||
import { StyledScrollWrapper } from '@/ui/utilities/scroll/components/StyledScrollWrapper';
|
||||
import { useListenScroll } from '@/ui/utilities/scroll/hooks/useListenScroll';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import {
|
||||
PipelineProgress,
|
||||
PipelineProgressOrderByWithRelationInput,
|
||||
@ -31,7 +30,7 @@ import { BoardOptions } from '../types/BoardOptions';
|
||||
|
||||
import { EntityBoardColumn } from './EntityBoardColumn';
|
||||
|
||||
const StyledCustomScrollWrapper = styled(StyledScrollWrapper)`
|
||||
const StyledCustomScrollWrapper = styled(ScrollWrapper)`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
@ -103,15 +102,10 @@ export function EntityBoard({
|
||||
return a.index - b.index;
|
||||
});
|
||||
|
||||
const scrollableRef = useRef<HTMLDivElement>(null);
|
||||
const boardRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useListenScroll({
|
||||
scrollableRef,
|
||||
});
|
||||
|
||||
return (boardColumns?.length ?? 0) > 0 ? (
|
||||
<StyledCustomScrollWrapper ref={scrollableRef}>
|
||||
<StyledCustomScrollWrapper>
|
||||
<BoardHeader
|
||||
viewName="All opportunities"
|
||||
viewIcon={<IconList size={theme.icon.size.md} />}
|
||||
|
||||
@ -2,14 +2,26 @@ import { ReactElement } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
|
||||
export const StyledShowPageContainer = styled.div`
|
||||
const StyledOuterContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: ${() => (useIsMobile() ? 'column' : 'row')};
|
||||
|
||||
gap: ${({ theme }) => (useIsMobile() ? theme.spacing(3) : '0')};
|
||||
height: ${() => (useIsMobile() ? '100%' : 'auto')};
|
||||
overflow-x: ${() => (useIsMobile() ? 'hidden' : 'auto')};
|
||||
width: ${() => (useIsMobile() ? `calc(100% - 2px);` : '100%')};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledInnerContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: ${() => (useIsMobile() ? 'column' : 'row')};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledScrollWrapper = styled(ScrollWrapper)`
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
border-radius: ${({ theme }) => theme.border.radius.md};
|
||||
`;
|
||||
|
||||
export type ShowPageContainerProps = {
|
||||
@ -17,5 +29,16 @@ export type ShowPageContainerProps = {
|
||||
};
|
||||
|
||||
export function ShowPageContainer({ children }: ShowPageContainerProps) {
|
||||
return <StyledShowPageContainer>{children} </StyledShowPageContainer>;
|
||||
const isMobile = useIsMobile();
|
||||
return isMobile ? (
|
||||
<StyledOuterContainer>
|
||||
<StyledScrollWrapper>
|
||||
<StyledInnerContainer>{children}</StyledInnerContainer>
|
||||
</StyledScrollWrapper>
|
||||
</StyledOuterContainer>
|
||||
) : (
|
||||
<StyledOuterContainer>
|
||||
<StyledInnerContainer>{children}</StyledInnerContainer>
|
||||
</StyledOuterContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,27 +2,33 @@ import { ReactElement } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
|
||||
const StyledShowPageLeftContainer = styled.div`
|
||||
const StyledOuterContainer = styled.div`
|
||||
background: ${({ theme }) => theme.background.secondary};
|
||||
border-bottom-left-radius: 8px;
|
||||
border-right: 1px solid
|
||||
${({ theme }) => {
|
||||
const isMobile = useIsMobile();
|
||||
return !isMobile ? theme.border.color.medium : 0;
|
||||
}};
|
||||
border-right: ${({ theme }) => {
|
||||
const isMobile = useIsMobile();
|
||||
return !isMobile ? `1px solid ${theme.border.color.medium}` : 'none';
|
||||
}};
|
||||
border-top-left-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(3)};
|
||||
padding: 0px ${({ theme }) => theme.spacing(3)};
|
||||
|
||||
z-index: 10;
|
||||
`;
|
||||
|
||||
const StyledInnerContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0px ${({ theme }) => theme.spacing(2)} 0px
|
||||
${({ theme }) => theme.spacing(3)};
|
||||
width: ${({ theme }) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return isMobile ? `calc(100% - ${theme.spacing(6)})` : '320px';
|
||||
return isMobile ? `calc(100% - ${theme.spacing(5)})` : '320px';
|
||||
}};
|
||||
|
||||
z-index: 10;
|
||||
`;
|
||||
|
||||
export type ShowPageLeftContainerProps = {
|
||||
@ -32,5 +38,16 @@ export type ShowPageLeftContainerProps = {
|
||||
export function ShowPageLeftContainer({
|
||||
children,
|
||||
}: ShowPageLeftContainerProps) {
|
||||
return <StyledShowPageLeftContainer>{children} </StyledShowPageLeftContainer>;
|
||||
const isMobile = useIsMobile();
|
||||
return isMobile ? (
|
||||
<StyledOuterContainer>
|
||||
<StyledInnerContainer>{children}</StyledInnerContainer>
|
||||
</StyledOuterContainer>
|
||||
) : (
|
||||
<StyledOuterContainer>
|
||||
<ScrollWrapper>
|
||||
<StyledInnerContainer>{children}</StyledInnerContainer>
|
||||
</ScrollWrapper>
|
||||
</StyledOuterContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -9,11 +9,7 @@ export const StyledShowPageRightContainer = styled.div`
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
overflow: ${() => (useIsMobile() ? 'none' : 'hidden')};
|
||||
width: ${({ theme }) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return isMobile ? `calc(100% - ${theme.spacing(6)})` : 'auto';
|
||||
}};
|
||||
width: calc(100% + 4px);
|
||||
`;
|
||||
|
||||
export type ShowPageRightContainerProps = {
|
||||
|
||||
@ -31,7 +31,7 @@ const StyledContainer = styled(motion.div)`
|
||||
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
z-index: 100;
|
||||
`;
|
||||
|
||||
const StyledRightDrawer = styled.div`
|
||||
|
||||
@ -8,8 +8,7 @@ import type {
|
||||
import { SortType } from '@/ui/filter-n-sort/types/interface';
|
||||
import { DragSelect } from '@/ui/utilities/drag-select/components/DragSelect';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { StyledScrollWrapper } from '@/ui/utilities/scroll/components/StyledScrollWrapper';
|
||||
import { useListenScroll } from '@/ui/utilities/scroll/hooks/useListenScroll';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
|
||||
import { EntityUpdateMutationContext } from '../contexts/EntityUpdateMutationHookContext';
|
||||
import { useLeaveTableFocus } from '../hooks/useLeaveTableFocus';
|
||||
@ -125,12 +124,6 @@ export function EntityTable<SortField>({
|
||||
},
|
||||
});
|
||||
|
||||
const scrollableRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useListenScroll({
|
||||
scrollableRef,
|
||||
});
|
||||
|
||||
return (
|
||||
<EntityUpdateMutationContext.Provider value={updateEntityMutation}>
|
||||
<StyledTableWithHeader>
|
||||
@ -143,12 +136,14 @@ export function EntityTable<SortField>({
|
||||
onViewSubmit={onViewSubmit}
|
||||
onImport={onImport}
|
||||
/>
|
||||
<StyledScrollWrapper ref={scrollableRef}>
|
||||
<StyledTable>
|
||||
<EntityTableHeader onColumnsChange={onColumnsChange} />
|
||||
<EntityTableBody />
|
||||
</StyledTable>
|
||||
</StyledScrollWrapper>
|
||||
<ScrollWrapper>
|
||||
<div>
|
||||
<StyledTable>
|
||||
<EntityTableHeader onColumnsChange={onColumnsChange} />
|
||||
<EntityTableBody />
|
||||
</StyledTable>
|
||||
</div>
|
||||
</ScrollWrapper>
|
||||
<DragSelect
|
||||
dragSelectable={tableBodyRef}
|
||||
onDragSelectionStart={resetTableRowSelection}
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
import { useRef } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { useListenScroll } from '../hooks/useListenScroll';
|
||||
|
||||
const StyledScrollWrapper = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
scrollbar-gutter: stable;
|
||||
width: 100%;
|
||||
|
||||
&.scrolling::-webkit-scrollbar-thumb {
|
||||
background-color: ${({ theme }) => theme.border.color.medium};
|
||||
}
|
||||
`;
|
||||
|
||||
export type ScrollWrapperProps = {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function ScrollWrapper({ children, className }: ScrollWrapperProps) {
|
||||
const scrollableRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useListenScroll({
|
||||
scrollableRef,
|
||||
});
|
||||
|
||||
return (
|
||||
<StyledScrollWrapper ref={scrollableRef} className={className}>
|
||||
{children}
|
||||
</StyledScrollWrapper>
|
||||
);
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export const StyledScrollWrapper = styled.div`
|
||||
display: flex;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
|
||||
&.scrolling::-webkit-scrollbar-thumb {
|
||||
background-color: ${({ theme }) => theme.border.color.medium};
|
||||
}
|
||||
`;
|
||||
Reference in New Issue
Block a user