diff options
| author | Cédric <42071178+BOTkirial@users.noreply.github.com> | 2025-11-02 22:48:38 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-02 21:48:38 +0000 |
| commit | 393bbd9a64d1b2248ce3e17dbde6f3485140f777 (patch) | |
| tree | 53ad2c08bf227d2de125c7b838a17e9903754b60 /apps/web/components/ui | |
| parent | 085c832c9ab6ada92e99a6987dcdf8bd67c3f317 (diff) | |
| download | karakeep-393bbd9a64d1b2248ce3e17dbde6f3485140f777.tar.zst | |
feat: Support inline toggling for todos. fixes #1931 (#1933)
* [1931] Can now chain the creation of todos from the quick add form
* [1931] Can now toggle todos from the masonry view + added a custom renderer for inputs of type checkbox (required to remove the readonly default attribute)
* handle nested lists and case
---------
Co-authored-by: Cédric <cedric.marinot@elosi.com>
Co-authored-by: Mohamed Bassem <me@mbassem.com>
Diffstat (limited to 'apps/web/components/ui')
| -rw-r--r-- | apps/web/components/ui/markdown/markdown-readonly.tsx | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/apps/web/components/ui/markdown/markdown-readonly.tsx b/apps/web/components/ui/markdown/markdown-readonly.tsx index 3c6daf31..5436e961 100644 --- a/apps/web/components/ui/markdown/markdown-readonly.tsx +++ b/apps/web/components/ui/markdown/markdown-readonly.tsx @@ -25,15 +25,61 @@ function PreWithCopyBtn({ className, ...props }: React.ComponentProps<"pre">) { export function MarkdownReadonly({ children: markdown, className, + onSave, }: { children: string; className?: string; + onSave?: (markdown: string) => void; }) { + /** + * This method is triggered when a checkbox is toggled from the masonry view + * It finds the index of the clicked checkbox inside of the note + * It then finds the corresponding markdown and changes it accordingly + */ + const handleTodoClick = (e: React.ChangeEvent<HTMLInputElement>) => { + e.preventDefault(); + const parent = e.target.closest(".prose"); + if (!parent) return; + const allCheckboxes = parent.querySelectorAll(".todo-checkbox"); + let checkboxIndex = 0; + allCheckboxes.forEach((cb, i) => { + if (cb === e.target) checkboxIndex = i; + }); + let i = 0; + const todoPattern = /^(\s*[-*+]\s*\[)( |x|X)(\])/gm; + const newMarkdown = markdown.replace( + todoPattern, + (match, prefix: string, state: string, suffix: string) => { + const currentIndex = i++; + if (currentIndex !== checkboxIndex) { + return match; + } + const isDone = state.toLowerCase() === "x"; + const nextState = isDone ? " " : "x"; + return `${prefix}${nextState}${suffix}`; + }, + ); + if (onSave) { + onSave(newMarkdown); + } + }; + return ( <Markdown remarkPlugins={[remarkGfm, remarkBreaks]} className={cn("prose dark:prose-invert", className)} components={{ + input: (props) => + props.type === "checkbox" ? ( + <input + checked={props.checked} + onChange={handleTodoClick} + type="checkbox" + className="todo-checkbox" + /> + ) : ( + <input {...props} readOnly /> + ), pre({ ...props }) { return <PreWithCopyBtn {...props} />; }, |
