fixes and better mermaid
This commit is contained in:
39
App.tsx
39
App.tsx
@ -27,12 +27,21 @@ import mermaid from 'mermaid';
|
|||||||
const extractJson = (text: string): any => {
|
const extractJson = (text: string): any => {
|
||||||
let jsonString = text.trim();
|
let jsonString = text.trim();
|
||||||
|
|
||||||
|
// Remove BOM and other invisible characters
|
||||||
|
jsonString = jsonString.replace(/^\uFEFF/, ''); // Remove BOM
|
||||||
|
jsonString = jsonString.replace(/^[\u200B-\u200D\uFEFF]/g, ''); // Remove zero-width characters
|
||||||
|
|
||||||
const fenceRegex = /^```(?:json)?\s*\n?(.*?)\n?\s*```$/s;
|
const fenceRegex = /^```(?:json)?\s*\n?(.*?)\n?\s*```$/s;
|
||||||
const match = jsonString.match(fenceRegex);
|
const match = jsonString.match(fenceRegex);
|
||||||
if (match && match[1]) {
|
if (match && match[1]) {
|
||||||
jsonString = match[1].trim();
|
jsonString = match[1].trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to parse directly first (most common case)
|
||||||
|
try {
|
||||||
|
return JSON.parse(jsonString);
|
||||||
|
} catch (directParseError) {
|
||||||
|
// If direct parsing fails, try the bracket extraction method
|
||||||
const lastBracket = jsonString.lastIndexOf('}');
|
const lastBracket = jsonString.lastIndexOf('}');
|
||||||
if (lastBracket === -1) {
|
if (lastBracket === -1) {
|
||||||
throw new Error("No closing brace '}' found in API response.");
|
throw new Error("No closing brace '}' found in API response.");
|
||||||
@ -57,7 +66,12 @@ const extractJson = (text: string): any => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const finalJsonString = jsonString.substring(firstBracket, lastBracket + 1);
|
const finalJsonString = jsonString.substring(firstBracket, lastBracket + 1);
|
||||||
|
try {
|
||||||
return JSON.parse(finalJsonString);
|
return JSON.parse(finalJsonString);
|
||||||
|
} catch (finalParseError) {
|
||||||
|
throw new Error(`JSON parsing failed: ${finalParseError.message}. Raw text: ${jsonString.substring(0, 100)}...`);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -184,15 +198,23 @@ const MermaidDiagram: React.FC<{ value: string; onChange: (value: string) => voi
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (value.trim()) {
|
if (value.trim()) {
|
||||||
const renderDiagram = async () => {
|
const renderDiagram = async () => {
|
||||||
try {
|
|
||||||
setError('');
|
|
||||||
renderCountRef.current += 1;
|
renderCountRef.current += 1;
|
||||||
const uniqueId = `mermaid-diagram-${renderCountRef.current}`;
|
const uniqueId = `mermaid-diagram-${renderCountRef.current}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setError('');
|
||||||
|
setDiagramHtml('');
|
||||||
const { svg } = await mermaid.render(uniqueId, value);
|
const { svg } = await mermaid.render(uniqueId, value);
|
||||||
setDiagramHtml(svg);
|
setDiagramHtml(svg);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : 'Mermaid diagram rendering failed');
|
setError(err instanceof Error ? err.message : 'Mermaid diagram rendering failed');
|
||||||
setDiagramHtml('');
|
setDiagramHtml('');
|
||||||
|
} finally {
|
||||||
|
// Clean up the DOM element that mermaid might have created
|
||||||
|
const element = document.getElementById(uniqueId);
|
||||||
|
if (element && element.parentNode) {
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
renderDiagram();
|
renderDiagram();
|
||||||
@ -202,6 +224,19 @@ const MermaidDiagram: React.FC<{ value: string; onChange: (value: string) => voi
|
|||||||
}
|
}
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
|
// Cleanup function to remove any lingering mermaid elements
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
// Clean up any mermaid elements that might be left in the DOM
|
||||||
|
const mermaidElements = document.querySelectorAll('[id^="mermaid-diagram-"]');
|
||||||
|
mermaidElements.forEach(element => {
|
||||||
|
if (element.parentNode) {
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -3,7 +3,7 @@ import { Exercise } from '../types';
|
|||||||
|
|
||||||
export const swaExercises7: Exercise[] = [
|
export const swaExercises7: Exercise[] = [
|
||||||
{
|
{
|
||||||
id: 'swa-6-1-ddd-tactical',
|
id: 'swa-7-1-ddd-tactical',
|
||||||
title: '6.1 - SWA - Domain-Driven Design (Tactical)',
|
title: '6.1 - SWA - Domain-Driven Design (Tactical)',
|
||||||
parts: [
|
parts: [
|
||||||
{
|
{
|
||||||
|
@ -512,9 +512,16 @@ CMD [ "serve", "-s", "dist", "-l", "8000" ]
|
|||||||
- **Real-time Preview**: Users can see their Mermaid diagram rendered as they type
|
- **Real-time Preview**: Users can see their Mermaid diagram rendered as they type
|
||||||
- **Error Handling**: Clear error messages for invalid Mermaid syntax
|
- **Error Handling**: Clear error messages for invalid Mermaid syntax
|
||||||
- **Unique Rendering**: Each render uses a unique ID to prevent caching issues that could cause diagrams to disappear
|
- **Unique Rendering**: Each render uses a unique ID to prevent caching issues that could cause diagrams to disappear
|
||||||
|
- **DOM Cleanup**: Proper cleanup of mermaid-generated DOM elements to prevent accumulation of leftover elements from failed renders
|
||||||
- **Consistent Styling**: Matches the existing design language of the application
|
- **Consistent Styling**: Matches the existing design language of the application
|
||||||
- **Accessibility**: Proper ARIA labels and semantic HTML structure
|
- **Accessibility**: Proper ARIA labels and semantic HTML structure
|
||||||
|
|
||||||
|
**Important Implementation Details**:
|
||||||
|
|
||||||
|
- **DOM Element Cleanup**: Added `finally` block in render function to clean up DOM elements that mermaid creates, especially important for failed renders which would otherwise leave orphaned elements
|
||||||
|
- **Component Unmount Cleanup**: Added cleanup `useEffect` to remove any lingering mermaid elements when component unmounts
|
||||||
|
- **Unique ID Generation**: Uses `useRef` counter to generate unique IDs for each render attempt, preventing mermaid's internal caching issues
|
||||||
|
|
||||||
This enhancement makes the application more suitable for software architecture exercises that require diagram creation and visualization.
|
This enhancement makes the application more suitable for software architecture exercises that require diagram creation and visualization.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
Reference in New Issue
Block a user