Upload image button

This commit is contained in:
2026-03-12 15:51:37 -05:00
parent 092e139f6e
commit 75723ed133
5 changed files with 127 additions and 55 deletions
+2 -51
View File
@@ -9,9 +9,7 @@ import {
AlignLeft, AlignCenter, AlignRight,
Trash2, AppWindow
} from "lucide-solid";
import { cn, convertImageToWebpFile } from "@/lib/utils";
import { activeTaskId, uploadTaskAttachment, activeNoteId, uploadNoteAttachment } from "@/store";
import { toast } from "solid-sonner";
import { cn } from "@/lib/utils";
export interface CommandItem {
title: string;
@@ -122,54 +120,7 @@ export const getSuggestionItems = ({ query }: { query: string }): CommandItem[]
description: "Upload an image.",
icon: ImageIcon,
command: ({ editor, range }: { editor: any, range: any }) => {
editor.chain().focus().deleteRange(range).run();
const taskId = activeTaskId();
const noteId = activeNoteId();
if (!taskId && !noteId) {
toast.error("Cannot upload image outside of a task or note.");
return;
}
const input = document.createElement("input");
input.type = "file";
input.accept = "image/*";
input.onchange = async () => {
if (input.files?.length) {
const originalFile = input.files[0];
toast.promise(
(async () => {
const webpFile = await convertImageToWebpFile(originalFile);
if (taskId) {
return uploadTaskAttachment(taskId, webpFile);
} else {
return uploadNoteAttachment(noteId!, webpFile);
}
})(),
{
loading: "Processing & uploading image...",
success: (url) => {
// Insert image, then run enter to add a newline (paragraph) below it.
// Without this, the image stays selected and the next keypress deletes it.
editor.chain()
.focus()
.setImage({ src: url })
.run();
// Manually force a new paragraph at the end so the user can keep typing
editor.chain()
.focus('end')
.insertContent('<p></p>')
.run();
return "Image uploaded.";
},
error: "Failed to upload image."
}
);
}
};
input.click();
editor.chain().focus().deleteRange(range).uploadImage().run();
},
},
{
+20 -2
View File
@@ -3,7 +3,7 @@ import { Sheet, SheetContent } from "@/components/ui/sheet";
import { type Task, removeTask, restoreTask, updateTask, saveTaskAsTemplate, shareTask, revokeShare, splitTask, loadTaskContent, currentTaskContext, cleanupTaskAttachments, getFavoriteTag } from "@/store";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { ArrowUpCircle, Clock, Calendar, Type, Trash2, X, Copy, MoreHorizontal, Gauge, Share2, UserMinus, GitBranch, Tag, Settings, Star } from "lucide-solid";
import { ArrowUpCircle, Clock, Calendar, Type, Trash2, X, Copy, MoreHorizontal, Gauge, Share2, UserMinus, GitBranch, Tag, Settings, Star, Image as ImageIcon } from "lucide-solid";
import { StatusCircle } from "./StatusCircle";
import { calculateDateFromUrgency, calculateUrgencyFromDate } from "@/store";
import { Button } from "./ui/button";
@@ -363,7 +363,7 @@ export const TaskDetail: Component<TaskDetailProps> = (props) => {
{/* Favorite */}
<div class="flex items-center gap-1 group shrink-0">
<span class="text-[0.625rem] uppercase font-bold tracking-wider text-muted-foreground/70 hidden sm:inline">Favorite</span>
<span class="text-[0.625rem] uppercase font-bold tracking-wider text-muted-foreground/70 hidden sm:inline"></span>
<Button
variant="ghost"
size="sm"
@@ -398,6 +398,24 @@ export const TaskDetail: Component<TaskDetailProps> = (props) => {
<span class="hidden sm:inline">Commands</span>
</Button>
</div>
{/* Image Upload Shortcut */}
<div class="flex items-center gap-1 shrink-0">
<Button
variant="ghost"
size="sm"
class="h-8 px-1 sm:px-2 text-[0.625rem] font-bold uppercase tracking-wider hover:bg-muted/50 flex items-center gap-1 sm:gap-1.5 text-muted-foreground hover:text-foreground transition-colors"
onClick={() => {
const instance = editorInstance();
if (instance) {
instance.chain().focus().uploadImage().run();
}
}}
>
<ImageIcon size={14} class="opacity-70" />
<span class="hidden sm:inline">Image</span>
</Button>
</div>
</div>
{/* Metadata Row (Dates/Timestamps) */}
+2
View File
@@ -27,6 +27,7 @@ import { Dropcursor } from "@tiptap/extension-dropcursor";
import { Mention } from "@tiptap/extension-mention";
import { userSuggestion, noteSuggestion } from "@/lib/mention-suggestion";
import { FileViewer } from "@/lib/extensions/file-viewer";
import { ImageUpload } from "@/lib/extensions/image-upload";
interface TaskEditorProps {
content?: string;
@@ -161,6 +162,7 @@ export const TaskEditor: Component<TaskEditorProps> = (props) => {
width: 2,
}),
FileViewer,
ImageUpload,
],
// Use untrack so the editor doesn't re-initialize when props.content changes
content: untrack(() => props.content) || "",