[ntp-history] Actionable header tile
A follow up will address the entire header tile being focusable when
the suggestion chip feature flag is false.
Demo:
Narrow modules:
https://drive.google.com/file/d/1AclQjcAOZH1_dZRrrHIccQIJLdqvUFZw/view
Screenshots:
https://drive.google.com/corp/drive/u/0/folders/1i3eicOrVdcm6IEB3dq4IWICUWuOuameK
https://drive.google.com/file/d/1CBcgT1GpANPWRkqXajyzSfmiJjGd8-yz/view
Fixed: 1474050
Change-Id: Ib7b2b84d6ba35d07a75a1b617fef862c3d9d7a76
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4827348
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Reviewed-by: Marlon Facey <mfacey@chromium.org>
Commit-Queue: Roman Arora <romanarora@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1191458}
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html
index 47cb2fa3..a021504 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html
+++ b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.html
@@ -4,13 +4,10 @@
border-radius: var(--ntp-module-item-border-radius);
display: flex;
flex-direction: column;
+ position: relative;
}
- :host([suggestion-chip-header-enabled_]) {
- background: transparent;
- border: none;
- }
-
+ :host([suggestion-chip-header-enabled_]),
:host([suggestion-chip-header-enabled_]) ntp-module-header-v2 {
background: transparent;
border: none;
@@ -24,26 +21,51 @@
}
}
- #label-container {
+ .label-container {
color: var(--color-new-tab-page-primary-foreground);
display: flex;
font-size: 20px;
height: 48px;
line-height: 24px;
+ margin-top: 8px;
padding: 0 16px;
}
- :host([suggestion-chip-header-enabled_]) #label-container {
- background: var(--color-new-tab-page-module-item-background);
- border-radius: var(--ntp-module-item-border-radius);
- height: 100%;
+ :host(:not([suggestion-chip-header-enabled_]):hover) {
+ cursor: pointer;
}
- :host([suggestion-chip-header-enabled_][format='wide']:not([show-related-searches])) #label-container {
- align-items: start;
- padding: 16px;
+ :host(:not([suggestion-chip-header-enabled_]):hover) .hover-layer,
+ #suggestion-chip:hover .hover-layer {
+ background: var(--color-new-tab-page-module-item-background-hovered);
+ display: block;
+ inset: 0;
+ position: absolute;
}
+ .hover-layer {
+ border-radius: var(--ntp-module-item-border-radius);
+ display: none;
+ pointer-events: none;
+ }
+
+ :host([suggestion-chip-header-enabled_]) .label-container {
+ background: var(--color-new-tab-page-module-item-background);
+ border-radius: var(--ntp-module-item-border-radius);
+ }
+
+ :host([suggestion-chip-header-enabled_][format='wide']:not([show-related-searches]))
+ .label-container {
+ align-items: start;
+ }
+
+ :host([suggestion-chip-header-enabled_][format='wide']
+ :not([show-related-searches])) #suggestion-chip {
+ height: 116px;
+ }
+
+
+
h2 {
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
@@ -62,13 +84,21 @@
#suggestion-chip {
display: flex;
font-size: var(--ntp-module-text-size);
+ position: relative;
+ text-decoration: none;
+ }
+
+ #suggestion-chip:focus, #suggestion-chip:focus-visible {
+ box-shadow: var(--ntp-focus-shadow);
+ outline: none;
}
#suggestion-chip-icon {
--cr-icon-ripple-size: 16px;
--cr-icon-image: url(chrome://resources/images/icon_history.svg);
+ align-self: center;
background-color: var(--color-new-tab-page-primary-foreground);
- margin: auto;
+ margin: 16px 0;
}
#suggestion-chip-label {
@@ -77,6 +107,7 @@
line-height: 20px;
}
</style>
+<div class="hover-layer" hidden="[[suggestionChipHeaderEnabled_]]"></div>
<ntp-module-header-v2
id="moduleHeaderElementV2"
header-text="[[i18n('modulesJourneysResumeJourney', '')]]"
@@ -84,12 +115,13 @@
menu-item-groups="[[getMenuItemGroups_()]]"
more-actions-text="[[i18n('modulesMoreActions', clusterLabel)]]">
</ntp-module-header-v2>
-<div id="label-container">
- <h2 id="label" hidden="[[suggestionChipHeaderEnabled_]]">
- [[clusterLabel]]
- </h2>
- <div id="suggestion-chip" hidden="[[!suggestionChipHeaderEnabled_]]">
- <div id="suggestion-chip-icon" class="cr-icon"></div>
- <h2 id="suggestion-chip-label">[[clusterLabel]]</h2>
- </div>
-</div>
+<h2 id="label" class="label-container"
+ hidden="[[suggestionChipHeaderEnabled_]]">
+[[clusterLabel]]
+</h2>
+<a id="suggestion-chip" class="label-container" href="[[normalizedUrl.url]]"
+ hidden="[[!suggestionChipHeaderEnabled_]]" on-click="onSuggestClick_">
+ <div class="hover-layer"></div>
+ <div id="suggestion-chip-icon" class="cr-icon"></div>
+ <h2 id="suggestion-chip-label">[[clusterLabel]]</h2>
+</a>
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.ts b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.ts
index b810c23f..5997959 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/header_tile.ts
@@ -8,6 +8,8 @@
import 'chrome://resources/cr_elements/cr_shared_style.css.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import {EventTracker} from 'chrome://resources/js/event_tracker.js';
+import {Url} from 'chrome://resources/mojo/url/mojom/url.mojom-webui.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {I18nMixin, loadTimeData} from '../../../i18n_setup.js';
@@ -39,17 +41,51 @@
/** Whether suggestion chip header will show. */
suggestionChipHeaderEnabled_: {
type: Boolean,
+ reflectToAttribute: true,
value: () => loadTimeData.getBoolean(
'historyClustersSuggestionChipHeaderEnabled'),
- reflectToAttribute: true,
},
};
}
- clusterLabel: string;
- private suggestionChipHeaderEnabled_: boolean;
+clusterId:
+ number;
+clusterLabel:
+ string;
+normalizedUrl:
+ Url;
+private suggestionChipHeaderEnabled_:
+ boolean;
+private eventTracker_:
+ EventTracker = new EventTracker();
+
+ override connectedCallback() {
+ super.connectedCallback();
+
+ if (!this.suggestionChipHeaderEnabled_) {
+ this.eventTracker_.add(this, 'click', this.onClick_);
+ }
+ }
+
+ override disconnectedCallback() {
+ super.disconnectedCallback();
+ this.eventTracker_.removeAll();
+ }
+
+ private onClick_(e: Event) {
+ e.stopPropagation();
+ this.dispatchEvent(new CustomEvent(
+ 'show-all-button-click', {bubbles: true, composed: true}));
+ }
+
+ private onSuggestClick_(e: Event) {
+ e.stopPropagation();
+ this.dispatchEvent(
+ new CustomEvent('suggest-click', {bubbles: true, composed: true}));
+ }
private onMenuButtonClick_(e: Event) {
+ e.stopPropagation();
this.$.moduleHeaderElementV2.showAt(e);
}
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.html b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.html
index b993771..4f6a221c 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.html
+++ b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.html
@@ -141,7 +141,9 @@
on-done-button-click="onDoneButtonClick_"
on-info-button-click="onInfoButtonClick_"
on-show-all-button-click="onShowAllButtonClick_"
+ on-suggest-click="onSuggestClick_"
cluster-label="[[computeLabel_()]]"
+ normalized-url="[[cluster.visits.0.normalizedUrl]]"
format$="[[format]]"
show-related-searches$="[[showRelatedSearches]]">
</history-clusters-header-v2>
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.ts b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.ts
index 19900004..08cbb548 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/history_clusters/module.ts
@@ -71,7 +71,7 @@
showRelatedSearches: {
type: Boolean,
- computed: `computeShowRelatedSearches()`,
+ computed: `computeShowRelatedSearches(cluster)`,
reflectToAttribute: true,
},
};
@@ -176,10 +176,16 @@
this.$.infoDialogRender.get().showModal();
}
+ private onSuggestClick_() {
+ HistoryClustersProxyImpl.getInstance().handler.recordClick(this.cluster.id);
+ this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
+ }
+
private onShowAllButtonClick_() {
- assert(this.cluster.label.length >= 2);
+ assert(this.cluster.label.length >= 2, 'Unexpected cluster label length');
HistoryClustersProxyImpl.getInstance().handler.showJourneysSidePanel(
this.cluster.label.substring(1, this.cluster.label.length - 1));
+ this.dispatchEvent(new Event('usage', {bubbles: true, composed: true}));
}
private shouldShowCartTile_(cart: Object): boolean {
diff --git a/chrome/browser/resources/new_tab_page/modules/v2/module_header.ts b/chrome/browser/resources/new_tab_page/modules/v2/module_header.ts
index e190d329..4c97751 100644
--- a/chrome/browser/resources/new_tab_page/modules/v2/module_header.ts
+++ b/chrome/browser/resources/new_tab_page/modules/v2/module_header.ts
@@ -68,7 +68,8 @@
}
}
- private onMenuButtonClick_() {
+ private onMenuButtonClick_(e: Event) {
+ e.stopPropagation();
this.dispatchEvent(new Event('menu-button-click', {bubbles: true}));
}
diff --git a/chrome/test/data/webui/new_tab_page/modules/v2/history_clusters/module_test.ts b/chrome/test/data/webui/new_tab_page/modules/v2/history_clusters/module_test.ts
index bea2c5c..f678191 100644
--- a/chrome/test/data/webui/new_tab_page/modules/v2/history_clusters/module_test.ts
+++ b/chrome/test/data/webui/new_tab_page/modules/v2/history_clusters/module_test.ts
@@ -41,6 +41,11 @@
return cluster;
}
+function removeHrefAndClick(element: HTMLElement) {
+ element.removeAttribute('href');
+ element.click();
+}
+
suite('NewTabPageModulesHistoryClustersV2ModuleTest', () => {
let handler: TestMock<PageHandlerRemote>;
@@ -131,8 +136,32 @@
assertTrue(!!$$(moduleElement, 'ntp-info-dialog'));
});
- test('Header contains label that is not hidden', async () => {
- // Arrange.
+ test(
+ 'Search suggestion header contains chip that is not hidden',
+ async () => {
+ // Arrange.
+ loadTimeData.overrideValues({
+ historyClustersSuggestionChipHeaderEnabled: true,
+ });
+ const moduleElements = await initializeModule(
+ [createSampleCluster(2, {label: '"Sample Journey"'})]);
+ const moduleElement = moduleElements[0];
+
+ // Act.
+ assertTrue(!!moduleElement);
+ const headerElement = $$(moduleElement, 'history-clusters-header-v2');
+ assertTrue(!!headerElement);
+ const label = $$(headerElement, '#label');
+ assertTrue(!!label);
+ const suggestionChip = $$(headerElement, '#suggestion-chip');
+ assertTrue(!!suggestionChip);
+
+ // Assert.
+ assertEquals((label as HTMLElement).hidden, true);
+ assertEquals((suggestionChip as HTMLElement).hidden, false);
+ });
+
+ test('Search suggestion header click triggers navigation', async () => {
loadTimeData.overrideValues({
historyClustersSuggestionChipHeaderEnabled: true,
});
@@ -144,14 +173,12 @@
assertTrue(!!moduleElement);
const headerElement = $$(moduleElement, 'history-clusters-header-v2');
assertTrue(!!headerElement);
- const label = $$(headerElement, '#label');
- assertTrue(!!label);
- const suggestionChip = $$(headerElement, '#suggestion-chip');
+ const suggestionChip = $$<HTMLElement>(headerElement, '#suggestion-chip');
assertTrue(!!suggestionChip);
- // Assert.
- assertEquals((label as HTMLElement).hidden, true);
- assertEquals((suggestionChip as HTMLElement).hidden, false);
+ const waitForUsageEvent = eventToPromise('usage', moduleElement);
+ removeHrefAndClick(suggestionChip);
+ await waitForUsageEvent;
});
test(
@@ -230,22 +257,46 @@
InteractionState.kDefault, 3);
});
+ test('Show History side panel invoked when clicking header', async () => {
+ loadTimeData.overrideValues({
+ historyClustersSuggestionChipHeaderEnabled: false,
+ });
+
+ const sampleClusterLabel = '"Sample Journey"';
+ const moduleElements = await initializeModule(
+ [createSampleCluster(2, {label: sampleClusterLabel})]);
+ const moduleElement = moduleElements[0];
+ assertTrue(!!moduleElement);
+ const headerElement = $$(moduleElement, 'history-clusters-header-v2');
+ assertTrue(!!headerElement);
+
+ const waitForUsageEvent = eventToPromise('usage', moduleElement);
+ headerElement.click();
+
+ assertEquals(
+ sampleClusterLabel.substring(1, sampleClusterLabel.length - 1),
+ handler.getArgs('showJourneysSidePanel')[0]);
+ await waitForUsageEvent;
+ });
+
test(
- 'Show Journeys side panel is invoked when performing show all action',
+ 'Show History side panel is invoked when performing show all action',
async () => {
const sampleClusterLabel = '"Sample Journey"';
const moduleElements = await initializeModule(
[createSampleCluster(2, {label: sampleClusterLabel})]);
const moduleElement = moduleElements[0];
assertTrue(!!moduleElement);
-
const headerElement = $$(moduleElement, 'history-clusters-header-v2');
assertTrue(!!headerElement);
+
+ const waitForUsageEvent = eventToPromise('usage', moduleElement);
headerElement!.dispatchEvent(new Event('show-all-button-click'));
assertEquals(
sampleClusterLabel.substring(1, sampleClusterLabel.length - 1),
handler.getArgs('showJourneysSidePanel')[0]);
+ await waitForUsageEvent;
});
[...Array(3).keys()].forEach(numRelatedSearches => {