diff --git a/apps/server/src/services/export/zip.ts b/apps/server/src/services/export/zip.ts index a175241d8..8d8d2de07 100644 --- a/apps/server/src/services/export/zip.ts +++ b/apps/server/src/services/export/zip.ts @@ -2,11 +2,11 @@ import html from "html"; import dateUtils from "../date_utils.js"; -import path from "path"; +import path, { join } from "path"; import mimeTypes from "mime-types"; import mdService from "./markdown.js"; import packageInfo from "../../../package.json" with { type: "json" }; -import { getContentDisposition, escapeHtml, getResourceDir } from "../utils.js"; +import { getContentDisposition, escapeHtml, getResourceDir, isDev } from "../utils.js"; import protectedSessionService from "../protected_session.js"; import sanitize from "sanitize-filename"; import fs from "fs"; @@ -22,7 +22,7 @@ import type BBranch from "../../becca/entities/bbranch.js"; import type BNote from "../../becca/entities/bnote.js"; import type { Response } from "express"; import type { NoteMetaFile } from "../meta/note_meta.js"; -import cssContent from "@triliumnext/ckeditor5/content.css"; +//import cssContent from "@triliumnext/ckeditor5/content.css"; import { renderNoteForExport } from "../../share/content_renderer.js"; type RewriteLinksFn = (content: string, noteMeta: NoteMeta) => string; @@ -328,12 +328,13 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h throw new Error("Missing note path."); } - const cssUrl = `${"../".repeat(noteMeta.notePath.length - 1)}style.css`; + const basePath = "../".repeat(noteMeta.notePath.length - 1); const htmlTitle = escapeHtml(title); if (note) { - content = renderNoteForExport(note, branch); + content = renderNoteForExport(note, branch, basePath); } else { + const cssUrl = basePath + "style.css"; // element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809 content = ` @@ -518,6 +519,7 @@ ${markdownContent}`; return; } + let cssContent = getShareThemeAssets("css"); archive.append(cssContent, { name: cssMeta.dataFileName }); } @@ -629,6 +631,19 @@ async function exportToZipFile(noteId: string, format: "markdown" | "html", zipF log.info(`Exported '${noteId}' with format '${format}' to '${zipFilePath}'`); } +function getShareThemeAssets(extension: string) { + let path: string | undefined; + if (isDev) { + path = join(getResourceDir(), "..", "..", "client", "dist", "src", `share.${extension}`); + } + + if (!path) { + throw new Error("Not yet defined."); + } + + return fs.readFileSync(path, "utf-8"); +} + export default { exportToZip, exportToZipFile diff --git a/apps/server/src/share/content_renderer.ts b/apps/server/src/share/content_renderer.ts index 465c605ca..4fbae0586 100644 --- a/apps/server/src/share/content_renderer.ts +++ b/apps/server/src/share/content_renderer.ts @@ -16,6 +16,8 @@ import log from "../services/log.js"; import { join } from "path"; import { readFileSync } from "fs"; +const shareAdjustedAssetPath = isDev ? assetPath : `../${assetPath}`; + /** * Represents the output of the content renderer. */ @@ -58,20 +60,50 @@ function getSharedSubTreeRoot(note: SNote | BNote | undefined): Subroot { return getSharedSubTreeRoot(parentBranch.getParentNote()); } -export function renderNoteForExport(note: BNote, parentBranch: BBranch) { +export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath: string) { const subRoot: Subroot = { branch: parentBranch, note: parentBranch.getNote() }; - return renderNoteContentInternal(note, subRoot, note.getParentNotes()[0].noteId); + + return renderNoteContentInternal(note, { + subRoot, + rootNoteId: note.getParentNotes()[0].noteId, + cssToLoad: [ + `${basePath}style.css` + ] + }); } export function renderNoteContent(note: SNote) { const subRoot = getSharedSubTreeRoot(note); - return renderNoteContentInternal(note, subRoot, "_share"); + + // Determine CSS to load. + const cssToLoad: string[] = []; + if (!isDev && !note.isLabelTruthy("shareOmitDefaultCss")) { + cssToLoad.push(`${shareAdjustedAssetPath}/src/share.css`); + cssToLoad.push(`${shareAdjustedAssetPath}/src/boxicons.css`); + } + + // Support custom CSS too. + for (const cssRelation of note.getRelations("shareCss")) { + cssToLoad.push(`api/notes/${cssRelation.value}/download`); + } + + return renderNoteContentInternal(note, { + subRoot, + rootNoteId: "_share", + cssToLoad + }); } -function renderNoteContentInternal(note: SNote | BNote, subRoot: Subroot, rootNoteId: string) { +interface RenderArgs { + subRoot: Subroot; + rootNoteId: string; + cssToLoad: string[]; +} + +function renderNoteContentInternal(note: SNote | BNote, renderArgs: RenderArgs) { const { header, content, isEmpty } = getContent(note); const showLoginInShareTheme = options.getOption("showLoginInShareTheme"); const opts = { @@ -79,14 +111,13 @@ function renderNoteContentInternal(note: SNote | BNote, subRoot: Subroot, rootNo header, content, isEmpty, - subRoot, - assetPath: isDev ? assetPath : `../${assetPath}`, + assetPath: shareAdjustedAssetPath, assetUrlFragment, appPath: isDev ? app_path : `../${app_path}`, showLoginInShareTheme, t, isDev, - rootNoteId + ...renderArgs }; // Check if the user has their own template. diff --git a/packages/share-theme/src/templates/page.ejs b/packages/share-theme/src/templates/page.ejs index ba3d45b44..820e32ad5 100644 --- a/packages/share-theme/src/templates/page.ejs +++ b/packages/share-theme/src/templates/page.ejs @@ -6,14 +6,8 @@ api/notes/<%= note.getRelation("shareFavicon").value %>/download<% } else { %>../favicon.ico<% } %>"> - - <% if (!isDev && !note.isLabelTruthy("shareOmitDefaultCss")) { %> - - - <% } %> - - <% for (const cssRelation of note.getRelations("shareCss")) { %> - + <% for (const url of cssToLoad) { %> + <% } %> <% for (const jsRelation of note.getRelations("shareJs")) { %>