Skip to content

Commit d9ec5bc

Browse files
ergunshDevtools-frontend LUCI CQ
authored andcommitted
[Freestyler] Update the layout and make main own the scroller
After moving the `.input-form` inside `main` container, we switch between it overlaying the messages (with `position: sticky`) or rendering it after the messages depending on the `main`s height. The layout now is: * `main` now owns the scroller which makes the scroller span to the end of the `.input-form`. * when there is empty space between left and right edges of the messages container and input form (main width > 688px), appearing of scrollbar is not causing the layout to shift. * when there isn't empty space between left and right edges of the messages container and input form (main width <= 688px), appearing of scrollbar causes the content to jump from right. * when there isn't empty space between left and right edges of the messages container, the lines of the message touch the edges. * the edges of the message & input form is always aligned. (screenshot crbug.com/40248266#comment38) Drive-by: * There is now less top padding in `.input-form`. Fixed: 372317501, 373600025 Change-Id: Id65d56bf7a424c6c3794180e475902221b8ade4e Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5975457 Commit-Queue: Ergün Erdoğmuş <[email protected]> Reviewed-by: Wolfgang Beyer <[email protected]>
1 parent 25acf9e commit d9ec5bc

File tree

2 files changed

+93
-47
lines changed

2 files changed

+93
-47
lines changed

front_end/panels/freestyler/components/FreestylerChatUi.ts

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ export class FreestylerChatUi extends HTMLElement {
382382
return;
383383
}
384384

385-
const scrollContainer = this.#shadow.querySelector('.messages-scroll-container') as HTMLElement;
385+
const scrollContainer = this.#shadow.querySelector('.chat-ui main') as HTMLElement;
386386
if (!scrollContainer) {
387387
return;
388388
}
@@ -910,14 +910,12 @@ export class FreestylerChatUi extends HTMLElement {
910910
#renderMessages = (): LitHtml.TemplateResult => {
911911
// clang-format off
912912
return html`
913-
<div class="messages-scroll-container" @scroll=${this.#handleScroll}>
914-
<div class="messages-container">
915-
${this.#props.messages.map((message, _, array) =>
916-
this.#renderChatMessage(message, {
917-
isLast: array.at(-1) === message,
918-
}),
919-
)}
920-
</div>
913+
<div class="messages-container">
914+
${this.#props.messages.map((message, _, array) =>
915+
this.#renderChatMessage(message, {
916+
isLast: array.at(-1) === message,
917+
}),
918+
)}
921919
</div>
922920
`;
923921
// clang-format on
@@ -927,7 +925,7 @@ export class FreestylerChatUi extends HTMLElement {
927925
const suggestions = this.#getEmptyStateSuggestions();
928926

929927
// clang-format off
930-
return html`<div class="empty-state-container messages-scroll-container">
928+
return html`<div class="empty-state-container">
931929
<div class="header">
932930
<div class="icon">
933931
<devtools-icon
@@ -1095,7 +1093,7 @@ export class FreestylerChatUi extends HTMLElement {
10951093
#renderDisabledState(contents: LitHtml.TemplateResult): LitHtml.TemplateResult {
10961094
// clang-format off
10971095
return html`
1098-
<div class="empty-state-container messages-scroll-container">
1096+
<div class="empty-state-container">
10991097
<div class="disabled-view">
11001098
<div class="disabled-view-icon-container">
11011099
<devtools-icon .data=${{
@@ -1119,31 +1117,29 @@ export class FreestylerChatUi extends HTMLElement {
11191117

11201118
// clang-format off
11211119
return html`
1122-
<main class="messages-scroll-container" @scroll=${this.#handleScroll}>
1123-
<div class="messages-container">
1124-
<section class="no-agent-message" jslog=${VisualLogging.section('no-agent-entrypoint')}>
1125-
<div class="header">
1126-
<devtools-icon name="smart-assistant"></devtools-icon>
1127-
<h2>${lockedString(UIStringsNotTranslate.ai)}</h2>
1128-
</div>
1129-
<div class="instructions">
1130-
<p>${lockedString(UIStringsNotTranslate.getStarted)}</p>
1131-
${config.devToolsFreestyler?.enabled ? html`
1132-
<p><strong>${lockedString(UIStringsNotTranslate.cssHelp)}</strong> ${lockedString(UIStringsNotTranslate.cssHelpExplainer)}</p>
1133-
` : LitHtml.nothing}
1134-
${(config.devToolsAiAssistanceFileAgent?.enabled || config.devToolsAiAssistanceFileAgentDogfood?.enabled) ? html`
1135-
<p><strong>${lockedString(UIStringsNotTranslate.fileHelp)}</strong> ${lockedString(UIStringsNotTranslate.fileHelpExplainer)}</p>
1136-
` : LitHtml.nothing}
1137-
${(config.devToolsAiAssistanceNetworkAgent?.enabled || config.devToolsExplainThisResourceDogfood?.enabled) ? html`
1138-
<p><strong>${lockedString(UIStringsNotTranslate.networkHelp)}</strong> ${lockedString(UIStringsNotTranslate.networkHelpExplainer)}</p>
1139-
` : LitHtml.nothing}
1140-
${(config.devToolsAiAssistancePerformanceAgent?.enabled || config.devToolsAiAssistancePerformanceAgentDogfood?.enabled) ? html`
1141-
<p><strong>${lockedString(UIStringsNotTranslate.performanceHelp)}</strong> ${lockedString(UIStringsNotTranslate.performanceHelpExplainer)}</p>
1142-
` : LitHtml.nothing}
1143-
</div>
1144-
</section>
1145-
</div>
1146-
</main>
1120+
<div class="messages-container">
1121+
<section class="no-agent-message" jslog=${VisualLogging.section('no-agent-entrypoint')}>
1122+
<div class="header">
1123+
<devtools-icon name="smart-assistant"></devtools-icon>
1124+
<h2>${lockedString(UIStringsNotTranslate.ai)}</h2>
1125+
</div>
1126+
<div class="instructions">
1127+
<p>${lockedString(UIStringsNotTranslate.getStarted)}</p>
1128+
${config.devToolsFreestyler?.enabled ? html`
1129+
<p><strong>${lockedString(UIStringsNotTranslate.cssHelp)}</strong> ${lockedString(UIStringsNotTranslate.cssHelpExplainer)}</p>
1130+
` : LitHtml.nothing}
1131+
${(config.devToolsAiAssistanceFileAgent?.enabled || config.devToolsAiAssistanceFileAgentDogfood?.enabled) ? html`
1132+
<p><strong>${lockedString(UIStringsNotTranslate.fileHelp)}</strong> ${lockedString(UIStringsNotTranslate.fileHelpExplainer)}</p>
1133+
` : LitHtml.nothing}
1134+
${(config.devToolsAiAssistanceNetworkAgent?.enabled || config.devToolsExplainThisResourceDogfood?.enabled) ? html`
1135+
<p><strong>${lockedString(UIStringsNotTranslate.networkHelp)}</strong> ${lockedString(UIStringsNotTranslate.networkHelpExplainer)}</p>
1136+
` : LitHtml.nothing}
1137+
${(config.devToolsAiAssistancePerformanceAgent?.enabled || config.devToolsAiAssistancePerformanceAgentDogfood?.enabled) ? html`
1138+
<p><strong>${lockedString(UIStringsNotTranslate.performanceHelp)}</strong> ${lockedString(UIStringsNotTranslate.performanceHelpExplainer)}</p>
1139+
` : LitHtml.nothing}
1140+
</div>
1141+
</section>
1142+
</div>
11471143
`;
11481144
// clang-format on
11491145
}
@@ -1172,7 +1168,7 @@ export class FreestylerChatUi extends HTMLElement {
11721168
// clang-format off
11731169
LitHtml.render(html`
11741170
<div class="chat-ui">
1175-
<main>
1171+
<main @scroll=${this.#handleScroll}>
11761172
${this.#renderMainContents()}
11771173
<form class="input-form" @submit=${this.#handleSubmit}>
11781174
${this.#props.state !== State.CONSENT_VIEW ? html`

front_end/panels/freestyler/components/freestylerChatUi.css

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,36 @@
3030
.input-form {
3131
display: flex;
3232
flex-direction: column;
33-
padding: var(--sys-size-8) var(--sys-size-5) 0 var(--sys-size-5);
33+
padding: var(--sys-size-5) var(--sys-size-5) 0 var(--sys-size-5);
3434
max-width: var(--sys-size-36);
35+
background-color: var(--sys-color-cdt-base-container);
3536
width: 100%;
37+
position: sticky;
38+
z-index: 9999;
39+
bottom: 0;
40+
/*
41+
The `box-shadow` is a workaround to hide the content appearing between the `.input-form`
42+
and the footer in some resolutions even though the `.input-form` has `bottom: 0`.
43+
*/
44+
box-shadow: 0 1px var(--sys-color-cdt-base-container);
45+
46+
/* Prevents the input form from jumping when the scrollbar is shown */
47+
/* 688px is the max width of the input form + left and right paddings: var(--sys-size-36) + 2 * var(--sys-size-5) */
48+
/* stylelint-disable-next-line at-rule-no-unknown */
49+
@container (width > 688px) {
50+
--half-scrollbar-width: calc((100cqw - 100%) / 2); /* stylelint-disable-line unit-no-unknown */
51+
52+
margin-left: var(--half-scrollbar-width);
53+
margin-right: calc(-1 * var(--half-scrollbar-width));
54+
}
55+
56+
/* when there isn't enough space to view the messages,
57+
do not overlay the input form on top of the messages */
58+
/* height < var(--sys-size-27) */
59+
/* stylelint-disable-next-line at-rule-no-unknown */
60+
@container (height < 224px) {
61+
position: static;
62+
}
3663
}
3764

3865
.chat-input-container {
@@ -102,17 +129,20 @@
102129
}
103130
}
104131

105-
.messages-scroll-container {
106-
overflow: auto;
132+
.messages-container {
107133
flex-grow: 1;
108-
scrollbar-gutter: stable both-edges;
109-
scrollbar-width: thin;
110134
width: 100%;
111-
}
112-
113-
.messages-container {
114-
margin: 0 auto;
115135
max-width: var(--sys-size-36);
136+
137+
/* Prevents the container from jumping when the scrollbar is shown */
138+
/* 688px is the max width of the input form + left and right paddings: var(--sys-size-36) + 2 * var(--sys-size-5) */
139+
/* stylelint-disable-next-line at-rule-no-unknown */
140+
@container (width > 688px) {
141+
--half-scrollbar-width: calc((100cqw - 100%) / 2); /* stylelint-disable-line unit-no-unknown */
142+
143+
margin-left: var(--half-scrollbar-width);
144+
margin-right: calc(-1 * var(--half-scrollbar-width));
145+
}
116146
}
117147

118148
.chat-message {
@@ -436,21 +466,41 @@ button.link {
436466
}
437467

438468
main {
469+
overflow-x: hidden;
470+
overflow-y: auto;
439471
display: flex;
440472
flex-direction: column;
441473
align-items: center;
442474
height: 100%;
443-
overflow-y: auto;
475+
container-type: size; /* stylelint-disable-line property-no-unknown */
476+
scrollbar-width: thin;
477+
/*
478+
Even though `transform: translateZ(1px)` doesn't have a visual effect,
479+
it puts `main` element into another rendering layer which somehow
480+
fixes the `.input-form` jumping on scroll issue.
481+
*/
482+
transform: translateZ(1px);
444483
}
445484

446485
.empty-state-container {
486+
flex-grow: 1;
447487
display: grid;
448488
align-items: center;
449489
justify-content: center;
450490
font: var(--sys-typescale-headline4);
451491
gap: var(--sys-size-11);
452492
padding: var(--sys-size-3);
453493

494+
/* Prevents the container from jumping when the scrollbar is shown */
495+
/* 688px is the max width of the input form + left and right paddings: var(--sys-size-36) + 2 * var(--sys-size-5) */
496+
/* stylelint-disable-next-line at-rule-no-unknown */
497+
@container (width > 688px) {
498+
--half-scrollbar-width: calc((100cqw - 100%) / 2); /* stylelint-disable-line unit-no-unknown */
499+
500+
margin-left: var(--half-scrollbar-width);
501+
margin-right: calc(-1 * var(--half-scrollbar-width));
502+
}
503+
454504
.header {
455505
display: flex;
456506
flex-direction: column;

0 commit comments

Comments
 (0)