Merge remote-tracking branch 'origin/main' into patch-2

This commit is contained in:
Elian Doran
2025-10-21 11:26:18 +03:00
125 changed files with 3716 additions and 1229 deletions

View File

@@ -35,13 +35,13 @@
"chore:generate-openapi": "tsx bin/generate-openapi.js"
},
"devDependencies": {
"@playwright/test": "1.56.0",
"@stylistic/eslint-plugin": "5.4.0",
"@playwright/test": "1.56.1",
"@stylistic/eslint-plugin": "5.5.0",
"@types/express": "5.0.3",
"@types/node": "22.18.10",
"@types/node": "22.18.11",
"@types/yargs": "17.0.33",
"@vitest/coverage-v8": "3.2.4",
"eslint": "9.37.0",
"eslint": "9.38.0",
"eslint-plugin-simple-import-sort": "12.1.1",
"esm": "3.2.25",
"jsdoc": "4.0.5",

View File

@@ -1,4 +1,3 @@
import type child_process from "child_process";
import { describe, beforeAll, afterAll } from "vitest";
let etapiAuthToken: string | undefined;
@@ -12,8 +11,6 @@ type SpecDefinitionsFunc = () => void;
function describeEtapi(description: string, specDefinitions: SpecDefinitionsFunc): void {
describe(description, () => {
let appProcess: ReturnType<typeof child_process.spawn>;
beforeAll(async () => {});
afterAll(() => {});

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/client",
"version": "0.99.1",
"version": "0.99.2",
"description": "JQuery-based client for TriliumNext, used for both web and desktop (via Electron)",
"private": true,
"license": "AGPL-3.0-only",
@@ -15,7 +15,7 @@
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
},
"dependencies": {
"@eslint/js": "9.37.0",
"@eslint/js": "9.38.0",
"@excalidraw/excalidraw": "0.18.0",
"@fullcalendar/core": "6.1.19",
"@fullcalendar/daygrid": "6.1.19",
@@ -52,13 +52,13 @@
"leaflet": "1.9.4",
"leaflet-gpx": "2.2.0",
"mark.js": "8.11.1",
"marked": "16.4.0",
"marked": "16.4.1",
"mermaid": "11.12.0",
"mind-elixir": "5.3.2",
"mind-elixir": "5.3.3",
"normalize.css": "8.0.1",
"panzoom": "9.4.3",
"preact": "10.27.2",
"react-i18next": "16.0.1",
"react-i18next": "16.1.0",
"reveal.js": "5.2.1",
"split.js": "1.6.5",
"svg-pan-zoom": "3.6.2",
@@ -76,7 +76,7 @@
"@types/reveal.js": "5.2.1",
"@types/tabulator-tables": "6.2.11",
"copy-webpack-plugin": "13.0.1",
"happy-dom": "20.0.4",
"happy-dom": "20.0.7",
"script-loader": "0.7.2",
"vite-plugin-static-copy": "3.1.4"
}

View File

@@ -326,9 +326,11 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded">
}
// Collections must always display a note list, even if no children.
const viewType = note.getLabelValue("viewType") ?? "grid";
if (!["list", "grid"].includes(viewType)) {
return true;
if (note.type === "book") {
const viewType = note.getLabelValue("viewType") ?? "grid";
if (!["list", "grid"].includes(viewType)) {
return true;
}
}
if (!note.hasChildren()) {

View File

@@ -1,6 +1,5 @@
import server from "../services/server.js";
import noteAttributeCache from "../services/note_attribute_cache.js";
import ws from "../services/ws.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import cssClassManager from "../services/css_class_manager.js";
import type { Froca } from "../services/froca-interface.js";
@@ -586,7 +585,7 @@ export default class FNote {
let childBranches = this.getChildBranches();
if (!childBranches) {
ws.logError(`No children for '${this.noteId}'. This shouldn't happen.`);
console.error(`No children for '${this.noteId}'. This shouldn't happen.`);
return [];
}

View File

@@ -138,7 +138,7 @@ export default class DesktopLayout {
.child(new PromotedAttributesWidget())
.child(<SqlTableSchemas />)
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<NoteList media="screen" />)
.child(<SearchResult />)
.child(<SqlResults />)
.child(<ScrollPadding />)

View File

@@ -66,6 +66,6 @@ export function applyModals(rootContainer: RootContainer) {
.child(<PopupEditorFormattingToolbar />)
.child(new PromotedAttributesWidget())
.child(new NoteDetailWidget())
.child(<NoteList displayOnlyCollections />))
.child(<NoteList media="screen" displayOnlyCollections />))
.child(<CallToActionDialog />);
}

View File

@@ -154,7 +154,7 @@ export default class MobileLayout {
.filling()
.contentSized()
.child(new NoteDetailWidget())
.child(<NoteList />)
.child(<NoteList media="screen" />)
.child(<FilePropertiesWrapper />)
)
.child(<MobileEditorToolbar />)

155
apps/client/src/print.css Normal file
View File

@@ -0,0 +1,155 @@
:root {
--print-font-size: 11pt;
--ck-content-color-image-caption-background: transparent !important;
}
html,
body {
width: 100%;
height: 100%;
color: black;
}
@page {
margin: 2cm;
}
.note-list-widget.full-height,
.note-list-widget.full-height .note-list-widget-content {
height: unset !important;
}
.component {
contain: none !important;
}
body[data-note-type="text"] .ck-content {
font-size: var(--print-font-size);
text-align: justify;
}
.ck-content figcaption {
font-style: italic;
}
.ck-content a {
text-decoration: none;
}
.ck-content a:not([href^="#root/"]) {
text-decoration: underline;
color: #374a75;
}
.ck-content .todo-list__label * {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
@supports selector(.todo-list__label__description:has(*)) and (height: 1lh) {
.ck-content .todo-list__label__description {
/* The percentage of the line height that the check box occupies */
--box-ratio: 0.75;
/* The size of the gap between the check box and the caption */
--box-text-gap: 0.25em;
--box-size: calc(1lh * var(--box-ratio));
--box-vert-offset: calc((1lh - var(--box-size)) / 2);
display: inline-block;
padding-inline-start: calc(var(--box-size) + var(--box-text-gap));
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-blank-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5C3.89%2c3 3%2c3.89 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5C21%2c3.89 20.1%2c3 19%2c3M19%2c5V19H5V5H19Z' /%3e%3c/svg%3e");
background-position: 0 var(--box-vert-offset);
background-size: var(--box-size);
background-repeat: no-repeat;
}
.ck-content .todo-list__label:has(input[type="checkbox"]:checked) .todo-list__label__description {
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5A2%2c2 0 0%2c0 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5A2%2c2 0 0%2c0 19%2c3M19%2c5V19H5V5H19M10%2c17L6%2c13L7.41%2c11.58L10%2c14.17L16.59%2c7.58L18%2c9' /%3e%3c/svg%3e");
}
.ck-content .todo-list__label input[type="checkbox"] {
display: none !important;
}
}
/* #region Footnotes */
.footnote-reference a,
.footnote-back-link a {
text-decoration: none !important;
}
li.footnote-item {
position: relative;
width: fit-content;
}
.ck-content .footnote-back-link {
margin-right: 0.25em;
}
.ck-content .footnote-content {
display: inline-block;
width: unset;
}
/* #endregion */
/* #region Widows and orphans */
p,
blockquote {
widows: 4;
orphans: 4;
}
pre > code {
widows: 6;
orphans: 6;
overflow: auto;
white-space: pre-wrap !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
page-break-after: avoid;
break-after: avoid;
}
/* #endregion */
/* #region Tables */
.table thead th,
.table td,
.table th {
/* Fix center vertical alignment of table cells */
vertical-align: middle;
}
pre {
box-shadow: unset !important;
border: 0.75pt solid gray !important;
border-radius: 2pt !important;
}
th,
span[style] {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
/* #endregion */
/* #region Page breaks */
.page-break {
page-break-after: always;
break-after: always;
}
.page-break > *,
.page-break::after {
display: none !important;
}
/* #endregion */

92
apps/client/src/print.tsx Normal file
View File

@@ -0,0 +1,92 @@
import FNote from "./entities/fnote";
import { render } from "preact";
import { CustomNoteList } from "./widgets/collections/NoteList";
import { useCallback, useLayoutEffect, useRef } from "preact/hooks";
import content_renderer from "./services/content_renderer";
interface RendererProps {
note: FNote;
onReady: () => void;
}
async function main() {
const notePath = window.location.hash.substring(1);
const noteId = notePath.split("/").at(-1);
if (!noteId) return;
await import("./print.css");
const froca = (await import("./services/froca")).default;
const note = await froca.getNote(noteId);
render(<App note={note} noteId={noteId} />, document.body);
}
function App({ note, noteId }: { note: FNote | null | undefined, noteId: string }) {
const sentReadyEvent = useRef(false);
const onReady = useCallback(() => {
if (sentReadyEvent.current) return;
window.dispatchEvent(new Event("note-ready"));
window._noteReady = true;
sentReadyEvent.current = true;
}, []);
const props: RendererProps | undefined | null = note && { note, onReady };
if (!note || !props) return <Error404 noteId={noteId} />
useLayoutEffect(() => {
document.body.dataset.noteType = note.type;
}, [ note ]);
return (
<>
{note.type === "book"
? <CollectionRenderer {...props} />
: <SingleNoteRenderer {...props} />
}
</>
);
}
function SingleNoteRenderer({ note, onReady }: RendererProps) {
const containerRef = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
async function load() {
if (note.type === "text") {
await import("@triliumnext/ckeditor5/src/theme/ck-content.css");
}
const { $renderedContent } = await content_renderer.getRenderedContent(note, { noChildrenList: true });
containerRef.current?.replaceChildren(...$renderedContent);
}
load().then(() => requestAnimationFrame(onReady))
}, [ note ]);
return <>
<h1>{note.title}</h1>
<main ref={containerRef} />
</>;
}
function CollectionRenderer({ note, onReady }: RendererProps) {
return <CustomNoteList
isEnabled
note={note}
notePath={note.getBestNotePath().join("/")}
ntxId="print"
highlightedTokens={null}
media="print"
onReady={onReady}
/>;
}
function Error404({ noteId }: { noteId: string }) {
return (
<main>
<p>The note you are trying to print could not be found.</p>
<small>{noteId}</small>
</main>
)
}
main();

View File

@@ -40,20 +40,23 @@ class FrocaImpl implements Froca {
constructor() {
this.initializedPromise = this.loadInitialTree();
this.#clear();
}
async loadInitialTree() {
const resp = await server.get<SubtreeResponse>("tree");
// clear the cache only directly before adding new content which is important for e.g., switching to protected session
this.#clear();
this.addResp(resp);
}
#clear() {
this.notes = {};
this.branches = {};
this.attributes = {};
this.attachments = {};
this.blobPromises = {};
this.addResp(resp);
}
async loadSubTree(subTreeNoteId: string) {

View File

@@ -61,7 +61,11 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle
highlightedText = highlightAuto(text);
} else if (normalizedMimeType) {
await ensureMimeTypesForHighlighting(normalizedMimeType);
highlightedText = highlight(text, { language: normalizedMimeType });
try {
highlightedText = highlight(text, { language: normalizedMimeType });
} catch (e) {
console.warn("Unable to apply syntax highlight.", e);
}
}
if (highlightedText) {
@@ -76,7 +80,7 @@ export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
// Load theme.
const currentThemeName = String(options.get("codeBlockTheme"));
loadHighlightingTheme(currentThemeName);
await loadHighlightingTheme(currentThemeName);
// Load mime types.
let mimeTypes: MimeType[];
@@ -98,17 +102,16 @@ export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
highlightingLoaded = true;
}
export function loadHighlightingTheme(themeName: string) {
export async function loadHighlightingTheme(themeName: string) {
const themePrefix = "default:";
let theme: Theme | null = null;
if (themeName.includes(themePrefix)) {
if (glob.device === "print") {
theme = Themes.vs;
} else if (themeName.includes(themePrefix)) {
theme = Themes[themeName.substring(themePrefix.length)];
}
if (!theme) {
theme = Themes.default;
}
loadTheme(theme);
await loadTheme(theme ?? Themes.default);
}
/**

View File

@@ -304,6 +304,8 @@ async function sendPing() {
}
setTimeout(() => {
if (glob.device === "print") return;
ws = connectWebSocket();
lastPingTs = Date.now();

View File

@@ -1,322 +0,0 @@
:root {
--main-background-color: white;
--root-background: var(--main-background-color);
--launcher-pane-background-color: var(--main-background-color);
--main-text-color: black;
--input-text-color: var(--main-text-color);
--print-font-size: 11pt;
}
@page {
margin: 2cm;
}
.ck-content {
font-size: var(--print-font-size);
text-align: justify;
}
.note-detail-readonly-text {
padding: 0 !important;
}
.no-print,
.no-print *,
.tab-row-container,
.tab-row-widget,
.title-bar-buttons,
#launcher-pane,
#left-pane,
#center-pane > *:not(.split-note-container-widget),
#right-pane,
.title-row .note-icon-widget,
.title-row .icon-action,
.ribbon-container,
.promoted-attributes-widget,
.scroll-padding-widget,
.note-list-widget,
.spacer {
display: none !important;
}
body.mobile #mobile-sidebar-wrapper,
body.mobile .classic-toolbar-widget,
body.mobile .action-button {
display: none !important;
}
body.mobile #detail-container {
max-height: unset;
}
body.mobile .note-title-widget {
padding: 0 !important;
}
body,
#root-widget,
#rest-pane > div.component:first-child,
.note-detail-printable,
.note-detail-editable-text-editor {
height: unset !important;
overflow: auto;
}
.ck.ck-editor__editable_inline {
overflow: hidden !important;
}
.note-title-widget input,
.note-detail-editable-text,
.note-detail-editable-text-editor {
padding: 0 !important;
}
html,
body {
width: unset !important;
height: unset !important;
overflow: visible;
position: unset;
/* https://github.com/zadam/trilium/issues/3202 */
color: black;
}
#root-widget,
#horizontal-main-container,
#rest-pane,
#vertical-main-container,
#center-pane,
.split-note-container-widget,
.note-split:not(.hidden-ext),
body.mobile #mobile-rest-container {
display: block !important;
overflow: auto;
border-radius: 0 !important;
}
#center-pane,
#rest-pane,
.note-split,
body.mobile #detail-container {
width: unset !important;
max-width: unset !important;
}
.component {
contain: none !important;
}
/* Respect page breaks */
.page-break {
page-break-after: always;
break-after: always;
}
.page-break > * {
display: none !important;
}
.relation-map-wrapper {
height: 100vh !important;
}
.table thead th,
.table td,
.table th {
/* Fix center vertical alignment of table cells */
vertical-align: middle;
}
pre {
box-shadow: unset !important;
border: 0.75pt solid gray !important;
border-radius: 2pt !important;
}
th,
span[style] {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
/*
* Text note specific fixes
*/
.ck-widget {
outline: none !important;
}
.ck-placeholder,
.ck-widget__type-around,
.ck-widget__selection-handle {
display: none !important;
}
.ck-widget.table td.ck-editor__nested-editable.ck-editor__nested-editable_focused,
.ck-widget.table td.ck-editor__nested-editable:focus,
.ck-widget.table th.ck-editor__nested-editable.ck-editor__nested-editable_focused,
.ck-widget.table th.ck-editor__nested-editable:focus {
background: unset !important;
outline: unset !important;
}
.include-note .include-note-content {
max-height: unset !important;
overflow: unset !important;
}
/* TODO: This will break once we translate the language */
.ck-content pre[data-language="Auto-detected"]:after {
display: none !important;
}
/*
* Code note specific fixes.
*/
.note-detail-code pre {
border: unset !important;
border-radius: unset !important;
}
/*
* Links
*/
.note-detail-printable a {
text-decoration: none;
}
.note-detail-printable a:not([href^="#root/"]) {
text-decoration: underline;
color: #374a75;
}
.note-detail-printable a::after {
/* Hide the external link trailing arrow */
display: none !important;
}
/*
* TODO list check boxes
*/
.note-detail-printable .todo-list__label * {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
@supports selector(.todo-list__label__description:has(*)) and (height: 1lh) {
.note-detail-printable .todo-list__label__description {
/* The percentage of the line height that the check box occupies */
--box-ratio: 0.75;
/* The size of the gap between the check box and the caption */
--box-text-gap: 0.25em;
--box-size: calc(1lh * var(--box-ratio));
--box-vert-offset: calc((1lh - var(--box-size)) / 2);
display: inline-block;
padding-inline-start: calc(var(--box-size) + var(--box-text-gap));
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-blank-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5C3.89%2c3 3%2c3.89 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5C21%2c3.89 20.1%2c3 19%2c3M19%2c5V19H5V5H19Z' /%3e%3c/svg%3e");
background-position: 0 var(--box-vert-offset);
background-size: var(--box-size);
background-repeat: no-repeat;
}
.note-detail-printable .todo-list__label:has(input[type="checkbox"]:checked) .todo-list__label__description {
/* Source: https://pictogrammers.com/library/mdi/icon/checkbox-outline/ */
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='currentColor'%3e%3cpath d='M19%2c3H5A2%2c2 0 0%2c0 3%2c5V19A2%2c2 0 0%2c0 5%2c21H19A2%2c2 0 0%2c0 21%2c19V5A2%2c2 0 0%2c0 19%2c3M19%2c5V19H5V5H19M10%2c17L6%2c13L7.41%2c11.58L10%2c14.17L16.59%2c7.58L18%2c9' /%3e%3c/svg%3e");
}
.note-detail-printable .todo-list__label input[type="checkbox"] {
display: none !important;
}
}
/*
* Blockquotes
*/
.note-detail-printable blockquote {
box-shadow: unset;
}
/*
* Figures
*/
.note-detail-printable figcaption {
--accented-background-color: transparent;
font-style: italic;
}
/*
* Footnotes
*/
.note-detail-printable .footnote-reference a,
.footnote-back-link a {
text-decoration: none;
}
/* Make the "^" link cover the whole area of the footnote item */
.footnote-section {
clear: both;
}
.note-detail-printable li.footnote-item {
position: relative;
width: fit-content;
}
.note-detail-printable .footnote-back-link,
.note-detail-printable .footnote-back-link *,
.note-detail-printable .footnote-back-link a {
display: block;
position: absolute;
top: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
}
.note-detail-printable .footnote-back-link a {
color: transparent;
}
.note-detail-printable .footnote-content {
display: inline-block;
width: unset;
}
/*
* Widows and orphans
*/
p,
blockquote {
widows: 4;
orphans: 4;
}
pre > code {
widows: 6;
orphans: 6;
overflow: auto;
white-space: pre-wrap !important;
}
h1,
h2,
h3,
h4,
h5,
h6 {
page-break-after: avoid;
break-after: avoid;
}

View File

@@ -2422,4 +2422,14 @@ footer.webview-footer button {
.revision-diff-removed {
background: rgba(255, 100, 100, 0.5);
text-decoration: line-through;
}
iframe.print-iframe {
position: absolute;
top: 0;
left: -600px;
right: -600px;
bottom: 0;
width: 0;
height: 0;
}

View File

@@ -25,7 +25,8 @@
"branch_prefix": {
"edit_branch_prefix": "تعديل بادئة الفرع",
"prefix": "البادئة: ",
"save": "حفظ"
"save": "حفظ",
"help_on_tree_prefix": "مساعدة حول بادئة الشجرة"
},
"bulk_actions": {
"bulk_actions": "اجراءات جماعية",
@@ -44,7 +45,8 @@
"options": "خيارات",
"upload": "تحميل",
"choose_files": "اختر الملفات",
"shrink_images": "تصغير الصور"
"shrink_images": "تصغير الصور",
"upload_attachments_to_note": "تحميل المرفقات الى الملاحظة"
},
"attribute_detail": {
"name": "الاسم",
@@ -74,7 +76,14 @@
"date_time": "التاريخ والوقت",
"label_definition": "تفاصيل تعريف التصنيف",
"relation_definition": "تفاصيل تعريف العلاقة",
"attr_detail_title": "عنوان تفاصيل السمة"
"attr_detail_title": "عنوان تفاصيل السمة",
"close_button_title": "الغاء التغييرات و اغلاق",
"attr_is_owned_by": "السمة مملوكة ل",
"save_and_close": "حفظ ونسخ <kbd>Ctrl+Enter</kbd>",
"workspace_calendar_root": "‎تحديد جذر التقويم لكل مساحة عمل",
"hide_highlight_widget": "اخفاء عنصر واجهة قائمة التمييزات",
"is_owned_by_note": "تخص الملاحظة",
"and_more": "... و {{count}}مرات اكثر."
},
"rename_label": {
"to": "الى",
@@ -86,7 +95,8 @@
"move_note": {
"to": "الى",
"move_note": "نقل الملاحظة",
"target_parent_note": "ملاحظة الاصل الهدف"
"target_parent_note": "ملاحظة الاصل الهدف",
"on_all_matched_notes": "على كل الملاحظات المطابقة"
},
"add_relation": {
"to": "الى",
@@ -106,7 +116,8 @@
"update_relation": "تحديث العلاقة",
"relation_name": "اسم العلاقة",
"target_note": "الملاحظة الهدف",
"update_relation_target": "تحدث علاقة الهدف"
"update_relation_target": "تحدث علاقة الهدف",
"on_all_matched_notes": "على كل الملاحظات المطابقة"
},
"attachments_actions": {
"download": "تنزيل",
@@ -114,7 +125,9 @@
"open_custom": "فتح مخصص",
"rename_attachment": "اعادة تسمية المرفق",
"delete_attachment": "حذف المرفق",
"upload_new_revision": "رفع مراجعة جديدة"
"upload_new_revision": "رفع مراجعة جديدة",
"copy_link_to_clipboard": "نسخ الرابط الى الحافظة",
"convert_attachment_into_note": "تحويل المرفق الى ملاحظة"
},
"calendar": {
"week": "أسبوع",
@@ -146,7 +159,9 @@
"month_previous": "الشهر السابق",
"month_next": "الشهر التالي",
"year_previous": "السنة السابقة",
"year_next": "السنة التالية"
"year_next": "السنة التالية",
"cannot_find_day_note": "لا يمكن ايجاد ملاحظة اليوم",
"cannot_find_week_note": "لايمكن ايجاد ملاحظة الاسبوع"
},
"global_menu": {
"menu": "القائمة",
@@ -171,7 +186,11 @@
"open_dev_tools": "فتح ادوات المطور",
"show_backend_log": "اظهار سجل الخلفية",
"new-version-available": "متوفر تحديث جديد",
"download-update": "احصل على الاصدار{{latestVersion}}"
"download-update": "احصل على الاصدار{{latestVersion}}",
"switch_to_mobile_version": "التبديل الى اصدار الهاتف المحمول",
"switch_to_desktop_version": "التبديل الى اصدار سطح المكتب",
"show_shared_notes_subtree": "عرض شجرة الملاحظات المشتركة",
"open_sql_console_history": "فتح سجل لوحة تحكم SQL"
},
"zpetne_odkazy": {
"relation": "العلاقة",
@@ -181,7 +200,8 @@
"note_icon": {
"category": "الفئة:",
"search": "بحث:",
"change_note_icon": "تغيير ايقونة الملاحظة"
"change_note_icon": "تغيير ايقونة الملاحظة",
"reset-default": "اعادة تعيين الى الايقونة الافتراضية"
},
"basic_properties": {
"language": "اللغة",
@@ -204,7 +224,8 @@
"collapse_all_notes": "طي كل الملاحظات",
"include_archived_notes": "عرض الملاحظات المؤرشفة",
"expand_all_children": "توسيع جميع العناصر الفرعية",
"presentation": "عرض تقديمي"
"presentation": "عرض تقديمي",
"invalid_view_type": "نوع العرض {{type}} غير صالح"
},
"file_properties": {
"download": "تنزيل",
@@ -223,7 +244,8 @@
"file_type": "نوع الملف",
"file_size": "حجم الملف",
"original_file_name": "اسم الملف الاصلي",
"upload_new_revision": "رفع مراجعة جديدة"
"upload_new_revision": "رفع مراجعة جديدة",
"copy_reference_to_clipboard": "نسخ المرجع الى الحافظة"
},
"note_info_widget": {
"created": "انشاء",
@@ -258,14 +280,20 @@
"order_by": "ترتيب حسب",
"search_parameters": "معايير البحث",
"add_search_option": "اضافة خيار البحث:",
"save_to_note": "حفظ في تلملاحظة"
"save_to_note": "حفظ في تلملاحظة",
"limit_description": "تحديد عدد النتائج",
"search_execute": "البحث وتنفيذ الأجراءات",
"unknown_search_option": "خيار بحث غير معروف {{searchOptionName}}",
"actions_executed": "اجراءات تم تنفيذها."
},
"ancestor": {
"label": "السلف",
"depth_label": "العمق",
"depth_doesnt_matter": "لايهم",
"direct_children": "العقد الفرعية المباشرة",
"depth_eq": "يساوي تماما {{count}}"
"depth_eq": "يساوي تماما {{count}}",
"depth_gt": "هو اكبر من {{count}}",
"depth_lt": "هو اصغر من {{count}}"
},
"limit": {
"limit": "الحد الاقصى"
@@ -285,7 +313,9 @@
"revision_count": "عدد المراجعات",
"parent_count": "عدد النسخ",
"owned_label_count": "عدد التسميات",
"owned_relation_count": "عدد العلاقات"
"owned_relation_count": "عدد العلاقات",
"date_modified": "تاريخ اخر تعديل",
"children_count": "عدد الملاحظات الفرعية"
},
"search_string": {
"search_prefix": "بحث:",
@@ -299,7 +329,10 @@
"force_full_sync_button": "فرض مزامنة كاملة",
"finished-successfully": "تم انتهاء المزامنة بنجاح.",
"full_sync_triggered": "تم تشغيل المزامنة الكاملة",
"failed": "فشل في المزامنة: {{message}}"
"failed": "فشل في المزامنة: {{message}}",
"fill_entity_changes_button": "ملء سجلات تغييرات الكيانات",
"filling_entity_changes": "جار ملء صفوف تغييرات الكيانات",
"sync_rows_filled_successfully": "تمة تعبئة بيانات المزامنة بنجاح"
},
"fonts": {
"fonts": "خطوط",
@@ -338,7 +371,8 @@
"export": "تصدير",
"export_note_title": "تصدير الملاحظة",
"export_status": "حالة التصدير",
"export_finished_successfully": "اكتمل التصدير بنجاح."
"export_finished_successfully": "اكتمل التصدير بنجاح.",
"export_in_progress": "جار التصدير: {{progressCount}}"
},
"help": {
"troubleshooting": "أستكشاف الاخطاء واصلاحها",
@@ -366,7 +400,9 @@
"scrollToActiveNote": "مدتمرير الى الملاحظة النشطة",
"jumpToParentNote": "الانتقال الى الملاحظة الاصل",
"movingCloningNotes": "نقل/ استنساخ الملاحظات",
"deleteNotes": "حذف الملاحظة/ الشجرة الفرعية"
"deleteNotes": "حذف الملاحظة/ الشجرة الفرعية",
"collapseWholeTree": "طي شجرة الملاحظة باكملها",
"followLink": "اتبع تلرابط تحت المؤشر"
},
"import": {
"options": "خيارات",
@@ -378,14 +414,18 @@
"chooseImportFile": "اختر ملف الاستيراد",
"failed": "فشل الاستيراد: {{messege}}.",
"html_import_tags": {
"title": "علامات استيراد HTML"
"title": "علامات استيراد HTML",
"reset_button": "اعادة التعيين الى القائمة الافتراضية"
},
"successful": "اكتمل الاستيراد بنجاح."
"successful": "اكتمل الاستيراد بنجاح.",
"in-progress": "جار الاستيراد: {{progress}}"
},
"include_note": {
"label_note": "ملاحظة",
"dialog_title": "تضمين ملاحظة",
"button_include": "تضمين ملاحظة"
"button_include": "تضمين ملاحظة",
"box_size_small": "صغير (10 سطور تقريبا)",
"box_size_medium": "متوسط ( 30 سطر تقريبا)"
},
"info": {
"closeButton": "أغلاق",
@@ -409,7 +449,8 @@
"protected_session_password": {
"close_label": "أغلاق",
"modal_title": "جلسة محمية",
"start_button": "بدء جلسة محمية"
"start_button": "بدء جلسة محمية",
"help_title": "مساعدة حول الملاحظات المحمية"
},
"revisions": {
"delete_button": "حذف",
@@ -423,7 +464,8 @@
"mime": "MIME: ",
"delete_all_button": "حذف كل المراجعات",
"settings": "اعدادات مراجعة الملاحظة",
"diff_not_available": "المقارنة غير متوفرة."
"diff_not_available": "المقارنة غير متوفرة.",
"help_title": "مساعدة حول مراجعات الملاحظة"
},
"sort_child_notes": {
"title": "عنوان",
@@ -442,7 +484,8 @@
"recent_changes": {
"undelete_link": "الغاء الحذف",
"title": "التغيرات الاخيرة",
"no_changes_message": "لايوجد تغيير لحد الان..."
"no_changes_message": "لايوجد تغيير لحد الان...",
"erase_notes_button": "مسح الملاحظات المحذوفة الان"
},
"edited_notes": {
"deleted": "(حذف)",
@@ -458,7 +501,8 @@
"max_width_unit": "بكسل",
"title": "عرض المحتوى",
"reload_button": "اعادة تحميل الواجهة",
"max_width_label": "اقصى عرض للمحتوى"
"max_width_label": "اقصى عرض للمحتوى",
"reload_description": "تغييرات من خيارات المظهر"
},
"native_title_bar": {
"enabled": "مفعل",
@@ -479,7 +523,8 @@
"ui-performance": {
"title": "أداء",
"enable-shadows": "تفعيل الضلال",
"enable-smooth-scroll": "تمكين التمرير السلس"
"enable-smooth-scroll": "تمكين التمرير السلس",
"enable-motion": "تمكين الانتقالات والرسوم المتحركة"
},
"ai_llm": {
"progress": "تقدم",
@@ -543,7 +588,8 @@
"start_indexing": "بدء الفهرسة",
"chat": {
"root_note_title": "دردشات AI",
"new_chat_title": "دردشة جديدة"
"new_chat_title": "دردشة جديدة",
"create_new_ai_chat": "انشاء دردشة AI جديدة"
},
"selected_provider": "المزود المحدد",
"select_model": "اختر النموذج...",
@@ -571,7 +617,21 @@
"enable_ai": "تمكين خصائص AI/LLM",
"reprocess_index": "اعادة بناء فهرس البحث",
"index_rebuilding": "جار تحسين الفهرس {{percentage}}",
"voyage_configuration": "اعدادت Voyage AI"
"voyage_configuration": "اعدادت Voyage AI",
"openai_model_description": "الامثلة: gpt-4o, gpt-4-turbo, gpt-3.5-turbo",
"partial": "{{ percentage }} % مكتمل",
"retry_queued": "تم جدولة الملاحظة لاعادة المحاولة",
"max_notes_per_llm_query": "اكبر عدد للملاحظات لكل استعلام",
"remove_provider": "احذف المزود من البحث",
"restore_provider": "استعادة المزود الى البحث",
"reprocess_index_error": "حدث خطأ اثناء اعادة بناء فهرس البحث",
"auto_refresh_notice": "تحديث تلقائي كل {{seconds}} ثانية",
"note_queued_for_retry": "الملاحظة جاهزة لاعادة المحاولة لاحقا",
"failed_to_retry_note": "‎فشل في اعادة محاولة معالجة المحاولة",
"failed_to_retry_all": "فشل في اعادة محاولة معالجة الملاحظة",
"error_generating_response": "‌فشل في توليد استجابة من ال AI",
"create_new_ai_chat": "انشاء دردشة AI جديدة",
"error_fetching": "فشل في استرجاع النماذج: {{error}}"
},
"code_auto_read_only_size": {
"unit": "حروف",
@@ -586,7 +646,8 @@
"enable_image_compression": "تمكين ضغط الصورة"
},
"revisions_snapshot_limit": {
"snapshot_number_limit_unit": "لقطات"
"snapshot_number_limit_unit": "لقطات",
"note_revisions_snapshot_limit_title": "الحد الاقصى لنسخ الملاحظات الاحتياطية"
},
"search_engine": {
"bing": "Bing",
@@ -874,7 +935,10 @@
"unset-field-placeholder": "غير محدد",
"open_external_link": "فتح رابط خارجي",
"add_new_attribute": "اضافة سمة جديدة",
"remove_this_attribute": "حذف هذه السمة"
"remove_this_attribute": "حذف هذه السمة",
"unknown_label_type": "نوع التسمية {{type}} غير معروف",
"unknown_attribute_type": "نوع السمة {{type}} غير معروف",
"remove_color": "حذف لون التسمية"
},
"duration": {
"seconds": "ثواني",
@@ -885,7 +949,8 @@
"editorfeatures": {
"title": "مميزات",
"note_completion_enabled": "تمكين الاكمال التلقائي للملاحظة",
"emoji_completion_enabled": "تفعيل الاكمال التلقائي للرموز التعبيرية"
"emoji_completion_enabled": "تفعيل الاكمال التلقائي للرموز التعبيرية",
"slash_commands_enabled": "تفعيل اوامر Slash"
},
"book_properties_config": {
"raster": "نقطي",
@@ -921,7 +986,8 @@
"add_label": "اضافة تسمية",
"to_value": "الى القيمة",
"new_value_placeholder": "قيمة جديدة",
"label_name_placeholder": "اسم التسمية"
"label_name_placeholder": "اسم التسمية",
"help_text": "عل كل الملاحظات المطابقة:"
},
"delete_label": {
"delete_label": "حذف التسمية",
@@ -939,7 +1005,8 @@
},
"rename_note": {
"rename_note": "اعادة تسمية الملاحظة",
"new_note_title": "عنوان ملاحظة جديد"
"new_note_title": "عنوان ملاحظة جديد",
"rename_note_title_to": "اعادة تسمية عنوان الملاحظة الى"
},
"delete_relation": {
"delete_relation": "حذف العلاقة",
@@ -966,7 +1033,8 @@
"search_in_note": "بحث في الملاحظة",
"open_note_externally": "فتح الملاحظة خارجيا",
"open_note_custom": "فتح ملاحظة مخصص",
"print_pdf": "تصدير كملف PDF..."
"print_pdf": "تصدير كملف PDF...",
"convert_into_attachment_failed": "فشل تحويل الملاحظة {{title}}."
},
"update_available": {
"update_available": "تحديث متوفر"
@@ -974,7 +1042,8 @@
"code_buttons": {
"execute_button_title": "تنفيذ السكريبت",
"save_to_note_button_title": "حفظ في الملاحظا",
"opening_api_docs_message": "جاري فتح مستدات API..."
"opening_api_docs_message": "جاري فتح مستدات API...",
"trilium_api_docs_button_title": "فتح مستندات API لتريليوم"
},
"hide_floating_buttons_button": {
"button_title": "اخفاء الازرار"
@@ -994,13 +1063,15 @@
"title": "خريطة الملاحظة",
"fix-nodes": "اصلاح العقد",
"link-distance": "مسافة الرابط",
"open_full": "توسيع للعرض الكامل"
"open_full": "توسيع للعرض الكامل",
"collapse": "طي الى الحجم الطبيعي"
},
"owned_attribute_list": {
"owned_attributes": "السمات المملوكة"
},
"similar_notes": {
"title": "ملاحظات مشابهة"
"title": "ملاحظات مشابهة",
"no_similar_notes_found": "لاتوجد ملاحظة مشابهة."
},
"fast_search": {
"fast_search": "بحث سريع"
@@ -1010,7 +1081,8 @@
"example_title": "انظر هذا المثال:"
},
"attachment_detail": {
"owning_note": "الملاحظة المالكة: "
"owning_note": "الملاحظة المالكة: ",
"list_of_all_attachments": "قائمة بكل المرفقات"
},
"attachment_list": {
"owning_note": "الملاحظة المالكة: ",
@@ -1021,14 +1093,21 @@
"protecting-title": "الحالة المحمية",
"unprotecting-title": "الحالة الغير محمية",
"protecting-finished-successfully": "تم الحماية بنجاح.",
"unprotecting-finished-successfully": "تم ازالة الحماية بنجاح."
"unprotecting-finished-successfully": "تم ازالة الحماية بنجاح.",
"start_session_button": "البدء بالجلسة المحمية </kbd>enter</kbd>",
"protecting-in-progress": "جار الحماية: {{count}}",
"unprotecting-in-progress-count": "‏جار الغاء الحماية: {{count}}"
},
"relation_map": {
"remove_note": "حذف الملاحظة",
"edit_title": "تعديل العنوان",
"rename_note": "اعادة تسمية الملاحظة",
"remove_relation": "حذف العلاقة",
"default_new_note_title": "ملاحظة جديدة"
"default_new_note_title": "ملاحظة جديدة",
"open_in_new_tab": "فتح في تبويب جديد",
"enter_new_title": "ادخل عنوان ملاحظة جديدة:",
"note_not_found": "الملاحظة {{noteId}} غير موجودة!",
"cannot_match_transform": "تعذر مطابقة التحويل: {{transform}}"
},
"web_view": {
"web_view": "عرض الويب"
@@ -1045,7 +1124,8 @@
"vacuum_database": {
"title": "تحرير مساحة قاعدة البيانات",
"button_text": "تحرير مساحة قاعدة البيانات",
"vacuuming_database": "جار تحرير مساحة قاعدة الييانات..."
"vacuuming_database": "جار تحرير مساحة قاعدة الييانات...",
"database_vacuumed": "تم تنظيف قاعدة البيانات"
},
"ribbon": {
"widgets": "ادوات الشريط"
@@ -1054,7 +1134,8 @@
"use_vim_keybindings_in_code_notes": "اختصارات لوحة المفاتيح باسلوب Vim"
},
"network_connections": {
"network_connections_title": "اتصالات الشبكة"
"network_connections_title": "اتصالات الشبكة",
"check_for_updates": "‪التحقق من وجود تحديثات تلقائية"
},
"tray": {
"title": "شريط النظام"
@@ -1189,7 +1270,9 @@
},
"move_to": {
"notes_to_move": "الملاحظات المراد نقلها",
"target_parent_note": "ملاحظة الاصل الهدف"
"target_parent_note": "ملاحظة الاصل الهدف",
"dialog_title": "انقل الملاحظات الى...",
"move_button": "نقل الىالملاحظة المحددة"
},
"delete_revisions": {
"delete_note_revisions": "حذف مراجعات الملاحظة"
@@ -1236,7 +1319,10 @@
"enter_workspace": "ادخل مساحة العمل {{title}}"
},
"attribute_editor": {
"save_attributes": "حفظ السمات <enter>"
"save_attributes": "حفظ السمات <enter>",
"add_a_new_attribute": "اضافة سمة جديدة",
"add_new_label_definition": "اضافة تعريف لتسمية جديدة",
"add_new_relation_definition": "اضافة تعريف لعلاقة جديدة"
},
"zen_mode": {
"button_exit": "الخروج من وضع Zen"
@@ -1246,7 +1332,8 @@
},
"note_erasure_timeout": {
"note_erasure_timeout_title": "مهلة مسح الملاحظة",
"erase_notes_after": "مسح الملاحظات بعد:"
"erase_notes_after": "مسح الملاحظات بعد:",
"erase_deleted_notes_now": "مسح الملاحظات المحذوفة الان"
},
"ws": {
"sync-check-failed": "فشل التحقق من المزامنة!"
@@ -1257,5 +1344,27 @@
"presentation_view": {
"start-presentation": "بدء العرض التقديمي",
"edit-slide": "تعديل هذه الشريحة"
},
"jump_to_note": {
"search_button": "البحث في النص الكامل"
},
"password_not_set": {
"title": "لم يتم تعيين كلمة المرور",
"go_to_password_options": "اذهب الى خيارات كلمة المرور"
},
"abstract_bulk_action": {
"remove_this_search_action": "حذف اجراء البحث هذا"
},
"show_toc_widget_button": {
"show_toc": "عرض جدول المحتويات"
},
"svg_export_button": {
"button_title": "تصدير المخطط ك SVG"
},
"abstract_search_option": {
"remove_this_search_option": "حذف خيار البحث هذا"
},
"revisions_snapshot_interval": {
"note_revisions_snapshot_interval_title": "الفاصل الزمني لنسخ الملاحظات الاحتياطية"
}
}

View File

@@ -4,7 +4,7 @@
"homepage": "Domovská stránka:",
"app_version": "Verze aplikace:",
"db_version": "Verze DB:",
"sync_version": "Verze sync:",
"sync_version": "Verze synchronizace:",
"build_date": "Datum sestavení:",
"build_revision": "Revize sestavení:",
"data_directory": "Datový adresář:"
@@ -36,6 +36,29 @@
"add_link": "Přidat odkaz",
"help_on_links": "Nápověda k odkazům",
"note": "Poznámka",
"search_note": "hledat poznámku podle názvu"
"search_note": "hledat poznámku podle názvu",
"link_title": "Název odkazu",
"button_add_link": "Přidat odkaz"
},
"branch_prefix": {
"prefix": "Prefix: ",
"save": "Uložit"
},
"bulk_actions": {
"bulk_actions": "Hromadné akce",
"affected_notes": "Ovlivněné poznámky",
"notes": "Poznámky"
},
"confirm": {
"cancel": "Zrušit",
"ok": "OK"
},
"delete_notes": {
"cancel": "Zrušit",
"ok": "OK",
"close": "Zavřít"
},
"export": {
"close": "Zavřít"
}
}

View File

@@ -646,7 +646,8 @@
"about": "Über Trilium Notes",
"logout": "Abmelden",
"show-cheatsheet": "Cheatsheet anzeigen",
"toggle-zen-mode": "Zen Modus"
"toggle-zen-mode": "Zen Modus",
"new-version-available": "Neues Update verfügbar"
},
"sync_status": {
"unknown": "<p>Der Synchronisations-Status wird bekannt, sobald der nächste Synchronisierungsversuch gestartet wird.</p><p>Klicke, um eine Synchronisierung jetzt auszulösen.</p>",
@@ -763,7 +764,8 @@
"table": "Tabelle",
"geo-map": "Weltkarte",
"board": "Tafel",
"include_archived_notes": "Zeige archivierte Notizen"
"include_archived_notes": "Zeige archivierte Notizen",
"presentation": "Präsentation"
},
"edited_notes": {
"no_edited_notes_found": "An diesem Tag wurden noch keine Notizen bearbeitet...",
@@ -2074,5 +2076,9 @@
},
"collections": {
"rendering_error": "Aufgrund eines Fehlers können keine Inhalte angezeigt werden."
},
"presentation_view": {
"edit-slide": "Diese Folie bearbeiten",
"start-presentation": "Präsentation starten"
}
}

View File

@@ -164,6 +164,7 @@
"importIntoNote": "Import into note",
"chooseImportFile": "Choose import file",
"importDescription": "Content of the selected file(s) will be imported as child note(s) into",
"importZipRecommendation": "When importing a ZIP file, the note hierarchy will reflect the subdirectory structure within the archive.",
"options": "Options",
"safeImportTooltip": "Trilium <code>.zip</code> export files can contain executable scripts which may contain harmful behavior. Safe import will deactivate automatic execution of all imported scripts. Uncheck \"Safe import\" only if the imported archive is supposed to contain executable scripts and you completely trust the contents of the import file.",
"safeImport": "Safe import",
@@ -1722,7 +1723,9 @@
"window-on-top": "Keep Window on Top"
},
"note_detail": {
"could_not_find_typewidget": "Could not find typeWidget for type '{{type}}'"
"could_not_find_typewidget": "Could not find typeWidget for type '{{type}}'",
"printing": "Printing in progress...",
"printing_pdf": "Exporting to PDF in progress..."
},
"note_title": {
"placeholder": "type note's title here..."

View File

@@ -692,6 +692,14 @@
"help_text_body3": "In alternativa, è possibile aggiungere etichette e relazioni utilizzando il pulsante <code>+</code> sul lato destro.",
"save_attributes": "Salva attributi <enter>",
"add_a_new_attribute": "Aggiungi un nuovo attributo",
"add_new_label": "Aggiungi nuova etichetta <kbd data-command=\"addNewLabel\"></kbd>"
"add_new_label": "Aggiungi nuova etichetta <kbd data-command=\"addNewLabel\"></kbd>",
"add_new_relation": "Aggiungi nuova relazione <kbd data-command=\"addNewRelation\"></kbd>",
"add_new_relation_definition": "Aggiungi una nuova definizione di relazione",
"placeholder": "Digitare qui le etichette e le relazioni"
},
"execute_script": {
"execute_script": "Esegui script",
"help_text": "È possibile eseguire semplici script sulle note abbinate.",
"example_1": "Ad esempio, per aggiungere una stringa al titolo di una nota, utilizzare questo piccolo script:"
}
}

View File

@@ -282,8 +282,8 @@
"selectAllNotes": "現在のレベルのノートをすべて選択",
"selectNote": "ノートを選択",
"copyNotes": "アクティブなノート(または現在の選択範囲)をクリップボードにコピーする(<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">クローン</a>に使用)",
"cutNotes": "アクティブなノート(または現在の選択範囲)をクリップボードにカットする(ノートの移動に使用)",
"pasteNotes": "ノートをサブノートとしてアクティブノートに貼り付ける(コピーされたかカットされたかに よって、移動またはクローンになる)",
"cutNotes": "アクティブなノート(または現在の選択範囲)をクリップボードに切り取り(ノートの移動に使用)",
"pasteNotes": "ノートをサブノートとしてアクティブノートに貼り付ける(コピーされたか切り取りされたかに よって、移動またはクローンになる)",
"deleteNotes": "ノート/サブツリーを削除",
"editingNotes": "ノート編集",
"editNoteTitle": "押下するとツリーペインからタイトルの編集に移ります。タイトルの編集からEnterキーを押すと、本文の編集に移動します。<kbd>Ctrl+.</kbd> で本文の編集からツリーペインに戻ります。",
@@ -302,7 +302,7 @@
"showDevTools": "開発者ツールを表示",
"showSQLConsole": "SQLコンソールを表示",
"other": "その他",
"quickSearch": "クイックサーチにフォーカス",
"quickSearch": "クイック検索にフォーカス",
"inPageSearch": "ページ内検索",
"showJumpToNoteDialog": "<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">「ジャンプ先」ダイアログ</a>を表示",
"moveNoteUpDown": "ノートリストでノートを上/下に移動",
@@ -405,7 +405,7 @@
"unprotect-subtree": "サブツリーの保護を解除",
"copy-clone": "コピー/クローン",
"clone-to": "クローン先...",
"cut": "カット",
"cut": "切り取り",
"move-to": "移動先...",
"paste-into": "貼り付け",
"paste-after": "後ろに貼り付け",
@@ -1189,7 +1189,7 @@
"options": "オプション"
},
"quick-search": {
"placeholder": "クイックサーチ",
"placeholder": "クイック検索",
"searching": "検索中...",
"no-results": "結果は見つかりませんでした",
"more-results": "... および {{number}} 件の他の結果。",
@@ -1245,7 +1245,7 @@
"duplicated": "ノート \"{{title}}\" は複製されました。"
},
"clipboard": {
"cut": "ノートはクリップボードにカットされました。",
"cut": "ノートはクリップボードに切り取りとられました。",
"copied": "ノートはクリップボードにコピーされました。",
"copy_failed": "権限の問題で、クリップボードにコピーできません。",
"copy_success": "クリップボードにコピーしました。"
@@ -1296,7 +1296,7 @@
},
"electron_context_menu": {
"add-term-to-dictionary": "辞書に \"{{term}}\" を追加",
"cut": "カット",
"cut": "切り取り",
"copy": "コピー",
"copy-link": "リンクをコピー",
"paste": "貼り付け",
@@ -1882,7 +1882,9 @@
"window-on-top": "ウィンドウを最前面に維持"
},
"note_detail": {
"could_not_find_typewidget": "タイプ {{type}} の typeWidget が見つかりませんでした"
"could_not_find_typewidget": "タイプ {{type}} の typeWidget が見つかりませんでした",
"printing": "印刷中です...",
"printing_pdf": "PDF へのエクスポート中です..."
},
"watched_file_update_status": {
"ignore_this_change": "この変更を無視する",

File diff suppressed because it is too large Load Diff

View File

@@ -765,7 +765,8 @@
"table": "表格",
"geo-map": "地理地圖",
"board": "看板",
"include_archived_notes": "顯示已封存筆記"
"include_archived_notes": "顯示已封存筆記",
"presentation": "簡報"
},
"edited_notes": {
"no_edited_notes_found": "今天還沒有編輯過的筆記...",
@@ -1516,7 +1517,9 @@
"window-on-top": "保持此視窗置頂"
},
"note_detail": {
"could_not_find_typewidget": "找不到類型為 '{{type}}' 的 typeWidget"
"could_not_find_typewidget": "找不到類型為 '{{type}}' 的 typeWidget",
"printing": "正在列印…",
"printing_pdf": "正在匯出為 PDF…"
},
"note_title": {
"placeholder": "請輸入筆記標題..."
@@ -2074,5 +2077,10 @@
},
"collections": {
"rendering_error": "發現錯誤,無法顯示內容。"
},
"presentation_view": {
"edit-slide": "編輯此投影片",
"start-presentation": "開始簡報",
"slide-overview": "切換投影片概覽"
}
}

View File

@@ -16,7 +16,7 @@ interface ElectronProcess {
interface CustomGlobals {
isDesktop: typeof utils.isDesktop;
isMobile: typeof utils.isMobile;
device: "mobile" | "desktop";
device: "mobile" | "desktop" | "print";
getComponentByEl: typeof appContext.getComponentByEl;
getHeaders: typeof server.getHeaders;
getReferenceLinkTitle: (href: string) => Promise<string>;
@@ -59,6 +59,9 @@ declare global {
process?: ElectronProcess;
glob?: CustomGlobals;
/** On the printing endpoint, set to true when the note has fully loaded and is ready to be printed/exported as PDF. */
_noteReady?: boolean;
EXCALIDRAW_ASSET_PATH?: string;
}

View File

@@ -1,4 +1,4 @@
import { allViewTypes, ViewModeProps, ViewTypeOptions } from "./interface";
import { allViewTypes, ViewModeMedia, ViewModeProps, ViewTypeOptions } from "./interface";
import { useNoteContext, useNoteLabel, useNoteLabelBoolean, useTriliumEvent } from "../react/hooks";
import FNote from "../../entities/fnote";
import "./NoteList.css";
@@ -22,9 +22,11 @@ interface NoteListProps {
displayOnlyCollections?: boolean;
isEnabled: boolean;
ntxId: string | null | undefined;
media: ViewModeMedia;
onReady?: () => void;
}
export default function NoteList<T extends object>(props: Pick<NoteListProps, "displayOnlyCollections">) {
export default function NoteList<T extends object>(props: Pick<NoteListProps, "displayOnlyCollections" | "media" | "onReady">) {
const { note, noteContext, notePath, ntxId } = useNoteContext();
const isEnabled = noteContext?.hasNoteList();
return <CustomNoteList note={note} isEnabled={!!isEnabled} notePath={notePath} ntxId={ntxId} {...props} />
@@ -34,10 +36,10 @@ export function SearchNoteList<T extends object>(props: Omit<NoteListProps, "isE
return <CustomNoteList {...props} isEnabled={true} />
}
function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, notePath, highlightedTokens, displayOnlyCollections, ntxId }: NoteListProps) {
export function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, notePath, highlightedTokens, displayOnlyCollections, ntxId, onReady, ...restProps }: NoteListProps) {
const widgetRef = useRef<HTMLDivElement>(null);
const viewType = useNoteViewType(note);
const noteIds = useNoteIds(note, viewType, ntxId);
const noteIds = useNoteIds(shouldEnable ? note : null, viewType, ntxId);
const isFullHeight = (viewType && viewType !== "list" && viewType !== "grid");
const [ isIntersecting, setIsIntersecting ] = useState(false);
const shouldRender = (isFullHeight || isIntersecting || note?.type === "book");
@@ -76,12 +78,14 @@ function CustomNoteList<T extends object>({ note, isEnabled: shouldEnable, noteP
note, noteIds, notePath,
highlightedTokens,
viewConfig: viewModeConfig[0],
saveConfig: viewModeConfig[1]
saveConfig: viewModeConfig[1],
onReady: onReady ?? (() => {}),
...restProps
}
}
return (
<div ref={widgetRef} className={`note-list-widget component ${isFullHeight ? "full-height" : ""}`}>
<div ref={widgetRef} className={`note-list-widget component ${isFullHeight && isEnabled ? "full-height" : ""}`}>
{props && isEnabled && (
<div className="note-list-widget-content">
{getComponentByViewType(viewType, props)}
@@ -123,7 +127,7 @@ function useNoteViewType(note?: FNote | null): ViewTypeOptions | undefined {
}
}
function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined, ntxId: string | null | undefined) {
export function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined, ntxId: string | null | undefined) {
const [ noteIds, setNoteIds ] = useState<string[]>([]);
const [ includeArchived ] = useNoteLabelBoolean(note, "includeArchived");
@@ -136,7 +140,7 @@ function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions |
}
async function getNoteIds(note: FNote) {
if (viewType === "list" || viewType === "grid") {
if (viewType === "list" || viewType === "grid" || viewType === "table" || note.type === "search") {
return note.getChildNoteIds();
} else {
return await note.getSubtreeNoteIds(includeArchived);
@@ -187,7 +191,7 @@ function useNoteIds(note: FNote | null | undefined, viewType: ViewTypeOptions |
return noteIds;
}
function useViewModeConfig<T extends object>(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined) {
export function useViewModeConfig<T extends object>(note: FNote | null | undefined, viewType: ViewTypeOptions | undefined) {
const [ viewConfig, setViewConfig ] = useState<[T | undefined, (data: T) => void]>();
useEffect(() => {

View File

@@ -66,7 +66,7 @@ async function recursiveGroupBy(branches: FBranch[], byColumn: ColumnMap, groupB
const note = await branch.getNote();
if (!note || (!includeArchived && note.isArchived)) continue;
if (note.hasChildren()) {
if (note.type !== "search" && note.hasChildren()) {
await recursiveGroupBy(note.getChildBranches(), byColumn, groupByColumn, includeArchived);
}

View File

@@ -3,6 +3,8 @@ import FNote from "../../entities/fnote";
export const allViewTypes = ["list", "grid", "calendar", "table", "geoMap", "board", "presentation"] as const;
export type ViewTypeOptions = typeof allViewTypes[number];
export type ViewModeMedia = "screen" | "print";
export interface ViewModeProps<T extends object> {
note: FNote;
notePath: string;
@@ -13,4 +15,6 @@ export interface ViewModeProps<T extends object> {
highlightedTokens: string[] | null | undefined;
viewConfig: T | undefined;
saveConfig(newConfig: T): void;
media: ViewModeMedia;
onReady(): void;
}

View File

@@ -106,6 +106,12 @@
text-align: center;
}
.note-list.list-view .note-path {
margin-left: 0.5em;
vertical-align: middle;
opacity: 0.5;
}
/* #region Grid view */
.note-list.grid-view .note-list-container {
display: flex;

View File

@@ -74,7 +74,7 @@ function ListNoteCard({ note, parentNote, expand, highlightedTokens }: { note: F
/>
<Icon className="note-icon" icon={note.getIcon()} />
<NoteLink className="note-book-title" notePath={notePath} noPreview showNotePath={note.type === "search"} highlightedTokens={highlightedTokens} />
<NoteLink className="note-book-title" notePath={notePath} noPreview showNotePath={parentNote.type === "search"} highlightedTokens={highlightedTokens} />
<NoteAttributes note={note} />
</h5>

View File

@@ -1,4 +1,4 @@
import { ViewModeProps } from "../interface";
import { ViewModeMedia, ViewModeProps } from "../interface";
import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
import Reveal from "reveal.js";
import slideBaseStylesheet from "reveal.js/dist/reveal.css?raw";
@@ -14,11 +14,11 @@ import { t } from "../../../services/i18n";
import { DEFAULT_THEME, loadPresentationTheme } from "./themes";
import FNote from "../../../entities/fnote";
export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) {
export default function PresentationView({ note, noteIds, media, onReady }: ViewModeProps<{}>) {
const [ presentation, setPresentation ] = useState<PresentationModel>();
const containerRef = useRef<HTMLDivElement>(null);
const [ api, setApi ] = useState<Reveal.Api>();
const stylesheets = usePresentationStylesheets(note);
const stylesheets = usePresentationStylesheets(note, media);
function refresh() {
buildPresentationModel(note).then(setPresentation);
@@ -33,31 +33,59 @@ export default function PresentationView({ note, noteIds }: ViewModeProps<{}>) {
useLayoutEffect(refresh, [ note, noteIds ]);
return presentation && stylesheets && (
useEffect(() => {
// We need to wait for Reveal.js to initialize (by setting api) and for the presentation to become available.
if (api && presentation) {
// Timeout is necessary because it otherwise can cause flakiness by rendering only the first slide.
setTimeout(onReady, 200);
}
}, [ api, presentation ]);
if (!presentation || !stylesheets) return;
const content = (
<>
<ShadowDom
className="presentation-container"
containerRef={containerRef}
>
{stylesheets.map(stylesheet => <style>{stylesheet}</style>)}
<Presentation presentation={presentation} setApi={setApi} />
</ShadowDom>
<ButtonOverlay containerRef={containerRef} api={api} />
{stylesheets.map(stylesheet => <style>{stylesheet}</style>)}
<Presentation presentation={presentation} setApi={setApi} />
</>
)
);
if (media === "screen") {
return (
<>
<ShadowDom
className="presentation-container"
containerRef={containerRef}
>{content}</ShadowDom>
<ButtonOverlay containerRef={containerRef} api={api} />
</>
)
} else if (media === "print") {
// Printing needs a query parameter that is read by Reveal.js.
const url = new URL(window.location.href);
url.searchParams.set("print-pdf", "");
window.history.replaceState({}, '', url);
// Shadow DOM doesn't work well with Reveal.js's PDF printing mechanism.
return content;
}
}
function usePresentationStylesheets(note: FNote) {
function usePresentationStylesheets(note: FNote, media: ViewModeMedia) {
const [ themeName ] = useNoteLabelWithDefault(note, "presentation:theme", DEFAULT_THEME);
const [ stylesheets, setStylesheets ] = useState<string[]>();
useLayoutEffect(() => {
loadPresentationTheme(themeName).then((themeStylesheet) => {
setStylesheets([
let stylesheets = [
slideBaseStylesheet,
themeStylesheet,
slideCustomStylesheet
].map(stylesheet => stylesheet.replace(/:root/g, ":host")));
];
if (media === "screen") {
// We are rendering in the shadow DOM, so the global variables are not set correctly.
stylesheets = stylesheets.map(stylesheet => stylesheet.replace(/:root/g, ":host"));
}
setStylesheets(stylesheets);
});
}, [ themeName ]);
@@ -128,6 +156,7 @@ function Presentation({ presentation, setApi } : { presentation: PresentationMod
const api = new Reveal(containerRef.current, {
transition: "slide",
embedded: true,
pdfMaxPagesPerSlide: 1,
keyboardCondition(event) {
// Full-screen requests sometimes fail, we rely on the UI button instead.
if (event.key === "f") {

View File

@@ -26,7 +26,7 @@ export async function buildPresentationModel(note: FNote): Promise<PresentationM
const slideNotes = await note.getChildNotes();
const slides: PresentationSlideModel[] = await Promise.all(slideNotes.map(async slideNote => ({
...(await buildSlideModel(slideNote)),
verticalSlides: await buildVerticalSlides(slideNote)
verticalSlides: note.type !== "search" ? await buildVerticalSlides(slideNote) : undefined
})));
postProcessSlides(slides);

View File

@@ -2,7 +2,7 @@ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "p
import { ViewModeProps } from "../interface";
import { buildColumnDefinitions } from "./columns";
import getAttributeDefinitionInformation, { buildRowDefinitions, TableData } from "./rows";
import { useLegacyWidget, useNoteLabelBoolean, useNoteLabelInt, useSpacedUpdate, useTriliumEvent } from "../../react/hooks";
import { useLegacyWidget, useNoteLabelBoolean, useNoteLabelInt, useTriliumEvent } from "../../react/hooks";
import Tabulator from "./tabulator";
import { Tabulator as VanillaTabulator, SortModule, FormatModule, InteractionModule, EditModule, ResizeColumnsModule, FrozenColumnsModule, PersistenceModule, MoveColumnsModule, MoveRowsModule, ColumnDefinition, DataTreeModule, Options, RowComponent} from 'tabulator-tables';
import { useContextMenu } from "./context_menu";
@@ -17,6 +17,7 @@ import AttributeDetailWidget from "../../attribute_widgets/attribute_detail";
import attributes from "../../../services/attributes";
import { RefObject } from "preact";
import SpacedUpdate from "../../../services/spaced_update";
import froca from "../../../services/froca";
interface TableConfig {
tableData: {
@@ -132,25 +133,27 @@ function useData(note: FNote, noteIds: string[], viewConfig: TableConfig | undef
const [ isSorted ] = useNoteLabelBoolean(note, "sorted");
const [ movableRows, setMovableRows ] = useState(false);
function refresh() {
async function refresh() {
const info = getAttributeDefinitionInformation(note);
buildRowDefinitions(note, info, includeArchived, maxDepth).then(({ definitions: rowData, hasSubtree: hasChildren, rowNumber }) => {
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber,
position: newAttributePosition.current ?? undefined
});
setColumnDefs(columnDefs);
setRowData(rowData);
setHasChildren(hasChildren);
resetNewAttributePosition();
// Ensure all note IDs are loaded.
await froca.getNotes(noteIds);
const { definitions: rowData, hasSubtree: hasChildren, rowNumber } = await buildRowDefinitions(note, info, includeArchived, maxDepth);
const columnDefs = buildColumnDefinitions({
info,
movableRows,
existingColumnData: viewConfig?.tableData?.columns,
rowNumberHint: rowNumber,
position: newAttributePosition.current ?? undefined
});
setColumnDefs(columnDefs);
setRowData(rowData);
setHasChildren(hasChildren);
resetNewAttributePosition();
}
useEffect(refresh, [ note, noteIds, maxDepth, movableRows ]);
useEffect(() => { refresh() }, [ note, noteIds, maxDepth, movableRows ]);
useTriliumEvent("entitiesReloaded", ({ loadResults}) => {
// React to column changes.

View File

@@ -20,6 +20,10 @@ export async function buildRowDefinitions(parentNote: FNote, infos: AttributeDef
let hasSubtree = false;
let rowNumber = childBranches.length;
if (parentNote.type === "search") {
maxDepth = 0;
}
for (const branch of childBranches) {
const note = await branch.getNote();
if (!note || (!includeArchived && note.isArchived)) {

View File

@@ -37,7 +37,7 @@ export default function ImportDialog() {
onSubmit={async () => {
if (!files || !parentNoteId) {
return;
}
}
const options: UploadFilesOptions = {
safeImport: boolToString(safeImport),
@@ -51,11 +51,19 @@ export default function ImportDialog() {
setShown(false);
await importService.uploadFiles("notes", parentNoteId, Array.from(files), options);
}}
onHidden={() => setShown(false)}
onHidden={() => {
setShown(false);
setFiles(null);
}}
footer={<Button text={t("import.import")} primary disabled={!files} />}
show={shown}
>
<FormGroup name="files" label={t("import.chooseImportFile")} description={<>{t("import.importDescription")} <strong>{ noteTitle }</strong></>}>
<FormGroup name="files" label={t("import.chooseImportFile")} description={
<>
{t("import.importDescription")} <strong>{ noteTitle }</strong>.<br />
{t("import.importZipRecommendation")}
</>
}>
<FormFileUpload multiple onChange={setFiles} />
</FormGroup>
@@ -82,7 +90,7 @@ export default function ImportDialog() {
currentValue={codeImportedAsCode} onChange={setCodeImportedAsCode}
/>
<FormCheckbox
name="replace-underscores-with-spaces" label={t("import.replaceUnderscoresWithSpaces")}
name="replace-underscores-with-spaces" label={t("import.replaceUnderscoresWithSpaces")}
currentValue={replaceUnderscoresWithSpaces} onChange={setReplaceUnderscoresWithSpaces}
/>
</FormMultiGroup>
@@ -92,4 +100,4 @@ export default function ImportDialog() {
function boolToString(value: boolean) {
return value ? "true" : "false";
}
}

View File

@@ -40,14 +40,17 @@ export default function UploadAttachmentsDialog() {
if (!files || !parentNoteId) {
return;
}
setIsUploading(true);
const filesCopy = Array.from(files);
await importService.uploadFiles("attachments", parentNoteId, filesCopy, { shrinkImages });
setIsUploading(false);
setShown(false);
}}
onHidden={() => setShown(false)}
onHidden={() => {
setShown(false);
setFiles(null);
}}
show={shown}
>
<FormGroup name="files" label={t("upload_attachments.choose_files")} description={description}>
@@ -55,7 +58,7 @@ export default function UploadAttachmentsDialog() {
</FormGroup>
<FormGroup name="shrink-images" label={t("upload_attachments.options")}>
<FormCheckbox
<FormCheckbox
hint={t("upload_attachments.tooltip")} label={t("upload_attachments.shrink_images")}
currentValue={shrinkImages} onChange={setShrinkImages}
/>

View File

@@ -28,11 +28,12 @@ import ContentWidgetTypeWidget from "./type_widgets/content_widget.js";
import AttachmentListTypeWidget from "./type_widgets/attachment_list.js";
import AttachmentDetailTypeWidget from "./type_widgets/attachment_detail.js";
import MindMapWidget from "./type_widgets/mind_map.js";
import utils from "../services/utils.js";
import utils, { isElectron } from "../services/utils.js";
import type { NoteType } from "../entities/fnote.js";
import type TypeWidget from "./type_widgets/type_widget.js";
import { MermaidTypeWidget } from "./type_widgets/mermaid.js";
import AiChatTypeWidget from "./type_widgets/ai_chat.js";
import toast from "../services/toast.js";
const TPL = /*html*/`
<div class="note-detail">
@@ -140,6 +141,13 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
doRender() {
this.$widget = $(TPL);
this.contentSized();
if (utils.isElectron()) {
const { ipcRenderer } = utils.dynamicRequire("electron");
ipcRenderer.on("print-done", () => {
toast.closePersistent("printing");
});
}
}
async refresh() {
@@ -297,18 +305,53 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
return;
}
// Trigger in timeout to dismiss the menu while printing.
setTimeout(window.print, 0);
toast.showPersistent({
icon: "bx bx-loader-circle bx-spin",
message: t("note_detail.printing"),
id: "printing"
});
if (isElectron()) {
const { ipcRenderer } = utils.dynamicRequire("electron");
ipcRenderer.send("print-note", {
notePath: this.notePath
});
} else {
const iframe = document.createElement('iframe');
iframe.src = `?print#${this.notePath}`;
iframe.className = "print-iframe";
document.body.appendChild(iframe);
iframe.onload = () => {
if (!iframe.contentWindow) {
toast.closePersistent("printing");
document.body.removeChild(iframe);
return;
}
iframe.contentWindow.addEventListener("note-ready", () => {
toast.closePersistent("printing");
iframe.contentWindow?.print();
document.body.removeChild(iframe);
});
};
}
}
async exportAsPdfEvent() {
if (!this.noteContext?.isActive() || !this.note) {
if (!this.noteContext?.isActive() || !this.note || !this.notePath) {
return;
}
toast.showPersistent({
icon: "bx bx-loader-circle bx-spin",
message: t("note_detail.printing_pdf"),
id: "printing"
});
const { ipcRenderer } = utils.dynamicRequire("electron");
ipcRenderer.send("export-as-pdf", {
title: this.note.title,
notePath: this.notePath,
pageSize: this.note.getAttributeValue("label", "printPageSize") ?? "Letter",
landscape: this.note.hasAttribute("label", "printLandscape")
});

View File

@@ -78,6 +78,10 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
return true;
}
if (note.type === "search" && ![ "grid", "list" ].includes(note.getLabelValue("viewType") ?? "list")) {
return true;
}
return !!note?.isLabelTruthy("fullContentWidth");
}
@@ -87,7 +91,7 @@ export default class NoteWrapperWidget extends FlexContainer<BasicWidget> {
const noteId = this.noteContext?.noteId;
if (
loadResults.isNoteReloaded(noteId) ||
loadResults.getAttributeRows().find((attr) => attr.type === "label" && ["cssClass", "language"].includes(attr.name ?? "") && attributeService.isAffecting(attr, this.noteContext?.note))
loadResults.getAttributeRows().find((attr) => attr.type === "label" && ["cssClass", "language", "viewType"].includes(attr.name ?? "") && attributeService.isAffecting(attr, this.noteContext?.note))
) {
this.refresh();
}

View File

@@ -1,6 +1,6 @@
import { Ref } from "preact";
import Button, { ButtonProps } from "./Button";
import { useRef } from "preact/hooks";
import { useEffect, useRef } from "preact/hooks";
interface FormFileUploadProps {
name?: string;
@@ -11,6 +11,11 @@ interface FormFileUploadProps {
}
export default function FormFileUpload({ inputRef, name, onChange, multiple, hidden }: FormFileUploadProps) {
// Prevent accidental reuse of a file selected in a previous instance of the upload form.
useEffect(() => {
onChange(null);
}, []);
return (
<label class="tn-file-input tn-input-field" style={hidden ? { display: "none" } : undefined}>
<input
@@ -18,7 +23,7 @@ export default function FormFileUpload({ inputRef, name, onChange, multiple, hid
name={name}
type="file"
class="form-control-file"
multiple={multiple}
multiple={multiple}
onChange={e => onChange((e.target as HTMLInputElement).files)} />
</label>
)
@@ -26,7 +31,7 @@ export default function FormFileUpload({ inputRef, name, onChange, multiple, hid
/**
* Combination of a button with a hidden file upload field.
*
*
* @param param the change listener for the file upload and the properties for the button.
*/
export function FormFileUploadButton({ onChange, ...buttonProps }: Omit<ButtonProps, "onClick"> & Pick<FormFileUploadProps, "onChange">) {
@@ -39,10 +44,10 @@ export function FormFileUploadButton({ onChange, ...buttonProps }: Omit<ButtonPr
onClick={() => inputRef.current?.click()}
/>
<FormFileUpload
inputRef={inputRef}
inputRef={inputRef}
hidden
onChange={onChange}
/>
</>
)
}
}

View File

@@ -9,22 +9,26 @@ interface FormTextBoxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "
}
export default function FormTextBox({ inputRef, className, type, currentValue, onChange, onBlur, autoFocus, ...rest}: FormTextBoxProps) {
if (type === "number" && currentValue) {
const { min, max } = rest;
const currentValueNum = parseInt(currentValue, 10);
if (min && currentValueNum < parseInt(String(min), 10)) {
currentValue = String(min);
} else if (max && currentValueNum > parseInt(String(max), 10)) {
currentValue = String(max);
}
}
useEffect(() => {
if (autoFocus) {
inputRef?.current?.focus();
}
}, []);
function applyLimits(value: string) {
if (type === "number") {
const { min, max } = rest;
const currentValueNum = parseInt(value, 10);
if (min && currentValueNum < parseInt(String(min), 10)) {
return String(min);
} else if (max && currentValueNum > parseInt(String(max), 10)) {
return String(max);
}
}
return value;
}
return (
<input
ref={inputRef}
@@ -33,11 +37,13 @@ export default function FormTextBox({ inputRef, className, type, currentValue, o
value={currentValue}
onInput={onChange && (e => {
const target = e.currentTarget;
onChange?.(target.value, target.validity);
const currentValue = applyLimits(e.currentTarget.value);
onChange?.(currentValue, target.validity);
})}
onBlur={onBlur && (e => {
const target = e.currentTarget;
onBlur(target.value);
onBlur={(e => {
const currentValue = applyLimits(e.currentTarget.value);
e.currentTarget.value = currentValue;
onBlur?.(currentValue);
})}
{...rest}
/>
@@ -49,6 +55,6 @@ export function FormTextBoxWithUnit(props: FormTextBoxProps & { unit: string })
<label class="input-group tn-number-unit-pair">
<FormTextBox {...props} />
<span class="input-group-text">{props.unit}</span>
</label>
</label>
)
}
}

View File

@@ -25,7 +25,8 @@ const VIEW_TYPE_MAPPINGS: Record<ViewTypeOptions, string> = {
export default function CollectionPropertiesTab({ note }: TabContext) {
const [ viewType, setViewType ] = useNoteLabel(note, "viewType");
const viewTypeWithDefault = (viewType ?? "grid") as ViewTypeOptions;
const defaultViewType = (note?.type === "search" ? "list" : "grid");
const viewTypeWithDefault = (viewType ?? defaultViewType) as ViewTypeOptions;
const properties = bookPropertiesConfig[viewTypeWithDefault].properties;
return (
@@ -121,6 +122,7 @@ function CheckboxPropertyView({ note, property }: { note: FNote, property: Check
function NumberPropertyView({ note, property }: { note: FNote, property: NumberProperty }) {
//@ts-expect-error Interop with text box which takes in string values even for numbers.
const [ value, setValue ] = useNoteLabel(note, property.bindToLabel);
const disabled = property.disabled?.(note);
return (
<LabelledEntry label={property.label}>
@@ -129,6 +131,7 @@ function NumberPropertyView({ note, property }: { note: FNote, property: NumberP
currentValue={value ?? ""} onChange={setValue}
style={{ width: (property.width ?? 100) + "px" }}
min={property.min ?? 0}
disabled={disabled}
/>
</LabelledEntry>
)

View File

@@ -47,11 +47,11 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
const canBeConvertedToAttachment = note?.isEligibleForConversionToAttachment();
const isSearchable = ["text", "code", "book", "mindMap", "doc"].includes(note.type);
const isInOptions = note.noteId.startsWith("_options");
const isPrintable = ["text", "code"].includes(note.type);
const isPrintable = ["text", "code"].includes(note.type) || (note.type === "book" && note.getLabelValue("viewType") === "presentation");
const isElectron = getIsElectron();
const isMac = getIsMac();
const hasSource = ["text", "code", "relationMap", "mermaid", "canvas", "mindMap"].includes(note.type);
const isSearchOrBook = ["search", "book"].includes(note.type);
const isSearchOrBook = ["search", "book"].includes(note.type);
return (
<Dropdown
@@ -74,7 +74,7 @@ function NoteContextMenu({ note, noteContext }: { note: FNote, noteContext?: Not
<CommandItem icon="bx bx-export" text={t("note_actions.export_note")}
disabled={isInOptions || note.noteId === "_backendLog"}
command={() => noteContext?.notePath && parentComponent?.triggerCommand("showExportDialog", {
notePath: noteContext.notePath,
notePath: noteContext.notePath,
defaultType: "single"
})} />
<FormDropdownDivider />
@@ -133,4 +133,4 @@ function ConvertToAttachment({ note }: { note: FNote }) {
}}
>{t("note_actions.convert_into_attachment")}</FormListItem>
)
}
}

View File

@@ -1,6 +1,6 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
import { t } from "../../services/i18n";
import { useNoteContext, useNoteProperty, useStaticTooltip, useStaticTooltipWithKeyboardShortcut, useTooltip, useTriliumEvent, useTriliumEvents } from "../react/hooks";
import { useNoteContext, useNoteProperty, useStaticTooltipWithKeyboardShortcut, useTriliumEvents } from "../react/hooks";
import "./style.css";
import { VNode } from "preact";
import BasicPropertiesTab from "./BasicPropertiesTab";
@@ -24,7 +24,6 @@ import InheritedAttributesTab from "./InheritedAttributesTab";
import CollectionPropertiesTab from "./CollectionPropertiesTab";
import SearchDefinitionTab from "./SearchDefinitionTab";
import NoteActions from "./NoteActions";
import keyboard_actions from "../../services/keyboard_actions";
import { KeyboardActionNames } from "@triliumnext/commons";
interface TitleContext {
@@ -81,7 +80,7 @@ const TAB_CONFIGURATION = numberObjectsInPlace<TabConfiguration>([
title: t("book_properties.book_properties"),
icon: "bx bx-book",
content: CollectionPropertiesTab,
show: ({ note }) => note?.type === "book",
show: ({ note }) => note?.type === "book" || note?.type === "search",
toggleCommand: "toggleRibbonTabBookProperties"
},
{

View File

@@ -31,6 +31,7 @@ export interface NumberProperty {
bindToLabel: FilterLabelsByType<number>;
width?: number;
min?: number;
disabled?: (note: FNote) => boolean;
}
interface ComboBoxItem {
@@ -154,7 +155,8 @@ export const bookPropertiesConfig: Record<ViewTypeOptions, BookConfig> = {
label: t("book_properties_config.max-nesting-depth"),
type: "number",
bindToLabel: "maxNestingDepth",
width: 65
width: 65,
disabled: (note) => note.type === "search"
}
]
},

View File

@@ -1,7 +1,7 @@
.search-result-widget {
flex-grow: 100000;
flex-shrink: 100000;
min-height: 0;
height: 100%;
overflow: auto;
contain: none !important;
}

View File

@@ -4,7 +4,6 @@ import Alert from "./react/Alert";
import { useNoteContext, useTriliumEvent } from "./react/hooks";
import "./search_result.css";
import { SearchNoteList } from "./collections/NoteList";
// import NoteListRenderer from "../services/note_list_renderer";
enum SearchResultState {
NO_RESULTS,
@@ -43,7 +42,7 @@ export default function SearchResult() {
});
return (
<div className="search-result-widget">
<div className={`search-result-widget ${!state ? "hidden-ext" : ""}`}>
{state === SearchResultState.NOT_EXECUTED && (
<Alert type="info" className="search-not-executed-yet">{t("search_result.search_not_executed")}</Alert>
)}
@@ -54,6 +53,7 @@ export default function SearchResult() {
{state === SearchResultState.GOT_RESULTS && (
<SearchNoteList
media="screen"
note={note}
notePath={notePath}
highlightedTokens={highlightedTokens}

View File

@@ -294,7 +294,7 @@ function MaxContentWidth() {
<FormGroup name="max-content-width" label={t("max_content_width.max_width_label")}>
<FormTextBoxWithUnit
type="number" min={MIN_CONTENT_WIDTH} step="10"
currentValue={maxContentWidth} onChange={setMaxContentWidth}
currentValue={maxContentWidth} onBlur={setMaxContentWidth}
unit={t("max_content_width.max_width_unit")}
/>
</FormGroup>

View File

@@ -76,7 +76,8 @@ export default defineConfig(() => ({
setup: join(__dirname, "src", "setup.ts"),
share: join(__dirname, "src", "share.ts"),
set_password: join(__dirname, "src", "set_password.ts"),
runtime: join(__dirname, "src", "runtime.ts")
runtime: join(__dirname, "src", "runtime.ts"),
print: join(__dirname, "src", "print.tsx")
},
output: {
entryFileNames: "src/[name].js",

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/desktop",
"version": "0.99.1",
"version": "0.99.2",
"description": "Build your personal knowledge base with Trilium Notes",
"private": true,
"main": "src/main.ts",

View File

@@ -1,6 +1,6 @@
{
"name": "@triliumnext/server",
"version": "0.99.1",
"version": "0.99.2",
"description": "The server-side component of TriliumNext, which exposes the client via the web, allows for sync and provides a REST API for both internal and external use.",
"private": true,
"main": "./src/main.ts",
@@ -105,12 +105,12 @@
"is-svg": "6.1.0",
"jimp": "1.6.0",
"js-yaml": "4.1.0",
"marked": "16.4.0",
"marked": "16.4.1",
"mime-types": "3.0.1",
"multer": "2.0.2",
"normalize-strings": "1.1.1",
"ollama": "0.6.0",
"openai": "6.4.0",
"openai": "6.5.0",
"rand-token": "1.0.1",
"safe-compare": "1.1.4",
"sanitize-filename": "1.6.3",

File diff suppressed because one or more lines are too long

View File

@@ -302,7 +302,9 @@
<td><code>color</code>
</td>
<td>defines color of the note in note tree, links etc. Use any valid CSS color
value like 'red' or #a13d5f</td>
value like 'red' or #a13d5f
<br>Note: this color may be automatically adjusted when displayed to ensure
sufficient contrast with the background.</td>
</tr>
<tr>
<td><code>keyboardShortcut</code>

View File

@@ -1,42 +0,0 @@
<p>
<img src="Export as PDF_image.png">
</p>
<p>Screenshot of the note contextual menu indicating the “Export as PDF”
option.</p>
<p>On the desktop application of Trilium it is possible to export a note
as PDF. On the server or PWA (mobile), the option is not available due
to technical constraints and it will be hidden.</p>
<p>To print a note, select the
<img src="1_Export as PDF_image.png">button to the right of the note and select <em>Export as PDF</em>.</p>
<p>Afterwards you will be prompted to select where to save the PDF file.</p>
<h2>Automatic opening of the file</h2>
<p>When the PDF is exported, it is automatically opened with the system default
application for easy preview.</p>
<p>Note that if you are using Linux with the GNOME desktop environment, sometimes
the default application might seem incorrect (such as opening in GIMP).
This is because it uses Gnome's “Recommended applications” list.</p>
<p>To solve this, you can change the recommended application for PDFs via
this command line. First, list the available applications via <code>gio mime application/pdf</code> and
then set the desired one. For example to use GNOME's Evince:</p><pre><code class="language-text-x-trilium-auto">gio mime application/pdf</code></pre>
<h2>Reporting issues with the rendering</h2>
<p>Should you encounter any visual issues in the resulting PDF file (e.g.
a table does not fit properly, there is cut off text, etc.) feel free to
<a
href="#root/_help_wy8So3yZZlH9">report the issue</a>. In this case, it's best to offer a sample note (click
on the
<img src="1_Export as PDF_image.png">button, select Export note → This note and all of its descendants → HTML
in ZIP archive). Make sure not to accidentally leak any personal information.</p>
<h2>Landscape mode</h2>
<p>When exporting to PDF, there are no customizable settings such as page
orientation, size, etc. However, it is possible to specify a given note
to be printed as a PDF in landscape mode by adding the <code>#printLandscape</code> attribute
to it (see&nbsp;<a class="reference-link" href="#root/_help_zEY4DaJG4YT5">Attributes</a>).</p>
<h2>Page size</h2>
<p>By default, the resulting PDF will be in Letter format. It is possible
to adjust it to another page size via the <code>#printPageSize</code> attribute,
with one of the following values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.</p>
<h2>Keyboard shortcut</h2>
<p>It's possible to trigger the export to PDF from the keyboard by going
to&nbsp;<em>Keyboard shortcuts</em>&nbsp;in&nbsp;<a class="reference-link"
href="#root/_help_4TIF1oA4VQRO">Options</a>&nbsp;and assigning a key combination
for the <code>exportAsPdf</code> action.</p>

View File

@@ -0,0 +1,118 @@
<figure class="image">
<img style="aspect-ratio:951/432;" src="Printing & Exporting as PD.png"
width="951" height="432">
<figcaption>Screenshot of the note contextual menu indicating the “Export as PDF”
option.</figcaption>
</figure>
<h2>Printing</h2>
<p>This feature allows printing of notes. It works on both the desktop client,
but also on the web.</p>
<p>Note that not all note types are printable as of now. We do plan to increase
the coverage of supported note types in the future.</p>
<p>To print a note, select the
<img src="1_Printing & Exporting as PD.png"
width="29" height="31">button to the right of the note and select <em>Print note</em>. Depending
on the size and type of the note, this can take up to a few seconds. Afterwards
you will be redirected to the system/browser printing dialog.</p>
<aside
class="admonition note">
<p>Printing and exporting as PDF are not perfect. Due to technical limitations,
and sometimes even browser glitches the text might appear cut off in some
circumstances.&nbsp;</p>
</aside>
<h2>Reporting issues with the rendering</h2>
<p>Should you encounter any visual issues in the resulting PDF file (e.g.
a table does not fit properly, there is cut off text, etc.) feel free to
<a
href="#root/_help_wy8So3yZZlH9">report the issue</a>. In this case, it's best to offer a sample note (click
on the
<img src="1_Printing & Exporting as PD.png" width="29" height="31">button, select Export note → This note and all of its descendants → HTML
in ZIP archive). Make sure not to accidentally leak any personal information.</p>
<p>Consider adjusting font sizes and using <a href="#root/_help_CohkqWQC1iBv">page breaks</a> to
work around the layout.</p>
<h2>Exporting as PDF</h2>
<p>On the desktop application of Trilium it is possible to export a note
as PDF. On the server or PWA (mobile), the option is not available due
to technical constraints and it will be hidden.</p>
<p>To print a note, select the
<img src="1_Printing & Exporting as PD.png">button to the right of the note and select <em>Export as PDF</em>. Afterwards
you will be prompted to select where to save the PDF file.</p>
<aside class="admonition tip">
<p>Although direct export as PDF is not available in the browser version
of the application, it's still possible to generate a PDF by selecting
the <em>Print </em>option instead and selecting “Save to PDF” as the printer
(depending on the browser). Generally, Mozilla Firefox has better printing
capabilities.</p>
</aside>
<h3>Automatic opening of the file</h3>
<p>When the PDF is exported, it is automatically opened with the system default
application for easy preview.</p>
<p>Note that if you are using Linux with the GNOME desktop environment, sometimes
the default application might seem incorrect (such as opening in GIMP).
This is because it uses Gnome's “Recommended applications” list.</p>
<p>To solve this, you can change the recommended application for PDFs via
this command line. First, list the available applications via <code>gio mime application/pdf</code> and
then set the desired one. For example to use GNOME's Evince:</p><pre><code class="language-text-x-trilium-auto">gio mime application/pdf</code></pre>
<h3>Customizing exporting as PDF</h3>
<p>When exporting to PDF, there are no customizable settings such as page
orientation, size. However, there are a few&nbsp;<a class="reference-link"
href="#root/_help_zEY4DaJG4YT5">Attributes</a>&nbsp;to adjust some of the
settings:</p>
<ul>
<li data-list-item-id="e91eb69cdf42469e4f21852a6b27616b3">To print in landscape mode instead of portrait (useful for big diagrams
or slides), add <code>#printLandscape</code>.</li>
<li data-list-item-id="e111f43a2b5200816649515c5718b6c31">By default, the resulting PDF will be in Letter format. It is possible
to adjust it to another page size via the <code>#printPageSize</code> attribute,
with one of the following values: <code>A0</code>, <code>A1</code>, <code>A2</code>, <code>A3</code>, <code>A4</code>, <code>A5</code>, <code>A6</code>, <code>Legal</code>, <code>Letter</code>, <code>Tabloid</code>, <code>Ledger</code>.</li>
</ul>
<aside class="admonition note">
<p>These options have no effect when used with the printing feature, since
the user-defined settings are used instead.</p>
</aside>
<h2>Keyboard shortcut</h2>
<p>It's possible to trigger both printing and export as PDF from the keyboard
by going to&nbsp;<em>Keyboard shortcuts</em>&nbsp;in&nbsp;<a class="reference-link"
href="#root/_help_4TIF1oA4VQRO">Options</a>&nbsp;and assigning a key combination
for:</p>
<ul>
<li class="ck-list-marker-italic" data-list-item-id="e4065a346baa2fcc2f0bfe436f4026375"><em>Print Active Note</em>
</li>
<li class="ck-list-marker-italic" data-list-item-id="e358a65968ddc456ba39276f3d03e67ab"><em>Export Active Note as PDF</em>
</li>
</ul>
<h2>Constraints &amp; limitations</h2>
<p>Not all&nbsp;<a class="reference-link" href="#root/_help_KSZ04uQ2D1St">Note Types</a>&nbsp;are
supported when printing, in which case the <em>Print</em> and <em>Export as PDF</em> options
will be disabled.</p>
<ul>
<li data-list-item-id="e10824952bca3d35d824df6ff828a674f">For&nbsp;<a class="reference-link" href="#root/_help_6f9hih2hXXZk">Code</a>&nbsp;notes:
<ul>
<li data-list-item-id="ea6c43aec2902c6e071541491e8bd60ac">Line numbers are not printed.</li>
<li data-list-item-id="efddf7e53853db4e34d16d154b8ed4928">Syntax highlighting is enabled, however a default theme (Visual Studio)
is enforced.</li>
</ul>
</li>
<li data-list-item-id="e015b49c0f3289d6899c5a8b234d5be8b">For&nbsp;<a class="reference-link" href="#root/_help_GTwFsgaA0lCt">Collections</a>:
<ul>
<li data-list-item-id="ee53ebf2cbc850302a779b29475441b0b">Only&nbsp;<a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation View</a>&nbsp;is
currently supported.</li>
<li data-list-item-id="ebb55f62a0f525b810fd11fadc01e86ac">We plan to add support for all the collection types at some point.</li>
</ul>
</li>
<li data-list-item-id="e25476c9600ab387eda79fa5eec0b5394">Using&nbsp;<a class="reference-link" href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;for
printing is not longer supported, due to a more stable but isolated mechanism.
<ul>
<li data-list-item-id="eeb0dc52913013746ad4c3709296fab6b">We plan to introduce a new mechanism specifically for a print CSS.</li>
</ul>
</li>
</ul>
<h2>Under the hood</h2>
<p>Both printing and exporting as PDF use the same mechanism: a note is rendered
individually in a separate webpage that is then sent to the browser or
the Electron application either for printing or exporting as PDF.</p>
<p>The webpage that renders a single note can actually be accessed in a web
browser. For example <code>http://localhost:8080/#root/WWRGzqHUfRln/RRZsE9Al8AIZ?ntxId=0o4fzk</code> becomes <code>http://localhost:8080/?print#root/WWRGzqHUfRln/RRZsE9Al8AIZ</code>.</p>
<p>Accessing the print note in a web browser allows for easy debugging to
understand why a particular note doesn't render well. The mechanism for
rendering is similar to the one used in&nbsp;<a class="reference-link"
href="#root/_help_0ESUbbAxVnoK">Note List</a>.</p>

View File

@@ -49,11 +49,19 @@
<p>Now the text will be displayed above while still maintaining the collection
view.</p>
<h3>Using saved search</h3>
<p>Since collections are based on the&nbsp;<a class="reference-link" href="#root/_help_0ESUbbAxVnoK">Note List</a>&nbsp;mechanism,
it's possible to apply the same configuration to&nbsp;<a class="reference-link"
href="#root/_help_m523cpzocqaD">Saved Search</a>&nbsp;to do advanced querying
and presenting the result in an adequate matter such as a calendar, a table
or even a map.</p>
<p>Collections, by default, only display the child notes. However, it is
possible to use the&nbsp;<a class="reference-link" href="#root/_help_eIg8jdvaoNNd">Search</a>&nbsp;functionality
to display notes all across the tree, with advanced querying functionality.</p>
<p>To do so, simply start a&nbsp;<a class="reference-link" href="#root/_help_eIg8jdvaoNNd">Search</a>&nbsp;and
go to the <em>Collection Properties</em> tab in the&nbsp;<a class="reference-link"
href="#root/_help_BlN9DFI679QC">Ribbon</a>&nbsp;and select a desired type
of collection. To keep the search-based collection, use a&nbsp;<a class="reference-link"
href="#root/_help_m523cpzocqaD">Saved Search</a>.</p>
<aside class="admonition important">
<p>While in search, none of the collections will not display the child notes
of the search results. The reason is that the search might hit a note multiple
times, causing an exponential rise in the number of results.</p>
</aside>
<h3>Creating a collection from scratch</h3>
<p>By default, collections come with a default configuration and sometimes
even sample notes. To create a collection completely from scratch:</p>

View File

@@ -6,33 +6,31 @@
within Trilium.</p>
<h2>How it works</h2>
<ul>
<li data-list-item-id="e51cbe078fb06e2bfdfb1f2bf6fd82225">Each slide is a child note of the collection.</li>
<li data-list-item-id="efffc6f15623109770c57338c61b4ccb6">The order of the child notes determines the order of the slides.</li>
<li
data-list-item-id="e1a795af0f85ba888f84586be6ed2de2a">Unlike traditional presentation software, slides can be laid out both
<li>Each slide is a child note of the collection.</li>
<li>The order of the child notes determines the order of the slides.</li>
<li>Unlike traditional presentation software, slides can be laid out both
horizontally and vertically (see belwo for more information).</li>
<li data-list-item-id="e9a2a74d8e19974766f65416100e8f877">Direct children will be laid out horizontally and the children of those
will be laid out vertically. Children deeper than two levels of nesting
are ignored.</li>
<li>Direct children will be laid out horizontally and the children of those
will be laid out vertically. Children deeper than two levels of nesting
are ignored.</li>
</ul>
<h2>Interaction and navigation</h2>
<p>In the floating buttons section (top-right):</p>
<ul>
<li data-list-item-id="ee6dd604137e6918dcfac24fe271b05bf">Edit button to go to the corresponding note of the current slide.</li>
<li
data-list-item-id="e4805f237077e9dc8ddbed2cb0b56e585">Press Overview button (or the <kbd>O</kbd> key) to show a birds-eye view
<li>Edit button to go to the corresponding note of the current slide.</li>
<li>Press Overview button (or the <kbd>O</kbd> key) to show a birds-eye view
of the slides. Press the button again to disable it.</li>
<li data-list-item-id="ee714da289257895faf87a26f6849e050">Press the “Start presentation” button to show the presentation in full-screen.</li>
<li>Press the “Start presentation” button to show the presentation in full-screen.</li>
</ul>
<p>The following keyboard shortcuts are supported:</p>
<ul>
<li data-list-item-id="e5a34fbaa9c98cd91ffac8301e153a083">Press <kbd></kbd> and <kbd></kbd> (or <kbd>H</kbd> and <kbd>L</kbd>) to go
<li>Press <kbd></kbd> and <kbd></kbd> (or <kbd>H</kbd> and <kbd>L</kbd>) to go
to the slide on the left or on the right (horizontal).</li>
<li data-list-item-id="e39394b060a9b767d04c466440106cbf0">Press <kbd></kbd> and <kbd></kbd> &nbsp;(or <kbd>K</kbd> and <kbd>J</kbd>)
<li>Press <kbd></kbd> and <kbd></kbd> &nbsp;(or <kbd>K</kbd> and <kbd>J</kbd>)
to go to the upward or downward slide (vertical).</li>
<li data-list-item-id="e17441e9598f687e89a161a8afe2f703d">Press <kbd>Space</kbd> and <kbd>Shift</kbd> + <kbd>Space</kbd> or &nbsp;to go
<li>Press <kbd>Space</kbd> and <kbd>Shift</kbd> + <kbd>Space</kbd> or &nbsp;to go
to the next/previous slide in order.</li>
<li data-list-item-id="e4212130fc1fdc5de980e2e40feae68c2">And a few more, press <kbd>?</kbd> to display a popup with all the supported
<li>And a few more, press <kbd>?</kbd> to display a popup with all the supported
keyboard combinations.</li>
</ul>
<h2>Vertical slides and nesting</h2>
@@ -42,15 +40,15 @@
<p>This horizontal/vertical organization affects transitions (especially
on the “slide” transition), however it is most noticeable in navigation.</p>
<ul>
<li data-list-item-id="e9245eba99da45713930c1714202add31">Pressing <kbd></kbd> and <kbd></kbd> will navigate through slides horizontally,
<li>Pressing <kbd></kbd> and <kbd></kbd> will navigate through slides horizontally,
thus skipping vertical notes under the current slide. This is useful to
skip entire chapters/related slides.&nbsp;</li>
<li data-list-item-id="ef9aedf69e5e2a599e9fbd0de1b89b4ad">Pressing <kbd></kbd> and <kbd></kbd> will navigate through the vertical
skip entire chapters/related slides.</li>
<li>Pressing <kbd></kbd> and <kbd></kbd> will navigate through the vertical
slides at the current level.</li>
<li data-list-item-id="e436fc36f74a22fdefe31e498684e23b3">Pressing <kbd>Space</kbd> and <kbd>Shift</kbd> + <kbd>Space</kbd> will go to
<li>Pressing <kbd>Space</kbd> and <kbd>Shift</kbd> + <kbd>Space</kbd> will go to
the next/previous slide in order, regardless of the direction. This is
generally the key combination to use when presenting.</li>
<li data-list-item-id="e9c5dcf5efec250876bd2c527082e76d7">The arrows on the bottom-right of the slide will also reflect this navigation
<li>The arrows on the bottom-right of the slide will also reflect this navigation
scheme.</li>
</ul>
<figure class="image image-style-align-right image_resized" style="width:55.57%;">
@@ -62,19 +60,19 @@
slides.</p>
<p>In the following example, the note structure is as follows:</p>
<ul>
<li data-list-item-id="e4d5d440ec56a9c81b7c8323ab142478d">Presentation collection
<li>Presentation collection
<ul>
<li data-list-item-id="e255021a351d18e2792c15ab2b80c0a57">Trilium Notes (demo page)</li>
<li data-list-item-id="ef6f95ec54572aa247a13e8104a2db0c3">“Introduction” slide
<li>Trilium Notes (demo page)</li>
<li>“Introduction” slide
<ul>
<li data-list-item-id="eccb526d7f2dd67ac686f8e963e660a77">“The challenge of personal knowledge management”</li>
<li data-list-item-id="e0aca477122bb0b00ab9b3bc163436b5f">“Note-taking structures”</li>
<li>“The challenge of personal knowledge management”</li>
<li>“Note-taking structures”</li>
</ul>
</li>
<li data-list-item-id="e3bbbe33c8d7a18cb17cd0de29b6eff05">“Demo &amp; Feature highlights” slide
<li>“Demo &amp; Feature highlights” slide
<ul>
<li data-list-item-id="ebf5e3fe8a8b4400f21d5cc99b8198898">“Really fast installation process”</li>
<li data-list-item-id="e0b6885a0bf7f76fa2ce7801f004a2d42">Video slide</li>
<li>“Really fast installation process”</li>
<li>Video slide</li>
</ul>
</li>
</ul>
@@ -83,56 +81,54 @@
<h2>Customization</h2>
<p>At collection level, it's possible to adjust:</p>
<ul>
<li data-list-item-id="edc0a7c71ee836a225a8793e3cb1e29e8">The theme of the entire presentation to one of the predefined themes by
going to the&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/Vc8PjrjAGuOp/_help_BlN9DFI679QC">Ribbon</a>&nbsp;and
<li>The theme of the entire presentation to one of the predefined themes by
going to the&nbsp;<a class="reference-link" href="#root/_help_BlN9DFI679QC">Ribbon</a>&nbsp;and
looking for the <em>Collection Properties</em> tab.</li>
<li data-list-item-id="ed04e1bd7a997de717d8b8b8b90f19e7f">It's currently not possible to create custom themes, although it is planned.</li>
<li
data-list-item-id="edb37c7902c9e464de4555ec3ede05403">Note that it is note possible to alter the CSS via&nbsp;<a class="reference-link"
href="#root/pOsGYCXsbNQG/pKK96zzmvBGf/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;because
the slides are rendered isolated (in a shadow DOM).</li>
<li>It's currently not possible to create custom themes, although it is planned.</li>
<li>Note that it is note possible to alter the CSS via&nbsp;<a class="reference-link"
href="#root/_help_AlhDUqhENtH7">Custom app-wide CSS</a>&nbsp;because the
slides are rendered isolated (in a shadow DOM).</li>
</ul>
<p>At slide level:</p>
<ul>
<li data-list-item-id="eb9c23ec94dcd00a3a8539d3cd633d7df">It's possible to adjust the background color of a slide by using the
<li>It's possible to adjust the background color of a slide by using the
<a
href="#root/pOsGYCXsbNQG/tC7s2alapj8V/zEY4DaJG4YT5/_help_OFXdgB2nNk1F">predefined promoted attribute</a>for the color or manually setting <code>#slide:background</code> to
href="#root/_help_OFXdgB2nNk1F">predefined promoted attribute</a>for the color or manually setting <code>#slide:background</code> to
a hex color.</li>
<li data-list-item-id="e70af66a7d3468b7fa86badb1e2c93cc9">More complex backgrounds can be achieved via gradients. There's no UI
<li>More complex backgrounds can be achieved via gradients. There's no UI
for it; it has to be set via <code>#slide:background</code> to a CSS gradient
definition such as: <code>linear-gradient(to bottom, #283b95, #17b2c3)</code>.</li>
</ul>
<h2>Tips and tricks</h2>
<ul>
<li data-list-item-id="ec501025735d0063969f2a48eedb651dc">Text notes generally respect the formatting (bold, italic, foreground
<li>Text notes generally respect the formatting (bold, italic, foreground
and background colors) and font size. Code blocks and tables also work.</li>
<li
data-list-item-id="e8acd457a2660726905aee30a9325a620">Try using more than just text notes, the presentation uses the same mechanism
as <a href="#root/pOsGYCXsbNQG/tC7s2alapj8V/_help_R9pX4DGra2Vt">shared notes</a> and&nbsp;
<li>Try using more than just text notes, the presentation uses the same mechanism
as <a href="#root/_help_R9pX4DGra2Vt">shared notes</a> and&nbsp;<a class="reference-link"
href="#root/_help_0ESUbbAxVnoK">Note List</a>&nbsp;so it should be able
to display&nbsp;<a class="reference-link" href="#root/_help_s1aBHPd79XYj">Mermaid Diagrams</a>,&nbsp;
<a
class="reference-link" href="#root/pOsGYCXsbNQG/gh7bpGYxajRS/BFs8mudNFgCS/_help_0ESUbbAxVnoK">Note List</a>&nbsp;so it should be able to display&nbsp;<a class="reference-link"
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_s1aBHPd79XYj">Mermaid Diagrams</a>,&nbsp;
<a
class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_grjYqerjn243">Canvas</a>&nbsp;and&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_gBbsAeiuUxI5">Mind Map</a>&nbsp;in
full-screen (without the interactivity).
<ul>
<li data-list-item-id="e91cdf4823552f771ed802de7fd6330e4">Consider using a transparent background for&nbsp;<a class="reference-link"
href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_grjYqerjn243">Canvas</a>, if
the slides have a custom background (go to the hamburger menu in the Canvas,
press the button select a custom color and write <code>transparent</code>).</li>
<li
data-list-item-id="ebed408174c89a15dc9b0ee74d36e2e70">
<p>For&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/_help_s1aBHPd79XYj">Mermaid Diagrams</a>,
some of them have a predefined background which can be changed via the
frontmatter. For example, for XY-charts:</p><pre><code class="language-text-x-trilium-auto">---
class="reference-link" href="#root/_help_grjYqerjn243">Canvas</a>&nbsp;and&nbsp;<a class="reference-link" href="#root/_help_gBbsAeiuUxI5">Mind Map</a>&nbsp;in
full-screen (without the interactivity).
<ul>
<li>
<p>Consider using a transparent background for&nbsp;<a class="reference-link"
href="#root/_help_grjYqerjn243">Canvas</a>, if the slides have a custom
background (go to the hamburger menu in the Canvas, press the button select
a custom color and write <code>transparent</code>).</p>
</li>
<li>
<p>For&nbsp;<a class="reference-link" href="#root/_help_s1aBHPd79XYj">Mermaid Diagrams</a>,
some of them have a predefined background which can be changed via the
frontmatter. For example, for XY-charts:</p><pre><code class="language-text-x-trilium-auto">---
config:
themeVariables:
xyChart:
backgroundColor: transparent
---</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2>Under the hood</h2>
<p>The Presentation view uses <a href="https://revealjs.com/">Reveal.js</a> to

View File

@@ -1,38 +1,37 @@
<p>It is possible to provide a CSS file to be used regardless of the theme
set by the user.</p>
<figure class="table">
<table>
<thead>
<tr>
<th>&nbsp;</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<img src="Custom app-wide CSS_image.png">
</td>
<td>Start by creating a new note and changing the note type to CSS</td>
</tr>
<tr>
<td>
<img src="2_Custom app-wide CSS_image.png">
</td>
<td>In the ribbon, press the “Owned Attributes” section and type <code>#appCss</code>.</td>
</tr>
<tr>
<td>
<img src="3_Custom app-wide CSS_image.png">
</td>
<td>Type the desired CSS.&nbsp;&nbsp;
<br>
<br>Generally it's a good idea to append <code>!important</code> for the styles
that are being changed, in order to prevent other</td>
</tr>
</tbody>
</table>
</figure>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<img src="Custom app-wide CSS_image.png">
</td>
<td>Start by creating a new note and changing the note type to CSS</td>
</tr>
<tr>
<td>
<img src="2_Custom app-wide CSS_image.png">
</td>
<td>In the ribbon, press the “Owned Attributes” section and type <code>#appCss</code>.</td>
</tr>
<tr>
<td>
<img src="3_Custom app-wide CSS_image.png">
</td>
<td>Type the desired CSS.&nbsp;&nbsp;
<br>
<br>Generally it's a good idea to append <code>!important</code> for the styles
that are being changed, in order to prevent other</td>
</tr>
</tbody>
</table>
<h2>Seeing the changes</h2>
<p>Adding a new <em>app CSS note</em> or modifying an existing one does not
immediately apply changes. To see the changes, press Ctrl+Shift+R to refresh
@@ -54,10 +53,9 @@
workspaces.</p>
<p>To do so:</p>
<ol>
<li data-list-item-id="eaca1b6777262e20c38dae5e2c2ef8496">In the note with <code>#workspace</code>, add an inheritable attribute <code>#cssClass(inheritable)</code> with
<li>In the note with <code>#workspace</code>, add an inheritable attribute <code>#cssClass(inheritable)</code> with
a value that uniquely identifies the workspace (say <code>my-workspace</code>).</li>
<li
data-list-item-id="e01663cf2128c10a0cd0cab1bb27fd44d">Anywhere in the note structure, create a CSS note with <code>#appCss</code>.</li>
<li>Anywhere in the note structure, create a CSS note with <code>#appCss</code>.</li>
</ol>
<h4>Change the color of the icons in the&nbsp;<a class="reference-link" href="#root/_help_oPVyFC7WL2Lp">Note Tree</a></h4><pre><code class="language-text-x-trilium-auto">.fancytree-node.my-workspace.fancytree-custom-icon {
color: #ff0000;
@@ -73,8 +71,8 @@
width="641" height="630">
</figure>
<ol>
<li data-list-item-id="e6e7ec9751bdc6f7846d10bf42c42c9b1">Insert an image in any note and take the URL of the image.</li>
<li data-list-item-id="edc7f77ed718593d91bda3b2983b81bed">Use the following CSS, adjusting the <code>background-image</code> and <code>width</code> and <code>height</code> to
<li>Insert an image in any note and take the URL of the image.</li>
<li>Use the following CSS, adjusting the <code>background-image</code> and <code>width</code> and <code>height</code> to
the desired values.</li>
</ol><pre><code class="language-text-x-trilium-auto">.note-split.my-workspace .scrolling-container:after {
position: fixed;
@@ -94,5 +92,5 @@
<p>Some parts of the application can't be styled directly via custom CSS
because they are rendered in an isolated mode (shadow DOM), more specifically:</p>
<ul>
<li data-list-item-id="e3ce2c089fe536bc42856bb1b5edc8c8e">The slides in a&nbsp;<a class="reference-link" href="#root/pOsGYCXsbNQG/KSZ04uQ2D1St/GTwFsgaA0lCt/_help_zP3PMqaG71Ct">Presentation View</a>.</li>
<li>The slides in a&nbsp;<a class="reference-link" href="#root/_help_zP3PMqaG71Ct">Presentation View</a>.</li>
</ul>

View File

@@ -76,7 +76,15 @@
"find-in-text": "اظهار/اخفاء لوحة الفتح",
"toggle-full-screen": "اظهار/اخفاء وضع ملء الشاشة",
"reset-zoom-level": "اعادة ضبط مستوى التكبير",
"toggle-book-properties": "اظهار/اخفاء خصائص المجموعة"
"toggle-book-properties": "اظهار/اخفاء خصائص المجموعة",
"show-note-source": "عرض مربع حوار \"مصدر الملاحظات\"",
"show-revisions": "عرض مربع حوار \" مراجعات الملاحظة\"",
"show-recent-changes": "عرض مربع حوار \" التغيرات الاخيرة\"",
"show-sql-console": "فتح صفحة \" وحدة تحكم SQL\"",
"show-backend-log": "فتح صفحة \"سجل الخلفية\"",
"edit-readonly-note": "تعديل ملاحظة القراءة فقط",
"attributes-labels-and-relations": "سمات ( تسميات و علاقات)",
"render-active-note": "عرض ( اعادة عرض) الملاحظة المؤرشفة"
},
"setup_sync-from-server": {
"note": "ملاحظة:",
@@ -164,7 +172,10 @@
"launch-bar-templates-title": "قوالب شريط التشغيل",
"base-abstract-launcher-title": "المشغل الاساسي المجرد",
"llm-chat-title": "الدردشة مع الملاحظات",
"localization": "اللغة والمنطقة"
"localization": "اللغة والمنطقة",
"go-to-previous-note-title": "اذهب الى الملاحظة السابقة",
"go-to-next-note-title": "اذهب الى الملاحظة التالية",
"open-today-journal-note-title": "فتح ملاحظة مجلة اليوم"
},
"tray": {
"bookmarks": "العلامات المرجعية",
@@ -173,7 +184,8 @@
"recents": "الملاحظات الحديثة",
"new-note": "ملاحظة جديدة",
"show-windows": "اظهار النوافذ",
"open_new_window": "فتح نافذة جديدة"
"open_new_window": "فتح نافذة جديدة",
"today": "فتح ملاحظة مجلة اليوم"
},
"modals": {
"error_title": "خطأ"
@@ -211,7 +223,8 @@
"presentation": "عرض تقديمي",
"presentation_slide": "شريحة العرض التقديمي",
"presentation_slide_first": "الشريحة الاولى",
"presentation_slide_second": "الشريحة الثانية"
"presentation_slide_second": "الشريحة الثانية",
"background": "الخلفية"
},
"login": {
"title": "تسجيل الدخول",
@@ -230,11 +243,13 @@
"setup": {
"next": "التالي",
"title": "تثبيت",
"heading": "تثبيت تريليوم للملاحظات"
"heading": "تثبيت تريليوم للملاحظات",
"init-in-progress": "جار تهيئة المستند"
},
"setup_sync-from-desktop": {
"step6-here": "هنا",
"heading": "مزامنة من سطح المكتب"
"heading": "مزامنة من سطح المكتب",
"step3": "انقر على صنف المزامنة."
},
"setup_sync-in-progress": {
"outstanding-items-default": "غير متوفر",
@@ -312,7 +327,19 @@
"edit-read-only-note": "تحرير ملاحظة للقراءة فقط",
"add-new-label": "اضافة تسمية جديدة",
"reload-frontend-app": "اعادة تحميل الواجهة الامامية للتطبيق",
"force-save-revision": "فرض حفظ المراجعة"
"force-save-revision": "فرض حفظ المراجعة",
"toggle-note-hoisting": "اظهار/ اخفاء التركيز في الملاحظة",
"back-in-note-history": "الرجوع الى سجل الملاحظة",
"forward-in-note-history": "التقدم للامام في سجل الملاحظة",
"scroll-to-active-note": "تمرير تلى الملاحظة النشطة",
"create-note-into-inbox": "انشاء ملاحظة في البريد الوارد",
"copy-notes-to-clipboard": "نسخ الملاحظات الى الخافظة",
"paste-notes-from-clipboard": "لصق الملاحظات الى الحافظة",
"cut-notes-to-clipboard": "قص الملاحظات الى الحافظة",
"toggle-system-tray-icon": "تبديل ايقونة علبة النظام",
"switch-to-first-tab": "التبديل الى التبويب الاول",
"follow-link-under-cursor": "اتبع الرابط اسفل المؤشر",
"paste-markdown-into-text": "لصق نص بتنسبق Markdown"
},
"share_404": {
"title": "غير موجود",

View File

@@ -307,7 +307,12 @@
"board_note_second": "Zweite Notiz",
"board_note_third": "Dritte Notiz",
"board_status_todo": "To-Do",
"board_status_progress": "In Bearbeitung"
"board_status_progress": "In Bearbeitung",
"presentation": "Präsentation",
"presentation_slide": "Präsentationsfolie",
"presentation_slide_first": "Erste Folie",
"presentation_slide_second": "Zweite Folie",
"background": "Hintergrund"
},
"keyboard_action_names": {
"copy-notes-to-clipboard": "Notizen in Zwischenablage kopieren",

View File

@@ -373,7 +373,8 @@
"export_filter": "PDF Document (*.pdf)",
"unable-to-export-message": "The current note could not be exported as a PDF.",
"unable-to-export-title": "Unable to export as PDF",
"unable-to-save-message": "The selected file could not be written to. Try again or select another destination."
"unable-to-save-message": "The selected file could not be written to. Try again or select another destination.",
"unable-to-print": "Unable to print the note"
},
"tray": {
"tooltip": "Trilium Notes",

View File

@@ -22,7 +22,7 @@
"move-notes-to": "選択したノートを移動",
"copy-notes-to-clipboard": "選択したノートをクリップボードにコピー",
"paste-notes-from-clipboard": "クリップボードからアクティブなノートにノートを貼り付け",
"cut-notes-to-clipboard": "選択したノートをクリップボードにカット",
"cut-notes-to-clipboard": "選択したノートをクリップボードに切り取り",
"select-all-notes-in-parent": "現在のノートレベルと同じノートをすべて選択する",
"add-note-above-to-the-selection": "上のノートを選択範囲に追加",
"add-note-below-to-selection": "下のノートを選択範囲に追加",
@@ -101,16 +101,16 @@
"toggle-book-properties": "コレクションプロパティ切り替え",
"toggle-zen-mode": "禅モード集中した編集のための最小限のUIを有効/無効にする",
"add-include-note-to-text": "ノートを埋め込むダイアログを開く",
"toggle-promoted-attributes": "プロモートされた属性をトグルする",
"toggle-promoted-attributes": "プロモート属性切り替え",
"force-save-revision": "アクティブノートの新しいノートリヴィジョンを強制する",
"toggle-classic-editor-toolbar": "固定ツールバーを持ったエディターのフォーマットタブをトグルする"
"toggle-classic-editor-toolbar": "固定ツールバーエディターの書式設定タブ切り替え"
},
"keyboard_action_names": {
"back-in-note-history": "ノートの履歴を戻る",
"forward-in-note-history": "ノートの履歴を進む",
"command-palette": "コマンドパレット",
"scroll-to-active-note": "アクティブノートまでスクロール",
"quick-search": "クイックサーチ",
"quick-search": "クイック検索",
"search-in-subtree": "サブツリー内を検索",
"expand-subtree": "サブツリーを展開",
"collapse-subtree": "サブツリーを折りたたむ",
@@ -128,7 +128,7 @@
"move-notes-to": "ノートを移動",
"copy-notes-to-clipboard": "ノートをクリップボードにコピー",
"paste-notes-from-clipboard": "クリップボードからノートを貼り付け",
"cut-notes-to-clipboard": "ノートをクリップボードにカット",
"cut-notes-to-clipboard": "ノートをクリップボードに切り取り",
"select-all-notes-in-parent": "親ノート内のすべてのノートを選択",
"add-note-above-to-selection": "選択範囲に上のノートを追加",
"add-note-below-to-selection": "選択範囲に下のノートを追加",
@@ -200,7 +200,7 @@
"force-save-revision": "強制保存リビジョン",
"add-include-note-to-text": "埋め込みノートを追加",
"toggle-ribbon-tab-classic-editor": "リボンタブのクラシックエディターに切り替える",
"toggle-ribbon-tab-promoted-attributes": "リボンタブプロモート属性を切り替える"
"toggle-ribbon-tab-promoted-attributes": "リボンタブ切り替え:プロモート属性"
},
"login": {
"title": "ログイン",
@@ -312,7 +312,7 @@
"new-note-title": "新しいノート",
"bookmarks-title": "ブックマーク",
"open-today-journal-note-title": "今日の日記を開く",
"quick-search-title": "クイックサーチ",
"quick-search-title": "クイック検索",
"recent-changes-title": "最近の変更",
"root-title": "隠されたノート",
"note-map-title": "ノートマップ",
@@ -361,7 +361,8 @@
"export_filter": "PDFドキュメント (*.pdf)",
"unable-to-export-message": "現在のートをPDFとしてエクスポートできませんでした。",
"unable-to-export-title": "PDFとしてエクスポートできません",
"unable-to-save-message": "選択されたファイルに書き込めませんでした。もう一度試すか、別の保存先を選択してください。"
"unable-to-save-message": "選択されたファイルに書き込めませんでした。もう一度試すか、別の保存先を選択してください。",
"unable-to-print": "ノートを印刷できません"
},
"tray": {
"tooltip": "Trilium Notes",
@@ -415,7 +416,8 @@
"presentation": "プレゼンテーション",
"presentation_slide": "プレゼンテーションスライド",
"presentation_slide_first": "最初のスライド",
"presentation_slide_second": "2番目のスライド"
"presentation_slide_second": "2番目のスライド",
"background": "背景"
},
"share_404": {
"title": "該当なし",

View File

@@ -13,7 +13,7 @@
"sort-child-notes": "Sortuj podnotatki",
"creating-and-moving-notes": "Tworzenie oraz przestawianie notatek",
"create-note-after": "Utwórz notatkę po aktywnej notatce",
"create-note-into": "Utwórz notatkę jako podnotatka aktywnej notatki",
"create-note-into": "Utwórz notatkę jako pod-notatka aktywnej notatki",
"create-note-into-inbox": "Utwórz notatkę w skrzyncę (jeśli zdefiniowana) lub jako notatka dnia",
"delete-note": "Usuń notatkę",
"move-note-up": "Przestaw notatkę wyżej",

View File

@@ -373,7 +373,8 @@
"export_filter": "PDF 文件 (*.pdf)",
"unable-to-export-message": "目前筆記無法被匯出為 PDF 。",
"unable-to-export-title": "無法匯出為 PDF",
"unable-to-save-message": "所選檔案無法被寫入。請重試或選擇其他路徑。"
"unable-to-save-message": "所選檔案無法被寫入。請重試或選擇其他路徑。",
"unable-to-print": "無法列印筆記"
},
"tray": {
"tooltip": "Trilium 筆記",
@@ -423,7 +424,12 @@
"board_note_third": "第三個筆記",
"board_status_todo": "待辦",
"board_status_progress": "進行中",
"board_status_done": "已完成"
"board_status_done": "已完成",
"presentation": "簡報",
"presentation_slide": "簡報投影片",
"presentation_slide_first": "第一張投影片",
"presentation_slide_second": "第二張投影片",
"background": "背景"
},
"sql_init": {
"db_not_initialized_desktop": "資料庫尚未初始化,請依螢幕指示操作。",

View File

@@ -3,7 +3,7 @@
window.glob = {
device: "<%= device %>",
baseApiUrl: 'api/',
baseApiUrl: "<%= baseApiUrl %>",
activeDialog: null,
maxEntityChangeIdAtLoad: <%= maxEntityChangeIdAtLoad %>,
maxEntityChangeSyncIdAtLoad: <%= maxEntityChangeSyncIdAtLoad %>,

View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="favicon.ico">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" />
<link rel="manifest" crossorigin="use-credentials" href="../manifest.webmanifest">
<title>Trilium Notes</title>
<script src="../<%= appPath %>/runtime.js" crossorigin type="module"></script>
</head>
<body
id="trilium-print"
lang="<%= currentLocale.id %>" dir="<%= currentLocale.rtl ? 'rtl' : 'ltr' %>"
>
<noscript><%= t("javascript-required") %></noscript>
<script>
// hide body to reduce flickering on the startup. This is done through JS and not CSS to not hide <noscript>
document.getElementsByTagName("body")[0].style.display = "none";
</script>
<%- include("./partials/windowGlobal.ejs", locals) %>
<!-- Required for correct loading of scripts in Electron -->
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
<script src="../<%= appPath %>/print.js" crossorigin type="module"></script>
</body>
</html>

View File

@@ -16,9 +16,11 @@ import type { Request, Response } from "express";
import type BNote from "../becca/entities/bnote.js";
import { getCurrentLocale } from "../services/i18n.js";
type View = "desktop" | "mobile" | "print";
function index(req: Request, res: Response) {
const options = optionService.getOptionMap();
const view = getView(req);
const options = optionService.getOptionMap();
//'overwrite' set to false (default) => the existing token will be re-used and validated
//'validateOnReuse' set to false => if validation fails, generate a new token instead of throwing an error
@@ -57,13 +59,19 @@ function index(req: Request, res: Response) {
isProtectedSessionAvailable: protectedSessionService.isProtectedSessionAvailable(),
maxContentWidth: Math.max(640, parseInt(options.maxContentWidth)),
triliumVersion: packageJson.version,
assetPath: assetPath,
appPath: appPath,
assetPath,
appPath,
baseApiUrl: 'api/',
currentLocale: getCurrentLocale()
});
}
function getView(req: Request): "desktop" | "mobile" {
function getView(req: Request): View {
// Special override for printing.
if ("print" in req.query) {
return "print";
}
// Electron always uses the desktop view.
if (isElectron) {
return "desktop";

View File

@@ -378,8 +378,6 @@ function register(app: express.Application) {
asyncApiRoute(PST, "/api/llm/chat/:chatNoteId/messages", llmRoute.sendMessage);
asyncApiRoute(PST, "/api/llm/chat/:chatNoteId/messages/stream", llmRoute.streamMessage);
// LLM provider endpoints - moved under /api/llm/providers hierarchy
asyncApiRoute(GET, "/api/llm/providers/ollama/models", ollamaRoute.listModels);
asyncApiRoute(GET, "/api/llm/providers/openai/models", openaiRoute.listModels);

View File

@@ -8,10 +8,12 @@ import sqlInit from "./sql_init.js";
import cls from "./cls.js";
import keyboardActionsService from "./keyboard_actions.js";
import electron from "electron";
import type { App, BrowserWindowConstructorOptions, BrowserWindow, WebContents } from "electron";
import type { App, BrowserWindowConstructorOptions, BrowserWindow, WebContents, IpcMainEvent } from "electron";
import { formatDownloadTitle, isDev, isMac, isWindows } from "./utils.js";
import { t } from "i18next";
import { RESOURCE_DIR } from "./resource_dir.js";
import { PerformanceObserverEntryList } from "perf_hooks";
import options from "./options.js";
// Prevent the window being garbage collected
let mainWindow: BrowserWindow | null;
@@ -67,61 +69,102 @@ electron.ipcMain.on("create-extra-window", (event, arg) => {
createExtraWindow(arg.extraWindowHash);
});
interface PrintOpts {
notePath: string;
printToPdf: boolean;
}
interface ExportAsPdfOpts {
notePath: string;
title: string;
landscape: boolean;
pageSize: "A0" | "A1" | "A2" | "A3" | "A4" | "A5" | "A6" | "Legal" | "Letter" | "Tabloid" | "Ledger";
}
electron.ipcMain.on("export-as-pdf", async (e, opts: ExportAsPdfOpts) => {
const browserWindow = electron.BrowserWindow.fromWebContents(e.sender);
if (!browserWindow) {
return;
}
const filePath = electron.dialog.showSaveDialogSync(browserWindow, {
defaultPath: formatDownloadTitle(opts.title, "file", "application/pdf"),
filters: [
{
name: t("pdf.export_filter"),
extensions: ["pdf"]
}
]
electron.ipcMain.on("print-note", async (e, { notePath }: PrintOpts) => {
const browserWindow = await getBrowserWindowForPrinting(e, notePath);
browserWindow.webContents.print({}, (success, failureReason) => {
if (!success) {
electron.dialog.showErrorBox(t("pdf.unable-to-print"), failureReason);
}
e.sender.send("print-done");
browserWindow.destroy();
});
if (!filePath) {
return;
}
let buffer: Buffer;
try {
buffer = await browserWindow.webContents.printToPDF({
landscape: opts.landscape,
pageSize: opts.pageSize,
generateDocumentOutline: true,
generateTaggedPDF: true,
printBackground: true,
displayHeaderFooter: true,
headerTemplate: `<div></div>`,
footerTemplate: `
<div class="pageNumber" style="width: 100%; text-align: center; font-size: 10pt;">
</div>
`
});
} catch (e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-export-message"));
return;
}
try {
await fs.writeFile(filePath, buffer);
} catch (e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-save-message"));
return;
}
electron.shell.openPath(filePath);
});
electron.ipcMain.on("export-as-pdf", async (e, { title, notePath, landscape, pageSize }: ExportAsPdfOpts) => {
const browserWindow = await getBrowserWindowForPrinting(e, notePath);
async function print() {
const filePath = electron.dialog.showSaveDialogSync(browserWindow, {
defaultPath: formatDownloadTitle(title, "file", "application/pdf"),
filters: [
{
name: t("pdf.export_filter"),
extensions: ["pdf"]
}
]
});
if (!filePath) return;
let buffer: Buffer;
try {
buffer = await browserWindow.webContents.printToPDF({
landscape,
pageSize,
generateDocumentOutline: true,
generateTaggedPDF: true,
printBackground: true,
displayHeaderFooter: true,
headerTemplate: `<div></div>`,
footerTemplate: `
<div class="pageNumber" style="width: 100%; text-align: center; font-size: 10pt;">
</div>
`
});
} catch (e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-export-message"));
return;
}
try {
await fs.writeFile(filePath, buffer);
} catch (e) {
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-save-message"));
return;
}
electron.shell.openPath(filePath);
}
try {
await print();
} finally {
e.sender.send("print-done");
browserWindow.destroy();
}
});
async function getBrowserWindowForPrinting(e: IpcMainEvent, notePath: string) {
const browserWindow = new electron.BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
offscreen: true,
session: e.sender.session
},
});
await browserWindow.loadURL(`http://127.0.0.1:${port}/?print#${notePath}`);
await browserWindow.webContents.executeJavaScript(`
new Promise(resolve => {
if (window._noteReady) return resolve();
window.addEventListener("note-ready", () => resolve());
});
`);
return browserWindow;
}
async function createMainWindow(app: App) {
if ("setUserTasks" in app) {
app.setUserTasks([

View File

@@ -13,11 +13,11 @@
"preact": "10.27.2",
"preact-iso": "2.11.0",
"preact-render-to-string": "6.6.2",
"react-i18next": "16.0.1"
"react-i18next": "16.1.0"
},
"devDependencies": {
"@preact/preset-vite": "2.10.2",
"eslint": "9.37.0",
"eslint": "9.38.0",
"eslint-config-preact": "2.0.0",
"typescript": "5.9.3",
"user-agent-data-types": "0.4.2",

View File

@@ -72,7 +72,8 @@
"download_scoop": "Scoop",
"download_exe": "تحميل ملف التثبيت (exe.)",
"title_x64": "ويندوز 64 بت",
"download_zip": "النسخة المحمولة بصيغة zip"
"download_zip": "النسخة المحمولة بصيغة zip",
"title_arm64": "نظام ويندوز عاى ARM"
},
"download_helper_desktop_linux": {
"download_deb": ".deb",
@@ -81,7 +82,8 @@
"download_rpm": "rpm.",
"download_flatpak": "flatpak.",
"title_x64": "لينيكس 64 بت",
"download_zip": "النسخة المحمولة بصيغة zip"
"download_zip": "النسخة المحمولة بصيغة zip",
"title_arm64": "نظام لينكس على ARM"
},
"download_helper_server_docker": {
"download_ghcr": "ghcr.io",
@@ -97,7 +99,8 @@
"download_now": {
"text": "تنزيل الان ",
"platform_small": "لاجل{{platform}}",
"linux_small": "لLinux"
"linux_small": "لLinux",
"linux_big": "اصدار v {{version}} لنظام لينكس"
},
"faq": {
"title": "الاسئلة المتكررة"

View File

@@ -1 +1,9 @@
{}
{
"get-started": {
"title": "Aan de slag",
"desktop_title": "Download de desktop applicatie (v{{version}})",
"architecture": "Architectuur:",
"older_releases": "Bekijk oudere versies",
"server_title": "Richt een server in voor toegang vanaf meerdere apparaten"
}
}

View File

@@ -1 +1,192 @@
{}
{
"get-started": {
"desktop_title": "Pobierz wersję desktopową (v{{version}})",
"architecture": "Architektura:",
"older_releases": "Sprawdź poprzednie wydania",
"server_title": "Skonfiguruj serwer, aby mieć dostęp z wielu urządzeń",
"title": "Start"
},
"hero_section": {
"title": "Uporządkuj swoje myśli i zbuduj bazę Twojej wiedzy.",
"subtitle": "Trilium to otwartoźródłowe rozwiązanie do notowania i organizacji swojej personalnej bazy wiedzy. Używaj go lokalnie na swoim komputerze lub synchronizuj swoje notatki na własnym serwerze i miej do nich dostęp gdziekolwiek jesteś.",
"get_started": "Start",
"github": "GitHub",
"dockerhub": "Docker Hub",
"screenshot_alt": "Zrzut ekranu wersji desktopowej Trilium Notes"
},
"organization_benefits": {
"title": "Układ",
"note_structure_title": "Struktura notatek",
"note_structure_description": "Notatki mogą być ułożone w hierarchię. Każda notatka może zawierać w sobie inne, co pozwala umieścić tą samą notatkę w wielu miejscach w hierarchii i nie wymusza to tworzenia dodatkowych folderów.",
"attributes_title": "Etykiety i korelacje",
"attributes_description": "Porządkuj łatwiej swoje notatki przy użyciu relacji i etykiet, używaj ich jako odnośników w tabelach i tablicach.",
"hoisting_title": "Przestrzenie robocze i windowanie notatek",
"hoisting_description": "Łatwo oddziel swoje personalne notatki od tych z pracy przez grupowanie ich w przestrzenie robocze, które pomogą ci się skupić na danym temacie."
},
"productivity_benefits": {
"title": "Produktywność i bezpieczeństwo",
"revisions_title": "Historia zmian",
"revisions_content": "Notatki są regularnie zapisywane w tle, co pozwala to przeglądać i cofać wprowadzone zmiany. Zapisy można także wykonywać \"na życzenie\".",
"sync_title": "Synchronizacja",
"sync_content": "Używaj własnych lub chmurowych instancji do łatwiejszej synchronizacji notatek między wieloma urządzeniami, w tym twoim telefonem używając PWA.",
"protected_notes_title": "Notatki chronione",
"protected_notes_content": "Chroń wrażliwe informacje szyfrując notatki i blokując dostęp do nich za pomocą hasła sesji.",
"jump_to_title": "Szybkie wyszukiwanie i komendy",
"jump_to_content": "Szybko i łatwo wyszukuj swoje notatki używając funkcji lub komend, nawet gdy nie pamiętasz dokładnej ich nazwy.",
"search_title": "Dokładne wyszukiwanie",
"search_content": "Albo wyszukaj tekst w notatkach, możesz dostosować zakres szukania do konkretnej notatki albo hierarchii pliku.",
"web_clipper_title": "Web clipper",
"web_clipper_content": "Dołączaj strony internetowe albo ich zrzuty i umieszczaj je bezpośrednio w swoich notatkach dzięki rozszerzeniu do przeglądarki."
},
"note_types": {
"text_title": "Notatki tekstowe",
"text_description": "Edytuj notatki w graficznym interfejsie (WYSIWYG), który wspiera tabele, obrazy, działania matematyczne i bloki kodu z podświetlaniem składni. Szybko formatuj tekst używając skrótów (Markdown), jak i komend (/).",
"code_title": "Notatki kodowe",
"code_description": "Duże fragmenty kodu źródłowego albo skryptów można umieścić w dedykowanych plikach z własnym edytorem. Podświetlenie składni i struktur, różne motywy i wsparcie dla wielu języków programowania ułatwi edycję.",
"file_title": "Obsługa plików",
"file_description": "Dodawaj pliki takie jak PDF-y, zdjęcia i pliki wideo z podglądem w aplikacji.",
"canvas_title": "Płótno",
"canvas_description": "Dodawaj kształty, zdjęcia i tekst na nieskończonym płótnie, używając tej samej technologii co excalidraw.com. Idealne do diagramów, szkiców i projektowania.",
"mermaid_title": "Diagramy Mermaid",
"mermaid_description": "Twórz diagramy, takie jak schematy blokowe, diagramy klas i sekwencyjne, wykresy Gantta i wiele innych, korzystając z składni Mermaid.",
"mindmap_title": "Mapy myśli",
"mindmap_description": "Organizuj wizualnie swoje myśli albo przeprowadź sesję burzy mózgów.",
"others_list": "I wiele innych: <0>mapa notatek</0>, <1>mapa powiązań</1>, <2>zapisane wyszukiwania</2>, <3>renderowane notatki</3>, and <4>podgląd stron www</4>."
},
"extensibility_benefits": {
"title": "Udostępnianie i rozszerzenia",
"import_export_title": "Import/Export",
"import_export_description": "Łatwa interakcja z innymi aplikacjami przy użyciu formatów Markdown, ENEX i OLM.",
"share_title": "Udostępniaj notatki w internecie",
"share_description": "Jeśli masz własny serwer, możesz go używać do udostępniania danych notatek z innymi.",
"scripting_title": "Zaawansowane skrypty",
"scripting_description": "Stwórz swoje własne integracje z Trilium przy użyciu personalizowanych widżetów albo z serwerowych skryptów.",
"api_title": "REST API",
"api_description": "Twórz integracje Trilium z użyciem REST API."
},
"collections": {
"calendar_title": "Kalendarze",
"calendar_description": "Organizuj swoje prywatne i służbowe wydarzenia używając kalendarza. Miej plany pod kontrolą z tygodniowym, miesięcznym i rocznym podglądem. Twórz i edytuj wydarzenia w prosty i intuicyjny sposób.",
"table_title": "Tabele",
"table_description": "Wyświetlaj i edytuj informacje o notatkach w tabelach na wiele sposobów dzięki wielu typom kolumn: Tekstowym, numerycznym, z polami wyboru, z datami i godzinami, zawierającym linki, z kolorowymi wypełnieniami i powiązaniami notatek. Możesz nawet wyświetlić całe drzewo hierarchii w tabeli.",
"board_title": "Tablice",
"board_description": "Organizuj swoje zadania i postępy projektów w tablicach Kanban z prostym tworzeniem nowych elementów i kolumn, a możliwość graficznego ich przenoszenia ułatwi zmianę statusu i pozwoli zachować porządek.",
"geomap_title": "Mapy",
"geomap_description": "Zaplanuj wakacje albo interesujące miejsca bezpośrednio na mapie, używaj personalizowanych pinezek. Dzięki możliwości importu plików GPX możesz wyświetlać przebyte trasy."
},
"faq": {
"title": "Częste pytania",
"mobile_question": "Czy jest dostępna aplikacja mobilna?",
"mobile_answer": "Aktualnie nie ma oficjalnej aplikacji mobilnej, jednak jeśli posiadasz uruchomioną aplikacje na serwerze, to możesz mieć dostęp za pomocą przeglądarki, a nawet zainstalować ją jako PWA. Dla systemu android jest nieoficjalna aplikacja \"TriliumDroid\", która działa nawet w trybie offline (jak zwykła desktopowa).",
"database_question": "Gdzie są przechowywane moje dane?",
"database_answer": "Wszystkie twoje notatki są przechowywane w bazie danych SQLite, w folderze aplikacji (lokalnie). Trilium używa baz danych zamiast zwykłych plików tekstowych dla lepszej wydajności i niektórych funkcji, które byłoby trudno zaimplementować w inny sposób (np. ta sama notatka w wielu miejscach). Folder aplikacji możesz łatwo znaleźć w zakładce \"O programie\".",
"server_question": "Czy muszę posiadać serwer, aby używać Trilium?",
"server_answer": "Nie, serwer umożliwia dostęp do aplikacji z poziomu przeglądarki, i obsługuje synchronizację na wielu urządzeniach. Z początku wystarczającym rozwiązaniem jest aplikacja desktopowa.",
"scaling_question": "Jak dobrze aplikacja radzi sobie z dużą ilością notatek?",
"scaling_answer": "W zależności od użycia, aplikacja powinna być w stanie utrzymać bezproblemowo do 100 000 notatek. Trzeba zaznaczyć, że synchronizacja czasami może skończyć się niepowodzeniem w przypadku wielu plików ponad 1GB. Trilium jest bardziej przystosowane do tworzenia baz wiedzy, niż do jako katalog plików (np. NextCloud).",
"network_share_question": "Czy mogę udostępniać moje bazy danych przez dyski sieciowe?",
"network_share_answer": "Nie, ogólnie przesyłanie baz SQLite przez dyski sieciowe nie jest dobrym pomysłem. Czasami może to zadziałać, ale istnieje szansa, że taka baza danych może zostać uszkodzona przez niedoskonałości blokad plików w sieci.",
"security_question": "Jak są chronione moje dane?",
"security_answer": "Domyślnie notatki nie są szyfrowane i mogą być odczytane bezpośrednio z bazy danych. Kiedy notatka zostanie oznaczona jako zaszyfrowana, to ta notatka szyfrowana jest używając AES-128-CBC."
},
"final_cta": {
"title": "Gotowy aby zacząć przygodę z Trilium Notes?",
"description": "Zbuduj swoją personalną bazę wiedzy z zaawansowanymi funkcjami i pełną prywatnością.",
"get_started": "Start"
},
"components": {
"link_learn_more": "Dowiedz się więcej....",
"list_with_screenshot_alt": "Zrzut ekranu wybranej funkcji"
},
"download_now": {
"text": "Pobierz teraz ",
"platform_big": "v{{version}} dla {{platform}}",
"platform_small": "dla {{platform}}",
"linux_big": "v{{version}} dla Linuxa",
"linux_small": "dla Linuxa",
"more_platforms": "Więcej platform i konfiguracja serwera"
},
"footer": {
"copyright_and_the": " i ",
"copyright_community": "społeczność"
},
"social_buttons": {
"github": "GitHub",
"github_discussions": "GitHub - Forum",
"matrix": "Matrix",
"reddit": "Reddit"
},
"support_us": {
"title": "Wesprzyj nas",
"financial_donations_title": "Wsparcie finansowe",
"financial_donations_description": "Trilium jest tworzone i rozwijane przez <Link>setki godzin pracy</Link>. Twoje wsparcie utrzymuje projekt jako otwartoźródłowy, pomaga dodawać nowe rzeczy i pokrywa koszty hostingu.",
"financial_donations_cta": "Rozważ wsparcie głównego programisty (<Link>eliandoran</Link>) poza aplikacją przez:",
"github_sponsors": "GitHub Sponsors",
"paypal": "PayPal",
"buy_me_a_coffee": "Postaw mi wirtualną kawę"
},
"contribute": {
"title": "Inne sposoby wsparcia",
"way_translate": "Przetłumacz aplikacja na swój natywny język przez <Link>Weblate</Link>.",
"way_community": "Dołącz do społeczności na <Discussions>GitHub Discussions</Discussions> lub na <Matrix>Matrix</Matrix>.",
"way_reports": "Zgłoś błędy przez<Link>GitHub issues</Link>.",
"way_document": "Pomóż nam w doskonaleniu dokumentacji przez informowanie nas o lukach albo sam pomóż w tworzeniu treści (dokumentacja, FAQ, poradniki).",
"way_market": "Powiedz o nas swoim znajomym, na blogu albo na social mediach."
},
"404": {
"title": "404: Nie znaleziono strony",
"description": "Strona, której szukasz, nie istnieje. Mogła zostać usunięta, albo wpisany adres jest niepoprawny."
},
"download_helper_desktop_windows": {
"title_x64": "Windows 64-bit",
"title_arm64": "Windows na ARM",
"description_x64": "Kompatybilne z urządzeniami Intel i AMD działającymi pod kontrolą Windows 10 i 11.",
"description_arm64": "Kompatybilne z procesorami ARM (np. Qualcomm Snapdragon).",
"quick_start": "Aby zainstalować przez WinGet:",
"download_exe": "Pobierz instalator (.exe)",
"download_zip": "Wersja przenośna - Portable (.zip)",
"download_scoop": "Scoop"
},
"download_helper_desktop_linux": {
"title_x64": "Linux 64-bit",
"title_arm64": "Linux na ARM",
"description_x64": "Dla większości dystrybucji Linux, kompatybilnych z architekturą x86_64.",
"description_arm64": "Dla dystrybucji ARM Linux kompatybilnych z architekturą aarch64.",
"quick_start": "Wybierz odpowiedni format paczki, w zależności od twojej dystrybucji:",
"download_deb": ".deb",
"download_rpm": ".rpm",
"download_flatpak": ".flatpak",
"download_zip": "Wersja przenośna - Portable (.zip)",
"download_nixpkgs": "nixpkgs",
"download_aur": "AUR"
},
"download_helper_desktop_macos": {
"title_x64": "macOS z Intel",
"title_arm64": "macOS z Apple Silicon (ARM)",
"description_x64": "Dla macOS w wersji Big Sur i późniejszymi, z procesorem Intel.",
"description_arm64": "Dla produktów Apple z procesorami M1 i M2.",
"quick_start": "Instalacja przez Homebrew:",
"download_dmg": "Pobierz instalator (.dmg)",
"download_homebrew_cask": "Homebrew Cask",
"download_zip": "Wersja przenośna - Portable (.zip)"
},
"download_helper_server_docker": {
"title": "Własny serwer przez Docker",
"description": "Łatwa instalacja na Windows, Linux albo macOS używając Docker container.",
"download_dockerhub": "Docker Hub",
"download_ghcr": "ghcr.io"
},
"download_helper_server_linux": {
"title": "Własny serwer na Linux",
"description": "Wrzuć Trilium Notes na swój serwer albo VPS, kompatybilne z większością dystrybucji.",
"download_tar_x64": "x64 (.tar.xz)",
"download_tar_arm64": "ARM (.tar.xz)",
"download_nixos": "moduł NixOS"
},
"download_helper_server_hosted": {
"title": "Płatny Serwer - Hosting",
"description": "Trilium Notes hostowane na PikaPods, płatnym serwisie dla łatwego dostępu i zarządzania. Bezpośrednio nie związanie z Trilium team.",
"download_pikapod": "Konfiguruj na PikaPods",
"download_triliumcc": "Alternatywnie patrz na trilium.cc"
}
}

View File

@@ -127,7 +127,7 @@ export const downloadMatrix: DownloadMatrix = {
title: t("download_helper_server_docker.title"),
description: t("download_helper_server_docker.description"),
helpUrl: "https://docs.triliumnotes.org/User%20Guide/User%20Guide/Installation%20%26%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.html",
quickStartCode: "docker pull triliumnext/trilium\ndocker run -p 8080:8080 -d ./data:/home/node/trilium-data triliumnext/trilium",
quickStartCode: "docker pull triliumnext/trilium\ndocker run -p 8080:8080 -d -v ./data:/home/node/trilium-data triliumnext/trilium",
downloads: {
dockerhub: {
name: t("download_helper_server_docker.download_dockerhub"),

View File

@@ -30,6 +30,13 @@ Trilium Notes 是一款免费且开源、跨平台的阶层式笔记应用程序
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📖 文件
**请访问我们完整的文档:[docs.triliumnotes.org](https://docs.triliumnotes.org/)**

View File

@@ -30,6 +30,12 @@ Trilium Notes 是一款免費且開源、跨平台的階層式筆記應用程式
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ 下載
- [最新版本](https://github.com/TriliumNext/Trilium/releases/latest)
穩定版本,推薦給大多數使用者。
- [夜間構建](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
不穩定開發版本,每日更新最新功能與修復內容。
## 📚 文件
**可以在 [docs.triliumnotes.org](https://docs.triliumnotes.org/) 查看完整使用說明**

9
docs/README-ar.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚توثيق
**Visit our comprehensive documentation at
@@ -132,7 +139,7 @@ The original Trilium developer ([Zadam](https://github.com/zadam)) has
graciously given the Trilium repository to the community project which resides
at https://github.com/TriliumNext
### ⬆️Migrating from Zadam/Trilium?
### ⬆️ الهجرة من Zadam الى تريليوم؟
There are no special migration steps to migrate from a zadam/Trilium instance to
a TriliumNext/Trilium instance. Simply [install

7
docs/README-ca.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

9
docs/README-cs.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Stáhnout
- [Nejnovější verze](https://github.com/TriliumNext/Trilium/releases/latest)
stabilní verze, doporučena pro většinu uživatelů.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at
@@ -59,7 +66,7 @@ Our documentation is available in multiple formats:
- [Patterns of Personal Knowledge
Base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
## 🎁 Features
## 🎁 Funkce
* Notes can be arranged into arbitrarily deep tree. Single note can be placed
into multiple places in the tree (see

40
docs/README-de.md vendored
View File

@@ -29,38 +29,44 @@ Trilium Notes ist eine freie, open-source, plattformfreie, hierarchische
Notiz-Anwendung mit Fokus auf die Erstellung großer persönlicher
Wissenssammlungen.
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for
quick overview:
Siehe [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) für
einen schnellen Überblick:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Neueste Version](https://github.com/TriliumNext/Trilium/releases/latest)
stabile Version, für die meisten Benutzer empfohlen.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
instabile Entwicklungsversion, die täglich mit den neuesten Funktionen und
Fehlerbehebungen aktualisiert wird.
## 📚 Dokumentation
**Visit our comprehensive documentation at
**Besuche unsere umfassende Dokumentation unter
[docs.triliumnotes.org](https://docs.triliumnotes.org/)**
Unsere Dokumentation ist verfügbar in mehreren Formaten:
- **Online Documentation**: Browse the full documentation at
- **Online-Dokumentation**: Die vollständige Dokumentation finden man unter
[docs.triliumnotes.org](https://docs.triliumnotes.org/)
- **In-App Help**: Press `F1` within Trilium to access the same documentation
directly in the application
- **GitHub**: Navigate through the [User
Guide](./docs/User%20Guide/User%20Guide/) in this repository
- **GitHub**: Durchsuche das
[Benutzerhandbuch](./docs/User%20Guide/User%20Guide/) in diesem Repository
### Quick Links
- [Getting Started Guide](https://docs.triliumnotes.org/)
- [Installation
Instructions](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
### Schnellzugriff
- [Erste Schritte](https://docs.triliumnotes.org/)
- [Installationsanleitung](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation.md)
- [Docker
Setup](./docs/User%20Guide/User%20Guide/Installation%20&%20Setup/Server%20Installation/1.%20Installing%20the%20server/Using%20Docker.md)
- [Upgrading
TriliumNext](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
- [Basic Concepts and
Features](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
- [Patterns of Personal Knowledge
Base](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
- [TriliumNext
aktualisieren](./docs/User%20Guide/User%20Guide/Installation%20%26%20Setup/Upgrading%20TriliumNext.md)
- [Grundkonzepte und
Funktionen](./docs/User%20Guide/User%20Guide/Basic%20Concepts%20and%20Features/Notes.md)
- [Muster persönlicher
Wissensdatenbanken](https://triliumnext.github.io/Docs/Wiki/patterns-of-personal-knowledge)
## 🎁 Features
## 🎁 Funktionen
* Notes can be arranged into arbitrarily deep tree. Single note can be placed
into multiple places in the tree (see

7
docs/README-el.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-es.md vendored
View File

@@ -36,6 +36,13 @@ resumen rápido:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentación
**Accede a la documentación completa en

7
docs/README-fa.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-fi.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-fr.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-hr.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-hu.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-id.md vendored
View File

@@ -34,6 +34,13 @@ untuk ikhtisar cepat:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Dokumentasi
**Kunjungi dokumentasi lengkap kami di

7
docs/README-it.md vendored
View File

@@ -34,6 +34,13 @@ una panoramica veloce:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentazione
**Vedi tutta la documentazione su

6
docs/README-ja.md vendored
View File

@@ -32,6 +32,12 @@ Trilium Notes
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ ダウンロード
- [最新リリース](https://github.com/TriliumNext/Trilium/releases/latest)
安定バージョン。ほとんどのユーザーに推奨されます。
- [ナイトリービルド](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
不安定な開発バージョン。最新の機能と修正が毎日更新されます。
## 📚 ドキュメント
**包括的なドキュメントは [docs.triliumnotes.org](https://docs.triliumnotes.org/) でご覧ください**

7
docs/README-ko.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-md.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

20
docs/README-nl.md vendored
View File

@@ -12,9 +12,9 @@
# Trilium Notes
![GitHub Sponsoren](https://img.shields.io/github/sponsors/eliandoran)
![LiberaPay patrons](https://img.shields.io/liberapay/patrons/ElianDoran)\
![LiberaPay supporters](https://img.shields.io/liberapay/patrons/ElianDoran)\
![Docker Pulls](https://img.shields.io/docker/pulls/triliumnext/trilium)
![GitHub Downloads (all assets, all
![GitHub Downloads (alle bestanden, alle
releases)](https://img.shields.io/github/downloads/triliumnext/trilium/total)\
[![RelativeCI](https://badges.relative-ci.com/badges/Di5q7dz9daNDZ9UXi0Bp?branch=develop)](https://app.relative-ci.com/projects/Di5q7dz9daNDZ9UXi0Bp)
[![Vertaling
@@ -25,14 +25,22 @@ status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted
| [Japanese](./docs/README-ja.md) | [Italian](./docs/README-it.md) |
[Spanish](./docs/README-es.md)
Trilium Notes is a free and open-source, cross-platform hierarchical note taking
application with focus on building large personal knowledge bases.
Trillium Notes is een gratis en open-source, platformonafhankelijke,
hiërarchische notitie-applicatie die zich richt op het opbouwen van grote
persoonlijke kennisbanken.
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for
quick overview:
Bekijk [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour)
voor een snel overzicht:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentatie
**Bekijk onze beknopte documentatie op

27
docs/README-pl.md vendored
View File

@@ -25,24 +25,32 @@ status](https://hosted.weblate.org/widget/trilium/svg-badge.svg)](https://hosted
| [Japanese](./docs/README-ja.md) | [Italian](./docs/README-it.md) |
[Spanish](./docs/README-es.md)
Trilium Notes is a free and open-source, cross-platform hierarchical note taking
application with focus on building large personal knowledge bases.
Trilium Notes to darmowa, otwarto-źródłowa i wieloplatformowa aplikacja do
tworzenia hierarchicznych notatek, skoncentrowana na budowaniu dużych osobistych
baz wiedzy.
See [screenshots](https://triliumnext.github.io/Docs/Wiki/screenshot-tour) for
quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## 📚 Documentation
## Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly) -
niestabilna wersja deweloperska, aktualizowana codziennie o najnowsze funkcje
i poprawki.
**Visit our comprehensive documentation at
## 📚Dokumentacja
**Odwiedź naszą obszerną dokumentację na
[docs.triliumnotes.org](https://docs.triliumnotes.org/)**
Our documentation is available in multiple formats:
Nasza dokumentacja jest dostępna w wielu formatach:
- **Online Documentation**: Browse the full documentation at
[docs.triliumnotes.org](https://docs.triliumnotes.org/)
- **In-App Help**: Press `F1` within Trilium to access the same documentation
directly in the application
- **Pomoc w aplikacji**: Naciśnij `F1` w Trilium, aby uzyskać dostęp do tej
samej dokumentacji bezpośrednio w aplikacji
- **GitHub**: Navigate through the [User
Guide](./docs/User%20Guide/User%20Guide/) in this repository
@@ -64,9 +72,10 @@ Our documentation is available in multiple formats:
* Notes can be arranged into arbitrarily deep tree. Single note can be placed
into multiple places in the tree (see
[cloning](https://triliumnext.github.io/Docs/Wiki/cloning-notes))
* Rich WYSIWYG note editor including e.g. tables, images and
[math](https://triliumnext.github.io/Docs/Wiki/text-notes) with markdown
* Bogaty edytor notatek WYSIWYG, zawierający np. tabele, obrazy i
[math](https://triliumnext.github.io/Docs/Wiki/text-notes) z
[autoformat](https://triliumnext.github.io/Docs/Wiki/text-notes#autoformat)
Markdown
* Support for editing [notes with source
code](https://triliumnext.github.io/Docs/Wiki/code-notes), including syntax
highlighting

7
docs/README-pt.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

7
docs/README-ro.md vendored
View File

@@ -34,6 +34,13 @@ ecran](https://triliumnext.github.io/Docs/Wiki/screenshot-tour):
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentație
**Vizitați documentația noastră detaliată la

7
docs/README-ru.md vendored
View File

@@ -33,6 +33,13 @@ Trilium Notes это приложение для заметок с иера
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Документация
**Visit our comprehensive documentation at

7
docs/README-sl.md vendored
View File

@@ -33,6 +33,13 @@ quick overview:
<a href="https://triliumnext.github.io/Docs/Wiki/screenshot-tour"><img src="./docs/app.png" alt="Trilium Screenshot" width="1000"></a>
## ⏬ Download
- [Latest release](https://github.com/TriliumNext/Trilium/releases/latest)
stable version, recommended for most users.
- [Nightly build](https://github.com/TriliumNext/Trilium/releases/tag/nightly)
unstable development version, updated daily with the latest features and
fixes.
## 📚 Documentation
**Visit our comprehensive documentation at

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