mirror of
https://github.com/zadam/trilium.git
synced 2025-10-19 14:49:01 +02:00
feat(collection/presentation): add button to edit slide
This commit is contained in:
parent
8a85edf2db
commit
502e9b86bc
@ -438,4 +438,22 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
|
||||
}
|
||||
}
|
||||
|
||||
export function openInCurrentNoteContext(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent | React.PointerEvent<HTMLCanvasElement> | null, notePath: string, viewScope?: ViewScope) {
|
||||
const ntxId = $(evt?.target as any)
|
||||
.closest("[data-ntx-id]")
|
||||
.attr("data-ntx-id");
|
||||
|
||||
const noteContext = ntxId ? appContext.tabManager.getNoteContextById(ntxId) : appContext.tabManager.getActiveContext();
|
||||
|
||||
if (noteContext) {
|
||||
noteContext.setNote(notePath, { viewScope }).then(() => {
|
||||
if (noteContext !== appContext.tabManager.getActiveContext()) {
|
||||
appContext.tabManager.activateNoteContext(noteContext.ntxId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
appContext.tabManager.openContextWithNote(notePath, { viewScope, activate: true });
|
||||
}
|
||||
}
|
||||
|
||||
export default NoteContext;
|
||||
|
@ -4,6 +4,7 @@ import appContext, { type NoteCommandData } from "../components/app_context.js";
|
||||
import froca from "./froca.js";
|
||||
import utils from "./utils.js";
|
||||
import { ALLOWED_PROTOCOLS } from "@triliumnext/commons";
|
||||
import { openInCurrentNoteContext } from "../components/note_context.js";
|
||||
|
||||
function getNotePathFromUrl(url: string) {
|
||||
const notePathMatch = /#(root[A-Za-z0-9_/]*)$/.exec(url);
|
||||
@ -316,21 +317,7 @@ function goToLinkExt(evt: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent
|
||||
viewScope
|
||||
});
|
||||
} else if (isLeftClick) {
|
||||
const ntxId = $(evt?.target as any)
|
||||
.closest("[data-ntx-id]")
|
||||
.attr("data-ntx-id");
|
||||
|
||||
const noteContext = ntxId ? appContext.tabManager.getNoteContextById(ntxId) : appContext.tabManager.getActiveContext();
|
||||
|
||||
if (noteContext) {
|
||||
noteContext.setNote(notePath, { viewScope }).then(() => {
|
||||
if (noteContext !== appContext.tabManager.getActiveContext()) {
|
||||
appContext.tabManager.activateNoteContext(noteContext.ntxId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
appContext.tabManager.openContextWithNote(notePath, { viewScope, activate: true });
|
||||
}
|
||||
openInCurrentNoteContext(evt, notePath, viewScope);
|
||||
}
|
||||
} else if (hrefLink) {
|
||||
const withinEditLink = $link?.hasClass("ck-link-actions__preview");
|
||||
|
@ -9,6 +9,7 @@ import ShadowDom from "../../react/ShadowDom";
|
||||
import ActionButton from "../../react/ActionButton";
|
||||
import "./index.css";
|
||||
import { RefObject } from "preact";
|
||||
import { openInCurrentNoteContext } from "../../../components/note_context";
|
||||
|
||||
const stylesheets = [
|
||||
slideBaseStylesheet,
|
||||
@ -19,6 +20,7 @@ const stylesheets = [
|
||||
export default function PresentationView({ note }: ViewModeProps<{}>) {
|
||||
const [ presentation, setPresentation ] = useState<PresentationModel>();
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const apiRef = useRef<Reveal.Api>(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
buildPresentationModel(note).then(setPresentation);
|
||||
@ -31,29 +33,41 @@ export default function PresentationView({ note }: ViewModeProps<{}>) {
|
||||
containerRef={containerRef}
|
||||
>
|
||||
{stylesheets.map(stylesheet => <style>{stylesheet}</style>)}
|
||||
<Presentation presentation={presentation} />
|
||||
<Presentation presentation={presentation} apiRef={apiRef} />
|
||||
</ShadowDom>
|
||||
<ButtonOverlay containerRef={containerRef} />
|
||||
<ButtonOverlay containerRef={containerRef} apiRef={apiRef} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function ButtonOverlay({ containerRef }: { containerRef: RefObject<HTMLDivElement> }) {
|
||||
function ButtonOverlay({ containerRef, apiRef }: { containerRef: RefObject<HTMLDivElement>, apiRef: RefObject<Reveal.Api> }) {
|
||||
return (
|
||||
<div className="presentation-button-bar">
|
||||
<ActionButton
|
||||
icon="bx bx-fullscreen" text="Start presentation"
|
||||
onClick={() => {
|
||||
containerRef.current?.requestFullscreen();
|
||||
icon="bx bx-edit"
|
||||
text="Edit this slide"
|
||||
onClick={e => {
|
||||
const currentSlide = apiRef.current?.getCurrentSlide();
|
||||
const noteId = getNoteIdFromSlide(currentSlide);
|
||||
|
||||
if (noteId) {
|
||||
openInCurrentNoteContext(e, noteId);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<ActionButton
|
||||
icon="bx bx-fullscreen"
|
||||
text="Start presentation"
|
||||
onClick={() => containerRef.current?.requestFullscreen()}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function Presentation({ presentation } : { presentation: PresentationModel }) {
|
||||
function Presentation({ presentation, apiRef: externalApiRef } : { presentation: PresentationModel, apiRef: RefObject<Reveal.Api> }) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const apiRef = useRef<Reveal.Api | null>(null);
|
||||
const apiRef = useRef<Reveal.Api>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (apiRef.current || !containerRef.current) return;
|
||||
@ -70,8 +84,9 @@ function Presentation({ presentation } : { presentation: PresentationModel }) {
|
||||
return true;
|
||||
},
|
||||
});
|
||||
externalApiRef.current = apiRef.current;
|
||||
apiRef.current.initialize().then(() => {
|
||||
console.log("Slide.js initialized.");
|
||||
// Initialization logic.
|
||||
});
|
||||
|
||||
return () => {
|
||||
@ -97,16 +112,21 @@ function Presentation({ presentation } : { presentation: PresentationModel }) {
|
||||
function Slide({ slide }: { slide: PresentationSlideModel }) {
|
||||
if (!slide.verticalSlides) {
|
||||
// Normal slide.
|
||||
return <section dangerouslySetInnerHTML={slide.content} />;
|
||||
return <section data-note-id={slide.noteId} dangerouslySetInnerHTML={slide.content} />;
|
||||
} else {
|
||||
// Slide with sub notes (show as vertical slides).
|
||||
return (
|
||||
<section>
|
||||
<section dangerouslySetInnerHTML={slide.content} />
|
||||
<section data-note-id={slide.noteId} dangerouslySetInnerHTML={slide.content} />
|
||||
{slide.verticalSlides.map((slide) => (
|
||||
<section dangerouslySetInnerHTML={slide.content} />
|
||||
<section data-note-id={slide.noteId} dangerouslySetInnerHTML={slide.content} />
|
||||
))}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function getNoteIdFromSlide(slide: HTMLElement | undefined) {
|
||||
if (!slide) return;
|
||||
return slide.dataset.noteId;
|
||||
}
|
||||
|
@ -2,12 +2,14 @@ import FNote from "../../../entities/fnote";
|
||||
|
||||
type DangerouslySetInnerHTML = { __html: string; };
|
||||
|
||||
export interface PresentationSlideModel {
|
||||
content: DangerouslySetInnerHTML;
|
||||
verticalSlides: PresentationVerticalSlideModel[] | undefined;
|
||||
/** A top-level slide with optional vertical slides. */
|
||||
export interface PresentationSlideModel extends PresentationSlideBaseModel {
|
||||
verticalSlides: PresentationSlideBaseModel[] | undefined;
|
||||
}
|
||||
|
||||
interface PresentationVerticalSlideModel {
|
||||
/** Either a top-level slide or a vertical slide. */
|
||||
interface PresentationSlideBaseModel {
|
||||
noteId: string;
|
||||
content: DangerouslySetInnerHTML;
|
||||
}
|
||||
|
||||
@ -22,6 +24,7 @@ export async function buildPresentationModel(note: FNote): Promise<PresentationM
|
||||
|
||||
for (const slideNote of slideNotes) {
|
||||
slides.push({
|
||||
noteId: slideNote.noteId,
|
||||
content: processContent(await slideNote.getContent() ?? ""),
|
||||
verticalSlides: await buildVerticalSlides(slideNote)
|
||||
})
|
||||
@ -30,13 +33,14 @@ export async function buildPresentationModel(note: FNote): Promise<PresentationM
|
||||
return { slides };
|
||||
}
|
||||
|
||||
async function buildVerticalSlides(parentSlideNote: FNote): Promise<undefined | PresentationVerticalSlideModel[]> {
|
||||
async function buildVerticalSlides(parentSlideNote: FNote): Promise<undefined | PresentationSlideBaseModel[]> {
|
||||
const children = await parentSlideNote.getChildNotes();
|
||||
if (!children.length) return;
|
||||
|
||||
const slides: PresentationVerticalSlideModel[] = [];
|
||||
const slides: PresentationSlideBaseModel[] = [];
|
||||
for (const child of children) {
|
||||
slides.push({
|
||||
noteId: child.noteId,
|
||||
content: processContent(await child.getContent())
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user