From 2f4207a44af4cede62284a16cae9605a763eac80 Mon Sep 17 00:00:00 2001 From: Timothy Cardoza Date: Thu, 5 Feb 2026 11:01:05 -0600 Subject: [PATCH] added indent and outdent buttons on mobile when editing task description --- src/components/TaskEditor.tsx | 75 ++++++++++++++++++++++++++++++++--- src/components/ui/button.tsx | 1 + 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/components/TaskEditor.tsx b/src/components/TaskEditor.tsx index dba058c..4b584b5 100644 --- a/src/components/TaskEditor.tsx +++ b/src/components/TaskEditor.tsx @@ -1,10 +1,12 @@ -import { type Component, createEffect, untrack } from "solid-js"; +import { type Component, createEffect, untrack, Show, createSignal } from "solid-js"; import { createTiptapEditor } from "solid-tiptap"; import StarterKit from "@tiptap/starter-kit"; import Placeholder from "@tiptap/extension-placeholder"; import TaskList from "@tiptap/extension-task-list"; import TaskItem from "@tiptap/extension-task-item"; import { cn } from "@/lib/utils"; +import { Indent, Outdent } from "lucide-solid"; +import { Button } from "./ui/button"; import { SlashCommands } from "@/lib/slash-command"; import { suggestion } from "@/lib/slash-renderer"; @@ -19,6 +21,7 @@ interface TaskEditorProps { export const TaskEditor: Component = (props) => { let editorRef: HTMLDivElement | undefined; + const [isFocused, setIsFocused] = createSignal(false); const editor = createTiptapEditor(() => ({ element: editorRef!, @@ -59,6 +62,11 @@ export const TaskEditor: Component = (props) => { onUpdate: ({ editor }) => { props.onUpdate(editor.getHTML()); }, + onFocus: () => setIsFocused(true), + onBlur: () => { + // Delay blur to allow button clicks + setTimeout(() => setIsFocused(false), 200); + }, editorProps: { attributes: { class: cn( @@ -95,11 +103,66 @@ export const TaskEditor: Component = (props) => { } }); + const handleIndent = (e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + const eInstance = editor(); + if (!eInstance) return; + + if (eInstance.can().sinkListItem('taskItem')) { + eInstance.chain().focus().sinkListItem('taskItem').run(); + } else if (eInstance.can().sinkListItem('listItem')) { + eInstance.chain().focus().sinkListItem('listItem').run(); + } + }; + + const handleOutdent = (e: MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + const eInstance = editor(); + if (!eInstance) return; + + if (eInstance.can().liftListItem('taskItem')) { + eInstance.chain().focus().liftListItem('taskItem').run(); + } else if (eInstance.can().liftListItem('listItem')) { + eInstance.chain().focus().liftListItem('listItem').run(); + } + }; + return ( -
editor()?.chain().focus().run()} - /> +
+
editor()?.chain().focus().run()} + /> + + {/* Mobile Indentation Toolbar */} + +
+ + +
+ + +
+ +
); }; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 8570c5f..1d6d808 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -34,6 +34,7 @@ export interface ButtonProps extends VariantProps { onClick?: (e: MouseEvent) => void onMouseEnter?: (e: MouseEvent) => void onMouseLeave?: (e: MouseEvent) => void + onMouseDown?: (e: MouseEvent) => void children?: JSX.Element size?: "default" | "sm" | "lg" | "icon" variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"