Merge branch 'main' into renovate/officeparser-6.x
18
.github/actions/build-electron/action.yml
vendored
@@ -66,12 +66,20 @@ runs:
|
||||
if: ${{ inputs.os == 'linux' }}
|
||||
shell: ${{ inputs.shell }}
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install rpm flatpak-builder elfutils
|
||||
sudo apt-get update && sudo apt-get install rpm flatpak-builder elfutils libfuse2
|
||||
flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
FLATPAK_ARCH=$(if [[ ${{ inputs.arch }} = 'arm64' ]]; then echo 'aarch64'; else echo 'x86_64'; fi)
|
||||
FLATPAK_VERSION='24.08'
|
||||
flatpak install --user --no-deps --arch $FLATPAK_ARCH --assumeyes runtime/org.freedesktop.Platform/$FLATPAK_ARCH/$FLATPAK_VERSION runtime/org.freedesktop.Sdk/$FLATPAK_ARCH/$FLATPAK_VERSION org.electronjs.Electron2.BaseApp/$FLATPAK_ARCH/$FLATPAK_VERSION
|
||||
|
||||
- name: Install appimagetool
|
||||
if: ${{ inputs.os == 'linux' }}
|
||||
shell: ${{ inputs.shell }}
|
||||
run: |
|
||||
APPIMAGETOOL_ARCH=$(if [[ ${{ inputs.arch }} = 'arm64' ]]; then echo 'aarch64'; else echo 'x86_64'; fi)
|
||||
wget -q "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${APPIMAGETOOL_ARCH}.AppImage" -O /usr/local/bin/appimagetool
|
||||
chmod +x /usr/local/bin/appimagetool
|
||||
|
||||
- name: Update build info
|
||||
shell: ${{ inputs.shell }}
|
||||
run: pnpm run chore:update-build-info
|
||||
@@ -90,6 +98,14 @@ runs:
|
||||
TARGET_ARCH: ${{ inputs.arch }}
|
||||
run: pnpm run --filter desktop electron-forge:make --arch=${{ inputs.arch }} --platform=${{ inputs.forge_platform }}
|
||||
|
||||
- name: Build AppImage
|
||||
if: ${{ inputs.os == 'linux' }}
|
||||
shell: ${{ inputs.shell }}
|
||||
env:
|
||||
TRILIUM_ARTIFACT_NAME_HINT: TriliumNotes-${{ github.ref_name }}-${{ inputs.os }}-${{ inputs.arch }}
|
||||
APPIMAGE_EXTRACT_AND_RUN: "1"
|
||||
run: bash apps/desktop/scripts/build-appimage.sh ${{ inputs.arch }}
|
||||
|
||||
# Add DMG signing step
|
||||
- name: Sign DMG
|
||||
if: inputs.os == 'macos'
|
||||
|
||||
44
.github/workflows/claude-code-review.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Claude Code Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, ready_for_review, reopened]
|
||||
# Optional: Only run on specific file changes
|
||||
# paths:
|
||||
# - "src/**/*.ts"
|
||||
# - "src/**/*.tsx"
|
||||
# - "src/**/*.js"
|
||||
# - "src/**/*.jsx"
|
||||
|
||||
jobs:
|
||||
claude-review:
|
||||
# Optional: Filter by PR author
|
||||
# if: |
|
||||
# github.event.pull_request.user.login == 'external-contributor' ||
|
||||
# github.event.pull_request.user.login == 'new-developer' ||
|
||||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code Review
|
||||
id: claude-review
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
|
||||
plugins: 'code-review@claude-code-plugins'
|
||||
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
|
||||
50
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Claude Code
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
claude:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
actions: read # Required for Claude to read CI results on PRs
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
|
||||
# This is an optional setting that allows Claude to read CI results on PRs
|
||||
additional_permissions: |
|
||||
actions: read
|
||||
|
||||
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
||||
# prompt: 'Update the pull request description to include a summary of changes.'
|
||||
|
||||
# Optional: Add claude_args to customize behavior and configuration
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
# claude_args: '--allowed-tools Bash(gh pr *)'
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"license": "AGPL-3.0-only",
|
||||
"packageManager": "pnpm@10.33.0",
|
||||
"devDependencies": {
|
||||
"@redocly/cli": "2.26.0",
|
||||
"@redocly/cli": "2.28.0",
|
||||
"archiver": "7.0.1",
|
||||
"fs-extra": "11.3.4",
|
||||
"js-yaml": "4.1.1",
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
"mind-elixir": "5.10.0",
|
||||
"panzoom": "9.4.4",
|
||||
"preact": "10.29.1",
|
||||
"react-i18next": "17.0.2",
|
||||
"react-i18next": "17.0.3",
|
||||
"react-window": "2.2.7",
|
||||
"reveal.js": "6.0.1",
|
||||
"rrule": "2.8.1",
|
||||
|
||||
@@ -66,7 +66,15 @@ class FAttribute {
|
||||
}
|
||||
|
||||
get isAutoLink() {
|
||||
return this.type === "relation" && ["internalLink", "imageLink", "relationMapLink", "includeNoteLink"].includes(this.name);
|
||||
if (this.type === "relation") {
|
||||
return ["internalLink", "imageLink", "relationMapLink", "includeNoteLink"].includes(this.name);
|
||||
}
|
||||
|
||||
if (this.type === "label") {
|
||||
return this.name === "internalBookmark";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
get toString() {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
:root {
|
||||
--print-font-size: 11pt;
|
||||
--ck-content-color-image-caption-background: transparent !important;
|
||||
}
|
||||
|
||||
@page {
|
||||
@@ -11,9 +10,12 @@
|
||||
|
||||
html,
|
||||
body {
|
||||
--print-font-family: var(--detail-font-family, sans-serif);
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: black;
|
||||
font-family: var(--print-font-family);
|
||||
}
|
||||
|
||||
.note-list-widget.full-height,
|
||||
@@ -26,6 +28,12 @@ body {
|
||||
}
|
||||
|
||||
body[data-note-type="text"] .ck-content {
|
||||
--ck-content-font-family: var(--print-font-family);
|
||||
--ck-content-font-size: var(--print-font-size);
|
||||
--ck-content-font-color: black;
|
||||
--ck-content-line-height: 1.5;
|
||||
--ck-content-color-image-caption-background: transparent;
|
||||
|
||||
font-size: var(--print-font-size);
|
||||
text-align: justify;
|
||||
}
|
||||
@@ -154,4 +162,4 @@ span[style] {
|
||||
.page-break::after {
|
||||
display: none !important;
|
||||
}
|
||||
/* #endregion */
|
||||
/* #endregion */
|
||||
|
||||
@@ -31,6 +31,13 @@ async function main() {
|
||||
if (!noteId) return;
|
||||
|
||||
await import("./print.css");
|
||||
|
||||
// Load the user's font preferences so that --detail-font-family is available.
|
||||
const fontLink = document.createElement("link");
|
||||
fontLink.rel = "stylesheet";
|
||||
fontLink.href = "api/fonts";
|
||||
document.head.appendChild(fontLink);
|
||||
|
||||
const note = await froca.getNote(noteId);
|
||||
|
||||
const bodyWrapper = document.createElement("div");
|
||||
@@ -105,6 +112,9 @@ function SingleNoteRenderer({ note, onReady }: RendererProps) {
|
||||
|
||||
// Check custom CSS.
|
||||
await loadCustomCss(note);
|
||||
|
||||
// Wait for all fonts (including those from custom CSS) to finish loading.
|
||||
await document.fonts.ready;
|
||||
}
|
||||
|
||||
load().then(() => requestAnimationFrame(() => onReady({
|
||||
@@ -130,6 +140,7 @@ function CollectionRenderer({ note, onReady, onProgressChanged }: RendererProps)
|
||||
media="print"
|
||||
onReady={async (data: PrintReport) => {
|
||||
await loadCustomCss(note);
|
||||
await document.fonts.ready;
|
||||
onReady(data);
|
||||
}}
|
||||
onProgressChanged={onProgressChanged}
|
||||
|
||||
@@ -7,6 +7,10 @@ async function renderAttribute(attribute: FAttribute, renderIsInheritable: boole
|
||||
const isInheritable = renderIsInheritable && attribute.isInheritable ? `(inheritable)` : "";
|
||||
const $attr = $("<span>");
|
||||
|
||||
if (attribute.isAutoLink) {
|
||||
return $attr;
|
||||
}
|
||||
|
||||
if (attribute.type === "label") {
|
||||
$attr.append(document.createTextNode(`#${attribute.name}${isInheritable}`));
|
||||
|
||||
@@ -15,9 +19,6 @@ async function renderAttribute(attribute: FAttribute, renderIsInheritable: boole
|
||||
$attr.append(document.createTextNode(formatValue(attribute.value)));
|
||||
}
|
||||
} else if (attribute.type === "relation") {
|
||||
if (attribute.isAutoLink) {
|
||||
return $attr;
|
||||
}
|
||||
|
||||
// when the relation has just been created, then it might not have a value
|
||||
if (attribute.value) {
|
||||
|
||||
@@ -60,6 +60,8 @@ export interface ViewScope {
|
||||
*/
|
||||
tocPreviousVisible?: boolean;
|
||||
tocCollapsedHeadings?: Set<string>;
|
||||
/** When set, scrolls to a bookmark anchor within the note after navigation. */
|
||||
bookmark?: string;
|
||||
}
|
||||
|
||||
interface CreateLinkOptions {
|
||||
@@ -244,7 +246,7 @@ export function parseNavigationStateFromUrl(url: string | undefined) {
|
||||
hoistedNoteId = value;
|
||||
} else if (name === "searchString") {
|
||||
searchString = value; // supports triggering search from URL, e.g. #?searchString=blabla
|
||||
} else if (["viewMode", "attachmentId"].includes(name)) {
|
||||
} else if (["viewMode", "attachmentId", "bookmark"].includes(name)) {
|
||||
(viewScope as any)[name] = value;
|
||||
} else if (name === "popup") {
|
||||
openInPopup = true;
|
||||
@@ -432,6 +434,13 @@ async function loadReferenceLinkTitle($el: JQuery<HTMLElement>, href: string | n
|
||||
const title = await getReferenceLinkTitle(href);
|
||||
$el.text(title);
|
||||
|
||||
if (viewScope?.bookmark) {
|
||||
$el.append($("<small>").append(
|
||||
$("<span>").addClass("bx bx-bookmark"),
|
||||
document.createTextNode(viewScope.bookmark)
|
||||
));
|
||||
}
|
||||
|
||||
if (note) {
|
||||
const icon = await getLinkIcon(noteId, viewScope.viewMode);
|
||||
|
||||
@@ -457,8 +466,8 @@ async function getReferenceLinkTitle(href: string) {
|
||||
|
||||
return attachment ? attachment.title : "[missing attachment]";
|
||||
}
|
||||
return note.title;
|
||||
|
||||
return note.title;
|
||||
}
|
||||
|
||||
function getReferenceLinkTitleSync(href: string) {
|
||||
@@ -481,8 +490,12 @@ function getReferenceLinkTitleSync(href: string) {
|
||||
|
||||
return attachment ? attachment.title : "[missing attachment]";
|
||||
}
|
||||
return note.title;
|
||||
|
||||
if (viewScope?.bookmark) {
|
||||
return `${note.title} - ${viewScope.bookmark}`;
|
||||
}
|
||||
|
||||
return note.title;
|
||||
}
|
||||
|
||||
if (glob.device !== "print") {
|
||||
|
||||
@@ -714,6 +714,15 @@ html .note-detail-editable-text :not(figure, .include-note, hr):first-child {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ck-content a.reference-link small {
|
||||
margin-left: 0.25em;
|
||||
opacity: 0.5;
|
||||
|
||||
>span {
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read-only text content
|
||||
*/
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
"link_title_mirrors": "link title mirrors the note's current title",
|
||||
"link_title_arbitrary": "link title can be changed arbitrarily",
|
||||
"link_title": "Link title",
|
||||
"anchor": "Anchor (optional)",
|
||||
"anchor_none": "None (link to note)",
|
||||
"button_add_link": "Add link"
|
||||
},
|
||||
"branch_prefix": {
|
||||
@@ -860,6 +862,9 @@
|
||||
"no_inherited_attributes": "No inherited attributes.",
|
||||
"none": "none"
|
||||
},
|
||||
"auto_link_attribute_list": {
|
||||
"title": "System Attributes"
|
||||
},
|
||||
"note_info_widget": {
|
||||
"note_id": "Note ID",
|
||||
"created": "Created",
|
||||
|
||||
@@ -615,7 +615,8 @@
|
||||
"collections": "コレクション",
|
||||
"ai-chat": "AI チャット",
|
||||
"spreadsheet": "スプレッドシート",
|
||||
"llm-chat": "AI チャット"
|
||||
"llm-chat": "AI チャット",
|
||||
"markdown": "Markdown"
|
||||
},
|
||||
"edited_notes": {
|
||||
"no_edited_notes_found": "この日の編集されたノートはまだありません...",
|
||||
@@ -2479,5 +2480,10 @@
|
||||
},
|
||||
"launcher_button_context_menu": {
|
||||
"remove_from_launch_bar": "ランチャーバーから削除"
|
||||
},
|
||||
"display_mode": {
|
||||
"source": "ソースビュー",
|
||||
"split": "分割ビュー",
|
||||
"preview": "プレビュー"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,13 +89,21 @@
|
||||
},
|
||||
"delete_notes": {
|
||||
"delete_all_clones_description": "同時刪除所有克隆(可以在最近修改中撤消)",
|
||||
"erase_notes_description": "通常(軟)刪除僅標記筆記為已刪除,可以在一段時間內透過最近修改對話方塊撤消。勾選此選項將立即擦除筆記,無法撤銷。",
|
||||
"erase_notes_description": "立即刪除筆記,而非執行軟刪除。此操作無法撤銷,且會強制重新載入應用程式。",
|
||||
"erase_notes_warning": "永久擦除筆記(無法撤銷),包括所有克隆。這將強制應用程式重新載入。",
|
||||
"notes_to_be_deleted": "將刪除以下筆記 ({{notesCount}})",
|
||||
"notes_to_be_deleted": "待刪除筆記 ({{notesCount}})",
|
||||
"no_note_to_delete": "沒有筆記將被刪除(僅克隆)。",
|
||||
"broken_relations_to_be_deleted": "將刪除以下關聯並斷開連接 ({{ relationCount}})",
|
||||
"broken_relations_to_be_deleted": "斷開的關聯 ({{ relationCount}})",
|
||||
"cancel": "取消",
|
||||
"close": "關閉"
|
||||
"close": "關閉",
|
||||
"title": "刪除筆記",
|
||||
"clones_label": "克隆",
|
||||
"delete_clones_description_one": "同時刪除 {{count}} 個其他克隆。此操作可在最近修改中撤銷。",
|
||||
"erase_notes_label": "永久擦除",
|
||||
"table_note_with_relation": "有關聯的筆記",
|
||||
"table_relation": "關聯",
|
||||
"table_points_to": "指向 (已刪除)",
|
||||
"delete": "刪除"
|
||||
},
|
||||
"export": {
|
||||
"export_note_title": "匯出筆記",
|
||||
@@ -206,7 +214,8 @@
|
||||
"box_size_small": "小型(顯示大約 10 行)",
|
||||
"box_size_medium": "中型 (顯示大約30行)",
|
||||
"box_size_full": "完整顯示(完整文字框)",
|
||||
"button_include": "內嵌筆記"
|
||||
"button_include": "內嵌筆記",
|
||||
"box_size_expandable": "可展開(預設為摺疊狀態)"
|
||||
},
|
||||
"info": {
|
||||
"modalTitle": "資訊消息",
|
||||
@@ -1430,7 +1439,7 @@
|
||||
"expand-subtree": "展開子階層",
|
||||
"collapse-subtree": "收摺子階層",
|
||||
"sort-by": "排序方式…",
|
||||
"recent-changes-in-subtree": "子階層中的最近更改",
|
||||
"recent-changes-in-subtree": "子階層中的最近修改",
|
||||
"convert-to-attachment": "轉換為附件",
|
||||
"copy-note-path-to-clipboard": "複製筆記路徑至剪貼簿",
|
||||
"protect-subtree": "保護子階層",
|
||||
@@ -2334,5 +2343,14 @@
|
||||
"history": "對話歷史",
|
||||
"recent_chats": "最近的對話",
|
||||
"no_chats": "無先前的對話記錄"
|
||||
},
|
||||
"revisions": {
|
||||
"note_revisions": "筆記歷史版本",
|
||||
"delete_all_revisions": "刪除此筆記的所有歷史版本",
|
||||
"delete_all_button": "刪除所有歷史版本",
|
||||
"help_title": "關於筆記歷史版本的說明",
|
||||
"confirm_delete_all": "您要刪除此筆記的所有歷史版本嗎?",
|
||||
"no_revisions": "尚無此筆記的歷史版本...",
|
||||
"restore_button": "還原"
|
||||
}
|
||||
}
|
||||
|
||||
2
apps/client/src/types-fancytree.d.ts
vendored
@@ -269,6 +269,8 @@ declare namespace Fancytree {
|
||||
lazy: boolean;
|
||||
/** Alternative description used as hover banner */
|
||||
tooltip: string;
|
||||
/** `<li>` element wrapping this node. `null` if the node has not been rendered yet. */
|
||||
li: HTMLLIElement | null;
|
||||
/** Outer element of single nodes */
|
||||
span: HTMLElement;
|
||||
/** Outer element of single nodes for table extension */
|
||||
|
||||
@@ -5,6 +5,7 @@ import FormRadioGroup from "../react/FormRadioGroup";
|
||||
import NoteAutocomplete from "../react/NoteAutocomplete";
|
||||
import { useRef, useState, useEffect } from "preact/hooks";
|
||||
import tree from "../../services/tree";
|
||||
import froca from "../../services/froca";
|
||||
import note_autocomplete, { Suggestion } from "../../services/note_autocomplete";
|
||||
import { logError } from "../../services/ws";
|
||||
import FormGroup from "../react/FormGroup.js";
|
||||
@@ -24,6 +25,9 @@ export default function AddLinkDialog() {
|
||||
const [ linkTitle, setLinkTitle ] = useState("");
|
||||
const [ linkType, setLinkType ] = useState<LinkType>();
|
||||
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
||||
const [ bookmarks, setBookmarks ] = useState<string[]>([]);
|
||||
const [ selectedBookmark, setSelectedBookmark ] = useState("");
|
||||
const [ noteTitle, setNoteTitle ] = useState("");
|
||||
const [ shown, setShown ] = useState(false);
|
||||
const hasSubmittedRef = useRef(false);
|
||||
|
||||
@@ -41,26 +45,34 @@ export default function AddLinkDialog() {
|
||||
}, [ opts ]);
|
||||
|
||||
async function setDefaultLinkTitle(noteId: string) {
|
||||
const noteTitle = await tree.getNoteTitle(noteId);
|
||||
setLinkTitle(noteTitle);
|
||||
}
|
||||
|
||||
function resetExternalLink() {
|
||||
if (linkType === "external-link") {
|
||||
setLinkType("reference-link");
|
||||
}
|
||||
const title = await tree.getNoteTitle(noteId);
|
||||
setNoteTitle(title);
|
||||
setLinkTitle(title);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const resetExternalLink = () =>
|
||||
setLinkType((prev) => prev === "external-link" ? "reference-link" : prev);
|
||||
|
||||
if (!suggestion) {
|
||||
resetExternalLink();
|
||||
setBookmarks([]);
|
||||
setSelectedBookmark("");
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
|
||||
if (suggestion.notePath) {
|
||||
const noteId = tree.getNoteIdFromUrl(suggestion.notePath);
|
||||
if (noteId) {
|
||||
setDefaultLinkTitle(noteId);
|
||||
froca.getNote(noteId).then((note) => {
|
||||
if (cancelled) return;
|
||||
const bkms = note?.getLabels("internalBookmark").map((l) => l.value) ?? [];
|
||||
setBookmarks(bkms);
|
||||
setSelectedBookmark("");
|
||||
});
|
||||
}
|
||||
resetExternalLink();
|
||||
}
|
||||
@@ -69,8 +81,18 @@ export default function AddLinkDialog() {
|
||||
setLinkTitle(suggestion.externalLink);
|
||||
setLinkType("external-link");
|
||||
}
|
||||
|
||||
return () => { cancelled = true; };
|
||||
}, [suggestion]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedBookmark) {
|
||||
setLinkTitle(`${noteTitle} - ${selectedBookmark}`);
|
||||
} else {
|
||||
setLinkTitle(noteTitle);
|
||||
}
|
||||
}, [selectedBookmark, noteTitle]);
|
||||
|
||||
function onShown() {
|
||||
const $autocompleteEl = refToJQuerySelector(autocompleteRef);
|
||||
if (!opts?.text) {
|
||||
@@ -114,8 +136,11 @@ export default function AddLinkDialog() {
|
||||
hasSubmittedRef.current = false;
|
||||
|
||||
if (suggestion.notePath) {
|
||||
// Handle note link
|
||||
opts.addLink(suggestion.notePath, linkType === "reference-link" ? null : linkTitle);
|
||||
// Handle note link, optionally with a bookmark anchor
|
||||
const path = selectedBookmark
|
||||
? `${suggestion.notePath}?bookmark=${encodeURIComponent(selectedBookmark)}`
|
||||
: suggestion.notePath;
|
||||
opts.addLink(path, linkType === "reference-link" ? null : linkTitle);
|
||||
} else if (suggestion.externalLink) {
|
||||
// Handle external link
|
||||
opts.addLink(suggestion.externalLink, linkTitle, true);
|
||||
@@ -123,6 +148,9 @@ export default function AddLinkDialog() {
|
||||
}
|
||||
|
||||
setSuggestion(null);
|
||||
setBookmarks([]);
|
||||
setSelectedBookmark("");
|
||||
setNoteTitle("");
|
||||
setShown(false);
|
||||
}}
|
||||
show={shown}
|
||||
@@ -138,6 +166,21 @@ export default function AddLinkDialog() {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{bookmarks.length > 0 && (
|
||||
<FormGroup label={t("add_link.anchor")} name="anchor">
|
||||
<select
|
||||
className="form-select"
|
||||
value={selectedBookmark}
|
||||
onChange={(e) => setSelectedBookmark((e.target as HTMLSelectElement).value)}
|
||||
>
|
||||
<option value="">{t("add_link.anchor_none")}</option>
|
||||
{bookmarks.map((bk) => (
|
||||
<option key={bk} value={bk}>{bk}</option>
|
||||
))}
|
||||
</select>
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
{!opts?.hasSelection && (
|
||||
<div className="add-link-title-settings">
|
||||
{(linkType !== "external-link") && (
|
||||
|
||||
@@ -3,13 +3,14 @@ import { t } from "../../services/i18n";
|
||||
import FormGroup from "../react/FormGroup";
|
||||
import NoteAutocomplete from "../react/NoteAutocomplete";
|
||||
import FormList, { FormListHeader, FormListItem } from "../react/FormList";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useEffect, useRef, useState } from "preact/hooks";
|
||||
import note_types from "../../services/note_types";
|
||||
import { MenuCommandItem, MenuItem } from "../../menus/context_menu";
|
||||
import { TreeCommandNames } from "../../menus/tree_context_menu";
|
||||
import { Suggestion } from "../../services/note_autocomplete";
|
||||
import SimpleBadge from "../react/Badge";
|
||||
import { useTriliumEvent } from "../react/hooks";
|
||||
import { refToJQuerySelector } from "../react/react_utils";
|
||||
|
||||
export interface ChooseNoteTypeResponse {
|
||||
success: boolean;
|
||||
@@ -30,6 +31,8 @@ export default function NoteTypeChooserDialogComponent() {
|
||||
const [ shown, setShown ] = useState(false);
|
||||
const [ parentNote, setParentNote ] = useState<Suggestion | null>();
|
||||
const [ noteTypes, setNoteTypes ] = useState<MenuItem<TreeCommandNames>[]>([]);
|
||||
const modalRef = useRef<HTMLDivElement>(null);
|
||||
const autocompleteRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useTriliumEvent("chooseNoteType", ({ callback }) => {
|
||||
setCallback(() => callback);
|
||||
@@ -68,11 +71,17 @@ export default function NoteTypeChooserDialogComponent() {
|
||||
|
||||
return (
|
||||
<Modal
|
||||
modalRef={modalRef}
|
||||
title={t("note_type_chooser.modal_title")}
|
||||
className="note-type-chooser-dialog"
|
||||
size="md"
|
||||
zIndex={1100} // note type chooser needs to be higher than other dialogs from which it is triggered, e.g. "add link"
|
||||
scrollable
|
||||
onShown={() => {
|
||||
refToJQuerySelector(autocompleteRef)
|
||||
.trigger("focus")
|
||||
.trigger("select");
|
||||
}}
|
||||
onHidden={() => {
|
||||
callback?.({ success: false });
|
||||
setShown(false);
|
||||
@@ -82,6 +91,7 @@ export default function NoteTypeChooserDialogComponent() {
|
||||
>
|
||||
<FormGroup name="parent-note" label={t("note_type_chooser.change_path_prompt")}>
|
||||
<NoteAutocomplete
|
||||
inputRef={autocompleteRef}
|
||||
onChange={setParentNote}
|
||||
placeholder={t("note_type_chooser.search_placeholder")}
|
||||
opts={{
|
||||
|
||||
@@ -87,7 +87,8 @@
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.inherited-attributes-widget {
|
||||
.inherited-attributes-widget,
|
||||
.auto-link-attributes-widget {
|
||||
display: inline;
|
||||
|
||||
> div {
|
||||
|
||||
@@ -26,6 +26,7 @@ import LinkButton from "../react/LinkButton";
|
||||
import { ParentComponent } from "../react/react_utils";
|
||||
import { ContentLanguagesModal, NoteTypeCodeNoteList, NoteTypeOptionsModal, useLanguageSwitcher, useMimeTypes } from "../ribbon/BasicPropertiesTab";
|
||||
import AttributeEditor, { AttributeEditorImperativeHandlers } from "../ribbon/components/AttributeEditor";
|
||||
import AutoLinkAttributesTab from "../ribbon/AutoLinkAttributesTab";
|
||||
import InheritedAttributesTab from "../ribbon/InheritedAttributesTab";
|
||||
import { NoteSizeWidget, useNoteMetadata } from "../ribbon/NoteInfoTab";
|
||||
import { NotePathsWidget, useSortedNotePaths } from "../ribbon/NotePathsTab";
|
||||
@@ -401,6 +402,11 @@ function AttributesPane({ note, noteContext, attributesShown, setAttributesShown
|
||||
<span class="attributes-panel-label">{t("inherited_attribute_list.title")}</span>
|
||||
<InheritedAttributesTab {...context} emptyListString="inherited_attribute_list.none" />
|
||||
|
||||
{glob.isDev && <div>
|
||||
<span class="attributes-panel-label">{t("auto_link_attribute_list.title")}</span>
|
||||
<AutoLinkAttributesTab {...context} />
|
||||
</div>}
|
||||
|
||||
<AttributeEditor
|
||||
{...context}
|
||||
api={api}
|
||||
|
||||
@@ -1534,8 +1534,11 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
const hoistedNotePath = await treeService.resolveNotePath(this.noteContext.hoistedNoteId);
|
||||
|
||||
if (!forceUpdate && this.lastFilteredHoistedNotePath === hoistedNotePath) {
|
||||
// no need to re-filter if the hoisting did not change
|
||||
// (helps with flickering on simple note change with large subtrees)
|
||||
// Hoisting did not change, so skip the expensive re-filter (avoids flickering on
|
||||
// simple note changes with large subtrees). The hidden-node class must still be
|
||||
// reapplied — the <li> may have been recreated by a lazy reload (e.g. via
|
||||
// `getNodeFromPath` → `parentNode.load(true)` after an import into root).
|
||||
this.toggleHiddenNode(this.noteContext.hoistedNoteId !== "root");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1568,8 +1571,9 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
|
||||
toggleHiddenNode(show: boolean) {
|
||||
const hiddenNode = this.getNodesByNoteId("_hidden")[0];
|
||||
// TODO: Check how .li exists here.
|
||||
$((hiddenNode as any).li).toggleClass("hidden-node-is-hidden", !show);
|
||||
if (hiddenNode?.li) {
|
||||
$(hiddenNode.li).toggleClass("hidden-node-is-hidden", !show);
|
||||
}
|
||||
}
|
||||
|
||||
async frocaReloadedEvent() {
|
||||
|
||||
69
apps/client/src/widgets/ribbon/AutoLinkAttributesTab.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
|
||||
import FAttribute from "../../entities/fattribute";
|
||||
import attributes from "../../services/attributes";
|
||||
import froca from "../../services/froca";
|
||||
import { useTriliumEvent } from "../react/hooks";
|
||||
import { joinElements } from "../react/react_utils";
|
||||
import { TabContext } from "./ribbon-interface";
|
||||
|
||||
type AutoLinkAttributesTabArgs = Pick<TabContext, "note" | "componentId">;
|
||||
|
||||
export default function AutoLinkAttributesTab({ note, componentId }: AutoLinkAttributesTabArgs) {
|
||||
const [autoLinkAttributes, setAutoLinkAttributes] = useState<FAttribute[]>();
|
||||
|
||||
function refresh() {
|
||||
if (!note) return;
|
||||
const attrs = note.getAttributes().filter((attr) => attr.isAutoLink && attr.noteId === note.noteId);
|
||||
setAutoLinkAttributes(attrs);
|
||||
}
|
||||
|
||||
useEffect(refresh, [note]);
|
||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||
if (loadResults.getAttributeRows(componentId).find((attr) => attributes.isAffecting(attr, note))) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
if (!autoLinkAttributes?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="auto-link-attributes-widget">
|
||||
<div className="auto-link-attributes-container selectable-text">
|
||||
{joinElements(autoLinkAttributes.map((attribute) => (
|
||||
<AutoLinkAttribute key={attribute.attributeId} attribute={attribute} />
|
||||
)), " ")}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AutoLinkAttribute({ attribute }: { attribute: FAttribute }) {
|
||||
const [html, setHtml] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
renderAutoLink(attribute).then(setHtml);
|
||||
}, [attribute]);
|
||||
|
||||
return <span dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
}
|
||||
|
||||
async function renderAutoLink(attribute: FAttribute) {
|
||||
if (attribute.type === "label") {
|
||||
return `#${escapeHtml(attribute.name)}=${escapeHtml(attribute.value)}`;
|
||||
}
|
||||
|
||||
const note = await froca.getNote(attribute.value);
|
||||
if (!note) return "";
|
||||
|
||||
const link = `<a href="#root/${attribute.value}" class="reference-link">${escapeHtml(note.title)}</a>`;
|
||||
return `~${escapeHtml(attribute.name)}=${link}`;
|
||||
}
|
||||
|
||||
function escapeHtml(text: string) {
|
||||
const el = document.createElement("span");
|
||||
el.textContent = text;
|
||||
return el.innerHTML;
|
||||
}
|
||||
@@ -61,6 +61,17 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
||||
onContentChange(newContent) {
|
||||
contentRef.current = newContent;
|
||||
watchdogRef.current?.editor?.setData(newContent);
|
||||
|
||||
// Scroll to bookmark anchor if navigated with ?bookmark=...
|
||||
const viewScope = noteContext?.viewScope;
|
||||
if (viewScope?.bookmark) {
|
||||
requestAnimationFrame(() => {
|
||||
const el = watchdogRef.current?.editor?.editing.view.getDomRoot()
|
||||
?.querySelector(`[id="${CSS.escape(viewScope.bookmark!)}"]`);
|
||||
el?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
viewScope.bookmark = undefined;
|
||||
});
|
||||
}
|
||||
},
|
||||
dataSaved(savedData) {
|
||||
// Store back the saved data in order to retrieve it in case the CKEditor crashes.
|
||||
@@ -263,6 +274,7 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
||||
// We are not using CKEditor's built-in watch dog content, instead we are using the data we store regularly in the spaced update (see `dataSaved`).
|
||||
editor.setData(contentRef.current);
|
||||
parentComponent?.triggerEvent("textEditorRefreshed", { ntxId, editor });
|
||||
|
||||
}}
|
||||
/>}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import "@triliumnext/ckeditor5";
|
||||
|
||||
import clsx from "clsx";
|
||||
import { Ref } from "preact";
|
||||
import { useEffect, useLayoutEffect, useMemo } from "preact/hooks";
|
||||
import { useEffect, useLayoutEffect, useMemo, useRef as usePreactRef } from "preact/hooks";
|
||||
|
||||
import appContext from "../../../components/app_context";
|
||||
import FNote from "../../../entities/fnote";
|
||||
@@ -24,6 +24,17 @@ import { loadIncludedNote, refreshIncludedNote, setupImageOpening } from "./util
|
||||
export default function ReadOnlyText({ note, noteContext, ntxId }: TypeWidgetProps) {
|
||||
const blob = useNoteBlob(note);
|
||||
const { isRtl } = useNoteLanguage(note);
|
||||
const readOnlyContentRef = usePreactRef<HTMLDivElement>(null);
|
||||
|
||||
// Scroll to bookmark anchor if navigated with ?bookmark=...
|
||||
useEffect(() => {
|
||||
const viewScope = noteContext?.viewScope;
|
||||
if (!viewScope?.bookmark || !readOnlyContentRef.current) return;
|
||||
|
||||
const el = readOnlyContentRef.current.querySelector(`[id="${CSS.escape(viewScope.bookmark)}"]`);
|
||||
el?.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
viewScope.bookmark = undefined;
|
||||
}, [blob]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -31,6 +42,7 @@ export default function ReadOnlyText({ note, noteContext, ntxId }: TypeWidgetPro
|
||||
html={blob?.content ?? ""}
|
||||
ntxId={ntxId}
|
||||
dir={isRtl ? "rtl" : "ltr"}
|
||||
contentRef={readOnlyContentRef}
|
||||
/>
|
||||
|
||||
<TouchBar>
|
||||
|
||||
@@ -133,6 +133,15 @@ export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfi
|
||||
defaultProtocol: "https://",
|
||||
allowedProtocols: ALLOWED_PROTOCOLS
|
||||
},
|
||||
bookmark: {
|
||||
toolbar: [
|
||||
"bookmarkPreview",
|
||||
"|",
|
||||
"editBookmark",
|
||||
"copyAnchorLink",
|
||||
"removeBookmark"
|
||||
]
|
||||
},
|
||||
emoji: {
|
||||
definitionsUrl: window.glob.isDev
|
||||
? new URL(import.meta.url).origin + emojiDefinitionsUrl
|
||||
|
||||
@@ -6,7 +6,7 @@ WHERE powershell.exe > NUL 2>&1
|
||||
IF %ERRORLEVEL% NEQ 0 GOTO BATCH ELSE GOTO POWERSHELL
|
||||
|
||||
:POWERSHELL
|
||||
powershell -ExecutionPolicy Bypass -NonInteractive -NoLogo -Command "Set-Item -Path Env:TRILIUM_DATA_DIR -Value './trilium-data'; ./trilium.exe"
|
||||
powershell -ExecutionPolicy Bypass -NonInteractive -NoLogo -Command "Set-Item -Path Env:TRILIUM_DATA_DIR -Value './trilium-data'; Set-Item -Path Env:TRILIUM_ELECTRON_DATA_DIR -Value './trilium-electron-data'; Set-Item -Path Env:ELECTRON_NO_ATTACH_CONSOLE -Value '1'; ./trilium.exe"
|
||||
GOTO END
|
||||
|
||||
:BATCH
|
||||
@@ -17,6 +17,8 @@ chcp 65001
|
||||
SET DIR=%~dp0
|
||||
SET DIR=%DIR:~0,-1%
|
||||
SET TRILIUM_DATA_DIR=%DIR%\trilium-data
|
||||
SET TRILIUM_ELECTRON_DATA_DIR=%DIR%\trilium-electron-data
|
||||
SET ELECTRON_NO_ATTACH_CONSOLE=1
|
||||
cd "%DIR%"
|
||||
start trilium.exe
|
||||
GOTO END
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
DIR=`dirname "$0"`
|
||||
export TRILIUM_DATA_DIR="$DIR/trilium-data"
|
||||
export TRILIUM_ELECTRON_DATA_DIR="$DIR/trilium-electron-data"
|
||||
|
||||
exec "$DIR/trilium"
|
||||
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
"url": "https://triliumnotes.org"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "cross-env TRILIUM_PORT=37742 TRILIUM_DATA_DIR=data tsx ../../scripts/electron-start.mts src/main.ts",
|
||||
"dev": "cross-env TRILIUM_PORT=37742 TRILIUM_DATA_DIR=data TRILIUM_ELECTRON_DATA_DIR=data-electron-37742 tsx ../../scripts/electron-start.mts src/main.ts",
|
||||
"start-no-dir": "cross-env TRILIUM_PORT=37743 tsx ../../scripts/electron-start.mts src/main.ts",
|
||||
"build": "tsx scripts/build.ts",
|
||||
"start-prod": "pnpm build && cross-env TRILIUM_DATA_DIR=data TRILIUM_PORT=37841 ELECTRON_IS_DEV=0 electron dist",
|
||||
"start-prod": "pnpm build && cross-env TRILIUM_DATA_DIR=data TRILIUM_ELECTRON_DATA_DIR=data-electron-37841 TRILIUM_PORT=37841 ELECTRON_IS_DEV=0 electron dist",
|
||||
"start-prod-no-dir": "pnpm build && cross-env TRILIUM_PORT=37841 ELECTRON_IS_DEV=0 electron dist",
|
||||
"electron-forge:make": "pnpm build && electron-forge make dist",
|
||||
"electron-forge:make-flatpak": "pnpm build && DEBUG=* electron-forge make dist --targets=@electron-forge/maker-flatpak",
|
||||
"electron-forge:package": "pnpm build && electron-forge package dist",
|
||||
"electron-forge:start": "pnpm build && electron-forge start dist",
|
||||
"e2e": "pnpm build && cross-env TRILIUM_INTEGRATION_TEST=memory-no-store TRILIUM_PORT=8082 TRILIUM_DATA_DIR=data-e2e ELECTRON_IS_DEV=0 playwright test"
|
||||
"e2e": "pnpm build && cross-env TRILIUM_INTEGRATION_TEST=memory-no-store TRILIUM_PORT=8082 TRILIUM_DATA_DIR=data-e2e TRILIUM_ELECTRON_DATA_DIR=data-e2e-electron-8082 ELECTRON_IS_DEV=0 playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/remote": "2.1.3",
|
||||
|
||||
101
apps/desktop/scripts/build-appimage.sh
Executable file
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Build an AppImage from the packaged Electron app.
|
||||
#
|
||||
# Usage: ./build-appimage.sh [arch]
|
||||
# arch: x64 or arm64 (default: x64)
|
||||
#
|
||||
# Prerequisites:
|
||||
# - The Electron app must already be packaged via `electron-forge make` or `electron-forge package`
|
||||
# - appimagetool must be available in PATH
|
||||
#
|
||||
# Environment variables:
|
||||
# TRILIUM_ARTIFACT_NAME_HINT: If set, used as the base name for the output file
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
DESKTOP_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
FORGE_DIR="$DESKTOP_DIR/electron-forge"
|
||||
|
||||
ARCH="${1:-x64}"
|
||||
EXECUTABLE_NAME="trilium"
|
||||
PRODUCT_NAME="Trilium Notes"
|
||||
|
||||
# Map architecture names
|
||||
case "$ARCH" in
|
||||
x64) APPIMAGE_ARCH="x86_64" ;;
|
||||
arm64) APPIMAGE_ARCH="aarch64" ;;
|
||||
*) echo "Unsupported architecture: $ARCH"; exit 1 ;;
|
||||
esac
|
||||
|
||||
# Find the packaged app directory
|
||||
PACKAGED_DIR="$DESKTOP_DIR/dist/out/$PRODUCT_NAME-linux-$ARCH"
|
||||
if [ ! -d "$PACKAGED_DIR" ]; then
|
||||
echo "Error: Packaged app not found at $PACKAGED_DIR"
|
||||
echo "Run 'electron-forge make' or 'electron-forge package' first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Building AppImage from: $PACKAGED_DIR"
|
||||
|
||||
# Create AppDir structure
|
||||
APPDIR="$DESKTOP_DIR/dist/out/$PRODUCT_NAME.AppDir"
|
||||
rm -rf "$APPDIR"
|
||||
mkdir -p "$APPDIR"
|
||||
|
||||
# Copy the packaged app contents into the AppDir
|
||||
cp -a "$PACKAGED_DIR"/. "$APPDIR/"
|
||||
|
||||
# Create the AppRun entry point
|
||||
cat > "$APPDIR/AppRun" << 'APPRUN_EOF'
|
||||
#!/bin/bash
|
||||
HERE="$(dirname "$(readlink -f "$0")")"
|
||||
exec "$HERE/trilium" "$@"
|
||||
APPRUN_EOF
|
||||
chmod +x "$APPDIR/AppRun"
|
||||
|
||||
# Create the .desktop file
|
||||
cat > "$APPDIR/$EXECUTABLE_NAME.desktop" << DESKTOP_EOF
|
||||
[Desktop Entry]
|
||||
Name=$PRODUCT_NAME
|
||||
Comment=Build your personal knowledge base with Trilium Notes
|
||||
GenericName=Note Taking Application
|
||||
Exec=$EXECUTABLE_NAME %U
|
||||
Icon=$EXECUTABLE_NAME
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
StartupWMClass=$PRODUCT_NAME
|
||||
Categories=Office;Utility;
|
||||
DESKTOP_EOF
|
||||
|
||||
# Copy the icon (AppImage expects it at the root of AppDir)
|
||||
if [ -f "$FORGE_DIR/app-icon/png/256x256.png" ]; then
|
||||
cp "$FORGE_DIR/app-icon/png/256x256.png" "$APPDIR/$EXECUTABLE_NAME.png"
|
||||
elif [ -f "$APPDIR/icon.png" ]; then
|
||||
cp "$APPDIR/icon.png" "$APPDIR/$EXECUTABLE_NAME.png"
|
||||
else
|
||||
echo "Warning: No icon found"
|
||||
fi
|
||||
|
||||
# Determine output filename
|
||||
UPLOAD_DIR="$DESKTOP_DIR/upload"
|
||||
mkdir -p "$UPLOAD_DIR"
|
||||
|
||||
if [ -n "${TRILIUM_ARTIFACT_NAME_HINT:-}" ]; then
|
||||
OUTPUT_NAME="${TRILIUM_ARTIFACT_NAME_HINT//\//-}.AppImage"
|
||||
else
|
||||
VERSION=$(node -e "console.log(require('$DESKTOP_DIR/package.json').version)")
|
||||
OUTPUT_NAME="TriliumNotes-v${VERSION}-linux-${ARCH}.AppImage"
|
||||
fi
|
||||
|
||||
OUTPUT_PATH="$UPLOAD_DIR/$OUTPUT_NAME"
|
||||
|
||||
# Build the AppImage
|
||||
echo "Creating AppImage: $OUTPUT_PATH"
|
||||
ARCH="$APPIMAGE_ARCH" appimagetool "$APPDIR" "$OUTPUT_PATH"
|
||||
|
||||
# Clean up the AppDir
|
||||
rm -rf "$APPDIR"
|
||||
|
||||
echo "AppImage created successfully: $OUTPUT_PATH"
|
||||
@@ -10,7 +10,7 @@ import electronDebug from "electron-debug";
|
||||
import electronDl from "electron-dl";
|
||||
import { PRODUCT_NAME } from "./app-info";
|
||||
import port from "@triliumnext/server/src/services/port.js";
|
||||
import { join } from "path";
|
||||
import { join, resolve } from "path";
|
||||
import { deferred, LOCALES } from "../../../packages/commons/src";
|
||||
|
||||
async function main() {
|
||||
@@ -101,10 +101,16 @@ async function main() {
|
||||
|
||||
/**
|
||||
* Returns a unique user data directory for Electron so that single instance locks between legitimately different instances such as different port or data directory can still act independently, but we are focusing the main window otherwise.
|
||||
*
|
||||
* When running in portable mode, set TRILIUM_ELECTRON_DATA_DIR (e.g. via the trilium-portable script)
|
||||
* so that no Electron files are written to the system's roaming profile (e.g. %APPDATA% on Windows).
|
||||
*/
|
||||
function getUserData() {
|
||||
const name = `${app.getName()}-${port}`;
|
||||
return join(app.getPath("appData"), name);
|
||||
if (process.env.TRILIUM_ELECTRON_DATA_DIR) {
|
||||
return resolve(process.env.TRILIUM_ELECTRON_DATA_DIR);
|
||||
}
|
||||
|
||||
return join(app.getPath("appData"), `${app.getName()}-${port}`);
|
||||
}
|
||||
|
||||
async function onReady() {
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "3.0.69",
|
||||
"@ai-sdk/google": "3.0.63",
|
||||
"@ai-sdk/openai": "3.0.52",
|
||||
"@ai-sdk/openai": "3.0.53",
|
||||
"@modelcontextprotocol/sdk": "^1.12.1",
|
||||
"ai": "6.0.159",
|
||||
"ai": "6.0.161",
|
||||
"better-sqlite3": "12.9.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"js-yaml": "4.1.1",
|
||||
|
||||
2
apps/server/src/assets/doc_notes/en/User Guide/!!!meta.json
generated
vendored
@@ -165,10 +165,16 @@ class="admonition note">
|
||||
class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>.</li>
|
||||
</ul>
|
||||
<p>For example, to change the font of the document from the one defined by
|
||||
the theme or the user to a serif one:</p><pre><code class="language-text-x-trilium-auto">body {
|
||||
--main-font-family: serif !important;
|
||||
--detail-font-family: var(--main-font-family) !important;
|
||||
the theme or the user to a serif one:</p><pre><code class="language-text-x-trilium-auto">body {
|
||||
--print-font-family: serif;
|
||||
--print-font-size: 11pt;
|
||||
}</code></pre>
|
||||
<aside class="admonition important">
|
||||
<p>When altering <code spellcheck="false">--print-font-family</code>, make
|
||||
sure the change is done at <code spellcheck="false">body</code> level and
|
||||
not <code spellcheck="false">:root</code>, since otherwise it won't be picked
|
||||
up due to specificity rules.</p>
|
||||
</aside>
|
||||
<p>To remark:</p>
|
||||
<ul>
|
||||
<li>Multiple CSS notes can be add by using multiple <code spellcheck="false">~printCss</code> relations.</li>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<p>Split view is a feature of <a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_s1aBHPd79XYj">Mermaid Diagrams</a> and
|
||||
<p>Split view is a feature of <a class="reference-link" href="#root/_help_s1aBHPd79XYj">Mermaid Diagrams</a> and
|
||||
<a
|
||||
class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_6RM1Q7ppFVoj">Markdown</a> notes which displays both the source code on one side
|
||||
class="reference-link" href="#root/_help_6RM1Q7ppFVoj">Markdown</a> notes which displays both the source code on one side
|
||||
and the preview of the content on the other.</p>
|
||||
<p><a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_s1aBHPd79XYj">Mermaid Diagrams</a> also
|
||||
<p><a class="reference-link" href="#root/_help_s1aBHPd79XYj">Mermaid Diagrams</a> also
|
||||
allow changing between a horizontal or a vertical split, to accommodate
|
||||
for the various sizes of diagrams.</p>
|
||||
<h2>Display modes and interaction</h2>
|
||||
@@ -20,12 +20,12 @@
|
||||
<li><em>Preview</em> which displays only the rendering of the diagram or text
|
||||
in full screen, especially useful for read-only notes.</li>
|
||||
</ul>
|
||||
<p>These buttons can be found near the <a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_8YBEPzcpUgxw">Note buttons</a> section
|
||||
on the <a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_IjZS7iK5EXtb">New Layout</a>,
|
||||
or in the <a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_XpOYSgsLkTJy">Floating buttons</a> on
|
||||
<p>These buttons can be found near the <a class="reference-link" href="#root/_help_8YBEPzcpUgxw">Note buttons</a> section
|
||||
on the <a class="reference-link" href="#root/_help_IjZS7iK5EXtb">New Layout</a>,
|
||||
or in the <a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a> on
|
||||
the old layout.</p>
|
||||
<p>The display node is stored at note level.</p>
|
||||
<h2>Relation to read-only notes</h2>
|
||||
<p>If a note is marked as <a href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/BFs8mudNFgCS/_help_CoFPLs3dRlXc">read-only</a>,
|
||||
the source view will not be editable. While in preview mode, marking a
|
||||
note as read-only has no effect since the preview itself is not editable.</p>
|
||||
<p>If a note is marked as <a href="#root/_help_CoFPLs3dRlXc">read-only</a>, the
|
||||
source view will not be editable. While in preview mode, marking a note
|
||||
as read-only has no effect since the preview itself is not editable.</p>
|
||||
@@ -70,6 +70,19 @@
|
||||
this:</p><pre><code class="language-text-x-trilium-auto">TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data trilium</code></pre>
|
||||
<p>You can then save the above command as a shell script on your path for
|
||||
convenience.</p>
|
||||
<h2>Electron user data directory (desktop only)</h2>
|
||||
<p>When running the desktop application, Electron stores internal data (caches,
|
||||
spell-check dictionaries, session storage, etc.) separately from the Trilium
|
||||
data directory. By default this goes to the system's application data folder
|
||||
(e.g. <code spellcheck="false">%APPDATA%</code> on Windows), which may be
|
||||
undesirable in corporate environments with roaming profiles or when running
|
||||
in portable mode.</p>
|
||||
<p>To keep Electron data out of the system's roaming profile, set the
|
||||
<code
|
||||
spellcheck="false">TRILIUM_ELECTRON_DATA_DIR</code>environment variable to an explicit path.
|
||||
The <code spellcheck="false">trilium-portable</code> script does this automatically,
|
||||
pointing it to <code spellcheck="false">trilium-electron-data/</code> next
|
||||
to the application.</p>
|
||||
<h2>Fine-grained directory/path location</h2>
|
||||
<p>Apart from the data directory, some of the subdirectories of it can be
|
||||
moved elsewhere by changing an environment variable:</p>
|
||||
@@ -129,5 +142,13 @@
|
||||
</td>
|
||||
<td>Path to <a class="reference-link" href="#root/_help_Gzjqa934BdH4">Configuration (config.ini or environment variables)</a> file.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code spellcheck="false">TRILIUM_ELECTRON_DATA_DIR</code>
|
||||
</td>
|
||||
<td>System appData</td>
|
||||
<td>Directory for Electron internal data (caches, spell-check dictionaries,
|
||||
etc.). Set this in portable mode to avoid writing to the system profile
|
||||
(desktop only).</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -23,7 +23,9 @@
|
||||
<li><code spellcheck="false">trilium-portable</code>: Launches Trilium in
|
||||
portable mode, where the <a href="#root/_help_tAassRL4RSQL">data directory</a> is
|
||||
created within the application's directory, making it easy to move the
|
||||
entire setup.</li>
|
||||
entire setup. Electron's internal data (caches, dictionaries, etc.) is
|
||||
also stored within the data directory, so no files are written to the system's
|
||||
roaming profile.</li>
|
||||
<li><code spellcheck="false">trilium-safe-mode</code>: Boots Trilium in "safe
|
||||
mode," disabling any startup scripts that might cause the application to
|
||||
crash.</li>
|
||||
|
||||
190
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types.html
generated
vendored
@@ -9,8 +9,7 @@
|
||||
note where to place the new one and select:</p>
|
||||
<ul>
|
||||
<li><em>Insert note after</em>, to put the new note underneath the one selected.</li>
|
||||
<li
|
||||
><em>Insert child note</em>, to insert the note as a child of the selected
|
||||
<li><em>Insert child note</em>, to insert the note as a child of the selected
|
||||
note.</li>
|
||||
</ul>
|
||||
<p>
|
||||
@@ -21,8 +20,7 @@
|
||||
<li>When adding a <a href="#root/_help_QEAPj01N5f7w">link</a> in a <a class="reference-link"
|
||||
href="#root/_help_iPIMuisry3hd">Text</a> note, type the desired title of
|
||||
the new note and press Enter. Afterwards the type of the note will be asked.</li>
|
||||
<li
|
||||
>Similarly, when creating a new tab, type the desired title and press Enter.</li>
|
||||
<li>Similarly, when creating a new tab, type the desired title and press Enter.</li>
|
||||
</ul>
|
||||
<h2>Changing the type of a note</h2>
|
||||
<p>It is possible to change the type of a note after it has been created
|
||||
@@ -32,96 +30,94 @@
|
||||
edit the <a href="#root/_help_4FahAwuGTAwC">source of a note</a>.</p>
|
||||
<h2>Supported note types</h2>
|
||||
<p>The following note types are supported by Trilium:</p>
|
||||
<figure class="table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Note Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_iPIMuisry3hd">Text</a>
|
||||
</td>
|
||||
<td>The default note type, which allows for rich text formatting, images,
|
||||
admonitions and right-to-left support.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>
|
||||
</td>
|
||||
<td>Uses a mono-space font and can be used to store larger chunks of code
|
||||
or plain text than a text note, and has better syntax highlighting.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_m523cpzocqaD">Saved Search</a>
|
||||
</td>
|
||||
<td>Stores the information about a search (the search text, criteria, etc.)
|
||||
for later use. Can be used for quick filtering of a large amount of notes,
|
||||
for example. The search can easily be triggered.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_iRwzGnHPzonm">Relation Map</a>
|
||||
</td>
|
||||
<td>Allows easy creation of notes and relations between them. Can be used
|
||||
for mainly relational data such as a family tree.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_bdUJEHsAPYQR">Note Map</a>
|
||||
</td>
|
||||
<td>Displays the relationships between the notes, whether via relations or
|
||||
their hierarchical structure.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_HcABDtFCkbFN">Render Note</a>
|
||||
</td>
|
||||
<td>Used in <a class="reference-link" href="#root/_help_CdNpE2pqjmI6">Scripting</a>,
|
||||
it displays the HTML content of another note. This allows displaying any
|
||||
kind of content, provided there is a script behind it to generate it.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>
|
||||
</td>
|
||||
<td>Displays the children of the note either as a grid, a list, or for a more
|
||||
specialized case: a calendar.
|
||||
<br>
|
||||
<br>Generally useful for easy reading of short notes.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_s1aBHPd79XYj">Mermaid Diagrams</a>
|
||||
</td>
|
||||
<td>Displays diagrams such as bar charts, flow charts, state diagrams, etc.
|
||||
Requires a bit of technical knowledge since the diagrams are written in
|
||||
a specialized format.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_grjYqerjn243">Canvas</a>
|
||||
</td>
|
||||
<td>Allows easy drawing of sketches, diagrams, handwritten content. Uses the
|
||||
same technology behind <a href="https://excalidraw.com">excalidraw.com</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_1vHRoWCEjj0L">Web View</a>
|
||||
</td>
|
||||
<td>Displays the content of an external web page, similar to a browser.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_gBbsAeiuUxI5">Mind Map</a>
|
||||
</td>
|
||||
<td>Easy for brainstorming ideas, by placing them in a hierarchical layout.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_81SGnPGMk7Xc">Geo Map</a>
|
||||
</td>
|
||||
<td>Displays the children of the note as a geographical map, one use-case
|
||||
would be to plan vacations. It even has basic support for tracks. Notes
|
||||
can also be created from it.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_W8vYD3Q1zjCR">File</a>
|
||||
</td>
|
||||
<td>Represents an uploaded file such as PDFs, images, video or audio files.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Note Type</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_iPIMuisry3hd">Text</a>
|
||||
</td>
|
||||
<td>The default note type, which allows for rich text formatting, images,
|
||||
admonitions and right-to-left support.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>
|
||||
</td>
|
||||
<td>Uses a mono-space font and can be used to store larger chunks of code
|
||||
or plain text than a text note, and has better syntax highlighting.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_m523cpzocqaD">Saved Search</a>
|
||||
</td>
|
||||
<td>Stores the information about a search (the search text, criteria, etc.)
|
||||
for later use. Can be used for quick filtering of a large amount of notes,
|
||||
for example. The search can easily be triggered.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_iRwzGnHPzonm">Relation Map</a>
|
||||
</td>
|
||||
<td>Allows easy creation of notes and relations between them. Can be used
|
||||
for mainly relational data such as a family tree.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_bdUJEHsAPYQR">Note Map</a>
|
||||
</td>
|
||||
<td>Displays the relationships between the notes, whether via relations or
|
||||
their hierarchical structure.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_HcABDtFCkbFN">Render Note</a>
|
||||
</td>
|
||||
<td>Used in <a class="reference-link" href="#root/_help_CdNpE2pqjmI6">Scripting</a>,
|
||||
it displays the HTML content of another note. This allows displaying any
|
||||
kind of content, provided there is a script behind it to generate it.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>
|
||||
</td>
|
||||
<td>Displays the children of the note either as a grid, a list, or for a more
|
||||
specialized case: a calendar.
|
||||
<br>
|
||||
<br>Generally useful for easy reading of short notes.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_s1aBHPd79XYj">Mermaid Diagrams</a>
|
||||
</td>
|
||||
<td>Displays diagrams such as bar charts, flow charts, state diagrams, etc.
|
||||
Requires a bit of technical knowledge since the diagrams are written in
|
||||
a specialized format.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_grjYqerjn243">Canvas</a>
|
||||
</td>
|
||||
<td>Allows easy drawing of sketches, diagrams, handwritten content. Uses the
|
||||
same technology behind <a href="https://excalidraw.com">excalidraw.com</a>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_1vHRoWCEjj0L">Web View</a>
|
||||
</td>
|
||||
<td>Displays the content of an external web page, similar to a browser.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_gBbsAeiuUxI5">Mind Map</a>
|
||||
</td>
|
||||
<td>Easy for brainstorming ideas, by placing them in a hierarchical layout.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_81SGnPGMk7Xc">Geo Map</a>
|
||||
</td>
|
||||
<td>Displays the children of the note as a geographical map, one use-case
|
||||
would be to plan vacations. It even has basic support for tracks. Notes
|
||||
can also be created from it.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_W8vYD3Q1zjCR">File</a>
|
||||
</td>
|
||||
<td>Represents an uploaded file such as PDFs, images, video or audio files.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
37
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/File.html
generated
vendored
@@ -5,8 +5,7 @@
|
||||
create a <em>File</em> note type directly:</p>
|
||||
<ul>
|
||||
<li>Drag a file into the <a class="reference-link" href="#root/_help_oPVyFC7WL2Lp">Note Tree</a>.</li>
|
||||
<li
|
||||
>Right click a note and select <em>Import into note</em> and point it to
|
||||
<li>Right click a note and select <em>Import into note</em> and point it to
|
||||
one of the supported files.</li>
|
||||
</ul>
|
||||
<h2>Supported file types</h2>
|
||||
@@ -83,30 +82,28 @@
|
||||
href="#root/_help_BlN9DFI679QC">Ribbon</a>.
|
||||
<ul>
|
||||
<li><em>Download</em>, which will download the file for local use.</li>
|
||||
<li
|
||||
><em>Open</em>, will will open the file with the system-default application.</li>
|
||||
<li
|
||||
>Upload new revision to replace the file with a new one.</li>
|
||||
<li><em>Open</em>, will will open the file with the system-default application.</li>
|
||||
<li>Upload new revision to replace the file with a new one.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>It is <strong>not</strong> possible to change the note type of a <em>File</em> note.</li>
|
||||
<li
|
||||
>Convert into an <a href="#root/_help_0vhv7lsOLy82">attachment</a> from the <a href="#root/_help_8YBEPzcpUgxw">note menu</a>.</li>
|
||||
</li>
|
||||
<li>It is <strong>not</strong> possible to change the note type of a <em>File</em> note.</li>
|
||||
<li>Convert into an <a href="#root/_help_0vhv7lsOLy82">attachment</a> from the <a href="#root/_help_8YBEPzcpUgxw">note menu</a>.</li>
|
||||
</ul>
|
||||
<h2>Relation with other notes</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Files are also displayed in the <a class="reference-link" href="#root/_help_0ESUbbAxVnoK">Note List</a> based
|
||||
on their type:</p>
|
||||
<p>
|
||||
<img class="image_resized" style="aspect-ratio:853/315;width:50%;" src="4_File_image.png"
|
||||
width="853" height="315">
|
||||
</p>
|
||||
<img class="image_resized" style="aspect-ratio:853/315;width:50%;"
|
||||
src="4_File_image.png" width="853" height="315">
|
||||
</li>
|
||||
<li>
|
||||
<p>Non-image files can be embedded into text notes as read-only widgets via
|
||||
the <a class="reference-link" href="#root/_help_nBAXQFj20hS1">Include Note</a> functionality.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Image files can be embedded into text notes like normal images via
|
||||
<a
|
||||
class="reference-link" href="#root/_help_0Ofbk1aSuVRu">Image references</a>.</p>
|
||||
</li>
|
||||
<li>Non-image files can be embedded into text notes as read-only widgets via
|
||||
the <a class="reference-link" href="#root/_help_nBAXQFj20hS1">Include Note</a> functionality.</li>
|
||||
<li
|
||||
>Image files can be embedded into text notes like normal images via
|
||||
<a
|
||||
class="reference-link" href="#root/_help_0Ofbk1aSuVRu">Image references</a>.</li>
|
||||
</ul>
|
||||
77
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Markdown.html
generated
vendored
@@ -1,13 +1,12 @@
|
||||
<p>Trilium has always supported Markdown through its <a href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/mHbBMPDPkVV5/_help_Oau6X9rCuegd">import feature</a>,
|
||||
<p>Trilium has always supported Markdown through its <a href="#root/_help_Oau6X9rCuegd">import feature</a>,
|
||||
however the file was either transformed to a <a class="reference-link"
|
||||
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_iPIMuisry3hd">Text</a> note
|
||||
(converted to Trilium's internal HTML format) or saved as a <a class="reference-link"
|
||||
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_6f9hih2hXXZk">Code</a> note
|
||||
href="#root/_help_iPIMuisry3hd">Text</a> note (converted to Trilium's internal
|
||||
HTML format) or saved as a <a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a> note
|
||||
with only syntax highlight.</p>
|
||||
<p>This note type is a split view, meaning that both the source code and
|
||||
a preview of the document are displayed side-by-side. See <a class="reference-link"
|
||||
href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_SL5f1Auq7sVN">Note types with split view</a> for
|
||||
more information.</p>
|
||||
href="#root/_help_SL5f1Auq7sVN">Note types with split view</a> for more
|
||||
information.</p>
|
||||
<h2>Rationale</h2>
|
||||
<p>The goal of this note type is to fill a gap: rendering Markdown but not
|
||||
altering its structure or its whitespace which would inevitably change
|
||||
@@ -37,77 +36,65 @@
|
||||
<li
|
||||
>Code blocks with syntax highlight (e.g. <code spellcheck="false">```js</code>)
|
||||
and automatic syntax highlight</li>
|
||||
<li><a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/iPIMuisry3hd/_help_NwBbFdNZ9h7O">Block quotes & admonitions</a>
|
||||
<li><a class="reference-link" href="#root/_help_NwBbFdNZ9h7O">Block quotes & admonitions</a>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/iPIMuisry3hd/_help_YfYAtQBcfo5V">Math Equations</a>
|
||||
<li><a class="reference-link" href="#root/_help_YfYAtQBcfo5V">Math Equations</a>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_s1aBHPd79XYj">Mermaid Diagrams</a> using
|
||||
<li><a class="reference-link" href="#root/_help_s1aBHPd79XYj">Mermaid Diagrams</a> using
|
||||
<code
|
||||
spellcheck="false">```mermaid</code>
|
||||
</li>
|
||||
<li>
|
||||
<p><a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/iPIMuisry3hd/_help_nBAXQFj20hS1">Include Note</a> (no
|
||||
<p><a class="reference-link" href="#root/_help_nBAXQFj20hS1">Include Note</a> (no
|
||||
builtin Markdown syntax, but HTML syntax works just fine):</p><pre><code class="language-text-x-trilium-auto"><section class="include-note" data-note-id="vJDjQm0VK8Na" data-box-size="expandable">
|
||||
&nbsp;
|
||||
&nbsp;
|
||||
</section>n</code></pre>
|
||||
</li>
|
||||
<li>
|
||||
<p><a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/iPIMuisry3hd/QEAPj01N5f7w/_help_hrZ1D00cLbal">Internal (reference) links</a> via
|
||||
<p><a class="reference-link" href="#root/_help_hrZ1D00cLbal">Internal (reference) links</a> via
|
||||
its HTML syntax, or through a <em>Wikilinks</em>-like format (only
|
||||
<a
|
||||
class="reference-link" href="#root/pOsGYCXsbNQG/tC7s2alapj8V/_help_m1lbrzyKDaRB">Note ID</a>):</p><pre><code class="language-text-x-trilium-auto">[[Hg8TS5ZOxti6]]</code></pre>
|
||||
class="reference-link" href="#root/_help_m1lbrzyKDaRB">Note ID</a>):</p><pre><code class="language-text-x-trilium-auto">[[Hg8TS5ZOxti6]]</code></pre>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Creating Markdown notes</h2>
|
||||
<p>There are two ways to create a Markdown note:</p>
|
||||
<ol>
|
||||
<li>Create a new note (e.g. in the <a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_oPVyFC7WL2Lp">Note Tree</a>)
|
||||
<li>Create a new note (e.g. in the <a class="reference-link" href="#root/_help_oPVyFC7WL2Lp">Note Tree</a>)
|
||||
and select the type <em>Markdown</em>, just like all the other note types.</li>
|
||||
<li
|
||||
>Create a note of type <a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_6f9hih2hXXZk">Code</a> and
|
||||
select as the language either <em>Markdown </em>or <em>GitHub-Flavored Markdown</em>.
|
||||
>Create a note of type <a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a> and
|
||||
select as the language either <em>Markdown</em> or <em>GitHub-Flavored Markdown</em>.
|
||||
This maintains compatibility with your existing notes prior to the introduction
|
||||
of this feature.</li>
|
||||
</ol>
|
||||
<aside class="admonition note">
|
||||
<p>There is no distinction between the new Markdown note type and code notes
|
||||
of type Markdown; internally both are represented as <a class="reference-link"
|
||||
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_6f9hih2hXXZk">Code</a> notes
|
||||
with the proper MIME type (e.g. <code spellcheck="false">text/x-markdown</code>).</p>
|
||||
href="#root/_help_6f9hih2hXXZk">Code</a> notes with the proper MIME type
|
||||
(e.g. <code spellcheck="false">text/x-markdown</code>).</p>
|
||||
</aside>
|
||||
<h2>Import/export</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<p>By default, when importing a single Markdown file it automatically gets
|
||||
converted to a <a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_iPIMuisry3hd">Text</a> note.
|
||||
To avoid that and have it imported as a Markdown note instead:</p>
|
||||
<li>By default, when importing a single Markdown file it automatically gets
|
||||
converted to a <a class="reference-link" href="#root/_help_iPIMuisry3hd">Text</a> note.
|
||||
To avoid that and have it imported as a Markdown note instead:
|
||||
<ul>
|
||||
<li>
|
||||
<p>Right click the <a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_oPVyFC7WL2Lp">Note Tree</a> and
|
||||
select <em>Import into note</em>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Select the file normally.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Uncheck <em>Import HTML, Markdown and TXT as text notes if it's unclear from the metadata</em>.</p>
|
||||
</li>
|
||||
<li>Right click the <a class="reference-link" href="#root/_help_oPVyFC7WL2Lp">Note Tree</a> and
|
||||
select <em>Import into note</em>.</li>
|
||||
<li>Select the file normally.</li>
|
||||
<li>Uncheck <em>Import HTML, Markdown and TXT as text notes if it's unclear from the metadata</em>.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>When exporting Markdown files, the extension is preserved and the content
|
||||
remains the same as in the source view.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Once exported as a Trilium ZIP, the ZIP will preserve the Markdown type
|
||||
without converting to text notes thanks to the meta-information in it.</p>
|
||||
</li>
|
||||
<li>When exporting Markdown files, the extension is preserved and the content
|
||||
remains the same as in the source view.</li>
|
||||
<li>Once exported as a Trilium ZIP, the ZIP will preserve the Markdown type
|
||||
without converting to text notes thanks to the meta-information in it.</li>
|
||||
</ul>
|
||||
<h2>Conversion between text notes and Markdown notes</h2>
|
||||
<p>Currently there is no built-in functionality to convert a <a class="reference-link"
|
||||
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_iPIMuisry3hd">Text</a> note
|
||||
into a Markdown note or vice-versa. We do have plans to address this in
|
||||
the future.</p>
|
||||
href="#root/_help_iPIMuisry3hd">Text</a> note into a Markdown note or vice-versa.
|
||||
We do have plans to address this in the future.</p>
|
||||
<p>This can be achieved manually, for a single note:</p>
|
||||
<ol>
|
||||
<li>Export the file as Markdown, with single format.</li>
|
||||
@@ -135,6 +122,6 @@
|
||||
<p>This feature of synchronizing the scroll is based on blocks but it's provided
|
||||
on a best-effort basis since our underlying Markdown library doesn't support
|
||||
this feature natively, so we had to implement our own algorithm. Feel free
|
||||
to <a href="#root/pOsGYCXsbNQG/BgmBlOIl72jZ/_help_wy8So3yZZlH9">report issues</a>,
|
||||
but always provide a sample Markdown file to be able to reproduce it.</p>
|
||||
to <a href="#root/_help_wy8So3yZZlH9">report issues</a>, but always provide a
|
||||
sample Markdown file to be able to reproduce it.</p>
|
||||
</aside>
|
||||
@@ -12,8 +12,8 @@
|
||||
the diagram.</p>
|
||||
<p>This note type is a split view, meaning that both the source code and
|
||||
a preview of the document are displayed side-by-side. See <a class="reference-link"
|
||||
href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_SL5f1Auq7sVN">Note types with split view</a> for
|
||||
more information.</p>
|
||||
href="#root/_help_SL5f1Auq7sVN">Note types with split view</a> for more
|
||||
information.</p>
|
||||
<h2>Sample diagrams</h2>
|
||||
<p>Starting with v0.103.0, Mermaid diagrams no longer start with a sample
|
||||
flowchart, but instead a pane at the bottom will show all the supported
|
||||
@@ -52,34 +52,30 @@
|
||||
<img src="1_Mermaid Diagrams_image.png">
|
||||
</li>
|
||||
<li>The preview can be moved around by holding the left mouse button and dragging.</li>
|
||||
<li
|
||||
>Zooming can also be done by using the scroll wheel.</li>
|
||||
<li>The zoom and position on the preview will remain fixed as the diagram
|
||||
changes, to be able to work more easily with large diagrams.</li>
|
||||
</ul>
|
||||
<li>Zooming can also be done by using the scroll wheel.</li>
|
||||
<li>The zoom and position on the preview will remain fixed as the diagram
|
||||
changes, to be able to work more easily with large diagrams.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>The size of the source/preview panes can be adjusted by hovering over
|
||||
the border between them and dragging it with the mouse.</li>
|
||||
<li>In the <a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a> area:
|
||||
<ul>
|
||||
<li>The source/preview can be laid out left-right or bottom-top via the <em>Move editing pane to the left / bottom</em> option.</li>
|
||||
<li
|
||||
>Press <em>Lock editing</em> to automatically mark the note as read-only.
|
||||
<li>Press <em>Lock editing</em> to automatically mark the note as read-only.
|
||||
In this mode, the code pane is hidden and the diagram is displayed full-size.
|
||||
Similarly, press <em>Unlock editing</em> to mark a read-only note as editable.</li>
|
||||
<li
|
||||
>Press the <em>Copy image reference to the clipboard</em> to be able to insert
|
||||
the image representation of the diagram into a text note. See <a class="reference-link"
|
||||
href="#root/_help_0Ofbk1aSuVRu">Image references</a> for more information.</li>
|
||||
<li
|
||||
>Press the <em>Export diagram as SVG</em> to download a scalable/vector rendering
|
||||
of the diagram. Can be used to present the diagram without degrading when
|
||||
zooming.</li>
|
||||
<li>Press the <em>Copy image reference to the clipboard</em> to be able to insert
|
||||
the image representation of the diagram into a text note. See <a class="reference-link"
|
||||
href="#root/_help_0Ofbk1aSuVRu">Image references</a> for more information.</li>
|
||||
<li>Press the <em>Export diagram as SVG</em> to download a scalable/vector rendering
|
||||
of the diagram. Can be used to present the diagram without degrading when
|
||||
zooming.</li>
|
||||
<li>Press the <em>Export diagram as PNG</em> to download a normal image (at
|
||||
1x scale, raster) of the diagram. Can be used to send the diagram in more
|
||||
traditional channels such as e-mail.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Errors in the diagram</h2>
|
||||
<p>If there is an error in the source code, the error will be displayed in
|
||||
|
||||
30
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Render Note.html
generated
vendored
@@ -13,13 +13,11 @@
|
||||
<ol>
|
||||
<li>HTML language for the legacy/vanilla method, with what needs to be displayed
|
||||
(for example <code spellcheck="false"><p>Hello world.</p></code>).</li>
|
||||
<li
|
||||
>JSX for the Preact-based approach (see below).</li>
|
||||
</ol>
|
||||
<li>JSX for the Preact-based approach (see below).</li>
|
||||
</ol>
|
||||
</li>
|
||||
<li>Create a <a class="reference-link" href="#root/_help_HcABDtFCkbFN">Render Note</a>.</li>
|
||||
<li
|
||||
>Assign the <code spellcheck="false">renderNote</code> <a href="#root/_help_zEY4DaJG4YT5">relation</a> to
|
||||
<li>Assign the <code spellcheck="false">renderNote</code> <a href="#root/_help_zEY4DaJG4YT5">relation</a> to
|
||||
point at the previously created code note.</li>
|
||||
</ol>
|
||||
<h2>Legacy scripting using jQuery</h2>
|
||||
@@ -48,9 +46,10 @@ $dateEl.text(new Date());</code></pre>
|
||||
need to provide a HTML anymore.</p>
|
||||
<p>Here are the steps to creating a simple render note:</p>
|
||||
<ol>
|
||||
<li>Create a note of type <a class="reference-link" href="#root/_help_HcABDtFCkbFN">Render Note</a>.</li>
|
||||
<li
|
||||
>
|
||||
<li>
|
||||
<p>Create a note of type <a class="reference-link" href="#root/_help_HcABDtFCkbFN">Render Note</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Create a child <a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a> note
|
||||
with JSX as the language.
|
||||
<br>As an example, use the following content:</p><pre><code class="language-text-x-trilium-auto">export default function() {
|
||||
@@ -60,17 +59,20 @@ $dateEl.text(new Date());</code></pre>
|
||||
</>
|
||||
);
|
||||
}</code></pre>
|
||||
</li>
|
||||
<li>In the parent render note, define a <code spellcheck="false">~renderNote</code> relation
|
||||
pointing to the newly created child.</li>
|
||||
<li>Refresh the render note and it should display a “Hello world” message.</li>
|
||||
</li>
|
||||
<li>
|
||||
<p>In the parent render note, define a <code spellcheck="false">~renderNote</code> relation
|
||||
pointing to the newly created child.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Refresh the render note and it should display a “Hello world” message.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<h2>Refreshing the note</h2>
|
||||
<p>It's possible to refresh the note via:</p>
|
||||
<ul>
|
||||
<li>The corresponding button in <a class="reference-link" href="#root/_help_XpOYSgsLkTJy">Floating buttons</a>.</li>
|
||||
<li
|
||||
>The “Render active note” <a href="#root/_help_A9Oc6YKKc65v">keyboard shortcut</a> (not
|
||||
<li>The “Render active note” <a href="#root/_help_A9Oc6YKKc65v">keyboard shortcut</a> (not
|
||||
assigned by default).</li>
|
||||
</ul>
|
||||
<h2>Examples</h2>
|
||||
|
||||
@@ -64,9 +64,8 @@
|
||||
yet:</p>
|
||||
<ul>
|
||||
<li>Trilium-specific formulas (e.g. to obtain the title of a note).</li>
|
||||
<li
|
||||
>User-defined formulas</li>
|
||||
<li>Cross-workbook calculation</li>
|
||||
<li>User-defined formulas</li>
|
||||
<li>Cross-workbook calculation</li>
|
||||
</ul>
|
||||
<p>If you would like us to work on these features, consider <a href="https://triliumnotes.org/en/support-us">supporting us</a>.</p>
|
||||
<h2>Known limitations</h2>
|
||||
@@ -81,8 +80,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li>There is currently no export functionality, as stated previously.</li>
|
||||
<li
|
||||
>There is no dedicated mobile support. Mobile support is currently experimental
|
||||
<li>There is no dedicated mobile support. Mobile support is currently experimental
|
||||
in Univer and when it becomes stable, we could potentially integrate it
|
||||
into Trilium as well.</li>
|
||||
</ul>
|
||||
333
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text.html
generated
vendored
@@ -20,171 +20,168 @@
|
||||
<p>Fore more information see <a class="reference-link" href="#root/_help_nRhnJkTT8cPs">Formatting toolbar</a>.</p>
|
||||
<h2>Features and formatting</h2>
|
||||
<p>Here's a list of various features supported by text notes:</p>
|
||||
<figure
|
||||
class="table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dedicated article</th>
|
||||
<th>Feature</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_Gr6xFaF6ioJ5">General formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Headings (section titles, paragraph)</li>
|
||||
<li>Font size</li>
|
||||
<li>Bold, italic, underline, strike-through</li>
|
||||
<li>Superscript, subscript</li>
|
||||
<li>Font color & background color</li>
|
||||
<li>Remove formatting</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_S6Xx8QIWTV66">Lists</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Bulleted lists</li>
|
||||
<li>Numbered lists</li>
|
||||
<li>To-do lists</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NwBbFdNZ9h7O">Block quotes & admonitions</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Block quotes</li>
|
||||
<li>Admonitions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NdowYOC1GFKS">Tables</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Basic tables</li>
|
||||
<li>Merging cells</li>
|
||||
<li>Styling tables and cells.</li>
|
||||
<li>Table captions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_UYuUB1ZekNQU">Developer-specific formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Inline code</li>
|
||||
<li>Code blocks</li>
|
||||
<li>Keyboard shortcuts</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_AgjCISero73a">Footnotes</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Footnotes</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_mT0HEkOsz6i1">Images</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Images</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_QEAPj01N5f7w">Links</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>External links</li>
|
||||
<li>Internal Trilium links</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_nBAXQFj20hS1">Include Note</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Include note</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_CohkqWQC1iBv">Insert buttons</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Symbols</li>
|
||||
<li><a class="reference-link" href="#root/_help_YfYAtQBcfo5V">Math Equations</a>
|
||||
</li>
|
||||
<li>Mermaid diagrams</li>
|
||||
<li>Horizontal ruler</li>
|
||||
<li>Page break</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_dEHYtoWWi8ct">Other features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Indentation
|
||||
<ul>
|
||||
<li>Markdown import</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_2x0ZAX9ePtzV">Cut to subnote</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_gLt3vA97tMcp">Premium features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li><a class="reference-link" href="#root/_help_ZlN4nump6EbW">Slash Commands</a>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_5wZallV2Qo1t">Format Painter</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
<h2>Read-Only vs. Editing Mode</h2>
|
||||
<p>Text notes are usually opened in edit mode. However, they may open in
|
||||
read-only mode if the note is too big or the note is explicitly marked
|
||||
as read-only. For more information, see <a class="reference-link"
|
||||
href="#root/_help_CoFPLs3dRlXc">Read-Only Notes</a>.</p>
|
||||
<h2>Keyboard shortcuts</h2>
|
||||
<p>There are numerous keyboard shortcuts to format the text without having
|
||||
to use the mouse. For a reference of all the key combinations, see
|
||||
<a
|
||||
class="reference-link" href="#root/_help_A9Oc6YKKc65v">Keyboard Shortcuts</a>. In addition, see <a class="reference-link"
|
||||
href="#root/_help_QrtTYPmdd1qq">Markdown-like formatting</a> as an alternative
|
||||
to the keyboard shortcuts.</p>
|
||||
<h2>Technical details</h2>
|
||||
<p>For the text editing functionality, Trilium uses a commercial product
|
||||
(with an open-source base) called <a class="reference-link" href="#root/_help_MI26XDLSAlCD">CKEditor</a>.
|
||||
This brings the benefit of having a powerful WYSIWYG (What You See Is What
|
||||
You Get) editor.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dedicated article</th>
|
||||
<th>Feature</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_Gr6xFaF6ioJ5">General formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Headings (section titles, paragraph)</li>
|
||||
<li>Font size</li>
|
||||
<li>Bold, italic, underline, strike-through</li>
|
||||
<li>Superscript, subscript</li>
|
||||
<li>Font color & background color</li>
|
||||
<li>Remove formatting</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_S6Xx8QIWTV66">Lists</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Bulleted lists</li>
|
||||
<li>Numbered lists</li>
|
||||
<li>To-do lists</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NwBbFdNZ9h7O">Block quotes & admonitions</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Block quotes</li>
|
||||
<li>Admonitions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_NdowYOC1GFKS">Tables</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Basic tables</li>
|
||||
<li>Merging cells</li>
|
||||
<li>Styling tables and cells.</li>
|
||||
<li>Table captions</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_UYuUB1ZekNQU">Developer-specific formatting</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Inline code</li>
|
||||
<li>Code blocks</li>
|
||||
<li>Keyboard shortcuts</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_AgjCISero73a">Footnotes</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Footnotes</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_mT0HEkOsz6i1">Images</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Images</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_QEAPj01N5f7w">Links</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>External links</li>
|
||||
<li>Internal Trilium links</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_nBAXQFj20hS1">Include Note</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Include note</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_CohkqWQC1iBv">Insert buttons</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Symbols</li>
|
||||
<li><a class="reference-link" href="#root/_help_YfYAtQBcfo5V">Math Equations</a>
|
||||
</li>
|
||||
<li>Mermaid diagrams</li>
|
||||
<li>Horizontal ruler</li>
|
||||
<li>Page break</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_dEHYtoWWi8ct">Other features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Indentation
|
||||
<ul>
|
||||
<li>Markdown import</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_2x0ZAX9ePtzV">Cut to subnote</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a class="reference-link" href="#root/_help_gLt3vA97tMcp">Premium features</a>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li><a class="reference-link" href="#root/_help_ZlN4nump6EbW">Slash Commands</a>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_KC1HB96bqqHX">Templates</a>
|
||||
</li>
|
||||
<li><a class="reference-link" href="#root/_help_5wZallV2Qo1t">Format Painter</a>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Read-Only vs. Editing Mode</h2>
|
||||
<p>Text notes are usually opened in edit mode. However, they may open in
|
||||
read-only mode if the note is too big or the note is explicitly marked
|
||||
as read-only. For more information, see <a class="reference-link"
|
||||
href="#root/_help_CoFPLs3dRlXc">Read-Only Notes</a>.</p>
|
||||
<h2>Keyboard shortcuts</h2>
|
||||
<p>There are numerous keyboard shortcuts to format the text without having
|
||||
to use the mouse. For a reference of all the key combinations, see
|
||||
<a
|
||||
class="reference-link" href="#root/_help_A9Oc6YKKc65v">Keyboard Shortcuts</a>. In addition, see <a class="reference-link"
|
||||
href="#root/_help_QrtTYPmdd1qq">Markdown-like formatting</a> as an alternative
|
||||
to the keyboard shortcuts.</p>
|
||||
<h2>Technical details</h2>
|
||||
<p>For the text editing functionality, Trilium uses a commercial product
|
||||
(with an open-source base) called <a class="reference-link" href="#root/_help_MI26XDLSAlCD">CKEditor</a>.
|
||||
This brings the benefit of having a powerful WYSIWYG (What You See Is What
|
||||
You Get) editor.</p>
|
||||
|
Before Width: | Height: | Size: 703 B After Width: | Height: | Size: 703 B |
70
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Anchors.html
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
<aside class="admonition note">
|
||||
<p>This feature used to be called <em>Bookmarks</em> (as it is the official
|
||||
name in the editor we are using), but in order not to collide with the
|
||||
concept of <a class="reference-link" href="#root/_help_u3YFHC9tQlpm">Bookmarks</a>,
|
||||
we have renamed it to <em>Anchors.</em>
|
||||
</p>
|
||||
</aside>
|
||||
<p>Anchors allows creating <a href="#root/_help_QEAPj01N5f7w">links</a> to a certain
|
||||
part of a note, such as referencing a particular heading or section within
|
||||
a note.</p>
|
||||
<p>This feature was introduced in TriliumNext v0.94.0 and augmented in v0.130.0
|
||||
to support linking across notes.</p>
|
||||
<h2>Interaction</h2>
|
||||
<ul>
|
||||
<li>To create a anchor:
|
||||
<ul>
|
||||
<li>Place the cursor at the desired position where to place the anchor.</li>
|
||||
<li>Look for the
|
||||
<img src="Anchors_plus.png"
|
||||
width="15" height="16">button in the <a class="reference-link" href="#root/_help_nRhnJkTT8cPs">Formatting toolbar</a>,
|
||||
and then press the
|
||||
<img src="1_Anchors_plus.png"
|
||||
width="12" height="15">button.</li>
|
||||
<li>Alternatively, use <a class="reference-link" href="#root/_help_ZlN4nump6EbW">Slash Commands</a> and
|
||||
look for <em>anchor</em>.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>To place a link to a anchor:
|
||||
<ul>
|
||||
<li>Place the cursor at the desired position of the link.</li>
|
||||
<li>From the <a href="#root/_help_QEAPj01N5f7w">link</a> pane, select the <em>Anchors</em> section
|
||||
and select the desired anchor.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Linking across notes</h2>
|
||||
<p>Trilium v0.103.0 introduces cross-note Anchors, which makes it possible
|
||||
to create <a class="reference-link" href="#root/_help_hrZ1D00cLbal">Internal (reference) links</a> which
|
||||
point to a specific anchor in that document.</p>
|
||||
<h3>Compatibility with documents from previous versions</h3>
|
||||
<p>For notes created prior to Trilium v0.103.0, you might notice that the
|
||||
Anchors might not be identified. This limitation is intentional in order
|
||||
not to have to re-process all the notes, looking for anchors.</p>
|
||||
<p>To fix this, simply go that note and make any change (e.g. inserting a
|
||||
space), this will trigger the recalculation of the links.</p>
|
||||
<h3>Linking to anchors through the <em>Add link</em> dialog</h3>
|
||||
<ol>
|
||||
<li>Create an anchor in the target note using the same process as described
|
||||
above.</li>
|
||||
<li>In another note, press <kbd>Ctrl</kbd>+<kbd>L</kbd> to insert an internal
|
||||
link. Select the target note containing Anchors.</li>
|
||||
<li>If the target note contains Anchors, a section will appear underneath
|
||||
the note selector with the list of Anchors.</li>
|
||||
<li>Add the link normally.</li>
|
||||
</ol>
|
||||
<p>Clicking on a reference link pointing to a anchor will automatically scroll
|
||||
to the desired section.</p>
|
||||
<h3>Linking to anchors through the bookmark toolbar</h3>
|
||||
<ol>
|
||||
<li>Create an anchor in the target note using the same process as described
|
||||
above.</li>
|
||||
<li>Click on the anchor to reveal the anchor's floating toolbar.</li>
|
||||
<li>Click on the <em>Copy anchor reference link</em> button.</li>
|
||||
<li>Go to the note where to insert the link and press <kbd>Ctrl</kbd>+<kbd>V</kbd>.</li>
|
||||
</ol>
|
||||
<aside class="admonition note">
|
||||
<p>Use this method only to insert <a class="reference-link" href="#root/_help_hrZ1D00cLbal">Internal (reference) links</a> between
|
||||
two documents. To link to an anchor on the same note, use the <em>Insert link</em> dialog
|
||||
(<kbd>Ctrl</kbd>+<kbd>K</kbd>) and select the <em>Anchors</em> item instead.</p>
|
||||
</aside>
|
||||
|
Before Width: | Height: | Size: 636 B After Width: | Height: | Size: 636 B |
31
apps/server/src/assets/doc_notes/en/User Guide/User Guide/Note Types/Text/Bookmarks.html
generated
vendored
@@ -1,31 +0,0 @@
|
||||
<p>Bookmarks allows creating <a href="#root/_help_QEAPj01N5f7w">links</a> to a certain
|
||||
part of a note, such as referencing a particular heading.</p>
|
||||
<p>Technically, bookmarks are HTML anchors.</p>
|
||||
<p>This feature was introduced in TriliumNext 0.94.0.</p>
|
||||
<h2>Interaction</h2>
|
||||
<ul>
|
||||
<li>To create a bookmark:
|
||||
<ul>
|
||||
<li>Place the cursor at the desired position where to place the bookmark.</li>
|
||||
<li>Look for the
|
||||
<img src="Bookmarks_plus.png"
|
||||
width="15" height="16">button in the <a class="reference-link" href="#root/_help_nRhnJkTT8cPs">Formatting toolbar</a>,
|
||||
and then press the
|
||||
<img src="1_Bookmarks_plus.png"
|
||||
width="12" height="15">button.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>To place a link to a bookmark:
|
||||
<ul>
|
||||
<li>Place the cursor at the desired position of the link.</li>
|
||||
<li>From the <a href="#root/_help_QEAPj01N5f7w">link</a> pane, select the <em>Bookmarks</em> section
|
||||
and select the desired bookmark.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Limitations</h2>
|
||||
<ul>
|
||||
<li>Currently it's not possible to create a link to a bookmark from a different
|
||||
note. This functionality will be added after the internal links feature
|
||||
is enhanced to support bookmarks.</li>
|
||||
</ul>
|
||||
@@ -4,7 +4,7 @@
|
||||
reveal special inserable items and blocks such as symbols, Math expressions
|
||||
and separators.</p>
|
||||
<h2>Bookmarks</h2>
|
||||
<p>See the dedicated <a class="reference-link" href="#root/_help_oSuaNgyyKnhu">Bookmarks</a> section.</p>
|
||||
<p>See the dedicated <a class="reference-link" href="#root/_help_oSuaNgyyKnhu">Anchors</a> section.</p>
|
||||
<h2>Emoji</h2>
|
||||
<figure class="image image-style-align-right image_resized" style="width:42.4%;">
|
||||
<img style="aspect-ratio:366/410;" src="Insert buttons_plus.png"
|
||||
|
||||
@@ -382,7 +382,8 @@
|
||||
"migration": {
|
||||
"old_version": "現在のバージョンからの直接的な移行はサポートされていません。まず最新のv0.60.4にアップグレードしてから、このバージョンにアップグレードしてください。",
|
||||
"error_message": "バージョン {{version}} への移行中にエラーが発生しました: {{stack}}",
|
||||
"wrong_db_version": "データベースのバージョン({{version}})は、アプリケーションが想定しているバージョン({{targetVersion}})よりも新しく、互換性のないバージョンによって作成された可能性があります。この問題を解決するには、Triliumを最新バージョンにアップグレードしてください。"
|
||||
"wrong_db_version": "データベースのバージョン({{version}})は、アプリケーションが想定しているバージョン({{targetVersion}})よりも新しく、互換性のないバージョンによって作成された可能性があります。この問題を解決するには、Triliumを最新バージョンにアップグレードしてください。",
|
||||
"invalid_db_version": "データベースのバージョン番号が無効です。これは通常、データベース内の 'dbVersion' オプションが破損していることを示しています。バックアップから復元してください。"
|
||||
},
|
||||
"modals": {
|
||||
"error_title": "エラー"
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
"show-note-source": "顯示筆記來源對話方塊",
|
||||
"show-options": "打開選項頁面",
|
||||
"show-revisions": "顯示筆記歷史版本對話方塊",
|
||||
"show-recent-changes": "顯示最近更改對話方塊",
|
||||
"show-recent-changes": "顯示最近修改對話方塊",
|
||||
"show-sql-console": "打開 SQL 控制台頁面",
|
||||
"show-backend-log": "打開後端日誌頁面",
|
||||
"text-note-operations": "文字筆記操作",
|
||||
@@ -261,7 +261,7 @@
|
||||
"show-note-source": "顯示筆記原始碼",
|
||||
"show-options": "顯示選項",
|
||||
"show-revisions": "顯示歷史版本",
|
||||
"show-recent-changes": "顯示最近更改",
|
||||
"show-recent-changes": "顯示最近修改",
|
||||
"show-sql-console": "顯示 SQL 控制台",
|
||||
"show-backend-log": "顯示後端日誌",
|
||||
"show-help": "顯示說明",
|
||||
|
||||
@@ -85,6 +85,13 @@
|
||||
"reload-frontend-app": "ئالدى تەرەپ ئەپىنى قايتا يۈكلەش",
|
||||
"open-dev-tools": "تەتقىقاتچى قوراللىرىنى ئېچىش",
|
||||
"find-in-text": "تېكىست ئىچىدىن ئىزدەش",
|
||||
"toggle-left-note-tree-panel": "سول تەرەپ (خاتىرە دەرىخى) تاختىسىنى ئالماشتۇرۇش"
|
||||
"toggle-left-note-tree-panel": "سول تەرەپ (خاتىرە دەرىخى) تاختىسىنى ئالماشتۇرۇش",
|
||||
"toggle-full-screen": "پۈتۈن ئېكران شەكلىگە ئالماشتۇرۇش",
|
||||
"zoom-out": "كىچىكلىتىش",
|
||||
"zoom-in": "چوڭايتىش",
|
||||
"note-navigation": "خاتىرە يولباشچىسى",
|
||||
"reset-zoom-level": "چوڭ-كىچىكلىك دەرىجىسىنى ئەسلىگە كەلتۈرۈش",
|
||||
"copy-without-formatting": "تاللانغان تېكىستنى فارماٹسىز كۆچۈرۈش",
|
||||
"force-save-revision": "نۆۋەتتىكى خاتىرىنىڭ يېڭى نەشرىنى مەجبۇرىي قۇرۇش/ساقلاش"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,15 @@ class BAttribute extends AbstractBeccaEntity<BAttribute> {
|
||||
}
|
||||
|
||||
isAutoLink() {
|
||||
return this.type === "relation" && ["internalLink", "imageLink", "relationMapLink", "includeNoteLink"].includes(this.name);
|
||||
if (this.type === "relation") {
|
||||
return ["internalLink", "imageLink", "relationMapLink", "includeNoteLink"].includes(this.name);
|
||||
}
|
||||
|
||||
if (this.type === "label") {
|
||||
return this.name === "internalBookmark";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
get note() {
|
||||
|
||||
@@ -77,7 +77,7 @@ function getAttributeNames(type: string, nameLike: string) {
|
||||
}
|
||||
}
|
||||
|
||||
names = names.filter((name) => !["internalLink", "imageLink", "includeNoteLink", "relationMapLink"].includes(name));
|
||||
names = names.filter((name) => !["internalLink", "imageLink", "includeNoteLink", "relationMapLink", "internalBookmark"].includes(name));
|
||||
|
||||
names.sort((a, b) => {
|
||||
const aPrefix = a.toLowerCase().startsWith(nameLike);
|
||||
|
||||
@@ -50,4 +50,26 @@ describe("sanitize", () => {
|
||||
</figure>`;
|
||||
expect(html_sanitizer.sanitize(dirty)).toBe(clean);
|
||||
});
|
||||
|
||||
describe("bookmark anchors", () => {
|
||||
it("preserves id attribute on empty <a> tags (CKEditor bookmarks)", () => {
|
||||
const dirty = `<a id="my-bookmark"></a>`;
|
||||
expect(html_sanitizer.sanitize(dirty)).toBe(dirty);
|
||||
});
|
||||
|
||||
it("preserves id attribute on <a> tags with bookmark class", () => {
|
||||
const dirty = `<a id="chapter-1" class="ck-bookmark"></a>`;
|
||||
expect(html_sanitizer.sanitize(dirty)).toBe(dirty);
|
||||
});
|
||||
|
||||
it("strips id attribute from non-anchor tags to prevent DOM clobbering", () => {
|
||||
const dirty = `<div id="loginForm">content</div>`;
|
||||
expect(html_sanitizer.sanitize(dirty)).toBe(`<div>content</div>`);
|
||||
});
|
||||
|
||||
it("strips id attribute from <img> tags to prevent DOM clobbering", () => {
|
||||
const dirty = `<img id="someId" src="test.png" />`;
|
||||
expect(html_sanitizer.sanitize(dirty)).toBe(`<img src="test.png" />`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,6 +42,7 @@ function sanitize(dirtyHtml: string) {
|
||||
allowedTags: allowedTags as string[],
|
||||
allowedAttributes: {
|
||||
"*": ["class", "style", "title", "src", "href", "hash", "disabled", "align", "alt", "center", "data-*"],
|
||||
a: ["id"], // CKEditor bookmark anchors use <a id="name"></a>
|
||||
input: ["type", "checked"],
|
||||
img: ["width", "height"],
|
||||
code: [ "spellcheck" ]
|
||||
|
||||
42
apps/server/src/services/notes.spec.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { findBookmarks } from "./notes.js";
|
||||
|
||||
describe("findBookmarks", () => {
|
||||
it("extracts bookmark IDs from empty anchor tags", () => {
|
||||
const content = `<p>Hello</p><a id="chapter-1"></a><p>World</p>`;
|
||||
expect(findBookmarks(content)).toEqual(["chapter-1"]);
|
||||
});
|
||||
|
||||
it("extracts multiple bookmarks", () => {
|
||||
const content = `<a id="intro"></a><p>Text</p><a id="conclusion"></a>`;
|
||||
expect(findBookmarks(content)).toEqual(["intro", "conclusion"]);
|
||||
});
|
||||
|
||||
it("returns empty array when no bookmarks exist", () => {
|
||||
const content = `<p>No bookmarks here</p>`;
|
||||
expect(findBookmarks(content)).toEqual([]);
|
||||
});
|
||||
|
||||
it("ignores anchor tags with href (regular links, not bookmarks)", () => {
|
||||
const content = `<a href="#root/abc123" id="some-id">link</a>`;
|
||||
expect(findBookmarks(content)).toEqual([]);
|
||||
});
|
||||
|
||||
it("handles bookmarks with various valid ID characters", () => {
|
||||
const content = `<a id="my_bookmark-2.0"></a>`;
|
||||
expect(findBookmarks(content)).toEqual(["my_bookmark-2.0"]);
|
||||
});
|
||||
|
||||
it("does not produce duplicates", () => {
|
||||
const content = `<a id="same"></a><a id="same"></a>`;
|
||||
expect(findBookmarks(content)).toEqual(["same"]);
|
||||
});
|
||||
|
||||
it("matches self-closing bookmark anchors (CKEditor empty elements)", () => {
|
||||
const content = `<p>Text</p><a id="my-bookmark"></a><p>More</p>`;
|
||||
// CKEditor may also output without closing tag
|
||||
const contentNoClose = `<p>Text</p><a id="my-bookmark"><p>More</p>`;
|
||||
expect(findBookmarks(content)).toEqual(["my-bookmark"]);
|
||||
expect(findBookmarks(contentNoClose)).toEqual(["my-bookmark"]);
|
||||
});
|
||||
});
|
||||
@@ -454,6 +454,54 @@ function findImageLinks(content: string, foundLinks: FoundLink[]) {
|
||||
return content.replace(/src="[^"]*\/api\/images\//g, 'src="api/images/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts bookmark IDs from CKEditor bookmark anchors (`<a id="..."></a>` without href).
|
||||
* Bookmarks are stored as labels on the note so they can be looked up without parsing content.
|
||||
*/
|
||||
export function findBookmarks(content: string): string[] {
|
||||
const re = /<a\s+id="([^"]+)"[^>]*>(<\/a>)?/g;
|
||||
const bookmarks: string[] = [];
|
||||
let match;
|
||||
|
||||
while ((match = re.exec(content))) {
|
||||
// Skip anchors that also have an href (those are regular links, not bookmarks)
|
||||
if (match[0].includes("href=")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const id = match[1];
|
||||
if (!bookmarks.includes(id)) {
|
||||
bookmarks.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
function saveBookmarks(note: BNote, content: string) {
|
||||
const foundBookmarks = findBookmarks(content);
|
||||
const existingBookmarks = note.getOwnedLabels("internalBookmark");
|
||||
|
||||
for (const bookmarkId of foundBookmarks) {
|
||||
const existing = existingBookmarks.find((l) => l.value === bookmarkId);
|
||||
|
||||
if (!existing) {
|
||||
new BAttribute({
|
||||
noteId: note.noteId,
|
||||
type: "label",
|
||||
name: "internalBookmark",
|
||||
value: bookmarkId
|
||||
}).save();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove bookmarks that are no longer in the content
|
||||
const unusedBookmarks = existingBookmarks.filter((l) => !foundBookmarks.includes(l.value));
|
||||
for (const unused of unusedBookmarks) {
|
||||
unused.markAsDeleted();
|
||||
}
|
||||
}
|
||||
|
||||
function findInternalLinks(content: string, foundLinks: FoundLink[]) {
|
||||
const re = /href="[^"]*#root[a-zA-Z0-9_\/]*\/([a-zA-Z0-9_]+)\/?"/g;
|
||||
let match;
|
||||
@@ -695,6 +743,7 @@ function saveLinks(note: BNote, content: string | Buffer) {
|
||||
content = findImageLinks(content, foundLinks);
|
||||
content = findInternalLinks(content, foundLinks);
|
||||
content = findIncludeNoteLinks(content, foundLinks);
|
||||
saveBookmarks(note, content);
|
||||
|
||||
({ forceFrontendReload, content } = checkImageAttachments(note, content));
|
||||
} else if (note.type === "relationMap" && typeof content === "string") {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"packageManager": "pnpm@10.33.0",
|
||||
"devDependencies": {
|
||||
"@wxt-dev/auto-icons": "1.1.1",
|
||||
"wxt": "0.20.21"
|
||||
"wxt": "0.20.22"
|
||||
},
|
||||
"dependencies": {
|
||||
"cash-dom": "8.1.5"
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"preact": "10.29.1",
|
||||
"preact-iso": "2.11.1",
|
||||
"preact-render-to-string": "6.6.7",
|
||||
"react-i18next": "17.0.2"
|
||||
"react-i18next": "17.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "2.10.5",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Documentation
|
||||
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/1ysfcELr4Xua/Documentation_image.png" width="205" height="162">
|
||||
There are multiple types of documentation for Trilium:<img class="image-style-align-right" src="api/images/BZVD2exxpGnn/Documentation_image.png" width="205" height="162">
|
||||
|
||||
* The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing <kbd>F1</kbd>.
|
||||
* The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers.
|
||||
|
||||
2
docs/README-ja.md
vendored
@@ -63,7 +63,7 @@ Trilium Notes
|
||||
|
||||
* ノートは任意の深さのツリーに配置できます。1つのノートをツリー内の複数の場所に配置できます([クローン](https://docs.triliumnotes.org/user-guide/concepts/notes/cloning)を参照)
|
||||
* 豊富な WYSIWYG ノートエディター 例:
|
||||
表、画像、[数式](https://docs.triliumnotes.org/user-guide/note-types/text) とマークダウン
|
||||
表、画像、[数式](https://docs.triliumnotes.org/user-guide/note-types/text) と markdown
|
||||
[自動フォーマット](https://docs.triliumnotes.org/user-guide/note-types/text/markdown-formatting)
|
||||
など
|
||||
* 構文ハイライト表示を含む
|
||||
|
||||
31
docs/README-ug.md
vendored
@@ -285,23 +285,24 @@ pnpm run --filter desktop electron-forge:make --arch=x64 --platform=win32
|
||||
|
||||
### تەتقىقاتچى ھۆججەتلىرى
|
||||
|
||||
Please view the [documentation
|
||||
guide](https://github.com/TriliumNext/Trilium/blob/main/docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md)
|
||||
for details. If you have more questions, feel free to reach out via the links
|
||||
described in the "Discuss with us" section above.
|
||||
تەپسىلاتلار ئۈچۈن [ھۆججەت
|
||||
يېتەكچىسى](https://github.com/TriliumNext/Trilium/blob/main/docs/Developer%20Guide/Developer%20Guide/Environment%20Setup.md)گە
|
||||
قاراڭ. ئەگەر تېخىمۇ كۆپ سوئاللىرىڭىز بولسا، ئۈستىدىكى "بىز بىلەن ئالاقىلىشىڭ"
|
||||
بۆلىكىدە تەمىنلەنگەن ئۇلىنىشلار ئارقىلىق بىز بىلەن ئالاقىلىشىڭنى قارشى ئالىمىز.
|
||||
|
||||
## 👏 Shoutouts
|
||||
## 👏 مىننەتدارلىق
|
||||
|
||||
* [zadam](https://github.com/zadam) for the original concept and implementation
|
||||
of the application.
|
||||
* [Sarah Hussein](https://github.com/Sarah-Hussein) for designing the
|
||||
application icon.
|
||||
* [nriver](https://github.com/nriver) for his work on internationalization.
|
||||
* [Thomas Frei](https://github.com/thfrei) for his original work on the Canvas.
|
||||
* [antoniotejada](https://github.com/nriver) for the original syntax highlight
|
||||
widget.
|
||||
* [Dosu](https://dosu.dev/) for providing us with the automated responses to
|
||||
GitHub issues and discussions.
|
||||
* ئەپنىڭ ئەسلى ئۇقۇم لاھىيەسى ۋە ئەمەلگە ئاشۇرۇلۇشىغا تۆھپە قوشقان
|
||||
[zadam](https://github.com/zadam).
|
||||
* ئەپ سىنبەلگىسىنى لاھىيەلىگەن [Sarah
|
||||
Hussein](https://github.com/Sarah-Hussein).
|
||||
* خەلقئارالاشتۇرۇش خىزمىتىگە تۆھپە قوشقان [nriver](https://github.com/nriver).
|
||||
* Canvas جەھەتتىكى ئەسلى ئىجادىي خىزمەتلىرى ئۈچۈن [Thomas
|
||||
Frei](https://github.com/thfrei).
|
||||
* ئەسلى گرامماتىكا گەۋدىلەندۈرۈش كىچىك زاپچاسلارنى ئاپتورى
|
||||
[antoniotejada](https://github.com/nriver).
|
||||
* GitHub مەسىلىلىرى ۋە مۇنازىرىلىرىگە ئاپتوماتىك جاۋاب قايتۇرۇش بىلەن تەمىنلىگەن
|
||||
[Dosu](https://dosu.dev/).
|
||||
* [Tabler Icons](https://tabler.io/icons) for the system tray icons.
|
||||
|
||||
Trilium would not be possible without the technologies behind it:
|
||||
|
||||
365
docs/User Guide/!!!meta.json
vendored
@@ -3984,42 +3984,42 @@
|
||||
"name": "internalLink",
|
||||
"value": "s1aBHPd79XYj",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "6RM1Q7ppFVoj",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "CoFPLs3dRlXc",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "8YBEPzcpUgxw",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "IjZS7iK5EXtb",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "XpOYSgsLkTJy",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "CoFPLs3dRlXc",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
@@ -7188,6 +7188,93 @@
|
||||
],
|
||||
"dirFileName": "Text",
|
||||
"children": [
|
||||
{
|
||||
"isClone": false,
|
||||
"noteId": "oSuaNgyyKnhu",
|
||||
"notePath": [
|
||||
"pOsGYCXsbNQG",
|
||||
"KSZ04uQ2D1St",
|
||||
"iPIMuisry3hd",
|
||||
"oSuaNgyyKnhu"
|
||||
],
|
||||
"title": "Anchors",
|
||||
"notePosition": 10,
|
||||
"prefix": null,
|
||||
"isExpanded": false,
|
||||
"type": "text",
|
||||
"mime": "text/html",
|
||||
"attributes": [
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "u3YFHC9tQlpm",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "QEAPj01N5f7w",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "nRhnJkTT8cPs",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "ZlN4nump6EbW",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "hrZ1D00cLbal",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "iconClass",
|
||||
"value": "bx bx-bookmark",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
"value": "bookmarks",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
"dataFileName": "Anchors.md",
|
||||
"attachments": [
|
||||
{
|
||||
"attachmentId": "2cn9iY3Qgyjs",
|
||||
"title": "plus.png",
|
||||
"role": "image",
|
||||
"mime": "image/png",
|
||||
"position": 10,
|
||||
"dataFileName": "Anchors_plus.png"
|
||||
},
|
||||
{
|
||||
"attachmentId": "JaiAT3dHDIyy",
|
||||
"title": "plus.png",
|
||||
"role": "image",
|
||||
"mime": "image/png",
|
||||
"position": 10,
|
||||
"dataFileName": "1_Anchors_plus.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"isClone": false,
|
||||
"noteId": "NwBbFdNZ9h7O",
|
||||
@@ -7198,7 +7285,7 @@
|
||||
"NwBbFdNZ9h7O"
|
||||
],
|
||||
"title": "Block quotes & admonitions",
|
||||
"notePosition": 10,
|
||||
"notePosition": 20,
|
||||
"prefix": null,
|
||||
"isExpanded": false,
|
||||
"type": "text",
|
||||
@@ -7262,72 +7349,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"isClone": false,
|
||||
"noteId": "oSuaNgyyKnhu",
|
||||
"notePath": [
|
||||
"pOsGYCXsbNQG",
|
||||
"KSZ04uQ2D1St",
|
||||
"iPIMuisry3hd",
|
||||
"oSuaNgyyKnhu"
|
||||
],
|
||||
"title": "Bookmarks",
|
||||
"notePosition": 20,
|
||||
"prefix": null,
|
||||
"isExpanded": false,
|
||||
"type": "text",
|
||||
"mime": "text/html",
|
||||
"attributes": [
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "QEAPj01N5f7w",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "nRhnJkTT8cPs",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "iconClass",
|
||||
"value": "bx bx-bookmark",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
"value": "bookmarks",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
"dataFileName": "Bookmarks.md",
|
||||
"attachments": [
|
||||
{
|
||||
"attachmentId": "2cn9iY3Qgyjs",
|
||||
"title": "plus.png",
|
||||
"role": "image",
|
||||
"mime": "image/png",
|
||||
"position": 10,
|
||||
"dataFileName": "Bookmarks_plus.png"
|
||||
},
|
||||
{
|
||||
"attachmentId": "JaiAT3dHDIyy",
|
||||
"title": "plus.png",
|
||||
"role": "image",
|
||||
"mime": "image/png",
|
||||
"position": 10,
|
||||
"dataFileName": "1_Bookmarks_plus.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"isClone": false,
|
||||
"noteId": "veGu4faJErEM",
|
||||
@@ -10147,17 +10168,24 @@
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "XpOYSgsLkTJy",
|
||||
"value": "SL5f1Auq7sVN",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "0Ofbk1aSuVRu",
|
||||
"value": "XpOYSgsLkTJy",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "0Ofbk1aSuVRu",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "shareAlias",
|
||||
@@ -10171,13 +10199,6 @@
|
||||
"value": "bx bx-selection",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "SL5f1Auq7sVN",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
@@ -10839,6 +10860,90 @@
|
||||
"type": "text",
|
||||
"mime": "text/html",
|
||||
"attributes": [
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "Oau6X9rCuegd",
|
||||
"isInheritable": false,
|
||||
"position": 10
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "iPIMuisry3hd",
|
||||
"isInheritable": false,
|
||||
"position": 20
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "6f9hih2hXXZk",
|
||||
"isInheritable": false,
|
||||
"position": 30
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "SL5f1Auq7sVN",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "NwBbFdNZ9h7O",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "YfYAtQBcfo5V",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "s1aBHPd79XYj",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "nBAXQFj20hS1",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "hrZ1D00cLbal",
|
||||
"isInheritable": false,
|
||||
"position": 90
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "m1lbrzyKDaRB",
|
||||
"isInheritable": false,
|
||||
"position": 100
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "oPVyFC7WL2Lp",
|
||||
"isInheritable": false,
|
||||
"position": 110
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "wy8So3yZZlH9",
|
||||
"isInheritable": false,
|
||||
"position": 120
|
||||
},
|
||||
{
|
||||
"type": "label",
|
||||
"name": "iconClass",
|
||||
@@ -10852,90 +10957,6 @@
|
||||
"value": "markdown",
|
||||
"isInheritable": false,
|
||||
"position": 40
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "Oau6X9rCuegd",
|
||||
"isInheritable": false,
|
||||
"position": 50
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "iPIMuisry3hd",
|
||||
"isInheritable": false,
|
||||
"position": 60
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "6f9hih2hXXZk",
|
||||
"isInheritable": false,
|
||||
"position": 70
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "oPVyFC7WL2Lp",
|
||||
"isInheritable": false,
|
||||
"position": 80
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "wy8So3yZZlH9",
|
||||
"isInheritable": false,
|
||||
"position": 150
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "SL5f1Auq7sVN",
|
||||
"isInheritable": false,
|
||||
"position": 160
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "NwBbFdNZ9h7O",
|
||||
"isInheritable": false,
|
||||
"position": 170
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "YfYAtQBcfo5V",
|
||||
"isInheritable": false,
|
||||
"position": 180
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "s1aBHPd79XYj",
|
||||
"isInheritable": false,
|
||||
"position": 190
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "nBAXQFj20hS1",
|
||||
"isInheritable": false,
|
||||
"position": 200
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "hrZ1D00cLbal",
|
||||
"isInheritable": false,
|
||||
"position": 210
|
||||
},
|
||||
{
|
||||
"type": "relation",
|
||||
"name": "internalLink",
|
||||
"value": "m1lbrzyKDaRB",
|
||||
"isInheritable": false,
|
||||
"position": 220
|
||||
}
|
||||
],
|
||||
"format": "markdown",
|
||||
|
||||
@@ -99,12 +99,15 @@ To do so:
|
||||
For example, to change the font of the document from the one defined by the theme or the user to a serif one:
|
||||
|
||||
```
|
||||
body {
|
||||
--main-font-family: serif !important;
|
||||
--detail-font-family: var(--main-font-family) !important;
|
||||
body {
|
||||
--print-font-family: serif;
|
||||
--print-font-size: 11pt;
|
||||
}
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> When altering `--print-font-family`, make sure the change is done at `body` level and not `:root`, since otherwise it won't be picked up due to specificity rules.
|
||||
|
||||
To remark:
|
||||
|
||||
* Multiple CSS notes can be add by using multiple `~printCss` relations.
|
||||
|
||||
@@ -77,6 +77,12 @@ TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data trilium
|
||||
|
||||
You can then save the above command as a shell script on your path for convenience.
|
||||
|
||||
## Electron user data directory (desktop only)
|
||||
|
||||
When running the desktop application, Electron stores internal data (caches, spell-check dictionaries, session storage, etc.) separately from the Trilium data directory. By default this goes to the system's application data folder (e.g. `%APPDATA%` on Windows), which may be undesirable in corporate environments with roaming profiles or when running in portable mode.
|
||||
|
||||
To keep Electron data out of the system's roaming profile, set the `TRILIUM_ELECTRON_DATA_DIR` environment variable to an explicit path. The `trilium-portable` script does this automatically, pointing it to `trilium-electron-data/` next to the application.
|
||||
|
||||
## Fine-grained directory/path location
|
||||
|
||||
Apart from the data directory, some of the subdirectories of it can be moved elsewhere by changing an environment variable:
|
||||
@@ -88,4 +94,5 @@ Apart from the data directory, some of the subdirectories of it can be moved els
|
||||
| `TRILIUM_LOG_DIR` | `${TRILIUM_DATA_DIR}/log` | Directory where daily <a class="reference-link" href="../Troubleshooting/Error%20logs/Backend%20(server)%20logs.md">Backend (server) logs</a> are stored. |
|
||||
| `TRILIUM_TMP_DIR` | `${TRILIUM_DATA_DIR}/tmp` | Directory where temporary files are stored (for example when opening in an external app). |
|
||||
| `TRILIUM_ANONYMIZED_DB_DIR` | `${TRILIUM_DATA_DIR}/anonymized-db` | Directory where a <a class="reference-link" href="../Troubleshooting/Anonymized%20Database.md">Anonymized Database</a> is stored. |
|
||||
| `TRILIUM_CONFIG_INI_PATH` | `${TRILIUM_DATA_DIR}/config.ini` | Path to <a class="reference-link" href="../Advanced%20Usage/Configuration%20(config.ini%20or%20e.md">Configuration (config.ini or environment variables)</a> file. |
|
||||
| `TRILIUM_CONFIG_INI_PATH` | `${TRILIUM_DATA_DIR}/config.ini` | Path to <a class="reference-link" href="../Advanced%20Usage/Configuration%20(config.ini%20or%20e.md">Configuration (config.ini or environment variables)</a> file. |
|
||||
| `TRILIUM_ELECTRON_DATA_DIR` | System appData | Directory for Electron internal data (caches, spell-check dictionaries, etc.). Set this in portable mode to avoid writing to the system profile (desktop only). |
|
||||
@@ -11,7 +11,7 @@ Trilium offers various startup scripts to customize your experience:
|
||||
|
||||
* `trilium-no-cert-check`: Starts Trilium without validating [TLS certificates](Server%20Installation/HTTPS%20\(TLS\).md), useful if connecting to a server with a self-signed certificate.
|
||||
* Alternatively, set the `NODE_TLS_REJECT_UNAUTHORIZED=0` environment variable before starting Trilium.
|
||||
* `trilium-portable`: Launches Trilium in portable mode, where the [data directory](Data%20directory.md) is created within the application's directory, making it easy to move the entire setup.
|
||||
* `trilium-portable`: Launches Trilium in portable mode, where the [data directory](Data%20directory.md) is created within the application's directory, making it easy to move the entire setup. Electron's internal data (caches, dictionaries, etc.) is also stored within the data directory, so no files are written to the system's roaming profile.
|
||||
* `trilium-safe-mode`: Boots Trilium in "safe mode," disabling any startup scripts that might cause the application to crash.
|
||||
|
||||
## Synchronization
|
||||
|
||||
@@ -33,7 +33,7 @@ The following features are supported by Trilium's Markdown format and will show
|
||||
|
||||
```
|
||||
<section class="include-note" data-note-id="vJDjQm0VK8Na" data-box-size="expandable">
|
||||
|
||||
|
||||
</section>n
|
||||
```
|
||||
* <a class="reference-link" href="Text/Links/Internal%20(reference)%20links.md">Internal (reference) links</a> via its HTML syntax, or through a _Wikilinks_\-like format (only <a class="reference-link" href="../Advanced%20Usage/Note%20ID.md">Note ID</a>):
|
||||
@@ -55,7 +55,6 @@ There are two ways to create a Markdown note:
|
||||
## Import/export
|
||||
|
||||
* By default, when importing a single Markdown file it automatically gets converted to a <a class="reference-link" href="Text.md">Text</a> note. To avoid that and have it imported as a Markdown note instead:
|
||||
|
||||
* Right click the <a class="reference-link" href="../Basic%20Concepts%20and%20Features/UI%20Elements/Note%20Tree.md">Note Tree</a> and select _Import into note_.
|
||||
* Select the file normally.
|
||||
* Uncheck _Import HTML, Markdown and TXT as text notes if it's unclear from the metadata_.
|
||||
|
||||
|
Before Width: | Height: | Size: 703 B After Width: | Height: | Size: 703 B |
46
docs/User Guide/User Guide/Note Types/Text/Anchors.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# Anchors
|
||||
> [!NOTE]
|
||||
> This feature used to be called _Bookmarks_ (as it is the official name in the editor we are using), but in order not to collide with the concept of <a class="reference-link" href="../../Basic%20Concepts%20and%20Features/Navigation/Bookmarks.md">Bookmarks</a>, we have renamed it to _Anchors._
|
||||
|
||||
Anchors allows creating [links](Links.md) to a certain part of a note, such as referencing a particular heading or section within a note.
|
||||
|
||||
This feature was introduced in TriliumNext v0.94.0 and augmented in v0.130.0 to support linking across notes.
|
||||
|
||||
## Interaction
|
||||
|
||||
* To create a anchor:
|
||||
* Place the cursor at the desired position where to place the anchor.
|
||||
* Look for the <img src="Anchors_plus.png" width="15" height="16"> button in the <a class="reference-link" href="Formatting%20toolbar.md">Formatting toolbar</a>, and then press the <img src="1_Anchors_plus.png" width="12" height="15"> button.
|
||||
* Alternatively, use <a class="reference-link" href="Premium%20features/Slash%20Commands.md">Slash Commands</a> and look for _anchor_.
|
||||
* To place a link to a anchor:
|
||||
* Place the cursor at the desired position of the link.
|
||||
* From the [link](Links.md) pane, select the _Anchors_ section and select the desired anchor.
|
||||
|
||||
## Linking across notes
|
||||
|
||||
Trilium v0.103.0 introduces cross-note Anchors, which makes it possible to create <a class="reference-link" href="Links/Internal%20(reference)%20links.md">Internal (reference) links</a> which point to a specific anchor in that document.
|
||||
|
||||
### Compatibility with documents from previous versions
|
||||
|
||||
For notes created prior to Trilium v0.103.0, you might notice that the Anchors might not be identified. This limitation is intentional in order not to have to re-process all the notes, looking for anchors.
|
||||
|
||||
To fix this, simply go that note and make any change (e.g. inserting a space), this will trigger the recalculation of the links.
|
||||
|
||||
### Linking to anchors through the _Add link_ dialog
|
||||
|
||||
1. Create an anchor in the target note using the same process as described above.
|
||||
2. In another note, press <kbd>Ctrl</kbd>+<kbd>L</kbd> to insert an internal link. Select the target note containing Anchors.
|
||||
3. If the target note contains Anchors, a section will appear underneath the note selector with the list of Anchors.
|
||||
4. Add the link normally.
|
||||
|
||||
Clicking on a reference link pointing to a anchor will automatically scroll to the desired section.
|
||||
|
||||
### Linking to anchors through the bookmark toolbar
|
||||
|
||||
1. Create an anchor in the target note using the same process as described above.
|
||||
2. Click on the anchor to reveal the anchor's floating toolbar.
|
||||
3. Click on the _Copy anchor reference link_ button.
|
||||
4. Go to the note where to insert the link and press <kbd>Ctrl</kbd>+<kbd>V</kbd>.
|
||||
|
||||
> [!NOTE]
|
||||
> Use this method only to insert <a class="reference-link" href="Links/Internal%20(reference)%20links.md">Internal (reference) links</a> between two documents. To link to an anchor on the same note, use the _Insert link_ dialog (<kbd>Ctrl</kbd>+<kbd>K</kbd>) and select the _Anchors_ item instead.
|
||||
|
Before Width: | Height: | Size: 636 B After Width: | Height: | Size: 636 B |
@@ -1,19 +0,0 @@
|
||||
# Bookmarks
|
||||
Bookmarks allows creating [links](Links.md) to a certain part of a note, such as referencing a particular heading.
|
||||
|
||||
Technically, bookmarks are HTML anchors.
|
||||
|
||||
This feature was introduced in TriliumNext 0.94.0.
|
||||
|
||||
## Interaction
|
||||
|
||||
* To create a bookmark:
|
||||
* Place the cursor at the desired position where to place the bookmark.
|
||||
* Look for the <img src="Bookmarks_plus.png" width="15" height="16"> button in the <a class="reference-link" href="Formatting%20toolbar.md">Formatting toolbar</a>, and then press the <img src="1_Bookmarks_plus.png" width="12" height="15"> button.
|
||||
* To place a link to a bookmark:
|
||||
* Place the cursor at the desired position of the link.
|
||||
* From the [link](Links.md) pane, select the _Bookmarks_ section and select the desired bookmark.
|
||||
|
||||
## Limitations
|
||||
|
||||
* Currently it's not possible to create a link to a bookmark from a different note. This functionality will be added after the internal links feature is enhanced to support bookmarks.
|
||||
@@ -3,7 +3,7 @@ Press the <img src="4_Insert buttons_image.png" width="34" height="16"> button i
|
||||
|
||||
## Bookmarks
|
||||
|
||||
See the dedicated <a class="reference-link" href="Bookmarks.md">Bookmarks</a> section.
|
||||
See the dedicated <a class="reference-link" href="Anchors.md">Anchors</a> section.
|
||||
|
||||
## Emoji
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ import internalLinkIcon from './icons/trilium.svg?raw';
|
||||
import noteIcon from './icons/note.svg?raw';
|
||||
import importMarkdownIcon from './icons/markdown-mark.svg?raw';
|
||||
import { icons as mathIcons, MathUI } from '@triliumnext/ckeditor5-math';
|
||||
import { BookmarkUI } from "ckeditor5";
|
||||
import bxBookmark from "boxicons/svg/regular/bx-bookmark.svg?raw";
|
||||
|
||||
type SlashCommandDefinition = SlashCommandEditorConfig["extraCommands"][number];
|
||||
|
||||
@@ -74,6 +76,19 @@ export default function buildExtraCommands(): SlashCommandDefinition[] {
|
||||
description: "Import a markdown file into this note",
|
||||
icon: importMarkdownIcon,
|
||||
commandName: MARKDOWN_IMPORT_COMMAND
|
||||
},
|
||||
{
|
||||
id: "anchor",
|
||||
title: "Anchor",
|
||||
description: "Insert an anchor for internal linking",
|
||||
aliases: [ "bookmark" ],
|
||||
icon: bxBookmark,
|
||||
execute: (editor: Editor) => {
|
||||
// Defer to the next event loop tick so the slash command fully finishes
|
||||
// its DOM/selection cleanup; _showFormView needs the view and mapper to
|
||||
// be in a settled state for balloon positioning.
|
||||
setTimeout(() => (editor.plugins.get(BookmarkUI) as any)._showFormView(), 0);
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { Mermaid } from "@triliumnext/ckeditor5-mermaid";
|
||||
import { Admonition } from "@triliumnext/ckeditor5-admonition";
|
||||
import { Footnotes } from "@triliumnext/ckeditor5-footnotes";
|
||||
import { Math, AutoformatMath } from "@triliumnext/ckeditor5-math";
|
||||
import CopyAnchorLinkButton from "./plugins/copy_anchor_link.js";
|
||||
|
||||
// import "@triliumnext/ckeditor5-mermaid/index.css";
|
||||
// import "@triliumnext/ckeditor5-admonition/index.css";
|
||||
@@ -63,6 +64,7 @@ const TRILIUM_PLUGINS: typeof Plugin[] = [
|
||||
AdmonitionToolbar,
|
||||
IncludeNoteBoxSizeDropdown,
|
||||
IncludeNoteToolbar,
|
||||
CopyAnchorLinkButton,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
51
packages/ckeditor5/src/plugins/copy_anchor_link.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { ButtonView, Plugin } from "ckeditor5";
|
||||
import copyIcon from "../icons/copy.svg?raw";
|
||||
import { escapeHtml } from "../utils";
|
||||
|
||||
/**
|
||||
* Adds a "Copy anchor link" button to the bookmark/anchor widget toolbar.
|
||||
* When clicked, copies a reference link href (e.g. `#root/noteId?bookmark=anchorName`)
|
||||
* to the clipboard.
|
||||
*/
|
||||
export default class CopyAnchorLinkButton extends Plugin {
|
||||
|
||||
public init() {
|
||||
const editor = this.editor;
|
||||
|
||||
editor.ui.componentFactory.add("copyAnchorLink", (locale) => {
|
||||
const button = new ButtonView(locale);
|
||||
const t = locale.t;
|
||||
|
||||
button.set({
|
||||
label: t("Copy anchor reference link"),
|
||||
icon: copyIcon,
|
||||
tooltip: true
|
||||
});
|
||||
|
||||
this.listenTo(button, "execute", () => {
|
||||
const selection = editor.model.document.selection;
|
||||
const selectedElement = selection.getSelectedElement();
|
||||
|
||||
if (selectedElement?.name === "bookmark") {
|
||||
const bookmarkId = selectedElement.getAttribute("bookmarkId") as string;
|
||||
const noteId = glob.getActiveContextNote()?.noteId;
|
||||
|
||||
if (noteId && bookmarkId) {
|
||||
const href = `#root/${noteId}?bookmark=${encodeURIComponent(bookmarkId)}`;
|
||||
const title = glob.getReferenceLinkTitleSync(href);
|
||||
const html = `<a class="reference-link" href="${escapeHtml(href)}">${escapeHtml(title)}</a>`;
|
||||
navigator.clipboard.write([
|
||||
new ClipboardItem({
|
||||
"text/html": new Blob([html], { type: "text/html" }),
|
||||
"text/plain": new Blob([href], { type: "text/plain" })
|
||||
})
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return button;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,16 @@ window.CKEDITOR_TRANSLATIONS = {
|
||||
en: {
|
||||
dictionary: {
|
||||
"Insert template": "Insert text snippet",
|
||||
"Search template": "Search text snippet"
|
||||
"Search template": "Search text snippet",
|
||||
"Bookmark": "Anchor",
|
||||
"Bookmarks": "Anchors",
|
||||
"Bookmark name": "Anchor name",
|
||||
"Bookmark must not be empty.": "Anchor name must not be empty.",
|
||||
"Bookmark name already exists.": "Anchor name already exists.",
|
||||
"Bookmark name cannot contain space characters.": "Anchor name cannot contain space characters.",
|
||||
"Edit bookmark": "Edit anchor",
|
||||
"Enter the bookmark name without spaces.": "Enter the anchor name without spaces.",
|
||||
"Bookmark toolbar": "Anchor toolbar"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { DifferItemAttribute, Editor, ModelDocumentFragment, ModelElement, ModelNode } from "ckeditor5";
|
||||
|
||||
export function escapeHtml(str: string): string {
|
||||
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
||||
}
|
||||
|
||||
function hasHeadingAncestor(node: ModelElement | ModelNode | ModelDocumentFragment | null): boolean {
|
||||
let current: ModelElement | ModelNode | ModelDocumentFragment | null = node;
|
||||
while (current) {
|
||||
|
||||
@@ -91,6 +91,7 @@ export default [
|
||||
{ type: "label", name: "printPageSize" },
|
||||
{ type: "label", name: "printScale" },
|
||||
{ type: "label", name: "printMargins" },
|
||||
{ type: "label", name: "internalBookmark" },
|
||||
|
||||
// relation names
|
||||
{ type: "relation", name: "internalLink" },
|
||||
|
||||
85
packages/commons/src/lib/markdown_renderer.spec.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { extractCodeBlocks } from "./markdown_renderer.js";
|
||||
|
||||
describe("extractCodeBlocks", () => {
|
||||
it("should extract a fenced code block", () => {
|
||||
const input = "before\n```js\nconsole.log('hi');\n```\nafter";
|
||||
const { processedText, placeholderMap } = extractCodeBlocks(input);
|
||||
|
||||
expect(placeholderMap.size).toBe(1);
|
||||
expect(processedText).toContain("before\n");
|
||||
expect(processedText).toContain("\nafter");
|
||||
expect(processedText).not.toContain("```");
|
||||
|
||||
const placeholder = [...placeholderMap.keys()][0];
|
||||
expect(placeholderMap.get(placeholder)).toBe("```js\nconsole.log('hi');\n```");
|
||||
});
|
||||
|
||||
it("should extract inline code", () => {
|
||||
const input = "use `console.log` here";
|
||||
const { processedText, placeholderMap } = extractCodeBlocks(input);
|
||||
|
||||
expect(placeholderMap.size).toBe(1);
|
||||
expect(processedText).not.toContain("`console.log`");
|
||||
|
||||
const placeholder = [...placeholderMap.keys()][0];
|
||||
expect(placeholderMap.get(placeholder)).toBe("`console.log`");
|
||||
});
|
||||
|
||||
it("should extract multiple fenced code blocks independently", () => {
|
||||
const input = "```js\na\n```\ntext\n```py\nb\n```";
|
||||
const { processedText, placeholderMap } = extractCodeBlocks(input);
|
||||
|
||||
expect(placeholderMap.size).toBe(2);
|
||||
expect(processedText).toContain("text");
|
||||
});
|
||||
|
||||
it("should not treat inline backtick-escaped triple backticks as a fenced code block", () => {
|
||||
const input = [
|
||||
"* Code blocks with syntax highlight (e.g. ` ```js `) and automatic syntax highlight",
|
||||
"* Block quotes & admonitions",
|
||||
"* Math Equations",
|
||||
"* Mermaid Diagrams using ` ```mermaid `"
|
||||
].join("\n");
|
||||
|
||||
const { processedText, placeholderMap } = extractCodeBlocks(input);
|
||||
|
||||
// All four bullet points must survive
|
||||
expect(processedText).toContain("Block quotes & admonitions");
|
||||
expect(processedText).toContain("Math Equations");
|
||||
expect(processedText).toContain("Mermaid Diagrams");
|
||||
expect(processedText).toContain("automatic syntax highlight");
|
||||
|
||||
// The inline code spans should be extracted, not fenced code blocks
|
||||
for (const value of placeholderMap.values()) {
|
||||
expect(value).not.toMatch(/^```[\s\S]*```$/);
|
||||
}
|
||||
});
|
||||
|
||||
it("should not swallow content between two inline triple-backtick mentions", () => {
|
||||
const input = "Use ` ```js ` for JS and ` ```py ` for Python";
|
||||
const { processedText } = extractCodeBlocks(input);
|
||||
|
||||
expect(processedText).toContain("for JS and");
|
||||
expect(processedText).toContain("for Python");
|
||||
});
|
||||
|
||||
it("should handle a real fenced code block after inline triple backticks", () => {
|
||||
const input = [
|
||||
"Use ` ```js ` for JavaScript.",
|
||||
"",
|
||||
"```py",
|
||||
"print('hello')",
|
||||
"```"
|
||||
].join("\n");
|
||||
|
||||
const { processedText, placeholderMap } = extractCodeBlocks(input);
|
||||
|
||||
expect(processedText).toContain("for JavaScript.");
|
||||
|
||||
// Should have the inline code and the fenced block as separate entries
|
||||
const values = [...placeholderMap.values()];
|
||||
const hasFencedBlock = values.some((v) => v.includes("print('hello')"));
|
||||
expect(hasFencedBlock).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -106,13 +106,13 @@ function handleH1(content: string, title: string): string {
|
||||
});
|
||||
}
|
||||
|
||||
function extractCodeBlocks(text: string): { processedText: string; placeholderMap: Map<string, string> } {
|
||||
export function extractCodeBlocks(text: string): { processedText: string; placeholderMap: Map<string, string> } {
|
||||
const codeMap = new Map<string, string>();
|
||||
let id = 0;
|
||||
const timestamp = Date.now();
|
||||
|
||||
text = text
|
||||
.replace(/```[\s\S]*?```/g, (m) => {
|
||||
.replace(/^[ \t]*```[^\n]*\n[\s\S]*?^[ \t]*```[ \t]*$/gm, (m) => {
|
||||
const key = `<!--CODE_BLOCK_${timestamp}_${id++}-->`;
|
||||
codeMap.set(key, m);
|
||||
return key;
|
||||
|
||||
108
pnpm-lock.yaml
generated
@@ -187,8 +187,8 @@ importers:
|
||||
apps/build-docs:
|
||||
devDependencies:
|
||||
'@redocly/cli':
|
||||
specifier: 2.26.0
|
||||
version: 2.26.0(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)
|
||||
specifier: 2.28.0
|
||||
version: 2.28.0(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)
|
||||
archiver:
|
||||
specifier: 7.0.1
|
||||
version: 7.0.1
|
||||
@@ -358,8 +358,8 @@ importers:
|
||||
specifier: 10.29.1
|
||||
version: 10.29.1
|
||||
react-i18next:
|
||||
specifier: 17.0.2
|
||||
version: 17.0.2(i18next@26.0.4(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2)
|
||||
specifier: 17.0.3
|
||||
version: 17.0.3(i18next@26.0.4(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2)
|
||||
react-window:
|
||||
specifier: 2.2.7
|
||||
version: 2.2.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||
@@ -575,14 +575,14 @@ importers:
|
||||
specifier: 3.0.63
|
||||
version: 3.0.63(zod@4.3.6)
|
||||
'@ai-sdk/openai':
|
||||
specifier: 3.0.52
|
||||
version: 3.0.52(zod@4.3.6)
|
||||
specifier: 3.0.53
|
||||
version: 3.0.53(zod@4.3.6)
|
||||
'@modelcontextprotocol/sdk':
|
||||
specifier: ^1.12.1
|
||||
version: 1.29.0(zod@4.3.6)
|
||||
ai:
|
||||
specifier: 6.0.159
|
||||
version: 6.0.159(zod@4.3.6)
|
||||
specifier: 6.0.161
|
||||
version: 6.0.161(zod@4.3.6)
|
||||
better-sqlite3:
|
||||
specifier: 12.9.0
|
||||
version: 12.9.0
|
||||
@@ -890,10 +890,10 @@ importers:
|
||||
devDependencies:
|
||||
'@wxt-dev/auto-icons':
|
||||
specifier: 1.1.1
|
||||
version: 1.1.1(wxt@0.20.21(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3))
|
||||
version: 1.1.1(wxt@0.20.22(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3))
|
||||
wxt:
|
||||
specifier: 0.20.21
|
||||
version: 0.20.21(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3)
|
||||
specifier: 0.20.22
|
||||
version: 0.20.22(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3)
|
||||
|
||||
apps/website:
|
||||
dependencies:
|
||||
@@ -910,8 +910,8 @@ importers:
|
||||
specifier: 6.6.7
|
||||
version: 6.6.7(preact@10.29.1)
|
||||
react-i18next:
|
||||
specifier: 17.0.2
|
||||
version: 17.0.2(i18next@26.0.4(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2)
|
||||
specifier: 17.0.3
|
||||
version: 17.0.3(i18next@26.0.4(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2)
|
||||
devDependencies:
|
||||
'@preact/preset-vite':
|
||||
specifier: 2.10.5
|
||||
@@ -1482,8 +1482,8 @@ packages:
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
|
||||
'@ai-sdk/gateway@3.0.96':
|
||||
resolution: {integrity: sha512-BDiVEMUVHGpngReeigzLyJobG0TvzYbNGzdHI8JYBZHrjOX4aL6qwIls7z3p7V4TuXVWUCbG8TSWEe7ksX4Vhw==}
|
||||
'@ai-sdk/gateway@3.0.98':
|
||||
resolution: {integrity: sha512-Ol+nP8PIlj8FjN8qKlxhE89N0woqAaGi9CUBGp1boe3RafpphJ7WMuq/RErSvxtwTqje03TP+zIdzP113krxRg==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
@@ -1494,8 +1494,8 @@ packages:
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
|
||||
'@ai-sdk/openai@3.0.52':
|
||||
resolution: {integrity: sha512-4Rr8NCGmfWTz6DCUvixn9UmyZcMatiHn0zWoMzI3JCUe9R1P/vsPOpCBALKoSzVYOjyJnhtnVIbfUKujcS39uw==}
|
||||
'@ai-sdk/openai@3.0.53':
|
||||
resolution: {integrity: sha512-Wld+Rbc05KaUn08uBt06eEuwcgalcIFtIl32Yp+GxuZXUQwOb6YeAuq+C6da4ch6BurFoqEaLemJVwjBb7x+PQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
@@ -4872,27 +4872,27 @@ packages:
|
||||
'@redocly/cli-otel@0.1.2':
|
||||
resolution: {integrity: sha512-Bg7BoO5t1x3lVK+KhA5aGPmeXpQmdf6WtTYHhelKJCsQ+tRMiJoFAQoKHoBHAoNxXrhlS3K9lKFLHGmtxsFQfA==}
|
||||
|
||||
'@redocly/cli@2.26.0':
|
||||
resolution: {integrity: sha512-24S1ls0qvu3uaPiW4OImy06CpImAkUOd3h7OG+Hq9By5pPavjOE34KtdQTaaFso3e1qgzXYdQh6HPqEY1nTZgA==}
|
||||
'@redocly/cli@2.28.0':
|
||||
resolution: {integrity: sha512-hAHtMjo4fLdLqZXtZwQqlwGnAiOzEAh7EPbE01rs9j7cewj2btOXrGQW8v6Eg3gDh+i77/DOxxazRWvZ/zAa7w==}
|
||||
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
'@redocly/config@0.22.2':
|
||||
resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==}
|
||||
|
||||
'@redocly/config@0.46.1':
|
||||
resolution: {integrity: sha512-dSdkB2wRLtvl3f7ayRu9vqVhUMjjRaxZlHgRbgOtPPXxn4uI/ciDO87h4CJb7Iet+OVpevpAU6gU8bo5qVbQxg==}
|
||||
'@redocly/config@0.48.0':
|
||||
resolution: {integrity: sha512-8W3wz+Q7y4e9klJWlYOvQWK5r7P2Mo589vcjtlT5coOxsyAdt53k8Vb8iAqnRiGWExbjBQmSbL2XbuU747Nf6Q==}
|
||||
|
||||
'@redocly/openapi-core@1.34.5':
|
||||
resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==}
|
||||
engines: {node: '>=18.17.0', npm: '>=9.5.0'}
|
||||
|
||||
'@redocly/openapi-core@2.26.0':
|
||||
resolution: {integrity: sha512-BjTPzSV1Gv430W9S/7i5T/dEZDK00GFk6ILCNTI+31pA9lEFJOXc0XRJT+V3v+m3nXIgGoo6GgqeLdAiM10rNg==}
|
||||
'@redocly/openapi-core@2.28.0':
|
||||
resolution: {integrity: sha512-Htpp4PsjKMgEuMT9iJu4iuFFzWCDe8FylvpGaQEA5D7jZXWv+8XvnqhpGCKN2cM/n/Uri2QfqNdw0JlKIC59sg==}
|
||||
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
|
||||
|
||||
'@redocly/respect-core@2.26.0':
|
||||
resolution: {integrity: sha512-mejFg26XNp8pqHwnL75QvI7MO4dhgFKa+v35OgOcVMrU9tGZ/VaFbplEyvdrRgjoonguXoLDoMN4Iw1rWlZg0g==}
|
||||
'@redocly/respect-core@2.28.0':
|
||||
resolution: {integrity: sha512-svjCRzXsj/EyN7chfB9pTVYvWT1+hlOqMkZVlkrH6PqFKXAHYeP47YRW9+3omUSDBd1Ph4A4J4NBUW1PRph5+g==}
|
||||
engines: {node: '>=22.12.0 || >=20.19.0 <21.0.0', npm: '>=10'}
|
||||
|
||||
'@replit/codemirror-indentation-markers@6.5.3':
|
||||
@@ -6770,8 +6770,8 @@ packages:
|
||||
resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ai@6.0.159:
|
||||
resolution: {integrity: sha512-S18ozG7Dkm3Ud1tzOtAK5acczD4vygfml80RkpM9VWMFpvAFwAKSHaGYkATvPQHIE+VpD1tJY9zcTXLZ/zR5cw==}
|
||||
ai@6.0.161:
|
||||
resolution: {integrity: sha512-ufhmijmx2YyWTPAicGgtpLOB/xD7mG8zKs1pT1Trj+JL/3r1rS8fkMi/cHZoChSAQSGB4pgmcWVxDrVTUvK2IQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4.1.8
|
||||
@@ -10860,9 +10860,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
mlly@1.7.4:
|
||||
resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==}
|
||||
|
||||
mlly@1.8.0:
|
||||
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
||||
|
||||
@@ -11891,8 +11888,8 @@ packages:
|
||||
peerDependencies:
|
||||
react: ^19.2.4
|
||||
|
||||
react-i18next@17.0.2:
|
||||
resolution: {integrity: sha512-shBftH2vaTWK2Bsp7FiL+cevx3xFJlvFxmsDFQSrJc+6twHkP0tv/bGa01VVWzpreUVVwU+3Hev5iFqRg65RwA==}
|
||||
react-i18next@17.0.3:
|
||||
resolution: {integrity: sha512-x4xjvUNZ56T+zfXWNedNnCET9Xq1IBYWX7IsWo5cCQ/RT+Rm7GWqt0h9PShFi4IhyMnsdiu1C6Jc4DE+/S3PFQ==}
|
||||
peerDependencies:
|
||||
i18next: '>= 26.0.1'
|
||||
react: '>= 16.8.0'
|
||||
@@ -14099,8 +14096,8 @@ packages:
|
||||
resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
wxt@0.20.21:
|
||||
resolution: {integrity: sha512-rDocJ9QEWKnGd7NTTTxKIJ5MsXwv9lXk4/ITFS9eeksTCYotshxzAiptkRPEHCgsJNiGMNY/UFNxVDyqWGe7Bw==}
|
||||
wxt@0.20.22:
|
||||
resolution: {integrity: sha512-njFI77H0dAbK/bQCN8u8QYiusg6GKDPMtsQDCqIfrh1oGHMHgrMEMgeGOlqAltG9OOGGB1DvFYDzTvxqfEKVKQ==}
|
||||
engines: {bun: '>=1.2.0', node: '>=20.12.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -14270,7 +14267,7 @@ snapshots:
|
||||
'@ai-sdk/provider-utils': 4.0.23(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@ai-sdk/gateway@3.0.96(zod@4.3.6)':
|
||||
'@ai-sdk/gateway@3.0.98(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.23(zod@4.3.6)
|
||||
@@ -14283,7 +14280,7 @@ snapshots:
|
||||
'@ai-sdk/provider-utils': 4.0.23(zod@4.3.6)
|
||||
zod: 4.3.6
|
||||
|
||||
'@ai-sdk/openai@3.0.52(zod@4.3.6)':
|
||||
'@ai-sdk/openai@3.0.53(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.23(zod@4.3.6)
|
||||
@@ -18747,15 +18744,15 @@ snapshots:
|
||||
dependencies:
|
||||
ulid: 2.4.0
|
||||
|
||||
'@redocly/cli@2.26.0(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)':
|
||||
'@redocly/cli@2.28.0(@opentelemetry/api@1.9.0)(bufferutil@4.0.9)(core-js@3.46.0)(encoding@0.1.13)(utf-8-validate@6.0.5)':
|
||||
dependencies:
|
||||
'@opentelemetry/exporter-trace-otlp-http': 0.202.0(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/resources': 2.0.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/sdk-trace-node': 2.0.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/semantic-conventions': 1.34.0
|
||||
'@redocly/cli-otel': 0.1.2
|
||||
'@redocly/openapi-core': 2.26.0
|
||||
'@redocly/respect-core': 2.26.0
|
||||
'@redocly/openapi-core': 2.28.0
|
||||
'@redocly/respect-core': 2.28.0
|
||||
abort-controller: 3.0.0
|
||||
ajv: '@redocly/ajv@8.18.0'
|
||||
ajv-formats: 3.0.1(@redocly/ajv@8.18.0)
|
||||
@@ -18789,7 +18786,7 @@ snapshots:
|
||||
|
||||
'@redocly/config@0.22.2': {}
|
||||
|
||||
'@redocly/config@0.46.1':
|
||||
'@redocly/config@0.48.0':
|
||||
dependencies:
|
||||
json-schema-to-ts: 2.7.2
|
||||
|
||||
@@ -18807,10 +18804,10 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@redocly/openapi-core@2.26.0':
|
||||
'@redocly/openapi-core@2.28.0':
|
||||
dependencies:
|
||||
'@redocly/ajv': 8.18.0
|
||||
'@redocly/config': 0.46.1
|
||||
'@redocly/config': 0.48.0
|
||||
ajv: '@redocly/ajv@8.18.0'
|
||||
ajv-formats: 3.0.1(@redocly/ajv@8.18.0)
|
||||
colorette: 1.4.0
|
||||
@@ -18820,12 +18817,12 @@ snapshots:
|
||||
pluralize: 8.0.0
|
||||
yaml-ast-parser: 0.0.43
|
||||
|
||||
'@redocly/respect-core@2.26.0':
|
||||
'@redocly/respect-core@2.28.0':
|
||||
dependencies:
|
||||
'@faker-js/faker': 7.6.0
|
||||
'@noble/hashes': 1.8.0
|
||||
'@redocly/ajv': 8.18.0
|
||||
'@redocly/openapi-core': 2.26.0
|
||||
'@redocly/openapi-core': 2.28.0
|
||||
ajv: '@redocly/ajv@8.18.0'
|
||||
better-ajv-errors: 1.2.0(@redocly/ajv@8.18.0)
|
||||
colorette: 2.0.20
|
||||
@@ -21577,12 +21574,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
react: 19.2.4
|
||||
|
||||
'@wxt-dev/auto-icons@1.1.1(wxt@0.20.21(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3))':
|
||||
'@wxt-dev/auto-icons@1.1.1(wxt@0.20.22(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3))':
|
||||
dependencies:
|
||||
defu: 6.1.6
|
||||
fs-extra: 11.3.4
|
||||
sharp: 0.34.5
|
||||
wxt: 0.20.21(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3)
|
||||
wxt: 0.20.22(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3)
|
||||
|
||||
'@wxt-dev/browser@0.1.40':
|
||||
dependencies:
|
||||
@@ -21668,9 +21665,9 @@ snapshots:
|
||||
clean-stack: 2.2.0
|
||||
indent-string: 4.0.0
|
||||
|
||||
ai@6.0.159(zod@4.3.6):
|
||||
ai@6.0.161(zod@4.3.6):
|
||||
dependencies:
|
||||
'@ai-sdk/gateway': 3.0.96(zod@4.3.6)
|
||||
'@ai-sdk/gateway': 3.0.98(zod@4.3.6)
|
||||
'@ai-sdk/provider': 3.0.8
|
||||
'@ai-sdk/provider-utils': 4.0.23(zod@4.3.6)
|
||||
'@opentelemetry/api': 1.9.0
|
||||
@@ -24676,7 +24673,7 @@ snapshots:
|
||||
|
||||
glob@13.0.6:
|
||||
dependencies:
|
||||
minimatch: 10.2.4
|
||||
minimatch: 10.2.5
|
||||
minipass: 7.1.3
|
||||
path-scurry: 2.0.2
|
||||
|
||||
@@ -25924,7 +25921,7 @@ snapshots:
|
||||
|
||||
local-pkg@1.1.1:
|
||||
dependencies:
|
||||
mlly: 1.7.4
|
||||
mlly: 1.8.0
|
||||
pkg-types: 2.3.0
|
||||
quansync: 0.2.10
|
||||
|
||||
@@ -26707,13 +26704,6 @@ snapshots:
|
||||
|
||||
mkdirp@1.0.4: {}
|
||||
|
||||
mlly@1.7.4:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
pathe: 2.0.3
|
||||
pkg-types: 1.3.1
|
||||
ufo: 1.6.1
|
||||
|
||||
mlly@1.8.0:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
@@ -27813,7 +27803,7 @@ snapshots:
|
||||
react: 19.2.4
|
||||
scheduler: 0.27.0
|
||||
|
||||
react-i18next@17.0.2(i18next@26.0.4(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2):
|
||||
react-i18next@17.0.3(i18next@26.0.4(typescript@6.0.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@6.0.2):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.29.2
|
||||
html-parse-stringify: 3.0.1
|
||||
@@ -30417,7 +30407,7 @@ snapshots:
|
||||
is-wsl: 3.1.1
|
||||
powershell-utils: 0.1.0
|
||||
|
||||
wxt@0.20.21(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3):
|
||||
wxt@0.20.22(@types/node@24.12.2)(eslint@10.2.0(jiti@2.6.1))(jiti@2.6.1)(less@4.1.3)(rollup@4.60.1)(sass-embedded@1.91.0)(sass@1.91.0)(terser@5.44.0)(tsx@4.21.0)(yaml@2.8.3):
|
||||
dependencies:
|
||||
'@1natsu/wait-element': 4.1.2
|
||||
'@aklinker1/rollup-plugin-visualizer': 5.12.0(rollup@4.60.1)
|
||||
|
||||