forked from lobehub/lobe-chat
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
💄 style: improve PWA install guide (lobehub#2617)
* ✨ feat: Update PWA install * ✨ feat: Update usePlatform * ✨ feat: Update isSonomaOrLaterSafari * 🐛 fix: Fix isSonomaOrLaterSafari * 🐛 fix: Fix isSupportInstallPWA * ✅ test: Add test * ✅ test: Add isSonomaOrLaterSafari test
- Loading branch information
1 parent
4a23cad
commit 7fee545
Showing
13 changed files
with
346 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use client'; | ||
|
||
import dynamic from 'next/dynamic'; | ||
import { memo } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
import { PWA_INSTALL_ID } from '@/const/layoutTokens'; | ||
import { usePlatform } from '@/hooks/usePlatform'; | ||
|
||
// @ts-ignore | ||
const PWA: any = dynamic(() => import('@khmyznikov/pwa-install/dist/pwa-install.react.js'), { | ||
ssr: false, | ||
}); | ||
|
||
const PWAInstall = memo(() => { | ||
const { t } = useTranslation('metadata'); | ||
const { isPWA } = usePlatform(); | ||
if (isPWA) return null; | ||
return <PWA description={t('chat.description')} id={PWA_INSTALL_ID} />; | ||
}); | ||
|
||
export default PWAInstall; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { act, renderHook } from '@testing-library/react'; | ||
import { pwaInstallHandler } from 'pwa-install-handler'; | ||
import { afterEach, describe, expect, it, vi } from 'vitest'; | ||
|
||
import { PWA_INSTALL_ID } from '@/const/layoutTokens'; | ||
|
||
import { usePWAInstall } from './usePWAInstall'; | ||
import { usePlatform } from './usePlatform'; | ||
|
||
// Mocks | ||
vi.mock('./usePlatform', () => ({ | ||
usePlatform: vi.fn(), | ||
})); | ||
|
||
vi.mock('@/utils/env', () => ({ | ||
isOnServerSide: false, | ||
})); | ||
|
||
vi.mock('pwa-install-handler', () => ({ | ||
pwaInstallHandler: { | ||
addListener: vi.fn(), | ||
removeListener: vi.fn(), | ||
getEvent: vi.fn(), | ||
}, | ||
})); | ||
|
||
describe('usePWAInstall', () => { | ||
afterEach(() => { | ||
vi.clearAllMocks(); | ||
}); | ||
|
||
it('should return canInstall as false when in PWA', () => { | ||
vi.mocked(usePlatform).mockReturnValue({ isSupportInstallPWA: true, isPWA: true } as any); | ||
|
||
const { result } = renderHook(() => usePWAInstall()); | ||
|
||
expect(result.current.canInstall).toBe(false); | ||
}); | ||
|
||
it('should return canInstall based on canInstall state when support PWA', () => { | ||
vi.mocked(usePlatform).mockReturnValue({ isSupportInstallPWA: true, isPWA: false } as any); | ||
|
||
const { result, rerender } = renderHook(() => usePWAInstall()); | ||
|
||
expect(result.current.canInstall).toBe(false); | ||
|
||
act(() => { | ||
vi.mocked(pwaInstallHandler.addListener).mock.calls[0][0](true); | ||
}); | ||
|
||
rerender(); | ||
|
||
expect(result.current.canInstall).toBe(true); | ||
}); | ||
|
||
it('should return canInstall as true when not support PWA', () => { | ||
vi.mocked(usePlatform).mockReturnValue({ isSupportInstallPWA: false, isPWA: false } as any); | ||
|
||
const { result } = renderHook(() => usePWAInstall()); | ||
|
||
expect(result.current.canInstall).toBe(true); | ||
}); | ||
|
||
it('should call pwa.showDialog when install is called', () => { | ||
const mockShowDialog = vi.fn(); | ||
document.body.innerHTML = `<div id="${PWA_INSTALL_ID}"></div>`; | ||
const pwaElement: any = document.querySelector(`#${PWA_INSTALL_ID}`); | ||
pwaElement.showDialog = mockShowDialog; | ||
|
||
const { result } = renderHook(() => usePWAInstall()); | ||
|
||
act(() => { | ||
result.current.install(); | ||
}); | ||
|
||
expect(mockShowDialog).toHaveBeenCalledWith(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,39 @@ | ||
import { pwaInstallHandler } from 'pwa-install-handler'; | ||
import { useEffect, useState } from 'react'; | ||
|
||
import { PWA_INSTALL_ID } from '@/const/layoutTokens'; | ||
import { isOnServerSide } from '@/utils/env'; | ||
|
||
import { usePlatform } from './usePlatform'; | ||
|
||
export const usePWAInstall = () => { | ||
const [canInstall, setCanInstall] = useState(false); | ||
const { isSupportInstallPWA, isPWA } = usePlatform(); | ||
|
||
useEffect(() => { | ||
if (isOnServerSide) return; | ||
pwaInstallHandler.addListener(setCanInstall); | ||
return () => { | ||
pwaInstallHandler.removeListener(setCanInstall); | ||
}; | ||
}, []); | ||
|
||
const installCheck = () => { | ||
// 当在 PWA 中时,不显示安装按钮 | ||
if (isPWA) return false; | ||
// 其他情况下,根据是否可以安装来显示安装按钮 (如已经安装则不显示) | ||
if (isSupportInstallPWA) return canInstall; | ||
// 当在不支持 PWA 的环境中时,安装按钮 (此时为安装教程) | ||
return true; | ||
}; | ||
|
||
return { | ||
canInstall, | ||
install: pwaInstallHandler.install, | ||
canInstall: installCheck(), | ||
install: () => { | ||
const pwa: any = document.querySelector(`#${PWA_INSTALL_ID}`); | ||
if (!pwa) return; | ||
pwa.externalPromptEvent = pwaInstallHandler.getEvent(); | ||
pwa?.showDialog(true); | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { renderHook } from '@testing-library/react'; | ||
import { describe, expect, it, vi } from 'vitest'; | ||
|
||
import * as platformUtils from '@/utils/platform'; | ||
|
||
import { usePlatform } from './usePlatform'; | ||
|
||
// Mocks | ||
vi.mock('@/utils/platform', () => ({ | ||
getBrowser: vi.fn(), | ||
getPlatform: vi.fn(), | ||
isInStandaloneMode: vi.fn(), | ||
isSonomaOrLaterSafari: vi.fn(), | ||
})); | ||
|
||
describe('usePlatform', () => { | ||
it('should return correct platform info for Mac OS and Chrome', () => { | ||
vi.mocked(platformUtils.getPlatform).mockReturnValue('Mac OS'); | ||
vi.mocked(platformUtils.getBrowser).mockReturnValue('Chrome'); | ||
vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(false); | ||
vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(false); | ||
|
||
const { result } = renderHook(() => usePlatform()); | ||
|
||
expect(result.current).toEqual({ | ||
isApple: true, | ||
isChrome: true, | ||
isChromium: true, | ||
isEdge: false, | ||
isIOS: false, | ||
isMacOS: true, | ||
isPWA: false, | ||
isSafari: false, | ||
isSonomaOrLaterSafari: false, | ||
isSupportInstallPWA: true, | ||
}); | ||
}); | ||
|
||
it('should return correct platform info for iOS and Safari', () => { | ||
vi.mocked(platformUtils.getPlatform).mockReturnValue('iOS'); | ||
vi.mocked(platformUtils.getBrowser).mockReturnValue('Safari'); | ||
vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(true); | ||
vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(true); | ||
|
||
const { result } = renderHook(() => usePlatform()); | ||
|
||
expect(result.current).toEqual({ | ||
isApple: true, | ||
isChrome: false, | ||
isChromium: false, | ||
isEdge: false, | ||
isIOS: true, | ||
isMacOS: false, | ||
isPWA: true, | ||
isSafari: true, | ||
isSonomaOrLaterSafari: true, | ||
isSupportInstallPWA: false, | ||
}); | ||
}); | ||
|
||
it('should return correct platform info for Windows and Edge', () => { | ||
vi.mocked(platformUtils.getPlatform).mockReturnValue('Windows'); | ||
vi.mocked(platformUtils.getBrowser).mockReturnValue('Edge'); | ||
vi.mocked(platformUtils.isInStandaloneMode).mockReturnValue(false); | ||
vi.mocked(platformUtils.isSonomaOrLaterSafari).mockReturnValue(false); | ||
|
||
const { result } = renderHook(() => usePlatform()); | ||
|
||
expect(result.current).toEqual({ | ||
isApple: false, | ||
isChrome: false, | ||
isChromium: true, | ||
isEdge: true, | ||
isIOS: false, | ||
isMacOS: false, | ||
isPWA: false, | ||
isSafari: false, | ||
isSonomaOrLaterSafari: false, | ||
isSupportInstallPWA: true, | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,32 @@ | ||
import { useRef } from 'react'; | ||
|
||
import { getBrowser, getPlatform } from '@/utils/platform'; | ||
import { | ||
getBrowser, | ||
getPlatform, | ||
isInStandaloneMode, | ||
isSonomaOrLaterSafari, | ||
} from '@/utils/platform'; | ||
|
||
export const usePlatform = () => { | ||
const platform = useRef(getPlatform()); | ||
const browser = useRef(getBrowser()); | ||
return { | ||
|
||
const platformInfo = { | ||
isApple: platform.current && ['Mac OS', 'iOS'].includes(platform.current), | ||
isChrome: browser.current === 'Chrome', | ||
isChromium: browser.current && ['Chrome', 'Edge', 'Opera', 'Brave'].includes(browser.current), | ||
isEdge: browser.current === 'Edge', | ||
isIOS: platform.current === 'iOS', | ||
isMacOS: platform.current === 'Mac OS', | ||
isPWA: isInStandaloneMode(), | ||
isSafari: browser.current === 'Safari', | ||
isSonomaOrLaterSafari: isSonomaOrLaterSafari(), | ||
}; | ||
|
||
return { | ||
...platformInfo, | ||
isSupportInstallPWA: | ||
(platformInfo.isChromium && !platformInfo.isIOS) || | ||
(platformInfo.isMacOS && platformInfo.isSonomaOrLaterSafari), | ||
}; | ||
}; |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.