Merge branch 'main' into feat/extra-window

This commit is contained in:
SiriusXT 2026-01-04 14:13:25 +08:00
commit 31c70938d6
234 changed files with 3024 additions and 1944 deletions

View File

@ -382,7 +382,8 @@ export type CommandMappings = {
reloadTextEditor: CommandData;
chooseNoteType: CommandData & {
callback: ChooseNoteTypeCallback
}
};
customDownload: CommandData;
};
type EventMappings = {

View File

@ -23,6 +23,8 @@ export interface SetNoteOpts {
export type GetTextEditorCallback = (editor: CKTextEditor) => void;
export type SaveState = "saved" | "saving" | "unsaved" | "error";
export interface NoteContextDataMap {
toc: HeadingContext;
pdfPages: {
@ -32,13 +34,16 @@ export interface NoteContextDataMap {
requestThumbnail(page: number): void;
};
pdfAttachments: {
attachments: Array<{ filename: string; size: number }>;
attachments: PdfAttachment[];
downloadAttachment(filename: string): void;
};
pdfLayers: {
layers: Array<{ id: string; name: string; visible: boolean }>;
layers: PdfLayer[];
toggleLayer(layerId: string, visible: boolean): void;
};
saveState: {
state: SaveState;
};
}
type ContextDataKey = keyof NoteContextDataMap;

View File

@ -1,35 +1,35 @@
import { applyModals } from "./layout_commons.js";
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
import { useNoteContext } from "../widgets/react/hooks.jsx";
import CloseZenModeButton from "../widgets/close_zen_button.js";
import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
import FlexContainer from "../widgets/containers/flex_container.js";
import FloatingButtons from "../widgets/FloatingButtons.jsx";
import type AppContext from "../components/app_context.js";
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
import CloseZenModeButton from "../widgets/close_zen_button.js";
import NoteList from "../widgets/collections/NoteList.jsx";
import NoteTitleWidget from "../widgets/note_title.js";
import ContentHeader from "../widgets/containers/content_header.js";
import FlexContainer from "../widgets/containers/flex_container.js";
import RootContainer from "../widgets/containers/root_container.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import FloatingButtons from "../widgets/FloatingButtons.jsx";
import { MOBILE_FLOATING_BUTTONS } from "../widgets/FloatingButtonsDefinitions.jsx";
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
import MobileDetailMenu from "../widgets/mobile_widgets/mobile_detail_menu.js";
import ScreenContainer from "../widgets/mobile_widgets/screen_container.js";
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
import NoteTitleWidget from "../widgets/note_title.js";
import NoteTreeWidget from "../widgets/note_tree.js";
import NoteWrapperWidget from "../widgets/note_wrapper.js";
import NoteDetail from "../widgets/NoteDetail.jsx";
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
import QuickSearchWidget from "../widgets/quick_search.js";
import { useNoteContext } from "../widgets/react/hooks.jsx";
import ReadOnlyNoteInfoBar from "../widgets/ReadOnlyNoteInfoBar.jsx";
import RootContainer from "../widgets/containers/root_container.js";
import ScreenContainer from "../widgets/mobile_widgets/screen_container.js";
import ScrollingContainer from "../widgets/containers/scrolling_container.js";
import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx";
import FilePropertiesTab from "../widgets/ribbon/FilePropertiesTab.jsx";
import SearchDefinitionTab from "../widgets/ribbon/SearchDefinitionTab.jsx";
import SearchResult from "../widgets/search_result.jsx";
import SharedInfoWidget from "../widgets/shared_info.js";
import SidebarContainer from "../widgets/mobile_widgets/sidebar_container.js";
import StandaloneRibbonAdapter from "../widgets/ribbon/components/StandaloneRibbonAdapter.jsx";
import TabRowWidget from "../widgets/tab_row.js";
import ToggleSidebarButton from "../widgets/mobile_widgets/toggle_sidebar_button.jsx";
import type AppContext from "../components/app_context.js";
import NoteDetail from "../widgets/NoteDetail.jsx";
import MobileEditorToolbar from "../widgets/type_widgets/text/mobile_editor_toolbar.jsx";
import PromotedAttributes from "../widgets/PromotedAttributes.jsx";
import SplitNoteContainer from "../widgets/containers/split_note_container.js";
import LauncherContainer from "../widgets/launch_bar/LauncherContainer.jsx";
import { applyModals } from "./layout_commons.js";
const MOBILE_CSS = `
<style>
@ -194,11 +194,11 @@ export default class MobileLayout {
}
function FilePropertiesWrapper() {
const { note } = useNoteContext();
const { note, ntxId } = useNoteContext();
return (
<div>
{note?.type === "file" && <FilePropertiesTab note={note} />}
{note?.type === "file" && <FilePropertiesTab note={note} ntxId={ntxId} />}
</div>
);
}

View File

@ -1,18 +1,19 @@
import renderService from "./render.js";
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
import WheelZoom from 'vanilla-js-wheel-zoom';
import FAttachment from "../entities/fattachment.js";
import FNote from "../entities/fnote.js";
import imageContextMenuService from "../menus/image_context_menu.js";
import { t } from "../services/i18n.js";
import renderText from "./content_renderer_text.js";
import renderDoc from "./doc_renderer.js";
import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
import openService from "./open.js";
import protectedSessionService from "./protected_session.js";
import protectedSessionHolder from "./protected_session_holder.js";
import openService from "./open.js";
import utils from "./utils.js";
import FNote from "../entities/fnote.js";
import FAttachment from "../entities/fattachment.js";
import imageContextMenuService from "../menus/image_context_menu.js";
import renderService from "./render.js";
import { applySingleBlockSyntaxHighlight } from "./syntax_highlight.js";
import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
import renderDoc from "./doc_renderer.js";
import { t } from "../services/i18n.js";
import WheelZoom from 'vanilla-js-wheel-zoom';
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
import renderText from "./content_renderer_text.js";
import utils from "./utils.js";
let idCounter = 1;
@ -152,7 +153,7 @@ function renderImage(entity: FNote | FAttachment, $renderedContent: JQuery<HTMLE
const $img = $("<img>")
.attr("src", url || "")
.attr("id", "attachment-image-" + idCounter++)
.attr("id", `attachment-image-${idCounter++}`)
.css("max-width", "100%");
$renderedContent.append($img);
@ -231,14 +232,14 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
$downloadButton.on("click", (e) => {
e.stopPropagation();
openService.downloadFileNote(entity.noteId)
openService.downloadFileNote(entity, null, null);
});
$openButton.on("click", async (e) => {
const iconEl = $openButton.find("> .bx");
iconEl.removeClass("bx bx-link-external");
iconEl.addClass("bx bx-loader spin");
e.stopPropagation();
await openService.openNoteExternally(entity.noteId, entity.mime)
await openService.openNoteExternally(entity.noteId, entity.mime);
iconEl.removeClass("bx bx-loader spin");
iconEl.addClass("bx bx-link-external");
});
@ -266,7 +267,7 @@ async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery
try {
await loadElkIfNeeded(mermaid, content);
const { svg } = await mermaid.mermaidAPI.render("in-mermaid-graph-" + idCounter++, content);
const { svg } = await mermaid.mermaidAPI.render(`in-mermaid-graph-${idCounter++}`, content);
$renderedContent.append($(postprocessMermaidSvg(svg)));
} catch (e) {

View File

@ -1,6 +1,8 @@
import utils from "./utils.js";
import Component from "../components/component.js";
import FNote from "../entities/fnote.js";
import options from "./options.js";
import server from "./server.js";
import utils from "./utils.js";
type ExecFunction = (command: string, cb: (err: string, stdout: string, stderror: string) => void) => void;
@ -36,9 +38,14 @@ function download(url: string) {
}
}
export function downloadFileNote(noteId: string) {
const url = `${getFileUrl("notes", noteId)}?${Date.now()}`; // don't use cache
export function downloadFileNote(note: FNote, parentComponent: Component | null, ntxId: string | null | undefined) {
if (note.type === "file" && note.mime === "application/pdf" && parentComponent) {
// Special handling, manages its own downloading process.
parentComponent.triggerEvent("customDownload", { ntxId });
return;
}
const url = `${getFileUrl("notes", note.noteId)}?${Date.now()}`; // don't use cache
download(url);
}
@ -97,7 +104,7 @@ async function openCustom(type: string, entityId: string, mime: string) {
// Note that the path separator must be \ instead of /
filePath = filePath.replace(/\//g, "\\");
}
const command = `rundll32.exe shell32.dll,OpenAs_RunDLL ` + filePath;
const command = `rundll32.exe shell32.dll,OpenAs_RunDLL ${filePath}`;
exec(command, (err, stdout, stderr) => {
if (err) {
console.error("Open Note custom: ", err);
@ -131,10 +138,10 @@ export function getUrlForDownload(url: string) {
if (utils.isElectron()) {
// electron needs absolute URL, so we extract current host, port, protocol
return `${getHost()}/${url}`;
} else {
// web server can be deployed on subdomain, so we need to use a relative path
return url;
}
// web server can be deployed on subdomain, so we need to use a relative path
return url;
}
function canOpenInBrowser(mime: string) {

View File

@ -1,22 +1,30 @@
import type { SaveState } from "../components/note_context";
import { getErrorMessage } from "./utils";
type Callback = () => Promise<void> | void;
export type StateCallback = (state: SaveState) => void;
export default class SpacedUpdate {
private updater: Callback;
private lastUpdated: number;
private changed: boolean;
private updateInterval: number;
private changeForbidden?: boolean;
private stateCallback?: StateCallback;
constructor(updater: Callback, updateInterval = 1000) {
constructor(updater: Callback, updateInterval = 1000, stateCallback?: StateCallback) {
this.updater = updater;
this.lastUpdated = Date.now();
this.changed = false;
this.updateInterval = updateInterval;
this.stateCallback = stateCallback;
}
scheduleUpdate() {
if (!this.changeForbidden) {
this.changed = true;
this.stateCallback?.("unsaved");
setTimeout(() => this.triggerUpdate());
}
}
@ -26,10 +34,13 @@ export default class SpacedUpdate {
this.changed = false; // optimistic...
try {
this.stateCallback?.("saving");
await this.updater();
this.stateCallback?.("saved");
} catch (e) {
this.changed = true;
this.stateCallback?.("error");
logError(getErrorMessage(e));
throw e;
}
}
@ -59,15 +70,22 @@ export default class SpacedUpdate {
this.updateInterval = interval;
}
triggerUpdate() {
async triggerUpdate() {
if (!this.changed) {
return;
}
if (Date.now() - this.lastUpdated > this.updateInterval) {
this.updater();
this.stateCallback?.("saving");
try {
await this.updater();
this.stateCallback?.("saved");
this.changed = false;
} catch (e) {
this.stateCallback?.("error");
logError(getErrorMessage(e));
}
this.lastUpdated = Date.now();
this.changed = false;
} else {
// update isn't triggered but changes are still pending, so we need to schedule another check
this.scheduleUpdate();

View File

@ -484,7 +484,6 @@
"delete_button": "حذف",
"download_button": "تنزيل",
"restore_button": "أستعادة",
"preview": "معاينة:",
"note_revisions": "مراجعات الملاحظة",
"diff_on": "عرض الفروقات",
"diff_off": "عرض المحتوى",

View File

@ -64,8 +64,7 @@
"restore_button": "Restaura",
"delete_button": "Suprimeix",
"download_button": "Descarrega",
"mime": "MIME: ",
"preview": "Vista prèvia:"
"mime": "MIME: "
},
"sort_child_notes": {
"title": "títol",

View File

@ -290,7 +290,6 @@
"download_button": "下载",
"mime": "MIME 类型: ",
"file_size": "文件大小:",
"preview": "预览:",
"preview_not_available": "无法预览此类型的笔记。",
"diff_on": "显示差异",
"diff_off": "显示内容",
@ -2231,6 +2230,7 @@
"attachments_other": "{{count}} 个附件",
"pages_other": "共{{count}}页",
"pages_alt": "第{{pageNumber}}页",
"pages_loading": "加载中..."
"pages_loading": "加载中...",
"layers_other": "{{count}} 层"
}
}

View File

@ -281,7 +281,6 @@
"download_button": "Herunterladen",
"mime": "MIME: ",
"file_size": "Dateigröße:",
"preview": "Vorschau:",
"preview_not_available": "Für diesen Notiztyp ist keine Vorschau verfügbar.",
"restore_button": "Wiederherstellen",
"delete_button": "Löschen",

View File

@ -295,7 +295,6 @@
"download_button": "Download",
"mime": "MIME: ",
"file_size": "File size:",
"preview": "Preview:",
"preview_not_available": "Preview isn't available for this note type."
},
"sort_child_notes": {
@ -2209,7 +2208,14 @@
"execute_script": "Run script",
"execute_script_description": "This note is a script note. Click to execute the script.",
"execute_sql": "Run SQL",
"execute_sql_description": "This note is a SQL note. Click to execute the SQL query."
"execute_sql_description": "This note is a SQL note. Click to execute the SQL query.",
"save_status_saved": "Saved",
"save_status_saving": "Saving...",
"save_status_unsaved": "Unsaved",
"save_status_error": "Save failed",
"save_status_saving_tooltip": "Changes are being saved.",
"save_status_unsaved_tooltip": "There are unsaved changes. They will be saved automatically in a moment.",
"save_status_error_tooltip": "An error occurred while saving the note. If possible, try copying the note content elsewhere and reloading the application."
},
"status_bar": {
"language_title": "Change content language",

View File

@ -279,7 +279,6 @@
"download_button": "Descargar",
"mime": "MIME: ",
"file_size": "Tamaño del archivo:",
"preview": "Vista previa:",
"preview_not_available": "La vista previa no está disponible para este tipo de notas.",
"diff_off": "Mostrar contenido",
"diff_on": "Mostrar diferencia",

View File

@ -285,7 +285,6 @@
"download_button": "Télécharger",
"mime": "MIME : ",
"file_size": "Taille du fichier :",
"preview": "Aperçu :",
"preview_not_available": "L'aperçu n'est pas disponible pour ce type de note.",
"restore_button": "Restaurer",
"delete_button": "Supprimer",

View File

@ -902,7 +902,6 @@
"download_button": "Scarica",
"mime": "MIME: ",
"file_size": "Dimensione del file:",
"preview": "Anteprima:",
"preview_not_available": "L'anteprima non è disponibile per questo tipo di nota."
},
"sort_child_notes": {

View File

@ -654,7 +654,6 @@
"revision_deleted": "ノートの変更履歴は削除されました。",
"settings": "ノートの変更履歴の設定",
"file_size": "ファイルサイズ:",
"preview": "プレビュー:",
"preview_not_available": "このノートタイプではプレビューは利用できません。",
"diff_on": "差分を表示",
"diff_off": "内容を表示",

View File

@ -959,7 +959,6 @@
"download_button": "Pobierz",
"mime": "MIME: ",
"file_size": "Rozmiar pliku:",
"preview": "Podgląd:",
"preview_not_available": "Podgląd nie jest dostępny dla tego typu notatki."
},
"sort_child_notes": {

View File

@ -274,7 +274,6 @@
"download_button": "Descarregar",
"mime": "MIME: ",
"file_size": "Tamanho do ficheiro:",
"preview": "Visualizar:",
"preview_not_available": "A visualização não está disponível para este tipo de nota."
},
"sort_child_notes": {

View File

@ -439,7 +439,6 @@
"download_button": "Download",
"mime": "MIME: ",
"file_size": "Tamanho do arquivo:",
"preview": "Visualizar:",
"preview_not_available": "A visualização não está disponível para este tipo de nota.",
"diff_on": "Exibir diferença",
"diff_off": "Exibir conteúdo",

View File

@ -1103,7 +1103,6 @@
"mime": "MIME: ",
"no_revisions": "Nu există încă nicio revizie pentru această notiță...",
"note_revisions": "Revizii ale notiței",
"preview": "Previzualizare:",
"preview_not_available": "Nu este disponibilă o previzualizare pentru acest tip de notiță.",
"restore_button": "Restaurează",
"revision_deleted": "Revizia notiței a fost ștearsă.",

View File

@ -387,7 +387,6 @@
"revision_deleted": "Версия заметки была удалена.",
"download_button": "Скачать",
"file_size": "Размер файла:",
"preview": "Предпросмотр:",
"preview_not_available": "Предпосмотр недоступен для заметки этого типа.",
"mime": "MIME: ",
"settings": "Настройка версионирования заметок",

View File

@ -271,7 +271,6 @@
"download_button": "Preuzmi",
"mime": "MIME: ",
"file_size": "Veličina datoteke:",
"preview": "Pregled:",
"preview_not_available": "Pregled nije dostupan za ovaj tip beleške."
},
"sort_child_notes": {

View File

@ -29,8 +29,9 @@
"widget-render-error": {
"title": "無法渲染自訂 React 元件"
},
"widget-missing-parent": "自訂元件未定義強制性的 \"{{property}}\" 屬性。",
"open-script-note": "打開腳本筆記"
"widget-missing-parent": "自訂元件未定義強制性的 \"{{property}}\" 屬性。\n\n若此腳本需在無 UI 的情況下執行,請改用 \"#run=frontendStartup\"。",
"open-script-note": "打開腳本筆記",
"scripting-error": "自訂腳本錯誤:{{title}}"
},
"add_link": {
"add_link": "新增連結",
@ -287,7 +288,6 @@
"download_button": "下載",
"mime": "MIME類型 ",
"file_size": "檔案大小:",
"preview": "預覽:",
"preview_not_available": "無法預覽此類型的筆記。",
"restore_button": "還原",
"delete_button": "刪除",
@ -762,7 +762,15 @@
"note_icon": {
"change_note_icon": "更改筆記圖標",
"search": "搜尋:",
"reset-default": "重置為預設圖標"
"reset-default": "重置為預設圖標",
"search_placeholder_one": "在 {{count}} 個圖示包中搜尋 {{number}} 個圖示",
"search_placeholder_other": "",
"search_placeholder_filtered": "在 {{name}} 中搜尋 {{number}} 個圖示",
"filter": "篩選",
"filter-none": "所有圖示",
"filter-default": "預設圖示",
"icon_tooltip": "{{name}}\n圖示包{{iconPack}}",
"no_results": "找不到圖示。"
},
"basic_properties": {
"note_type": "筆記類型",
@ -1404,7 +1412,7 @@
"will_be_deleted_in": "此附件將在 {{time}} 後自動刪除",
"will_be_deleted_soon": "該附件即將被自動刪除",
"deletion_reason": ",因為該附件未連結在筆記的內容中。為防止被刪除,請將附件連結重新新增至內容中或將附件轉換為筆記。",
"role_and_size": "角色:{{role}},大小:{{size}}",
"role_and_size": "角色:{{role}},大小:{{size}}MIME{{- mimeType}}",
"link_copied": "已複製附件連結到剪貼簿。",
"unrecognized_role": "無法識別的附件角色 '{{role}}'。"
},
@ -1548,7 +1556,11 @@
"create-child-note": "建立子筆記",
"unhoist": "取消聚焦",
"toggle-sidebar": "切換側邊欄",
"dropping-not-allowed": "不允許移動筆記至此處。"
"dropping-not-allowed": "不允許移動筆記至此處。",
"clone-indicator-tooltip": "此筆記有 {{- count}} 個父級:{{- parents}}",
"clone-indicator-tooltip-single": "此筆記已克隆(新增 1 個父級:{{- parent}}",
"shared-indicator-tooltip": "此筆記已公開分享",
"shared-indicator-tooltip-with-url": "此筆記已公開分享至:{{- url}}"
},
"title_bar_buttons": {
"window-on-top": "保持此視窗置頂"
@ -1556,7 +1568,12 @@
"note_detail": {
"could_not_find_typewidget": "找不到類型為 '{{type}}' 的 typeWidget",
"printing": "正在列印…",
"printing_pdf": "正在匯出為 PDF…"
"printing_pdf": "正在匯出為 PDF…",
"print_report_title": "列印報告",
"print_report_collection_content_one": "集合中的 {{count}} 篇筆記無法列印,因為它們不被支援或受到保護。",
"print_report_collection_content_other": "",
"print_report_collection_details_button": "查看詳情",
"print_report_collection_details_ignored_notes": "忽略的筆記"
},
"note_title": {
"placeholder": "請輸入筆記標題...",
@ -1566,7 +1583,8 @@
"note_type_switcher_others": "其他筆記類型",
"note_type_switcher_templates": "模板",
"note_type_switcher_collection": "集合",
"edited_notes": "編輯過的筆記"
"edited_notes": "今天編輯過的筆記",
"promoted_attributes": "升級屬性"
},
"search_result": {
"no_notes_found": "沒有找到符合搜尋條件的筆記。",
@ -2219,5 +2237,15 @@
},
"attributes_panel": {
"title": "筆記屬性"
},
"pdf": {
"attachments_one": "{{count}} 個附件",
"attachments_other": "",
"layers_one": "{{count}} 層",
"layers_other": "",
"pages_one": "共 {{count}} 頁",
"pages_other": "",
"pages_alt": "第 {{pageNumber}} 頁",
"pages_loading": "載入中…"
}
}

View File

@ -321,7 +321,6 @@
"download_button": "Завантажити",
"mime": "МІМЕ: ",
"file_size": "Розмір файлу:",
"preview": "Попередній перегляд:",
"preview_not_available": "Попередній перегляд недоступний для цього типу нотатки.",
"diff_on": "Показати різницю",
"diff_off": "Показати вміст",

View File

@ -1,3 +1,15 @@
type HistoryData = {
files: {
fingerprint: string;
page: number;
zoom: string;
scrollLeft: number;
scrollTop: number;
rotation: number;
sidebarView: number;
}[];
};
interface Window {
/**
* By default, pdf.js will try to store information about the opened PDFs such as zoom and scroll position in local storage.
@ -5,11 +17,100 @@ interface Window {
* This variable represents the direct content used by the pdf.js viewer in its local storage key, but in plain JS object format.
* The variable must be set early at startup, before pdf.js fully initializes.
*/
TRILIUM_VIEW_HISTORY_STORE?: object;
TRILIUM_VIEW_HISTORY_STORE?: HistoryData;
/**
* If set to true, hides the pdf.js viewer default sidebar containing the outline, page navigation, etc.
* This needs to be set early in the main method.
*/
TRILIUM_HIDE_SIDEBAR?: boolean;
TRILIUM_NOTE_ID: string;
TRILIUM_NTX_ID: string | null | undefined;
}
interface PdfOutlineItem {
title: string;
level: number;
dest: unknown;
id: string;
items: PdfOutlineItem[];
}
interface WithContext {
ntxId: string;
noteId: string | null | undefined;
}
interface PdfDocumentModifiedMessage extends WithContext {
type: "pdfjs-viewer-document-modified";
data: Uint8Array<ArrayBufferLike>;
}
interface PdfSaveViewHistoryMessage extends WithContext {
type: "pdfjs-viewer-save-view-history";
data: string;
}
interface PdfViewerTocMessage {
type: "pdfjs-viewer-toc";
data: PdfOutlineItem[];
}
interface PdfViewerActiveHeadingMessage {
type: "pdfjs-viewer-active-heading";
headingId: string;
}
interface PdfViewerPageInfoMessage {
type: "pdfjs-viewer-page-info";
totalPages: number;
currentPage: number;
}
interface PdfViewerCurrentPageMessage {
type: "pdfjs-viewer-current-page";
currentPage: number;
}
interface PdfViewerThumbnailMessage {
type: "pdfjs-viewer-thumbnail";
pageNumber: number;
dataUrl: string;
}
interface PdfAttachment {
filename: string;
size: number;
}
interface PdfViewerAttachmentsMessage {
type: "pdfjs-viewer-attachments";
attachments: PdfAttachment[];
downloadAttachment?: (fileName: string) => void;
}
interface PdfLayer {
id: string;
name: string;
visible: boolean;
}
interface PdfViewerLayersMessage {
type: "pdfjs-viewer-layers";
layers: PdfLayer[];
toggleLayer?: (layerId: string, visible: boolean) => void;
}
type PdfMessageEvent = MessageEvent<
PdfDocumentModifiedMessage
| PdfSaveViewHistoryMessage
| PdfViewerTocMessage
| PdfViewerActiveHeadingMessage
| PdfViewerPageInfoMessage
| PdfViewerCurrentPageMessage
| PdfViewerThumbnailMessage
| PdfViewerAttachmentsMessage
| PdfViewerLayersMessage
>;

View File

@ -14,7 +14,7 @@ body.mobile .revisions-dialog {
flex-grow: 1;
width: 100%;
}
.modal-body {
height: fit-content !important;
flex-direction: column;
@ -24,7 +24,7 @@ body.mobile .revisions-dialog {
.modal-footer {
font-size: 0.9em;
}
.revision-list {
height: fit-content !important;
max-height: 20vh;
@ -32,7 +32,7 @@ body.mobile .revisions-dialog {
padding: 0 1em;
flex-shrink: 0;
}
.modal-body > .revision-content-wrapper {
flex-grow: 1;
max-width: unset !important;
@ -40,24 +40,68 @@ body.mobile .revisions-dialog {
margin: 0;
display: block !important;
}
.modal-body > .revision-content-wrapper > div:first-of-type {
flex-direction: column;
}
.revision-title {
font-size: 1rem;
}
.revision-title-buttons {
text-align: center;
display: flex;
gap: 0.25em;
flex-wrap: wrap;
}
.revision-content {
padding: 0.5em;
height: fit-content;
}
}
}
.revisions-dialog {
.revision-title-buttons {
flex-shrink: 0;
}
.revision-list {
flex-shrink: 0;
}
.revision-content.type-file {
display: flex;
min-width: 0;
min-height: 0;
flex-grow: 1;
.file-preview-table {
th,
td {
padding: 0.25em 0;
}
}
.revision-file-preview {
display: flex;
flex-direction: column;
min-width: 0;
min-height: 0;
flex-grow: 1;
}
.revision-file-preview-content {
flex-grow: 1;
min-height: 0;
display: flex;
flex-direction: column;
> * {
height: 100%;
}
}
}
}

View File

@ -1,26 +1,31 @@
import type { RevisionPojo, RevisionItem } from "@triliumnext/commons";
import "./revisions.css";
import type { RevisionItem, RevisionPojo } from "@triliumnext/commons";
import clsx from "clsx";
import { diffWords } from "diff";
import type { CSSProperties } from "preact/compat";
import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks";
import appContext from "../../components/app_context";
import FNote from "../../entities/fnote";
import dialog from "../../services/dialog";
import froca from "../../services/froca";
import { t } from "../../services/i18n";
import { renderMathInElement } from "../../services/math";
import open from "../../services/open";
import options from "../../services/options";
import protected_session_holder from "../../services/protected_session_holder";
import server from "../../services/server";
import toast from "../../services/toast";
import Button from "../react/Button";
import FormToggle from "../react/FormToggle";
import Modal from "../react/Modal";
import FormList, { FormListItem } from "../react/FormList";
import utils from "../../services/utils";
import { Dispatch, StateUpdater, useEffect, useRef, useState } from "preact/hooks";
import protected_session_holder from "../../services/protected_session_holder";
import { renderMathInElement } from "../../services/math";
import type { CSSProperties } from "preact/compat";
import open from "../../services/open";
import ActionButton from "../react/ActionButton";
import options from "../../services/options";
import Button from "../react/Button";
import FormList, { FormListItem } from "../react/FormList";
import FormToggle from "../react/FormToggle";
import { useTriliumEvent } from "../react/hooks";
import { diffWords } from "diff";
import "./revisions.css";
import Modal from "../react/Modal";
import { RawHtmlBlock } from "../react/RawHtml";
import PdfViewer from "../type_widgets/file/PdfViewer";
export default function RevisionsDialog() {
const [ note, setNote ] = useState<FNote>();
@ -47,7 +52,7 @@ export default function RevisionsDialog() {
setRevisions(undefined);
setNoteContent(undefined);
}
}, [ note?.noteId, refreshCounter ]);
}, [ note, refreshCounter ]);
if (revisions?.length && !currentRevision) {
setCurrentRevision(revisions[0]);
@ -102,38 +107,38 @@ export default function RevisionsDialog() {
setRevisions(undefined);
}}
show={shown}
>
<RevisionsList
revisions={revisions ?? []}
onSelect={(revisionId) => {
const correspondingRevision = (revisions ?? []).find((r) => r.revisionId === revisionId);
if (correspondingRevision) {
setCurrentRevision(correspondingRevision);
}
}}
currentRevision={currentRevision}
/>
>
<RevisionsList
revisions={revisions ?? []}
onSelect={(revisionId) => {
const correspondingRevision = (revisions ?? []).find((r) => r.revisionId === revisionId);
if (correspondingRevision) {
setCurrentRevision(correspondingRevision);
}
}}
currentRevision={currentRevision}
/>
<div className="revision-content-wrapper" style={{
flexGrow: "1",
marginInlineStart: "20px",
display: "flex",
flexDirection: "column",
maxWidth: "calc(100% - 150px)",
minWidth: 0
}}>
<RevisionPreview
noteContent={noteContent}
revisionItem={currentRevision}
showDiff={showDiff}
setShown={setShown}
onRevisionDeleted={() => {
setRefreshCounter(c => c + 1);
setCurrentRevision(undefined);
}} />
</div>
<div className="revision-content-wrapper" style={{
flexGrow: "1",
marginInlineStart: "20px",
display: "flex",
flexDirection: "column",
maxWidth: "calc(100% - 150px)",
minWidth: 0
}}>
<RevisionPreview
noteContent={noteContent}
revisionItem={currentRevision}
showDiff={showDiff}
setShown={setShown}
onRevisionDeleted={() => {
setRefreshCounter(c => c + 1);
setCurrentRevision(undefined);
}} />
</div>
</Modal>
)
);
}
function RevisionsList({ revisions, onSelect, currentRevision }: { revisions: RevisionItem[], onSelect: (val: string) => void, currentRevision?: RevisionItem }) {
@ -141,6 +146,7 @@ function RevisionsList({ revisions, onSelect, currentRevision }: { revisions: Re
<FormList onSelect={onSelect} fullHeight wrapperClassName="revision-list">
{revisions.map((item) =>
<FormListItem
key={item.revisionId}
value={item.revisionId}
active={currentRevision && item.revisionId === currentRevision.revisionId}
>
@ -202,14 +208,17 @@ function RevisionPreview({noteContent, revisionItem, showDiff, setShown, onRevis
text={t("revisions.download_button")}
onClick={() => {
if (revisionItem.revisionId) {
open.downloadRevision(revisionItem.noteId, revisionItem.revisionId)}
}
open.downloadRevision(revisionItem.noteId, revisionItem.revisionId);}
}
}/>
</>
}
</div>)}
</div>
<div className="revision-content use-tn-links selectable-text" style={{ overflow: "auto", wordBreak: "break-word" }}>
<div
className={clsx("revision-content use-tn-links selectable-text", `type-${revisionItem?.type}`)}
style={{ overflow: "auto", wordBreak: "break-word" }}
>
<RevisionContent noteContent={noteContent} revisionItem={revisionItem} fullRevision={fullRevision} showDiff={showDiff}/>
</div>
</>
@ -230,16 +239,16 @@ const CODE_STYLE: CSSProperties = {
function RevisionContent({ noteContent, revisionItem, fullRevision, showDiff }: { noteContent?:string, revisionItem?: RevisionItem, fullRevision?: RevisionPojo, showDiff: boolean}) {
const content = fullRevision?.content;
if (!revisionItem || !content) {
if (!revisionItem || !fullRevision) {
return <></>;
}
if (showDiff) {
return <RevisionContentDiff noteContent={noteContent} itemContent={content} itemType={revisionItem.type}/>
return <RevisionContentDiff noteContent={noteContent} itemContent={content} itemType={revisionItem.type}/>;
}
switch (revisionItem.type) {
case "text":
return <RevisionContentText content={content} />
return <RevisionContentText content={content} />;
case "code":
return <pre style={CODE_STYLE}>{content}</pre>;
case "image":
@ -256,28 +265,11 @@ function RevisionContent({ noteContent, revisionItem, fullRevision, showDiff }:
// as a URL to be used in a note. Instead, if they copy and paste it into a note, it will be uploaded as a new note
return <img
src={`data:${fullRevision.mime};base64,${fullRevision.content}`}
style={IMAGE_STYLE} />
style={IMAGE_STYLE} />;
}
}
case "file":
return <table cellPadding="10">
<tr>
<th>{t("revisions.mime")}</th>
<td>{revisionItem.mime}</td>
</tr>
<tr>
<th>{t("revisions.file_size")}</th>
<td>{revisionItem.contentLength && utils.formatSize(revisionItem.contentLength)}</td>
</tr>
{fullRevision.content &&
<tr>
<td colspan={2}>
<strong>{t("revisions.preview")}</strong>
<pre className="file-preview-content" style={CODE_STYLE}>{fullRevision.content}</pre>
</td>
</tr>
}
</table>;
return <FilePreview fullRevision={fullRevision} revisionItem={revisionItem} />;
case "canvas":
case "mindMap":
case "mermaid": {
@ -287,7 +279,7 @@ function RevisionContent({ noteContent, revisionItem, fullRevision, showDiff }:
style={IMAGE_STYLE} />;
}
default:
return <>{t("revisions.preview_not_available")}</>
return <>{t("revisions.preview_not_available")}</>;
}
}
@ -298,7 +290,7 @@ function RevisionContentText({ content }: { content: string | Buffer<ArrayBuffer
renderMathInElement(contentRef.current, { trust: true });
}
}, [content]);
return <div ref={contentRef} className="ck-content" dangerouslySetInnerHTML={{ __html: content as string }}></div>
return <RawHtmlBlock containerRef={contentRef} className="ck-content" html={content as string} />;
}
function RevisionContentDiff({ noteContent, itemContent, itemType }: {
@ -330,9 +322,9 @@ function RevisionContentDiff({ noteContent, itemContent, itemType }: {
return `<span class="revision-diff-added">${utils.escapeHtml(part.value)}</span>`;
} else if (part.removed) {
return `<span class="revision-diff-removed">${utils.escapeHtml(part.value)}</span>`;
} else {
return utils.escapeHtml(part.value);
}
return utils.escapeHtml(part.value);
}).join("");
if (contentRef.current) {
@ -340,7 +332,7 @@ function RevisionContentDiff({ noteContent, itemContent, itemType }: {
}
}, [noteContent, itemContent, itemType]);
return <div ref={contentRef} className="ck-content" style={{ whiteSpace: "pre-wrap" }}></div>;
return <div ref={contentRef} className="ck-content" style={{ whiteSpace: "pre-wrap" }} />;
}
function RevisionFooter({ note }: { note?: FNote }) {
@ -348,7 +340,7 @@ function RevisionFooter({ note }: { note?: FNote }) {
return <></>;
}
let revisionsNumberLimit: number | string = parseInt(note?.getLabelValue("versioningLimit") ?? "");
let revisionsNumberLimit: number | string = parseInt(note?.getLabelValue("versioningLimit") ?? "", 10);
if (!Number.isInteger(revisionsNumberLimit)) {
revisionsNumberLimit = options.getInt("revisionSnapshotNumberLimit") ?? 0;
}
@ -370,10 +362,67 @@ function RevisionFooter({ note }: { note?: FNote }) {
</>;
}
function FilePreview({ revisionItem, fullRevision }: { revisionItem: RevisionItem, fullRevision: RevisionPojo }) {
return (
<div className="revision-file-preview">
<table className="file-preview-table">
<tbody>
<tr>
<th>{t("revisions.mime")}</th>
<td>{revisionItem.mime}</td>
</tr>
<tr>
<th>{t("revisions.file_size")}</th>
<td>{revisionItem.contentLength && utils.formatSize(revisionItem.contentLength)}</td>
</tr>
</tbody>
</table>
<div class="revision-file-preview-content">
<FilePreviewInner revisionItem={revisionItem} fullRevision={fullRevision} />
</div>
</div>
);
}
function FilePreviewInner({ revisionItem, fullRevision }: { revisionItem: RevisionItem, fullRevision: RevisionPojo }) {
if (revisionItem.mime.startsWith("audio/")) {
return (
<audio
src={`api/revisions/${revisionItem.revisionId}/download`}
controls
/>
);
}
if (revisionItem.mime.startsWith("video/")) {
return (
<video
src={`api/revisions/${revisionItem.revisionId}/download`}
controls
/>
);
}
if (revisionItem.mime === "application/pdf") {
return (
<PdfViewer
pdfUrl={`../../api/revisions/${revisionItem.revisionId}/download`}
/>
);
}
if (fullRevision.content) {
return <pre className="file-preview-content" style={CODE_STYLE}>{fullRevision.content}</pre>;
}
return t("revisions.preview_not_available");
}
async function getNote(noteId?: string | null) {
if (noteId) {
return await froca.getNote(noteId);
} else {
return appContext.tabManager.getActiveContextNote();
}
return appContext.tabManager.getActiveContextNote();
}

View File

@ -2,6 +2,11 @@
contain: none;
}
@keyframes fadeOut {
from { opacity: var(--default-opacity); }
to { opacity: 0; }
}
.note-badges {
display: flex;
gap: 5px;
@ -16,6 +21,23 @@
&.share-badge {--color: var(--badge-share-background-color);}
&.clipped-note-badge {--color: var(--badge-clipped-note-background-color);}
&.execute-badge {--color: var(--badge-execute-background-color);}
&.save-status-badge {
--default-opacity: 0.4;
opacity: var(--default-opacity);
transition: opacity 250ms ease-in;
color: var(--main-text-color);
&.error {
color: var(--dropdown-item-icon-destructive-color);
opacity: 1;
}
&.saved {
animation: fadeOut 250ms ease-in 5s forwards;
pointer-events: none;
}
}
min-width: 0;
.text {

View File

@ -1,17 +1,20 @@
import "./NoteBadges.css";
import { clsx } from "clsx";
import { copyTextWithToast } from "../../services/clipboard_ext";
import { t } from "../../services/i18n";
import { goToLinkExt } from "../../services/link";
import { Badge, BadgeWithDropdown } from "../react/Badge";
import { FormDropdownDivider, FormListItem } from "../react/FormList";
import { useIsNoteReadOnly, useNoteContext, useNoteLabel, useNoteLabelBoolean } from "../react/hooks";
import { useGetContextData, useIsNoteReadOnly, useNoteContext, useNoteLabel, useNoteLabelBoolean } from "../react/hooks";
import { useShareState } from "../ribbon/BasicPropertiesTab";
import { useShareInfo } from "../shared_info";
export default function NoteBadges() {
return (
<div className="note-badges">
<SaveStatusBadge />
<ReadOnlyBadge />
<ShareBadge />
<ClippedNoteBadge />
@ -105,3 +108,42 @@ function ExecuteBadge() {
/>
);
}
export function SaveStatusBadge() {
const saveState = useGetContextData("saveState");
if (!saveState) return;
const stateConfig = {
saved: {
icon: "bx bx-check",
title: t("breadcrumb_badges.save_status_saved"),
tooltip: undefined
},
saving: {
icon: "bx bx-loader bx-spin",
title: t("breadcrumb_badges.save_status_saving"),
tooltip: t("breadcrumb_badges.save_status_saving_tooltip")
},
unsaved: {
icon: "bx bx-pencil",
title: t("breadcrumb_badges.save_status_unsaved"),
tooltip: t("breadcrumb_badges.save_status_unsaved_tooltip")
},
error: {
icon: "bx bxs-error",
title: t("breadcrumb_badges.save_status_error"),
tooltip: t("breadcrumb_badges.save_status_error_tooltip")
}
};
const { icon, title, tooltip } = stateConfig[saveState.state];
return (
<Badge
className={clsx("save-status-badge", saveState.state)}
icon={icon}
text={title}
tooltip={tooltip}
/>
);
}

View File

@ -19,7 +19,7 @@ import options, { type OptionValue } from "../../services/options";
import protected_session_holder from "../../services/protected_session_holder";
import server from "../../services/server";
import shortcuts, { Handler, removeIndividualBinding } from "../../services/shortcuts";
import SpacedUpdate from "../../services/spaced_update";
import SpacedUpdate, { type StateCallback } from "../../services/spaced_update";
import toast, { ToastOptions } from "../../services/toast";
import tree from "../../services/tree";
import utils, { escapeRegExp, getErrorMessage, randomString, reloadFrontendApp } from "../../services/utils";
@ -63,22 +63,29 @@ export function useTriliumEvents<T extends EventNames>(eventNames: T[], handler:
useDebugValue(() => eventNames.join(", "));
}
export function useSpacedUpdate(callback: () => void | Promise<void>, interval = 1000) {
export function useSpacedUpdate(callback: () => void | Promise<void>, interval = 1000, stateCallback?: StateCallback) {
const callbackRef = useRef(callback);
const stateCallbackRef = useRef(stateCallback);
const spacedUpdateRef = useRef<SpacedUpdate>(new SpacedUpdate(
() => callbackRef.current(),
interval
interval,
(state) => stateCallbackRef.current?.(state)
));
// Update callback ref when it changes
useEffect(() => {
callbackRef.current = callback;
}, [callback]);
}, [ callback ]);
// Update state callback when it changes.
useEffect(() => {
stateCallbackRef.current = stateCallback;
}, [ stateCallback ]);
// Update interval if it changes
useEffect(() => {
spacedUpdateRef.current?.setUpdateInterval(interval);
}, [interval]);
}, [ interval ]);
return spacedUpdateRef.current;
}
@ -121,7 +128,12 @@ export function useEditorSpacedUpdate({ note, noteType, noteContext, getData, on
dataSaved?.(data);
};
}, [ note, getData, dataSaved, noteType, parentComponent ]);
const spacedUpdate = useSpacedUpdate(callback);
const stateCallback = useCallback<StateCallback>((state) => {
noteContext?.setContextData("saveState", {
state
});
}, [ noteContext ]);
const spacedUpdate = useSpacedUpdate(callback, updateInterval, stateCallback);
// React to note/blob changes.
useEffect(() => {

View File

@ -1,3 +1,5 @@
import { useContext } from "preact/hooks";
import FNote from "../../entities/fnote";
import { t } from "../../services/i18n";
import { downloadFileNote, openNoteExternally } from "../../services/open";
@ -8,11 +10,14 @@ import { formatSize } from "../../services/utils";
import Button from "../react/Button";
import { FormFileUploadButton } from "../react/FormFileUpload";
import { useNoteBlob, useNoteLabel } from "../react/hooks";
import { ParentComponent } from "../react/react_utils";
import { TabContext } from "./ribbon-interface";
export default function FilePropertiesTab({ note }: { note?: FNote | null }) {
export default function FilePropertiesTab({ note, ntxId }: Pick<TabContext, "note" | "ntxId">) {
const [ originalFileName ] = useNoteLabel(note, "originalFileName");
const canAccessProtectedNote = !note?.isProtected || protected_session_holder.isProtectedSessionAvailable();
const blob = useNoteBlob(note);
const parentComponent = useContext(ParentComponent);
return (
<div className="file-properties-widget">
@ -40,7 +45,7 @@ export default function FilePropertiesTab({ note }: { note?: FNote | null }) {
text={t("file_properties.download")}
primary
disabled={!canAccessProtectedNote}
onClick={() => downloadFileNote(note.noteId)}
onClick={() => downloadFileNote(note, parentComponent, ntxId)}
/>
<Button

View File

@ -44,7 +44,7 @@ export default function ImagePropertiesTab({ note, ntxId }: TabContext) {
text={t("image_properties.download")}
icon="bx bx-download"
primary
onClick={() => downloadFileNote(note.noteId)}
onClick={() => downloadFileNote(note, parentComponent, ntxId)}
/>
<Button

View File

@ -135,13 +135,13 @@ function OpenExternallyButton({ note, noteMime }: NoteActionsCustomInnerProps) {
);
}
function DownloadFileButton({ note }: NoteActionsCustomInnerProps) {
function DownloadFileButton({ note, parentComponent, ntxId }: NoteActionsCustomInnerProps) {
return (
<ActionButton
icon="bx bx-download"
text={t("file_properties.download")}
disabled={!note.isContentAvailable()}
onClick={() => downloadFileNote(note.noteId)}
onClick={() => downloadFileNote(note, parentComponent, ntxId)}
/>
);
}

View File

@ -1,5 +1,4 @@
import { RefObject } from "preact";
import { useCallback, useEffect, useRef } from "preact/hooks";
import { useEffect, useRef } from "preact/hooks";
import appContext from "../../../components/app_context";
import type NoteContext from "../../../components/note_context";
@ -7,15 +6,8 @@ import FBlob from "../../../entities/fblob";
import FNote from "../../../entities/fnote";
import server from "../../../services/server";
import { useViewModeConfig } from "../../collections/NoteList";
import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
const VARIABLE_WHITELIST = new Set([
"root-background",
"main-background-color",
"main-border-color",
"main-text-color",
"theme-style"
]);
import { useTriliumEvent } from "../../react/hooks";
import PdfViewer from "./PdfViewer";
export default function PdfPreview({ note, blob, componentId, noteContext }: {
note: FNote;
@ -24,20 +16,21 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
componentId: string | undefined;
}) {
const iframeRef = useRef<HTMLIFrameElement>(null);
const { onLoad } = useStyleInjection(iframeRef);
const historyConfig = useViewModeConfig(note, "pdfHistory");
const [ locale ] = useTriliumOption("locale");
const [ newLayout ] = useTriliumOptionBool("newLayout");
const historyConfig = useViewModeConfig<HistoryData>(note, "pdfHistory");
useEffect(() => {
function handleMessage(event: MessageEvent) {
if (event.data?.type === "pdfjs-viewer-document-modified" && event.data?.data) {
const blob = new Blob([event.data.data], { type: note.mime });
server.upload(`notes/${note.noteId}/file`, new File([blob], note.title, { type: note.mime }), componentId);
function handleMessage(event: PdfMessageEvent) {
if (event.data?.type === "pdfjs-viewer-document-modified") {
const blob = new Blob([event.data.data as Uint8Array<ArrayBuffer>], { type: note.mime });
if (event.data.noteId === note.noteId && event.data.ntxId === noteContext.ntxId) {
server.upload(`notes/${note.noteId}/file`, new File([blob], note.title, { type: note.mime }), componentId);
}
}
if (event.data.type === "pdfjs-viewer-save-view-history" && event.data?.data) {
historyConfig?.storeFn(JSON.parse(event.data.data));
if (event.data.noteId === note.noteId && event.data.ntxId === noteContext.ntxId) {
historyConfig?.storeFn(JSON.parse(event.data.data));
}
}
if (event.data.type === "pdfjs-viewer-toc") {
@ -152,18 +145,25 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
}
}, [ blob ]);
useTriliumEvent("customDownload", ({ ntxId }) => {
if (ntxId !== noteContext.ntxId) return;
iframeRef.current?.contentWindow?.postMessage({
type: "trilium-request-download"
});
});
return (historyConfig &&
<iframe
<PdfViewer
iframeRef={iframeRef}
tabIndex={300}
ref={iframeRef}
class="pdf-preview"
src={`pdfjs/web/viewer.html?file=../../api/notes/${note.noteId}/open&lang=${locale}&sidebar=${newLayout ? "0" : "1"}`}
pdfUrl={`../../api/notes/${note.noteId}/open`}
onLoad={() => {
const win = iframeRef.current?.contentWindow;
if (win) {
win.TRILIUM_VIEW_HISTORY_STORE = historyConfig.config;
win.TRILIUM_NOTE_ID = note.noteId;
win.TRILIUM_NTX_ID = noteContext.ntxId;
}
onLoad();
if (iframeRef.current?.contentWindow) {
iframeRef.current.contentWindow.addEventListener('click', () => {
@ -175,66 +175,6 @@ export default function PdfPreview({ note, blob, componentId, noteContext }: {
);
}
function useStyleInjection(iframeRef: RefObject<HTMLIFrameElement>) {
const styleRef = useRef<HTMLStyleElement | null>(null);
// First load.
const onLoad = useCallback(() => {
const doc = iframeRef.current?.contentDocument;
if (!doc) return;
const style = doc.createElement('style');
style.id = 'client-root-vars';
style.textContent = cssVarsToString(getRootCssVariables());
styleRef.current = style;
doc.head.appendChild(style);
}, [ iframeRef ]);
// React to changes.
useEffect(() => {
const listener = () => {
styleRef.current!.textContent = cssVarsToString(getRootCssVariables());
};
const media = window.matchMedia("(prefers-color-scheme: dark)");
media.addEventListener("change", listener);
return () => media.removeEventListener("change", listener);
}, [ iframeRef ]);
return {
onLoad
};
}
function getRootCssVariables() {
const styles = getComputedStyle(document.documentElement);
const vars: Record<string, string> = {};
for (let i = 0; i < styles.length; i++) {
const prop = styles[i];
if (prop.startsWith('--') && VARIABLE_WHITELIST.has(prop.substring(2))) {
vars[`--tn-${prop.substring(2)}`] = styles.getPropertyValue(prop).trim();
}
}
return vars;
}
function cssVarsToString(vars: Record<string, string>) {
return `:root {\n${Object.entries(vars)
.map(([k, v]) => ` ${k}: ${v};`)
.join('\n')}\n}`;
}
interface PdfOutlineItem {
title: string;
level: number;
dest: unknown;
id: string;
items: PdfOutlineItem[];
}
interface PdfHeading {
level: number;
text: string;

View File

@ -0,0 +1,90 @@
import type { HTMLAttributes, RefObject } from "preact";
import { useCallback, useEffect, useRef } from "preact/hooks";
import { useSyncedRef, useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
const VARIABLE_WHITELIST = new Set([
"root-background",
"main-background-color",
"main-border-color",
"main-text-color"
]);
interface PdfViewerProps extends Pick<HTMLAttributes<HTMLIFrameElement>, "tabIndex"> {
iframeRef?: RefObject<HTMLIFrameElement>;
/** Note: URLs are relative to /pdfjs/web. */
pdfUrl: string;
onLoad?(): void;
}
/**
* Reusable component displaying a PDF. The PDF needs to be provided via a URL.
*/
export default function PdfViewer({ iframeRef: externalIframeRef, pdfUrl, onLoad }: PdfViewerProps) {
const iframeRef = useSyncedRef(externalIframeRef, null);
const [ locale ] = useTriliumOption("locale");
const [ newLayout ] = useTriliumOptionBool("newLayout");
const injectStyles = useStyleInjection(iframeRef);
return (
<iframe
ref={iframeRef}
class="pdf-preview"
src={`pdfjs/web/viewer.html?file=${pdfUrl}&lang=${locale}&sidebar=${newLayout ? "0" : "1"}`}
onLoad={() => {
injectStyles();
onLoad?.();
}}
/>
);
}
function useStyleInjection(iframeRef: RefObject<HTMLIFrameElement>) {
const styleRef = useRef<HTMLStyleElement | null>(null);
// First load.
const onLoad = useCallback(() => {
const doc = iframeRef.current?.contentDocument;
if (!doc) return;
const style = doc.createElement('style');
style.id = 'client-root-vars';
style.textContent = cssVarsToString(getRootCssVariables());
styleRef.current = style;
doc.head.appendChild(style);
}, [ iframeRef ]);
// React to changes.
useEffect(() => {
const listener = () => {
styleRef.current!.textContent = cssVarsToString(getRootCssVariables());
};
const media = window.matchMedia("(prefers-color-scheme: dark)");
media.addEventListener("change", listener);
return () => media.removeEventListener("change", listener);
}, [ iframeRef ]);
return onLoad;
}
function getRootCssVariables() {
const styles = getComputedStyle(document.documentElement);
const vars: Record<string, string> = {};
for (let i = 0; i < styles.length; i++) {
const prop = styles[i];
if (prop.startsWith('--') && VARIABLE_WHITELIST.has(prop.substring(2))) {
vars[`--tn-${prop.substring(2)}`] = styles.getPropertyValue(prop).trim();
}
}
return vars;
}
function cssVarsToString(vars: Record<string, string>) {
return `:root {\n${Object.entries(vars)
.map(([k, v]) => ` ${k}: ${v};`)
.join('\n')}\n}`;
}

File diff suppressed because one or more lines are too long

View File

@ -35,11 +35,11 @@ class="image image_resized" style="width:74.04%;">
href="#root/_help_vvUCN7FDkq7G">Installing Ollama</a>.</p>
<p>To see what embedding models Ollama has available, you can check out
<a
href="https://ollama.com/search?c=embedding">this search</a>on their website, and then <code>pull</code> whichever one
you want to try out. A popular choice is <code>mxbai-embed-large</code>.</p>
href="https://ollama.com/search?c=embedding">this search</a>on their website, and then <code spellcheck="false">pull</code> whichever
one you want to try out. A popular choice is <code spellcheck="false">mxbai-embed-large</code>.</p>
<p>First, we'll need to select the Ollama provider from the tabs of providers,
then we will enter in the Base URL for our Ollama. Since our Ollama is
running on our local machine, our Base URL is <code>http://localhost:11434</code>.
running on our local machine, our Base URL is <code spellcheck="false">http://localhost:11434</code>.
We will then hit the “refresh” button to have it fetch our models:</p>
<figure
class="image image_resized" style="width:82.28%;">
@ -80,57 +80,57 @@ class="image image_resized" style="width:74.04%;">
<p>These are the tools that currently exist, and will certainly be updated
to be more effectively (and even more to be added!):</p>
<ul>
<li><code>search_notes</code>
<li><code spellcheck="false">search_notes</code>
<ul>
<li>Semantic search</li>
</ul>
</li>
<li><code>keyword_search</code>
<li><code spellcheck="false">keyword_search</code>
<ul>
<li>Keyword-based search</li>
</ul>
</li>
<li><code>attribute_search</code>
<li><code spellcheck="false">attribute_search</code>
<ul>
<li>Attribute-specific search</li>
</ul>
</li>
<li><code>search_suggestion</code>
<li><code spellcheck="false">search_suggestion</code>
<ul>
<li>Search syntax helper</li>
</ul>
</li>
<li><code>read_note</code>
<li><code spellcheck="false">read_note</code>
<ul>
<li>Read note content (helps the LLM read Notes)</li>
</ul>
</li>
<li><code>create_note</code>
<li><code spellcheck="false">create_note</code>
<ul>
<li>Create a Note</li>
</ul>
</li>
<li><code>update_note</code>
<li><code spellcheck="false">update_note</code>
<ul>
<li>Update a Note</li>
</ul>
</li>
<li><code>manage_attributes</code>
<li><code spellcheck="false">manage_attributes</code>
<ul>
<li>Manage attributes on a Note</li>
</ul>
</li>
<li><code>manage_relationships</code>
<li><code spellcheck="false">manage_relationships</code>
<ul>
<li>Manage the various relationships between Notes</li>
</ul>
</li>
<li><code>extract_content</code>
<li><code spellcheck="false">extract_content</code>
<ul>
<li>Used to smartly extract content from a Note</li>
</ul>
</li>
<li><code>calendar_integration</code>
<li><code spellcheck="false">calendar_integration</code>
<ul>
<li>Used to find date notes, create date notes, get the daily note, etc.</li>
</ul>

View File

@ -23,14 +23,14 @@ class="image image_resized" style="width:50.49%;">
<img style="aspect-ratio:1161/480;" src="2_Installing Ollama_image.png"
width="1161" height="480">
</figure>
<p>Also, you should have access to the <code>ollama</code> CLI via Powershell
or CMD:</p>
<p>Also, you should have access to the <code spellcheck="false">ollama</code> CLI
via Powershell or CMD:</p>
<figure class="image image_resized" style="width:86.09%;">
<img style="aspect-ratio:1730/924;" src="5_Installing Ollama_image.png"
width="1730" height="924">
</figure>
<p>After Ollama is installed, you can go ahead and <code>pull</code> the models
you want to use and run. Here's a command to pull my favorite tool-compatible
<p>After Ollama is installed, you can go ahead and <code spellcheck="false">pull</code> the
models you want to use and run. Here's a command to pull my favorite tool-compatible
model and embedding model as of April 2025:</p><pre><code class="language-text-x-trilium-auto">ollama pull llama3.1:8b
ollama pull mxbai-embed-large</code></pre>
<p>Also, you can make sure it's running by going to <a href="http://localhost:11434">http://localhost:11434</a> and

View File

@ -28,125 +28,160 @@
where you can track your daily weight. This data is then used in <a href="#root/_help_R7abl2fc6Mxi">Weight tracker</a>.</p>
<h2>Week Note and Quarter Note</h2>
<p>Week and quarter notes are disabled by default, since it might be too
much for some people. To enable them, you need to set <code>#enableWeekNote</code> and <code>#enableQuarterNote</code> attributes
on the root calendar note, which is identified by <code>#calendarRoot</code> label.
Week note is affected by the first week of year option. Be careful when
you already have some week notes created, it will not automatically change
the existing week notes and might lead to some duplicates.</p>
much for some people. To enable them, you need to set <code spellcheck="false">#enableWeekNote</code> and
<code
spellcheck="false">#enableQuarterNote</code>attributes on the root calendar note, which is
identified by <code spellcheck="false">#calendarRoot</code> label. Week note
is affected by the first week of year option. Be careful when you already
have some week notes created, it will not automatically change the existing
week notes and might lead to some duplicates.</p>
<h2>Templates</h2>
<p>Trilium provides <a href="#root/_help_KC1HB96bqqHX">template</a> functionality,
and it could be used together with day notes.</p>
<p>You can define one of the following relations on the root of the journal
(identified by <code>#calendarRoot</code> label):</p>
(identified by <code spellcheck="false">#calendarRoot</code> label):</p>
<ul>
<li>yearTemplate</li>
<li>quarterTemplate (if <code>#enableQuarterNote</code> is set)</li>
<li>quarterTemplate (if <code spellcheck="false">#enableQuarterNote</code> is
set)</li>
<li>monthTemplate</li>
<li>weekTemplate (if <code>#enableWeekNote</code> is set)</li>
<li>weekTemplate (if <code spellcheck="false">#enableWeekNote</code> is set)</li>
<li>dateTemplate</li>
</ul>
<p>All of these are relations. When Trilium creates a new note for year or
month or date, it will take a look at the root and attach a corresponding <code>~template</code> relation
to the newly created role. Using this, you can e.g. create your daily template
with e.g. checkboxes for daily routine etc.</p>
month or date, it will take a look at the root and attach a corresponding
<code
spellcheck="false">~template</code>relation to the newly created role. Using this, you can
e.g. create your daily template with e.g. checkboxes for daily routine
etc.</p>
<h3>Migrate from old template usage</h3>
<p>If you have been using Journal prior to version v0.93.0, the previous
template pattern likely used was <code>~child:template=</code>.
template pattern likely used was <code spellcheck="false">~child:template=</code>.
<br>To transition to the new system:</p>
<ol>
<li>Set up the new template pattern in the Calendar root note.</li>
<li>Use <a href="#root/_help_ivYnonVFBxbQ">Bulk Actions</a> to remove <code>child:template</code> and <code>child:child:template</code> from
all notes under the Journal (calendar root).</li>
<li>Use <a href="#root/_help_ivYnonVFBxbQ">Bulk Actions</a> to remove <code spellcheck="false">child:template</code> and
<code
spellcheck="false">child:child:template</code>from all notes under the Journal (calendar
root).</li>
<li>Ensure that all old template patterns are fully removed to prevent conflicts
with the new setup.</li>
</ol>
<h2>Naming pattern</h2>
<p>You can customize the title of generated journal notes by defining a <code>#datePattern</code>, <code>#weekPattern</code>, <code>#monthPattern</code>, <code>#quarterPattern</code> and <code>#yearPattern</code> attribute
on a root calendar note (identified by <code>#calendarRoot</code> label).
The naming pattern replacements follow a level-up compatibility - each
level can use replacements from itself and all levels above it. For example, <code>#monthPattern</code> can
use month, quarter and year replacements, while <code>#weekPattern</code> can
use week, month, quarter and year replacements. But it is not possible
to use week replacements in <code>#monthPattern</code>.</p>
<p>You can customize the title of generated journal notes by defining a
<code
spellcheck="false">#datePattern</code>, <code spellcheck="false">#weekPattern</code>,
<code
spellcheck="false">#monthPattern</code>, <code spellcheck="false">#quarterPattern</code> and
<code
spellcheck="false">#yearPattern</code>attribute on a root calendar note (identified by
<code
spellcheck="false">#calendarRoot</code>label). The naming pattern replacements follow a level-up
compatibility - each level can use replacements from itself and all levels
above it. For example, <code spellcheck="false">#monthPattern</code> can
use month, quarter and year replacements, while <code spellcheck="false">#weekPattern</code> can
use week, month, quarter and year replacements. But it is not possible
to use week replacements in <code spellcheck="false">#monthPattern</code>.</p>
<h3>Date pattern</h3>
<p>It's possible to customize the title of generated date notes by defining
a <code>#datePattern</code> attribute on a root calendar note (identified
by <code>#calendarRoot</code> label). Following are possible values:</p>
a <code spellcheck="false">#datePattern</code> attribute on a root calendar
note (identified by <code spellcheck="false">#calendarRoot</code> label).
Following are possible values:</p>
<ul>
<li><code>{isoDate}</code> results in an ISO 8061 formatted date (e.g. "2025-03-09"
for March 9, 2025)</li>
<li><code>{dateNumber}</code> results in a number like <code>9</code> for the
9th day of the month, <code>11</code> for the 11th day of the month</li>
<li><code>{dateNumberPadded}</code> results in a number like <code>09</code> for
the 9th day of the month, <code>11</code> for the 11th day of the month</li>
<li><code>{ordinal}</code> is replaced with the ordinal date (e.g. 1st, 2nd,
3rd) etc.</li>
<li><code>{weekDay}</code> results in the full day name (e.g. <code>Monday</code>)</li>
<li><code>{weekDay3}</code> is replaced with the first 3 letters of the day,
e.g. Mon, Tue, etc.</li>
<li><code>{weekDay2}</code> is replaced with the first 2 letters of the day,
e.g. Mo, Tu, etc.</li>
<li><code spellcheck="false">{isoDate}</code> results in an ISO 8061 formatted
date (e.g. "2025-03-09" for March 9, 2025)</li>
<li><code spellcheck="false">{dateNumber}</code> results in a number like
<code
spellcheck="false">9</code>for the 9th day of the month, <code spellcheck="false">11</code> for
the 11th day of the month</li>
<li><code spellcheck="false">{dateNumberPadded}</code> results in a number
like <code spellcheck="false">09</code> for the 9th day of the month,
<code
spellcheck="false">11</code>for the 11th day of the month</li>
<li><code spellcheck="false">{ordinal}</code> is replaced with the ordinal
date (e.g. 1st, 2nd, 3rd) etc.</li>
<li><code spellcheck="false">{weekDay}</code> results in the full day name
(e.g. <code spellcheck="false">Monday</code>)</li>
<li><code spellcheck="false">{weekDay3}</code> is replaced with the first 3
letters of the day, e.g. Mon, Tue, etc.</li>
<li><code spellcheck="false">{weekDay2}</code> is replaced with the first 2
letters of the day, e.g. Mo, Tu, etc.</li>
</ul>
<p>The default is <code>{dateNumberPadded} - {weekDay}</code>
<p>The default is <code spellcheck="false">{dateNumberPadded} - {weekDay}</code>
</p>
<h3>Week pattern</h3>
<p>It is also possible to customize the title of generated week notes through
the <code>#weekPattern</code> attribute on the root calendar note. The options
are:</p>
the <code spellcheck="false">#weekPattern</code> attribute on the root calendar
note. The options are:</p>
<ul>
<li><code>{weekNumber}</code> results in a number like <code>9</code> for the
9th week of the year, <code>11</code> for the 11th week of the year</li>
<li><code>{weekNumberPadded}</code> results in a number like <code>09</code> for
the 9th week of the year, <code>11</code> for the 11th week of the year</li>
<li><code>{shortWeek}</code> results in a short week string like <code>W9</code> for
the 9th week of the year, <code>W11</code> for the 11th week of the year</li>
<li><code>{shortWeek3}</code> results in a short week string like <code>W09</code> for
the 9th week of the year, <code>W11</code> for the 11th week of the year</li>
<li><code spellcheck="false">{weekNumber}</code> results in a number like
<code
spellcheck="false">9</code>for the 9th week of the year, <code spellcheck="false">11</code> for
the 11th week of the year</li>
<li><code spellcheck="false">{weekNumberPadded}</code> results in a number
like <code spellcheck="false">09</code> for the 9th week of the year,
<code
spellcheck="false">11</code>for the 11th week of the year</li>
<li><code spellcheck="false">{shortWeek}</code> results in a short week string
like <code spellcheck="false">W9</code> for the 9th week of the year,
<code
spellcheck="false">W11</code>for the 11th week of the year</li>
<li><code spellcheck="false">{shortWeek3}</code> results in a short week string
like <code spellcheck="false">W09</code> for the 9th week of the year,
<code
spellcheck="false">W11</code>for the 11th week of the year</li>
</ul>
<p>The default is <code>Week {weekNumber}</code>
<p>The default is <code spellcheck="false">Week {weekNumber}</code>
</p>
<h3>Month pattern</h3>
<p>It is also possible to customize the title of generated month notes through
the <code>#monthPattern</code> attribute on the root calendar note. The options
are:</p>
the <code spellcheck="false">#monthPattern</code> attribute on the root calendar
note. The options are:</p>
<ul>
<li><code>{isoMonth}</code> results in an ISO 8061 formatted month (e.g. "2025-03"
for March 2025)</li>
<li><code>{monthNumber}</code> results in a number like <code>9</code> for September,
and <code>11</code> for November</li>
<li><code>{monthNumberPadded}</code> results in a number like <code>09</code> for
September, and <code>11</code> for November</li>
<li><code>{month}</code> results in the full month name (e.g. <code>September</code> or <code>October</code>)</li>
<li><code>{shortMonth3}</code> is replaced with the first 3 letters of the
month, e.g. Jan, Feb, etc.</li>
<li><code>{shortMonth4}</code> is replaced with the first 4 letters of the
month, e.g. Sept, Octo, etc.</li>
<li><code spellcheck="false">{isoMonth}</code> results in an ISO 8061 formatted
month (e.g. "2025-03" for March 2025)</li>
<li><code spellcheck="false">{monthNumber}</code> results in a number like
<code
spellcheck="false">9</code>for September, and <code spellcheck="false">11</code> for November</li>
<li><code spellcheck="false">{monthNumberPadded}</code> results in a number
like <code spellcheck="false">09</code> for September, and <code spellcheck="false">11</code> for
November</li>
<li><code spellcheck="false">{month}</code> results in the full month name
(e.g. <code spellcheck="false">September</code> or <code spellcheck="false">October</code>)</li>
<li><code spellcheck="false">{shortMonth3}</code> is replaced with the first
3 letters of the month, e.g. Jan, Feb, etc.</li>
<li><code spellcheck="false">{shortMonth4}</code> is replaced with the first
4 letters of the month, e.g. Sept, Octo, etc.</li>
</ul>
<p>The default is <code>{monthNumberPadded} - {month}</code>
<p>The default is <code spellcheck="false">{monthNumberPadded} - {month}</code>
</p>
<h3>Quarter pattern</h3>
<p>It is also possible to customize the title of generated quarter notes
through the <code>#quarterPattern</code> attribute on the root calendar note.
The options are:</p>
through the <code spellcheck="false">#quarterPattern</code> attribute on
the root calendar note. The options are:</p>
<ul>
<li><code>{quarterNumber}</code> results in a number like <code>1</code> for
the 1st quarter of the year</li>
<li><code>{shortQuarter}</code> results in a short quarter string like <code>Q1</code> for
the 1st quarter of the year</li>
<li><code spellcheck="false">{quarterNumber}</code> results in a number like
<code
spellcheck="false">1</code>for the 1st quarter of the year</li>
<li><code spellcheck="false">{shortQuarter}</code> results in a short quarter
string like <code spellcheck="false">Q1</code> for the 1st quarter of the
year</li>
</ul>
<p>The default is <code>Quarter {quarterNumber}</code>
<p>The default is <code spellcheck="false">Quarter {quarterNumber}</code>
</p>
<h3>Year pattern</h3>
<p>It is also possible to customize the title of generated year notes through
the <code>#yearPattern</code> attribute on the root calendar note. The options
are:</p>
the <code spellcheck="false">#yearPattern</code> attribute on the root calendar
note. The options are:</p>
<ul>
<li><code>{year}</code> results in the full year (e.g. <code>2025</code>)</li>
<li><code spellcheck="false">{year}</code> results in the full year (e.g.
<code
spellcheck="false">2025</code>)</li>
</ul>
<p>The default is <code>{year}</code>
<p>The default is <code spellcheck="false">{year}</code>
</p>
<h2>Implementation</h2>
<p>Trilium has some special support for day notes in the form of <a href="https://triliumnext.github.io/Notes/backend_api/BackendScriptApi.html">backend Script API</a> -
see e.g. getDayNote() function.</p>
<p>Day (and year, month) notes are created with a label - e.g. <code>#dateNote="2025-03-09"</code> this
<p>Day (and year, month) notes are created with a label - e.g. <code spellcheck="false">#dateNote="2025-03-09"</code> this
can then be used by other scripts to add new notes to day note etc.</p>

View File

@ -14,13 +14,13 @@
note and doneDate note (with <a href="#root/_help_kBrnXNG3Hplm">prefix</a> of either
"TODO" or "DONE").</p>
<h2>Implementation</h2>
<p>New tasks are created in the TODO note which has <code>~child:template</code>
<p>New tasks are created in the TODO note which has <code spellcheck="false">~child:template</code>
<a
href="#root/_help_zEY4DaJG4YT5">relation</a>(see <a href="#root/_help_bwZpz2ajCEwO">attribute inheritance</a>)
pointing to the task template.</p>
<h3>Attributes</h3>
<p>Task template defines several <a href="#root/_help_OFXdgB2nNk1F">promoted attributes</a> -
todoDate, doneDate, tags, location. Importantly it also defines <code>~runOnAttributeChange</code> relation
todoDate, doneDate, tags, location. Importantly it also defines <code spellcheck="false">~runOnAttributeChange</code> relation
- <a href="#root/_help_GPERMystNGTB">event</a> handler which is run on attribute
change. This <a href="#root/_help_CdNpE2pqjmI6">script</a> handles when e.g. we
fill out the doneDate attribute - meaning the task is done and should be
@ -56,10 +56,10 @@
span.fancytree-node.done .fancytree-title {
color: green !important;
}</code></pre>
<p>This <a href="#root/_help_6f9hih2hXXZk">code note</a> has <code>#appCss</code>
<p>This <a href="#root/_help_6f9hih2hXXZk">code note</a> has <code spellcheck="false">#appCss</code>
<a
href="#root/_help_zEY4DaJG4YT5">label</a>which is recognized by Trilium on startup and loaded as CSS into
the application.</p>
<p>Second part of this functionality is based in event handler described
above which assigns <code>#cssClass</code> label to the task to either "done"
or "todo" based on the task status.</p>
above which assigns <code spellcheck="false">#cssClass</code> label to the
task to either "done" or "todo" based on the task status.</p>

View File

@ -1,28 +1,31 @@
<p>
<img src="Weight Tracker_image.png">
</p>
<p>The <code>Weight Tracker</code> is a <a href="#root/_help_GLks18SNjxmC">Script API</a> showcase
<p>The <code spellcheck="false">Weight Tracker</code> is a <a href="#root/_help_GLks18SNjxmC">Script API</a> showcase
present in the <a href="#root/_help_wX4HbRucYSDD">demo notes</a>.</p>
<p>By adding <code>weight</code> as a <a href="#root/_help_OFXdgB2nNk1F">promoted attribute</a> in
<p>By adding <code spellcheck="false">weight</code> as a <a href="#root/_help_OFXdgB2nNk1F">promoted attribute</a> in
the <a href="#root/_help_KC1HB96bqqHX">template</a> from which <a href="#root/_help_l0tKav7yLHGF">day notes</a> are
created, you can aggregate the data and plot weight change over time.</p>
<h2>Implementation</h2>
<p>The <code>Weight Tracker</code> note in the screenshot above is of the type <code>Render Note</code>.
That type of note doesn't have any useful content itself. Instead it is
a placeholder where a <a href="#root/_help_CdNpE2pqjmI6">script</a> can render
its output.</p>
<p>Scripts for <code>Render Notes</code> are defined in a <a href="#root/_help_zEY4DaJG4YT5">relation</a> called <code>~renderNote</code>.
In this example, it's the <code>Weight Tracker</code>'s child <code>Implementation</code>.
The Implementation consists of two <a href="#root/_help_6f9hih2hXXZk">code notes</a> that
contain some HTML and JavaScript respectively, which load all the notes
with a <code>weight</code> attribute and display their values in a chart.</p>
<p>The <code spellcheck="false">Weight Tracker</code> note in the screenshot
above is of the type <code spellcheck="false">Render Note</code>. That type
of note doesn't have any useful content itself. Instead it is a placeholder
where a <a href="#root/_help_CdNpE2pqjmI6">script</a> can render its output.</p>
<p>Scripts for <code spellcheck="false">Render Notes</code> are defined in
a <a href="#root/_help_zEY4DaJG4YT5">relation</a> called <code spellcheck="false">~renderNote</code>.
In this example, it's the <code spellcheck="false">Weight Tracker</code>'s
child <code spellcheck="false">Implementation</code>. The Implementation
consists of two <a href="#root/_help_6f9hih2hXXZk">code notes</a> that contain
some HTML and JavaScript respectively, which load all the notes with a
<code
spellcheck="false">weight</code>attribute and display their values in a chart.</p>
<p>To actually render the chart, we're using a third party library called
<a
href="https://www.chartjs.org/">chart.js</a>which is imported as an attachment, since it's not built into
Trilium.</p>
<h3>Code</h3>
<p>Here's the content of the script which is placed in a <a href="#root/_help_6f9hih2hXXZk">code note</a> of
type <code>JS Frontend</code>:</p><pre><code class="language-text-x-trilium-auto">async function getChartData() {
type <code spellcheck="false">JS Frontend</code>:</p><pre><code class="language-text-x-trilium-auto">async function getChartData() {
const days = await api.runOnBackend(async () =&gt; {
const notes = api.getNotesWithLabel('weight');
const days = [];
@ -68,6 +71,7 @@ new chartjs.Chart(ctx, {
data: await getChartData()
});</code></pre>
<h2>How to remove the Weight Tracker button from the top bar</h2>
<p>In the link map of the <code>Weight Tracker</code>, there is a note called <code>Button</code>.
Open it and delete or comment out its contents. The <code>Weight Tracker</code> button
<p>In the link map of the <code spellcheck="false">Weight Tracker</code>,
there is a note called <code spellcheck="false">Button</code>. Open it and
delete or comment out its contents. The <code spellcheck="false">Weight Tracker</code> button
will disappear after you restart Trilium.</p>

View File

@ -29,9 +29,9 @@
<ol>
<li><strong>System attributes</strong>
<br>As the name suggest, these attributes have a special meaning since they
are interpreted by Trilium. For example the <code>color</code> attribute
are interpreted by Trilium. For example the <code spellcheck="false">color</code> attribute
will change the color of the note as displayed in the&nbsp;<a class="reference-link"
href="#root/_help_oPVyFC7WL2Lp">Note Tree</a>&nbsp;and links, and <code>iconClass</code> will
href="#root/_help_oPVyFC7WL2Lp">Note Tree</a>&nbsp;and links, and <code spellcheck="false">iconClass</code> will
change the icon of a note.</li>
<li><strong>User-defined attributes</strong>
<br>These are free-form labels or relations that can be used by the user.
@ -43,8 +43,8 @@
<p>In practice, Trilium makes no direct distinction of whether an attribute
is a system one or a user-defined one. A label or relation is considered
a system attribute if it matches one of the built-in names (e.g. like the
aforementioned <code>iconClass</code>). Keep this in mind when creating
&nbsp;<a class="reference-link" href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;in
aforementioned <code spellcheck="false">iconClass</code>). Keep this in
mind when creating &nbsp;<a class="reference-link" href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;in
order not to accidentally alter a system attribute (unless intended).</p>
<h2>Viewing the list of attributes</h2>
<p>Both the labels and relations for the current note are displayed in the <em>Owned Attributes</em> section
@ -52,8 +52,8 @@
where they can be viewed and edited. Inherited attributes are displayed
in the <em>Inherited Attributes</em> section of the ribbon, where they can
only be viewed.</p>
<p>In the list of attributes, labels are prefixed with the <code>#</code> character
whereas relations are prefixed with the <code>~</code> character.</p>
<p>In the list of attributes, labels are prefixed with the <code spellcheck="false">#</code> character
whereas relations are prefixed with the <code spellcheck="false">~</code> character.</p>
<h2>Attribute Definitions and Promoted Attributes</h2>
<p><a class="reference-link" href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;create
a form-like editing experience for attributes, which makes it easy to enhancing

View File

@ -3,43 +3,49 @@
generally in parent-child relations (or anywhere if using templates).</p>
<h2>Standard Inheritance</h2>
<p>In Trilium, attributes can be automatically inherited by child notes if
they have the <code>isInheritable</code> flag set to <code>true</code>. This
means the attribute (a key-value pair) is applied to the note and all its
descendants.</p>
they have the <code spellcheck="false">isInheritable</code> flag set to
<code
spellcheck="false">true</code>. This means the attribute (a key-value pair) is applied to
the note and all its descendants.</p>
<p>To make an attribute inheritable, simply use the visual editor for&nbsp;
<a
class="reference-link" href="#root/_help_HI6GBBIduIgv">Labels</a>&nbsp;or&nbsp;<a class="reference-link" href="#root/_help_Cq5X6iKQop6R">Relations</a>.
Alternatively, the attribute can be manually defined where <code>#myLabel=value</code> becomes <code>#myLabel(inheritable)=value</code> when
inheritable.</p>
<p>As an example, the <code>archived</code> label can be set to be inheritable,
allowing you to hide a whole subtree of notes from searches and other dialogs
by applying this label at the top level.</p>
Alternatively, the attribute can be manually defined where <code spellcheck="false">#myLabel=value</code> becomes
<code
spellcheck="false">#myLabel(inheritable)=value</code>when inheritable.</p>
<p>As an example, the <code spellcheck="false">archived</code> label can be
set to be inheritable, allowing you to hide a whole subtree of notes from
searches and other dialogs by applying this label at the top level.</p>
<p>Standard inheritance forces all the notes that are children (and sub-children)
of a note to have that particular label or relation. If there is a need
to have some notes not inherit one of the labels, then <em>copying inheritance</em> or <em>template inheritance</em> needs
to be used instead.</p>
<h2>Copying Inheritance</h2>
<p>Copying inheritance differs from standard inheritance by using a <code>child:</code> prefix
in the attribute name. This prefix causes new child notes to automatically
receive specific attributes from the parent note. These attributes are
independent of the parent and will persist even if the note is moved elsewhere.</p>
<p>If a parent note has the label <code>#child:exampleAttribute</code>, all
newly created child notes (one level deep) will inherit the <code>#exampleAttribute</code> label.
<p>Copying inheritance differs from standard inheritance by using a
<code
spellcheck="false">child:</code>prefix in the attribute name. This prefix causes new child
notes to automatically receive specific attributes from the parent note.
These attributes are independent of the parent and will persist even if
the note is moved elsewhere.</p>
<p>If a parent note has the label <code spellcheck="false">#child:exampleAttribute</code>,
all newly created child notes (one level deep) will inherit the <code spellcheck="false">#exampleAttribute</code> label.
This can be useful for setting default properties for notes in a specific
section.</p>
<p>Similarly, for relations use <code>~child:myRelation</code>.</p>
<p>Similarly, for relations use <code spellcheck="false">~child:myRelation</code>.</p>
<p>Due to the way it's designed, copying inheritance cannot be used to cascade
infinitely within a hierarchy. For that use case, consider using either
standard inheritance or templates.</p>
<h3>Chained inheritance</h3>
<p>It is possible to define labels across multiple levels of depth. For example, <code>#child:child:child:foo</code> applied
to a root note would create:</p>
<p>It is possible to define labels across multiple levels of depth. For example,
<code
spellcheck="false">#child:child:child:foo</code>applied to a root note would create:</p>
<ul>
<li><code>#child:child:foo</code> on the first-level children.</li>
<li><code>#child:foo</code> on the second-level children.</li>
<li><code>#foo</code> on the third-level children.</li>
<li><code spellcheck="false">#child:child:foo</code> on the first-level children.</li>
<li><code spellcheck="false">#child:foo</code> on the second-level children.</li>
<li><code spellcheck="false">#foo</code> on the third-level children.</li>
</ul>
<p>Similarly, use <code>~child:child:child:foo</code> if dealing with relations.</p>
<p>Similarly, use <code spellcheck="false">~child:child:child:foo</code> if
dealing with relations.</p>
<p>Do note that same as simple copying inheritance, the changes will not
apply retroactively to existing notes in the hierarchy, it will only apply
to the newly created notes.</p>

View File

@ -3,10 +3,11 @@
<h2>Common use cases</h2>
<ul>
<li><strong>Metadata for personal use</strong>: Assign labels with optional
values for categorization, such as <code>#year=1999</code>, <code>#genre="sci-fi"</code>,
or <code>#author="Neal Stephenson"</code>. This can be combined with&nbsp;
<a
class="reference-link" href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;to make their display more user-friendly.</li>
values for categorization, such as <code spellcheck="false">#year=1999</code>,
<code
spellcheck="false">#genre="sci-fi"</code>, or <code spellcheck="false">#author="Neal Stephenson"</code>.
This can be combined with&nbsp;<a class="reference-link" href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;to
make their display more user-friendly.</li>
<li><strong>Configuration</strong>: Labels can configure advanced features
or settings (see reference below).</li>
<li><strong>Scripts and Plugins</strong>: Used to tag notes with special metadata,
@ -36,21 +37,24 @@
<p>In the <em>Owned Attributes</em> section in the&nbsp;<a class="reference-link"
href="#root/_help_BlN9DFI679QC">Ribbon</a>:</p>
<ul>
<li>To create a label called <code>myLabel</code> with no value, simply type <code>#myLabel</code>.</li>
<li>To create a label called <code>myLabel</code> with a value <code>value</code>,
simply type <code>#myLabel=value</code>.</li>
<li>If the value contains spaces, then the text must be quoted: <code>#myLabel="Hello world"</code>.</li>
<li>To create a label called <code spellcheck="false">myLabel</code> with no
value, simply type <code spellcheck="false">#myLabel</code>.</li>
<li>To create a label called <code spellcheck="false">myLabel</code> with a
value <code spellcheck="false">value</code>, simply type <code spellcheck="false">#myLabel=value</code>.</li>
<li>If the value contains spaces, then the text must be quoted: <code spellcheck="false">#myLabel="Hello world"</code>.</li>
<li>If the string contains quotes (regardless of whether it has spaces), then
the text must be quoted with apostrophes instead: <code>#myLabel='Hello "world"'</code>.</li>
<li>To create an inheritable label called <code>myLabel</code>, simply write <code>#myLabel(inheritable)</code> for
no value or <code>#myLabel(inheritable)=value</code> if there is a value.</li>
the text must be quoted with apostrophes instead: <code spellcheck="false">#myLabel='Hello "world"'</code>.</li>
<li>To create an inheritable label called <code spellcheck="false">myLabel</code>,
simply write <code spellcheck="false">#myLabel(inheritable)</code> for no
value or <code spellcheck="false">#myLabel(inheritable)=value</code> if there
is a value.</li>
</ul>
<h2>Predefined labels</h2>
<p>This is a list of labels that Trilium natively supports.</p>
<aside class="admonition tip">
<p>Some labels presented here end with a <code>*</code>. That means that there
are multiple labels with the same prefix, consult the specific page linked
in the description of that label for more information.</p>
<p>Some labels presented here end with a <code spellcheck="false">*</code>.
That means that there are multiple labels with the same prefix, consult
the specific page linked in the description of that label for more information.</p>
</aside>
<table class="ck-table-resized">
<colgroup>

View File

@ -47,8 +47,9 @@
</ol>
<h2>How attribute definitions actually work</h2>
<p>When a new promoted attribute definition is created, it creates a corresponding
label prefixed with either <code>label</code> or <code>relation</code>, depending
on the definition type:</p><pre><code class="language-text-x-trilium-auto">#label:myColor(inheritable)="promoted,alias=Color,multi,color"</code></pre>
label prefixed with either <code spellcheck="false">label</code> or
<code
spellcheck="false">relation</code>, depending on the definition type:</p><pre><code class="language-text-x-trilium-auto">#label:myColor(inheritable)="promoted,alias=Color,multi,color"</code></pre>
<p>The only purpose of the attribute definition is to set up a template.
If the attribute was marked as promoted, then it's also displayed to the
user for easy editing.</p>
@ -97,7 +98,7 @@
make use of this practice, for example:
<ul>
<li>Calendars add “Start Date”, “End Date”, “Start Time” and “End Time” as
promoted attributes. These map to system attributes such as <code>startDate</code> which
promoted attributes. These map to system attributes such as <code spellcheck="false">startDate</code> which
are then interpreted by the calendar view.</li>
<li><a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation</a>&nbsp;adds
a “Background” promoted attribute for each of the slide to easily be able
@ -105,29 +106,29 @@
</ul>
</li>
<li>The Trilium documentation (which is edited in Trilium) uses a promoted
attribute to be able to easily edit the <code>#shareAlias</code> (see&nbsp;
attribute to be able to easily edit the <code spellcheck="false">#shareAlias</code> (see&nbsp;
<a
class="reference-link" href="#root/_help_R9pX4DGra2Vt">Sharing</a>) in order to form clean URLs.</li>
<li>If you always edit a particular system attribute such as <code>#color</code>,
<li>If you always edit a particular system attribute such as <code spellcheck="false">#color</code>,
simply create a promoted attribute for it to make it easier.</li>
</ul>
<h3>Inverse relation</h3>
<p>Some relations always occur in pairs - my favorite example is on the family.
If you have a note representing husband and note representing wife, then
there might be a relation between those two of <code>isPartnerOf</code>.
there might be a relation between those two of <code spellcheck="false">isPartnerOf</code>.
This is bidirectional relationship - meaning that if a relation is pointing
from husband to wife then there should be always another relation pointing
from wife to husband.</p>
<p>Another example is with parent-child relationship. Again these always
occur in pairs, but in this case it's not exact same relation - the one
going from parent to child might be called <code>isParentOf</code> and the
other one going from child to parent might be called <code>isChildOf</code>.</p>
going from parent to child might be called <code spellcheck="false">isParentOf</code> and
the other one going from child to parent might be called <code spellcheck="false">isChildOf</code>.</p>
<p>Relation definition allows you to specify such "inverse relation" - for
the relation you just define you specify which is the inverse relation.
Note that in the second example we should have two relation definitions
- one for <code>isParentOf</code> which defines <code>isChildOf</code> as inverse
relation and then second relation definition for <code>isChildOf</code> which
defines <code>isParentOf</code> as inverse relation.</p>
- one for <code spellcheck="false">isParentOf</code> which defines <code spellcheck="false">isChildOf</code> as
inverse relation and then second relation definition for <code spellcheck="false">isChildOf</code> which
defines <code spellcheck="false">isParentOf</code> as inverse relation.</p>
<p>What this does internally is that whenever we save a relation which has
defined inverse relation, we check that this inverse relation exists on
the relation target note. Similarly, when we delete relation, we also delete

View File

@ -39,27 +39,30 @@
<p>In the <em>Owned Attributes</em> section in the&nbsp;<a class="reference-link"
href="#root/_help_BlN9DFI679QC">Ribbon</a>:</p>
<ul>
<li>To create a relation called <code>myRelation</code>:
<li>To create a relation called <code spellcheck="false">myRelation</code>:
<ul>
<li>First type <code>~myRelation=@</code>.</li>
<li>First type <code spellcheck="false">~myRelation=@</code>.</li>
<li>After this, an autocompletion box should appear.</li>
<li>Type the title of the note to point to and press <kbd>Enter</kbd> to confirm
(or click the desired note).</li>
<li>Alternatively copy a note from the&nbsp;<a class="reference-link" href="#root/_help_oPVyFC7WL2Lp">Note Tree</a>&nbsp;and
paste it after the <code>=</code> sign (without the <code>@</code>, in this
case).</li>
paste it after the <code spellcheck="false">=</code> sign (without the
<code
spellcheck="false">@</code>, in this case).</li>
</ul>
</li>
<li>To create an inheritable relation, follow the same steps as previously
described but instead of <code>~myRelation</code> write <code>~myRelation(inheritable)</code>.</li>
described but instead of <code spellcheck="false">~myRelation</code> write
<code
spellcheck="false">~myRelation(inheritable)</code>.</li>
</ul>
<h2>Predefined relations</h2>
<p>These relations are supported and used internally by Trilium.</p>
<aside
class="admonition tip">
<p>Some relations presented here end with a <code>*</code>. That means that
there are multiple relations with the same prefix, consult the specific
page linked in the description of that relation for more information.</p>
<p>Some relations presented here end with a <code spellcheck="false">*</code>.
That means that there are multiple relations with the same prefix, consult
the specific page linked in the description of that relation for more information.</p>
</aside>
<table>
<thead>
@ -70,20 +73,20 @@ class="admonition tip">
</thead>
<tbody>
<tr>
<td><code>runOn*</code>
<td><code spellcheck="false">runOn*</code>
</td>
<td>See&nbsp;<a class="reference-link" href="#root/_help_GPERMystNGTB">Events</a>
</td>
</tr>
<tr>
<td><code>template</code>
<td><code spellcheck="false">template</code>
</td>
<td>note's attributes will be inherited even without a parent-child relationship,
note's content and subtree will be added to instance notes if empty. See
documentation for details.</td>
</tr>
<tr>
<td><code>inherit</code>
<td><code spellcheck="false">inherit</code>
</td>
<td>note's attributes will be inherited even without a parent-child relationship.
See&nbsp;<a class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>&nbsp;for
@ -91,50 +94,53 @@ class="admonition tip">
the documentation.</td>
</tr>
<tr>
<td><code>renderNote</code>
<td><code spellcheck="false">renderNote</code>
</td>
<td>notes of type&nbsp;<a class="reference-link" href="#root/_help_HcABDtFCkbFN">Render Note</a>&nbsp;will
be rendered using a code note (HTML or script) and it is necessary to point
using this relation to which note should be rendered</td>
</tr>
<tr>
<td><code>widget_relation</code>
<td><code spellcheck="false">widget_relation</code>
</td>
<td>target of this relation will be executed and rendered as a widget in the
sidebar</td>
</tr>
<tr>
<td><code>shareCss</code>
<td><code spellcheck="false">shareCss</code>
</td>
<td>CSS note which will be injected into the share page. CSS note must be
in the shared sub-tree as well. Consider using <code>share_hidden_from_tree</code> and <code>share_omit_default_css</code> as
well.</td>
in the shared sub-tree as well. Consider using <code spellcheck="false">share_hidden_from_tree</code> and
<code
spellcheck="false">share_omit_default_css</code>as well.</td>
</tr>
<tr>
<td><code>shareJs</code>
<td><code spellcheck="false">shareJs</code>
</td>
<td>JavaScript note which will be injected into the share page. JS note must
be in the shared sub-tree as well. Consider using <code>share_hidden_from_tree</code>.</td>
be in the shared sub-tree as well. Consider using <code spellcheck="false">share_hidden_from_tree</code>.</td>
</tr>
<tr>
<td><code>shareHtml</code>
<td><code spellcheck="false">shareHtml</code>
</td>
<td>HTML note which will be injected into the share page at locations specified
by the <code>shareHtmlLocation</code> label. HTML note must be in the shared
sub-tree as well. Consider using <code>share_hidden_from_tree</code>.</td>
by the <code spellcheck="false">shareHtmlLocation</code> label. HTML note
must be in the shared sub-tree as well. Consider using <code spellcheck="false">share_hidden_from_tree</code>.</td>
</tr>
<tr>
<td><code>shareTemplate</code>
<td><code spellcheck="false">shareTemplate</code>
</td>
<td>Embedded JavaScript note that will be used as the template for displaying
the shared note. Falls back to the default template. Consider using <code>share_hidden_from_tree</code>.</td>
the shared note. Falls back to the default template. Consider using
<code
spellcheck="false">share_hidden_from_tree</code>.</td>
</tr>
<tr>
<td><code>shareFavicon</code>
<td><code spellcheck="false">shareFavicon</code>
</td>
<td>Favicon note to be set in the shared page. Typically you want to set it
to share root and make it inheritable. Favicon note must be in the shared
sub-tree as well. Consider using <code>share_hidden_from_tree</code>.</td>
sub-tree as well. Consider using <code spellcheck="false">share_hidden_from_tree</code>.</td>
</tr>
</tbody>
</table>

View File

@ -116,8 +116,9 @@
<a
class="reference-link" href="#root/_help_habiZ3HU8Kw8">FNote</a>, for example:
<ul>
<li><code>NEW: ${note.title}</code> will prefix all notes with <code>NEW:</code> .</li>
<li><code>${note.dateCreatedObj.format('MM-DD:')}: ${note.title}</code> will
<li><code spellcheck="false">NEW: ${note.title}</code> will prefix all notes
with <code spellcheck="false">NEW:</code> .</li>
<li><code spellcheck="false">${note.dateCreatedObj.format('MM-DD:')}: ${note.title}</code> will
prefix the note titles with each note's creation date (in month-day format).</li>
</ul>
</li>
@ -155,12 +156,13 @@
<li>Examples:
<ul>
<li>
<p>To apply a suffix (<code>- suffix</code> in this example), to the note
title:</p><pre><code class="language-application-javascript-env-backend">note.title = note.title + " - suffix";</code></pre>
<p>To apply a suffix (<code spellcheck="false">- suffix</code> in this example),
to the note title:</p><pre><code class="language-application-javascript-env-backend">note.title = note.title + " - suffix";</code></pre>
</li>
<li>
<p>To alter attributes of a note based on another attribute, such as setting
the <code>#shareAlias</code> label to the title of the note:</p><pre><code class="language-application-javascript-env-backend">note.setLabel("shareAlias", note.title)</code></pre>
the <code spellcheck="false">#shareAlias</code> label to the title of the
note:</p><pre><code class="language-application-javascript-env-backend">note.setLabel("shareAlias", note.title)</code></pre>
</li>
</ul>
</li>

View File

@ -1,11 +1,12 @@
<p>Trilium supports configuration via a file named <code>config.ini</code> and
<p>Trilium supports configuration via a file named <code spellcheck="false">config.ini</code> and
environment variables. This document provides a comprehensive reference
for all configuration options.</p>
<h2>Location of the configuration file</h2>
<p>The configuration file is not located in the same directory as the application.
Instead, the <code>config.ini</code> is located in the&nbsp;<a class="reference-link"
href="#root/_help_tAassRL4RSQL">Data directory</a>. As such, the configuration
file is only available after starting the application and creating a database.</p>
Instead, the <code spellcheck="false">config.ini</code> is located in the&nbsp;
<a
class="reference-link" href="#root/_help_tAassRL4RSQL">Data directory</a>. As such, the configuration file is only available
after starting the application and creating a database.</p>
<h2>Configuration Precedence</h2>
<p>Configuration values are loaded in the following order of precedence (highest
to lowest):</p>
@ -18,13 +19,15 @@
</ol>
<h2>Environment Variable Patterns</h2>
<p>Trilium supports multiple environment variable patterns for flexibility.
The primary pattern is: <code>TRILIUM_[SECTION]_[KEY]</code>
The primary pattern is: <code spellcheck="false">TRILIUM_[SECTION]_[KEY]</code>
</p>
<p>Where:</p>
<ul>
<li><code>SECTION</code> is the INI section name in UPPERCASE</li>
<li><code>KEY</code> is the camelCase configuration key converted to UPPERCASE
(e.g., <code>instanceName</code><code>INSTANCENAME</code>)</li>
<li><code spellcheck="false">SECTION</code> is the INI section name in UPPERCASE</li>
<li><code spellcheck="false">KEY</code> is the camelCase configuration key
converted to UPPERCASE (e.g., <code spellcheck="false">instanceName</code>
<code
spellcheck="false">INSTANCENAME</code>)</li>
</ul>
<p>Additionally, shorter aliases are available for common configurations
(see Alternative Variables section below).</p>
@ -41,35 +44,35 @@
</thead>
<tbody>
<tr>
<td><code>TRILIUM_GENERAL_INSTANCENAME</code>
<td><code spellcheck="false">TRILIUM_GENERAL_INSTANCENAME</code>
</td>
<td>string</td>
<td>""</td>
<td>Instance name for API identification</td>
</tr>
<tr>
<td><code>TRILIUM_GENERAL_NOAUTHENTICATION</code>
<td><code spellcheck="false">TRILIUM_GENERAL_NOAUTHENTICATION</code>
</td>
<td>boolean</td>
<td>false</td>
<td>Disable authentication (server only)</td>
</tr>
<tr>
<td><code>TRILIUM_GENERAL_NOBACKUP</code>
<td><code spellcheck="false">TRILIUM_GENERAL_NOBACKUP</code>
</td>
<td>boolean</td>
<td>false</td>
<td>Disable automatic backups</td>
</tr>
<tr>
<td><code>TRILIUM_GENERAL_NODESKTOPICON</code>
<td><code spellcheck="false">TRILIUM_GENERAL_NODESKTOPICON</code>
</td>
<td>boolean</td>
<td>false</td>
<td>Disable desktop icon creation</td>
</tr>
<tr>
<td><code>TRILIUM_GENERAL_READONLY</code>
<td><code spellcheck="false">TRILIUM_GENERAL_READONLY</code>
</td>
<td>boolean</td>
<td>false</td>
@ -90,70 +93,70 @@
</thead>
<tbody>
<tr>
<td><code>TRILIUM_NETWORK_HOST</code>
<td><code spellcheck="false">TRILIUM_NETWORK_HOST</code>
</td>
<td>string</td>
<td>"0.0.0.0"</td>
<td>Server host binding</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_PORT</code>
<td><code spellcheck="false">TRILIUM_NETWORK_PORT</code>
</td>
<td>string</td>
<td>"3000"</td>
<td>Server port</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_HTTPS</code>
<td><code spellcheck="false">TRILIUM_NETWORK_HTTPS</code>
</td>
<td>boolean</td>
<td>false</td>
<td>Enable HTTPS</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_CERTPATH</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CERTPATH</code>
</td>
<td>string</td>
<td>""</td>
<td>SSL certificate path</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_KEYPATH</code>
<td><code spellcheck="false">TRILIUM_NETWORK_KEYPATH</code>
</td>
<td>string</td>
<td>""</td>
<td>SSL key path</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_TRUSTEDREVERSEPROXY</code>
<td><code spellcheck="false">TRILIUM_NETWORK_TRUSTEDREVERSEPROXY</code>
</td>
<td>boolean/string</td>
<td>false</td>
<td>Reverse proxy trust settings</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_CORSALLOWORIGIN</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CORSALLOWORIGIN</code>
</td>
<td>string</td>
<td>""</td>
<td>CORS allowed origins</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_CORSALLOWMETHODS</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CORSALLOWMETHODS</code>
</td>
<td>string</td>
<td>""</td>
<td>CORS allowed methods</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_CORSALLOWHEADERS</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CORSALLOWHEADERS</code>
</td>
<td>string</td>
<td>""</td>
<td>CORS allowed headers</td>
</tr>
<tr>
<td><code>TRILIUM_NETWORK_CORSRESOURCEPOLICY</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CORSRESOURCEPOLICY</code>
</td>
<td>string</td>
<td>same-origin</td>
@ -175,7 +178,7 @@
</thead>
<tbody>
<tr>
<td><code>TRILIUM_SESSION_COOKIEMAXAGE</code>
<td><code spellcheck="false">TRILIUM_SESSION_COOKIEMAXAGE</code>
</td>
<td>integer</td>
<td>1814400</td>
@ -196,21 +199,21 @@
</thead>
<tbody>
<tr>
<td><code>TRILIUM_SYNC_SYNCSERVERHOST</code>
<td><code spellcheck="false">TRILIUM_SYNC_SYNCSERVERHOST</code>
</td>
<td>string</td>
<td>""</td>
<td>Sync server host URL</td>
</tr>
<tr>
<td><code>TRILIUM_SYNC_SYNCSERVERTIMEOUT</code>
<td><code spellcheck="false">TRILIUM_SYNC_SYNCSERVERTIMEOUT</code>
</td>
<td>string</td>
<td>"120000"</td>
<td>Sync server timeout in milliseconds</td>
</tr>
<tr>
<td><code>TRILIUM_SYNC_SYNCPROXY</code>
<td><code spellcheck="false">TRILIUM_SYNC_SYNCPROXY</code>
</td>
<td>string</td>
<td>""</td>
@ -231,42 +234,42 @@
</thead>
<tbody>
<tr>
<td><code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHBASEURL</code>
<td><code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHBASEURL</code>
</td>
<td>string</td>
<td>""</td>
<td>OAuth/OpenID base URL</td>
</tr>
<tr>
<td><code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTID</code>
<td><code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTID</code>
</td>
<td>string</td>
<td>""</td>
<td>OAuth client ID</td>
</tr>
<tr>
<td><code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTSECRET</code>
<td><code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTSECRET</code>
</td>
<td>string</td>
<td>""</td>
<td>OAuth client secret</td>
</tr>
<tr>
<td><code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL</code>
<td><code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL</code>
</td>
<td>string</td>
<td>"<a href="https://accounts.google.com">https://accounts.google.com</a>"</td>
<td>OAuth issuer base URL</td>
</tr>
<tr>
<td><code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERNAME</code>
<td><code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERNAME</code>
</td>
<td>string</td>
<td>"Google"</td>
<td>OAuth issuer display name</td>
</tr>
<tr>
<td><code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERICON</code>
<td><code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERICON</code>
</td>
<td>string</td>
<td>""</td>
@ -287,7 +290,7 @@
</thead>
<tbody>
<tr>
<td><code>TRILIUM_LOGGING_RETENTIONDAYS</code>
<td><code spellcheck="false">TRILIUM_LOGGING_RETENTIONDAYS</code>
</td>
<td>integer</td>
<td>90</td>
@ -301,38 +304,59 @@
and work identically to their longer counterparts:</p>
<h3>Network CORS Variables</h3>
<ul>
<li><code>TRILIUM_NETWORK_CORS_ALLOW_ORIGIN</code> (alternative to <code>TRILIUM_NETWORK_CORSALLOWORIGIN</code>)</li>
<li><code>TRILIUM_NETWORK_CORS_ALLOW_METHODS</code> (alternative to <code>TRILIUM_NETWORK_CORSALLOWMETHODS</code>)</li>
<li><code>TRILIUM_NETWORK_CORS_ALLOW_HEADERS</code> (alternative to <code>TRILIUM_NETWORK_CORSALLOWHEADERS</code>)</li>
<li><code>TRILIUM_NETWORK_CORS_RESOURCE_POLICY</code> (alternative to <code>TRILIUM_NETWORK_CORSRESOURCEPOLICY</code>)</li>
<li><code spellcheck="false">TRILIUM_NETWORK_CORS_ALLOW_ORIGIN</code> (alternative
to <code spellcheck="false">TRILIUM_NETWORK_CORSALLOWORIGIN</code>)</li>
<li><code spellcheck="false">TRILIUM_NETWORK_CORS_ALLOW_METHODS</code> (alternative
to <code spellcheck="false">TRILIUM_NETWORK_CORSALLOWMETHODS</code>)</li>
<li><code spellcheck="false">TRILIUM_NETWORK_CORS_ALLOW_HEADERS</code> (alternative
to <code spellcheck="false">TRILIUM_NETWORK_CORSALLOWHEADERS</code>)</li>
<li><code spellcheck="false">TRILIUM_NETWORK_CORS_RESOURCE_POLICY</code> (alternative
to <code spellcheck="false">TRILIUM_NETWORK_CORSRESOURCEPOLICY</code>)</li>
</ul>
<h3>Sync Variables</h3>
<ul>
<li><code>TRILIUM_SYNC_SERVER_HOST</code> (alternative to <code>TRILIUM_SYNC_SYNCSERVERHOST</code>)</li>
<li><code>TRILIUM_SYNC_SERVER_TIMEOUT</code> (alternative to <code>TRILIUM_SYNC_SYNCSERVERTIMEOUT</code>)</li>
<li><code>TRILIUM_SYNC_SERVER_PROXY</code> (alternative to <code>TRILIUM_SYNC_SYNCPROXY</code>)</li>
<li><code spellcheck="false">TRILIUM_SYNC_SERVER_HOST</code> (alternative to
<code
spellcheck="false">TRILIUM_SYNC_SYNCSERVERHOST</code>)</li>
<li><code spellcheck="false">TRILIUM_SYNC_SERVER_TIMEOUT</code> (alternative
to <code spellcheck="false">TRILIUM_SYNC_SYNCSERVERTIMEOUT</code>)</li>
<li><code spellcheck="false">TRILIUM_SYNC_SERVER_PROXY</code> (alternative
to <code spellcheck="false">TRILIUM_SYNC_SYNCPROXY</code>)</li>
</ul>
<h3>OAuth/MFA Variables</h3>
<ul>
<li><code>TRILIUM_OAUTH_BASE_URL</code> (alternative to <code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHBASEURL</code>)</li>
<li><code>TRILIUM_OAUTH_CLIENT_ID</code> (alternative to <code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTID</code>)</li>
<li><code>TRILIUM_OAUTH_CLIENT_SECRET</code> (alternative to <code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTSECRET</code>)</li>
<li><code>TRILIUM_OAUTH_ISSUER_BASE_URL</code> (alternative to <code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL</code>)</li>
<li><code>TRILIUM_OAUTH_ISSUER_NAME</code> (alternative to <code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERNAME</code>)</li>
<li><code>TRILIUM_OAUTH_ISSUER_ICON</code> (alternative to <code>TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERICON</code>)</li>
<li><code spellcheck="false">TRILIUM_OAUTH_BASE_URL</code> (alternative to
<code
spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHBASEURL</code>)</li>
<li><code spellcheck="false">TRILIUM_OAUTH_CLIENT_ID</code> (alternative to
<code
spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTID</code>)</li>
<li><code spellcheck="false">TRILIUM_OAUTH_CLIENT_SECRET</code> (alternative
to <code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTSECRET</code>)</li>
<li><code spellcheck="false">TRILIUM_OAUTH_ISSUER_BASE_URL</code> (alternative
to <code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL</code>)</li>
<li><code spellcheck="false">TRILIUM_OAUTH_ISSUER_NAME</code> (alternative
to <code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERNAME</code>)</li>
<li><code spellcheck="false">TRILIUM_OAUTH_ISSUER_ICON</code> (alternative
to <code spellcheck="false">TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERICON</code>)</li>
</ul>
<h3>Logging Variables</h3>
<ul>
<li><code>TRILIUM_LOGGING_RETENTION_DAYS</code> (alternative to <code>TRILIUM_LOGGING_RETENTIONDAYS</code>)</li>
<li><code spellcheck="false">TRILIUM_LOGGING_RETENTION_DAYS</code> (alternative
to <code spellcheck="false">TRILIUM_LOGGING_RETENTIONDAYS</code>)</li>
</ul>
<h2>Boolean Values</h2>
<p>Boolean environment variables accept the following values:</p>
<ul>
<li><strong>True</strong>: <code>"true"</code>, <code>"1"</code>, <code>1</code>
<li><strong>True</strong>: <code spellcheck="false">"true"</code>, <code spellcheck="false">"1"</code>,
<code
spellcheck="false">1</code>
</li>
<li><strong>False</strong>: <code>"false"</code>, <code>"0"</code>, <code>0</code>
<li><strong>False</strong>: <code spellcheck="false">"false"</code>, <code spellcheck="false">"0"</code>,
<code
spellcheck="false">0</code>
</li>
<li>Any other value defaults to <code>false</code>
<li>Any other value defaults to <code spellcheck="false">false</code>
</li>
</ul>
<h2>Using Environment Variables</h2>

View File

@ -1,40 +1,40 @@
<p>By default, Trilium cannot be accessed in web browsers by requests coming
from other domains/origins than Trilium itself.&nbsp;</p>
<p>However, it is possible to manually configure <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS">Cross-Origin Resource Sharing (CORS)</a> since
Trilium v0.93.0 using environment variables or <code>config.ini</code>,
Trilium v0.93.0 using environment variables or <code spellcheck="false">config.ini</code>,
as follows:</p>
<table>
<thead>
<tr>
<th>CORS Header</th>
<th>Corresponding option in <code>config.ini</code>
<th>Corresponding option in <code spellcheck="false">config.ini</code>
</th>
<th>Corresponding option in environment variables in the <code>Network</code> section</th>
<th>Corresponding option in environment variables in the <code spellcheck="false">Network</code> section</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Access-Control-Allow-Origin</code>
<td><code spellcheck="false">Access-Control-Allow-Origin</code>
</td>
<td><code>TRILIUM_NETWORK_CORS_ALLOW_ORIGIN</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CORS_ALLOW_ORIGIN</code>
</td>
<td><code>corsAllowOrigin</code>
<td><code spellcheck="false">corsAllowOrigin</code>
</td>
</tr>
<tr>
<td><code>Access-Control-Allow-Methods</code>
<td><code spellcheck="false">Access-Control-Allow-Methods</code>
</td>
<td><code>TRILIUM_NETWORK_CORS_ALLOW_METHODS</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CORS_ALLOW_METHODS</code>
</td>
<td><code>corsAllowMethods</code>
<td><code spellcheck="false">corsAllowMethods</code>
</td>
</tr>
<tr>
<td><code>Access-Control-Allow-Headers</code>
<td><code spellcheck="false">Access-Control-Allow-Headers</code>
</td>
<td><code>TRILIUM_NETWORK_CORS_ALLOW_HEADERS</code>
<td><code spellcheck="false">TRILIUM_NETWORK_CORS_ALLOW_HEADERS</code>
</td>
<td><code>corsAllowHeaders</code>
<td><code spellcheck="false">corsAllowHeaders</code>
</td>
</tr>
</tbody>

View File

@ -4,14 +4,15 @@
is set up with), sometimes it can be useful to distinguish the instance
you are running on.</p>
<h2>Setting the instance name</h2>
<p>To set up a name for the instance, modify the <code>config.ini</code>:</p><pre><code class="language-text-x-trilium-auto">[General]
<p>To set up a name for the instance, modify the <code spellcheck="false">config.ini</code>:</p><pre><code class="language-text-x-trilium-auto">[General]
instanceName=Hello</code></pre>
<h2>Distinguishing the instance on back-end</h2>
<p>Use <code>api.getInstanceName()</code> to obtain the instance name of the
current server, as specified in the config file or in environment variables.</p>
<p>Use <code spellcheck="false">api.getInstanceName()</code> to obtain the
instance name of the current server, as specified in the config file or
in environment variables.</p>
<h2>Limiting script runs based on instance</h2>
<p>For a script that is run periodically or on a certain event, it's possible
to limit it to certain instances without having to change the code. Just
add <code>runOnInstance</code> and set as the value the instance name where
the script should run. To run on multiple named instances, simply add the
label multiple times.</p>
add <code spellcheck="false">runOnInstance</code> and set as the value the
instance name where the script should run. To run on multiple named instances,
simply add the label multiple times.</p>

View File

@ -1,7 +1,7 @@
<p>Trilium provides a mechanism for <a href="#root/_help_CdNpE2pqjmI6">scripts</a> to
open a public REST endpoint. This opens a way for various integrations
with other services - a simple example would be creating new note from
Slack by issuing a slash command (e.g. <code>/trilium buy milk</code>).</p>
Slack by issuing a slash command (e.g. <code spellcheck="false">/trilium buy milk</code>).</p>
<h2>Create note from outside Trilium</h2>
<p>Let's take a look at an example. The goal is to provide a REST endpoint
to which we can send title and content and Trilium will create a note.</p>
@ -24,10 +24,12 @@ else {
}</code></pre>
<p>This script note has also following two attributes:</p>
<ul>
<li>label <code>#customRequestHandler</code> with value <code>create-note</code>
<li>label <code spellcheck="false">#customRequestHandler</code> with value
<code
spellcheck="false">create-note</code>
</li>
<li>relation <code>~targetNote</code> pointing to a note where new notes should
be saved</li>
<li>relation <code spellcheck="false">~targetNote</code> pointing to a note
where new notes should be saved</li>
</ul>
<h3>Explanation</h3>
<p>Let's test this by using an HTTP client to send a request:</p><pre><code class="language-text-x-trilium-auto">POST http://your-trilium-server/custom/create-note
@ -38,16 +40,18 @@ Content-Type: application/json
"title": "hello",
"content": "world"
}+++++++++++++++++++++++++++++++++++++++++++++++</code></pre>
<p>Notice the <code>/custom</code> part in the request path - Trilium considers
any request with this prefix as "custom" and tries to find a matching handler
by looking at all notes which have <code>customRequestHandler</code> <a href="#root/_help_zEY4DaJG4YT5">label</a>.
Value of this label then contains a regular expression which will match
the request path (in our case trivial regex "create-note").</p>
<p>Trilium will then find our code note created above and execute it. <code>api.req</code>, <code>api.res</code> are
set to <a href="https://expressjs.com/en/api.html#req">request</a> and
<p>Notice the <code spellcheck="false">/custom</code> part in the request path
- Trilium considers any request with this prefix as "custom" and tries
to find a matching handler by looking at all notes which have <code spellcheck="false">customRequestHandler</code>
<a
href="https://expressjs.com/en/api.html#res">response</a>objects from which we can get details of the request and also
respond.</p>
href="#root/_help_zEY4DaJG4YT5">label</a>. Value of this label then contains a regular expression which
will match the request path (in our case trivial regex "create-note").</p>
<p>Trilium will then find our code note created above and execute it.
<code
spellcheck="false">api.req</code>, <code spellcheck="false">api.res</code> are set to <a href="https://expressjs.com/en/api.html#req">request</a> and
<a
href="https://expressjs.com/en/api.html#res">response</a>objects from which we can get details of the request and also
respond.</p>
<p>In the code note we check the request method and then use trivial authentication
- keep in mind that these endpoints are by default totally unauthenticated,
and you need to take care of this yourself.</p>
@ -56,20 +60,21 @@ Content-Type: application/json
href="#root/_help_GLks18SNjxmC">Script API</a>.</p>
<h2>Custom resource provider</h2>
<p>Another common use case is that you want to just expose a file note -
in such case you create label <code>customResourceProvider</code> (value
in such case you create label <code spellcheck="false">customResourceProvider</code> (value
is again path regex).</p>
<p>For more information, see&nbsp;<a href="#root/_help_d3fAXQ2diepH">Custom Resource Providers</a>.</p>
<h2>Advanced concepts</h2>
<p><code>api.req</code> and <code>api.res</code> are Express.js objects - you
can always look into its <a href="https://expressjs.com/en/api.html">documentation</a> for
<p><code spellcheck="false">api.req</code> and <code spellcheck="false">api.res</code> are
Express.js objects - you can always look into its <a href="https://expressjs.com/en/api.html">documentation</a> for
details.</p>
<h3>Parameters</h3>
<p>REST request paths often contain parameters in the URL, e.g.:</p><pre><code class="language-text-x-trilium-auto">http://your-trilium-server/custom/notes/123</code></pre>
<p>The last part is dynamic so the matching of the URL must also be dynamic
- for this reason the matching is done with regular expressions. Following <code>customRequestHandler</code> value
would match it:</p><pre><code class="language-text-x-trilium-auto">notes/([0-9]+)</code></pre>
- for this reason the matching is done with regular expressions. Following
<code
spellcheck="false">customRequestHandler</code>value would match it:</p><pre><code class="language-text-x-trilium-auto">notes/([0-9]+)</code></pre>
<p>Additionally, this also defines a matching group with the use of parenthesis
which then makes it easier to extract the value. The matched groups are
available in <code>api.pathParams</code>:</p><pre><code class="language-text-x-trilium-auto">const noteId = api.pathParams[0];</code></pre>
<p>Often you also need query params (as in e.g. <code>http://your-trilium-server/custom/notes?noteId=123</code>),
you can get those with standard express <code>req.query.noteId</code>.</p>
available in <code spellcheck="false">api.pathParams</code>:</p><pre><code class="language-text-x-trilium-auto">const noteId = api.pathParams[0];</code></pre>
<p>Often you also need query params (as in e.g. <code spellcheck="false">http://your-trilium-server/custom/notes?noteId=123</code>),
you can get those with standard express <code spellcheck="false">req.query.noteId</code>.</p>

View File

@ -6,26 +6,31 @@
<ol>
<li>Import a file such as an image or a font into Trilium by drag &amp; drop.</li>
<li>Select the file and go to the <em>Owned Attributes</em> section.</li>
<li>Add the label <code>#customResourceProvider=hello</code>.</li>
<li>To test if it is working, use a browser to navigate to <code>&lt;protocol&gt;://&lt;host&gt;/custom/hello</code> (where <code>&lt;protocol&gt;</code> is
either <code>http</code> or <code>https</code> based on your setup, and <code>&lt;host&gt;</code> is
the host or IP to your Trilium server instance). If you are running the
TriliumNext application without a server, use <code>http://localhost:37840</code> as
the base URL.</li>
<li>Add the label <code spellcheck="false">#customResourceProvider=hello</code>.</li>
<li>To test if it is working, use a browser to navigate to <code spellcheck="false">&lt;protocol&gt;://&lt;host&gt;/custom/hello</code> (where
<code
spellcheck="false">&lt;protocol&gt;</code>is either <code spellcheck="false">http</code> or
<code
spellcheck="false">https</code>based on your setup, and <code spellcheck="false">&lt;host&gt;</code> is
the host or IP to your Trilium server instance). If you are running the
TriliumNext application without a server, use <code spellcheck="false">http://localhost:37840</code> as
the base URL.</li>
<li>If everything went well, at the previous step the browser should have
downloaded the file uploaded in the first step.</li>
</ol>
<p>Instead of <code>hello</code>, the name can be:</p>
<p>Instead of <code spellcheck="false">hello</code>, the name can be:</p>
<ul>
<li>A path, such as <code>fonts/Roboto.ttf</code>, which would be accessible
via <code>&lt;host&gt;/custom/fonts/Roboto.ttf</code>.</li>
<li>A path, such as <code spellcheck="false">fonts/Roboto.ttf</code>, which
would be accessible via <code spellcheck="false">&lt;host&gt;/custom/fonts/Roboto.ttf</code>.</li>
<li>As a more advanced use case, a regular expression to match multiple routes,
such as <code>hello/.*</code> which will be accessible via <code>/custom/hello/1</code>, <code>/custom/hello/2</code>, <code>/custom/hello/world</code>,
etc.</li>
such as <code spellcheck="false">hello/.*</code> which will be accessible
via <code spellcheck="false">/custom/hello/1</code>, <code spellcheck="false">/custom/hello/2</code>,
<code
spellcheck="false">/custom/hello/world</code>, etc.</li>
</ul>
<h2>Using it in a theme</h2>
<p>For example, if you have a custom font to be imported by the theme, first
upload a font file into Trilium and assign it the <code>#customResourceProvider=fonts/myfont.ttf</code> attribute.</p>
upload a font file into Trilium and assign it the <code spellcheck="false">#customResourceProvider=fonts/myfont.ttf</code> attribute.</p>
<p>Then modify the theme CSS to point to:</p><pre><code class="language-text-css">@font-face {
font-family: customFont;
src: url("/custom/fonts/myfont.ttf");

View File

@ -1,7 +1,7 @@
<p>Your Trilium data is stored in a <a href="https://www.sqlite.org">SQLite</a> database
which contains all notes, tree structure, metadata, and most of the configuration.
The database file is named <code>document.db</code> and is stored in the
application's default&nbsp;<a href="#root/_help_tAassRL4RSQL">Data directory</a>.</p>
The database file is named <code spellcheck="false">document.db</code> and
is stored in the application's default&nbsp;<a href="#root/_help_tAassRL4RSQL">Data directory</a>.</p>
<h2>Demo Notes</h2>
<p>When first starting Trilium, it will provide a set of notes to showcase
various features of the application.</p>
@ -19,9 +19,12 @@
the application, it will generate a new database containing the original
demo notes.</p>
<p>To delete the database, simply go to the <a href="#root/_help_tAassRL4RSQL">data directory</a> and
delete the <code>document.db</code> file (and any other files starting with <code>document.db</code>).</p>
delete the <code spellcheck="false">document.db</code> file (and any other
files starting with <code spellcheck="false">document.db</code>).</p>
<p>If you do not need to preserve any configurations that might be stored
in the <code>config.ini</code> file, you can just delete all of the <a href="#root/_help_tAassRL4RSQL">data directory's</a> contents
to fully restore the application to its original state. You can also review
the <a href="#root/_help_Gzjqa934BdH4">configuration</a> file to provide all <code>config.ini</code> values
as environment variables instead.</p>
in the <code spellcheck="false">config.ini</code> file, you can just delete
all of the <a href="#root/_help_tAassRL4RSQL">data directory's</a> contents to
fully restore the application to its original state. You can also review
the <a href="#root/_help_Gzjqa934BdH4">configuration</a> file to provide all
<code
spellcheck="false">config.ini</code>values as environment variables instead.</p>

View File

@ -2,7 +2,7 @@
uses is desirable.</p>
<p>If you are doing any advanced development or troubleshooting where you
manually modify the database, you might want to consider creating backups
of your <code>document.db</code> file.</p>
of your <code spellcheck="false">document.db</code> file.</p>
<h2>Modifying it internally using the SQL Console</h2>
<p>The SQL Console is Trilium's built-in database editor.</p>
<p>See&nbsp;<a class="reference-link" href="#root/_help_YKWqdJhzi2VY">SQL Console</a>.</p>
@ -31,6 +31,8 @@
<h3>Using the SQLite CLI</h3>
<p>First, start the SQLite 3 CLI by specifying the path to the database:</p><pre><code class="language-text-x-trilium-auto">sqlite3 ~/.local/share/trilium-data/document.db</code></pre>
<ul>
<li>In the prompt simply type the statement and make sure it ends with a <code>;</code> character.</li>
<li>To exit, simply type <code>.quit</code> and enter.</li>
<li>In the prompt simply type the statement and make sure it ends with a
<code
spellcheck="false">;</code>character.</li>
<li>To exit, simply type <code spellcheck="false">.quit</code> and enter.</li>
</ul>

View File

@ -1,7 +1,7 @@
<p>When a new note is created, its name is by default "new note". In some
cases, it can be desirable to have a different or even a dynamic default
note title.</p>
<p>For this use case, Trilium (since v0.52) supports <code>#titleTemplate</code>
<p>For this use case, Trilium (since v0.52) supports <code spellcheck="false">#titleTemplate</code>
<a
href="#root/_help_zEY4DaJG4YT5">label</a>. You can create such a label for a given note, assign it a value,
and this value will be used as a default title when creating child notes.
@ -18,17 +18,17 @@
</ul>
</li>
</ul>
<p>Now, to the parent note "2022 Books" you can assign label <code>#titleTemplate="[Author name]: [Book title], [Publication year]"</code>.</p>
<p>Now, to the parent note "2022 Books" you can assign label <code spellcheck="false">#titleTemplate="[Author name]: [Book title], [Publication year]"</code>.</p>
<p>And all children of "2022 Books" will be created with initial title "[Author
name]: [Book title], [Publication year]". There's no artificial intelligence
here, the idea is to just prompt you to manually fill in the pieces of
information into the note title by yourself.</p>
<h2>Dynamic value</h2>
<p>The value of <code>#titleTemplate</code> is evaluated at the point of note's
creation as a JavaScript string, which means it can be enriched with the
help of JS string interpolation with dynamic data.</p>
<p>Second variable injected is <code>parentNote</code> which gives access to
the parent <a href="#root/_help_habiZ3HU8Kw8"><code>FNote</code></a>.</p>
<p>The value of <code spellcheck="false">#titleTemplate</code> is evaluated
at the point of note's creation as a JavaScript string, which means it
can be enriched with the help of JS string interpolation with dynamic data.</p>
<p>Second variable injected is <code spellcheck="false">parentNote</code> which
gives access to the parent <a href="#root/_help_habiZ3HU8Kw8"><code spellcheck="false">FNote</code></a>.</p>
<p>See also&nbsp;<a class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>&nbsp;which
provides similar capabilities, including default note's content.</p>
<h3>Examples</h3>
@ -42,13 +42,13 @@
<li>2022-05-15: Backup delay</li>
</ul>
</li>
<li>You can automatize the date assignment by assigning a label <code>#titleTemplate="${now.format('YYYY-MM-DD')}: "</code> to
<li>You can automatize the date assignment by assigning a label <code spellcheck="false">#titleTemplate="${now.format('YYYY-MM-DD')}: "</code> to
the parent note "Incidents". Whenever a new child note is created, the
title template is evaluated with the injected <a href="https://day.js.org/docs/en/display/format">now</a> object.</li>
</ul>
</li>
<li>To use a parent's attribute in the title of new notes: <code>#titleTemplate="${parentNote.getLabelValue('authorName')}'s literary works"</code>
<li>To use a parent's attribute in the title of new notes: <code spellcheck="false">#titleTemplate="${parentNote.getLabelValue('authorName')}'s literary works"</code>
</li>
<li>To mirror the parent's note title: <code>${parentNote.title}</code>
<li>To mirror the parent's note title: <code spellcheck="false">${parentNote.title}</code>
</li>
</ul>

View File

@ -13,22 +13,26 @@
<h2>Obtaining a token</h2>
<p>All operations with the REST API have to be authenticated using a token.
You can get this token either from Options -&gt; ETAPI or programmatically
using the <code>/auth/login</code> REST call (see the <a href="https://github.com/TriliumNext/Trilium/blob/master/src/etapi/etapi.openapi.yaml">spec</a>).</p>
using the <code spellcheck="false">/auth/login</code> REST call (see the
<a
href="https://github.com/TriliumNext/Trilium/blob/master/src/etapi/etapi.openapi.yaml">spec</a>).</p>
<h2>Authentication</h2>
<h3>Via the <code>Authorization</code> header</h3><pre><code class="language-text-x-trilium-auto">GET https://myserver.com/etapi/app-info
<h3>Via the <code spellcheck="false">Authorization</code> header</h3><pre><code class="language-text-x-trilium-auto">GET https://myserver.com/etapi/app-info
Authorization: ETAPITOKEN</code></pre>
<p>where <code>ETAPITOKEN</code> is the token obtained in the previous step.</p>
<p>where <code spellcheck="false">ETAPITOKEN</code> is the token obtained in
the previous step.</p>
<p>For compatibility with various tools, it's also possible to specify the
value of the <code>Authorization</code> header in the format <code>Bearer ETAPITOKEN</code> (since
0.93.0).</p>
value of the <code spellcheck="false">Authorization</code> header in the
format <code spellcheck="false">Bearer ETAPITOKEN</code> (since 0.93.0).</p>
<h3>Basic authentication</h3>
<p>Since v0.56 you can also use basic auth format:</p><pre><code class="language-text-x-trilium-auto">GET https://myserver.com/etapi/app-info
Authorization: Basic BATOKEN</code></pre>
<ul>
<li>Where <code>BATOKEN = BASE64(username + ':' + password)</code> - this is
a standard Basic Auth serialization</li>
<li>Where <code>username</code> is "etapi"</li>
<li>And <code>password</code> is the generated ETAPI token described above.</li>
<li>Where <code spellcheck="false">BATOKEN = BASE64(username + ':' + password)</code> -
this is a standard Basic Auth serialization</li>
<li>Where <code spellcheck="false">username</code> is "etapi"</li>
<li>And <code spellcheck="false">password</code> is the generated ETAPI token
described above.</li>
</ul>
<p>Basic Auth is meant to be used with tools which support only basic auth.</p>
<h2>Interaction using Bash scripts</h2>
@ -44,13 +48,13 @@ NOTE_ID="i6ra4ZshJhgN"
curl "$SERVER/etapi/notes/$NOTE_ID/content" -H "Authorization: $TOKEN" </code></pre>
<p>Make sure to replace the values of:</p>
<ul>
<li><code>TOKEN</code> with your ETAPI token.</li>
<li><code>SERVER</code> with the correct protocol, host name and port to your
Trilium instance.</li>
<li><code>NOTE_ID</code> with an existing note ID to download.</li>
<li><code spellcheck="false">TOKEN</code> with your ETAPI token.</li>
<li><code spellcheck="false">SERVER</code> with the correct protocol, host
name and port to your Trilium instance.</li>
<li><code spellcheck="false">NOTE_ID</code> with an existing note ID to download.</li>
</ul>
<p>As another example, to obtain a .zip export of a note and place it in
a directory called <code>out</code>, simply replace the last statement in
the script with:</p><pre><code class="language-text-x-trilium-auto">curl -H "Authorization: $TOKEN" \
a directory called <code spellcheck="false">out</code>, simply replace the
last statement in the script with:</p><pre><code class="language-text-x-trilium-auto">curl -H "Authorization: $TOKEN" \
-X GET "$SERVER/etapi/notes/$NOTE_ID/export" \
--output "out/$NOTE_ID.zip"</code></pre>

View File

@ -2,9 +2,9 @@
Trilium instance, designed for external monitoring systems like Prometheus.</p>
<h2><strong>Endpoint</strong></h2>
<ul>
<li><strong>URL</strong>: <code>/etapi/metrics</code>
<li><strong>URL</strong>: <code spellcheck="false">/etapi/metrics</code>
</li>
<li><strong>Method</strong>: <code>GET</code>
<li><strong>Method</strong>: <code spellcheck="false">GET</code>
</li>
<li><strong>Authentication</strong>: ETAPI token required</li>
<li><strong>Default Format</strong>: Prometheus text format</li>
@ -34,39 +34,50 @@ trilium_notes_total 1234 1701432000
<h2><strong>Available Metrics</strong></h2>
<h3><strong>Instance Information</strong></h3>
<ul>
<li><code>trilium_info</code> - Version and build information with labels</li>
<li><code spellcheck="false">trilium_info</code> - Version and build information
with labels</li>
</ul>
<h3><strong>Database Metrics</strong></h3>
<ul>
<li><code>trilium_notes_total</code> - Total notes (including deleted)</li>
<li><code>trilium_notes_deleted</code> - Number of deleted notes</li>
<li><code>trilium_notes_active</code> - Number of active notes</li>
<li><code>trilium_notes_protected</code> - Number of protected notes</li>
<li><code>trilium_attachments_total</code> - Total attachments</li>
<li><code>trilium_attachments_active</code> - Active attachments</li>
<li><code>trilium_revisions_total</code> - Total note revisions</li>
<li><code>trilium_branches_total</code> - Active branches</li>
<li><code>trilium_attributes_total</code> - Active attributes</li>
<li><code>trilium_blobs_total</code> - Total blob records</li>
<li><code>trilium_etapi_tokens_total</code> - Active ETAPI tokens</li>
<li><code>trilium_embeddings_total</code> - Note embeddings (if available)</li>
<li><code spellcheck="false">trilium_notes_total</code> - Total notes (including
deleted)</li>
<li><code spellcheck="false">trilium_notes_deleted</code> - Number of deleted
notes</li>
<li><code spellcheck="false">trilium_notes_active</code> - Number of active
notes</li>
<li><code spellcheck="false">trilium_notes_protected</code> - Number of protected
notes</li>
<li><code spellcheck="false">trilium_attachments_total</code> - Total attachments</li>
<li><code spellcheck="false">trilium_attachments_active</code> - Active attachments</li>
<li><code spellcheck="false">trilium_revisions_total</code> - Total note revisions</li>
<li><code spellcheck="false">trilium_branches_total</code> - Active branches</li>
<li><code spellcheck="false">trilium_attributes_total</code> - Active attributes</li>
<li><code spellcheck="false">trilium_blobs_total</code> - Total blob records</li>
<li><code spellcheck="false">trilium_etapi_tokens_total</code> - Active ETAPI
tokens</li>
<li><code spellcheck="false">trilium_embeddings_total</code> - Note embeddings
(if available)</li>
</ul>
<h3><strong>Categorized Metrics</strong></h3>
<ul>
<li><code>trilium_notes_by_type{type="text|code|image|file"}</code> - Notes
by type</li>
<li><code>trilium_attachments_by_type{mime_type="..."}</code> - Attachments
by MIME type</li>
<li><code spellcheck="false">trilium_notes_by_type{type="text|code|image|file"}</code> -
Notes by type</li>
<li><code spellcheck="false">trilium_attachments_by_type{mime_type="..."}</code> -
Attachments by MIME type</li>
</ul>
<h3><strong>Statistics</strong></h3>
<ul>
<li><code>trilium_database_size_bytes</code> - Database size in bytes</li>
<li><code>trilium_oldest_note_timestamp</code> - Timestamp of oldest note</li>
<li><code>trilium_newest_note_timestamp</code> - Timestamp of newest note</li>
<li><code>trilium_last_modified_timestamp</code> - Last modification timestamp</li>
<li><code spellcheck="false">trilium_database_size_bytes</code> - Database
size in bytes</li>
<li><code spellcheck="false">trilium_oldest_note_timestamp</code> - Timestamp
of oldest note</li>
<li><code spellcheck="false">trilium_newest_note_timestamp</code> - Timestamp
of newest note</li>
<li><code spellcheck="false">trilium_last_modified_timestamp</code> - Last
modification timestamp</li>
</ul>
<h2><strong>Prometheus Configuration</strong></h2>
<p>Add to your <code>prometheus.yml</code>:</p><pre><code class="language-text-x-trilium-auto">scrape_configs:
<p>Add to your <code spellcheck="false">prometheus.yml</code>:</p><pre><code class="language-text-x-trilium-auto">scrape_configs:
- job_name: 'trilium'
static_configs:
- targets: ['localhost:8080']
@ -76,9 +87,9 @@ trilium_notes_total 1234 1701432000
</code></pre>
<h2><strong>Error Responses</strong></h2>
<ul>
<li><code>400</code> - Invalid format parameter</li>
<li><code>401</code> - Missing or invalid ETAPI token</li>
<li><code>500</code> - Internal server error</li>
<li><code spellcheck="false">400</code> - Invalid format parameter</li>
<li><code spellcheck="false">401</code> - Missing or invalid ETAPI token</li>
<li><code spellcheck="false">500</code> - Internal server error</li>
</ul>
<h2><strong>Grafana Dashboard</strong></h2>
<figure class="image">

View File

@ -9,8 +9,8 @@
feel free to report them either via a ticket or via the Matrix.</p>
<h2>Downloading the nightly release manually</h2>
<p>Go to <a href="https://github.com/TriliumNext/Trilium/releases/tag/nightly">github.com/TriliumNext/Trilium/releases/tag/nightly</a> and
look for the artifacts starting with <code>TriliumNotes-main</code>. Choose
the appropriate one for your platform (e.g. <code>windows-x64.zip</code>).</p>
look for the artifacts starting with <code spellcheck="false">TriliumNotes-main</code>.
Choose the appropriate one for your platform (e.g. <code spellcheck="false">windows-x64.zip</code>).</p>
<p>Depending on your use case, you can either test the portable version or
even use the installer.</p>
<aside class="admonition note">

View File

@ -27,15 +27,16 @@
<ul>
<li>However, the database is still read-only, so all modifications will be
reset if the server is restarted.</li>
<li>Whenever this occurs, <code>ERROR: read-only DB ignored</code> will be shown
in the logs.</li>
<li>Whenever this occurs, <code spellcheck="false">ERROR: read-only DB ignored</code> will
be shown in the logs.</li>
</ul>
</li>
</ul>
<h2>Setting a database as read-only</h2>
<p>First, make sure the database is initialized (e.g. the first set up is
complete). Then modify the <a href="#root/_help_Gzjqa934BdH4">config.ini</a> by
looking for the <code>[General]</code> section and adding a new <code>readOnly</code> field:</p><pre><code class="language-text-x-trilium-auto">[General]
looking for the <code spellcheck="false">[General]</code> section and adding
a new <code spellcheck="false">readOnly</code> field:</p><pre><code class="language-text-x-trilium-auto">[General]
readOnly=true</code></pre>
<p>If your server is already running, restart it to apply the changes.</p>
<p>Similarly, to disable read-only remove the line or set it to <code>false</code>.</p>
<p>Similarly, to disable read-only remove the line or set it to <code spellcheck="false">false</code>.</p>

View File

@ -1,12 +1,19 @@
<p>Safe mode is triggered by setting the <code>TRILIUM_SAFE_MODE</code> environment
variable to a truthy value, usually <code>1</code>.</p>
<p>In each artifact there is a <code>trilium-safe-mode.sh</code> (or <code>.bat</code>)
script to enable it.</p>
<p>Safe mode is triggered by setting the <code spellcheck="false">TRILIUM_SAFE_MODE</code> environment
variable to a truthy value, usually <code spellcheck="false">1</code>.</p>
<p>In each artifact there is a <code spellcheck="false">trilium-safe-mode.sh</code> (or
<code
spellcheck="false">.bat</code>) script to enable it.</p>
<p>What it does:</p>
<ul>
<li>Disables <code>customWidget</code> launcher types in <code>app/widgets/containers/launcher.js</code>.</li>
<li>Disables the running of <code>mobileStartup</code> or <code>frontendStartup</code> scripts.</li>
<li>Disables <code spellcheck="false">customWidget</code> launcher types in
<code
spellcheck="false">app/widgets/containers/launcher.js</code>.</li>
<li>Disables the running of <code spellcheck="false">mobileStartup</code> or
<code
spellcheck="false">frontendStartup</code>scripts.</li>
<li>Displays the root note instead of the previously saved session.</li>
<li>Disables the running of <code>backendStartup</code>, <code>hourly</code>, <code>daily</code> scripts
and checks for the hidden subtree.</li>
<li>Disables the running of <code spellcheck="false">backendStartup</code>,
<code
spellcheck="false">hourly</code>, <code spellcheck="false">daily</code> scripts and checks
for the hidden subtree.</li>
</ul>

View File

@ -182,7 +182,7 @@ class="image">
<h2>Sharing a note</h2>
<ol>
<li>
<p><strong>Enable Sharing</strong>: To share a note, toggle the <code>Shared</code> switch
<p><strong>Enable Sharing</strong>: To share a note, toggle the <code spellcheck="false">Shared</code> switch
within the note's interface. Once sharing is enabled, an URL will appear,
which you can click to access the shared note.</p>
<p>
@ -193,7 +193,7 @@ class="image">
<li>
<p><strong>Access the Shared Note</strong>: The link provided will open the
note in your browser. If your server is not configured with a public IP,
the URL will refer to <code>localhost (127.0.0.1)</code>.</p>
the URL will refer to <code spellcheck="false">localhost (127.0.0.1)</code>.</p>
</li>
</ol>
<h2>Sharing a note subtree</h2>
@ -222,9 +222,11 @@ class="image">
such as Nginx or Apache to serve static content.</li>
</ul>
<h3>Password protection</h3>
<p>To protect shared notes with a username and password, you can use the <code>#shareCredentials</code> attribute.
Add this label to the note with the format <code>#shareCredentials="username:password"</code>.
To protect an entire subtree, make sure the label is <a href="#root/_help_bwZpz2ajCEwO">inheritable</a>.</p>
<p>To protect shared notes with a username and password, you can use the
<code
spellcheck="false">#shareCredentials</code>attribute. Add this label to the note with the
format <code spellcheck="false">#shareCredentials="username:password"</code>.
To protect an entire subtree, make sure the label is <a href="#root/_help_bwZpz2ajCEwO">inheritable</a>.</p>
<h2>Advanced sharing options</h2>
<h3>Customizing the appearance of shared notes</h3>
<p>The default design should be a good starting point, but you can customize
@ -232,46 +234,52 @@ class="image">
<ul>
<li><strong>Custom CSS</strong>: Link a CSS&nbsp;<a class="reference-link"
href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;note to the shared page by adding
a <code>~shareCss</code> relation to the note. If you want this style to
apply to the entire subtree, make the label inheritable. You can hide the
CSS code note from the tree navigation by adding the <code>#shareHiddenFromTree</code> label.</li>
a <code spellcheck="false">~shareCss</code> relation to the note. If you
want this style to apply to the entire subtree, make the label inheritable.
You can hide the CSS code note from the tree navigation by adding the
<code
spellcheck="false">#shareHiddenFromTree</code>label.</li>
<li><strong>Omitting Default CSS</strong>: For extensive styling changes,
use the <code>#shareOmitDefaultCss</code> label to avoid conflicts with Trilium's
<a
href="#root/_help_Wy267RK4M69c">default stylesheet</a>.</li>
use the <code spellcheck="false">#shareOmitDefaultCss</code> label to avoid
conflicts with Trilium's <a href="#root/_help_Wy267RK4M69c">default stylesheet</a>.</li>
</ul>
<h3>Adding JavaScript</h3>
<p>You can inject custom JavaScript into the shared note using the <code>~shareJs</code> relation.
<p>You can inject custom JavaScript into the shared note using the <code spellcheck="false">~shareJs</code> relation.
This allows you to access note attributes or traverse the note tree using
the <code>fetchNote()</code> API, which retrieves note data based on its
ID.</p>
the <code spellcheck="false">fetchNote()</code> API, which retrieves note
data based on its ID.</p>
<h3>Adding custom HTML</h3>
<p>You can inject custom HTML snippets into specific locations of the shared
page using the <code>~shareHtml</code> relation. The HTML note should contain
the raw HTML content you want to inject, and you can control where it appears
by adding the <code>#shareHtmlLocation</code> label to the HTML snippet note
itself.</p>
<p>The <code>#shareHtmlLocation</code> label accepts values in the format <code>location:position</code>:</p>
page using the <code spellcheck="false">~shareHtml</code> relation. The HTML
note should contain the raw HTML content you want to inject, and you can
control where it appears by adding the <code spellcheck="false">#shareHtmlLocation</code> label
to the HTML snippet note itself.</p>
<p>The <code spellcheck="false">#shareHtmlLocation</code> label accepts values
in the format <code spellcheck="false">location:position</code>:</p>
<ul>
<li><strong>Locations</strong>: <code>head</code>, <code>body</code>, <code>content</code>
<li><strong>Locations</strong>: <code spellcheck="false">head</code>,
<code
spellcheck="false">body</code>, <code spellcheck="false">content</code>
</li>
<li><strong>Positions</strong>: <code>start</code>, <code>end</code>
<li><strong>Positions</strong>: <code spellcheck="false">start</code>,
<code
spellcheck="false">end</code>
</li>
</ul>
<p>For example:</p>
<ul>
<li><code>#shareHtmlLocation=head:start</code> - Injects HTML at the beginning
of the <code>&lt;head&gt;</code> section</li>
<li><code>#shareHtmlLocation=head:end</code> - Injects HTML at the end of the <code>&lt;head&gt;</code> section
(default)</li>
<li><code>#shareHtmlLocation=body:start</code> - Injects HTML at the beginning
of the <code>&lt;body&gt;</code> section</li>
<li><code>#shareHtmlLocation=content:start</code> - Injects HTML at the beginning
of the content area</li>
<li><code>#shareHtmlLocation=content:end</code> - Injects HTML at the end of
the content area</li>
<li><code spellcheck="false">#shareHtmlLocation=head:start</code> - Injects
HTML at the beginning of the <code spellcheck="false">&lt;head&gt;</code> section</li>
<li><code spellcheck="false">#shareHtmlLocation=head:end</code> - Injects HTML
at the end of the <code spellcheck="false">&lt;head&gt;</code> section (default)</li>
<li><code spellcheck="false">#shareHtmlLocation=body:start</code> - Injects
HTML at the beginning of the <code spellcheck="false">&lt;body&gt;</code> section</li>
<li><code spellcheck="false">#shareHtmlLocation=content:start</code> - Injects
HTML at the beginning of the content area</li>
<li><code spellcheck="false">#shareHtmlLocation=content:end</code> - Injects
HTML at the end of the content area</li>
</ul>
<p>If no location is specified, the HTML will be injected at <code>content:end</code> by
<p>If no location is specified, the HTML will be injected at <code spellcheck="false">content:end</code> by
default.</p>
<p>Example:</p><pre><code class="language-application-javascript-env-backend">const currentNote = await fetchNote();
const parentNote = await fetchNote(currentNote.parentNoteIds[0]);
@ -280,42 +288,47 @@ for (const attr of parentNote.attributes) {
console.log(attr.type, attr.name, attr.value);
}</code></pre>
<h3>Creating human-readable URL aliases</h3>
<p>Shared notes typically have URLs like <code>http://domain.tld/share/knvU8aJy4dJ7</code>,
<p>Shared notes typically have URLs like <code spellcheck="false">http://domain.tld/share/knvU8aJy4dJ7</code>,
where the last part is the note's ID. You can make these URLs more user-friendly
by adding the <code>#shareAlias</code> label to individual notes (e.g., <code>#shareAlias=highlighting</code>).
This will change the URL to <code>http://domain.tld/share/highlighting</code>.</p>
by adding the <code spellcheck="false">#shareAlias</code> label to individual
notes (e.g., <code spellcheck="false">#shareAlias=highlighting</code>).
This will change the URL to <code spellcheck="false">http://domain.tld/share/highlighting</code>.</p>
<p><strong>Important</strong>:</p>
<ol>
<li>Ensure that aliases are unique.</li>
<li>Using slashes (<code>/</code>) within aliases to create subpaths is not
supported.</li>
<li>Using slashes (<code spellcheck="false">/</code>) within aliases to create
subpaths is not supported.</li>
</ol>
<aside class="admonition tip">
<ul>
<li>To easily identify pages that don't have a share alias, run a&nbsp;
<a
class="reference-link" href="#root/_help_eIg8jdvaoNNd">Search</a>&nbsp;with <code>#!shareAlias</code>.</li>
class="reference-link" href="#root/_help_eIg8jdvaoNNd">Search</a>&nbsp;with <code spellcheck="false">#!shareAlias</code>.</li>
<li>To be able to enter the share alias faster, consider using&nbsp;<a class="reference-link"
href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;(for example <code>#label:shareAlias(inheritable)="promoted,alias=Slug,single,text"</code>).</li>
href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;(for example
<code
spellcheck="false">#label:shareAlias(inheritable)="promoted,alias=Slug,single,text"</code>).</li>
</ul>
</aside>
<h3>Setting a custom favicon</h3>
<p>To customize the favicon for your shared pages, create a relation <code>~shareFavicon</code> pointing
to a file note containing the favicon (e.g., in <code>.ico</code> format).</p>
<p>To customize the favicon for your shared pages, create a relation
<code
spellcheck="false">~shareFavicon</code>pointing to a file note containing the favicon (e.g.,
in <code spellcheck="false">.ico</code> format).</p>
<h3>Sharing a note as the root</h3>
<p>You can designate a specific note or folder as the root of your shared
content by adding the <code>#shareRoot</code> label. This note will be linked
when visiting <code>[http://domain.tld/share](http://domain/share)</code>,
content by adding the <code spellcheck="false">#shareRoot</code> label. This
note will be linked when visiting <code spellcheck="false">[http://domain.tld/share](http://domain/share)</code>,
making it easier to use Trilium as a fully-fledged website.</p>
<aside class="admonition tip">
<p>Consider combining this with the <code>#shareIndex</code> label, which will
display a list of all shared notes.</p>
<p>Consider combining this with the <code spellcheck="false">#shareIndex</code> label,
which will display a list of all shared notes.</p>
</aside>
<h3>Displaying an index of shared notes</h3>
<p>When accessing a share, the sub-notes will be displayed in a tree on the
left. But since multiple note trees can be shared, it might be useful to
display a list of all the different share trees.</p>
<p>To do so, create a shared text note and apply the <code>shareIndex</code> label.
<p>To do so, create a shared text note and apply the <code spellcheck="false">shareIndex</code> label.
When viewed, the list of shared roots will be displayed at the bottom of
the note.</p>
<h2>Attribute reference</h2>
@ -419,23 +432,27 @@ for (const attr of parentNote.attributes) {
</thead>
<tbody>
<tr>
<td><code>~shareLogo</code>
<td><code spellcheck="false">~shareLogo</code>
</td>
<td>Relation set to an image to use as logo. The image must be part of the
share tree (it can be hidden if needed).</td>
</tr>
<tr>
<td><code>#shareLogoWidth</code>
<td><code spellcheck="false">#shareLogoWidth</code>
</td>
<td>The width (in pixels, without unit) to set for the logo. Default is <code>53</code>.</td>
<td>The width (in pixels, without unit) to set for the logo. Default is
<code
spellcheck="false">53</code>.</td>
</tr>
<tr>
<td><code>#shareLogoHeight</code>
<td><code spellcheck="false">#shareLogoHeight</code>
</td>
<td>The height (in pixels, without unit) to set for the logo. Default is <code>40</code>.</td>
<td>The height (in pixels, without unit) to set for the logo. Default is
<code
spellcheck="false">40</code>.</td>
</tr>
<tr>
<td><code>#shareRootLink</code>
<td><code spellcheck="false">#shareRootLink</code>
</td>
<td>URL to navigate to when the logo is pressed.</td>
</tr>
@ -452,27 +469,27 @@ for (const attr of parentNote.attributes) {
</thead>
<tbody>
<tr>
<td><code>#shareOpenGraphColor</code>
<td><code spellcheck="false">#shareOpenGraphColor</code>
</td>
<td>This adjusts the <code>theme-color</code> meta-property.</td>
<td>This adjusts the <code spellcheck="false">theme-color</code> meta-property.</td>
</tr>
<tr>
<td><code>#shareOpenGraphURL</code>
<td><code spellcheck="false">#shareOpenGraphURL</code>
</td>
<td>This adjusts the <code>og:url</code> and <code>twitter:url</code> meta-properties.</td>
<td>This adjusts the <code spellcheck="false">og:url</code> and <code spellcheck="false">twitter:url</code> meta-properties.</td>
</tr>
<tr>
<td><code>#shareOpenGraphDomain</code>
<td><code spellcheck="false">#shareOpenGraphDomain</code>
</td>
<td>Adjusts the <code>twitter:domain</code> meta-property.</td>
<td>Adjusts the <code spellcheck="false">twitter:domain</code> meta-property.</td>
</tr>
<tr>
<td><code>#shareOpenGraphImage</code>
<br><code>~shareOpenGraphImage</code>
<td><code spellcheck="false">#shareOpenGraphImage</code>
<br><code spellcheck="false">~shareOpenGraphImage</code>
</td>
<td>Can be either a label, case in which the value is passed on as-is, or
it can be a relation to an image&nbsp;<a class="reference-link" href="#root/_help_W8vYD3Q1zjCR">File</a>.
This controls the <code>og:image</code> meta-property.</td>
This controls the <code spellcheck="false">og:image</code> meta-property.</td>
</tr>
</tbody>
</table>

View File

@ -25,10 +25,10 @@
exporting to static HTML files comes with a few subtle differences:</p>
<ul>
<li>The URL structure is different. Where in normal sharing it's something
along the way of <code>example.com/share/noteid</code>, the notes follow
an hierarchical structure, such as <code>docs.triliumnotes.org/user-guide/concepts/navigation/tree-concepts</code>.</li>
<li>The <code>favicon.ico</code> is not handled automatically, it needs to be
manually added on the server after the export is generated.</li>
along the way of <code spellcheck="false">example.com/share/noteid</code>,
the notes follow an hierarchical structure, such as <code spellcheck="false">docs.triliumnotes.org/user-guide/concepts/navigation/tree-concepts</code>.</li>
<li>The <code spellcheck="false">favicon.ico</code> is not handled automatically,
it needs to be manually added on the server after the export is generated.</li>
<li>The “Last updated” for notes is not available.</li>
<li>The search functionality works slightly different since the normal one
requires an active API to work. In the static export, search still works
@ -36,8 +36,8 @@
</ul>
<h2>Differences from normal .zip export</h2>
<ul>
<li>The name of the files/URLs will prefer <code>shareAlias</code> to allow
for clean URLs.</li>
<li>The name of the files/URLs will prefer <code spellcheck="false">shareAlias</code> to
allow for clean URLs.</li>
<li>The export requires a functional web server as the pages will not render
properly if accessed locally via a web browser due to the use of module
scripts.</li>
@ -54,12 +54,12 @@
<h2>Testing locally</h2>
<p>As mentioned previously, the exported static pages require a website to
function. In order to test locally, a web server needs to be used.</p>
<p>One example is to use the Node.js-based <a href="https://www.npmjs.com/package/http-server"><code>http-server</code></a> which
<p>One example is to use the Node.js-based <a href="https://www.npmjs.com/package/http-server"><code spellcheck="false">http-server</code></a> which
can be installed via:</p><pre><code class="language-text-x-trilium-auto">npm i -g http-server</code></pre>
<p>Once installed simply:</p>
<ol>
<li>Extract the exported .zip file.</li>
<li>Inside the extracted directory, run <code>http-server</code>.</li>
<li>Inside the extracted directory, run <code spellcheck="false">http-server</code>.</li>
<li>Access the indicated address (e.g. <a href="http://localhost:8080">http://localhost:8080</a>).</li>
</ol>
<h2>Automation</h2>

View File

@ -6,7 +6,7 @@
reverse_proxy /share http://localhost:8080/share
}</code></pre>
<p>This is for newer versions where the share functionality is isolated,
for older versions it's required to also include <code>/assets</code>.<sup><a href="#fn2b8mg20aol8">[1]</a></sup>
for older versions it's required to also include <code spellcheck="false">/assets</code>.<sup><a href="#fn2b8mg20aol8">[1]</a></sup>
</p>
<ol>
<li>

View File

@ -24,12 +24,12 @@
</table>
<h2>By adding an attribute to the note</h2>
<p>Simply add the <code>#shareRaw</code> attribute and the note will always
be rendered <em>raw</em> when accessed from the share URL.</p>
<p>Simply add the <code spellcheck="false">#shareRaw</code> attribute and the
note will always be rendered <em>raw</em> when accessed from the share URL.</p>
<h2>By altering the URL</h2>
<p>Append <code>?raw</code> to the URL to display a note in its raw format
regardless of whether the <code>#shareRaw</code> attribute is added on the
note.</p>
<p>Append <code spellcheck="false">?raw</code> to the URL to display a note
in its raw format regardless of whether the <code spellcheck="false">#shareRaw</code> attribute
is added on the note.</p>
<p>
<img src="Serving directly the conte.png">
</p>

View File

@ -22,7 +22,7 @@
by us to fit our needs.</li>
<li>We also make use of modified upstream plugins such as <a href="https://github.com/ckeditor/ckeditor5-mermaid">ckeditor/ckeditor5-mermaid</a> to
allow inline Mermaid code.</li>
<li><a href="https://github.com/mlewand/ckeditor5-keyboard-marker">mlewand/ckeditor5-keyboard-marker: Plugin adds support for the keyboard input element (<code>&lt;kbd&gt;</code>) to CKEditor 5.</a>
<li><a href="https://github.com/mlewand/ckeditor5-keyboard-marker">mlewand/ckeditor5-keyboard-marker: Plugin adds support for the keyboard input element (<code spellcheck="false">&lt;kbd&gt;</code>) to CKEditor 5.</a>
</li>
<li>A modified version of <a href="https://github.com/ThomasAitken/ckeditor5-footnotes">ThomasAitken/ckeditor5-footnotes: Footnotes plugin for CKEditor5</a> to
allow footnotes.</li>

View File

@ -4,9 +4,9 @@
<ol>
<li><strong>Attribute Inheritance</strong>: All attributes from the template
note are <a href="#root/_help_bwZpz2ajCEwO">inherited</a> by the instance notes.
Even attributes with <code>#isInheritable=false</code> are inherited by the
instance notes, although only inheritable attributes are further inherited
by the children of the instance notes.</li>
Even attributes with <code spellcheck="false">#isInheritable=false</code> are
inherited by the instance notes, although only inheritable attributes are
further inherited by the children of the instance notes.</li>
<li><strong>Content Duplication</strong>: The content of the template note
is copied to the instance note, provided the instance note is empty at
the time of template assignment.</li>
@ -35,33 +35,38 @@
<img src="Templates_template-create-.png"
alt="show child note templates">
</p>
<p>For the template to appear in the menu, the template note must have the <code>#template</code> label.
Do not confuse this with the <code>~template</code> relation, which links
the instance note to the template note. If you use <a href="#root/_help_9sRHySam5fXb">workspaces</a>,
you can also mark templates with <code>#workspaceTemplate</code> to display
them only in the workspace.</p>
<p>For the template to appear in the menu, the template note must have the
<code
spellcheck="false">#template</code>label. Do not confuse this with the <code spellcheck="false">~template</code> relation,
which links the instance note to the template note. If you use <a href="#root/_help_9sRHySam5fXb">workspaces</a>,
you can also mark templates with <code spellcheck="false">#workspaceTemplate</code> to
display them only in the workspace.</p>
<p>Templates can also be added or changed after note creation by creating
a <code>~template</code> relation pointing to the desired template note.&nbsp;</p>
<p>To specify a template for child notes, you can use a <code>~child:template</code> relation
a <code spellcheck="false">~template</code> relation pointing to the desired
template note.&nbsp;</p>
<p>To specify a template for child notes, you can use a <code spellcheck="false">~child:template</code> relation
pointing to the appropriate template note. There is no limit to the depth
of the hierarchy — you can use <code>~child:child:template</code>, <code>~child:child:child:template</code>,
and so on.</p>
of the hierarchy — you can use <code spellcheck="false">~child:child:template</code>,
<code
spellcheck="false">~child:child:child:template</code>, and so on.</p>
<aside class="admonition important">
<p>Changing the template hierarchy after the parent note is created will
not retroactively apply to newly created child notes.
<br>For example, if you initially use <code>~child:template</code> and later
switch to <code>~child:child:template</code>, it will not automatically
apply the new template to the grandchild notes. Only the structure present
at the time of note creation is considered.</p>
<br>For example, if you initially use <code spellcheck="false">~child:template</code> and
later switch to <code spellcheck="false">~child:child:template</code>, it
will not automatically apply the new template to the grandchild notes.
Only the structure present at the time of note creation is considered.</p>
</aside>
<h2>Additional Notes</h2>
<p>From a visual perspective, templates can define <code>#iconClass</code> and <code>#cssClass</code> attributes,
allowing all instance notes (e.g., books) to display a specific icon and
CSS style.</p>
<p>From a visual perspective, templates can define <code spellcheck="false">#iconClass</code> and
<code
spellcheck="false">#cssClass</code>attributes, allowing all instance notes (e.g., books)
to display a specific icon and CSS style.</p>
<p>Explore the concept further in the <a href="#root/_help_wX4HbRucYSDD">demo notes</a>,
including examples like the <a href="#root/_help_iRwzGnHPzonm">Relation Map</a>,
<a
href="#root/_help_xYjQUYhpbUEW">Task Manager</a>, and <a href="#root/_help_l0tKav7yLHGF">Day Notes</a>.</p>
<p>Additionally, see <a href="#root/_help_47ZrP6FNuoG8">default note title</a> for
creating title templates. Note templates and title templates can be combined
by creating a <code>#titleTemplate</code> for a template note.</p>
by creating a <code spellcheck="false">#titleTemplate</code> for a template
note.</p>

View File

@ -3,7 +3,9 @@
<li>HTML:
<ul>
<li>This is the main format used by Trilium, where standard tags are used
to represent basic formatting and layout (e.g. <code>&lt;strong&gt;</code>, <code>&lt;table&gt;</code>, <code>&lt;pre&gt;</code>).</li>
to represent basic formatting and layout (e.g. <code spellcheck="false">&lt;strong&gt;</code>,
<code
spellcheck="false">&lt;table&gt;</code>, <code spellcheck="false">&lt;pre&gt;</code>).</li>
<li>Note that HTML is not a standardized format so some more specific features
such as admonitions or&nbsp;<a class="reference-link" href="#root/_help_hrZ1D00cLbal">Internal (reference) links</a>&nbsp;might
not be supported by other applications.</li>

View File

@ -13,7 +13,9 @@
<p>Trilium internal links (that mirror a note's title and display its icon)
are embedded as HTML in order to preserve the information on import.</p>
<h2>Math equations</h2>
<p>Both inline and display equations are supported, using the <code>$</code> and <code>$$</code> syntaxes.</p>
<p>Both inline and display equations are supported, using the <code spellcheck="false">$</code> and
<code
spellcheck="false">$$</code>syntaxes.</p>
<h2>Admonitions</h2>
<p>The Markdown syntax for admonitions as supported by Trilium is the one
that GitHub uses, which is as follows:</p><pre><code class="language-text-x-trilium-auto">&gt; [!NOTE]
@ -28,14 +30,17 @@
&gt; [!CAUTION]
&gt; This is a caution.</code></pre>
<p>There are currently no plans of supporting alternative admonition syntaxes
such as <code>!!! note</code>.</p>
such as <code spellcheck="false">!!! note</code>.</p>
<h2>Wikilinks</h2>
<p>Basic support for wikilinks has been added in v0.96.0:</p>
<ul>
<li><code>[[foo/bar]]</code> will look for the <code>bar.md</code> file in the <code>foo</code> directory
and turn it into an internal link.</li>
<li><code>![[foo/baz.png]]</code> will look for the <code>baz.png</code> file
in the <code>foo</code> directory and turn it into an image.</li>
<li><code spellcheck="false">[[foo/bar]]</code> will look for the <code spellcheck="false">bar.md</code> file
in the <code spellcheck="false">foo</code> directory and turn it into an
internal link.</li>
<li><code spellcheck="false">![[foo/baz.png]]</code> will look for the
<code
spellcheck="false">baz.png</code>file in the <code spellcheck="false">foo</code> directory
and turn it into an image.</li>
</ul>
<p>This feature is import-only, which means that it will turn wikilinks into
Trilium-compatible syntax, but it will not export Trilium Notes into Markdown

View File

@ -38,7 +38,8 @@
<p>If the Onenote header (that is at the top of each Onenote page) is not
desired, you can use the following regex to remove them in a text editor
like VsCode:</p>
<p>Find (using regex): <code>.&lt;div.*&gt;&lt;h1</code> Replace with: <code>&lt;h1</code>
<p>Find (using regex): <code spellcheck="false">.&lt;div.*&gt;&lt;h1</code> Replace
with: <code spellcheck="false">&lt;h1</code>
</p>
</li>
</ul>

View File

@ -2,9 +2,9 @@
some of these may work only in certain contexts (e.g. in tree pane or note
editor).</p>
<p>It is also possible to configure most keyboard shortcuts in Options -&gt;
Keyboard shortcuts. Using <code>global:</code> prefix, you can assign a shortcut
which will work even without Trilium being in focus (requires app restart
to take effect).</p>
Keyboard shortcuts. Using <code spellcheck="false">global:</code> prefix,
you can assign a shortcut which will work even without Trilium being in
focus (requires app restart to take effect).</p>
<h2>Tree</h2>
<p>See the corresponding section:&nbsp;<a class="reference-link" href="#root/_help_DvdZhoQZY9Yd">Keyboard shortcuts</a>
</p>
@ -20,7 +20,7 @@
<li><kbd>Alt</kbd> + <kbd>C</kbd> collapse whole note tree</li>
<li><kbd>Alt</kbd> + <kbd>-</kbd> (alt with minus sign) collapse subtree (if
some subtree takes too much space on tree pane you can collapse it)</li>
<li>you can define a <a href="#root/_help_zEY4DaJG4YT5">label</a> <code>#keyboardShortcut</code> with
<li>you can define a <a href="#root/_help_zEY4DaJG4YT5">label</a> <code spellcheck="false">#keyboardShortcut</code> with
e.g. value <kbd>Ctrl</kbd> + <kbd>I</kbd> . Pressing this keyboard combination
will then bring you to the note on which it is defined. Note that Trilium
must be reloaded/restarted (<kbd>Ctrl</kbd> + <kbd>R</kbd> ) for changes to

View File

@ -8,5 +8,5 @@
<p>
<img src="Bookmarks_bookmark-folder.png">
</p>
<p>To do this, you need to add a <code>#bookmarkFolder</code> label to the
note.</p>
<p>To do this, you need to add a <code spellcheck="false">#bookmarkFolder</code> label
to the note.</p>

View File

@ -28,9 +28,9 @@
<h2>Recent notes</h2>
<p>Jump to note also has the ability to show the list of recently viewed
/ edited notes and quickly jump to it.</p>
<p>To access this functionality, click on <code>Jump to</code> button on the
top. By default, (when nothing is entered into autocomplete), this dialog
will show the list of recent notes.</p>
<p>To access this functionality, click on <code spellcheck="false">Jump to</code> button
on the top. By default, (when nothing is entered into autocomplete), this
dialog will show the list of recent notes.</p>
<p>Alternatively you can click on the "time" icon on the right.</p>
<h2>Command Palette</h2>
<figure class="image image-style-align-center">
@ -46,8 +46,8 @@
<ul>
<li>Press <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>J</kbd> to display the command
palette directly.</li>
<li>If in the “Jump to” dialog, type <code>&gt;</code> in the search to switch
to the command palette.</li>
<li>If in the “Jump to” dialog, type <code spellcheck="false">&gt;</code> in
the search to switch to the command palette.</li>
</ul>
<p>Interaction:</p>
<ul>
@ -57,7 +57,8 @@
</ul>
<p>To exit the command palette:</p>
<ul>
<li>Remove the <code>&gt;</code> in the search to go back to the note search.</li>
<li>Remove the <code spellcheck="false">&gt;</code> in the search to go back
to the note search.</li>
<li>Press <kbd>Esc</kbd> to dismiss the dialog entirely.</li>
</ul>
<h3>Options available</h3>

View File

@ -9,8 +9,10 @@
<img src="Note Navigation_image.png">
</p>
<h2>Jump to note</h2>
<p>This is useful to quickly find and view arbitrary notes - click on <code>Jump to</code> button
on the top or press <kbd>Ctrl</kbd> + <kbd>J</kbd> . Then type part of the
note name and autocomplete will help you pick the desired note.</p>
<p>This is useful to quickly find and view arbitrary notes - click on
<code
spellcheck="false">Jump to</code>button on the top or press <kbd>Ctrl</kbd> + <kbd>J</kbd> .
Then type part of the note name and autocomplete will help you pick the
desired note.</p>
<p>See&nbsp;<a class="reference-link" href="#root/_help_F1r9QtzQLZqm">Jump to Note</a>&nbsp;for
more information.</p>

View File

@ -52,9 +52,9 @@
</ol>
<h3>Keyboard Navigation</h3>
<ul>
<li>Press <code>Enter</code> to open the first result</li>
<li>Press <code spellcheck="false">Enter</code> to open the first result</li>
<li>Use arrow keys to navigate through results</li>
<li>Press <code>Escape</code> to close the quick search</li>
<li>Press <code spellcheck="false">Escape</code> to close the quick search</li>
</ul>
<h2>Using Quick Search</h2>
<ol>
@ -66,23 +66,24 @@
<li><strong>Match locations</strong>: Bold text indicates where matches occur</li>
</ol>
<h2>Quick Search - Exact Match Operator</h2>
<p>Quick Search now supports the exact match operator (<code>=</code>) at
the beginning of your search query. This allows you to search for notes
<p>Quick Search now supports the exact match operator (<code spellcheck="false">=</code>)
at the beginning of your search query. This allows you to search for notes
where the title or content exactly matches your search term, rather than
just containing it.</p>
<h3>Usage</h3>
<p>To use exact match in Quick Search:</p>
<ol>
<li>Start your search query with the <code>=</code> operator</li>
<li>Follow it immediately with your search term (no space after <code>=</code>)</li>
<li>Start your search query with the <code spellcheck="false">=</code> operator</li>
<li>Follow it immediately with your search term (no space after <code spellcheck="false">=</code>)</li>
</ol>
<h4>Examples</h4>
<ul>
<li><code>=example</code> - Finds notes with title exactly "example" or content
exactly "example"</li>
<li><code>=Project Plan</code> - Finds notes with title exactly "Project Plan"
or content exactly "Project Plan"</li>
<li><code>='hello world'</code> - Use quotes for multi-word exact matches</li>
<li><code spellcheck="false">=example</code> - Finds notes with title exactly
"example" or content exactly "example"</li>
<li><code spellcheck="false">=Project Plan</code> - Finds notes with title
exactly "Project Plan" or content exactly "Project Plan"</li>
<li><code spellcheck="false">='hello world'</code> - Use quotes for multi-word
exact matches</li>
</ul>
<h4>Comparison with Regular Search</h4>
<table>
@ -94,12 +95,12 @@
</thead>
<tbody>
<tr>
<td><code>example</code>
<td><code spellcheck="false">example</code>
</td>
<td>Finds all notes containing "example" anywhere in title or content</td>
</tr>
<tr>
<td><code>=example</code>
<td><code spellcheck="false">=example</code>
</td>
<td>Finds only notes where the title equals "example" or content equals "example"
exactly</td>
@ -108,7 +109,7 @@
</table>
<h3>Technical Details</h3>
<p>When you use the <code>=</code> operator:</p>
<p>When you use the <code spellcheck="false">=</code> operator:</p>
<ul>
<li>The search performs an exact match on note titles</li>
<li>For note content, it looks for exact matches of the entire content</li>
@ -117,11 +118,12 @@
</ul>
<h3>Limitations</h3>
<ul>
<li>The <code>=</code> operator must be at the very beginning of the search
query</li>
<li>Spaces after <code>=</code> will treat it as a regular search</li>
<li>Multiple <code>=</code> operators (like <code>==example</code>) are treated
as regular text search</li>
<li>The <code spellcheck="false">=</code> operator must be at the very beginning
of the search query</li>
<li>Spaces after <code spellcheck="false">=</code> will treat it as a regular
search</li>
<li>Multiple <code spellcheck="false">=</code> operators (like <code spellcheck="false">==example</code>)
are treated as regular text search</li>
</ul>
<h3>Use Cases</h3>
<p>This feature is particularly useful when:</p>
@ -134,8 +136,9 @@
<h3>Related Features</h3>
<ul>
<li>For more complex exact matching queries, use the full <a href="#root/_help_eIg8jdvaoNNd">Search</a> functionality</li>
<li>For fuzzy matching (finding results despite typos), use the <code>~=</code> operator
<li>For fuzzy matching (finding results despite typos), use the <code spellcheck="false">~=</code> operator
in the full search</li>
<li>For partial matches with wildcards, use operators like <code>*=*</code>, <code>=*</code>,
or <code>*=</code> in the full search</li>
<li>For partial matches with wildcards, use operators like <code spellcheck="false">*=*</code>,
<code
spellcheck="false">=*</code>, or <code spellcheck="false">*=</code> in the full search</li>
</ul>

View File

@ -40,9 +40,9 @@
<li>Options:
<ul>
<li><em>Case sensitive</em> the search will distinguish upper case characters
from lower case (e.g. searching for Hello will not match <code>hello</code>).</li>
from lower case (e.g. searching for Hello will not match <code spellcheck="false">hello</code>).</li>
<li><em>Match words</em> - the search will find only exact word matches (e.g.
searching for <code>Java</code> will not match <code>JavaScript</code>).</li>
searching for <code spellcheck="false">Java</code> will not match <code spellcheck="false">JavaScript</code>).</li>
</ul>
</li>
</ul>

View File

@ -118,47 +118,51 @@
</ol>
<h3>Simple Note Search Examples</h3>
<ul>
<li><code>rings tolkien</code>: Full-text search to find notes containing
both "rings" and "tolkien".</li>
<li><code>"The Lord of the Rings" Tolkien</code>: Full-text search where "The
Lord of the Rings" must match exactly.</li>
<li><code>note.content *=* rings OR note.content *=* tolkien</code>: Find
notes containing "rings" or "tolkien" in their content.</li>
<li><code>towers #book</code>: Combine full-text and attribute search to find
notes containing "towers" and having the "book" label.</li>
<li><code>towers #book or #author</code>: Search for notes containing "towers"
and having either the "book" or "author" label.</li>
<li><code>towers #!book</code>: Search for notes containing "towers" and not
having the "book" label.</li>
<li><code>#book #publicationYear = 1954</code>: Find notes with the "book"
label and "publicationYear" set to 1954.</li>
<li><code>#genre *=* fan</code>: Find notes with the "genre" label containing
the substring "fan". Additional operators include <code>*=*</code> for "contains", <code>=*</code> for
"starts with", <code>*=</code> for "ends with", and <code>!=</code> for "is
not equal to".</li>
<li><code>#book #publicationYear &gt;= 1950 #publicationYear &lt; 1960</code>:
<li><code spellcheck="false">rings tolkien</code>: Full-text search to find
notes containing both "rings" and "tolkien".</li>
<li><code spellcheck="false">"The Lord of the Rings" Tolkien</code>: Full-text
search where "The Lord of the Rings" must match exactly.</li>
<li><code spellcheck="false">note.content *=* rings OR note.content *=* tolkien</code>:
Find notes containing "rings" or "tolkien" in their content.</li>
<li><code spellcheck="false">towers #book</code>: Combine full-text and attribute
search to find notes containing "towers" and having the "book" label.</li>
<li><code spellcheck="false">towers #book or #author</code>: Search for notes
containing "towers" and having either the "book" or "author" label.</li>
<li><code spellcheck="false">towers #!book</code>: Search for notes containing
"towers" and not having the "book" label.</li>
<li><code spellcheck="false">#book #publicationYear = 1954</code>: Find notes
with the "book" label and "publicationYear" set to 1954.</li>
<li><code spellcheck="false">#genre *=* fan</code>: Find notes with the "genre"
label containing the substring "fan". Additional operators include
<code
spellcheck="false">*=*</code>for "contains", <code spellcheck="false">=*</code> for "starts
with", <code spellcheck="false">*=</code> for "ends with", and <code spellcheck="false">!=</code> for
"is not equal to".</li>
<li><code spellcheck="false">#book #publicationYear &gt;= 1950 #publicationYear &lt; 1960</code>:
Use numeric operators to find all books published in the 1950s.</li>
<li><code>#dateNote &gt;= TODAY-30</code>: Find notes with the "dateNote"
label within the last 30 days. Supported date values include NOW +- seconds,
TODAY +- days, MONTH +- months, YEAR +- years.</li>
<li><code>~author.title *=* Tolkien</code>: Find notes related to an author
whose title contains "Tolkien".</li>
<li><code>#publicationYear %= '19[0-9]{2}'</code>: Use the '%=' operator to
match a regular expression (regex). This feature has been available since
Trilium 0.52.</li>
<li><code>note.content %= '\\d{2}:\\d{2} (PM|AM)'</code>: Find notes that
mention a time. Backslashes in a regex must be escaped.</li>
<li><code spellcheck="false">#dateNote &gt;= TODAY-30</code>: Find notes with
the "dateNote" label within the last 30 days. Supported date values include
NOW +- seconds, TODAY +- days, MONTH +- months, YEAR +- years.</li>
<li><code spellcheck="false">~author.title *=* Tolkien</code>: Find notes
related to an author whose title contains "Tolkien".</li>
<li><code spellcheck="false">#publicationYear %= '19[0-9]{2}'</code>: Use
the '%=' operator to match a regular expression (regex). This feature has
been available since Trilium 0.52.</li>
<li><code spellcheck="false">note.content %= '\\d{2}:\\d{2} (PM|AM)'</code>:
Find notes that mention a time. Backslashes in a regex must be escaped.</li>
</ul>
<h3>Fuzzy Search</h3>
<p>Trilium supports fuzzy search operators that find results with typos or
spelling variations:</p>
<ul>
<li><code>#title ~= trilim</code>: Fuzzy exact match - finds notes with titles
like "Trilium" even if you typed "trilim" (with typo)</li>
<li><code>#content ~* progra</code>: Fuzzy contains match - finds notes containing
words like "program", "programmer", "programming" even with slight misspellings</li>
<li><code>note.content ~* develpment</code>: Will find notes containing "development"
despite the typo</li>
<li><code spellcheck="false">#title ~= trilim</code>: Fuzzy exact match -
finds notes with titles like "Trilium" even if you typed "trilim" (with
typo)</li>
<li><code spellcheck="false">#content ~* progra</code>: Fuzzy contains match
- finds notes containing words like "program", "programmer", "programming"
even with slight misspellings</li>
<li><code spellcheck="false">note.content ~* develpment</code>: Will find
notes containing "development" despite the typo</li>
</ul>
<p><strong>Important notes about fuzzy search:</strong>
</p>
@ -171,8 +175,8 @@
</ul>
<h3>Advanced Use Cases</h3>
<ul>
<li><code>~author.relations.son.title = 'Christopher Tolkien'</code>: Search
for notes with an "author" relation to a note that has a "son" relation
<li><code spellcheck="false">~author.relations.son.title = 'Christopher Tolkien'</code>:
Search for notes with an "author" relation to a note that has a "son" relation
to "Christopher Tolkien". This can be modeled with the following note structure:
<ul>
<li>Books
@ -197,30 +201,52 @@
</li>
</ul>
</li>
<li><code>~author.title *= Tolkien OR (#publicationDate &gt;= 1954 AND #publicationDate &lt;= 1960)</code>:
<li><code spellcheck="false">~author.title *= Tolkien OR (#publicationDate &gt;= 1954 AND #publicationDate &lt;= 1960)</code>:
Use boolean expressions and parentheses to group expressions. Note that
expressions starting with a parenthesis need an "expression separator sign"
(# or ~) prepended.</li>
<li><code>note.parents.title = 'Books'</code>: Find notes with a parent named
"Books".</li>
<li><code>note.parents.parents.title = 'Books'</code>: Find notes with a grandparent
named "Books".</li>
<li><code>note.ancestors.title = 'Books'</code>: Find notes with an ancestor
named "Books".</li>
<li><code>note.children.title = 'sub-note'</code>: Find notes with a child
named "sub-note".</li>
<li><code spellcheck="false">note.parents.title = 'Books'</code>: Find notes
with a parent named "Books".</li>
<li><code spellcheck="false">note.parents.parents.title = 'Books'</code>:
Find notes with a grandparent named "Books".</li>
<li><code spellcheck="false">note.ancestors.title = 'Books'</code>: Find notes
with an ancestor named "Books".</li>
<li><code spellcheck="false">note.children.title = 'sub-note'</code>: Find
notes with a child named "sub-note".</li>
</ul>
<h3>Search with Note Properties</h3>
<p>Notes have properties that can be used in searches, such as <code>noteId</code>, <code>dateModified</code>, <code>dateCreated</code>, <code>isProtected</code>, <code>type</code>, <code>title</code>, <code>text</code>, <code>content</code>, <code>rawContent</code>, <code>ownedLabelCount</code>, <code>labelCount</code>, <code>ownedRelationCount</code>, <code>relationCount</code>, <code>ownedRelationCountIncludingLinks</code>, <code>relationCountIncludingLinks</code>, <code>ownedAttributeCount</code>, <code>attributeCount</code>, <code>targetRelationCount</code>, <code>targetRelationCountIncludingLinks</code>, <code>parentCount</code>, <code>childrenCount</code>, <code>isArchived</code>, <code>contentSize</code>, <code>noteSize</code>,
and <code>revisionCount</code>.</p>
<p>These properties can be accessed via the <code>note.</code> prefix, e.g., <code>note.type = code AND note.mime = 'application/json'</code>.</p>
<p>Notes have properties that can be used in searches, such as <code spellcheck="false">noteId</code>,
<code
spellcheck="false">dateModified</code>, <code spellcheck="false">dateCreated</code>,
<code
spellcheck="false">isProtected</code>, <code spellcheck="false">type</code>, <code spellcheck="false">title</code>,
<code
spellcheck="false">text</code>, <code spellcheck="false">content</code>, <code spellcheck="false">rawContent</code>,
<code
spellcheck="false">ownedLabelCount</code>, <code spellcheck="false">labelCount</code>,
<code
spellcheck="false">ownedRelationCount</code>, <code spellcheck="false">relationCount</code>,
<code
spellcheck="false">ownedRelationCountIncludingLinks</code>, <code spellcheck="false">relationCountIncludingLinks</code>,
<code
spellcheck="false">ownedAttributeCount</code>, <code spellcheck="false">attributeCount</code>,
<code
spellcheck="false">targetRelationCount</code>, <code spellcheck="false">targetRelationCountIncludingLinks</code>,
<code
spellcheck="false">parentCount</code>, <code spellcheck="false">childrenCount</code>,
<code
spellcheck="false">isArchived</code>, <code spellcheck="false">contentSize</code>, <code spellcheck="false">noteSize</code>,
and <code spellcheck="false">revisionCount</code>.</p>
<p>These properties can be accessed via the <code spellcheck="false">note.</code> prefix,
e.g., <code spellcheck="false">note.type = code AND note.mime = 'application/json'</code>.</p>
<h3>Order by and Limit</h3><pre><code class="language-text-x-trilium-auto">#author=Tolkien orderBy #publicationDate desc, note.title limit 10</code></pre>
<p>This example will:</p>
<ol>
<li>Find notes with the author label "Tolkien".</li>
<li>Order the results by <code>publicationDate</code> in descending order.</li>
<li>Use <code>note.title</code> as a secondary ordering if publication dates
are equal.</li>
<li>Order the results by <code spellcheck="false">publicationDate</code> in
descending order.</li>
<li>Use <code spellcheck="false">note.title</code> as a secondary ordering if
publication dates are equal.</li>
<li>Limit the results to the first 10 notes.</li>
</ol>
<h3>Negation</h3>
@ -267,11 +293,11 @@
#author.title *=* Tolkien</code></pre>
<h3>Separating Full-Text and Attribute Parts</h3>
<p>Search syntax allows combining full-text search with attribute-based search.
For example, <code>tolkien #book</code> contains:</p>
For example, <code spellcheck="false">tolkien #book</code> contains:</p>
<ol>
<li>Full-text tokens - <code>tolkien</code>
<li>Full-text tokens - <code spellcheck="false">tolkien</code>
</li>
<li>Attribute expressions - <code>#book</code>
<li>Attribute expressions - <code spellcheck="false">#book</code>
</li>
</ol>
<p>Trilium detects the separation between full text search and attribute/property
@ -288,13 +314,13 @@
<p>Three types of quotes are supported: single, double, and backtick.</p>
<h3>Type Coercion</h3>
<p>Label values are technically strings but can be coerced for numeric comparisons:</p><pre><code class="language-text-x-trilium-auto">note.dateCreated =* '2019-05'</code></pre>
<p>This finds notes created in May 2019. Numeric operators like <code>#publicationYear &gt;= 1960</code> convert
<p>This finds notes created in May 2019. Numeric operators like <code spellcheck="false">#publicationYear &gt;= 1960</code> convert
string values to numbers for comparison.</p>
<h2>Auto-Trigger Search from URL</h2>
<p>You can open Trilium and automatically trigger a search by including the
search <a href="https://meyerweb.com/eric/tools/dencoder/">url encoded</a> string
in the URL:</p>
<p><code>http://localhost:8080/#?searchString=abc</code>
<p><code spellcheck="false">http://localhost:8080/#?searchString=abc</code>
</p>
<h2>Search Configuration</h2>
<h3>Parameters</h3>

View File

@ -4,8 +4,9 @@
<p>A note is the central entity in TriliumNext. For more details, see <a href="#root/_help_BFs8mudNFgCS">Note</a>.</p>
<h2>Branch</h2>
<p>A branch describes the placement of a note within the note tree. Essentially,
it is a tuple of <code>parentNoteId</code> and <code>noteId</code>, indicating
that the given note is placed as a child under the specified parent note.</p>
it is a tuple of <code spellcheck="false">parentNoteId</code> and <code spellcheck="false">noteId</code>,
indicating that the given note is placed as a child under the specified
parent note.</p>
<p>Each note can have multiple branches, meaning any note can be placed in
multiple locations within the tree. This concept is referred to as "
<a

View File

@ -32,44 +32,44 @@
</thead>
<tbody>
<tr>
<td><code>workspace</code>
<td><code spellcheck="false">workspace</code>
</td>
<td>Marks this note as a workspace, button to enter the workspace is controlled
by this</td>
</tr>
<tr>
<td><code>workspaceIconClass</code>
<td><code spellcheck="false">workspaceIconClass</code>
</td>
<td>defines box icon CSS class which will be used in tab when hoisted to this
note</td>
</tr>
<tr>
<td><code>workspaceTabBackgroundColor</code>
<td><code spellcheck="false">workspaceTabBackgroundColor</code>
</td>
<td>CSS color used in the note tab when hoisted to this note, use any CSS
color format, e.g. "lightblue" or "#ddd". See <a href="https://www.w3schools.com/cssref/css_colors.asp">https://www.w3schools.com/cssref/css_colors.asp</a>.</td>
</tr>
<tr>
<td><code>workspaceCalendarRoot</code>
<td><code spellcheck="false">workspaceCalendarRoot</code>
</td>
<td>Marking a note with this label will define a new per-workspace calendar
for&nbsp;<a class="reference-link" href="#root/_help_l0tKav7yLHGF">Day Notes</a>.
If there's no such note, the global calendar will be used.</td>
</tr>
<tr>
<td><code>workspaceTemplate</code>
<td><code spellcheck="false">workspaceTemplate</code>
</td>
<td>This note will appear in the selection of available template when creating
new note, but only when hoisted into a workspace containing this template</td>
</tr>
<tr>
<td><code>workspaceSearchHome</code>
<td><code spellcheck="false">workspaceSearchHome</code>
</td>
<td>new search notes will be created as children of this note when hoisted
to some ancestor of this workspace note</td>
</tr>
<tr>
<td><code>workspaceInbox</code>
<td><code spellcheck="false">workspaceInbox</code>
</td>
<td>default inbox location for new notes when hoisted to some ancestor of
this workspace note</td>

View File

@ -1,5 +1,6 @@
<p>Archived notes are notes which have <code>archived</code> <a href="#root/_help_zEY4DaJG4YT5">attribute</a> -
either directly or <a href="#root/_help_bwZpz2ajCEwO">inherited</a>.</p>
<p>Archived notes are notes which have <code spellcheck="false">archived</code>
<a
href="#root/_help_zEY4DaJG4YT5">attribute</a>- either directly or <a href="#root/_help_bwZpz2ajCEwO">inherited</a>.</p>
<p>Such notes are then by default not shown in the autocomplete and in the
full text <a href="#root/_help_eIg8jdvaoNNd">search</a>.</p>
<p>This can be useful for notes which are no longer very useful but still

View File

@ -1,9 +1,9 @@
<p>Icons are useful for distinguishing notes. At the technical level, they
are set by the <code>iconClass</code> attribute which adds a CSS class to
the note. For example <code>#iconClass="bx bx-calendar"</code> will show
a calendar instead of the default page or folder icon. Looking up and remembering
the css class names is not necessary. While editing a note, click on the
icon next to the title to bring up a chooser gallery:</p>
are set by the <code spellcheck="false">iconClass</code> attribute which
adds a CSS class to the note. For example <code spellcheck="false">#iconClass="bx bx-calendar"</code> will
show a calendar instead of the default page or folder icon. Looking up
and remembering the css class names is not necessary. While editing a note,
click on the icon next to the title to bring up a chooser gallery:</p>
<p>
<img src="Note Icons_note-icon-chang.png"
alt="change note icon">

View File

@ -6,12 +6,12 @@
of the note for easy navigation.</p>
<h2>Configuration</h2>
<ul>
<li>To hide the note list for a particular note, simply apply the <code>hideChildrenOverview</code>
<li>To hide the note list for a particular note, simply apply the <code spellcheck="false">hideChildrenOverview</code>
<a
href="#root/_help_zEY4DaJG4YT5">label</a>.</li>
<li>For some view types, such as Grid view, only a subset of notes will be
displayed and pagination can be used to navigate through all of them for
performance reasons. To adjust the number of notes per page, set <code>pageSize</code> to
performance reasons. To adjust the number of notes per page, set <code spellcheck="false">pageSize</code> to
the desired number.</li>
</ul>
<h2>View types</h2>
@ -21,4 +21,4 @@
<p>Generally the view type can only be changed in a&nbsp;<a class="reference-link"
href="#root/_help_GTwFsgaA0lCt">Collections</a>&nbsp;note from the&nbsp;<a class="reference-link"
href="#root/_help_BlN9DFI679QC">Ribbon</a>, but it can also be changed manually
on any type of note using the <code>#viewType</code> attribute.</p>
on any type of note using the <code spellcheck="false">#viewType</code> attribute.</p>

View File

@ -4,15 +4,15 @@
<p>Time interval of taking note snapshot is configurable in the Options -&gt;
Other dialog. This provides a tradeoff between more revisions and more
data to store.</p>
<p>To turn off note versioning for a particular note (or subtree), add <code>disableVersioning</code>
<a
href="#root/_help_zEY4DaJG4YT5">label</a>to the note.</p>
<p>To turn off note versioning for a particular note (or subtree), add
<code
spellcheck="false">disableVersioning</code> <a href="#root/_help_zEY4DaJG4YT5">label</a>to the note.</p>
<h2>Note Revision Snapshots Limit</h2>
<p>The limit on the number of note snapshots can be configured in the Options
-&gt; Other dialog. The note revision snapshot number limit refers to the
maximum number of revisions that can be saved for each note. Where -1 means
no limit, 0 means delete all revisions. You can set the maximum revisions
for a single note through the <code>versioningLimit=X</code> label.</p>
for a single note through the <code spellcheck="false">versioningLimit=X</code> label.</p>
<p>The note limit will not take effect immediately; it will only apply when
the note is modified.</p>
<p>You can click the <strong>Erase excess revision snapshots now</strong> button

View File

@ -4,6 +4,7 @@
<figcaption>Screenshot of the note contextual menu indicating the “Export as PDF”
option.</figcaption>
</figure>
<h2>Printing</h2>
<p>This feature allows printing of notes. It works on both the desktop client,
but also on the web.</p>
@ -59,10 +60,9 @@ class="admonition note">
orientation, size. However, there are a few&nbsp;<a class="reference-link"
href="#root/_help_zEY4DaJG4YT5">Attributes</a>&nbsp;to adjust some of the settings:</p>
<ul>
<li data-list-item-id="eec9214505f224e0ef7d50955357f6f52">To print in landscape mode instead of portrait (useful for big diagrams
<li>To print in landscape mode instead of portrait (useful for big diagrams
or slides), add <code spellcheck="false">#printLandscape</code>.</li>
<li
data-list-item-id="ebc1a98e97b39978d0165f0befbf103a9">By default, the resulting PDF will be in Letter format. It is possible
<li>By default, the resulting PDF will be in Letter format. It is possible
to adjust it to another page size via the <code spellcheck="false">#printPageSize</code> attribute,
with one of the following values: <code spellcheck="false">A0</code>,
<code
@ -82,10 +82,9 @@ class="admonition note">
<p>Since v0.100.0, it is possible to print more than one note at the time
by using&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>:</p>
<ol>
<li data-list-item-id="e218b7d45c9a9ce882f16112aec9333be">First create a collection.</li>
<li data-list-item-id="e159ed2993b564448ee15f5796bba1d31">Configure it to use&nbsp;<a class="reference-link" href="#root/_help_mULW0Q3VojwY">List View</a>.</li>
<li
data-list-item-id="ea82f390047ea239e7793145768738b97">Print the collection note normally.</li>
<li>First create a collection.</li>
<li>Configure it to use&nbsp;<a class="reference-link" href="#root/_help_mULW0Q3VojwY">List View</a>.</li>
<li>Print the collection note normally.</li>
</ol>
<p>The resulting collection will contain all the children of the collection,
while maintaining the hierarchy.</p>
@ -102,9 +101,9 @@ class="admonition note">
href="#root/_help_4TIF1oA4VQRO">Options</a>&nbsp;and assigning a key combination
for:</p>
<ul>
<li class="ck-list-marker-italic" data-list-item-id="e6b80294fd7a2d5f5d7cbf831691b53c8"><em>Print Active Note</em>
<li><em>Print Active Note</em>
</li>
<li class="ck-list-marker-italic" data-list-item-id="eb2cc694f51e4e25dcf1f814e64523df9"><em>Export Active Note as PDF</em>
<li><em>Export Active Note as PDF</em>
</li>
</ul>
<h2>Constraints &amp; limitations</h2>
@ -112,43 +111,43 @@ class="admonition note">
supported when printing, in which case the <em>Print</em> and <em>Export as PDF</em> options
will be disabled.</p>
<ul>
<li data-list-item-id="e38dd484ec45f9bddf43bb9ecf708d339">For&nbsp;<a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;notes:
<li>For&nbsp;<a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;notes:
<ul>
<li data-list-item-id="e88456d3f86ed7e8656f60b837bf27f9f">Line numbers are not printed.</li>
<li data-list-item-id="e1e5e18b8dedac46c49cc46360b6a444f">Syntax highlighting is enabled, however a default theme (Visual Studio)
<li>Line numbers are not printed.</li>
<li>Syntax highlighting is enabled, however a default theme (Visual Studio)
is enforced.</li>
</ul>
</li>
<li data-list-item-id="e025b80306e7f736f3ae08e5693ab522e">For&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>,
<li>For&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>,
the following are supported:
<ul>
<li data-list-item-id="e3553e19731217829ba704c7bbacf86f4"><a class="reference-link" href="#root/_help_mULW0Q3VojwY">List View</a>, allowing
<li><a class="reference-link" href="#root/_help_mULW0Q3VojwY">List View</a>, allowing
to print multiple notes at once while preserving hierarchy (similar to
a book).</li>
<li data-list-item-id="e96cab6a4cb4a18b1fa98d49f40d29496"><a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation</a>,
<li><a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation</a>,
where each slide/sub-note is displayed.
<ul>
<li data-list-item-id="ea145a7d22299304fbed7d8acb2cc05a0">Most note types are supported, especially the ones that have an image
representation such as&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_grjYqerjn243">Canvas</a>&nbsp;and&nbsp;
<li>Most note types are supported, especially the ones that have an image
representation such as&nbsp;<a class="reference-link" href="#root/_help_grjYqerjn243">Canvas</a>&nbsp;and&nbsp;
<a
class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_gBbsAeiuUxI5">Mind Map</a>.</li>
class="reference-link" href="#root/_help_gBbsAeiuUxI5">Mind Map</a>.</li>
</ul>
</li>
<li data-list-item-id="e6eecc96905c6fb3d05ab360fbf02c395"><a class="reference-link" href="#root/_help_2FvYrpmOXm29">Table</a>, where the
<li><a class="reference-link" href="#root/_help_2FvYrpmOXm29">Table</a>, where the
table is rendered in a print-friendly way.
<ul>
<li data-list-item-id="e44cd46142fff861654387e9b040bb051">Tables that are too complex (especially if they have multiple columns)
<li>Tables that are too complex (especially if they have multiple columns)
might not fit properly, however tables with a large number of rows are
supported thanks to pagination.</li>
<li data-list-item-id="edf28072a875e21fc21e18e7ddc0fec26">Consider printing in landscape mode, or using <code spellcheck="false">#printLandscape</code> if
<li>Consider printing in landscape mode, or using <code spellcheck="false">#printLandscape</code> if
exporting to PDF.</li>
</ul>
</li>
<li data-list-item-id="e504297e0bafefa23c8c0ba28d67889e8">The rest of the collections are not supported, but we plan to add support
<li>The rest of the collections are not supported, but we plan to add support
for all the collection types at some point.</li>
</ul>
</li>
<li data-list-item-id="eb2113dc9bd86628162fe2eb47488f5f2">Using&nbsp;<a class="reference-link" href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;for
<li>Using&nbsp;<a class="reference-link" href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;for
printing is no longer supported, instead a custom <code spellcheck="false">printCss</code> relation
needs to be used (see below).</li>
</ul>
@ -159,10 +158,10 @@ class="admonition note">
printing.</p>
<p>To do so:</p>
<ul>
<li data-list-item-id="e3df5625e58cea9d50974335203d99caa">Create a CSS <a href="#root/_help_6f9hih2hXXZk">code note</a>.</li>
<li data-list-item-id="e48c1388ee530c6301c75c8136617cf8f">On the note being printed, apply the <code spellcheck="false">~printCss</code> relation
<li>Create a CSS <a href="#root/_help_6f9hih2hXXZk">code note</a>.</li>
<li>On the note being printed, apply the <code spellcheck="false">~printCss</code> relation
to point to the newly created CSS code note.</li>
<li data-list-item-id="eaecc4fd4d22747aa15c85c988aab6d79">To apply the CSS to multiple notes, consider using <a href="#root/_help_bwZpz2ajCEwO">inheritable attributes</a> or&nbsp;
<li>To apply the CSS to multiple notes, consider using <a href="#root/_help_bwZpz2ajCEwO">inheritable attributes</a> or&nbsp;
<a
class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>.</li>
</ul>
@ -173,14 +172,13 @@ class="admonition note">
}</code></pre>
<p>To remark:</p>
<ul>
<li data-list-item-id="ec9cd88d328b97422c11f4b25c1042ed5">Multiple CSS notes can be add by using multiple <code spellcheck="false">~printCss</code> relations.</li>
<li
data-list-item-id="e5ff782914a559055a1a72dda1be246bd">If the note pointing to the <code spellcheck="false">printCss</code> doesn't
<li>Multiple CSS notes can be add by using multiple <code spellcheck="false">~printCss</code> relations.</li>
<li>If the note pointing to the <code spellcheck="false">printCss</code> doesn't
have the right note type or mime type, it will be ignored.</li>
<li data-list-item-id="eab7b697428ef92d60ab6cd65bda76b69">If migrating from a previous version where&nbsp;<a class="reference-link"
href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>, there's no need for
<code
spellcheck="false">@media print {</code>since the style-sheet is used only for printing.</li>
<li>If migrating from a previous version where&nbsp;<a class="reference-link"
href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>, there's no need for
<code
spellcheck="false">@media print {</code>since the style-sheet is used only for printing.</li>
</ul>
<h2>Under the hood</h2>
<p>Both printing and exporting as PDF use the same mechanism: a note is rendered

View File

@ -36,8 +36,9 @@
<p>Apart from using the ribbon as previously mentioned, it's also possible
to use <a href="#root/_help_zEY4DaJG4YT5">labels</a> to change the behavior:</p>
<ul>
<li>To set as read-only, apply the <code>readOnly</code> label to the note.</li>
<li>To disable automatic read-only (always editable), apply the <code>autoReadOnlyDisabled</code> label.</li>
<li>To set as read-only, apply the <code spellcheck="false">readOnly</code> label
to the note.</li>
<li>To disable automatic read-only (always editable), apply the <code spellcheck="false">autoReadOnlyDisabled</code> label.</li>
</ul>
<h2>Temporarily editing a read-only note</h2>
<p>When accessing a read-only note, it's possible to temporarily edit it

View File

@ -14,35 +14,41 @@
<p>Child notes can be automatically sorted by attaching specific <a href="#root/_help_zEY4DaJG4YT5">labels</a> to
the parent note:</p>
<ul>
<li><code>#sorted</code>: Enables sorting. Can optionally include the name
of the note's property/label for sorting criteria (details below).</li>
<li><code>#sortDirection</code>: By default, sorting is ascending. Set this
to <code>desc</code> to sort in descending order.</li>
<li><code>#sortFoldersFirst</code>: Notes with children will be sorted to
the top.</li>
<li><code spellcheck="false">#sorted</code>: Enables sorting. Can optionally
include the name of the note's property/label for sorting criteria (details
below).</li>
<li><code spellcheck="false">#sortDirection</code>: By default, sorting is
ascending. Set this to <code spellcheck="false">desc</code> to sort in descending
order.</li>
<li><code spellcheck="false">#sortFoldersFirst</code>: Notes with children
will be sorted to the top.</li>
</ul>
<p>Sorting is done by comparing note properties or specific labels on child
notes. There are four sorting levels, with the first having the highest
priority. Lower priority levels are applied only if higher priority comparisons
result in equality.</p>
<ol>
<li><strong>Top Label Sorting</strong>: Child notes with the <code>#top</code> label
<li><strong>Top Label Sorting</strong>: Child notes with the <code spellcheck="false">#top</code> label
will appear at the top of the folder.</li>
<li><strong>Bottom Label Sorting</strong>: (Introduced in Trilium 0.62) Child
notes with the <code>#bottom</code> label will appear at the bottom of the
folder.</li>
notes with the <code spellcheck="false">#bottom</code> label will appear
at the bottom of the folder.</li>
<li><strong>Property/Label-Based Sorting</strong>: Sorting is based on the
parent note's <code>#sorted</code> label:
parent note's <code spellcheck="false">#sorted</code> label:
<ul>
<li><strong>Default Sorting</strong>: If <code>#sorted</code> has no value,
notes are sorted alphabetically.</li>
<li><strong>Property Sorting</strong>: If <code>#sorted</code> is set to <code>title</code>, <code>dateModified</code>,
or <code>dateCreated</code>, notes are sorted based on the specified property.</li>
<li><strong>Label Sorting</strong>: If <code>#sorted</code> has any other value,
this value is treated as the name of a child note's label, and sorting
is based on the values of this label. For example, setting <code>#sorted=myOrder</code> on
the parent note and using <code>#myOrder=001</code>, <code>#myOrder=002</code>,
etc., on child notes.</li>
<li><strong>Default Sorting</strong>: If <code spellcheck="false">#sorted</code> has
no value, notes are sorted alphabetically.</li>
<li><strong>Property Sorting</strong>: If <code spellcheck="false">#sorted</code> is
set to <code spellcheck="false">title</code>, <code spellcheck="false">dateModified</code>,
or <code spellcheck="false">dateCreated</code>, notes are sorted based on
the specified property.</li>
<li><strong>Label Sorting</strong>: If <code spellcheck="false">#sorted</code> has
any other value, this value is treated as the name of a child note's label,
and sorting is based on the values of this label. For example, setting
<code
spellcheck="false">#sorted=myOrder</code>on the parent note and using <code spellcheck="false">#myOrder=001</code>,
<code
spellcheck="false">#myOrder=002</code>, etc., on child notes.</li>
</ul>
</li>
<li><strong>Alphabetical Sorting</strong>: Used as a last resort when other

View File

@ -10,13 +10,13 @@
<p>Trilium supports custom user themes, allowing you to personalize the application's
appearance. To create a custom theme, follow these steps:</p>
<ol>
<li data-list-item-id="eca8bbfc636daa344eaabbbb94ea94c3f"><strong>Create a CSS Code Note</strong>: Start by creating a new <a href="#root/_help_6f9hih2hXXZk">code note</a> with
<li><strong>Create a CSS Code Note</strong>: Start by creating a new <a href="#root/_help_6f9hih2hXXZk">code note</a> with
the <code spellcheck="false">CSS</code> type.</li>
<li data-list-item-id="e5ae35a0ee455e32c200fc095bf8415ac"><strong>Annotate with</strong> <code spellcheck="false">#appTheme</code>:
<li><strong>Annotate with</strong> <code spellcheck="false">#appTheme</code>:
Add the <a href="#root/_help_zEY4DaJG4YT5">attribute</a> <code spellcheck="false">#appTheme=my-theme-name</code> to
your note, where <code spellcheck="false">my-theme-name</code> is the name
of your custom theme.</li>
<li data-list-item-id="e7cd8c79dcf2d9edc2d03c924b9d954e1"><strong>Define Your Styles</strong>: Write your custom CSS within the
<li><strong>Define Your Styles</strong>: Write your custom CSS within the
note. Below is an example of a custom theme:</li>
</ol><pre><code class="language-text-x-trilium-auto">@font-face {
font-family: 'Raleway';
@ -74,12 +74,12 @@ body .CodeMirror {
<h3>Activating Your Custom Theme</h3>
<p>Once you've created your custom theme:</p>
<ol>
<li data-list-item-id="ee141db479e6972f78a12a2ece4be4d8f">Go to "Menu" -&gt; "Options" -&gt; "Appearance."</li>
<li data-list-item-id="e36a48638934829faceb5b68dececd6c7">In the theme selection dropdown, you should see your custom theme listed
<li>Go to "Menu" -&gt; "Options" -&gt; "Appearance."</li>
<li>In the theme selection dropdown, you should see your custom theme listed
under the name you provided with the <code spellcheck="false">#appTheme</code>
<a
href="#root/_help_zEY4DaJG4YT5">label</a>.</li>
<li data-list-item-id="eb7987a455a323d619c83e04a3f660cf9">Select your custom theme to activate it.</li>
<li>Select your custom theme to activate it.</li>
</ol>
<p>If you make changes to your theme, press <kbd>Ctrl</kbd> + <kbd>R</kbd> to
reload the frontend and apply your updates.</p>
@ -100,13 +100,11 @@ body .CodeMirror {
<h3>Applying Custom CSS</h3>
<p>To use custom CSS:</p>
<ol>
<li data-list-item-id="e34f8b4bcba7c20fb1b7653fe36ded3da"><strong>Create a CSS Code Note</strong>: Create a new&nbsp;<a class="reference-link"
<li><strong>Create a CSS Code Note</strong>: Create a new&nbsp;<a class="reference-link"
href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;note with the <code spellcheck="false">CSS</code> type.</li>
<li
data-list-item-id="ec697ca6baf249b374caa04b0817a54f0"><strong>Add the</strong> <code spellcheck="false">appCss</code> <strong>Label</strong>:
<li><strong>Add the</strong> <code spellcheck="false">appCss</code> <strong>Label</strong>:
Annotate the note with the <code spellcheck="false">#appCss</code> <a href="#root/_help_zEY4DaJG4YT5">label</a>.</li>
<li
data-list-item-id="e33d95fa67b19ef88f2561c3addecade8"><strong>Write Your CSS</strong>: Add your custom CSS rules to the note.</li>
<li><strong>Write Your CSS</strong>: Add your custom CSS rules to the note.</li>
</ol>
<p>For example:</p><pre><code class="language-text-x-trilium-auto">/* Custom CSS to style specific elements */
.tree-item {
@ -122,11 +120,10 @@ body .CodeMirror {
<h3>Styling Specific Notes in the Tree</h3>
<p>To apply specific styles to certain notes in the tree:</p>
<ul>
<li data-list-item-id="e885cbe8b8c440d4bf71c95d5f8c73340"><strong>Use the</strong> <code spellcheck="false">cssClass</code> <strong>Attribute</strong>:
<li><strong>Use the</strong> <code spellcheck="false">cssClass</code> <strong>Attribute</strong>:
Add the <code spellcheck="false">cssClass</code> <a href="#root/_help_zEY4DaJG4YT5">attribute</a> to
a note, and assign it a value representing the desired CSS class.</li>
<li
data-list-item-id="e168c9c99d3bf9e7af0d0bd03ee6903f5"><strong>Define an</strong> <code spellcheck="false">iconClass</code>: You
<li><strong>Define an</strong> <code spellcheck="false">iconClass</code>: You
can also define a custom icon for a note using the <code spellcheck="false">iconClass</code> attribute,
selecting from <a href="https://boxicons.com">Box Icons</a> or your own custom
classes.</li>

View File

@ -4,21 +4,20 @@
<aside
class="admonition note">
<p><strong>Icon packs are third-party content</strong>
<br>
<br>The Trilium maintainers are not responsible for keeping these icon packs
</p>
<p>The Trilium maintainers are not responsible for keeping these icon packs
up to date. If you have an issue with a specific icon pack, then the issue
must be reported to the third-party developer responsible for it, not the
Trilium team.</p>
</aside>
<p>To import an icon pack:</p>
<ol>
<li data-list-item-id="e72cd89899a976ca5c54e089df2285d41">Ideally, create a dedicated spot in your note tree where to place the
<li>Ideally, create a dedicated spot in your note tree where to place the
icon packs.</li>
<li data-list-item-id="ed7f941fe865c5f14e1ae724831e49ba1">Right click the note where to put it and select <em>Import into note</em>.</li>
<li
data-list-item-id="e1b6980592dddab6a0235dd070b3b7067">Uncheck <em>Safe import</em>.</li>
<li data-list-item-id="edd29376be6fbf3b9c59275145457de3b">Select <em>Import</em>.</li>
<li data-list-item-id="ea9ae8004d6cd7b349ac648cde9141977"><a href="#root/pOsGYCXsbNQG/BgmBlOIl72jZ/_help_s8alTXmpFR61">Refresh the application</a>.</li>
<li>Right click the note where to put it and select <em>Import into note</em>.</li>
<li>Uncheck <em>Safe import</em>.</li>
<li>Select <em>Import</em>.</li>
<li><a href="#root/_help_s8alTXmpFR61">Refresh the application</a>.</li>
</ol>
<aside class="admonition warning">
<p>Since <em>Safe import</em> is disabled, make sure you trust the source as
@ -30,11 +29,11 @@ class="admonition note">
<h2>Creating an icon pack</h2>
<p>Creating an icon pack requires some scripting knowledge outside Trilium
in order to generate the list of icons. For information, see&nbsp;<a class="reference-link"
href="#root/pKK96zzmvBGf/_help_g1mlRoU8CsqC">Creating an icon pack</a>.</p>
href="#root/_help_g1mlRoU8CsqC">Creating an icon pack</a>.</p>
<h2>Using an icon from an icon pack</h2>
<p>After <a href="#root/pOsGYCXsbNQG/BgmBlOIl72jZ/_help_s8alTXmpFR61">refreshing the application</a>,
the icon pack should be enabled by default. To test this, simply select
an existing note or create a new one and try to change the note icon.</p>
<p>After <a href="#root/_help_s8alTXmpFR61">refreshing the application</a>, the
icon pack should be enabled by default. To test this, simply select an
existing note or create a new one and try to change the note icon.</p>
<p>There should be a <em>Filter</em> button to the right of the search bar
in the icon list. Clicking it allows filtering by icon pack and the newly
imported icon pack should be displayed there.</p>
@ -42,35 +41,33 @@ class="admonition note">
<p>If the icon pack is missing from that list, then most likely there's something
wrong with it.</p>
<ul>
<li data-list-item-id="e0a36a4a12c83b68ed1affd67e7ffa850">Try checking the&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/BgmBlOIl72jZ/qzNzp9LYQyPT/_help_bnyigUA2UK7s">Backend (server) logs</a>&nbsp;for
<li>Try checking the&nbsp;<a class="reference-link" href="#root/_help_bnyigUA2UK7s">Backend (server) logs</a>&nbsp;for
clues and make sure that the icon pack has the <code spellcheck="false">#iconPack</code>
<a
href="#root/pOsGYCXsbNQG/tC7s2alapj8V/zEY4DaJG4YT5/_help_HI6GBBIduIgv">label</a>with a value assigned to it (a prefix).</li>
<li data-list-item-id="e33510913f0656b1c14c5f0c7278093c7">Icon packs that are <a href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/BFs8mudNFgCS/_help_bwg0e8ewQMak">protected</a> are
ignored.</li>
href="#root/_help_HI6GBBIduIgv">label</a>with a value assigned to it (a prefix).</li>
<li>Icon packs that are <a href="#root/_help_bwg0e8ewQMak">protected</a> are ignored.</li>
</ul>
</aside>
<h2>Integration with the share and export functionality</h2>
<p>Custom icon packs are also supported by the&nbsp;<a class="reference-link"
href="#root/pOsGYCXsbNQG/tC7s2alapj8V/_help_R9pX4DGra2Vt">Sharing</a>&nbsp;feature,
where they will be shown in the note tree. However, in order for an icon
pack to be visible to the share function, the icon pack note must also
be shared.</p>
href="#root/_help_R9pX4DGra2Vt">Sharing</a>&nbsp;feature, where they will be
shown in the note tree. However, in order for an icon pack to be visible
to the share function, the icon pack note must also be shared.</p>
<p>If you are using a custom share theme, make sure it supports the
<code
spellcheck="false">iconPackCss</code>, otherwise icons will not show up. Check the original
share template source code for reference.</p>
<p>Custom icon packs will also be preserved when&nbsp;<a class="reference-link"
href="#root/pOsGYCXsbNQG/tC7s2alapj8V/R9pX4DGra2Vt/_help_ycBFjKrrwE9p">Exporting static HTML for web publishing</a>.
href="#root/_help_ycBFjKrrwE9p">Exporting static HTML for web publishing</a>.
In this case, there's no requirement to make the icon pack shared.</p>
<h2>What happens if I remove an icon pack</h2>
<p>If an icon pack is removed or disabled (by removing or altering its
<code
spellcheck="false">#iconPack</code>label), all the notes that use this icon pack will show
in the&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_oPVyFC7WL2Lp">Note Tree</a>&nbsp;with
in the&nbsp;<a class="reference-link" href="#root/_help_oPVyFC7WL2Lp">Note Tree</a>&nbsp;with
no icon. This won't cause any issues apart from looking strange.</p>
<p>The solution is to replace the icons with some else, try using&nbsp;
<a
class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/wArbEsdSae6g/_help_eIg8jdvaoNNd">Search</a>&nbsp;which supports bulk actions, to identify the notes with
class="reference-link" href="#root/_help_eIg8jdvaoNNd">Search</a>&nbsp;which supports bulk actions, to identify the notes with
the now deleted icon pack (by looking for the prefix) and changing or removing
their <code spellcheck="false">iconClass</code>.</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -58,11 +58,13 @@
<p><strong>Note Launcher</strong>
<br>A note launcher will simply navigate to a specified note.</p>
<ol>
<li>Set the <code>target</code> promoted attribute to the note to navigate to.</li>
<li>Optionally, set <code>hoistedNote</code> to hoist a particular note. See&nbsp;
<a
href="#root/_help_OR8WJ7Iz9K4U">Note Hoisting</a>&nbsp;for more information.</li>
<li>Optionally, set a <code>keyboardShortcut</code> to trigger the launcher.</li>
<li>Set the <code spellcheck="false">target</code> promoted attribute to the
note to navigate to.</li>
<li>Optionally, set <code spellcheck="false">hoistedNote</code> to hoist a particular
note. See&nbsp;<a href="#root/_help_OR8WJ7Iz9K4U">Note Hoisting</a>&nbsp;for
more information.</li>
<li>Optionally, set a <code spellcheck="false">keyboardShortcut</code> to trigger
the launcher.</li>
</ol>
</li>
<li>
@ -71,8 +73,10 @@
<a
href="#root/_help_CdNpE2pqjmI6">Scripts</a>&nbsp;for more information.</p>
<ol>
<li>Set <code>script</code> to point to the desired script to run.</li>
<li>Optionally, set a <code>keyboardShortcut</code> to trigger the launcher.</li>
<li>Set <code spellcheck="false">script</code> to point to the desired script
to run.</li>
<li>Optionally, set a <code spellcheck="false">keyboardShortcut</code> to trigger
the launcher.</li>
</ol>
</li>
<li>

View File

@ -12,7 +12,7 @@
<p>For more information, consult the <a href="#root/_help_AlJ73vBCjWDw">dedicated page</a>.</p>
<figure
class="image">
<img style="aspect-ratio:1150/27;" src="4_New Layout_image.png"
<img style="aspect-ratio:1150/27;" src="5_New Layout_image.png"
width="1150" height="27">
</figure>
@ -38,7 +38,7 @@ class="image">
can be scrolled past.</figcaption>
</figure>
<figure class="image">
<img style="aspect-ratio:910/104;" src="3_New Layout_image.png"
<img style="aspect-ratio:910/104;" src="4_New Layout_image.png"
width="910" height="104">
<figcaption>The fixed title bar. The title only appears after scrolling past the <em>Inline title</em>.</figcaption>
</figure>
@ -50,7 +50,7 @@ class="image">
the <em>Inline title</em>. Apart from changing the note type, it's also
possible to apply a <a href="#root/_help_KC1HB96bqqHX">template</a>.</p>
<p>The switcher will disappear as soon as a text is entered.</p>
<img src="5_New Layout_image.png"
<img src="6_New Layout_image.png"
width="735" height="143">
<h3>Note badges</h3>
@ -58,7 +58,7 @@ class="image">
about the note such as whether it is read-only. Some of the badges are
also interactive.</p>
<figure class="image">
<img style="aspect-ratio:910/49;" src="2_New Layout_image.png"
<img style="aspect-ratio:910/49;" src="3_New Layout_image.png"
width="910" height="49">
</figure>
<p>The following badges are available:</p>
@ -108,6 +108,21 @@ class="image">
href="#root/_help_eIg8jdvaoNNd">Search</a>&nbsp;and&nbsp;<a class="reference-link"
href="#root/_help_m523cpzocqaD">Saved Search</a>.</li>
</ul>
<h3>Save status indicator</h3>
<p>
<img class="image-style-align-right" src="2_New Layout_image.png"
width="168" height="47">To the right of the note title, a temporary indicators appears after making
a change to the document that indicates whether the document has been saved.</p>
<p>It indicates the following states:</p>
<ul>
<li><em>Unsaved</em>, if the changes will be saved soon.</li>
<li><em>Saving</em>, if the changes are being saved.</li>
<li><em>Saved</em>, if all the changes were successfully saved to the server.</li>
<li><em>Error</em>, if the changes could not be saved, for example due to
a communication server with the server.</li>
</ul>
<p>After all changes have been saved, the indicator will hide automatically
after a few seconds.</p>
<h2>Changing to the existing layout</h2>
<h3>Removal of the ribbon</h3>
<p>The most significant change is the removal of the ribbon. All the actions
@ -177,13 +192,13 @@ class="image">
<li>Some smaller ribbon tabs were converted to badges that appear near the
note title in the breadcrumb section:
<ul>
<li>Original URL indicator for clipped web pages (<code>#pageUrl</code>).</li>
<li>Original URL indicator for clipped web pages (<code spellcheck="false">#pageUrl</code>).</li>
<li>SQL and script execute buttons.</li>
</ul>
</li>
</ul>
<aside class="admonition note">
<p>The ribbon keyboard shortcuts (e.g. <code>toggleRibbonTabClassicEditor</code>)
<p>The ribbon keyboard shortcuts (e.g. <code spellcheck="false">toggleRibbonTabClassicEditor</code>)
have been repurposed to work on the new layout, where they will toggle
the appropriate panel.</p>
</aside>

View File

@ -29,9 +29,10 @@
</ul>
<h2>Context Menu</h2>
<p>You can also move notes using the familiar cut and paste functions available
in the context menu, or with the associated keyboard <a href="#root/_help_A9Oc6YKKc65v">shortcuts</a>: <code>CTRL-C</code> (
<a
href="#root/_help_IakOLONlIfGI">copy</a>), <kbd>Ctrl</kbd> + <kbd>X</kbd> (cut) and <kbd>Ctrl</kbd> + <kbd>V</kbd> (paste).</p>
in the context menu, or with the associated keyboard <a href="#root/_help_A9Oc6YKKc65v">shortcuts</a>:
<code
spellcheck="false">CTRL-C</code>( <a href="#root/_help_IakOLONlIfGI">copy</a>), <kbd>Ctrl</kbd> + <kbd>X</kbd> (cut)
and <kbd>Ctrl</kbd> + <kbd>V</kbd> (paste).</p>
<p>See&nbsp;<a class="reference-link" href="#root/_help_YtSN43OrfzaA">Note tree contextual menu</a>&nbsp;for
more information.</p>
<h2>Keyboard shortcuts</h2>

View File

@ -216,7 +216,7 @@
<li><strong>Copy note path to clipboard</strong>
<ul>
<li>Copies a URL fragment representing the full path to this branch for a
note, such as <code>#root/Hb2E70L7HPuf/4sRFgMZhYFts/2IVuShedRJ3U/LJVMvKXOFv7n</code>.</li>
note, such as <code spellcheck="false">#root/Hb2E70L7HPuf/4sRFgMZhYFts/2IVuShedRJ3U/LJVMvKXOFv7n</code>.</li>
<li>The URL to manually create&nbsp;<a class="reference-link" href="#root/_help_QEAPj01N5f7w">Links</a>&nbsp;within
notes, or for note&nbsp;<a class="reference-link" href="#root/_help_wArbEsdSae6g">Navigation</a>.</li>
</ul>

View File

@ -13,7 +13,7 @@
<p>Note that the sidebar is not displayed if it would otherwise be empty,
for example if there are too few headings and there are no highlights.</p>
<h2>Toggling the right sidebar</h2>
<p>The sidebar can be hidden or shown by using the <code>toggleRightPane</code> keyboard
<p>The sidebar can be hidden or shown by using the <code spellcheck="false">toggleRightPane</code> keyboard
shortcut, which is not assigned by default.</p>
<h2>Relation with splits</h2>
<p>When using&nbsp;<a class="reference-link" href="#root/_help_luNhaphA37EO">Split View</a>,

View File

@ -15,7 +15,7 @@
the “Zen Mode” option:</p>
<p>Aside from the global menu, it's also possible to activate this mode by
using a keyboard shortcut (which is <kbd>F9</kbd> since TriliumNext 0.92.5
and <kbd>Alt</kbd>+<kbd>Z</kbd> for older versions). Look for <code>toggleZenMode</code> in
and <kbd>Alt</kbd>+<kbd>Z</kbd> for older versions). Look for <code spellcheck="false">toggleZenMode</code> in
the shortcut configuration.</p>
<p>Once Zen Mode is activated, all the UI elements of the application will
be hidden away, including the global menu. In that case, the Zen Mode can
@ -37,9 +37,10 @@
11 with background effects off.</p>
<h2>Split windows and tabs</h2>
<p>Tabs are completely hidden, however it's still possible to use keyboard
shortcuts such as <code>firstTab</code> (<kbd>Ctrl</kbd>+<kbd>1</kbd> by default), <code>secondTab</code> (<kbd>Ctrl</kbd>+<kbd>2</kbd> by
default). There are also some newer shortcuts such as <code>activateNextTab</code> (<kbd>Ctrl</kbd>+<kbd>Tab</kbd>)
or <code>activatePreviousTab</code> (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Tab</kbd>)
shortcuts such as <code spellcheck="false">firstTab</code> (<kbd>Ctrl</kbd>+<kbd>1</kbd> by
default), <code spellcheck="false">secondTab</code> (<kbd>Ctrl</kbd>+<kbd>2</kbd> by
default). There are also some newer shortcuts such as <code spellcheck="false">activateNextTab</code> (<kbd>Ctrl</kbd>+<kbd>Tab</kbd>)
or <code spellcheck="false">activatePreviousTab</code> (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Tab</kbd>)
that allow easy navigation, however make sure that they are configured
properly in the settings.</p>
<p>For the split view of notes, there are no keyboard shortcuts at the time

View File

@ -61,7 +61,7 @@
<br>
<img src="Calendar_image.png">
</li>
<li>Creating new notes from the calendar will respect the <code>~child:template</code> relation
<li>Creating new notes from the calendar will respect the <code spellcheck="false">~child:template</code> relation
if set on the Collection note.</li>
</ul>
<h2>Interacting with events</h2>
@ -180,62 +180,68 @@
</thead>
<tbody>
<tr>
<td><code>#startDate</code>
<td><code spellcheck="false">#startDate</code>
</td>
<td>The date the event starts, which will display it in the calendar. The
format is <code>YYYY-MM-DD</code> (year, month and day separated by a minus
sign).</td>
format is <code spellcheck="false">YYYY-MM-DD</code> (year, month and day
separated by a minus sign).</td>
</tr>
<tr>
<td><code>#endDate</code>
<td><code spellcheck="false">#endDate</code>
</td>
<td>Similar to <code>startDate</code>, mentions the end date if the event spans
across multiple days. The date is inclusive, so the end day is also considered.
The attribute can be missing for single-day events.</td>
<td>Similar to <code spellcheck="false">startDate</code>, mentions the end
date if the event spans across multiple days. The date is inclusive, so
the end day is also considered. The attribute can be missing for single-day
events.</td>
</tr>
<tr>
<td><code>#startTime</code>
<td><code spellcheck="false">#startTime</code>
</td>
<td>The time the event starts at. If this value is missing, then the event
is considered a full-day event. The format is <code>HH:MM</code> (hours in
24-hour format and minutes).</td>
is considered a full-day event. The format is <code spellcheck="false">HH:MM</code> (hours
in 24-hour format and minutes).</td>
</tr>
<tr>
<td><code>#endTime</code>
<td><code spellcheck="false">#endTime</code>
</td>
<td>Similar to <code>startTime</code>, it mentions the time at which the event
ends (in relation with <code>endDate</code> if present, or <code>startDate</code>).</td>
<td>Similar to <code spellcheck="false">startTime</code>, it mentions the time
at which the event ends (in relation with <code spellcheck="false">endDate</code> if
present, or <code spellcheck="false">startDate</code>).</td>
</tr>
<tr>
<td><code>#color</code>
<td><code spellcheck="false">#color</code>
</td>
<td>Displays the event with a specified color (named such as <code>red</code>, <code>gray</code> or
hex such as <code>#FF0000</code>). This will also change the color of the
note in other places such as the note tree.</td>
<td>Displays the event with a specified color (named such as <code spellcheck="false">red</code>,
<code
spellcheck="false">gray</code>or hex such as <code spellcheck="false">#FF0000</code>). This
will also change the color of the note in other places such as the note
tree.</td>
</tr>
<tr>
<td><code>#calendar:color</code>
<td><code spellcheck="false">#calendar:color</code>
</td>
<td><strong>❌️ Removed since v0.100.0. Use</strong> <code>**#color**</code> <strong>instead.</strong>
<td><strong>❌️ Removed since v0.100.0. Use</strong> <code spellcheck="false">**#color**</code> <strong>instead.</strong>
<br>
<br>Similar to <code>#color</code>, but applies the color only for the event
in the calendar and not for other places such as the note tree.</td>
<br>Similar to <code spellcheck="false">#color</code>, but applies the color
only for the event in the calendar and not for other places such as the
note tree.</td>
</tr>
<tr>
<td><code>#iconClass</code>
<td><code spellcheck="false">#iconClass</code>
</td>
<td>If present, the icon of the note will be displayed to the left of the
event title.</td>
</tr>
<tr>
<td><code>#calendar:title</code>
<td><code spellcheck="false">#calendar:title</code>
</td>
<td>Changes the title of an event to point to an attribute of the note other
than the title, can either a label or a relation (without the <code>#</code> or <code>~</code> symbol).
See <em>Use-cases</em> for more information.</td>
than the title, can either a label or a relation (without the <code spellcheck="false">#</code> or
<code
spellcheck="false">~</code>symbol). See <em>Use-cases</em> for more information.</td>
</tr>
<tr>
<td><code>#calendar:displayedAttributes</code>
<td><code spellcheck="false">#calendar:displayedAttributes</code>
</td>
<td>Allows displaying the value of one or more attributes in the calendar
like this:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
@ -243,38 +249,40 @@
<br>
<img src="9_Calendar_image.png">&nbsp;&nbsp;&nbsp;
<br>
<br><code>#weight="70" #Mood="Good" #calendar:displayedAttributes="weight,Mood"</code>&nbsp;&nbsp;&nbsp;
<br><code spellcheck="false">#weight="70" #Mood="Good" #calendar:displayedAttributes="weight,Mood"</code>&nbsp;&nbsp;&nbsp;
<br>
<br>It can also be used with relations, case in which it will display the
title of the target note:&nbsp;&nbsp;&nbsp;&nbsp;
<br>
<br><code>~assignee=@My assignee #calendar:displayedAttributes="assignee"</code>
<br><code spellcheck="false">~assignee=@My assignee #calendar:displayedAttributes="assignee"</code>
</td>
</tr>
<tr>
<td><code>#calendar:startDate</code>
<td><code spellcheck="false">#calendar:startDate</code>
</td>
<td>Allows using a different label to represent the start date, other than <code>startDate</code> (e.g. <code>expiryDate</code>).
The label name <strong>must not be</strong> prefixed with <code>#</code>.
If the label is not defined for a note, the default will be used instead.</td>
<td>Allows using a different label to represent the start date, other than
<code
spellcheck="false">startDate</code>(e.g. <code spellcheck="false">expiryDate</code>). The
label name <strong>must not be</strong> prefixed with <code spellcheck="false">#</code>.
If the label is not defined for a note, the default will be used instead.</td>
</tr>
<tr>
<td><code>#calendar:endDate</code>
<td><code spellcheck="false">#calendar:endDate</code>
</td>
<td>Similar to <code>#calendar:startDate</code>, allows changing the attribute
which is being used to read the end date.</td>
<td>Similar to <code spellcheck="false">#calendar:startDate</code>, allows
changing the attribute which is being used to read the end date.</td>
</tr>
<tr>
<td><code>#calendar:startTime</code>
<td><code spellcheck="false">#calendar:startTime</code>
</td>
<td>Similar to <code>#calendar:startDate</code>, allows changing the attribute
which is being used to read the start time.</td>
<td>Similar to <code spellcheck="false">#calendar:startDate</code>, allows
changing the attribute which is being used to read the start time.</td>
</tr>
<tr>
<td><code>#calendar:endTime</code>
<td><code spellcheck="false">#calendar:endTime</code>
</td>
<td>Similar to <code>#calendar:startDate</code>, allows changing the attribute
which is being used to read the end time.</td>
<td>Similar to <code spellcheck="false">#calendar:startDate</code>, allows
changing the attribute which is being used to read the end time.</td>
</tr>
</tbody>
</table>
@ -284,7 +292,8 @@
<img src="11_Calendar_image.png">
</p>
<p>The calendar displays all the child notes of the Collection that have
a <code>#startDate</code>. An <code>#endDate</code> can optionally be added.</p>
a <code spellcheck="false">#startDate</code>. An <code spellcheck="false">#endDate</code> can
optionally be added.</p>
<p>If editing the start date and end date from the note itself is desirable,
the following attributes can be added to the Collection note:</p><pre><code class="language-text-x-trilium-auto">#viewType=calendar #label:startDate(inheritable)="promoted,alias=Start Date,single,date"
#label:endDate(inheritable)="promoted,alias=End Date,single,date"
@ -301,19 +310,19 @@
<p>It is possible to integrate the calendar view into the Journal with day
notes. In order to do so change the note type of the Journal note (calendar
root) to Collection and then select the Calendar View.</p>
<p>Based on the <code>#calendarRoot</code> (or <code>#workspaceCalendarRoot</code>)
<p>Based on the <code spellcheck="false">#calendarRoot</code> (or <code spellcheck="false">#workspaceCalendarRoot</code>)
attribute, the calendar will know that it's in a calendar and apply the
following:</p>
<ul>
<li>The calendar events are now rendered based on their <code>dateNote</code> attribute
rather than <code>startDate</code>.</li>
<li>The calendar events are now rendered based on their <code spellcheck="false">dateNote</code> attribute
rather than <code spellcheck="false">startDate</code>.</li>
<li>Interactive editing such as dragging over an empty era or resizing an
event is no longer possible.</li>
<li>Clicking on the empty space on a date will automatically open that day's
note or create it if it does not exist.</li>
<li>Direct children of a day note will be displayed on the calendar despite
not having a <code>dateNote</code> attribute. Children of the child notes
will not be displayed.</li>
not having a <code spellcheck="false">dateNote</code> attribute. Children
of the child notes will not be displayed.</li>
</ul>
<img src="8_Calendar_image.png" width="1217"
height="724">
@ -322,11 +331,13 @@ height="724">
<p>By default, events are displayed on the calendar by their note title.
However, it is possible to configure a different attribute to be displayed
instead.</p>
<p>To do so, assign <code>#calendar:title</code> to the child note (not the
calendar/Collection note), with the value being <code>name</code> where <code>name</code> can
be any label (make not to add the <code>#</code> prefix). The attribute can
also come through inheritance such as a template attribute. If the note
does not have the requested label, the title of the note will be used instead.</p>
<p>To do so, assign <code spellcheck="false">#calendar:title</code> to the
child note (not the calendar/Collection note), with the value being
<code
spellcheck="false">name</code>where <code spellcheck="false">name</code> can be any label (make
not to add the <code spellcheck="false">#</code> prefix). The attribute can
also come through inheritance such as a template attribute. If the note
does not have the requested label, the title of the note will be used instead.</p>
<table>
<thead>
<tr>
@ -350,9 +361,9 @@ height="724">
</table>
<h3>Using a relation attribute as event title</h3>
<p>Similarly to using an attribute, use <code>#calendar:title</code> and set
it to <code>name</code> where <code>name</code> is the name of the relation
to use.</p>
<p>Similarly to using an attribute, use <code spellcheck="false">#calendar:title</code> and
set it to <code spellcheck="false">name</code> where <code spellcheck="false">name</code> is
the name of the relation to use.</p>
<p>Moreover, if there are more relations of the same name, they will be displayed
as multiple events coming from the same note.</p>
<table>
@ -373,9 +384,9 @@ height="724">
</tr>
</tbody>
</table>
<p>Note that it's even possible to have a <code>#calendar:title</code> on the
target note (e.g. “John Smith”) which will try to render an attribute of
it. Note that it's not possible to use a relation here as well for safety
<p>Note that it's even possible to have a <code spellcheck="false">#calendar:title</code> on
the target note (e.g. “John Smith”) which will try to render an attribute
of it. Note that it's not possible to use a relation here as well for safety
reasons (an accidental recursion &nbsp;of attributes could cause the application
to loop infinitely).</p>
<table>

View File

@ -136,7 +136,7 @@
the <em>Read-only</em> section for more information.</p>
</aside>
<h2>How the location of the markers is stored</h2>
<p>The location of a marker is stored in the <code>#geolocation</code> attribute
<p>The location of a marker is stored in the <code spellcheck="false">#geolocation</code> attribute
of the child notes:</p>
<img src="18_Geo Map_image.png"
width="1288" height="278">
@ -185,7 +185,7 @@ width="1288" height="278">
<li>Open the location using an external application (if the operating system
supports it).</li>
<li>Open the note in a new tab, split or window.</li>
<li>Remove the marker from the map, which will remove the <code>#geolocation</code> attribute
<li>Remove the marker from the map, which will remove the <code spellcheck="false">#geolocation</code> attribute
of the note. To add it back again, the coordinates have to be manually
added back in.</li>
</ol>
@ -197,10 +197,11 @@ width="1288" height="278">
alt="image" width="523" height="295">
</figure>
<p>The markers will have the same icon as the note.</p>
<p>It's possible to add a custom color to a marker by assigning them a <code>#color</code> attribute
such as <code>#color=green</code>.</p>
<p>It's possible to add a custom color to a marker by assigning them a
<code
spellcheck="false">#color</code>attribute such as <code spellcheck="false">#color=green</code>.</p>
<h2>Adding the coordinates manually</h2>
<p>In a nutshell, create a child note and set the <code>#geolocation</code> attribute
<p>In a nutshell, create a child note and set the <code spellcheck="false">#geolocation</code> attribute
to the coordinates.</p>
<p>The value of the attribute is made up of the latitude and longitude separated
by a comma.</p>
@ -228,8 +229,10 @@ width="1288" height="278">
<br>Simply click on the first item displaying the coordinates and they will
be copied to clipboard.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<br>
<br>Then paste the value inside the text box into the <code>#geolocation</code> attribute
of a child note of the map (don't forget to surround the value with a <code>"</code> character).</td>
<br>Then paste the value inside the text box into the <code spellcheck="false">#geolocation</code> attribute
of a child note of the map (don't forget to surround the value with a
<code
spellcheck="false">"</code>character).</td>
</tr>
<tr>
<td>2</td>
@ -249,8 +252,8 @@ width="1288" height="278">
width="1074" height="276">
</figure>
</td>
<td>And then go to Owned Attributes and type <code>#geolocation="</code>, then
paste from the clipboard as-is and then add the ending <code>"</code> character.
<td>And then go to Owned Attributes and type <code spellcheck="false">#geolocation="</code>,
then paste from the clipboard as-is and then add the ending <code spellcheck="false">"</code> character.
Press Enter to confirm and the map should now be updated to contain the
new note.</td>
</tr>
@ -294,7 +297,7 @@ width="1288" height="278">
<img class="image_resized" style="aspect-ratio:640/276;width:100%;" src="5_Geo Map_image.png"
width="640" height="276">
</td>
<td>Simply paste the value inside the text box into the <code>#geolocation</code> attribute
<td>Simply paste the value inside the text box into the <code spellcheck="false">#geolocation</code> attribute
of a child note of the map and then it should be displayed on the map.</td>
</tr>
</tbody>
@ -331,7 +334,7 @@ width="1288" height="278">
</figure>
</td>
<td>In order for the file to be recognized as a GPS track, it needs to show
up as <code>application/gpx+xml</code> in the <em>File type</em> field.</td>
up as <code spellcheck="false">application/gpx+xml</code> in the <em>File type</em> field.</td>
</tr>
<tr>
<td>3</td>
@ -350,8 +353,8 @@ width="1288" height="278">
<aside class="admonition note">
<p>The starting point of the track will be displayed as a marker, with the
name of the note underneath. The start marker will also respect the icon
and the <code>color</code> of the note. The end marker is displayed with
a distinct icon.</p>
and the <code spellcheck="false">color</code> of the note. The end marker
is displayed with a distinct icon.</p>
<p>If the GPX contains waypoints, they will also be displayed. If they have
a name, it is displayed when hovering over it with the mouse.</p>
</aside>
@ -370,7 +373,7 @@ width="1288" height="278">
<h3>Map Style</h3>
<p>The styling of the map can be adjusted in the <em>Collection Properties</em> tab
in the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>&nbsp;or
manually via the <code>#map:style</code> attribute.</p>
manually via the <code spellcheck="false">#map:style</code> attribute.</p>
<p>The geo map comes with two different types of styles:</p>
<ul>
<li>Raster styles
@ -398,8 +401,8 @@ width="1288" height="278">
</aside>
<h3>Scale</h3>
<p>Activating this option via the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>&nbsp;or
manually via <code>#map:scale</code> will display an indicator in the bottom-left
of the scale of the map.</p>
manually via <code spellcheck="false">#map:scale</code> will display an indicator
in the bottom-left of the scale of the map.</p>
<h2>Troubleshooting</h2>
<figure class="image image-style-align-right image_resized" style="width:34.06%;">
<img style="aspect-ratio:678/499;" src="13_Geo Map_image.png"

View File

@ -7,8 +7,8 @@
adjusted.</p>
<h2>How it works</h2>
<p>When first creating a collection of <em>Board</em> type, a few subnotes
will be created, each having a <code>#status</code> label set. The board
then groups each note by the value of the status attribute.</p>
will be created, each having a <code spellcheck="false">#status</code> label
set. The board then groups each note by the value of the status attribute.</p>
<p>Notes are displayed recursively, so even the child notes of the child
notes will be displayed. However, unlike the&nbsp;<a class="reference-link"
href="#root/_help_2FvYrpmOXm29">Table</a>, the notes are not displayed in a hierarchy.</p>
@ -40,7 +40,7 @@
<li>Enter the name of the note and press <kbd>Enter</kbd> or click away. To
dismiss the creation of a new note, simply press <kbd>Escape</kbd> or leave
the name empty.</li>
<li>Once created, the new note will have an attribute (<code>status</code> label
<li>Once created, the new note will have an attribute (<code spellcheck="false">status</code> label
by default) set to the name of the column.</li>
</ul>
</li>
@ -126,15 +126,16 @@
<li>Relation attributes are also supported as well, showing a link with the
target note title and icon.</li>
<li>Currently, it's not possible to adjust which promoted attributes are displayed,
since all promoted attributes will be displayed (except the <code>board:groupBy</code> one).
since all promoted attributes will be displayed (except the <code spellcheck="false">board:groupBy</code> one).
There are plans to improve upon this being able to hide promoted attributes
individually.</li>
</ul>
<h3>Grouping by another label</h3>
<p>By default, the label used to group the notes is <code>#status</code>.
It is possible to use a different label if needed by defining a label named <code>#board:groupBy</code> with
the value being the attribute to use (with or without <code>#</code> attribute
prefix).</p>
<p>By default, the label used to group the notes is <code spellcheck="false">#status</code>.
It is possible to use a different label if needed by defining a label named
<code
spellcheck="false">#board:groupBy</code>with the value being the attribute to use (with or
without <code spellcheck="false">#</code> attribute prefix).</p>
<h3>Grouping by relations</h3>
<figure class="image image-style-align-right">
<img style="aspect-ratio:535/245;" src="1_Kanban Board_image.png"
@ -164,11 +165,14 @@
<p>First, create a Kanban board from scratch and not a template:</p>
</li>
<li>
<p>Assign <code>#viewType=board #hidePromotedAttributes</code> to emulate the
default template.</p>
<p>Assign <code spellcheck="false">#viewType=board #hidePromotedAttributes</code> to
emulate the default template.</p>
</li>
<li>
<p>Set <code>#board:groupBy</code> to the name of a relation to group by, <strong>including the</strong> <code>~</code> <strong>prefix</strong> (e.g. <code>~status</code>).</p>
<p>Set <code spellcheck="false">#board:groupBy</code> to the name of a relation
to group by, <strong>including the</strong> <code spellcheck="false">~</code> <strong>prefix</strong> (e.g.
<code
spellcheck="false">~status</code>).</p>
</li>
<li>
<p>Optionally, use&nbsp;<a class="reference-link" href="#root/_help_OFXdgB2nNk1F">Promoted Attributes</a>&nbsp;for

Some files were not shown because too many files have changed in this diff Show More