From c92bcd064a8ea1e036b2105ad05862bb8b726f38 Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Wed, 26 Aug 2026 02:21:48 +0100 Subject: [PATCH] fix: make ALT more visible --- .../src/features/editor/styles/media.css | 54 +++++++++++++++++++ packages/editor-ext/src/lib/drawio.ts | 6 ++- packages/editor-ext/src/lib/excalidraw.ts | 6 ++- packages/editor-ext/src/lib/image/image.ts | 6 ++- packages/editor-ext/src/lib/media-utils.ts | 21 ++++++++ 5 files changed, 90 insertions(+), 3 deletions(-) diff --git a/apps/client/src/features/editor/styles/media.css b/apps/client/src/features/editor/styles/media.css index 0b02cdbeb..14725b9fe 100644 --- a/apps/client/src/features/editor/styles/media.css +++ b/apps/client/src/features/editor/styles/media.css @@ -38,6 +38,60 @@ line-height: var(--mantine-line-height-md); } + .media-alt-badge { + position: absolute; + right: 8px; + bottom: 8px; + z-index: 1; + padding: 2px 8px; + border-radius: 6px; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.03em; + cursor: default; + user-select: none; + background-color: var(--mantine-color-body); + + @mixin light { + border: 1px solid var(--mantine-color-gray-3); + color: var(--mantine-color-gray-7); + } + + @mixin dark { + border: 1px solid var(--mantine-color-dark-4); + color: var(--mantine-color-dark-1); + } + + @media print { + display: none; + } + + &::after { + content: attr(data-alt); + display: none; + position: absolute; + right: 0; + bottom: calc(100% + 6px); + width: max-content; + max-width: 320px; + padding: 6px 10px; + border-radius: var(--mantine-radius-default); + font-size: var(--mantine-font-size-sm); + font-weight: 400; + letter-spacing: normal; + line-height: var(--mantine-line-height-sm); + white-space: pre-wrap; + overflow-wrap: break-word; + text-align: start; + background-color: var(--mantine-color-gray-9); + color: var(--mantine-color-white); + } + + &:hover::after { + display: block; + } + } + .media-pulse { animation: media-pulse 1.2s ease-in-out infinite; diff --git a/packages/editor-ext/src/lib/drawio.ts b/packages/editor-ext/src/lib/drawio.ts index 14d70f394..63e2f3460 100644 --- a/packages/editor-ext/src/lib/drawio.ts +++ b/packages/editor-ext/src/lib/drawio.ts @@ -2,7 +2,7 @@ import { Node, mergeAttributes } from "@tiptap/core"; import { ResizableNodeView } from "./resizable-nodeview"; import type { ResizableNodeViewDirection } from "./resizable-nodeview"; import { ReactNodeViewRenderer } from "@tiptap/react"; -import { normalizeFileUrl } from "./media-utils"; +import { normalizeFileUrl, syncAltBadge } from "./media-utils"; export type DrawioResizeOptions = { enabled: boolean; @@ -293,6 +293,8 @@ export const Drawio = Node.create({ const container = nodeView.dom as HTMLElement; applyAlignment(container, align); + syncAltBadge(nodeView.wrapper, updatedNode.attrs.alt); + currentNode = updatedNode; return true; }, @@ -310,6 +312,8 @@ export const Drawio = Node.create({ const dom = nodeView.dom as HTMLElement; + syncAltBadge(nodeView.wrapper, node.attrs.alt); + applyAlignment(dom, node.attrs.align || "center"); // Handle percentage width backward compat diff --git a/packages/editor-ext/src/lib/excalidraw.ts b/packages/editor-ext/src/lib/excalidraw.ts index 59b28f7fa..de35bde0f 100644 --- a/packages/editor-ext/src/lib/excalidraw.ts +++ b/packages/editor-ext/src/lib/excalidraw.ts @@ -2,7 +2,7 @@ import { Node, mergeAttributes } from "@tiptap/core"; import { ResizableNodeView } from "./resizable-nodeview"; import type { ResizableNodeViewDirection } from "./resizable-nodeview"; import { ReactNodeViewRenderer } from "@tiptap/react"; -import { normalizeFileUrl } from "./media-utils"; +import { normalizeFileUrl, syncAltBadge } from "./media-utils"; export type ExcalidrawResizeOptions = { enabled: boolean; @@ -293,6 +293,8 @@ export const Excalidraw = Node.create({ const container = nodeView.dom as HTMLElement; applyAlignment(container, align); + syncAltBadge(nodeView.wrapper, updatedNode.attrs.alt); + currentNode = updatedNode; return true; }, @@ -310,6 +312,8 @@ export const Excalidraw = Node.create({ const dom = nodeView.dom as HTMLElement; + syncAltBadge(nodeView.wrapper, node.attrs.alt); + applyAlignment(dom, node.attrs.align || "center"); // Handle percentage width backward compat diff --git a/packages/editor-ext/src/lib/image/image.ts b/packages/editor-ext/src/lib/image/image.ts index 6a9219264..bafdf82b8 100644 --- a/packages/editor-ext/src/lib/image/image.ts +++ b/packages/editor-ext/src/lib/image/image.ts @@ -7,7 +7,7 @@ import { } from "@tiptap/core"; import { ResizableNodeView } from "../resizable-nodeview"; import type { ResizableNodeViewDirection } from "../resizable-nodeview"; -import { normalizeFileUrl } from "../media-utils"; +import { normalizeFileUrl, syncAltBadge } from "../media-utils"; export type ImageResizeOptions = { enabled: boolean; @@ -316,6 +316,8 @@ export const TiptapImage = Image.extend({ const container = nodeView.dom as HTMLElement; applyAlignment(container, align); + syncAltBadge(nodeView.wrapper, updatedNode.attrs.alt); + currentNode = updatedNode; return true; }, @@ -333,6 +335,8 @@ export const TiptapImage = Image.extend({ const dom = nodeView.dom as HTMLElement; + syncAltBadge(nodeView.wrapper, node.attrs.alt); + // Apply initial alignment applyAlignment(dom, node.attrs.align || "center"); diff --git a/packages/editor-ext/src/lib/media-utils.ts b/packages/editor-ext/src/lib/media-utils.ts index d18bcb69e..dfec750ca 100644 --- a/packages/editor-ext/src/lib/media-utils.ts +++ b/packages/editor-ext/src/lib/media-utils.ts @@ -7,6 +7,27 @@ export function normalizeFileUrl(src: string): string { return src || ""; } +export function syncAltBadge(wrapper: HTMLElement, alt: unknown): void { + const existing = wrapper.querySelector( + ":scope > .media-alt-badge", + ); + + if (typeof alt !== "string" || !alt.trim()) { + existing?.remove(); + return; + } + + const badge = existing ?? document.createElement("span"); + badge.dataset.alt = alt; + + if (!existing) { + badge.className = "media-alt-badge"; + badge.textContent = "ALT"; + badge.setAttribute("aria-hidden", "true"); + wrapper.appendChild(badge); + } +} + export type UploadFn = ( file: File, editor: Editor,