feat(collection/presentation): load themes

This commit is contained in:
Elian Doran 2025-10-16 11:35:15 +03:00
parent 8a86fdcd43
commit 7c2c89d4e2
No known key found for this signature in database
3 changed files with 45 additions and 20 deletions

View File

@ -2,7 +2,6 @@ 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, PresentationSlideBaseModel } from "./model";
import ShadowDom from "../../react/ShadowDom";
@ -10,19 +9,16 @@ import ActionButton from "../../react/ActionButton";
import "./index.css";
import { RefObject } from "preact";
import { openInCurrentNoteContext } from "../../../components/note_context";
import { useTriliumEvent } from "../../react/hooks";
import { useNoteLabelWithDefault, useTriliumEvent } from "../../react/hooks";
import { t } from "../../../services/i18n";
const stylesheets = [
slideBaseStylesheet,
slideThemeStylesheet,
slideCustomStylesheet
].map(stylesheet => stylesheet.replace(/:root/g, ":host"));
import { DEFAULT_THEME, loadPresentationTheme } from "./themes";
import FNote from "../../../entities/fnote";
export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) {
const [ presentation, setPresentation ] = useState<PresentationModel>();
const containerRef = useRef<HTMLDivElement>(null);
const [ api, setApi ] = useState<Reveal.Api>();
const stylesheets = usePresentationStylesheets(note);
function refresh() {
buildPresentationModel(note).then(setPresentation);
@ -36,7 +32,7 @@ export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) {
useLayoutEffect(refresh, [ note, noteIds ]);
return presentation && (
return presentation && stylesheets && (
<>
<ShadowDom
className="presentation-container"
@ -50,6 +46,23 @@ export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) {
)
}
function usePresentationStylesheets(note: FNote) {
const [ themeName ] = useNoteLabelWithDefault(note, "presentation:theme", DEFAULT_THEME);
const [ stylesheets, setStylesheets ] = useState<string[]>();
useLayoutEffect(() => {
loadPresentationTheme(themeName).then((themeStylesheet) => {
setStylesheets([
slideBaseStylesheet,
themeStylesheet,
slideCustomStylesheet
].map(stylesheet => stylesheet.replace(/:root/g, ":host")));
});
}, [ themeName ]);
return stylesheets;
}
function ButtonOverlay({ containerRef, api }: { containerRef: RefObject<HTMLDivElement>, api: Reveal.Api | undefined }) {
const [ isOverviewActive, setIsOverviewActive ] = useState(false);
useEffect(() => {

View File

@ -0,0 +1,10 @@
import { it, describe } from "vitest";
import { getPresentationThemes, loadPresentationTheme } from "./themes";
describe("Presentation themes", () => {
it("can load all themes", async () => {
const themes = getPresentationThemes();
await Promise.all(themes.map(theme => loadPresentationTheme(theme.id)));
});
});

View File

@ -1,3 +1,5 @@
export const DEFAULT_THEME = "white";
interface ThemeDefinition {
name: string;
loadTheme: () => Promise<typeof import("*.css?raw")>;
@ -10,39 +12,39 @@ const themes: Record<string, ThemeDefinition> = {
},
white: {
name: "White",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/white.css?raw")
},
beige: {
name: "Beige",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/beige.css?raw")
},
serif: {
name: "Serif",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/serif.css?raw")
},
simple: {
name: "Simple",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/simple.css?raw")
},
solarized: {
name: "Solarized",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/solarized.css?raw")
},
moon: {
name: "Moon",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/moon.css?raw")
},
dracula: {
name: "Dracula",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/dracula.css?raw")
},
sky: {
name: "Sky",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/sky.css?raw")
},
blood: {
name: "Blood",
loadTheme: () => import("reveal.js/dist/theme/black.css?raw")
loadTheme: () => import("reveal.js/dist/theme/blood.css?raw")
}
} as const;
@ -54,8 +56,8 @@ export function getPresentationThemes() {
}
export async function loadPresentationTheme(name: keyof typeof themes) {
const theme = themes[name];
if (!theme) return;
let theme = themes[name];
if (!theme) theme = themes[DEFAULT_THEME];
return (await theme.loadTheme()).default;
}