All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 10m8s
inline style 改为 CSS Module,z-index/圆角/关闭按钮与其他弹窗统一 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
import { useEffect, useState, useCallback } from 'react';
|
|
import { videoApi } from '../lib/api';
|
|
import styles from './AnnouncementModal.module.css';
|
|
|
|
interface Props {
|
|
/** If true, force show even if already read (for manual open) */
|
|
forceOpen?: boolean;
|
|
onClose?: () => void;
|
|
}
|
|
|
|
export function AnnouncementModal({ forceOpen, onClose }: Props) {
|
|
const [content, setContent] = useState('');
|
|
const [visible, setVisible] = useState(false);
|
|
|
|
useEffect(() => {
|
|
videoApi.getAnnouncement().then(({ data }) => {
|
|
if (data.enabled && data.announcement) {
|
|
setContent(data.announcement);
|
|
if (forceOpen || !data.is_read) {
|
|
setVisible(true);
|
|
}
|
|
}
|
|
}).catch(() => {});
|
|
}, [forceOpen]);
|
|
|
|
const handleClose = useCallback(() => {
|
|
videoApi.readAnnouncement().catch(() => {});
|
|
setVisible(false);
|
|
onClose?.();
|
|
}, [onClose]);
|
|
|
|
if (!visible || !content) return null;
|
|
|
|
return (
|
|
<div className={styles.overlay} onMouseDown={(e) => { if (e.target === e.currentTarget) handleClose(); }}>
|
|
<div className={styles.modal}>
|
|
<div className={styles.header}>
|
|
<span className={styles.title}>公告</span>
|
|
<button className={styles.closeBtn} onClick={handleClose}>
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
<line x1="18" y1="6" x2="6" y2="18" />
|
|
<line x1="6" y1="6" x2="18" y2="18" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div
|
|
className={styles.content}
|
|
dangerouslySetInnerHTML={{ __html: `<style>li{margin-left:16px}</style>${content}` }}
|
|
/>
|
|
<div className={styles.footer}>
|
|
<button className={styles.confirmBtn} onClick={handleClose}>
|
|
我知道了
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|