Implement IRC draggable display name width

pull/21833/head
Jorik Schellekens 2020-05-13 02:16:43 +01:00
parent fef4d882c4
commit 5029c3f143
7 changed files with 207 additions and 8 deletions

View File

@ -14,13 +14,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
$name-width: 70px;
$icon-width: 14px;
$timestamp-width: 45px;
$right-padding: 5px;
$irc-line-height: $font-18px;
.mx_IRCLayout {
--name-width: 70px;
line-height: $irc-line-height !important;
@ -48,7 +48,7 @@ $irc-line-height: $font-18px;
> .mx_SenderProfile {
order: 2;
flex-shrink: 0;
width: $name-width;
width: var(--name-width);
text-overflow: ellipsis;
text-align: right;
display: flex;
@ -122,7 +122,7 @@ $irc-line-height: $font-18px;
.mx_EventTile_emote {
> .mx_EventTile_avatar {
margin-left: calc($name-width + $icon-width + $right-padding);
margin-left: calc(var(--name-width) + $icon-width + $right-padding);
}
}
@ -132,7 +132,7 @@ $irc-line-height: $font-18px;
.mx_EventListSummary {
> .mx_EventTile_line {
padding-left: calc($name-width + $icon-width + $timestamp-width + 3 * $right-padding); // 15 px of padding
padding-left: calc(var(--name-width) + $icon-width + $timestamp-width + 3 * $right-padding); // 15 px of padding
}
.mx_EventListSummary_avatars {
@ -143,12 +143,12 @@ $irc-line-height: $font-18px;
.mx_EventTile.mx_EventTile_info {
.mx_EventTile_avatar {
left: calc($name-width + 10px + $icon-width);
left: calc(var(--name-width) + 10px + $icon-width);
top: 0;
}
.mx_EventTile_line {
left: calc($name-width + 10px + $icon-width);
left: calc(var(--name-width) + 10px + $icon-width);
}
.mx_TextualEvent {
@ -198,7 +198,16 @@ $irc-line-height: $font-18px;
margin: 0;
.mx_SenderProfile {
width: unset;
max-width: $name-width;
max-width: var(--name-width);
}
}
.mx_ProfileResizer {
position: absolute;
height: 100%;
width: 15px;
left: calc(80px + var(--name-width));
cursor: col-resize;
z-index: 100;
}
}

View File

@ -29,6 +29,7 @@ import SettingsStore from '../../settings/SettingsStore';
import {_t} from "../../languageHandler";
import {haveTileForEvent} from "../views/rooms/EventTile";
import {textForEvent} from "../../TextForEvent";
import IRCTimelineProfileResizer from "../views/elements/IRCTimelineProfileResizer";
const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes
const continuedTypes = ['m.sticker', 'm.room.message'];
@ -819,6 +820,11 @@ export default class MessagePanel extends React.Component {
);
}
let ircResizer = null;
if (this.state.useIRCLayout) {
ircResizer = <IRCTimelineProfileResizer minWidth={20} maxWidth={600} roomId={this.props.room.roomId} />;
}
return (
<ErrorBoundary>
<ScrollPanel
@ -831,6 +837,7 @@ export default class MessagePanel extends React.Component {
style={style}
stickyBottom={this.props.stickyBottom}
resizeNotifier={this.props.resizeNotifier}
fixedChildren={ircResizer}
>
{ topSpinner }
{ this._getEventTiles() }

View File

@ -144,6 +144,11 @@ export default createReactClass({
/* resizeNotifier: ResizeNotifier to know when middle column has changed size
*/
resizeNotifier: PropTypes.object,
/* fixedChildren: allows for children to be passed which are rendered outside
* of the wrapper
*/
fixedChildren: PropTypes.node,
},
getDefaultProps: function() {
@ -881,6 +886,7 @@ export default createReactClass({
return (<AutoHideScrollbar wrappedRef={this._collectScroll}
onScroll={this.onScroll}
className={`mx_ScrollPanel ${this.props.className}`} style={this.props.style}>
{ this.props.fixedChildren }
<div className="mx_RoomView_messageListWrapper">
<ol ref={this._itemlist} className="mx_RoomView_MessageList" aria-live="polite" role="list">
{ this.props.children }

View File

@ -0,0 +1,84 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
interface IProps {
className: string,
dragFunc: (currentLocation: ILocationState, event: MouseEvent) => ILocationState,
onMouseUp: (event: MouseEvent) => void,
}
interface IState {
onMouseMove: (event: MouseEvent) => void,
onMouseUp: (event: MouseEvent) => void,
location: ILocationState,
}
export interface ILocationState {
currentX: number,
currentY: number,
}
export default class Draggable extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
onMouseMove: this.onMouseMove.bind(this),
onMouseUp: this.onMouseUp.bind(this),
location: {
currentX: 0,
currentY: 0,
},
};
}
private onMouseDown = (event: MouseEvent): void => {
this.setState({
location: {
currentX: event.clientX,
currentY: event.clientY,
},
});
document.addEventListener("mousemove", this.state.onMouseMove);
document.addEventListener("mouseup", this.state.onMouseUp);
console.log("Mouse down")
}
private onMouseUp = (event: MouseEvent): void => {
document.removeEventListener("mousemove", this.state.onMouseMove);
document.removeEventListener("mouseup", this.state.onMouseUp);
this.props.onMouseUp(event);
console.log("Mouse up")
}
private onMouseMove(event: MouseEvent): void {
console.log("Mouse Move")
const newLocation = this.props.dragFunc(this.state.location, event);
this.setState({
location: newLocation,
});
}
render() {
return <div className={this.props.className} onMouseDown={this.onMouseDown.bind(this)} />
}
}

View File

@ -73,7 +73,7 @@ export default class ErrorBoundary extends React.PureComponent {
if (this.state.error) {
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
const newIssueUrl = "https://github.com/vector-im/riot-web/issues/new";
return <div className="mx_ErrorBoundary">
return <div className="mx_ErrorBoundary mx_IRCLayout">
<div className="mx_ErrorBoundary_body">
<h1>{_t("Something went wrong!")}</h1>
<p>{_t(

View File

@ -0,0 +1,86 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import React from 'react';
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
import Draggable, {ILocationState} from './Draggable';
interface IProps {
// Current room
roomId: string,
minWidth: number,
maxWidth: number,
};
interface IState {
width: number,
IRCLayoutRoot: HTMLElement,
};
export default class IRCTimelineProfileResizer extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
width: SettingsStore.getValue("ircDisplayNameWidth", this.props.roomId),
IRCLayoutRoot: null,
}
};
componentDidMount() {
this.setState({
IRCLayoutRoot: document.querySelector(".mx_IRCLayout") as HTMLElement,
}, () => this.updateCSSWidth(this.state.width))
}
private dragFunc = (location: ILocationState, event: React.MouseEvent<Element, MouseEvent>): ILocationState => {
const offset = event.clientX - location.currentX;
const newWidth = this.state.width + offset;
console.log({offset})
// If we're trying to go smaller than min width, don't.
if (this.state.width <= this.props.minWidth && offset <= 0) {
return location;
}
if (this.state.width >= this.props.maxWidth && offset >= 0) {
return location;
}
this.setState({
width: newWidth,
});
this.updateCSSWidth.bind(this)(newWidth);
return {
currentX: event.clientX,
currentY: location.currentY,
}
}
private updateCSSWidth(newWidth: number) {
this.state.IRCLayoutRoot.style.setProperty("--name-width", newWidth + "px");
}
private onMoueUp(event: MouseEvent) {
SettingsStore.setValue("ircDisplayNameWidth", this.props.roomId, SettingLevel.ROOM_DEVICE, this.state.width);
}
render() {
return <Draggable className="mx_ProfileResizer" dragFunc={this.dragFunc.bind(this)} onMouseUp={this.onMoueUp.bind(this)}/>
}
};

View File

@ -531,4 +531,11 @@ export const SETTINGS = {
MatrixClient.prototype.setCryptoTrustCrossSignedDevices, true,
),
},
"ircDisplayNameWidth": {
// We specifically want to have room-device > device so that users may set a device default
// with a per-room override.
supportedLevels: ['room-device', 'device'],
displayName: _td("IRC display name width"),
default: 80,
},
};