Initial attempt at sticky headers

Docs enclosed in diff.
This commit is contained in:
Travis Ralston
2020-06-13 11:54:40 -06:00
parent cbe9ade1c9
commit 1bbf2e053b
4 changed files with 154 additions and 10 deletions

View File

@@ -86,6 +86,70 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
}
};
// TODO: Apply this on resize, init, etc for reliability
private onScroll = (ev: React.MouseEvent<HTMLDivElement>) => {
const list = ev.target as HTMLDivElement;
const rlRect = list.getBoundingClientRect();
const bottom = rlRect.bottom;
const top = rlRect.top;
const sublists = list.querySelectorAll<HTMLDivElement>(".mx_RoomSublist2");
const headerHeight = 32; // Note: must match the CSS!
const headerRightMargin = 24; // calculated from margins and widths to align with non-sticky tiles
const headerStickyWidth = rlRect.width - headerRightMargin;
let gotBottom = false;
for (const sublist of sublists) {
const slRect = sublist.getBoundingClientRect();
const header = sublist.querySelector<HTMLDivElement>(".mx_RoomSublist2_headerText");
if (slRect.top + headerHeight > bottom && !gotBottom) {
console.log(`${header.textContent} is off the bottom`);
header.classList.add("mx_RoomSublist2_headerContainer_sticky");
header.classList.add("mx_RoomSublist2_headerContainer_stickyBottom");
header.style.width = `${headerStickyWidth}px`;
gotBottom = true;
} else if (slRect.top < top) {
console.log(`${header.textContent} is off the top`);
header.classList.add("mx_RoomSublist2_headerContainer_sticky");
header.classList.add("mx_RoomSublist2_headerContainer_stickyTop");
header.style.width = `${headerStickyWidth}px`;
header.style.top = `${rlRect.top}px`;
} else {
header.classList.remove("mx_RoomSublist2_headerContainer_sticky");
header.classList.remove("mx_RoomSublist2_headerContainer_stickyTop");
header.classList.remove("mx_RoomSublist2_headerContainer_stickyBottom");
header.style.width = `unset`;
}
// const name = header.textContent;
// if (hRect.bottom + headerHeight < top) {
// // Before the content (top of list)
// header.classList.add(
// "mx_RoomSublist2_headerContainer_sticky",
// "mx_RoomSublist2_headerContainer_stickyTop",
// );
// } else {
// header.classList.remove(
// "mx_RoomSublist2_headerContainer_sticky",
// "mx_RoomSublist2_headerContainer_stickyTop",
// "mx_RoomSublist2_headerContainer_stickyBottom",
// );
// }
// if (!hitMiddle && (headerHeight + hRect.top) >= bottom) {
// // if we got here, the header is visible
// hitMiddle = true;
// header.style.backgroundColor = 'red';
// } else {
// header.style.top = "0px";
// header.style.bottom = "unset";
// header.style.backgroundColor = "unset";
// }
}
};
private renderHeader(): React.ReactNode {
// TODO: Update when profile info changes
// TODO: Presence
@@ -191,7 +255,7 @@ export default class LeftPanel2 extends React.Component<IProps, IState> {
<aside className="mx_LeftPanel2_roomListContainer">
{this.renderHeader()}
{this.renderSearchExplore()}
<div className="mx_LeftPanel2_actualRoomListContainer">
<div className="mx_LeftPanel2_actualRoomListContainer" onScroll={this.onScroll}>
{roomList}
</div>
</aside>

30
src/utils/css.ts Normal file
View File

@@ -0,0 +1,30 @@
/*
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.
*/
export function addClass(classes: string, clazz: string): string {
if (!classes.includes(clazz)) return `${classes} ${clazz}`;
return classes;
}
export function removeClass(classes: string, clazz: string): string {
const idx = classes.indexOf(clazz);
if (idx >= 0) {
const beforeStr = classes.substring(0, idx);
const afterStr = classes.substring(idx + clazz.length);
return `${beforeStr} ${afterStr}`.trim();
}
return classes;
}