feat: enhance modal functionality and integrate new components
- Added keyframes and animation for a smooth scale-in effect in the Tailwind configuration. - Updated Image component to improve quality handling and style definitions. - Introduced WordViewer and WordViewerModal components for document viewing capabilities. - Enhanced Modal component to support embedded mode with customizable position and dimensions. - Integrated IframeModal across various pages for user assistance and content display. - Updated Content and Menu pages to utilize new components and improve user interaction. - Added utility function to retrieve public paths for resources.
This commit is contained in:
1 parent
13dd84a8a7
commit
4ce7520066
44 files changed
+1209
-100
No files matched your search
@@ -0,0 +1,215 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import mammoth from "mammoth";
|
||||
|
||||
interface WordViewerProps {
|
||||
/** Word 文档的路径 */
|
||||
docPath: string;
|
||||
/** 容器的类名 */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const WordViewer = ({ docPath, className = "" }: WordViewerProps) => {
|
||||
const [htmlContent, setHtmlContent] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [error, setError] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
const loadDocument = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
|
||||
// 获取 Word 文档
|
||||
const response = await fetch(docPath);
|
||||
if (!response.ok) {
|
||||
throw new Error("无法加载文档");
|
||||
}
|
||||
|
||||
// 转换为 ArrayBuffer
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
|
||||
// 使用 mammoth 转换为 HTML
|
||||
const result = await mammoth.convertToHtml({
|
||||
arrayBuffer: arrayBuffer,
|
||||
});
|
||||
|
||||
setHtmlContent(result.value);
|
||||
|
||||
// 如果有警告信息,可以在控制台输出
|
||||
if (result.messages.length > 0) {
|
||||
console.warn("文档转换警告:", result.messages);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("加载文档失败:", err);
|
||||
setError(err instanceof Error ? err.message : "加载文档失败");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
loadDocument();
|
||||
}, [docPath]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={`flex justify-center items-center ${className}`}>
|
||||
<div className="text-[#82B2D6] text-2xl font-bold">加载中...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className={`flex justify-center items-center ${className}`}>
|
||||
<div className="text-red-500 text-2xl font-bold">加载失败: {error}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`h-full flex flex-col p-4 ${className}`}>
|
||||
{/* 头部工具栏 */}
|
||||
{/* <div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-[#82B2D6] text-2xl font-bold">工作室活动文稿</h3>
|
||||
<a
|
||||
href={docPath}
|
||||
download="工作室活动文稿.docx"
|
||||
className="px-6 py-2 bg-[#82B2D6] text-white rounded-lg hover:bg-[#6a9bc4] transition-colors text-sm font-medium"
|
||||
>
|
||||
下载文档
|
||||
</a>
|
||||
</div> */}
|
||||
|
||||
{/* 文档内容区域 custom-scrollbar*/}
|
||||
<div className="flex-1 overflow-y-auto bg-white rounded-lg px-4 py-0 ">
|
||||
<div
|
||||
className="word-content"
|
||||
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
color: "#333",
|
||||
lineHeight: "1.8",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 内联样式 - 美化文档内容 */}
|
||||
<style>{`
|
||||
.word-content h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
margin: 1em 0 0.5em;
|
||||
color: #1a1a1a;
|
||||
border-bottom: 2px solid #82B2D6;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
|
||||
.word-content h2 {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
margin: 0.8em 0 0.4em;
|
||||
color: #2a2a2a;
|
||||
}
|
||||
|
||||
.word-content h3 {
|
||||
font-size: 1.3em;
|
||||
font-weight: bold;
|
||||
margin: 0.6em 0 0.3em;
|
||||
color: #3a3a3a;
|
||||
}
|
||||
|
||||
.word-content p {
|
||||
margin: 0.8em 0;
|
||||
text-align: justify;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
/* 表格内的段落不需要缩进 */
|
||||
.word-content table p {
|
||||
text-indent: 0;
|
||||
margin: 0.4em 0;
|
||||
}
|
||||
|
||||
.word-content img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
margin: 1.5em auto;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.word-content ul,
|
||||
.word-content ol {
|
||||
margin: 0.8em 0;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.word-content li {
|
||||
margin: 0.4em 0;
|
||||
}
|
||||
|
||||
.word-content table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 1em 0;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.word-content table th,
|
||||
.word-content table td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 0.8em;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.word-content table th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 表格第一列(标题列)固定宽度 */
|
||||
.word-content table tr td:first-child,
|
||||
.word-content table tr th:first-child {
|
||||
width: 200px;
|
||||
min-width: 200px;
|
||||
white-space: normal;
|
||||
font-weight: 600;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.word-content strong,
|
||||
.word-content b {
|
||||
font-weight: bold;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.word-content em,
|
||||
.word-content i {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.word-content a {
|
||||
color: #82B2D6;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.word-content a:hover {
|
||||
color: #6a9bc4;
|
||||
}
|
||||
|
||||
.word-content blockquote {
|
||||
border-left: 4px solid #82B2D6;
|
||||
padding-left: 1em;
|
||||
margin: 1em 0;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in new issue
Block a user