mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
Merge remote-tracking branch 'origin/develop' into feat/add-rootless-dockerfiles
This commit is contained in:
commit
a32f355193
@ -1,2 +1,7 @@
|
|||||||
_regroup
|
_regroup
|
||||||
_regroup_monorepo
|
_regroup_monorepo
|
||||||
|
|
||||||
|
# Asset copying respects .gitignore / .nxignore for some reason.
|
||||||
|
# See https://github.com/nrwl/nx/issues/20309
|
||||||
|
!dist
|
||||||
|
!node_modules
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -24,5 +24,7 @@
|
|||||||
},
|
},
|
||||||
"github-actions.workflows.pinned.workflows": [
|
"github-actions.workflows.pinned.workflows": [
|
||||||
".github/workflows/nightly.yml"
|
".github/workflows/nightly.yml"
|
||||||
]
|
],
|
||||||
|
"typescript.validate.enable": true,
|
||||||
|
"typescript.tsserver.experimental.enableProjectDiagnostics": true
|
||||||
}
|
}
|
@ -36,7 +36,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.52.0",
|
"@playwright/test": "1.52.0",
|
||||||
"@stylistic/eslint-plugin": "4.2.0",
|
"@stylistic/eslint-plugin": "4.4.0",
|
||||||
"@types/express": "5.0.1",
|
"@types/express": "5.0.1",
|
||||||
"@types/node": "22.15.21",
|
"@types/node": "22.15.21",
|
||||||
"@types/yargs": "17.0.33",
|
"@types/yargs": "17.0.33",
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
"@types/leaflet": "1.9.18",
|
"@types/leaflet": "1.9.18",
|
||||||
"@types/leaflet-gpx": "1.3.7",
|
"@types/leaflet-gpx": "1.3.7",
|
||||||
"@types/mark.js": "8.11.12",
|
"@types/mark.js": "8.11.12",
|
||||||
"@types/react": "19.1.4",
|
"@types/react": "19.1.5",
|
||||||
"@types/react-dom": "19.1.5",
|
"@types/react-dom": "19.1.5",
|
||||||
"copy-webpack-plugin": "13.0.0",
|
"copy-webpack-plugin": "13.0.0",
|
||||||
"happy-dom": "17.4.7",
|
"happy-dom": "17.4.7",
|
||||||
|
@ -1010,9 +1010,10 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
|
|||||||
font-size: var(--detail-font-size) !important;
|
font-size: var(--detail-font-size) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ck-mentions .ck-button.ck-on {
|
.ck-mentions {
|
||||||
background-color: var(--active-item-background-color) !important;
|
--ck-color-list-button-on-background: var(--active-item-background-color);
|
||||||
color: var(--active-item-text-color) !important;
|
--ck-color-list-button-on-background-focus: var(--ck-color-list-button-on-background);
|
||||||
|
--ck-color-list-button-on-text: var(--active-item-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ck-mentions .ck-button b {
|
.ck-mentions .ck-button b {
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
* Color scheme
|
* Color scheme
|
||||||
*/
|
*/
|
||||||
:root {
|
:root {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ⚠️ NOTICE: This theme is currently in the beta stage of development.
|
||||||
|
* The names and purposes of these CSS variables are subject to frequent changes.
|
||||||
|
*/
|
||||||
|
|
||||||
--theme-style: dark;
|
--theme-style: dark;
|
||||||
--native-titlebar-background: #00000000;
|
--native-titlebar-background: #00000000;
|
||||||
|
|
||||||
@ -89,6 +95,7 @@
|
|||||||
--menu-item-arrow-color: #ffffffa3;
|
--menu-item-arrow-color: #ffffffa3;
|
||||||
--menu-item-delimiter-color: #ffffff1c;
|
--menu-item-delimiter-color: #ffffff1c;
|
||||||
--menu-item-group-header-color: #ffffff91;
|
--menu-item-group-header-color: #ffffff91;
|
||||||
|
--menu-section-background-color: #fefefe08;
|
||||||
|
|
||||||
--modal-backdrop-color: #000;
|
--modal-backdrop-color: #000;
|
||||||
--modal-shadow-color: rgba(0, 0, 0, .5);
|
--modal-shadow-color: rgba(0, 0, 0, .5);
|
||||||
@ -236,6 +243,11 @@
|
|||||||
--help-code-background: #565656;
|
--help-code-background: #565656;
|
||||||
|
|
||||||
--ck-editor-popup-border-color: var(--modal-border-color);
|
--ck-editor-popup-border-color: var(--modal-border-color);
|
||||||
|
|
||||||
|
--ck-editor-toolbar-button-on-background: #ffffff3b;
|
||||||
|
--ck-editor-toolbar-button-on-color: white;
|
||||||
|
--ck-editor-toolbar-button-on-shadow: 1px 1px 2px rgba(0, 0, 0, .75);
|
||||||
|
--ck-editor-toolbar-dropdown-button-open-background: #ffffff14;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
* Color scheme
|
* Color scheme
|
||||||
*/
|
*/
|
||||||
:root {
|
:root {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ⚠️ NOTICE: This theme is currently in the beta stage of development.
|
||||||
|
* The names and purposes of these CSS variables are subject to frequent changes.
|
||||||
|
*/
|
||||||
|
|
||||||
--theme-style: light;
|
--theme-style: light;
|
||||||
--native-titlebar-background: #ffffff00;
|
--native-titlebar-background: #ffffff00;
|
||||||
|
|
||||||
@ -83,6 +89,7 @@
|
|||||||
--menu-item-arrow-color: #00000080;
|
--menu-item-arrow-color: #00000080;
|
||||||
--menu-item-delimiter-color: #00000030;
|
--menu-item-delimiter-color: #00000030;
|
||||||
--menu-item-group-header-color: #00000061;
|
--menu-item-group-header-color: #00000061;
|
||||||
|
--menu-section-background-color: #00000006;
|
||||||
|
|
||||||
--modal-backdrop-color: #7c7c7c;
|
--modal-backdrop-color: #7c7c7c;
|
||||||
--modal-shadow-color: #00000033;
|
--modal-shadow-color: #00000033;
|
||||||
@ -236,4 +243,9 @@
|
|||||||
--help-code-background: #d7d5d5;
|
--help-code-background: #d7d5d5;
|
||||||
|
|
||||||
--ck-editor-popup-border-color: var(--dropdown-border-color);
|
--ck-editor-popup-border-color: var(--dropdown-border-color);
|
||||||
|
--ck-editor-toolbar-button-on-background: #00000030;
|
||||||
|
--ck-editor-toolbar-button-on-color: black;
|
||||||
|
--ck-editor-toolbar-button-on-shadow: none;
|
||||||
|
--ck-editor-toolbar-dropdown-button-open-background: #0000000f;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,8 @@ body.mobile .dropdown-menu .dropdown-menu {
|
|||||||
border-radius: unset !important;
|
border-radius: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.desktop .dropdown-menu::before {
|
body.desktop .dropdown-menu::before,
|
||||||
|
:root .ck.ck-dropdown__panel::before {
|
||||||
content: "";
|
content: "";
|
||||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||||
border-radius: var(--dropdown-border-radius);
|
border-radius: var(--dropdown-border-radius);
|
||||||
|
@ -79,7 +79,7 @@ button.btn.btn-success kbd {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
:root .icon-action:not(.global-menu-button),
|
:root .icon-action:not(.global-menu-button),
|
||||||
:root .tn-tool-button,
|
:root .btn.tn-tool-button,
|
||||||
:root .btn-group .tn-tool-button:not(:last-child),
|
:root .btn-group .tn-tool-button:not(:last-child),
|
||||||
:root .btn-group .tn-tool-button:last-child {
|
:root .btn-group .tn-tool-button:last-child {
|
||||||
width: var(--icon-button-size);
|
width: var(--icon-button-size);
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
* Toolbar
|
* Toolbar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.ck.ck-toolbar {
|
.ck.ck-toolbar,
|
||||||
|
.ck.ck-block-toolbar-button {
|
||||||
--ck-color-toolbar-background: transparent;
|
--ck-color-toolbar-background: transparent;
|
||||||
|
|
||||||
--ck-color-button-default-background: transparent;
|
--ck-color-button-default-background: transparent;
|
||||||
@ -19,19 +20,62 @@
|
|||||||
|
|
||||||
--ck-color-button-on-background: transparent;
|
--ck-color-button-on-background: transparent;
|
||||||
--ck-color-button-on-hover-background: var(--hover-item-background-color);
|
--ck-color-button-on-hover-background: var(--hover-item-background-color);
|
||||||
|
--ck-color-button-default-active-background: var(--hover-item-background-color);
|
||||||
|
|
||||||
--ck-focus-ring: 1px solid var(--input-focus-outline-color);
|
--ck-color-split-button-hover-background: var(--ck-editor-toolbar-dropdown-button-open-background);
|
||||||
|
|
||||||
|
--ck-focus-ring: 1px solid transparent;
|
||||||
--ck-color-focus-border: var(--input-focus-outline-color);
|
--ck-color-focus-border: var(--input-focus-outline-color);
|
||||||
--ck-focus-outer-shadow: none;
|
--ck-focus-outer-shadow: none;
|
||||||
|
--ck-focus-disabled-outer-shadow: none;
|
||||||
|
|
||||||
--ck-border-radius: 6px;
|
--ck-border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Toolbar button in on state */
|
||||||
|
.ck.ck-toolbar .ck-button.ck-on:not(.ck-dropdown__button):not(.ck-list-item-button):not(.ck-button_with-text) {
|
||||||
|
--ck-color-button-on-background: var(--ck-editor-toolbar-button-on-background);
|
||||||
|
--ck-color-button-on-color: var(--ck-editor-toolbar-button-on-color);
|
||||||
|
box-shadow: var(--ck-editor-toolbar-button-on-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toolbar button with its dropdown open */
|
||||||
|
.ck.ck-toolbar .ck-button.ck-dropdown__button {
|
||||||
|
--ck-color-button-on-background: var(--ck-editor-toolbar-dropdown-button-open-background);
|
||||||
|
--ck-color-button-on-color: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The toolbar show / hide button for the current text block */
|
||||||
|
.ck.ck-block-toolbar-button {
|
||||||
|
--ck-color-button-on-background: transparent;
|
||||||
|
--ck-color-button-on-color: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root .ck.ck-toolbar .ck-button:not(.ck-disabled):active,
|
||||||
|
.ck.ck-block-toolbar-button:active {
|
||||||
|
background-color: var(--hover-item-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ck.ck-toolbar .ck-button:active:not(.ck-list-item-button):not(.ck-button_with-text):not(.ck-disabled) svg:not(.ck-dropdown__arrow),
|
||||||
|
.ck.ck-block-toolbar-button:active svg {
|
||||||
|
transform: scale(.8);
|
||||||
|
}
|
||||||
|
|
||||||
/* Disabled button */
|
/* Disabled button */
|
||||||
:root .classic-toolbar-widget .ck.ck-button.ck-disabled {
|
:root .classic-toolbar-widget .ck.ck-button.ck-disabled {
|
||||||
opacity: .75;
|
opacity: .75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Focus visible */
|
||||||
|
.ck.ck-toolbar .ck-button:focus-visible {
|
||||||
|
--ck-focus-ring: 1px solid var(--input-focus-outline-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the border from hovered split arrow button */
|
||||||
|
.ck.ck-splitbutton:hover > .ck-splitbutton__arrow:not(.ck-disabled)::after {
|
||||||
|
visibility: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dropdowns
|
* Dropdowns
|
||||||
*/
|
*/
|
||||||
@ -49,16 +93,61 @@
|
|||||||
border: 1px solid var(--ck-editor-popup-border-color) !important;
|
border: 1px solid var(--ck-editor-popup-border-color) !important;
|
||||||
border-radius: var(--dropdown-border-radius) !important;
|
border-radius: var(--dropdown-border-radius) !important;
|
||||||
background: var(--menu-background-color) !important;
|
background: var(--menu-background-color) !important;
|
||||||
backdrop-filter: var(--dropdown-backdrop-filter);
|
|
||||||
padding: var(--ck-editor-popup-padding);
|
padding: var(--ck-editor-popup-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Backdrop blur pseudo-element
|
||||||
|
*
|
||||||
|
* Since .ck-balloon-panel already uses the :after and :before pseudo-elements, there is no other
|
||||||
|
* option than using a :before on the children element to apply the backdrop blur.
|
||||||
|
* This pseudoelement will overflow and cover the entire surface of .ck-balloon-panel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root .ck-balloon-panel > .ck-toolbar,
|
||||||
|
:root .ck-balloon-panel > .ck-balloon-rotator {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root .ck-balloon-panel > .ck-toolbar::before,
|
||||||
|
:root .ck-balloon-panel > .ck-balloon-rotator::before {
|
||||||
|
--negative-padding: calc(0px - var(--ck-editor-popup-padding)); /* Compensate the parent's padding */
|
||||||
|
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: var(--negative-padding);
|
||||||
|
right: var(--negative-padding);
|
||||||
|
bottom: var(--negative-padding);
|
||||||
|
left: var(--negative-padding);
|
||||||
|
border-radius: var(--dropdown-border-radius);
|
||||||
|
backdrop-filter: var(--dropdown-backdrop-filter);
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root .ck.ck-dropdown__panel {
|
||||||
|
--ck-editor-popup-padding: var(--menu-padding-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown panel containing a toolbar */
|
||||||
|
:root .ck.ck-dropdown__panel:has(>.ck-toolbar) {
|
||||||
|
--ck-editor-popup-padding: calc(var(--menu-padding-size) - var(--ck-spacing-small));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bulleted / number list toolbar */
|
||||||
|
.ck-list-styles-list {
|
||||||
|
--ck-spacing-large: var(--ck-spacing-small);
|
||||||
|
}
|
||||||
|
|
||||||
:root ul.ck.ck-list,
|
:root ul.ck.ck-list,
|
||||||
:root div.ck.ck-balloon-panel:not(.ck-tooltip) {
|
:root div.ck.ck-balloon-panel:not(.ck-tooltip) {
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root .ck.ck-list {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Tooltip */
|
/* Tooltip */
|
||||||
:root div.ck.ck-balloon-panel.ck-tooltip {
|
:root div.ck.ck-balloon-panel.ck-tooltip {
|
||||||
--ck-color-panel-background: var(--toast-background); /* Arrow */
|
--ck-color-panel-background: var(--toast-background); /* Arrow */
|
||||||
@ -81,6 +170,15 @@
|
|||||||
box-shadow: unset;
|
box-shadow: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root .ck.ck-list__item {
|
||||||
|
min-width: 10em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Item with icon */
|
||||||
|
:root .ck.ck-button_with-text svg:first-child {
|
||||||
|
color: var(--menu-item-icon-color);
|
||||||
|
}
|
||||||
|
|
||||||
/* Checked list item */
|
/* Checked list item */
|
||||||
|
|
||||||
:root ul.ck.ck-list button.ck-button:hover,
|
:root ul.ck.ck-list button.ck-button:hover,
|
||||||
@ -91,6 +189,18 @@
|
|||||||
color: var(--hover-item-color);
|
color: var(--hover-item-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* List item checkmark container */
|
||||||
|
|
||||||
|
:root .ck.ck-list-item-button .ck-list-item-button__check-holder {
|
||||||
|
margin-inline-start: var(--ck-spacing-small);
|
||||||
|
margin-inline-end: var(--menu-padding-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
:root .ck.ck-list-item-button .ck-list-item-button__check-holder svg {
|
||||||
|
transform: scale(1.2);
|
||||||
|
color: var(--menu-item-icon-color);
|
||||||
|
}
|
||||||
|
|
||||||
/* Separator */
|
/* Separator */
|
||||||
:root .ck .ck-list__separator {
|
:root .ck .ck-list__separator {
|
||||||
margin: .5em 0;
|
margin: .5em 0;
|
||||||
@ -119,8 +229,8 @@
|
|||||||
bottom: var(--negative-padding);
|
bottom: var(--negative-padding);
|
||||||
left: var(--negative-padding);
|
left: var(--negative-padding);
|
||||||
right: var(--negative-padding);
|
right: var(--negative-padding);
|
||||||
border-top: 1px solid var(--ck-color-base-border);
|
border-top: 1px solid var(--ck-editor-popup-border-color);
|
||||||
background: rgba(0, 0, 0, .025);
|
background: var(--menu-section-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ck.ck-collapsible:last-child::before {
|
.ck.ck-collapsible:last-child::before {
|
||||||
@ -135,6 +245,24 @@
|
|||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Toolbar separators */
|
||||||
|
|
||||||
|
:root .ck.ck-toolbar .ck.ck-toolbar__separator {
|
||||||
|
background: transparent;
|
||||||
|
border-left: 1px solid var(--ck-color-toolbar-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The last separator of the toolbar */
|
||||||
|
:root .classic-toolbar-widget .ck.ck-toolbar__separator:last-of-type {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Heading dropdown */
|
||||||
|
|
||||||
|
:root .ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item {
|
||||||
|
min-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Font size dropdown */
|
/* Font size dropdown */
|
||||||
|
|
||||||
.ck-fontsize-option {
|
.ck-fontsize-option {
|
||||||
@ -152,6 +280,11 @@
|
|||||||
|
|
||||||
/* Color picker dropdown */
|
/* Color picker dropdown */
|
||||||
|
|
||||||
|
/* Color palette */
|
||||||
|
:root .ck.ck-color-selector .ck-color-grid {
|
||||||
|
--ck-editor-toolbar-button-on-shadow: none; /* Remove the shadow of the selected color button */
|
||||||
|
}
|
||||||
|
|
||||||
/* Color picker button */
|
/* Color picker button */
|
||||||
:root .ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker {
|
:root .ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker {
|
||||||
--ck-color-base-border: transparent; /* Remove the top border */
|
--ck-color-base-border: transparent; /* Remove the top border */
|
||||||
@ -160,8 +293,27 @@
|
|||||||
border-bottom-right-radius: var(--ck-border-radius);
|
border-bottom-right-radius: var(--ck-border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Current color checkmark */
|
||||||
|
:root .ck.ck-color-selector .ck-color-grid .ck-icon {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root .ck.ck-color-selector .ck-color-grid .ck-icon__fill {
|
||||||
|
fill: black !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Numbered list */
|
||||||
|
|
||||||
|
:root .ck.ck-list-properties_with-numbered-properties .ck.ck-list-styles-list {
|
||||||
|
min-width: 200px;
|
||||||
|
grid-template-columns: repeat(3, auto);
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-bottom: calc(var(--ck-spacing-medium) + var(--menu-padding-size));
|
||||||
|
}
|
||||||
|
|
||||||
/* Table dropdown */
|
/* Table dropdown */
|
||||||
|
|
||||||
|
/* Table rows / columns button grid container */
|
||||||
.ck-insert-table-dropdown__grid {
|
.ck-insert-table-dropdown__grid {
|
||||||
--ck-insert-table-dropdown-box-width: 16px;
|
--ck-insert-table-dropdown-box-width: 16px;
|
||||||
--ck-insert-table-dropdown-box-height: 16px;
|
--ck-insert-table-dropdown-box-height: 16px;
|
||||||
@ -170,6 +322,12 @@
|
|||||||
--ck-color-focus-border: var(--hover-item-text-color); /* Selected cell box border color */
|
--ck-color-focus-border: var(--hover-item-text-color); /* Selected cell box border color */
|
||||||
--ck-color-focus-outer-shadow: var(--hover-item-background-color); /* Selected cell box background color */
|
--ck-color-focus-outer-shadow: var(--hover-item-background-color); /* Selected cell box background color */
|
||||||
--ck-border-radius: 0;
|
--ck-border-radius: 0;
|
||||||
|
--ck-editor-toolbar-button-on-shadow: 1px 1px 1px rgba(0, 0, 0, .35);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Selected rows / column counter */
|
||||||
|
.ck.ck-insert-table-dropdown__label {
|
||||||
|
margin-top: var(--ck-spacing-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Admonitions dropdown */
|
/* Admonitions dropdown */
|
||||||
@ -215,6 +373,20 @@
|
|||||||
background: var(--hover-item-background-color);
|
background: var(--hover-item-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mention list (the autocompletion list for emojis, labels and relations) */
|
||||||
|
|
||||||
|
:root .ck-mentions {
|
||||||
|
--ck-color-list-button-on-background: var(--hover-item-background-color);
|
||||||
|
--ck-color-list-button-on-text: var(--hover-item-text-color);
|
||||||
|
--ck-color-list-button-hover-background: var(--ck-editor-toolbar-dropdown-button-open-background);
|
||||||
|
--ck-focus-ring: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "Keep on typing to see the emoji" placeholder */
|
||||||
|
#mention-list-item-id\:__EMOJI_HINT {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* EDITOR'S CONTENT
|
* EDITOR'S CONTENT
|
||||||
*/
|
*/
|
||||||
|
@ -110,6 +110,8 @@ export default class NoteTypeChooserDialog extends BasicWidget {
|
|||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (e.clickEvent) {
|
if (e.clickEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
} else {
|
||||||
|
this.modal.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"description": "Tool to compare content of Trilium databases. Useful for debugging sync problems.",
|
"description": "Tool to compare content of Trilium databases. Useful for debugging sync problems.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colors": "1.4.0",
|
"colors": "1.4.0",
|
||||||
"diff": "8.0.1",
|
"diff": "8.0.2",
|
||||||
"sqlite": "5.1.1",
|
"sqlite": "5.1.1",
|
||||||
"sqlite3": "5.1.7"
|
"sqlite3": "5.1.7"
|
||||||
},
|
},
|
||||||
|
@ -51,8 +51,8 @@ async function getMap(db: Database, query: string, params: any[] = []) {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFlattenedResults(db: Database, key: string, query: string, params: any[] = []) {
|
async function getFlattenedResults<T>(db: Database, key: string, query: string, params: any[] = []) {
|
||||||
const list = [];
|
const list: T[] = [];
|
||||||
const result = await getResults(db, query, params);
|
const result = await getResults(db, query, params);
|
||||||
|
|
||||||
for (const row of result) {
|
for (const row of result) {
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"jsc": {
|
|
||||||
"parser": {
|
|
||||||
"syntax": "typescript"
|
|
||||||
},
|
|
||||||
"target": "es2016"
|
|
||||||
}
|
|
||||||
}
|
|
@ -68,8 +68,8 @@ module.exports = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
rebuildConfig: {
|
rebuildConfig: {
|
||||||
force: true,
|
force: false,
|
||||||
extraModules: [ "better-sqlite3" ]
|
onlyModules: []
|
||||||
},
|
},
|
||||||
makers: [
|
makers: [
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Build your personal knowledge base with TriliumNext Notes",
|
"description": "Build your personal knowledge base with TriliumNext Notes",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "main.js",
|
"main": "main.cjs",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "2.1.2",
|
"@electron/remote": "2.1.2",
|
||||||
"better-sqlite3": "^11.9.1",
|
"better-sqlite3": "^11.9.1",
|
||||||
@ -17,7 +17,7 @@
|
|||||||
"@types/electron-squirrel-startup": "1.0.2",
|
"@types/electron-squirrel-startup": "1.0.2",
|
||||||
"@triliumnext/server": "workspace:*",
|
"@triliumnext/server": "workspace:*",
|
||||||
"copy-webpack-plugin": "13.0.0",
|
"copy-webpack-plugin": "13.0.0",
|
||||||
"electron": "36.2.1",
|
"electron": "36.3.1",
|
||||||
"@electron-forge/cli": "7.8.1",
|
"@electron-forge/cli": "7.8.1",
|
||||||
"@electron-forge/maker-deb": "7.8.1",
|
"@electron-forge/maker-deb": "7.8.1",
|
||||||
"@electron-forge/maker-dmg": "7.8.1",
|
"@electron-forge/maker-dmg": "7.8.1",
|
||||||
@ -29,7 +29,7 @@
|
|||||||
"prebuild-install": "^7.1.1"
|
"prebuild-install": "^7.1.1"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"forge": "../electron-forge/forge.config.cjs"
|
"forge": "./electron-forge/forge.config.cjs"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977",
|
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -44,6 +44,69 @@
|
|||||||
"nx": {
|
"nx": {
|
||||||
"name": "desktop",
|
"name": "desktop",
|
||||||
"targets": {
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/esbuild:esbuild",
|
||||||
|
"outputs": [
|
||||||
|
"{options.outputPath}"
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
],
|
||||||
|
"minify": true,
|
||||||
|
"thirdParty": true,
|
||||||
|
"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": "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": {
|
"rebuild-deps": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
@ -68,11 +131,11 @@
|
|||||||
"defaultConfiguration": "default",
|
"defaultConfiguration": "default",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"default": {
|
"default": {
|
||||||
"command": "electron .",
|
"command": "electron main.cjs",
|
||||||
"cwd": "{projectRoot}/dist"
|
"cwd": "{projectRoot}/dist"
|
||||||
},
|
},
|
||||||
"nixos": {
|
"nixos": {
|
||||||
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.js\"",
|
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"",
|
||||||
"cwd": ".",
|
"cwd": ".",
|
||||||
"forwardAllArgs": false
|
"forwardAllArgs": false
|
||||||
}
|
}
|
||||||
@ -86,11 +149,11 @@
|
|||||||
"defaultConfiguration": "default",
|
"defaultConfiguration": "default",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"default": {
|
"default": {
|
||||||
"command": "electron .",
|
"command": "electron main.cjs",
|
||||||
"cwd": "{projectRoot}/dist"
|
"cwd": "{projectRoot}/dist"
|
||||||
},
|
},
|
||||||
"nixos": {
|
"nixos": {
|
||||||
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.js\"",
|
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"",
|
||||||
"cwd": ".",
|
"cwd": ".",
|
||||||
"forwardAllArgs": false
|
"forwardAllArgs": false
|
||||||
}
|
}
|
||||||
@ -98,15 +161,24 @@
|
|||||||
},
|
},
|
||||||
"electron-forge:make": {
|
"electron-forge:make": {
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build"
|
"build",
|
||||||
|
"rebuild-deps"
|
||||||
],
|
],
|
||||||
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge make dist"
|
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge make dist"
|
||||||
},
|
},
|
||||||
"electron-forge:package": {
|
"electron-forge:package": {
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build"
|
"build",
|
||||||
|
"rebuild-deps"
|
||||||
],
|
],
|
||||||
"command": "pnpm -C apps/desktop exec cross-env NODE_INSTALLER=npm electron-forge package dist"
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ async function main() {
|
|||||||
await import("@triliumnext/server/src/main.js");
|
await import("@triliumnext/server/src/main.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function onReady() {
|
async function onReady() {
|
||||||
// electron.app.setAppUserModelId('com.github.zadam.trilium');
|
// electron.app.setAppUserModelId('com.github.zadam.trilium');
|
||||||
|
|
||||||
// if db is not initialized -> setup process
|
// if db is not initialized -> setup process
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../../tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"target": "ES2020",
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
|
"strict": false,
|
||||||
"types": [
|
"types": [
|
||||||
"node",
|
"node",
|
||||||
"express"
|
"express"
|
||||||
],
|
],
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo"
|
||||||
"verbatimModuleSyntax": false
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts"
|
"src/**/*.ts",
|
||||||
|
"../server/src/*.d.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"eslint.config.js",
|
"eslint.config.js",
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
|
||||||
const { join } = require('path');
|
|
||||||
|
|
||||||
const outputDir = join(__dirname, 'dist');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
output: {
|
|
||||||
path: outputDir,
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.css$/i,
|
|
||||||
type: "asset/source"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
target: [ "node" ],
|
|
||||||
plugins: [
|
|
||||||
new NxAppWebpackPlugin({
|
|
||||||
target: 'node',
|
|
||||||
compiler: 'tsc',
|
|
||||||
main: './src/electron-main.ts',
|
|
||||||
tsConfig: './tsconfig.app.json',
|
|
||||||
assets: ["./src/assets"],
|
|
||||||
optimization: false,
|
|
||||||
outputHashing: 'none',
|
|
||||||
generatePackageJson: false,
|
|
||||||
externalDependencies: [
|
|
||||||
"electron/main",
|
|
||||||
"@electron/remote/main",
|
|
||||||
"electron",
|
|
||||||
"@electron/remote",
|
|
||||||
"better-sqlite3"
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
new CopyPlugin({
|
|
||||||
patterns: [
|
|
||||||
{
|
|
||||||
from: "../client/dist",
|
|
||||||
to: join(outputDir, "public")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "../server/dist/node_modules",
|
|
||||||
to: join(outputDir, "node_modules")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "../server/dist/assets",
|
|
||||||
to: join(outputDir, "assets")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "node_modules/@electron/remote",
|
|
||||||
to: join(outputDir, "node_modules/@electron/remote")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "node_modules/prebuild-install",
|
|
||||||
to: join(outputDir, "node_modules/better-sqlite3/node_modules/prebuild-install")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "package.json",
|
|
||||||
to: join(outputDir, "package.json")
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
]
|
|
||||||
};
|
|
@ -3,12 +3,16 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.",
|
"description": "Desktop version of Trilium which imports the demo database (presented to new users at start-up) or the user guide and other documentation and saves the modifications for committing.",
|
||||||
|
"dependencies": {
|
||||||
|
"archiver": "7.0.1",
|
||||||
|
"better-sqlite3": "^11.9.1"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@triliumnext/client": "workspace:*",
|
"@triliumnext/client": "workspace:*",
|
||||||
"@triliumnext/desktop": "workspace:*",
|
"@triliumnext/desktop": "workspace:*",
|
||||||
"@types/fs-extra": "11.0.4",
|
"@types/fs-extra": "11.0.4",
|
||||||
"copy-webpack-plugin": "13.0.0",
|
"copy-webpack-plugin": "13.0.0",
|
||||||
"electron": "36.2.1",
|
"electron": "36.3.1",
|
||||||
"fs-extra": "11.3.0"
|
"fs-extra": "11.3.0"
|
||||||
},
|
},
|
||||||
"nx": {
|
"nx": {
|
||||||
@ -17,6 +21,59 @@
|
|||||||
"server"
|
"server"
|
||||||
],
|
],
|
||||||
"targets": {
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/esbuild:esbuild",
|
||||||
|
"outputs": [
|
||||||
|
"{options.outputPath}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"main": "apps/edit-docs/src/electron-docs-main.ts",
|
||||||
|
"outputPath": "apps/edit-docs/dist",
|
||||||
|
"outputFileName": "main.js",
|
||||||
|
"tsConfig": "apps/edit-docs/tsconfig.app.json",
|
||||||
|
"platform": "node",
|
||||||
|
"external": [
|
||||||
|
"electron",
|
||||||
|
"@electron/remote",
|
||||||
|
"better-sqlite3",
|
||||||
|
"./xhr-sync-worker.js"
|
||||||
|
],
|
||||||
|
"format": [
|
||||||
|
"cjs"
|
||||||
|
],
|
||||||
|
"minify": true,
|
||||||
|
"thirdParty": true,
|
||||||
|
"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": {
|
"rebuild-deps": {
|
||||||
"executor": "nx:run-commands",
|
"executor": "nx:run-commands",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
@ -41,19 +98,34 @@
|
|||||||
"defaultConfiguration": "default",
|
"defaultConfiguration": "default",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"default": {
|
"default": {
|
||||||
"command": "electron .",
|
"command": "electron main.cjs",
|
||||||
"cwd": "./apps/edit-docs/dist"
|
"cwd": "{projectRoot}/dist"
|
||||||
},
|
},
|
||||||
"nixos": {
|
"nixos": {
|
||||||
"command": "nix-shell -p electron_35 --run \"electron .\"",
|
"command": "nix-shell -p electron_35 --run \"electron {projectRoot}/dist/main.cjs\"",
|
||||||
"forwardAllArgs": false,
|
"cwd": ".",
|
||||||
"cwd": "./apps/edit-docs/dist"
|
"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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"archiver": "7.0.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,8 +13,9 @@ import TaskContext from "@triliumnext/server/src/services/task_context.js";
|
|||||||
import { deferred } from "@triliumnext/server/src/services/utils.js";
|
import { deferred } from "@triliumnext/server/src/services/utils.js";
|
||||||
import { parseNoteMetaFile } from "@triliumnext/server/src/services/in_app_help.js";
|
import { parseNoteMetaFile } from "@triliumnext/server/src/services/in_app_help.js";
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
|
import type NoteMeta from "@triliumnext/server/src/services/meta/note_meta.js";
|
||||||
import electron from "electron";
|
import electron from "electron";
|
||||||
import { onReady } from "@triliumnext/desktop/src/electron-main.js";
|
import windowService from "@triliumnext/server/src/services/window.js";
|
||||||
|
|
||||||
interface NoteMapping {
|
interface NoteMapping {
|
||||||
rootNoteId: string;
|
rootNoteId: string;
|
||||||
@ -55,12 +56,25 @@ const NOTE_MAPPINGS: NoteMapping[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
electron.app.on("ready", onReady);
|
const initializedPromise = deferred<void>();
|
||||||
|
electron.app.on("ready", async () => {
|
||||||
|
await initializedPromise;
|
||||||
|
|
||||||
|
console.log("Electron is ready!");
|
||||||
|
|
||||||
|
// Start the server.
|
||||||
|
await import("@triliumnext/server/src/main.js");
|
||||||
|
|
||||||
|
// Create the main window.
|
||||||
|
await windowService.createMainWindow(electron.app);
|
||||||
|
|
||||||
|
// Wait for the import to be finished and the application to be loaded before we listen to changes.
|
||||||
|
setTimeout(() => registerHandlers(), 10_000);
|
||||||
|
});
|
||||||
|
|
||||||
await initializeTranslations();
|
await initializeTranslations();
|
||||||
await initializeDatabase(true);
|
await initializeDatabase(true);
|
||||||
|
|
||||||
const initializedPromise = deferred<void>();
|
|
||||||
cls.init(async () => {
|
cls.init(async () => {
|
||||||
for (const mapping of NOTE_MAPPINGS) {
|
for (const mapping of NOTE_MAPPINGS) {
|
||||||
if (!mapping.exportOnly) {
|
if (!mapping.exportOnly) {
|
||||||
@ -70,11 +84,6 @@ async function main() {
|
|||||||
setOptions();
|
setOptions();
|
||||||
initializedPromise.resolve();
|
initializedPromise.resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
await initializedPromise;
|
|
||||||
|
|
||||||
// Wait for the import to be finished and the application to be loaded before we listen to changes.
|
|
||||||
setTimeout(() => registerHandlers(), 10_000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setOptions() {
|
async function setOptions() {
|
||||||
|
@ -40,4 +40,4 @@ async function exportData() {
|
|||||||
await exportToZipFile("root", "html", DEMO_ZIP_PATH);
|
await exportToZipFile("root", "html", DEMO_ZIP_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
await main();
|
main();
|
||||||
|
@ -1,16 +1,21 @@
|
|||||||
{
|
{
|
||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../../tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"target": "ES2020",
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
|
"strict": false,
|
||||||
"types": [
|
"types": [
|
||||||
"node"
|
"node",
|
||||||
|
"express"
|
||||||
],
|
],
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo",
|
"tsBuildInfoFile": "dist/tsconfig.app.tsbuildinfo"
|
||||||
"verbatimModuleSyntax": false
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*.ts"
|
"src/**/*.ts",
|
||||||
|
"../server/src/*.d.ts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"eslint.config.js",
|
"eslint.config.js",
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
|
||||||
const { join } = require('path');
|
|
||||||
|
|
||||||
const outputDir = join(__dirname, 'dist');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
output: {
|
|
||||||
path: join(__dirname, 'dist'),
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.css$/i,
|
|
||||||
type: "asset/source"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new NxAppWebpackPlugin({
|
|
||||||
target: 'node',
|
|
||||||
compiler: 'tsc',
|
|
||||||
main: './src/electron-docs-main.ts',
|
|
||||||
tsConfig: './tsconfig.app.json',
|
|
||||||
optimization: false,
|
|
||||||
outputHashing: 'none',
|
|
||||||
generatePackageJson: true,
|
|
||||||
externalDependencies: [
|
|
||||||
"electron/main",
|
|
||||||
"@electron/remote/main",
|
|
||||||
"electron",
|
|
||||||
"@electron/remote",
|
|
||||||
"better-sqlite3"
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
new CopyPlugin({
|
|
||||||
patterns: [
|
|
||||||
{
|
|
||||||
from: "../desktop/dist/node_modules",
|
|
||||||
to: join(outputDir, "node_modules")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "../desktop/dist/assets",
|
|
||||||
to: join(outputDir, "assets")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
from: "../desktop/dist/public",
|
|
||||||
to: join(outputDir, "public")
|
|
||||||
},
|
|
||||||
]
|
|
||||||
})
|
|
||||||
],
|
|
||||||
};
|
|
@ -26,7 +26,8 @@ export default defineConfig({
|
|||||||
command: 'pnpm server:start-prod',
|
command: 'pnpm server:start-prod',
|
||||||
url: baseURL,
|
url: baseURL,
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: !process.env.CI,
|
||||||
cwd: workspaceRoot
|
cwd: workspaceRoot,
|
||||||
|
timeout: 5 * 60 * 1000
|
||||||
} : undefined,
|
} : undefined,
|
||||||
projects: [
|
projects: [
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
TRILIUM_ENV=dev
|
TRILIUM_ENV=dev
|
||||||
TRILIUM_DATA_DIR=./apps/server/data
|
TRILIUM_DATA_DIR=./apps/server/data
|
||||||
|
TRILIUM_RESOURCE_DIR=./apps/server/dist
|
||||||
TRILIUM_PUBLIC_SERVER=http://localhost:4200
|
TRILIUM_PUBLIC_SERVER=http://localhost:4200
|
@ -1,13 +1,13 @@
|
|||||||
FROM node:22.15.1-bullseye-slim AS builder
|
FROM node:22.16.0-bullseye-slim AS builder
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
# Install native dependencies since we might be building cross-platform.
|
# Install native dependencies since we might be building cross-platform.
|
||||||
WORKDIR /usr/src/app/build
|
WORKDIR /usr/src/app/build
|
||||||
COPY ./dist/package.json ./dist/pnpm-lock.yaml ./docker/pnpm-workspace.yaml /usr/src/app/
|
COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
|
||||||
# We have to use --no-frozen-lockfile due to CKEditor patches
|
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||||
|
|
||||||
FROM node:22.15.1-bullseye-slim
|
FROM node:22.16.0-bullseye-slim
|
||||||
# Install only runtime dependencies
|
# Install only runtime dependencies
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
@ -25,4 +25,4 @@ FROM node:22.15.1-bullseye-slim
|
|||||||
# Configure container
|
# Configure container
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
CMD [ "sh", "./start-docker.sh" ]
|
CMD [ "sh", "./start-docker.sh" ]
|
||||||
HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.js
|
HEALTHCHECK --start-period=10s CMD exec gosu node node /usr/src/app/docker_healthcheck.cjs
|
@ -1,13 +1,13 @@
|
|||||||
FROM node:22.15.1-alpine AS builder
|
FROM node:22.16.0-alpine AS builder
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
# Install native dependencies since we might be building cross-platform.
|
# Install native dependencies since we might be building cross-platform.
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
COPY ./dist/package.json ./dist/pnpm-lock.yaml ./docker/pnpm-workspace.yaml /usr/src/app/
|
COPY ./docker/package.json ./docker/pnpm-workspace.yaml /usr/src/app/
|
||||||
# We have to use --no-frozen-lockfile due to CKEditor patches
|
# We have to use --no-frozen-lockfile due to CKEditor patches
|
||||||
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
RUN pnpm install --no-frozen-lockfile --prod && pnpm rebuild
|
||||||
|
|
||||||
FROM node:22.15.1-alpine
|
FROM node:22.16.0-alpine
|
||||||
# Install runtime dependencies
|
# Install runtime dependencies
|
||||||
RUN apk add --no-cache su-exec shadow
|
RUN apk add --no-cache su-exec shadow
|
||||||
|
|
||||||
@ -23,4 +23,4 @@ FROM node:22.15.1-alpine
|
|||||||
# Configure container
|
# Configure container
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
CMD [ "sh", "./start-docker.sh" ]
|
CMD [ "sh", "./start-docker.sh" ]
|
||||||
HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.js
|
HEALTHCHECK --start-period=10s CMD exec su-exec node node /usr/src/app/docker_healthcheck.cjs
|
5
apps/server/docker/package.json
Normal file
5
apps/server/docker/package.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"better-sqlite3": "11.10.0"
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@
|
|||||||
"@types/archiver": "6.0.3",
|
"@types/archiver": "6.0.3",
|
||||||
"@types/better-sqlite3": "7.6.13",
|
"@types/better-sqlite3": "7.6.13",
|
||||||
"@types/cls-hooked": "4.3.9",
|
"@types/cls-hooked": "4.3.9",
|
||||||
"@types/compression": "1.7.5",
|
"@types/compression": "1.8.0",
|
||||||
"@types/cookie-parser": "1.4.8",
|
"@types/cookie-parser": "1.4.8",
|
||||||
"@types/debounce": "1.2.4",
|
"@types/debounce": "1.2.4",
|
||||||
"@types/ejs": "3.1.5",
|
"@types/ejs": "3.1.5",
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"@types/ws": "8.18.1",
|
"@types/ws": "8.18.1",
|
||||||
"@types/xml2js": "0.4.14",
|
"@types/xml2js": "0.4.14",
|
||||||
"express-http-proxy": "2.1.1",
|
"express-http-proxy": "2.1.1",
|
||||||
"@anthropic-ai/sdk": "0.51.0",
|
"@anthropic-ai/sdk": "0.52.0",
|
||||||
"@braintree/sanitize-url": "7.1.1",
|
"@braintree/sanitize-url": "7.1.1",
|
||||||
"@triliumnext/commons": "workspace:*",
|
"@triliumnext/commons": "workspace:*",
|
||||||
"@triliumnext/express-partial-content": "workspace:*",
|
"@triliumnext/express-partial-content": "workspace:*",
|
||||||
@ -59,7 +59,7 @@
|
|||||||
"debounce": "2.2.0",
|
"debounce": "2.2.0",
|
||||||
"debug": "4.4.1",
|
"debug": "4.4.1",
|
||||||
"ejs": "3.1.10",
|
"ejs": "3.1.10",
|
||||||
"electron": "36.2.1",
|
"electron": "36.3.1",
|
||||||
"electron-debug": "4.1.0",
|
"electron-debug": "4.1.0",
|
||||||
"electron-window-state": "5.0.3",
|
"electron-window-state": "5.0.3",
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
@ -88,7 +88,7 @@
|
|||||||
"multer": "2.0.0",
|
"multer": "2.0.0",
|
||||||
"normalize-strings": "1.1.1",
|
"normalize-strings": "1.1.1",
|
||||||
"ollama": "0.5.15",
|
"ollama": "0.5.15",
|
||||||
"openai": "4.100.0",
|
"openai": "4.103.0",
|
||||||
"rand-token": "1.0.1",
|
"rand-token": "1.0.1",
|
||||||
"safe-compare": "1.1.4",
|
"safe-compare": "1.1.4",
|
||||||
"sanitize-filename": "1.6.3",
|
"sanitize-filename": "1.6.3",
|
||||||
@ -105,38 +105,21 @@
|
|||||||
"tmp": "0.2.3",
|
"tmp": "0.2.3",
|
||||||
"turndown": "7.2.0",
|
"turndown": "7.2.0",
|
||||||
"unescape": "1.0.1",
|
"unescape": "1.0.1",
|
||||||
"webpack": "5.99.9",
|
|
||||||
"ws": "8.18.2",
|
"ws": "8.18.2",
|
||||||
"xml2js": "0.6.2",
|
"xml2js": "0.6.2",
|
||||||
"yauzl": "3.2.0",
|
"yauzl": "3.2.0"
|
||||||
"copy-webpack-plugin": "13.0.0"
|
|
||||||
},
|
},
|
||||||
"nx": {
|
"nx": {
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"targets": {
|
"targets": {
|
||||||
"build": {
|
|
||||||
"dependsOn": [
|
|
||||||
"^build",
|
|
||||||
"client:build"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"serve": {
|
"serve": {
|
||||||
"executor": "@nx/js:node",
|
"executor": "@nx/js:node",
|
||||||
"defaultConfiguration": "development",
|
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build"
|
"build-without-client"
|
||||||
],
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"buildTarget": "server:build",
|
"buildTarget": "server:build-without-client:development",
|
||||||
"runBuildTargetDependencies": false
|
"runBuildTargetDependencies": false
|
||||||
},
|
|
||||||
"configurations": {
|
|
||||||
"development": {
|
|
||||||
"buildTarget": "server:build:development"
|
|
||||||
},
|
|
||||||
"production": {
|
|
||||||
"buildTarget": "server:build:production"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"package": {
|
"package": {
|
||||||
@ -149,7 +132,7 @@
|
|||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build"
|
"build"
|
||||||
],
|
],
|
||||||
"command": "node apps/server/dist/main.js"
|
"command": "node apps/server/dist/main.cjs"
|
||||||
},
|
},
|
||||||
"docker-build": {
|
"docker-build": {
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
@ -183,7 +166,118 @@
|
|||||||
"command": "docker run -p 8081:8080 triliumnext-alpine"
|
"command": "docker run -p 8081:8080 triliumnext-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"
|
||||||
|
],
|
||||||
|
"declarationRootDir": "apps/server/src"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"minify": false,
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "apps/server/src/assets",
|
||||||
|
"output": "assets"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/esbuild:esbuild",
|
||||||
|
"outputs": [
|
||||||
|
"{options.outputPath}"
|
||||||
|
],
|
||||||
|
"dependsOn": [
|
||||||
|
"^build",
|
||||||
|
"client:build"
|
||||||
|
],
|
||||||
|
"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",
|
||||||
|
"minify": true,
|
||||||
|
"thirdParty": true,
|
||||||
|
"esbuildOptions": {
|
||||||
|
"splitting": false,
|
||||||
|
"loader": {
|
||||||
|
".css": "text"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalEntryPoints": [
|
||||||
|
"apps/server/src/docker_healthcheck.ts"
|
||||||
|
],
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "apps/server/src/assets",
|
||||||
|
"output": "assets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"glob": "**/*",
|
||||||
|
"input": "apps/client/dist",
|
||||||
|
"output": "public"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"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"
|
||||||
}
|
}
|
@ -137,7 +137,7 @@ export default async function buildApp() {
|
|||||||
startScheduledCleanup();
|
startScheduledCleanup();
|
||||||
|
|
||||||
if (utils.isElectron) {
|
if (utils.isElectron) {
|
||||||
(await import("@electron/remote/main")).initialize();
|
(await import("@electron/remote/main/index.js")).initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="container login-page">
|
<div class="container login-page">
|
||||||
<div class="col-xs-12 col-sm-10 col-md-6 col-lg-4 col-xl-4 mx-auto pt-4">
|
<div class="col-xs-12 col-sm-10 col-md-6 col-lg-4 col-xl-4 mx-auto pt-4">
|
||||||
<img class="img-fluid d-block mx-auto" style="height: 8rem;" src="<%= assetPath %>/images/icon-color.svg" aria-hidden="true" draggable="false" >
|
<img class="img-fluid d-block mx-auto" style="height: 8rem;" src="<%= assetPathFragment %>/images/icon-color.svg" aria-hidden="true" draggable="false" >
|
||||||
<h1 class="text-center"><%= t("login.heading") %></h1>
|
<h1 class="text-center"><%= t("login.heading") %></h1>
|
||||||
|
|
||||||
<% if (ssoEnabled) { %>
|
<% if (ssoEnabled) { %>
|
||||||
|
@ -36,7 +36,7 @@ interface DateLimits {
|
|||||||
maxDate: string;
|
maxDate: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SimilarNote {
|
export interface SimilarNote {
|
||||||
score: number;
|
score: number;
|
||||||
notePath: string[];
|
notePath: string[];
|
||||||
noteId: string;
|
noteId: string;
|
||||||
|
@ -6,7 +6,7 @@ import etapiTokenService from "../services/etapi_tokens.js";
|
|||||||
import config from "../services/config.js";
|
import config from "../services/config.js";
|
||||||
import type { NextFunction, Request, RequestHandler, Response, Router } from "express";
|
import type { NextFunction, Request, RequestHandler, Response, Router } from "express";
|
||||||
import type { ValidatorMap } from "./etapi-interface.js";
|
import type { ValidatorMap } from "./etapi-interface.js";
|
||||||
import type { ApiRequestHandler } from "../routes/routes.js";
|
import type { ApiRequestHandler } from "../routes/route_api.js";
|
||||||
const GENERIC_CODE = "GENERIC";
|
const GENERIC_CODE = "GENERIC";
|
||||||
|
|
||||||
type HttpMethod = "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head";
|
type HttpMethod = "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head";
|
||||||
|
@ -116,7 +116,7 @@ function getLinkMap(req: Request) {
|
|||||||
}).notes;
|
}).notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const noteIds = new Set(unfilteredNotes.filter((note) => ignoreExcludeFromNoteMap || !note.isLabelTruthy("excludeFromNoteMap")).map((note) => note.noteId));
|
const noteIds = new Set<string>(unfilteredNotes.filter((note) => ignoreExcludeFromNoteMap || !note.isLabelTruthy("excludeFromNoteMap")).map((note) => note.noteId));
|
||||||
|
|
||||||
if (mapRootNote.type === "search") {
|
if (mapRootNote.type === "search") {
|
||||||
noteIds.delete(mapRootNote.noteId);
|
noteIds.delete(mapRootNote.noteId);
|
||||||
|
@ -118,7 +118,7 @@ function createNote(req: Request) {
|
|||||||
throw new ValidationError("Missing or incorrect type for target branch ID.");
|
throw new ValidationError("Missing or incorrect type for target branch ID.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const { note, branch } = noteService.createNewNoteWithTarget(target, targetBranchId, params);
|
const { note, branch } = noteService.createNewNoteWithTarget(target, String(targetBranchId), params);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
note,
|
note,
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { assetUrlFragment } from "../services/asset_path.js";
|
import { assetUrlFragment } from "../services/asset_path.js";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import { getResourceDir, isDev } from "../services/utils.js";
|
import { getResourceDir, isDev } from "../services/utils.js";
|
||||||
import type serveStatic from "serve-static";
|
import type serveStatic from "serve-static";
|
||||||
import proxy from "express-http-proxy";
|
import proxy from "express-http-proxy";
|
||||||
|
import { existsSync } from "fs";
|
||||||
|
|
||||||
const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOptions<express.Response<unknown, Record<string, unknown>>>) => {
|
const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOptions<express.Response<unknown, Record<string, unknown>>>) => {
|
||||||
if (!isDev) {
|
if (!isDev) {
|
||||||
@ -17,7 +17,7 @@ const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOp
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function register(app: express.Application) {
|
async function register(app: express.Application) {
|
||||||
const srcRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
const srcRoot = path.join(__dirname, "..");
|
||||||
const resourceDir = getResourceDir();
|
const resourceDir = getResourceDir();
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
@ -29,14 +29,19 @@ async function register(app: express.Application) {
|
|||||||
proxyReqPathResolver: (req) => "/" + assetUrlFragment + `/@fs` + req.url
|
proxyReqPathResolver: (req) => "/" + assetUrlFragment + `/@fs` + req.url
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
app.use(`/${assetUrlFragment}/src`, persistentCacheStatic(path.join(resourceDir, "public", "src")));
|
const publicDir = path.join(resourceDir, "public");
|
||||||
app.use(`/${assetUrlFragment}/stylesheets`, persistentCacheStatic(path.join(resourceDir, "public", "stylesheets")));
|
if (!existsSync(publicDir)) {
|
||||||
app.use(`/${assetUrlFragment}/libraries`, persistentCacheStatic(path.join(resourceDir, "public", "libraries")));
|
throw new Error("Public directory is missing at: " + path.resolve(publicDir));
|
||||||
app.use(`/${assetUrlFragment}/fonts`, persistentCacheStatic(path.join(resourceDir, "public", "fonts")));
|
}
|
||||||
app.use(`/${assetUrlFragment}/translations/`, persistentCacheStatic(path.join(resourceDir, "public", "translations")));
|
|
||||||
app.use(`/${assetUrlFragment}/images`, persistentCacheStatic(path.join(resourceDir, "assets", "images")));
|
app.use(`/${assetUrlFragment}/src`, persistentCacheStatic(path.join(publicDir, "src")));
|
||||||
app.use(`/node_modules/`, persistentCacheStatic(path.join(resourceDir, "public/node_modules")));
|
app.use(`/${assetUrlFragment}/stylesheets`, persistentCacheStatic(path.join(publicDir, "stylesheets")));
|
||||||
|
app.use(`/${assetUrlFragment}/libraries`, persistentCacheStatic(path.join(publicDir, "libraries")));
|
||||||
|
app.use(`/${assetUrlFragment}/fonts`, persistentCacheStatic(path.join(publicDir, "fonts")));
|
||||||
|
app.use(`/${assetUrlFragment}/translations/`, persistentCacheStatic(path.join(publicDir, "translations")));
|
||||||
|
app.use(`/node_modules/`, persistentCacheStatic(path.join(publicDir, "node_modules")));
|
||||||
}
|
}
|
||||||
|
app.use(`/${assetUrlFragment}/images`, persistentCacheStatic(path.join(resourceDir, "assets", "images")));
|
||||||
app.use(`/${assetUrlFragment}/doc_notes`, persistentCacheStatic(path.join(resourceDir, "assets", "doc_notes")));
|
app.use(`/${assetUrlFragment}/doc_notes`, persistentCacheStatic(path.join(resourceDir, "assets", "doc_notes")));
|
||||||
app.use(`/assets/vX/fonts`, express.static(path.join(srcRoot, "public/fonts")));
|
app.use(`/assets/vX/fonts`, express.static(path.join(srcRoot, "public/fonts")));
|
||||||
app.use(`/assets/vX/images`, express.static(path.join(srcRoot, "..", "images")));
|
app.use(`/assets/vX/images`, express.static(path.join(srcRoot, "..", "images")));
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ipcMain } from "electron";
|
import electron from "electron";
|
||||||
|
|
||||||
interface Response {
|
interface Response {
|
||||||
statusCode: number;
|
statusCode: number;
|
||||||
@ -10,7 +10,7 @@ interface Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init(app: Express.Application) {
|
function init(app: Express.Application) {
|
||||||
ipcMain.on("server-request", (event, arg) => {
|
electron.ipcMain.on("server-request", (event, arg) => {
|
||||||
const req = {
|
const req = {
|
||||||
url: arg.url,
|
url: arg.url,
|
||||||
method: arg.method,
|
method: arg.method,
|
||||||
@ -50,7 +50,7 @@ function init(app: Express.Application) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return app._router.handle(req, res, () => {});
|
return (app as any)._router.handle(req, res, () => {});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import optionService from "../services/options.js";
|
|||||||
import myScryptService from "../services/encryption/my_scrypt.js";
|
import myScryptService from "../services/encryption/my_scrypt.js";
|
||||||
import log from "../services/log.js";
|
import log from "../services/log.js";
|
||||||
import passwordService from "../services/encryption/password.js";
|
import passwordService from "../services/encryption/password.js";
|
||||||
import assetPath from "../services/asset_path.js";
|
import assetPath, { assetUrlFragment } from "../services/asset_path.js";
|
||||||
import appPath from "../services/app_path.js";
|
import appPath from "../services/app_path.js";
|
||||||
import ValidationError from "../errors/validation_error.js";
|
import ValidationError from "../errors/validation_error.js";
|
||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
@ -13,12 +13,14 @@ import openID from '../services/open_id.js';
|
|||||||
import openIDEncryption from '../services/encryption/open_id_encryption.js';
|
import openIDEncryption from '../services/encryption/open_id_encryption.js';
|
||||||
|
|
||||||
function loginPage(req: Request, res: Response) {
|
function loginPage(req: Request, res: Response) {
|
||||||
|
// Login page is triggered twice. Once here, and another time if the password is failed.
|
||||||
res.render('login', {
|
res.render('login', {
|
||||||
wrongPassword: false,
|
wrongPassword: false,
|
||||||
wrongTotp: false,
|
wrongTotp: false,
|
||||||
totpEnabled: totp.isTotpEnabled(),
|
totpEnabled: totp.isTotpEnabled(),
|
||||||
ssoEnabled: openID.isOpenIDEnabled(),
|
ssoEnabled: openID.isOpenIDEnabled(),
|
||||||
assetPath: assetPath,
|
assetPath: assetPath,
|
||||||
|
assetPathFragment: assetUrlFragment,
|
||||||
appPath: appPath,
|
appPath: appPath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -169,6 +171,7 @@ function sendLoginError(req: Request, res: Response, errorType: 'password' | 'to
|
|||||||
totpEnabled: totp.isTotpEnabled(),
|
totpEnabled: totp.isTotpEnabled(),
|
||||||
ssoEnabled: openID.isOpenIDEnabled(),
|
ssoEnabled: openID.isOpenIDEnabled(),
|
||||||
assetPath: assetPath,
|
assetPath: assetPath,
|
||||||
|
assetPathFragment: assetUrlFragment,
|
||||||
appPath: appPath,
|
appPath: appPath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import express from "express";
|
import express, { type RequestHandler } from "express";
|
||||||
import multer from "multer";
|
import multer from "multer";
|
||||||
import log from "../services/log.js";
|
import log from "../services/log.js";
|
||||||
import cls from "../services/cls.js";
|
import cls from "../services/cls.js";
|
||||||
@ -166,7 +166,7 @@ function handleException(e: unknown | Error, method: HttpMethod, path: string, r
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createUploadMiddleware() {
|
export function createUploadMiddleware(): RequestHandler {
|
||||||
const multerOptions: multer.Options = {
|
const multerOptions: multer.Options = {
|
||||||
fileFilter: (req: express.Request, file, cb) => {
|
fileFilter: (req: express.Request, file, cb) => {
|
||||||
// UTF-8 file names are not well decoded by multer/busboy, so we handle the conversion on our side.
|
// UTF-8 file names are not well decoded by multer/busboy, so we handle the conversion on our side.
|
||||||
|
@ -3,6 +3,7 @@ import session, { Store } from "express-session";
|
|||||||
import sessionSecret from "../services/session_secret.js";
|
import sessionSecret from "../services/session_secret.js";
|
||||||
import config from "../services/config.js";
|
import config from "../services/config.js";
|
||||||
import log from "../services/log.js";
|
import log from "../services/log.js";
|
||||||
|
import type express from "express";
|
||||||
|
|
||||||
class SQLiteSessionStore extends Store {
|
class SQLiteSessionStore extends Store {
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ class SQLiteSessionStore extends Store {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sessionParser = session({
|
const sessionParser: express.RequestHandler = session({
|
||||||
secret: sessionSecret,
|
secret: sessionSecret,
|
||||||
resave: false, // true forces the session to be saved back to the session store, even if the session was never modified during the request.
|
resave: false, // true forces the session to be saved back to the session store, even if the session was never modified during the request.
|
||||||
saveUninitialized: false, // true forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified.
|
saveUninitialized: false, // true forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import BUILTIN_ATTRIBUTES from "./builtin_attributes.js";
|
import BUILTIN_ATTRIBUTES from "./builtin_attributes.js";
|
||||||
import fs from "fs-extra";
|
import fs from "fs";
|
||||||
import dataDir from "./data_dir.js";
|
import dataDir from "./data_dir.js";
|
||||||
import dateUtils from "./date_utils.js";
|
import dateUtils from "./date_utils.js";
|
||||||
import Database from "better-sqlite3";
|
import Database from "better-sqlite3";
|
||||||
|
@ -224,14 +224,14 @@ export interface Api {
|
|||||||
* @param date in YYYY-MM-DD format
|
* @param date in YYYY-MM-DD format
|
||||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||||
*/
|
*/
|
||||||
getDayNote(date: string, rootNote?: BNote): Promise<BNote | null>;
|
getDayNote(date: string, rootNote?: BNote): BNote | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns today's day note. If such note doesn't exist, it is created.
|
* Returns today's day note. If such note doesn't exist, it is created.
|
||||||
*
|
*
|
||||||
* @param rootNote specify calendar root note, normally leave empty to use the default calendar
|
* @param rootNote specify calendar root note, normally leave empty to use the default calendar
|
||||||
*/
|
*/
|
||||||
getTodayNote(rootNote?: BNote): Promise<BNote | null>;
|
getTodayNote(rootNote?: BNote): BNote | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns note for the first date of the week of the given date.
|
* Returns note for the first date of the week of the given date.
|
||||||
@ -239,7 +239,7 @@ export interface Api {
|
|||||||
* @param date in YYYY-MM-DD format
|
* @param date in YYYY-MM-DD format
|
||||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||||
*/
|
*/
|
||||||
getWeekFirstDayNote(date: string, rootNote: BNote): Promise<BNote | null>;
|
getWeekFirstDayNote(date: string, rootNote: BNote): BNote | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns week note for given date. If such a note doesn't exist, it is created.
|
* Returns week note for given date. If such a note doesn't exist, it is created.
|
||||||
@ -247,7 +247,7 @@ export interface Api {
|
|||||||
* @param date in YYYY-MM-DD format
|
* @param date in YYYY-MM-DD format
|
||||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||||
*/
|
*/
|
||||||
getWeekNote(date: string, rootNote: BNote): Promise<BNote | null>;
|
getWeekNote(date: string, rootNote: BNote): BNote | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns month note for given date. If such a note doesn't exist, it is created.
|
* Returns month note for given date. If such a note doesn't exist, it is created.
|
||||||
@ -255,7 +255,7 @@ export interface Api {
|
|||||||
* @param date in YYYY-MM format
|
* @param date in YYYY-MM format
|
||||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||||
*/
|
*/
|
||||||
getMonthNote(date: string, rootNote: BNote): Promise<BNote | null>;
|
getMonthNote(date: string, rootNote: BNote): BNote | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns quarter note for given date. If such a note doesn't exist, it is created.
|
* Returns quarter note for given date. If such a note doesn't exist, it is created.
|
||||||
@ -263,7 +263,7 @@ export interface Api {
|
|||||||
* @param date in YYYY-MM format
|
* @param date in YYYY-MM format
|
||||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||||
*/
|
*/
|
||||||
getQuarterNote(date: string, rootNote: BNote): Promise<BNote | null>;
|
getQuarterNote(date: string, rootNote: BNote): BNote | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns year note for given year. If such a note doesn't exist, it is created.
|
* Returns year note for given year. If such a note doesn't exist, it is created.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import dateUtils from "./date_utils.js";
|
import dateUtils from "./date_utils.js";
|
||||||
import optionService from "./options.js";
|
import optionService from "./options.js";
|
||||||
import fs from "fs-extra";
|
import fs from "fs";
|
||||||
import dataDir from "./data_dir.js";
|
import dataDir from "./data_dir.js";
|
||||||
import log from "./log.js";
|
import log from "./log.js";
|
||||||
import syncMutexService from "./sync_mutex.js";
|
import syncMutexService from "./sync_mutex.js";
|
||||||
|
@ -4,19 +4,26 @@ import sql_init from "./sql_init.js";
|
|||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
import { getResourceDir } from "./utils.js";
|
import { getResourceDir } from "./utils.js";
|
||||||
import hidden_subtree from "./hidden_subtree.js";
|
import hidden_subtree from "./hidden_subtree.js";
|
||||||
import { LOCALES, type Locale } from "@triliumnext/commons";
|
import { LOCALES, type Locale, type LOCALE_IDS } from "@triliumnext/commons";
|
||||||
import dayjs, { Dayjs } from "dayjs";
|
import dayjs, { Dayjs } from "dayjs";
|
||||||
|
|
||||||
const DAYJS_LOCALE_MAP: Record<string, string> = {
|
const DAYJS_LOADER: Record<LOCALE_IDS, () => Promise<typeof import("dayjs/locale/en.js")>> = {
|
||||||
cn: "zh-cn",
|
"ar": () => import("dayjs/locale/ar.js"),
|
||||||
tw: "zh-tw"
|
"cn": () => import("dayjs/locale/zh-cn.js"),
|
||||||
};
|
"de": () => import("dayjs/locale/de.js"),
|
||||||
|
"en": () => import("dayjs/locale/en.js"),
|
||||||
let dayjsLocale: string;
|
"es": () => import("dayjs/locale/es.js"),
|
||||||
|
"fa": () => import("dayjs/locale/fa.js"),
|
||||||
|
"fr": () => import("dayjs/locale/fr.js"),
|
||||||
|
"he": () => import("dayjs/locale/he.js"),
|
||||||
|
"ku": () => import("dayjs/locale/ku.js"),
|
||||||
|
"ro": () => import("dayjs/locale/ro.js"),
|
||||||
|
"tw": () => import("dayjs/locale/zh-tw.js")
|
||||||
|
}
|
||||||
|
|
||||||
export async function initializeTranslations() {
|
export async function initializeTranslations() {
|
||||||
const resourceDir = getResourceDir();
|
const resourceDir = getResourceDir();
|
||||||
const Backend = (await import("i18next-fs-backend")).default;
|
const Backend = (await import("i18next-fs-backend/cjs")).default;
|
||||||
const locale = getCurrentLanguage();
|
const locale = getCurrentLanguage();
|
||||||
|
|
||||||
// Initialize translations
|
// Initialize translations
|
||||||
@ -30,12 +37,7 @@ export async function initializeTranslations() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Initialize dayjs locale.
|
// Initialize dayjs locale.
|
||||||
dayjsLocale = DAYJS_LOCALE_MAP[locale] ?? locale;
|
const dayjsLocale = await DAYJS_LOADER[locale]();
|
||||||
try {
|
|
||||||
await import(`dayjs/locale/${dayjsLocale}.js`);
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(`Could not load locale ${dayjsLocale}`, err);
|
|
||||||
}
|
|
||||||
dayjs.locale(dayjsLocale);
|
dayjs.locale(dayjsLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,8 +50,8 @@ export function getLocales(): Locale[] {
|
|||||||
return LOCALES;
|
return LOCALES;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentLanguage() {
|
function getCurrentLanguage(): LOCALE_IDS {
|
||||||
let language;
|
let language: string;
|
||||||
if (sql_init.isDbInitialized()) {
|
if (sql_init.isDbInitialized()) {
|
||||||
language = options.getOptionOrNull("locale");
|
language = options.getOptionOrNull("locale");
|
||||||
}
|
}
|
||||||
@ -59,7 +61,7 @@ function getCurrentLanguage() {
|
|||||||
language = "en";
|
language = "en";
|
||||||
}
|
}
|
||||||
|
|
||||||
return language;
|
return language as LOCALE_IDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function changeLanguage(locale: string) {
|
export async function changeLanguage(locale: string) {
|
||||||
|
@ -194,9 +194,43 @@ second line 2</code></pre><ul><li>Hello</li><li>world</li></ul><ol><li>Hello</li
|
|||||||
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("converts multi-line display math expressions into Mathtex format", () => {
|
||||||
|
const input = `$$
|
||||||
|
\\sqrt{x^{2}+1} \\
|
||||||
|
+ \\frac{1}{2}
|
||||||
|
$$`;
|
||||||
|
const expected = /*html*/`<span class="math-tex">\\[
|
||||||
|
\\sqrt{x^{2}+1} \\
|
||||||
|
+ \\frac{1}{2}
|
||||||
|
\\]</span>`;
|
||||||
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("ignores math formulas inside code blocks and converts inline math expressions correctly", () => {
|
||||||
|
const result = markdownService.renderToHtml(trimIndentation`\
|
||||||
|
\`\`\`unknownlanguage
|
||||||
|
$$a+b$$
|
||||||
|
\`\`\`
|
||||||
|
`, "title");
|
||||||
|
expect(result).toBe(trimIndentation`\
|
||||||
|
<pre><code class="language-text-x-trilium-auto">$$a+b$$</code></pre>`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("converts specific inline math expression into Mathtex format", () => {
|
||||||
|
const input = `This is a formula: $\\mathcal{L}_{task} + \\mathcal{L}_{od}$ inside a sentence.`;
|
||||||
|
const expected = /*html*/`<p>This is a formula: <span class="math-tex">\\(\\mathcal{L}_{task} + \\mathcal{L}_{od}\\)</span> inside a sentence.</p>`;
|
||||||
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("converts math expressions inside list items into Mathtex format", () => {
|
||||||
|
const input = `- First item with formula: $E = mc^2$`;
|
||||||
|
const expected = /*html*/`<ul><li>First item with formula: <span class="math-tex">\\(E = mc^2\\)</span></li></ul>`;
|
||||||
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
it("converts display math expressions into Mathtex format", () => {
|
it("converts display math expressions into Mathtex format", () => {
|
||||||
const input = `$$\sqrt{x^{2}+1}$$`;
|
const input = `$$\sqrt{x^{2}+1}$$`;
|
||||||
const expected = /*html*/`<p><span class="math-tex">\\[\sqrt{x^{2}+1}\\]</span></p>`;
|
const expected = /*html*/`<span class="math-tex">\\[\sqrt{x^{2}+1}\\]</span>`;
|
||||||
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -240,7 +274,7 @@ second line 2</code></pre><ul><li>Hello</li><li>world</li></ul><ol><li>Hello</li
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("imports todo lists properly", () => {
|
it("imports todo lists properly", () => {
|
||||||
const input = trimIndentation`\
|
const input = trimIndentation`\
|
||||||
- [x] Hello
|
- [x] Hello
|
||||||
- [ ] World`;
|
- [ ] World`;
|
||||||
const expected = `<ul class="todo-list"><li><label class="todo-list__label"><input type="checkbox" checked="checked" disabled="disabled"><span class="todo-list__label__description">Hello</span></label></li><li><label class="todo-list__label"><input type="checkbox" disabled="disabled"><span class="todo-list__label__description">World</span></label></li></ul>`;
|
const expected = `<ul class="todo-list"><li><label class="todo-list__label"><input type="checkbox" checked="checked" disabled="disabled"><span class="todo-list__label__description">Hello</span></label></li><li><label class="todo-list__label"><input type="checkbox" disabled="disabled"><span class="todo-list__label__description">World</span></label></li></ul>`;
|
||||||
|
@ -23,19 +23,7 @@ class CustomMarkdownRenderer extends Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
paragraph(data: Tokens.Paragraph): string {
|
paragraph(data: Tokens.Paragraph): string {
|
||||||
let text = super.paragraph(data).trimEnd();
|
return super.paragraph(data).trimEnd();
|
||||||
|
|
||||||
if (text.includes("$")) {
|
|
||||||
// Display math
|
|
||||||
text = text.replaceAll(/(?<!\\)\$\$(.+)\$\$/g,
|
|
||||||
`<span class="math-tex">\\\[$1\\\]</span>`);
|
|
||||||
|
|
||||||
// Inline math
|
|
||||||
text = text.replaceAll(/(?<!\\)\$(.+?)\$/g,
|
|
||||||
`<span class="math-tex">\\\($1\\\)</span>`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code({ text, lang }: Tokens.Code): string {
|
code({ text, lang }: Tokens.Code): string {
|
||||||
@ -133,11 +121,17 @@ function renderToHtml(content: string, title: string) {
|
|||||||
// Double-escape slashes in math expression because they are otherwise consumed by the parser somewhere.
|
// Double-escape slashes in math expression because they are otherwise consumed by the parser somewhere.
|
||||||
content = content.replaceAll("\\$", "\\\\$");
|
content = content.replaceAll("\\$", "\\\\$");
|
||||||
|
|
||||||
let html = parse(content, {
|
// Extract formulas and replace them with placeholders to prevent interference from Markdown rendering
|
||||||
|
const { processedText, placeholderMap: formulaMap } = extractFormulas(content);
|
||||||
|
|
||||||
|
let html = parse(processedText, {
|
||||||
async: false,
|
async: false,
|
||||||
renderer: renderer
|
renderer: renderer
|
||||||
}) as string;
|
}) as string;
|
||||||
|
|
||||||
|
// After rendering, replace placeholders back with the formula HTML
|
||||||
|
html = restoreFromMap(html, formulaMap);
|
||||||
|
|
||||||
// h1 handling needs to come before sanitization
|
// h1 handling needs to come before sanitization
|
||||||
html = importUtils.handleH1(html, title);
|
html = importUtils.handleH1(html, title);
|
||||||
html = htmlSanitizer.sanitize(html);
|
html = htmlSanitizer.sanitize(html);
|
||||||
@ -165,6 +159,59 @@ function getNormalizedMimeFromMarkdownLanguage(language: string | undefined) {
|
|||||||
return MIME_TYPE_AUTO;
|
return MIME_TYPE_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractCodeBlocks(text: string): { processedText: string, placeholderMap: Map<string, string> } {
|
||||||
|
const codeMap = new Map<string, string>();
|
||||||
|
let id = 0;
|
||||||
|
const timestamp = Date.now();
|
||||||
|
|
||||||
|
// Multi-line code block and Inline code
|
||||||
|
text = text.replace(/```[\s\S]*?```/g, (m) => {
|
||||||
|
const key = `<!--CODE_BLOCK_${timestamp}_${id++}-->`;
|
||||||
|
codeMap.set(key, m);
|
||||||
|
return key;
|
||||||
|
}).replace(/`[^`\n]+`/g, (m) => {
|
||||||
|
const key = `<!--INLINE_CODE_${timestamp}_${id++}-->`;
|
||||||
|
codeMap.set(key, m);
|
||||||
|
return key;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { processedText: text, placeholderMap: codeMap };
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractFormulas(text: string): { processedText: string, placeholderMap: Map<string, string> } {
|
||||||
|
// Protect the $ signs inside code blocks from being recognized as formulas.
|
||||||
|
const { processedText: noCodeText, placeholderMap: codeMap } = extractCodeBlocks(text);
|
||||||
|
|
||||||
|
const formulaMap = new Map<string, string>();
|
||||||
|
let id = 0;
|
||||||
|
const timestamp = Date.now();
|
||||||
|
|
||||||
|
// Display math and Inline math
|
||||||
|
let processedText = noCodeText.replace(/(?<!\\)\$\$((?:(?!\n{2,})[\s\S])+?)\$\$/g, (_, formula) => {
|
||||||
|
const key = `<!--FORMULA_BLOCK_${timestamp}_${id++}-->`;
|
||||||
|
const rendered = `<span class="math-tex">\\[${formula}\\]</span>`;
|
||||||
|
formulaMap.set(key, rendered);
|
||||||
|
return key;
|
||||||
|
}).replace(/(?<!\\)\$(.+?)\$/g, (_, formula) => {
|
||||||
|
const key = `<!--FORMULA_INLINE_${timestamp}_${id++}-->`;
|
||||||
|
const rendered = `<span class="math-tex">\\(${formula}\\)</span>`;
|
||||||
|
formulaMap.set(key, rendered);
|
||||||
|
return key;
|
||||||
|
});
|
||||||
|
|
||||||
|
processedText = restoreFromMap(processedText, codeMap);
|
||||||
|
|
||||||
|
return { processedText, placeholderMap: formulaMap };
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreFromMap(text: string, map: Map<string, string>): string {
|
||||||
|
if (map.size === 0) return text;
|
||||||
|
const pattern = [...map.keys()]
|
||||||
|
.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
|
||||||
|
.join('|');
|
||||||
|
return text.replace(new RegExp(pattern, 'g'), match => map.get(match) ?? match);
|
||||||
|
}
|
||||||
|
|
||||||
const renderer = new CustomMarkdownRenderer({ async: false });
|
const renderer = new CustomMarkdownRenderer({ async: false });
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -26,7 +26,7 @@ import type {
|
|||||||
*
|
*
|
||||||
* Manages and provides access to all available agent tools.
|
* Manages and provides access to all available agent tools.
|
||||||
*/
|
*/
|
||||||
class AgentToolsManager {
|
export class AgentToolsManager {
|
||||||
private vectorSearchTool: VectorSearchTool | null = null;
|
private vectorSearchTool: VectorSearchTool | null = null;
|
||||||
private noteNavigatorTool: NoteNavigatorTool | null = null;
|
private noteNavigatorTool: NoteNavigatorTool | null = null;
|
||||||
private queryDecompositionTool: QueryDecompositionTool | null = null;
|
private queryDecompositionTool: QueryDecompositionTool | null = null;
|
||||||
|
@ -16,14 +16,12 @@ import vectorStore from "./embeddings/index.js";
|
|||||||
import providerManager from "./providers/providers.js";
|
import providerManager from "./providers/providers.js";
|
||||||
import { ContextExtractor } from "./context/index.js";
|
import { ContextExtractor } from "./context/index.js";
|
||||||
import eventService from "../events.js";
|
import eventService from "../events.js";
|
||||||
import type { NoteEmbeddingContext } from "./embeddings/embeddings_interface.js";
|
|
||||||
import type { OptionDefinitions } from "@triliumnext/commons";
|
|
||||||
import sql from "../sql.js";
|
import sql from "../sql.js";
|
||||||
import sqlInit from "../sql_init.js";
|
import sqlInit from "../sql_init.js";
|
||||||
import { CONTEXT_PROMPTS } from './constants/llm_prompt_constants.js';
|
import { CONTEXT_PROMPTS } from './constants/llm_prompt_constants.js';
|
||||||
import { SEARCH_CONSTANTS } from './constants/search_constants.js';
|
import { SEARCH_CONSTANTS } from './constants/search_constants.js';
|
||||||
|
|
||||||
class IndexService {
|
export class IndexService {
|
||||||
private initialized = false;
|
private initialized = false;
|
||||||
private indexingInProgress = false;
|
private indexingInProgress = false;
|
||||||
private contextExtractor = new ContextExtractor();
|
private contextExtractor = new ContextExtractor();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import backupService from "./backup.js";
|
import backupService from "./backup.js";
|
||||||
import sql from "./sql.js";
|
import sql from "./sql.js";
|
||||||
import fs from "fs-extra";
|
import fs from "fs";
|
||||||
import log from "./log.js";
|
import log from "./log.js";
|
||||||
import { crash } from "./utils.js";
|
import { crash } from "./utils.js";
|
||||||
import resourceDir from "./resource_dir.js";
|
import resourceDir from "./resource_dir.js";
|
||||||
|
@ -207,7 +207,7 @@ async function getClient(opts: ClientOpts): Promise<Client> {
|
|||||||
// it's not clear how to explicitly configure proxy (as opposed to system proxy),
|
// it's not clear how to explicitly configure proxy (as opposed to system proxy),
|
||||||
// so in that case, we always use node's modules
|
// so in that case, we always use node's modules
|
||||||
if (isElectron && !opts.proxy) {
|
if (isElectron && !opts.proxy) {
|
||||||
return (await import("electron")).net as Client;
|
return (await import("electron")).net as unknown as Client;
|
||||||
} else {
|
} else {
|
||||||
const { protocol } = url.parse(opts.url);
|
const { protocol } = url.parse(opts.url);
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import becca from "../becca/becca.js";
|
|||||||
import type BNote from "../becca/entities/bnote.js";
|
import type BNote from "../becca/entities/bnote.js";
|
||||||
import type { ApiParams } from "./backend_script_api_interface.js";
|
import type { ApiParams } from "./backend_script_api_interface.js";
|
||||||
|
|
||||||
interface Bundle {
|
export interface Bundle {
|
||||||
note?: BNote;
|
note?: BNote;
|
||||||
noteId?: string;
|
noteId?: string;
|
||||||
script: string;
|
script: string;
|
||||||
|
@ -8,7 +8,7 @@ import log from "./log.js";
|
|||||||
import type { Statement, Database as DatabaseType, RunResult } from "better-sqlite3";
|
import type { Statement, Database as DatabaseType, RunResult } from "better-sqlite3";
|
||||||
import dataDir from "./data_dir.js";
|
import dataDir from "./data_dir.js";
|
||||||
import cls from "./cls.js";
|
import cls from "./cls.js";
|
||||||
import fs from "fs-extra";
|
import fs from "fs";
|
||||||
import Database from "better-sqlite3";
|
import Database from "better-sqlite3";
|
||||||
import ws from "./ws.js";
|
import ws from "./ws.js";
|
||||||
import becca_loader from "../becca/becca_loader.js";
|
import becca_loader from "../becca/becca_loader.js";
|
||||||
@ -352,7 +352,6 @@ function disableSlowQueryLogging<T>(cb: () => T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
dbConnection,
|
|
||||||
insert,
|
insert,
|
||||||
replace,
|
replace,
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { BrowserWindow, Menu, Tray, ipcMain, nativeTheme } from "electron";
|
import electron from "electron";
|
||||||
|
import type { BrowserWindow, Tray } from "electron";
|
||||||
import { default as i18next, t } from "i18next";
|
import { default as i18next, t } from "i18next";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
|
|
||||||
import becca from "../becca/becca.js";
|
import becca from "../becca/becca.js";
|
||||||
import becca_service from "../becca/becca_service.js";
|
import becca_service from "../becca/becca_service.js";
|
||||||
@ -33,7 +33,7 @@ function getTrayIconPath() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getIconPath(name: string) {
|
function getIconPath(name: string) {
|
||||||
const suffix = !isMac && nativeTheme.shouldUseDarkColors ? "-inverted" : "";
|
const suffix = !isMac && electron.nativeTheme.shouldUseDarkColors ? "-inverted" : "";
|
||||||
return path.resolve(path.join(getResourceDir(), "assets", "images", "tray", `${name}Template${suffix}.png`));
|
return path.resolve(path.join(getResourceDir(), "assets", "images", "tray", `${name}Template${suffix}.png`));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ function updateTrayMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const contextMenu = Menu.buildFromTemplate([
|
const contextMenu = electron.Menu.buildFromTemplate([
|
||||||
...windowVisibilityMenuItems,
|
...windowVisibilityMenuItems,
|
||||||
{ type: "separator" },
|
{ type: "separator" },
|
||||||
{
|
{
|
||||||
@ -255,7 +255,7 @@ function updateTrayMenu() {
|
|||||||
type: "normal",
|
type: "normal",
|
||||||
icon: getIconPath("close"),
|
icon: getIconPath("close"),
|
||||||
click: () => {
|
click: () => {
|
||||||
const windows = BrowserWindow.getAllWindows();
|
const windows = electron.BrowserWindow.getAllWindows();
|
||||||
windows.forEach(window => {
|
windows.forEach(window => {
|
||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
@ -287,7 +287,7 @@ function createTray() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tray = new Tray(getTrayIconPath());
|
tray = new electron.Tray(getTrayIconPath());
|
||||||
tray.setToolTip(t("tray.tooltip"));
|
tray.setToolTip(t("tray.tooltip"));
|
||||||
// Restore focus
|
// Restore focus
|
||||||
tray.on("click", changeVisibility);
|
tray.on("click", changeVisibility);
|
||||||
@ -295,9 +295,9 @@ function createTray() {
|
|||||||
|
|
||||||
if (!isMac) {
|
if (!isMac) {
|
||||||
// macOS uses template icons which work great on dark & light themes.
|
// macOS uses template icons which work great on dark & light themes.
|
||||||
nativeTheme.on("updated", updateTrayMenu);
|
electron.nativeTheme.on("updated", updateTrayMenu);
|
||||||
}
|
}
|
||||||
ipcMain.on("reload-tray", updateTrayMenu);
|
electron.ipcMain.on("reload-tray", updateTrayMenu);
|
||||||
i18next.on("languageChanged", updateTrayMenu);
|
i18next.on("languageChanged", updateTrayMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import entityChangesService from "./entity_changes.js";
|
|||||||
import becca from "../becca/becca.js";
|
import becca from "../becca/becca.js";
|
||||||
import type BNote from "../becca/entities/bnote.js";
|
import type BNote from "../becca/entities/bnote.js";
|
||||||
|
|
||||||
interface ValidationResponse {
|
export interface ValidationResponse {
|
||||||
branch: BBranch | null;
|
branch: BBranch | null;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
message?: string;
|
message?: string;
|
||||||
|
@ -9,8 +9,6 @@ import escape from "escape-html";
|
|||||||
import sanitize from "sanitize-filename";
|
import sanitize from "sanitize-filename";
|
||||||
import mimeTypes from "mime-types";
|
import mimeTypes from "mime-types";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
import { dirname, join } from "path";
|
|
||||||
import type NoteMeta from "./meta/note_meta.js";
|
import type NoteMeta from "./meta/note_meta.js";
|
||||||
import log from "./log.js";
|
import log from "./log.js";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
@ -226,7 +224,7 @@ export function timeLimit<T>(promise: Promise<T>, limitMs: number, errorMessage?
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeferredPromise<T> extends Promise<T> {
|
export interface DeferredPromise<T> extends Promise<T> {
|
||||||
resolve: (value: T | PromiseLike<T>) => void;
|
resolve: (value: T | PromiseLike<T>) => void;
|
||||||
reject: (reason?: any) => void;
|
reject: (reason?: any) => void;
|
||||||
}
|
}
|
||||||
@ -299,7 +297,7 @@ export function getResourceDir() {
|
|||||||
return path.dirname(process.argv[1]);
|
return path.dirname(process.argv[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return join(dirname(fileURLToPath(import.meta.url)), "..");
|
return path.join(__dirname, "..");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Deduplicate with src/public/app/services/utils.ts
|
// TODO: Deduplicate with src/public/app/services/utils.ts
|
||||||
|
@ -7,14 +7,11 @@ import log from "./log.js";
|
|||||||
import sqlInit from "./sql_init.js";
|
import sqlInit from "./sql_init.js";
|
||||||
import cls from "./cls.js";
|
import cls from "./cls.js";
|
||||||
import keyboardActionsService from "./keyboard_actions.js";
|
import keyboardActionsService from "./keyboard_actions.js";
|
||||||
import * as remoteMain from "@electron/remote/main";
|
import electron from "electron";
|
||||||
import { BrowserWindow, shell, type App, type BrowserWindowConstructorOptions, type WebContents } from "electron";
|
import type { App, BrowserWindowConstructorOptions, BrowserWindow, WebContents } from "electron";
|
||||||
import { dialog, ipcMain } from "electron";
|
|
||||||
import { formatDownloadTitle, isDev, isMac, isWindows } from "./utils.js";
|
import { formatDownloadTitle, isDev, isMac, isWindows } from "./utils.js";
|
||||||
|
|
||||||
import { fileURLToPath } from "url";
|
|
||||||
import { dirname } from "path";
|
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
|
import { RESOURCE_DIR } from "./resource_dir.js";
|
||||||
|
|
||||||
// Prevent the window being garbage collected
|
// Prevent the window being garbage collected
|
||||||
let mainWindow: BrowserWindow | null;
|
let mainWindow: BrowserWindow | null;
|
||||||
@ -28,14 +25,14 @@ function trackWindowFocus(win: BrowserWindow) {
|
|||||||
allWindows = allWindows.filter(w => !w.isDestroyed() && w !== win);
|
allWindows = allWindows.filter(w => !w.isDestroyed() && w !== win);
|
||||||
allWindows.push(win);
|
allWindows.push(win);
|
||||||
if (!optionService.getOptionBool("disableTray")) {
|
if (!optionService.getOptionBool("disableTray")) {
|
||||||
ipcMain.emit("reload-tray");
|
electron.ipcMain.emit("reload-tray");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
win.on("closed", () => {
|
win.on("closed", () => {
|
||||||
allWindows = allWindows.filter(w => !w.isDestroyed());
|
allWindows = allWindows.filter(w => !w.isDestroyed());
|
||||||
if (!optionService.getOptionBool("disableTray")) {
|
if (!optionService.getOptionBool("disableTray")) {
|
||||||
ipcMain.emit("reload-tray");
|
electron.ipcMain.emit("reload-tray");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -66,7 +63,7 @@ async function createExtraWindow(extraWindowHash: string) {
|
|||||||
trackWindowFocus(win);
|
trackWindowFocus(win);
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.on("create-extra-window", (event, arg) => {
|
electron.ipcMain.on("create-extra-window", (event, arg) => {
|
||||||
createExtraWindow(arg.extraWindowHash);
|
createExtraWindow(arg.extraWindowHash);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -76,13 +73,13 @@ interface ExportAsPdfOpts {
|
|||||||
pageSize: "A0" | "A1" | "A2" | "A3" | "A4" | "A5" | "A6" | "Legal" | "Letter" | "Tabloid" | "Ledger";
|
pageSize: "A0" | "A1" | "A2" | "A3" | "A4" | "A5" | "A6" | "Legal" | "Letter" | "Tabloid" | "Ledger";
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcMain.on("export-as-pdf", async (e, opts: ExportAsPdfOpts) => {
|
electron.ipcMain.on("export-as-pdf", async (e, opts: ExportAsPdfOpts) => {
|
||||||
const browserWindow = BrowserWindow.fromWebContents(e.sender);
|
const browserWindow = electron.BrowserWindow.fromWebContents(e.sender);
|
||||||
if (!browserWindow) {
|
if (!browserWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = dialog.showSaveDialogSync(browserWindow, {
|
const filePath = electron.dialog.showSaveDialogSync(browserWindow, {
|
||||||
defaultPath: formatDownloadTitle(opts.title, "file", "application/pdf"),
|
defaultPath: formatDownloadTitle(opts.title, "file", "application/pdf"),
|
||||||
filters: [
|
filters: [
|
||||||
{
|
{
|
||||||
@ -111,18 +108,18 @@ ipcMain.on("export-as-pdf", async (e, opts: ExportAsPdfOpts) => {
|
|||||||
`
|
`
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-export-message"));
|
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-export-message"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.writeFile(filePath, buffer);
|
await fs.writeFile(filePath, buffer);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-save-message"));
|
electron.dialog.showErrorBox(t("pdf.unable-to-export-title"), t("pdf.unable-to-save-message"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
shell.openPath(filePath);
|
electron.shell.openPath(filePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function createMainWindow(app: App) {
|
async function createMainWindow(app: App) {
|
||||||
@ -226,7 +223,8 @@ function getWindowExtraOpts() {
|
|||||||
return extraOpts;
|
return extraOpts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function configureWebContents(webContents: WebContents, spellcheckEnabled: boolean) {
|
async function configureWebContents(webContents: WebContents, spellcheckEnabled: boolean) {
|
||||||
|
const remoteMain = (await import("@electron/remote/main/index.js")).default;
|
||||||
remoteMain.enable(webContents);
|
remoteMain.enable(webContents);
|
||||||
|
|
||||||
webContents.setWindowOpenHandler((details) => {
|
webContents.setWindowOpenHandler((details) => {
|
||||||
@ -259,7 +257,7 @@ function configureWebContents(webContents: WebContents, spellcheckEnabled: boole
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getIcon() {
|
function getIcon() {
|
||||||
return path.join(dirname(fileURLToPath(import.meta.url)), "../../images/app-icons/png/256x256" + (isDev ? "-dev" : "") + ".png");
|
return path.join(RESOURCE_DIR, "images/app-icons/png/256x256" + (isDev ? "-dev" : "") + ".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createSetupWindow() {
|
async function createSetupWindow() {
|
||||||
|
@ -195,9 +195,11 @@ function register(router: Router) {
|
|||||||
try {
|
try {
|
||||||
const content = templateNote.getContent();
|
const content = templateNote.getContent();
|
||||||
if (typeof content === "string") {
|
if (typeof content === "string") {
|
||||||
const ejsResult = ejs.render(content, opts, { includer });
|
import("ejs").then((ejs) => {
|
||||||
res.send(ejsResult);
|
const ejsResult = ejs.render(content, opts, { includer });
|
||||||
useDefaultView = false; // Rendering went okay, don't use default view
|
res.send(ejsResult);
|
||||||
|
useDefaultView = false; // Rendering went okay, don't use default view
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
const [errMessage, errStack] = safeExtractMessageAndStackFromError(e);
|
||||||
|
@ -4,4 +4,4 @@
|
|||||||
[ ! -z "${USER_GID}" ] && groupmod -og ${USER_GID} node || echo "No USER_GID specified, leaving 1000"
|
[ ! -z "${USER_GID}" ] && groupmod -og ${USER_GID} node || echo "No USER_GID specified, leaving 1000"
|
||||||
|
|
||||||
chown -R node:node /home/node
|
chown -R node:node /home/node
|
||||||
exec su -c "node ./main" node
|
exec su -c "node ./main.cjs" node
|
@ -5,6 +5,7 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
|
"strict": false,
|
||||||
"types": [
|
"types": [
|
||||||
"node",
|
"node",
|
||||||
"express"
|
"express"
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
|
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
|
||||||
const { join } = require('path');
|
|
||||||
|
|
||||||
const outputDir = join(__dirname, 'dist');
|
|
||||||
|
|
||||||
function buildFilesToCopy() {
|
|
||||||
const files = [];
|
|
||||||
|
|
||||||
files.push({
|
|
||||||
from: "../client/dist",
|
|
||||||
to: join(outputDir, "public")
|
|
||||||
});
|
|
||||||
|
|
||||||
const nodePaths = [
|
|
||||||
// Required as they are native dependencies and cannot be well bundled.
|
|
||||||
"better-sqlite3",
|
|
||||||
"bindings",
|
|
||||||
"file-uri-to-path"
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const nodePath of nodePaths) {
|
|
||||||
files.push({
|
|
||||||
from: join("node_modules", nodePath),
|
|
||||||
to: join(outputDir, "node_modules", nodePath)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
output: {
|
|
||||||
path: outputDir
|
|
||||||
},
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.css$/i,
|
|
||||||
type: "asset/source"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new NxAppWebpackPlugin({
|
|
||||||
target: 'node',
|
|
||||||
compiler: 'tsc',
|
|
||||||
main: './src/main.ts',
|
|
||||||
tsConfig: './tsconfig.app.json',
|
|
||||||
assets: ["./src/assets"],
|
|
||||||
optimization: false,
|
|
||||||
outputHashing: 'none',
|
|
||||||
generatePackageJson: true,
|
|
||||||
additionalEntryPoints: [
|
|
||||||
"./src/docker_healthcheck.ts"
|
|
||||||
],
|
|
||||||
externalDependencies: [
|
|
||||||
"electron/main",
|
|
||||||
"@electron/remote/main",
|
|
||||||
"electron",
|
|
||||||
"@electron/remote",
|
|
||||||
"better-sqlite3"
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
new CopyPlugin({
|
|
||||||
patterns: buildFilesToCopy()
|
|
||||||
})
|
|
||||||
]
|
|
||||||
};
|
|
@ -1,4 +1,7 @@
|
|||||||
# v0.94.0
|
# v0.94.0
|
||||||
|
> [!CAUTION]
|
||||||
|
> **For (advanced) manual setups only:** Following a tooling change, the main entry point has changed from `main.js` to `main.cjs`. Same goes for the Electron build.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> If you enjoyed this release, consider showing a token of appreciation by:
|
> If you enjoyed this release, consider showing a token of appreciation by:
|
||||||
>
|
>
|
||||||
@ -22,6 +25,7 @@
|
|||||||
* [Incorrect import of multiple inline math](https://github.com/TriliumNext/Notes/pull/1906) by @SiriusXT
|
* [Incorrect import of multiple inline math](https://github.com/TriliumNext/Notes/pull/1906) by @SiriusXT
|
||||||
* [Random EPERM: operation not permitted on Windows](https://github.com/TriliumNext/Notes/issues/249)
|
* [Random EPERM: operation not permitted on Windows](https://github.com/TriliumNext/Notes/issues/249)
|
||||||
* [The update button is sometimes blank](https://github.com/TriliumNext/Notes/pull/1975) by @SiriusXT
|
* [The update button is sometimes blank](https://github.com/TriliumNext/Notes/pull/1975) by @SiriusXT
|
||||||
|
* [Unable to handle multi line mathematical formulas when importing markdown](https://github.com/TriliumNext/Notes/pull/1984) by @SiriusXT
|
||||||
|
|
||||||
## ✨ Improvements
|
## ✨ Improvements
|
||||||
|
|
||||||
@ -37,21 +41,7 @@
|
|||||||
* Added the Nix language (and also in code blocks for text notes).
|
* Added the Nix language (and also in code blocks for text notes).
|
||||||
* Added an indentation marker.
|
* Added an indentation marker.
|
||||||
* Note: syntax highlighting for some languages (mostly HTML-template languages such as EJS, JSP) is no longer supported due to lack of upstream support. If this is a problem, feel free to report an issue and we can see what can be done about it.
|
* Note: syntax highlighting for some languages (mostly HTML-template languages such as EJS, JSP) is no longer supported due to lack of upstream support. If this is a problem, feel free to report an issue and we can see what can be done about it.
|
||||||
* Syntax highlighting in code blocks for text notes:
|
* Added support for additional syntax highlighting for code blocks in text notes: Cypher, XML-DTD, Jinja2, ClojureScript, Perl, Scala, Scheme, Swift, SystemVerilog, mIRC, Cobol, Dylan, RPM Specfile, TCCN3.
|
||||||
* Added support for Cypher.
|
|
||||||
* Added support for XML-DTD.
|
|
||||||
* Added support for Jinja2.
|
|
||||||
* Added support for ClojureScript.
|
|
||||||
* Added support for Perl.
|
|
||||||
* Added support for Scala.
|
|
||||||
* Added support for Scheme.
|
|
||||||
* Added support for Swift.
|
|
||||||
* Added support for SystemVerilog.
|
|
||||||
* Added support for mIRC.
|
|
||||||
* Added support for Cobol.
|
|
||||||
* Added support for Dylan.
|
|
||||||
* Added support for RPM Specfile.
|
|
||||||
* Added support for TCCN3.
|
|
||||||
* Mermaid diagrams: basic syntax highlight (not all diagram types are supported) and code folding.
|
* Mermaid diagrams: basic syntax highlight (not all diagram types are supported) and code folding.
|
||||||
* Slight organization in Appearance settings: code block themes are now in "Text Notes", added a "Related settings" section in Appearance.
|
* Slight organization in Appearance settings: code block themes are now in "Text Notes", added a "Related settings" section in Appearance.
|
||||||
* [Added support for opening and activating a note in a new tab using Ctrl+Shift+click on notes in the launcher pane, note tree, or note images](https://github.com/TriliumNext/Notes/pull/1854) by @SiriusXT
|
* [Added support for opening and activating a note in a new tab using Ctrl+Shift+click on notes in the launcher pane, note tree, or note images](https://github.com/TriliumNext/Notes/pull/1854) by @SiriusXT
|
||||||
|
10
nx.json
10
nx.json
@ -54,16 +54,6 @@
|
|||||||
"watchDepsTargetName": "watch-deps"
|
"watchDepsTargetName": "watch-deps"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"plugin": "@nx/webpack/plugin",
|
|
||||||
"options": {
|
|
||||||
"buildTargetName": "build",
|
|
||||||
"serveTargetName": "serve",
|
|
||||||
"previewTargetName": "preview",
|
|
||||||
"buildDepsTargetName": "build-deps",
|
|
||||||
"watchDepsTargetName": "watch-deps"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"plugin": "@nx/playwright/plugin",
|
"plugin": "@nx/playwright/plugin",
|
||||||
"options": {
|
"options": {
|
||||||
|
27
package.json
27
package.json
@ -27,19 +27,17 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@electron/rebuild": "4.0.1",
|
"@electron/rebuild": "4.0.1",
|
||||||
"@nx/devkit": "21.1.0",
|
"@nx/devkit": "21.1.2",
|
||||||
"@nx/esbuild": "21.1.0",
|
"@nx/esbuild": "21.1.2",
|
||||||
"@nx/eslint": "21.1.0",
|
"@nx/eslint": "21.1.2",
|
||||||
"@nx/eslint-plugin": "21.1.0",
|
"@nx/eslint-plugin": "21.1.2",
|
||||||
"@nx/express": "21.1.0",
|
"@nx/express": "21.1.2",
|
||||||
"@nx/js": "21.1.0",
|
"@nx/js": "21.1.2",
|
||||||
"@nx/node": "21.1.0",
|
"@nx/node": "21.1.2",
|
||||||
"@nx/playwright": "21.1.0",
|
"@nx/playwright": "21.1.2",
|
||||||
"@nx/vite": "21.1.0",
|
"@nx/vite": "21.1.2",
|
||||||
"@nx/web": "21.1.0",
|
"@nx/web": "21.1.2",
|
||||||
"@nx/webpack": "21.1.0",
|
|
||||||
"@playwright/test": "^1.36.0",
|
"@playwright/test": "^1.36.0",
|
||||||
"@svgr/webpack": "^8.0.1",
|
|
||||||
"@swc-node/register": "~1.10.0",
|
"@swc-node/register": "~1.10.0",
|
||||||
"@swc/cli": "~0.7.0",
|
"@swc/cli": "~0.7.0",
|
||||||
"@swc/core": "~1.11.0",
|
"@swc/core": "~1.11.0",
|
||||||
@ -59,7 +57,7 @@
|
|||||||
"jiti": "2.4.2",
|
"jiti": "2.4.2",
|
||||||
"jsdom": "~26.1.0",
|
"jsdom": "~26.1.0",
|
||||||
"jsonc-eslint-parser": "^2.1.0",
|
"jsonc-eslint-parser": "^2.1.0",
|
||||||
"nx": "21.1.0",
|
"nx": "21.1.2",
|
||||||
"react-refresh": "^0.17.0",
|
"react-refresh": "^0.17.0",
|
||||||
"swc-loader": "0.2.6",
|
"swc-loader": "0.2.6",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
@ -69,8 +67,7 @@
|
|||||||
"upath": "2.0.1",
|
"upath": "2.0.1",
|
||||||
"vite": "^6.0.0",
|
"vite": "^6.0.0",
|
||||||
"vite-plugin-dts": "~4.5.0",
|
"vite-plugin-dts": "~4.5.0",
|
||||||
"vitest": "^3.0.0",
|
"vitest": "^3.0.0"
|
||||||
"webpack-cli": "^6.0.0"
|
|
||||||
},
|
},
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"author": {
|
"author": {
|
||||||
|
@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" width="208" height="128" viewBox="0 0 208 128"><rect width="198" height="118" x="5" y="5" ry="10" stroke="#000" stroke-width="10" fill="none"/><path d="M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39zm125 0l-30-33h20V30h20v35h20z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="208" height="128" viewBox="0 0 208 128"><rect width="198" height="118" x="5" y="5" ry="10" stroke="currentColor" stroke-width="10" fill="none"/><path d="M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39zm125 0l-30-33h20V30h20v35h20z"/></svg>
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 290 B |
@ -9,7 +9,7 @@ export interface Locale {
|
|||||||
electronLocale?: string;
|
electronLocale?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LOCALES: Locale[] = [
|
const UNSORTED_LOCALES = [
|
||||||
{
|
{
|
||||||
id: "en",
|
id: "en",
|
||||||
name: "English",
|
name: "English",
|
||||||
@ -75,4 +75,9 @@ export const LOCALES: Locale[] = [
|
|||||||
rtl: true,
|
rtl: true,
|
||||||
contentOnly: true
|
contentOnly: true
|
||||||
}
|
}
|
||||||
].sort((a, b) => a.name.localeCompare(b.name));
|
] as const;
|
||||||
|
|
||||||
|
export const LOCALES: Locale[] = Array.from(UNSORTED_LOCALES)
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
export type LOCALE_IDS = typeof UNSORTED_LOCALES[number]["id"];
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
"jsc": {
|
|
||||||
"target": "es2017",
|
|
||||||
"parser": {
|
|
||||||
"syntax": "typescript",
|
|
||||||
"decorators": true,
|
|
||||||
"dynamicImport": true
|
|
||||||
},
|
|
||||||
"transform": {
|
|
||||||
"decoratorMetadata": true,
|
|
||||||
"legacyDecorator": true
|
|
||||||
},
|
|
||||||
"keepClassNames": true,
|
|
||||||
"externalHelpers": true,
|
|
||||||
"loose": true
|
|
||||||
},
|
|
||||||
"module": {
|
|
||||||
"type": "commonjs"
|
|
||||||
},
|
|
||||||
"sourceMaps": true,
|
|
||||||
"exclude": ["jest.config.ts",".*\\.spec.tsx?$",".*\\.test.tsx?$","./src/jest-setup.ts$","./**/jest-setup.ts$",".*.js$"]
|
|
||||||
}
|
|
@ -5,16 +5,16 @@
|
|||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/main.js",
|
||||||
"module": "./dist/index.js",
|
"module": "./dist/main.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
".": {
|
".": {
|
||||||
"development": "./src/index.ts",
|
"development": "./src/index.ts",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
"import": "./dist/index.js",
|
"import": "./dist/main.js",
|
||||||
"default": "./dist/index.js"
|
"default": "./dist/main.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -27,16 +27,29 @@
|
|||||||
"name": "express-partial-content",
|
"name": "express-partial-content",
|
||||||
"targets": {
|
"targets": {
|
||||||
"build": {
|
"build": {
|
||||||
"executor": "@nx/js:swc",
|
"executor": "@nx/esbuild:esbuild",
|
||||||
"outputs": [
|
"outputs": [
|
||||||
"{options.outputPath}"
|
"{options.outputPath}"
|
||||||
],
|
],
|
||||||
|
"defaultConfiguration": "production",
|
||||||
"options": {
|
"options": {
|
||||||
"outputPath": "packages/express-partial-content/dist",
|
|
||||||
"tsConfig": "packages/express-partial-content/tsconfig.lib.json",
|
|
||||||
"packageJson": "packages/express-partial-content/package.json",
|
|
||||||
"main": "packages/express-partial-content/src/index.ts",
|
"main": "packages/express-partial-content/src/index.ts",
|
||||||
"stripLeadingPaths": true
|
"outputPath": "packages/express-partial-content/dist",
|
||||||
|
"outputFileName": "main.js",
|
||||||
|
"tsConfig": "packages/express-partial-content/tsconfig.lib.json",
|
||||||
|
"platform": "node",
|
||||||
|
"format": [
|
||||||
|
"esm"
|
||||||
|
],
|
||||||
|
"declarationRootDir": "packages/express-partial-content/src"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"minify": false
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"minify": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1985
pnpm-lock.yaml
generated
1985
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,7 @@ onlyBuiltDependencies:
|
|||||||
|
|
||||||
overrides:
|
overrides:
|
||||||
"node-abi": 4.8.0
|
"node-abi": 4.8.0
|
||||||
|
"@types/express-serve-static-core": 5.0.6
|
||||||
|
|
||||||
shamefullyHoist: true
|
shamefullyHoist: true
|
||||||
nodeLinker: isolated
|
nodeLinker: isolated
|
||||||
|
@ -4,27 +4,64 @@
|
|||||||
* This script is used internally by the `rebuild-deps` target of the `desktop`. Normally we could use
|
* This script is used internally by the `rebuild-deps` target of the `desktop`. Normally we could use
|
||||||
* `electron-rebuild` CLI directly, but it would rebuild the monorepo-level dependencies and breaks
|
* `electron-rebuild` CLI directly, but it would rebuild the monorepo-level dependencies and breaks
|
||||||
* the server build (and it doesn't expose a CLI option to override this).
|
* the server build (and it doesn't expose a CLI option to override this).
|
||||||
|
*
|
||||||
|
* A side purpose is to generate a fake `package.json` file in the `dist` directory
|
||||||
|
* that contains only the native dependencies. This is used by `electron-forge`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { join, resolve } from "path";
|
import { join, resolve } from "path";
|
||||||
import { rebuild } from "@electron/rebuild"
|
import { rebuild } from "@electron/rebuild"
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync, rmSync, writeFileSync } from "fs";
|
||||||
|
|
||||||
function getElectronVersion(distDir: string) {
|
const nativeDependencies = [
|
||||||
if (process.argv[3]) {
|
"better-sqlite3"
|
||||||
return process.argv[3];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
const packageJsonPath = join(distDir, "package.json");
|
function parsePackageJson(distDir: string) {
|
||||||
|
const packageJsonPath = join(distDir, "../package.json");
|
||||||
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
||||||
|
let electronVersion: string;
|
||||||
|
|
||||||
const electronVersion = packageJson?.devDependencies?.electron ?? packageJson?.dependencies?.electron;
|
if (process.argv[3]) {
|
||||||
if (!electronVersion) {
|
electronVersion = process.argv[3];
|
||||||
console.error(`Unable to retrieve Electron version in '${resolve(packageJsonPath)}'.`);
|
} else {
|
||||||
process.exit(3);
|
electronVersion = packageJson?.devDependencies?.electron ?? packageJson?.dependencies?.electron;
|
||||||
|
if (!electronVersion) {
|
||||||
|
console.error(`Unable to retrieve Electron version in '${resolve(packageJsonPath)}'.`);
|
||||||
|
process.exit(3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return electronVersion;
|
return {
|
||||||
|
electronVersion,
|
||||||
|
packageJson
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createFakePackageJson(distPath: string, packageJson: any) {
|
||||||
|
const finalDependencies = {};
|
||||||
|
for (const dep of nativeDependencies) {
|
||||||
|
finalDependencies[dep] = packageJson.dependencies[dep];
|
||||||
|
}
|
||||||
|
|
||||||
|
const fakePackageJson: any = {
|
||||||
|
name: "trilium",
|
||||||
|
version: packageJson.version,
|
||||||
|
main: packageJson.main,
|
||||||
|
author: packageJson.author,
|
||||||
|
license: packageJson.license,
|
||||||
|
description: packageJson.description,
|
||||||
|
dependencies: finalDependencies,
|
||||||
|
devDependencies: {
|
||||||
|
"electron": packageJson.devDependencies?.electron || packageJson.dependencies?.electron,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (packageJson?.config?.forge) {
|
||||||
|
fakePackageJson.config = {
|
||||||
|
forge: join("..", packageJson.config.forge)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
writeFileSync(distPath, JSON.stringify(fakePackageJson, null, 2), "utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
@ -34,7 +71,10 @@ function main() {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const electronVersion = getElectronVersion(distDir);
|
const { electronVersion, packageJson } = parsePackageJson(distDir);
|
||||||
|
const packageJsonPath = join(distDir, "package.json");
|
||||||
|
createFakePackageJson(packageJsonPath, packageJson);
|
||||||
|
|
||||||
console.log(`Rebuilding ${distDir} with version ${electronVersion}...`);
|
console.log(`Rebuilding ${distDir} with version ${electronVersion}...`);
|
||||||
|
|
||||||
rebuild({
|
rebuild({
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
"moduleResolution": "nodenext",
|
"moduleResolution": "nodenext",
|
||||||
"noEmitOnError": true,
|
"noEmitOnError": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": false, // TODO: Re-enable it at some point.
|
||||||
"noImplicitOverride": false, // TODO: Re-enable it at some point.
|
"noImplicitOverride": false, // TODO: Re-enable it at some point.
|
||||||
"noImplicitReturns": false, // TODO: Re-enable it at some point.
|
"noImplicitReturns": false, // TODO: Re-enable it at some point.
|
||||||
"noUnusedLocals": false, // TODO: Re-enable it at some point.
|
"noUnusedLocals": false, // TODO: Re-enable it at some point.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user