Remove SCSS files related to components, layouts, and Bootstrap variables no longer in use
This commit is contained in:
+64
-90
@@ -1,104 +1,78 @@
|
||||
<mat-card appearance="outlined">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Edit tutorial</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content >
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label class="label-style">Title</mat-label>
|
||||
<input matInput required
|
||||
[(ngModel)]="tutorial.title">
|
||||
</mat-form-field>
|
||||
<form [formGroup]="form" novalidate>
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label class="label-style">Title</mat-label>
|
||||
<input matInput
|
||||
formControlName="title"
|
||||
>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-label class="label-style">Title image</mat-label>
|
||||
<mat-divider></mat-divider>
|
||||
<table class="example-full-width">
|
||||
<tr>
|
||||
<td style="width: 120px;">
|
||||
<img style="width: 120px; height: 120px" src="{{tutorial.titleimage}}" alt="">
|
||||
</td>
|
||||
<td>
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Title image</mat-label>
|
||||
<input matInput disabled
|
||||
[(ngModel)]="tutorial.titleimage">
|
||||
</mat-form-field>
|
||||
<div>
|
||||
<button mat-raised-button color="primary" (click)="openSelectImageDialog('100ms', '5ms')">Select image</button>
|
||||
<button mat-raised-button color="primary" (click)="openUploadImageDialog('100ms', '5ms')">Upload image</button>
|
||||
</div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="example-full-width">
|
||||
<mat-label class="label-style">Description</mat-label>
|
||||
<mat-label class="label-style">Title image</mat-label>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Markdown text | Result">
|
||||
<textarea class="variable-textarea" [(ngModel)]="tutorial.description"></textarea>
|
||||
<markdown class="variable-binding" [data]="tutorial.description"></markdown>
|
||||
</mat-tab>
|
||||
<mat-tab label="Editor">
|
||||
<div class="markdown-editor-container">
|
||||
<div class="markdown-editor">
|
||||
<form novalidate>
|
||||
<angular-markdown-editor
|
||||
textareaId="editor1"
|
||||
[options]="editorOptions"
|
||||
name="markdownText"
|
||||
[(ngModel)]="tutorial.description"
|
||||
(onFullscreenExit)="hidePreview()"
|
||||
>
|
||||
</angular-markdown-editor>
|
||||
</form>
|
||||
<table class="example-full-width">
|
||||
<tr>
|
||||
<td>
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Title image</mat-label>
|
||||
<input matInput
|
||||
formControlName="titleimage"
|
||||
[disabled]="true"
|
||||
>
|
||||
</mat-form-field>
|
||||
<div>
|
||||
<button mat-raised-button color="primary" (click)="openSelectImageDialog('100ms', '5ms')">Select image</button>
|
||||
<button mat-raised-button color="primary" (click)="openUploadImageDialog('100ms', '5ms')">Upload image</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Result">
|
||||
<markdown class="preview" [data]="tutorial.description"></markdown>
|
||||
</mat-tab>
|
||||
<mat-tab label="Example">
|
||||
<textarea class="variable-textarea" [(ngModel)]="markdown"></textarea>
|
||||
<markdown class="variable-binding" [data]="markdown"></markdown>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@if(tutorial.titleimage){
|
||||
<div class="example-full-width content-center">
|
||||
<img style="width: 716px; height: 400px" src="{{tutorial.titleimage}}" alt="">
|
||||
</div>
|
||||
}
|
||||
<div class="example-full-width">
|
||||
<mat-label class="label-style">Body</mat-label>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Markdown text | Result">
|
||||
<textarea class="variable-textarea"
|
||||
|
||||
<div class="example-full-width">
|
||||
<mat-label class="label-style">Body</mat-label>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Markdown text | Result">
|
||||
<textarea class="variable-textarea" [(ngModel)]="tutorial.body"></textarea>
|
||||
<markdown class="variable-binding" [data]="tutorial.body"></markdown>
|
||||
</mat-tab>
|
||||
<mat-tab label="Editor">
|
||||
<form novalidate>
|
||||
<angular-markdown-editor style="color: #1a1a1a"
|
||||
textareaId="editor2"
|
||||
[options]="editorOptions"
|
||||
name="markdownText"
|
||||
[(ngModel)]="tutorial.body"
|
||||
(onFullscreenExit)="hidePreview()"
|
||||
formControlName = "body"
|
||||
(input)="onBodyChange($event)"
|
||||
>
|
||||
</angular-markdown-editor>
|
||||
</form>
|
||||
</mat-tab>
|
||||
<mat-tab label="Result">
|
||||
<markdown class="preview" [data]="tutorial.body"></markdown>
|
||||
</mat-tab>
|
||||
<mat-tab label="Example">
|
||||
<textarea class="variable-textarea" [(ngModel)]="markdown"></textarea>
|
||||
<markdown class="variable-binding" [data]="markdown"></markdown>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
|
||||
</textarea>
|
||||
<markdown class="variable-binding" [data]="tutorial.body"></markdown>
|
||||
</mat-tab>
|
||||
<!--<mat-tab label="Editor">
|
||||
<form novalidate>
|
||||
<angular-markdown-editor style="color: #1a1a1a"
|
||||
textareaId="editor2"
|
||||
[options]="editorOptions"
|
||||
name="markdownText"
|
||||
[(ngModel)]="tutorial.body"
|
||||
(onFullscreenExit)="hidePreview()"
|
||||
>
|
||||
</angular-markdown-editor>
|
||||
</form>
|
||||
</mat-tab>-->
|
||||
<mat-tab label="Result">
|
||||
<markdown class="preview" [data]="tutorial.body"></markdown>
|
||||
</mat-tab>
|
||||
<mat-tab label="Example">
|
||||
<textarea class="variable-textarea" [value]="markdown"></textarea>
|
||||
<markdown class="variable-binding" [data]="markdown"></markdown>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
</form>
|
||||
</mat-card-content>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-card-actions>
|
||||
|
||||
<button matButton (click)="updateTutorial()">Save</button>
|
||||
<button matButton (click)="updateTutorial()" [disabled]="form.invalid">Save</button>
|
||||
@if (hasError){
|
||||
<mat-error>
|
||||
{{errorMessage}}
|
||||
|
||||
+11
@@ -19,6 +19,11 @@ mat-card-title{
|
||||
|
||||
.example-full-width {
|
||||
width: 100%;
|
||||
margin-bottom: inherit;
|
||||
|
||||
}
|
||||
.content-center{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,3 +62,9 @@ mat-card-title{
|
||||
border-color: var(--mat-card-outlined-outline-color, var(--mat-sys-outline-variant));
|
||||
box-shadow: var(--mat-card-outlined-container-elevation, var(--mat-sys-level0));
|
||||
}
|
||||
|
||||
|
||||
.label-style{
|
||||
font-size: xx-large;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
+66
-73
@@ -4,7 +4,15 @@ import {MatButton} from '@angular/material/button';
|
||||
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||
import {MatError, MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||
import {MatTab, MatTabGroup} from '@angular/material/tabs';
|
||||
import {FormBuilder, FormGroup, FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
FormGroup,
|
||||
FormsModule,
|
||||
ReactiveFormsModule, ValidationErrors,
|
||||
ValidatorFn,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import {Tutorial} from '../../../models/tutorial.model';
|
||||
import {UserApiService} from '../user-api.service';
|
||||
import {ActivatedRoute, RouterLink} from '@angular/router';
|
||||
@@ -13,6 +21,18 @@ import {MatDivider} from '@angular/material/divider';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {DialogSelectImageComponent} from '../dialog-select-image.component/dialog-select-image.component';
|
||||
import {DialogUploadImageComponent} from '../dialog-upload-image.component/dialog-upload-image.component';
|
||||
import {GlobalConstants} from '../../../global-constants';
|
||||
|
||||
const nonBlank = (): ValidatorFn => (c: AbstractControl): ValidationErrors | null =>
|
||||
c.value && /\S/.test(c.value) ? null : { nonBlank: true };
|
||||
|
||||
type TutorialFormValue = {
|
||||
title: string;
|
||||
titleimage: string;
|
||||
body: string;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'app-tutorial-edit.component',
|
||||
@@ -40,41 +60,34 @@ import {DialogUploadImageComponent} from '../dialog-upload-image.component/dialo
|
||||
styleUrl: './tutorial-edit.component.scss',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class TutorialEditComponent implements OnInit{
|
||||
export class TutorialEditComponent{
|
||||
|
||||
tutorial: Tutorial = new Tutorial();
|
||||
submitted = false;
|
||||
|
||||
hasError = false;
|
||||
errorMessage = '';
|
||||
markdownText="";
|
||||
bsEditorInstance!: EditorInstance;
|
||||
tutorialForm!: FormGroup;
|
||||
editorOptions!: EditorOption;
|
||||
|
||||
readonly dialog = inject(MatDialog);
|
||||
|
||||
|
||||
markdown = `## Markdown __rulez__!
|
||||
---
|
||||
markdown = GlobalConstants.MARKDOWN_EXAMPLE;
|
||||
|
||||
### Syntax highlight
|
||||
\`\`\`typescript
|
||||
const language = 'typescript';
|
||||
\`\`\`
|
||||
private fb = inject(FormBuilder);
|
||||
|
||||
### Lists
|
||||
1. Ordered list
|
||||
2. Another bullet point
|
||||
- Unordered list
|
||||
- Another unordered bullet
|
||||
form = this.fb.nonNullable.group({
|
||||
|
||||
title: ['', [Validators.required, nonBlank()] ],
|
||||
body: ['', [Validators.required, nonBlank()] ],
|
||||
|
||||
titleimage: this.fb.nonNullable.control({ value: '', disabled: true }),
|
||||
|
||||
});
|
||||
|
||||
### Blockquote
|
||||
> Blockquote to the max`;
|
||||
private id: string | null | undefined;
|
||||
|
||||
constructor(private userApiService: UserApiService,
|
||||
private route: ActivatedRoute,
|
||||
private fb: FormBuilder,
|
||||
private markdownService: MarkdownService
|
||||
) {
|
||||
|
||||
@@ -88,66 +101,42 @@ const language = 'typescript';
|
||||
this.userApiService.getTutorial(this.id).subscribe(
|
||||
data=>{
|
||||
this.tutorial = data;
|
||||
this.form.patchValue(this.fromModel(this.tutorial));
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.editorOptions = {
|
||||
autofocus: false,
|
||||
iconlibrary: 'fa',
|
||||
height: 300,
|
||||
savable: false,
|
||||
onFullscreenExit: (e) => this.hidePreview(),
|
||||
onShow: (e) => this.bsEditorInstance = e,
|
||||
parser: (val) => this.parse(val)
|
||||
// Map Model -> Form value
|
||||
private fromModel(m: Tutorial): Partial<TutorialFormValue> {
|
||||
return {
|
||||
title: m.title ?? '',
|
||||
body: m.body ?? '',
|
||||
titleimage: m.titleimage ?? '',
|
||||
|
||||
};
|
||||
this.buildForm(this.tutorial.description);
|
||||
|
||||
}
|
||||
|
||||
buildForm(markdownText: string | undefined) {
|
||||
this.tutorialForm = this.fb.group({
|
||||
body: [markdownText],
|
||||
isPreview: [true]
|
||||
});
|
||||
}
|
||||
/** highlight all code found, needs to be wrapped in timer to work properly */
|
||||
highlight() {
|
||||
setTimeout(() => {
|
||||
this.markdownService.highlight();
|
||||
});
|
||||
}
|
||||
|
||||
hidePreview() {
|
||||
if (this.bsEditorInstance && this.bsEditorInstance.hidePreview) {
|
||||
this.bsEditorInstance.hidePreview();
|
||||
}
|
||||
}
|
||||
|
||||
showFullScreen(isFullScreen: boolean) {
|
||||
if (this.bsEditorInstance && this.bsEditorInstance.setFullscreen) {
|
||||
this.bsEditorInstance.showPreview();
|
||||
this.bsEditorInstance.setFullscreen(isFullScreen);
|
||||
}
|
||||
}
|
||||
|
||||
parse(inputValue: string) {
|
||||
const markedOutput = this.markdownService.parse(inputValue.trim());
|
||||
this.highlight();
|
||||
|
||||
return markedOutput;
|
||||
}
|
||||
|
||||
onFormChanges(): void {
|
||||
this.tutorialForm.valueChanges.subscribe(formData => {
|
||||
if (formData) {
|
||||
this.markdownText = formData.body;
|
||||
}
|
||||
});
|
||||
// Map Form value -> Model (compose with existing model if you need to keep id, etc.)
|
||||
private toModel(): Tutorial {
|
||||
const v = this.form.getRawValue(); // TutorialFormValue
|
||||
return {
|
||||
...this.tutorial, // keep immutable fields like id
|
||||
title: v.title.trim(),
|
||||
body: v.body.trim(),
|
||||
//
|
||||
titleimage: v.titleimage,
|
||||
modified: new Date(),
|
||||
};
|
||||
}
|
||||
|
||||
updateTutorial(): void {
|
||||
if (this.form.invalid) {
|
||||
this.form.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
this.tutorial = this.toModel();
|
||||
// send `updated` to your API here
|
||||
this.userApiService.update(this.id, this.tutorial)
|
||||
.subscribe(
|
||||
response => {
|
||||
@@ -186,7 +175,7 @@ const language = 'typescript';
|
||||
return;
|
||||
}
|
||||
this.tutorial.titleimage = result.url;
|
||||
|
||||
this.form.patchValue({ titleimage: result.url });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -211,7 +200,11 @@ const language = 'typescript';
|
||||
return;
|
||||
}
|
||||
this.tutorial.titleimage = result.url;
|
||||
|
||||
this.form.patchValue({ titleimage: result.url });
|
||||
});
|
||||
}
|
||||
|
||||
onBodyChange($event: Event) {
|
||||
this.tutorial.body = this.form.get('body')?.value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user