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);