diff --git a/pw_web/log-viewer/src/components/log-list/log-list.styles.ts b/pw_web/log-viewer/src/components/log-list/log-list.styles.ts
index 8b6fee61f4..bc45c0de53 100644
--- a/pw_web/log-viewer/src/components/log-list/log-list.styles.ts
+++ b/pw_web/log-viewer/src/components/log-list/log-list.styles.ts
@@ -26,13 +26,14 @@ export const styles = css`
font-family: 'Roboto Mono', monospace;
font-size: 1rem;
height: 100%;
+ overflow: hidden;
position: relative;
}
.table-container {
+ display: grid;
height: 100%;
- overflow: auto;
- padding-bottom: 3rem;
+ overflow: scroll;
scroll-behavior: auto;
width: 100%;
}
@@ -118,7 +119,8 @@ export const styles = css`
}
th[hidden],
- td[hidden] {
+ td[hidden],
+ .jump-to-bottom-btn[hidden] {
display: none;
}
@@ -134,6 +136,15 @@ export const styles = css`
align-items: flex-start;
}
+ .jump-to-bottom-btn {
+ --md-filled-button-container-elevation: 4;
+ --md-filled-button-hover-container-elevation: 4;
+ bottom: 2rem;
+ left: 50%;
+ position: absolute;
+ transform: translate(-50%);
+ }
+
.resize-handle {
background-color: var(--sys-log-viewer-color-table-cell-outline);
bottom: 0;
@@ -186,17 +197,20 @@ export const styles = css`
height: 100%;
pointer-events: none;
position: absolute;
- top: 0;
width: 8rem;
}
- .right-indicator {
+ .bottom-indicator {
+ align-self: flex-end;
background: linear-gradient(
- to right,
+ to bottom,
transparent,
var(--sys-log-viewer-color-overflow-indicator)
);
- right: 0;
+ height: 8rem;
+ pointer-events: none;
+ position: absolute;
+ width: 100%;
}
.left-indicator {
@@ -205,7 +219,16 @@ export const styles = css`
transparent,
var(--sys-log-viewer-color-overflow-indicator)
);
- left: 0;
+ justify-self: flex-start;
+ }
+
+ .right-indicator {
+ background: linear-gradient(
+ to right,
+ transparent,
+ var(--sys-log-viewer-color-overflow-indicator)
+ );
+ justify-self: flex-end;
}
mark {
@@ -214,4 +237,40 @@ export const styles = css`
color: var(--md-sys-color-on-primary-container);
outline: 1px solid var(--sys-log-viewer-color-table-mark);
}
+
+ ::-webkit-scrollbar {
+ -webkit-appearance: auto;
+ }
+
+ ::-webkit-scrollbar-corner {
+ background: var(--md-sys-color-surface-container-low);
+ }
+
+ ::-webkit-scrollbar-thumb {
+ min-height: 3rem;
+ }
+
+ ::-webkit-scrollbar-thumb:horizontal {
+ border-radius: 20px;
+ box-shadow: inset 0 0 2rem 2rem var(--md-sys-color-outline-variant);
+ border: inset 3px transparent;
+ border-top: inset 4px transparent;
+ }
+
+ ::-webkit-scrollbar-thumb:vertical {
+ border-radius: 20px;
+ box-shadow: inset 0 0 2rem 2rem var(--md-sys-color-outline-variant);
+ border: inset 3px transparent;
+ border-left: inset 4px transparent;
+ }
+
+ ::-webkit-scrollbar-track:horizontal {
+ box-shadow: inset 0 0 2rem 2rem var(--md-sys-color-surface-container-low);
+ border-top: solid 1px var(--md-sys-color-outline-variant);
+ }
+
+ ::-webkit-scrollbar-track:vertical {
+ box-shadow: inset 0 0 2rem 2rem var(--md-sys-color-surface-container-low);
+ border-left: solid 1px var(--md-sys-color-outline-variant);
+ }
`;
diff --git a/pw_web/log-viewer/src/components/log-list/log-list.ts b/pw_web/log-viewer/src/components/log-list/log-list.ts
index 2f0343ff1d..89d0a7fa41 100644
--- a/pw_web/log-viewer/src/components/log-list/log-list.ts
+++ b/pw_web/log-viewer/src/components/log-list/log-list.ts
@@ -60,10 +60,14 @@ export class LogList extends LitElement {
@state()
private _isOverflowingToRight = false;
- /** A number reprecenting the scroll percentage in the horizontal direction. */
+ /** A number representing the scroll percentage in the horizontal direction. */
@state()
private _scrollPercentageLeft = 0;
+ /** A number representing visibility of vertical scroll indicator. */
+ @state()
+ private _scrollDownOpacity = 0;
+
/**
* Indicates whether to automatically scroll the table container to the
* bottom when new log entries are added.
@@ -71,6 +75,7 @@ export class LogList extends LitElement {
@state()
private _autoscrollIsEnabled = true;
+ @query('.jump-to-bottom-btn') private _jumpBottomBtn!: HTMLButtonElement;
@query('.table-container') private _tableContainer!: HTMLDivElement;
@query('table') private _table!: HTMLTableElement;
@query('tbody') private _tableBody!: HTMLTableSectionElement;
@@ -115,7 +120,7 @@ export class LogList extends LitElement {
if (changedProperties.has('logs')) {
this.setFieldNames(this.logs);
- this.scrollTableToBottom();
+ this.handleTableScroll();
}
if (changedProperties.has('colsHidden')) {
@@ -151,19 +156,22 @@ export class LogList extends LitElement {
/** Called when the Lit virtualizer updates its range of entries. */
private onRangeChanged = () => {
this.updateGridTemplateColumns();
- this.scrollTableToBottom();
+ if (this._autoscrollIsEnabled) {
+ this.scrollTableToBottom();
+ }
};
- /** Scrolls to the bottom of the table container if autoscroll is enabled. */
+ /** Scrolls to the bottom of the table container. */
private scrollTableToBottom() {
- if (this._autoscrollIsEnabled) {
- const container = this._tableContainer;
+ const container = this._tableContainer;
- // TODO(b/289101398): Refactor `setTimeout` usage
- setTimeout(() => {
- container.scrollTop = container.scrollHeight;
- }, 0); // Complete any rendering tasks before scrolling
- }
+ // TODO(b/289101398): Refactor `setTimeout` usage
+ setTimeout(() => {
+ container.scrollTop = container.scrollHeight;
+ this._autoscrollIsEnabled = true;
+ this._jumpBottomBtn.hidden = true;
+ this._scrollDownOpacity = 0;
+ }, 0); // Complete any rendering tasks before scrolling
}
/** Clears the `gridTemplateColumns` value for all rows in the table. */
@@ -275,13 +283,15 @@ export class LogList extends LitElement {
this._scrollPercentageLeft = scrollLeft / maxScrollLeft || 0;
if (
- container.scrollHeight - container.scrollTop <=
- container.offsetHeight
+ Math.floor(container.scrollHeight - container.scrollTop) <=
+ Math.floor(container.offsetHeight)
) {
- this._autoscrollIsEnabled = true;
+ this.scrollTableToBottom();
return;
}
this._autoscrollIsEnabled = false;
+ this._jumpBottomBtn.hidden = false;
+ this._scrollDownOpacity = 1;
this.requestUpdate();
};
@@ -343,7 +353,7 @@ export class LogList extends LitElement {
for (let i = 0; i < totalColumns; i++) {
if (i === columnIndex) {
gridTemplateColumns += `${newWidth}px `;
- return;
+ continue;
}
const otherColumnHeader = this._table.querySelector(
`th:nth-child(${i + 1})`,
@@ -378,9 +388,17 @@ export class LogList extends LitElement {
})}
-
${this.overflowIndicators()}
+