mirror of
https://github.com/docmost/docmost.git
synced 2026-08-29 01:37:05 +08:00
fix: make ALT more visible
This commit is contained in:
@@ -38,6 +38,60 @@
|
|||||||
line-height: var(--mantine-line-height-md);
|
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 {
|
.media-pulse {
|
||||||
animation: media-pulse 1.2s ease-in-out infinite;
|
animation: media-pulse 1.2s ease-in-out infinite;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Node, mergeAttributes } from "@tiptap/core";
|
|||||||
import { ResizableNodeView } from "./resizable-nodeview";
|
import { ResizableNodeView } from "./resizable-nodeview";
|
||||||
import type { ResizableNodeViewDirection } from "./resizable-nodeview";
|
import type { ResizableNodeViewDirection } from "./resizable-nodeview";
|
||||||
import { ReactNodeViewRenderer } from "@tiptap/react";
|
import { ReactNodeViewRenderer } from "@tiptap/react";
|
||||||
import { normalizeFileUrl } from "./media-utils";
|
import { normalizeFileUrl, syncAltBadge } from "./media-utils";
|
||||||
|
|
||||||
export type DrawioResizeOptions = {
|
export type DrawioResizeOptions = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
@@ -293,6 +293,8 @@ export const Drawio = Node.create<DrawioOptions>({
|
|||||||
const container = nodeView.dom as HTMLElement;
|
const container = nodeView.dom as HTMLElement;
|
||||||
applyAlignment(container, align);
|
applyAlignment(container, align);
|
||||||
|
|
||||||
|
syncAltBadge(nodeView.wrapper, updatedNode.attrs.alt);
|
||||||
|
|
||||||
currentNode = updatedNode;
|
currentNode = updatedNode;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@@ -310,6 +312,8 @@ export const Drawio = Node.create<DrawioOptions>({
|
|||||||
|
|
||||||
const dom = nodeView.dom as HTMLElement;
|
const dom = nodeView.dom as HTMLElement;
|
||||||
|
|
||||||
|
syncAltBadge(nodeView.wrapper, node.attrs.alt);
|
||||||
|
|
||||||
applyAlignment(dom, node.attrs.align || "center");
|
applyAlignment(dom, node.attrs.align || "center");
|
||||||
|
|
||||||
// Handle percentage width backward compat
|
// Handle percentage width backward compat
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Node, mergeAttributes } from "@tiptap/core";
|
|||||||
import { ResizableNodeView } from "./resizable-nodeview";
|
import { ResizableNodeView } from "./resizable-nodeview";
|
||||||
import type { ResizableNodeViewDirection } from "./resizable-nodeview";
|
import type { ResizableNodeViewDirection } from "./resizable-nodeview";
|
||||||
import { ReactNodeViewRenderer } from "@tiptap/react";
|
import { ReactNodeViewRenderer } from "@tiptap/react";
|
||||||
import { normalizeFileUrl } from "./media-utils";
|
import { normalizeFileUrl, syncAltBadge } from "./media-utils";
|
||||||
|
|
||||||
export type ExcalidrawResizeOptions = {
|
export type ExcalidrawResizeOptions = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
@@ -293,6 +293,8 @@ export const Excalidraw = Node.create<ExcalidrawOptions>({
|
|||||||
const container = nodeView.dom as HTMLElement;
|
const container = nodeView.dom as HTMLElement;
|
||||||
applyAlignment(container, align);
|
applyAlignment(container, align);
|
||||||
|
|
||||||
|
syncAltBadge(nodeView.wrapper, updatedNode.attrs.alt);
|
||||||
|
|
||||||
currentNode = updatedNode;
|
currentNode = updatedNode;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@@ -310,6 +312,8 @@ export const Excalidraw = Node.create<ExcalidrawOptions>({
|
|||||||
|
|
||||||
const dom = nodeView.dom as HTMLElement;
|
const dom = nodeView.dom as HTMLElement;
|
||||||
|
|
||||||
|
syncAltBadge(nodeView.wrapper, node.attrs.alt);
|
||||||
|
|
||||||
applyAlignment(dom, node.attrs.align || "center");
|
applyAlignment(dom, node.attrs.align || "center");
|
||||||
|
|
||||||
// Handle percentage width backward compat
|
// Handle percentage width backward compat
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from "@tiptap/core";
|
} from "@tiptap/core";
|
||||||
import { ResizableNodeView } from "../resizable-nodeview";
|
import { ResizableNodeView } from "../resizable-nodeview";
|
||||||
import type { ResizableNodeViewDirection } from "../resizable-nodeview";
|
import type { ResizableNodeViewDirection } from "../resizable-nodeview";
|
||||||
import { normalizeFileUrl } from "../media-utils";
|
import { normalizeFileUrl, syncAltBadge } from "../media-utils";
|
||||||
|
|
||||||
export type ImageResizeOptions = {
|
export type ImageResizeOptions = {
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
@@ -316,6 +316,8 @@ export const TiptapImage = Image.extend<ImageOptions>({
|
|||||||
const container = nodeView.dom as HTMLElement;
|
const container = nodeView.dom as HTMLElement;
|
||||||
applyAlignment(container, align);
|
applyAlignment(container, align);
|
||||||
|
|
||||||
|
syncAltBadge(nodeView.wrapper, updatedNode.attrs.alt);
|
||||||
|
|
||||||
currentNode = updatedNode;
|
currentNode = updatedNode;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@@ -333,6 +335,8 @@ export const TiptapImage = Image.extend<ImageOptions>({
|
|||||||
|
|
||||||
const dom = nodeView.dom as HTMLElement;
|
const dom = nodeView.dom as HTMLElement;
|
||||||
|
|
||||||
|
syncAltBadge(nodeView.wrapper, node.attrs.alt);
|
||||||
|
|
||||||
// Apply initial alignment
|
// Apply initial alignment
|
||||||
applyAlignment(dom, node.attrs.align || "center");
|
applyAlignment(dom, node.attrs.align || "center");
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,27 @@ export function normalizeFileUrl(src: string): string {
|
|||||||
return src || "";
|
return src || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function syncAltBadge(wrapper: HTMLElement, alt: unknown): void {
|
||||||
|
const existing = wrapper.querySelector<HTMLElement>(
|
||||||
|
":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 = (
|
export type UploadFn = (
|
||||||
file: File,
|
file: File,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
|
|||||||
Reference in New Issue
Block a user