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 |