feat(client/print): render presentation without shadow DOM

This commit is contained in:
Elian Doran 2025-10-18 21:56:10 +03:00
parent e374b31a1c
commit f6d7ecab40
No known key found for this signature in database
8 changed files with 36 additions and 18 deletions

View File

@ -138,7 +138,7 @@ export default class DesktopLayout {
.child(new PromotedAttributesWidget())
.child(<SqlTableSchemas />)
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<NoteList media="screen" />)
.child(<SearchResult />)
.child(<SqlResults />)
.child(<ScrollPadding />)

View File

@ -66,6 +66,6 @@ export function applyModals(rootContainer: RootContainer) {
.child(<PopupEditorFormattingToolbar />)
.child(new PromotedAttributesWidget())
.child(new NoteDetailWidget())
.child(<NoteList displayOnlyCollections />))
.child(<NoteList media="screen" displayOnlyCollections />))
.child(<CallToActionDialog />);
}

View File

@ -154,7 +154,7 @@ export default class MobileLayout {
.filling()
.contentSized()
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<NoteList media="screen" />)
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)

View File

@ -32,6 +32,7 @@ function handleCollection(note: FNote) {
notePath={note.getBestNotePath().join("/")}
ntxId="print"
highlightedTokens={null}
media="print"
/>
);
}

View File

@ -1,4 +1,4 @@
import { allViewTypes, ViewModeProps, ViewTypeOptions } from "./interface";
import { allViewTypes, ViewModeMedia, ViewModeProps, ViewTypeOptions } from "./interface";
import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "../react/hooks";
import FNote from "../../entities/fnote";
import "./NoteList.css";
@ -22,9 +22,10 @@ interface NoteListProps {
displayOnlyCollections?: boolean;
isEnabled: boolean;
ntxId: string | null | undefined;
media: ViewModeMedia;
}
export default function NoteList<T extends object>(props: Pick<NoteListProps, "displayOnlyCollections">) {
export default function NoteList<T extends object>(props: Pick<NoteListProps, "displayOnlyCollections" | "media">) {
const { note, noteContext, notePath, ntxId } = useNoteContext();
const isEnabled = noteContext?.hasNoteList();
return <CustomNoteList note={note} isEnabled={!!isEnabled} notePath={notePath} ntxId={ntxId} {...props} />
@ -34,7 +35,7 @@ export function SearchNoteList<T extends object>(props: Omit<NoteListProps, "isE
return <CustomNoteList {...props} isEnabled={true} />
}
export function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, notePath, highlightedTokens, displayOnlyCollections, ntxId }: NoteListProps) {
export function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, notePath, highlightedTokens, displayOnlyCollections, ntxId, ...restProps }: NoteListProps) {
const widgetRef = useRef<HTMLDivElement>(null);
const viewType = useNoteViewType(note);
const noteIds = useNoteIds(note, viewType, ntxId);
@ -76,7 +77,8 @@ export function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable
note, noteIds, notePath,
highlightedTokens,
viewConfig: viewModeConfig[0],
saveConfig: viewModeConfig[1]
saveConfig: viewModeConfig[1],
...restProps
}
}

View File

@ -3,6 +3,8 @@ import FNote from "../../entities/fnote";
export const allViewTypes = ["list", "grid", "calendar", "table", "geoMap", "board", "presentation"] as const;
export type ViewTypeOptions = typeof allViewTypes[number];
export type ViewModeMedia = "screen" | "print";
export interface ViewModeProps<T extends object> {
note: FNote;
notePath: string;
@ -13,4 +15,5 @@ export interface ViewModeProps<T extends object> {
highlightedTokens: string[] | null | undefined;
viewConfig: T | undefined;
saveConfig(newConfig: T): void;
media: ViewModeMedia;
}

View File

@ -14,7 +14,7 @@ import { t } from "../../../services/i18n";
import { DEFAULT_THEME, loadPresentationTheme } from "./themes";
import FNote from "../../../entities/fnote";
export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) {
export default function PresentationView({ note, noteIds, media }: ViewModeProps<{}>) {
const [ presentation, setPresentation ] = useState<PresentationModel>();
const containerRef = useRef<HTMLDivElement>(null);
const [ api, setApi ] = useState<Reveal.Api>();
@ -33,18 +33,28 @@ export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) {
useLayoutEffect(refresh, [ note, noteIds ]);
return presentation && stylesheets && (
if (!presentation || !stylesheets) return;
const content = (
<>
<ShadowDom
className="presentation-container"
containerRef={containerRef}
>
{stylesheets.map(stylesheet => <style>{stylesheet}</style>)}
<Presentation presentation={presentation} setApi={setApi} />
</ShadowDom>
<ButtonOverlay containerRef={containerRef} api={api} />
{stylesheets.map(stylesheet => <style>{stylesheet}</style>)}
<Presentation presentation={presentation} setApi={setApi} />
</>
)
);
if (media === "screen") {
return (
<>
<ShadowDom
className="presentation-container"
containerRef={containerRef}
>{content}</ShadowDom>
<ButtonOverlay containerRef={containerRef} api={api} />
</>
)
} else {
// Shadow DOM doesn't work well with Reveal.js's PDF printing mechanism.
return content;
}
}
function usePresentationStylesheets(note: FNote) {
@ -128,6 +138,7 @@ function Presentation({ presentation, setApi } : { presentation: PresentationMod
const api = new Reveal(containerRef.current, {
transition: "slide",
embedded: true,
pdfMaxPagesPerSlide: 1,
keyboardCondition(event) {
// Full-screen requests sometimes fail, we rely on the UI button instead.
if (event.key === "f") {

View File

@ -54,6 +54,7 @@ export default function SearchResult() {
{state === SearchResultState.GOT_RESULTS && (
<SearchNoteList
media="screen"
note={note}
notePath={notePath}
highlightedTokens={highlightedTokens}