mirror of
https://github.com/lordmathis/lemma.git
synced 2025-12-25 10:54:23 +00:00
Add autocompletion for wiki links
This commit is contained in:
@@ -104,6 +104,7 @@ describe('ContentView', () => {
|
||||
handleContentChange={mockHandleContentChange}
|
||||
handleSave={mockHandleSave}
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -121,6 +122,7 @@ describe('ContentView', () => {
|
||||
handleContentChange={mockHandleContentChange}
|
||||
handleSave={mockHandleSave}
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -138,6 +140,7 @@ describe('ContentView', () => {
|
||||
handleContentChange={mockHandleContentChange}
|
||||
handleSave={mockHandleSave}
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -157,6 +160,7 @@ describe('ContentView', () => {
|
||||
handleContentChange={mockHandleContentChange}
|
||||
handleSave={mockHandleSave}
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -179,6 +183,7 @@ describe('ContentView', () => {
|
||||
handleContentChange={mockHandleContentChange}
|
||||
handleSave={mockHandleSave}
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -208,6 +213,7 @@ describe('ContentView', () => {
|
||||
handleContentChange={mockHandleContentChange}
|
||||
handleSave={mockHandleSave}
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import Editor from './Editor';
|
||||
import MarkdownPreview from './MarkdownPreview';
|
||||
import { getFileUrl, isImageFile } from '../../utils/fileHelpers';
|
||||
import { useWorkspace } from '@/contexts/WorkspaceContext';
|
||||
import type { FileNode } from '../../types/models';
|
||||
|
||||
type ViewTab = 'source' | 'preview';
|
||||
|
||||
@@ -14,6 +15,7 @@ interface ContentViewProps {
|
||||
handleContentChange: (content: string) => void;
|
||||
handleSave: (filePath: string, content: string) => Promise<boolean>;
|
||||
handleFileSelect: (filePath: string | null) => Promise<void>;
|
||||
files: FileNode[];
|
||||
}
|
||||
|
||||
const ContentView: React.FC<ContentViewProps> = ({
|
||||
@@ -23,6 +25,7 @@ const ContentView: React.FC<ContentViewProps> = ({
|
||||
handleContentChange,
|
||||
handleSave,
|
||||
handleFileSelect,
|
||||
files,
|
||||
}) => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
if (!currentWorkspace) {
|
||||
@@ -67,6 +70,7 @@ const ContentView: React.FC<ContentViewProps> = ({
|
||||
handleContentChange={handleContentChange}
|
||||
handleSave={handleSave}
|
||||
selectedFile={selectedFile}
|
||||
files={files}
|
||||
/>
|
||||
) : (
|
||||
<MarkdownPreview content={content} handleFileSelect={handleFileSelect} />
|
||||
|
||||
@@ -1,17 +1,22 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import React, { useEffect, useRef, useMemo } from 'react';
|
||||
import { basicSetup } from 'codemirror';
|
||||
import { EditorState } from '@codemirror/state';
|
||||
import { EditorView, keymap } from '@codemirror/view';
|
||||
import { markdown } from '@codemirror/lang-markdown';
|
||||
import { defaultKeymap } from '@codemirror/commands';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { autocompletion } from '@codemirror/autocomplete';
|
||||
import { useWorkspace } from '../../hooks/useWorkspace';
|
||||
import { createWikiLinkCompletions } from '../../utils/wikiLinkCompletion';
|
||||
import { flattenFileTree } from '../../utils/fileHelpers';
|
||||
import type { FileNode } from '../../types/models';
|
||||
|
||||
interface EditorProps {
|
||||
content: string;
|
||||
handleContentChange: (content: string) => void;
|
||||
handleSave: (filePath: string, content: string) => Promise<boolean>;
|
||||
selectedFile: string;
|
||||
files: FileNode[];
|
||||
}
|
||||
|
||||
const Editor: React.FC<EditorProps> = ({
|
||||
@@ -19,11 +24,19 @@ const Editor: React.FC<EditorProps> = ({
|
||||
handleContentChange,
|
||||
handleSave,
|
||||
selectedFile,
|
||||
files,
|
||||
}) => {
|
||||
const { colorScheme } = useWorkspace();
|
||||
const { colorScheme, currentWorkspace } = useWorkspace();
|
||||
const editorRef = useRef<HTMLDivElement>(null);
|
||||
const viewRef = useRef<EditorView | null>(null);
|
||||
|
||||
// Flatten file tree for autocompletion, respecting showHiddenFiles setting
|
||||
const showHiddenFiles = currentWorkspace?.showHiddenFiles || false;
|
||||
const flatFiles = useMemo(
|
||||
() => flattenFileTree(files, showHiddenFiles),
|
||||
[files, showHiddenFiles]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleEditorSave = (view: EditorView): boolean => {
|
||||
void handleSave(selectedFile, view.state.doc.toString());
|
||||
@@ -71,6 +84,12 @@ const Editor: React.FC<EditorProps> = ({
|
||||
}),
|
||||
theme,
|
||||
colorScheme === 'dark' ? oneDark : [],
|
||||
autocompletion({
|
||||
override: [createWikiLinkCompletions(flatFiles)],
|
||||
activateOnTyping: true,
|
||||
maxRenderedOptions: 10,
|
||||
closeOnBlur: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -87,7 +106,7 @@ const Editor: React.FC<EditorProps> = ({
|
||||
};
|
||||
// TODO: Refactor
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [colorScheme, handleContentChange, handleSave, selectedFile]);
|
||||
}, [colorScheme, handleContentChange, handleSave, selectedFile, flatFiles]);
|
||||
|
||||
useEffect(() => {
|
||||
if (viewRef.current && content !== viewRef.current.state.doc.toString()) {
|
||||
|
||||
@@ -53,6 +53,7 @@ const Layout: React.FC = () => {
|
||||
selectedFile={selectedFile}
|
||||
handleFileSelect={handleFileSelect}
|
||||
loadFileList={loadFileList}
|
||||
files={files}
|
||||
/>
|
||||
</Container>
|
||||
</AppShell.Main>
|
||||
|
||||
@@ -131,6 +131,7 @@ describe('MainContent', () => {
|
||||
selectedFile="docs/guide.md"
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
loadFileList={mockLoadFileList}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -156,6 +157,7 @@ describe('MainContent', () => {
|
||||
selectedFile="test.md"
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
loadFileList={mockLoadFileList}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -172,6 +174,7 @@ describe('MainContent', () => {
|
||||
selectedFile="test.md"
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
loadFileList={mockLoadFileList}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
@@ -188,6 +191,7 @@ describe('MainContent', () => {
|
||||
selectedFile={null}
|
||||
handleFileSelect={mockHandleFileSelect}
|
||||
loadFileList={mockLoadFileList}
|
||||
files={[]}
|
||||
/>
|
||||
</TestWrapper>
|
||||
);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { useFileContent } from '../../hooks/useFileContent';
|
||||
import { useFileOperations } from '../../hooks/useFileOperations';
|
||||
import { useGitOperations } from '../../hooks/useGitOperations';
|
||||
import { useModalContext } from '../../contexts/ModalContext';
|
||||
import type { FileNode } from '../../types/models';
|
||||
|
||||
type ViewTab = 'source' | 'preview';
|
||||
|
||||
@@ -19,12 +20,14 @@ interface MainContentProps {
|
||||
selectedFile: string | null;
|
||||
handleFileSelect: (filePath: string | null) => Promise<void>;
|
||||
loadFileList: () => Promise<void>;
|
||||
files: FileNode[];
|
||||
}
|
||||
|
||||
const MainContent: React.FC<MainContentProps> = ({
|
||||
selectedFile,
|
||||
handleFileSelect,
|
||||
loadFileList,
|
||||
files,
|
||||
}) => {
|
||||
const [activeTab, setActiveTab] = useState<ViewTab>('source');
|
||||
const {
|
||||
@@ -161,6 +164,7 @@ const MainContent: React.FC<MainContentProps> = ({
|
||||
handleContentChange={handleContentChange}
|
||||
handleSave={handleSaveFile}
|
||||
handleFileSelect={handleFileSelect}
|
||||
files={files}
|
||||
/>
|
||||
</Box>
|
||||
<CreateFileModal onCreateFile={handleCreateFile} />
|
||||
|
||||
Reference in New Issue
Block a user