diff --git a/src/features/command-palette/components/command-palette.tsx b/src/features/command-palette/components/command-palette.tsx
index 33d5eb2f..8ab27836 100644
--- a/src/features/command-palette/components/command-palette.tsx
+++ b/src/features/command-palette/components/command-palette.tsx
@@ -31,6 +31,7 @@ import KeybindingBadge from "@/ui/keybinding-badge";
import { createAdvancedActions } from "../constants/advanced-actions";
import { createFileActions } from "../constants/file-actions";
import { createGitActions } from "../constants/git-actions";
+import { createMarkdownActions } from "../constants/markdown-actions";
import { createNavigationActions } from "../constants/navigation-actions";
import { createSettingsActions } from "../constants/settings-actions";
import { createViewActions } from "../constants/view-actions";
@@ -78,6 +79,7 @@ const CommandPalette = () => {
const { showToast } = useToast();
const buffers = useBufferStore.use.buffers();
const activeBufferId = useBufferStore.use.activeBufferId();
+ const activeBuffer = buffers.find((b) => b.id === activeBufferId) || null;
const {
closeBuffer,
setActiveBuffer,
@@ -86,9 +88,23 @@ const CommandPalette = () => {
reopenClosedTab,
} = useBufferStore.use.actions();
const { zoomIn, zoomOut, resetZoom } = useZoomStore.use.actions();
+ const { openBuffer } = useBufferStore.use.actions();
+
+ // Helper function to check if the active buffer is a markdown file
+ const isMarkdownFile = () => {
+ if (!activeBuffer) return false;
+ const extension = activeBuffer.path.split(".").pop()?.toLowerCase();
+ return extension === "md" || extension === "markdown";
+ };
// Create all actions using factory functions
const allActions: Action[] = [
+ ...createMarkdownActions({
+ isMarkdownFile: isMarkdownFile(),
+ activeBuffer,
+ openBuffer,
+ onClose,
+ }),
...createViewActions({
isSidebarVisible,
setIsSidebarVisible,
diff --git a/src/features/command-palette/constants/markdown-actions.tsx b/src/features/command-palette/constants/markdown-actions.tsx
new file mode 100644
index 00000000..03593299
--- /dev/null
+++ b/src/features/command-palette/constants/markdown-actions.tsx
@@ -0,0 +1,59 @@
+import { Eye } from "lucide-react";
+import type { Buffer } from "@/features/editor/stores/buffer-store";
+import type { Action } from "../models/action.types";
+
+interface MarkdownActionsParams {
+ isMarkdownFile: boolean;
+ activeBuffer: Buffer | null;
+ openBuffer: (
+ path: string,
+ name: string,
+ content: string,
+ isImage?: boolean,
+ isSQLite?: boolean,
+ isDiff?: boolean,
+ isVirtual?: boolean,
+ diffData?: any,
+ isMarkdownPreview?: boolean,
+ sourceFilePath?: string,
+ ) => string;
+ onClose: () => void;
+}
+
+export const createMarkdownActions = (params: MarkdownActionsParams): Action[] => {
+ const { isMarkdownFile, activeBuffer, openBuffer, onClose } = params;
+
+ if (!isMarkdownFile || !activeBuffer) {
+ return [];
+ }
+
+ return [
+ {
+ id: "markdown-preview",
+ label: "Markdown: Preview Markdown",
+ description: "Open markdown preview in a new tab",
+ icon: ,
+ category: "Markdown",
+ action: () => {
+ // Create a virtual path for the preview
+ const previewPath = `${activeBuffer.path}:preview`;
+ const previewName = `${activeBuffer.name} (Preview)`;
+
+ // Open a new buffer for the preview
+ openBuffer(
+ previewPath,
+ previewName,
+ activeBuffer.content,
+ false, // isImage
+ false, // isSQLite
+ false, // isDiff
+ true, // isVirtual
+ undefined, // diffData
+ true, // isMarkdownPreview
+ activeBuffer.path, // sourceFilePath
+ );
+ onClose();
+ },
+ },
+ ];
+};
diff --git a/src/features/command-palette/models/action.types.ts b/src/features/command-palette/models/action.types.ts
index 3d876407..fb907b53 100644
--- a/src/features/command-palette/models/action.types.ts
+++ b/src/features/command-palette/models/action.types.ts
@@ -10,4 +10,4 @@ export interface Action {
action: () => void;
}
-export type ActionCategory = "View" | "Settings" | "File" | "Window" | "Navigation";
+export type ActionCategory = "View" | "Settings" | "File" | "Window" | "Navigation" | "Markdown";
diff --git a/src/features/editor/components/code-editor.tsx b/src/features/editor/components/code-editor.tsx
index c1e9846a..f649e788 100644
--- a/src/features/editor/components/code-editor.tsx
+++ b/src/features/editor/components/code-editor.tsx
@@ -13,7 +13,6 @@ import { useAppStore } from "@/stores/app-store";
import { useZoomStore } from "@/stores/zoom-store";
import { HoverTooltip } from "../lsp/hover-tooltip";
import { MarkdownPreview } from "../markdown/markdown-preview";
-import { isMarkdownFile } from "../utils/lines";
import { Editor } from "./editor";
import { EditorStylesheet } from "./stylesheet";
import Breadcrumb from "./toolbar/breadcrumb";
@@ -41,7 +40,6 @@ const CodeEditor = ({ className }: CodeEditorProps) => {
const { setRefs, setContent, setFileInfo } = useEditorStateStore.use.actions();
// No longer need to sync content - editor-view-store computes from buffer
const { setDisabled } = useEditorSettingsStore.use.actions();
- const isMarkdownPreview = useEditorSettingsStore.use.isMarkdownPreview();
const buffers = useBufferStore.use.buffers();
const activeBufferId = useBufferStore.use.activeBufferId();
@@ -61,8 +59,7 @@ const CodeEditor = ({ className }: CodeEditorProps) => {
const filePath = activeBuffer?.path || "";
const onChange = activeBuffer ? handleContentChange : () => {};
- const showMarkdownPreview =
- activeBuffer && isMarkdownFile(activeBuffer.path) && isMarkdownPreview;
+ const showMarkdownPreview = activeBuffer?.isMarkdownPreview || false;
// Initialize refs in store
useEffect(() => {
diff --git a/src/features/editor/components/toolbar/breadcrumb.tsx b/src/features/editor/components/toolbar/breadcrumb.tsx
index c5abf1ec..ef2c1ede 100644
--- a/src/features/editor/components/toolbar/breadcrumb.tsx
+++ b/src/features/editor/components/toolbar/breadcrumb.tsx
@@ -1,10 +1,9 @@
-import { ArrowLeft, ChevronRight, Eye, Search, Sparkles } from "lucide-react";
+import { ArrowLeft, ChevronRight, Search, Sparkles } from "lucide-react";
import { type RefObject, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { useEventListener, useOnClickOutside } from "usehooks-ts";
import { EDITOR_CONSTANTS } from "@/features/editor/config/constants";
import { useBufferStore } from "@/features/editor/stores/buffer-store";
-import { useEditorSettingsStore } from "@/features/editor/stores/settings-store";
import { useEditorStateStore } from "@/features/editor/stores/state-store";
import { logger } from "@/features/editor/utils/logger";
import FileIcon from "@/features/file-explorer/views/file.icon";
@@ -28,8 +27,6 @@ export default function Breadcrumb() {
const activeBuffer = buffers.find((b) => b.id === activeBufferId) || null;
const { rootFolderPath, handleFileSelect } = useFileSystemStore();
const { isFindVisible, setIsFindVisible } = useUIState();
- const isMarkdownPreview = useEditorSettingsStore.use.isMarkdownPreview();
- const { setIsMarkdownPreview } = useEditorSettingsStore.use.actions();
const { toggle: toggleInlineEditToolbar } = useInlineEditToolbarStore.use.actions();
const selection = useEditorStateStore.use.selection?.();
@@ -45,22 +42,12 @@ export default function Breadcrumb() {
setIsFindVisible(!isFindVisible);
};
- const handlePreviewClick = () => {
- setIsMarkdownPreview(!isMarkdownPreview);
- };
-
const handleInlineEditClick = () => {
toggleInlineEditToolbar();
};
const hasSelection = selection && selection.start.offset !== selection.end.offset;
- const isMarkdownFile = () => {
- if (!activeBuffer) return false;
- const extension = activeBuffer.path.split(".").pop()?.toLowerCase();
- return extension === "md" || extension === "markdown";
- };
-
const filePath = activeBuffer?.path || "";
const rootPath = rootFolderPath;
const onNavigate = handleNavigate;
@@ -232,17 +219,6 @@ export default function Breadcrumb() {
))}
- {isMarkdownFile() && (
-
- )}