1
This commit is contained in:
124
src/components/common/LegalDocumentModal.tsx
Normal file
124
src/components/common/LegalDocumentModal.tsx
Normal file
@@ -0,0 +1,124 @@
|
||||
import { FileText } from 'lucide-react';
|
||||
|
||||
import type { PlatformTheme } from '../../../packages/shared/src/contracts/runtime';
|
||||
import type {
|
||||
LegalDocument,
|
||||
LegalDocumentBlock,
|
||||
} from './legalDocuments';
|
||||
import { UnifiedModal } from './UnifiedModal';
|
||||
|
||||
type LegalDocumentModalProps = {
|
||||
document: LegalDocument | null;
|
||||
open: boolean;
|
||||
platformTheme?: PlatformTheme;
|
||||
zIndexClassName?: string;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
function LegalRichText({ text }: { text: string }) {
|
||||
const parts = text.split(/(\*\*[^*]+\*\*)/gu);
|
||||
|
||||
return (
|
||||
<>
|
||||
{parts.map((part, index) => {
|
||||
const boldMatch = /^\*\*([^*]+)\*\*$/u.exec(part);
|
||||
if (boldMatch) {
|
||||
return (
|
||||
<strong
|
||||
key={`${index}:${part}`}
|
||||
className="font-black text-[var(--platform-text-strong)]"
|
||||
>
|
||||
{boldMatch[1]}
|
||||
</strong>
|
||||
);
|
||||
}
|
||||
|
||||
return part;
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function LegalDocumentBodyBlock({
|
||||
block,
|
||||
}: {
|
||||
block: LegalDocumentBlock;
|
||||
}) {
|
||||
if (block.type === 'heading') {
|
||||
const className =
|
||||
block.level === 2
|
||||
? 'mt-5 text-base font-black leading-7 text-[var(--platform-text-strong)] first:mt-0'
|
||||
: 'mt-4 text-sm font-black leading-6 text-[var(--platform-text-strong)] first:mt-0';
|
||||
|
||||
return <div className={className}>{block.text}</div>;
|
||||
}
|
||||
|
||||
if (block.type === 'list') {
|
||||
return (
|
||||
<ul className="mt-3 list-disc space-y-2 pl-5 text-sm leading-7 text-[var(--platform-text-base)]">
|
||||
{block.items.map((item, index) => (
|
||||
<li key={`${index}:${item}`}>
|
||||
<LegalRichText text={item} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<p className="mt-3 whitespace-pre-line text-sm leading-7 text-[var(--platform-text-base)]">
|
||||
<LegalRichText text={block.text} />
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
export function LegalDocumentModal({
|
||||
document,
|
||||
open,
|
||||
platformTheme,
|
||||
zIndexClassName,
|
||||
onClose,
|
||||
}: LegalDocumentModalProps) {
|
||||
return (
|
||||
<UnifiedModal
|
||||
open={open && Boolean(document)}
|
||||
title={document?.title ?? '法律信息'}
|
||||
onClose={onClose}
|
||||
size="md"
|
||||
closeLabel="关闭法律信息"
|
||||
zIndexClassName={zIndexClassName ?? 'z-[150]'}
|
||||
overlayClassName={`platform-theme ${
|
||||
platformTheme ? `platform-theme--${platformTheme}` : ''
|
||||
}`}
|
||||
panelClassName="platform-remap-surface rounded-t-[1.4rem] sm:rounded-[1.4rem]"
|
||||
headerClassName="items-center"
|
||||
bodyClassName="px-4 py-0 sm:px-5"
|
||||
footerClassName="justify-stretch sm:justify-end"
|
||||
footer={
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="platform-button platform-button--secondary min-h-0 w-full rounded-[0.9rem] px-4 py-2.5 text-sm sm:w-auto"
|
||||
>
|
||||
我知道了
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<div className="max-h-[min(64vh,34rem)] overflow-y-auto py-4 pr-1">
|
||||
<div className="mb-4 flex items-center gap-2 text-[var(--platform-cool-text)]">
|
||||
<FileText className="h-4 w-4" />
|
||||
<span className="text-xs font-black tracking-[0.2em]">
|
||||
LEGAL
|
||||
</span>
|
||||
</div>
|
||||
{document?.blocks.map((block, index) => (
|
||||
<LegalDocumentBodyBlock
|
||||
// 中文注释:法律文本没有稳定段落 id,用序号只限定在静态文档渲染列表内。
|
||||
key={`${block.type}:${index}`}
|
||||
block={block}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</UnifiedModal>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user