mirror of https://github.com/fantasticit/think.git
client: detect isMobile on server
This commit is contained in:
parent
6941a5a226
commit
db55765e69
|
@ -14,6 +14,7 @@ import { useDocumentDetail } from 'data/document';
|
|||
import { useUser } from 'data/user';
|
||||
import { CHANGE_DOCUMENT_TITLE, event, triggerUseDocumentVersion } from 'event';
|
||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import { SecureDocumentIllustration } from 'illustrations/secure-document';
|
||||
import Router from 'next/router';
|
||||
|
@ -29,7 +30,8 @@ interface IProps {
|
|||
}
|
||||
|
||||
export const DocumentEditor: React.FC<IProps> = ({ documentId }) => {
|
||||
const { width: windowWith, isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const { width: windowWith } = useWindowSize();
|
||||
const { width, fontSize } = useDocumentStyle();
|
||||
const editorWrapClassNames = useMemo(() => {
|
||||
return width === 'standardWidth' ? styles.isStandardWidth : styles.isFullWidth;
|
||||
|
|
|
@ -14,6 +14,7 @@ import { useDocumentDetail } from 'data/document';
|
|||
import { useUser } from 'data/user';
|
||||
import { triggerJoinUser } from 'event';
|
||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import Router from 'next/router';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
|
@ -44,8 +45,9 @@ interface IProps {
|
|||
}
|
||||
|
||||
export const DocumentReader: React.FC<IProps> = ({ documentId }) => {
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const [container, setContainer] = useState<HTMLDivElement>();
|
||||
const { width: windowWidth, isMobile } = useWindowSize();
|
||||
const { width: windowWidth } = useWindowSize();
|
||||
const { width, fontSize } = useDocumentStyle();
|
||||
const editorWrapClassNames = useMemo(() => {
|
||||
return width === 'standardWidth' ? styles.isStandardWidth : styles.isFullWidth;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { IconArticle } from '@douyinfe/semi-icons';
|
||||
import {
|
||||
BackTop,
|
||||
Breadcrumb,
|
||||
|
@ -6,7 +5,6 @@ import {
|
|||
Form,
|
||||
Layout,
|
||||
Nav,
|
||||
Popover,
|
||||
Skeleton,
|
||||
Space,
|
||||
Typography,
|
||||
|
@ -22,7 +20,7 @@ import { Theme } from 'components/theme';
|
|||
import { User } from 'components/user';
|
||||
import { usePublicDocument } from 'data/document';
|
||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import Link from 'next/link';
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
@ -44,7 +42,7 @@ export const DocumentPublicReader: React.FC<IProps> = ({ documentId, hideLogo =
|
|||
const $form = useRef<FormApi>();
|
||||
const { data, loading, error, query } = usePublicDocument(documentId);
|
||||
const { width, fontSize } = useDocumentStyle();
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const editorWrapClassNames = useMemo(() => {
|
||||
return width === 'standardWidth' ? styles.isStandardWidth : styles.isFullWidth;
|
||||
}, [width]);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { IconArticle } from '@douyinfe/semi-icons';
|
||||
import { Button, Popover, Radio, RadioGroup, Slider, Typography } from '@douyinfe/semi-ui';
|
||||
import { useDocumentStyle } from 'hooks/use-document-style';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import React from 'react';
|
||||
|
||||
import styles from './index.module.scss';
|
||||
|
@ -10,7 +10,7 @@ import styles from './index.module.scss';
|
|||
const { Text } = Typography;
|
||||
|
||||
export const DocumentStyle = () => {
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const { width, fontSize, setWidth, setFontSize } = useDocumentStyle();
|
||||
const [visible, toggleVisible] = useToggle(false);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Popover, SideSheet, Typography } from '@douyinfe/semi-ui';
|
||||
import { createKeysLocalStorageLRUCache } from 'helpers/lru-cache';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { ACTIVITIES, EXPRESSIONES, GESTURES, OBJECTS, SKY_WEATHER, SYMBOLS } from './constants';
|
||||
|
@ -43,7 +43,7 @@ interface IProps {
|
|||
}
|
||||
|
||||
export const EmojiPicker: React.FC<IProps> = ({ onSelectEmoji, children }) => {
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const [recentUsed, setRecentUsed] = useState([]);
|
||||
const [visible, toggleVisible] = useToggle(false);
|
||||
const renderedList = useMemo(
|
||||
|
|
|
@ -4,8 +4,8 @@ import { Empty } from 'components/empty';
|
|||
import { IconMessage } from 'components/icons/IconMessage';
|
||||
import { useAllMessages, useReadMessages, useUnreadMessages } from 'data/message';
|
||||
import { useUser } from 'data/user';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import { EmptyBoxIllustration } from 'illustrations/empty-box';
|
||||
import Link from 'next/link';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
|
@ -87,7 +87,7 @@ const MessagesRender = ({ messageData, loading, error, onClick = null, page = 1,
|
|||
};
|
||||
|
||||
const MessageBox = () => {
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const [visible, toggleVisible] = useToggle(false);
|
||||
const { data: allMsgs, loading: allLoading, error: allError, page: allPage, setPage: allSetPage } = useAllMessages();
|
||||
const {
|
||||
|
|
|
@ -2,9 +2,9 @@ import { IconChevronDown, IconPlus } from '@douyinfe/semi-icons';
|
|||
import { Button, Dropdown } from '@douyinfe/semi-ui';
|
||||
import { DocumentCreator } from 'components/document/create';
|
||||
import { WikiCreator } from 'components/wiki/create';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useQuery } from 'hooks/use-query';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import React from 'react';
|
||||
|
||||
interface IProps {
|
||||
|
@ -12,7 +12,7 @@ interface IProps {
|
|||
}
|
||||
|
||||
export const WikiOrDocumentCreator: React.FC<IProps> = ({ onCreateDocument, children }) => {
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const { wikiId, docId } = useQuery<{ wikiId?: string; docId?: string }>();
|
||||
const [dropdownVisible, toggleDropdownVisible] = useToggle(false);
|
||||
const [visible, toggleVisible] = useToggle(false);
|
||||
|
|
|
@ -1,9 +1,23 @@
|
|||
export function isIOS() {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera;
|
||||
return /iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream;
|
||||
const getUserAgent = (ua = null) => {
|
||||
if (!ua) {
|
||||
if (typeof window !== 'undefined') {
|
||||
ua = navigator.userAgent || navigator.vendor || (window as any).opera;
|
||||
}
|
||||
}
|
||||
return ua;
|
||||
};
|
||||
|
||||
export function isIOS(ua = null) {
|
||||
const userAgent = getUserAgent(ua);
|
||||
return userAgent && /iPad|iPhone|iPod/.test(userAgent);
|
||||
}
|
||||
|
||||
export function isAndroid() {
|
||||
const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera;
|
||||
return /android/i.test(userAgent);
|
||||
export function isAndroid(ua = null) {
|
||||
const userAgent = getUserAgent(ua);
|
||||
return userAgent && /Android/i.test(userAgent);
|
||||
}
|
||||
|
||||
export function isMobile(ua = null) {
|
||||
const userAgent = getUserAgent(ua);
|
||||
return userAgent && /(iPhone|iPod|iPad|Android|BlackBerry)/i.test(userAgent);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { createGlobalHook } from './create-global-hook';
|
||||
import { useToggle } from './use-toggle';
|
||||
|
||||
const useOnMobile = (defaultIsMobile) => {
|
||||
const [isMobile, toggleIsMobile] = useToggle(defaultIsMobile);
|
||||
return {
|
||||
isMobile,
|
||||
toggleIsMobile,
|
||||
};
|
||||
};
|
||||
|
||||
export const IsOnMobile = createGlobalHook<{ isMobile?: boolean; toggle: () => void }, boolean>(useOnMobile);
|
|
@ -3,7 +3,6 @@ import { useEffect, useState } from 'react';
|
|||
interface Size {
|
||||
width: number | undefined;
|
||||
height: number | undefined;
|
||||
isMobile: boolean;
|
||||
}
|
||||
|
||||
const PC_MOBILE_CRITICAL_WIDTH = 765;
|
||||
|
@ -12,7 +11,6 @@ export function useWindowSize(): Size {
|
|||
const [windowSize, setWindowSize] = useState<Size>({
|
||||
width: undefined,
|
||||
height: undefined,
|
||||
isMobile: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -20,7 +18,6 @@ export function useWindowSize(): Size {
|
|||
setWindowSize({
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
isMobile: window.innerWidth <= PC_MOBILE_CRITICAL_WIDTH,
|
||||
});
|
||||
}
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Search } from 'components/search';
|
|||
import { Theme } from 'components/theme';
|
||||
import { User } from 'components/user';
|
||||
import { WikiOrDocumentCreator } from 'components/wiki-or-document-creator';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import Router, { useRouter } from 'next/router';
|
||||
|
@ -67,7 +68,8 @@ const menus = [
|
|||
|
||||
export const RouterHeader: React.FC = () => {
|
||||
const { pathname } = useRouter();
|
||||
const { width, isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const { width } = useWindowSize();
|
||||
const [dropdownVisible, toggleDropdownVisible] = useToggle(false);
|
||||
const [recentModalVisible, toggleRecentModalVisible] = useToggle(false);
|
||||
const [wikiModalVisible, toggleWikiModalVisible] = useToggle(false);
|
||||
|
|
|
@ -3,12 +3,18 @@ import 'viewerjs/dist/viewer.css';
|
|||
import 'styles/globals.scss';
|
||||
import 'tiptap/core/styles/index.scss';
|
||||
|
||||
import { isMobile } from 'helpers/env';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { Theme } from 'hooks/use-theme';
|
||||
import type { AppProps } from 'next/app';
|
||||
import Head from 'next/head';
|
||||
import React from 'react';
|
||||
|
||||
function MyApp({ Component, pageProps }: AppProps) {
|
||||
type P = AppProps<{ isMobile?: boolean }>;
|
||||
|
||||
function MyApp(props: AppProps & { isMobile?: boolean }) {
|
||||
const { Component, pageProps, isMobile } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
|
@ -40,10 +46,20 @@ function MyApp({ Component, pageProps }: AppProps) {
|
|||
))}
|
||||
</Head>
|
||||
<Theme.Provider>
|
||||
<IsOnMobile.Provider initialState={isMobile}>
|
||||
<Component {...pageProps} />
|
||||
</IsOnMobile.Provider>
|
||||
</Theme.Provider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
MyApp.getInitialProps = async (appContext) => {
|
||||
const request = appContext?.ctx?.req;
|
||||
|
||||
return {
|
||||
isMobile: isMobile(request?.headers['user-agent']),
|
||||
};
|
||||
};
|
||||
|
||||
export default MyApp;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Col, Dropdown, Modal, Row, SideSheet, Typography } from '@douyinfe/semi-ui';
|
||||
import { Dropdown, SideSheet, Typography } from '@douyinfe/semi-ui';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import styles from './style.module.scss';
|
||||
|
@ -85,7 +85,7 @@ export const ColorPicker: React.FC<{
|
|||
onSetColor: (arg: string) => void;
|
||||
disabled?: boolean;
|
||||
}> = ({ children, title = '颜色管理', onSetColor, disabled = false }) => {
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const [visible, toggleVisible] = useToggle(false);
|
||||
|
||||
const content = useMemo(
|
||||
|
|
|
@ -6,8 +6,8 @@ import { LogoName } from 'components/logo';
|
|||
import { getRandomColor } from 'helpers/color';
|
||||
import { isAndroid, isIOS } from 'helpers/env';
|
||||
import { useNetwork } from 'hooks/use-network';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
|
||||
import { Collaboration } from 'tiptap/core/extensions/collaboration';
|
||||
import { CollaborationCursor } from 'tiptap/core/extensions/collaboration-cursor';
|
||||
|
@ -30,7 +30,7 @@ export const EditorInstance = forwardRef((props: IProps, ref) => {
|
|||
const { hocuspocusProvider, editable, user, onTitleUpdate, status, menubar, renderInEditorPortal } = props;
|
||||
const $headerContainer = useRef<HTMLDivElement>();
|
||||
const $mainContainer = useRef<HTMLDivElement>();
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const { online } = useNetwork();
|
||||
const [created, toggleCreated] = useToggle(false);
|
||||
const editor = useEditor(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { Button, Input, Popover, SideSheet, Space, Typography } from '@douyinfe/semi-ui';
|
||||
import { IconSearchReplace } from 'components/icons';
|
||||
import { Tooltip } from 'components/tooltip';
|
||||
import { IsOnMobile } from 'hooks/use-on-mobile';
|
||||
import { useToggle } from 'hooks/use-toggle';
|
||||
import { useWindowSize } from 'hooks/use-window-size';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { SearchNReplace } from 'tiptap/core/extensions/search';
|
||||
import { Editor } from 'tiptap/editor';
|
||||
|
@ -10,7 +10,7 @@ import { Editor } from 'tiptap/editor';
|
|||
const { Text } = Typography;
|
||||
|
||||
export const Search: React.FC<{ editor: Editor }> = ({ editor }) => {
|
||||
const { isMobile } = useWindowSize();
|
||||
const { isMobile } = IsOnMobile.useHook();
|
||||
const [visible, toggleVisible] = useToggle(false);
|
||||
const [currentIndex, setCurrentIndex] = useState(-1);
|
||||
const [results, setResults] = useState([]);
|
||||
|
|
Loading…
Reference in New Issue