Merge pull request #1729 from mermaid-js/release-promotion

Release live editor
This commit is contained in:
Sidharth Vinod
2025-06-20 10:27:20 +05:30
committed by GitHub
8 changed files with 76 additions and 67 deletions
+1 -1
View File
@@ -2,6 +2,6 @@ MERMAID_DOMAIN=''
MERMAID_ANALYTICS_URL=''
MERMAID_RENDERER_URL='https://mermaid.ink'
MERMAID_KROKI_RENDERER_URL='https://kroki.io'
MERMAID_IS_ENABLED_MERMAID_CHART_LINKS=''
MERMAID_IS_ENABLED_MERMAID_CHART_LINKS='true'
# cp .env .env.local to make local changes
+3 -3
View File
@@ -49,6 +49,6 @@ jobs:
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
name: test-results
path: test-results/
retention-days: 7
+1 -1
View File
@@ -115,7 +115,7 @@
]
},
"engines": {
"node": ">=20.19.1"
"node": ">=20.19.0"
},
"packageManager": "pnpm@10.10.0+sha512.d615db246fe70f25dcfea6d8d73dee782ce23e2245e3c4f6f888249fb568149318637dca73c2c5c8ef2a4ca0d5657fb9567188bfab47f566d1ee6ce987815c39",
"pnpm": {
+16 -11
View File
@@ -32,20 +32,25 @@
<ExclamationCircleIcon class="size-6 text-destructive" aria-hidden="true" />
<div class="flex flex-col">
<p>Syntax error</p>
{#if env.isEnabledMermaidChartLinks}
<p class="text-xs text-white/60">Create a free account to repair with AI</p>
{#if env.isEnabledMermaidChartLinks && $stateStore.editorMode === 'code'}
<p class="text-xs text-white/60" data-testid={TID.aiHelpText}>
Create a free account to repair with AI
</p>
{/if}
</div>
</div>
<McWrapper>
<Button
variant="accent"
size="sm"
href={$urlsStore.mermaidChart({ medium: 'ai_repair' }).save}>
<MermaidChartIcon />
AI Repair
</Button>
</McWrapper>
{#if $stateStore.editorMode === 'code'}
<McWrapper>
<Button
variant="accent"
size="sm"
data-testid={TID.aiRepairButton}
href={$urlsStore.mermaidChart({ medium: 'ai_repair' }).save}>
<MermaidChartIcon />
AI Repair
</Button>
</McWrapper>
{/if}
</div>
<output class="max-h-32 overflow-auto bg-muted p-2" name="mermaid-error" for="editor">
<pre>{$stateStore.error?.toString()}</pre>
+2
View File
@@ -1,4 +1,6 @@
export const TID = {
aiHelpText: 'ai-help-text',
aiRepairButton: 'ai-repair-button',
copyMarkdown: 'copy-markdown',
diagramDocumentationButton: 'diagram-documentation-button',
downloadPNG: 'download-PNG',
+12 -51
View File
@@ -21,37 +21,6 @@
const commonParams = { utm_source: C.utmSource, utm_medium: 'banner_ad' } as const;
const randomTagLines: Taglines[] = [
{
label: 'Customize your layout and design in Mermaid Charts whiteboard!',
url: {
path: '/whiteboard',
params: { utm_campaign: 'whiteboard' }
}
},
{
label: 'Customize your layout and design in Mermaid Charts visual editor!',
url: {
path: '/whiteboard',
params: { utm_campaign: 'visual_editor' }
}
},
{
label: 'Customize your layout and design with Mermaid Charts GUI!',
url: {
path: '/whiteboard',
params: { utm_campaign: 'gui' }
}
},
{
label: 'Customize your layout and design in Mermaid Chart!',
url: {
path: '/whiteboard',
params: { utm_campaign: 'visual_editor_whiteboard_gui' }
}
}
];
let taglines: Taglines[] = [
{
label: 'Replace ChatGPT Pro, Mermaid.live, and Lucid Chart with Mermaid Chart',
@@ -66,33 +35,25 @@
path: '/landing',
params: { utm_campaign: 'team_collaboration' }
}
},
{
label: 'Customize your layout and design in Mermaid Charts visual editor!',
url: {
path: '/whiteboard',
params: { utm_campaign: 'visual_editor' }
}
}
];
const getRandomIndex = (array: unknown[]) => Math.floor(Math.random() * array.length);
const getSessionHeadlineIndex = (): number => {
const storageKey = 'mermaidBannerIndex';
const storedIndex = sessionStorage.getItem(storageKey);
if (storedIndex) {
return Number.parseInt(storedIndex, 10);
}
const randomIndex = getRandomIndex(randomTagLines);
sessionStorage.setItem(storageKey, randomIndex.toString());
return randomIndex;
};
const selectedHeadlineIndex = getSessionHeadlineIndex();
const currentBannerSet = [...taglines, randomTagLines[selectedHeadlineIndex]];
let index = $state(getRandomIndex(currentBannerSet));
let currentTagline = $derived(currentBannerSet[index]);
let index = $state(getRandomIndex(taglines));
let currentTagline = $derived(taglines[index]);
let shouldAnimate = $state(true);
const interval = setInterval(() => {
if (shouldAnimate) {
index = (index + 1) % currentBannerSet.length;
index = (index + 1) % taglines.length;
}
}, 5000);
@@ -117,9 +78,9 @@
class="col-start-1 row-start-1 flex items-center justify-center gap-4 no-underline"
in:fade={{ delay: 800 }}
out:fade={{ duration: 1000 }}>
<span class="text-sm tracking-wider text-white">{currentTagline.label}</span>
<span class="text-base tracking-wider text-white">{currentTagline.label}</span>
<Button
class="shrink-0 rounded-md bg-[#1E1A2E] px-3 py-1.5 text-sm font-semibold tracking-wide text-white hover:bg-[#261A56]">
class="shrink-0 rounded-md bg-[#1E1A2E] px-3 py-1.5 text-base font-semibold tracking-wide text-white hover:bg-[#261A56]">
Try now
</Button>
</a>
+34
View File
@@ -0,0 +1,34 @@
import { test } from './test';
test.describe('Error display tests', () => {
test('should show AI Repair button for syntax errors in Code tab', async ({ editPage }) => {
// Enter code with syntax error
await editPage.clearEditor();
await editPage.typeInEditor('graph TD\nA --> B -->');
// Verify error is displayed
await editPage.checkError('Syntax error');
// Verify AI Repair button and help text is shown in Code tab
await editPage.checkAIHelperVisibility(true);
});
test('should not show AI Repair button for errors in Config tab', async ({ editPage }) => {
// First enter valid diagram
await editPage.clearEditor();
await editPage.typeInEditor('graph TD\nA --> B');
// Switch to Config tab
await editPage.setEditorMode('Config');
// Enter invalid JSON in config
await editPage.clearEditor();
await editPage.typeInEditor('{\n "theme": "default",\n invalid json');
// Verify error is displayed
await editPage.checkError('Syntax error');
// Verify AI Repair button and help text is NOT shown in Config tab
await editPage.checkAIHelperVisibility(false);
});
});
+7
View File
@@ -103,6 +103,13 @@ export class EditorPage {
`Switch to ${theme === 'light' ? 'dark' : 'light'} theme`
);
}
async checkAIHelperVisibility(shouldBeVisible: boolean) {
const button = this.page.getByTestId(TID.aiRepairButton);
const helpText = this.page.getByTestId(TID.aiHelpText);
await expect(button)[shouldBeVisible ? 'toBeVisible' : 'toBeHidden']();
await expect(helpText)[shouldBeVisible ? 'toBeVisible' : 'toBeHidden']();
}
}
export const test = base.extend<{ editPage: EditorPage }>({