Skip to content

Commit

Permalink
Merge pull request #21 from anc95/right-menu
Browse files Browse the repository at this point in the history
feature: add context menu trigger
  • Loading branch information
anc95 authored Mar 19, 2023
2 parents 980141b + c094ba7 commit 59e8d45
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 25 deletions.
3 changes: 2 additions & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"permissions": [
"storage",
"clipboardRead"
"clipboardRead",
"contextMenus"
]
}
58 changes: 53 additions & 5 deletions src/background/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,55 @@
import type { MessagePayload } from "@/common/types"
import { EventName, launch_writely } from '@/common/event-name';
import { getSetting } from '@/common/store/settings';
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<EventName.openOptionsPage>) => {
if (message.type === 'open-options-page') {
chrome.runtime.openOptionsPage();
}
}
})
);

chrome.contextMenus.create({
title: 'Launch writely',
id: 'writely',
contexts: ['selection'],
});

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,
},
});
}
});
7 changes: 7 additions & 0 deletions src/common/event-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const launch_writely = 'launch-writely';

export enum EventName {
launchWritely = 'launch-writely',
launchWritelyResultPanel = 'launchWritelyResultPanel',
openOptionsPage = 'open-options-page',
}
9 changes: 6 additions & 3 deletions src/common/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
export type MessagePayload = {
type: 'open-options-page'
}
import { EventName } from './event-name';

export type MessagePayload<T extends EventName, D extends any = any> = {
type: T;
data?: D;
};
7 changes: 4 additions & 3 deletions src/content/container/ask-writely/content/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<PropsWithChildren> = () => {
return <CenterContent />;
};

const CenterContent = forwardRef<HTMLDivElement>((_, ref) => {
const [keyword, setkeyword] = useState<string>();
const { instruction, setInstruction } = useInstruction();
const { viewStatus, goToInputPage } = useView();

const handleClickIcon = useCallback(() => {
Expand All @@ -40,10 +41,10 @@ const CenterContent = forwardRef<HTMLDivElement>((_, ref) => {
}

if (viewStatus === 'result') {
return <ResultPanel text={keyword} />;
return <ResultPanel text={instruction} />;
}

return <InputPanel keyword={keyword} onChange={setkeyword} />;
return <InputPanel keyword={instruction} onChange={setInstruction} />;
});

const InputPanel: React.FC<{
Expand Down
4 changes: 2 additions & 2 deletions src/content/container/ask-writely/content/quick-prompt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export const QuickPrompt: React.FC<{

return (
<div>
{items.map((item) => (
<Card {...item} onClick={onClick} />
{items.map((item, index) => (
<Card {...item} key={index} onClick={onClick} />
))}
</div>
);
Expand Down
7 changes: 5 additions & 2 deletions src/content/container/ask-writely/result-panel/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -52,8 +53,10 @@ export const Header: React.FC = () => {
/>
<Operation
onClick={() => {
chrome.runtime.sendMessage<MessagePayload>({
type: 'open-options-page',
chrome.runtime.sendMessage<
MessagePayload<EventName.openOptionsPage>
>({
type: EventName.openOptionsPage,
});
}}
icon={<DashiconsAdminGeneric />}
Expand Down
9 changes: 6 additions & 3 deletions src/content/container/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -14,9 +15,11 @@ export const Menu: React.FC = () => {
getTargetContainer={() => getFixedDom()}
>
<SelectionManagerProvider>
<ViewProvider>
<AskWritely />
</ViewProvider>
<InstructionProvider>
<ViewProvider>
<AskWritely />
</ViewProvider>
</InstructionProvider>
</SelectionManagerProvider>
</ConfigProvider>
);
Expand Down
12 changes: 12 additions & 0 deletions src/content/container/store/instruction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useState } from 'react';
import { createContainer } from 'unstated-next';

export const { useContainer: useInstruction, Provider: InstructionProvider } =
createContainer(() => {
const [instruction, setInstruction] = useState<string>('');

return {
instruction,
setInstruction,
};
});
23 changes: 23 additions & 0 deletions src/content/container/store/view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
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(
Expand All @@ -10,6 +13,7 @@ const { useContainer: useView, Provider: ViewProvider } = createContainer(
const viewStatusRef = useRef<string>();
viewStatusRef.current = viewStatus;
const selection = useSelectionManager();
const { setInstruction } = useInstruction();
const disposeListRef = useRef<(() => void)[]>([]);

const disposeAll = useCallback(() => {
Expand Down Expand Up @@ -70,6 +74,25 @@ const { useContainer: useView, Provider: ViewProvider } = createContainer(
};
}, []);

useEffect(() => {
const listener = (message: MessagePayload<EventName.launchWritely>) => {
if (message.type === EventName.launchWritely) {
goToInputPage();
return;
}

if (message.type === EventName.launchWritelyResultPanel) {
setInstruction(message.data?.instruction);
goToResult();
return;
}
};

chrome.runtime.onMessage.addListener(listener);

return () => chrome.runtime.onMessage.removeListener(listener);
}, []);

return {
viewStatus,
goToInputPage,
Expand Down
12 changes: 6 additions & 6 deletions src/content/utils/selection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,7 @@ export class SelectionManager {

this.locked = locked;

if (locked) {
this.savedRange = this.selection.getRangeAt(0).cloneRange();
this.setText();
} else {
// this.restoreRange();
this.setText();
if (!locked) {
this.textPasted = false;
}
}
Expand Down Expand Up @@ -107,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);
Expand Down

0 comments on commit 59e8d45

Please sign in to comment.