diff options
| author | Mohamed Bassem <me@mbassem.com> | 2024-04-25 20:15:15 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-25 20:15:15 +0100 |
| commit | d07f2c90065f53d36a3fc0e7db54c32d54a2a332 (patch) | |
| tree | 27102aeb30ee9798ca639517ff577bc7d135a4b4 /apps/web/components/dashboard/EditableText.tsx | |
| parent | da6df7c7853e9c8350e52d6f4c17021667caf8b8 (diff) | |
| download | karakeep-d07f2c90065f53d36a3fc0e7db54c32d54a2a332.tar.zst | |
feature(web): Add ability to rename, merge and fast delete tags. Fixes #105 (#125)
* feature(web): Allow deleting tags from the all tags page
* feature(web): Add ability to rename, merge and fast delete tags. Fixes #105
Diffstat (limited to 'apps/web/components/dashboard/EditableText.tsx')
| -rw-r--r-- | apps/web/components/dashboard/EditableText.tsx | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/apps/web/components/dashboard/EditableText.tsx b/apps/web/components/dashboard/EditableText.tsx new file mode 100644 index 00000000..7539bd8f --- /dev/null +++ b/apps/web/components/dashboard/EditableText.tsx @@ -0,0 +1,146 @@ +import { useEffect, useRef, useState } from "react"; +import { ActionButtonWithTooltip } from "@/components/ui/action-button"; +import { ButtonWithTooltip } from "@/components/ui/button"; +import { + Tooltip, + TooltipContent, + TooltipPortal, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { Check, Pencil, X } from "lucide-react"; + +interface Props { + viewClassName?: string; + untitledClassName?: string; + editClassName?: string; + onSave: (title: string | null) => void; + isSaving: boolean; + originalText: string | null; + setEditable: (editable: boolean) => void; +} + +function EditMode({ + onSave: onSaveCB, + editClassName: className, + isSaving, + originalText, + setEditable, +}: Props) { + const ref = useRef<HTMLDivElement>(null); + + useEffect(() => { + if (ref.current) { + ref.current.focus(); + ref.current.textContent = originalText; + } + }, [ref]); + + const onSave = () => { + let toSave: string | null = ref.current?.textContent ?? null; + if (originalText == toSave) { + // Nothing to do here + return; + } + if (toSave == "") { + toSave = null; + } + onSaveCB(toSave); + setEditable(false); + }; + + return ( + <div className="flex gap-3"> + <div + ref={ref} + role="presentation" + className={className} + contentEditable={true} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault(); + } + }} + /> + <ActionButtonWithTooltip + tooltip="Save" + delayDuration={500} + size="none" + variant="ghost" + className="align-middle text-gray-400" + loading={isSaving} + onClick={() => onSave()} + > + <Check className="size-4" /> + </ActionButtonWithTooltip> + <ButtonWithTooltip + tooltip="Cancel" + delayDuration={500} + size="none" + variant="ghost" + className="align-middle text-gray-400" + onClick={() => { + setEditable(false); + }} + > + <X className="size-4" /> + </ButtonWithTooltip> + </div> + ); +} + +function ViewMode({ + originalText, + setEditable, + viewClassName, + untitledClassName, +}: Props) { + return ( + <Tooltip delayDuration={500}> + <div className="flex items-center gap-3 text-center"> + <TooltipTrigger asChild> + {originalText ? ( + <p className={viewClassName}>{originalText}</p> + ) : ( + <p className={untitledClassName}>Untitled</p> + )} + </TooltipTrigger> + <ButtonWithTooltip + delayDuration={500} + tooltip="Edit title" + size="none" + variant="ghost" + className="align-middle text-gray-400" + onClick={() => { + setEditable(true); + }} + > + <Pencil className="size-4" /> + </ButtonWithTooltip> + </div> + <TooltipPortal> + {originalText && ( + <TooltipContent side="bottom" className="max-w-[40ch]"> + {originalText} + </TooltipContent> + )} + </TooltipPortal> + </Tooltip> + ); +} + +export function EditableText(props: { + viewClassName?: string; + untitledClassName?: string; + editClassName?: string; + originalText: string | null; + onSave: (title: string | null) => void; + isSaving: boolean; +}) { + const [editable, setEditable] = useState(false); + + return editable ? ( + <EditMode setEditable={setEditable} {...props} /> + ) : ( + <ViewMode setEditable={setEditable} {...props} /> + ); +} |
