Skip to content

Commit 924c35b

Browse files
shakyShaneShane Osbourne
and
Shane Osbourne
authored
ntp: update notification + context menu fixes (#1178)
* ntp: update notification * linting * linting * adding support for context menu * docs structure * add visibilityMenuItems to contextMenu * make 'updateNotification' nullable on `initialSetup` * styling * lint * text update * Allow the component to be pulled up --------- Co-authored-by: Shane Osbourne <[email protected]>
1 parent 9d5850d commit 924c35b

40 files changed

+883
-103
lines changed

.stylelintrc.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@
3232
"keyframes-name-pattern": null,
3333
"block-no-empty": null,
3434
"selector-id-pattern": null,
35+
"selector-pseudo-class-no-unknown": null,
3536
"declaration-block-no-shorthand-property-overrides": null,
3637
"font-family-no-missing-generic-family-keyword": null,
3738
"font-family-name-quotes": null,
3839
"value-no-vendor-prefix": null
3940
}
40-
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"type": "object",
4+
"required": ["visibilityMenuItems"],
5+
"properties": {
6+
"visibilityMenuItems": {
7+
"type": "array",
8+
"items": {
9+
"type": "object",
10+
"title": "Visibility Menu Item",
11+
"required": ["id", "title"],
12+
"properties": {
13+
"id": {
14+
"type": "string"
15+
},
16+
"title": {
17+
"description": "Translated name of the section",
18+
"type": "string"
19+
}
20+
}
21+
}
22+
}
23+
}
24+
}

special-pages/messages/new-tab/examples/widgets.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,19 @@ const widgetConfig = {
3434
*/
3535
const initialSetupResponse = {
3636
widgets: [
37-
{ "id": "weatherWidget" },
38-
{ "id": "newsWidget" }
37+
{ "id": "updateNotification" },
38+
{ "id": "rmf" },
39+
{ "id": "favorites" },
40+
{ "id": "privacyStats" }
3941
],
4042
widgetConfigs: [
41-
{ "id": "weatherWidget", "visibility": "visible" },
42-
{ "id": "newsWidget", "visibility": "visible" }
43+
{ "id": "favorites", "visibility": "visible" },
44+
{ "id": "privacyStats", "visibility": "visible" }
4345
],
4446
env: 'production',
4547
locale: 'en',
46-
platform: {name: 'windows'}
48+
platform: { name: 'windows' },
49+
updateNotification: { content: null }
4750
}
4851

4952
export {}

special-pages/messages/new-tab/initialSetup.response.json

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "http://json-schema.org/draft-07/schema#",
33
"type": "object",
4-
"required": ["widgets", "widgetConfigs", "locale", "env", "platform"],
4+
"required": ["widgets", "widgetConfigs", "locale", "env", "platform", "updateNotification"],
55
"properties": {
66
"widgets": {
77
"$ref": "./types/widget-list.json"
@@ -25,6 +25,16 @@
2525
"enum": ["macos", "windows", "android", "ios", "integration"]
2626
}
2727
}
28+
},
29+
"updateNotification": {
30+
"oneOf": [
31+
{
32+
"type": "null"
33+
},
34+
{
35+
"$ref": "types/update-notification.json"
36+
}
37+
]
2838
}
2939
}
3040
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"type": "object",
4+
"title": "Update Notification Data",
5+
"required": ["content"],
6+
"properties": {
7+
"content": {
8+
"oneOf": [
9+
{
10+
"type": "null"
11+
},
12+
{
13+
"title": "Update Notification",
14+
"required": ["version", "notes"],
15+
"properties": {
16+
"version": {
17+
"type": "string"
18+
},
19+
"notes": {
20+
"type": "array",
21+
"items": {
22+
"type": "string"
23+
}
24+
}
25+
}
26+
}
27+
]
28+
}
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#"
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"allOf": [
4+
{
5+
"$ref": "types/update-notification.json"
6+
}
7+
]
8+
}

special-pages/pages/new-tab/app/components/App.module.css

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ body {
88
font-size: var(--body-font-size);
99
font-weight: var(--body-font-weight);
1010
line-height: var(--body-line-height);
11-
padding-left: var(--sp-6);
12-
padding-right: var(--sp-6);
1311
}
1412

1513
.layout {
1614
padding-top: var(--sp-16);
1715
padding-bottom: var(--sp-16);
18-
max-width: calc(504 * var(--px-in-rem));
1916
margin-left: auto;
2017
margin-right: auto;
2118
}
2219

20+
:global(.layout-centered) {
21+
margin-inline: auto;
22+
max-width: calc(504 * var(--px-in-rem));
23+
}

special-pages/pages/new-tab/app/components/Icons.js

+10
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,13 @@ export function Shield () {
4949
</svg>
5050
)
5151
}
52+
53+
export function Cross () {
54+
return (
55+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
56+
<path
57+
d="M11.4419 5.44194C11.686 5.19786 11.686 4.80214 11.4419 4.55806C11.1979 4.31398 10.8021 4.31398 10.5581 4.55806L8 7.11612L5.44194 4.55806C5.19786 4.31398 4.80214 4.31398 4.55806 4.55806C4.31398 4.80214 4.31398 5.19786 4.55806 5.44194L7.11612 8L4.55806 10.5581C4.31398 10.8021 4.31398 11.1979 4.55806 11.4419C4.80214 11.686 5.19786 11.686 5.44194 11.4419L8 8.88388L10.5581 11.4419C10.8021 11.686 11.1979 11.686 11.4419 11.4419C11.686 11.1979 11.686 10.8021 11.4419 10.5581L8.88388 8L11.4419 5.44194Z"
58+
fill="currentColor"/>
59+
</svg>
60+
)
61+
}

special-pages/pages/new-tab/app/customizer/Customizer.js

+31-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import styles from './Customizer.module.css'
44
import { VisibilityMenu } from './VisibilityMenu.js'
55
import { CustomizeIcon } from '../components/Icons.js'
66
import cn from 'classnames'
7+
import { useMessaging } from '../types.js'
78

89
/**
9-
* @import { Widgets, WidgetConfigItem, WidgetVisibility } from '../../../../types/new-tab.js'
10+
* @import { Widgets, WidgetConfigItem, WidgetVisibility, VisibilityMenuItem } from '../../../../types/new-tab.js'
1011
*/
1112

1213
/**
@@ -16,6 +17,8 @@ export function Customizer () {
1617
const { setIsOpen, buttonRef, dropdownRef, isOpen } = useDropdown()
1718
const [rowData, setRowData] = useState(/** @type {VisibilityRowData[]} */([]))
1819

20+
useContextMenu()
21+
1922
/**
2023
* Dispatch an event every time the customizer is opened - this
2124
* allows widgets to register themselves and provide titles/icons etc.
@@ -63,7 +66,7 @@ export function Customizer () {
6366
Customizer.OPEN_EVENT = 'ntp-customizer-open'
6467
Customizer.UPDATE_EVENT = 'ntp-customizer-update'
6568

66-
function getItems () {
69+
export function getItems () {
6770
/** @type {VisibilityRowData[]} */
6871
const next = []
6972
const detail = {
@@ -77,6 +80,32 @@ function getItems () {
7780
return next
7881
}
7982

83+
/**
84+
* Forward the contextmenu event
85+
*/
86+
export function useContextMenu () {
87+
const messaging = useMessaging()
88+
useEffect(() => {
89+
function handler (e) {
90+
e.preventDefault()
91+
e.stopImmediatePropagation()
92+
const items = getItems()
93+
/** @type {VisibilityMenuItem[]} */
94+
const simplified = items.map(item => {
95+
return {
96+
id: item.id,
97+
title: item.title
98+
}
99+
})
100+
messaging.contextMenu({ visibilityMenuItems: simplified })
101+
}
102+
document.body.addEventListener('contextmenu', handler)
103+
return () => {
104+
document.body.removeEventListener('contextmenu', handler)
105+
}
106+
}, [messaging])
107+
}
108+
80109
/**
81110
* @param {object} props
82111
* @param {string} [props.menuId]
+5-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
/**
2-
*
3-
* - {@link WidgetConfigService}
4-
* - {@link PrivacyStatsService}
5-
* - {@link RMFService}
2+
* @document ./new-tab.md
3+
* @document ./widget-list/widget-config.md
4+
* @document ./remote-messaging-framework/rmf.md
5+
* @document ./update-notification/update-notification.md
6+
* @document ./privacy-stats/privacy-stats.md
67
*
78
* @module NewTab Services
89
*/
9-
export * from './privacy-stats/privacy-stats.service.js'
10-
export * from './widget-list/widget-config.service.js'
11-
export * from './remote-messaging-framework/rmf.service.js'

special-pages/pages/new-tab/app/favorites/Favorites.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export function FavoritesCustomized () {
1515
return null
1616
}
1717
return (
18-
<p>Favourites here... (id: <code>{id}</code>)</p>
18+
<div class="layout-centered">
19+
<p>Favourites here... (id: <code>{id}</code>)</p>
20+
</div>
1921
)
2022
}

special-pages/pages/new-tab/app/index.js

+10-8
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { EnvironmentProvider, UpdateEnvironment } from '../../../shared/componen
44
import { Fallback } from '../../../shared/components/Fallback/Fallback.jsx'
55
import { ErrorBoundary } from '../../../shared/components/ErrorBoundary.js'
66
import { SettingsProvider } from './settings.provider.js'
7-
import { MessagingContext } from './types'
7+
import { InitialSetupContext, MessagingContext } from './types'
88
import { TranslationProvider } from '../../../shared/components/TranslationsProvider.js'
99
import { WidgetConfigService } from './widget-list/widget-config.service.js'
1010
import enStrings from '../src/locales/en/newtab.json'
@@ -91,13 +91,15 @@ export async function init (messaging, baseEnvironment) {
9191
<ErrorBoundary didCatch={didCatch} fallback={<Fallback showDetails={environment.env === 'development'}/>}>
9292
<UpdateEnvironment search={window.location.search}/>
9393
<MessagingContext.Provider value={messaging}>
94-
<SettingsProvider settings={settings}>
95-
<TranslationProvider translationObject={strings} fallback={strings} textLength={environment.textLength}>
96-
<WidgetConfigProvider api={widgetConfigAPI} widgetConfigs={init.widgetConfigs} widgets={init.widgets}>
97-
<App />
98-
</WidgetConfigProvider>
99-
</TranslationProvider>
100-
</SettingsProvider>
94+
<InitialSetupContext.Provider value={init}>
95+
<SettingsProvider settings={settings}>
96+
<TranslationProvider translationObject={strings} fallback={strings} textLength={environment.textLength}>
97+
<WidgetConfigProvider api={widgetConfigAPI} widgetConfigs={init.widgetConfigs} widgets={init.widgets}>
98+
<App />
99+
</WidgetConfigProvider>
100+
</TranslationProvider>
101+
</SettingsProvider>
102+
</InitialSetupContext.Provider>
101103
</MessagingContext.Provider>
102104
</ErrorBoundary>
103105
</EnvironmentProvider>
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
title: New Tab Page
3+
---
4+
5+
## Requests
6+
7+
- {@link "NewTab Messages".InitialSetupRequest `initialSetup`}
8+
- Returns {@link "NewTab Messages".InitialSetupResponse}
9+
- See the `initialSetupResponse` section of [example of initial data](../../../messages/new-tab/examples/widgets.js)
10+
11+
## Notifications
12+
13+
- {@link "NewTab Messages".ContextMenuNotification `contextMenu`}
14+
- Sent when the user right-clicks in the page
15+
- Note: Other widgets might prevent this (and send their own, eg: favorites)
16+
- Sends: {@link "NewTab Messages".ContextMenuNotify}
17+
- Example:
18+
19+
```json
20+
{
21+
"visibilityMenuItems": [
22+
{
23+
"id": "favorites",
24+
"title": "Favorites"
25+
},
26+
{
27+
"id": "privacyStats",
28+
"title": "Privacy Stats"
29+
}
30+
]
31+
}
32+
```
33+
34+
- {@link "NewTab Messages".ReportInitExceptionNotification `reportInitException`}
35+
- Sent when the application fails to initialize (for example, a JavaScript exception prevented it)
36+
- Sends: `{ message: string }` - see {@link "NewTab Messages".ReportInitExceptionNotify}
37+
38+
- {@link "NewTab Messages".ReportPageExceptionNotification `reportPageException`}
39+
- Sent when the application failed after initialization (for example, a JavaScript exception prevented it)
40+
- Sends: `{ message: string }` - see {@link "NewTab Messages".ReportPageExceptionNotify}

special-pages/pages/new-tab/app/privacy-stats/PrivacyStats.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { h } from 'preact'
2+
import cn from 'classnames'
23
import styles from './PrivacyStats.module.css'
34
import { useTypedTranslation } from '../types.js'
45
import { useContext, useState, useId, useCallback } from 'preact/hooks'
@@ -60,8 +61,9 @@ function PrivacyStatsConfigured ({ parentRef, expansion, data, toggle }) {
6061
// see: https://www.w3.org/WAI/ARIA/apg/patterns/accordion/examples/accordion/
6162
const WIDGET_ID = useId()
6263
const TOGGLE_ID = useId()
64+
6365
return (
64-
<div class={styles.root} ref={parentRef}>
66+
<div class={cn('layout-centered', styles.root)} ref={parentRef}>
6567
<Heading
6668
totalCount={data.totalCount}
6769
trackerCompanies={data.trackerCompanies}

special-pages/pages/new-tab/app/privacy-stats/PrivacyStats.module.css

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
align-items: start;
88
grid-template-columns: auto;
99
grid-row-gap: 18px;
10+
width: 100%;
1011

1112
@media screen and (prefers-color-scheme: dark) {
1213
border-color: var(--color-white-at-9);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
title: Privacy Stats
3+
---
4+
5+
## Requests:
6+
- {@link "NewTab Messages".StatsGetDataRequest `stats_getData`}
7+
- Used to fetch the initial data (during the first render)
8+
- returns {@link "NewTab Messages".PrivacyStatsData}
9+
10+
- {@link "NewTab Messages".StatsGetDataRequest `stats_getConfig`}
11+
- Used to fetch the initial config data (eg: expanded vs collapsed)
12+
- returns {@link "NewTab Messages".StatsConfig}
13+
14+
## Subscriptions:
15+
- {@link "NewTab Messages".StatsOnDataUpdateSubscription `stats_onDataUpdate`}.
16+
- The tracker/company data used in the feed.
17+
- returns {@link "NewTab Messages".PrivacyStatsData}
18+
- {@link "NewTab Messages".StatsOnDataUpdateSubscription `stats_onConfigUpdate`}.
19+
- The widget config
20+
- returns {@link "NewTab Messages".StatsConfig}
21+
22+
## Notifications:
23+
- {@link "NewTab Messages".StatsSetConfigNotification `stats_setConfig`}
24+
- Sent when the user toggles the expansion of the stats
25+
- sends {@link "NewTab Messages".StatsConfig}
26+
- example payload:
27+
```json
28+
{
29+
"expansion": "collapsed"
30+
}
31+
```
32+
33+
## Examples:
34+
The following examples show the data types in JSON format:
35+
[messages/new-tab/examples/stats.js](../../../../messages/new-tab/examples/stats.js)

0 commit comments

Comments
 (0)