Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions packages/happy-app/sources/components/markdown/MermaidRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import * as React from 'react';
import { View, Platform, Text } from 'react-native';
import { View, Platform, Text, Pressable } from 'react-native';
import { WebView } from 'react-native-webview';
import { StyleSheet, useUnistyles } from 'react-native-unistyles';
import { Typography } from '@/constants/Typography';
import { t } from '@/text';
import * as Clipboard from 'expo-clipboard';
import { Modal } from '@/modal';

// Style for Web platform
const webStyle: any = {
Expand All @@ -20,6 +22,26 @@ export const MermaidRenderer = React.memo((props: {
const { theme } = useUnistyles();
const [dimensions, setDimensions] = React.useState({ width: 0, height: 200 });
const [svgContent, setSvgContent] = React.useState<string | null>(null);
const [isHovered, setIsHovered] = React.useState(false);

const copyMermaidSource = React.useCallback(async () => {
try {
await Clipboard.setStringAsync(props.content);
Modal.alert(t('common.success'), t('markdown.mermaidCopied'), [{ text: t('common.ok'), style: 'cancel' }]);
} catch (error) {
console.error('Failed to copy mermaid source:', error);
Modal.alert(t('common.error'), t('markdown.copyFailed'), [{ text: t('common.ok'), style: 'cancel' }]);
}
}, [props.content]);

// Reusable copy button component
const renderCopyButton = (visible: boolean) => (
<View style={[style.copyButtonWrapper, visible && style.copyButtonWrapperVisible]}>
<Pressable style={style.copyButton} onPress={copyMermaidSource}>
<Text style={style.copyButtonText}>{t('common.copy')}</Text>
</Pressable>
</View>
);

const onLayout = React.useCallback((event: any) => {
const { width } = event.nativeEvent.layout;
Expand Down Expand Up @@ -93,12 +115,19 @@ export const MermaidRenderer = React.memo((props: {
}

return (
<View style={style.container}>
<View
style={style.container}
// @ts-ignore - Web only events
onMouseEnter={() => setIsHovered(true)}
// @ts-ignore - Web only events
onMouseLeave={() => setIsHovered(false)}
>
{/* @ts-ignore - Web only */}
<div
style={webStyle}
dangerouslySetInnerHTML={{ __html: svgContent }}
/>
{renderCopyButton(isHovered)}
</View>
);
}
Expand Down Expand Up @@ -164,6 +193,7 @@ export const MermaidRenderer = React.memo((props: {
}
}}
/>
{renderCopyButton(true)}
</View>
</View>
);
Expand All @@ -173,11 +203,13 @@ const style = StyleSheet.create((theme) => ({
container: {
marginVertical: 8,
width: '100%',
position: 'relative',
},
innerContainer: {
width: '100%',
backgroundColor: theme.colors.surfaceHighest,
borderRadius: 8,
position: 'relative',
},
loadingContainer: {
justifyContent: 'center',
Expand Down Expand Up @@ -215,4 +247,32 @@ const style = StyleSheet.create((theme) => ({
fontSize: 14,
lineHeight: 20,
},
copyButtonWrapper: {
position: 'absolute',
top: 8,
right: 8,
opacity: 0,
zIndex: 10,
elevation: 10,
pointerEvents: 'none',
},
copyButtonWrapperVisible: {
opacity: 1,
pointerEvents: 'auto',
},
copyButton: {
backgroundColor: theme.colors.surfaceHighest,
paddingHorizontal: 8,
paddingVertical: 4,
borderRadius: 4,
borderWidth: 1,
borderColor: theme.colors.divider,
cursor: 'pointer',
},
copyButtonText: {
...Typography.default(),
color: theme.colors.text,
fontSize: 12,
lineHeight: 16,
},
}));
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/ca.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ export const ca: TranslationStructure = {
codeCopied: 'Codi copiat',
copyFailed: 'Error al copiar',
mermaidRenderFailed: 'Error al renderitzar el diagrama mermaid',
mermaidCopied: 'Codi font de Mermaid copiat',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,7 @@ export const en: TranslationStructure = {
codeCopied: 'Code copied',
copyFailed: 'Failed to copy',
mermaidRenderFailed: 'Failed to render mermaid diagram',
mermaidCopied: 'Mermaid source copied',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ export const es: TranslationStructure = {
codeCopied: 'Código copiado',
copyFailed: 'Error al copiar',
mermaidRenderFailed: 'Error al renderizar el diagrama mermaid',
mermaidCopied: 'Código fuente de Mermaid copiado',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ export const it: TranslationStructure = {
codeCopied: 'Codice copiato',
copyFailed: 'Copia non riuscita',
mermaidRenderFailed: 'Impossibile renderizzare il diagramma mermaid',
mermaidCopied: 'Codice sorgente Mermaid copiato',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ export const ja: TranslationStructure = {
codeCopied: 'コードをコピーしました',
copyFailed: 'コピーに失敗しました',
mermaidRenderFailed: 'Mermaidダイアグラムのレンダリングに失敗しました',
mermaidCopied: 'Mermaidソースコードをコピーしました',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ export const pl: TranslationStructure = {
codeCopied: 'Kod skopiowany',
copyFailed: 'Błąd kopiowania',
mermaidRenderFailed: 'Nie udało się wyświetlić diagramu mermaid',
mermaidCopied: 'Kod źródłowy Mermaid skopiowany',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/pt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ export const pt: TranslationStructure = {
codeCopied: 'Código copiado',
copyFailed: 'Falha ao copiar',
mermaidRenderFailed: 'Falha ao renderizar diagrama mermaid',
mermaidCopied: 'Código fonte Mermaid copiado',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ export const ru: TranslationStructure = {
codeCopied: 'Код скопирован',
copyFailed: 'Ошибка копирования',
mermaidRenderFailed: 'Не удалось отобразить диаграмму mermaid',
mermaidCopied: 'Исходный код Mermaid скопирован',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/zh-Hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ export const zhHans: TranslationStructure = {
codeCopied: '代码已复制',
copyFailed: '复制失败',
mermaidRenderFailed: '渲染 mermaid 图表失败',
mermaidCopied: 'Mermaid 源码已复制',
},

artifacts: {
Expand Down
1 change: 1 addition & 0 deletions packages/happy-app/sources/text/translations/zh-Hant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ export const zhHant: TranslationStructure = {
codeCopied: '程式碼已複製',
copyFailed: '複製失敗',
mermaidRenderFailed: '渲染 mermaid 圖表失敗',
mermaidCopied: 'Mermaid 原始碼已複製',
},

artifacts: {
Expand Down