mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2025-12-20 02:08:57 +00:00
PinnedMessagesPanel: Add footer with Unpin all messages button
This commit is contained in:
@@ -1682,6 +1682,10 @@
|
|||||||
"messageformat": "Pinned messages",
|
"messageformat": "Pinned messages",
|
||||||
"description": "Conversation > Pinned messages panel (view all) > Title"
|
"description": "Conversation > Pinned messages panel (view all) > Title"
|
||||||
},
|
},
|
||||||
|
"icu:PinnedMessagesPanel__UnpinAllMessages": {
|
||||||
|
"messageformat": "Unpin all messages",
|
||||||
|
"description": "Conversation > Pinned messages panel (view all) > Unpin all messages button"
|
||||||
|
},
|
||||||
"icu:sessionEnded": {
|
"icu:sessionEnded": {
|
||||||
"messageformat": "Secure session reset",
|
"messageformat": "Secure session reset",
|
||||||
"description": "This is a past tense, informational message. In other words, your secure session has been reset."
|
"description": "This is a past tense, informational message. In other words, your secure session has been reset."
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
overflow-y: auto;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -28,12 +27,13 @@
|
|||||||
// Used for centering EmptyState in All Media view
|
// Used for centering EmptyState in All Media view
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
padding-top: calc(
|
|
||||||
#{variables.$header-height} + var(--title-bar-drag-area-height)
|
&--padding {
|
||||||
);
|
|
||||||
padding-inline: 24px;
|
padding-inline: 24px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -44,7 +44,6 @@
|
|||||||
#{variables.$header-height} + var(--title-bar-drag-area-height)
|
#{variables.$header-height} + var(--title-bar-drag-area-height)
|
||||||
);
|
);
|
||||||
padding-top: var(--title-bar-drag-area-height);
|
padding-top: var(--title-bar-drag-area-height);
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
z-index: variables.$z-index-base;
|
z-index: variables.$z-index-base;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
// Copyright 2025 Signal Messenger, LLC
|
// Copyright 2025 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import React, { Fragment, memo, useMemo, useRef, useState } from 'react';
|
import type { ForwardedRef, ReactNode } from 'react';
|
||||||
|
import React, {
|
||||||
|
forwardRef,
|
||||||
|
Fragment,
|
||||||
|
memo,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { useLayoutEffect } from '@react-aria/utils';
|
import { useLayoutEffect } from '@react-aria/utils';
|
||||||
import type { LocalizerType } from '../../../types/I18N.std.js';
|
import type { LocalizerType } from '../../../types/I18N.std.js';
|
||||||
import type { ConversationType } from '../../../state/ducks/conversations.preload.js';
|
import type { ConversationType } from '../../../state/ducks/conversations.preload.js';
|
||||||
@@ -16,6 +24,8 @@ import { getWidthBreakpoint } from '../../../util/timelineUtil.std.js';
|
|||||||
import { strictAssert } from '../../../util/assert.std.js';
|
import { strictAssert } from '../../../util/assert.std.js';
|
||||||
import { useSizeObserver } from '../../../hooks/useSizeObserver.dom.js';
|
import { useSizeObserver } from '../../../hooks/useSizeObserver.dom.js';
|
||||||
import { MessageInteractivity } from '../Message.dom.js';
|
import { MessageInteractivity } from '../Message.dom.js';
|
||||||
|
import { tw } from '../../../axo/tw.dom.js';
|
||||||
|
import { AxoButton } from '../../../axo/AxoButton.dom.js';
|
||||||
|
|
||||||
export type PinnedMessagesPanelProps = Readonly<{
|
export type PinnedMessagesPanelProps = Readonly<{
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
@@ -27,6 +37,7 @@ export type PinnedMessagesPanelProps = Readonly<{
|
|||||||
export const PinnedMessagesPanel = memo(function PinnedMessagesPanel(
|
export const PinnedMessagesPanel = memo(function PinnedMessagesPanel(
|
||||||
props: PinnedMessagesPanelProps
|
props: PinnedMessagesPanelProps
|
||||||
) {
|
) {
|
||||||
|
const { i18n } = props;
|
||||||
const containerElementRef = useRef<HTMLDivElement>(null);
|
const containerElementRef = useRef<HTMLDivElement>(null);
|
||||||
const [containerWidthBreakpoint, setContainerWidthBreakpoint] = useState(
|
const [containerWidthBreakpoint, setContainerWidthBreakpoint] = useState(
|
||||||
WidthBreakpoint.Wide
|
WidthBreakpoint.Wide
|
||||||
@@ -42,19 +53,9 @@ export const PinnedMessagesPanel = memo(function PinnedMessagesPanel(
|
|||||||
setContainerWidthBreakpoint(getWidthBreakpoint(size.width));
|
setContainerWidthBreakpoint(getWidthBreakpoint(size.width));
|
||||||
});
|
});
|
||||||
|
|
||||||
const scrollerLock = useMemo(() => {
|
|
||||||
return createScrollerLock('PinnedMessagesPanel', () => {
|
|
||||||
// noop - we probably don't need to do anything here because the only
|
|
||||||
// thing that can happen is the pinned messages getting removed/added
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AxoScrollArea.Root scrollbarWidth="wide">
|
<div className={tw('flex h-full flex-col')}>
|
||||||
<AxoScrollArea.Viewport>
|
<ScrollArea ref={containerElementRef}>
|
||||||
<AxoScrollArea.Content>
|
|
||||||
<div ref={containerElementRef}>
|
|
||||||
<ScrollerLockContext.Provider value={scrollerLock}>
|
|
||||||
{props.pinnedMessages.map((pinnedMessage, pinnedMessageIndex) => {
|
{props.pinnedMessages.map((pinnedMessage, pinnedMessageIndex) => {
|
||||||
const next = props.pinnedMessages[pinnedMessageIndex + 1];
|
const next = props.pinnedMessages[pinnedMessageIndex + 1];
|
||||||
const prev = props.pinnedMessages[pinnedMessageIndex - 1];
|
const prev = props.pinnedMessages[pinnedMessageIndex - 1];
|
||||||
@@ -76,6 +77,36 @@ export const PinnedMessagesPanel = memo(function PinnedMessagesPanel(
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
</ScrollArea>
|
||||||
|
<div className={tw('flex items-center justify-center p-2.5')}>
|
||||||
|
<AxoButton.Root variant="borderless-primary" size="lg">
|
||||||
|
{i18n('icu:PinnedMessagesPanel__UnpinAllMessages')}
|
||||||
|
</AxoButton.Root>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const ScrollArea = forwardRef(function ScrollArea(
|
||||||
|
props: { children: ReactNode },
|
||||||
|
ref: ForwardedRef<HTMLDivElement>
|
||||||
|
) {
|
||||||
|
const scrollerLock = useMemo(() => {
|
||||||
|
return createScrollerLock('PinnedMessagesPanel', () => {
|
||||||
|
// noop - we probably don't need to do anything here because the only
|
||||||
|
// thing that can happen is the pinned messages getting removed/added
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AxoScrollArea.Root scrollbarWidth="wide">
|
||||||
|
<AxoScrollArea.Hint edge="top" />
|
||||||
|
<AxoScrollArea.Hint edge="bottom" />
|
||||||
|
<AxoScrollArea.Viewport>
|
||||||
|
<AxoScrollArea.Content>
|
||||||
|
<div ref={ref}>
|
||||||
|
<ScrollerLockContext.Provider value={scrollerLock}>
|
||||||
|
{props.children}
|
||||||
</ScrollerLockContext.Provider>
|
</ScrollerLockContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
</AxoScrollArea.Content>
|
</AxoScrollArea.Content>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import React, {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
import classNames from 'classnames';
|
||||||
import type { PanelRenderType } from '../../types/Panels.std.js';
|
import type { PanelRenderType } from '../../types/Panels.std.js';
|
||||||
import { createLogger } from '../../logging/log.std.js';
|
import { createLogger } from '../../logging/log.std.js';
|
||||||
import { PanelType } from '../../types/Panels.std.js';
|
import { PanelType } from '../../types/Panels.std.js';
|
||||||
@@ -322,7 +323,14 @@ const PanelContainer = forwardRef<
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="ConversationPanel__body" ref={focusRef}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
'ConversationPanel__body',
|
||||||
|
panel.type !== PanelType.PinnedMessages &&
|
||||||
|
'ConversationPanel__body--padding'
|
||||||
|
)}
|
||||||
|
ref={focusRef}
|
||||||
|
>
|
||||||
<PanelElement conversationId={conversationId} panel={panel} />
|
<PanelElement conversationId={conversationId} panel={panel} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user