Add new Mermaid diagram examples and improve docs

Introduces new example components for basic, subgraph flowchart, simple ER, and API sequence Mermaid diagrams. Updates the documentation to provide clearer usage instructions, more examples, and improved structure. Refactors the Mermaid component to enhance zoom functionality, removes custom SVG message backgrounds, and adds a dedicated CSS file for zoom overlay theming.
This commit is contained in:
Jonathan Summers-Muir committed 2025-11-28 22:33:35 +08:00
1 parent b89b1d2b16
commit fcc4fef2c3
10 files changed
+276 -139

No files matched your search

+37 -4
View File
@@ -2601,13 +2601,46 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"mermaid-styling": {
name: "mermaid-styling",
"mermaid-flowchart-subgraph": {
name: "mermaid-flowchart-subgraph",
type: "components:example",
registryDependencies: ["mermaid"],
component: React.lazy(() => import("@/registry/default/example/mermaid-styling")),
component: React.lazy(() => import("@/registry/default/example/mermaid-flowchart-subgraph")),
source: "",
files: ["registry/default/example/mermaid-styling.tsx"],
files: ["registry/default/example/mermaid-flowchart-subgraph.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"mermaid-sequence-api": {
name: "mermaid-sequence-api",
type: "components:example",
registryDependencies: ["mermaid"],
component: React.lazy(() => import("@/registry/default/example/mermaid-sequence-api")),
source: "",
files: ["registry/default/example/mermaid-sequence-api.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"mermaid-er-simple": {
name: "mermaid-er-simple",
type: "components:example",
registryDependencies: ["mermaid"],
component: React.lazy(() => import("@/registry/default/example/mermaid-er-simple")),
source: "",
files: ["registry/default/example/mermaid-er-simple.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"mermaid-basic": {
name: "mermaid-basic",
type: "components:example",
registryDependencies: ["mermaid"],
component: React.lazy(() => import("@/registry/default/example/mermaid-basic")),
source: "",
files: ["registry/default/example/mermaid-basic.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
@@ -4,85 +4,123 @@ description: Render diagrams from text using Mermaid syntax.
component: true
---
<ComponentPreview name="mermaid-demo" peekCode wide />
## Installation
The Mermaid component is available from the `ui` package:
```tsx
import { Mermaid } from 'ui'
```
<ComponentPreview name="mermaid-basic" peekCode wide />
## Usage
### In MDX (Blog Posts)
The simplest way to add diagrams in blog posts is with a fenced code block using the `mermaid` language tag:
````mdx
```mermaid
flowchart LR
A[User Request] --> B{Authenticated?}
B -->|Yes| C[Process Request]
B -->|No| D[Return 401]
```
````
This is automatically rendered as a diagram. No imports needed.
### As a Component
For more control (custom className, disabling zoom), import and use the component directly:
```tsx
import { Mermaid } from 'ui'
```
```tsx
<Mermaid
chart={`
graph TD
A[Start] --> B[End]
export function MyDiagram() {
return (
<Mermaid
chart={`
flowchart LR
A[User Request] --> B{Authenticated?}
B -->|Yes| C[Process Request]
B -->|No| D[Return 401]
`}
/>
/>
)
}
```
## Examples
Use the component when you need to pass props like `className` or `zoomable`, conditionally render, or integrate with React logic.
### Supabase Architecture
## Flowcharts
<ComponentPreview name="mermaid-demo" />
Use `flowchart` or `graph` to create flowcharts with nodes and edges. Supports decision diamonds, different node shapes, and directional layouts (TD, LR, etc).
[View Mermaid flowchart docs](https://mermaid.js.org/syntax/flowchart.html)
---
### Flowchart
A basic request flow showing conditional branching with a decision node (`{}`), demonstrating how to visualize auth checks and data flow.
<ComponentPreview name="mermaid-flowchart" />
---
### With Subgraphs
### ER Diagram
Group related nodes into labeled subgraphs to show system boundaries. Useful for depicting frontend/backend separation or microservice architecture.
<ComponentPreview name="mermaid-er-diagram" />
<ComponentPreview name="mermaid-flowchart-subgraph" />
---
### Supabase Architecture
### Async Streaming (FDW)
Shows how client requests flow through the API Gateway to core services (Auth, PostgREST, Realtime) which all connect to PostgreSQL.
<ComponentPreview name="mermaid-sequence-async" />
---
### Sync Blocking (FDW)
<ComponentPreview name="mermaid-sequence-sync" />
---
<ComponentPreview name="mermaid-demo" />
### OAuth Authorization Flow
Illustrates the OAuth 2.0 authorization code flow, showing the handoff between a third-party app, your authorization endpoint, and Supabase Auth for token exchange.
<ComponentPreview name="mermaid-oauth-flow" />
## ER Diagrams
Use `erDiagram` to create entity-relationship diagrams showing database schemas. Great for documenting table relationships and foreign keys.
[View Mermaid ER diagram docs](https://mermaid.js.org/syntax/entityRelationshipDiagram.html)
A simple e-commerce schema showing cardinality between customers, orders, products, and line items using crow's foot notation.
<ComponentPreview name="mermaid-er-simple" />
### With Attributes
Include column definitions with types and constraints (PK, FK) to create more detailed schema documentation.
<ComponentPreview name="mermaid-er-diagram" />
## Sequence Diagrams
Use `sequenceDiagram` to show interactions between participants over time. Ideal for documenting API flows, authentication handshakes, or any request/response patterns.
[View Mermaid sequence diagram docs](https://mermaid.js.org/syntax/sequenceDiagram.html)
A typical authenticated API request showing JWT validation, database insert, and response flow between Client, API, Auth, and DB participants.
<ComponentPreview name="mermaid-sequence-api" />
### Async Streaming (FDW)
Shows how Foreign Data Wrappers can stream data asynchronously using bounded channels, with parallel execution indicated by the `par` block.
<ComponentPreview name="mermaid-sequence-async" />
### Sync Blocking (FDW)
Contrasts with async by showing traditional blocking FDW behavior where all rows are fetched and buffered before processing.
<ComponentPreview name="mermaid-sequence-sync" />
## Props
| Prop | Type | Description |
| ----------- | -------- | ------------------------------------ |
| `chart` | `string` | The Mermaid diagram definition |
| `className` | `string` | Optional CSS class for the container |
| Prop | Type | Default | Description |
| ----------- | --------- | ------- | ------------------------------------ |
| `chart` | `string` | — | The Mermaid diagram definition |
| `className` | `string` | — | Optional CSS class for the container |
| `zoomable` | `boolean` | `true` | Enable click-to-zoom on the diagram |
## Supported Diagram Types
## Learn More
Mermaid supports many diagram types including:
See the [Mermaid documentation](https://mermaid.js.org/intro/) for full syntax reference and additional diagram types.
- **Flowcharts** - `flowchart` or `graph`
- **Sequence Diagrams** - `sequenceDiagram`
- **Class Diagrams** - `classDiagram`
- **State Diagrams** - `stateDiagram-v2`
- **ER Diagrams** - `erDiagram`
- **Gantt Charts** - `gantt`
- **Pie Charts** - `pie`
- **Git Graphs** - `gitGraph`
```
See the [Mermaid documentation](https://mermaid.js.org/intro/) for full syntax reference.
```
@@ -0,0 +1,16 @@
import { Mermaid } from 'ui'
export default function MermaidBasic() {
return (
<Mermaid
chart={`
flowchart TD
A[Start] --> B{Is it working?}
B -->|Yes| C[Great!]
B -->|No| D[Debug]
D --> B
C --> E[End]
`}
/>
)
}
@@ -5,45 +5,25 @@ export default function MermaidDemo() {
<Mermaid
chart={`
flowchart TB
subgraph Client
App[Your Application]
end
Client[Your Application]
Gateway[API Gateway]
Auth[Auth]
API[PostgREST]
Realtime[Realtime]
PgBouncer[PgBouncer]
Postgres[(PostgreSQL)]
subgraph Gateway
Kong[Kong API Gateway]
end
subgraph Services
Auth[GoTrue<br/>Auth]
API[PostgREST<br/>REST API]
Realtime[Realtime<br/>WebSockets]
Storage[Storage API<br/>S3-compatible]
Meta[postgres-meta<br/>DB Management]
Functions[Deno<br/>Edge Functions]
GraphQL[pg_graphql<br/>GraphQL]
end
subgraph Data
Postgres[(PostgreSQL)]
Supavisor[Supavisor<br/>Connection Pooler]
end
App --> Kong
Kong --> Auth
Kong --> API
Kong --> Realtime
Kong --> Storage
Kong --> Meta
Kong --> Functions
Kong --> GraphQL
Auth --> Supavisor
API --> Supavisor
Realtime --> Supavisor
Storage --> Supavisor
Meta --> Supavisor
GraphQL --> Supavisor
Supavisor --> Postgres
Client --> Gateway
Client --> PgBouncer
Client <--> Realtime
Gateway --> Auth
Gateway --> API
Auth --> Postgres
API --> Postgres
Realtime <--> Postgres
PgBouncer --> Postgres
`}
/>
)
@@ -0,0 +1,14 @@
import { Mermaid } from 'ui'
export default function MermaidErSimple() {
return (
<Mermaid
chart={`
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE_ITEM : contains
PRODUCT ||--o{ LINE_ITEM : "ordered in"
`}
/>
)
}
@@ -0,0 +1,21 @@
import { Mermaid } from 'ui'
export default function MermaidFlowchartSubgraph() {
return (
<Mermaid
chart={`
flowchart LR
subgraph Frontend
A[React App] --> B[API Client]
end
subgraph Backend
C[Edge Functions] --> D[Database]
C --> E[Storage]
end
B --> C
`}
/>
)
}
@@ -0,0 +1,22 @@
import { Mermaid } from 'ui'
export default function MermaidSequenceApi() {
return (
<Mermaid
chart={`
sequenceDiagram
participant Client
participant API
participant Auth
participant DB
Client->>API: POST /api/data
API->>Auth: Validate JWT
Auth-->>API: Token valid
API->>DB: INSERT query
DB-->>API: Success
API-->>Client: 201 Created
`}
/>
)
}
+24
View File
@@ -1389,4 +1389,28 @@ export const examples: Registry = [
registryDependencies: ['mermaid'],
files: ['example/mermaid-oauth-flow.tsx'],
},
{
name: 'mermaid-flowchart-subgraph',
type: 'components:example',
registryDependencies: ['mermaid'],
files: ['example/mermaid-flowchart-subgraph.tsx'],
},
{
name: 'mermaid-sequence-api',
type: 'components:example',
registryDependencies: ['mermaid'],
files: ['example/mermaid-sequence-api.tsx'],
},
{
name: 'mermaid-er-simple',
type: 'components:example',
registryDependencies: ['mermaid'],
files: ['example/mermaid-er-simple.tsx'],
},
{
name: 'mermaid-basic',
type: 'components:example',
registryDependencies: ['mermaid'],
files: ['example/mermaid-basic.tsx'],
},
]
+22 -46
View File
@@ -1,6 +1,7 @@
'use client'
import 'react-medium-image-zoom/dist/styles.css'
import './mermaid-zoom.css'
import { useEffect, useRef, useState } from 'react'
import mermaid from 'mermaid'
@@ -42,7 +43,6 @@ const darkThemeVariables = {
clusterBorder: '#404040',
defaultLinkColor: '#3ecf8e',
edgeLabelBackground: '#171717',
// ER diagram specific
attributeBackgroundColorOdd: '#262626',
attributeBackgroundColorEven: '#171717',
rowOdd: '#262626',
@@ -85,7 +85,6 @@ const lightThemeVariables = {
clusterBorder: '#e5e5e5',
defaultLinkColor: '#3ecf8e',
edgeLabelBackground: '#ffffff',
// ER diagram specific
attributeBackgroundColorOdd: '#f5f5f5',
attributeBackgroundColorEven: '#ffffff',
rowOdd: '#f5f5f5',
@@ -129,6 +128,7 @@ export function Mermaid({ chart, className, zoomable = true }: MermaidProps) {
},
flowchart: {
useMaxWidth: false,
curve: 'linear',
},
er: {
useMaxWidth: false,
@@ -197,36 +197,6 @@ export function Mermaid({ chart, className, zoomable = true }: MermaidProps) {
rect.setAttribute('stroke', isPostgres ? '#336791' : isDark ? '#525252' : '#d4d4d4')
})
// Add pill backgrounds to message text (skip notes - they already have backgrounds)
const messageTexts = doc.querySelectorAll('.messageText')
messageTexts.forEach((text) => {
// Skip if there's already a sibling rect (notes have background rects)
const parent = text.parentElement
if (parent?.querySelector('rect')) return
const x = parseFloat(text.getAttribute('x') || '0')
const y = parseFloat(text.getAttribute('y') || '0')
const dy = text.getAttribute('dy')
// Parse dy (e.g., "1em" -> 16px)
const dyOffset = dy ? parseFloat(dy) * 16 : 0
const textContent = text.textContent || ''
const estimatedWidth = textContent.length * 9
const height = 28
const paddingX = 16
const rect = doc.createElementNS('http://www.w3.org/2000/svg', 'rect')
rect.setAttribute('x', String(x - estimatedWidth / 2 - paddingX))
rect.setAttribute('y', String(y + dyOffset - height / 2))
rect.setAttribute('width', String(estimatedWidth + paddingX * 2))
rect.setAttribute('height', String(height))
rect.setAttribute('rx', '14')
rect.setAttribute('fill', isDark ? '#262626' : '#f5f5f5')
rect.setAttribute('class', 'messageTextBg')
text.parentNode?.insertBefore(rect, text)
})
const serializer = new XMLSerializer()
const processedSvg = serializer.serializeToString(doc)
setSvg(processedSvg)
@@ -258,23 +228,29 @@ export function Mermaid({ chart, className, zoomable = true }: MermaidProps) {
)
}
const content = (
<div
ref={containerRef}
className={cn(
'my-6 flex justify-center rounded-lg border p-6 pb-8',
isDark ? 'bg-[#171717] border-[#333]' : 'bg-white border-[#e5e5e5]',
'[&_svg]:h-auto [&_svg]:max-w-full',
zoomable && 'cursor-zoom-in',
className
)}
dangerouslySetInnerHTML={{ __html: svg }}
/>
const containerClassName = cn(
'my-6 flex justify-center rounded-lg border p-6 pb-8',
isDark ? 'bg-[#171717] border-[#333]' : 'bg-white border-[#e5e5e5]',
className
)
if (zoomable) {
return <Zoom zoomMargin={40}>{content}</Zoom>
// Convert SVG to data URL for react-medium-image-zoom compatibility
const svgDataUrl = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svg)))}`
return (
<div ref={containerRef} className={containerClassName}>
<Zoom zoomMargin={40}>
<img src={svgDataUrl} alt="Mermaid diagram" className="h-auto max-w-full" />
</Zoom>
</div>
)
}
return content
return (
<div
ref={containerRef}
className={cn(containerClassName, '[&_svg]:h-auto [&_svg]:max-w-full')}
dangerouslySetInnerHTML={{ __html: svg }}
/>
)
}
@@ -0,0 +1,13 @@
@tailwind utilities;
@layer utilities {
[data-rmiz-modal-overlay='visible'] {
@apply !bg-white;
}
.dark [data-rmiz-modal-overlay='visible'],
[data-theme*='dark'] [data-rmiz-modal-overlay='visible'] {
@apply !bg-[#171717];
}
}