Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Optimize background image from avatar on left panel #6659

Merged
merged 12 commits into from
Aug 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
"cheerio": "^1.0.0-rc.9",
"classnames": "^2.2.6",
"commonmark": "^0.29.3",
"context-filter-polyfill": "^0.2.4",
"counterpart": "^0.18.6",
"diff-dom": "^4.2.2",
"diff-match-patch": "^1.0.5",
Expand Down Expand Up @@ -196,7 +195,6 @@
"decoderWorker\\.min\\.js": "<rootDir>/__mocks__/empty.js",
"decoderWorker\\.min\\.wasm": "<rootDir>/__mocks__/empty.js",
"waveWorker\\.min\\.js": "<rootDir>/__mocks__/empty.js",
"context-filter-polyfill": "<rootDir>/__mocks__/empty.js",
"workers/(.+)\\.worker\\.ts": "<rootDir>/__mocks__/workerMock.js",
"RecorderWorklet": "<rootDir>/__mocks__/empty.js"
},
Expand Down
20 changes: 2 additions & 18 deletions res/css/structures/_BackdropPanel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,15 @@ limitations under the License.
height: 100vh;
width: 100%;
overflow: hidden;

&::before {
content: " ";
position: absolute;
left: 0;
top: 0;
height: 100vh;
width: 100%;
background-color: var(--lp-background-overlay);
}
filter: blur(var(--lp-background-blur));
}

.mx_BackdropPanel--canvas {
.mx_BackdropPanel--image {
position: absolute;
top: 0;
left: 0;
min-height: 100%;
z-index: 0;
pointer-events: none;
overflow: hidden;

&:nth-of-type(2n-1) {
opacity: 0.2;
}
&:nth-of-type(2n) {
opacity: 0.1;
}
}
18 changes: 14 additions & 4 deletions res/css/structures/_GroupFilterPanel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

.mx_MatrixChat--with-avatar {
.mx_GroupFilterPanel {
background-color: transparent;
}
$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations

.mx_GroupFilterPanelContainer {
flex-grow: 0;
flex-shrink: 0;
width: $groupFilterPanelWidth;
height: 100%;

// Create another flexbox so the GroupFilterPanel fills the container
display: flex;
flex-direction: column;

// GroupFilterPanel handles its own CSS
}

.mx_GroupFilterPanel {
z-index: 1;
background-color: $groupFilterPanel-bg-color;
flex: 1;
cursor: pointer;
Expand Down
23 changes: 9 additions & 14 deletions res/css/structures/_LeftPanel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations
$roomListCollapsedWidth: 68px;

.mx_MatrixChat--with-avatar {
Expand All @@ -27,8 +26,17 @@ $roomListCollapsedWidth: 68px;
.mx_LeftPanel_wrapper {
display: flex;
max-width: 50%;

.mx_LeftPanel_wrapper--user {
background-color: $roomlist-bg-color;
display: flex;
overflow: hidden;
position: relative;
}
}



.mx_LeftPanel {
background-color: $roomlist-bg-color;
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
Expand All @@ -39,19 +47,6 @@ $roomListCollapsedWidth: 68px;
contain: content;
position: relative;

.mx_LeftPanel_GroupFilterPanelContainer {
flex-grow: 0;
flex-shrink: 0;
flex-basis: $groupFilterPanelWidth;
height: 100%;

// Create another flexbox so the GroupFilterPanel fills the container
display: flex;
flex-direction: column;

// GroupFilterPanel handles its own CSS
}

// Note: The 'room list' in this context is actually everything that isn't the tag
// panel, such as the menu options, breadcrumbs, filtering, etc
.mx_LeftPanel_roomListContainer {
Expand Down
8 changes: 2 additions & 6 deletions res/css/structures/_SpacePanel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,14 @@ $activeBorderTransparentGap: 1px;
$activeBackgroundColor: $roomtile-selected-bg-color;
$activeBorderColor: $secondary-fg-color;

.mx_MatrixChat--with-avatar {
.mx_SpacePanel {
background-color: transparent;
}
}

.mx_SpacePanel {
background-color: $groupFilterPanel-bg-color;
flex: 0 0 auto;
padding: 0;
margin: 0;
position: relative;
// Fix for the blurred avatar-background
z-index: 1;

// Create another flexbox so the Panel fills the container
display: flex;
Expand Down
4 changes: 1 addition & 3 deletions res/themes/dark/css/_dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,7 @@ $appearance-tab-border-color: $room-highlight-color;

// blur amounts for left left panel (only for element theme)
:root {
--llp-background-blur: 160px;
--lp-background-blur: 90px;
--lp-background-overlay: rgba(255, 255, 255, 0.055);
--lp-background-blur: 45px;
}

$composer-shadow-color: rgba(0, 0, 0, 0.28);
Expand Down
4 changes: 1 addition & 3 deletions res/themes/light/css/_light.scss
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,7 @@ $appearance-tab-border-color: $input-darker-bg-color;

// blur amounts for left left panel (only for element theme)
:root {
--llp-background-blur: 120px;
--lp-background-blur: 60px;
--lp-background-overlay: rgba(0, 0, 0, 0.055);
--lp-background-blur: 30px;
}
$composer-shadow-color: rgba(0, 0, 0, 0.04);

Expand Down
166 changes: 22 additions & 144 deletions src/components/structures/BackdropPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,153 +14,31 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { createRef } from "react";
import "context-filter-polyfill";

import UIStore from "../../stores/UIStore";
import React, { CSSProperties } from "react";

interface IProps {
backgroundImage?: CanvasImageSource;
}

interface IState {
// Left Panel image
lpImage?: string;
// Left-left panel image
llpImage?: string;
backgroundImage?: string;
blurMultiplier?: number;
}

export default class BackdropPanel extends React.PureComponent<IProps, IState> {
private leftLeftPanelRef = createRef<HTMLCanvasElement>();
private leftPanelRef = createRef<HTMLCanvasElement>();

private sizes = {
leftLeftPanelWidth: 0,
leftPanelWidth: 0,
height: 0,
};
private style = getComputedStyle(document.documentElement);

public state: IState = {};

public componentDidMount() {
UIStore.instance.on("SpacePanel", this.onResize);
UIStore.instance.on("GroupFilterPanelContainer", this.onResize);
this.onResize();
}

public componentWillUnmount() {
UIStore.instance.off("SpacePanel", this.onResize);
UIStore.instance.on("GroupFilterPanelContainer", this.onResize);
}

public componentDidUpdate(prevProps: IProps) {
if (prevProps.backgroundImage !== this.props.backgroundImage) {
this.setState({});
this.onResize();
export const BackdropPanel: React.FC<IProps> = ({ backgroundImage, blurMultiplier }) => {
if (!backgroundImage) return null;

const styles: CSSProperties = {};
if (blurMultiplier) {
const rootStyle = getComputedStyle(document.documentElement);
const blurValue = rootStyle.getPropertyValue('--lp-background-blur');
const pixelsValue = blurValue.replace('px', '');
const parsed = parseInt(pixelsValue, 10);
if (!isNaN(parsed)) {
styles.filter = `blur(${parsed * blurMultiplier}px)`;
}
}

private onResize = () => {
if (this.props.backgroundImage) {
const groupFilterPanelDimensions = UIStore.instance.getElementDimensions("GroupFilterPanelContainer");
const spacePanelDimensions = UIStore.instance.getElementDimensions("SpacePanel");
const roomListDimensions = UIStore.instance.getElementDimensions("LeftPanel");
this.sizes = {
leftLeftPanelWidth: spacePanelDimensions?.width ?? groupFilterPanelDimensions?.width ?? 0,
leftPanelWidth: roomListDimensions?.width ?? 0,
height: UIStore.instance.windowHeight,
};
this.refreshBackdropImage();
}
};

private refreshBackdropImage = (): void => {
const leftLeftPanelContext = this.leftLeftPanelRef.current.getContext("2d");
const leftPanelContext = this.leftPanelRef.current.getContext("2d");
const { leftLeftPanelWidth, leftPanelWidth, height } = this.sizes;
const width = leftLeftPanelWidth + leftPanelWidth;
const { backgroundImage } = this.props;

const imageWidth = (backgroundImage as ImageBitmap).width;
const imageHeight = (backgroundImage as ImageBitmap).height;

const contentRatio = imageWidth / imageHeight;
const containerRatio = width / height;
let resultHeight;
let resultWidth;
if (contentRatio > containerRatio) {
resultHeight = height;
resultWidth = height * contentRatio;
} else {
resultWidth = width;
resultHeight = width / contentRatio;
}

// This value has been chosen to be as close with rendering as the css-only
// backdrop-filter: blur effect was, mostly takes effect for vertical pictures.
const x = width * 0.1;
const y = (height - resultHeight) / 2;

this.leftLeftPanelRef.current.width = leftLeftPanelWidth;
this.leftLeftPanelRef.current.height = height;
this.leftPanelRef.current.width = (window.screen.width * 0.5);
this.leftPanelRef.current.height = height;

const spacesBlur = this.style.getPropertyValue('--llp-background-blur');
const roomListBlur = this.style.getPropertyValue('--lp-background-blur');

leftLeftPanelContext.filter = `blur(${spacesBlur})`;
leftPanelContext.filter = `blur(${roomListBlur})`;
leftLeftPanelContext.drawImage(
backgroundImage,
0, 0,
imageWidth, imageHeight,
x,
y,
resultWidth,
resultHeight,
);
leftPanelContext.drawImage(
backgroundImage,
0, 0,
imageWidth, imageHeight,
x - leftLeftPanelWidth,
y,
resultWidth,
resultHeight,
);
this.setState({
lpImage: this.leftPanelRef.current.toDataURL('image/jpeg', 1),
llpImage: this.leftLeftPanelRef.current.toDataURL('image/jpeg', 1),

});
};

public render() {
if (!this.props.backgroundImage) return null;
return <div className="mx_BackdropPanel">
{ this.state?.llpImage !== 'data:,' && <img
className="mx_BackdropPanel--canvas"
src={this.state.llpImage} /> }

{ this.state?.lpImage !== 'data:,' && <img
className="mx_BackdropPanel--canvas"
src={this.state.lpImage} /> }
<canvas
ref={this.leftLeftPanelRef}
className="mx_BackdropPanel--canvas"
style={{
display: this.state.lpImage ? 'none' : 'block',
}}
/>
<canvas
style={{
display: this.state.lpImage ? 'none' : 'block',
}}
ref={this.leftPanelRef}
className="mx_BackdropPanel--canvas"
/>
</div>;
}
}
return <div className="mx_BackdropPanel">
<img
style={styles}
className="mx_BackdropPanel--image"
src={backgroundImage} />
</div>;
};
export default BackdropPanel;
Loading