From d3f02a35d9702c41a80bac28a7b118c125d56b88 Mon Sep 17 00:00:00 2001 From: haitaoo Date: Thu, 20 Apr 2023 16:00:27 +0800 Subject: [PATCH] fix(ImgViewer): Migrate `ImgViewer` from hooks to component --- ui/src/components/Editor/Viewer.tsx | 13 +- ui/src/components/ImgViewer/index.css | 7 ++ .../ImgViewer}/index.tsx | 46 +++---- ui/src/components/index.ts | 2 + ui/src/hooks/index.ts | 2 - ui/src/index.scss | 8 -- ui/src/pages/Admin/Branding/index.tsx | 6 +- ui/src/pages/Admin/SettingsUsers/index.tsx | 3 + ui/src/pages/Layout/index.tsx | 6 +- .../Detail/components/Question/index.tsx | 13 +- ui/src/pages/Users/Settings/Profile/index.tsx | 117 +++++++++--------- ui/src/stores/siteInfo.ts | 21 ++-- 12 files changed, 127 insertions(+), 117 deletions(-) create mode 100644 ui/src/components/ImgViewer/index.css rename ui/src/{hooks/useImgViewer => components/ImgViewer}/index.tsx (67%) diff --git a/ui/src/components/Editor/Viewer.tsx b/ui/src/components/Editor/Viewer.tsx index db036f90..357be508 100644 --- a/ui/src/components/Editor/Viewer.tsx +++ b/ui/src/components/Editor/Viewer.tsx @@ -8,6 +8,7 @@ import { } from 'react'; import { markdownToHtml } from '@/services'; +import ImgViewer from '@/components/ImgViewer'; import { htmlRender } from './utils'; @@ -48,11 +49,13 @@ const Index = ({ value }, ref) => { }); return ( -
+ +
+ ); }; diff --git a/ui/src/components/ImgViewer/index.css b/ui/src/components/ImgViewer/index.css new file mode 100644 index 00000000..c70399f1 --- /dev/null +++ b/ui/src/components/ImgViewer/index.css @@ -0,0 +1,7 @@ +.img-viewer .cursor-zoom-out { + cursor: zoom-out !important; +} + +.img-viewer img:not(a img, img.broken) { + cursor: zoom-in; +} diff --git a/ui/src/hooks/useImgViewer/index.tsx b/ui/src/components/ImgViewer/index.tsx similarity index 67% rename from ui/src/hooks/useImgViewer/index.tsx rename to ui/src/components/ImgViewer/index.tsx index 6b3a30c2..eceb45b4 100644 --- a/ui/src/hooks/useImgViewer/index.tsx +++ b/ui/src/components/ImgViewer/index.tsx @@ -1,14 +1,13 @@ -import { useLayoutEffect, useState, MouseEvent, useEffect } from 'react'; +import { FC, MouseEvent, ReactNode, useEffect, useState } from 'react'; import { Modal } from 'react-bootstrap'; -import { useLocation } from 'react-router-dom'; -import ReactDOM from 'react-dom/client'; +import './index.css'; +import classnames from 'classnames'; -const div = document.createElement('div'); -const root = ReactDOM.createRoot(div); - -const useImgViewer = () => { - const location = useLocation(); +const Index: FC<{ + children: ReactNode; + className?: classnames.Argument; +}> = ({ children, className }) => { const [visible, setVisible] = useState(false); const [imgSrc, setImgSrc] = useState(''); const onClose = () => { @@ -47,8 +46,18 @@ const useImgViewer = () => { } }; - useLayoutEffect(() => { - root.render( + useEffect(() => { + return () => { + onClose(); + }; + }, []); + + return ( + // eslint-disable-next-line jsx-a11y/click-events-have-key-events +
+ {children} { scrollable contentClassName="bg-transparent" onHide={onClose}> - + {imgSrc} - , - ); - }); - useEffect(() => { - onClose(); - }, [location]); - return { - onClose, - checkClickForImgView, - }; + +
+ ); }; -export default useImgViewer; +export default Index; diff --git a/ui/src/components/index.ts b/ui/src/components/index.ts index 840d3f4a..ad83636b 100644 --- a/ui/src/components/index.ts +++ b/ui/src/components/index.ts @@ -39,6 +39,7 @@ import QuestionList from './QuestionList'; import HotQuestions from './HotQuestions'; import HttpErrorContent from './HttpErrorContent'; import CustomSidebar from './CustomSidebar'; +import ImgViewer from './ImgViewer'; export { Avatar, @@ -84,5 +85,6 @@ export { HotQuestions, HttpErrorContent, CustomSidebar, + ImgViewer, }; export type { EditorRef, JSONSchema, UISchema }; diff --git a/ui/src/hooks/index.ts b/ui/src/hooks/index.ts index f7942048..756d8724 100644 --- a/ui/src/hooks/index.ts +++ b/ui/src/hooks/index.ts @@ -10,7 +10,6 @@ import useChangePasswordModal from './useChangePasswordModal'; import usePageTags from './usePageTags'; import useLoginRedirect from './useLoginRedirect'; import usePromptWithUnload from './usePrompt'; -import useImgViewer from './useImgViewer'; export { useTagModal, @@ -25,5 +24,4 @@ export { usePageTags, useLoginRedirect, usePromptWithUnload, - useImgViewer, }; diff --git a/ui/src/index.scss b/ui/src/index.scss index 5a6efe88..29191bb8 100644 --- a/ui/src/index.scss +++ b/ui/src/index.scss @@ -120,14 +120,6 @@ a { cursor: pointer; } -.cursor-zoom-out { - cursor: zoom-out !important; -} - -img:not(a img, img.broken) { - cursor: zoom-in; -} - .resize-none { resize: none; } diff --git a/ui/src/pages/Admin/Branding/index.tsx b/ui/src/pages/Admin/Branding/index.tsx index acbe1e32..93a86d2d 100644 --- a/ui/src/pages/Admin/Branding/index.tsx +++ b/ui/src/pages/Admin/Branding/index.tsx @@ -1,7 +1,7 @@ import { FC, memo, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { JSONSchema, SchemaForm, UISchema } from '@/components'; +import { JSONSchema, SchemaForm, UISchema, ImgViewer } from '@/components'; import { FormDataType } from '@/common/interface'; import { brandSetting, getBrandSetting } from '@/services'; import { brandingStore } from '@/stores'; @@ -142,7 +142,7 @@ const Index: FC = () => { }, []); return ( -
+

{t('page_title')}

{ onSubmit={onSubmit} onChange={handleOnChange} /> -
+ ); }; diff --git a/ui/src/pages/Admin/SettingsUsers/index.tsx b/ui/src/pages/Admin/SettingsUsers/index.tsx index b8da8529..ad0ca476 100644 --- a/ui/src/pages/Admin/SettingsUsers/index.tsx +++ b/ui/src/pages/Admin/SettingsUsers/index.tsx @@ -146,6 +146,9 @@ const Index: FC = () => { useEffect(() => { getUsersSetting().then((resp) => { + if (!resp) { + return; + } const formMeta: Type.FormDataType = {}; Object.keys(formData).forEach((k) => { let v = resp[k]; diff --git a/ui/src/pages/Layout/index.tsx b/ui/src/pages/Layout/index.tsx index 97a682f2..e64925ff 100644 --- a/ui/src/pages/Layout/index.tsx +++ b/ui/src/pages/Layout/index.tsx @@ -15,7 +15,6 @@ import { HttpErrorContent, } from '@/components'; import { LoginToContinueModal } from '@/components/Modal'; -import { useImgViewer } from '@/hooks'; const Layout: FC = () => { const location = useLocation(); @@ -24,7 +23,6 @@ const Layout: FC = () => { toastClear(); }; const { code: httpStatusCode, reset: httpStatusReset } = errorCodeStore(); - const imgViewer = useImgViewer(); const { show: showLoginToContinueModal } = loginToContinueStore(); useEffect(() => { @@ -40,9 +38,7 @@ const Layout: FC = () => { }}>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */} -
+
{httpStatusCode ? ( ) : ( diff --git a/ui/src/pages/Questions/Detail/components/Question/index.tsx b/ui/src/pages/Questions/Detail/components/Question/index.tsx index 3cfb7de0..40fc0a25 100644 --- a/ui/src/pages/Questions/Detail/components/Question/index.tsx +++ b/ui/src/pages/Questions/Detail/components/Question/index.tsx @@ -12,6 +12,7 @@ import { FormatTime, htmlRender, Icon, + ImgViewer, } from '@/components'; import { formatCount, guard } from '@/utils'; import { following } from '@/services'; @@ -114,11 +115,13 @@ const Index: FC = ({ data, initPage, hasAnswer, isLogged }) => { return ; })}
-
+ +
+ { const [mailHash, setMailHash] = useState(''); const [count] = useState(0); const [profileAgent, setProfileAgent] = useState(); - const [formData, setFormData] = useState({ display_name: { value: '', @@ -343,66 +342,68 @@ const Index: React.FC = () => {
-
- {formData.avatar.type === 'gravatar' && ( - - 0 ? `&t=${new Date().valueOf()}` : '' - }`} - className="me-3 rounded" - /> - - - You can change image on - - gravatar.com - - - - - )} - - {formData.avatar.type === 'custom' && ( - - + +
+ {formData.avatar.type === 'gravatar' && ( + 0 ? `&t=${new Date().valueOf()}` : '' + }`} + className="me-3 rounded" /> - - - - - - + + + You can change image on + + gravatar.com + + + - - - You can upload your image. - - - - )} - {formData.avatar.type === 'default' && ( - - )} -
+ )} + + {formData.avatar.type === 'custom' && ( + + + + + + + + + + + + + You can upload your image. + + + + )} + {formData.avatar.type === 'default' && ( + + )} +
+ void; } +const defaultUsersConf: AdminSettingsUsers = { + allow_update_avatar: false, + allow_update_bio: false, + allow_update_display_name: false, + allow_update_location: false, + allow_update_username: false, + allow_update_website: false, + default_avatar: 'system', +}; + const siteInfo = create((set) => ({ siteInfo: { name: DEFAULT_SITE_NAME, @@ -22,15 +32,7 @@ const siteInfo = create((set) => ({ contact_email: '', permalink: 1, }, - users: { - allow_update_avatar: false, - allow_update_bio: false, - allow_update_display_name: false, - allow_update_location: false, - allow_update_username: false, - allow_update_website: false, - default_avatar: 'system', - }, + users: defaultUsersConf, version: '', revision: '', update: (params) => @@ -50,6 +52,7 @@ const siteInfo = create((set) => ({ }, updateUsers: (users) => { set(() => { + users ||= defaultUsersConf; return { users }; }); },