Merge branch 'develop' into feat/add-rootless-dockerfiles
| @@ -84,7 +84,7 @@ Download the binary release for your platform from the [latest release page](htt | ||||
|  | ||||
| If your distribution is listed in the table below, use your distribution's package. | ||||
|  | ||||
| [](https://repology.org/project/trilium-next-desktop/versions) | ||||
| [](https://repology.org/project/triliumnext/versions) | ||||
|  | ||||
| You may also download the binary release for your platform from the [latest release page](https://github.com/TriliumNext/Notes/releases/latest), unzip the package and run the `trilium` executable. | ||||
|  | ||||
|   | ||||
| @@ -1,593 +0,0 @@ | ||||
| /* !!!!!! TRILIUM CUSTOM CHANGES !!!!!! */ | ||||
|  | ||||
| .printed-content .ck-widget__selection-handle, .printed-content .ck-widget__type-around { /* gets rid of triangles: https://github.com/zadam/trilium/issues/1129 */ | ||||
|     display: none; | ||||
| } | ||||
|  | ||||
| .page-break { | ||||
|     page-break-after: always; | ||||
| } | ||||
|  | ||||
| .printed-content .page-break:after, | ||||
| .printed-content .page-break > * { | ||||
|     display: none !important; | ||||
| } | ||||
|  | ||||
| .ck-content li p { | ||||
|     margin: 0 !important; | ||||
| } | ||||
|  | ||||
| .admonition { | ||||
|     --accent-color: var(--card-border-color); | ||||
|     border: 1px solid var(--accent-color); | ||||
|     box-shadow: var(--card-box-shadow); | ||||
|     background: var(--card-background-color); | ||||
|     border-radius: 0.5em; | ||||
|     padding: 1em; | ||||
|     margin: 1.25em 0; | ||||
|     position: relative; | ||||
|     overflow: hidden; | ||||
| } | ||||
|  | ||||
| .admonition p:last-child { | ||||
|     margin-bottom: 0; | ||||
| } | ||||
|  | ||||
| .admonition p, h2 { | ||||
|     margin-top: 0; | ||||
| } | ||||
|  | ||||
| .admonition.note { --accent-color: #69c7ff; } | ||||
| .admonition.tip { --accent-color: #40c025; } | ||||
| .admonition.important { --accent-color: #9839f7; } | ||||
| .admonition.caution { --accent-color: #ff2e2e; } | ||||
| .admonition.warning { --accent-color: #e2aa03; } | ||||
|  | ||||
| /* | ||||
|  * CKEditor 5 (v41.0.0) content styles. | ||||
|  * Generated on Fri, 26 Jan 2024 10:23:49 GMT. | ||||
|  * For more information, check out https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/content-styles.html | ||||
|  */ | ||||
|  | ||||
| :root { | ||||
|     --ck-color-image-caption-background: hsl(0, 0%, 97%); | ||||
|     --ck-color-image-caption-text: hsl(0, 0%, 20%); | ||||
|     --ck-color-mention-background: hsla(341, 100%, 30%, 0.1); | ||||
|     --ck-color-mention-text: hsl(341, 100%, 30%); | ||||
|     --ck-color-selector-caption-background: hsl(0, 0%, 97%); | ||||
|     --ck-color-selector-caption-text: hsl(0, 0%, 20%); | ||||
|     --ck-highlight-marker-blue: hsl(201, 97%, 72%); | ||||
|     --ck-highlight-marker-green: hsl(120, 93%, 68%); | ||||
|     --ck-highlight-marker-pink: hsl(345, 96%, 73%); | ||||
|     --ck-highlight-marker-yellow: hsl(60, 97%, 73%); | ||||
|     --ck-highlight-pen-green: hsl(112, 100%, 27%); | ||||
|     --ck-highlight-pen-red: hsl(0, 85%, 49%); | ||||
|     --ck-image-style-spacing: 1.5em; | ||||
|     --ck-inline-image-style-spacing: calc(var(--ck-image-style-spacing) / 2); | ||||
|     --ck-todo-list-checkmark-size: 16px; | ||||
| } | ||||
|  | ||||
| /* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table .ck-table-resized { | ||||
|     table-layout: fixed; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table table { | ||||
|     overflow: hidden; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/tablecolumnresize.css */ | ||||
| .ck-content .table td, | ||||
| .ck-content .table th { | ||||
|     overflow-wrap: break-word; | ||||
|     position: relative; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table { | ||||
|     margin: 0.9em auto; | ||||
|     display: table; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table table { | ||||
|     border-collapse: collapse; | ||||
|     border-spacing: 0; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     border: 1px double hsl(0, 0%, 70%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table table td, | ||||
| .ck-content .table table th { | ||||
|     min-width: 2em; | ||||
|     padding: .4em; | ||||
|     border: 1px solid hsl(0, 0%, 75%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/table.css */ | ||||
| .ck-content .table table th { | ||||
|     font-weight: bold; | ||||
|     background: hsla(0, 0%, 0%, 5%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/table.css */ | ||||
| .ck-content[dir="rtl"] .table th { | ||||
|     text-align: right; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/table.css */ | ||||
| .ck-content[dir="ltr"] .table th { | ||||
|     text-align: left; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-table/theme/tablecaption.css */ | ||||
| .ck-content .table > figcaption { | ||||
|     display: table-caption; | ||||
|     caption-side: top; | ||||
|     word-break: break-word; | ||||
|     text-align: center; | ||||
|     color: var(--ck-color-selector-caption-text); | ||||
|     background-color: var(--ck-color-selector-caption-background); | ||||
|     padding: .6em; | ||||
|     font-size: .75em; | ||||
|     outline-offset: -1px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */ | ||||
| .ck-content .page-break { | ||||
|     position: relative; | ||||
|     clear: both; | ||||
|     padding: 5px 0; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */ | ||||
| .ck-content .page-break::after { | ||||
|     content: ''; | ||||
|     position: absolute; | ||||
|     border-bottom: 2px dashed hsl(0, 0%, 77%); | ||||
|     width: 100%; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */ | ||||
| .ck-content .page-break__label { | ||||
|     position: relative; | ||||
|     z-index: 1; | ||||
|     padding: .3em .6em; | ||||
|     display: block; | ||||
|     text-transform: uppercase; | ||||
|     border: 1px solid hsl(0, 0%, 77%); | ||||
|     border-radius: 2px; | ||||
|     font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif; | ||||
|     font-size: 0.75em; | ||||
|     font-weight: bold; | ||||
|     color: hsl(0, 0%, 20%); | ||||
|     background: hsl(0, 0%, 100%); | ||||
|     box-shadow: 2px 2px 1px hsla(0, 0%, 0%, 0.15); | ||||
|     -webkit-user-select: none; | ||||
|     -moz-user-select: none; | ||||
|     -ms-user-select: none; | ||||
|     user-select: none; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-media-embed/theme/mediaembed.css */ | ||||
| .ck-content .media { | ||||
|     clear: both; | ||||
|     margin: 0.9em 0; | ||||
|     display: block; | ||||
|     min-width: 15em; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list { | ||||
|     list-style: none; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list li { | ||||
|     position: relative; | ||||
|     margin-bottom: 5px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list li .todo-list { | ||||
|     margin-top: 5px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input { | ||||
|     -webkit-appearance: none; | ||||
|     display: inline-block; | ||||
|     position: relative; | ||||
|     width: var(--ck-todo-list-checkmark-size); | ||||
|     height: var(--ck-todo-list-checkmark-size); | ||||
|     vertical-align: middle; | ||||
|     border: 0; | ||||
|     left: -25px; | ||||
|     margin-right: -15px; | ||||
|     right: 0; | ||||
|     margin-left: 0; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content[dir=rtl] .todo-list .todo-list__label > input { | ||||
|     left: 0; | ||||
|     margin-right: 0; | ||||
|     right: -25px; | ||||
|     margin-left: -15px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input::before { | ||||
|     display: block; | ||||
|     position: absolute; | ||||
|     box-sizing: border-box; | ||||
|     content: ''; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     border: 1px solid hsl(0, 0%, 20%); | ||||
|     border-radius: 2px; | ||||
|     transition: 250ms ease-in-out box-shadow; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input::after { | ||||
|     display: block; | ||||
|     position: absolute; | ||||
|     box-sizing: content-box; | ||||
|     pointer-events: none; | ||||
|     content: ''; | ||||
|     left: calc( var(--ck-todo-list-checkmark-size) / 3 ); | ||||
|     top: calc( var(--ck-todo-list-checkmark-size) / 5.3 ); | ||||
|     width: calc( var(--ck-todo-list-checkmark-size) / 5.3 ); | ||||
|     height: calc( var(--ck-todo-list-checkmark-size) / 2.6 ); | ||||
|     border-style: solid; | ||||
|     border-color: transparent; | ||||
|     border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0; | ||||
|     transform: rotate(45deg); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input[checked]::before { | ||||
|     background: hsl(126, 64%, 41%); | ||||
|     border-color: hsl(126, 64%, 41%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label > input[checked]::after { | ||||
|     border-color: hsl(0, 0%, 100%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label .todo-list__label__description { | ||||
|     vertical-align: middle; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] { | ||||
|     position: absolute; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > input, | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input { | ||||
|     cursor: pointer; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > input:hover::before, .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input:hover::before { | ||||
|     box-shadow: 0 0 0 5px hsla(0, 0%, 0%, 0.1); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input { | ||||
|     -webkit-appearance: none; | ||||
|     display: inline-block; | ||||
|     position: relative; | ||||
|     width: var(--ck-todo-list-checkmark-size); | ||||
|     height: var(--ck-todo-list-checkmark-size); | ||||
|     vertical-align: middle; | ||||
|     border: 0; | ||||
|     left: -25px; | ||||
|     margin-right: -15px; | ||||
|     right: 0; | ||||
|     margin-left: 0; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content[dir=rtl] .todo-list .todo-list__label > span[contenteditable=false] > input { | ||||
|     left: 0; | ||||
|     margin-right: 0; | ||||
|     right: -25px; | ||||
|     margin-left: -15px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::before { | ||||
|     display: block; | ||||
|     position: absolute; | ||||
|     box-sizing: border-box; | ||||
|     content: ''; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|     border: 1px solid hsl(0, 0%, 20%); | ||||
|     border-radius: 2px; | ||||
|     transition: 250ms ease-in-out box-shadow; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input::after { | ||||
|     display: block; | ||||
|     position: absolute; | ||||
|     box-sizing: content-box; | ||||
|     pointer-events: none; | ||||
|     content: ''; | ||||
|     left: calc( var(--ck-todo-list-checkmark-size) / 3 ); | ||||
|     top: calc( var(--ck-todo-list-checkmark-size) / 5.3 ); | ||||
|     width: calc( var(--ck-todo-list-checkmark-size) / 5.3 ); | ||||
|     height: calc( var(--ck-todo-list-checkmark-size) / 2.6 ); | ||||
|     border-style: solid; | ||||
|     border-color: transparent; | ||||
|     border-width: 0 calc( var(--ck-todo-list-checkmark-size) / 8 ) calc( var(--ck-todo-list-checkmark-size) / 8 ) 0; | ||||
|     transform: rotate(45deg); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::before { | ||||
|     background: hsl(126, 64%, 41%); | ||||
|     border-color: hsl(126, 64%, 41%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label > span[contenteditable=false] > input[checked]::after { | ||||
|     border-color: hsl(0, 0%, 100%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/todolist.css */ | ||||
| .ck-editor__editable.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type=checkbox] { | ||||
|     position: absolute; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ol { | ||||
|     list-style-type: decimal; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ol ol { | ||||
|     list-style-type: lower-latin; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ol ol ol { | ||||
|     list-style-type: lower-roman; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ol ol ol ol { | ||||
|     list-style-type: upper-latin; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ol ol ol ol ol { | ||||
|     list-style-type: upper-roman; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ul { | ||||
|     list-style-type: disc; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ul ul { | ||||
|     list-style-type: circle; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ul ul ul { | ||||
|     list-style-type: square; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-list/theme/list.css */ | ||||
| .ck-content ul ul ul ul { | ||||
|     list-style-type: square; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image { | ||||
|     display: table; | ||||
|     clear: both; | ||||
|     text-align: center; | ||||
|     margin: 0.9em auto; | ||||
|     min-width: 50px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image img { | ||||
|     display: block; | ||||
|     margin: 0 auto; | ||||
|     max-width: 100%; | ||||
|     min-width: 100%; | ||||
|     height: auto; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image-inline { | ||||
|     /* | ||||
|      * Normally, the .image-inline would have "display: inline-block" and "img { width: 100% }" (to follow the wrapper while resizing).; | ||||
|      * Unfortunately, together with "srcset", it gets automatically stretched up to the width of the editing root. | ||||
|      * This strange behavior does not happen with inline-flex. | ||||
|      */ | ||||
|     display: inline-flex; | ||||
|     max-width: 100%; | ||||
|     align-items: flex-start; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image-inline picture { | ||||
|     display: flex; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/image.css */ | ||||
| .ck-content .image-inline picture, | ||||
| .ck-content .image-inline img { | ||||
|     flex-grow: 1; | ||||
|     flex-shrink: 1; | ||||
|     max-width: 100%; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imageresize.css */ | ||||
| .ck-content img.image_resized { | ||||
|     height: auto; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imageresize.css */ | ||||
| .ck-content .image.image_resized { | ||||
|     max-width: 100%; | ||||
|     display: block; | ||||
|     box-sizing: border-box; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imageresize.css */ | ||||
| .ck-content .image.image_resized img { | ||||
|     width: 100%; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imageresize.css */ | ||||
| .ck-content .image.image_resized > figcaption { | ||||
|     display: block; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagecaption.css */ | ||||
| .ck-content .image > figcaption { | ||||
|     display: table-caption; | ||||
|     caption-side: bottom; | ||||
|     word-break: break-word; | ||||
|     color: var(--ck-color-image-caption-text); | ||||
|     background-color: var(--ck-color-image-caption-background); | ||||
|     padding: .6em; | ||||
|     font-size: .75em; | ||||
|     outline-offset: -1px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-block-align-left, | ||||
| .ck-content .image-style-block-align-right { | ||||
|     max-width: calc(100% - var(--ck-image-style-spacing)); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-left, | ||||
| .ck-content .image-style-align-right { | ||||
|     clear: none; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-side { | ||||
|     float: right; | ||||
|     margin-left: var(--ck-image-style-spacing); | ||||
|     max-width: 50%; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-left { | ||||
|     float: left; | ||||
|     margin-right: var(--ck-image-style-spacing); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-center { | ||||
|     margin-left: auto; | ||||
|     margin-right: auto; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-align-right { | ||||
|     float: right; | ||||
|     margin-left: var(--ck-image-style-spacing); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-block-align-right { | ||||
|     margin-right: 0; | ||||
|     margin-left: auto; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-style-block-align-left { | ||||
|     margin-left: 0; | ||||
|     margin-right: auto; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content p + .image-style-align-left, | ||||
| .ck-content p + .image-style-align-right, | ||||
| .ck-content p + .image-style-side { | ||||
|     margin-top: 0; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-inline.image-style-align-left, | ||||
| .ck-content .image-inline.image-style-align-right { | ||||
|     margin-top: var(--ck-inline-image-style-spacing); | ||||
|     margin-bottom: var(--ck-inline-image-style-spacing); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-inline.image-style-align-left { | ||||
|     margin-right: var(--ck-inline-image-style-spacing); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-image/theme/imagestyle.css */ | ||||
| .ck-content .image-inline.image-style-align-right { | ||||
|     margin-left: var(--ck-inline-image-style-spacing); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-yellow { | ||||
|     background-color: var(--ck-highlight-marker-yellow); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-green { | ||||
|     background-color: var(--ck-highlight-marker-green); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-pink { | ||||
|     background-color: var(--ck-highlight-marker-pink); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .marker-blue { | ||||
|     background-color: var(--ck-highlight-marker-blue); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .pen-red { | ||||
|     color: var(--ck-highlight-pen-red); | ||||
|     background-color: transparent; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-highlight/theme/highlight.css */ | ||||
| .ck-content .pen-green { | ||||
|     color: var(--ck-highlight-pen-green); | ||||
|     background-color: transparent; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */ | ||||
| .ck-content blockquote { | ||||
|     overflow: hidden; | ||||
|     padding-right: 1.5em; | ||||
|     padding-left: 1.5em; | ||||
|     margin-left: 0; | ||||
|     margin-right: 0; | ||||
|     font-style: italic; | ||||
|     border-left: solid 5px hsl(0, 0%, 80%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-block-quote/theme/blockquote.css */ | ||||
| .ck-content[dir="rtl"] blockquote { | ||||
|     border-left: 0; | ||||
|     border-right: solid 5px hsl(0, 0%, 80%); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-basic-styles/theme/code.css */ | ||||
| .ck-content code { | ||||
|     background-color: hsla(0, 0%, 78%, 0.3); | ||||
|     padding: .15em; | ||||
|     border-radius: 2px; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-tiny { | ||||
|     font-size: .7em; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-small { | ||||
|     font-size: .85em; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-big { | ||||
|     font-size: 1.4em; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-font/theme/fontsize.css */ | ||||
| .ck-content .text-huge { | ||||
|     font-size: 1.8em; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-mention/theme/mention.css */ | ||||
| .ck-content .mention { | ||||
|     background: var(--ck-color-mention-background); | ||||
|     color: var(--ck-color-mention-text); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-horizontal-line/theme/horizontalline.css */ | ||||
| .ck-content hr { | ||||
|     margin: 15px 0; | ||||
|     height: 4px; | ||||
|     background: hsl(0, 0%, 87%); | ||||
|     border: 0; | ||||
| } | ||||
| /* @ckeditor/ckeditor5-code-block/theme/codeblock.css */ | ||||
| .ck-content pre { | ||||
|     padding: 1em; | ||||
|     text-align: left; | ||||
|     direction: ltr; | ||||
|     tab-size: 4; | ||||
|     white-space: pre-wrap; | ||||
|     font-style: normal; | ||||
|     min-width: 200px; | ||||
|     border: 0px; | ||||
|     border-radius: 6px; | ||||
|     box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.2); | ||||
| } | ||||
| .ck-content pre:not(.hljs) { | ||||
|     color: hsl(0, 0%, 20.8%);     | ||||
|     background: hsla(0, 0%, 78%, 0.3); | ||||
| } | ||||
| /* @ckeditor/ckeditor5-code-block/theme/codeblock.css */ | ||||
| .ck-content pre code { | ||||
|     background: unset; | ||||
|     padding: 0; | ||||
|     border-radius: 0; | ||||
| } | ||||
| @media print { | ||||
|     /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */ | ||||
|     .ck-content .page-break { | ||||
|         padding: 0; | ||||
|     } | ||||
|     /* @ckeditor/ckeditor5-page-break/theme/pagebreak.css */ | ||||
|     .ck-content .page-break::after { | ||||
|         display: none; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										43
									
								
								_regroup/test-etapi/api-metrics.http
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,43 @@ | ||||
| ### Test regular API metrics endpoint (requires session authentication) | ||||
|  | ||||
| ### Get metrics from regular API (default Prometheus format) | ||||
| GET {{triliumHost}}/api/metrics | ||||
|  | ||||
| > {% | ||||
| client.test("API metrics endpoint returns Prometheus format by default", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain"); | ||||
|     client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric"); | ||||
|     client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric"); | ||||
|     client.assert(response.body.includes("# HELP"), "Should contain HELP comments"); | ||||
|     client.assert(response.body.includes("# TYPE"), "Should contain TYPE comments"); | ||||
| }); | ||||
| %} | ||||
|  | ||||
| ### Get metrics in JSON format | ||||
| GET {{triliumHost}}/api/metrics?format=json | ||||
|  | ||||
| > {% | ||||
| client.test("API metrics endpoint returns JSON when requested", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("application/json"), "Content-Type should be application/json"); | ||||
|     client.assert(response.body.version, "Version info not present"); | ||||
|     client.assert(response.body.database, "Database info not present"); | ||||
|     client.assert(response.body.timestamp, "Timestamp not present"); | ||||
|     client.assert(typeof response.body.database.totalNotes === 'number', "Total notes should be a number"); | ||||
|     client.assert(typeof response.body.database.activeNotes === 'number', "Active notes should be a number"); | ||||
|     client.assert(response.body.noteTypes, "Note types breakdown not present"); | ||||
|     client.assert(response.body.attachmentTypes, "Attachment types breakdown not present"); | ||||
|     client.assert(response.body.statistics, "Statistics not present"); | ||||
| }); | ||||
| %} | ||||
|  | ||||
| ### Test invalid format parameter | ||||
| GET {{triliumHost}}/api/metrics?format=xml | ||||
|  | ||||
| > {% | ||||
| client.test("Invalid format parameter returns error", function() { | ||||
|     client.assert(response.status === 500, "Response status should be 500"); | ||||
|     client.assert(response.body.message.includes("prometheus"), "Error message should mention supported formats"); | ||||
| }); | ||||
| %}  | ||||
							
								
								
									
										82
									
								
								_regroup/test-etapi/metrics.http
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,82 @@ | ||||
| ### Test ETAPI metrics endpoint | ||||
|  | ||||
| # First login to get a token | ||||
| POST {{triliumHost}}/etapi/auth/login | ||||
| Content-Type: application/json | ||||
|  | ||||
| { | ||||
|   "password": "{{password}}" | ||||
| } | ||||
|  | ||||
| > {% | ||||
| client.test("Login successful", function() { | ||||
|     client.assert(response.status === 201, "Response status is not 201"); | ||||
|     client.assert(response.body.authToken, "Auth token not present"); | ||||
|     client.global.set("authToken", response.body.authToken); | ||||
| }); | ||||
| %} | ||||
|  | ||||
| ### Get metrics with authentication (default Prometheus format) | ||||
| GET {{triliumHost}}/etapi/metrics | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
| client.test("Metrics endpoint returns Prometheus format by default", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain"); | ||||
|     client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric"); | ||||
|     client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric"); | ||||
|     client.assert(response.body.includes("# HELP"), "Should contain HELP comments"); | ||||
|     client.assert(response.body.includes("# TYPE"), "Should contain TYPE comments"); | ||||
| }); | ||||
| %} | ||||
|  | ||||
| ### Get metrics in JSON format | ||||
| GET {{triliumHost}}/etapi/metrics?format=json | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
| client.test("Metrics endpoint returns JSON when requested", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("application/json"), "Content-Type should be application/json"); | ||||
|     client.assert(response.body.version, "Version info not present"); | ||||
|     client.assert(response.body.database, "Database info not present"); | ||||
|     client.assert(response.body.timestamp, "Timestamp not present"); | ||||
|     client.assert(typeof response.body.database.totalNotes === 'number', "Total notes should be a number"); | ||||
|     client.assert(typeof response.body.database.activeNotes === 'number', "Active notes should be a number"); | ||||
| }); | ||||
| %} | ||||
|  | ||||
| ### Get metrics in Prometheus format explicitly | ||||
| GET {{triliumHost}}/etapi/metrics?format=prometheus | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
| client.test("Metrics endpoint returns Prometheus format when requested", function() { | ||||
|     client.assert(response.status === 200, "Response status is not 200"); | ||||
|     client.assert(response.headers["content-type"].includes("text/plain"), "Content-Type should be text/plain"); | ||||
|     client.assert(response.body.includes("trilium_info"), "Should contain trilium_info metric"); | ||||
|     client.assert(response.body.includes("trilium_notes_total"), "Should contain trilium_notes_total metric"); | ||||
| }); | ||||
| %} | ||||
|  | ||||
| ### Test invalid format parameter | ||||
| GET {{triliumHost}}/etapi/metrics?format=xml | ||||
| Authorization: {{authToken}} | ||||
|  | ||||
| > {% | ||||
| client.test("Invalid format parameter returns error", function() { | ||||
|     client.assert(response.status === 400, "Response status should be 400"); | ||||
|     client.assert(response.body.code === "INVALID_FORMAT", "Error code should be INVALID_FORMAT"); | ||||
|     client.assert(response.body.message.includes("prometheus"), "Error message should mention supported formats"); | ||||
| }); | ||||
| %} | ||||
|  | ||||
| ### Test without authentication (should fail) | ||||
| GET {{triliumHost}}/etapi/metrics | ||||
|  | ||||
| > {% | ||||
| client.test("Metrics endpoint requires authentication", function() { | ||||
|     client.assert(response.status === 401, "Response status should be 401"); | ||||
| }); | ||||
| %}  | ||||
| @@ -159,6 +159,9 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded"> | ||||
|     } | ||||
|  | ||||
|     saveToRecentNotes(resolvedNotePath: string) { | ||||
|         if (options.is("databaseReadonly")) { | ||||
|             return; | ||||
|         } | ||||
|         setTimeout(async () => { | ||||
|             // we include the note in the recent list only if the user stayed on the note at least 5 seconds | ||||
|             if (resolvedNotePath && resolvedNotePath === this.notePath) { | ||||
| @@ -254,6 +257,10 @@ class NoteContext extends Component implements EventListener<"entitiesReloaded"> | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         if (options.is("databaseReadonly")) { | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         if (this.note.isLabelTruthy("readOnly")) { | ||||
|             return true; | ||||
|         } | ||||
|   | ||||
| @@ -44,6 +44,9 @@ export default class TabManager extends Component { | ||||
|             if (!appContext.isMainWindow) { | ||||
|                 return; | ||||
|             } | ||||
|             if (options.is("databaseReadonly")) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             const openNoteContexts = this.noteContexts | ||||
|                 .map((nc) => nc.getPojoState()) | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import froca from "./froca.js"; | ||||
| import linkService from "./link.js"; | ||||
| import utils from "./utils.js"; | ||||
| import { t } from "./i18n.js"; | ||||
| import toast from "./toast.js"; | ||||
|  | ||||
| let clipboardBranchIds: string[] = []; | ||||
| let clipboardMode: string | null = null; | ||||
| @@ -108,6 +109,39 @@ function isClipboardEmpty() { | ||||
|     return clipboardBranchIds.length === 0; | ||||
| } | ||||
|  | ||||
| export function copyText(text: string) { | ||||
|     if (!text) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     let succeeded = false; | ||||
|  | ||||
|     try { | ||||
|         if (navigator.clipboard) { | ||||
|             navigator.clipboard.writeText(text); | ||||
|             succeeded = true; | ||||
|         } else { | ||||
|             // Fallback method: https://stackoverflow.com/a/72239825 | ||||
|             const textArea = document.createElement("textarea"); | ||||
|             textArea.value = text; | ||||
|             document.body.appendChild(textArea); | ||||
|             textArea.focus(); | ||||
|             textArea.select(); | ||||
|             succeeded = document.execCommand('copy'); | ||||
|             document.body.removeChild(textArea); | ||||
|         } | ||||
|     } catch (e) { | ||||
|         console.warn(e); | ||||
|         succeeded = false; | ||||
|     } | ||||
|  | ||||
|     if (succeeded) { | ||||
|         toast.showMessage(t("code_block.copy_success")); | ||||
|     } else { | ||||
|         toast.showError(t("code_block.copy_failed")); | ||||
|     } | ||||
| } | ||||
|  | ||||
| export default { | ||||
|     pasteAfter, | ||||
|     pasteInto, | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import treeService from "./tree.js"; | ||||
| import FNote from "../entities/fnote.js"; | ||||
| import FAttachment from "../entities/fattachment.js"; | ||||
| import imageContextMenuService from "../menus/image_context_menu.js"; | ||||
| import { applySingleBlockSyntaxHighlight, applySyntaxHighlight } from "./syntax_highlight.js"; | ||||
| import { applySingleBlockSyntaxHighlight, formatCodeBlocks } from "./syntax_highlight.js"; | ||||
| import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js"; | ||||
| import renderDoc from "./doc_renderer.js"; | ||||
| import { t } from "../services/i18n.js"; | ||||
| @@ -106,7 +106,7 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HT | ||||
|             await linkService.loadReferenceLinkTitle($(el)); | ||||
|         } | ||||
|  | ||||
|         await applySyntaxHighlight($renderedContent); | ||||
|         await formatCodeBlocks($renderedContent); | ||||
|     } else if (note instanceof FNote) { | ||||
|         await renderChildrenList($renderedContent, note); | ||||
|     } | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import type FNote from "../entities/fnote.js"; | ||||
| import { getCurrentLanguage } from "./i18n.js"; | ||||
| import { applySyntaxHighlight } from "./syntax_highlight.js"; | ||||
| import { formatCodeBlocks } from "./syntax_highlight.js"; | ||||
|  | ||||
| export default function renderDoc(note: FNote) { | ||||
|     return new Promise<JQuery<HTMLElement>>((resolve) => { | ||||
| @@ -41,7 +41,7 @@ function processContent(url: string, $content: JQuery<HTMLElement>) { | ||||
|         $img.attr("src", dir + "/" + $img.attr("src")); | ||||
|     }); | ||||
|  | ||||
|     applySyntaxHighlight($content); | ||||
|     formatCodeBlocks($content); | ||||
| } | ||||
|  | ||||
| function getUrl(docNameValue: string, language: string) { | ||||
|   | ||||
| @@ -1,21 +1,23 @@ | ||||
| import { ensureMimeTypes, highlight, highlightAuto, loadTheme, Themes } from "@triliumnext/highlightjs"; | ||||
| import { ensureMimeTypes, highlight, highlightAuto, loadTheme, Themes, type AutoHighlightResult, type HighlightResult, type Theme } from "@triliumnext/highlightjs"; | ||||
| import mime_types from "./mime_types.js"; | ||||
| import options from "./options.js"; | ||||
| import { t } from "./i18n.js"; | ||||
| import { copyText } from "./clipboard.js"; | ||||
|  | ||||
| let highlightingLoaded = false; | ||||
|  | ||||
| /** | ||||
|  * Identifies all the code blocks (as `pre code`) under the specified hierarchy and uses the highlight.js library to obtain the highlighted text which is then applied on to the code blocks. | ||||
|  * Additionally, adds a "Copy to clipboard" button. | ||||
|  * | ||||
|  * @param $container the container under which to look for code blocks and to apply syntax highlighting to them. | ||||
|  */ | ||||
| export async function applySyntaxHighlight($container: JQuery<HTMLElement>) { | ||||
|     if (!isSyntaxHighlightEnabled()) { | ||||
|         return; | ||||
| export async function formatCodeBlocks($container: JQuery<HTMLElement>) { | ||||
|     const syntaxHighlightingEnabled = isSyntaxHighlightEnabled(); | ||||
|     if (syntaxHighlightingEnabled) { | ||||
|         await ensureMimeTypesForHighlighting(); | ||||
|     } | ||||
|  | ||||
|     await ensureMimeTypesForHighlighting(); | ||||
|  | ||||
|     const codeBlocks = $container.find("pre code"); | ||||
|     for (const codeBlock of codeBlocks) { | ||||
|         const normalizedMimeType = extractLanguageFromClassList(codeBlock); | ||||
| @@ -23,10 +25,22 @@ export async function applySyntaxHighlight($container: JQuery<HTMLElement>) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         applySingleBlockSyntaxHighlight($(codeBlock), normalizedMimeType); | ||||
|         applyCopyToClipboardButton($(codeBlock)); | ||||
|  | ||||
|         if (syntaxHighlightingEnabled) { | ||||
|             applySingleBlockSyntaxHighlight($(codeBlock), normalizedMimeType); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| export function applyCopyToClipboardButton($codeBlock: JQuery<HTMLElement>) { | ||||
|     const $copyButton = $("<button>") | ||||
|         .addClass("bx component icon-action tn-tool-button bx-copy copy-button") | ||||
|         .attr("title", t("code_block.copy_title")) | ||||
|         .on("click", () => copyText($codeBlock.text())); | ||||
|     $codeBlock.parent().append($copyButton); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Applies syntax highlight to the given code block (assumed to be <pre><code>), using highlight.js. | ||||
|  */ | ||||
| @@ -34,7 +48,7 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle | ||||
|     $codeBlock.parent().toggleClass("hljs"); | ||||
|     const text = $codeBlock.text(); | ||||
|  | ||||
|     let highlightedText = null; | ||||
|     let highlightedText: HighlightResult | AutoHighlightResult | null = null; | ||||
|     if (normalizedMimeType === mime_types.MIME_TYPE_AUTO) { | ||||
|         await ensureMimeTypesForHighlighting(); | ||||
|         highlightedText = highlightAuto(text); | ||||
| @@ -66,7 +80,7 @@ export async function ensureMimeTypesForHighlighting() { | ||||
|  | ||||
| export function loadHighlightingTheme(themeName: string) { | ||||
|     const themePrefix = "default:"; | ||||
|     let theme = null; | ||||
|     let theme: Theme | null = null; | ||||
|     if (themeName.includes(themePrefix)) { | ||||
|         theme = Themes[themeName.substring(themePrefix.length)]; | ||||
|     } | ||||
|   | ||||
| @@ -529,6 +529,31 @@ pre:not(.hljs) { | ||||
|     font-size: 100%; | ||||
| } | ||||
|  | ||||
| pre { | ||||
|     --copy-button-margin-size: .35em; | ||||
|  | ||||
|     position: relative; | ||||
| } | ||||
|  | ||||
| pre > button.copy-button { | ||||
|     position: absolute; | ||||
|     top: var(--copy-button-margin-size); | ||||
|     right: var(--copy-button-margin-size); | ||||
| } | ||||
|  | ||||
| :root pre:has(> button.copy-button) > code { | ||||
|     margin-right: calc(var(--icon-button-size) + (var(--copy-button-margin-size) * 2)); | ||||
| } | ||||
|  | ||||
| pre > button.copy-button:hover { | ||||
|     color: inherit !important; | ||||
|     opacity: 1; | ||||
| } | ||||
|  | ||||
| pre > button.copy-button:active { | ||||
|     background-color: unset !important; | ||||
| } | ||||
|  | ||||
| .pointer { | ||||
|     cursor: pointer; | ||||
| } | ||||
|   | ||||
| @@ -1830,7 +1830,10 @@ | ||||
|     "word_wrapping": "Word wrapping", | ||||
|     "theme_none": "No syntax highlighting", | ||||
|     "theme_group_light": "Light themes", | ||||
|     "theme_group_dark": "Dark themes" | ||||
|     "theme_group_dark": "Dark themes", | ||||
|     "copy_success": "The code block was copied to clipboard.", | ||||
|     "copy_failed": "The code block could not be copied to the clipboard due to lack of permissions.", | ||||
|     "copy_title": "Copy to clipboard" | ||||
|   }, | ||||
|   "classic_editor_toolbar": { | ||||
|     "title": "Formatting" | ||||
|   | ||||
							
								
								
									
										10
									
								
								apps/client/src/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -93,16 +93,6 @@ declare global { | ||||
|         getSelectedExternalLink(): string | undefined; | ||||
|         setSelectedExternalLink(externalLink: string | null | undefined); | ||||
|         setNote(noteId: string); | ||||
|         markRegExp(regex: RegExp, opts: { | ||||
|             element: string; | ||||
|             className: string; | ||||
|             separateWordSearch: boolean; | ||||
|             caseSensitive: boolean; | ||||
|             done?: () => void; | ||||
|         }); | ||||
|         unmark(opts?: { | ||||
|             done: () => void; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     interface JQueryStatic { | ||||
|   | ||||
| @@ -248,10 +248,10 @@ export default class FindWidget extends NoteContextAwareWidget { | ||||
|             case "code": | ||||
|                 return this.codeHandler; | ||||
|             case "text": | ||||
|                 return this.textHandler; | ||||
|             default: | ||||
|                 const readOnly = await this.noteContext?.isReadOnly(); | ||||
|                 return readOnly ? this.htmlHandler : this.textHandler; | ||||
|             default: | ||||
|                 console.warn("FindWidget: Unsupported note type for find widget", this.note?.type); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| // ck-find-result and ck-find-result_selected are the styles ck-editor | ||||
| // uses for highlighting matches, use the same one on CodeMirror | ||||
| // for consistency | ||||
| import type Mark from "mark.js"; | ||||
| import utils from "../services/utils.js"; | ||||
| import type FindWidget from "./find.js"; | ||||
| import type { FindResult } from "./find.js"; | ||||
| @@ -13,6 +14,7 @@ export default class FindInHtml { | ||||
|     private parent: FindWidget; | ||||
|     private currentIndex: number; | ||||
|     private $results: JQuery<HTMLElement> | null; | ||||
|     private mark?: Mark; | ||||
|  | ||||
|     constructor(parent: FindWidget) { | ||||
|         this.parent = parent; | ||||
| @@ -21,21 +23,24 @@ export default class FindInHtml { | ||||
|     } | ||||
|  | ||||
|     async performFind(searchTerm: string, matchCase: boolean, wholeWord: boolean) { | ||||
|         await import("mark.js"); | ||||
|  | ||||
|         const $content = await this.parent?.noteContext?.getContentElement(); | ||||
|         if (!$content || !$content.length) { | ||||
|             return Promise.resolve({ totalFound: 0, currentFound: 0 }); | ||||
|         } | ||||
|  | ||||
|         if (!this.mark) { | ||||
|             this.mark = new (await import("mark.js")).default($content[0]); | ||||
|         } | ||||
|  | ||||
|         const wholeWordChar = wholeWord ? "\\b" : ""; | ||||
|         const regExp = new RegExp(wholeWordChar + utils.escapeRegExp(searchTerm) + wholeWordChar, matchCase ? "g" : "gi"); | ||||
|  | ||||
|         return new Promise<FindResult>((res) => { | ||||
|             $content?.unmark({ | ||||
|             this.mark!.unmark({ | ||||
|                 done: () => { | ||||
|                     $content.markRegExp(regExp, { | ||||
|                     this.mark!.markRegExp(regExp, { | ||||
|                         element: "span", | ||||
|                         className: FIND_RESULT_CSS_CLASSNAME, | ||||
|                         separateWordSearch: false, | ||||
|                         caseSensitive: matchCase, | ||||
|                         done: async () => { | ||||
|                             this.$results = $content.find(`.${FIND_RESULT_CSS_CLASSNAME}`); | ||||
|                             const scrollingContainer = $content[0].closest('.scrolling-container'); | ||||
| @@ -73,10 +78,7 @@ export default class FindInHtml { | ||||
|     } | ||||
|  | ||||
|     async findBoxClosed(totalFound: number, currentFound: number) { | ||||
|         const $content = await this.parent?.noteContext?.getContentElement(); | ||||
|         if (typeof $content?.unmark === 'function') { | ||||
|             $content.unmark(); | ||||
|         } | ||||
|         this.mark?.unmark(); | ||||
|     } | ||||
|  | ||||
|     async jumpTo() { | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import { t } from "../../services/i18n.js"; | ||||
| import LoadResults from "../../services/load_results.js"; | ||||
| import type { AttributeRow } from "../../services/load_results.js"; | ||||
| import FNote from "../../entities/fnote.js"; | ||||
| import options from "../../services/options.js"; | ||||
|  | ||||
| export default class EditButton extends OnClickButtonWidget { | ||||
|     isEnabled(): boolean { | ||||
| @@ -27,6 +28,10 @@ export default class EditButton extends OnClickButtonWidget { | ||||
|     } | ||||
|  | ||||
|     async refreshWithNote(note: FNote): Promise<void> { | ||||
|         if (options.is("databaseReadonly")) { | ||||
|             this.toggleInt(false); | ||||
|             return; | ||||
|         } | ||||
|         if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) { | ||||
|             this.toggleInt(false); | ||||
|         } else { | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import { createChatSession, checkSessionExists, setupStreamingResponse, getDirec | ||||
| import { extractInChatToolSteps } from "./message_processor.js"; | ||||
| import { validateEmbeddingProviders } from "./validation.js"; | ||||
| import type { MessageData, ToolExecutionStep, ChatData } from "./types.js"; | ||||
| import { applySyntaxHighlight } from "../../services/syntax_highlight.js"; | ||||
| import { formatCodeBlocks } from "../../services/syntax_highlight.js"; | ||||
|  | ||||
| import "../../stylesheets/llm_chat.css"; | ||||
|  | ||||
| @@ -925,7 +925,7 @@ export default class LlmChatPanel extends BasicWidget { | ||||
|  | ||||
|         // Apply syntax highlighting if this is the final update | ||||
|         if (isDone) { | ||||
|             applySyntaxHighlight($(assistantMessageEl as HTMLElement)); | ||||
|             formatCodeBlocks($(assistantMessageEl as HTMLElement)); | ||||
|  | ||||
|             // Update message in the data model for storage | ||||
|             // Find the last assistant message to update, or add a new one if none exists | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  * Utility functions for LLM Chat | ||||
|  */ | ||||
| import { marked } from "marked"; | ||||
| import { applySyntaxHighlight } from "../../services/syntax_highlight.js"; | ||||
| import { formatCodeBlocks } from "../../services/syntax_highlight.js"; | ||||
|  | ||||
| /** | ||||
|  * Format markdown content for display | ||||
| @@ -62,7 +62,7 @@ export function escapeHtml(text: string): string { | ||||
|  * Apply syntax highlighting to content | ||||
|  */ | ||||
| export function applyHighlighting(element: HTMLElement): void { | ||||
|     applySyntaxHighlight($(element)); | ||||
|     formatCodeBlocks($(element)); | ||||
| } | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -1172,16 +1172,19 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { | ||||
|  | ||||
|             let noneCollapsedYet = true; | ||||
|  | ||||
|             this.tree.getRootNode().visit((node) => { | ||||
|                 if (node.isExpanded() && !noteIdsToKeepExpanded.has(node.data.noteId)) { | ||||
|                     node.setExpanded(false); | ||||
|             if (!options.is("databaseReadonly")) { | ||||
|                 // can't change expanded notes when database is readonly | ||||
|                 this.tree.getRootNode().visit((node) => { | ||||
|                     if (node.isExpanded() && !noteIdsToKeepExpanded.has(node.data.noteId)) { | ||||
|                         node.setExpanded(false); | ||||
|  | ||||
|                     if (noneCollapsedYet) { | ||||
|                         toastService.showMessage(t("note_tree.auto-collapsing-notes-after-inactivity")); | ||||
|                         noneCollapsedYet = false; | ||||
|                         if (noneCollapsedYet) { | ||||
|                             toastService.showMessage(t("note_tree.auto-collapsing-notes-after-inactivity")); | ||||
|                             noneCollapsedYet = false; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             }, false); | ||||
|                 }, false); | ||||
|             } | ||||
|  | ||||
|             this.filterHoistedBranch(true); | ||||
|         }, 600 * 1000); | ||||
|   | ||||
| @@ -3,6 +3,7 @@ import utils from "../../services/utils.js"; | ||||
| import linkService from "../../services/link.js"; | ||||
| import server from "../../services/server.js"; | ||||
| import type FNote from "../../entities/fnote.js"; | ||||
| import options from "../../services/options.js"; | ||||
| import type { ExcalidrawElement, Theme } from "@excalidraw/excalidraw/element/types"; | ||||
| import type { AppState, BinaryFileData, ExcalidrawImperativeAPI, ExcalidrawProps, LibraryItem, SceneData } from "@excalidraw/excalidraw/types"; | ||||
| import type { JSX } from "react"; | ||||
| @@ -447,6 +448,9 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|     } | ||||
|  | ||||
|     onChangeHandler() { | ||||
|         if (options.is("databaseReadonly")) { | ||||
|             return; | ||||
|         } | ||||
|         // changeHandler is called upon any tiny change in excalidraw. button clicked, hover, etc. | ||||
|         // make sure only when a new element is added, we actually save something. | ||||
|         const isNewSceneVersion = this.isNewSceneVersion(); | ||||
| @@ -540,7 +544,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|                         this.saveData(); | ||||
|                     }, | ||||
|                     onChange: () => this.onChangeHandler(), | ||||
|                     viewModeEnabled: false, | ||||
|                     viewModeEnabled: options.is("databaseReadonly"), | ||||
|                     zenModeEnabled: false, | ||||
|                     gridModeEnabled: false, | ||||
|                     isCollaborating: false, | ||||
| @@ -567,6 +571,10 @@ export default class ExcalidrawTypeWidget extends TypeWidget { | ||||
|      * info: sceneVersions are not incrementing. it seems to be a pseudo-random number | ||||
|      */ | ||||
|     isNewSceneVersion() { | ||||
|         if (options.is("databaseReadonly")) { | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         const sceneVersion = this.getSceneVersion(); | ||||
|  | ||||
|         return ( | ||||
|   | ||||
| @@ -1,17 +1,19 @@ | ||||
| import { ALLOWED_PROTOCOLS } from "../../../services/link.js"; | ||||
| import { MIME_TYPE_AUTO } from "@triliumnext/commons"; | ||||
| import type { EditorConfig } from "@triliumnext/ckeditor5"; | ||||
| import { getHighlightJsNameForMime } from "../../../services/mime_types.js"; | ||||
| import options from "../../../services/options.js"; | ||||
| import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js"; | ||||
| import utils from "../../../services/utils.js"; | ||||
| import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url"; | ||||
| import { copyText } from "../../../services/clipboard.js"; | ||||
|  | ||||
| const TEXT_FORMATTING_GROUP = { | ||||
|     label: "Text formatting", | ||||
|     icon: "text" | ||||
| }; | ||||
|  | ||||
| export function buildConfig() { | ||||
| export function buildConfig(): EditorConfig { | ||||
|     return { | ||||
|         image: { | ||||
|             styles: { | ||||
| @@ -111,6 +113,9 @@ export function buildConfig() { | ||||
|             defaultMimeType: MIME_TYPE_AUTO, | ||||
|             enabled: isSyntaxHighlightEnabled | ||||
|         }, | ||||
|         clipboard: { | ||||
|             copy: copyText | ||||
|         }, | ||||
|         // This value must be kept in sync with the language defined in webpack.config.js. | ||||
|         language: "en" | ||||
|     }; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import AbstractTextTypeWidget from "./abstract_text_type_widget.js"; | ||||
| import { applySyntaxHighlight } from "../../services/syntax_highlight.js"; | ||||
| import { formatCodeBlocks } from "../../services/syntax_highlight.js"; | ||||
| import type FNote from "../../entities/fnote.js"; | ||||
| import type { CommandListenerData, EventData } from "../../components/app_context.js"; | ||||
| import { getLocaleById } from "../../services/i18n.js"; | ||||
| @@ -125,7 +125,7 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget { | ||||
|         } | ||||
|  | ||||
|         await this.#applyInlineMermaid(); | ||||
|         await applySyntaxHighlight(this.$content); | ||||
|         await formatCodeBlocks(this.$content); | ||||
|     } | ||||
|  | ||||
|     async #applyInlineMermaid() { | ||||
|   | ||||
| @@ -215,8 +215,6 @@ class ListOrGridView extends ViewMode { | ||||
|  | ||||
|         const highlightedTokens = this.parentNote.highlightedTokens || []; | ||||
|         if (highlightedTokens.length > 0) { | ||||
|             await import("mark.js"); | ||||
|  | ||||
|             const regex = highlightedTokens.map((token) => utils.escapeRegExp(token)).join("|"); | ||||
|  | ||||
|             this.highlightRegex = new RegExp(regex, "gi"); | ||||
| @@ -320,11 +318,10 @@ class ListOrGridView extends ViewMode { | ||||
|         $expander.on("click", () => this.toggleContent($card, note, !$card.hasClass("expanded"))); | ||||
|  | ||||
|         if (this.highlightRegex) { | ||||
|             $card.find(".note-book-title").markRegExp(this.highlightRegex, { | ||||
|             const Mark = new (await import("mark.js")).default($card.find(".note-book-title")[0]); | ||||
|             Mark.markRegExp(this.highlightRegex, { | ||||
|                 element: "span", | ||||
|                 className: "ck-find-result", | ||||
|                 separateWordSearch: false, | ||||
|                 caseSensitive: false | ||||
|                 className: "ck-find-result" | ||||
|             }); | ||||
|         } | ||||
|  | ||||
| @@ -362,11 +359,10 @@ class ListOrGridView extends ViewMode { | ||||
|             }); | ||||
|  | ||||
|             if (this.highlightRegex) { | ||||
|                 $renderedContent.markRegExp(this.highlightRegex, { | ||||
|                 const Mark = new (await import("mark.js")).default($renderedContent[0]); | ||||
|                 Mark.markRegExp(this.highlightRegex, { | ||||
|                     element: "span", | ||||
|                     className: "ck-find-result", | ||||
|                     separateWordSearch: false, | ||||
|                     caseSensitive: false | ||||
|                     className: "ck-find-result" | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|   | ||||
| @@ -21,7 +21,7 @@ export default defineConfig(() => ({ | ||||
|     plugins: [ | ||||
|         viteStaticCopy({ | ||||
|             targets: assets.map((asset) => ({ | ||||
|                 src: `src/${asset}/**/*`, | ||||
|                 src: `src/${asset}/*`, | ||||
|                 dest: asset | ||||
|             })) | ||||
|         }), | ||||
| @@ -68,8 +68,8 @@ module.exports = { | ||||
|         ] | ||||
|     }, | ||||
|     rebuildConfig: { | ||||
|         force: false, | ||||
|         onlyModules: [] | ||||
|         force: true, | ||||
|         extraModules: [ "better-sqlite3" ] | ||||
|     }, | ||||
|     makers: [ | ||||
|         { | ||||
|   | ||||
| @@ -66,6 +66,7 @@ | ||||
|           ], | ||||
|           "minify": true, | ||||
|           "thirdParty": true, | ||||
|           "declaration": false, | ||||
|           "esbuildOptions": { | ||||
|             "splitting": false, | ||||
|             "loader": { | ||||
|   | ||||
| @@ -438,15 +438,15 @@ | ||||
|                       </li> | ||||
|                       <li>TODO | ||||
|                         <ul> | ||||
|                           <li><a href="root/Trilium%20Demo/Scripting%20examples/Task%20manager/Locations/work/Send%20invites%20for%20christmas%20par.html" | ||||
|                             target="detail">Send invites for christmas party</a> | ||||
|                           </li> | ||||
|                           <li><a href="root/Trilium%20Demo/Scripting%20examples/Task%20manager/Locations/tesco/Buy%20milk.html" | ||||
|                             target="detail">Buy milk</a> | ||||
|                           </li> | ||||
|                           <li><a href="root/Trilium%20Demo/Scripting%20examples/Task%20manager/Locations/mall/Buy%20some%20book%20for%20Bob.html" | ||||
|                             target="detail">Buy some book for Bob</a> | ||||
|                           </li> | ||||
|                           <li><a href="root/Trilium%20Demo/Scripting%20examples/Task%20manager/Locations/work/Send%20invites%20for%20christmas%20par.html" | ||||
|                             target="detail">Send invites for christmas party</a> | ||||
|                           </li> | ||||
|                         </ul> | ||||
|                       </li> | ||||
|                       <li>Implementation | ||||
| @@ -477,12 +477,12 @@ | ||||
|                           </li> | ||||
|                           <li>shopping | ||||
|                             <ul> | ||||
|                               <li><a href="root/Trilium%20Demo/Scripting%20examples/Task%20manager/Locations/mall/Buy%20some%20book%20for%20Bob.html" | ||||
|                                 target="detail">Buy some book for Bob</a> | ||||
|                               </li> | ||||
|                               <li><a href="root/Trilium%20Demo/Scripting%20examples/Task%20manager/Locations/tesco/Buy%20milk.html" | ||||
|                                 target="detail">Buy milk</a> | ||||
|                               </li> | ||||
|                               <li><a href="root/Trilium%20Demo/Scripting%20examples/Task%20manager/Locations/mall/Buy%20some%20book%20for%20Bob.html" | ||||
|                                 target="detail">Buy some book for Bob</a> | ||||
|                               </li> | ||||
|                             </ul> | ||||
|                           </li> | ||||
|                           <li>groceries | ||||
| @@ -18,28 +18,22 @@ | ||||
|           height="150"> | ||||
|         </figure> | ||||
|         <p><strong>Welcome to TriliumNext Notes!</strong> | ||||
| 
 | ||||
|         </p> | ||||
|         <p>This is initial "demo" document provided by TriliumNext by default to | ||||
|           showcase some of its features and also give you some ideas how you might | ||||
|           structure your notes. You can play with it, modify note content and tree | ||||
|           structure as you wish.</p> | ||||
|         <p>If you need any help, visit TriliumNext website: <a href="https://github.com/TriliumNext">https://github.com/TriliumNext</a> | ||||
| 
 | ||||
|         </p> | ||||
|          <h3>Cleanup</h3> | ||||
| 
 | ||||
|         <p>Once you're finished with experimenting and want to cleanup these pages, | ||||
|           you can simply delete them all.</p> | ||||
|          <h3>Formatting</h3> | ||||
| 
 | ||||
|         <p>TriliumNext supports classic formatting like <em>italic</em>, <strong>bold</strong>, <em><strong>bold and italic</strong></em>. | ||||
|           Of course you can add links like this one pointing to <a href="http://www.google.com">google.com</a> | ||||
| 
 | ||||
|         </p> | ||||
|         <p>Lists</p> | ||||
|         <p><strong>Ordered:</strong> | ||||
| 
 | ||||
|         </p> | ||||
|         <ol> | ||||
|           <li>First Item</li> | ||||
| @@ -54,7 +48,6 @@ | ||||
|           </li> | ||||
|         </ol> | ||||
|         <p><strong>Unordered:</strong> | ||||
| 
 | ||||
|         </p> | ||||
|         <ul> | ||||
|           <li>Item</li> | ||||
| @@ -14,22 +14,17 @@ | ||||
| 
 | ||||
|       <div class="ck-content"> | ||||
|         <h2>Main characters</h2> | ||||
| 
 | ||||
|         <p>… here put main characters …</p> | ||||
|         <p> </p> | ||||
|          <h2>Plot</h2> | ||||
| 
 | ||||
|         <p>… describe main plot lines …</p> | ||||
|         <p> </p> | ||||
|          <h2>Tone</h2> | ||||
| 
 | ||||
|         <p> </p> | ||||
|          <h2>Genre</h2> | ||||
| 
 | ||||
|         <p>scifi / drama / romance</p> | ||||
|         <p> </p> | ||||
|          <h2>Similar books</h2> | ||||
| 
 | ||||
|         <ul> | ||||
|           <li>…</li> | ||||
|         </ul> | ||||
| @@ -14,14 +14,11 @@ | ||||
| 
 | ||||
|       <div class="ck-content"> | ||||
|         <p>Checkout Kindle daily deals: <a href="https://www.amazon.com/gp/feature.html?docId=1000677541">https://www.amazon.com/gp/feature.html?docId=1000677541</a> | ||||
| 
 | ||||
|         </p> | ||||
|         <ul> | ||||
|           <li>Cixin Liu - <a href="https://www.amazon.com/Dark-Forest-Remembrance-Earths-Past/dp/0765386690/ref=pd_bxgy_14_img_2?_encoding=UTF8&pd_rd_i=0765386690&pd_rd_r=AB0J179TM9NTEAMHE240&pd_rd_w=FAhxX&pd_rd_wg=pLGK7&psc=1&refRID=AB0J179TM9NTEAMHE240">The Dark Forest</a> | ||||
| 
 | ||||
|           </li> | ||||
|           <li>Ann Leckie - <a href="https://www.amazon.com/Ancillary-Sword-Imperial-Radch-Leckie/dp/0316246654/ref=pd_sim_14_1?_encoding=UTF8&pd_rd_i=0316246654&pd_rd_r=D7KDTGZFP7YM1YSYVY4G&pd_rd_w=jkn28&pd_rd_wg=JVhtw&psc=1&refRID=D7KDTGZFP7YM1YSYVY4G">Ancillary Sword</a> | ||||
| 
 | ||||
|           </li> | ||||
|         </ul> | ||||
|       </div> | ||||
| @@ -18,25 +18,21 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">buy milk  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" checked="checked" disabled="disabled"><span class="todo-list__label__description">do the laundry  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" checked="checked" disabled="disabled"><span class="todo-list__label__description">watch TV  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">eat ice cream  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -20,9 +20,10 @@ | ||||
|           is first created it will try to automatically determine the programming | ||||
|           language, should that fail it is possible to manually adjust it. The color | ||||
|           scheme for the syntax highlighting is adjustable in settings. </p><pre><code class="language-application-javascript-env-frontend">function helloWorld() { | ||||
| 	alert("Hello world"); | ||||
| }</code></pre> | ||||
| 
 | ||||
| 	alert("Hello world"); | ||||
| 
 | ||||
| }</code></pre> | ||||
|         <p>For larger pieces of code it is better to use a code note, which uses | ||||
|           a fully-fledged code editor (CodeMirror). For an example of a code note, | ||||
|           see <a class="reference-link" href="../Scripting%20examples/Custom%20request%20handler.js">Custom request handler</a>.</p> | ||||
| @@ -15,9 +15,7 @@ | ||||
|       <div class="ck-content"> | ||||
|         <p><span class="math-tex">\(% \f is defined as #1f(#2) using the macro \f\relax{x} = \int_{-\infty}^\infty     \f\hat\xi\,e^{2 \pi i \xi x}     \,d\xi\)</span>Some | ||||
|           math examples:</p><span class="math-tex">\[\displaystyle \frac{1}{\Bigl(\sqrt{\phi \sqrt{5}}-\phi\Bigr) e^{\frac25 \pi}} = 1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}} {1+\frac{e^{-8\pi}} {1+\cdots} } } }\]</span> | ||||
| 
 | ||||
|         <p>Another:</p><span class="math-tex">\[\displaystyle \left( \sum_{k=1}^n a_k b_k \right)^2 \leq \left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)\]</span> | ||||
| 
 | ||||
|         <p>Inline math is also possible: <span class="math-tex">\(c^2 = a^2 + b^2\)</span> </p> | ||||
|         <p> </p> | ||||
|       </div> | ||||
| @@ -18,7 +18,7 @@ | ||||
|           href="https://en.wikipedia.org/wiki/Short_story">short story</a>by American writer <a href="https://en.wikipedia.org/wiki/Isaac_Asimov">Isaac Asimov</a>. | ||||
|             It first appeared in the November 1956 issue of <a href="https://en.wikipedia.org/wiki/Science_Fiction_Quarterly"><em>Science Fiction Quarterly</em></a>.</p> | ||||
|         <section | ||||
|         class="include-note" data-note-id="ZWCYra81yOFO" data-box-size="medium"> </section> | ||||
|         class="include-note" data-note-id="VsFbpoySMCE3" data-box-size="medium"> </section> | ||||
|           <p>This page demonstrates two things:</p> | ||||
|           <ul> | ||||
|             <li>possibility to <a href="#root/_hidden/_help/_help_KSZ04uQ2D1St/_help_iPIMuisry3hd/_help_nBAXQFj20hS1">include one note into another</a> | ||||
| @@ -14,7 +14,6 @@ | ||||
| 
 | ||||
|       <div class="ck-content"> | ||||
|         <p>You can read some explanation on how this journal works here: <a href="https://github.com/zadam/trilium/wiki/Day-notes">https://github.com/zadam/trilium/wiki/Day-notes</a> | ||||
| 
 | ||||
|         </p> | ||||
|       </div> | ||||
|     </div> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -17,7 +17,6 @@ | ||||
|           <li>XBox</li> | ||||
|           <li>Candles</li> | ||||
|           <li><a href="https://www.amazon.ca/Anker-SoundCore-Portable-Bluetooth-Resistance/dp/B01MTB55WH?pd_rd_wg=honW8&pd_rd_r=c9bb7c0f-0051-4da7-991f-4ca711a1b3e3&pd_rd_w=ciUpR&ref_=pd_gw_simh&pf_rd_r=K10XKX0NGPDNTYYP4BS4&pf_rd_p=5f1b460b-78c1-580e-929e-2878fe4859e8">Portable speakers</a> | ||||
| 
 | ||||
|           </li> | ||||
|           <li>...?</li> | ||||
|         </ul> | ||||
| @@ -14,10 +14,8 @@ | ||||
| 
 | ||||
|       <div class="ck-content"> | ||||
|         <p>Wiki: <a href="https://en.wikipedia.org/wiki/Trusted_timestamping">https://en.wikipedia.org/wiki/Trusted_timestamping</a> | ||||
| 
 | ||||
|         </p> | ||||
|         <p>Bozho: <a href="https://techblog.bozho.net/using-trusted-timestamping-java/">https://techblog.bozho.net/using-trusted-timestamping-java/</a> | ||||
| 
 | ||||
|         </p> | ||||
|         <p><strong>Trusted timestamping</strong> is the process of <a href="https://en.wikipedia.org/wiki/Computer_security">securely</a> keeping | ||||
|           track of the creation and modification time of a document. Security here | ||||
| @@ -16,7 +16,6 @@ | ||||
|         <p>Miscellaneous notes done on monday ...</p> | ||||
|         <p> </p> | ||||
|         <p>Interesting video: <a href="https://www.youtube.com/watch?v=_eSAF_qT_FY&feature=youtu.be">https://www.youtube.com/watch?v=_eSAF_qT_FY&feature=youtu.be</a> | ||||
| 
 | ||||
|         </p> | ||||
|         <p> </p> | ||||
|         <p> </p> | ||||
| Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB | 
| Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB | 
| Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB | 
| Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB | 
| Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB | 
| Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB | 
| Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB | 
| Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB | 
| Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB | 
| Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB | 
| Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB | 
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB | 
| @@ -18,7 +18,6 @@ | ||||
|           width="209" height="300"> | ||||
|         </figure> | ||||
|         <p>Maybe CodeNames? <a href="https://boardgamegeek.com/boardgame/178900/codenames">https://boardgamegeek.com/boardgame/178900/codenames</a> | ||||
| 
 | ||||
|         </p> | ||||
|       </div> | ||||
|     </div> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| @@ -18,7 +18,6 @@ | ||||
|           <li> | ||||
|             <label class="todo-list__label"> | ||||
|               <input type="checkbox" disabled="disabled"><span class="todo-list__label__description">  </span> | ||||
| 
 | ||||
|             </label> | ||||
|           </li> | ||||
|         </ul> | ||||
| Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB | 
| @@ -24,17 +24,14 @@ | ||||
|           <span | ||||
|           class="footnote-reference" data-footnote-reference="" data-footnote-index="1" | ||||
|           data-footnote-id="6qz4pm021mi" role="doc-noteref" id="fnref6qz4pm021mi"><sup><a href="#fn6qz4pm021mi">[1]</a></sup> | ||||
| 
 | ||||
|             </span> | ||||
|         </p> | ||||
|         <ol class="footnote-section footnotes" data-footnote-section="" role="doc-endnotes"> | ||||
|           <li class="footnote-item" data-footnote-item="" data-footnote-index="1" | ||||
|           data-footnote-id="6qz4pm021mi" role="doc-endnote" id="fn6qz4pm021mi"><span class="footnote-back-link" data-footnote-back-link="" data-footnote-id="6qz4pm021mi"><sup><strong><a href="#fnref6qz4pm021mi">^</a></strong></sup></span> | ||||
| 
 | ||||
|             <div | ||||
|             class="footnote-content" data-footnote-content=""> | ||||
|               <p><a href="https://www.thecollector.com/what-are-the-seven-wonders-of-the-world/">What Are the 7 Wonders of the World? (with HD Images) | TheCollector</a> | ||||
| 
 | ||||
|               </p> | ||||
|       </div> | ||||
|       </li> | ||||
| @@ -26,16 +26,13 @@ | ||||
|           been brought to its knees.<span class="footnote-reference" data-footnote-reference="" | ||||
|           data-footnote-index="1" data-footnote-id="o6g991vkrwj" role="doc-noteref" | ||||
|           id="fnrefo6g991vkrwj"><sup><a href="#fno6g991vkrwj">[1]</a></sup></span> | ||||
| 
 | ||||
|         </p> | ||||
|         <ol class="footnote-section footnotes" data-footnote-section="" role="doc-endnotes"> | ||||
|           <li class="footnote-item" data-footnote-item="" data-footnote-index="1" | ||||
|           data-footnote-id="o6g991vkrwj" role="doc-endnote" id="fno6g991vkrwj"><span class="footnote-back-link" data-footnote-back-link="" data-footnote-id="o6g991vkrwj"><sup><strong><a href="#fnrefo6g991vkrwj">^</a></strong></sup></span> | ||||
| 
 | ||||
|             <div | ||||
|             class="footnote-content" data-footnote-content=""> | ||||
|               <p><a href="https://www.thecollector.com/what-are-the-seven-wonders-of-the-world/">What Are the 7 Wonders of the World? (with HD Images) | TheCollector</a> | ||||
| 
 | ||||
|               </p> | ||||
|       </div> | ||||
|       </li> | ||||
| @@ -22,16 +22,13 @@ | ||||
|           around 1450 in polished drystone walls.<span class="footnote-reference" | ||||
|           data-footnote-reference="" data-footnote-index="1" data-footnote-id="4prjheuho88" | ||||
|           role="doc-noteref" id="fnref4prjheuho88"><sup><a href="#fn4prjheuho88">[1]</a></sup></span> | ||||
| 
 | ||||
|         </p> | ||||
|         <ol class="footnote-section footnotes" data-footnote-section="" role="doc-endnotes"> | ||||
|           <li class="footnote-item" data-footnote-item="" data-footnote-index="1" | ||||
|           data-footnote-id="4prjheuho88" role="doc-endnote" id="fn4prjheuho88"><span class="footnote-back-link" data-footnote-back-link="" data-footnote-id="4prjheuho88"><sup><strong><a href="#fnref4prjheuho88">^</a></strong></sup></span> | ||||
| 
 | ||||
|             <div | ||||
|             class="footnote-content" data-footnote-content=""> | ||||
|               <p><a href="https://www.thecollector.com/what-are-the-seven-wonders-of-the-world/">What Are the 7 Wonders of the World? (with HD Images) | TheCollector</a> | ||||
| 
 | ||||
|               </p> | ||||
|       </div> | ||||
|       </li> | ||||
| @@ -23,16 +23,13 @@ | ||||
|           by earthquakes.<span class="footnote-reference" data-footnote-reference="" | ||||
|           data-footnote-index="1" data-footnote-id="ej5sd0bakne" role="doc-noteref" | ||||
|           id="fnrefej5sd0bakne"><sup><a href="#fnej5sd0bakne">[1]</a></sup></span> | ||||
| 
 | ||||
|         </p> | ||||
|         <ol class="footnote-section footnotes" data-footnote-section="" role="doc-endnotes"> | ||||
|           <li class="footnote-item" data-footnote-item="" data-footnote-index="1" | ||||
|           data-footnote-id="ej5sd0bakne" role="doc-endnote" id="fnej5sd0bakne"><span class="footnote-back-link" data-footnote-back-link="" data-footnote-id="ej5sd0bakne"><sup><strong><a href="#fnrefej5sd0bakne">^</a></strong></sup></span> | ||||
| 
 | ||||
|             <div | ||||
|             class="footnote-content" data-footnote-content=""> | ||||
|               <p><a href="https://www.thecollector.com/what-are-the-seven-wonders-of-the-world/">What Are the 7 Wonders of the World? (with HD Images) | TheCollector</a> | ||||
| 
 | ||||
|               </p> | ||||
|       </div> | ||||
|       </li> | ||||
| @@ -26,17 +26,14 @@ | ||||
|           <span | ||||
|           class="footnote-reference" data-footnote-reference="" data-footnote-index="1" | ||||
|           data-footnote-id="4kitkusvyi3" role="doc-noteref" id="fnref4kitkusvyi3"><sup><a href="#fn4kitkusvyi3">[1]</a></sup> | ||||
| 
 | ||||
|             </span> | ||||
|         </p> | ||||
|         <ol class="footnote-section footnotes" data-footnote-section="" role="doc-endnotes"> | ||||
|           <li class="footnote-item" data-footnote-item="" data-footnote-index="1" | ||||
|           data-footnote-id="4kitkusvyi3" role="doc-endnote" id="fn4kitkusvyi3"><span class="footnote-back-link" data-footnote-back-link="" data-footnote-id="4kitkusvyi3"><sup><strong><a href="#fnref4kitkusvyi3">^</a></strong></sup></span> | ||||
| 
 | ||||
|             <div | ||||
|             class="footnote-content" data-footnote-content=""> | ||||
|               <p><a href="https://www.thecollector.com/what-are-the-seven-wonders-of-the-world/">What Are the 7 Wonders of the World? (with HD Images) | TheCollector</a> | ||||
| 
 | ||||
|               </p> | ||||
|       </div> | ||||
|       </li> | ||||
| @@ -23,17 +23,14 @@ | ||||
|           <span | ||||
|           class="footnote-reference" data-footnote-reference="" data-footnote-index="1" | ||||
|           data-footnote-id="o0o2das7ljm" role="doc-noteref" id="fnrefo0o2das7ljm"><sup><a href="#fno0o2das7ljm">[1]</a></sup> | ||||
| 
 | ||||
|             </span> | ||||
|         </p> | ||||
|         <ol class="footnote-section footnotes" data-footnote-section="" role="doc-endnotes"> | ||||
|           <li class="footnote-item" data-footnote-item="" data-footnote-index="1" | ||||
|           data-footnote-id="o0o2das7ljm" role="doc-endnote" id="fno0o2das7ljm"><span class="footnote-back-link" data-footnote-back-link="" data-footnote-id="o0o2das7ljm"><sup><strong><a href="#fnrefo0o2das7ljm">^</a></strong></sup></span> | ||||
| 
 | ||||
|             <div | ||||
|             class="footnote-content" data-footnote-content=""> | ||||
|               <p><a href="https://www.thecollector.com/what-are-the-seven-wonders-of-the-world/">What Are the 7 Wonders of the World? (with HD Images) | TheCollector</a> | ||||
| 
 | ||||
|               </p> | ||||
|       </div> | ||||
|       </li> | ||||
| @@ -23,16 +23,13 @@ | ||||
|           the complex.<span class="footnote-reference" data-footnote-reference="" | ||||
|           data-footnote-index="1" data-footnote-id="zzzjn52iwk" role="doc-noteref" | ||||
|           id="fnrefzzzjn52iwk"><sup><a href="#fnzzzjn52iwk">[1]</a></sup></span> | ||||
| 
 | ||||
|         </p> | ||||
|         <ol class="footnote-section footnotes" data-footnote-section="" role="doc-endnotes"> | ||||
|           <li class="footnote-item" data-footnote-item="" data-footnote-index="1" | ||||
|           data-footnote-id="zzzjn52iwk" role="doc-endnote" id="fnzzzjn52iwk"><span class="footnote-back-link" data-footnote-back-link="" data-footnote-id="zzzjn52iwk"><sup><strong><a href="#fnrefzzzjn52iwk">^</a></strong></sup></span> | ||||
| 
 | ||||
|             <div | ||||
|             class="footnote-content" data-footnote-content=""> | ||||
|               <p><a href="https://www.thecollector.com/what-are-the-seven-wonders-of-the-world/">What Are the 7 Wonders of the World? (with HD Images) | TheCollector</a> | ||||
| 
 | ||||
|               </p> | ||||
|       </div> | ||||
|       </li> | ||||
| Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |