Message List: Scroll notch (#1129)
This commit is contained in:
parent
b71e589620
commit
839b6b65f2
@ -5,7 +5,7 @@
|
|||||||
overflow: scroll;
|
overflow: scroll;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: overlay;
|
overflow-y: overlay;
|
||||||
margin-bottom: .3125rem;
|
margin-bottom: .5rem;
|
||||||
|
|
||||||
.mask-image-enabled & {
|
.mask-image-enabled & {
|
||||||
mask-image: linear-gradient(to top, transparent 0, #000 0.5rem);
|
mask-image: linear-gradient(to top, transparent 0, #000 0.5rem);
|
||||||
|
|||||||
@ -66,7 +66,8 @@ type OwnProps = {
|
|||||||
threadId: number;
|
threadId: number;
|
||||||
type: MessageListType;
|
type: MessageListType;
|
||||||
canPost: boolean;
|
canPost: boolean;
|
||||||
onFabToggle: (show: boolean) => void;
|
onFabToggle: (shouldShow: boolean) => void;
|
||||||
|
onNotchToggle: (shouldShow: boolean) => void;
|
||||||
hasTools?: boolean;
|
hasTools?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,6 +115,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
type,
|
type,
|
||||||
hasTools,
|
hasTools,
|
||||||
onFabToggle,
|
onFabToggle,
|
||||||
|
onNotchToggle,
|
||||||
isChatLoaded,
|
isChatLoaded,
|
||||||
isChannelChat,
|
isChannelChat,
|
||||||
canPost,
|
canPost,
|
||||||
@ -540,6 +542,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
isViewportNewest={isViewportNewest}
|
isViewportNewest={isViewportNewest}
|
||||||
firstUnreadId={firstUnreadId}
|
firstUnreadId={firstUnreadId}
|
||||||
onFabToggle={onFabToggle}
|
onFabToggle={onFabToggle}
|
||||||
|
onNotchToggle={onNotchToggle}
|
||||||
>
|
>
|
||||||
{renderMessages(
|
{renderMessages(
|
||||||
lang,
|
lang,
|
||||||
|
|||||||
@ -19,6 +19,7 @@ type OwnProps = {
|
|||||||
isViewportNewest?: boolean;
|
isViewportNewest?: boolean;
|
||||||
firstUnreadId?: number;
|
firstUnreadId?: number;
|
||||||
onFabToggle: AnyToVoidFunction;
|
onFabToggle: AnyToVoidFunction;
|
||||||
|
onNotchToggle: AnyToVoidFunction;
|
||||||
children: any;
|
children: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,6 +39,7 @@ const MessageScroll: FC<OwnProps> = ({
|
|||||||
isViewportNewest,
|
isViewportNewest,
|
||||||
firstUnreadId,
|
firstUnreadId,
|
||||||
onFabToggle,
|
onFabToggle,
|
||||||
|
onNotchToggle,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
@ -54,11 +56,13 @@ const MessageScroll: FC<OwnProps> = ({
|
|||||||
|
|
||||||
if (!messageIds || !messageIds.length) {
|
if (!messageIds || !messageIds.length) {
|
||||||
onFabToggle(false);
|
onFabToggle(false);
|
||||||
|
onNotchToggle(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isViewportNewest) {
|
if (!isViewportNewest) {
|
||||||
onFabToggle(true);
|
onFabToggle(true);
|
||||||
|
onNotchToggle(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +72,8 @@ const MessageScroll: FC<OwnProps> = ({
|
|||||||
const isAtBottom = scrollBottom === 0 || (IS_SAFARI && scrollBottom === 1);
|
const isAtBottom = scrollBottom === 0 || (IS_SAFARI && scrollBottom === 1);
|
||||||
|
|
||||||
onFabToggle(firstUnreadId ? !isAtBottom : !isNearBottom);
|
onFabToggle(firstUnreadId ? !isAtBottom : !isNearBottom);
|
||||||
}, [messageIds, isViewportNewest, containerRef, onFabToggle, firstUnreadId]);
|
onNotchToggle(!isAtBottom);
|
||||||
|
}, [messageIds, isViewportNewest, containerRef, onFabToggle, firstUnreadId, onNotchToggle]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
observe: observeIntersection,
|
observe: observeIntersection,
|
||||||
@ -114,6 +119,16 @@ const MessageScroll: FC<OwnProps> = ({
|
|||||||
|
|
||||||
useOnIntersect(fabTriggerRef, observeIntersectionForFab);
|
useOnIntersect(fabTriggerRef, observeIntersectionForFab);
|
||||||
|
|
||||||
|
const {
|
||||||
|
observe: observeIntersectionForNotch,
|
||||||
|
} = useIntersectionObserver({
|
||||||
|
rootRef: containerRef,
|
||||||
|
}, () => {
|
||||||
|
updateFabVisibility();
|
||||||
|
});
|
||||||
|
|
||||||
|
useOnIntersect(fabTriggerRef, observeIntersectionForNotch);
|
||||||
|
|
||||||
// Do not load more and show FAB when focusing
|
// Do not load more and show FAB when focusing
|
||||||
useOnChange(() => {
|
useOnChange(() => {
|
||||||
if (focusingId) {
|
if (focusingId) {
|
||||||
|
|||||||
@ -255,6 +255,27 @@
|
|||||||
transform: translate3d(0, calc(-1 * (var(--symbol-menu-height) + var(--symbol-menu-footer-height))), 0);
|
transform: translate3d(0, calc(-1 * (var(--symbol-menu-height) + var(--symbol-menu-footer-height))), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: -0.5rem;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.4) 2%, rgba(255, 255, 255, 0.4) 98%, rgba(255, 255, 255, 0) 100%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 200ms ease;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
left: -2%;
|
||||||
|
right: -2%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.with-notch::before {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -103,6 +103,7 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
|
|
||||||
const [dropAreaState, setDropAreaState] = useState(DropAreaState.None);
|
const [dropAreaState, setDropAreaState] = useState(DropAreaState.None);
|
||||||
const [isFabShown, setIsFabShown] = useState<boolean | undefined>();
|
const [isFabShown, setIsFabShown] = useState<boolean | undefined>();
|
||||||
|
const [isNotchShown, setIsNotchShown] = useState<boolean | undefined>();
|
||||||
const [isUnpinModalOpen, setIsUnpinModalOpen] = useState(false);
|
const [isUnpinModalOpen, setIsUnpinModalOpen] = useState(false);
|
||||||
|
|
||||||
const hasTools = hasPinnedOrAudioMessage && (
|
const hasTools = hasPinnedOrAudioMessage && (
|
||||||
@ -134,6 +135,7 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDropAreaState(DropAreaState.None);
|
setDropAreaState(DropAreaState.None);
|
||||||
setIsFabShown(undefined);
|
setIsFabShown(undefined);
|
||||||
|
setIsNotchShown(undefined);
|
||||||
}, [chatId]);
|
}, [chatId]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -198,6 +200,12 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
|
const footerClassName = buildClassName(
|
||||||
|
'middle-column-footer',
|
||||||
|
!renderingCanPost && 'no-composer',
|
||||||
|
renderingCanPost && isNotchShown && 'with-notch',
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id="MiddleColumn"
|
id="MiddleColumn"
|
||||||
@ -242,8 +250,9 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
|
|||||||
canPost={renderingCanPost}
|
canPost={renderingCanPost}
|
||||||
hasTools={renderingHasTools}
|
hasTools={renderingHasTools}
|
||||||
onFabToggle={setIsFabShown}
|
onFabToggle={setIsFabShown}
|
||||||
|
onNotchToggle={setIsNotchShown}
|
||||||
/>
|
/>
|
||||||
<div className={buildClassName('middle-column-footer', !renderingCanPost && 'no-composer')}>
|
<div className={footerClassName}>
|
||||||
{renderingCanPost && (
|
{renderingCanPost && (
|
||||||
<Composer
|
<Composer
|
||||||
chatId={renderingChatId}
|
chatId={renderingChatId}
|
||||||
|
|||||||
@ -46,7 +46,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.last-in-list {
|
&.last-in-list {
|
||||||
margin-bottom: 0.375rem;
|
margin-bottom: 0rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-in-selection-mode {
|
&.is-in-selection-mode {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user