fix: handling of images fixed

This commit is contained in:
2026-02-10 22:59:05 +01:00
parent 6bbf13dd41
commit 77e117ae06
6 changed files with 61 additions and 10 deletions

View File

@@ -337,6 +337,28 @@
color: var(--vscode-descriptionForeground); color: var(--vscode-descriptionForeground);
} }
.media-preview-image {
max-width: 100%;
max-height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
}
.media-preview-image img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 4px;
}
.media-preview-image.has-error::after {
content: 'Image not found';
color: var(--vscode-descriptionForeground);
font-size: 14px;
}
.media-details { .media-details {
width: 320px; width: 320px;
display: flex; display: flex;

View File

@@ -672,11 +672,17 @@ const MediaEditor: React.FC<{ mediaId: string }> = ({ mediaId }) => {
<div className="editor-content media-editor"> <div className="editor-content media-editor">
<div className="media-preview"> <div className="media-preview">
{item.mimeType.startsWith('image/') ? ( {item.mimeType.startsWith('image/') ? (
<div className="media-preview-placeholder"> <div className="media-preview-image">
<svg width="64" height="64" viewBox="0 0 24 24" fill="currentColor" opacity="0.3"> <img
<path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/> src={`bds-media://${item.id}`}
</svg> alt={item.alt || item.originalName}
<span>{item.originalName}</span> onError={(e) => {
// Fallback to placeholder if image fails to load
const target = e.target as HTMLImageElement;
target.style.display = 'none';
target.parentElement?.classList.add('has-error');
}}
/>
</div> </div>
) : ( ) : (
<div className="media-preview-placeholder"> <div className="media-preview-placeholder">

View File

@@ -207,6 +207,13 @@
background-color: var(--vscode-input-background); background-color: var(--vscode-input-background);
border-radius: 4px; border-radius: 4px;
flex-shrink: 0; flex-shrink: 0;
overflow: hidden;
}
.media-thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
} }
.media-item-info { .media-item-info {

View File

@@ -580,10 +580,14 @@ const MediaList: React.FC = () => {
> >
{item.mimeType.startsWith('image/') ? ( {item.mimeType.startsWith('image/') ? (
<div className="media-thumbnail"> <div className="media-thumbnail">
{/* Would load actual image in production */} <img
<svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor" opacity="0.5"> src={`bds-media://${item.id}`}
<path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/> alt={item.alt || item.originalName}
</svg> onError={(e) => {
const target = e.target as HTMLImageElement;
target.style.display = 'none';
}}
/>
</div> </div>
) : ( ) : (
<div className="media-thumbnail"> <div className="media-thumbnail">

View File

@@ -22,6 +22,8 @@ export const WysiwygEditor: React.FC<WysiwygEditorProps> = ({
}) => { }) => {
// Track if we're updating from internal changes vs external prop changes // Track if we're updating from internal changes vs external prop changes
const isInternalChange = useRef(false); const isInternalChange = useRef(false);
// Track if we're in the middle of a programmatic content sync (shouldn't trigger onChange)
const isSyncingContent = useRef(false);
const lastExternalContent = useRef(content); const lastExternalContent = useRef(content);
const editor = useEditor({ const editor = useEditor({
@@ -55,6 +57,10 @@ export const WysiwygEditor: React.FC<WysiwygEditorProps> = ({
], ],
content, content,
onUpdate: ({ editor }) => { onUpdate: ({ editor }) => {
// Don't call onChange during programmatic content sync
if (isSyncingContent.current) {
return;
}
isInternalChange.current = true; isInternalChange.current = true;
const markdown = editor.storage.markdown.getMarkdown(); const markdown = editor.storage.markdown.getMarkdown();
onChange(markdown); onChange(markdown);
@@ -67,7 +73,13 @@ export const WysiwygEditor: React.FC<WysiwygEditorProps> = ({
if (editor && content !== lastExternalContent.current) { if (editor && content !== lastExternalContent.current) {
// This is an external change (e.g., switching posts) // This is an external change (e.g., switching posts)
if (!isInternalChange.current) { if (!isInternalChange.current) {
// Mark that we're syncing to prevent onChange from firing
isSyncingContent.current = true;
editor.commands.setContent(content); editor.commands.setContent(content);
// Reset sync flag after a microtask to ensure onUpdate has fired
Promise.resolve().then(() => {
isSyncingContent.current = false;
});
} }
lastExternalContent.current = content; lastExternalContent.current = content;
isInternalChange.current = false; isInternalChange.current = false;

View File

@@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: file: blob:; worker-src 'self' blob:; font-src 'self' data:;" /> <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: file: blob: bds-media:; worker-src 'self' blob:; font-src 'self' data:;" />
<title>Blogging Desktop Server</title> <title>Blogging Desktop Server</title>
</head> </head>
<body> <body>