diff --git a/app/src/components/auth/LoginPage.tsx b/app/src/components/auth/LoginPage.tsx index 16370f9..b2ff858 100644 --- a/app/src/components/auth/LoginPage.tsx +++ b/app/src/components/auth/LoginPage.tsx @@ -1,5 +1,4 @@ -import type { FormEvent} from 'react'; -import React, { useState } from 'react'; +import React, { useState, type FormEvent } from 'react'; import { TextInput, PasswordInput, diff --git a/app/src/components/editor/Editor.tsx b/app/src/components/editor/Editor.tsx index aa54d9d..7bc5fd7 100644 --- a/app/src/components/editor/Editor.tsx +++ b/app/src/components/editor/Editor.tsx @@ -26,7 +26,7 @@ const Editor: React.FC = ({ useEffect(() => { const handleEditorSave = (view: EditorView): boolean => { - handleSave(selectedFile, view.state.doc.toString()); + void handleSave(selectedFile, view.state.doc.toString()); return true; }; @@ -85,6 +85,8 @@ const Editor: React.FC = ({ view.destroy(); viewRef.current = null; }; + // TODO: Refactor + // eslint-disable-next-line react-hooks/exhaustive-deps }, [colorScheme, handleContentChange, handleSave, selectedFile]); useEffect(() => { diff --git a/app/src/components/editor/MarkdownPreview.tsx b/app/src/components/editor/MarkdownPreview.tsx index 42adb58..b79e959 100644 --- a/app/src/components/editor/MarkdownPreview.tsx +++ b/app/src/components/editor/MarkdownPreview.tsx @@ -1,11 +1,10 @@ -import type { ReactNode } from 'react'; -import React, { useState, useEffect, useMemo } from 'react'; -import { unified } from 'unified'; +import React, { useState, useEffect, useMemo, type ReactNode } from 'react'; +import { unified, type Preset } from 'unified'; import remarkParse from 'remark-parse'; import remarkMath from 'remark-math'; import remarkRehype from 'remark-rehype'; import rehypeMathjax from 'rehype-mathjax'; -import rehypeReact from 'rehype-react'; +import rehypeReact, { type Options } from 'rehype-react'; import rehypePrism from 'rehype-prism'; import * as prod from 'react/jsx-runtime'; import { notifications } from '@mantine/notifications'; @@ -20,19 +19,19 @@ interface MarkdownPreviewProps { interface MarkdownImageProps { src: string; alt?: string; - [key: string]: any; + [key: string]: unknown; } interface MarkdownLinkProps { href: string; children: ReactNode; - [key: string]: any; + [key: string]: unknown; } interface MarkdownCodeProps { children: ReactNode; className?: string; - [key: string]: any; + [key: string]: unknown; } const MarkdownPreview: React.FC = ({ @@ -45,34 +44,33 @@ const MarkdownPreview: React.FC = ({ const baseUrl = window.API_BASE_URL; const { currentWorkspace } = useWorkspace(); - const handleLinkClick = ( - e: React.MouseEvent, - href: string - ): void => { - e.preventDefault(); - - if (href.startsWith(`${baseUrl}/internal/`)) { - // For existing files, extract the path and directly select it - const [filePath] = decodeURIComponent( - href.replace(`${baseUrl}/internal/`, '') - ).split('#'); - if (filePath) { - handleFileSelect(filePath); - } - } else if (href.startsWith(`${baseUrl}/notfound/`)) { - // For non-existent files, show a notification - const fileName = decodeURIComponent( - href.replace(`${baseUrl}/notfound/`, '') - ); - notifications.show({ - title: 'File Not Found', - message: `The file "${fileName}" does not exist.`, - color: 'red', - }); - } - }; - const processor = useMemo(() => { + const handleLinkClick = ( + e: React.MouseEvent, + href: string + ): void => { + e.preventDefault(); + + if (href.startsWith(`${baseUrl}/internal/`)) { + // For existing files, extract the path and directly select it + const [filePath] = decodeURIComponent( + href.replace(`${baseUrl}/internal/`, '') + ).split('#'); + if (filePath) { + void handleFileSelect(filePath); + } + } else if (href.startsWith(`${baseUrl}/notfound/`)) { + // For non-existent files, show a notification + const fileName = decodeURIComponent( + href.replace(`${baseUrl}/notfound/`, '') + ); + notifications.show({ + title: 'File Not Found', + message: `The file "${fileName}" does not exist.`, + color: 'red', + }); + } + }; // Only create the processor if we have a workspace name if (!currentWorkspace?.name) { return unified(); @@ -80,16 +78,18 @@ const MarkdownPreview: React.FC = ({ return unified() .use(remarkParse) - .use(remarkWikiLinks, currentWorkspace.name) // Now we know this is defined + .use(remarkWikiLinks, currentWorkspace.name) .use(remarkMath) .use(remarkRehype) .use(rehypeMathjax) - .use(rehypePrism) - .use(rehypeReact as any, { - production: true, + .use(rehypePrism as Preset) + .use(rehypeReact, { jsx: prod.jsx, jsxs: prod.jsxs, Fragment: prod.Fragment, + development: false, + elementAttributeNameCase: 'react', + stylePropertyNameCase: 'dom', components: { img: ({ src, alt, ...props }: MarkdownImageProps) => ( = ({ ); }, }, - }); - }, [baseUrl, handleFileSelect, currentWorkspace?.name]); + } as Options); + }, [currentWorkspace?.name, baseUrl, handleFileSelect]); useEffect(() => { const processContent = async (): Promise => { @@ -132,7 +132,7 @@ const MarkdownPreview: React.FC = ({ } }; - processContent(); + void processContent(); }, [content, processor, currentWorkspace]); return
{processedContent}
; diff --git a/app/src/components/files/FileActions.tsx b/app/src/components/files/FileActions.tsx index b846c9d..907bf88 100644 --- a/app/src/components/files/FileActions.tsx +++ b/app/src/components/files/FileActions.tsx @@ -61,7 +61,11 @@ const FileActions: React.FC = ({ { + handlePullChanges().catch((error) => { + console.error('Error pulling changes:', error); + }); + }} disabled={!settings.gitEnabled} > diff --git a/app/src/components/files/FileTree.tsx b/app/src/components/files/FileTree.tsx index 85c87b0..ee02761 100644 --- a/app/src/components/files/FileTree.tsx +++ b/app/src/components/files/FileTree.tsx @@ -1,10 +1,9 @@ import React, { useRef, useState, useLayoutEffect } from 'react'; -import type { NodeApi } from 'react-arborist'; -import { Tree } from 'react-arborist'; +import { Tree, type NodeApi } from 'react-arborist'; import { IconFile, IconFolder, IconFolderOpen } from '@tabler/icons-react'; import { Tooltip } from '@mantine/core'; import useResizeObserver from '@react-hook/resize-observer'; -import type { FileNode } from '../../types/fileApi'; +import type { FileNode } from '@/types/models'; interface Size { width: number; @@ -42,7 +41,11 @@ const FileIcon = ({ node }: { node: NodeApi }) => { }; // Define a Node component that matches what React-Arborist expects -function Node(props: any) { +function Node(props: { + node: NodeApi; + style: React.CSSProperties; + dragHandle: React.Ref; +}) { const { node, style, dragHandle } = props; const handleClick = () => { @@ -119,7 +122,7 @@ const FileTree: React.FC = ({ onActivate={(node) => { const fileNode = node.data as FileNode; if (!node.isInternal) { - handleFileSelect(fileNode.path); + void handleFileSelect(fileNode.path); } }} {...({ @@ -127,7 +130,7 @@ const FileTree: React.FC = ({ onNodeClick: (node: NodeApi) => { const fileNode = node.data; if (!node.isInternal) { - handleFileSelect(fileNode.path); + void handleFileSelect(fileNode.path); } }, } as any)}