diff --git a/.changeset/fn-7031-dock-files-binary-preview.md b/.changeset/fn-7031-dock-files-binary-preview.md
new file mode 100644
index 0000000000..83fa0f7d07
--- /dev/null
+++ b/.changeset/fn-7031-dock-files-binary-preview.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": patch
+---
+
+summary: Preview image, video, audio, and PDF files natively in the right-dock Files viewer.
+category: fix
+dev: Reuses the shared file-preview classification and download route in DockFilesView.
diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md
index 956bba7798..daaa8a63fc 100644
--- a/docs/dashboard-guide.md
+++ b/docs/dashboard-guide.md
@@ -52,7 +52,7 @@ The **Right Dock Panel** experiment is enabled by default. To disable it, open *
When enabled on desktop or tablet project screens, the right dock is a persistent far-right tools sidebar in the project content row. Use the in-dock collapse control to switch between the full tool panel and the compact far-right rail; the selected tool, expanded/collapsed state, width, and expanded modal size persist across reloads.
-The dock toolbar has built-in inline tool panels for **Activity**, **Activity Log**, **Git Manager**, **Files**, and project tool launchers such as **Import from GitHub** / **Import Tasks** workflow entry points and **Automation** actions when available. **Activity**, **Activity Log**, **Git Manager**, and **Files** render in embedded mode inside the dock instead of opening fixed popup overlays; **Files** opens by default and is the fallback when browser storage points at a removed dock key. Inline dock views have an expand button that opens the same view in a resizable modal for more room. Plugin overflow views may add additional right-dock tool tabs, except plugin destinations that explicitly belong in the left sidebar.
+The dock toolbar has built-in inline tool panels for **Activity**, **Activity Log**, **Git Manager**, **Files**, and project tool launchers such as **Import from GitHub** / **Import Tasks** workflow entry points and **Automation** actions when available. **Activity**, **Activity Log**, **Git Manager**, and **Files** render in embedded mode inside the dock instead of opening fixed popup overlays; **Files** opens by default and is the fallback when browser storage points at a removed dock key. Inline dock views have an expand button that opens the same view in a resizable modal for more room. The right-dock **Files** viewer and its expanded pop-out match the Files modal for browser-previewable file types: image, video/movie, audio, and PDF selections render as native browser previews, while editable text files keep the editor and save flow. Plugin overflow views may add additional right-dock tool tabs, except plugin destinations that explicitly belong in the left sidebar.
Use the desktop/tablet right dock this way:
diff --git a/packages/dashboard/app/components/DockFilesView.css b/packages/dashboard/app/components/DockFilesView.css
index 26b577d9cb..7fae3b65b8 100644
--- a/packages/dashboard/app/components/DockFilesView.css
+++ b/packages/dashboard/app/components/DockFilesView.css
@@ -109,6 +109,39 @@ Hidden until a file is selected; when selected it overlays the tree as the singl
min-height: 0;
}
+/*
+FNXC:RightDockFiles 2026-06-25-00:00:
+The dock Files viewer shares FileBrowserModal's native preview classes but needs dock-scoped flex sizing so image/video/audio/PDF previews fit both the compact single-panel stack and the two-pane pop-out without overflowing or showing the CodeMirror shell.
+*/
+.dock-files-preview {
+ flex: 1 1 auto;
+ min-width: 0;
+ min-height: 0;
+ width: 100%;
+ overflow: auto;
+}
+
+.dock-files-preview__media {
+ min-width: 0;
+}
+
+.dock-files-preview .file-browser-preview-media--image,
+.dock-files-preview .file-browser-preview-media--video {
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain;
+}
+
+.dock-files-preview .file-browser-preview-media--audio {
+ width: min(100%, calc(var(--space-xl) * 18));
+}
+
+.dock-files-preview .file-browser-preview-media--pdf {
+ width: 100%;
+ min-height: 0;
+ flex: 1 1 auto;
+}
+
.dock-files-viewer__status {
padding: var(--space-md);
font-size: var(--font-size-xs);
@@ -203,3 +236,15 @@ DETERMINISTIC two-pane layout for the RightDockExpandModal pop-out. Driven by th
.dock-files-view--two-pane .dock-files-view__viewer .dock-files-viewer__back {
display: none;
}
+
+@media (max-width: 768px) {
+ .dock-files-preview {
+ padding: var(--space-md);
+ }
+
+ .dock-files-preview .file-browser-preview-media--image,
+ .dock-files-preview .file-browser-preview-media--video,
+ .dock-files-preview .file-browser-preview-media--pdf {
+ width: 100%;
+ }
+}
diff --git a/packages/dashboard/app/components/DockFilesView.tsx b/packages/dashboard/app/components/DockFilesView.tsx
index cd57e368c1..ff16a48b76 100644
--- a/packages/dashboard/app/components/DockFilesView.tsx
+++ b/packages/dashboard/app/components/DockFilesView.tsx
@@ -1,10 +1,12 @@
-import { useCallback, useEffect, useState } from "react";
+import { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { ArrowLeft, Maximize2, Save } from "lucide-react";
import type { PluginDashboardViewContext } from "../plugins/types";
+import { downloadFileUrl } from "../api";
import { useWorkspaceFileBrowser } from "../hooks/useWorkspaceFileBrowser";
import { useWorkspaceFileEditor } from "../hooks/useWorkspaceFileEditor";
import { getScopedItem, removeScopedItem, scopedKey, setScopedItem } from "../utils/projectStorage";
+import { getFilePreviewKind, IMAGE_PREVIEW_EXTENSIONS, VIDEO_PREVIEW_EXTENSIONS, AUDIO_PREVIEW_EXTENSIONS, PDF_PREVIEW_EXTENSIONS } from "../utils/file-preview-kind";
import { FileBrowser } from "./FileBrowser";
import { FileEditor } from "./FileEditor";
import "./DockFilesView.css";
@@ -28,6 +30,30 @@ Share the current-file path through scoped localStorage (`kb-dashboard-dock-file
*/
export const DOCK_FILES_CURRENT_KEY = "kb-dashboard-dock-files-current";
+const BINARY_EXTENSIONS = new Set([
+ ...IMAGE_PREVIEW_EXTENSIONS,
+ ...VIDEO_PREVIEW_EXTENSIONS,
+ ...AUDIO_PREVIEW_EXTENSIONS,
+ ...PDF_PREVIEW_EXTENSIONS,
+ ".exe", ".dll", ".so", ".dylib",
+ ".zip", ".tar", ".gz", ".bz2", ".xz", ".7z", ".rar",
+ ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
+ ".avi", ".mkv", ".flv",
+ ".woff", ".woff2", ".ttf", ".otf", ".eot",
+ ".wasm", ".bin",
+]);
+
+function isBinaryFile(filename?: string | null): boolean {
+ if (!filename) {
+ return false;
+ }
+ const dotIndex = filename.lastIndexOf(".");
+ if (dotIndex < 0) {
+ return false;
+ }
+ return BINARY_EXTENSIONS.has(filename.slice(dotIndex).toLowerCase());
+}
+
/*
FNXC:RightDockFiles 2026-06-22-00:00:
The right-dock Files tool opens a clicked file INLINE inside the dock as a read-only viewer instead of immediately launching the resizable/movable FileBrowserModal.
@@ -78,9 +104,22 @@ export function DockFilesView({ projectId, openFile, layout = "auto" }: DockFile
return () => window.removeEventListener("storage", onStorage);
}, [projectId]);
+ const selectedPreviewKind = useMemo(() => getFilePreviewKind(selectedFile), [selectedFile]);
+ const isPreviewOnlyFile = selectedPreviewKind !== null;
+ const isReadOnlyBinaryFile = Boolean(selectedFile && !isPreviewOnlyFile && isBinaryFile(selectedFile));
+ const previewUrl = useMemo(() => {
+ if (!selectedFile || !selectedPreviewKind) {
+ return null;
+ }
+ return downloadFileUrl("project", selectedFile, projectId);
+ }, [projectId, selectedFile, selectedPreviewKind]);
+
/*
FNXC:RightDockFiles 2026-06-22-16:28:
The right-sidebar file viewer must be the same editor surface as the modal/mobile file browser: real workspace editor state, visible toolbar options, Preview/Edit for markdown, Line #, and Wrap. Use the shared editor hook instead of the old read-only content fetch so edits can be saved and the toolbar is not a reduced sidebar-only variant.
+
+ FNXC:RightDockFiles 2026-06-25-00:00:
+ Known image/video/audio/PDF selections render through browser-native previews loaded from the workspace-safe download route. Keep those preview-only files out of CodeMirror so binary bytes are never fetched as editor text; editable text keeps the existing FileEditor + Save path, while known non-preview binary extensions stay read-only without loading bytes as editor content.
*/
const {
content,
@@ -90,7 +129,7 @@ export function DockFilesView({ projectId, openFile, layout = "auto" }: DockFile
error: contentError,
save,
hasChanges,
- } = useWorkspaceFileEditor("project", selectedFile, Boolean(selectedFile), projectId);
+ } = useWorkspaceFileEditor("project", selectedFile, Boolean(selectedFile) && !isPreviewOnlyFile && !isReadOnlyBinaryFile, projectId);
const handleBack = useCallback(() => selectFile(null), [selectFile]);
const handlePopOut = useCallback(() => {
@@ -99,6 +138,9 @@ export function DockFilesView({ projectId, openFile, layout = "auto" }: DockFile
const handleToggleLineNumbers = useCallback(() => setShowLineNumbers((current) => !current), []);
const fileName = selectedFile ? selectedFile.split("/").pop() || selectedFile : "";
+ const selectedPreviewTitle = selectedFile
+ ? t("fileBrowser.previewTitle", "Preview for {{file}}", { file: selectedFile })
+ : "";
// FNXC:Files 2026-06-22-00:00:
// `data-selected` on the root lets the container query distinguish "no file selected" (narrow: viewer pane hidden so only the tree shows) from "file selected" (narrow: viewer pane covers the stack). When wide both panes are always visible regardless of this flag.
@@ -155,7 +197,7 @@ export function DockFilesView({ projectId, openFile, layout = "auto" }: DockFile
>
- {selectedFile ? (
+ {selectedFile && !isPreviewOnlyFile && !isReadOnlyBinaryFile ? (