mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 15:44:21 +00:00
Refactor imports and handle async operations in components
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import type { FormEvent} from 'react';
|
import React, { useState, type FormEvent } from 'react';
|
||||||
import React, { useState } from 'react';
|
|
||||||
import {
|
import {
|
||||||
TextInput,
|
TextInput,
|
||||||
PasswordInput,
|
PasswordInput,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const Editor: React.FC<EditorProps> = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleEditorSave = (view: EditorView): boolean => {
|
const handleEditorSave = (view: EditorView): boolean => {
|
||||||
handleSave(selectedFile, view.state.doc.toString());
|
void handleSave(selectedFile, view.state.doc.toString());
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -85,6 +85,8 @@ const Editor: React.FC<EditorProps> = ({
|
|||||||
view.destroy();
|
view.destroy();
|
||||||
viewRef.current = null;
|
viewRef.current = null;
|
||||||
};
|
};
|
||||||
|
// TODO: Refactor
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [colorScheme, handleContentChange, handleSave, selectedFile]);
|
}, [colorScheme, handleContentChange, handleSave, selectedFile]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { ReactNode } from 'react';
|
import React, { useState, useEffect, useMemo, type ReactNode } from 'react';
|
||||||
import React, { useState, useEffect, useMemo } from 'react';
|
import { unified, type Preset } from 'unified';
|
||||||
import { unified } from 'unified';
|
|
||||||
import remarkParse from 'remark-parse';
|
import remarkParse from 'remark-parse';
|
||||||
import remarkMath from 'remark-math';
|
import remarkMath from 'remark-math';
|
||||||
import remarkRehype from 'remark-rehype';
|
import remarkRehype from 'remark-rehype';
|
||||||
import rehypeMathjax from 'rehype-mathjax';
|
import rehypeMathjax from 'rehype-mathjax';
|
||||||
import rehypeReact from 'rehype-react';
|
import rehypeReact, { type Options } from 'rehype-react';
|
||||||
import rehypePrism from 'rehype-prism';
|
import rehypePrism from 'rehype-prism';
|
||||||
import * as prod from 'react/jsx-runtime';
|
import * as prod from 'react/jsx-runtime';
|
||||||
import { notifications } from '@mantine/notifications';
|
import { notifications } from '@mantine/notifications';
|
||||||
@@ -20,19 +19,19 @@ interface MarkdownPreviewProps {
|
|||||||
interface MarkdownImageProps {
|
interface MarkdownImageProps {
|
||||||
src: string;
|
src: string;
|
||||||
alt?: string;
|
alt?: string;
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MarkdownLinkProps {
|
interface MarkdownLinkProps {
|
||||||
href: string;
|
href: string;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MarkdownCodeProps {
|
interface MarkdownCodeProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
className?: string;
|
className?: string;
|
||||||
[key: string]: any;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({
|
const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({
|
||||||
@@ -45,34 +44,33 @@ const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({
|
|||||||
const baseUrl = window.API_BASE_URL;
|
const baseUrl = window.API_BASE_URL;
|
||||||
const { currentWorkspace } = useWorkspace();
|
const { currentWorkspace } = useWorkspace();
|
||||||
|
|
||||||
const handleLinkClick = (
|
|
||||||
e: React.MouseEvent<HTMLAnchorElement>,
|
|
||||||
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 processor = useMemo(() => {
|
||||||
|
const handleLinkClick = (
|
||||||
|
e: React.MouseEvent<HTMLAnchorElement>,
|
||||||
|
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
|
// Only create the processor if we have a workspace name
|
||||||
if (!currentWorkspace?.name) {
|
if (!currentWorkspace?.name) {
|
||||||
return unified();
|
return unified();
|
||||||
@@ -80,16 +78,18 @@ const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({
|
|||||||
|
|
||||||
return unified()
|
return unified()
|
||||||
.use(remarkParse)
|
.use(remarkParse)
|
||||||
.use(remarkWikiLinks, currentWorkspace.name) // Now we know this is defined
|
.use(remarkWikiLinks, currentWorkspace.name)
|
||||||
.use(remarkMath)
|
.use(remarkMath)
|
||||||
.use(remarkRehype)
|
.use(remarkRehype)
|
||||||
.use(rehypeMathjax)
|
.use(rehypeMathjax)
|
||||||
.use(rehypePrism)
|
.use(rehypePrism as Preset)
|
||||||
.use(rehypeReact as any, {
|
.use(rehypeReact, {
|
||||||
production: true,
|
|
||||||
jsx: prod.jsx,
|
jsx: prod.jsx,
|
||||||
jsxs: prod.jsxs,
|
jsxs: prod.jsxs,
|
||||||
Fragment: prod.Fragment,
|
Fragment: prod.Fragment,
|
||||||
|
development: false,
|
||||||
|
elementAttributeNameCase: 'react',
|
||||||
|
stylePropertyNameCase: 'dom',
|
||||||
components: {
|
components: {
|
||||||
img: ({ src, alt, ...props }: MarkdownImageProps) => (
|
img: ({ src, alt, ...props }: MarkdownImageProps) => (
|
||||||
<img
|
<img
|
||||||
@@ -115,8 +115,8 @@ const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
} as Options);
|
||||||
}, [baseUrl, handleFileSelect, currentWorkspace?.name]);
|
}, [currentWorkspace?.name, baseUrl, handleFileSelect]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const processContent = async (): Promise<void> => {
|
const processContent = async (): Promise<void> => {
|
||||||
@@ -132,7 +132,7 @@ const MarkdownPreview: React.FC<MarkdownPreviewProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
processContent();
|
void processContent();
|
||||||
}, [content, processor, currentWorkspace]);
|
}, [content, processor, currentWorkspace]);
|
||||||
|
|
||||||
return <div className="markdown-preview">{processedContent}</div>;
|
return <div className="markdown-preview">{processedContent}</div>;
|
||||||
|
|||||||
@@ -61,7 +61,11 @@ const FileActions: React.FC<FileActionsProps> = ({
|
|||||||
<ActionIcon
|
<ActionIcon
|
||||||
variant="default"
|
variant="default"
|
||||||
size="md"
|
size="md"
|
||||||
onClick={handlePullChanges}
|
onClick={() => {
|
||||||
|
handlePullChanges().catch((error) => {
|
||||||
|
console.error('Error pulling changes:', error);
|
||||||
|
});
|
||||||
|
}}
|
||||||
disabled={!settings.gitEnabled}
|
disabled={!settings.gitEnabled}
|
||||||
>
|
>
|
||||||
<IconGitPullRequest size={16} />
|
<IconGitPullRequest size={16} />
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import React, { useRef, useState, useLayoutEffect } from 'react';
|
import React, { useRef, useState, useLayoutEffect } from 'react';
|
||||||
import type { NodeApi } from 'react-arborist';
|
import { Tree, type NodeApi } from 'react-arborist';
|
||||||
import { Tree } from 'react-arborist';
|
|
||||||
import { IconFile, IconFolder, IconFolderOpen } from '@tabler/icons-react';
|
import { IconFile, IconFolder, IconFolderOpen } from '@tabler/icons-react';
|
||||||
import { Tooltip } from '@mantine/core';
|
import { Tooltip } from '@mantine/core';
|
||||||
import useResizeObserver from '@react-hook/resize-observer';
|
import useResizeObserver from '@react-hook/resize-observer';
|
||||||
import type { FileNode } from '../../types/fileApi';
|
import type { FileNode } from '@/types/models';
|
||||||
|
|
||||||
interface Size {
|
interface Size {
|
||||||
width: number;
|
width: number;
|
||||||
@@ -42,7 +41,11 @@ const FileIcon = ({ node }: { node: NodeApi<FileNode> }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Define a Node component that matches what React-Arborist expects
|
// Define a Node component that matches what React-Arborist expects
|
||||||
function Node(props: any) {
|
function Node(props: {
|
||||||
|
node: NodeApi<FileNode>;
|
||||||
|
style: React.CSSProperties;
|
||||||
|
dragHandle: React.Ref<HTMLDivElement>;
|
||||||
|
}) {
|
||||||
const { node, style, dragHandle } = props;
|
const { node, style, dragHandle } = props;
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
@@ -119,7 +122,7 @@ const FileTree: React.FC<FileTreeProps> = ({
|
|||||||
onActivate={(node) => {
|
onActivate={(node) => {
|
||||||
const fileNode = node.data as FileNode;
|
const fileNode = node.data as FileNode;
|
||||||
if (!node.isInternal) {
|
if (!node.isInternal) {
|
||||||
handleFileSelect(fileNode.path);
|
void handleFileSelect(fileNode.path);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
{...({
|
{...({
|
||||||
@@ -127,7 +130,7 @@ const FileTree: React.FC<FileTreeProps> = ({
|
|||||||
onNodeClick: (node: NodeApi<FileNode>) => {
|
onNodeClick: (node: NodeApi<FileNode>) => {
|
||||||
const fileNode = node.data;
|
const fileNode = node.data;
|
||||||
if (!node.isInternal) {
|
if (!node.isInternal) {
|
||||||
handleFileSelect(fileNode.path);
|
void handleFileSelect(fileNode.path);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
} as any)}
|
} as any)}
|
||||||
|
|||||||
Reference in New Issue
Block a user