Skip to content

Commit f4e8fc4

Browse files
authored
Export with share theme (#5830)
2 parents 7f22532 + dd5b3a3 commit f4e8fc4

File tree

33 files changed

+921
-499
lines changed

33 files changed

+921
-499
lines changed

apps/client/src/share.ts

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,6 @@ async function ensureJQuery() {
99
(window as any).$ = $;
1010
}
1111

12-
async function applyMath() {
13-
const anyMathBlock = document.querySelector("#content .math-tex");
14-
if (!anyMathBlock) {
15-
return;
16-
}
17-
18-
const renderMathInElement = (await import("./services/math.js")).renderMathInElement;
19-
renderMathInElement(document.getElementById("content"));
20-
}
21-
2212
async function formatCodeBlocks() {
2313
const anyCodeBlock = document.querySelector("#content pre");
2414
if (!anyCodeBlock) {
@@ -31,54 +21,4 @@ async function formatCodeBlocks() {
3121

3222
async function setupTextNote() {
3323
formatCodeBlocks();
34-
applyMath();
35-
36-
const setupMermaid = (await import("./share/mermaid.js")).default;
37-
setupMermaid();
38-
}
39-
40-
/**
41-
* Fetch note with given ID from backend
42-
*
43-
* @param noteId of the given note to be fetched. If false, fetches current note.
44-
*/
45-
async function fetchNote(noteId: string | null = null) {
46-
if (!noteId) {
47-
noteId = document.body.getAttribute("data-note-id");
48-
}
49-
50-
const resp = await fetch(`api/notes/${noteId}`);
51-
52-
return await resp.json();
5324
}
54-
55-
document.addEventListener(
56-
"DOMContentLoaded",
57-
() => {
58-
const noteType = determineNoteType();
59-
60-
if (noteType === "text") {
61-
setupTextNote();
62-
}
63-
64-
const toggleMenuButton = document.getElementById("toggleMenuButton");
65-
const layout = document.getElementById("layout");
66-
67-
if (toggleMenuButton && layout) {
68-
toggleMenuButton.addEventListener("click", () => layout.classList.toggle("showMenu"));
69-
}
70-
},
71-
false
72-
);
73-
74-
function determineNoteType() {
75-
const bodyClass = document.body.className;
76-
const match = bodyClass.match(/type-([^\s]+)/);
77-
return match ? match[1] : null;
78-
}
79-
80-
// workaround to prevent webpack from removing "fetchNote" as dead code:
81-
// add fetchNote as property to the window object
82-
Object.defineProperty(window, "fetchNote", {
83-
value: fetchNote
84-
});

apps/client/src/translations/en/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@
104104
"export_status": "Export status",
105105
"export_in_progress": "Export in progress: {{progressCount}}",
106106
"export_finished_successfully": "Export finished successfully.",
107-
"format_pdf": "PDF - for printing or sharing purposes."
107+
"format_pdf": "PDF - for printing or sharing purposes.",
108+
"share-format": "HTML for web publishing - uses the same theme that is used shared notes, but can be published as a static website."
108109
},
109110
"help": {
110111
"title": "Cheatsheet",

apps/client/src/widgets/dialogs/export.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ export default function ExportDialog() {
7979
values={[
8080
{ value: "html", label: t("export.format_html_zip") },
8181
{ value: "markdown", label: t("export.format_markdown") },
82-
{ value: "opml", label: t("export.format_opml") }
82+
{ value: "opml", label: t("export.format_opml") },
83+
{ value: "share", label: t("export.share-format") }
8384
]}
8485
/>
8586

apps/desktop/scripts/build.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ async function main() {
1111
// Copy assets.
1212
build.copy("src/assets", "assets/");
1313
build.copy("/apps/server/src/assets", "assets/");
14+
build.triggerBuildAndCopyTo("packages/share-theme", "share-theme/assets/");
1415
build.copy("/packages/share-theme/src/templates", "share-theme/templates/");
1516

1617
// Copy node modules dependencies

apps/edit-docs/src/edit-docs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { initializeTranslations } from "@triliumnext/server/src/services/i18n.js
66
import debounce from "@triliumnext/client/src/services/debounce.js";
77
import { extractZip, importData, initializeDatabase, startElectron } from "./utils.js";
88
import cls from "@triliumnext/server/src/services/cls.js";
9-
import type { AdvancedExportOptions } from "@triliumnext/server/src/services/export/zip.js";
9+
import type { AdvancedExportOptions, ExportFormat } from "@triliumnext/server/src/services/export/zip/abstract_provider.js";
1010
import { parseNoteMetaFile } from "@triliumnext/server/src/services/in_app_help.js";
1111
import type NoteMeta from "@triliumnext/server/src/services/meta/note_meta.js";
1212

@@ -75,7 +75,7 @@ async function setOptions() {
7575
optionsService.setOption("compressImages", "false");
7676
}
7777

78-
async function exportData(noteId: string, format: "html" | "markdown", outputPath: string, ignoredFiles?: Set<string>) {
78+
async function exportData(noteId: string, format: ExportFormat, outputPath: string, ignoredFiles?: Set<string>) {
7979
const zipFilePath = "output.zip";
8080

8181
try {

apps/server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@triliumnext/commons": "workspace:*",
3737
"@triliumnext/express-partial-content": "workspace:*",
3838
"@triliumnext/turndown-plugin-gfm": "workspace:*",
39+
"@triliumnext/highlightjs": "workspace:*",
3940
"@types/archiver": "7.0.0",
4041
"@types/better-sqlite3": "7.6.13",
4142
"@types/cls-hooked": "4.3.9",

apps/server/scripts/build.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ async function main() {
77

88
// Copy assets
99
build.copy("src/assets", "assets/");
10+
build.triggerBuildAndCopyTo("packages/share-theme", "share-theme/assets/");
1011
build.copy("/packages/share-theme/src/templates", "share-theme/templates/");
1112

1213
// Copy node modules dependencies

apps/server/src/becca/entities/bbranch.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,11 @@ class BBranch extends AbstractBeccaEntity<BBranch> {
278278
});
279279
}
280280
}
281+
282+
getParentNote() {
283+
return this.parentNote;
284+
}
285+
281286
}
282287

283288
export default BBranch;

apps/server/src/becca/entities/bnote.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,26 @@ class BNote extends AbstractBeccaEntity<BNote> {
17581758
return childBranches;
17591759
}
17601760

1761+
get encodedTitle() {
1762+
return encodeURIComponent(this.title);
1763+
}
1764+
1765+
getVisibleChildBranches() {
1766+
return this.getChildBranches().filter((branch) => !branch.getNote().isLabelTruthy("shareHiddenFromTree"));
1767+
}
1768+
1769+
getVisibleChildNotes() {
1770+
return this.getVisibleChildBranches().map((branch) => branch.getNote());
1771+
}
1772+
1773+
hasVisibleChildren() {
1774+
return this.getVisibleChildNotes().length > 0;
1775+
}
1776+
1777+
get shareId() {
1778+
return this.noteId;
1779+
}
1780+
17611781
/**
17621782
* Return an attribute by it's attributeId. Requires the attribute cache to be available.
17631783
* @param attributeId - the id of the attribute owned by this note

apps/server/src/etapi/notes.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import type { ParsedQs } from "qs";
1414
import type { NoteParams } from "../services/note-interface.js";
1515
import type { SearchParams } from "../services/search/services/types.js";
1616
import type { ValidatorMap } from "./etapi-interface.js";
17+
import type { ExportFormat } from "../services/export/zip/abstract_provider.js";
1718

1819
function register(router: Router) {
1920
eu.route(router, "get", "/etapi/notes", (req, res, next) => {
@@ -149,8 +150,8 @@ function register(router: Router) {
149150
const note = eu.getAndCheckNote(req.params.noteId);
150151
const format = req.query.format || "html";
151152

152-
if (typeof format !== "string" || !["html", "markdown"].includes(format)) {
153-
throw new eu.EtapiError(400, "UNRECOGNIZED_EXPORT_FORMAT", `Unrecognized export format '${format}', supported values are 'html' (default) or 'markdown'.`);
153+
if (typeof format !== "string" || !["html", "markdown", "share"].includes(format)) {
154+
throw new eu.EtapiError(400, "UNRECOGNIZED_EXPORT_FORMAT", `Unrecognized export format '${format}', supported values are 'html' (default), 'markdown' or 'share'.`);
154155
}
155156

156157
const taskContext = new TaskContext("no-progress-reporting", "export", null);
@@ -159,7 +160,7 @@ function register(router: Router) {
159160
// (e.g. branchIds are not seen in UI), that we export "note export" instead.
160161
const branch = note.getParentBranches()[0];
161162

162-
zipExportService.exportToZip(taskContext, branch, format as "html" | "markdown", res);
163+
zipExportService.exportToZip(taskContext, branch, format as ExportFormat, res);
163164
});
164165

165166
eu.route(router, "post", "/etapi/notes/:noteId/import", (req, res, next) => {

0 commit comments

Comments
 (0)