import React, { useMemo, useState } from 'react'; import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; import { Sparkles } from 'lucide-react'; import { version } from '../../package.json'; import changelogRaw from '../../CHANGELOG.md?raw'; import { useAuthStore } from '../store/authStore'; function renderInline(text: string): React.ReactNode[] { const parts = text.split(/(\*\*[^*]+\*\*|\*[^*]+\*|`[^`]+`)/g); return parts.map((part, i) => { if (part.startsWith('**') && part.endsWith('**')) return {part.slice(2, -2)}; if (part.startsWith('*') && part.endsWith('*')) return {part.slice(1, -1)}; if (part.startsWith('`') && part.endsWith('`')) return {part.slice(1, -1)}; return part; }); } interface Props { onClose: () => void; } export default function ChangelogModal({ onClose }: Props) { const { t } = useTranslation(); const [dontShow, setDontShow] = useState(false); const setShowChangelogOnUpdate = useAuthStore(s => s.setShowChangelogOnUpdate); const setLastSeenChangelogVersion = useAuthStore(s => s.setLastSeenChangelogVersion); const currentVersionData = useMemo(() => { const blocks = changelogRaw.split(/\n(?=## \[)/).filter((b: string) => b.startsWith('## [')); const block = blocks.find((b: string) => b.startsWith(`## [${version}]`)); if (!block) return null; const lines = block.split('\n'); const match = lines[0].match(/## \[([^\]]+)\](?:\s*-\s*(.+))?/); const body = lines.slice(1).join('\n').trim(); return { version: match?.[1] ?? version, date: match?.[2] ?? '', body }; }, []); const handleClose = () => { if (dontShow) setShowChangelogOnUpdate(false); setLastSeenChangelogVersion(version); onClose(); }; if (!currentVersionData) return null; return createPortal( <>
{t('changelog.modalTitle')} — v{version} {currentVersionData.date && ( {currentVersionData.date} )}
{currentVersionData.body.split('\n').map((line, i) => { if (line.startsWith('### ')) return
{renderInline(line.slice(4))}
; if (line.startsWith('#### ')) return
{renderInline(line.slice(5))}
; if (line.startsWith('- ')) return
{renderInline(line.slice(2))}
; if (line.trim() === '') return null; return
{renderInline(line)}
; })}
, document.body ); }