mirror of
https://github.com/zadam/trilium.git
synced 2026-01-10 16:44:29 +01:00
chore(export/share): inject font
This commit is contained in:
parent
da28f4505a
commit
d5b04864c8
@ -9,6 +9,7 @@ import type BBranch from "../../../becca/entities/bbranch.js";
|
|||||||
import type BNote from "../../../becca/entities/bnote.js";
|
import type BNote from "../../../becca/entities/bnote.js";
|
||||||
import { getShareThemeAssetDir } from "../../../routes/assets";
|
import { getShareThemeAssetDir } from "../../../routes/assets";
|
||||||
import { getDefaultTemplatePath, readTemplate, renderNoteForExport } from "../../../share/content_renderer";
|
import { getDefaultTemplatePath, readTemplate, renderNoteForExport } from "../../../share/content_renderer";
|
||||||
|
import { getIconPacks, MIME_TO_EXTENSION_MAPPINGS, ProcessedIconPack } from "../../icon_packs";
|
||||||
import NoteMeta, { NoteMetaFile } from "../../meta/note_meta";
|
import NoteMeta, { NoteMetaFile } from "../../meta/note_meta";
|
||||||
import { RESOURCE_DIR } from "../../resource_dir";
|
import { RESOURCE_DIR } from "../../resource_dir";
|
||||||
import { getResourceDir, isDev } from "../../utils";
|
import { getResourceDir, isDev } from "../../utils";
|
||||||
@ -29,6 +30,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
|
|||||||
private indexMeta: NoteMeta | null = null;
|
private indexMeta: NoteMeta | null = null;
|
||||||
private searchIndex: Map<string, SearchIndexEntry> = new Map();
|
private searchIndex: Map<string, SearchIndexEntry> = new Map();
|
||||||
private rootMeta: NoteMeta | null = null;
|
private rootMeta: NoteMeta | null = null;
|
||||||
|
private iconPacks: ProcessedIconPack[] = [];
|
||||||
|
|
||||||
prepareMeta(metaFile: NoteMetaFile): void {
|
prepareMeta(metaFile: NoteMetaFile): void {
|
||||||
const assets = [
|
const assets = [
|
||||||
@ -53,6 +55,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
|
|||||||
dataFileName: "index.html"
|
dataFileName: "index.html"
|
||||||
};
|
};
|
||||||
this.rootMeta = metaFile.files[0];
|
this.rootMeta = metaFile.files[0];
|
||||||
|
this.iconPacks = getIconPacks();
|
||||||
|
|
||||||
metaFile.files.push(this.indexMeta);
|
metaFile.files.push(this.indexMeta);
|
||||||
}
|
}
|
||||||
@ -70,7 +73,7 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
|
|||||||
whitespaceCharacters: "\t\r\n\f\u200b\u00a0\u2002"
|
whitespaceCharacters: "\t\r\n\f\u200b\u00a0\u2002"
|
||||||
}) : "";
|
}) : "";
|
||||||
|
|
||||||
content = renderNoteForExport(note, branch, basePath, noteMeta.notePath.slice(0, -1));
|
content = renderNoteForExport(note, branch, basePath, noteMeta.notePath.slice(0, -1), this.iconPacks);
|
||||||
if (typeof content === "string") {
|
if (typeof content === "string") {
|
||||||
content = content.replace(/href="[^"]*\.\/([a-zA-Z0-9_\/]{12})[^"]*"/g, (match, id) => {
|
content = content.replace(/href="[^"]*\.\/([a-zA-Z0-9_\/]{12})[^"]*"/g, (match, id) => {
|
||||||
if (match.includes("/assets/")) return match;
|
if (match.includes("/assets/")) return match;
|
||||||
@ -138,6 +141,18 @@ export default class ShareThemeExportProvider extends ZipExportProvider {
|
|||||||
const cssContent = getShareThemeAssets(assetMeta.dataFileName);
|
const cssContent = getShareThemeAssets(assetMeta.dataFileName);
|
||||||
this.archive.append(cssContent, { name: assetMeta.dataFileName });
|
this.archive.append(cssContent, { name: assetMeta.dataFileName });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inject the custom fonts.
|
||||||
|
for (const iconPack of this.iconPacks) {
|
||||||
|
const attachment = becca.getAttachment(iconPack.fontAttachmentId);
|
||||||
|
if (!attachment) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fontData = attachment.getContent();
|
||||||
|
const fontFileName = `assets/icon-pack-${iconPack.manifest.prefix.toLowerCase()}.${MIME_TO_EXTENSION_MAPPINGS[attachment.mime]}`;
|
||||||
|
this.archive.append(fontData, { name: fontFileName });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#save404() {
|
#save404() {
|
||||||
|
|||||||
@ -20,6 +20,12 @@ const MIME_TO_CSS_FORMAT_MAPPINGS: Record<typeof PREFERRED_MIME_TYPE[number], st
|
|||||||
"font/woff2": "woff2"
|
"font/woff2": "woff2"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MIME_TO_EXTENSION_MAPPINGS: Record<string, string> = {
|
||||||
|
"font/ttf": "ttf",
|
||||||
|
"font/woff": "woff",
|
||||||
|
"font/woff2": "woff2"
|
||||||
|
};
|
||||||
|
|
||||||
export interface IconPackManifest {
|
export interface IconPackManifest {
|
||||||
prefix: string;
|
prefix: string;
|
||||||
icons: Record<string, {
|
icons: Record<string, {
|
||||||
@ -28,7 +34,7 @@ export interface IconPackManifest {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProcessResult {
|
export interface ProcessedIconPack {
|
||||||
manifest: IconPackManifest;
|
manifest: IconPackManifest;
|
||||||
manifestNoteId: string;
|
manifestNoteId: string;
|
||||||
fontMime: string;
|
fontMime: string;
|
||||||
@ -38,7 +44,7 @@ interface ProcessResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getIconPacks() {
|
export function getIconPacks() {
|
||||||
const defaultIconPack: ProcessResult = {
|
const defaultIconPack: ProcessedIconPack = {
|
||||||
manifest: boxiconsManifest,
|
manifest: boxiconsManifest,
|
||||||
manifestNoteId: "builtin-boxicons-v2",
|
manifestNoteId: "builtin-boxicons-v2",
|
||||||
fontMime: "font/woff2",
|
fontMime: "font/woff2",
|
||||||
@ -49,7 +55,7 @@ export function getIconPacks() {
|
|||||||
const customIconPacks = search.searchNotes("#iconPack")
|
const customIconPacks = search.searchNotes("#iconPack")
|
||||||
.filter(note => !note.isProtected)
|
.filter(note => !note.isProtected)
|
||||||
.map(iconPackNote => processIconPack(iconPackNote))
|
.map(iconPackNote => processIconPack(iconPackNote))
|
||||||
.filter(Boolean) as ProcessResult[];
|
.filter(Boolean) as ProcessedIconPack[];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
defaultIconPack,
|
defaultIconPack,
|
||||||
@ -57,7 +63,7 @@ export function getIconPacks() {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateIconRegistry(iconPacks: ProcessResult[]): IconRegistry {
|
export function generateIconRegistry(iconPacks: ProcessedIconPack[]): IconRegistry {
|
||||||
const sources: IconRegistry["sources"] = [];
|
const sources: IconRegistry["sources"] = [];
|
||||||
|
|
||||||
for (const { manifest, title, icon } of iconPacks) {
|
for (const { manifest, title, icon } of iconPacks) {
|
||||||
@ -80,7 +86,7 @@ export function generateIconRegistry(iconPacks: ProcessResult[]): IconRegistry {
|
|||||||
return { sources };
|
return { sources };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function processIconPack(iconPackNote: BNote): ProcessResult | undefined {
|
export function processIconPack(iconPackNote: BNote): ProcessedIconPack | undefined {
|
||||||
const manifest = iconPackNote.getJsonContentSafely() as IconPackManifest;
|
const manifest = iconPackNote.getJsonContentSafely() as IconPackManifest;
|
||||||
if (!manifest) {
|
if (!manifest) {
|
||||||
log.error(`Icon pack is missing JSON manifest (or has syntax errors): ${iconPackNote.title} (${iconPackNote.noteId})`);
|
log.error(`Icon pack is missing JSON manifest (or has syntax errors): ${iconPackNote.title} (${iconPackNote.noteId})`);
|
||||||
@ -119,7 +125,7 @@ export function determineBestFontAttachment(iconPackNote: BNote) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateCss({ manifest, fontAttachmentId, fontMime }: ProcessResult, isShare = false) {
|
export function generateCss({ manifest, fontAttachmentId, fontMime }: ProcessedIconPack, isShare = false) {
|
||||||
try {
|
try {
|
||||||
const iconDeclarations: string[] = [];
|
const iconDeclarations: string[] = [];
|
||||||
for (const [ key, mapping ] of Object.entries(manifest.icons)) {
|
for (const [ key, mapping ] of Object.entries(manifest.icons)) {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import BAttachment from '../becca/entities/battachment.js';
|
|||||||
import type BBranch from "../becca/entities/bbranch.js";
|
import type BBranch from "../becca/entities/bbranch.js";
|
||||||
import BNote from "../becca/entities/bnote.js";
|
import BNote from "../becca/entities/bnote.js";
|
||||||
import assetPath, { assetUrlFragment } from "../services/asset_path.js";
|
import assetPath, { assetUrlFragment } from "../services/asset_path.js";
|
||||||
import { generateCss, getIconPacks } from "../services/icon_packs.js";
|
import { generateCss, getIconPacks, ProcessedIconPack } from "../services/icon_packs.js";
|
||||||
import log from "../services/log.js";
|
import log from "../services/log.js";
|
||||||
import options from "../services/options.js";
|
import options from "../services/options.js";
|
||||||
import utils, { getResourceDir, isDev, safeExtractMessageAndStackFromError } from "../services/utils.js";
|
import utils, { getResourceDir, isDev, safeExtractMessageAndStackFromError } from "../services/utils.js";
|
||||||
@ -69,14 +69,12 @@ function getSharedSubTreeRoot(note: SNote | BNote | undefined): Subroot {
|
|||||||
return getSharedSubTreeRoot(parentBranch.getParentNote());
|
return getSharedSubTreeRoot(parentBranch.getParentNote());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath: string, ancestors: string[]) {
|
export function renderNoteForExport(note: BNote, parentBranch: BBranch, basePath: string, ancestors: string[], iconPacks: ProcessedIconPack[]) {
|
||||||
const subRoot: Subroot = {
|
const subRoot: Subroot = {
|
||||||
branch: parentBranch,
|
branch: parentBranch,
|
||||||
note: parentBranch.getNote()
|
note: parentBranch.getNote()
|
||||||
};
|
};
|
||||||
|
|
||||||
const iconPacks = getIconPacks();
|
|
||||||
|
|
||||||
return renderNoteContentInternal(note, {
|
return renderNoteContentInternal(note, {
|
||||||
subRoot,
|
subRoot,
|
||||||
rootNoteId: parentBranch.noteId,
|
rootNoteId: parentBranch.noteId,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user