You've already forked element-web
mirror of
https://github.com/element-hq/element-web.git
synced 2026-10-23 11:09:01 +03:00
* Reopen the right panel when the current card is given new state
setCard's "same phase, new state" branch swapped the state of the card at
the top of the history but left the panel's own isOpen alone. If the panel
had been closed, the card was updated behind it and nothing appeared, so
the action looked like it had done nothing.
Show the panel in that branch, as the other two branches already do.
Also drop the unguarded index into a possibly empty history while we are
here: a matching phase can only have come from this room's own history, so
guard on it rather than trusting `hist[hist.length - 1]` to exist.
* Add a PDF viewer to the right panel
Open a PDF attachment in the right panel instead of having to download it
first. The viewer is pdf.js, rendering continuously with fit-to-width zoom,
pinch and ctrl-wheel zoom, and a page selector; the reading position is
remembered per file so reopening a document comes back where you left off.
The file body gains an optional "open" control next to download, which the
view model only asks for on PDFs shown as files in a timeline — not in an
export, and not in the download-only panels. FileBodyView renders nothing
for it otherwise, so every other file body is unchanged.
Encrypted attachments work unchanged: the handle the viewer is given reads
the bytes through MediaEventHelper's sourceBlob, which decrypts first.
The card stores only the source event id, so a restored panel re-derives
the media and drops the card if the event is no longer in the room.
* Add icon into the container instead of outside.
* Update translate + new images
* Load the right panel store lazily when opening a PDF
utils/pdfViewer is reached from the message body view models, and importing
RightPanelStore from it closed a cycle back to the message bodies:
utils/pdfViewer -> RightPanelStore -> SDKContextClass -> LegacyCallHandler
-> utils/notifications -> Unread -> EventTileFactory -> MessageEvent
-> MVoiceOrAudioBody -> MVoiceMessageBody -> extends MAudioBody
MVoiceMessageBody evaluated `extends MAudioBody` while MAudioBody was still
initialising, so the whole MAudioBody suite failed to load with "Class
extends value undefined is not a constructor or null".
Pull the store in through a dynamic import instead, as StoresApi already
does for the room list store. Nothing else under views/messages or
viewmodels imports RightPanelStore, which is what kept this cycle closed
until now.
openPdfViewer becomes async as a result; the click handler fires it with
`void` since opening the panel is not something the caller waits on.
* Code split the PDF viewer behind Suspense
Importing PdfViewer from the card put pdf.js into every module graph that
reaches the right panel, so RoomView pulled it in and the Jest suites failed
to parse it:
SyntaxError: Cannot use 'import.meta' outside a module
pdf.js locates its worker with `new URL(..., import.meta.url)`, which Jest
cannot compile, since it transpiles to CJS. That took out ExtrasApi-test and
anything else reaching RoomView.
Load the viewer with React.lazy instead, as the beacon components already do
for maplibre-gl. pdf.js is large and of no use until someone opens a PDF, so
keeping it out of the main bundle is worth doing on its own account; the Jest
suites stop seeing it as a side effect.
* Put the PDF viewer behind a lab
Ship the viewer disabled by default, as feature_pdf_viewer under the
Messaging group in Labs, alongside the other flags that change how message
content renders.
Two gates:
- FileBodyViewModel leads showOpen with the flag, and showInlineDownload
follows it, so with the lab off the file pill renders exactly as it did
before: attachment icon, file name, no actions.
- RightPanelStore drops a stored PdfViewer card when the flag is off, ahead
of the check for a displayable event. Without it, someone who had a PDF
open when they turned the lab off would get the viewer back on reload.
The existing "drops a PdfViewer card with no event to display" test now
enables the lab first; the gate had made it pass for the wrong reason.
* Drop the brand name from the PDF viewer lab
The i18n check forbids hardcoding "Element" in translations, since the brand
is configurable, and "Open PDFs in Element" tripped it:
"labs|pdf_viewer": contains forbidden hardcoded word
Keys that genuinely need the brand are allow-listed in the i18n job, but this
one does not: the label reads fine without it, and naming a panel the viewer
happens to use is the description's job anyway.
* Update card header to show file name + change edit icon to expend icon on filepreview
* Update storybook images to reflect new icon
* Update apps/web/src/viewmodels/message-body/FileBodyViewModel.ts
Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com>
* Removed @link as it did not go anywhere.
* Drop the self-referential @link in PdfViewerState docs
* Comment why the file tile actions are hidden in forward previews
* Test the RightPanel PdfViewer phase renders the viewer card
* Take the PDF viewer lab as a prop on FileBodyViewModel
* Dispatch an action to open the PDF viewer instead of importing the store
* Check the PDF signature before parsing the attachment
* MVVM PDF Viewer
* Fix Sonar
* Cap decoded image size and pin XFA off when opening a PDF
* Update apps/web/src/i18n/strings/en_EN.json
Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com>
* Use the real SettingsStore for the PDF viewer lab in tests
* Read the PDF viewer lab in the view, not the view model
* Declare the mock viewer's page field with the others
* Use the minified pdf.js worker
* Allow clicking on links in the PDF.
* Force use of a PDF worker
* Reduce logging noise.
* Cap PDF size
* Check blob size too
* Add support for clicking links in the canvas
* Report file size
* Tests
* cleanup
---------
Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com>
Co-authored-by: Half-Shot <will@half-shot.uk>
151 lines
4.4 KiB
Plaintext
151 lines
4.4 KiB
Plaintext
/*
|
|
Copyright 2024 New Vector Ltd.
|
|
Copyright 2021 Robin Townsend <robin@robin.town>
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE files in the repository root for full details.
|
|
*/
|
|
|
|
.mx_ForwardDialog {
|
|
width: 520px;
|
|
color: $primary-content;
|
|
display: flex;
|
|
flex-direction: column;
|
|
flex-wrap: nowrap;
|
|
min-height: 0;
|
|
height: 80vh;
|
|
|
|
> h3 {
|
|
margin: 0 0 6px;
|
|
color: $secondary-content;
|
|
font-size: $font-12px;
|
|
font-weight: var(--cpd-font-weight-semibold);
|
|
line-height: $font-15px;
|
|
}
|
|
|
|
> .mx_ForwardDialog_preview {
|
|
max-height: 30%;
|
|
flex-shrink: 0;
|
|
overflow-y: auto;
|
|
|
|
div {
|
|
pointer-events: none;
|
|
}
|
|
|
|
/* When forwarding messages from encrypted rooms, EventTile will complain */
|
|
/* that our preview is unencrypted, which doesn't actually matter */
|
|
/* We also hide download links to not encourage users to try interacting */
|
|
/* The file tile's inline download and open actions go for the same reason */
|
|
.mx_ReadReceiptGroup,
|
|
.mx_E2ePadlock,
|
|
.mx_MFileBody [data-type="download"],
|
|
.mx_MFileBody [data-type="actions"] {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
> hr {
|
|
width: 100%;
|
|
border: none;
|
|
border-top: 1px solid $input-border-color;
|
|
margin: 12px 0;
|
|
}
|
|
|
|
> .mx_ForwardList {
|
|
display: contents;
|
|
|
|
.mx_SearchBox {
|
|
/* To match the space around the title */
|
|
margin: 0 0 15px 0;
|
|
flex-grow: 0;
|
|
|
|
&:not(:focus-within) + .mx_ForwardList_content {
|
|
/* Inhibit the styling if focus is not within the input which handles keyboard accessibility */
|
|
--mx_ForwardList_entry_selectedBgColor: transparent;
|
|
}
|
|
}
|
|
|
|
.mx_ForwardList_content {
|
|
flex-grow: 1;
|
|
}
|
|
|
|
.mx_ForwardList_noResults {
|
|
display: block;
|
|
margin-top: 24px;
|
|
}
|
|
|
|
.mx_ForwardList_results {
|
|
&:not(:first-child) {
|
|
margin-top: 24px;
|
|
}
|
|
|
|
.mx_ForwardList_resultsList {
|
|
padding-right: 8px;
|
|
}
|
|
|
|
.mx_ForwardList_entry {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
height: 32px;
|
|
padding: 6px;
|
|
border-radius: 8px;
|
|
|
|
&:hover,
|
|
&.mx_ForwardList_entry_active {
|
|
background-color: var(--mx_ForwardList_entry_selectedBgColor, $spacePanel-bg-color);
|
|
}
|
|
|
|
.mx_ForwardList_roomButton {
|
|
display: flex;
|
|
margin-right: 12px;
|
|
min-width: 0;
|
|
|
|
.mx_DecoratedRoomAvatar {
|
|
margin-right: 12px;
|
|
}
|
|
|
|
.mx_ForwardList_entry_name,
|
|
.mx_ForwardList_entry_detail {
|
|
line-height: 30px;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.mx_ForwardList_entry_name {
|
|
font-size: $font-15px;
|
|
}
|
|
|
|
.mx_ForwardList_entry_detail {
|
|
font-size: $font-12px;
|
|
margin-left: 8px;
|
|
color: $tertiary-content;
|
|
}
|
|
}
|
|
|
|
.mx_ForwardList_sendButton {
|
|
position: relative;
|
|
margin-left: 12px;
|
|
|
|
&:not(.mx_ForwardList_canSend) .mx_ForwardList_sendLabel {
|
|
/* Hide the "Send" label while preserving button size */
|
|
visibility: hidden;
|
|
}
|
|
|
|
& > svg {
|
|
position: absolute;
|
|
width: 14px;
|
|
height: 14px;
|
|
color: $accent;
|
|
}
|
|
|
|
.mx_ForwardDialog_notificationBadge {
|
|
/* Match the failed to send indicator's color with the disabled button */
|
|
background-color: $button-danger-disabled-fg-color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|