From d1b81dd703f4578cdb923fcd31aedc6fc9c498fe Mon Sep 17 00:00:00 2001
From: duanfuxiang
Date: Tue, 29 Apr 2025 11:25:44 +0800
Subject: [PATCH] add system preview
---
src/PreviewView.tsx | 62 +++++++++++
src/components/chat-view/CustomModeView.tsx | 54 ++++++++-
.../chat-view/chat-input/ModeSelect.tsx | 2 +-
.../preview-view/PreviewViewRoot.tsx | 105 ++++++++++++++++++
src/constants.ts | 1 +
src/main.ts | 4 +-
src/utils/obsidian.ts | 4 +-
src/utils/prompt-generator.ts | 2 +-
8 files changed, 227 insertions(+), 7 deletions(-)
create mode 100644 src/PreviewView.tsx
create mode 100644 src/components/preview-view/PreviewViewRoot.tsx
diff --git a/src/PreviewView.tsx b/src/PreviewView.tsx
new file mode 100644
index 0000000..13430ca
--- /dev/null
+++ b/src/PreviewView.tsx
@@ -0,0 +1,62 @@
+import { TFile, View, WorkspaceLeaf } from 'obsidian'
+import { Root, createRoot } from 'react-dom/client'
+
+import PreviewViewRoot from './components/preview-view/PreviewViewRoot'
+import { PREVIEW_VIEW_TYPE } from './constants'
+import { AppProvider } from './contexts/AppContext'
+
+export type PreviewViewState = {
+ content: string
+ title?: string
+ file?: TFile
+ onClose?: () => void
+}
+
+export class PreviewView extends View {
+ private root: Root | null = null
+ private state: PreviewViewState | null = null
+
+ constructor(leaf: WorkspaceLeaf) {
+ super(leaf)
+ }
+
+ getViewType() {
+ return PREVIEW_VIEW_TYPE
+ }
+
+ getDisplayText() {
+ if (this.state?.title) {
+ return `Preview: ${this.state.title}`
+ }
+ return `Preview: ${this.state?.file?.name ?? 'Markdown'}`
+ }
+
+ async setState(state: PreviewViewState) {
+ this.state = state
+ // Should render here because onOpen is called before setState
+ this.render()
+ }
+
+ async onOpen() {
+ this.root = createRoot(this.containerEl)
+ }
+
+ async onClose() {
+ if (this.state?.onClose) {
+ this.state.onClose()
+ }
+ this.root?.unmount()
+ }
+
+ async render() {
+ if (!this.root || !this.state) return
+ this.root.render(
+
+ this.leaf.detach()}
+ />
+ ,
+ )
+ }
+}
diff --git a/src/components/chat-view/CustomModeView.tsx b/src/components/chat-view/CustomModeView.tsx
index 9e6f2ba..d17a1e2 100644
--- a/src/components/chat-view/CustomModeView.tsx
+++ b/src/components/chat-view/CustomModeView.tsx
@@ -1,11 +1,19 @@
import { ChevronDown, ChevronRight, Plus, Trash2, Undo2 } from 'lucide-react';
-import React, { useEffect, useState } from 'react';
+import { getLanguage } from 'obsidian';
+import React, { useEffect, useMemo, useState } from 'react';
+import { PREVIEW_VIEW_TYPE } from '../../constants';
import { useApp } from '../../contexts/AppContext';
+import { useDiffStrategy } from '../../contexts/DiffStrategyContext';
+import { useRAG } from '../../contexts/RAGContext';
+import { useSettings } from '../../contexts/SettingsContext';
import { CustomMode, GroupEntry, ToolGroup } from '../../database/json/custom-mode/types';
import { useCustomModes } from '../../hooks/use-custom-mode';
+import { PreviewView, PreviewViewState } from '../../PreviewView';
import { modes as buildinModes } from '../../utils/modes';
import { openOrCreateMarkdownFile } from '../../utils/obsidian';
+import { PromptGenerator, getFullLanguageName } from '../../utils/prompt-generator';
+
const CustomModeView = () => {
const app = useApp()
@@ -14,7 +22,16 @@ const CustomModeView = () => {
deleteCustomMode,
updateCustomMode,
customModeList,
+ customModePrompts
} = useCustomModes()
+ const { settings } = useSettings()
+ const { getRAGEngine } = useRAG()
+ const diffStrategy = useDiffStrategy()
+
+ const promptGenerator = useMemo(() => {
+ // @ts-expect-error
+ return new PromptGenerator(getRAGEngine, app, settings, diffStrategy, customModePrompts, customModeList)
+ }, [app, settings, diffStrategy, customModePrompts, customModeList])
// 当前选择的模式
const [selectedMode, setSelectedMode] = useState('ask')
@@ -326,8 +343,41 @@ const CustomModeView = () => {
)}
+
+ {/* 预览和保存 */}
-