feat(Nextjs): Mermaid diagram layout & support added & refactor setting.json to settings.json

This commit is contained in:
shiva raj badu 2025-07-29 13:30:19 +05:45
parent 71ff6e6adf
commit f09e24bacf
No known key found for this signature in database
12 changed files with 1252 additions and 7 deletions

View file

@ -151,7 +151,7 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
'menu', 'dropdown', 'tooltip', // UI components
'editor', 'wysiwyg', // Editor components
'calendar', 'datepicker', // Date picker components
'slider', 'carousel', // Interactive components
'slider', 'carousel', 'flowchart', 'mermaid', 'diagram',
];
// Check if current element or any parent is in ignored list
@ -167,6 +167,9 @@ const TiptapTextReplacer: React.FC<TiptapTextReplacerProps> = ({
if (ignoredClassPatterns.some(pattern => className.includes(pattern))) {
return true;
}
if (currentElement.id.includes('mermaid')) {
return true;
}
// Check for specific attributes that indicate non-text content
if (currentElement.hasAttribute('contenteditable') ||

View file

@ -30,19 +30,19 @@ export async function GET() {
!file.startsWith('.') &&
!file.includes('.test.') &&
!file.includes('.spec.') &&
file !== 'setting.json'
file !== 'settings.json'
)
// Read settings.json if it exists
let settings: GroupSetting | null = null
const settingsPath = path.join(groupPath, 'setting.json')
const settingsPath = path.join(groupPath, 'settings.json')
try {
const settingsContent = await fs.readFile(settingsPath, 'utf-8')
settings = JSON.parse(settingsContent) as GroupSetting
} catch (settingsError) {
console.warn(`No settings.json found for group ${groupName} or invalid JSON`)
// Provide default settings if setting.json is missing or invalid
// Provide default settings if settings.json is missing or invalid
settings = {
description: `${groupName} presentation layouts`,
ordered: false,

View file

@ -61,7 +61,7 @@ export const useGroupLayoutLoader = (groupSlug: string): UseGroupLayoutLoaderRet
const groupLayouts: LayoutInfo[] = []
// Use settings from setting.json or provide defaults
// Use settings from settings.json or provide defaults
const groupSettings: GroupSetting = targetGroupData.settings ? targetGroupData.settings : {
description: `${targetGroupData.groupName} presentation layouts`,
ordered: false,

File diff suppressed because it is too large Load diff

View file

@ -44,6 +44,7 @@
"jsonrepair": "^3.12.0",
"lucide-react": "^0.447.0",
"marked": "^15.0.11",
"mermaid": "^11.9.0",
"next": "^14.2.14",
"next-themes": "^0.4.6",
"puppeteer": "^24.13.0",

View file

@ -0,0 +1,136 @@
import React, { useEffect, useRef } from 'react'
import * as z from "zod";
export const layoutId = 'type-mermaid-slide'
export const layoutName = 'Mermaid Chart Slide'
export const layoutDescription = 'A clean layout for displaying Mermaid diagrams with title and optional description.'
const typeMermaidSlideSchema = z.object({
title: z.string().min(3).max(50).default('Process Flow').meta({
description: "Main title of the slide",
}),
description: z.string().min(10).max(200).optional().meta({
description: "Optional description text to provide context for the diagram",
}),
mermaidCode: z.string().min(10).default(`graph LR
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Fix it]
D --> B
C --> E[End]`).meta({
description: "Mermaid diagram code, and it must be a graph LR",
}),
theme: z.enum(['default', 'dark', 'forest', 'neutral']).default('default').meta({
description: "Mermaid theme to use",
})
})
export const Schema = typeMermaidSlideSchema
export type TypeMermaidSlideData = z.infer<typeof typeMermaidSlideSchema>
interface TypeMermaidSlideLayoutProps {
data: Partial<TypeMermaidSlideData>
}
const TypeMermaidSlideLayout: React.FC<TypeMermaidSlideLayoutProps> = ({ data: slideData }) => {
const { title, description, mermaidCode, theme } = slideData;
const mermaidRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const loadMermaid = async () => {
try {
// Dynamically import mermaid
const mermaid = (await import('mermaid')).default;
// Initialize mermaid with the selected theme
mermaid.initialize({
startOnLoad: true,
theme: theme || 'default',
themeVariables: {
primaryColor: '#3b82f6',
primaryTextColor: '#1f2937',
primaryBorderColor: '#e5e7eb',
lineColor: '#6b7280',
secondaryColor: '#f3f4f6',
tertiaryColor: '#ffffff'
},
flowchart: {
useMaxWidth: true,
htmlLabels: true,
curve: 'basis'
}
});
if (mermaidRef.current && mermaidCode) {
// Clear previous content
mermaidRef.current.innerHTML = '';
// Create a unique ID for this diagram
const diagramId = `mermaid-${Date.now()}`;
// Render the diagram
const { svg } = await mermaid.render(diagramId, mermaidCode);
mermaidRef.current.innerHTML = svg;
}
} catch (error) {
console.error('Error loading or rendering mermaid:', error);
if (mermaidRef.current) {
mermaidRef.current.innerHTML = `
<div class="flex items-center justify-center h-full text-red-500">
<div class="text-center">
<p class="text-lg font-semibold">Error rendering diagram</p>
<p class="text-sm mt-2">Please check your Mermaid syntax</p>
</div>
</div>
`;
}
}
};
loadMermaid();
}, [mermaidCode, theme]);
return (
<div className="w-full rounded-sm max-w-[1280px] shadow-lg px-3 sm:px-12 lg:px-20 py-[10px] sm:py-[40px] lg:py-[86px] max-h-[720px] flex flex-col items-center justify-center aspect-video bg-white relative z-20 mx-auto">
{/* Title */}
{title && (
<h1 className="text-xl sm:text-2xl lg:text-[40px] leading-[36px] lg:leading-[48px] font-bold text-gray-900 mb-4 lg:mb-8 text-center">
{title}
</h1>
)}
{/* Description */}
{description && (
<p className="text-gray-700 text-sm sm:text-base lg:text-[20px] leading-[20px] lg:leading-[30px] font-normal mb-6 lg:mb-8 text-center max-w-4xl">
{description}
</p>
)}
{/* Mermaid Diagram Container */}
<div className="flex-1 w-full flex items-center justify-center">
<div
ref={mermaidRef}
className="w-full h-full flex items-center justify-center min-h-[300px] max-h-[400px] overflow-hidden"
style={{
// Ensure the SVG scales properly
maxWidth: '100%',
maxHeight: '100%'
}}
/>
</div>
{/* Fallback content if no mermaid code is provided */}
{!mermaidCode && (
<div className="flex-1 w-full flex items-center justify-center">
<div className="text-center text-gray-500">
<p className="text-lg font-semibold">No diagram to display</p>
<p className="text-sm mt-2">Please provide Mermaid diagram code</p>
</div>
</div>
)}
</div>
)
}
export default TypeMermaidSlideLayout