Add user module routing, integrate markdown support, and enhance dialog functionality
This commit is contained in:
@@ -38,14 +38,26 @@
|
||||
<mat-card-header>
|
||||
<mat-card-title>Add tutorial</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content *ngIf="!submitted">
|
||||
<mat-card-content >
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Title</mat-label>
|
||||
<input matInput required
|
||||
[(ngModel)]="tutorial.title">
|
||||
</mat-form-field>
|
||||
<!-- <kendo-editor [(ngModel)]="tutorial.description" ></kendo-editor>-->
|
||||
<textarea matInput required [(ngModel)]="tutorial.description"></textarea>
|
||||
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Markdown text">
|
||||
<textarea class="variable-textarea" [(ngModel)]="tutorial.description"></textarea>
|
||||
<markdown class="variable-binding" [data]="tutorial.description"></markdown>
|
||||
</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>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button matButton (click)="saveTutorial()" *ngIf="!submitted">Save</button>
|
||||
|
||||
@@ -19,3 +19,34 @@ mat-card-title{
|
||||
.example-full-width {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.variable-binding,
|
||||
.variable-textarea {
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
.variable-textarea {
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.07);
|
||||
min-height: 420px;
|
||||
padding: 8px;
|
||||
transition: all 300ms ease-out;
|
||||
}
|
||||
|
||||
.variable-textarea:hover {
|
||||
box-shadow: 0 6px 12px 3px rgba(0,0,0,.09),
|
||||
0 2px 3px 1px rgba(0,0,0,.06);
|
||||
}
|
||||
|
||||
.variable-binding {
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.preview {
|
||||
/* display: block;
|
||||
float: right;*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import {FormsModule} from '@angular/forms';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||
import {NgIf} from '@angular/common';
|
||||
import {MatTab, MatTabGroup} from '@angular/material/tabs';
|
||||
import {MarkdownComponent} from 'ngx-markdown';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-tutorial',
|
||||
@@ -24,6 +26,9 @@ import {NgIf} from '@angular/common';
|
||||
MatInput,
|
||||
NgIf,
|
||||
MatLabel,
|
||||
MatTabGroup,
|
||||
MatTab,
|
||||
MarkdownComponent,
|
||||
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
@@ -35,9 +40,30 @@ export class AddTutorialComponent implements OnInit {
|
||||
description: '',
|
||||
published: false
|
||||
};
|
||||
submitted = false;
|
||||
submitted = false
|
||||
|
||||
constructor(private tutorialService: TutorialService) { }
|
||||
markdown = `## Markdown __rulez__!
|
||||
---
|
||||
|
||||
### Syntax highlight
|
||||
\`\`\`typescript
|
||||
const language = 'typescript';
|
||||
\`\`\`
|
||||
|
||||
### Lists
|
||||
1. Ordered list
|
||||
2. Another bullet point
|
||||
- Unordered list
|
||||
- Another unordered bullet
|
||||
|
||||
### Blockquote
|
||||
> Blockquote to the max`;
|
||||
|
||||
|
||||
|
||||
constructor(private tutorialService: TutorialService) {
|
||||
this.tutorial.description = this.markdown;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<h1 mat-dialog-title>Hi </h1>
|
||||
<form [formGroup]="signUpForm">
|
||||
<div mat-dialog-content>
|
||||
<p>User name</p>
|
||||
<mat-form-field class="fillField">
|
||||
<input matInput
|
||||
formControlName="username"
|
||||
[(ngModel)]="data.username"
|
||||
minlength="3"
|
||||
>
|
||||
</mat-form-field>
|
||||
<p>Email</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Email</mat-label>
|
||||
<input matInput type="email"
|
||||
formControlName="email"
|
||||
|
||||
placeholder="Ex. pat@example.com"
|
||||
[(ngModel)]="data.email"
|
||||
(blur)="updateErrorMessage()"
|
||||
required
|
||||
>
|
||||
@if (emailFormControl.invalid) {
|
||||
<mat-error>{{errorMessage()}}</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
<p>Password</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Enter your password</mat-label>
|
||||
<input matInput
|
||||
|
||||
formControlName = "password"
|
||||
[type]="hide() ? 'password' : 'text'"
|
||||
[(ngModel)]="data.password"
|
||||
minlength="6"
|
||||
required
|
||||
/>
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="clickEvent($event)"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide()"
|
||||
>
|
||||
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<p>Confirm password</p>
|
||||
<mat-form-field class="fillField">
|
||||
<mat-label>Confirm your password</mat-label>
|
||||
<input matInput
|
||||
|
||||
formControlName = "confirmPassword"
|
||||
[type]="hide() ? 'password' : 'text'"
|
||||
[(ngModel)]="data.confirmPassword"
|
||||
/>
|
||||
@if (signUpForm.get("confirmPassword")?.value !== signUpForm.get("password")?.value) {
|
||||
<mat-error>Passwords do not match</mat-error>
|
||||
}
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
(click)="clickEvent($event)"
|
||||
[attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide()"
|
||||
>
|
||||
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="login()">Login</button>
|
||||
<span class="menu-spacer"></span>
|
||||
<button mat-button mat-dialog-close (click)="onNoClick()">No Thanks</button>
|
||||
<button mat-button cdkFocusInitial (click)="signup()">Ok</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,7 @@
|
||||
.menu-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.fillField{
|
||||
width: 100%;
|
||||
};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DialogSignupComponent } from './dialog-signup.component';
|
||||
|
||||
describe('DialogSignupComponent', () => {
|
||||
let component: DialogSignupComponent;
|
||||
let fixture: ComponentFixture<DialogSignupComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [DialogSignupComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(DialogSignupComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,141 @@
|
||||
import {Component, CUSTOM_ELEMENTS_SCHEMA, EventEmitter, Inject, inject, OnInit, Output, signal} from '@angular/core';
|
||||
import {
|
||||
AbstractControl,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
FormGroupDirective,
|
||||
FormsModule,
|
||||
NgForm,
|
||||
ReactiveFormsModule, ValidationErrors, ValidatorFn,
|
||||
Validators
|
||||
} from '@angular/forms';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogRef,
|
||||
MatDialogTitle
|
||||
} from '@angular/material/dialog';
|
||||
import {MatFormField, MatInput, MatLabel, MatSuffix} from '@angular/material/input';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
import {DialogSignupData} from '../../main-module/main.component/main.component';
|
||||
import {ErrorStateMatcher} from '@angular/material/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dialog-signup.component',
|
||||
imports: [
|
||||
FormsModule,
|
||||
MatButtonModule,
|
||||
MatDialogActions,
|
||||
MatDialogClose,
|
||||
MatDialogContent,
|
||||
MatDialogTitle,
|
||||
MatFormField,
|
||||
MatIcon,
|
||||
MatInput,
|
||||
MatLabel,
|
||||
MatSuffix,
|
||||
MatFormField,
|
||||
ReactiveFormsModule,
|
||||
|
||||
],
|
||||
templateUrl: './dialog-signup.component.html',
|
||||
styleUrl: './dialog-signup.component.scss',
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
})
|
||||
export class DialogSignupComponent implements OnInit {
|
||||
readonly dialogRef = inject(MatDialogRef<DialogSignupComponent>);
|
||||
hide = signal(true);
|
||||
|
||||
@Output() signupClicked = new EventEmitter<any>();
|
||||
@Output() loginClicked = new EventEmitter<any>();
|
||||
|
||||
private _snackBar = inject(MatSnackBar);
|
||||
|
||||
durationInSeconds = 5;
|
||||
|
||||
emailFormControl = new FormControl('', [Validators.required, Validators.email]);
|
||||
|
||||
matcher = new MyErrorStateMatcher();
|
||||
|
||||
errorMessage = signal('');
|
||||
|
||||
signUpForm = new FormGroup({
|
||||
username: new FormControl('', [Validators.required]),
|
||||
email: new FormControl('', [Validators.required, Validators.email]),
|
||||
password: new FormControl('', [Validators.required]),
|
||||
confirmPassword: new FormControl('', [Validators.required, this.validateSamePassword]),
|
||||
});
|
||||
minPw = 8;
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data:DialogSignupData,
|
||||
private formBuilder: FormBuilder) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
updateErrorMessage() {
|
||||
if (this.emailFormControl.hasError('required')) {
|
||||
this.errorMessage.set('You must enter a value');
|
||||
} else if (this.emailFormControl.hasError('email')) {
|
||||
this.errorMessage.set('Not a valid email');
|
||||
} else {
|
||||
this.errorMessage.set('');
|
||||
}
|
||||
}
|
||||
|
||||
clickEvent(event: MouseEvent) {
|
||||
this.hide.set(!this.hide());
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
openSignupFailedSnackBar(errorMessage : string = "Sign up failed.") {
|
||||
this._snackBar.open(errorMessage , "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
openSignupSuccessSnackBar(message : string = "User registered successfully!") {
|
||||
this._snackBar.open(message, "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
signup() {
|
||||
if (!this.signUpForm.invalid) {
|
||||
this.signupClicked.emit(this.data);
|
||||
}
|
||||
}
|
||||
|
||||
login() {
|
||||
this.loginClicked.emit();
|
||||
}
|
||||
|
||||
private validateSamePassword(control: AbstractControl): ValidationErrors | null {
|
||||
const password = control.parent?.get('password');
|
||||
const confirmPassword = control.parent?.get('confirmPassword');
|
||||
return password?.value == confirmPassword?.value ? null : { 'notSame': true };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Error when invalid control is dirty, touched, or submitted. */
|
||||
export class MyErrorStateMatcher implements ErrorStateMatcher {
|
||||
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||
const isSubmitted = form && form.submitted;
|
||||
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@
|
||||
</div>
|
||||
|
||||
<div mat-dialog-actions>
|
||||
<button mat-button (click)="signup()">Sign Up</button>
|
||||
<span class="menu-spacer"></span>
|
||||
<button mat-button mat-dialog-close (click)="onNoClick()">No Thanks</button>
|
||||
<button mat-button [mat-dialog-close]="data" cdkFocusInitial>Ok</button>
|
||||
<button mat-button cdkFocusInitial (click)="login()">Ok</button>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
.menu-spacer {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.fillField{
|
||||
width: 100%;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {ChangeDetectionStrategy, Component, Inject, inject, signal} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, EventEmitter, Inject, inject, Output, signal} from '@angular/core';
|
||||
import {MatButtonModule} from "@angular/material/button";
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
@@ -14,7 +14,8 @@ import {MatFormField, MatLabel, MatSuffix} from "@angular/material/form-field";
|
||||
import {MatInput} from "@angular/material/input";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {MatIcon} from "@angular/material/icon";
|
||||
import {DialogData} from '../../main-module/main.component/main.component';
|
||||
import {DialogLoginData} from '../../main-module/main.component/main.component';
|
||||
import {MatSnackBar} from '@angular/material/snack-bar';
|
||||
|
||||
|
||||
|
||||
@@ -22,16 +23,32 @@ import {DialogData} from '../../main-module/main.component/main.component';
|
||||
@Component({
|
||||
selector: 'app-dialog',
|
||||
imports: [MatButtonModule, MatLabel, MatDialogActions, MatDialogClose, MatDialogTitle, MatDialogContent, MatFormField, MatInput, FormsModule, MatIcon, MatSuffix],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
|
||||
templateUrl: './dialog.component.html',
|
||||
styleUrl: './dialog.component.scss'
|
||||
styleUrl: './dialog.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DialogComponent {
|
||||
readonly dialogRef = inject(MatDialogRef<DialogComponent>);
|
||||
hide = signal(true);
|
||||
|
||||
@Output() loginClicked = new EventEmitter<any>();
|
||||
@Output() signupClicked = new EventEmitter<any>();
|
||||
|
||||
private _snackBar = inject(MatSnackBar);
|
||||
durationInSeconds = 5;
|
||||
|
||||
|
||||
constructor(
|
||||
@Inject(MAT_DIALOG_DATA) public data:DialogData) {}
|
||||
@Inject(MAT_DIALOG_DATA) public data:DialogLoginData) {
|
||||
|
||||
}
|
||||
|
||||
openLoginFailedSnackBar(errorMessage : string = "Login failed.") {
|
||||
this._snackBar.open(errorMessage , "", {
|
||||
duration: this.durationInSeconds * 1000,
|
||||
});
|
||||
}
|
||||
|
||||
onNoClick() {
|
||||
this.dialogRef.close();
|
||||
@@ -42,6 +59,15 @@ export class DialogComponent {
|
||||
this.hide.set(!this.hide());
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
login() {
|
||||
this.loginClicked.emit(this.data);
|
||||
|
||||
}
|
||||
|
||||
signup() {
|
||||
this.signupClicked.emit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<div class="navbar-wrapper">
|
||||
<div class="m-header">
|
||||
<mat-label>Jambotron</mat-label>
|
||||
<a href="javascript:" class="b-brand">
|
||||
<img src="assets/images/logo-dark.svg" alt="theme-logo" class="logo logo-dark logo-lg" />
|
||||
</a>
|
||||
</div>
|
||||
<!-- <app-nav-content (NavCollapsedMob)="navCollapseMob()" class="scroll-div w-100 compact"></app-nav-content>-->
|
||||
<mat-nav-list>
|
||||
<a mat-list-item routerLink="user-welcome">
|
||||
<span class="entry">
|
||||
<mat-icon>house</mat-icon>
|
||||
@if (!isCollapsed) {
|
||||
<span >Dashboard</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
<a mat-list-item routerLink="tutorials-list">
|
||||
<span class="entry">
|
||||
<mat-icon>newspaper</mat-icon>
|
||||
@if (!isCollapsed) {
|
||||
<span >Tutorials</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
<a mat-list-item routerLink="ai-models">
|
||||
<span class="entry">
|
||||
<mat-icon>house</mat-icon>
|
||||
@if (!isCollapsed) {
|
||||
<span >AI tools</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
</mat-nav-list>
|
||||
<div class="example-action-buttons">
|
||||
<button matButton (click)="accordion().openAll()">Expand All</button>
|
||||
<button matButton (click)="accordion().closeAll()">Collapse All</button>
|
||||
<!-- #docregion multi -->
|
||||
<mat-accordion class="example-headers-align" multi>
|
||||
<!-- #enddocregion multi -->
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<a mat-list-item routerLink="user-welcome">
|
||||
<span class="entry">
|
||||
<mat-icon>house</mat-icon>
|
||||
@if (!isCollapsed) {
|
||||
<span >Dashboard</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
</mat-panel-title>
|
||||
|
||||
</mat-expansion-panel-header>
|
||||
<mat-nav-list>
|
||||
<a mat-list-item routerLink="user-welcome">
|
||||
<span class="entry">
|
||||
<mat-icon>house</mat-icon>
|
||||
@if (!isCollapsed) {
|
||||
<span >Dashboard</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
<a mat-list-item routerLink="tutorials-list">
|
||||
<span class="entry">
|
||||
<mat-icon>newspaper</mat-icon>
|
||||
@if (!isCollapsed) {
|
||||
<span >Tutorials</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
<a mat-list-item routerLink="ai-models">
|
||||
<span class="entry">
|
||||
<mat-icon>house</mat-icon>
|
||||
@if (!isCollapsed) {
|
||||
<span >AI tools</span>
|
||||
}
|
||||
</span>
|
||||
</a>
|
||||
</mat-nav-list>
|
||||
</mat-expansion-panel>
|
||||
<!-- #docregion disabled -->
|
||||
<mat-expansion-panel disabled>
|
||||
<!-- #enddocregion disabled -->
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> Destination </mat-panel-title>
|
||||
<mat-panel-description>
|
||||
Type the country name
|
||||
<mat-icon>map</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Country</mat-label>
|
||||
<input matInput />
|
||||
</mat-form-field>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title> Day of the trip </mat-panel-title>
|
||||
<mat-panel-description>
|
||||
Inform the date you wish to travel
|
||||
<mat-icon>date_range</mat-icon>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>Date</mat-label>
|
||||
<input matInput [matDatepicker]="picker" (focus)="picker.open()" readonly />
|
||||
</mat-form-field>
|
||||
<mat-datepicker #picker></mat-datepicker>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
.entry{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding:0.75rem;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.example-action-buttons {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.example-headers-align .mat-expansion-panel-header-description {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.example-headers-align .mat-mdc-form-field + .mat-mdc-form-field {
|
||||
margin-left: 8px;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SideBarComponent } from './side-bar.component';
|
||||
|
||||
describe('SideBarComponent', () => {
|
||||
let component: SideBarComponent;
|
||||
let fixture: ComponentFixture<SideBarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SideBarComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(SideBarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
import {ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, viewChild} from '@angular/core';
|
||||
import {MatTree, MatTreeNode} from '@angular/material/tree';
|
||||
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
|
||||
import {MatDivider, MatListItem, MatNavList} from '@angular/material/list';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {RouterLink} from '@angular/router';
|
||||
import {
|
||||
MatAccordion, MatExpansionModule,
|
||||
MatExpansionPanel,
|
||||
MatExpansionPanelDescription,
|
||||
MatExpansionPanelTitle
|
||||
} from '@angular/material/expansion';
|
||||
import {MatDatepicker, MatDatepickerInput} from '@angular/material/datepicker';
|
||||
import {provideNativeDateAdapter} from '@angular/material/core';
|
||||
import {MatButton} from '@angular/material/button';
|
||||
|
||||
@Component({
|
||||
selector: 'app-side-bar',
|
||||
imports: [
|
||||
MatTree,
|
||||
MatTreeNode,
|
||||
MatLabel,
|
||||
MatNavList,
|
||||
MatListItem,
|
||||
MatIcon,
|
||||
RouterLink,
|
||||
MatExpansionPanel,
|
||||
MatExpansionPanelTitle,
|
||||
MatExpansionPanelDescription,
|
||||
MatFormField,
|
||||
MatInput,
|
||||
MatDatepickerInput,
|
||||
MatDatepicker,
|
||||
MatDivider,
|
||||
MatAccordion,
|
||||
MatButton,
|
||||
MatExpansionModule
|
||||
],
|
||||
templateUrl: './side-bar.component.html',
|
||||
styleUrl: './side-bar.component.scss',
|
||||
schemas:[CUSTOM_ELEMENTS_SCHEMA],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [provideNativeDateAdapter()],
|
||||
})
|
||||
|
||||
|
||||
|
||||
export class SideBarComponent {
|
||||
isCollapsed = false;
|
||||
|
||||
accordion = viewChild.required(MatAccordion);
|
||||
}
|
||||
|
||||
const TREE_DATA: TreeNode[] = [
|
||||
{
|
||||
name: 'Fruit',
|
||||
children: [{name: 'Apple'}, {name: 'Banana'}, {name: 'Fruit loops'}],
|
||||
},
|
||||
{
|
||||
name: 'Vegetables',
|
||||
children: [
|
||||
{
|
||||
name: 'Green',
|
||||
children: [{name: 'Broccoli'}, {name: 'Brussels sprouts'}],
|
||||
},
|
||||
{
|
||||
name: 'Orange',
|
||||
children: [{name: 'Pumpkins'}, {name: 'Carrots'}],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
interface TreeNode {
|
||||
name: string;
|
||||
children?: TreeNode[];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
<mat-card-header>
|
||||
<mat-card-title>{{tutorial.title}}</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content [innerHTML]="tutorial.description">
|
||||
<mat-card-content >
|
||||
<markdown class="variable-binding" [data]="tutorial.description"></markdown>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
}
|
||||
|
||||
@@ -2,13 +2,15 @@ import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||
import {Tutorial} from '../../models/tutorial.model';
|
||||
import {TutorialService} from '../../services/tutorial.service';
|
||||
import {MatCard, MatCardContent, MatCardHeader} from '@angular/material/card';
|
||||
import {MarkdownComponent} from 'ngx-markdown';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tutorials.component',
|
||||
imports: [
|
||||
MatCard,
|
||||
MatCardContent,
|
||||
MatCardHeader
|
||||
MatCardHeader,
|
||||
MarkdownComponent
|
||||
],
|
||||
templateUrl: './tutorials.component.html',
|
||||
styleUrl: './tutorials.component.scss',
|
||||
|
||||
Reference in New Issue
Block a user