Wiring of markdown-preview
This commit is contained in:
parent
e64a18b18b
commit
857f0ded57
@ -47,6 +47,7 @@
|
|||||||
"src/assets/css/ace-overrides.css"
|
"src/assets/css/ace-overrides.css"
|
||||||
],
|
],
|
||||||
"scripts":[
|
"scripts":[
|
||||||
|
"src/libs/showdown.min.js"
|
||||||
],
|
],
|
||||||
"optimization": true
|
"optimization": true
|
||||||
},
|
},
|
||||||
@ -110,7 +111,6 @@
|
|||||||
"src/styles.css"
|
"src/styles.css"
|
||||||
],
|
],
|
||||||
"scripts":[
|
"scripts":[
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<info-bar></info-bar>
|
<info-bar></info-bar>
|
||||||
<tabs></tabs>
|
<tabs></tabs>
|
||||||
<editors></editors>
|
<editors></editors>
|
||||||
|
<markdown-preview></markdown-preview>
|
||||||
<search-replace></search-replace>
|
<search-replace></search-replace>
|
||||||
|
|
||||||
<files-modal></files-modal>
|
<files-modal></files-modal>
|
||||||
|
@ -4,6 +4,7 @@ import { InfoBarComponent } from './editor/info-bar/info-bar.component';
|
|||||||
import { TabsComponent } from './editor/tabs/tabs.component';
|
import { TabsComponent } from './editor/tabs/tabs.component';
|
||||||
import { EditorsComponent } from './editor/editors.component';
|
import { EditorsComponent } from './editor/editors.component';
|
||||||
import { SearchReplaceComponent } from "./editor/search-replace/search-replace.component";
|
import { SearchReplaceComponent } from "./editor/search-replace/search-replace.component";
|
||||||
|
import { MarkdownPreviewComponent } from "./editor/markdown-preview/markdown-preview.component";
|
||||||
import { FilesModalComponent } from "./common/components/modals/files/files-modal.component";
|
import { FilesModalComponent } from "./common/components/modals/files/files-modal.component";
|
||||||
|
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ import { FilesModalComponent } from "./common/components/modals/files/files-moda
|
|||||||
TabsComponent,
|
TabsComponent,
|
||||||
EditorsComponent,
|
EditorsComponent,
|
||||||
SearchReplaceComponent,
|
SearchReplaceComponent,
|
||||||
|
MarkdownPreviewComponent,
|
||||||
FilesModalComponent
|
FilesModalComponent
|
||||||
],
|
],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
|
@ -28,10 +28,14 @@ export const Keybindings: Array<{}> = [
|
|||||||
name: "showLSPModal",
|
name: "showLSPModal",
|
||||||
bindKey: {win: "ctrl-shift-l", mac: "ctrl-shift-l"},
|
bindKey: {win: "ctrl-shift-l", mac: "ctrl-shift-l"},
|
||||||
readOnly: false
|
readOnly: false
|
||||||
|
}, {
|
||||||
|
name: "markdownPreviewPopup",
|
||||||
|
bindKey: {win: "ctrl-shift-m", mac: "ctrl-shift-m"},
|
||||||
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "searchPopup",
|
name: "searchPopup",
|
||||||
bindKey: {win: "ctrl-f", mac: "ctrl-f"},
|
bindKey: {win: "ctrl-f", mac: "ctrl-f"},
|
||||||
readOnly: true
|
readOnly: false
|
||||||
}, {
|
}, {
|
||||||
name: "replacePopup",
|
name: "replacePopup",
|
||||||
bindKey: {win: "ctrl-r", mac: "ctrl-r"},
|
bindKey: {win: "ctrl-r", mac: "ctrl-r"},
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { ReplaySubject, Observable } from 'rxjs';
|
||||||
|
|
||||||
|
import { ServiceMessage } from '../../../types/service-message.type';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class MarkdownPreviewService {
|
||||||
|
private messageSubject: ReplaySubject<ServiceMessage> = new ReplaySubject<ServiceMessage>(1);
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public sendMessage(data: ServiceMessage): void {
|
||||||
|
this.messageSubject.next(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMessage$(): Observable<ServiceMessage> {
|
||||||
|
return this.messageSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { Injectable, inject } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ReplaySubject, Observable } from 'rxjs';
|
import { ReplaySubject, Observable } from 'rxjs';
|
||||||
|
|
||||||
import { ServiceMessage } from '../../../types/service-message.type';
|
import { ServiceMessage } from '../../../types/service-message.type';
|
||||||
|
@ -7,6 +7,7 @@ import { TabsService } from '../../common/services/editor/tabs/tabs.service';
|
|||||||
import { EditorsService } from '../../common/services/editor/editors.service';
|
import { EditorsService } from '../../common/services/editor/editors.service';
|
||||||
import { FilesService } from '../../common/services/files.service';
|
import { FilesService } from '../../common/services/files.service';
|
||||||
import { SearchReplaceService } from '../../common/services/editor/search-replace/search-replace.service';
|
import { SearchReplaceService } from '../../common/services/editor/search-replace/search-replace.service';
|
||||||
|
import { MarkdownPreviewService } from '../../common/services/editor/markdown-preview/markdown-preview.service';
|
||||||
|
|
||||||
import { EditorSettings } from "../../common/configs/editor.config";
|
import { EditorSettings } from "../../common/configs/editor.config";
|
||||||
import { NewtonFile } from '../../common/types/file.type';
|
import { NewtonFile } from '../../common/types/file.type';
|
||||||
@ -23,12 +24,13 @@ export class CodeViewBase {
|
|||||||
public leftSiblingUUID!: string;
|
public leftSiblingUUID!: string;
|
||||||
public rightSiblingUUID!: string;
|
public rightSiblingUUID!: string;
|
||||||
|
|
||||||
protected infoBarService: InfoBarService = inject(InfoBarService);
|
protected infoBarService: InfoBarService = inject(InfoBarService);
|
||||||
protected filesModalService: FilesModalService = inject(FilesModalService);
|
protected filesModalService: FilesModalService = inject(FilesModalService);
|
||||||
protected tabsService: TabsService = inject(TabsService);
|
protected tabsService: TabsService = inject(TabsService);
|
||||||
protected editorsService: EditorsService = inject(EditorsService);
|
protected editorsService: EditorsService = inject(EditorsService);
|
||||||
protected filesService: FilesService = inject(FilesService);
|
protected filesService: FilesService = inject(FilesService);
|
||||||
protected searchReplaceService: SearchReplaceService = inject(SearchReplaceService);
|
protected searchReplaceService: SearchReplaceService = inject(SearchReplaceService);
|
||||||
|
protected markdownPreviewService: MarkdownPreviewService = inject(MarkdownPreviewService);
|
||||||
|
|
||||||
@ViewChild('editor') editorElm!: ElementRef;
|
@ViewChild('editor') editorElm!: ElementRef;
|
||||||
@Input() editorSettings!: typeof EditorSettings;
|
@Input() editorSettings!: typeof EditorSettings;
|
||||||
@ -95,6 +97,12 @@ export class CodeViewBase {
|
|||||||
this.editor.showKeyboardShortcuts();
|
this.editor.showKeyboardShortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public markdownPreviewPopup() {
|
||||||
|
let message = new ServiceMessage();
|
||||||
|
message.action = "toggle-markdown-preview";
|
||||||
|
this.markdownPreviewService.sendMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
public searchPopup() {
|
public searchPopup() {
|
||||||
let message = new ServiceMessage();
|
let message = new ServiceMessage();
|
||||||
message.action = "toggle-search-replace";
|
message.action = "toggle-search-replace";
|
||||||
|
@ -117,6 +117,11 @@ export class CodeViewComponent extends CodeViewBase {
|
|||||||
this.editorsService.sendMessage(message);
|
this.editorsService.sendMessage(message);
|
||||||
this.searchReplaceService.sendMessage(message);
|
this.searchReplaceService.sendMessage(message);
|
||||||
|
|
||||||
|
message = new ServiceMessage();
|
||||||
|
message.action = "set-active-editor";
|
||||||
|
message.rawData = this;
|
||||||
|
this.markdownPreviewService.sendMessage(message);
|
||||||
|
|
||||||
this.updateInfoBar();
|
this.updateInfoBar();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div [innerHtml]="bodyHtml || defaultHtml">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,96 @@
|
|||||||
|
import { Component, HostBinding, inject } from '@angular/core';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
|
import { MarkdownPreviewService } from '../../common/services/editor/markdown-preview/markdown-preview.service';
|
||||||
|
|
||||||
|
import { ServiceMessage } from '../../common/types/service-message.type';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'markdown-preview',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
],
|
||||||
|
templateUrl: './markdown-preview.component.html',
|
||||||
|
styleUrl: './markdown-preview.component.css',
|
||||||
|
host: {
|
||||||
|
'class': 'container-fluid markdown-preview'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class MarkdownPreviewComponent {
|
||||||
|
private unsubscribe: Subject<void> = new Subject();
|
||||||
|
|
||||||
|
private markdownPreviewService: MarkdownPreviewService = inject(MarkdownPreviewService);
|
||||||
|
|
||||||
|
@HostBinding("class.hidden") isHidden: boolean = true;
|
||||||
|
converter: any = new showdown.Converter();
|
||||||
|
defaultHtml: string = "<h1>NOT a Markdown file...</h1>"
|
||||||
|
bodyHtml: string = "";
|
||||||
|
|
||||||
|
private editorComponent!: any;
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ngAfterViewInit(): void {
|
||||||
|
this.loadSubscribers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ngOnDestroy() {
|
||||||
|
this.unsubscribe.next();
|
||||||
|
this.unsubscribe.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadSubscribers() {
|
||||||
|
this.markdownPreviewService.getMessage$().pipe(
|
||||||
|
takeUntil(this.unsubscribe)
|
||||||
|
).subscribe((message: ServiceMessage) => {
|
||||||
|
if (message.action === "toggle-markdown-preview") {
|
||||||
|
this.toggleMarkdownPreview(message);
|
||||||
|
} else if (message.action === "set-active-editor") {
|
||||||
|
this.setActiveEditor(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private toggleMarkdownPreview(message: ServiceMessage) {
|
||||||
|
this.isHidden = !this.isHidden;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.updatePreview();
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setActiveEditor(message: ServiceMessage) {
|
||||||
|
if (this.editorComponent == message.rawData) return;
|
||||||
|
|
||||||
|
this.editorComponent = message.rawData;
|
||||||
|
|
||||||
|
if (this.isHidden) return;
|
||||||
|
|
||||||
|
this.updatePreview();
|
||||||
|
}
|
||||||
|
|
||||||
|
public updatePreview() {
|
||||||
|
let fileMode = this.editorComponent.editor.session.getMode()["$id"];
|
||||||
|
let isMdFile = (fileMode.includes("markdown"));
|
||||||
|
this.bodyHtml = "";
|
||||||
|
|
||||||
|
if (!isMdFile) return;
|
||||||
|
|
||||||
|
let mdStr = this.editorComponent.editor.session.getValue();
|
||||||
|
let pathParts = this.editorComponent.activeFile.path.split("/");
|
||||||
|
let basePath = "file://" + pathParts.slice(0, -1).join("/");
|
||||||
|
this.bodyHtml = this.converter.makeHtml(
|
||||||
|
mdStr.replaceAll("](images", `](${basePath}/images`)
|
||||||
|
.replaceAll("](imgs", `](${basePath}/imgs`)
|
||||||
|
.replaceAll("](pictures", `](${basePath}/pictures`)
|
||||||
|
.replaceAll("](pics", `](${basePath}/pics`)
|
||||||
|
.replaceAll("](screenshots", `](${basePath}/screenshots`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -91,7 +91,7 @@ export class SearchReplaceComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setActiveEditor(message: ServiceMessage) {
|
private setActiveEditor(message: ServiceMessage) {
|
||||||
if (!this.isHidden && this.editor == message.rawData) return;
|
if (this.editor == message.rawData) return;
|
||||||
|
|
||||||
this.editor = message.rawData;
|
this.editor = message.rawData;
|
||||||
|
|
||||||
|
@ -20,22 +20,34 @@ body {
|
|||||||
|
|
||||||
/* CLASSES */
|
/* CLASSES */
|
||||||
|
|
||||||
|
.markdown-preview {
|
||||||
|
top: 2em;
|
||||||
|
bottom: 2em;
|
||||||
|
right: 2em;
|
||||||
|
z-index: 900;
|
||||||
|
position: fixed;
|
||||||
|
display: inline-block;
|
||||||
|
width: 50vw;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: rgba(64, 64, 64, 0.84);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-replace {
|
||||||
|
bottom: 2em;
|
||||||
|
left: 2em;
|
||||||
|
right: 2em;
|
||||||
|
z-index: 800;
|
||||||
|
display: inline-block;
|
||||||
|
position: fixed;
|
||||||
|
background-color: rgba(64, 64, 64, 0.64);
|
||||||
|
}
|
||||||
|
|
||||||
.info-bar {
|
.info-bar {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: rgba(255, 255, 255, 0.84);
|
color: rgba(255, 255, 255, 0.84);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-replace {
|
|
||||||
bottom: 2em;
|
|
||||||
z-index: 999;
|
|
||||||
display: inline-block;
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
background-color: rgba(64, 64, 64, 0.24);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.tabs {
|
.tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
3
src/libs/showdown.min.js
vendored
Normal file
3
src/libs/showdown.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
src/typings.d.ts
vendored
Normal file
1
src/typings.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare var showdown: any;
|
@ -16,8 +16,11 @@
|
|||||||
"declaration": false,
|
"declaration": false,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"forceConsistentCasingInFileNames": true
|
"forceConsistentCasingInFileNames": true,
|
||||||
}
|
},
|
||||||
|
"includes": [
|
||||||
|
"src/typings.d.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -53,7 +56,10 @@
|
|||||||
"strictInjectionParameters": true,
|
"strictInjectionParameters": true,
|
||||||
"strictInputAccessModifiers": true,
|
"strictInputAccessModifiers": true,
|
||||||
"strictTemplates": true
|
"strictTemplates": true
|
||||||
}
|
},
|
||||||
|
"includes": [
|
||||||
|
"src/typings.d.ts"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
Loading…
Reference in New Issue
Block a user