Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/desktop/src/preload.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { contextBridge, ipcRenderer } from "electron";
import { contextBridge, ipcRenderer, webUtils } from "electron";
import type { DesktopBridge } from "@t3tools/contracts";

const PICK_FOLDER_CHANNEL = "desktop:pick-folder";
Expand All @@ -15,6 +15,7 @@ const wsUrl = process.env.T3CODE_DESKTOP_WS_URL ?? null;

contextBridge.exposeInMainWorld("desktopBridge", {
getWsUrl: () => wsUrl,
getPathForFile: (file: File) => webUtils.getPathForFile(file),
pickFolder: () => ipcRenderer.invoke(PICK_FOLDER_CHANNEL),
confirm: (message) => ipcRenderer.invoke(CONFIRM_CHANNEL, message),
setTheme: (theme) => ipcRenderer.invoke(SET_THEME_CHANNEL, theme),
Expand Down
31 changes: 24 additions & 7 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ const EMPTY_AVAILABLE_EDITORS: EditorId[] = [];
const EMPTY_PROVIDER_STATUSES: ServerProviderStatus[] = [];
const EMPTY_PENDING_USER_INPUT_ANSWERS: Record<string, PendingUserInputDraftAnswer> = {};
const COMPOSER_PATH_QUERY_DEBOUNCE_MS = 120;
const COMPOSER_FILE_PATH_SEPARATOR = " ";
const SCRIPT_TERMINAL_COLS = 120;
const SCRIPT_TERMINAL_ROWS = 30;
const WORKTREE_BRANCH_PREFIX = "t3code";
Expand Down Expand Up @@ -2450,17 +2451,32 @@ export default function ChatView({ threadId }: ChatViewProps) {
removeComposerImageFromDraft(imageId);
};

const addComposerAttachments = (files: File[]) => {
const imageFiles = files.filter((f) => f.type.startsWith("image/"));
const nonImageFiles = files.filter((f) => !f.type.startsWith("image/"));

if (imageFiles.length > 0) {
addComposerImages(imageFiles);
}

if (nonImageFiles.length > 0) {
const paths = nonImageFiles.map(
(file) => window.desktopBridge?.getPathForFile(file) ?? file.name,
);
const insertion = paths
.map((p) => (p.includes(" ") ? `"${p}"` : p))
.join(COMPOSER_FILE_PATH_SEPARATOR);
composerEditorRef.current?.insertTextAndFocus(insertion);
}
};

const onComposerPaste = (event: React.ClipboardEvent<HTMLElement>) => {
const files = Array.from(event.clipboardData.files);
if (files.length === 0) {
return;
}
const imageFiles = files.filter((file) => file.type.startsWith("image/"));
if (imageFiles.length === 0) {
return;
}
event.preventDefault();
addComposerImages(imageFiles);
addComposerAttachments(files);
};

const onComposerDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
Expand Down Expand Up @@ -2504,8 +2520,9 @@ export default function ChatView({ threadId }: ChatViewProps) {
dragDepthRef.current = 0;
setIsDragOverComposer(false);
const files = Array.from(event.dataTransfer.files);
addComposerImages(files);
focusComposer();
const hasNonImageFiles = files.some((f) => !f.type.startsWith("image/"));
addComposerAttachments(files);
if (!hasNonImageFiles) focusComposer();
};

const onRevertToTurnCount = useCallback(
Expand Down
20 changes: 19 additions & 1 deletion apps/web/src/components/ComposerPromptEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ export interface ComposerPromptEditorHandle {
focusAt: (cursor: number) => void;
focusAtEnd: () => void;
readSnapshot: () => { value: string; cursor: number };
insertTextAndFocus: (text: string) => void;
}

interface ComposerPromptEditorProps {
Expand Down Expand Up @@ -699,6 +700,22 @@ function ComposerPromptEditorInner({
return snapshot;
}, [editor]);

const insertTextAndFocus = useCallback(
(text: string) => {
const rootElement = editor.getRootElement();
if (rootElement) {
rootElement.focus();
}
editor.update(() => {
const selection = $getSelection();
if ($isRangeSelection(selection)) {
selection.insertText(text);
}
});
},
[editor],
);

useImperativeHandle(
editorRef,
() => ({
Expand All @@ -712,8 +729,9 @@ function ComposerPromptEditorInner({
focusAt(snapshotRef.current.value.length);
},
readSnapshot,
insertTextAndFocus,
}),
[focusAt, readSnapshot],
[focusAt, readSnapshot, insertTextAndFocus],
);

const handleEditorChange = useCallback((editorState: EditorState) => {
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/src/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface DesktopUpdateActionResult {

export interface DesktopBridge {
getWsUrl: () => string | null;
getPathForFile: (file: File) => string;
pickFolder: () => Promise<string | null>;
confirm: (message: string) => Promise<boolean>;
setTheme: (theme: DesktopTheme) => Promise<void>;
Expand Down