Rework backdrop to draw one image with two different level of blur
This commit is contained in:
parent
36ba65b534
commit
8f345dc1ba
8 changed files with 89 additions and 61 deletions
|
@ -18,7 +18,6 @@ $groupFilterPanelWidth: 56px; // only applies in this file, used for calculation
|
||||||
$roomListCollapsedWidth: 68px;
|
$roomListCollapsedWidth: 68px;
|
||||||
|
|
||||||
.mx_LeftPanel {
|
.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
|
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
|
||||||
min-width: 206px;
|
min-width: 206px;
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
|
|
|
@ -39,10 +39,10 @@ limitations under the License.
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_MatrixToolbar {
|
.mx_MatrixToolbar {
|
||||||
|
@ -76,7 +76,7 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not the left panel, and not the resize handle, so the roomview/groupview/... */
|
/* not the left panel, and not the resize handle, so the roomview/groupview/... */
|
||||||
.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle) {
|
.mx_MatrixChat > :not(.mx_LeftPanel):not(.mx_SpacePanel):not(.mx_ResizeHandle):not(canvas) {
|
||||||
background-color: $primary-bg-color;
|
background-color: $primary-bg-color;
|
||||||
|
|
||||||
flex: 1 1 0;
|
flex: 1 1 0;
|
||||||
|
|
|
@ -24,7 +24,6 @@ $activeBorderColor: $secondary-fg-color;
|
||||||
|
|
||||||
.mx_SpacePanel {
|
.mx_SpacePanel {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
background-color: $groupFilterPanel-bg-color;
|
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -17,25 +17,44 @@ limitations under the License.
|
||||||
import React, { createRef } from "react";
|
import React, { createRef } from "react";
|
||||||
import "context-filter-polyfill";
|
import "context-filter-polyfill";
|
||||||
|
|
||||||
|
import UIStore from "../../stores/UIStore";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
width?: number;
|
|
||||||
height?: number;
|
|
||||||
backgroundImage?: CanvasImageSource;
|
backgroundImage?: CanvasImageSource;
|
||||||
blur?: string;
|
|
||||||
opacity?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class BackdropPanel extends React.PureComponent<IProps> {
|
interface IState {
|
||||||
private canvasRef = createRef<HTMLCanvasElement>();
|
spacePanelWidth: number;
|
||||||
private ctx: CanvasRenderingContext2D;
|
roomListWidth: number;
|
||||||
|
viewportHeight: number;
|
||||||
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
export default class BackdropPanel extends React.PureComponent<IProps, IState> {
|
||||||
blur: "60px",
|
private spacesCanvasRef = createRef<HTMLCanvasElement>();
|
||||||
opacity: .15,
|
private roomListCanvasRef = createRef<HTMLCanvasElement>();
|
||||||
};
|
|
||||||
|
private spacesCtx: CanvasRenderingContext2D;
|
||||||
|
private roomListCtx: CanvasRenderingContext2D;
|
||||||
|
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
spacePanelWidth: 0,
|
||||||
|
roomListWidth: 0,
|
||||||
|
viewportHeight: UIStore.instance.windowHeight,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
this.ctx = this.canvasRef.current.getContext("2d");
|
this.spacesCtx = this.spacesCanvasRef.current.getContext("2d");
|
||||||
|
this.roomListCtx = this.roomListCanvasRef.current.getContext("2d");
|
||||||
|
UIStore.instance.on("SpacePanel", this.onResize);
|
||||||
|
UIStore.instance.on("LeftPanel", this.onResize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
UIStore.instance.off("SpacePanel", this.onResize);
|
||||||
|
UIStore.instance.off("LeftPanel", this.onResize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidUpdate() {
|
public componentDidUpdate() {
|
||||||
|
@ -44,15 +63,25 @@ export default class BackdropPanel extends React.PureComponent<IProps> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onResize = () => {
|
||||||
|
const spacePanelDimensions = UIStore.instance.getElementDimensions("SpacePanel");
|
||||||
|
const roomListDimensions = UIStore.instance.getElementDimensions("LeftPanel");
|
||||||
|
this.setState({
|
||||||
|
spacePanelWidth: spacePanelDimensions ? spacePanelDimensions.width : 0,
|
||||||
|
roomListWidth: roomListDimensions ? roomListDimensions.width : 0,
|
||||||
|
viewportHeight: UIStore.instance.windowHeight,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
private refreshBackdropImage = (): void => {
|
private refreshBackdropImage = (): void => {
|
||||||
const { width, height, backgroundImage } = this.props;
|
const width = this.state.spacePanelWidth + this.state.roomListWidth;
|
||||||
this.canvasRef.current.width = width;
|
const height = this.state.viewportHeight;
|
||||||
this.canvasRef.current.height = height;
|
const { backgroundImage } = this.props;
|
||||||
|
|
||||||
const imageWidth = (backgroundImage as ImageBitmap).width
|
const imageWidth = (backgroundImage as ImageBitmap).width
|
||||||
|| (backgroundImage as HTMLImageElement).naturalWidth;
|
|| (backgroundImage as HTMLImageElement).naturalWidth;
|
||||||
const imageHeight = (backgroundImage as ImageBitmap).height
|
const imageHeight = (backgroundImage as ImageBitmap).height
|
||||||
|| (backgroundImage as HTMLImageElement).naturalHeight;
|
|| (backgroundImage as HTMLImageElement).naturalHeight;
|
||||||
|
|
||||||
const contentRatio = imageWidth / imageHeight;
|
const contentRatio = imageWidth / imageHeight;
|
||||||
const containerRatio = width / height;
|
const containerRatio = width / height;
|
||||||
|
@ -69,23 +98,48 @@ export default class BackdropPanel extends React.PureComponent<IProps> {
|
||||||
const x = (width - resultWidth) / 2;
|
const x = (width - resultWidth) / 2;
|
||||||
const y = (height - resultHeight) / 2;
|
const y = (height - resultHeight) / 2;
|
||||||
|
|
||||||
this.ctx.filter = `blur(${this.props.blur})`;
|
this.spacesCanvasRef.current.width = this.state.spacePanelWidth;
|
||||||
this.ctx.drawImage(
|
this.spacesCanvasRef.current.height = this.state.viewportHeight;
|
||||||
|
this.roomListCanvasRef.current.width = this.state.roomListWidth;
|
||||||
|
this.roomListCanvasRef.current.height = this.state.viewportHeight;
|
||||||
|
|
||||||
|
this.spacesCtx.filter = `blur(30px)`;
|
||||||
|
this.roomListCtx.filter = `blur(60px)`;
|
||||||
|
this.spacesCtx.drawImage(
|
||||||
backgroundImage,
|
backgroundImage,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
resultWidth,
|
resultWidth,
|
||||||
resultHeight,
|
resultHeight,
|
||||||
);
|
);
|
||||||
|
this.roomListCtx.drawImage(
|
||||||
|
backgroundImage,
|
||||||
|
0, 0,
|
||||||
|
imageWidth, imageHeight,
|
||||||
|
x - this.state.spacePanelWidth,
|
||||||
|
y,
|
||||||
|
resultWidth,
|
||||||
|
resultHeight,
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <canvas
|
return <>
|
||||||
ref={this.canvasRef}
|
<canvas
|
||||||
className="mx_BackdropPanel"
|
ref={this.spacesCanvasRef}
|
||||||
style={{
|
className="mx_BackdropPanel"
|
||||||
opacity: this.props.opacity,
|
style={{
|
||||||
}}
|
opacity: .15,
|
||||||
/>;
|
}}
|
||||||
|
/>
|
||||||
|
<canvas
|
||||||
|
style={{
|
||||||
|
transform: `translateX(${this.state.spacePanelWidth}px)`,
|
||||||
|
opacity: .1,
|
||||||
|
}}
|
||||||
|
ref={this.roomListCanvasRef}
|
||||||
|
className="mx_BackdropPanel"
|
||||||
|
/>
|
||||||
|
</>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import UserTagTile from "../views/elements/UserTagTile";
|
import UserTagTile from "../views/elements/UserTagTile";
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import BackdropPanel from "./BackdropPanel";
|
|
||||||
import UIStore from "../../stores/UIStore";
|
import UIStore from "../../stores/UIStore";
|
||||||
|
|
||||||
@replaceableComponent("structures.GroupFilterPanel")
|
@replaceableComponent("structures.GroupFilterPanel")
|
||||||
|
@ -153,14 +152,7 @@ class GroupFilterPanel extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const panelDimensions = UIStore.instance.getElementDimensions("GroupPanel");
|
|
||||||
|
|
||||||
return <div className={classes} onClick={this.onClearFilterClick} ref={this.ref}>
|
return <div className={classes} onClick={this.onClearFilterClick} ref={this.ref}>
|
||||||
<BackdropPanel
|
|
||||||
backgroundImage={this.props.backgroundImage}
|
|
||||||
width={panelDimensions?.width}
|
|
||||||
height={panelDimensions?.height}
|
|
||||||
/>
|
|
||||||
<AutoHideScrollbar
|
<AutoHideScrollbar
|
||||||
className="mx_GroupFilterPanel_scroller"
|
className="mx_GroupFilterPanel_scroller"
|
||||||
onClick={this.onClick}
|
onClick={this.onClick}
|
||||||
|
|
|
@ -43,12 +43,10 @@ import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore";
|
import SpaceStore, { UPDATE_SELECTED_SPACE } from "../../stores/SpaceStore";
|
||||||
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
|
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
|
||||||
import UIStore from "../../stores/UIStore";
|
import UIStore from "../../stores/UIStore";
|
||||||
import BackdropPanel from "./BackdropPanel";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
isMinimized: boolean;
|
isMinimized: boolean;
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
backgroundImage?: CanvasImageSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -426,7 +424,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
if (this.state.showGroupFilterPanel) {
|
if (this.state.showGroupFilterPanel) {
|
||||||
leftLeftPanel = (
|
leftLeftPanel = (
|
||||||
<div className="mx_LeftPanel_GroupFilterPanelContainer">
|
<div className="mx_LeftPanel_GroupFilterPanelContainer">
|
||||||
<GroupFilterPanel backgroundImage={this.props.backgroundImage} />
|
<GroupFilterPanel />
|
||||||
{SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null}
|
{SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -453,15 +451,8 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
"mx_AutoHideScrollbar",
|
"mx_AutoHideScrollbar",
|
||||||
);
|
);
|
||||||
|
|
||||||
const panelDimensions = UIStore.instance.getElementDimensions("LeftPanel");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={containerClasses} ref={this.ref}>
|
<div className={containerClasses} ref={this.ref}>
|
||||||
<BackdropPanel
|
|
||||||
backgroundImage={this.props.backgroundImage}
|
|
||||||
width={panelDimensions?.width}
|
|
||||||
height={panelDimensions?.height}
|
|
||||||
/>
|
|
||||||
{leftLeftPanel}
|
{leftLeftPanel}
|
||||||
<aside className="mx_LeftPanel_roomListContainer">
|
<aside className="mx_LeftPanel_roomListContainer">
|
||||||
{this.renderHeader()}
|
{this.renderHeader()}
|
||||||
|
|
|
@ -65,6 +65,7 @@ import ToastContainer from './ToastContainer';
|
||||||
import MyGroups from "./MyGroups";
|
import MyGroups from "./MyGroups";
|
||||||
import UserView from "./UserView";
|
import UserView from "./UserView";
|
||||||
import GroupView from "./GroupView";
|
import GroupView from "./GroupView";
|
||||||
|
import BackdropPanel from "./BackdropPanel";
|
||||||
|
|
||||||
// We need to fetch each pinned message individually (if we don't already have it)
|
// We need to fetch each pinned message individually (if we don't already have it)
|
||||||
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
||||||
|
@ -643,13 +644,15 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
>
|
>
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
<div ref={this._resizeContainer} className={bodyClasses}>
|
<div ref={this._resizeContainer} className={bodyClasses}>
|
||||||
|
<BackdropPanel
|
||||||
|
backgroundImage={this.state.backgroundImage}
|
||||||
|
/>
|
||||||
{ SettingsStore.getValue("feature_spaces")
|
{ SettingsStore.getValue("feature_spaces")
|
||||||
? <SpacePanel backgroundImage={this.state.backgroundImage} />
|
? <SpacePanel />
|
||||||
: null }
|
: null }
|
||||||
<LeftPanel
|
<LeftPanel
|
||||||
isMinimized={this.props.collapseLhs || false}
|
isMinimized={this.props.collapseLhs || false}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
backgroundImage={this.state.backgroundImage}
|
|
||||||
/>
|
/>
|
||||||
<ResizeHandle />
|
<ResizeHandle />
|
||||||
{ pageElement }
|
{ pageElement }
|
||||||
|
|
|
@ -43,7 +43,6 @@ import { Key } from "../../../Keyboard";
|
||||||
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
||||||
import { NotificationState } from "../../../stores/notifications/NotificationState";
|
import { NotificationState } from "../../../stores/notifications/NotificationState";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import BackdropPanel from "../../structures/BackdropPanel";
|
|
||||||
import UIStore from "../../../stores/UIStore";
|
import UIStore from "../../../stores/UIStore";
|
||||||
|
|
||||||
interface IButtonProps {
|
interface IButtonProps {
|
||||||
|
@ -180,9 +179,7 @@ const InnerSpacePanel = React.memo<IInnerSpacePanelProps>(({ children, isPanelCo
|
||||||
</div>;
|
</div>;
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {}
|
||||||
backgroundImage?: CanvasImageSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SpacePanel = (props: IProps) => {
|
const SpacePanel = (props: IProps) => {
|
||||||
// We don't need the handle as we position the menu in a constant location
|
// We don't need the handle as we position the menu in a constant location
|
||||||
|
@ -274,7 +271,6 @@ const SpacePanel = (props: IProps) => {
|
||||||
UIStore.instance.stopTrackingElementDimensions("SpacePanel");
|
UIStore.instance.stopTrackingElementDimensions("SpacePanel");
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
const panelDimensions = UIStore.instance.getElementDimensions("SpacePanel");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DragDropContext onDragEnd={result => {
|
<DragDropContext onDragEnd={result => {
|
||||||
|
@ -288,12 +284,6 @@ const SpacePanel = (props: IProps) => {
|
||||||
onKeyDown={onKeyDownHandler}
|
onKeyDown={onKeyDownHandler}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
<BackdropPanel
|
|
||||||
backgroundImage={props.backgroundImage}
|
|
||||||
width={panelDimensions?.width}
|
|
||||||
height={panelDimensions?.height}
|
|
||||||
opacity={.3}
|
|
||||||
/>
|
|
||||||
<Droppable droppableId="top-level-spaces">
|
<Droppable droppableId="top-level-spaces">
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
<AutoHideScrollbar
|
<AutoHideScrollbar
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue