From 5223a3c5a6f2eb61a872e1730d7bedfcef5257b0 Mon Sep 17 00:00:00 2001 From: fullex <0xfullex@gmail.com> Date: Mon, 31 Mar 2025 12:15:57 +0800 Subject: [PATCH] feat: minapp show© current REAL url and can open it --- .../MinApp/MinappPopupContainer.tsx | 76 ++++++++++++++++--- .../components/MinApp/WebviewContainer.tsx | 10 ++- src/renderer/src/i18n/locales/en-us.json | 3 +- src/renderer/src/i18n/locales/ja-jp.json | 3 +- src/renderer/src/i18n/locales/ru-ru.json | 3 +- src/renderer/src/i18n/locales/zh-cn.json | 3 +- src/renderer/src/i18n/locales/zh-tw.json | 3 +- 7 files changed, 84 insertions(+), 17 deletions(-) diff --git a/src/renderer/src/components/MinApp/MinappPopupContainer.tsx b/src/renderer/src/components/MinApp/MinappPopupContainer.tsx index 6b668795..18ebb171 100644 --- a/src/renderer/src/components/MinApp/MinappPopupContainer.tsx +++ b/src/renderer/src/components/MinApp/MinappPopupContainer.tsx @@ -1,6 +1,7 @@ import { CloseOutlined, CodeOutlined, + CopyOutlined, ExportOutlined, MinusOutlined, PushpinOutlined, @@ -42,6 +43,9 @@ const MinappPopupContainer: React.FC = () => { const [isPopupShow, setIsPopupShow] = useState(true) /** whether the current minapp is ready */ const [isReady, setIsReady] = useState(false) + /** the current REAL url of the minapp + * different from the app preset url, because user may navigate in minapp */ + const [currentUrl, setCurrentUrl] = useState(null) /** store the last minapp id and show status */ const lastMinappId = useRef(null) @@ -59,6 +63,11 @@ const MinappPopupContainer: React.FC = () => { /** set the popup display status */ useEffect(() => { if (minappShow) { + // init the current url + if (currentMinappId && currentAppInfo) { + setCurrentUrl(currentAppInfo.url) + } + setIsPopupShow(true) if (webviewLoadedRefs.current.get(currentMinappId)) { @@ -168,6 +177,13 @@ const MinappPopupContainer: React.FC = () => { } } + /** the callback function to handle the webview navigate to new url */ + const handleWebviewNavigate = (appid: string, url: string) => { + if (appid === currentMinappId) { + setCurrentUrl(url) + } + } + /** will open the devtools of the minapp */ const handleOpenDevTools = (appid: string) => { const webview = webviewRefs.current.get(appid) @@ -187,12 +203,9 @@ const MinappPopupContainer: React.FC = () => { } } - /** only open the current url */ - const handleOpenLink = (appid: string) => { - const webview = webviewRefs.current.get(appid) - if (webview) { - window.api.openWebsite(webview.getURL()) - } + /** open the giving url in browser */ + const handleOpenLink = (url: string) => { + window.api.openWebsite(url) } /** toggle the pin status of the minapp */ @@ -205,11 +218,41 @@ const MinappPopupContainer: React.FC = () => { } /** Title bar of the popup */ - const Title = ({ appInfo }: { appInfo: AppInfo | null }) => { + const Title = ({ appInfo, url }: { appInfo: AppInfo | null; url: string | null }) => { if (!appInfo) return null + + const handleCopyUrl = (event: any, url: string) => { + //don't show app-wide context menu + event.preventDefault() + navigator.clipboard + .writeText(url) + .then(() => { + window.message.success('URL ' + t('message.copy.success')) + }) + .catch(() => { + window.message.error('URL ' + t('message.copy.failed')) + }) + } + return ( - {appInfo.name} + + {url ?? appInfo.url}
+ + {t('minapp.popup.rightclick_copyurl')} + + } + mouseEnterDelay={0.8} + placement="rightBottom" + styles={{ + root: { + maxWidth: '400px' + } + }}> + handleCopyUrl(e, url ?? appInfo.url)}>{appInfo.name} +
@@ -266,6 +309,7 @@ const MinappPopupContainer: React.FC = () => { url={app.url} onSetRefCallback={handleWebviewSetRef} onLoadedCallback={handleWebviewLoaded} + onNavigateCallback={handleWebviewNavigate} /> )) @@ -275,7 +319,7 @@ const MinappPopupContainer: React.FC = () => { return ( } + title={} placement="bottom" onClose={handlePopupMinimize} open={isPopupShow} @@ -321,8 +365,18 @@ const TitleText = styled.div` font-size: 14px; color: var(--color-text-1); margin-right: 10px; - user-select: none; + -webkit-app-region: no-drag; ` + +const TitleTextTooltip = styled.span` + font-size: 0.8rem; + + .icon-copy { + font-size: 0.7rem; + padding-right: 5px; + } +` + const ButtonsGroup = styled.div` display: flex; flex-direction: row; diff --git a/src/renderer/src/components/MinApp/WebviewContainer.tsx b/src/renderer/src/components/MinApp/WebviewContainer.tsx index f56cdc08..203122e0 100644 --- a/src/renderer/src/components/MinApp/WebviewContainer.tsx +++ b/src/renderer/src/components/MinApp/WebviewContainer.tsx @@ -11,12 +11,14 @@ const WebviewContainer = memo( appid, url, onSetRefCallback, - onLoadedCallback + onLoadedCallback, + onNavigateCallback }: { appid: string url: string onSetRefCallback: (appid: string, element: WebviewTag | null) => void onLoadedCallback: (appid: string) => void + onNavigateCallback: (appid: string, url: string) => void }) => { const webviewRef = useRef<WebviewTag | null>(null) @@ -47,8 +49,13 @@ const WebviewContainer = memo( onLoadedCallback(appid) } + const handleNavigate = (event: any) => { + onNavigateCallback(appid, event.url) + } + webviewRef.current.addEventListener('new-window', handleNewWindow) webviewRef.current.addEventListener('did-finish-load', handleLoaded) + webviewRef.current.addEventListener('did-navigate-in-page', handleNavigate) // we set the url when the webview is ready webviewRef.current.src = url @@ -56,6 +63,7 @@ const WebviewContainer = memo( return () => { webviewRef.current?.removeEventListener('new-window', handleNewWindow) webviewRef.current?.removeEventListener('did-finish-load', handleLoaded) + webviewRef.current?.removeEventListener('did-navigate-in-page', handleNavigate) } // because the appid and url are enough, no need to add onLoadedCallback // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index cbdb6787..a2054b9f 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -547,7 +547,8 @@ "close": "Close MinApp", "minimize": "Minimize MinApp", "devtools": "Developer Tools", - "openExternal": "Open in Browser" + "openExternal": "Open in Browser", + "rightclick_copyurl": "Right-click to copy URL" }, "sidebar.add.title": "Add to sidebar", "sidebar.remove.title": "Remove from sidebar", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index 0c7c5a9b..442b4c0a 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -547,7 +547,8 @@ "close": "ミニアプリを閉じる", "minimize": "ミニアプリを最小化", "devtools": "開発者ツール", - "openExternal": "ブラウザで開く" + "openExternal": "ブラウザで開く", + "rightclick_copyurl": "右クリックでURLをコピー" }, "sidebar.add.title": "サイドバーに追加", "sidebar.remove.title": "サイドバーから削除", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 70cdbbe0..636317d1 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -547,7 +547,8 @@ "close": "Закрыть встроенное приложение", "minimize": "Свернуть встроенное приложение", "devtools": "Инструменты разработчика", - "openExternal": "Открыть в браузере" + "openExternal": "Открыть в браузере", + "rightclick_copyurl": "ПКМ → Копировать URL" }, "sidebar.add.title": "Добавить в боковую панель", "sidebar.remove.title": "Удалить из боковой панели", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 9b8197d1..c7f6eb53 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -547,7 +547,8 @@ "close": "关闭小程序", "minimize": "最小化小程序", "devtools": "开发者工具", - "openExternal": "在浏览器中打开" + "openExternal": "在浏览器中打开", + "rightclick_copyurl": "右键复制URL" }, "sidebar.add.title": "添加到侧边栏", "sidebar.remove.title": "从侧边栏移除", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 96946816..222b1f0d 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -547,7 +547,8 @@ "close": "關閉小工具", "minimize": "最小化小工具", "devtools": "開發者工具", - "openExternal": "在瀏覽器中開啟" + "openExternal": "在瀏覽器中開啟", + "rightclick_copyurl": "右鍵複製URL" }, "sidebar.add.title": "新增到側邊欄", "sidebar.remove.title": "從側邊欄移除",