From ebbf13e17d66eb06d90ae53605807847057860b3 Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 19 Mar 2023 15:42:09 +0800 Subject: [PATCH 1/3] support right menu --- manifest.json | 3 +- src/background/index.ts | 30 +++++++++++++++---- src/common/event-name.ts | 6 ++++ src/common/types.d.ts | 8 +++-- .../ask-writely/result-panel/header.tsx | 7 +++-- src/content/container/store/view.ts | 18 +++++++++++ src/content/utils/selection/index.ts | 2 -- 7 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 src/common/event-name.ts diff --git a/manifest.json b/manifest.json index 6b43f20..a63aa27 100644 --- a/manifest.json +++ b/manifest.json @@ -30,6 +30,7 @@ }, "permissions": [ "storage", - "clipboardRead" + "clipboardRead", + "contextMenus" ] } \ No newline at end of file diff --git a/src/background/index.ts b/src/background/index.ts index e0fe425..47cc7ca 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,7 +1,27 @@ -import type { MessagePayload } from "@/common/types" +import { EventName, launch_writely } from '@/common/event-name'; +import type { MessagePayload } from '@/common/types'; -chrome.runtime.onMessage.addListener(async (message: MessagePayload) => { - if (message.type === 'open-options-page') { - chrome.runtime.openOptionsPage() +chrome.runtime.onMessage.addListener( + async (message: MessagePayload) => { + if (message.type === 'open-options-page') { + chrome.runtime.openOptionsPage(); + } } -}) +); + +chrome.contextMenus.create({ + title: 'Writely', + id: 'writely', + contexts: ['selection'], + // onclick: (info) => { + // chrome.runtime.sendMessage(launch_writely); + // }, +}); + +chrome.contextMenus.onClicked.addListener((info, tab) => { + if (info.menuItemId === 'writely' && tab.id) { + chrome.tabs.sendMessage(tab.id, { + type: EventName.launchWritely, + }); + } +}); diff --git a/src/common/event-name.ts b/src/common/event-name.ts new file mode 100644 index 0000000..6e60203 --- /dev/null +++ b/src/common/event-name.ts @@ -0,0 +1,6 @@ +export const launch_writely = 'launch-writely'; + +export enum EventName { + launchWritely = 'launch-writely', + openOptionsPage = 'open-options-page', +} diff --git a/src/common/types.d.ts b/src/common/types.d.ts index 873ccb8..3693272 100644 --- a/src/common/types.d.ts +++ b/src/common/types.d.ts @@ -1,3 +1,5 @@ -export type MessagePayload = { - type: 'open-options-page' -} \ No newline at end of file +import { EventName } from './event-name'; + +export type MessagePayload = { + type: T; +}; diff --git a/src/content/container/ask-writely/result-panel/header.tsx b/src/content/container/ask-writely/result-panel/header.tsx index 3b25771..94a575e 100644 --- a/src/content/container/ask-writely/result-panel/header.tsx +++ b/src/content/container/ask-writely/result-panel/header.tsx @@ -10,6 +10,7 @@ import { useView } from '../../store/view'; import i18next from 'i18next'; import { useResultPanel } from '../../store/result-panel'; import type { MessagePayload } from '@/common/types'; +import { EventName } from '@/common/event-name'; export const Header: React.FC = () => { const { hide, goToInputPage } = useView(); @@ -52,8 +53,10 @@ export const Header: React.FC = () => { /> { - chrome.runtime.sendMessage({ - type: 'open-options-page', + chrome.runtime.sendMessage< + MessagePayload + >({ + type: EventName.openOptionsPage, }); }} icon={} diff --git a/src/content/container/store/view.ts b/src/content/container/store/view.ts index 802af5c..6411b85 100644 --- a/src/content/container/store/view.ts +++ b/src/content/container/store/view.ts @@ -1,3 +1,5 @@ +import { EventName } from '@/common/event-name'; +import { MessagePayload } from '@/common/types'; import { useCallback, useEffect, useRef, useState } from 'react'; import { createContainer } from 'unstated-next'; import { useSelectionManager } from './selection'; @@ -70,6 +72,22 @@ const { useContainer: useView, Provider: ViewProvider } = createContainer( }; }, []); + useEffect(() => { + const listener = (message: MessagePayload) => { + if (message.type !== EventName.launchWritely) { + return; + } + + if (viewStatusRef.current === 'none') { + goToInputPage(); + } + }; + + chrome.runtime.onMessage.addListener(listener); + + return () => chrome.runtime.onMessage.removeListener(listener); + }, []); + return { viewStatus, goToInputPage, diff --git a/src/content/utils/selection/index.ts b/src/content/utils/selection/index.ts index 018b9ad..d25f673 100644 --- a/src/content/utils/selection/index.ts +++ b/src/content/utils/selection/index.ts @@ -46,8 +46,6 @@ export class SelectionManager { this.savedRange = this.selection.getRangeAt(0).cloneRange(); this.setText(); } else { - // this.restoreRange(); - this.setText(); this.textPasted = false; } } From d92522bc2070b4348c1ff86c646ba3dadd160427 Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 19 Mar 2023 15:43:08 +0800 Subject: [PATCH 2/3] support right menu --- src/content/container/ask-writely/content/quick-prompt.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/container/ask-writely/content/quick-prompt.tsx b/src/content/container/ask-writely/content/quick-prompt.tsx index 4b95270..2501f18 100644 --- a/src/content/container/ask-writely/content/quick-prompt.tsx +++ b/src/content/container/ask-writely/content/quick-prompt.tsx @@ -11,8 +11,8 @@ export const QuickPrompt: React.FC<{ return (
- {items.map((item) => ( - + {items.map((item, index) => ( + ))}
); From c094ba70d90674e8c399ce936fab69f25f9f7776 Mon Sep 17 00:00:00 2001 From: anc95 <1481988258@qq.com> Date: Sun, 19 Mar 2023 16:59:42 +0800 Subject: [PATCH 3/3] add self-instruction to context-menu --- src/background/index.ts | 36 ++++++++++++++++--- src/common/event-name.ts | 1 + src/common/types.d.ts | 3 +- .../container/ask-writely/content/index.tsx | 7 ++-- src/content/container/index.tsx | 9 +++-- src/content/container/store/instruction.ts | 12 +++++++ src/content/container/store/view.ts | 11 ++++-- src/content/utils/selection/index.ts | 10 +++--- 8 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 src/content/container/store/instruction.ts diff --git a/src/background/index.ts b/src/background/index.ts index 47cc7ca..fe6eee2 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1,4 +1,5 @@ import { EventName, launch_writely } from '@/common/event-name'; +import { getSetting } from '@/common/store/settings'; import type { MessagePayload } from '@/common/types'; chrome.runtime.onMessage.addListener( @@ -10,18 +11,45 @@ chrome.runtime.onMessage.addListener( ); chrome.contextMenus.create({ - title: 'Writely', + title: 'Launch writely', id: 'writely', contexts: ['selection'], - // onclick: (info) => { - // chrome.runtime.sendMessage(launch_writely); - // }, }); +chrome.contextMenus.create({ + title: 'Writely instructions', + id: 'writely-instructions', + contexts: ['selection'], +}); + +const createSubMenu = async () => { + const settings = await getSetting(); + + settings.customInstructions?.map((instruction) => { + chrome.contextMenus.create({ + title: instruction, + id: instruction, + contexts: ['selection'], + parentId: 'writely-instructions', + }); + }); +}; + +createSubMenu(); + chrome.contextMenus.onClicked.addListener((info, tab) => { if (info.menuItemId === 'writely' && tab.id) { chrome.tabs.sendMessage(tab.id, { type: EventName.launchWritely, }); } + + if (info.parentMenuItemId === 'writely-instructions') { + chrome.tabs.sendMessage(tab.id, { + type: EventName.launchWritelyResultPanel, + data: { + instruction: info.menuItemId, + }, + }); + } }); diff --git a/src/common/event-name.ts b/src/common/event-name.ts index 6e60203..87be813 100644 --- a/src/common/event-name.ts +++ b/src/common/event-name.ts @@ -2,5 +2,6 @@ export const launch_writely = 'launch-writely'; export enum EventName { launchWritely = 'launch-writely', + launchWritelyResultPanel = 'launchWritelyResultPanel', openOptionsPage = 'open-options-page', } diff --git a/src/common/types.d.ts b/src/common/types.d.ts index 3693272..c01401e 100644 --- a/src/common/types.d.ts +++ b/src/common/types.d.ts @@ -1,5 +1,6 @@ import { EventName } from './event-name'; -export type MessagePayload = { +export type MessagePayload = { type: T; + data?: D; }; diff --git a/src/content/container/ask-writely/content/index.tsx b/src/content/container/ask-writely/content/index.tsx index c571eaf..9fb7815 100644 --- a/src/content/container/ask-writely/content/index.tsx +++ b/src/content/container/ask-writely/content/index.tsx @@ -15,13 +15,14 @@ import { IcOutlineKeyboardReturn } from '@/components/icon/return'; import { useView } from '../../store/view'; import { DashiconsMove } from '@/components/icon/drag'; import { QuickPrompt } from './quick-prompt'; +import { useInstruction } from '../../store/instruction'; export const Content: React.FC = () => { return ; }; const CenterContent = forwardRef((_, ref) => { - const [keyword, setkeyword] = useState(); + const { instruction, setInstruction } = useInstruction(); const { viewStatus, goToInputPage } = useView(); const handleClickIcon = useCallback(() => { @@ -40,10 +41,10 @@ const CenterContent = forwardRef((_, ref) => { } if (viewStatus === 'result') { - return ; + return ; } - return ; + return ; }); const InputPanel: React.FC<{ diff --git a/src/content/container/index.tsx b/src/content/container/index.tsx index 55dffff..464f23f 100644 --- a/src/content/container/index.tsx +++ b/src/content/container/index.tsx @@ -5,6 +5,7 @@ import { AskWritely, getFixedDom } from './ask-writely'; import { SelectionManagerProvider } from './store/selection'; import 'highlight.js/styles/github.css'; import { ViewProvider } from './store/view'; +import { InstructionProvider } from './store/instruction'; export const Menu: React.FC = () => { return ( @@ -14,9 +15,11 @@ export const Menu: React.FC = () => { getTargetContainer={() => getFixedDom()} > - - - + + + + + ); diff --git a/src/content/container/store/instruction.ts b/src/content/container/store/instruction.ts new file mode 100644 index 0000000..7240803 --- /dev/null +++ b/src/content/container/store/instruction.ts @@ -0,0 +1,12 @@ +import { useState } from 'react'; +import { createContainer } from 'unstated-next'; + +export const { useContainer: useInstruction, Provider: InstructionProvider } = + createContainer(() => { + const [instruction, setInstruction] = useState(''); + + return { + instruction, + setInstruction, + }; + }); diff --git a/src/content/container/store/view.ts b/src/content/container/store/view.ts index 6411b85..c711250 100644 --- a/src/content/container/store/view.ts +++ b/src/content/container/store/view.ts @@ -2,6 +2,7 @@ import { EventName } from '@/common/event-name'; import { MessagePayload } from '@/common/types'; import { useCallback, useEffect, useRef, useState } from 'react'; import { createContainer } from 'unstated-next'; +import { useInstruction } from './instruction'; import { useSelectionManager } from './selection'; const { useContainer: useView, Provider: ViewProvider } = createContainer( @@ -12,6 +13,7 @@ const { useContainer: useView, Provider: ViewProvider } = createContainer( const viewStatusRef = useRef(); viewStatusRef.current = viewStatus; const selection = useSelectionManager(); + const { setInstruction } = useInstruction(); const disposeListRef = useRef<(() => void)[]>([]); const disposeAll = useCallback(() => { @@ -74,12 +76,15 @@ const { useContainer: useView, Provider: ViewProvider } = createContainer( useEffect(() => { const listener = (message: MessagePayload) => { - if (message.type !== EventName.launchWritely) { + if (message.type === EventName.launchWritely) { + goToInputPage(); return; } - if (viewStatusRef.current === 'none') { - goToInputPage(); + if (message.type === EventName.launchWritelyResultPanel) { + setInstruction(message.data?.instruction); + goToResult(); + return; } }; diff --git a/src/content/utils/selection/index.ts b/src/content/utils/selection/index.ts index d25f673..776af67 100644 --- a/src/content/utils/selection/index.ts +++ b/src/content/utils/selection/index.ts @@ -42,10 +42,7 @@ export class SelectionManager { this.locked = locked; - if (locked) { - this.savedRange = this.selection.getRangeAt(0).cloneRange(); - this.setText(); - } else { + if (!locked) { this.textPasted = false; } } @@ -105,6 +102,11 @@ export class SelectionManager { y: e.y + 10, }; + if (!this.locked) { + this.savedRange = this.selection.getRangeAt(0).cloneRange(); + this.setText(); + } + this.selectChangeHandlers.forEach((handler) => handler(this.selection)); } }, 300);