diff --git a/public/icons/icon-192x192.png b/public/icons/icon-192x192.png new file mode 100644 index 000000000000..cc29879cf45b Binary files /dev/null and b/public/icons/icon-192x192.png differ diff --git a/public/icons/icon-512x512.png b/public/icons/icon-512x512.png new file mode 100644 index 000000000000..3794e502aac6 Binary files /dev/null and b/public/icons/icon-512x512.png differ diff --git a/public/icons/icon-maskable-192x192.png b/public/icons/icon-maskable-192x192.png new file mode 100644 index 000000000000..a42d249d22b8 Binary files /dev/null and b/public/icons/icon-maskable-192x192.png differ diff --git a/public/icons/icon-maskable-512x512.png b/public/icons/icon-maskable-512x512.png new file mode 100644 index 000000000000..42f62ed253c8 Binary files /dev/null and b/public/icons/icon-maskable-512x512.png differ diff --git a/public/manifest.json b/public/manifest.json index f60695757282..2a2a0af68dc6 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -4,23 +4,38 @@ "display": "fullscreen", "icons": [ { - "src": "https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/android-chrome-192x192.png", + "src": "/icons/icon-192x192.png", "sizes": "192x192", - "type": "image/png" + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-maskable-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" }, { - "src": "https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/android-chrome-512x512.png", + "src": "/icons/icon-512x512.png", "sizes": "512x512", - "type": "image/png" + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icons/icon-maskable-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" } ], + "id": "/", "name": "LobeChat", "orientation": "portrait", "scope": "/", "screenshots": [ { - "src": "https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-960x720.png", - "sizes": "960x720", + "src": "https://registry.npmmirror.com/@lobehub/assets-favicons/1.4.0/files/assets/og-960x540.png", + "sizes": "960x540", "type": "image/png" } ], diff --git a/src/app/chat/features/Conversation/ChatList/index.tsx b/src/app/chat/features/Conversation/ChatList/index.tsx index d080009e6de0..8b46ef6a7357 100644 --- a/src/app/chat/features/Conversation/ChatList/index.tsx +++ b/src/app/chat/features/Conversation/ChatList/index.tsx @@ -1,4 +1,5 @@ import { ChatList, RenderMessage } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; import isEqual from 'fast-deep-equal'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -15,10 +16,22 @@ import FunctionCall from './Plugins/FunctionCall'; import PluginMessage from './Plugins/PluginMessage'; import SkeletonList from './SkeletonList'; -const List = () => { +const useStyles = createStyles(({ css, responsive, cx, stylish }) => + cx( + stylish.noScrollbar, + css` + overflow-x: hidden; + ${responsive.mobile} { + width: 100vw; + } + `, + ), +); + +const List = memo(() => { const init = useSessionChatInit(); const { t } = useTranslation('common'); - + const { styles } = useStyles(); const data = useSessionStore(chatSelectors.currentChatsWithGuideMessage, isEqual); const [ @@ -83,6 +96,7 @@ const List = () => { return ( { type={displayMode || 'chat'} /> ); -}; +}); -export default memo(List); +export default List; diff --git a/src/app/chat/features/Conversation/Input/ActionBar/ActionRight.tsx b/src/app/chat/features/Conversation/Input/ActionBar/ActionRight.tsx index 6d7ef7478455..85d8849244f7 100644 --- a/src/app/chat/features/Conversation/Input/ActionBar/ActionRight.tsx +++ b/src/app/chat/features/Conversation/Input/ActionBar/ActionRight.tsx @@ -1,30 +1,36 @@ import { ActionIcon } from '@lobehub/ui'; import { Popconfirm } from 'antd'; +import { useResponsive } from 'antd-style'; import { Eraser } from 'lucide-react'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { useSessionStore } from '@/store/session'; +import SaveTopic from '../Footer/SaveTopic'; + const ActionsRight = memo(() => { const { t } = useTranslation('setting'); const [clearMessage] = useSessionStore((s) => [s.clearMessage, s.updateAgentConfig]); - + const { mobile } = useResponsive(); return ( - clearMessage()} - placement={'topRight'} - title={t('confirmClearCurrentMessages', { ns: 'common' })} - > - - + <> + {mobile && } + clearMessage()} + placement={'topRight'} + title={t('confirmClearCurrentMessages', { ns: 'common' })} + > + + + ); }); diff --git a/src/app/chat/features/Conversation/Input/Mobile.tsx b/src/app/chat/features/Conversation/Input/Mobile.tsx index 109d707603b4..4ae834805262 100644 --- a/src/app/chat/features/Conversation/Input/Mobile.tsx +++ b/src/app/chat/features/Conversation/Input/Mobile.tsx @@ -1,12 +1,35 @@ +import { createStyles } from 'antd-style'; import { ReactNode, memo } from 'react'; +import SafeSpacing from '@/components/SafeSpacing'; +import { CHAT_TEXTAREA_HEIGHT_MOBILE } from '@/const/layoutTokens'; + +const useStyles = createStyles( + ({ css, token }) => css` + position: fixed; + right: 0; + bottom: 0; + left: 0; + + width: 100vw; + + background: ${token.colorBgLayout}; + `, +); + interface ChatInputMobileLayoutProps { children: ReactNode; expand?: boolean; } const ChatInputMobileLayout = memo(({ children }) => { - return
{children}
; + const { styles } = useStyles(); + return ( + <> + +
{children}
+ + ); }); export default ChatInputMobileLayout; diff --git a/src/app/chat/index.tsx b/src/app/chat/index.tsx index b0007da6793b..c4c5f40d1acc 100644 --- a/src/app/chat/index.tsx +++ b/src/app/chat/index.tsx @@ -13,8 +13,8 @@ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle'; import Conversation from './features/Conversation'; import Header from './features/Header'; import SideBar from './features/Sidebar'; +import DesktopLayout from './layout.desktop'; import MobileLayout from './layout.mobile'; -import DesktopLayout from './layout.pc'; const Chat = memo(() => { const { mobile } = useResponsive(); diff --git a/src/app/chat/layout.pc.tsx b/src/app/chat/layout.desktop.tsx similarity index 100% rename from src/app/chat/layout.pc.tsx rename to src/app/chat/layout.desktop.tsx diff --git a/src/app/chat/settings/index.tsx b/src/app/chat/settings/index.tsx index acf076b0b44e..df0df0001fcc 100644 --- a/src/app/chat/settings/index.tsx +++ b/src/app/chat/settings/index.tsx @@ -11,8 +11,8 @@ import { useSessionStore } from '@/store/session'; import { agentSelectors } from '@/store/session/selectors'; import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle'; +import DesktopLayout from './layout.desktop'; import MobileLayout from './layout.mobile'; -import DesktopLayout from './layout.pc'; const EditPage = memo(() => { const { mobile } = useResponsive(); diff --git a/src/app/chat/settings/layout.pc.tsx b/src/app/chat/settings/layout.desktop.tsx similarity index 93% rename from src/app/chat/settings/layout.pc.tsx rename to src/app/chat/settings/layout.desktop.tsx index 75ed52516008..5d4614d7a78f 100644 --- a/src/app/chat/settings/layout.pc.tsx +++ b/src/app/chat/settings/layout.desktop.tsx @@ -4,7 +4,7 @@ import { Flexbox } from 'react-layout-kit'; import SafeSpacing from '@/components/SafeSpacing'; import { HEADER_HEIGHT } from '@/const/layoutTokens'; -import ChatLayout from '../layout.pc'; +import ChatLayout from '../layout.desktop'; import Header from './features/Header'; const DesktopLayout = memo(({ children }) => { diff --git a/src/app/market/index.tsx b/src/app/market/index.tsx index 9fad7dafa459..ddab1e24ae43 100644 --- a/src/app/market/index.tsx +++ b/src/app/market/index.tsx @@ -10,8 +10,8 @@ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle'; import AgentCard from './features/AgentCard'; import AgentSearchBar from './features/AgentSearchBar'; +import DesktopLayout from './layout.desktop'; import MobileLayout from './layout.mobile'; -import DesktopLayout from './layout.pc'; const Market = memo(() => { const { t } = useTranslation('common'); diff --git a/src/app/market/layout.pc.tsx b/src/app/market/layout.desktop.tsx similarity index 100% rename from src/app/market/layout.pc.tsx rename to src/app/market/layout.desktop.tsx diff --git a/src/app/metadata.ts b/src/app/metadata.ts index 0831c013afed..c946b10ae563 100644 --- a/src/app/metadata.ts +++ b/src/app/metadata.ts @@ -8,13 +8,6 @@ const title = genSiteHeadTitle(); const description = pkg.description; const metadata: Metadata = { appleWebApp: { - startupImage: [ - 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/splash-750x1624.png', - { - media: '(device-width: 768px) and (device-height: 1024px)', - url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/splash-2048x2732.png', - }, - ], statusBarStyle: 'black-translucent', title: title, }, @@ -23,10 +16,6 @@ const metadata: Metadata = { apple: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/apple-touch-icon.png', icon: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/favicon-32x32.png', - other: { - rel: 'mask-icon', - url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/safari-pinned-tab.svg', - }, shortcut: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/favicon.ico', }, @@ -37,13 +26,13 @@ const metadata: Metadata = { { alt: title, height: 360, - url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-480x360.png', + url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/1.4.0/files/assets/og-480x270.png', width: 480, }, { alt: title, height: 720, - url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-960x720.png', + url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/1.4.0/files/assets/og-960x540.png', width: 960, }, ], @@ -57,7 +46,7 @@ const metadata: Metadata = { { color: '#fff', media: '(prefers-color-scheme: light)' }, { color: '#000', media: '(prefers-color-scheme: dark)' }, ], - title: genSiteHeadTitle(), + title: title, viewport: { initialScale: 1, maximumScale: 1, diff --git a/src/app/settings/index.tsx b/src/app/settings/index.tsx index 721dd247330c..bf720d9ecafb 100644 --- a/src/app/settings/index.tsx +++ b/src/app/settings/index.tsx @@ -9,8 +9,8 @@ import { useSwitchSideBarOnInit } from '@/store/global'; import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle'; import Settings from './features/Settings'; +import DesktopLayout from './layout.desktop'; import MobileLayout from './layout.mobile'; -import DesktopLayout from './layout.pc'; const Setting = memo(() => { const { mobile } = useResponsive(); diff --git a/src/app/settings/layout.pc.tsx b/src/app/settings/layout.desktop.tsx similarity index 100% rename from src/app/settings/layout.pc.tsx rename to src/app/settings/layout.desktop.tsx diff --git a/src/app/welcome/index.tsx b/src/app/welcome/index.tsx index 7caf378d6511..46a9a8a32c3e 100644 --- a/src/app/welcome/index.tsx +++ b/src/app/welcome/index.tsx @@ -9,8 +9,8 @@ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle'; import Banner from './features/Banner'; import Footer from './features/Footer'; +import Layout from './layout.desktop'; import Mobile from './layout.mobile'; -import Layout from './layout.pc'; const Welcome = memo(() => { const { mobile } = useResponsive(); diff --git a/src/app/welcome/layout.pc.tsx b/src/app/welcome/layout.desktop.tsx similarity index 100% rename from src/app/welcome/layout.pc.tsx rename to src/app/welcome/layout.desktop.tsx diff --git a/src/app/welcome/layout.mobile.tsx b/src/app/welcome/layout.mobile.tsx index d9573a998e2a..9f330d83695e 100644 --- a/src/app/welcome/layout.mobile.tsx +++ b/src/app/welcome/layout.mobile.tsx @@ -10,7 +10,7 @@ const WelcomeLayout = memo(({ children }) => { } />} showTabBar - style={{ background: theme.colorBgContainer }} + style={{ background: theme.colorBgLayout }} > {children} diff --git a/src/const/layoutTokens.ts b/src/const/layoutTokens.ts index 0e8e98e8f313..e296e5b7483e 100644 --- a/src/const/layoutTokens.ts +++ b/src/const/layoutTokens.ts @@ -4,6 +4,7 @@ export const HEADER_HEIGHT = 64; export const MOBILE_NABBAR_HEIGHT = 44; export const MOBILE_TABBAR_HEIGHT = 48; export const CHAT_TEXTAREA_HEIGHT = 200; +export const CHAT_TEXTAREA_HEIGHT_MOBILE = 180; export const CHAT_SIDEBAR_WIDTH = 280; export const MARKET_SIDEBAR_WIDTH = 400; export const FOLDER_WIDTH = 256; diff --git a/src/hooks/useIsPWA.ts b/src/hooks/useIsPWA.ts index 550fc531160d..7defeee104d9 100644 --- a/src/hooks/useIsPWA.ts +++ b/src/hooks/useIsPWA.ts @@ -4,8 +4,7 @@ export const useIsPWA = () => { const [isPWA, setIsPWA] = useState(false); useEffect(() => { - const isInStandaloneMode = () => - 'standalone' in window.navigator && window.navigator['standalone']; + const isInStandaloneMode = () => window.matchMedia('(display-mode: standalone)').matches; if (isInStandaloneMode()) { setIsPWA(true); }