mirror of
https://github.com/zadam/trilium.git
synced 2025-11-15 09:45:52 +01:00
Merge remote-tracking branch 'origin/main' into react/collections
This commit is contained in:
@@ -9,6 +9,11 @@
|
||||
"email": "contact@eliandoran.me",
|
||||
"url": "https://github.com/TriliumNext/Notes"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build",
|
||||
"test": "vitest",
|
||||
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
|
||||
},
|
||||
"dependencies": {
|
||||
"@eslint/js": "9.34.0",
|
||||
"@excalidraw/excalidraw": "0.18.0",
|
||||
@@ -30,7 +35,7 @@
|
||||
"autocomplete.js": "0.38.1",
|
||||
"bootstrap": "5.3.8",
|
||||
"boxicons": "2.1.4",
|
||||
"dayjs": "1.11.14",
|
||||
"dayjs": "1.11.18",
|
||||
"dayjs-plugin-utc": "0.1.2",
|
||||
"debounce": "2.2.0",
|
||||
"draggabilly": "3.0.0",
|
||||
@@ -52,7 +57,7 @@
|
||||
"normalize.css": "8.0.1",
|
||||
"panzoom": "9.4.3",
|
||||
"preact": "10.27.1",
|
||||
"react-i18next": "15.7.2",
|
||||
"react-i18next": "15.7.3",
|
||||
"split.js": "1.6.5",
|
||||
"svg-pan-zoom": "3.6.2",
|
||||
"tabulator-tables": "6.3.1",
|
||||
@@ -71,18 +76,5 @@
|
||||
"happy-dom": "18.0.1",
|
||||
"script-loader": "0.7.2",
|
||||
"vite-plugin-static-copy": "3.1.2"
|
||||
},
|
||||
"nx": {
|
||||
"name": "client",
|
||||
"targets": {
|
||||
"serve": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
},
|
||||
"circular-deps": {
|
||||
"command": "pnpx dpdm -T {projectRoot}/src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { t } from "./services/i18n.js";
|
||||
import options from "./services/options.js";
|
||||
import type ElectronRemote from "@electron/remote";
|
||||
import type Electron from "electron";
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import "boxicons/css/boxicons.min.css";
|
||||
import "autocomplete.js/index_jquery.js";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
|
||||
// @ts-ignore - module = undefined
|
||||
// Required for correct loading of scripts in Electron
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import appContext from "./components/app_context.js";
|
||||
import noteAutocompleteService from "./services/note_autocomplete.js";
|
||||
import glob from "./services/glob.js";
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import "boxicons/css/boxicons.min.css";
|
||||
import "autocomplete.js/index_jquery.js";
|
||||
|
||||
|
||||
@@ -48,6 +48,6 @@ function getUrl(docNameValue: string, language: string) {
|
||||
// Cannot have spaces in the URL due to how JQuery.load works.
|
||||
docNameValue = docNameValue.replaceAll(" ", "%20");
|
||||
|
||||
const basePath = window.glob.isDev ? new URL(window.glob.assetPath).pathname : window.glob.assetPath;
|
||||
const basePath = window.glob.isDev ? window.glob.assetPath + "/.." : window.glob.assetPath;
|
||||
return `${basePath}/doc_notes/${language}/${docNameValue}.html`;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
import "./stylesheets/auth.css";
|
||||
|
||||
// @TriliumNextTODO: is this even needed anymore?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import "jquery";
|
||||
import utils from "./services/utils.js";
|
||||
import ko from "knockout";
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "bootstrap/dist/css/bootstrap.min.css";
|
||||
|
||||
// TriliumNextTODO: properly make use of below types
|
||||
// type SetupModelSetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import "normalize.css";
|
||||
import "boxicons/css/boxicons.min.css";
|
||||
import "@triliumnext/ckeditor5/content.css";
|
||||
import "@triliumnext/ckeditor5/src/theme/ck-content.css";
|
||||
import "@triliumnext/share-theme/styles/index.css";
|
||||
import "@triliumnext/share-theme/scripts/index.js";
|
||||
|
||||
|
||||
2
apps/client/src/stylesheets/bootstrap.scss
vendored
2
apps/client/src/stylesheets/bootstrap.scss
vendored
@@ -1,2 +0,0 @@
|
||||
/* Import all of Bootstrap's CSS */
|
||||
@use "bootstrap/scss/bootstrap";
|
||||
@@ -1134,6 +1134,7 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
||||
|
||||
.toast-body {
|
||||
white-space: preserve-breaks;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ck-mentions .ck-button {
|
||||
@@ -1463,7 +1464,7 @@ body:not(.mobile) #launcher-pane.horizontal .dropdown-submenu > .dropdown-menu {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
color: var(--launcher-pane-text-color);
|
||||
background-color: var(--launcher-pane-background-color);
|
||||
background: transparent;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -2366,3 +2367,12 @@ footer.webview-footer button {
|
||||
content: "\ec24";
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* CK Edito */
|
||||
|
||||
/* Insert text snippet: limit the width of the listed items to avoid overly long names */
|
||||
:root body.desktop div.ck-template-form li.ck-list__item .ck-template-form__text-part > span {
|
||||
max-width: 25vw;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
--main-text-color: #ccc;
|
||||
--main-border-color: #454545;
|
||||
--subtle-border-color: #313131;
|
||||
--dropdown-border-color: #292929;
|
||||
--dropdown-border-color: #404040;
|
||||
--dropdown-shadow-opacity: 0.6;
|
||||
--dropdown-item-icon-destructive-color: #de6e5b;
|
||||
--disabled-tooltip-icon-color: #7fd2ef;
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
--quick-search-focus-border: #00000029;
|
||||
--quick-search-focus-background: #ffffff80;
|
||||
--quick-search-focus-color: #000;
|
||||
--quick-search-result-content-background: #00000017;
|
||||
--quick-search-result-content-background: #0000000f;
|
||||
--quick-search-result-highlight-color: #c65050;
|
||||
|
||||
--left-pane-collapsed-border-color: #0000000d;
|
||||
|
||||
@@ -329,6 +329,8 @@ body.mobile .dropdown-menu .dropdown-item.submenu-open .dropdown-toggle::after {
|
||||
|
||||
#toast-container .toast .toast-body {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
button.btn.btn-primary,
|
||||
button.btn.btn-secondary,
|
||||
button.btn.btn-sm:not(.select-button),
|
||||
button.btn.btn-success {
|
||||
button.btn.btn-success,
|
||||
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -21,7 +22,8 @@ button.btn.btn-success {
|
||||
button.btn.btn-primary:hover,
|
||||
button.btn.btn-secondary:hover,
|
||||
button.btn.btn-sm:not(.select-button):hover,
|
||||
button.btn.btn-success:hover {
|
||||
button.btn.btn-success:hover,
|
||||
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):hover {
|
||||
background: var(--cmd-button-hover-background-color);
|
||||
color: var(--cmd-button-hover-text-color);
|
||||
}
|
||||
@@ -29,7 +31,8 @@ button.btn.btn-success:hover {
|
||||
button.btn.btn-primary:active,
|
||||
button.btn.btn-secondary:active,
|
||||
button.btn.btn-sm:not(.select-button):active,
|
||||
button.btn.btn-success:active {
|
||||
button.btn.btn-success:active,
|
||||
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):active {
|
||||
opacity: 0.85;
|
||||
box-shadow: unset;
|
||||
background: var(--cmd-button-background-color) !important;
|
||||
@@ -40,14 +43,16 @@ button.btn.btn-success:active {
|
||||
button.btn.btn-primary:disabled,
|
||||
button.btn.btn-secondary:disabled,
|
||||
button.btn.btn-sm:not(.select-button):disabled,
|
||||
button.btn.btn-success:disabled {
|
||||
button.btn.btn-success:disabled,
|
||||
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text.ck-disabled {
|
||||
opacity: var(--cmd-button-disabled-opacity);
|
||||
}
|
||||
|
||||
button.btn.btn-primary:focus-visible,
|
||||
button.btn.btn-secondary:focus-visible,
|
||||
button.btn.btn-sm:not(.select-button):focus-visible,
|
||||
button.btn.btn-success:focus-visible {
|
||||
button.btn.btn-success:focus-visible,
|
||||
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel, .ck-button-replaceall, .ck-button-replace).ck-button_with-text:not(.ck-disabled):focus-visible {
|
||||
outline: 2px solid var(--input-focus-outline-color);
|
||||
}
|
||||
|
||||
@@ -149,8 +154,11 @@ input[type="password"],
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
:root input.ck.ck-input-text,
|
||||
:root input.ck.ck-input-number,
|
||||
textarea.form-control,
|
||||
textarea,
|
||||
:root textarea.ck.ck-textarea,
|
||||
.tn-input-field {
|
||||
outline: 3px solid transparent;
|
||||
outline-offset: 6px;
|
||||
@@ -167,8 +175,11 @@ input[type="password"]:hover,
|
||||
input[type="date"]:hover,
|
||||
input[type="time"]:hover,
|
||||
input[type="datetime-local"]:hover,
|
||||
:root input.ck.ck-input-text:not([readonly="true"]):hover,
|
||||
:root input.ck.ck-input-number:not([readonly="true"]):hover,
|
||||
textarea.form-control:hover,
|
||||
textarea:hover,
|
||||
:root textarea.ck.ck-textarea:hover,
|
||||
.tn-input-field:hover {
|
||||
background: var(--input-hover-background);
|
||||
color: var(--input-hover-color);
|
||||
@@ -181,8 +192,11 @@ input[type="password"]:focus,
|
||||
input[type="date"]:focus,
|
||||
input[type="time"]:focus,
|
||||
input[type="datetime-local"]:focus,
|
||||
:root input.ck.ck-input-text:focus,
|
||||
:root input.ck.ck-input-number:focus,
|
||||
textarea.form-control:focus,
|
||||
textarea:focus,
|
||||
:root textarea.ck.ck-textarea:focus,
|
||||
.tn-input-field:focus,
|
||||
.tn-input-field:focus-within {
|
||||
box-shadow: unset;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
:root {
|
||||
--ck-font-face: var(--main-font-family);
|
||||
--ck-input-label-height: 1.5em;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -307,6 +308,11 @@
|
||||
fill: black !important;
|
||||
}
|
||||
|
||||
/* Hex color input box prefix */
|
||||
:root .ck.ck-color-selector .ck-color-picker__hash-view {
|
||||
margin-top: var(--ck-input-label-height);
|
||||
}
|
||||
|
||||
/* Numbered list */
|
||||
|
||||
:root .ck.ck-list-properties_with-numbered-properties .ck.ck-list-styles-list {
|
||||
@@ -363,19 +369,86 @@
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
/* Action buttons */
|
||||
/* Text snippet dropdown */
|
||||
|
||||
:root .ck-link-actions button.ck-button,
|
||||
:root .ck-link-form button.ck-button {
|
||||
--ck-border-radius: 6px;
|
||||
|
||||
background: transparent;
|
||||
box-shadow: unset;
|
||||
div.ck-template-form {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
:root .ck-link-actions button.ck-button:hover,
|
||||
:root .ck-link-form button.ck-button:hover {
|
||||
background: var(--hover-item-background-color);
|
||||
div.ck-template-form .ck-labeled-field-view {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Template item */
|
||||
|
||||
:root div.ck-template-form li.ck-list__item button.ck-template-button {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
/* Template icon */
|
||||
:root .ck-template-form .ck-button__icon {
|
||||
--ck-spacing-medium: 2px;
|
||||
}
|
||||
|
||||
:root div.ck-template-form .note-icon {
|
||||
color: var(--menu-item-icon-color);
|
||||
}
|
||||
|
||||
/* Template name */
|
||||
div.ck-template-form .ck-template-form__text-part {
|
||||
color: var(--hover-item-text-color);
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
div.ck-template-form .ck-template-form__text-part mark {
|
||||
background: unset;
|
||||
color: var(--quick-search-result-highlight-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Template description */
|
||||
:root div.ck-template-form .ck-template-form__description {
|
||||
opacity: .5;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
/* Messages */
|
||||
div.ck-template-form .ck-search__info > span {
|
||||
line-height: initial;
|
||||
color: var(--muted-text-color);
|
||||
}
|
||||
|
||||
div.ck-template-form .ck-search__info span:nth-child(2) {
|
||||
display: block;
|
||||
opacity: .5;
|
||||
margin-top: 8px;
|
||||
font-size: .9em;
|
||||
}
|
||||
|
||||
/* Link dropdown */
|
||||
|
||||
:root .ck.ck-form.ck-link-form ul.ck-link-form__providers-list {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
/* Math popup */
|
||||
|
||||
.ck-math-form .ck-labeled-field-view {
|
||||
--ck-input-label-height: 0;
|
||||
|
||||
margin-inline-end: 8px;
|
||||
}
|
||||
|
||||
/* Emoji dropdown */
|
||||
|
||||
.ck-emoji-picker-form .ck-emoji__search .ck-button_with-text:not(.ck-list-item-button) {
|
||||
margin-top: var(--ck-input-label-height);
|
||||
}
|
||||
|
||||
/* Find and replace dialog */
|
||||
|
||||
.ck-find-and-replace-form .ck-find-and-replace-form__inputs button {
|
||||
margin-top: var(--ck-input-label-height);
|
||||
}
|
||||
|
||||
/* Mention list (the autocompletion list for emojis, labels and relations) */
|
||||
@@ -392,6 +465,58 @@
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/*
|
||||
* FORMS
|
||||
*/
|
||||
|
||||
/*
|
||||
* Buttons
|
||||
*/
|
||||
|
||||
button.ck.ck-button:is(.ck-button-action, .ck-button-save, .ck-button-cancel).ck-button_with-text {
|
||||
--ck-color-text: var(--cmd-button-text-color);
|
||||
|
||||
min-width: 60px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/*
|
||||
* Text boxes
|
||||
*/
|
||||
|
||||
.ck.ck-labeled-field-view {
|
||||
padding-top: var(--ck-input-label-height) !important; /* Create space for the label */
|
||||
}
|
||||
|
||||
.ck.ck-labeled-field-view > .ck.ck-labeled-field-view__input-wrapper > label.ck.ck-label {
|
||||
/* Move the label above the text box regardless of the text box state */
|
||||
transform: translate(0, calc(-.2em - var(--ck-input-label-height))) !important;
|
||||
|
||||
padding-left: 0 !important;
|
||||
background: transparent;
|
||||
font-size: .85em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
:root input.ck.ck-input-text[readonly="true"] {
|
||||
cursor: not-allowed;
|
||||
background: var(--input-background-color);
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
|
||||
:root .ck.ck-form__row.ck-form__row_with-submit > :not(:first-child) {
|
||||
margin-inline-start: 16px;
|
||||
}
|
||||
|
||||
.ck.ck-form__row_with-submit button {
|
||||
margin-top: var(--ck-input-label-height);
|
||||
}
|
||||
|
||||
.ck.ck-form__header {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* EDITOR'S CONTENT
|
||||
*/
|
||||
|
||||
@@ -59,8 +59,7 @@ body.background-effects.platform-win32.layout-vertical {
|
||||
}
|
||||
|
||||
body.background-effects.platform-win32,
|
||||
body.background-effects.platform-win32 #root-widget,
|
||||
body.background-effects.platform-win32 #launcher-pane .launcher-button {
|
||||
body.background-effects.platform-win32 #root-widget {
|
||||
background: transparent !important;
|
||||
}
|
||||
|
||||
@@ -575,31 +574,20 @@ div.quick-search .search-button.show {
|
||||
* Quick search results
|
||||
*/
|
||||
|
||||
div.quick-search .dropdown-menu {
|
||||
--quick-search-item-delimiter-color: transparent;
|
||||
--menu-item-icon-vert-offset: -.065em;
|
||||
}
|
||||
|
||||
/* Item */
|
||||
.quick-search .dropdown-menu *.dropdown-item {
|
||||
padding: 8px 12px !important;
|
||||
}
|
||||
|
||||
/* Note icon */
|
||||
.quick-search .dropdown-menu .dropdown-item > .bx {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
.quick-search .quick-search-item-icon {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
/* Note title */
|
||||
.quick-search .dropdown-menu .dropdown-item > a {
|
||||
color: var(--menu-text-color);
|
||||
}
|
||||
|
||||
.quick-search .dropdown-menu .dropdown-item > a:hover {
|
||||
--hover-item-background-color: transparent;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Note path */
|
||||
.quick-search .dropdown-menu small {
|
||||
display: block;
|
||||
@@ -622,9 +610,8 @@ div.quick-search .search-button.show {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Divider line */
|
||||
.quick-search .dropdown-item::after {
|
||||
display: none;
|
||||
.quick-search div.dropdown-divider {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -899,6 +886,80 @@ body.layout-horizontal .tab-row-container {
|
||||
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container {
|
||||
border-bottom: unset !important;
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .note-tab-wrapper {
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .toggle-button {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .toggle-button:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: -10px;
|
||||
right: -10px;
|
||||
top: 29px;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left,
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-left:after,
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .tab-scroll-button-right:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[active]:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: -32768px;
|
||||
top: var(--tab-height);
|
||||
right: calc(100% - 1px);
|
||||
height: 1px;
|
||||
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .note-tab[active]:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 100%;
|
||||
top: var(--tab-height);
|
||||
right: 0;
|
||||
width: 100vw;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
|
||||
}
|
||||
|
||||
body.electron.background-effects.layout-horizontal .tab-row-container .note-new-tab:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: -4px;
|
||||
top: calc(var(--tab-height), -1);
|
||||
right: 0;
|
||||
width: 100vw;
|
||||
height: 1px;
|
||||
border-bottom: 1px solid var(--launcher-pane-horiz-border-color);
|
||||
}
|
||||
|
||||
body.layout-vertical.electron.platform-darwin .tab-row-container {
|
||||
border-bottom: 1px solid var(--subtle-border-color);
|
||||
}
|
||||
|
||||
@@ -1440,7 +1440,9 @@
|
||||
"open-in-popup": "快速编辑"
|
||||
},
|
||||
"shared_info": {
|
||||
"help_link": "访问 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a> 获取帮助。"
|
||||
"help_link": "访问 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a> 获取帮助。",
|
||||
"shared_publicly": "该笔记已在 {{- link}} 上公开分享。",
|
||||
"shared_locally": "此笔记在本地通过 {{- link}} 进行共享。"
|
||||
},
|
||||
"note_types": {
|
||||
"text": "文本",
|
||||
@@ -1518,7 +1520,8 @@
|
||||
"hoist-this-note-workspace": "聚焦此笔记(工作区)",
|
||||
"refresh-saved-search-results": "刷新保存的搜索结果",
|
||||
"create-child-note": "创建子笔记",
|
||||
"unhoist": "取消聚焦"
|
||||
"unhoist": "取消聚焦",
|
||||
"toggle-sidebar": "切换侧边栏"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "保持此窗口置顶"
|
||||
|
||||
@@ -1404,8 +1404,8 @@
|
||||
"open-in-popup": "Schnellbearbeitung"
|
||||
},
|
||||
"shared_info": {
|
||||
"shared_publicly": "Diese Notiz ist öffentlich geteilt auf {{- link}}",
|
||||
"shared_locally": "Diese Notiz ist lokal geteilt auf {{- link}}",
|
||||
"shared_publicly": "Diese Notiz ist öffentlich geteilt auf {{- link}}.",
|
||||
"shared_locally": "Diese Notiz ist lokal geteilt auf {{- link}}.",
|
||||
"help_link": "Für Hilfe besuche <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
|
||||
},
|
||||
"note_types": {
|
||||
@@ -1484,7 +1484,8 @@
|
||||
"hoist-this-note-workspace": "Diese Notiz fokussieren (Arbeitsbereich)",
|
||||
"refresh-saved-search-results": "Gespeicherte Suchergebnisse aktualisieren",
|
||||
"create-child-note": "Unternotiz anlegen",
|
||||
"unhoist": "Fokus verlassen"
|
||||
"unhoist": "Fokus verlassen",
|
||||
"toggle-sidebar": "Seitenleiste ein-/ausblenden"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Dieses Fenster immer oben halten"
|
||||
|
||||
@@ -13,29 +13,127 @@
|
||||
"critical-error": {
|
||||
"title": "Błąd krytyczny",
|
||||
"message": "Wystąpił krytyczny błąd uniemożliwiający uruchomienie aplikacji:\n\n{{message}}\n\nJest to spowodowane najprawdopodobniej niespodziewanym błędem skryptu. Spróbuj uruchomić aplikację ponownie w trybie bezpiecznym i zaadresuj problem."
|
||||
},
|
||||
"widget-error": {
|
||||
"title": "Nie udało się zainicjować widżetu",
|
||||
"message-custom": "Niestandardowy widżet z notatki o identyfikatorze \"{{id}}\", i tytule \"{{title}}\" nie mógł zostać zainicjowany z powodu:\n\n{{message}}",
|
||||
"message-unknown": "Nieznany widżet nie mógł być zainicjowany z powodu:\n\n{{message}}"
|
||||
},
|
||||
"bundle-error": {
|
||||
"title": "Nie udało się załadować niestandardowego skryptu",
|
||||
"message": "Skrypt z notatki o identyfikatorze \"{{id}}\", tytule \"{{title}}: nie został uruchomiony z powodu:\n\n{{message}}"
|
||||
}
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Dodaj link"
|
||||
"add_link": "Dodaj link",
|
||||
"note": "Notatka",
|
||||
"search_note": "Wyszukaj notatkę po nazwie",
|
||||
"link_title_arbitrary": "Tytuł linku można dowolnie zmieniać",
|
||||
"link_title": "Tytuł linku",
|
||||
"button_add_link": "Dodaj link"
|
||||
},
|
||||
"branch_prefix": {
|
||||
"save": "Zapisz"
|
||||
"save": "Zapisz",
|
||||
"edit_branch_prefix": "Edytuj prefiks gałęzi",
|
||||
"prefix": "Prefiks: ",
|
||||
"branch_prefix_saved": "Zapisano prefiks gałęzi."
|
||||
},
|
||||
"bulk_actions": {
|
||||
"labels": "Etykiety",
|
||||
"notes": "Notatki",
|
||||
"other": "Inne",
|
||||
"relations": "Powiązania"
|
||||
"relations": "Powiązania",
|
||||
"bulk_actions": "Działania zbiorcze",
|
||||
"include_descendants": "Uwzględnia rozwinięcia wybranych notatek",
|
||||
"available_actions": "Dostępne działania",
|
||||
"chosen_actions": "Wybrane działania",
|
||||
"execute_bulk_actions": "Wykonaj zbiór działań",
|
||||
"bulk_actions_executed": "Zbiór działań został wykonany prawidłowo.",
|
||||
"none_yet": "Brak zaznaczonych działań... dodaj działanie poprzez kliknięcie jednej z dostępnych opcji powyżej."
|
||||
},
|
||||
"confirm": {
|
||||
"ok": "OK",
|
||||
"cancel": "Anuluj"
|
||||
"cancel": "Anuluj",
|
||||
"confirmation": "Potwierdzenie",
|
||||
"are_you_sure_remove_note": "Czy napewno chcesz usunąć notatkę \"{{title}}\" z mapy powiązań? ",
|
||||
"if_you_dont_check": "Jeśli nie zaznaczysz tej opcji, notatka zostanie usunięta jedynie z mapy powiązań.",
|
||||
"also_delete_note": "Usuń dodatkowo notatkę"
|
||||
},
|
||||
"delete_notes": {
|
||||
"cancel": "Anuluj",
|
||||
"close": "Zamknij"
|
||||
"close": "Zamknij",
|
||||
"delete_notes_preview": "Usuń podgląd notatek",
|
||||
"delete_all_clones_description": "Usuń również wszystkie sklonowania (działanie może zostać cofnięte w ostatnich zmianach)",
|
||||
"erase_notes_description": "Normalne (miękkie) usuwanie zaznacza jedynie notatki jako usunięte i można je przywrócić (w oknie dialogowym ostatnich zmian) przez wyznaczony okres czasu. Zaznaczenie tej opcji spowoduje natychmiastowe usunięcie notatek, bez możliwości ich przywrócenia.",
|
||||
"erase_notes_warning": "Usuń notatki permanentnie (bez opcji ich przywrócenia), włączając wszystkie kopie. Działanie to wymaga ponownego uruchomienia aplikacji.",
|
||||
"notes_to_be_deleted": "Następujące notatki zostaną usunięte ({{notesCount}})",
|
||||
"no_note_to_delete": "Żadne notatki nie zostaną usunięte (jedynie kopie).",
|
||||
"broken_relations_to_be_deleted": "Następujące powiązania zostaną uszkodzone i usunięte ({{ relationCount}})",
|
||||
"ok": "OK",
|
||||
"deleted_relation_text": "Notatka {{- note}} (do usunięcia) jest powiązana przez relację {{- relation}} pochodzącą z {{- source}}."
|
||||
},
|
||||
"export": {
|
||||
"close": "Zamknij"
|
||||
"close": "Zamknij",
|
||||
"export_note_title": "Eksportuj notatkę",
|
||||
"export_type_subtree": "Ta notatka oraz wszystkie podrzędne",
|
||||
"format_html": "HTML - rekomendowany jako zachowujący całość formatowania",
|
||||
"format_html_zip": "HTML w archiwum ZIP - rekomendowany jako zachowujący całość formatowania.",
|
||||
"format_markdown": "Markdown - zachowuje większość formatowania.",
|
||||
"format_opml": "OPML - format wymiany danych dla outlinerów zawierający tylko tekst. Formatowanie, obrazy i pliki nie są uwzględnione.",
|
||||
"opml_version_1": "OPML v1.0 - tylko zwykły tekst",
|
||||
"opml_version_2": "OPML v2.0 - umożliwia również HTML",
|
||||
"export_type_single": "Tylko ta notatka, bez elementów podrzędnych",
|
||||
"export": "Eksportuj",
|
||||
"choose_export_type": "Wybierz najpierw rodzaj pliku do eksportu",
|
||||
"export_status": "Status eksportu",
|
||||
"export_in_progress": "Postęp eksportowania: {{progressCount}}",
|
||||
"export_finished_successfully": "Eksportowanie zakończone.",
|
||||
"format_pdf": "PDF - w celu drukowania lub udostępniania."
|
||||
},
|
||||
"clone_to": {
|
||||
"clone_notes_to": "Sklonuj notatki do...",
|
||||
"notes_to_clone": "Notatki do sklonowania",
|
||||
"search_for_note_by_its_name": "Wyszukaj notatkę po jej nazwie",
|
||||
"cloned_note_prefix_title": "Sklonowana notatka zostanie wyświetlona w drzewie notatki z podanym prefiksem",
|
||||
"prefix_optional": "Prefiks (opcjonalne)",
|
||||
"clone_to_selected_note": "Sklonuj do wybranej notatki",
|
||||
"no_path_to_clone_to": "Brak ścieżki do sklonowania.",
|
||||
"note_cloned": "Notatka \"{{clonedTitle}}\" została sklonowana do \"{{targetTitle}}\""
|
||||
},
|
||||
"help": {
|
||||
"title": "Ściągawka",
|
||||
"noteNavigation": "Nawigacja po notatkach",
|
||||
"goUpDown": "przewijanie w górę/w dół w liście notatek",
|
||||
"collapseExpand": "zwiń/rozwiń zbiór",
|
||||
"notSet": "niezdefiniowany",
|
||||
"goBackForwards": "przewijaj do tyłu/do przodu w historii",
|
||||
"showJumpToNoteDialog": "pokaż <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/note-navigation.html#jump-to-note\">\"przejdź do dialogu</a>",
|
||||
"scrollToActiveNote": "przewiń do aktywnej notatki",
|
||||
"jumpToParentNote": "przejdź do głównej notatki",
|
||||
"collapseWholeTree": "zwiń całe drzewko notatki",
|
||||
"collapseSubTree": "zwiń gałąź notatki",
|
||||
"tabShortcuts": "Skóry kart",
|
||||
"newTabNoteLink": "link notatki otwiera notatkę w nowej karcie",
|
||||
"newTabWithActivationNoteLink": "link notatki otwiera i aktywuje notatkę w nowej karcie",
|
||||
"onlyInDesktop": "Tylko na komputerze stacjonarnym (wersja Electron)",
|
||||
"openEmptyTab": "Otwórz pustą kartę",
|
||||
"closeActiveTab": "zamknij aktywną kartę",
|
||||
"activateNextTab": "aktywuj następną kartę",
|
||||
"activatePreviousTab": "aktywuj poprzednią kartę",
|
||||
"creatingNotes": "Tworzenie notatek",
|
||||
"createNoteAfter": "Utwórz nową notatkę obok obecnie aktywnej",
|
||||
"createNoteInto": "Utwórz nową podnotatkę w obecnie otwartej",
|
||||
"editBranchPrefix": "edytuj <a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/tree-concepts.html#prefix\">prefiks</a> aktywnej kopii notatki",
|
||||
"movingCloningNotes": "Przenoszenie / kopiowanie notatek",
|
||||
"moveNoteUpDown": "Przenieś notatkę w górę/w dół na liście notatek",
|
||||
"moveNoteUpHierarchy": "Przenieś notatkę w górę w hierarchii",
|
||||
"multiSelectNote": "Zaznacz wiele notatek powyżej/poniżej",
|
||||
"selectAllNotes": "Wybierz wszystkie notatki na obecnym poziomie",
|
||||
"selectNote": "Wybierz notatkę",
|
||||
"copyNotes": "skopiuj obecną notatkę (lub obecną sekcję) do schowka (zastosowanie dla<a class=\"external\" href=\"https://triliumnext.github.io/Docs/Wiki/cloning-notes.html#cloning-notes\">klonowania</a>)",
|
||||
"cutNotes": "przytnij obecną notatkę (lub obecną sekcję) do schowka (zastosowanie dla przenoszenia notatek)",
|
||||
"pasteNotes": "wklej notatkę jako podnotatka w obecnej notatce (rozumiane jako przenieś lub skopiuj, w zależności czy notatka była skopiowana czy wycięta)",
|
||||
"deleteNotes": "usuń notatkę / gałąź",
|
||||
"editingNotes": "Edytowanie notatek"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,7 +994,7 @@
|
||||
"invalid_view_type": "Tipo de visualização inválido '{{type}}'",
|
||||
"calendar": "Calendário",
|
||||
"table": "Tabela",
|
||||
"geo-map": "Geo Map",
|
||||
"geo-map": "Mapa geográfico",
|
||||
"board": "Quadro"
|
||||
},
|
||||
"edited_notes": {
|
||||
@@ -1278,7 +1278,7 @@
|
||||
"handwriting-system-fonts": "Fontes de escrita à mão de sistema",
|
||||
"serif": "Serifa",
|
||||
"sans-serif": "Sem Serifa",
|
||||
"monospace": "Monospace",
|
||||
"monospace": "Monoespaçado",
|
||||
"system-default": "Padrão do Sistema",
|
||||
"note_tree_and_detail_font_sizing": "Note que o tamanho da fonte da árvore e dos detalhes é relativo à configuração principal do tamanho de fonte."
|
||||
},
|
||||
@@ -1518,7 +1518,7 @@
|
||||
"doc": "Documento",
|
||||
"widget": "Widget",
|
||||
"confirm-change": "Não é recomentado alterar o tipo da nota quando o conteúdo da nota não está vazio. Quer continuar assim mesmo?",
|
||||
"geo-map": "Geo Map",
|
||||
"geo-map": "Mapa geográfico",
|
||||
"beta-feature": "Beta",
|
||||
"ai-chat": "Chat IA",
|
||||
"task-list": "Lista de Tarefas",
|
||||
@@ -1579,7 +1579,8 @@
|
||||
"hoist-this-note-workspace": "Fixar esta nota (workspace)",
|
||||
"refresh-saved-search-results": "Atualizar resultados de pesquisa salvos",
|
||||
"create-child-note": "Criar nota filha",
|
||||
"unhoist": "Desafixar"
|
||||
"unhoist": "Desafixar",
|
||||
"toggle-sidebar": "Alternar barra lateral"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Manter Janela no Topo"
|
||||
@@ -2022,6 +2023,8 @@
|
||||
"handshake_failed": "Falha no handshake com o servidor de sincronização, erro: {{message}}"
|
||||
},
|
||||
"shared_info": {
|
||||
"help_link": "Para ajuda, visite a <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>."
|
||||
"help_link": "Para ajuda, visite a <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>.",
|
||||
"shared_publicly": "Esta nota é compartilhada publicamente em {{- link}}.",
|
||||
"shared_locally": "Esta nota é compartilhada localmente em {{- link}}."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,7 +742,8 @@
|
||||
"save-changes": "Сохранить и применить изменения",
|
||||
"saved-search-note-refreshed": "Сохраненная поисковая заметка обновлена.",
|
||||
"refresh-saved-search-results": "Обновить сохраненные результаты поиска",
|
||||
"automatically-collapse-notes-title": "Заметки будут свернуты после определенного периода бездействия, чтобы навести порядок в дереве."
|
||||
"automatically-collapse-notes-title": "Заметки будут свернуты после определенного периода бездействия, чтобы навести порядок в дереве.",
|
||||
"toggle-sidebar": "Переключить боковую панель"
|
||||
},
|
||||
"quick-search": {
|
||||
"no-results": "Результаты не найдены",
|
||||
@@ -1974,8 +1975,8 @@
|
||||
},
|
||||
"shared_info": {
|
||||
"help_link": "Для получения справки посетите <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">вики</a>.",
|
||||
"shared_locally": "Заметка общедоступна локально в {{- link}}",
|
||||
"shared_publicly": "Заметка общедоступна публично в {{- link}}"
|
||||
"shared_locally": "Заметка общедоступна локально в {{- link}}.",
|
||||
"shared_publicly": "Заметка общедоступна публично в {{- link}}."
|
||||
},
|
||||
"note_create": {
|
||||
"duplicated": "Создан дубль заметки \"{{title}}\"."
|
||||
|
||||
@@ -1399,7 +1399,9 @@
|
||||
"open-in-popup": "快速編輯"
|
||||
},
|
||||
"shared_info": {
|
||||
"help_link": "如需幫助,請訪問 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>。"
|
||||
"help_link": "如需幫助,請訪問 <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">wiki</a>。",
|
||||
"shared_publicly": "此筆記已公開分享於 {{- link}}。",
|
||||
"shared_locally": "此筆記已於本地分享至 {{- link}}。"
|
||||
},
|
||||
"note_types": {
|
||||
"text": "文字",
|
||||
@@ -1477,7 +1479,8 @@
|
||||
"hoist-this-note-workspace": "聚焦此筆記(工作區)",
|
||||
"refresh-saved-search-results": "重新整理儲存的搜尋結果",
|
||||
"create-child-note": "建立子筆記",
|
||||
"unhoist": "取消聚焦"
|
||||
"unhoist": "取消聚焦",
|
||||
"toggle-sidebar": "切換側邊欄"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "保持此視窗置頂"
|
||||
|
||||
@@ -844,7 +844,8 @@
|
||||
"note_type": "Тип нотатки",
|
||||
"editable": "Редагув.",
|
||||
"basic_properties": "Основні Властивості",
|
||||
"language": "Мова"
|
||||
"language": "Мова",
|
||||
"configure_code_notes": "Конфігурація нотатки з кодом..."
|
||||
},
|
||||
"book_properties": {
|
||||
"view_type": "Тип перегляду",
|
||||
@@ -1586,7 +1587,8 @@
|
||||
"hoist-this-note-workspace": "Закріпити цю нотатку (робочий простір)",
|
||||
"refresh-saved-search-results": "Оновити збережені результати пошуку",
|
||||
"create-child-note": "Створити дочірню нотатку",
|
||||
"unhoist": "Відкріпити"
|
||||
"unhoist": "Відкріпити",
|
||||
"toggle-sidebar": "Перемикання бічної панелі"
|
||||
},
|
||||
"title_bar_buttons": {
|
||||
"window-on-top": "Тримати вікно зверху"
|
||||
@@ -1909,8 +1911,8 @@
|
||||
"open-in-popup": "Швидке редагування"
|
||||
},
|
||||
"shared_info": {
|
||||
"shared_publicly": "Ця нотатка опублікована на {{- link}}",
|
||||
"shared_locally": "Цю нотатку опубліковано локально на {{- link}}",
|
||||
"shared_publicly": "Ця нотатка опублікована на {{- link}}.",
|
||||
"shared_locally": "Цю нотатку опубліковано локально на {{- link}}.",
|
||||
"help_link": "Щоб отримати допомогу, відвідайте <a href=\"https://triliumnext.github.io/Docs/Wiki/sharing.html\">вікі</a>."
|
||||
},
|
||||
"note_types": {
|
||||
@@ -2018,5 +2020,11 @@
|
||||
},
|
||||
"units": {
|
||||
"percentage": "%"
|
||||
},
|
||||
"ui-performance": {
|
||||
"title": "Продуктивність",
|
||||
"enable-motion": "Увімкнути переходи та анімацію",
|
||||
"enable-shadows": "Увімкнути тіні",
|
||||
"enable-backdrop-effects": "Увімкнути фонові ефекти для меню, спливаючих вікон та панелей"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"about": {
|
||||
"homepage": "Trang chủ:",
|
||||
"title": "Về Trilium Notes"
|
||||
"title": "Về Trilium Notes",
|
||||
"app_version": "Phiên bản:",
|
||||
"db_version": "Phiên bản DB:",
|
||||
"sync_version": "Phiên bản liên kết:"
|
||||
},
|
||||
"add_link": {
|
||||
"add_link": "Thêm liên kết",
|
||||
@@ -26,7 +29,8 @@
|
||||
"close": "Đóng"
|
||||
},
|
||||
"help": {
|
||||
"other": "Khác"
|
||||
"other": "Khác",
|
||||
"notSet": "chưa được đặt"
|
||||
},
|
||||
"toast": {
|
||||
"critical-error": {
|
||||
@@ -69,12 +73,16 @@
|
||||
"add_label": {
|
||||
"add_label": "Thêm nhãn",
|
||||
"label_name_placeholder": "tên nhãn",
|
||||
"help_text_item2": "hoặc thay đổi giá trị của nhãn có sẵn"
|
||||
"help_text_item2": "hoặc thay đổi giá trị của nhãn có sẵn",
|
||||
"new_value_placeholder": "giá trị mới"
|
||||
},
|
||||
"rename_label": {
|
||||
"rename_label": "Đặt lại tên nhãn"
|
||||
},
|
||||
"call_to_action": {
|
||||
"dismiss": "Bỏ qua"
|
||||
},
|
||||
"abstract_search_option": {
|
||||
"remove_this_search_option": "Xoá lựa chọn tìm kiếm này"
|
||||
}
|
||||
}
|
||||
|
||||
2
apps/client/src/types-fancytree.d.ts
vendored
2
apps/client/src/types-fancytree.d.ts
vendored
@@ -113,7 +113,7 @@ declare namespace Fancytree {
|
||||
generateFormElements(selected?: boolean, active?: boolean): void;
|
||||
|
||||
/** Return the currently active node or null. */
|
||||
getActiveNode(): FancytreeNode;
|
||||
getActiveNode(): FancytreeNode | null;
|
||||
|
||||
/** Return the first top level node if any (not the invisible root node). */
|
||||
getFirstChild(): FancytreeNode;
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
import utils from "../../services/utils.js";
|
||||
import contextMenu from "../../menus/context_menu.js";
|
||||
import contextMenu, { MenuCommandItem } from "../../menus/context_menu.js";
|
||||
import treeService from "../../services/tree.js";
|
||||
import ButtonFromNoteWidget from "./button_from_note.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import type { CommandNames } from "../../components/app_context.js";
|
||||
import type { WebContents } from "electron";
|
||||
|
||||
interface ContextMenuItem {
|
||||
title: string;
|
||||
idx: string;
|
||||
uiIcon: string;
|
||||
}
|
||||
import link from "../../services/link.js";
|
||||
|
||||
export default class HistoryNavigationButton extends ButtonFromNoteWidget {
|
||||
private webContents?: WebContents;
|
||||
@@ -47,24 +42,20 @@ export default class HistoryNavigationButton extends ButtonFromNoteWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
let items: ContextMenuItem[] = [];
|
||||
let items: MenuCommandItem<string>[] = [];
|
||||
|
||||
const history = this.webContents.navigationHistory;
|
||||
const activeIndex = history.getActiveIndex();
|
||||
const history = this.webContents.navigationHistory.getAllEntries();
|
||||
const activeIndex = this.webContents.navigationHistory.getActiveIndex();
|
||||
|
||||
for (const idx in history) {
|
||||
const url = history[idx];
|
||||
const parts = url.split("#");
|
||||
if (parts.length < 2) continue;
|
||||
|
||||
const notePathWithTab = parts[1];
|
||||
const notePath = notePathWithTab.split("-")[0];
|
||||
const { notePath } = link.parseNavigationStateFromUrl(history[idx].url);
|
||||
if (!notePath) continue;
|
||||
|
||||
const title = await treeService.getNotePathTitle(notePath);
|
||||
|
||||
items.push({
|
||||
title,
|
||||
idx,
|
||||
command: idx,
|
||||
uiIcon:
|
||||
parseInt(idx) === activeIndex
|
||||
? "bx bx-radio-circle-marked" // compare with type coercion!
|
||||
@@ -84,9 +75,10 @@ export default class HistoryNavigationButton extends ButtonFromNoteWidget {
|
||||
x: e.pageX,
|
||||
y: e.pageY,
|
||||
items,
|
||||
selectMenuItemHandler: (item: any) => {
|
||||
if (item && item.idx && this.webContents) {
|
||||
this.webContents.goToIndex(item.idx);
|
||||
selectMenuItemHandler: (item: MenuCommandItem<string>) => {
|
||||
if (item && item.command && this.webContents) {
|
||||
const idx = parseInt(item.command, 10);
|
||||
this.webContents.navigationHistory.goToIndex(idx);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -382,7 +382,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
if (event.shiftKey && !ctrlKey) {
|
||||
const activeNode = this.getActiveNode();
|
||||
|
||||
if (activeNode.getParent() !== node.getParent()) {
|
||||
if (activeNode?.getParent() !== node.getParent()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -729,7 +729,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
|
||||
shortcutService.bindElShortcut($(this.tree.$container), key, () => {
|
||||
const node = this.tree.getActiveNode();
|
||||
return handler(node, {} as JQuery.KeyDownEvent);
|
||||
return node && handler(node, {} as JQuery.KeyDownEvent);
|
||||
// return false from the handler will stop default handling.
|
||||
});
|
||||
}
|
||||
@@ -921,8 +921,9 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
nodes.push(node);
|
||||
}
|
||||
|
||||
if (nodes.length === 0) {
|
||||
nodes.push(this.getActiveNode());
|
||||
const activeNode = this.getActiveNode();
|
||||
if (nodes.length === 0 && activeNode) {
|
||||
nodes.push(activeNode);
|
||||
}
|
||||
|
||||
// hidden subtree is hackily hidden via CSS when hoisted to root
|
||||
@@ -967,9 +968,6 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
this.collapseTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {FancytreeNode|null}
|
||||
*/
|
||||
getActiveNode() {
|
||||
return this.tree.getActiveNode();
|
||||
}
|
||||
@@ -1219,7 +1217,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
}
|
||||
|
||||
const activeNode = this.getActiveNode();
|
||||
const activeNodeFocused = activeNode?.hasFocus();
|
||||
const activeNodeFocused = !!activeNode?.hasFocus();
|
||||
const activeNotePath = activeNode ? treeService.getNotePath(activeNode) : null;
|
||||
|
||||
const refreshCtx: RefreshContext = {
|
||||
@@ -1531,7 +1529,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
|
||||
// Automatically expand the hoisted note by default
|
||||
const node = this.getActiveNode();
|
||||
if (node.data.noteId === this.noteContext.hoistedNoteId){
|
||||
if (node?.data.noteId === this.noteContext.hoistedNoteId){
|
||||
this.setExpanded(node.data.branchId, true);
|
||||
}
|
||||
}
|
||||
@@ -1809,6 +1807,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
||||
const triggerCommand = (command: TreeCommandNames) => {
|
||||
const node = this.getActiveNode();
|
||||
if (!node) return;
|
||||
const notePath = treeService.getNotePath(node);
|
||||
|
||||
this.triggerCommand<TreeCommandNames>(command, {
|
||||
@@ -1825,6 +1824,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
||||
icon: buildIcon("NSImageNameTouchBarAddTemplate"),
|
||||
click: () => {
|
||||
const node = this.getActiveNode();
|
||||
if (!node) return;
|
||||
const notePath = treeService.getNotePath(node);
|
||||
noteCreateService.createNote(notePath, {
|
||||
isProtected: node.data.isProtected
|
||||
|
||||
@@ -15,13 +15,15 @@ const TPL = /*html*/`
|
||||
padding: 10px 10px 10px 0px;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
|
||||
.quick-search button, .quick-search input {
|
||||
border: 0;
|
||||
font-size: 100% !important;
|
||||
}
|
||||
|
||||
|
||||
.quick-search .dropdown-menu {
|
||||
--quick-search-item-delimiter-color: var(--dropdown-border-color);
|
||||
|
||||
max-height: 80vh;
|
||||
min-width: 400px;
|
||||
max-width: 720px;
|
||||
@@ -38,14 +40,14 @@ const TPL = /*html*/`
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.quick-search .dropdown-item:not(:last-child)::after {
|
||||
.quick-search .dropdown-item + .dropdown-item::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: var(--dropdown-border-color);
|
||||
border-bottom: 1px solid var(--quick-search-item-delimiter-color);
|
||||
}
|
||||
|
||||
.quick-search .dropdown-item:last-child::after {
|
||||
@@ -92,6 +94,8 @@ const TPL = /*html*/`
|
||||
background-color: var(--accented-background-color);
|
||||
color: var(--main-text-color);
|
||||
font-size: .85em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Search result highlighting */
|
||||
@@ -106,6 +110,10 @@ const TPL = /*html*/`
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.quick-search .bx-loader {
|
||||
margin-inline-end: 4px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div class="input-group-prepend">
|
||||
@@ -220,7 +228,11 @@ export default class QuickSearchWidget extends BasicWidget {
|
||||
this.isLoadingMore = false;
|
||||
|
||||
this.$dropdownMenu.empty();
|
||||
this.$dropdownMenu.append(`<span class="dropdown-item disabled"><span class="bx bx-loader bx-spin"></span>${t("quick-search.searching")}</span>`);
|
||||
this.$dropdownMenu.append(`
|
||||
<span class="dropdown-item disabled">
|
||||
<span class="bx bx-loader bx-spin"></span>
|
||||
${t("quick-search.searching")}
|
||||
</span>`);
|
||||
|
||||
const { searchResultNoteIds, searchResults, error } = await server.get<QuickSearchResponse>(`quick-search/${encodeURIComponent(searchString)}`);
|
||||
|
||||
|
||||
@@ -388,7 +388,7 @@ async function setupFonts() {
|
||||
if (!glob.isDev) {
|
||||
path = `${window.location.pathname}/node_modules/@excalidraw/excalidraw/dist/prod`;
|
||||
} else {
|
||||
path = (await import("../../../node_modules/@excalidraw/excalidraw/dist/prod/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2?url")).default;
|
||||
path = (await import("../../../../../node_modules/@excalidraw/excalidraw/dist/prod/fonts/Excalifont/Excalifont-Regular-a88b72a24fb54c9f94e3b5fdaa7481c9.woff2?url")).default;
|
||||
let pathComponents = path.split("/");
|
||||
path = pathComponents.slice(0, pathComponents.length - 2).join("/");
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { buildExtraCommands, type EditorConfig, PREMIUM_PLUGINS } from "@trilium
|
||||
import { getHighlightJsNameForMime } from "../../../services/mime_types.js";
|
||||
import options from "../../../services/options.js";
|
||||
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
|
||||
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url";
|
||||
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/src/emoji_definitions/en.json?url";
|
||||
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
|
||||
import getTemplates from "./snippets.js";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import utils from "../../../services/utils.js";
|
||||
import options from "../../../services/options.js";
|
||||
import IconAlignCenter from "@ckeditor/ckeditor5-icons/theme/icons/align-center.svg?raw";
|
||||
|
||||
const TEXT_FORMATTING_GROUP = {
|
||||
label: "Text formatting",
|
||||
@@ -77,7 +78,7 @@ export function buildClassicToolbar(multilineToolbar: boolean) {
|
||||
items: ["imageUpload", "|", "link", "bookmark", "internallink", "includeNote", "|", "specialCharacters", "emoji", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
||||
},
|
||||
"|",
|
||||
"alignment",
|
||||
buildAlignmentToolbar(),
|
||||
"outdent",
|
||||
"indent",
|
||||
"|",
|
||||
@@ -134,7 +135,7 @@ export function buildFloatingToolbar() {
|
||||
items: ["link", "bookmark", "internallink", "includeNote", "|", "math", "mermaid", "horizontalLine", "pageBreak", "dateTime"]
|
||||
},
|
||||
"|",
|
||||
"alignment",
|
||||
buildAlignmentToolbar(),
|
||||
"outdent",
|
||||
"indent",
|
||||
"|",
|
||||
@@ -147,3 +148,11 @@ export function buildFloatingToolbar() {
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function buildAlignmentToolbar() {
|
||||
return {
|
||||
label: "Alignment",
|
||||
icon: IconAlignCenter,
|
||||
items: ["alignment:left", "alignment:center", "alignment:right", "|", "alignment:justify"]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import { buildSelectedBackgroundColor } from "../../components/touch_bar.js";
|
||||
import { buildConfig, BuildEditorOptions, OPEN_SOURCE_LICENSE_KEY } from "./ckeditor/config.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor, type MentionFeed, type WatchdogConfig, EditorConfig } from "@triliumnext/ckeditor5";
|
||||
import "@triliumnext/ckeditor5/index.css";
|
||||
import { updateTemplateCache } from "./ckeditor/snippets.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
|
||||
@@ -2,26 +2,23 @@
|
||||
import { join, resolve } from 'path';
|
||||
import { defineConfig, type Plugin } from 'vite';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||
import asset_path from './src/asset_path';
|
||||
import webpackStatsPlugin from 'rollup-plugin-webpack-stats';
|
||||
import preact from "@preact/preset-vite";
|
||||
|
||||
const assets = [ "assets", "stylesheets", "fonts", "translations" ];
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/client',
|
||||
base: process.env.NODE_ENV === "production" ? "" : asset_path,
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
plugins: [
|
||||
preact(),
|
||||
const isDev = process.env.NODE_ENV === "development";
|
||||
let plugins: any = [
|
||||
preact({
|
||||
babel: {
|
||||
compact: !isDev
|
||||
}
|
||||
})
|
||||
];
|
||||
|
||||
if (!isDev) {
|
||||
plugins = [
|
||||
...plugins,
|
||||
viteStaticCopy({
|
||||
targets: assets.map((asset) => ({
|
||||
src: `src/${asset}/*`,
|
||||
@@ -32,20 +29,22 @@ export default defineConfig(() => ({
|
||||
structured: true,
|
||||
targets: [
|
||||
{
|
||||
src: "node_modules/@excalidraw/excalidraw/dist/prod/fonts/*",
|
||||
src: "../../node_modules/@excalidraw/excalidraw/dist/prod/fonts/*",
|
||||
dest: "",
|
||||
}
|
||||
]
|
||||
}),
|
||||
webpackStatsPlugin()
|
||||
] as Plugin[],
|
||||
]
|
||||
}
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/client',
|
||||
base: "",
|
||||
plugins,
|
||||
resolve: {
|
||||
alias: [
|
||||
// Force the use of dist in development mode because upstream ESM is broken (some hybrid between CJS and ESM, will be improved in upcoming versions).
|
||||
{
|
||||
find: "@triliumnext/highlightjs",
|
||||
replacement: resolve(__dirname, "node_modules/@triliumnext/highlightjs/dist")
|
||||
},
|
||||
{
|
||||
find: "react",
|
||||
replacement: "preact/compat"
|
||||
@@ -63,10 +62,6 @@ export default defineConfig(() => ({
|
||||
"preact/hooks"
|
||||
]
|
||||
},
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
build: {
|
||||
target: "esnext",
|
||||
outDir: './dist',
|
||||
@@ -105,18 +100,6 @@ export default defineConfig(() => ({
|
||||
"./src/test/setup.ts"
|
||||
]
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: [
|
||||
"@triliumnext/highlightjs"
|
||||
]
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
quietDeps: true
|
||||
}
|
||||
}
|
||||
},
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
To build and run manually:
|
||||
|
||||
```sh
|
||||
nx build db-compare
|
||||
pnpm build db-compare
|
||||
node ./apps/db-compare/dist/compare.js
|
||||
```
|
||||
|
||||
To serve development build with arguments:
|
||||
|
||||
```sh
|
||||
nx serve db-compare --args "apps/server/spec/db/document_v214.db" --args "apps/server/spec/db/document_v214_migrated.db"
|
||||
pnpm dev --args "apps/server/spec/db/document_v214.db" --args "apps/server/spec/db/document_v214_migrated.db"
|
||||
```
|
||||
@@ -9,63 +9,8 @@
|
||||
"sqlite": "5.1.1",
|
||||
"sqlite3": "5.1.7"
|
||||
},
|
||||
"nx": {
|
||||
"name": "db-compare",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/esbuild:esbuild",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"platform": "node",
|
||||
"outputPath": "apps/db-compare/dist",
|
||||
"format": [
|
||||
"cjs"
|
||||
],
|
||||
"bundle": false,
|
||||
"main": "apps/db-compare/src/compare.ts",
|
||||
"tsConfig": "apps/db-compare/tsconfig.app.json",
|
||||
"assets": [],
|
||||
"esbuildOptions": {
|
||||
"sourcemap": true,
|
||||
"outExtension": {
|
||||
".js": ".js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"development": {},
|
||||
"production": {
|
||||
"esbuildOptions": {
|
||||
"sourcemap": false,
|
||||
"outExtension": {
|
||||
".js": ".js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nx/js:node",
|
||||
"defaultConfiguration": "development",
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"options": {
|
||||
"buildTarget": "db-compare:build",
|
||||
"runBuildTargetDependencies": false
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "db-compare:build:development"
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "db-compare:build:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"scripts": {
|
||||
"dev": "tsx src/compare.ts",
|
||||
"build": "esbuild --platform=node --format=cjs --outdir=dist src/compare.ts"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
TRILIUM_INTEGRATION_TEST=memory-no-store
|
||||
TRILIUM_PORT=8082
|
||||
TRILIUM_DATA_DIR=data
|
||||
@@ -1,15 +0,0 @@
|
||||
import playwright from "eslint-plugin-playwright";
|
||||
import baseConfig from "../../eslint.config.mjs";
|
||||
|
||||
export default [
|
||||
playwright.configs["flat/recommended"],
|
||||
...baseConfig,
|
||||
{
|
||||
files: [
|
||||
"**/*.ts",
|
||||
"**/*.js"
|
||||
],
|
||||
// Override or add rules here
|
||||
rules: {}
|
||||
}
|
||||
];
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"name": "@triliumnext/desktop-e2e",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"nx": {
|
||||
"name": "desktop-e2e",
|
||||
"implicitDependencies": [
|
||||
"client",
|
||||
"desktop"
|
||||
],
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"dependsOn": [
|
||||
"desktop:build",
|
||||
"desktop:rebuild-deps"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"dotenv": "17.2.1",
|
||||
"electron": "37.4.0"
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"outDir": "out-tsc/playwright",
|
||||
"sourceMap": false
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.js",
|
||||
"playwright.config.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.spec.js",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.test.js",
|
||||
"src/**/*.d.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"out-tsc",
|
||||
"test-output",
|
||||
"eslint.config.js",
|
||||
"eslint.config.mjs",
|
||||
"eslint.config.cjs"
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
node-linker = hoisted
|
||||
@@ -1 +0,0 @@
|
||||
TRILIUM_PORT=37743
|
||||
@@ -1,3 +0,0 @@
|
||||
TRILIUM_PORT=37741
|
||||
TRILIUM_DATA_DIR=../data
|
||||
NODE_OPTIONS=--enable-source-maps
|
||||
@@ -60,7 +60,7 @@ test('First setup', async () => {
|
||||
// Verify the shared link is valid
|
||||
const requestContext = await request.newContext();
|
||||
const response = await requestContext.get(linkUrl!);
|
||||
expect(response).toBeOK();
|
||||
await expect(response).toBeOK();
|
||||
|
||||
await mainWindow.waitForTimeout(5000);
|
||||
});
|
||||
@@ -3,7 +3,23 @@
|
||||
"version": "0.98.1",
|
||||
"description": "Build your personal knowledge base with Trilium Notes",
|
||||
"private": true,
|
||||
"main": "main.cjs",
|
||||
"main": "src/main.ts",
|
||||
"license": "AGPL-3.0-only",
|
||||
"author": {
|
||||
"name": "Trilium Notes Team",
|
||||
"email": "contact@eliandoran.me",
|
||||
"url": "https://github.com/TriliumNext/Notes"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data tsx ../../scripts/electron-start.mts src/main.ts",
|
||||
"start-no-dir": "cross-env TRILIUM_PORT=37743 tsx ../../scripts/electron-start.mts src/main.ts",
|
||||
"build": "tsx scripts/build.ts",
|
||||
"start-prod": "pnpm build && cross-env TRILIUM_DATA_DIR=data TRILIUM_PORT=37841 ELECTRON_IS_DEV=0 electron dist",
|
||||
"electron-forge:make": "pnpm build && cross-env electron-forge make dist",
|
||||
"electron-forge:package": "pnpm build && electron-forge package dist",
|
||||
"electron-forge:start": "pnpm build && electron-forge start dist",
|
||||
"e2e": "pnpm build && cross-env TRILIUM_INTEGRATION_TEST=memory-no-store TRILIUM_PORT=8082 TRILIUM_DATA_DIR=data-e2e ELECTRON_IS_DEV=0 playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron/remote": "2.1.3",
|
||||
"better-sqlite3": "^12.0.0",
|
||||
@@ -15,6 +31,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/electron-squirrel-startup": "1.0.2",
|
||||
"@triliumnext/commons": "workspace:*",
|
||||
"@triliumnext/server": "workspace:*",
|
||||
"copy-webpack-plugin": "13.0.1",
|
||||
"electron": "37.4.0",
|
||||
@@ -27,174 +44,5 @@
|
||||
"@electron-forge/maker-zip": "7.8.3",
|
||||
"@electron-forge/plugin-auto-unpack-natives": "7.8.3",
|
||||
"prebuild-install": "^7.1.1"
|
||||
},
|
||||
"config": {
|
||||
"forge": "./electron-forge/forge.config.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"start-prod": "nx build desktop && cross-env TRILIUM_DATA_DIR=data TRILIUM_RESOURCE_DIR=dist TRILIUM_PORT=37841 electron dist/main.js"
|
||||
},
|
||||
"license": "AGPL-3.0-only",
|
||||
"author": {
|
||||
"name": "Trilium Notes Team",
|
||||
"email": "contact@eliandoran.me",
|
||||
"url": "https://github.com/TriliumNext/Notes"
|
||||
},
|
||||
"nx": {
|
||||
"name": "desktop",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/esbuild:esbuild",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"defaultConfiguration": "production",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"minify": true,
|
||||
"sourcemap": false
|
||||
},
|
||||
"development": {
|
||||
"minify": false,
|
||||
"sourcemap": true
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"main": "apps/desktop/src/electron-main.ts",
|
||||
"outputPath": "apps/desktop/dist",
|
||||
"outputFileName": "main.js",
|
||||
"tsConfig": "apps/desktop/tsconfig.app.json",
|
||||
"platform": "node",
|
||||
"external": [
|
||||
"electron",
|
||||
"@electron/remote",
|
||||
"better-sqlite3",
|
||||
"./xhr-sync-worker.js"
|
||||
],
|
||||
"format": [
|
||||
"cjs"
|
||||
],
|
||||
"thirdParty": true,
|
||||
"declaration": false,
|
||||
"esbuildOptions": {
|
||||
"splitting": false,
|
||||
"loader": {
|
||||
".css": "text"
|
||||
}
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/dist/node_modules",
|
||||
"output": "node_modules"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/desktop/node_modules/@electron/remote",
|
||||
"output": "node_modules/@electron/remote"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/dist/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "packages/share-theme/src/templates",
|
||||
"output": "share-theme/templates"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/desktop/src/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/dist/public",
|
||||
"output": "public"
|
||||
},
|
||||
{
|
||||
"glob": "xhr-sync-worker.js",
|
||||
"input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr",
|
||||
"output": ""
|
||||
}
|
||||
],
|
||||
"declarationRootDir": "apps/desktop/src"
|
||||
}
|
||||
},
|
||||
"rebuild-deps": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"defaultConfiguration": "default",
|
||||
"cache": false,
|
||||
"configurations": {
|
||||
"default": {
|
||||
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist"
|
||||
},
|
||||
"nixos": {
|
||||
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist $(nix-shell -p electron_35 --run \"electron --version\")"
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [
|
||||
"rebuild-deps"
|
||||
],
|
||||
"defaultConfiguration": "default",
|
||||
"configurations": {
|
||||
"default": {
|
||||
"command": "electron main.cjs",
|
||||
"cwd": "{projectRoot}/dist"
|
||||
},
|
||||
"nixos": {
|
||||
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"",
|
||||
"cwd": ".",
|
||||
"forwardAllArgs": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve-nodir": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [
|
||||
"rebuild-deps"
|
||||
],
|
||||
"defaultConfiguration": "default",
|
||||
"configurations": {
|
||||
"default": {
|
||||
"command": "electron main.cjs",
|
||||
"cwd": "{projectRoot}/dist"
|
||||
},
|
||||
"nixos": {
|
||||
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"",
|
||||
"cwd": ".",
|
||||
"forwardAllArgs": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"electron-forge:make": {
|
||||
"dependsOn": [
|
||||
"build",
|
||||
"rebuild-deps"
|
||||
],
|
||||
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge make dist"
|
||||
},
|
||||
"electron-forge:package": {
|
||||
"dependsOn": [
|
||||
"build",
|
||||
"rebuild-deps"
|
||||
],
|
||||
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge package dist"
|
||||
},
|
||||
"electron-forge:start": {
|
||||
"dependsOn": [
|
||||
"build",
|
||||
"rebuild-deps"
|
||||
],
|
||||
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm TRILIUM_DATA_DIR=./data electron-forge start dist"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
|
||||
require('dotenv').config({
|
||||
path: __dirname + "/" + ".env"
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
@@ -14,6 +9,8 @@ export default defineConfig({
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
testDir: "e2e",
|
||||
outputDir: "test-output",
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
46
apps/desktop/scripts/build.ts
Normal file
46
apps/desktop/scripts/build.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { join } from "path";
|
||||
import BuildHelper from "../../../scripts/build-utils";
|
||||
import originalPackageJson from "../package.json" with { type: "json" };
|
||||
import { writeFileSync } from "fs";
|
||||
|
||||
const build = new BuildHelper("apps/desktop");
|
||||
|
||||
async function main() {
|
||||
await build.buildBackend([ "src/main.ts"]);
|
||||
|
||||
// Copy assets.
|
||||
build.copy("src/assets", "assets/");
|
||||
build.copy("/apps/server/src/assets", "assets/");
|
||||
build.copy("/packages/share-theme/src/templates", "share-theme/templates/");
|
||||
|
||||
// Copy node modules dependencies
|
||||
build.copyNodeModules([ "better-sqlite3", "bindings", "file-uri-to-path", "@electron/remote" ]);
|
||||
build.copy("/node_modules/jsdom/lib/jsdom/living/xhr/xhr-sync-worker.js", "xhr-sync-worker.js");
|
||||
|
||||
// Integrate the client.
|
||||
build.triggerBuildAndCopyTo("apps/client", "public/");
|
||||
build.deleteFromOutput("public/webpack-stats.json");
|
||||
|
||||
generatePackageJson();
|
||||
}
|
||||
|
||||
function generatePackageJson() {
|
||||
const { version, author, license, description, dependencies, devDependencies } = originalPackageJson;
|
||||
const packageJson = {
|
||||
name: "trilium",
|
||||
main: "main.cjs",
|
||||
version, author, license, description,
|
||||
dependencies: {
|
||||
"better-sqlite3": dependencies["better-sqlite3"],
|
||||
},
|
||||
devDependencies: {
|
||||
electron: devDependencies.electron
|
||||
},
|
||||
config: {
|
||||
forge: "../electron-forge/forge.config.ts"
|
||||
}
|
||||
};
|
||||
writeFileSync(join(build.outDir, "package.json"), JSON.stringify(packageJson, null, "\t"), "utf-8");
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -15,65 +15,8 @@
|
||||
"@types/mime-types": "^3.0.0",
|
||||
"@types/yargs": "^17.0.33"
|
||||
},
|
||||
"nx": {
|
||||
"name": "dump-db",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/esbuild:esbuild",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"defaultConfiguration": "production",
|
||||
"options": {
|
||||
"platform": "node",
|
||||
"outputPath": "apps/dump-db/dist",
|
||||
"format": [
|
||||
"cjs"
|
||||
],
|
||||
"bundle": false,
|
||||
"main": "apps/dump-db/src/main.ts",
|
||||
"tsConfig": "apps/dump-db/tsconfig.app.json",
|
||||
"assets": [
|
||||
"apps/dump-db/src/assets"
|
||||
],
|
||||
"esbuildOptions": {
|
||||
"sourcemap": true,
|
||||
"outExtension": {
|
||||
".js": ".js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"development": {},
|
||||
"production": {
|
||||
"esbuildOptions": {
|
||||
"sourcemap": false,
|
||||
"outExtension": {
|
||||
".js": ".js"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nx/js:node",
|
||||
"defaultConfiguration": "development",
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"options": {
|
||||
"buildTarget": "dump-db:build",
|
||||
"runBuildTargetDependencies": false
|
||||
},
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "dump-db:build:development"
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "dump-db:build:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"scripts": {
|
||||
"dev": "tsx src/main.ts",
|
||||
"build": "esbuild --platform=node --format=cjs --outdir=dist src/main.ts"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
TRILIUM_DATA_DIR=../data
|
||||
TRILIUM_INTEGRATION_TEST=memory-no-store
|
||||
TRILIUM_PORT=37741
|
||||
|
||||
# Paths are relative to dist root
|
||||
DOCS_ROOT=../../../docs
|
||||
USER_GUIDE_ROOT=../../../apps/server/src/assets/doc_notes/en/User Guide
|
||||
@@ -15,120 +15,8 @@
|
||||
"electron": "37.4.0",
|
||||
"fs-extra": "11.3.1"
|
||||
},
|
||||
"nx": {
|
||||
"name": "edit-docs",
|
||||
"implicitDependencies": [
|
||||
"server"
|
||||
],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/esbuild:esbuild",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"main": "apps/edit-docs/src/edit-docs.ts",
|
||||
"outputPath": "apps/edit-docs/dist",
|
||||
"tsConfig": "apps/edit-docs/tsconfig.app.json",
|
||||
"platform": "node",
|
||||
"additionalEntryPoints": [
|
||||
"apps/edit-docs/src/edit-demo.ts"
|
||||
],
|
||||
"external": [
|
||||
"electron",
|
||||
"@electron/remote",
|
||||
"better-sqlite3",
|
||||
"./xhr-sync-worker.js"
|
||||
],
|
||||
"format": [
|
||||
"cjs"
|
||||
],
|
||||
"minify": false,
|
||||
"thirdParty": true,
|
||||
"declaration": false,
|
||||
"esbuildOptions": {
|
||||
"splitting": false,
|
||||
"loader": {
|
||||
".css": "text"
|
||||
}
|
||||
},
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/dist/node_modules",
|
||||
"output": "node_modules"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/dist/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/dist/public",
|
||||
"output": "public"
|
||||
},
|
||||
{
|
||||
"glob": "xhr-sync-worker.js",
|
||||
"input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr",
|
||||
"output": ""
|
||||
}
|
||||
],
|
||||
"declarationRootDir": "apps/edit-docs/src"
|
||||
}
|
||||
},
|
||||
"rebuild-deps": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"defaultConfiguration": "default",
|
||||
"cache": true,
|
||||
"configurations": {
|
||||
"default": {
|
||||
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist"
|
||||
},
|
||||
"nixos": {
|
||||
"command": "cross-env DEBUG=* tsx scripts/electron-rebuild.mts {projectRoot}/dist $(nix-shell -p electron_35 --run \"electron --version\")"
|
||||
}
|
||||
}
|
||||
},
|
||||
"edit-docs": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [
|
||||
"rebuild-deps"
|
||||
],
|
||||
"defaultConfiguration": "default",
|
||||
"configurations": {
|
||||
"default": {
|
||||
"command": "electron edit-docs.cjs",
|
||||
"cwd": "{projectRoot}/dist"
|
||||
},
|
||||
"nixos": {
|
||||
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/edit-docs.cjs\"",
|
||||
"cwd": ".",
|
||||
"forwardAllArgs": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"edit-demo": {
|
||||
"executor": "nx:run-commands",
|
||||
"dependsOn": [
|
||||
"rebuild-deps"
|
||||
],
|
||||
"defaultConfiguration": "default",
|
||||
"configurations": {
|
||||
"default": {
|
||||
"command": "electron edit-demo.cjs",
|
||||
"cwd": "{projectRoot}/dist"
|
||||
},
|
||||
"nixos": {
|
||||
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/edit-demo.cjs\"",
|
||||
"cwd": ".",
|
||||
"forwardAllArgs": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"scripts": {
|
||||
"edit-docs": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-docs.ts",
|
||||
"edit-demo": "cross-env TRILIUM_PORT=37741 TRILIUM_DATA_DIR=data TRILIUM_INTEGRATION_TEST=memory-no-store DOCS_ROOT=../../../docs USER_GUIDE_ROOT=\"../../server/src/assets/doc_notes/en/User Guide\" tsx ../../scripts/electron-start.mts src/edit-demo.ts"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
TRILIUM_INTEGRATION_TEST=memory
|
||||
TRILIUM_PORT=8082
|
||||
TRILIUM_DATA_DIR=apps/server/spec/db
|
||||
@@ -2,21 +2,10 @@
|
||||
"name": "@triliumnext/server-e2e",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"nx": {
|
||||
"name": "server-e2e",
|
||||
"implicitDependencies": [
|
||||
"client",
|
||||
"server"
|
||||
],
|
||||
"targets": {
|
||||
"e2e": {
|
||||
"dependsOn": [
|
||||
"server:build"
|
||||
]
|
||||
}
|
||||
}
|
||||
"scripts": {
|
||||
"e2e": "playwright test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dotenv": "17.2.1"
|
||||
"dotenv": "17.2.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,44 @@
|
||||
import { defineConfig, devices } from '@playwright/test';
|
||||
import { nxE2EPreset } from '@nx/playwright/preset';
|
||||
import { workspaceRoot } from '@nx/devkit';
|
||||
|
||||
require('dotenv').config({
|
||||
path: __dirname + "/" + ".env"
|
||||
});
|
||||
import { join } from 'path';
|
||||
|
||||
// For CI, you may want to set BASE_URL to the deployed application.
|
||||
const port = process.env['TRILIUM_PORT'];
|
||||
const port = process.env['TRILIUM_PORT'] ?? "8082";
|
||||
const baseURL = process.env['BASE_URL'] || `http://127.0.0.1:${port}`;
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
...nxE2EPreset(__filename, { testDir: './src' }),
|
||||
testDir: "src",
|
||||
reporter: [["list"], ["html", { outputFolder: "test-output" }]],
|
||||
outputDir: "test-output",
|
||||
retries: 3,
|
||||
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
baseURL,
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
/* Run your local dev server before starting the tests */
|
||||
webServer: !process.env.TRILIUM_DOCKER ? {
|
||||
command: 'pnpm server:start-prod',
|
||||
command: 'pnpm start-prod-no-dir',
|
||||
url: baseURL,
|
||||
reuseExistingServer: !process.env.CI,
|
||||
cwd: workspaceRoot,
|
||||
cwd: join(__dirname, "../server"),
|
||||
env: {
|
||||
TRILIUM_DATA_DIR: "spec/db",
|
||||
TRILIUM_PORT: port,
|
||||
TRILIUM_INTEGRATION_TEST: "memory"
|
||||
},
|
||||
timeout: 5 * 60 * 1000
|
||||
} : undefined,
|
||||
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
|
||||
// {
|
||||
// name: "firefox",
|
||||
// use: { ...devices["Desktop Firefox"] },
|
||||
// },
|
||||
|
||||
// {
|
||||
// name: "webkit",
|
||||
// use: { ...devices["Desktop Safari"] },
|
||||
// },
|
||||
|
||||
// Uncomment for mobile browsers support
|
||||
/* {
|
||||
name: 'Mobile Chrome',
|
||||
use: { ...devices['Pixel 5'] },
|
||||
},
|
||||
{
|
||||
name: 'Mobile Safari',
|
||||
use: { ...devices['iPhone 12'] },
|
||||
}, */
|
||||
|
||||
// Uncomment for branded browsers
|
||||
/* {
|
||||
name: 'Microsoft Edge',
|
||||
use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
||||
},
|
||||
{
|
||||
name: 'Google Chrome',
|
||||
use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
||||
} */
|
||||
],
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
@@ -79,7 +79,7 @@ test("Tabs are restored in right order", async ({ page, context }) => {
|
||||
|
||||
// Refresh the page and check the order.
|
||||
await app.goto( { preserveTabs: true });
|
||||
await expect(app.getTab(0)).toContainText("Code notes");
|
||||
await expect(app.getTab(0)).toContainText("Code notes", { timeout: 15_000 });
|
||||
await expect(app.getTab(1)).toContainText("Text notes");
|
||||
await expect(app.getTab(2)).toContainText("Mermaid");
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
TRILIUM_ENV=dev
|
||||
TRILIUM_DATA_DIR=./apps/server/spec/db
|
||||
TRILIUM_RESOURCE_DIR=./apps/server/dist
|
||||
TRILIUM_PUBLIC_SERVER=http://localhost:4200
|
||||
TRILIUM_PORT=8086
|
||||
TRILIUM_INTEGRATION_TEST=edit
|
||||
@@ -1,3 +0,0 @@
|
||||
TRILIUM_ENV=dev
|
||||
TRILIUM_RESOURCE_DIR=./apps/server/dist
|
||||
TRILIUM_PUBLIC_SERVER=http://localhost:4200
|
||||
@@ -1,4 +0,0 @@
|
||||
TRILIUM_ENV=dev
|
||||
TRILIUM_DATA_DIR=./apps/server/data
|
||||
TRILIUM_RESOURCE_DIR=./apps/server/dist
|
||||
TRILIUM_PUBLIC_SERVER=http://localhost:4200
|
||||
@@ -1,3 +0,0 @@
|
||||
TRILIUM_ENV=production
|
||||
TRILIUM_DATA_DIR=./apps/server/data
|
||||
TRILIUM_PORT=8082
|
||||
@@ -1,4 +0,0 @@
|
||||
TRILIUM_ENV=dev
|
||||
TRILIUM_DATA_DIR=./spec/db
|
||||
TRILIUM_PUBLIC_SERVER=http://localhost:4200
|
||||
TRILIUM_INTEGRATION_TEST=memory
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:22.18.0-bullseye-slim AS builder
|
||||
FROM node:22.19.0-bullseye-slim AS builder
|
||||
RUN corepack enable
|
||||
|
||||
# Install native dependencies since we might be building cross-platform.
|
||||
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
|
||||
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||
|
||||
FROM node:22.18.0-bullseye-slim
|
||||
FROM node:22.19.0-bullseye-slim
|
||||
# Install only runtime dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:22.18.0-alpine AS builder
|
||||
FROM node:22.19.0-alpine AS builder
|
||||
RUN corepack enable
|
||||
|
||||
# Install native dependencies since we might be building cross-platform.
|
||||
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
|
||||
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||
|
||||
FROM node:22.18.0-alpine
|
||||
FROM node:22.19.0-alpine
|
||||
# Install runtime dependencies
|
||||
RUN apk add --no-cache su-exec shadow
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:22.18.0-alpine AS builder
|
||||
FROM node:22.19.0-alpine AS builder
|
||||
RUN corepack enable
|
||||
|
||||
# Install native dependencies since we might be building cross-platform.
|
||||
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
|
||||
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||
|
||||
FROM node:22.18.0-alpine
|
||||
FROM node:22.19.0-alpine
|
||||
# Create a non-root user with configurable UID/GID
|
||||
ARG USER=trilium
|
||||
ARG UID=1001
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:22.18.0-bullseye-slim AS builder
|
||||
FROM node:22.19.0-bullseye-slim AS builder
|
||||
RUN corepack enable
|
||||
|
||||
# Install native dependencies since we might be building cross-platform.
|
||||
@@ -7,7 +7,7 @@ COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
|
||||
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||
|
||||
FROM node:22.18.0-bullseye-slim
|
||||
FROM node:22.19.0-bullseye-slim
|
||||
# Create a non-root user with configurable UID/GID
|
||||
ARG USER=trilium
|
||||
ARG UID=1001
|
||||
|
||||
@@ -3,11 +3,38 @@
|
||||
"version": "0.98.1",
|
||||
"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",
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_ENV=development TRILIUM_ENV=dev TRILIUM_DATA_DIR=data TRILIUM_RESOURCE_DIR=src tsx watch --ignore '../client/node_modules/.vite-temp' ./src/main.ts",
|
||||
"start-no-dir": "cross-env NODE_ENV=development TRILIUM_ENV=dev TRILIUM_RESOURCE_DIR=src tsx watch --ignore '../client/node_modules/.vite-temp' ./src/main.ts",
|
||||
"edit-integration-db": "cross-env NODE_ENV=development TRILIUM_PORT=8086 TRILIUM_ENV=dev TRILIUM_DATA_DIR=spec/db TRILIUM_INTEGRATION_TEST=edit TRILIUM_RESOURCE_DIR=src tsx watch --ignore '../client/node_modules/.vite-temp' ./src/main.ts",
|
||||
"build": "tsx scripts/build.ts",
|
||||
"package": "pnpm build && bash scripts/build-server.sh",
|
||||
"test": "vitest",
|
||||
"test-build": "vitest --config vitest.build.config.mts",
|
||||
"start-prod": "cross-env TRILIUM_DATA_DIR=data pnpm start-prod-no-dir",
|
||||
"start-prod-no-dir": "pnpm build && cross-env TRILIUM_ENV=production TRILIUM_PORT=8082 node dist/main.cjs",
|
||||
"circular-deps": "dpdm -T src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular",
|
||||
"docker-build-debian": "pnpm build && docker build . -t triliumnext-debian -f Dockerfile",
|
||||
"docker-build-alpine": "pnpm build && docker build . -t triliumnext-alpine -f Dockerfile.alpine",
|
||||
"docker-build-rootless-debian": "pnpm build && docker build . -t triliumnext-rootless-debian -f Dockerfile.rootless",
|
||||
"docker-build-rootless-alpine": "pnpm build && docker build . -t triliumnext-rootless-alpine -f Dockerfile.alpine.rootless",
|
||||
"docker-start-debian": "pnpm docker-build-debian && docker run -p 8081:8080 triliumnext-debian",
|
||||
"docker-start-alpine": "pnpm docker-build-alpine && docker run -p 8081:8080 triliumnext-alpine",
|
||||
"docker-start-rootless-debian": "pnpm docker-build-rootless-debian && docker run -p 8081:8080 triliumnext-rootless-debian",
|
||||
"docker-start-rootless-alpine": "pnpm docker-build-rootless-alpine && docker run -p 8081:8080 triliumnext-rootless-alpine"
|
||||
},
|
||||
"dependencies": {
|
||||
"better-sqlite3": "12.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "0.60.0",
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@electron/remote": "2.1.3",
|
||||
"@preact/preset-vite": "2.10.2",
|
||||
"@triliumnext/commons": "workspace:*",
|
||||
"@triliumnext/express-partial-content": "workspace:*",
|
||||
"@triliumnext/turndown-plugin-gfm": "workspace:*",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/better-sqlite3": "7.6.13",
|
||||
"@types/cls-hooked": "4.3.9",
|
||||
@@ -38,16 +65,11 @@
|
||||
"@types/turndown": "5.0.5",
|
||||
"@types/ws": "8.18.1",
|
||||
"@types/xml2js": "0.4.14",
|
||||
"express-http-proxy": "2.1.1",
|
||||
"@anthropic-ai/sdk": "0.60.0",
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@triliumnext/commons": "workspace:*",
|
||||
"@triliumnext/express-partial-content": "workspace:*",
|
||||
"@triliumnext/turndown-plugin-gfm": "workspace:*",
|
||||
"archiver": "7.0.1",
|
||||
"async-mutex": "0.5.0",
|
||||
"axios": "1.11.0",
|
||||
"bindings": "1.5.0",
|
||||
"bootstrap": "5.3.8",
|
||||
"chardet": "2.1.0",
|
||||
"cheerio": "1.1.2",
|
||||
"chokidar": "4.0.3",
|
||||
@@ -55,7 +77,7 @@
|
||||
"compression": "1.8.1",
|
||||
"cookie-parser": "1.4.7",
|
||||
"csrf-csrf": "3.2.2",
|
||||
"dayjs": "1.11.14",
|
||||
"dayjs": "1.11.18",
|
||||
"debounce": "2.2.0",
|
||||
"debug": "4.4.1",
|
||||
"ejs": "3.1.10",
|
||||
@@ -64,6 +86,7 @@
|
||||
"electron-window-state": "5.0.3",
|
||||
"escape-html": "1.0.3",
|
||||
"express": "5.1.0",
|
||||
"express-http-proxy": "2.1.1",
|
||||
"express-openid-connect": "^2.17.1",
|
||||
"express-rate-limit": "8.0.1",
|
||||
"express-session": "1.18.2",
|
||||
@@ -105,272 +128,9 @@
|
||||
"tmp": "0.2.5",
|
||||
"turndown": "7.2.1",
|
||||
"unescape": "1.0.1",
|
||||
"vite": "^7.1.3",
|
||||
"ws": "8.18.3",
|
||||
"xml2js": "0.6.2",
|
||||
"yauzl": "3.2.0"
|
||||
},
|
||||
"nx": {
|
||||
"name": "server",
|
||||
"implicitDependencies": [
|
||||
"share-theme"
|
||||
],
|
||||
"targets": {
|
||||
"serve": {
|
||||
"executor": "@nx/js:node",
|
||||
"dependsOn": [
|
||||
{
|
||||
"projects": [
|
||||
"client"
|
||||
],
|
||||
"target": "serve"
|
||||
},
|
||||
"build-without-client"
|
||||
],
|
||||
"continuous": true,
|
||||
"options": {
|
||||
"buildTarget": "server:build-without-client:development",
|
||||
"runBuildTargetDependencies": false
|
||||
}
|
||||
},
|
||||
"serve-nodir": {
|
||||
"executor": "@nx/js:node",
|
||||
"dependsOn": [
|
||||
{
|
||||
"projects": [
|
||||
"client"
|
||||
],
|
||||
"target": "serve"
|
||||
},
|
||||
"build-without-client"
|
||||
],
|
||||
"continuous": true,
|
||||
"options": {
|
||||
"buildTarget": "server:build-without-client:development",
|
||||
"runBuildTargetDependencies": false
|
||||
}
|
||||
},
|
||||
"edit-integration-db": {
|
||||
"executor": "@nx/js:node",
|
||||
"dependsOn": [
|
||||
{
|
||||
"projects": [
|
||||
"client"
|
||||
],
|
||||
"target": "serve"
|
||||
},
|
||||
"build-without-client"
|
||||
],
|
||||
"continuous": true,
|
||||
"options": {
|
||||
"buildTarget": "server:build-without-client:development",
|
||||
"runBuildTargetDependencies": false
|
||||
}
|
||||
},
|
||||
"package": {
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"command": "bash apps/server/scripts/build-server.sh"
|
||||
},
|
||||
"start-prod": {
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"command": "node apps/server/dist/main.cjs"
|
||||
},
|
||||
"docker-build": {
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "{projectRoot}"
|
||||
},
|
||||
"executor": "nx:run-commands",
|
||||
"defaultConfiguration": "alpine",
|
||||
"configurations": {
|
||||
"debian": {
|
||||
"command": "docker build . -t triliumnext-debian -f Dockerfile"
|
||||
},
|
||||
"alpine": {
|
||||
"command": "docker build . -t triliumnext-alpine -f Dockerfile.alpine"
|
||||
},
|
||||
"rootless-debian": {
|
||||
"command": "docker build . -t triliumnext-rootless-debian -f Dockerfile.rootless"
|
||||
},
|
||||
"rootless-alpine": {
|
||||
"command": "docker build . -t triliumnext-rootless-alpine -f Dockerfile.alpine.rootless"
|
||||
}
|
||||
}
|
||||
},
|
||||
"docker-start": {
|
||||
"dependsOn": [
|
||||
"docker-build"
|
||||
],
|
||||
"executor": "nx:run-commands",
|
||||
"defaultConfiguration": "alpine",
|
||||
"configurations": {
|
||||
"debian": {
|
||||
"command": "docker run -p 8081:8080 triliumnext-debian"
|
||||
},
|
||||
"alpine": {
|
||||
"command": "docker run -p 8081:8080 triliumnext-alpine"
|
||||
},
|
||||
"rootless-debian": {
|
||||
"command": "docker run -p 8081:8080 triliumnext-rootless-debian"
|
||||
},
|
||||
"rootless-alpine": {
|
||||
"command": "docker run -p 8081:8080 triliumnext-rootless-alpine"
|
||||
}
|
||||
}
|
||||
},
|
||||
"build-without-client": {
|
||||
"executor": "@nx/esbuild:esbuild",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"main": "apps/server/src/main.ts",
|
||||
"outputPath": "apps/server/dist",
|
||||
"outputFileName": "main.js",
|
||||
"tsConfig": "apps/server/tsconfig.app.json",
|
||||
"platform": "node",
|
||||
"format": [
|
||||
"cjs"
|
||||
],
|
||||
"esbuildOptions": {
|
||||
"loader": {
|
||||
".css": "text",
|
||||
".ejs": "text"
|
||||
}
|
||||
},
|
||||
"declarationRootDir": "apps/server/src",
|
||||
"minify": false,
|
||||
"sourcemap": true,
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/src/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "packages/share-theme/src/templates",
|
||||
"output": "share-theme/templates"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"build": {
|
||||
"executor": "@nx/esbuild:esbuild",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"client:build"
|
||||
],
|
||||
"defaultConfiguration": "production",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"minify": true,
|
||||
"sourcemap": false
|
||||
},
|
||||
"development": {
|
||||
"minify": false,
|
||||
"sourcemap": true
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"main": "apps/server/src/main.ts",
|
||||
"outputPath": "apps/server/dist",
|
||||
"tsConfig": "apps/server/tsconfig.app.json",
|
||||
"platform": "node",
|
||||
"external": [
|
||||
"electron",
|
||||
"@electron/remote",
|
||||
"better-sqlite3",
|
||||
"./xhr-sync-worker.js"
|
||||
],
|
||||
"format": [
|
||||
"cjs"
|
||||
],
|
||||
"declarationRootDir": "apps/server/src",
|
||||
"thirdParty": true,
|
||||
"declaration": false,
|
||||
"esbuildOptions": {
|
||||
"splitting": false,
|
||||
"loader": {
|
||||
".css": "text",
|
||||
".ejs": "text"
|
||||
}
|
||||
},
|
||||
"additionalEntryPoints": [
|
||||
"apps/server/src/docker_healthcheck.ts"
|
||||
],
|
||||
"assets": [
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/src/assets",
|
||||
"output": "assets"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "packages/share-theme/src/templates",
|
||||
"output": "share-theme/templates"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/client/dist",
|
||||
"output": "public",
|
||||
"ignore": [
|
||||
"webpack-stats.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/node_modules/better-sqlite3",
|
||||
"output": "node_modules/better-sqlite3"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/node_modules/bindings",
|
||||
"output": "node_modules/bindings"
|
||||
},
|
||||
{
|
||||
"glob": "**/*",
|
||||
"input": "apps/server/node_modules/file-uri-to-path",
|
||||
"output": "node_modules/file-uri-to-path"
|
||||
},
|
||||
{
|
||||
"glob": "xhr-sync-worker.js",
|
||||
"input": "apps/server/node_modules/jsdom/lib/jsdom/living/xhr",
|
||||
"output": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"test-build": {
|
||||
"dependsOn": [
|
||||
"build"
|
||||
],
|
||||
"command": "vitest --config {projectRoot}/vitest.build.config.mts"
|
||||
},
|
||||
"circular-deps": {
|
||||
"command": "pnpx dpdm -T {projectRoot}/src/**/*.ts --tree=false --warning=false --skip-dynamic-imports=circular"
|
||||
}
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
"./src/*": "./src/*",
|
||||
".": {
|
||||
"development": "./src/main.ts",
|
||||
"types": "./dist/main.d.ts",
|
||||
"import": "./dist/main.js",
|
||||
"default": "./dist/main.js"
|
||||
}
|
||||
},
|
||||
"types": "./dist/main.d.ts",
|
||||
"module": "./dist/main.js",
|
||||
"main": "./dist/main.js"
|
||||
}
|
||||
}
|
||||
22
apps/server/scripts/build.ts
Normal file
22
apps/server/scripts/build.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import BuildHelper from "../../../scripts/build-utils";
|
||||
|
||||
const build = new BuildHelper("apps/server");
|
||||
|
||||
async function main() {
|
||||
await build.buildBackend([ "src/main.ts", "src/docker_healthcheck.ts" ])
|
||||
|
||||
// Copy assets
|
||||
build.copy("src/assets", "assets/");
|
||||
build.copy("/packages/share-theme/src/templates", "share-theme/templates/");
|
||||
|
||||
// Copy node modules dependencies
|
||||
build.copyNodeModules([ "better-sqlite3", "bindings", "file-uri-to-path" ]);
|
||||
build.copy("/node_modules/jsdom/lib/jsdom/living/xhr/xhr-sync-worker.js", "xhr-sync-worker.js");
|
||||
build.copy("/node_modules/ckeditor5/dist/ckeditor5-content.css", "ckeditor5-content.css");
|
||||
|
||||
// Integrate the client.
|
||||
build.triggerBuildAndCopyTo("apps/client", "public/");
|
||||
build.deleteFromOutput("public/webpack-stats.json");
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -30,5 +30,5 @@ describe("etapi/import", () => {
|
||||
.expect(201);
|
||||
expect(response.body.note.title).toStrictEqual("Journal");
|
||||
expect(response.body.branch.parentNoteId).toStrictEqual("root");
|
||||
});
|
||||
}, 10_000);
|
||||
});
|
||||
|
||||
@@ -60,16 +60,16 @@
|
||||
"add-new-label": "新增新標籤",
|
||||
"create-new-relation": "新增新關聯",
|
||||
"ribbon-tabs": "功能區分頁",
|
||||
"toggle-basic-properties": "顯示基本屬性",
|
||||
"toggle-file-properties": "顯示檔案屬性",
|
||||
"toggle-image-properties": "顯示圖像屬性",
|
||||
"toggle-owned-attributes": "顯示自有屬性",
|
||||
"toggle-inherited-attributes": "顯示繼承屬性",
|
||||
"toggle-promoted-attributes": "顯示升級的屬性",
|
||||
"toggle-link-map": "顯示連結地圖",
|
||||
"toggle-note-info": "顯示筆記資訊",
|
||||
"toggle-note-paths": "顯示筆記路徑",
|
||||
"toggle-similar-notes": "顯示相似筆記",
|
||||
"toggle-basic-properties": "切換基本屬性",
|
||||
"toggle-file-properties": "切換檔案屬性",
|
||||
"toggle-image-properties": "切換圖像屬性",
|
||||
"toggle-owned-attributes": "切換自有屬性",
|
||||
"toggle-inherited-attributes": "切換繼承屬性",
|
||||
"toggle-promoted-attributes": "切換升級的屬性",
|
||||
"toggle-link-map": "切換連結地圖",
|
||||
"toggle-note-info": "切換筆記資訊",
|
||||
"toggle-note-paths": "切換筆記路徑",
|
||||
"toggle-similar-notes": "切換相似筆記",
|
||||
"other": "其他",
|
||||
"toggle-right-pane": "切換右側面板的顯示,包括目錄和高亮",
|
||||
"print-active-note": "列印目前筆記",
|
||||
@@ -80,7 +80,7 @@
|
||||
"unhoist": "取消任何聚焦",
|
||||
"reload-frontend-app": "重新載入前端應用",
|
||||
"open-dev-tools": "打開開發者工具",
|
||||
"toggle-left-note-tree-panel": "顯示左側(筆記樹)面板",
|
||||
"toggle-left-note-tree-panel": "切換左側(筆記樹)面板",
|
||||
"toggle-full-screen": "切換全螢幕",
|
||||
"zoom-out": "縮小",
|
||||
"zoom-in": "放大",
|
||||
@@ -89,7 +89,7 @@
|
||||
"copy-without-formatting": "以純文字複製所選文字",
|
||||
"force-save-revision": "強制新增 / 儲存目前筆記的新版本",
|
||||
"show-help": "顯示用戶說明",
|
||||
"toggle-book-properties": "顯示集合屬性",
|
||||
"toggle-book-properties": "切換集合屬性",
|
||||
"back-in-note-history": "跳轉至歷史記錄中的上一個筆記",
|
||||
"forward-in-note-history": "跳轉至歷史記錄中的下一個筆記",
|
||||
"open-command-palette": "打開命令面板",
|
||||
@@ -100,8 +100,8 @@
|
||||
"clone-notes-to": "克隆所選的筆記至",
|
||||
"move-notes-to": "移動所選的筆記至",
|
||||
"show-cheatsheet": "顯示常用鍵盤快捷鍵",
|
||||
"find-in-text": "顯示搜尋面板",
|
||||
"toggle-classic-editor-toolbar": "顯示固定工具列編輯器的格式分頁",
|
||||
"find-in-text": "切換搜尋面板",
|
||||
"toggle-classic-editor-toolbar": "切換固定工具列編輯器的格式分頁",
|
||||
"export-as-pdf": "匯出目前筆記為 PDF",
|
||||
"toggle-zen-mode": "啟用 / 禁用禪模式(極簡界面以專注編輯)"
|
||||
},
|
||||
@@ -275,30 +275,30 @@
|
||||
"edit-read-only-note": "編輯唯讀筆記",
|
||||
"add-new-label": "新增標籤",
|
||||
"add-new-relation": "新增關聯",
|
||||
"toggle-ribbon-tab-classic-editor": "顯示功能區分頁:經典編輯器",
|
||||
"toggle-ribbon-tab-basic-properties": "顯示功能區分頁:基本屬性",
|
||||
"toggle-ribbon-tab-book-properties": "顯示功能區分頁:書籍屬性",
|
||||
"toggle-ribbon-tab-file-properties": "顯示功能區分頁:檔案屬性",
|
||||
"toggle-ribbon-tab-image-properties": "顯示功能區分頁:圖片屬性",
|
||||
"toggle-ribbon-tab-owned-attributes": "顯示功能區分頁:自有屬性",
|
||||
"toggle-ribbon-tab-inherited-attributes": "顯示功能區分頁:繼承屬性",
|
||||
"toggle-ribbon-tab-promoted-attributes": "顯示功能區分頁:升級屬性",
|
||||
"toggle-ribbon-tab-note-map": "顯示功能區分頁:筆記地圖",
|
||||
"toggle-ribbon-tab-note-info": "顯示功能區分頁:筆記資訊",
|
||||
"toggle-ribbon-tab-note-paths": "顯示功能區分頁:筆記路徑",
|
||||
"toggle-ribbon-tab-similar-notes": "顯示功能區分頁:相似筆記",
|
||||
"toggle-right-pane": "打開右側面板",
|
||||
"toggle-ribbon-tab-classic-editor": "切換功能區分頁:經典編輯器",
|
||||
"toggle-ribbon-tab-basic-properties": "切換功能區分頁:基本屬性",
|
||||
"toggle-ribbon-tab-book-properties": "切換功能區分頁:書籍屬性",
|
||||
"toggle-ribbon-tab-file-properties": "切換功能區分頁:檔案屬性",
|
||||
"toggle-ribbon-tab-image-properties": "切換功能區分頁:圖片屬性",
|
||||
"toggle-ribbon-tab-owned-attributes": "切換功能區分頁:自有屬性",
|
||||
"toggle-ribbon-tab-inherited-attributes": "切換功能區分頁:繼承屬性",
|
||||
"toggle-ribbon-tab-promoted-attributes": "切換功能區分頁:升級屬性",
|
||||
"toggle-ribbon-tab-note-map": "切換功能區分頁:筆記地圖",
|
||||
"toggle-ribbon-tab-note-info": "切換功能區分頁:筆記資訊",
|
||||
"toggle-ribbon-tab-note-paths": "切換功能區分頁:筆記路徑",
|
||||
"toggle-ribbon-tab-similar-notes": "切換功能區分頁:相似筆記",
|
||||
"toggle-right-pane": "切換右側面板",
|
||||
"print-active-note": "列印目前筆記",
|
||||
"export-active-note-as-pdf": "匯出目前筆記為 PDF",
|
||||
"open-note-externally": "於外部打開筆記",
|
||||
"render-active-note": "渲染目前筆記",
|
||||
"run-active-note": "執行目前筆記",
|
||||
"toggle-note-hoisting": "聚焦筆記",
|
||||
"toggle-note-hoisting": "切換聚焦筆記",
|
||||
"unhoist-note": "取消聚焦筆記",
|
||||
"reload-frontend-app": "重新載入前端程式",
|
||||
"open-developer-tools": "打開開發者工具",
|
||||
"find-in-text": "在文字中尋找",
|
||||
"toggle-left-pane": "打開左側面板",
|
||||
"toggle-left-pane": "切換左側面板",
|
||||
"toggle-full-screen": "切換全螢幕",
|
||||
"command-palette": "命令面板"
|
||||
},
|
||||
|
||||
@@ -3,7 +3,6 @@ import path from "path";
|
||||
import express from "express";
|
||||
import { getResourceDir, isDev } from "../services/utils.js";
|
||||
import type serveStatic from "serve-static";
|
||||
import proxy from "express-http-proxy";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOptions<express.Response<unknown, Record<string, unknown>>>) => {
|
||||
@@ -17,17 +16,22 @@ const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOp
|
||||
};
|
||||
|
||||
async function register(app: express.Application) {
|
||||
const srcRoot = path.join(__dirname, "..");
|
||||
const srcRoot = path.join(__dirname, "..", "..");
|
||||
const resourceDir = getResourceDir();
|
||||
|
||||
if (isDev) {
|
||||
const publicUrl = process.env.TRILIUM_PUBLIC_SERVER;
|
||||
if (!publicUrl) {
|
||||
throw new Error("Missing TRILIUM_PUBLIC_SERVER");
|
||||
}
|
||||
app.use("/" + assetUrlFragment + `/@fs`, proxy(publicUrl, {
|
||||
proxyReqPathResolver: (req) => "/" + assetUrlFragment + `/@fs` + req.url
|
||||
}));
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
const { createServer: createViteServer } = await import("vite");
|
||||
const vite = await createViteServer({
|
||||
server: { middlewareMode: true },
|
||||
appType: "custom",
|
||||
cacheDir: path.join(srcRoot, "../../.cache/vite"),
|
||||
base: `/${assetUrlFragment}/`,
|
||||
root: path.join(srcRoot, "../client")
|
||||
});
|
||||
app.use(`/${assetUrlFragment}/`, (req, res, next) => {
|
||||
req.url = `/${assetUrlFragment}` + req.url;
|
||||
vite.middlewares(req, res, next);
|
||||
});
|
||||
} else {
|
||||
const publicDir = path.join(resourceDir, "public");
|
||||
if (!existsSync(publicDir)) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import assetPath from "./asset_path.js";
|
||||
import { isDev } from "./utils.js";
|
||||
|
||||
export default assetPath + "/src";
|
||||
export default isDev ? assetPath : assetPath + "/src";
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import packageJson from "../../package.json" with { type: "json" };
|
||||
import { isDev } from "./utils";
|
||||
|
||||
/**
|
||||
* The URL prefix for assets (e.g. `assets/v1.2.3`).
|
||||
*/
|
||||
export const assetUrlFragment = `assets/v${packageJson.version}`;
|
||||
const assetPath = isDev ? `http://localhost:4200/${assetUrlFragment}` : assetUrlFragment;
|
||||
|
||||
/**
|
||||
* Similar to the {@link assetUrlFragment}, but on dev mode it also contains the `/src` suffix.
|
||||
*/
|
||||
const assetPath = isDev ? assetUrlFragment + "/src" : assetUrlFragment;
|
||||
|
||||
export default assetPath;
|
||||
|
||||
@@ -6,7 +6,7 @@ import path from "path";
|
||||
import mimeTypes from "mime-types";
|
||||
import mdService from "./markdown.js";
|
||||
import packageInfo from "../../../package.json" with { type: "json" };
|
||||
import { getContentDisposition, escapeHtml, getResourceDir } from "../utils.js";
|
||||
import { getContentDisposition, escapeHtml, getResourceDir, isDev } from "../utils.js";
|
||||
import protectedSessionService from "../protected_session.js";
|
||||
import sanitize from "sanitize-filename";
|
||||
import fs from "fs";
|
||||
@@ -21,7 +21,6 @@ import type AttributeMeta from "../meta/attribute_meta.js";
|
||||
import type BBranch from "../../becca/entities/bbranch.js";
|
||||
import type { Response } from "express";
|
||||
import type { NoteMetaFile } from "../meta/note_meta.js";
|
||||
import cssContent from "@triliumnext/ckeditor5/content.css";
|
||||
|
||||
type RewriteLinksFn = (content: string, noteMeta: NoteMeta) => string;
|
||||
|
||||
@@ -515,7 +514,11 @@ ${markdownContent}`;
|
||||
return;
|
||||
}
|
||||
|
||||
archive.append(cssContent, { name: cssMeta.dataFileName });
|
||||
const cssFile = isDev
|
||||
? path.join(__dirname, "../../../../../node_modules/ckeditor5/dist/ckeditor5-content.css")
|
||||
: path.join(getResourceDir(), "ckeditor5-content.css");
|
||||
|
||||
archive.append(fs.readFileSync(cssFile, "utf-8"), { name: cssMeta.dataFileName });
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import log from "./log.js";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
@@ -10,7 +9,7 @@ const ELECTRON_APP_ROOT_DIR = path.resolve(RESOURCE_DIR, "../..");
|
||||
const DB_INIT_DIR = path.resolve(RESOURCE_DIR, "db");
|
||||
|
||||
if (!fs.existsSync(DB_INIT_DIR)) {
|
||||
log.error(`Could not find DB initialization directory: ${DB_INIT_DIR}`);
|
||||
console.error(`Could not find DB initialization directory: ${DB_INIT_DIR}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,10 @@ import becca_loader from "../becca/becca_loader.js";
|
||||
import entity_changes from "./entity_changes.js";
|
||||
import config from "./config.js";
|
||||
|
||||
const dbOpts: Database.Options = {
|
||||
nativeBinding: process.env.BETTERSQLITE3_NATIVE_PATH || undefined
|
||||
};
|
||||
|
||||
let dbConnection: DatabaseType = buildDatabase();
|
||||
let statementCache: Record<string, Statement> = {};
|
||||
|
||||
@@ -23,15 +27,18 @@ function buildDatabase() {
|
||||
if (process.env.TRILIUM_INTEGRATION_TEST === "memory") {
|
||||
return buildIntegrationTestDatabase();
|
||||
} else if (process.env.TRILIUM_INTEGRATION_TEST === "memory-no-store") {
|
||||
return new Database(":memory:");
|
||||
return new Database(":memory:", dbOpts);
|
||||
}
|
||||
|
||||
return new Database(dataDir.DOCUMENT_PATH, { readonly: config.General.readOnly });
|
||||
return new Database(dataDir.DOCUMENT_PATH, {
|
||||
...dbOpts,
|
||||
readonly: config.General.readOnly
|
||||
});
|
||||
}
|
||||
|
||||
function buildIntegrationTestDatabase(dbPath?: string) {
|
||||
const dbBuffer = fs.readFileSync(dbPath ?? dataDir.DOCUMENT_PATH);
|
||||
return new Database(dbBuffer);
|
||||
return new Database(dbBuffer, dbOpts);
|
||||
}
|
||||
|
||||
function rebuildIntegrationTestDatabase(dbPath?: string) {
|
||||
|
||||
@@ -29,12 +29,21 @@ function getTrayIconPath() {
|
||||
name = "icon-color";
|
||||
}
|
||||
|
||||
return path.resolve(path.join(getResourceDir(), "assets", "images", "tray", `${name}.png`));
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return path.join(__dirname, "../../../desktop/src/assets/images/tray", `${name}.png`);
|
||||
} else {
|
||||
return path.resolve(path.join(getResourceDir(), "assets", "images", "tray", `${name}.png`));
|
||||
}
|
||||
}
|
||||
|
||||
function getIconPath(name: string) {
|
||||
const suffix = !isMac && electron.nativeTheme.shouldUseDarkColors ? "-inverted" : "";
|
||||
return path.resolve(path.join(getResourceDir(), "assets", "images", "tray", `${name}Template${suffix}.png`));
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return path.join(__dirname, "../../../desktop/src/assets/images/tray", `${name}Template${suffix}.png`);
|
||||
} else {
|
||||
return path.resolve(path.join(getResourceDir(), "assets", "images", "tray", `${name}Template${suffix}.png`));
|
||||
}
|
||||
}
|
||||
|
||||
function registerVisibilityListener(window: BrowserWindow) {
|
||||
|
||||
@@ -224,7 +224,7 @@ function getWindowExtraOpts() {
|
||||
}
|
||||
|
||||
async function configureWebContents(webContents: WebContents, spellcheckEnabled: boolean) {
|
||||
const remoteMain = (await import("@electron/remote/main/index.js")).default;
|
||||
const remoteMain = (await import("@electron/remote/main/index.js"));
|
||||
remoteMain.enable(webContents);
|
||||
|
||||
webContents.setWindowOpenHandler((details) => {
|
||||
@@ -257,7 +257,11 @@ async function configureWebContents(webContents: WebContents, spellcheckEnabled:
|
||||
}
|
||||
|
||||
function getIcon() {
|
||||
return path.join(RESOURCE_DIR, "../public/assets/icon.png");
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return path.join(__dirname, "../../../desktop/electron-forge/app-icon/png/256x256-dev.png");
|
||||
} else {
|
||||
return path.join(RESOURCE_DIR, "../public/assets/icon.png");
|
||||
}
|
||||
}
|
||||
|
||||
async function createSetupWindow() {
|
||||
|
||||
@@ -18,6 +18,7 @@ import utils, { isDev, safeExtractMessageAndStackFromError } from "../services/u
|
||||
import options from "../services/options.js";
|
||||
import { t } from "i18next";
|
||||
import ejs from "ejs";
|
||||
import { join } from "path";
|
||||
|
||||
function getSharedSubTreeRoot(note: SNote): { note?: SNote; branch?: SBranch } {
|
||||
if (note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) {
|
||||
@@ -401,7 +402,9 @@ function register(router: Router) {
|
||||
|
||||
function renderDefault(res: Response<any, Record<string, any>>, template: "page" | "404", opts: any = {}) {
|
||||
// Path is relative to apps/server/dist/assets/views
|
||||
const shareThemePath = `../../share-theme/templates/${template}.ejs`;
|
||||
const shareThemePath = process.env.NODE_ENV === "development"
|
||||
? join(__dirname, `../../../../packages/share-theme/src/templates/${template}.ejs`)
|
||||
: `../../share-theme/templates/${template}.ejs`;
|
||||
res.render(shareThemePath, opts);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@ import sql_init from "../services/sql_init.js";
|
||||
let dbConnection!: Database.Database;
|
||||
|
||||
sql_init.dbReady.then(() => {
|
||||
dbConnection = new Database(dataDir.DOCUMENT_PATH, { readonly: true });
|
||||
dbConnection = new Database(dataDir.DOCUMENT_PATH, {
|
||||
readonly: true,
|
||||
nativeBinding: process.env.BETTERSQLITE3_NATIVE_PATH || undefined
|
||||
});
|
||||
|
||||
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `SIGTERM`].forEach((eventType) => {
|
||||
process.on(eventType, () => {
|
||||
|
||||
@@ -10,6 +10,11 @@ export default defineConfig(() => ({
|
||||
globals: true,
|
||||
setupFiles: ["./spec/setup.ts"],
|
||||
environment: "node",
|
||||
env: {
|
||||
NODE_ENV: "development",
|
||||
TRILIUM_DATA_DIR: "./spec/db",
|
||||
TRILIUM_INTEGRATION_TEST: "memory"
|
||||
},
|
||||
include: ['{src,spec}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
exclude: [
|
||||
"spec/build-checks/**",
|
||||
|
||||
@@ -4,8 +4,8 @@ Landing page for Trilium Notes powered by [Svelte](https://github.com/sveltejs/c
|
||||
|
||||
## Developing
|
||||
|
||||
To run a dev server that will hot-reload changes: `pnpm nx run website:dev`
|
||||
To run a dev server that will hot-reload changes: `pnpm dev`
|
||||
|
||||
## Building
|
||||
|
||||
To create a production build: `pnpm nx run website:build`
|
||||
To create a production build: `pnpm build`
|
||||
|
||||
@@ -33,14 +33,5 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@inlang/paraglide-js": "^2.0.0"
|
||||
},
|
||||
"nx": {
|
||||
"targets": {
|
||||
"typecheck": {
|
||||
"dependsOn": [
|
||||
"build"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user