From 3a302cf5b27dd50e06e1bc2ee221667c3c358a55 Mon Sep 17 00:00:00 2001 From: Nicola Benaglia Date: Fri, 18 Apr 2025 20:12:48 +0200 Subject: [PATCH] Refactor chat style and other stuff --- src/Wallets.tsx | 2 +- src/assets/svgs/Download.tsx | 4 +- src/assets/svgs/Logout.tsx | 4 +- src/assets/svgs/Return.tsx | 4 +- src/components/Apps/AppsCategoryDesktop.tsx | 153 +++--- src/components/Apps/AppsLibraryDesktop.tsx | 6 +- src/components/Chat/MessageItem.tsx | 2 +- src/components/Chat/TipTap.tsx | 510 ++++++++++---------- src/components/Chat/chat.css | 31 +- src/styles/theme-dark.ts | 2 +- 10 files changed, 377 insertions(+), 341 deletions(-) diff --git a/src/Wallets.tsx b/src/Wallets.tsx index 02fb10a..3c53c52 100644 --- a/src/Wallets.tsx +++ b/src/Wallets.tsx @@ -457,7 +457,7 @@ const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => { {wallet?.address0} diff --git a/src/assets/svgs/Download.tsx b/src/assets/svgs/Download.tsx index 7e19e1c..28ac605 100644 --- a/src/assets/svgs/Download.tsx +++ b/src/assets/svgs/Download.tsx @@ -21,8 +21,8 @@ export const Download: React.FC = ({ xmlns="http://www.w3.org/2000/svg" > = ({ color, opacity, ...children }) => { xmlns="http://www.w3.org/2000/svg" > = ({ color, opacity, ...children }) => { xmlns="http://www.w3.org/2000/svg" > { - const [searchValue, setSearchValue] = useState(""); + const [searchValue, setSearchValue] = useState(''); const virtuosoRef = useRef(); const { rootHeight } = useContext(MyContext); const categoryList = useMemo(() => { - if(category?.id === 'all') return availableQapps + if (category?.id === 'all') return availableQapps; return availableQapps.filter( (app) => app?.metadata?.category === category?.id ); }, [availableQapps, category]); - const [debouncedValue, setDebouncedValue] = useState(""); // Debounced value + const [debouncedValue, setDebouncedValue] = useState(''); // Debounced value // Debounce logic useEffect(() => { const handler = setTimeout(() => { setDebouncedValue(searchValue); - }, 350); setTimeout(() => { - virtuosoRef.current.scrollToIndex({ - index: 0 - }); + if (virtuosoRef.current) { + virtuosoRef.current.scrollToIndex({ index: 0 }); + } }, 500); // Cleanup timeout if searchValue changes before the timeout completes return () => { @@ -127,8 +129,13 @@ export const AppsCategoryDesktop = ({ const searchedList = useMemo(() => { if (!debouncedValue) return categoryList; - return categoryList.filter((app) => - app.name.toLowerCase().includes(debouncedValue.toLowerCase()) || (app?.metadata?.title && app?.metadata?.title?.toLowerCase().includes(debouncedValue.toLowerCase())) + return categoryList.filter( + (app) => + app.name.toLowerCase().includes(debouncedValue.toLowerCase()) || + (app?.metadata?.title && + app?.metadata?.title + ?.toLowerCase() + .includes(debouncedValue.toLowerCase())) ); }, [debouncedValue, categoryList]); @@ -141,7 +148,7 @@ export const AppsCategoryDesktop = ({ myName={myName} isFromCategory={true} parentStyles={{ - padding: '0px 10px' + padding: '0px 10px', }} /> ); @@ -150,27 +157,29 @@ export const AppsCategoryDesktop = ({ return ( - + @@ -189,7 +198,7 @@ export const AppsCategoryDesktop = ({ {searchValue && ( { - setSearchValue(""); + setSearchValue(''); }} > @@ -202,9 +211,9 @@ export const AppsCategoryDesktop = ({ @@ -215,7 +224,7 @@ export const AppsCategoryDesktop = ({ diff --git a/src/components/Apps/AppsLibraryDesktop.tsx b/src/components/Apps/AppsLibraryDesktop.tsx index 48003c4..7fcc998 100644 --- a/src/components/Apps/AppsLibraryDesktop.tsx +++ b/src/components/Apps/AppsLibraryDesktop.tsx @@ -135,9 +135,9 @@ export const AppsLibraryDesktop = ({ setDebouncedValue(searchValue); }, 350); setTimeout(() => { - virtuosoRef.current.scrollToIndex({ - index: 0, - }); + if (virtuosoRef.current) { + virtuosoRef.current.scrollToIndex({ index: 0 }); + } }, 500); // Cleanup timeout if searchValue changes before the timeout completes return () => { diff --git a/src/components/Chat/MessageItem.tsx b/src/components/Chat/MessageItem.tsx index 0bfb5f0..11cc381 100644 --- a/src/components/Chat/MessageItem.tsx +++ b/src/components/Chat/MessageItem.tsx @@ -167,7 +167,7 @@ export const MessageItem = React.memo( >
{ + +const MenuBar = ({ + setEditorRef, + isChat, + isDisabledEditorEnter, + setIsDisabledEditorEnter, +}) => { const { editor } = useCurrentEditor(); const fileInputRef = useRef(null); + const theme = useTheme(); if (!editor) { return null; @@ -67,15 +68,15 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi new Compressor(file, { quality: 0.6, maxWidth: 1200, - mimeType: "image/webp", + mimeType: 'image/webp', success(result) { - compressedFile = new File([result], "image.webp", { - type: "image/webp", + compressedFile = new File([result], 'image.webp', { + type: 'image/webp', }); resolve(); }, error(err) { - console.error("Image compression error:", err); + console.error('Image compression error:', err); }, }); }); @@ -87,9 +88,9 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor .chain() .focus() - .setImage({ src: url, style: "width: auto" }) + .setImage({ src: url, style: 'width: auto' }) .run(); - fileInputRef.current.value = ""; + fileInputRef.current.value = ''; }; reader.readAsDataURL(compressedFile); } @@ -102,7 +103,7 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi const handlePaste = (event) => { const items = event.clipboardData.items; for (const item of items) { - if (item.type.startsWith("image/")) { + if (item.type.startsWith('image/')) { const file = item.getAsFile(); if (file) { event.preventDefault(); // Prevent the default paste behavior @@ -114,24 +115,29 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi useEffect(() => { if (editor) { - editor.view.dom.addEventListener("paste", handlePaste); + editor.view.dom.addEventListener('paste', handlePaste); return () => { - editor.view.dom.removeEventListener("paste", handlePaste); + editor.view.dom.removeEventListener('paste', handlePaste); }; } }, [editor]); return (
-
+
editor.chain().focus().toggleBold().run()} disabled={!editor.can().chain().focus().toggleBold().run()} sx={{ - color: editor.isActive("bold") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('bold') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -140,8 +146,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi onClick={() => editor.chain().focus().toggleItalic().run()} disabled={!editor.can().chain().focus().toggleItalic().run()} sx={{ - color: editor.isActive("italic") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('italic') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -150,8 +158,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi onClick={() => editor.chain().focus().toggleStrike().run()} disabled={!editor.can().chain().focus().toggleStrike().run()} sx={{ - color: editor.isActive("strike") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('strike') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -160,8 +170,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi onClick={() => editor.chain().focus().toggleCode().run()} disabled={!editor.can().chain().focus().toggleCode().run()} sx={{ - color: editor.isActive("code") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('code') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -170,13 +182,13 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi onClick={() => editor.chain().focus().unsetAllMarks().run()} sx={{ color: - editor.isActive("bold") || - editor.isActive("italic") || - editor.isActive("strike") || - editor.isActive("code") - ? "white" - : "gray", - padding: isMobile ? "5px" : "revert", + editor.isActive('bold') || + editor.isActive('italic') || + editor.isActive('strike') || + editor.isActive('code') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -184,8 +196,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor.chain().focus().toggleBulletList().run()} sx={{ - color: editor.isActive("bulletList") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('bulletList') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -193,8 +207,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor.chain().focus().toggleOrderedList().run()} sx={{ - color: editor.isActive("orderedList") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('orderedList') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -202,8 +218,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor.chain().focus().toggleCodeBlock().run()} sx={{ - color: editor.isActive("codeBlock") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('codeBlock') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -211,8 +229,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor.chain().focus().toggleBlockquote().run()} sx={{ - color: editor.isActive("blockquote") ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('blockquote') + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -220,7 +240,7 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor.chain().focus().setHorizontalRule().run()} disabled={!editor.can().chain().focus().setHorizontalRule().run()} - sx={{ color: "gray", padding: isMobile ? "5px" : "revert" }} + sx={{ color: 'gray', padding: isMobile ? '5px' : 'revert' }} > @@ -229,8 +249,10 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor.chain().focus().toggleHeading({ level: 1 }).run() } sx={{ - color: editor.isActive("heading", { level: 1 }) ? "white" : "gray", - padding: isMobile ? "5px" : "revert", + color: editor.isActive('heading', { level: 1 }) + ? theme.palette.text.primary + : theme.palette.text.secondary, + padding: isMobile ? '5px' : 'revert', }} > @@ -238,66 +260,68 @@ const MenuBar = ({ setEditorRef, isChat, isDisabledEditorEnter, setIsDisabledEdi editor.chain().focus().undo().run()} disabled={!editor.can().chain().focus().undo().run()} - sx={{ color: "gray", padding: isMobile ? "5px" : "revert" }} + sx={{ color: 'gray', padding: isMobile ? '5px' : 'revert' }} > editor.chain().focus().redo().run()} disabled={!editor.can().chain().focus().redo().run()} - sx={{ color: "gray" }} + sx={{ color: 'gray' }} > {isChat && ( { - setIsDisabledEditorEnter(!isDisabledEditorEnter) - }} - > - - - disable enter - - + sx={{ + display: 'flex', + alignItems: 'center', + marginLeft: '5px', + cursor: 'pointer', + }} + onClick={() => { + setIsDisabledEditorEnter(!isDisabledEditorEnter); + }} + > + + + disable enter + + )} {!isChat && ( <> handleImageUpload(event.target.files[0])} accept="image/*" /> @@ -322,7 +346,7 @@ const extensions = [ }, }), Placeholder.configure({ - placeholder: "Start typing here...", + placeholder: 'Start typing here...', }), ImageResize, ]; @@ -340,12 +364,13 @@ export default ({ overrideMobile, customEditorHeight, membersWithNames, - enableMentions + enableMentions, }) => { - const [isDisabledEditorEnter, setIsDisabledEditorEnter] = useRecoilState(isDisabledEditorEnterAtom) - + const [isDisabledEditorEnter, setIsDisabledEditorEnter] = useRecoilState( + isDisabledEditorEnterAtom + ); const extensionsFiltered = isChat - ? extensions.filter((item) => item?.name !== "image") + ? extensions.filter((item) => item?.name !== 'image') : extensions; const editorRef = useRef(null); const setEditorRefFunc = (editorInstance) => { @@ -359,20 +384,14 @@ export default ({ // { id: 3, label: 'Charlie' }, // ]; - - - const users = useMemo(()=> { - return (membersWithNames || [])?.map((item)=> { + const users = useMemo(() => { + return (membersWithNames || [])?.map((item) => { return { id: item, - label: item - } - }) - }, [membersWithNames]) - - - - + label: item, + }; + }); + }, [membersWithNames]); const usersRef = useRef([]); useEffect(() => { @@ -386,13 +405,13 @@ export default ({ const handleBlur = () => { const htmlContent = editorRef.current.getHTML(); - if (!htmlContent?.trim() || htmlContent?.trim() === "

") { + if (!htmlContent?.trim() || htmlContent?.trim() === '

') { // Set focus state based on content } }; - const additionalExtensions = useMemo(()=> { - if(!enableMentions) return [] + const additionalExtensions = useMemo(() => { + if (!enableMentions) return []; return [ Mention.configure({ HTMLAttributes: { @@ -409,122 +428,129 @@ export default ({ let popup; // Reference to the Tippy.js instance let component; - return { - onStart: props => { - component = new ReactRenderer(MentionList, { - props, - editor: props.editor, - }) - - if (!props.clientRect) { - return - } - - popup = tippy('body', { - getReferenceClientRect: props.clientRect, - appendTo: () => document.body, - content: component.element, - showOnCreate: true, - interactive: true, - trigger: 'manual', - placement: 'bottom-start', - }) - }, - - onUpdate(props) { - component.updateProps(props) - - if (!props.clientRect) { - return - } - - popup[0].setProps({ - getReferenceClientRect: props.clientRect, - }) - }, - - onKeyDown(props) { - if (props.event.key === 'Escape') { - popup[0].hide() - - return true - } - - return component.ref?.onKeyDown(props) - }, - - onExit() { - popup[0].destroy() - component.destroy() - }, - } + return { + onStart: (props) => { + component = new ReactRenderer(MentionList, { + props, + editor: props.editor, + }); + + if (!props.clientRect) { + return; + } + + popup = tippy('body', { + getReferenceClientRect: props.clientRect, + appendTo: () => document.body, + content: component.element, + showOnCreate: true, + interactive: true, + trigger: 'manual', + placement: 'bottom-start', + }); + }, + + onUpdate(props) { + component.updateProps(props); + + if (!props.clientRect) { + return; + } + + popup[0].setProps({ + getReferenceClientRect: props.clientRect, + }); + }, + + onKeyDown(props) { + if (props.event.key === 'Escape') { + popup[0].hide(); + + return true; + } + + return component.ref?.onKeyDown(props); + }, + + onExit() { + popup[0].destroy(); + component.destroy(); + }, + }; }, }, - }) - ] - }, [enableMentions]) + }), + ]; + }, [enableMentions]); - const handleSetIsDisabledEditorEnter = useCallback((val)=> { - setIsDisabledEditorEnter(val) + const handleSetIsDisabledEditorEnter = useCallback((val) => { + setIsDisabledEditorEnter(val); localStorage.setItem('settings-disable-editor-enter', JSON.stringify(val)); - - }, []) - + }, []); return ( -
- - ) - } - extensions={[...extensionsFiltered, ...additionalExtensions - ]} - content={content} - onCreate={({ editor }) => { - editor.on("focus", handleFocus); // Listen for focus event - editor.on("blur", handleBlur); // Listen for blur event +
{ - editor.on('focus', handleFocus); // Ensure focus is updated - editor.on('blur', handleBlur); // Ensure blur is updated - }} - editorProps={{ - attributes: { - class: "tiptap-prosemirror", - style: - isMobile ? - `overflow: auto; min-height: ${ - customEditorHeight ? "200px" : "0px" - }; max-height:calc(100svh - ${customEditorHeight || "140px"})`: `overflow: auto; max-height: 250px`, - }, - handleKeyDown(view, event) { - if (!disableEnter && !isDisabledEditorEnter && event.key === "Enter") { - if (event.shiftKey) { - view.dispatch( - view.state.tr.replaceSelectionWith( - view.state.schema.nodes.hardBreak.create() - ) - ); - return true; - } else { - if (typeof onEnter === "function") { - onEnter(); + > + + ) + } + extensions={[...extensionsFiltered, ...additionalExtensions]} + content={content} + onCreate={({ editor }) => { + editor.on('focus', handleFocus); // Listen for focus event + editor.on('blur', handleBlur); // Listen for blur event + }} + onUpdate={({ editor }) => { + editor.on('focus', handleFocus); // Ensure focus is updated + editor.on('blur', handleBlur); // Ensure blur is updated + }} + editorProps={{ + attributes: { + class: 'tiptap-prosemirror', + style: isMobile + ? `overflow: auto; min-height: ${ + customEditorHeight ? '200px' : '0px' + }; max-height:calc(100svh - ${customEditorHeight || '140px'})` + : `overflow: auto; max-height: 250px`, + }, + handleKeyDown(view, event) { + if ( + !disableEnter && + !isDisabledEditorEnter && + event.key === 'Enter' + ) { + if (event.shiftKey) { + view.dispatch( + view.state.tr.replaceSelectionWith( + view.state.schema.nodes.hardBreak.create() + ) + ); + return true; + } else { + if (typeof onEnter === 'function') { + onEnter(); + } + return true; } - return true; } - } - return false; - }, - }} - /> + return false; + }, + }} + />
- ); }; diff --git a/src/components/Chat/chat.css b/src/components/Chat/chat.css index 61e0189..73fa159 100644 --- a/src/components/Chat/chat.css +++ b/src/components/Chat/chat.css @@ -1,6 +1,6 @@ .tiptap { margin-top: 0; - color: ''; /* Set default font color to white */ + color: theme => theme.palette.text.primary; width: 100%; } @@ -26,7 +26,7 @@ line-height: 1.1; margin-top: 2.5rem; text-wrap: pretty; - color: white; /* Ensure heading font color is white */ + color: theme => theme.palette.text.primary; } .tiptap h1, @@ -55,18 +55,18 @@ /* Code and preformatted text styles */ .tiptap code { - background-color: #27282c; /* Set code background color to #27282c */ + background-color: theme => theme.palette.background.default; border-radius: 0.4rem; - color: white; /* Ensure inline code text color is white */ + color: theme => theme.palette.text.primary; font-size: 0.85rem; padding: 0.25em 0.3em; text-wrap: pretty; } .tiptap pre { - background: #27282c; /* Set code block background color to #27282c */ + background: theme => theme.palette.background.default; border-radius: 0.5rem; - color: white; /* Ensure code block text color is white */ + color: theme => theme.palette.text.primary; font-family: 'JetBrainsMono', monospace; margin: 1.5rem 0; padding: 0.75rem 1rem; @@ -86,7 +86,7 @@ border-left: 3px solid var(--gray-3); margin: 1.5rem 0; padding-left: 1rem; - color: white; /* Ensure blockquote text color is white */ + color: theme => theme.palette.text.primary; text-wrap: pretty; } @@ -102,11 +102,12 @@ .tiptap p { font-size: 16px; - color: white; /* Ensure paragraph text color is white */ + color: theme => theme.palette.text.primary; margin: 0px; } + .tiptap p.is-editor-empty:first-child::before { - color: #adb5bd; + color: theme => theme.palette.text.primary; content: attr(data-placeholder); float: left; height: 0; @@ -133,17 +134,17 @@ .tiptap [data-type='mention'] { box-decoration-break: clone; - color: lightblue; + color: theme => theme.palette.text.secondary; padding: 0.1rem 0.3rem; } .unread-divider { - width: 90%; - color: white; border-bottom: 1px solid white; + border-radius: 2px; + color: theme => theme.palette.text.primary; display: flex; justify-content: center; - border-radius: 2px; + width: 90%; } .mention-item { @@ -168,11 +169,11 @@ font-size: 16px; width: 100%; border: none; - color: white; + color: theme => theme.palette.text.primary; cursor: pointer; &:hover, &:hover.is-selected { - background-color: gray; + background-color: theme => theme.palette.background.secondary; } } } diff --git a/src/styles/theme-dark.ts b/src/styles/theme-dark.ts index afe8980..9c9e610 100644 --- a/src/styles/theme-dark.ts +++ b/src/styles/theme-dark.ts @@ -15,7 +15,7 @@ const darkThemeOptions: ThemeOptions = { }, background: { default: 'rgb(49, 51, 56)', - paper: 'rgb(46, 46, 49)', + paper: 'rgb(96, 96, 97)', }, text: { primary: 'rgb(255, 255, 255)',