Skip to content

Commit c5db232

Browse files
committed
separate context menu from customizer menu
1 parent 4675eae commit c5db232

File tree

7 files changed

+94
-34
lines changed

7 files changed

+94
-34
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import styles from './App.module.css';
44
import { useCustomizerDrawerSettings, usePlatformName } from '../settings.provider.js';
55
import { WidgetList } from '../widget-list/WidgetList.js';
66
import { useGlobalDropzone } from '../dropzone.js';
7-
import { CustomizerButton, CustomizerMenuPositionedFixed, useContextMenu } from '../customizer/components/CustomizerMenu.js';
7+
import { CustomizerButton, CustomizerMenuPositionedFixed } from '../customizer/components/CustomizerMenu.js';
88
import { useDrawer, useDrawerControls } from './Drawer.js';
99
import { CustomizerDrawer } from '../customizer/components/CustomizerDrawer.js';
1010
import { BackgroundConsumer } from './BackgroundProvider.js';
1111
import { useComputed } from '@preact/signals';
1212
import { CustomizerThemesContext } from '../customizer/CustomizerProvider.js';
1313
import { useContext } from 'preact/hooks';
1414
import { InlineErrorBoundary } from '../InlineErrorBoundary.js';
15+
import { useContextMenu } from '../context-menu.js';
1516

1617
/**
1718
* Renders the App component.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { useMessaging } from './types.js';
2+
import { useEffect } from 'preact/hooks';
3+
4+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
5+
class ContextMenuItem {
6+
/** @type {string} */
7+
title;
8+
/** @type {string} */
9+
id;
10+
/** @type {number} */
11+
index;
12+
}
13+
14+
const OPEN_EVENT = 'ntp-contextMenu-open';
15+
16+
/**
17+
* @returns {ContextMenuItem[]}
18+
*/
19+
export function collect() {
20+
/** @type {ContextMenuItem[]} */
21+
const next = [];
22+
const detail = {
23+
register: (/** @type {ContextMenuItem} */ incoming) => {
24+
next.push(incoming);
25+
},
26+
};
27+
const event = new CustomEvent(OPEN_EVENT, { detail });
28+
window.dispatchEvent(event);
29+
next.sort((a, b) => a.index - b.index);
30+
return next;
31+
}
32+
33+
/**
34+
* Forward the contextmenu event
35+
*/
36+
export function useContextMenu() {
37+
const messaging = useMessaging();
38+
useEffect(() => {
39+
function handler(e) {
40+
e.preventDefault();
41+
e.stopImmediatePropagation();
42+
const items = collect();
43+
/** @type {Omit<ContextMenuItem, "index">[]} */
44+
const simplified = items
45+
.filter((x) => !x.id.startsWith('_'))
46+
.map((item) => {
47+
return {
48+
id: item.id,
49+
title: item.title,
50+
};
51+
});
52+
messaging.contextMenu({ visibilityMenuItems: simplified });
53+
}
54+
document.body.addEventListener('contextmenu', handler);
55+
return () => {
56+
document.body.removeEventListener('contextmenu', handler);
57+
};
58+
}, [messaging]);
59+
}
60+
61+
/**
62+
* Call this to opt-in to the visibility menu
63+
* @param {ContextMenuItem} row
64+
*/
65+
export function useContextMenuItem({ title, id, index }) {
66+
useEffect(() => {
67+
const handler = (/** @type {CustomEvent<any>} */ e) => {
68+
e.detail.register({ title, id, index });
69+
};
70+
window.addEventListener(OPEN_EVENT, handler);
71+
return () => window.removeEventListener(OPEN_EVENT, handler);
72+
}, [title, id, index]);
73+
}

special-pages/pages/new-tab/app/customizer/components/CustomizerMenu.js

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { h } from 'preact';
22
import { useEffect } from 'preact/hooks';
33
import styles from './Customizer.module.css';
44
import { CustomizeIcon } from '../../components/Icons.js';
5-
import { useMessaging, useTypedTranslation } from '../../types.js';
5+
import { useTypedTranslation } from '../../types.js';
66

77
/**
88
* @import { WidgetVisibility, VisibilityMenuItem } from '../../../types/new-tab.js'
@@ -21,7 +21,10 @@ import { useMessaging, useTypedTranslation } from '../../types.js';
2121
export const OPEN_EVENT = 'ntp-customizer-open';
2222
export const UPDATE_EVENT = 'ntp-customizer-update';
2323

24-
export function getItems() {
24+
/**
25+
* @returns {VisibilityRowData[]}
26+
*/
27+
export function getCustomizerItems() {
2528
/** @type {VisibilityRowData[]} */
2629
const next = [];
2730
const detail = {
@@ -35,34 +38,6 @@ export function getItems() {
3538
return next;
3639
}
3740

38-
/**
39-
* Forward the contextmenu event
40-
*/
41-
export function useContextMenu() {
42-
const messaging = useMessaging();
43-
useEffect(() => {
44-
function handler(e) {
45-
e.preventDefault();
46-
e.stopImmediatePropagation();
47-
const items = getItems();
48-
/** @type {VisibilityMenuItem[]} */
49-
const simplified = items
50-
.filter((x) => !x.id.startsWith('_'))
51-
.map((item) => {
52-
return {
53-
id: item.id,
54-
title: item.title,
55-
};
56-
});
57-
messaging.contextMenu({ visibilityMenuItems: simplified });
58-
}
59-
document.body.addEventListener('contextmenu', handler);
60-
return () => {
61-
document.body.removeEventListener('contextmenu', handler);
62-
};
63-
}, [messaging]);
64-
}
65-
6641
/**
6742
* @param {object} props
6843
* @param {string} [props.menuId]

special-pages/pages/new-tab/app/customizer/components/VisibilityMenuSection.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { useLayoutEffect, useState } from 'preact/hooks';
2-
import { getItems, UPDATE_EVENT } from './CustomizerMenu.js';
2+
import { getCustomizerItems, UPDATE_EVENT } from './CustomizerMenu.js';
33
import { EmbeddedVisibilityMenu } from './VisibilityMenu.js';
44
import { h } from 'preact';
55

66
export function VisibilityMenuSection() {
77
const [rowData, setRowData] = useState(() => {
8-
const items = /** @type {import("./CustomizerMenu.js").VisibilityRowData[]} */ (getItems());
8+
const items = /** @type {import("./CustomizerMenu.js").VisibilityRowData[]} */ (getCustomizerItems());
99
return items;
1010
});
1111
useLayoutEffect(() => {
1212
function handler() {
13-
setRowData(getItems());
13+
setRowData(getCustomizerItems());
1414
}
1515

1616
window.addEventListener(UPDATE_EVENT, handler);

special-pages/pages/new-tab/app/favorites/components/FavoritesCustomized.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { FavoritesMemo } from './Favorites.js';
1111
import { viewTransition } from '../../utils.js';
1212
import { CustomizerContext } from '../../customizer/CustomizerProvider.js';
1313
import { Shield } from '../../components/Icons.js';
14+
import { useContextMenuItem } from '../../context-menu.js';
1415

1516
/**
1617
* @typedef {import('../../../types/new-tab.ts').Favorite} Favorite
@@ -68,6 +69,7 @@ export function FavoritesCustomized() {
6869
// register with the visibility menu
6970
const title = t('favorites_menu_title');
7071
useCustomizer({ title, id, icon: <Shield />, toggle, visibility: visibility.value, index });
72+
useContextMenuItem({ title, id, index });
7173

7274
if (visibility.value === 'hidden') {
7375
return null;

special-pages/pages/new-tab/app/omnibar/components/OmnibarCustomized.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { h } from 'preact';
66

77
import { OmnibarConsumer } from './OmnibarConsumer.js';
88
import { SearchIcon } from '../../components/Icons.js';
9+
import { useContextMenuItem } from '../../context-menu.js';
910

1011
/**
1112
* @import enStrings from "../strings.json"
@@ -29,6 +30,12 @@ export function OmnibarCustomized() {
2930
const { visibility, id, toggle, index } = useVisibility();
3031

3132
useCustomizer({ title: sectionTitle, id, icon: <SearchIcon />, toggle, visibility: visibility.value, index });
33+
useContextMenuItem({ title: sectionTitle, id, index });
34+
useContextMenuItem({
35+
title: t('omnibar_toggleDuckAi'),
36+
id: `${id}-toggleAi`,
37+
index: index + 0.1,
38+
});
3239

3340
if (visibility.value === 'hidden') {
3441
return null;

special-pages/pages/new-tab/app/protections/components/ProtectionsCustomized.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { h } from 'preact';
66

77
import { ProtectionsConsumer } from './ProtectionsConsumer.js';
88
import { DuckFoot } from '../../components/Icons.js';
9+
import { useContextMenuItem } from '../../context-menu.js';
910

1011
/**
1112
* @import enStrings from "../strings.json"
@@ -29,6 +30,7 @@ export function ProtectionsCustomized() {
2930
const { visibility, id, toggle, index } = useVisibility();
3031

3132
useCustomizer({ title: sectionTitle, id, icon: <DuckFoot />, toggle, visibility: visibility.value, index });
33+
useContextMenuItem({ title: sectionTitle, id, index });
3234

3335
if (visibility.value === 'hidden') {
3436
return null;

0 commit comments

Comments
 (0)