Skip to content

Commit

Permalink
Add *.md support for plugin's details
Browse files Browse the repository at this point in the history
  • Loading branch information
DmitryAstafyev committed Feb 13, 2025
1 parent dee830f commit 88c9767
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 16 deletions.
113 changes: 110 additions & 3 deletions application/client/src/app/ui/tabs/plugins/details/component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
import { Component, ChangeDetectorRef, Input } from '@angular/core';
import {
Component,
ChangeDetectorRef,
Input,
ViewChild,
ElementRef,
AfterViewInit,
AfterContentInit,
OnDestroy,
} from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Ilc, IlcInterface } from '@env/decorators/component';
import { Initial } from '@env/decorators/initial';
import { ChangesDetector } from '@ui/env/extentions/changes';
import { micromark } from 'micromark';
import { PluginDesc } from '../desc';
import { Provider } from '../provider';
import { bridge } from '@service/bridge';

import * as dom from '@ui/env/dom';

@Component({
selector: 'app-plugins-manager-details',
Expand All @@ -13,13 +27,106 @@ import { Provider } from '../provider';
})
@Initial()
@Ilc()
export class Details extends ChangesDetector {
export class Details extends ChangesDetector implements AfterViewInit, AfterContentInit, OnDestroy {
@Input() public provider!: Provider;
@Input() public plugin!: PluginDesc;

constructor(cdRef: ChangeDetectorRef) {
@ViewChild('content') contentRef!: ElementRef<HTMLElement>;

public readme: SafeHtml = '';
public loading: boolean = false;

protected async load(): Promise<void> {
const drop = () => {
this.loading = false;
this.readme = '';
this.detectChanges();
};
this.loading = true;
this.links().unbind();
this.detectChanges();
if (!this.plugin.path) {
return drop();
}
const delimiter = await bridge.folders().delimiter();
const path = `${this.plugin.path.filename}${delimiter}README.md`;
if (!(await bridge.files().exists(path))) {
return drop();
}
bridge
.files()
.read(path)
.then((content: string) => {
this.readme = this.sanitizer.bypassSecurityTrustHtml(micromark(content));
this.detectChanges();
this.links().bind();
})
.catch((err: Error) => {
this.log().error(`Fail to read "${path}": ${err.message}`);
this.readme = '';
})
.finally(() => {
this.loading = false;
this.detectChanges();
});
}

protected links(): {
bind(): void;
unbind(): void;
} {
return {
bind: (): void => {
const links = this.contentRef.nativeElement.querySelectorAll('a');
if (links === null) {
return;
}
links.forEach((link: HTMLAnchorElement) => {
link.addEventListener('click', this.redirect);
});
},
unbind: (): void => {
const links = this.contentRef.nativeElement.querySelectorAll('a');
if (links === null) {
return;
}
links.forEach((link: HTMLAnchorElement) => {
link.removeEventListener('click', this.redirect);
});
},
};
}

protected safeLoad(): void {
this.load().catch((err: Error) => {
this.log().error(`Fail to load plugin's details: ${err.message}`);
});
}

protected redirect(event: MouseEvent): void {
dom.stop(event);
// TODO: safe openening URL
}

constructor(cdRef: ChangeDetectorRef, protected readonly sanitizer: DomSanitizer) {
super(cdRef);
}

public ngAfterViewInit(): void {
this.safeLoad();
}

public ngAfterContentInit(): void {
this.env().subscriber.register(
this.provider.subjects.get().selected.subscribe(() => {
this.safeLoad();
}),
);
}

public ngOnDestroy(): void {
this.links().unbind();
}
}

export interface Details extends IlcInterface {}
27 changes: 24 additions & 3 deletions application/client/src/app/ui/tabs/plugins/details/styles.less
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
@import '../../../styles/variables.less';

:host {
position: relative;
position: absolute;
display: flex;
flex-direction: column;
top: 12px;
left: 12px;
bottom: 12px;
right: 12px;
overflow: hidden;
& div.info {
margin: 0 6px;
overflow: hidden;
position: relative;
margin: 0 6px 12px 0;
& p {
text-align: left;
}
}
& div.actions {
position: relative;
display: flex;
margin: 0 0 12px 0;
flex-direction: row;
justify-content: end;
}
& div.readme {
position: relative;
overflow-y: auto;
overflow-x: hidden;
flex: auto;

}
}
11 changes: 11 additions & 0 deletions application/client/src/app/ui/tabs/plugins/details/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,14 @@
<p class="title t-normal color-scheme-0">{{plugin.name}}</p>
<p class="subtitle t-small color-scheme-2">{{plugin.desc}}</p>
</div>
<div class="actions">
<button class="flat-codicon-button">Remove</button>
<button class="flat-codicon-button">Visit Home Page</button>
<button class="flat-codicon-button">Inspect Logs</button>
</div>
<div class="readme">
<ng-container *ngIf="loading">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</ng-container>
<div #content class="markdown" [innerHTML]="readme"></div>
</div>
8 changes: 4 additions & 4 deletions application/client/src/app/ui/tabs/plugins/list/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Provider } from '../provider';
import { PluginDesc } from '../desc';

export enum Target {
Active,
Installed,
Available,
}

Expand Down Expand Up @@ -41,16 +41,16 @@ export class List extends ChangesDetector implements AfterContentInit {

public getTitle(): string {
switch (this.target) {
case Target.Active:
return 'Active Plugins';
case Target.Installed:
return 'Installed Plugins';
case Target.Available:
return 'Available Plugins';
}
}

protected update() {
switch (this.target) {
case Target.Active:
case Target.Installed:
this.plugins = this.provider.get().active();
break;
case Target.Available:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, ChangeDetectorRef, Input, HostListener } from '@angular/core';
import { Component, ChangeDetectorRef, Input, HostListener, HostBinding } from '@angular/core';
import { Ilc, IlcInterface } from '@env/decorators/component';
import { Initial } from '@env/decorators/initial';
import { ChangesDetector } from '@ui/env/extentions/changes';
Expand All @@ -20,6 +20,13 @@ export class Plugin extends ChangesDetector {
@HostListener('click', ['$event']) onClick(_event: MouseEvent) {
this.provider.select(this.plugin.entity.dir_path);
}
@HostBinding('class') get getClass() {
return !this.provider.selected
? ''
: this.provider.selected.entity.dir_path === this.plugin.entity.dir_path
? 'selected'
: '';
}
constructor(cdRef: ChangeDetectorRef) {
super(cdRef);
}
Expand Down
10 changes: 10 additions & 0 deletions application/client/src/app/ui/tabs/plugins/plugin/styles.less
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@
align-items: center;
flex-direction: row;
cursor: default;
&.selected {
&::after{
position: absolute;
content: '';
height: 100%;
left: -2px;
width: 2px;
background: @scheme-color-accent;
}
}
& div.icon {
& mat-icon {
font-size: 18px;
Expand Down
6 changes: 1 addition & 5 deletions application/client/src/app/ui/tabs/plugins/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,7 @@
<div class="right">
<app-plugins-manager-list
[provider]="provider"
[target]="Target.Active"
></app-plugins-manager-list>
<app-plugins-manager-list
[provider]="provider"
[target]="Target.Available"
[target]="Target.Installed"
></app-plugins-manager-list>
<mat-card>
<mat-card-content>
Expand Down

0 comments on commit 88c9767

Please sign in to comment.