Merge remote-tracking branch 'origin/develop' into feature/client_typescript_port1

; Conflicts:
;	package-lock.json
This commit is contained in:
Elian Doran 2024-12-19 19:05:51 +02:00
commit ba6c6cb77f
No known key found for this signature in database
64 changed files with 953 additions and 551 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 256 256" version="1.1" viewBox="0 0 256 256" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<title>TrilliumNext Notes</title>
<title>TriliumNext Notes</title>
<path fill="black" d="m232.6 27.598c-17.706 0.092041-40.298 3.7127-58.258 10.104-1.7959 0.63909-3.5465 1.3043-5.2402 1.998-3.1 1.2-6.0988 2.6016-8.7988 4.1016-2.2 1.2-4.3016 2.4988-6.1016 3.7988-21.6 15.5-27.9 44.2-28.6 65.4l14.9-10.5 14.301-10 51.199-35.9-49.1 39.301-14.1 11.299-14.801 11.801c20.4 6.5 52.4 9.7992 74.9-6.3008 3.1886-2.319 6.4708-5.1162 9.7559-8.459 0.14708-0.08175 0.29689-0.1571 0.44336-0.24023 2.3386-2.3386 4.7705-4.8714 7.0215-7.5898 0.02928-0.033868 0.05864-0.065681 0.08789-0.099609 0.0964-0.038723 0.1948-0.072111 0.29102-0.11133 14.544-16.737 27.833-39.152 32.252-55.658 0.67979-2.5395 1.1487-4.9387 1.3809-7.1562 0.11607-1.1088 0.17422-2.173 0.16797-3.1855-1.0438-0.3625-2.1849-0.68557-3.4121-0.9707-1.2272-0.28513-2.542-0.53096-3.9336-0.74024s-2.8595-0.38069-4.3965-0.51562c-3.0739-0.26987-6.4198-0.39341-9.9609-0.375zm-202.79 20.252c-11.737-0.05-22.113 1.4004-28.312 4.6504 0.9 5.6625 4.3309 13.419 9.3125 21.77v0.001953c3.3209 5.5664 7.332 11.395 11.74 17.043v0.001953c6.6127 8.4716 14.122 16.534 21.547 22.684 2.3 1.9 4.5008 3.5996 6.8008 5.0996 0.048555 0.0124 0.097907 0.019 0.14648 0.03125 1.7845 1.2837 3.569 2.2777 5.3535 3.1699 20.8 10.4 45.5 3.7984 62.1-4.1016l-14.301-7.2988-13.6-6.9004-48.127-24.607 49.928 21.707 14.5 6.3008 15.199 6.5996c-3.4-18.3-14.099-44-35.799-54.9-3.3-1.6-6.9004-3.1004-10.9-4.4004-2.9-0.9-5.8996-1.7-9.0996-2.5-11.65-2.75-24.751-4.2996-36.488-4.3496zm97.488 73.85 3.6992 13.9 3.5996 13.201 12.801 47.6-15.9-47-4.5-13.4-4.8008-14.199c-10.3 13.4-21.3 36.199-15.5 57.199 0.8747 3.11 2.1333 6.3182 3.6719 9.709 0.01066 0.06374 0.01836 0.12769 0.0293 0.19141 1.1 2.5 2.3988 5.0992 3.7988 7.6992 10.4 18.8 27.701 38.501 39.701 42.801 0.00763-0.00936 0.01581-0.01991 0.02344-0.0293 0.02502 0.00909 0.05119 0.02035 0.07617 0.0293 8.8-10.8 16.8-42.601 15.9-65.701-0.1-2.7-0.30117-5.2992-0.70117-7.6992-0.3-1.9-0.69922-3.8-1.1992-5.5-5.6-20.2-25.199-32.601-40.699-38.801z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 256 256" version="1.1" viewBox="0 0 256 256" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<title>TrilliumNext Notes</title>
<title>TriliumNext Notes</title>
<style type="text/css">
.st0{fill:#95C980;}
.st1{fill:#72B755;}

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 256 256" version="1.1" viewBox="0 0 256 256" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<title>TrilliumNext Notes</title>
<title>TriliumNext Notes</title>
<g>
<path d="m202.9 112.7c-22.5 16.1-54.5 12.8-74.9 6.3l14.8-11.8 14.1-11.3 49.1-39.3-51.2 35.9-14.3 10-14.9 10.5c0.7-21.2 7-49.9 28.6-65.4 1.8-1.3 3.9-2.6 6.1-3.8 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.4 2.8-4.9 5.4-7.4 7.8-3.4 3.5-6.8 6.4-10.1 8.8z" fill="#ab60e3"/>
<path d="m213.1 104c-22.2 12.6-51.4 9.3-70.3 3.2l14.1-11.3 49.1-39.3-51.2 35.9-14.3 10c0.5-18.1 4.9-42.1 19.7-58.6 2.7-1.5 5.7-2.9 8.8-4.1 27.1-11.1 68.5-15.3 85.2-9.5 0.1 16.2-15.9 45.4-33.9 65.9-2.3 2.8-4.8 5.4-7.2 7.8z" fill="#8038b8"/>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 256 256" version="1.1" viewBox="0 0 256 256" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<title>TrilliumNext Notes</title>
<title>TriliumNext Notes</title>
<path fill="white" d="m232.6 27.598c-17.706 0.092041-40.298 3.7127-58.258 10.104-1.7959 0.63909-3.5465 1.3043-5.2402 1.998-3.1 1.2-6.0988 2.6016-8.7988 4.1016-2.2 1.2-4.3016 2.4988-6.1016 3.7988-21.6 15.5-27.9 44.2-28.6 65.4l14.9-10.5 14.301-10 51.199-35.9-49.1 39.301-14.1 11.299-14.801 11.801c20.4 6.5 52.4 9.7992 74.9-6.3008 3.1886-2.319 6.4708-5.1162 9.7559-8.459 0.14708-0.08175 0.29689-0.1571 0.44336-0.24023 2.3386-2.3386 4.7705-4.8714 7.0215-7.5898 0.02928-0.033868 0.05864-0.065681 0.08789-0.099609 0.0964-0.038723 0.1948-0.072111 0.29102-0.11133 14.544-16.737 27.833-39.152 32.252-55.658 0.67979-2.5395 1.1487-4.9387 1.3809-7.1562 0.11607-1.1088 0.17422-2.173 0.16797-3.1855-1.0438-0.3625-2.1849-0.68557-3.4121-0.9707-1.2272-0.28513-2.542-0.53096-3.9336-0.74024s-2.8595-0.38069-4.3965-0.51562c-3.0739-0.26987-6.4198-0.39341-9.9609-0.375zm-202.79 20.252c-11.737-0.05-22.113 1.4004-28.312 4.6504 0.9 5.6625 4.3309 13.419 9.3125 21.77v0.001953c3.3209 5.5664 7.332 11.395 11.74 17.043v0.001953c6.6127 8.4716 14.122 16.534 21.547 22.684 2.3 1.9 4.5008 3.5996 6.8008 5.0996 0.048555 0.0124 0.097907 0.019 0.14648 0.03125 1.7845 1.2837 3.569 2.2777 5.3535 3.1699 20.8 10.4 45.5 3.7984 62.1-4.1016l-14.301-7.2988-13.6-6.9004-48.127-24.607 49.928 21.707 14.5 6.3008 15.199 6.5996c-3.4-18.3-14.099-44-35.799-54.9-3.3-1.6-6.9004-3.1004-10.9-4.4004-2.9-0.9-5.8996-1.7-9.0996-2.5-11.65-2.75-24.751-4.2996-36.488-4.3496zm97.488 73.85 3.6992 13.9 3.5996 13.201 12.801 47.6-15.9-47-4.5-13.4-4.8008-14.199c-10.3 13.4-21.3 36.199-15.5 57.199 0.8747 3.11 2.1333 6.3182 3.6719 9.709 0.01066 0.06374 0.01836 0.12769 0.0293 0.19141 1.1 2.5 2.3988 5.0992 3.7988 7.6992 10.4 18.8 27.701 38.501 39.701 42.801 0.00763-0.00936 0.01581-0.01991 0.02344-0.0293 0.02502 0.00909 0.05119 0.02035 0.07617 0.0293 8.8-10.8 16.8-42.601 15.9-65.701-0.1-2.7-0.30117-5.2992-0.70117-7.6992-0.3-1.9-0.69922-3.8-1.1992-5.5-5.6-20.2-25.199-32.601-40.699-38.801z"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

43
package-lock.json generated
View File

@ -25,7 +25,7 @@
"bootstrap": "5.3.3",
"boxicons": "2.1.4",
"cheerio": "1.0.0",
"chokidar": "4.0.1",
"chokidar": "4.0.2",
"cls-hooked": "4.2.2",
"codemirror": "5.65.18",
"compression": "1.7.5",
@ -42,7 +42,7 @@
"escape-html": "1.0.3",
"eslint": "9.17.0",
"express": "4.21.2",
"express-rate-limit": "7.4.1",
"express-rate-limit": "7.5.0",
"express-session": "1.18.1",
"force-graph": "1.47.1",
"fs-extra": "11.2.0",
@ -51,7 +51,7 @@
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.6",
"i18next": "24.1.0",
"i18next": "24.1.2",
"i18next-fs-backend": "2.6.0",
"i18next-http-backend": "3.0.1",
"image-type": "5.2.0",
@ -65,10 +65,10 @@
"jquery.fancytree": "2.38.3",
"jsdom": "25.0.1",
"jsplumb": "2.15.6",
"katex": "0.16.15",
"katex": "0.16.17",
"knockout": "3.5.1",
"mark.js": "8.11.1",
"marked": "15.0.3",
"marked": "15.0.4",
"mermaid": "11.4.1",
"mime-types": "2.1.35",
"mind-elixir": "4.3.3",
@ -5694,9 +5694,9 @@
}
},
"node_modules/chokidar": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.2.tgz",
"integrity": "sha512-/b57FK+bblSU+dfewfFe0rT1YjVDfOmeLQwCAuC+vwvgLkXboATqqmy+Ipux6JrF6L5joe5CBnFOw+gLWH6yKg==",
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
@ -8390,9 +8390,10 @@
}
},
"node_modules/express-rate-limit": {
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.4.1.tgz",
"integrity": "sha512-KS3efpnpIDVIXopMc65EMbWbUht7qvTCdtCR2dD/IZmi9MIkopYESwyRqLgv8Pfu589+KqDqOdzJWW7AHoACeg==",
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.0.tgz",
"integrity": "sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==",
"license": "MIT",
"engines": {
"node": ">= 16"
},
@ -8400,7 +8401,7 @@
"url": "https://github.com/sponsors/express-rate-limit"
},
"peerDependencies": {
"express": "4 || 5 || ^5.0.0-beta.1"
"express": "^4.11 || 5 || ^5.0.0-beta.1"
}
},
"node_modules/express-session": {
@ -9912,9 +9913,9 @@
}
},
"node_modules/i18next": {
"version": "24.1.0",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-24.1.0.tgz",
"integrity": "sha512-suKlX82AlptkMUO5YRfaAeH4FQyyKvR66jNaubTMiyPPMx7INU6PXAiy3PGULc0q6K+t9nxmDf/TRj9KjAivmw==",
"version": "24.1.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-24.1.2.tgz",
"integrity": "sha512-th/075GW0Ub1gYDMHLiZXMGSfGv1aP1VqjT3fma/12hNHCNlH8oJMftvlDzycT/R+KoULWk+xLU8H1JRwV85qw==",
"funding": [
{
"type": "individual",
@ -11723,9 +11724,9 @@
}
},
"node_modules/katex": {
"version": "0.16.15",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.15.tgz",
"integrity": "sha512-yE9YJIEAk2aZ+FL/G8r+UGw0CTUzEA8ZFy6E+8tc3spHUKq3qBnzCkI1CQwGoI9atJhVyFPEypQsTY7mJ1Pi9w==",
"version": "0.16.17",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.16.17.tgz",
"integrity": "sha512-OyzSrXBllz+Jdc9Auiw0kt21gbZ4hkz8Q5srVAb2U9INcYIfGKbxe+bvNvEz1bQ/NrDeRRho5eLCyk/L03maAw==",
"funding": [
"https://opencollective.com/katex",
"https://github.com/sponsors/katex"
@ -12281,9 +12282,9 @@
}
},
"node_modules/marked": {
"version": "15.0.3",
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.3.tgz",
"integrity": "sha512-Ai0cepvl2NHnTcO9jYDtcOEtVBNVYR31XnEA3BndO7f5As1wzpcOceSUM8FDkNLJNIODcLpDTWay/qQhqbuMvg==",
"version": "15.0.4",
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.4.tgz",
"integrity": "sha512-TCHvDqmb3ZJ4PWG7VEGVgtefA5/euFmsIhxtD0XsBxI39gUSKL81mIRFdt0AiNQozUahd4ke98ZdirExd/vSEw==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"

View File

@ -68,7 +68,7 @@
"bootstrap": "5.3.3",
"boxicons": "2.1.4",
"cheerio": "1.0.0",
"chokidar": "4.0.1",
"chokidar": "4.0.2",
"cls-hooked": "4.2.2",
"codemirror": "5.65.18",
"compression": "1.7.5",
@ -85,7 +85,7 @@
"escape-html": "1.0.3",
"eslint": "9.17.0",
"express": "4.21.2",
"express-rate-limit": "7.4.1",
"express-rate-limit": "7.5.0",
"express-session": "1.18.1",
"force-graph": "1.47.1",
"fs-extra": "11.2.0",
@ -94,7 +94,7 @@
"html2plaintext": "2.1.4",
"http-proxy-agent": "7.0.2",
"https-proxy-agent": "7.0.6",
"i18next": "24.1.0",
"i18next": "24.1.2",
"i18next-fs-backend": "2.6.0",
"i18next-http-backend": "3.0.1",
"image-type": "5.2.0",
@ -108,10 +108,10 @@
"jquery.fancytree": "2.38.3",
"jsdom": "25.0.1",
"jsplumb": "2.15.6",
"katex": "0.16.15",
"katex": "0.16.17",
"knockout": "3.5.1",
"mark.js": "8.11.1",
"marked": "15.0.3",
"marked": "15.0.4",
"mermaid": "11.4.1",
"mime-types": "2.1.35",
"mind-elixir": "4.3.3",

View File

@ -0,0 +1,52 @@
import markdownExportService from "../../../src/services/export/md.js";
import { trimIndentation } from "../../support/utils.js";
describe("Markdown export", () => {
it("trims language tag for code blocks", () => {
const html = trimIndentation`\
<p>A diff:</p>
<pre><code class="language-text-x-diff">Hello
-world
+worldy
</code></pre>`;
const expected = trimIndentation`\
A diff:
\`\`\`diff
Hello
-world
+worldy
\`\`\``;
expect(markdownExportService.toMarkdown(html)).toBe(expected);
});
it("removes auto tag for code blocks", () => {
const html = trimIndentation`\
<pre><code class="language-text-x-trilium-auto">Hello
-world
+worldy
</code></pre>`;
const expected = trimIndentation`\
\`\`\`
Hello
-world
+worldy
\`\`\``;
expect(markdownExportService.toMarkdown(html)).toBe(expected);
});
it("supports code block with no language tag", () => {
const html = trimIndentation`\
<pre><code>Hello</code></pre>`;
const expected = trimIndentation`\
\`\`\`
Hello
\`\`\``;
expect(markdownExportService.toMarkdown(html)).toBe(expected);
});
});

View File

@ -0,0 +1,14 @@
import { trimIndentation } from "./utils.js";
describe("Utils", () => {
it("trims indentation", () => {
expect(trimIndentation`\
Hello
world
123`
).toBe(`\
Hello
world
123`);
});
});

21
spec/support/utils.ts Normal file
View File

@ -0,0 +1,21 @@
export function trimIndentation(strings: TemplateStringsArray) {
const str = strings.toString();
// Count the number of spaces on the first line.
let numSpaces = 0;
while (str.charAt(numSpaces) == ' ' && numSpaces < str.length) {
numSpaces++;
}
// Trim the indentation of the first line in all the lines.
const lines = str.split("\n");
const output = [];
for (let i=0; i<lines.length; i++) {
let numSpacesLine = 0;
while (str.charAt(numSpacesLine) == ' ' && numSpacesLine < str.length) {
numSpacesLine++;
}
output.push(lines[i].substring(numSpacesLine));
}
return output.join("\n");
}

View File

@ -57,7 +57,7 @@ app.use(`/icon.png`, express.static(path.join(scriptDir, 'public/icon.png')));
app.use(sessionParser);
app.use(favicon(`${scriptDir}/../images/app-icons/icon.ico`));
assets.register(app);
await assets.register(app);
routes.register(app);
custom.register(app);
error_handlers.register(app);

View File

@ -98,7 +98,7 @@ class BAttachment extends AbstractBeccaEntity<BAttachment> {
/** @returns true if the note has string content (not binary) */
hasStringContent(): boolean {
return this.type !== undefined && utils.isStringNote(this.type, this.mime);
return utils.isStringNote(this.type, this.mime); // here was !== undefined && utils.isStringNote(this.type, this.mime); I dont know why we need !=undefined. But it filters out canvas libary items
}
isContentAvailable() {

View File

@ -82,9 +82,10 @@ export default class RootCommandExecutor extends Component {
async showBackendLogCommand() {
await appContext.tabManager.openTabWithNoteWithHoisting('_backendLog', { activate: true });
}
async showLaunchBarSubtreeCommand() {
await this.showAndHoistSubtree('_lbRoot');
this.showLeftPaneCommand();
}
async showShareSubtreeCommand() {

View File

@ -227,7 +227,7 @@ export default class RibbonContainer extends NoteContextAwareWidget {
.attr('data-ribbon-component-name', ribbonWidget.name)
.append($('<span class="ribbon-tab-title-icon">')
.addClass(ret.icon)
.attr("data-title", ret.title)
.attr("title", ret.title)
.attr('data-toggle-command', ribbonWidget.toggleCommand))
.append(" ")
.append($('<span class="ribbon-tab-title-label">').text(ret.title));

View File

@ -12,7 +12,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t("about.title")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('about.close')}"></button>
</div>
<div class="modal-body">
<table class="table table-borderless text-nowrap">

View File

@ -45,8 +45,8 @@ const TPL = `
<h4>${t('bulk_actions.affected_notes')}: <span class="affected-note-count">0</span></h4>
<div class="form-check">
<input class="include-descendants form-check-input" type="checkbox" value="">
<label class="form-check-label">${t('bulk_actions.include_descendants')}</label>
<input id="include-descendants" class="include-descendants form-check-input" type="checkbox" value="">
<label for="include-descendants" class="form-check-label">${t('bulk_actions.include_descendants')}</label>
</div>
<h4>${t('bulk_actions.available_actions')}</h4>

View File

@ -15,7 +15,7 @@ const TPL = `
<div class="modal-header">
<h5 class="modal-title flex-grow-1">${t('clone_to.clone_notes_to')}</h5>
<button type="button" class="help-button" title="${t('clone_to.help_on_links')}" data-help-page="cloning-notes.html">?</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('clone_to.close')}"></button>
</div>
<form class="clone-to-form">
<div class="modal-body">

View File

@ -9,7 +9,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t('confirm.confirmation')}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('confirm.close')}"></button>
</div>
<div class="modal-body">
<div class="confirm-dialog-content"></div>

View File

@ -11,17 +11,17 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">${t('delete_notes.delete_notes_preview')}</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('delete_notes.close')}"></button>
</div>
<div class="modal-body">
<div class="form-checkbox">
<input class="delete-all-clones form-check-input" value="1" type="checkbox">
<label class="form-check-label">${t('delete_notes.delete_all_clones_description')}</label>
<input id="delete-all-clones" class="delete-all-clones form-check-input" value="1" type="checkbox">
<label for="delete-all-clones" class="form-check-label">${t('delete_notes.delete_all_clones_description')}</label>
</div>
<div class="form-checkbox" style="margin-bottom: 1rem">
<input class="erase-notes form-check-input" value="1" type="checkbox">
<label class="form-check-label">${t('delete_notes.erase_notes_warning')}</label>
<input id="erase-notes" class="erase-notes form-check-input" value="1" type="checkbox">
<label for="erase-notes" class="form-check-label">${t('delete_notes.erase_notes_warning')}</label>
</div>
<div class="delete-notes-list-wrapper">

View File

@ -11,7 +11,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t('include_note.dialog_title')}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('include_note.close')}"></button>
</div>
<form class="include-note-form">
<div class="modal-body">

View File

@ -12,7 +12,7 @@ const TPL = `<div class="jump-to-note-dialog modal mx-auto" tabindex="-1" role="
<div class="input-group">
<input class="jump-to-note-autocomplete form-control" placeholder="${t('jump_to_note.search_placeholder')}">
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('jump_to_note.close')}"></button>
</div>
<div class="modal-body">
<div class="algolia-autocomplete-container jump-to-note-results"></div>

View File

@ -12,7 +12,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t("markdown_import.dialog_title")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("markdown_import.close")}"></button>
</div>
<div class="modal-body">
<p>${t("markdown_import.modal_body_text")}</p>

View File

@ -13,7 +13,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title me-auto">${t("move_to.dialog_title")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("move_to.close")}"></button>
</div>
<form class="move-to-form">
<div class="modal-body">

View File

@ -24,7 +24,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t("note_type_chooser.modal_title")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("note_type_chooser.close")}"></button>
</div>
<div class="modal-body">
${t("note_type_chooser.modal_body")}

View File

@ -8,7 +8,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t("password_not_set.title")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("password_not_set.close")}"></button>
</div>
<div class="modal-body">
${t("password_not_set.body1")}

View File

@ -9,7 +9,7 @@ const TPL = `
<form class="prompt-dialog-form">
<div class="modal-header">
<h5 class="prompt-title modal-title">${t("prompt.title")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('prompt.close')}"></button>
</div>
<div class="modal-body"></div>
<div class="modal-footer">

View File

@ -14,8 +14,8 @@ const TPL = `
</div>
<form class="protected-session-password-form">
<div class="modal-body">
<label class="col-form-label">${t("protected_session_password.form_label")}</label>
<input class="form-control protected-session-password" type="password">
<label for="protected-session-password" class="col-form-label">${t("protected_session_password.form_label")}asbd</label>
<input id="protected-session-password" class="form-control protected-session-password" type="password">
</div>
<div class="modal-footer">
<button class="btn btn-primary">${t("protected_session_password.start_button")}</button>

View File

@ -18,7 +18,7 @@ const TPL = `
<div class="modal-header">
<h5 class="modal-title flex-grow-1">${t('recent_changes.title')}</h5>
<button class="erase-deleted-notes-now-button btn btn-sm" style="padding: 0 10px">${t('recent_changes.erase_notes_button')}</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('recent_changes.close')}"></button>
</div>
<div class="modal-body">
<div class="recent-changes-content"></div>

View File

@ -46,7 +46,7 @@ const TPL = `
title="${t("revisions.delete_all_revisions")}"
style="padding: 0 10px 0 10px;" type="button">${t("revisions.delete_all_button")}</button>
<button class="help-button" type="button" data-help-page="note-revisions.html" title="${t("revisions.help_title")}">?</button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("revisions.close")}"></button>
</div>
<div class="modal-body" style="display: flex; height: 80vh;">
<div class="dropdown">

View File

@ -8,44 +8,44 @@ const TPL = `<div class="sort-child-notes-dialog modal mx-auto" tabindex="-1" ro
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t("sort_child_notes.sort_children_by")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("sort_child_notes.close")}"></button>
</div>
<form class="sort-child-notes-form">
<div class="modal-body">
<h5>${t("sort_child_notes.sorting_criteria")}</h5>
<div class="form-check">
<input class="form-check-input" type="radio" name="sort-by" value="title" checked>
<label class="form-check-label">${t("sort_child_notes.title")}</label>
<input id="sort-by-title" class="form-check-input" type="radio" name="sort-by" value="title" checked>
<label for="sort-by-title" class="form-check-label">${t("sort_child_notes.title")}</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="sort-by" value="dateCreated">
<label class="form-check-label">${t("sort_child_notes.date_created")}</label>
<input id="sort-by-dateCreated" class="form-check-input" type="radio" name="sort-by" value="dateCreated">
<label for="sort-by-dateCreated" class="form-check-label">${t("sort_child_notes.date_created")}</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="sort-by" value="dateModified">
<label class="form-check-label">${t("sort_child_notes.date_modified")}</label>
<input id="sort-by-dateModified" class="form-check-input" type="radio" name="sort-by" value="dateModified">
<label for="sort-by-dateModified" class="form-check-label">${t("sort_child_notes.date_modified")}</label>
</div>
<br/>
<h5>${t("sort_child_notes.sorting_direction")}</h5>
<div class="form-check">
<input class="form-check-input" type="radio" name="sort-direction" value="asc" checked>
<label class="form-check-label">${t("sort_child_notes.ascending")}</label>
<input id="sort-direction-asc" class="form-check-input" type="radio" name="sort-direction" value="asc" checked>
<label for="sort-direction-asc" class="form-check-label">${t("sort_child_notes.ascending")}</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="sort-direction" value="desc">
<label class="form-check-label">${t("sort_child_notes.descending")}</label>
<input id="sort-direction-desc" class="form-check-input" type="radio" name="sort-direction" value="desc">
<label for="sort-direction-desc" class="form-check-label">${t("sort_child_notes.descending")}</label>
</div>
<br />
<h5>${t("sort_child_notes.folders")}</h5>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="sort-folders-first" value="1">
<label class="form-check-label">${t("sort_child_notes.sort_folders_at_top")}</label>
<input id="sort-folders-first" class="form-check-input" type="checkbox" name="sort-folders-first" value="1">
<label for="sort-folders-first" class="form-check-label">${t("sort_child_notes.sort_folders_at_top")}</label>
</div>
<br />
<h5>${t("sort_child_notes.natural_sort")}</h5>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="sort-natural" value="1">
<label class="form-check-label">${t("sort_child_notes.sort_with_respect_to_different_character_sorting")}</label>
<input id="sort-natural" class="form-check-input" type="checkbox" name="sort-natural" value="1">
<label for="sort-natural" class="form-check-label">${t("sort_child_notes.sort_with_respect_to_different_character_sorting")}</label>
</div>
<br />
<div class="form-check">

View File

@ -11,7 +11,7 @@ const TPL = `
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">${t("upload_attachments.upload_attachments_to_note")}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t('upload_attachments.close')}"></button>
</div>
<form class="upload-attachment-form">
<div class="modal-body">

View File

@ -76,7 +76,7 @@ export default class QuickSearchWidget extends BasicWidget {
});
shortcutService.bindElShortcut(this.$searchString, 'down', () => {
this.$dropdownMenu.find('.dropdown-item:first').focus();
this.$dropdownMenu.find('.dropdown-item:not(.disabled):first').focus();
});
shortcutService.bindElShortcut(this.$searchString, 'esc', () => {

View File

@ -96,7 +96,6 @@ export default class SyncStatusWidget extends BasicWidget {
return;
}
console.log("Align ", this.settings.titlePlacement);
bootstrap.Tooltip.getOrCreateInstance(this.$widget.find(`.sync-status-${className}`), {
html: true,
placement: this.settings.titlePlacement,

View File

@ -116,7 +116,6 @@ const TAB_ROW_TPL = `
.tab-row-widget .note-tab,
.tab-row-widget .note-tab * {
user-select: none;
cursor: default;
}
@ -140,7 +139,7 @@ const TAB_ROW_TPL = `
pointer-events: all;
color: var(--inactive-tab-text-color);
--tab-background-color: var(--workspace-tab-background-color);
background-color: var(--tab-background-color, var(--inactive-tab-background-color));
background-color: var(--tab-background-color, var(--inactive-tab-background-color));
}
.tab-row-widget .note-tab[active] .note-tab-wrapper {
@ -177,6 +176,7 @@ const TAB_ROW_TPL = `
bottom: 0;
right: 0;
left: 0;
z-index: 1000;
}
.tab-row-widget .note-tab .note-tab-close {

View File

@ -22,7 +22,6 @@ export default class TemplateSwitchWidget extends SwitchWidget {
this.$switchOffButton.attr("title", t("template_switch.toggle-off-hint"));
this.$helpButton.attr("data-help-page", "template.html").show();
this.$helpButton.on('click', e => utils.openHelp($(e.target)));
}
async switchOn() {

View File

@ -2,7 +2,7 @@ import libraryLoader from '../../services/library_loader.js';
import TypeWidget from './type_widget.js';
import utils from '../../services/utils.js';
import linkService from '../../services/link.js';
import server from '../../services/server.js';
const TPL = `
<div class="canvas-widget note-detail-canvas note-detail-printable note-detail">
<style>
@ -115,6 +115,11 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
this.reactHandlers; // used to control react state
this.libraryChanged = false;
// these 2 variables are needed to compare the library state (all library items) after loading to the state when the library changed. So we can find attachments to be deleted.
//every libraryitem is saved on its own json file in the attachments of the note.
this.librarycache = [];
this.attachmentMetadata=[]
}
static getType() {
@ -236,23 +241,47 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
fileArray.push(file);
}
Promise.all(
(await note.getAttachmentsByRole('canvasLibraryItem'))
.map(async attachment => {
const blob = await attachment.getBlob();
return {
blob, // Save the blob for libraryItems
metadata: { // metadata to use in the cache variables for comparing old library state and new one. We delete unnecessary items later, calling the server directly
attachmentId: attachment.attachmentId,
title: attachment.title,
},
};
})
).then(results => {
if (note.noteId !== this.currentNoteId) {
// current note changed in the course of the async operation
return;
}
// Extract libraryItems from the blobs
const libraryItems = results
.map(result => result.blob.getJsonContentSafely())
.filter(item => !!item);
// Extract metadata for each attachment
const metadata = results.map(result => result.metadata);
// Update the library and save to independent variables
this.excalidrawApi.updateLibrary({ libraryItems, merge: false });
// save state of library to compare it to the new state later.
this.librarycache = libraryItems;
this.attachmentMetadata = metadata;
});
// Update the scene
this.excalidrawApi.updateScene(sceneData);
this.excalidrawApi.addFiles(fileArray);
this.excalidrawApi.history.clear();
}
Promise.all(
(await note.getAttachmentsByRole('canvasLibraryItem'))
.map(attachment => attachment.getBlob())
).then(blobs => {
if (note.noteId !== this.currentNoteId) {
// current note changed in the course of the async operation
return;
}
const libraryItems = blobs.map(blob => blob.getJsonContentSafely()).filter(item => !!item);
this.excalidrawApi.updateLibrary({libraryItems, merge: false});
});
// set initial scene version
if (this.currentSceneVersion === this.SCENE_VERSION_INITIAL) {
@ -313,19 +342,54 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
// there's no separate method to get library items, so have to abuse this one
const libraryItems = await this.excalidrawApi.updateLibrary({merge: true});
// excalidraw saves the library as a own state. the items are saved to libraryItems. then we compare the library right now with a libraryitemcache. The cache is filled when we first load the Library into the note.
//We need the cache to delete old attachments later in the server.
const libraryItemsMissmatch = this.librarycache.filter(obj1 => !libraryItems.some(obj2 => obj1.id === obj2.id));
// before we saved the metadata of the attachments in a cache. the title of the attachment is a combination of libraryitem ´s ID und it´s name.
// we compare the library items in the libraryitemmissmatch variable (this one saves all libraryitems that are different to the state right now. E.g. you delete 1 item, this item is saved as mismatch)
// then we combine its id and title and search the according attachmentID.
const matchingItems = this.attachmentMetadata.filter(meta => {
// Loop through the second array and check for a match
return libraryItemsMissmatch.some(item => {
// Combine the `name` and `id` from the second array
const combinedTitle = `${item.id}${item.name}`;
return meta.title === combinedTitle;
});
});
// we save the attachment ID`s in a variable and delete every attachmentID. Now the items that the user deleted will be deleted.
const attachmentIds = matchingItems.map(item => item.attachmentId);
//delete old attachments that are no longer used
for (const item of attachmentIds){
await server.remove(`attachments/${item}`);
}
let position = 10;
// prepare data to save to server e.g. new library items.
for (const libraryItem of libraryItems) {
attachments.push({
role: 'canvasLibraryItem',
title: libraryItem.id,
title: libraryItem.id + libraryItem.name,
mime: 'application/json',
content: JSON.stringify(libraryItem),
position: position
});
position += 10;
}
}
return {

View File

@ -28,8 +28,8 @@ const TPL = `
<div class="form-group row">
<div class="col-6">
<label>${t("highlighting.color-scheme")}</label>
<select class="theme-select form-select"></select>
<label for="highlighting-color-scheme-select">${t("highlighting.color-scheme")}</label>
<select id="highlighting-color-scheme-select" class="theme-select form-select"></select>
</div>
<div class="col-6 side-checkbox">

View File

@ -8,8 +8,8 @@ const TPL = `
<div class="form-group row">
<div class="col-12">
<label>${t("electron_integration.zoom-factor")}</label>
<input type="number" class="zoom-factor-select form-control options-number-input" min="0.3" max="2.0" step="0.1"/>
<label for="zoom-factor-select">${t("electron_integration.zoom-factor")}</label>
<input id="zoom-factor-select" type="number" class="zoom-factor-select form-control options-number-input" min="0.3" max="2.0" step="0.1"/>
<p>${t("zoom_factor.description")}</p>
</div>
</div>

View File

@ -36,15 +36,15 @@ const TPL = `
<div class="form-group row">
<div class="col-6">
<label>${t("fonts.font_family")}</label>
<select class="main-font-family form-select"></select>
<label for="main-font-family">${t("fonts.font_family")}</label>
<select id="main-font-family" class="main-font-family form-select"></select>
</div>
<div class="col-6">
<label>${t("fonts.size")}</label>
<label for="main-font-size">${t("fonts.size")}</label>
<div class="input-group">
<input type="number" class="main-font-size form-control options-number-input" min="50" max="200" step="10"/>
<input id="main-font-size" type="number" class="main-font-size form-control options-number-input" min="50" max="200" step="10"/>
<span class="input-group-text">%</span>
</div>
</div>
@ -54,15 +54,15 @@ const TPL = `
<div class="form-group row">
<div class="col-4">
<label>${t("fonts.font_family")}</label>
<select class="tree-font-family form-select"></select>
<label for="tree-font-family">${t("fonts.font_family")}</label>
<select id="tree-font-family" class="tree-font-family form-select"></select>
</div>
<div class="col-6">
<label>${t("fonts.size")}</label>
<label for="tree-font-size">${t("fonts.size")}</label>
<div class="input-group">
<input type="number" class="tree-font-size form-control options-number-input" min="50" max="200" step="10"/>
<input id="tree-font-size" type="number" class="tree-font-size form-control options-number-input" min="50" max="200" step="10"/>
<span class="input-group-text">%</span>
</div>
</div>
@ -72,15 +72,15 @@ const TPL = `
<div class="form-group row">
<div class="col-4">
<label>${t("fonts.font_family")}</label>
<select class="detail-font-family form-select"></select>
<label for="detail-font-family">${t("fonts.font_family")}</label>
<select id="detail-font-family" class="detail-font-family form-select"></select>
</div>
<div class="col-6">
<label>${t("fonts.size")}</label>
<label for="detail-font-size">${t("fonts.size")}</label>
<div class="input-group">
<input type="number" class="detail-font-size form-control options-number-input" min="50" max="200" step="10"/>
<input id="detail-font-size" type="number" class="detail-font-size form-control options-number-input" min="50" max="200" step="10"/>
<span class="input-group-text">%</span>
</div>
</div>
@ -90,15 +90,15 @@ const TPL = `
<div class="form-group row">
<div class="col-4">
<label>${t("fonts.font_family")}</label>
<select class="monospace-font-family form-select"></select>
<label for="monospace-font-family">${t("fonts.font_family")}</label>
<select id="monospace-font-family" class="monospace-font-family form-select"></select>
</div>
<div class="col-6">
<label>${t("fonts.size")}</label>
<label for="monospace-font-size">${t("fonts.size")}</label>
<div class="input-group">
<input type="number" class="monospace-font-size form-control options-number-input" min="50" max="200" step="10"/>
<input id="monospace-font-size" type="number" class="monospace-font-size form-control options-number-input" min="50" max="200" step="10"/>
<span class="input-group-text">%</span>
</div>
</div>

View File

@ -9,13 +9,13 @@ const TPL = `
<div class="form-group row">
<div class="col-6">
<label>${t("i18n.language")}</label>
<select class="locale-select form-select"></select>
<label for="locale-select">${t("i18n.language")}</label>
<select id="locale-select" class="locale-select form-select"></select>
</div>
<div class="col-6">
<label>${t("i18n.first-day-of-the-week")}</label>
<select class="first-day-of-week-select form-select">
<label for="first-day-of-week-select">${t("i18n.first-day-of-the-week")}</label>
<select id="first-day-of-week-select" class="first-day-of-week-select form-select">
<option value="0">${t("i18n.sunday")}</option>
<option value="1">${t("i18n.monday")}</option>
</select>

View File

@ -12,8 +12,8 @@ const TPL = `
<div class="form-group row">
<div class="col-6">
<label>${t("max_content_width.max_width_label")}</label>
<input type="number" min="${MIN_VALUE}" step="10" class="max-content-width form-control options-number-input">
<label for="max-content-width">${t("max_content_width.max_width_label")}</label>
<input id="max-content-width" type="number" min="${MIN_VALUE}" step="10" class="max-content-width form-control options-number-input">
</div>
</div>

View File

@ -31,8 +31,8 @@ const TPL = `
<div class="form-group row">
<div class="col-6">
<label>${t("theme.theme_label")}</label>
<select class="theme-select form-select"></select>
<label for="theme-select">${t("theme.theme_label")}</label>
<select id="theme-select" class="theme-select form-select"></select>
</div>
<div class="col-6 side-checkbox">
@ -69,8 +69,11 @@ export default class ThemeOptions extends OptionsWidget {
async optionsLoaded(options) {
const themes = [
{ val: 'next', title: t("theme.triliumnext") },
{ val: 'next-light', title: t("theme.triliumnext-light") },
{ val: 'next-dark', title: t("theme.triliumnext-dark") },
{ val: 'auto', title: t('theme.auto_theme') },
{ val: 'light', title: t('theme.light_theme') },
{ val: 'dark', title: t('theme.dark_theme') }
{ val: 'dark', title: t('theme.dark_theme') }
].concat(await server.get('options/user-themes'));
this.$themeSelect.empty();

View File

@ -8,8 +8,8 @@ const TPL = `
<p>${t('code_auto_read_only_size.description')}</p>
<div class="form-group">
<label>${t('code_auto_read_only_size.label')}</label>
<input class="auto-readonly-size-code form-control options-number-input" type="number" min="0">
<label for="auto-readonly-size-code">${t('code_auto_read_only_size.label')}</label>
<input id="auto-readonly-size-code" class="auto-readonly-size-code form-control options-number-input" type="number" min="0">
</div>
</div>`;

View File

@ -10,8 +10,8 @@ const TPL = `
<form class="sync-setup-form">
<div class="form-group">
<label>${t("search_engine.predefined_templates_label")}</label>
<select class="predefined-search-engine-select form-control">
<label for="predefined-search-engine-select">${t("search_engine.predefined_templates_label")}</label>
<select id="predefined-search-engine-select" class="predefined-search-engine-select form-control">
<option value="Bing">${t("search_engine.bing")}</option>
<option value="Baidu">${t("search_engine.baidu")}</option>
<option value="DuckDuckGo">${t("search_engine.duckduckgo")}</option>

View File

@ -14,18 +14,18 @@ const TPL = `
<form class="change-password-form">
<div class="old-password-form-group form-group">
<label>${t("password.old_password")}</label>
<input class="old-password form-control" type="password">
<label for="old-password">${t("password.old_password")}</label>
<input id="old-password" class="old-password form-control" type="password">
</div>
<div class="form-group">
<label>${t("password.new_password")}</label>
<input class="new-password1 form-control" type="password">
<label for="new-password1">${t("password.new_password")}</label>
<input id="new-password1" class="new-password1 form-control" type="password">
</div>
<div class="form-group">
<label>${t("password.new_password_confirmation")}</label>
<input class="new-password2 form-control" type="password">
<label for="new-password2">${t("password.new_password_confirmation")}</label>
<input id="new-password2" class="new-password2 form-control" type="password">
</div>
<button class="save-password-button btn btn-primary">${t("password.change_password")}</button>
@ -38,8 +38,8 @@ const TPL = `
<p>${t("password.protected_session_timeout_description")} <a href="https://triliumnext.github.io/Docs/Wiki/protected-notes.html" class="external">${t("password.wiki")}</a> ${t("password.for_more_info")}</p>
<div class="form-group">
<label>${t("password.protected_session_timeout_label")}</label>
<input class="protected-session-timeout-in-seconds form-control options-number-input" type="number" min="60">
<label for="protected-session-timeout-in-seconds">${t("password.protected_session_timeout_label")}</label>
<input id="protected-session-timeout-in-seconds" class="protected-session-timeout-in-seconds form-control options-number-input" type="number" min="60">
</div>
</div>`;

View File

@ -24,8 +24,8 @@ const TPL_ELECTRON = `
<br/>
<div class="form-group">
<label>${t('spellcheck.language_code_label')}</label>
<input type="text" class="spell-check-language-code form-control" placeholder="${t('spellcheck.language_code_placeholder')}">
<label for="spell-check-language-code">${t('spellcheck.language_code_label')}</label>
<input id="spell-check-language-code" type="text" class="spell-check-language-code form-control" placeholder="${t('spellcheck.language_code_placeholder')}">
</div>
<p>${t('spellcheck.multiple_languages_info')}</p>

View File

@ -9,18 +9,18 @@ const TPL = `
<form class="sync-setup-form">
<div class="form-group">
<label>${t('sync_2.server_address')}</label>
<input class="sync-server-host form-control" placeholder="https://<host>:<port>">
<label for="sync-server-host" >${t('sync_2.server_address')}</label>
<input id="sync-server-host" class="sync-server-host form-control" placeholder="https://<host>:<port>">
</div>
<div class="form-group">
<label>${t('sync_2.timeout')}</label>
<input class="sync-server-timeout form-control" min="1" max="10000000" type="number" style="text-align: left;">
<label for="sync-server-timeout" >${t('sync_2.timeout')}</label>
<input id="sync-server-timeout" class="sync-server-timeout form-control" min="1" max="10000000" type="number" style="text-align: left;">
</div>
<div class="form-group">
<label>${t('sync_2.proxy_label')}</label>
<input class="sync-proxy form-control" placeholder="https://<host>:<port>">
<label for="sync-proxy form-control" >${t('sync_2.proxy_label')}</label>
<input id="sync-proxy form-control" class="sync-proxy form-control" placeholder="https://<host>:<port>">
<p><strong>${t('sync_2.note')}:</strong> ${t('sync_2.note_description')}</p>
<p>${t('sync_2.special_value_description')}</p>

View File

@ -8,8 +8,8 @@ const TPL = `
<p>${t("text_auto_read_only_size.description")}</p>
<div class="form-group">
<label>${t("text_auto_read_only_size.label")}</label>
<input class="auto-readonly-size-text form-control options-number-input" type="number" min="0">
<label for="auto-readonly-size-text">${t("text_auto_read_only_size.label")}</label>
<input id="auto-readonly-size-text" class="auto-readonly-size-text form-control options-number-input" type="number" min="0">
</div>
</div>`;

View File

@ -0,0 +1,170 @@
/* Import the Next theme base style */
@import url(./theme-next/base.css);
/*
* Color scheme
*/
:root {
--theme-style: dark;
--native-titlebar-background: #00000000;
--main-background-color: #333;
--main-text-color: #ccc;
--main-border-color: #454545;
--subtle-border-color: #313131;
--dropdown-border-color: #292929;
--dropdown-shadow-opacity: .6;
--dropdown-item-icon-destructive-color: #de6e5b;
--disabled-tooltip-icon-color: #7fd2ef;
--accented-background-color: #555;
--button-background-color: transparent;
--button-border-color: #ccc;
--button-text-color: currentColor;
--button-border-radius: 5px;
--button-disabled-background-color: transparent;
--button-disabled-text-color: #999;
--primary-button-background-color: #888;
--primary-button-text-color: white;
--primary-button-border-color: #999;
--muted-text-color: #bbb;
--input-text-color: #ccc;
--input-background-color: #333;
--hover-item-text-color: #efefef;
--hover-item-background-color: #ffffff24;
--hover-item-border-color: transparent;
--active-item-text-color: var(--left-pane-text-color);
--active-item-background-color: #777;
--active-item-border-color: transparent;
--new-tab-button-background: #fff0;
--new-tab-button-color: #ffffff96;
--new-tab-button-shadow: 2px 2px 4px rgba(0, 0, 0, .4);
--new-tab-button-hover-background: #fff3;
--new-tab-button-hover-color: white;
--menu-text-color: #e3e3e3;
--menu-background-color: #222222d9;
--menu-item-icon-color: #8c8c8c;
--menu-item-disabled-opacity: .5;
--menu-item-keyboard-shortcut-color: #ffffff8f;
--menu-item-arrow-color: #ffffffa3;
--menu-item-delimiter-color: #ffffff1c;
--modal-background-color: #333;
--modal-backdrop-color: #444;
--quick-search-background: #ffffff12;
--quick-search-color: #ffffff52;
--quick-search-hover-background: #ffffff1f;
--quick-search-focus-border: #80808095;
--quick-search-focus-background: #ffffff1f;
--quick-search-focus-color: white;
--left-pane-collapsed-border-color: #0009;
--left-pane-background-color: #1f1f1f;
--left-pane-text-color: #AAAAAA;
--left-pane-item-hover-background: #ffffff0d;
--left-pane-item-selected-background: #ffffff25;
--left-pane-item-selected-color: #dfdfdf;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, .6);
--left-pane-item-action-button-background: #ffffff73;
--left-pane-item-action-button-color: black;
--left-pane-item-action-button-hover-background: #ffffffad;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, .15);
--left-pane-item-selected-action-button-hover-shadow: 2px 2px 10px rgba(0, 0, 0, .25);
--launcher-pane-background-color: #1a1a1a;
--launcher-pane-horizontal-background-color: #282828;
--launcher-pane-horizontal-border-color: rgb(22, 22, 22);
--launcher-pane-text-color: #909090;
--launcher-pane-button-hover-color: #ffffff;
--launcher-pane-button-hover-background: #ffffff1c;
--launcher-pane-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, .2);
--protected-session-active-icon-color: #8edd8e;
--sync-status-error-pulse-color: #f47871;
--root-background: var(--left-pane-background-color);
--gutter-color: transparent;
--gutter-hover-color: #626262;
--tab-close-button-hover-background: #a45353;
--tab-close-button-hover-color: white;
--active-tab-background-color: #ffffff1c;
--active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-text-color: #ffffffcd;
--active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, .2), -1px -1px 3px rgba(0, 0, 0, .4);
--active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, .4);
--inactive-tab-background-color: transparent;
--inactive-tab-hover-background-color: #ffffff0f;
--inactive-tab-text-color: #7c7c7c;
--right-pane-item-hover-background: #ffffff26;
--right-pane-item-hover-color: white;
--scrollbar-border-color: #666;
--scrollbar-background-color: #333;
--link-color: lightskyblue;
--mermaid-theme: dark;
--code-block-box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6);
--card-background-color: #363636;
--card-background-hover-color: #3c3c3c;
--card-background-press-color: #464646;
--card-border-color: #222222;
--card-box-shadow: 0 0 12px rgba(0, 0, 0, 0.15);
--calendar-color: var(--menu-text-color);
--calendar-weekday-labels-color: var(--muted-text-color);
--calendar-day-hover-color: var(--hover-item-text-color);
--calendar-day-hover-background: var(--active-item-background-color);
--calendar-day-highlight-background: #8080805a;
--timeline-bullet-color: gray;
--timeline-bullet-hover-color: white;
--timeline-connector-color: #464646;
--timeline-connector-active-color: #545454;
--timeline-connector-hover-blend-mode: exclusion;
--tooltip-background-color: rgba(67, 67, 67, 0.86);
--tooltip-foreground-color: #ffffffeb;
--tooltip-shadow-color: rgba(0, 0, 0, 0.4);
}
/*
* Dark color scheme tweaks
*/
body ::-webkit-calendar-picker-indicator {
filter: invert(1);
}
body .CodeMirror {
filter: invert(90%) hue-rotate(180deg);
}
.excalidraw.theme--dark {
--theme-filter: invert(80%) hue-rotate(180deg) !important;
}
body .todo-list input[type="checkbox"]:not(:checked):before {
border-color: var(--muted-text-color) !important;
}
.btn-close {
filter: invert(1);
}

View File

@ -0,0 +1,145 @@
/* Import the Next theme base style */
@import url(./theme-next/base.css);
/*
* Color scheme
*/
:root {
--theme-style: light;
--native-titlebar-background: #ffffff00;
--main-background-color: white;
--main-text-color: black;
--main-border-color: #dbdbdb;
--subtle-border-color: rgba(0, 0, 0, 0.1);
--dropdown-border-color: #ccc;
--dropdown-shadow-opacity: .2;
--dropdown-item-icon-destructive-color: #ec5138;
--disabled-tooltip-icon-color: #004382;
--accented-background-color: #f5f5f5;
--button-background-color: transparent;
--button-border-color: #ddd;
--button-text-color: black;
--button-border-radius: 5px;
--button-disabled-background-color: #ddd;
--button-disabled-text-color: black;
--primary-button-background-color: #6c757d;
--primary-button-text-color: white;
--primary-button-border-color: #6c757d;
--muted-text-color: #666;
--input-text-color: black;
--input-background-color: transparent;
--hover-item-text-color: black;
--hover-item-background-color: #0000001a;
--hover-item-border-color: transparent;
--active-item-text-color: var(--left-pane-text-color);
--active-item-background-color: #ddd;
--active-item-border-color: transparent;
--menu-text-color: #272727;
--menu-background-color: #ffffffd9;
--menu-item-icon-color: #727272;
--menu-item-disabled-opacity: .5;
--menu-item-keyboard-shortcut-color: #666666a8;
--menu-item-arrow-color: #00000080;
--menu-item-delimiter-color: #00000030;
--modal-background-color: white;
--modal-backdrop-color: black;
--quick-search-background: #00000012;
--quick-search-color: #06060682;
--quick-search-hover-background: #00000020;
--quick-search-focus-border: #00000029;
--quick-search-focus-background: #ffffff80;
--quick-search-focus-color: #000;
--left-pane-collapsed-border-color: #0000000d;
--left-pane-background-color: #f2f2f2;
--left-pane-text-color: #383838;
--left-pane-item-hover-background: #eaeaea;
--left-pane-item-selected-background: white;
--left-pane-item-selected-color: black;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, .2);
--left-pane-item-action-button-background: #d7d7d7;
--left-pane-item-action-button-color: inherit;
--left-pane-item-action-button-hover-background: white;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, .15);
--left-pane-item-selected-action-button-hover-shadow: 2px 2px 10px rgba(0, 0, 0, .25);
--launcher-pane-background-color: #e8e8e8;
--launcher-pane-horizontal-background-color: #fafafa;
--launcher-pane-horizontal-border-color: rgba(0, 0, 0, 0.1);
--launcher-pane-text-color: #000000bd;
--launcher-pane-button-hover-color: black;
--launcher-pane-button-hover-background: white;
--launcher-pane-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, .075);
--protected-session-active-icon-color: #16b516;
--sync-status-error-pulse-color: #ff5528;
--root-background: var(--left-pane-background-color);
--gutter-color: transparent;
--gutter-hover-color: #bfbfbf;
--tab-close-button-hover-background: #c95a5a;
--tab-close-button-hover-color: white;
--active-tab-background-color: white;
--active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-text-color: black;
--active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, .1), -1px -1px 3px rgba(0, 0, 0, .05);
--active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, .1);
--inactive-tab-background-color: transparent;
--inactive-tab-hover-background-color: #00000016;
--inactive-tab-text-color: #4e4e4e;
--new-tab-button-background: #d8d8d8;
--new-tab-button-color: #3a3a3a;
--new-tab-button-shadow: 2px 2px 4px rgba(0, 0, 0, .2);
--new-tab-button-hover-background: white;
--new-tab-button-hover-color: black;
--right-pane-item-hover-background: #ececec;
--right-pane-item-hover-color: inherit;
--scrollbar-border-color: #ddd;
--scrollbar-background-color: #ddd;
--link-color: blue;
--mermaid-theme: default;
--code-block-box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.1), 0px 0px 2px rgba(0, 0, 0, 0.2);
--card-background-color: var(--accented-background-color);
--card-background-hover-color: #f9f9f9;
--card-background-press-color: #efefef;
--card-border-color: #eaeaea;
--card-shadow-color: rgba(0, 0, 0, 0.1);
--card-box-shadow: 0 0 12px var(--card-shadow-color);
--calendar-color: var(--menu-text-color);
--calendar-weekday-labels-color: var(--muted-text-color);
--calendar-day-hover-color: var(--hover-item-text-color);
--calendar-day-hover-background: var(--active-item-background-color);
--calendar-day-highlight-background: #80808024;
--timeline-bullet-color: #a5a5a5;
--timeline-bullet-hover-color: black;
--timeline-connector-color: #f1f1f1;
--timeline-connector-active-color: #ddd;
--timeline-connector-hover-blend-mode: multiply;
--tooltip-background-color: rgba(255, 255, 255, 0.85);
--tooltip-foreground-color: #000000ba;
--tooltip-shadow-color: rgba(0, 0, 0, .15);
}

View File

@ -1,393 +1,7 @@
@import url(./theme-next/shell.css);
@import url(./theme-next/settings.css);
@import url(./theme-next/notes/text.css);
/* Import the light color scheme.
* This is the base color scheme, always active and overridden by the dark
* color scheme stylesheet when necessary. */
@import url(./theme-next-light.css);
@font-face {
font-family: "Noto Sans";
src: url(../fonts/Noto_Sans/NotoSans-VariableFont_wdth\,wght.ttf);
}
@font-face {
font-family: "Ubuntu Sans";
src: url(../fonts/Ubuntu_Sans/UbuntuSans-VariableFont_wdth\,wght.ttf);
}
@font-face {
font-family: "Nunito";
src: url(../fonts/Nunito/Nunito-VariableFont_wght.ttf);
}
@font-face {
font-family: "Inter";
src: url(../fonts/Inter/Inter-VariableFont_opsz\,wght.ttf);
}
:root {
/* --main-font-family: "Noto Sans", sans-serif; */
--main-font-family: "Segoe UI", sans-serif;
/* --main-font-family: "Ubuntu", sans-serif; */
/* --main-font-family: "Nunito", sans-serif; */
/* --main-font-family: "Inter", sans-serif; */
--main-font-size: normal;
--tree-font-family: var(--main-font-family);
--tree-font-size: normal;
--detail-font-family: var(--main-font-family);
--detail-font-size: normal;
--monospace-font-family: JetBrainsLight;
--monospace-font-size: normal;
--left-pane-item-selected-shadow-size: 2px;
--launcher-pane-size: 58px;
--launcher-pane-horizontal-size: 54px;
--launcher-pane-horizontal-icon-size: 20px;
--launcher-pane-button-margin: 6px;
--launcher-pane-button-gap: 3px;
--tree-actions-toolbar-horizontal-margin: 8px;
--tree-actions-toolbar-vertical-margin: 8px;
--tree-actions-toolbar-padding-size: 4px;
--tree-actions-toolbar-collapsed-width: 40px;
--tree-actions-toolbar-expand-button-size: 25px;
--tab-bar-height: 50px;
--tab-height: 36px;
--tab-first-item-horiz-offset: 1px;
--new-tab-button-size: 24px;
--center-pane-border-radius: 10px;
--menu-padding-size: 8px;
--menu-item-icon-vert-offset: 0;
--more-accented-background-color: var(--card-background-hover-color);
--timeline-left-gap: 20px;
--timeline-right-gap: 20px;
--timeline-item-top-padding: 4px;
--timeline-item-bottom-padding: 8px;
--timeline-bullet-size: 10px;
--timeline-bullet-vertical-pos: .75em;
--timeline-connector-size: 4px;
/* Theme capabilities */
--tab-note-icons: true;
}
/*
* THEME COLORS
*/
/*
* Light theme scheme
*/
:root {
--theme-style: light;
--native-titlebar-background: #ffffff00;
--main-background-color: white;
--main-text-color: black;
--main-border-color: #dbdbdb;
--subtle-border-color: rgba(0, 0, 0, 0.1);
--dropdown-border-color: #ccc;
--dropdown-shadow-opacity: .2;
--dropdown-item-icon-destructive-color: #ec5138;
--disabled-tooltip-icon-color: #004382;
--accented-background-color: #f5f5f5;
--button-background-color: transparent;
--button-border-color: #ddd;
--button-text-color: black;
--button-border-radius: 5px;
--button-disabled-background-color: #ddd;
--button-disabled-text-color: black;
--primary-button-background-color: #6c757d;
--primary-button-text-color: white;
--primary-button-border-color: #6c757d;
--muted-text-color: #666;
--input-text-color: black;
--input-background-color: transparent;
--hover-item-text-color: black;
--hover-item-background-color: #0000001a;
--hover-item-border-color: transparent;
--active-item-text-color: var(--left-pane-text-color);
--active-item-background-color: #ddd;
--active-item-border-color: transparent;
--menu-text-color: #272727;
--menu-background-color: #ffffffd9;
--menu-item-icon-color: #727272;
--menu-item-disabled-opacity: .5;
--menu-item-keyboard-shortcut-color: #666666a8;
--menu-item-arrow-color: #00000080;
--menu-item-delimiter-color: #00000030;
--modal-background-color: white;
--modal-backdrop-color: black;
--quick-search-background: #00000012;
--quick-search-color: #06060682;
--quick-search-hover-background: #00000020;
--quick-search-focus-border: #00000029;
--quick-search-focus-background: #ffffff80;
--quick-search-focus-color: #000;
--left-pane-collapsed-border-color: #0000000d;
--left-pane-background-color: #f2f2f2;
--left-pane-text-color: #383838;
--left-pane-item-hover-background: #eaeaea;
--left-pane-item-selected-background: white;
--left-pane-item-selected-color: black;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, .2);
--left-pane-item-action-button-background: #d7d7d7;
--left-pane-item-action-button-color: inherit;
--left-pane-item-action-button-hover-background: white;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, .15);
--left-pane-item-selected-action-button-hover-shadow: 2px 2px 10px rgba(0, 0, 0, .25);
--launcher-pane-background-color: #e8e8e8;
--launcher-pane-horizontal-background-color: #fafafa;
--launcher-pane-horizontal-border-color: rgba(0, 0, 0, 0.1);
--launcher-pane-text-color: #000000bd;
--launcher-pane-button-hover-color: black;
--launcher-pane-button-hover-background: white;
--launcher-pane-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, .075);
--protected-session-active-icon-color: #16b516;
--sync-status-error-pulse-color: #ff5528;
--root-background: var(--left-pane-background-color);
--gutter-color: transparent;
--gutter-hover-color: #bfbfbf;
--tab-close-button-hover-background: #c95a5a;
--tab-close-button-hover-color: white;
--active-tab-background-color: white;
--active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-text-color: black;
--active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, .1), -1px -1px 3px rgba(0, 0, 0, .05);
--active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, .1);
--inactive-tab-background-color: transparent;
--inactive-tab-hover-background-color: #00000016;
--inactive-tab-text-color: #4e4e4e;
--new-tab-button-background: #d8d8d8;
--new-tab-button-color: #3a3a3a;
--new-tab-button-shadow: 2px 2px 4px rgba(0, 0, 0, .2);
--new-tab-button-hover-background: white;
--new-tab-button-hover-color: black;
--right-pane-item-hover-background: #ececec;
--right-pane-item-hover-color: inherit;
--scrollbar-border-color: #ddd;
--scrollbar-background-color: #ddd;
--link-color: blue;
--mermaid-theme: default;
--code-block-box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.1), 0px 0px 2px rgba(0, 0, 0, 0.2);
--card-background-color: var(--accented-background-color);
--card-background-hover-color: #f9f9f9;
--card-background-press-color: #efefef;
--card-border-color: #eaeaea;
--card-shadow-color: rgba(0, 0, 0, 0.1);
--card-box-shadow: 0 0 12px var(--card-shadow-color);
--calendar-color: var(--menu-text-color);
--calendar-weekday-labels-color: var(--muted-text-color);
--calendar-day-hover-color: var(--hover-item-text-color);
--calendar-day-hover-background: var(--active-item-background-color);
--calendar-day-highlight-background: #80808024;
--timeline-bullet-color: #a5a5a5;
--timeline-bullet-hover-color: black;
--timeline-connector-color: #f1f1f1;
--timeline-connector-active-color: #ddd;
--timeline-connector-hover-blend-mode: multiply;
--tooltip-background-color: rgba(255, 255, 255, 0.85);
--tooltip-foreground-color: #000000ba;
--tooltip-shadow-color: rgba(0, 0, 0, .15);
}
/*
* Dark color scheme
*/
@media (prefers-color-scheme: dark) {
:root {
--theme-style: dark;
--native-titlebar-background: #00000000;
--main-background-color: #333;
--main-text-color: #ccc;
--main-border-color: #454545;
--subtle-border-color: #313131;
--dropdown-border-color: #292929;
--dropdown-shadow-opacity: .6;
--dropdown-item-icon-destructive-color: #de6e5b;
--disabled-tooltip-icon-color: #7fd2ef;
--accented-background-color: #555;
--button-background-color: transparent;
--button-border-color: #ccc;
--button-text-color: currentColor;
--button-border-radius: 5px;
--button-disabled-background-color: transparent;
--button-disabled-text-color: #999;
--primary-button-background-color: #888;
--primary-button-text-color: white;
--primary-button-border-color: #999;
--muted-text-color: #bbb;
--input-text-color: #ccc;
--input-background-color: #333;
--hover-item-text-color: #efefef;
--hover-item-background-color: #ffffff24;
--hover-item-border-color: transparent;
--active-item-text-color: var(--left-pane-text-color);
--active-item-background-color: #777;
--active-item-border-color: transparent;
--new-tab-button-background: #fff0;
--new-tab-button-color: #ffffff96;
--new-tab-button-shadow: 2px 2px 4px rgba(0, 0, 0, .4);
--new-tab-button-hover-background: #fff3;
--new-tab-button-hover-color: white;
--menu-text-color: #e3e3e3;
--menu-background-color: #222222d9;
--menu-item-icon-color: #8c8c8c;
--menu-item-disabled-opacity: .5;
--menu-item-keyboard-shortcut-color: #ffffff8f;
--menu-item-arrow-color: #ffffffa3;
--menu-item-delimiter-color: #ffffff1c;
--modal-background-color: #333;
--modal-backdrop-color: #444;
--quick-search-background: #ffffff12;
--quick-search-color: #ffffff52;
--quick-search-hover-background: #ffffff1f;
--quick-search-focus-border: #80808095;
--quick-search-focus-background: #ffffff1f;
--quick-search-focus-color: white;
--left-pane-collapsed-border-color: #0009;
--left-pane-background-color: #1f1f1f;
--left-pane-text-color: #AAAAAA;
--left-pane-item-hover-background: #ffffff0d;
--left-pane-item-selected-background: #ffffff25;
--left-pane-item-selected-color: #dfdfdf;
--left-pane-item-selected-shadow: 1px 1px 2px rgba(0, 0, 0, .6);
--left-pane-item-action-button-background: #ffffff73;
--left-pane-item-action-button-color: black;
--left-pane-item-action-button-hover-background: #ffffffad;
--left-pane-item-action-button-hover-shadow: 2px 2px 3px rgba(0, 0, 0, .15);
--left-pane-item-selected-action-button-hover-shadow: 2px 2px 10px rgba(0, 0, 0, .25);
--launcher-pane-background-color: #1a1a1a;
--launcher-pane-horizontal-background-color: #282828;
--launcher-pane-horizontal-border-color: rgb(22, 22, 22);
--launcher-pane-text-color: #909090;
--launcher-pane-button-hover-color: #ffffff;
--launcher-pane-button-hover-background: #ffffff1c;
--launcher-pane-button-hover-shadow: 4px 4px 4px rgba(0, 0, 0, .2);
--protected-session-active-icon-color: #8edd8e;
--sync-status-error-pulse-color: #f47871;
--root-background: var(--left-pane-background-color);
--gutter-color: transparent;
--gutter-hover-color: #626262;
--tab-close-button-hover-background: #a45353;
--tab-close-button-hover-color: white;
--active-tab-background-color: #ffffff1c;
--active-tab-hover-background-color: var(--active-tab-background-color);
--active-tab-text-color: #ffffffcd;
--active-tab-shadow: 3px 3px 6px rgba(0, 0, 0, .2), -1px -1px 3px rgba(0, 0, 0, .4);
--active-tab-dragging-shadow: var(--active-tab-shadow), 0 0 20px rgba(0, 0, 0, .4);
--inactive-tab-background-color: transparent;
--inactive-tab-hover-background-color: #ffffff0f;
--inactive-tab-text-color: #7c7c7c;
--right-pane-item-hover-background: #ffffff26;
--right-pane-item-hover-color: white;
--scrollbar-border-color: #666;
--scrollbar-background-color: #333;
--link-color: lightskyblue;
--mermaid-theme: dark;
--code-block-box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.6);
--card-background-color: #363636;
--card-background-hover-color: #3c3c3c;
--card-background-press-color: #464646;
--card-border-color: #222222;
--card-box-shadow: 0 0 12px rgba(0, 0, 0, 0.15);
--calendar-color: var(--menu-text-color);
--calendar-weekday-labels-color: var(--muted-text-color);
--calendar-day-hover-color: var(--hover-item-text-color);
--calendar-day-hover-background: var(--active-item-background-color);
--calendar-day-highlight-background: #8080805a;
--timeline-bullet-color: gray;
--timeline-bullet-hover-color: white;
--timeline-connector-color: #464646;
--timeline-connector-active-color: #545454;
--timeline-connector-hover-blend-mode: exclusion;
--tooltip-background-color: rgba(67, 67, 67, 0.86);
--tooltip-foreground-color: #ffffffeb;
--tooltip-shadow-color: rgba(0, 0, 0, 0.4);
}
body ::-webkit-calendar-picker-indicator {
filter: invert(1);
}
body .CodeMirror {
filter: invert(90%) hue-rotate(180deg);
}
.excalidraw.theme--dark {
--theme-filter: invert(80%) hue-rotate(180deg) !important;
}
body .todo-list input[type="checkbox"]:not(:checked):before {
border-color: var(--muted-text-color) !important;
}
.btn-close {
filter: invert(1);
}
}
/* Import the dark color scheme when the system preference is set to dark mode */
@import url(./theme-next-dark.css) (prefers-color-scheme: dark);

View File

@ -0,0 +1,79 @@
@import url(./shell.css);
@import url(./settings.css);
@import url(./notes/text.css);
@font-face {
font-family: "Noto Sans";
src: url(../fonts/Noto_Sans/NotoSans-VariableFont_wdth\,wght.ttf);
}
@font-face {
font-family: "Ubuntu Sans";
src: url(../fonts/Ubuntu_Sans/UbuntuSans-VariableFont_wdth\,wght.ttf);
}
@font-face {
font-family: "Nunito";
src: url(../fonts/Nunito/Nunito-VariableFont_wght.ttf);
}
@font-face {
font-family: "Inter";
src: url(../fonts/Inter/Inter-VariableFont_opsz\,wght.ttf);
}
:root {
/* --main-font-family: "Noto Sans", sans-serif; */
--main-font-family: "Segoe UI", sans-serif;
/* --main-font-family: "Ubuntu", sans-serif; */
/* --main-font-family: "Nunito", sans-serif; */
/* --main-font-family: "Inter", sans-serif; */
--main-font-size: normal;
--tree-font-family: var(--main-font-family);
--tree-font-size: normal;
--detail-font-family: var(--main-font-family);
--detail-font-size: normal;
--monospace-font-family: JetBrainsLight;
--monospace-font-size: normal;
--left-pane-item-selected-shadow-size: 2px;
--launcher-pane-size: 58px;
--launcher-pane-horizontal-size: 54px;
--launcher-pane-horizontal-icon-size: 20px;
--launcher-pane-button-margin: 6px;
--launcher-pane-button-gap: 3px;
--tree-actions-toolbar-horizontal-margin: 8px;
--tree-actions-toolbar-vertical-margin: 8px;
--tree-actions-toolbar-padding-size: 4px;
--tree-actions-toolbar-collapsed-width: 40px;
--tree-actions-toolbar-expand-button-size: 25px;
--tab-bar-height: 50px;
--tab-height: 36px;
--tab-first-item-horiz-offset: 1px;
--new-tab-button-size: 24px;
--center-pane-border-radius: 10px;
--menu-padding-size: 8px;
--menu-item-icon-vert-offset: 0;
--more-accented-background-color: var(--card-background-hover-color);
--timeline-left-gap: 20px;
--timeline-right-gap: 20px;
--timeline-item-top-padding: 4px;
--timeline-item-bottom-padding: 8px;
--timeline-bullet-size: 10px;
--timeline-bullet-vertical-pos: .75em;
--timeline-connector-size: 4px;
/* Theme capabilities */
--tab-note-icons: true;
}

View File

@ -109,6 +109,7 @@ body.layout-horizontal > .horizontal {
#launcher-pane.horizontal {
height: var(--launcher-pane-size) !important;
border-bottom: 1px solid var(--launcher-pane-horizontal-border-color);
align-items: center;
}
#launcher-pane .launcher-button,
@ -138,8 +139,10 @@ body.layout-horizontal > .horizontal {
}
#launcher-pane .launcher-button:hover,
#launcher-pane .launcher-button.right-dropdown-button.show {
background: var(--launcher-pane-button-hover-background);
#launcher-pane .launcher-button.right-dropdown-button.show,
#launcher-pane.horizontal .global-menu-button:hover,
#launcher-pane.horizontal .global-menu-button.show {
background: var(--launcher-pane-button-hover-background) !important;
color: var(--launcher-pane-button-hover-color);
box-shadow: var(--launcher-pane-button-hover-shadow);
transition: background-color 100ms ease-in,
@ -1075,6 +1078,97 @@ body .calendar-dropdown-widget .calendar-body a:hover {
padding-top: 12px;
}
/*
* Jump to note
*/
.jump-to-note-dialog .modal-dialog {
--modal-background-color: var(--menu-background-color);
--bs-modal-header-border-width: 0;
--bs-modal-footer-border-width: 0;
--bs-modal-footer-gap: 0;
backdrop-filter: var(--dropdown-backdrop-filter);
}
.jump-to-note-dialog .modal-content {
box-shadow: 0 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
border: 1px solid var(--dropdown-border-color);
padding: 32px;
border-radius: 8px;
}
.jump-to-note-dialog .modal-header {
padding: unset !important;
}
.jump-to-note-dialog .modal-body {
padding: 26px 0 !important;
}
/* Search box wrapper */
.jump-to-note-dialog .input-group {
margin-right: 16px;
background: var(--quick-search-background);
border: 2px solid transparent;
border-radius: 6px;
color: var(--quick-search-color);
}
.jump-to-note-dialog .input-group:hover {
background: var(--quick-search-hover-background);
}
/* Focused search box */
.jump-to-note-dialog .input-group:focus-within {
border-color: var(--quick-search-focus-border);
background: var(--quick-search-focus-background);
color: var(--quick-search-focus-color)
}
/* Search box input */
.jump-to-note-dialog .input-group input {
--bs-border-width: 0;
box-shadow: unset;
background: transparent;
color: currentColor;
}
/* Search box buttons */
.jump-to-note-dialog .input-group button {
--bs-border-width: 0;
--accented-background-color: transparent;
padding: 0 4px;
}
.jump-to-note-dialog .input-group button:last-child {
padding-right: .75em;
}
.jump-to-note-dialog .input-clearer-button {
background: transparent !important;
}
/* List body */
.jump-to-note-dialog .jump-to-note-results .aa-suggestions {
padding: 0;
}
/* List item */
.jump-to-note-dialog .aa-suggestions div {
border-radius: 6px;
padding: 6px 12px;
color: var(--menu-text-color);
cursor: default;
}
/* Selected list item */
.jump-to-note-dialog .aa-suggestions div.aa-cursor {
background: var(--hover-item-background-color);
color: var(--hover-item-text-color);
}
/*
* Recent changes list
*/

View File

@ -0,0 +1,7 @@
/* Import the light color scheme.
* This is the base color scheme, always active and overridden by the dark
* color scheme stylesheet when necessary. */
@import url(./theme-light.css);
/* Import the dark color scheme when the system preference is set to dark mode */
@import url(./theme-dark.css) (prefers-color-scheme: dark);

View File

@ -147,7 +147,7 @@
"numberedList": "<kbd>1.</kbd> oder <kbd>1)</kbd> gefolgt von Leerzeichen für nummerierte Liste",
"blockQuote": "Beginne eine Zeile mit <kbd>></kbd> gefolgt von einem Leerzeichen für Blockzitate",
"troubleshooting": "Fehlerbehebung",
"reloadFrontend": "Trillium-Frontend neuladen",
"reloadFrontend": "Trilium-Frontend neuladen",
"showDevTools": "Entwicklertools anzeigen",
"showSQLConsole": "SQL-Konsole anzeigen",
"other": "Andere",
@ -660,7 +660,7 @@
},
"code_buttons": {
"execute_button_title": "Skript ausführen",
"trilium_api_docs_button_title": "Öffne die Trillium-API-Dokumentation",
"trilium_api_docs_button_title": "Öffne die Trilium-API-Dokumentation",
"save_to_note_button_title": "In die Notiz speichern",
"opening_api_docs_message": "API-Dokumentation wird geöffnet...",
"sql_console_saved_message": "SQL-Konsolennotiz wurde in {{note_path}} gespeichert"

View File

@ -1,6 +1,7 @@
{
"about": {
"title": "About TriliumNext Notes",
"close": "Close",
"homepage": "Homepage:",
"app_version": "App version:",
"db_version": "DB version:",
@ -59,6 +60,7 @@
},
"clone_to": {
"clone_notes_to": "Clone notes to...",
"close": "Close",
"help_on_links": "Help on links",
"notes_to_clone": "Notes to clone",
"target_parent_note": "Target parent note",
@ -71,6 +73,7 @@
},
"confirm": {
"confirmation": "Confirmation",
"close": "Close",
"cancel": "Cancel",
"ok": "OK",
"are_you_sure_remove_note": "Are you sure you want to remove the note \"{{title}}\" from relation map? ",
@ -79,6 +82,7 @@
},
"delete_notes": {
"delete_notes_preview": "Delete notes preview",
"close": "Close",
"delete_all_clones_description": "Delete also all clones (can be undone in recent changes)",
"erase_notes_description": "Normal (soft) deletion only marks the notes as deleted and they can be undeleted (in recent changes dialog) within a period of time. Checking this option will erase the notes immediately and it won't be possible to undelete the notes.",
"erase_notes_warning": "Erase notes permanently (can't be undone), including all clones. This will force application reload.",
@ -189,6 +193,7 @@
},
"include_note": {
"dialog_title": "Include note",
"close": "Close",
"label_note": "Note",
"placeholder_search": "search for note by its name",
"box_size_prompt": "Box size of the included note:",
@ -204,16 +209,19 @@
},
"jump_to_note": {
"search_placeholder": "search for note by its name",
"close": "Close",
"search_button": "Search in full text <kbd>Ctrl+Enter</kbd>"
},
"markdown_import": {
"dialog_title": "Markdown import",
"close": "Close",
"modal_body_text": "Because of browser sandbox it's not possible to directly read clipboard from JavaScript. Please paste the Markdown to import to textarea below and click on Import button",
"import_button": "Import Ctrl+Enter",
"import_success": "Markdown content has been imported into the document."
},
"move_to": {
"dialog_title": "Move notes to ...",
"close": "Close",
"notes_to_move": "Notes to move",
"target_parent_note": "Target parent note",
"search_placeholder": "search for note by its name",
@ -223,16 +231,19 @@
},
"note_type_chooser": {
"modal_title": "Choose note type",
"close": "Close",
"modal_body": "Choose note type / template of the new note:",
"templates": "Templates:"
},
"password_not_set": {
"title": "Password is not set",
"close": "Close",
"body1": "Protected notes are encrypted using a user password, but password has not been set yet.",
"body2": "To be able to protect notes, click <a class=\"open-password-options-button\" href=\"javascript:\">here</a> to open the Options dialog and set your password."
},
"prompt": {
"title": "Prompt",
"close": "Close",
"ok": "OK <kbd>enter</kbd>",
"defaultTitle": "Prompt"
},
@ -246,6 +257,7 @@
"recent_changes": {
"title": "Recent changes",
"erase_notes_button": "Erase deleted notes now",
"close": "Close",
"deleted_notes_message": "Deleted notes have been erased.",
"no_changes_message": "No changes yet...",
"undelete_link": "undelete",
@ -256,6 +268,7 @@
"delete_all_revisions": "Delete all revisions of this note",
"delete_all_button": "Delete all revisions",
"help_title": "Help on Note Revisions",
"close": "Close",
"revision_last_edited": "This revision was last edited on {{date}}",
"confirm_delete_all": "Do you want to delete all revisions of this note? This action will erase the revision title and content, but still preserve the revision metadata.",
"no_revisions": "No revisions for this note yet...",
@ -277,6 +290,7 @@
},
"sort_child_notes": {
"sort_children_by": "Sort children by...",
"close": "Close",
"sorting_criteria": "Sorting criteria",
"title": "title",
"date_created": "date created",
@ -294,6 +308,7 @@
},
"upload_attachments": {
"upload_attachments_to_note": "Upload attachments to note",
"close": "Close",
"choose_files": "Choose files",
"files_will_be_uploaded": "Files will be uploaded as attachments into",
"options": "Options",
@ -1072,9 +1087,12 @@
"title": "Application Theme",
"theme_label": "Theme",
"override_theme_fonts_label": "Override theme fonts",
"auto_theme": "Auto",
"light_theme": "Light",
"dark_theme": "Dark",
"triliumnext": "TriliumNext (beta)",
"triliumnext": "TriliumNext Beta (Follow system color scheme)",
"triliumnext-light": "TriliumNext Beta (Light)",
"triliumnext-dark": "TriliumNext Beta (Dark)",
"layout": "Layout",
"layout-vertical-title": "Vertical",
"layout-horizontal-title": "Horizontal",

View File

@ -153,7 +153,7 @@
"numberedList": "<kbd>1.</kbd> o <kbd>1)</kbd> seguido de espacio para la lista numerada",
"blockQuote": "comience una línea con <kbd>></kbd> seguido de espacio para el bloque de cita",
"troubleshooting": "Solución de problemas",
"reloadFrontend": "recargar la interfaz de Trillium",
"reloadFrontend": "recargar la interfaz de Trilium",
"showDevTools": "mostrar herramientas de desarrollador",
"showSQLConsole": "mostrar consola SQL",
"other": "Otro",

View File

@ -1195,8 +1195,12 @@
"title": "Pragul de mod de citire automat"
},
"theme": {
"auto_theme": "Temă auto (se adaptează la schema de culori a sistemului)",
"dark_theme": "Temă întunecată",
"light_theme": "Temă luminoasă",
"triliumnext": "TriliumNext Beta (se adaptează la schema de culori a sistemului)",
"triliumnext-light": "TriliumNext Beta (luminoasă)",
"triliumnext-dark": "TriliumNext Beta (întunecată)",
"override_theme_fonts_label": "Suprascrie fonturile temei",
"theme_label": "Temă",
"title": "Tema aplicației",
@ -1204,8 +1208,7 @@
"layout-horizontal-description": "bara de lansare se află sub bara de taburi, bara de taburi este pe toată lungimea.",
"layout-horizontal-title": "Orizontal",
"layout-vertical-title": "Vertical",
"layout-vertical-description": "bara de lansare se află pe stânga (implicit)",
"triliumnext": "TriliumNext (experimentală)"
"layout-vertical-description": "bara de lansare se află pe stânga (implicit)"
},
"toast": {
"critical-error": {

View File

@ -4,8 +4,6 @@ import { fileURLToPath } from "url";
import express from "express";
import env from "../services/env.js";
import serveStatic from "serve-static";
import webpack from "webpack";
import webpackMiddleware from "webpack-dev-middleware";
const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOptions<express.Response<any, Record<string, any>>>) => {
if (!env.isDev()) {
@ -17,9 +15,12 @@ const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOp
return express.static(root, options);
};
function register(app: express.Application) {
async function register(app: express.Application) {
const srcRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
if (env.isDev()) {
const webpack = (await import("webpack")).default;
const webpackMiddleware = (await import("webpack-dev-middleware")).default;
const frontendCompiler = webpack({
mode: "development",
entry: {

View File

@ -61,13 +61,19 @@ function index(req: Request, res: Response) {
}
function getThemeCssUrl(theme: string, themeNote: BNote | null) {
if (theme === 'light') {
if (theme === 'auto') {
return `${assetPath}/stylesheets/theme.css`;
} else if (theme === 'light') {
// light theme is always loaded as baseline
return false;
} else if (theme === 'dark') {
return `${assetPath}/stylesheets/theme-dark.css`;
} else if (theme === "next") {
return `${assetPath}/stylesheets/theme-next.css`;
} else if (theme === "next-light") {
return `${assetPath}/stylesheets/theme-next-light.css`;
} else if (theme === "next-dark") {
return `${assetPath}/stylesheets/theme-next-dark.css`;
} else if (!process.env.TRILIUM_SAFE_MODE && themeNote) {
return `api/notes/download/${themeNote.noteId}`;
} else {

View File

@ -5,15 +5,57 @@ import turndownPluginGfm from "joplin-turndown-plugin-gfm";
let instance: TurndownService | null = null;
const fencedCodeBlockFilter: TurndownService.Rule = {
filter: function (node, options) {
return (
options.codeBlockStyle === 'fenced' &&
node.nodeName === 'PRE' &&
node.firstChild !== null &&
node.firstChild.nodeName === 'CODE'
)
},
replacement: function (content, node, options) {
if (!node.firstChild || !("getAttribute" in node.firstChild) || typeof node.firstChild.getAttribute !== "function") {
return content;
}
const className = node.firstChild.getAttribute('class') || ''
const language = rewriteLanguageTag((className.match(/language-(\S+)/) || [null, ''])[1]);
return (
'\n\n' + options.fence + language + '\n' +
node.firstChild.textContent +
'\n' + options.fence + '\n\n'
)
}
};
function toMarkdown(content: string) {
if (instance === null) {
instance = new TurndownService({ codeBlockStyle: 'fenced' });
// Filter is heavily based on: https://github.com/mixmark-io/turndown/issues/274#issuecomment-458730974
instance.addRule('fencedCodeBlock', fencedCodeBlockFilter);
instance.use(turndownPluginGfm.gfm);
}
return instance.turndown(content);
}
function rewriteLanguageTag(source: string) {
if (!source) {
return source;
}
if (source === "text-x-trilium-auto") {
return "";
}
return source
.split("-")
.at(-1);
}
export default {
toMarkdown
};

View File

@ -12,6 +12,7 @@ import striptags from "striptags";
import utils from "../../utils.js";
import sql from "../../sql.js";
const ALLOWED_OPERATORS = ['=', '!=', '*=*', '*=', '=*', '%='];
const cachedRegexes: Record<string, RegExp> = {};
@ -133,6 +134,74 @@ class NoteContentFulltextExp extends Expression {
content = content.replace(/&nbsp;/g, ' ');
}
else if (type === 'mindMap' && mime === 'application/json') {
let mindMapcontent = JSON.parse (content);
// Define interfaces for the JSON structure
interface MindmapNode {
id: string;
topic: string;
children: MindmapNode[]; // Recursive structure
direction?: number;
expanded?: boolean;
}
interface MindmapData {
nodedata: MindmapNode;
arrows: any[]; // If you know the structure, replace `any` with the correct type
summaries: any[];
direction: number;
theme: {
name: string;
type: string;
palette: string[];
cssvar: Record<string, string>; // Object with string keys and string values
};
}
// Recursive function to collect all topics
function collectTopics(node: MindmapNode): string[] {
// Collect the current node's topic
let topics = [node.topic];
// If the node has children, collect topics recursively
if (node.children && node.children.length > 0) {
for (const child of node.children) {
topics = topics.concat(collectTopics(child));
}
}
return topics;
}
// Start extracting from the root node
const topicsArray = collectTopics(mindMapcontent.nodedata);
// Combine topics into a single string
const topicsString = topicsArray.join(", ");
content = utils.normalize(topicsString.toString());
}
else if (type === 'canvas' && mime === 'application/json') {
interface Element {
type: string;
text?: string; // Optional since not all objects have a `text` property
id: string;
[key: string]: any; // Other properties that may exist
}
let canvasContent = JSON.parse (content);
const elements: Element [] = canvasContent.elements;
const texts = elements
.filter((element: Element) => element.type === 'text' && element.text) // Filter for 'text' type elements with a 'text' property
.map((element: Element) => element.text!); // Use `!` to assert `text` is defined after filtering
content =utils.normalize(texts.toString())
}
return content.trim();
}

View File

@ -160,7 +160,7 @@ const STRING_MIME_TYPES = [
"image/svg+xml"
];
function isStringNote(type: string | null, mime: string) {
function isStringNote(type: string | undefined, mime: string) {
// render and book are string note in the sense that they are expected to contain empty string
return (type && ["text", "code", "relationMap", "search", "render", "book", "mermaid", "canvas"].includes(type))
|| mime.startsWith('text/')

View File

@ -62,7 +62,7 @@ class SAttachment extends AbstractShacaEntity {
/** @returns true if the attachment has string content (not binary) */
hasStringContent() {
return utils.isStringNote(null, this.mime);
return utils.isStringNote(undefined, this.mime);
}
getPojo() {

View File

@ -94,7 +94,7 @@
},
"login": {
"title": "Iniciar sesión",
"heading": "Iniciar sesión en Trillium",
"heading": "Iniciar sesión en Trilium",
"incorrect-password": "La contraseña es incorrecta. Por favor inténtalo de nuevo.",
"password": "Contraseña",
"remember-me": "Recordarme",
@ -109,7 +109,7 @@
},
"javascript-required": "Trilium requiere que JavaScript esté habilitado.",
"setup": {
"heading": "Configuración de TrilliumNext Notes",
"heading": "Configuración de TriliumNext Notes",
"new-document": "Soy un usuario nuevo y quiero crear un nuevo documento de Trilium para mis notas",
"sync-from-desktop": "Ya tengo una instancia de escritorio y quiero configurar la sincronización con ella",
"sync-from-server": "Ya tengo una instancia de servidor y quiero configurar la sincronización con ella",