diff --git a/app/(presentation)/presentation/layout.jsx b/app/(presentation)/presentation/layout.jsx
index f85fd44..368a3b2 100644
--- a/app/(presentation)/presentation/layout.jsx
+++ b/app/(presentation)/presentation/layout.jsx
@@ -1,6 +1,5 @@
import Context from "@/context/Context";
-
export default function RootLayout({ children }) {
return (
diff --git a/components/presentation/Presentation.css b/components/presentation/Presentation.css
new file mode 100644
index 0000000..df4d5c6
--- /dev/null
+++ b/components/presentation/Presentation.css
@@ -0,0 +1,121 @@
+.reveal-container {
+ height: 100vh;
+ width: 100%;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 1000;
+ background: black;
+}
+
+.reveal-container .reveal {
+ height: 100% !important;
+ width: 100% !important;
+}
+
+.reveal-container .reveal .slides {
+ height: 100% !important;
+}
+
+.reveal-container .reveal .slides section {
+ height: 100% !important;
+ display: flex !important;
+ flex-direction: column !important;
+ justify-content: center !important;
+ align-items: center !important;
+ text-align: center !important;
+ padding: 2rem !important;
+ color: white !important;
+}
+
+.reveal-container .reveal .slides section h1,
+.reveal-container .reveal .slides section h2,
+.reveal-container .reveal .slides section h3,
+.reveal-container .reveal .slides section h4,
+.reveal-container .reveal .slides section h5,
+.reveal-container .reveal .slides section h6 {
+ margin-bottom: 1rem !important;
+ color: white !important;
+}
+
+.reveal-container .reveal .slides section p {
+ margin-bottom: 0.5rem !important;
+ line-height: 1.6 !important;
+ color: white !important;
+}
+
+.reveal-container .reveal .slides section ul,
+.reveal-container .reveal .slides section ol {
+ text-align: left !important;
+ margin: 1rem 0 !important;
+ color: white !important;
+}
+
+.reveal-container .reveal .slides section li {
+ margin-bottom: 0.5rem !important;
+ color: white !important;
+}
+
+.reveal-container .reveal .slides section code {
+ background: #333 !important;
+ color: #fff !important;
+ padding: 0.2rem 0.4rem !important;
+ border-radius: 3px !important;
+ font-family: 'Courier New', monospace !important;
+}
+
+.reveal-container .reveal .slides section pre {
+ background: #333 !important;
+ color: #fff !important;
+ padding: 1rem !important;
+ border-radius: 5px !important;
+ text-align: left !important;
+ overflow-x: auto !important;
+}
+
+.reveal-container .reveal .slides section blockquote {
+ border-left: 4px solid #666 !important;
+ padding-left: 1rem !important;
+ margin: 1rem 0 !important;
+ text-align: left !important;
+ color: #ccc !important;
+}
+
+.reveal-container .reveal .slides section table {
+ border-collapse: collapse !important;
+ width: 100% !important;
+ margin: 1rem 0 !important;
+ color: white !important;
+}
+
+.reveal-container .reveal .slides section th,
+.reveal-container .reveal .slides section td {
+ border: 1px solid #666 !important;
+ padding: 0.5rem !important;
+ text-align: left !important;
+ color: white !important;
+}
+
+.reveal-container .reveal .slides section th {
+ background: #444 !important;
+}
+
+.reveal-container .reveal .slides section img {
+ max-width: 100% !important;
+ height: auto !important;
+ margin: 1rem 0 !important;
+}
+
+.reveal-container .reveal .slides section .btn {
+ display: inline-block !important;
+ padding: 0.5rem 1rem !important;
+ background: #007bff !important;
+ color: white !important;
+ text-decoration: none !important;
+ border-radius: 0.25rem !important;
+ margin: 0.5rem !important;
+}
+
+.reveal-container .reveal .slides section .btn:hover {
+ background: #0056b3 !important;
+}
diff --git a/components/presentation/Presentation.jsx b/components/presentation/Presentation.jsx
index e320fa2..cd11765 100644
--- a/components/presentation/Presentation.jsx
+++ b/components/presentation/Presentation.jsx
@@ -1,153 +1,146 @@
'use client';
-import { useEffect, useRef } from 'react';
+import { useEffect, useRef, useState, useCallback, useMemo } from 'react';
import Reveal from 'reveal.js';
import 'reveal.js/dist/reveal.css';
import 'reveal.js/dist/theme/black.css';
import { marked } from 'marked';
+import './Presentation.css';
+
+// Reveal.js配置
+const REVEAL_CONFIG = {
+ hash: true,
+ transition: 'slide',
+ transitionSpeed: 'default',
+ backgroundTransition: 'fade',
+ controls: true,
+ progress: true,
+ center: true,
+ touch: true,
+ loop: false,
+ rtl: false,
+ navigationMode: 'default',
+ shuffle: false,
+ fragments: true,
+ fragmentInURL: false,
+ embedded: false,
+ help: true,
+ showNotes: false,
+ autoPlayMedia: null,
+ preloadIframes: null,
+ autoSlide: 0,
+ autoSlideStoppable: true,
+ autoSlideMethod: Reveal.navigateNext,
+ defaultTiming: null,
+ mouseWheel: false,
+ hideInactiveCursor: true,
+ hideCursorTime: 5000,
+ previewLinks: false,
+ postMessage: true,
+ postMessageEvents: false,
+ focusBodyOnPageVisibilityChange: true,
+ viewDistance: 3,
+ mobileViewDistance: 2,
+ display: 'block',
+ hideAnchorsOnUrl: false,
+ plugins: []
+};
+
+// 配置marked解析器(只配置一次)
+marked.setOptions({
+ breaks: true,
+ gfm: true,
+ headerIds: false,
+ mangle: false,
+});
export default function Presentation({ data }) {
const deckRef = useRef(null);
const revealRef = useRef(null);
+ const [mounted, setMounted] = useState(false);
+ const [error, setError] = useState(null);
+ // 客户端挂载检测
useEffect(() => {
- if (!data) return;
+ setMounted(true);
+ }, []);
- // 配置 marked 解析器
- marked.setOptions({
- breaks: true,
- gfm: true,
- headerIds: false,
- mangle: false,
- });
-
- // 初始化 Reveal.js
- if (revealRef.current) {
- revealRef.current.destroy();
- }
-
- revealRef.current = new Reveal(deckRef.current, {
- hash: true,
- transition: 'slide',
- transitionSpeed: 'default',
- backgroundTransition: 'fade',
- controls: true,
- progress: true,
- center: true,
- touch: true,
- loop: false,
- rtl: false,
- navigationMode: 'default',
- shuffle: false,
- fragments: true,
- fragmentInURL: false,
- embedded: false,
- help: true,
- showNotes: false,
- autoPlayMedia: null,
- preloadIframes: null,
- autoSlide: 0,
- autoSlideStoppable: true,
- autoSlideMethod: Reveal.navigateNext,
- defaultTiming: null,
- mouseWheel: false,
- hideInactiveCursor: true,
- hideCursorTime: 5000,
- previewLinks: false,
- postMessage: true,
- postMessageEvents: false,
- focusBodyOnPageVisibilityChange: true,
- viewDistance: 3,
- mobileViewDistance: 2,
- display: 'block',
- hideAnchorsOnUrl: false,
- plugins: []
- });
-
- revealRef.current.initialize();
-
- // 在Reveal.js初始化后,更新slides内容
- setTimeout(() => {
- if (deckRef.current) {
- const slides = parseMarkdownToSlides(data);
- const slidesContainer = deckRef.current.querySelector('.slides');
- if (slidesContainer) {
- slidesContainer.innerHTML = slides;
- }
- }
- }, 100);
-
- // 清理函数
- return () => {
- if (revealRef.current) {
- revealRef.current.destroy();
- }
- };
- }, [data]);
-
- // 将数据解析为幻灯片
- const parseMarkdownToSlides = (data) => {
+ // 解析Markdown内容为幻灯片
+ const parseMarkdownToSlides = useCallback((data) => {
if (!data) {
return ` 暂无内容 内容解析失败,请检查数据格式演示文稿
解析错误
${data.subtitle}
` : ''} - ${data.description ? `${data.subtitle}
` : ''} + ${data.description ? `${item.item_subtitle}
`); } - // 描述 if (item.item_description) { slideContent.push(`