feat(Nextjs): Mermaid diagram layout & support added & refactor setting.json to settings.json
This commit is contained in:
parent
71ff6e6adf
commit
f09e24bacf
12 changed files with 1252 additions and 7 deletions
Binary file not shown.
|
|
@ -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') ||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
1109
servers/nextjs/package-lock.json
generated
1109
servers/nextjs/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Add table
Reference in a new issue