Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: 익스텐션이 설치되었는지 여부를 판단한다 & 사이드 패널 여부를 체크하여 자동으로 스탭을 넘어간다 #87

Merged
merged 6 commits into from
Oct 15, 2024
3 changes: 3 additions & 0 deletions chrome-extension/lib/background/index.ts
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ import {
I18n,
requestObserverMemoPage,
requestUpdateSidePanel,
responseGetExtensionManifest,
responseOpenSidePanel,
Storage,
Tab,
@@ -100,3 +101,5 @@ chrome.tabs.onUpdated.addListener(async () => {

// content-ui에서 메시지를 전달받아 사이드 패널을 연다.
responseOpenSidePanel();

responseGetExtensionManifest();
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { EXTENSION_ID } from '@src/constants';
import { Runtime } from '../module';

export const BRIDGE_TYPE_GET_EXTENSION_MANIFEST = 'BRIDGE_TYPE_GET_EXTENSION_MANIFEST';
export const requestGetExtensionManifest = (callbackFn: (response: chrome.runtime.Manifest) => void) => {
chrome.runtime.sendMessage(EXTENSION_ID, { type: BRIDGE_TYPE_GET_EXTENSION_MANIFEST }, callbackFn);
};
export const responseGetExtensionManifest = () => {
const manifest = chrome.runtime.getManifest();
Runtime.onMessageExternal(BRIDGE_TYPE_GET_EXTENSION_MANIFEST, (_, __, sendResponse) => sendResponse(manifest));
};
10 changes: 10 additions & 0 deletions packages/shared/src/utils/extension/bridge/getSidePanelOpen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { EXTENSION_ID } from '@src/constants';
import { Runtime } from '../module';

export const BRIDGE_TYPE_GET_SIDE_PANEL_OPEN = 'BRIDGE_TYPE_GET_SIDE_PANEL_OPEN';
export const requestGetSidePanelOpen = (callbackFn: () => void) =>
chrome.runtime.sendMessage(EXTENSION_ID, { type: BRIDGE_TYPE_GET_SIDE_PANEL_OPEN }, callbackFn);
export const responseGetSidePanelOpen = () =>
Runtime.onMessageExternal(BRIDGE_TYPE_GET_SIDE_PANEL_OPEN, (_, __, sendResponse) => {
sendResponse();
});
2 changes: 2 additions & 0 deletions packages/shared/src/utils/extension/bridge/index.ts
Original file line number Diff line number Diff line change
@@ -5,3 +5,5 @@ export * from './getSummary';
export * from './updateSidePanel';
export * from './observeMemoPage';
export * from './refetchTheMemoList';
export * from './getExtensionManifest';
export * from './getSidePanelOpen';
6 changes: 5 additions & 1 deletion packages/shared/src/utils/extension/bridge/type.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { BRIDGE_TYPE_GET_EXTENSION_MANIFEST } from './getExtensionManifest';
import { BRIDGE_TYPE_GET_SIDE_PANEL_OPEN } from './getSidePanelOpen';
import { BRIDGE_TYPE_GET_SUMMARY } from './getSummary';
import { BRIDGE_TYPE_OBSERVER_MEMO_PAGE } from './observeMemoPage';
import { BRIDGE_TYPE_OPEN_SIDE_PANEL } from './openSidePanel';
@@ -11,7 +13,9 @@ export type BridgeType =
| typeof BRIDGE_TYPE_GET_SUMMARY
| typeof BRIDGE_TYPE_UPDATE_SIDE_PANEL
| typeof BRIDGE_TYPE_OBSERVER_MEMO_PAGE
| typeof BRIDGE_TYPE_REFETCH_THE_MEMO_LIST;
| typeof BRIDGE_TYPE_REFETCH_THE_MEMO_LIST
| typeof BRIDGE_TYPE_GET_EXTENSION_MANIFEST
| typeof BRIDGE_TYPE_GET_SIDE_PANEL_OPEN;
export interface BridgeRequest<T> {
type: BridgeType;
payload?: T;
6 changes: 3 additions & 3 deletions packages/shared/src/utils/extension/module/runtime.ts
Original file line number Diff line number Diff line change
@@ -43,15 +43,15 @@ export class Runtime {
*/
static async onMessageExternal<TPayload>(
type: BridgeType,
callbackFn: (
callbackFn?: (
request: BridgeRequest<TPayload>,
sender: chrome.runtime.MessageSender,
sendResponse: (response?: string) => void,
sendResponse: (response?: unknown) => void,
) => void,
): Promise<void> {
return chrome.runtime.onMessageExternal.addListener((request, sender, sendResponse) => {
if (!request?.type || request.type !== type) return;
callbackFn(request, sender, sendResponse);
callbackFn?.(request, sender, sendResponse);
});
}

28 changes: 28 additions & 0 deletions packages/web/src/app/login/components/ExtensionVersion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use client';

import { URL_CHROME_STORE } from '@extension/shared/constants';
import { useDidMount } from '@extension/shared/hooks';
import { requestGetExtensionManifest } from '@extension/shared/utils/extension';
import { useState } from 'react';

export default function ExtensionVersion() {
const [version, setVersion] = useState<null | string>(null);

useDidMount(() => {
try {
requestGetExtensionManifest(manifest => {
setVersion(manifest.version);
});
} catch (e) {
const answer = window.confirm(
'익스텐션을 설치하지 않으셨군요. 설치해야 메모 기능을 이용하실 수 있습니다. 설치하러 가시겠습니까?',
);
if (!answer) return;
location.href = URL_CHROME_STORE;
}
});

if (version)
return <p className="w-full text-sm absolute right-2 bottom-2 text-gray-600 text-end">설치된 버전 : {version}</p>;
return;
}
2 changes: 2 additions & 0 deletions packages/web/src/app/login/components/LoginSection.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { signInWithOAuth } from '@src/utils/supabase.server';
import Image from 'next/image';
import ExtensionVersion from './ExtensionVersion';

export default async function LoginSection() {
return (
@@ -19,6 +20,7 @@ export default async function LoginSection() {
구글 로그인
</button>
</form>
<ExtensionVersion />
</section>
);
}
1 change: 1 addition & 0 deletions packages/web/src/app/login/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as PersonalInformationInfo } from './PersonalInformationInfo';
export { default as LoginSection } from './LoginSection';
export { default as ExtensionVersion } from './ExtensionVersion';
2 changes: 2 additions & 0 deletions packages/web/src/app/memos/components/MemoRefresh.tsx
Original file line number Diff line number Diff line change
@@ -5,11 +5,13 @@ import React from 'react';

import { toast } from 'react-toastify';
import { motion, SVGMotionProps } from 'framer-motion';
import { driverObj } from '../utils';

interface MemoRefreshProps extends SVGMotionProps<SVGSVGElement> {}
export default function MemoRefresh({ ...props }: MemoRefreshProps) {
const queryClient = useQueryClient();
const handleClick = async () => {
driverObj.moveNext();
await queryClient.invalidateQueries({ queryKey: queryKeys.memoList() });
toast.success('새로고침이 완료되었습니다.');
};
14 changes: 13 additions & 1 deletion packages/web/src/app/memos/utils/guide.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import { driver } from 'driver.js';
import 'driver.js/dist/driver.css';
import { requestGetSidePanelOpen } from '@extension/shared/utils/extension';

export const driverObj = driver({
showProgress: true,
allowClose: false,
popoverClass: 'driverjs-theme',
nextBtnText: '다음',
doneBtnText: '종료',
prevBtnText: '이전',
steps: [
{
popover: {
title: '환영합니다 🎉',
description: `메모를 한 번 해볼까요?\nOption + S를 눌러 사이드 패널을 열어보세요 !`,
onPopoverRender: () => {
setInterval(() => {
requestGetSidePanelOpen(() => {
if (driverObj.getActiveIndex() !== 0) return;
driverObj.moveNext();
});
}, 500);
},
},
},
{
popover: {
title: '메모 저장',
description: `메모를 입력하시고, Command + S를 눌러 저장해보세요.\n메모 테두리가 파랑색 테두리에서 기본 테두리로 돌아왔다면 저장에 성공한 거에요!\n또한, 3초마다 자동으로 저장되니 안심하세요 ☺️`,
description: `잘하셨어요 !\n이제 이 사이드 패널에서 메모를 기록하실 수 있답니다.\n메모를 입력하고, Command + S를 눌러 저장해보세요.\n메모 테두리가 파랑색 테두리에서 기본 테두리로 돌아왔다면 저장에 성공한 거에요!\n또한, 3초마다 자동으로 저장되니 안심하세요 ☺️`,
},
},
{
4 changes: 4 additions & 0 deletions pages/side-panel/src/SidePanel.tsx
Original file line number Diff line number Diff line change
@@ -12,8 +12,12 @@ import {
SummaryHeader,
SummaryProvider,
} from './components';
import { useDidMount } from '@extension/shared/hooks';
import { responseGetSidePanelOpen } from '@extension/shared/utils/extension';

export default function SidePanel() {
useDidMount(responseGetSidePanelOpen);

return (
<QueryProvider>
<OverlayProvider>