Add markdown editor node
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
74b7cdadc7
commit
b588865137
@ -48,9 +48,15 @@
|
||||
},
|
||||
{
|
||||
"input": "src/assets/font/fonts.css"
|
||||
},
|
||||
{
|
||||
"input": "node_modules/katex/dist/katex.min.css"
|
||||
}
|
||||
],
|
||||
"scripts": []
|
||||
"scripts": [
|
||||
"node_modules/marked/lib/marked.js",
|
||||
"node_modules/katex/dist/katex.min.js"
|
||||
]
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
|
92
package-lock.json
generated
92
package-lock.json
generated
@ -2126,6 +2126,11 @@
|
||||
"integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/marked": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-1.1.0.tgz",
|
||||
"integrity": "sha512-j8XXj6/l9kFvCwMyVqozznqpd/nk80krrW+QiIJN60Uu9gX5Pvn4/qPJ2YngQrR3QREPwmrE1f9/EWKVTFzoEw=="
|
||||
},
|
||||
"@types/minimatch": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
|
||||
@ -3636,6 +3641,17 @@
|
||||
"integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
|
||||
"dev": true
|
||||
},
|
||||
"clipboard": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
|
||||
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"good-listener": "^1.2.2",
|
||||
"select": "^1.1.2",
|
||||
"tiny-emitter": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
|
||||
@ -3795,8 +3811,7 @@
|
||||
"commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
|
||||
},
|
||||
"commondir": {
|
||||
"version": "1.0.1",
|
||||
@ -4758,6 +4773,12 @@
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
},
|
||||
"delegate": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
|
||||
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
|
||||
"optional": true
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
@ -4992,6 +5013,11 @@
|
||||
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-toolkit": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/emoji-toolkit/-/emoji-toolkit-6.0.1.tgz",
|
||||
"integrity": "sha512-QZZq0beHg753JxcBt89UBFqzwYNuMtXhNO+jY3viSAndewmn9biTE5glaro1RA0uWJ4hKqw4k1Mboe1M6sGkMA=="
|
||||
},
|
||||
"emojis-list": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
|
||||
@ -6003,6 +6029,15 @@
|
||||
"slash": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"good-listener": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
|
||||
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"delegate": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
@ -7830,6 +7865,14 @@
|
||||
"source-map-support": "^0.5.5"
|
||||
}
|
||||
},
|
||||
"katex": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/katex/-/katex-0.12.0.tgz",
|
||||
"integrity": "sha512-y+8btoc/CK70XqcHqjxiGWBOeIL8upbS0peTPXTvgrh21n1RiWWcIpSWM+4uXq+IAgNh9YYQWdc7LVDPDAEEAg==",
|
||||
"requires": {
|
||||
"commander": "^2.19.0"
|
||||
}
|
||||
},
|
||||
"killable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||
@ -8227,6 +8270,11 @@
|
||||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"marked": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.0.tgz",
|
||||
"integrity": "sha512-tiRxakgbNPBr301ihe/785NntvYyhxlqcL3YaC8CaxJQh7kiaEtrN9B/eK2I2943Yjkh5gw25chYFDQhOMCwMA=="
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
@ -8652,6 +8700,26 @@
|
||||
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
|
||||
"dev": true
|
||||
},
|
||||
"ngx-markdown": {
|
||||
"version": "10.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ngx-markdown/-/ngx-markdown-10.1.1.tgz",
|
||||
"integrity": "sha512-bUVgN6asb35d5U4xM5CNfo7pSpuwqJSdTgK0PhNZzLiaiyPIK2owtLF6sWGhxTThJu+LngJPjj4MQ+AFe/s8XQ==",
|
||||
"requires": {
|
||||
"@types/marked": "^1.1.0",
|
||||
"emoji-toolkit": "^6.0.1",
|
||||
"katex": "^0.12.0",
|
||||
"marked": "^1.1.0",
|
||||
"prismjs": "^1.20.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
|
||||
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"ngx-monaco-editor": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ngx-monaco-editor/-/ngx-monaco-editor-8.1.1.tgz",
|
||||
@ -10480,6 +10548,14 @@
|
||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
|
||||
"dev": true
|
||||
},
|
||||
"prismjs": {
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.22.0.tgz",
|
||||
"integrity": "sha512-lLJ/Wt9yy0AiSYBf212kK3mM5L8ycwlyTlSxHBAneXLR0nzFMlZ5y7riFPF3E33zXOF2IH95xdY5jIyZbM9z/w==",
|
||||
"requires": {
|
||||
"clipboard": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
@ -11582,6 +11658,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
|
||||
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
|
||||
"optional": true
|
||||
},
|
||||
"select-hose": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
|
||||
@ -12970,6 +13052,12 @@
|
||||
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
|
||||
"dev": true
|
||||
},
|
||||
"tiny-emitter": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
|
||||
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
|
||||
"optional": true
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
|
@ -30,6 +30,7 @@
|
||||
"ag-grid-community": "^22.1.1",
|
||||
"core-js": "^2.5.4",
|
||||
"moment": "^2.24.0",
|
||||
"ngx-markdown": "^10.1.1",
|
||||
"ngx-monaco-editor": "^8.1.1",
|
||||
"rxjs": "~6.6.3",
|
||||
"tslib": "^1.9.0",
|
||||
|
@ -14,6 +14,7 @@ import { TreeModule } from '@circlon/angular-tree-component';
|
||||
import {AgGridModule} from 'ag-grid-angular';
|
||||
import {MonacoEditorModule} from 'ngx-monaco-editor';
|
||||
import { APP_BASE_HREF, PlatformLocation } from '@angular/common';
|
||||
import { MarkdownModule } from 'ngx-markdown';
|
||||
|
||||
/**
|
||||
* This function is used internal to get a string instance of the `<base href="" />` value from `index.html`.
|
||||
@ -42,6 +43,7 @@ export function getBaseHref(platformLocation: PlatformLocation): string {
|
||||
TreeModule,
|
||||
AgGridModule.withComponents([]),
|
||||
MonacoEditorModule.forRoot(),
|
||||
MarkdownModule.forRoot(),
|
||||
],
|
||||
providers: [
|
||||
StatusBar,
|
||||
|
@ -27,7 +27,9 @@ import {BooleanRendererComponent} from './editor/database/renderers/boolean-rend
|
||||
import {SearchComponent} from './search/Search.component';
|
||||
|
||||
import {NormComponent} from './nodes/norm/norm.component';
|
||||
import {MarkdownComponent as MarkdownEditorComponent} from './nodes/markdown/markdown.component';
|
||||
import {DirectivesModule} from '../directives/directives.module';
|
||||
import {MarkdownModule} from "ngx-markdown";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -53,6 +55,7 @@ import {DirectivesModule} from '../directives/directives.module';
|
||||
SearchComponent,
|
||||
|
||||
NormComponent,
|
||||
MarkdownEditorComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
@ -63,6 +66,7 @@ import {DirectivesModule} from '../directives/directives.module';
|
||||
ContenteditableModule,
|
||||
MonacoEditorModule,
|
||||
DirectivesModule,
|
||||
MarkdownModule,
|
||||
],
|
||||
entryComponents: [
|
||||
NodePickerComponent,
|
||||
@ -87,6 +91,7 @@ import {DirectivesModule} from '../directives/directives.module';
|
||||
SearchComponent,
|
||||
|
||||
NormComponent,
|
||||
MarkdownEditorComponent,
|
||||
],
|
||||
exports: [
|
||||
NodePickerComponent,
|
||||
@ -111,6 +116,7 @@ import {DirectivesModule} from '../directives/directives.module';
|
||||
SearchComponent,
|
||||
|
||||
NormComponent,
|
||||
MarkdownEditorComponent,
|
||||
]
|
||||
})
|
||||
export class ComponentsModule {}
|
||||
|
@ -3,6 +3,10 @@
|
||||
<i class="fa" slot="start" [ngClass]="typeIcons.node"></i>
|
||||
<ion-label>Paragraph</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button (click)="onSelect('markdown')" class="markdown">
|
||||
<i class="fa" slot="start" [ngClass]="typeIcons.markdown"></i>
|
||||
<ion-label>Markdown</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button (click)="onSelect('database_ref')" class="db">
|
||||
<i class="fa" slot="start" [ngClass]="typeIcons.db"></i>
|
||||
<ion-label>Database</ion-label>
|
||||
|
@ -25,3 +25,9 @@ i {
|
||||
color: var(--noded-background-files);
|
||||
}
|
||||
}
|
||||
|
||||
.markdown {
|
||||
i {
|
||||
color: var(--noded-background-markdown);
|
||||
}
|
||||
}
|
||||
|
11
src/app/components/nodes/markdown/markdown.component.html
Normal file
11
src/app/components/nodes/markdown/markdown.component.html
Normal file
@ -0,0 +1,11 @@
|
||||
<div class="container" (click)="onFocusIn()">
|
||||
<div class="editor-container" *ngIf="showEditor">
|
||||
<ngx-monaco-editor class="editor"
|
||||
[options]="editorOptions"
|
||||
[(ngModel)]="contents"
|
||||
(ngModelChange)="onContentsChanged($event)"
|
||||
#editor
|
||||
></ngx-monaco-editor>
|
||||
</div>
|
||||
<div class="display" markdown katex [data]="contents"></div>
|
||||
</div>
|
23
src/app/components/nodes/markdown/markdown.component.scss
Normal file
23
src/app/components/nodes/markdown/markdown.component.scss
Normal file
@ -0,0 +1,23 @@
|
||||
.container {
|
||||
display: flex;
|
||||
min-height: 600px;
|
||||
flex-direction: row;
|
||||
|
||||
.editor-container, .display {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.editor-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.editor {
|
||||
border: 1px solid lightgrey;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.display {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
77
src/app/components/nodes/markdown/markdown.component.ts
Normal file
77
src/app/components/nodes/markdown/markdown.component.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import {Component, HostListener, Input, OnInit, ViewChild} from '@angular/core';
|
||||
import {EditorNodeContract} from '../EditorNode.contract';
|
||||
import {EditorService} from '../../../service/editor.service';
|
||||
import {v4} from 'uuid';
|
||||
|
||||
@Component({
|
||||
selector: 'editor-markdown',
|
||||
templateUrl: './markdown.component.html',
|
||||
styleUrls: ['./markdown.component.scss'],
|
||||
})
|
||||
export class MarkdownComponent extends EditorNodeContract implements OnInit {
|
||||
// @ViewChild('editable') editable;
|
||||
@Input() nodeId: string;
|
||||
|
||||
// public isFocused = false;
|
||||
public initialValue = 'Click to edit...';
|
||||
protected savedValue = 'Click to edit...';
|
||||
public contents = '';
|
||||
private dirtyOverride = false;
|
||||
public showEditor = false;
|
||||
|
||||
public editorOptions = {
|
||||
language: 'markdown',
|
||||
uri: v4(),
|
||||
readOnly: false,
|
||||
automaticLayout: true,
|
||||
};
|
||||
|
||||
constructor(
|
||||
public readonly editorService: EditorService,
|
||||
) {
|
||||
super();
|
||||
this.contents = this.initialValue;
|
||||
this.savedValue = this.initialValue;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.editorService.registerNodeEditor(this.nodeId, this).then(() => {
|
||||
if ( !this.node.Value ) {
|
||||
this.node.Value = {};
|
||||
}
|
||||
|
||||
if ( this.node.Value.Value ) {
|
||||
this.initialValue = this.node.Value.Value;
|
||||
this.savedValue = this.node.Value.Value;
|
||||
}
|
||||
|
||||
this.contents = this.initialValue;
|
||||
});
|
||||
}
|
||||
|
||||
public isDirty(): boolean | Promise<boolean> {
|
||||
return this.dirtyOverride || this.contents !== this.savedValue;
|
||||
}
|
||||
|
||||
public writeChangesToNode(): void | Promise<void> {
|
||||
this.node.Value.Mode = 'code';
|
||||
this.node.Value.Value = this.contents;
|
||||
this.node.value = this.contents;
|
||||
this.savedValue = this.contents;
|
||||
}
|
||||
|
||||
onContentsChanged(event) {
|
||||
if ( event !== this.savedValue ) {
|
||||
this.editorService.triggerSave();
|
||||
}
|
||||
}
|
||||
|
||||
onFocusIn() {
|
||||
this.showEditor = true;
|
||||
}
|
||||
|
||||
@HostListener('document:keyup.escape', ['$event'])
|
||||
onFocusOut(event) {
|
||||
this.showEditor = false;
|
||||
}
|
||||
}
|
@ -37,6 +37,9 @@
|
||||
<ng-container *ngIf="node.isNorm()">
|
||||
<editor-norm style="flex: 1;" [nodeId]="node.UUID"></editor-norm>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="node.type === 'markdown'">
|
||||
<editor-markdown style="flex: 1;" [nodeId]="node.UUID"></editor-markdown>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="node.type === 'database_ref'">
|
||||
<editor-database style="flex: 1;" [nodeId]="node.UUID"></editor-database>
|
||||
</ng-container>
|
||||
|
@ -32,6 +32,10 @@ ion-icon.invisible {
|
||||
&.file_ref {
|
||||
color: var(--noded-background-files);
|
||||
}
|
||||
|
||||
&.markdown {
|
||||
color: var(--noded-background-markdown);
|
||||
}
|
||||
}
|
||||
|
||||
.host-add-button {
|
||||
|
@ -1,6 +1,6 @@
|
||||
export default class HostRecord {
|
||||
public value = '';
|
||||
public type: 'paragraph'|'database_ref'|'code_ref'|'file_ref' = 'paragraph';
|
||||
public type: 'paragraph'|'database_ref'|'code_ref'|'file_ref'|'markdown' = 'paragraph';
|
||||
|
||||
public CreatedAt: string;
|
||||
public PageId: string;
|
||||
|
@ -9,4 +9,5 @@ export const NodeTypeIcons = {
|
||||
code_ref: 'fa fa-code',
|
||||
file_ref: 'fa fa-archive',
|
||||
files: 'fa fa-archive',
|
||||
markdown: 'fab fa-markdown',
|
||||
};
|
||||
|
@ -29,6 +29,7 @@
|
||||
@import "~ag-grid-community/dist/styles/ag-grid.css";
|
||||
@import "~ag-grid-community/dist/styles/ag-theme-balham.css";
|
||||
@import "~@fortawesome/fontawesome-free/css/all.min.css";
|
||||
@import "~@fortawesome/fontawesome-free/css/brands.min.css";
|
||||
|
||||
:root {
|
||||
--noded-background-note: #3A86FF;
|
||||
@ -50,6 +51,10 @@
|
||||
--noded-background-files: #0E7B81;
|
||||
--noded-color-files: white;
|
||||
--noded-background-files-hover: #14AFB8;
|
||||
|
||||
--noded-background-markdown: #5F4D30;
|
||||
--noded-color-markdown: white;
|
||||
--noded-color-markdown-hover: #7A633E;
|
||||
}
|
||||
|
||||
div.picker-wrapper {
|
||||
|
Loading…
Reference in New Issue
Block a user