import { ViewModeProps } from "../interface"; import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks"; import Reveal from "reveal.js"; import slideBaseStylesheet from "reveal.js/dist/reveal.css?raw"; import slideThemeStylesheet from "reveal.js/dist/theme/black.css?raw"; import slideCustomStylesheet from "./slidejs.css?raw"; import { buildPresentationModel, PresentationModel, PresentationSlideModel } from "./model"; import ShadowDom from "../../react/ShadowDom"; import ActionButton from "../../react/ActionButton"; import "./index.css"; import { RefObject } from "preact"; import { openInCurrentNoteContext } from "../../../components/note_context"; import { useTriliumEvent } from "../../react/hooks"; const stylesheets = [ slideBaseStylesheet, slideThemeStylesheet, slideCustomStylesheet ].map(stylesheet => stylesheet.replace(/:root/g, ":host")); export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) { const [ presentation, setPresentation ] = useState(); const containerRef = useRef(null); const apiRef = useRef(null); function refresh() { buildPresentationModel(note).then(setPresentation); } useTriliumEvent("entitiesReloaded", ({ loadResults }) => { if (loadResults.getNoteIds().find(noteId => noteIds.includes(noteId))) { console.log("Needs reload!"); refresh(); } }); useLayoutEffect(refresh, [ note, noteIds ]); return presentation && ( <> {stylesheets.map(stylesheet => )} ) } function ButtonOverlay({ containerRef, apiRef }: { containerRef: RefObject, apiRef: RefObject }) { return (
{ const currentSlide = apiRef.current?.getCurrentSlide(); const noteId = getNoteIdFromSlide(currentSlide); if (noteId) { openInCurrentNoteContext(e, noteId); } }} /> containerRef.current?.requestFullscreen()} />
) } function Presentation({ presentation, apiRef: externalApiRef } : { presentation: PresentationModel, apiRef: RefObject }) { const containerRef = useRef(null); const apiRef = useRef(null); const isFirstRenderRef = useRef(true); useEffect(() => { if (apiRef.current || !containerRef.current) return; const api = new Reveal(containerRef.current, { transition: "slide", embedded: true, keyboardCondition(event) { // Full-screen requests sometimes fail, we rely on the UI button instead. if (event.key === "f") { return false; } return true; }, }); externalApiRef.current = apiRef.current; api.initialize().then(() => { apiRef.current = api; }); return () => { api.destroy(); apiRef.current = null; } }, [ ]); useEffect(() => { if (!isFirstRenderRef.current) { apiRef.current?.sync(); } isFirstRenderRef.current = false; }, [ presentation ]); return (
{presentation.slides?.map(slide => ( ))}
) } function Slide({ slide }: { slide: PresentationSlideModel }) { if (!slide.verticalSlides) { // Normal slide. return
; } else { // Slide with sub notes (show as vertical slides). return (
{slide.verticalSlides.map((slide) => (
))}
) } } function getNoteIdFromSlide(slide: HTMLElement | undefined) { if (!slide) return; return slide.dataset.noteId; }