2026-04-18-19-37-56 - 四项编辑器体验优化:视频按钮位置、占位符文字居中、删除恢复尺寸、安全对齐
This commit is contained in:
@@ -356,11 +356,24 @@ export default function ReportEditor() {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const src = event.target?.result as string;
|
||||
const mw = placeholder.style.maxWidth || placeholder.style.width || '200px';
|
||||
const mh = placeholder.style.maxHeight || placeholder.style.height || '200px';
|
||||
placeholder.innerHTML = `
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<img src="${src}" style="max-width: 100%; height: auto; display: block; margin: 0 auto;" draggable="false">
|
||||
<img src="${src}" style="max-width:${mw};max-height:${mh};display:block;object-fit:contain;object-position:left top;" draggable="false">
|
||||
`;
|
||||
placeholder.classList.add('has-image');
|
||||
placeholder.style.border = 'none';
|
||||
placeholder.style.background = 'transparent';
|
||||
placeholder.style.width = 'auto';
|
||||
placeholder.style.height = 'auto';
|
||||
placeholder.style.lineHeight = 'normal';
|
||||
placeholder.style.maxWidth = mw;
|
||||
placeholder.style.maxHeight = mh;
|
||||
placeholder.style.textAlign = 'left';
|
||||
placeholder.style.verticalAlign = 'top';
|
||||
placeholder.style.justifyContent = 'flex-start';
|
||||
placeholder.style.alignItems = 'flex-start';
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
};
|
||||
@@ -409,12 +422,25 @@ export default function ReportEditor() {
|
||||
e.preventDefault();
|
||||
if (placeholder.classList.contains('has-image')) {
|
||||
placeholder.classList.remove('has-image');
|
||||
const w = parseInt(placeholder.style.maxWidth || placeholder.style.width || '0');
|
||||
const text = w > 0 && w < 80 ? '插图' : '插入/点击放置图片';
|
||||
placeholder.innerHTML = `
|
||||
<span class="delete-btn" contenteditable="false">×</span>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">插入/点击放置图片</span>
|
||||
<span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);display:block;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">${text}</span>
|
||||
`;
|
||||
placeholder.style.border = '1px dashed #cbd5e1';
|
||||
placeholder.style.background = '#f8fafc';
|
||||
const mw = placeholder.style.maxWidth;
|
||||
const mh = placeholder.style.maxHeight;
|
||||
if (mw) placeholder.style.width = mw;
|
||||
if (mh) {
|
||||
placeholder.style.height = mh;
|
||||
placeholder.style.lineHeight = mh;
|
||||
}
|
||||
placeholder.style.textAlign = 'center';
|
||||
placeholder.style.verticalAlign = 'middle';
|
||||
placeholder.style.justifyContent = 'center';
|
||||
placeholder.style.alignItems = 'center';
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
} else {
|
||||
@@ -532,6 +558,19 @@ export default function ReportEditor() {
|
||||
}
|
||||
};
|
||||
|
||||
const changeAlignment = (align: 'left' | 'center' | 'right' | 'justify') => {
|
||||
const sel = window.getSelection();
|
||||
if (!sel || !sel.rangeCount) return;
|
||||
let node = sel.getRangeAt(0).commonAncestorContainer;
|
||||
if (node.nodeType === Node.TEXT_NODE) node = node.parentNode as Node;
|
||||
const block = (node as HTMLElement).closest('p, div, td, h1, h2, h3, li');
|
||||
if (block) {
|
||||
(block as HTMLElement).style.textAlign = align;
|
||||
if (editorRef.current) contentRef.current = editorRef.current.innerHTML;
|
||||
saveDraftToStorage();
|
||||
}
|
||||
};
|
||||
|
||||
const insertTable = () => {
|
||||
editorRef.current?.focus();
|
||||
setTableModal({ isOpen: true, rows: '2', cols: '3' });
|
||||
@@ -1413,9 +1452,9 @@ export default function ReportEditor() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-1 pr-3 mr-3 border-r border-border">
|
||||
<button onClick={() => execCmd('justifyLeft')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="左对齐"><AlignLeft size={16} /></button>
|
||||
<button onClick={() => execCmd('justifyCenter')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="居中"><AlignCenter size={16} /></button>
|
||||
<button onClick={() => execCmd('justifyRight')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="右对齐"><AlignRight size={16} /></button>
|
||||
<button onMouseDown={(e) => e.preventDefault()} onClick={() => changeAlignment('left')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="左对齐"><AlignLeft size={16} /></button>
|
||||
<button onMouseDown={(e) => e.preventDefault()} onClick={() => changeAlignment('center')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="居中"><AlignCenter size={16} /></button>
|
||||
<button onMouseDown={(e) => e.preventDefault()} onClick={() => changeAlignment('right')} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="右对齐"><AlignRight size={16} /></button>
|
||||
</div>
|
||||
<div className="flex gap-1">
|
||||
<button onClick={insertTable} className="w-9 h-9 flex items-center justify-center rounded-lg hover:bg-white text-text-muted hover:text-text-main transition-colors" title="表格"><Table size={16} /></button>
|
||||
@@ -1821,13 +1860,6 @@ export default function ReportEditor() {
|
||||
/>
|
||||
|
||||
<div className="flex gap-2 overflow-x-auto pb-2 no-scrollbar items-center">
|
||||
<button
|
||||
onClick={() => videoInputRef.current?.click()}
|
||||
className="shrink-0 w-24 h-[68px] flex flex-col items-center justify-center gap-1 border-2 border-dashed border-border rounded-xl hover:border-accent hover:bg-slate-50 transition-all text-text-muted hover:text-accent"
|
||||
>
|
||||
<Video size={18} />
|
||||
<span className="text-[10px] font-bold">上传视频</span>
|
||||
</button>
|
||||
{videos.map((v, i) => (
|
||||
<div
|
||||
key={v.id}
|
||||
@@ -1853,6 +1885,13 @@ export default function ReportEditor() {
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
onClick={() => videoInputRef.current?.click()}
|
||||
className="shrink-0 w-24 h-[68px] flex flex-col items-center justify-center gap-1 border-2 border-dashed border-border rounded-xl hover:border-accent hover:bg-slate-50 transition-all text-text-muted hover:text-accent"
|
||||
>
|
||||
<Video size={18} />
|
||||
<span className="text-[10px] font-bold">上传视频</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{currentVideoIndex !== -1 && videos.length > 0 && (
|
||||
@@ -1996,14 +2035,14 @@ export default function ReportEditor() {
|
||||
const id = 'ph_' + Date.now();
|
||||
let html: string;
|
||||
if (inTable) {
|
||||
const styleStr = 'display:flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;background:#f8fafc;cursor:pointer;width:100%;height:100%;max-width:200px;max-height:200px;min-height:60px;margin:0 auto;';
|
||||
html = `<div id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false"${modeAttr} style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;">${hintText}</span></div>`;
|
||||
const styleStr = 'position:relative;display:flex;align-items:center;justify-content:center;border:1px dashed #cbd5e1;background:#f8fafc;cursor:pointer;width:100%;height:100%;max-width:200px;max-height:200px;min-height:60px;margin:0 auto;';
|
||||
html = `<div id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false"${modeAttr} style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);display:block;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">${hintText}</span></div>`;
|
||||
} else {
|
||||
let styleStr = 'display:inline-block;text-align:center;border:1px dashed #cbd5e1;background:#f8fafc;vertical-align:middle;margin:0 4px;cursor:pointer;position:relative;';
|
||||
styleStr += `width:${w}px;height:${h}px;max-width:${w}px;max-height:${h}px;line-height:${h}px;`;
|
||||
const showShortText = w > 0 && w < 80;
|
||||
const text = showShortText ? '插图' : hintText;
|
||||
html = `<span id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false"${modeAttr} style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;display:inline-block;vertical-align:middle;line-height:normal;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">${text}</span></span>​`;
|
||||
html = `<span id="${id}" class="image-placeholder" data-placeholder="true" contenteditable="false"${modeAttr} style="${styleStr}"><span class="delete-btn" contenteditable="false">×</span><span class="placeholder-text" style="color:#94a3b8;font-size:11px;pointer-events:none;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);display:block;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;">${text}</span></span>​`;
|
||||
}
|
||||
execCmd('insertHTML', html);
|
||||
setPlaceholderModal({...placeholderModal, isOpen: false});
|
||||
|
||||
Reference in New Issue
Block a user