feat: minapp show&copy current REAL url and can open it

This commit is contained in:
fullex 2025-03-31 12:15:57 +08:00 committed by 亢奋猫
parent 72c5de3b81
commit 5223a3c5a6
7 changed files with 84 additions and 17 deletions

View File

@ -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<string | null>(null)
/** store the last minapp id and show status */
const lastMinappId = useRef<string | null>(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 (
<TitleContainer style={{ justifyContent: 'space-between' }}>
<TitleText>{appInfo.name}</TitleText>
<Tooltip
title={
<TitleTextTooltip>
{url ?? appInfo.url} <br />
<CopyOutlined className="icon-copy" />
{t('minapp.popup.rightclick_copyurl')}
</TitleTextTooltip>
}
mouseEnterDelay={0.8}
placement="rightBottom"
styles={{
root: {
maxWidth: '400px'
}
}}>
<TitleText onContextMenu={(e) => handleCopyUrl(e, url ?? appInfo.url)}>{appInfo.name}</TitleText>
</Tooltip>
<ButtonsGroup className={isWindows ? 'windows' : ''}>
<Tooltip title={t('minapp.popup.refresh')} mouseEnterDelay={0.8} placement="bottom">
<Button onClick={() => handleReload(appInfo.id)}>
@ -228,7 +271,7 @@ const MinappPopupContainer: React.FC = () => {
)}
{appInfo.canOpenExternalLink && (
<Tooltip title={t('minapp.popup.openExternal')} mouseEnterDelay={0.8} placement="bottom">
<Button onClick={() => handleOpenLink(appInfo.id)}>
<Button onClick={() => handleOpenLink(url ?? appInfo.url)}>
<ExportOutlined />
</Button>
</Tooltip>
@ -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 (
<Drawer
title={<Title appInfo={currentAppInfo} />}
title={<Title appInfo={currentAppInfo} url={currentUrl} />}
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;

View File

@ -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

View File

@ -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",

View File

@ -547,7 +547,8 @@
"close": "ミニアプリを閉じる",
"minimize": "ミニアプリを最小化",
"devtools": "開発者ツール",
"openExternal": "ブラウザで開く"
"openExternal": "ブラウザで開く",
"rightclick_copyurl": "右クリックでURLをコピー"
},
"sidebar.add.title": "サイドバーに追加",
"sidebar.remove.title": "サイドバーから削除",

View File

@ -547,7 +547,8 @@
"close": "Закрыть встроенное приложение",
"minimize": "Свернуть встроенное приложение",
"devtools": "Инструменты разработчика",
"openExternal": "Открыть в браузере"
"openExternal": "Открыть в браузере",
"rightclick_copyurl": "ПКМ → Копировать URL"
},
"sidebar.add.title": "Добавить в боковую панель",
"sidebar.remove.title": "Удалить из боковой панели",

View File

@ -547,7 +547,8 @@
"close": "关闭小程序",
"minimize": "最小化小程序",
"devtools": "开发者工具",
"openExternal": "在浏览器中打开"
"openExternal": "在浏览器中打开",
"rightclick_copyurl": "右键复制URL"
},
"sidebar.add.title": "添加到侧边栏",
"sidebar.remove.title": "从侧边栏移除",

View File

@ -547,7 +547,8 @@
"close": "關閉小工具",
"minimize": "最小化小工具",
"devtools": "開發者工具",
"openExternal": "在瀏覽器中開啟"
"openExternal": "在瀏覽器中開啟",
"rightclick_copyurl": "右鍵複製URL"
},
"sidebar.add.title": "新增到側邊欄",
"sidebar.remove.title": "從側邊欄移除",