diff --git a/apps/client/src/services/image.ts b/apps/client/src/services/image.ts index f13a9a3c7..ca0d816c5 100644 --- a/apps/client/src/services/image.ts +++ b/apps/client/src/services/image.ts @@ -1,7 +1,7 @@ import { t } from "./i18n.js"; import toastService, { showError } from "./toast.js"; -function copyImageReferenceToClipboard($imageWrapper: JQuery) { +export function copyImageReferenceToClipboard($imageWrapper: JQuery) { try { $imageWrapper.attr("contenteditable", "true"); selectImage($imageWrapper.get(0)); diff --git a/apps/client/src/services/utils.ts b/apps/client/src/services/utils.ts index 68af11651..5462011cb 100644 --- a/apps/client/src/services/utils.ts +++ b/apps/client/src/services/utils.ts @@ -1,5 +1,6 @@ import dayjs from "dayjs"; import type { ViewScope } from "./link.js"; +import { FNote } from "./frontend_script_entrypoint.js"; const SVG_MIME = "image/svg+xml"; @@ -574,8 +575,7 @@ function copyHtmlToClipboard(content: string) { document.removeEventListener("copy", listener); } -// TODO: Set to FNote once the file is ported. -function createImageSrcUrl(note: { noteId: string; title: string }) { +export function createImageSrcUrl(note: FNote) { return `api/images/${note.noteId}/${encodeURIComponent(note.title)}?timestamp=${Date.now()}`; } diff --git a/apps/client/src/stylesheets/theme-next/shell.css b/apps/client/src/stylesheets/theme-next/shell.css index 8c460846f..d569dec91 100644 --- a/apps/client/src/stylesheets/theme-next/shell.css +++ b/apps/client/src/stylesheets/theme-next/shell.css @@ -1477,13 +1477,6 @@ div.floating-buttons-children .close-floating-buttons:has(.close-floating-button padding-inline-start: 8px; } -/* Copy image reference */ - -.floating-buttons .copy-image-reference-button .hidden-image-copy { - /* Take out of the the hidden image from flexbox to prevent the layout being affected */ - position: absolute; -} - /* Code, relation map buttons */ .floating-buttons .code-buttons-widget, diff --git a/apps/client/src/widgets/FloatingButtons.tsx b/apps/client/src/widgets/FloatingButtons.tsx index fa41bc54c..f38200072 100644 --- a/apps/client/src/widgets/FloatingButtons.tsx +++ b/apps/client/src/widgets/FloatingButtons.tsx @@ -5,7 +5,7 @@ import ActionButton, { ActionButtonProps } from "./react/ActionButton"; import FNote from "../entities/fnote"; import NoteContext from "../components/note_context"; import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useNoteProperty, useTriliumEvent, useTriliumEvents, useTriliumOption, useTriliumOptionBool } from "./react/hooks"; -import { useContext, useEffect, useMemo, useState } from "preact/hooks"; +import { useContext, useEffect, useMemo, useRef, useState } from "preact/hooks"; import { ParentComponent } from "./react/react_utils"; import Component from "../components/component"; import { VNode } from "preact"; @@ -13,11 +13,12 @@ import attributes from "../services/attributes"; import appContext, { EventData, EventNames } from "../components/app_context"; import protected_session_holder from "../services/protected_session_holder"; import options from "../services/options"; -import { openInAppHelpFromUrl } from "../services/utils"; +import { createImageSrcUrl, openInAppHelpFromUrl } from "../services/utils"; import toast from "../services/toast"; import server from "../services/server"; import { SaveSqlConsoleResponse } from "@triliumnext/commons"; import tree from "../services/tree"; +import { copyImageReferenceToClipboard } from "../services/image"; interface FloatingButtonContext { parentComponent: Component; @@ -87,6 +88,12 @@ const FLOATING_BUTTON_DEFINITIONS: FloatingButtonDefinition[] = [ { component: GeoMapButtons, isEnabled: ({ note }) => note?.getLabelValue("viewType") === "geoMap" && !note.hasLabel("readOnly") + }, + { + component: CopyImageReferenceButton, + isEnabled: ({ note, noteContext }) => + ["mermaid", "canvas", "mindMap"].includes(note?.type ?? "") + && note?.isContentAvailable() && noteContext.viewScope?.viewMode === "default" } ]; @@ -320,6 +327,31 @@ function GeoMapButtons({ triggerEvent }) { ); } +function CopyImageReferenceButton({ note }: FloatingButtonContext) { + const hiddenImageCopyRef = useRef(null); + + return ( + <> + { + if (!hiddenImageCopyRef.current) return; + const imageEl = document.createElement("img"); + imageEl.src = createImageSrcUrl(note); + hiddenImageCopyRef.current.replaceChildren(imageEl); + copyImageReferenceToClipboard($(hiddenImageCopyRef.current)); + hiddenImageCopyRef.current.removeChild(imageEl); + }} + /> + +