Merge pull request #82 from liosha84/81-small-bug-fix

Remove SCSS files related to components, layouts, and Bootstrap varia…
This commit is contained in:
liosha84
2025-08-11 14:26:13 +03:00
committed by GitHub
75 changed files with 811 additions and 11333 deletions
+2 -1
View File
@@ -37,8 +37,9 @@
}
],
"styles": [
"@angular/material/prebuilt-themes/azure-blue.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/styles.scss",
"node_modules/prismjs/themes/prism-okaidia.css",
"node_modules/prismjs/plugins/line-numbers/prism-line-numbers.css",
"node_modules/prismjs/plugins/line-highlight/prism-line-highlight.css",
@@ -0,0 +1,24 @@
<!-- html -->
<nav aria-label="Breadcrumb" class="breadcrumb">
@let breadcrumbs = breadcrumbs$ | async;
<a mat-button [routerLink]="['/']">
<mat-icon>home</mat-icon>
</a>
@if (breadcrumbs) {
@for (bc of breadcrumbs; track bc.url; let last = $last) {
@if (!last) {
<a mat-button [routerLink]="bc.url">
<mat-icon class="sep">chevron_right</mat-icon>
{{ bc.label }}</a>
} @else {
<a mat-button >
<mat-icon class="sep">chevron_right</mat-icon>
{{ bc.label }}</a>
}
}
}
</nav>
<mat-divider></mat-divider>
@@ -0,0 +1,15 @@
.breadcrumb {
display: flex;
align-items: center;
gap: 4px;
margin-bottom: inherit;
}
.breadcrumb .sep {
font-size: 16px;
opacity: 0.6;
}
.breadcrumb a[mat-button] {
min-width: auto;
padding: 0 4px;
text-transform: none;
}
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { BreadcrumbsComponent } from './breadcrumbs.component';
describe('BreadcrumbsComponent', () => {
let component: BreadcrumbsComponent;
let fixture: ComponentFixture<BreadcrumbsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [BreadcrumbsComponent]
})
.compileComponents();
fixture = TestBed.createComponent(BreadcrumbsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,58 @@
import {Component, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA} from '@angular/core';
import {ActivatedRoute, NavigationEnd, Router, RouterLink} from '@angular/router';
import {MatButton} from '@angular/material/button';
import {AsyncPipe, NgForOf, NgIf} from '@angular/common';
import {MatIcon} from '@angular/material/icon';
import {Observable, startWith} from 'rxjs';
import {filter, map} from 'rxjs/operators';
import {MatDivider} from '@angular/material/divider';
type Breadcrumb = { label: string; url: string };
@Component({
selector: 'app-breadcrumbs',
imports: [
RouterLink,
MatIcon,
MatButton,
NgIf,
AsyncPipe,
NgForOf,
MatDivider
],
templateUrl: './breadcrumbs.component.html',
styleUrl: './breadcrumbs.component.scss',
schemas:[CUSTOM_ELEMENTS_SCHEMA,NO_ERRORS_SCHEMA]
})
export class BreadcrumbsComponent {
breadcrumbs$: Observable<Breadcrumb[]>;
constructor(private router: Router, private route: ActivatedRoute) {
this.breadcrumbs$ = this.router.events.pipe(
filter(e => e instanceof NavigationEnd),
startWith(null),
map(() => this.build(this.route.root))
);
}
private build(route: ActivatedRoute, url = '', crumbs: Breadcrumb[] = []): Breadcrumb[] {
const children = route.children;
if (!children || children.length === 0) return crumbs;
for (const child of children) {
if (child.outlet !== 'primary') continue;
const routeURL = child.snapshot.url.map(s => s.path).join('/');
if (routeURL) url += `/${routeURL}`;
const label = child.snapshot.data['breadcrumb'] as string | undefined;
if (label) crumbs.push({ label, url });
return this.build(child, url, crumbs);
}
return crumbs;
}
}
@@ -13,6 +13,7 @@
</button>
</mat-toolbar>
<input
id="fileInput"
type="file"
fileName="fileInput"
(change)="selectFile($event)"
+18
View File
@@ -21,4 +21,22 @@ export class GlobalConstants {
}
})();
public static readonly MARKDOWN_EXAMPLE =`## 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`;
}
@@ -3,6 +3,7 @@
>
</app-side-bar-admin>
<div class="pc-container">
<app-breadcrumbs></app-breadcrumbs>
<router-outlet />
</div>
@@ -2,11 +2,13 @@ import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
import {Router, RouterOutlet} from "@angular/router";
import {DOCUMENT} from '@angular/common';
import {SideBarAdminComponent} from '../side-bar-admin.component/side-bar-admin.component';
import {BreadcrumbsComponent} from '../../../components/breadcrumbs.component/breadcrumbs.component';
@Component({
selector: 'app-admin.component',
imports: [
RouterOutlet,
SideBarAdminComponent
SideBarAdminComponent,
BreadcrumbsComponent
],
schemas:[CUSTOM_ELEMENTS_SCHEMA],
templateUrl: './admin.component.html',
@@ -5,23 +5,28 @@ const ADMIN_ROUTES: Routes = [
{
path: '',
component: AdminComponent,
data:{breadcrumb: 'Admin'},
children: [
{ path: '', pathMatch: 'full', redirectTo: 'admin-welcome' },
{
path: 'admin-welcome',
loadComponent: () => import('../admin-module/admin-welcome.component/admin-welcome.component').then((c) => c.AdminWelcomeComponent),
data:{breadcrumb: 'Welcome'}
},
{
path: 'settings',
loadComponent: () => import('../admin-module/settings.component/settings.component').then((c) => c.SettingsComponent)
loadComponent: () => import('../admin-module/settings.component/settings.component').then((c) => c.SettingsComponent),
data:{breadcrumb: 'Settings'}
},
{
path: 'system',
loadComponent: () => import('../admin-module/system.component/system.component').then((c) => c.SystemComponent)
loadComponent: () => import('../admin-module/system.component/system.component').then((c) => c.SystemComponent),
data:{breadcrumb: 'System'}
},
{
path: 'users',
loadComponent: () => import('../admin-module/users.component/users.component').then((c) => c.UsersComponent)
loadComponent: () => import('../admin-module/users.component/users.component').then((c) => c.UsersComponent),
data:{breadcrumb: 'Users'}
}
]
}
@@ -28,10 +28,11 @@
alt="" width="100%" height="100%">
<mat-toolbar class="image-toolbar">
<mat-toolbar-row>
<span class="menu-spacer"></span>
<button matMiniFab matTooltip="Dawnload image" aria-label="Download" (click)="downloadImage(image.url)">
<mat-icon>download</mat-icon>
</button>
<span class="menu-spacer"></span>
@if (isLoggedIn) {
<button matMiniFab matTooltip="Save to server" aria-label="Save" (click)="save(image.url)" >
<mat-icon>upload_file</mat-icon>
@@ -29,5 +29,9 @@ mat-toolbar{
.router_outlet{
margin-top: 65px;
height: 100%;
min-height: fit-content;
}
.component{
height: 100%;
}
@@ -10,6 +10,7 @@ const MAIN_ROUTES: Routes =[
path: 'tutorials',
loadChildren: () =>
import('../tutorials-module/tutorials.module').then((m) => m.TutorialsModule),
},
{
path: 'ai',
@@ -25,6 +26,8 @@ const MAIN_ROUTES: Routes =[
path: 'user',
loadChildren: () =>
import('../user-module/user.module').then((m) => m.UserModule),
},
{
path: 'moderator',
@@ -1,4 +1,5 @@
<app-side-bar-moderator class="pc-sidebar" ></app-side-bar-moderator>
<div class="pc-container">
<app-breadcrumbs></app-breadcrumbs>
<router-outlet></router-outlet>
</div>
@@ -1,6 +1,7 @@
import { Component } from '@angular/core';
import {RouterOutlet} from '@angular/router';
import {SideBarModeratorComponent} from '../side-bar-moderator.component/side-bar-moderator.component';
import {BreadcrumbsComponent} from '../../../components/breadcrumbs.component/breadcrumbs.component';
@@ -9,6 +10,7 @@ import {SideBarModeratorComponent} from '../side-bar-moderator.component/side-ba
imports: [
RouterOutlet,
SideBarModeratorComponent,
BreadcrumbsComponent,
],
templateUrl: './moderator.component.html',
@@ -6,19 +6,23 @@ const MODERATOR_ROUTES: Routes = [
{
path: '',
component: ModeratorComponent,
data:{breadcrumb: 'Moderator'},
children: [
{ path: '', pathMatch: 'full', redirectTo: 'moderator-welcome' }, // default redirect
{
path: 'moderator-welcome',
loadComponent: () => import('../moderator-module/moderator-welcome.component/moderator-welcome.component').then((c) => c.ModeratorWelcomeComponent),
data:{breadcrumb: 'Welcome'}
},
{
path: 'tutorials-list',
loadComponent: () => import('../moderator-module/tutorials-list.component/tutorials-list.component').then((c) => c.TutorialsListComponent)
loadComponent: () => import('../moderator-module/tutorials-list.component/tutorials-list.component').then((c) => c.TutorialsListComponent),
data:{breadcrumb: 'Tutorials List'}
},
{
path: 'tutorial-preview',
loadComponent: () => import('../moderator-module/tutorial-preview.component/tutorial-preview.component').then((c) => c.TutorialPreviewComponent)
loadComponent: () => import('../moderator-module/tutorial-preview.component/tutorial-preview.component').then((c) => c.TutorialPreviewComponent),
data:{breadcrumb: 'Tutorial Preview'}
}
]
}
@@ -1,28 +1,75 @@
<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>Title</mat-label>
<input matInput required
[(ngModel)]="tutorial.title">
</mat-form-field>
<mat-tab-group>
<mat-tab label="Preview">
<markdown class="preview" [data]="tutorial.body"></markdown>
</mat-tab>
<mat-tab label="Edit">
<textarea class="variable-textarea" [(ngModel)]="tutorial.body"></textarea>
<markdown class="variable-binding" [data]="tutorial.body"></markdown>
</mat-tab>
<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-tab label="Example">
<textarea class="variable-textarea" [(ngModel)]="markdown"></textarea>
<markdown class="variable-binding" [data]="markdown"></markdown>
</mat-tab>
</mat-tab-group>
<mat-label class="label-style">Title image</mat-label>
<mat-divider></mat-divider>
<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>
</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="Result">
<markdown class="preview" [data]="tutorial.body"></markdown>
</mat-tab>
<mat-tab label="Markdown text | Result">
<textarea class="variable-textarea"
formControlName = "body"
(input)="onBodyChange($event)"
>
</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="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)="publishTutorial()">Publicate</button>
@@ -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;
}
@@ -1,5 +1,13 @@
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {FormsModule} from "@angular/forms";
import {Component, CUSTOM_ELEMENTS_SCHEMA, inject} from '@angular/core';
import {
AbstractControl,
FormBuilder,
FormsModule,
ReactiveFormsModule,
ValidationErrors,
ValidatorFn,
Validators
} from "@angular/forms";
import {MarkdownComponent} from "ngx-markdown";
import {MatButton} from "@angular/material/button";
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from "@angular/material/card";
@@ -8,6 +16,27 @@ import {MatTab, MatTabGroup} from "@angular/material/tabs";
import {ActivatedRoute, RouterLink} from "@angular/router";
import {Tutorial} from '../../../models/tutorial.model';
import {ModeratorApiService} from '../moderator-api.service';
import {GlobalConstants} from '../../../global-constants';
import {MatDivider} from '@angular/material/divider';
import {MatDialog} from '@angular/material/dialog';
import {
DialogSelectImageComponent
} from '../../user-module/dialog-select-image.component/dialog-select-image.component';
import {
DialogUploadImageComponent
} from '../../user-module/dialog-upload-image.component/dialog-upload-image.component';
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-preview.component',
@@ -27,7 +56,9 @@ import {ModeratorApiService} from '../moderator-api.service';
MatTabGroup,
RouterLink,
MatError,
MatFormField
MatFormField,
MatDivider,
ReactiveFormsModule
],
templateUrl: './tutorial-preview.component.html',
styleUrl: './tutorial-preview.component.scss',
@@ -38,22 +69,23 @@ export class TutorialPreviewComponent {
submitted = false;
hasError = false;
errorMessage = '';
markdown = `## Markdown __rulez__!
---
markdown = GlobalConstants.MARKDOWN_EXAMPLE;
### Syntax highlight
\`\`\`typescript
const language = 'typescript';
\`\`\`
readonly dialog = inject(MatDialog);
### Lists
1. Ordered list
2. Another bullet point
- Unordered list
- Another unordered bullet
### Blockquote
> Blockquote to the max`;
private fb = inject(FormBuilder);
form = this.fb.nonNullable.group({
title: ['', [Validators.required, nonBlank()] ],
body: ['', [Validators.required, nonBlank()] ],
titleimage: this.fb.nonNullable.control({ value: '', disabled: true }),
});
private id: string | null | undefined;
@@ -69,11 +101,43 @@ const language = 'typescript';
this.moderatorApiService.getTutorial(this.id).subscribe(
data=>{
this.tutorial = data;
console.log(data);
this.form.patchValue(this.fromModel(data));
}
);
}
// Map Model -> Form value
private fromModel(m: Tutorial): Partial<TutorialFormValue> {
return {
title: m.title ?? '',
body: m.body ?? '',
titleimage: m.titleimage ?? '',
};
}
// 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(),
};
}
publishTutorial(): void {
if (this.form.invalid) {
this.form.markAllAsTouched();
return;
}
this.tutorial = this.toModel();
// send `updated` to your API here
this.tutorial.published = true;
this.moderatorApiService.publish(this.id, this.tutorial)
.subscribe(
@@ -90,4 +154,59 @@ const language = 'typescript';
this.hasError = true;
});
}
onBodyChange($event: Event) {
this.tutorial.body = this.form.get('body')?.value;
}
openSelectImageDialog(enterAnimationDuration: string, exitAnimationDuration: string) {
let dialogSelectRef = this.dialog.open(DialogSelectImageComponent, {
height: '500px',
width: '600px',
enterAnimationDuration,
exitAnimationDuration,
// data: {username: this.dialogLoginData.username, password: this.dialogLoginData.password}
});
dialogSelectRef.componentInstance.uploadClicked.subscribe(result => {
dialogSelectRef.close();
this.openUploadImageDialog(enterAnimationDuration, exitAnimationDuration);
})
const dialogSelectSubscription = dialogSelectRef.componentInstance.selectClicked
.subscribe(result => {
console.log('Got the data!', result);
if (result == null) {
return;
}
this.tutorial.titleimage = result.url;
this.form.patchValue({ titleimage: result.url });
});
}
openUploadImageDialog(enterAnimationDuration: string, exitAnimationDuration: string) {
let dialogSelectRef = this.dialog.open(DialogUploadImageComponent, {
height: '500px',
width: '600px',
enterAnimationDuration,
exitAnimationDuration,
// data: {username: this.dialogLoginData.username, password: this.dialogLoginData.password}
});
dialogSelectRef.componentInstance.openSelectDialogClicked.subscribe(result => {
dialogSelectRef.close();
this.openSelectImageDialog(enterAnimationDuration, exitAnimationDuration);
})
const dialogUploadSubscription = dialogSelectRef.componentInstance.selectUploadedImageClicked
.subscribe(result => {
console.log('Got the data!', result);
if (result == null) {
return;
}
this.tutorial.titleimage = result.url;
this.form.patchValue({ titleimage: result.url });
});
}
}
@@ -1,10 +1,18 @@
<div class="container-card-view">
@for(tutorial of tutorials; track $index){
<mat-card>
<img mat-card-image [src]="tutorial.titleimage" alt="Photo of a" />
<mat-card
routerLink="../tutorial-view" [queryParams]="{id:tutorial.id}"
style="cursor: grab"
>
<mat-card-content>
<img mat-card-image [src]="tutorial.titleimage" alt="Photo of a" />
<!--<a routerLink="../tutorial-view" [queryParams]="{id:tutorial.id}">
</a>-->
</mat-card-content>
<mat-card-actions>
<button mat-button routerLink="../tutorial-view" [queryParams]="{id:tutorial.id}" target="_blank">{{tutorial.title}}</button>
<a class="app-link" routerLink="../tutorial-view" [queryParams]="{id:tutorial.id}">{{tutorial.title}}</a>
</mat-card-actions>
</mat-card>
@@ -11,15 +11,7 @@
object-fit: cover;
padding: 24px;
justify-content: center;
//width: 100%;
//height: 100%;
//padding-top: 20px;
//display: flex;
//flex-wrap: wrap;
//flex-direction: row;
//align-content: flex-start;
//justify-content: space-around;
//align-items: center;
min-height: fit-content;
}
.container {
@@ -38,3 +30,38 @@ img {
gap: 24px;
}
.app-link{
font-weight: bold;
color:cyan;
}
.app-link:link{
text-decoration:none;
}
.app-link:visited{
//color:#ff0000;
text-decoration:none;
}
.app-link:hover{
//color:#ff0000;
text-decoration:underline;
}
.mat-mdc-card{
background-color: rgba(153,153,153,0.16);
backdrop-filter: blur(8px);
border-radius: 0;
}
.mat-mdc-card-content {
padding: 0;
}
.mat-mdc-card-content:first-child{
padding-top: 0;
}
.mat-mdc-card-actions{
min-height: 64px;
backdrop-filter: blur(8px);
background-color: #1d284a85;
}
@@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import {Tutorial} from '../../../models/tutorial.model';
import {MatCard, MatCardActions, MatCardImage} from '@angular/material/card';
import {MatCard, MatCardActions, MatCardContent, MatCardImage} from '@angular/material/card';
import {RouterLink} from '@angular/router';
import {MatButton} from '@angular/material/button';
import {TutorialsApiService} from '../tutorials-api.service';
@@ -12,7 +12,8 @@ import {TutorialsApiService} from '../tutorials-api.service';
MatCardActions,
RouterLink,
MatButton,
MatCardImage
MatCardImage,
MatCardContent
],
templateUrl: './tutorials-card-view.component.html',
styleUrl: './tutorials-card-view.component.scss'
@@ -1 +1,4 @@
<router-outlet></router-outlet>
<router-outlet></router-outlet>
@@ -6,4 +6,6 @@
}
.component{
height: 100%;
}
@@ -4,7 +4,7 @@
<!-- <mat-nav-list>-->
@for (fileInfo of fileInfos; track fileInfo){
<a mat-list-item (click)="select(fileInfo)">
<img style="width: 120px; height: 120px" src="{{fileInfo.url}}" alt="">
<img style="width: 179px; height: 100px" src="{{fileInfo.url}}" alt="">
<span class="entry">
<!-- @if (!isCollapsed) {-->
@@ -1,26 +1,26 @@
<mat-card appearance="outlined">
<mat-card-header>
<mat-card-title>Add tutorial</mat-card-title>
</mat-card-header>
<mat-card-content >
<mat-card-content>
<form [formGroup]="form" novalidate>
<mat-form-field class="example-full-width">
<mat-label class="label-style">Title</mat-label>
<input matInput required
[(ngModel)]="tutorial.title">
<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">
<input matInput
formControlName="titleimage"
[disabled]="true"
>
</mat-form-field>
<div>
<button mat-raised-button color="primary" (click)="openSelectImageDialog('100ms', '5ms')">Select image</button>
@@ -30,50 +30,27 @@
</td>
</tr>
</table>
<div class="example-full-width">
<mat-label class="label-style">Description</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>
</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>
@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" [(ngModel)]="tutorial.body"></textarea>
<textarea class="variable-textarea"
formControlName = "body"
(input)="onBodyChange($event)"
>
</textarea>
<markdown class="variable-binding" [data]="tutorial.body"></markdown>
</mat-tab>
<mat-tab label="Editor">
<!--<mat-tab label="Editor">
<form novalidate>
<angular-markdown-editor style="color: #1a1a1a"
textareaId="editor2"
@@ -84,26 +61,38 @@
>
</angular-markdown-editor>
</form>
</mat-tab>
</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>
<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>
@if (hasError){
<mat-error>
{{errorMessage}}
</mat-error>
}
@if (submitted){
<div >
<h4>Tutorial was submitted successfully!</h4>
<button matButton (click)="newTutorial()">Add new tutorial</button>
<button matButton routerLink="../tutorials-list">Back to list</button>
</div>
} @else {
<button matButton (click)="saveTutorial()" >Save</button>
<button matButton (click)="saveTutorial()"
[disabled]="form.invalid"
>
Save
</button>
}
</mat-card-actions>
</mat-card>
@@ -24,6 +24,9 @@ mat-card-title{
.example-full-width {
width: 100%;
}
.content-center{
text-align: center;
}
.variable-binding,
@@ -55,7 +58,7 @@ mat-card-title{
}
.label-style{
font-size: -webkit-xxx-large;
font-size: xx-large;
font-weight: bold;
}
@@ -2,21 +2,44 @@ import {Component, CUSTOM_ELEMENTS_SCHEMA, inject, OnInit} from '@angular/core';
import {UserApiService} from '../user-api.service';
import {TokenStorageService} from '../../../services/token-storage.service';
import {EventBusService} from '../../../_shared/event-bus.service';
import {Router} from '@angular/router';
import {Router, RouterLink} from '@angular/router';
import {AuthService} from '../../../services/auth.service';
import {Tutorial} from '../../../models/tutorial.model';
import {MarkdownComponent, MarkdownService} from 'ngx-markdown';
import {MatButton} from '@angular/material/button';
import {MatCard, MatCardActions, MatCardContent, MatCardHeader} from '@angular/material/card';
import {MatFormField, MatInput, MatLabel} from '@angular/material/input';
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,
FormControl,
FormGroup,
FormsModule,
ReactiveFormsModule, ValidationErrors,
ValidatorFn,
Validators
} from '@angular/forms';
import {AngularMarkdownEditorModule, EditorInstance, EditorOption} from 'angular-markdown-editor';
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 {FileUploadComponent} from '../../../components/file-upload.component/file-upload.component';
import {MatDivider} from '@angular/material/divider';
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-add.component',
@@ -35,140 +58,122 @@ import {MatDivider} from '@angular/material/divider';
ReactiveFormsModule,
FormsModule,
AngularMarkdownEditorModule,
MatDivider
MatDivider,
MatError,
RouterLink
],
templateUrl: './tutorial-add.component.html',
styleUrl: './tutorial-add.component.scss',
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class TutorialAddComponent implements OnInit{
export class TutorialAddComponent{
tutorial: Tutorial = new Tutorial();
submitted = false;
markdownText = '';
showEditor = true;
bsEditorInstance!: EditorInstance;
tutorialForm!: FormGroup;
editorOptions!: EditorOption;
readonly dialog = inject(MatDialog);
markdown = GlobalConstants.MARKDOWN_EXAMPLE;
private fb = inject(FormBuilder);
markdown = `## Markdown __rulez__!
---
form = this.fb.nonNullable.group({
### Syntax highlight
\`\`\`typescript
const language = 'typescript';
\`\`\`
title: ['', [Validators.required, nonBlank()] ],
body: ['', [Validators.required, nonBlank()] ],
### Lists
1. Ordered list
2. Another bullet point
- Unordered list
- Another unordered bullet
titleimage: this.fb.nonNullable.control({ value: '', disabled: true }),
### Blockquote
> Blockquote to the max`;
});
hasError = false;
errorMessage = '';
constructor(private fb: FormBuilder,
constructor(
private markdownService: MarkdownService,
private userApiService: UserApiService,
) {
this.tutorial.description = this.markdown;
this.tutorial.title="";
this.tutorial.titleimage="";
this.tutorial.body = this.markdown;
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,
created: new Date(),
};
}
saveTutorial(): void {
const data = {
title: this.tutorial.title,
description: this.tutorial.description,
body: this.tutorial.body,
published: this.tutorial.published,
titleimage: this.tutorial.titleimage,
created: new Date(),
modified: new Date(),
tobepublished: false,
isEdit: false,
isAdmin: false,
isSuperAdmin: false,
isUser: false,
};
if (this.form.invalid) {
this.form.markAllAsTouched();
return;
}
this.tutorial = this.toModel();
// send `updated` to your API here
this.userApiService.create(this.tutorial)
.subscribe(
response => {
console.log(response);
this.submitted = true;
},
)
const data = {
title: this.tutorial.title,
description: this.tutorial.description,
body: this.tutorial.body,
published: this.tutorial.published,
titleimage: this.tutorial.titleimage,
created: new Date(),
modified: new Date(),
tobepublished: false,
isEdit: false,
isAdmin: false,
isSuperAdmin: false,
isUser: false,
}
this.userApiService.create(data)
.subscribe(
response => {
console.log(response);
this.submitted = true;
this.hasError = false;
},
error => {
console.log(error);
this.errorMessage = error.error.message;
this.hasError = true;
});
this.userApiService.create(data)
.subscribe(
response => {
console.log(response);
this.submitted = true;
},
error => {
console.log(error);
});
}
newTutorial(): void {
this.submitted = false;
this.tutorial = {
title: '',
description: '',
body:"",
published: false
};
}
@@ -195,6 +200,7 @@ const language = 'typescript';
return;
}
this.tutorial.titleimage = result.url;
this.form.patchValue({ titleimage: result.url });
});
}
@@ -220,7 +226,12 @@ 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;
}
}
@@ -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}}
@@ -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;
}
@@ -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;
}
}
@@ -1,4 +1,6 @@
<article class="table-header">
<button mat-raised-button routerLink="../tutorial-add">Add tutorial</button>
<button
class="button-remove-rows"
mat-button
@@ -6,7 +8,7 @@
>
Remove Rows
</button>
<button mat-raised-button routerLink="../tutorial-add">Add tutorial</button>
</article>
<table mat-table [dataSource]="dataSource">
@@ -22,6 +22,7 @@ import {
import {DatePipe} from '@angular/common';
import {MatCheckbox} from '@angular/material/checkbox';
import {MatSlideToggle} from '@angular/material/slide-toggle';
import {BreadcrumbsComponent} from '../../../components/breadcrumbs.component/breadcrumbs.component';
@Component({
@@ -43,7 +44,8 @@ import {MatSlideToggle} from '@angular/material/slide-toggle';
MatCheckbox,
DatePipe,
MatCell,
MatSlideToggle
MatSlideToggle,
BreadcrumbsComponent
],
schemas:[CUSTOM_ELEMENTS_SCHEMA],
templateUrl: './tutorials-list.component.html',
@@ -4,6 +4,7 @@
</app-side-bar-user>
<div class="pc-container">
<app-breadcrumbs></app-breadcrumbs>
<router-outlet></router-outlet>
</div>
@@ -1,13 +0,0 @@
//---------------
.pc-sidebar{
top: 65px;
overflow-y: auto;
background-color: rgba(153, 153, 153, 0.16);
backdrop-filter: blur(8px);
}
.pc-container{
top: 0px;
padding-left: 5px;
padding-right: 5px;
}
@@ -3,12 +3,14 @@ import {RouterOutlet} from '@angular/router';
import {MatSidenav} from '@angular/material/sidenav';
import {BreakpointObserver} from '@angular/cdk/layout';
import {SideBarUserComponent} from '../side-bar-user.component/side-bar-user.component';
import {BreadcrumbsComponent} from '../../../components/breadcrumbs.component/breadcrumbs.component';
@Component({
selector: 'app-user.component',
imports: [
RouterOutlet,
SideBarUserComponent
SideBarUserComponent,
BreadcrumbsComponent
],
templateUrl: './user.component.html',
styleUrl: './user.component.scss',
@@ -7,30 +7,39 @@ const USER_ROUTES: Routes = [
path: '',
component: UserComponent,
data:{breadcrumb: 'User'},
children: [
{ path: '', pathMatch: 'full', redirectTo: 'user-welcome' }, // default redirect
{
path: 'user-welcome',
loadComponent: () => import('../user-module/user-welcome.component/user-welcome.component').then((c) => c.UserWelcomeComponent),
data:{breadcrumb: 'Welcome'}
},
{
path: 'tutorials-list',
loadComponent: () => import('../user-module/tutorials-list.component/tutorials-list.component').then((c) => c.TutorialsListComponent)
loadComponent: () => import('../user-module/tutorials-list.component/tutorials-list.component').then((c) => c.TutorialsListComponent),
data:{breadcrumb: 'Tutorials List'}
},
{
path: 'tutorial-add',
loadComponent: () => import('../user-module/tutorial-add.component/tutorial-add.component').then((c) => c.TutorialAddComponent)
loadComponent: () => import('../user-module/tutorial-add.component/tutorial-add.component').then((c) => c.TutorialAddComponent),
data:{breadcrumb: 'Add Tutorial'}
},
{
path: 'tutorial-edit',
loadComponent: () => import('../user-module/tutorial-edit.component/tutorial-edit.component').then((c) => c.TutorialEditComponent)
loadComponent: () => import('../user-module/tutorial-edit.component/tutorial-edit.component').then((c) => c.TutorialEditComponent),
data:{breadcrumb: 'Edit Tutorial'}
},
{
path: 'ai-models',
loadComponent: () => import('../user-module/ai-models.component/ai-models.component').then((c) => c.AiModelsComponent)
loadComponent: () => import('../user-module/ai-models.component/ai-models.component').then((c) => c.AiModelsComponent),
data:{breadcrumb: 'AI'}
},
{
path: 'images',
loadComponent: () => import('../user-module/images.component/images.component').then((c) => c.ImagesComponent)
loadComponent: () => import('../user-module/images.component/images.component').then((c) => c.ImagesComponent),
data:{breadcrumb: 'Images'}
}
]
}
+2
View File
@@ -7,6 +7,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
<link rel="stylesheet"
href="https://fonts.googleapis.com/css?family= Jersey 20 Charted:wght@300;400;500&display=swap">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<!-- Google tag (gtag.js) -->
-34
View File
@@ -1,34 +0,0 @@
@import '../../../node_modules/bootstrap/scss/maps';
@import '../../../node_modules/bootstrap/scss/mixins';
@import '../../../node_modules/bootstrap/scss/root';
@import '../../../node_modules/bootstrap/scss/reboot';
@import '../../../node_modules/bootstrap/scss/type';
@import '../../../node_modules/bootstrap/scss/images';
@import '../../../node_modules/bootstrap/scss/containers';
@import '../../../node_modules/bootstrap/scss/grid';
@import '../../../node_modules/bootstrap/scss/tables';
@import '../../../node_modules/bootstrap/scss/forms';
@import '../../../node_modules/bootstrap/scss/buttons';
@import '../../../node_modules/bootstrap/scss/transitions';
@import '../../../node_modules/bootstrap/scss/dropdown';
@import '../../../node_modules/bootstrap/scss/button-group';
@import '../../../node_modules/bootstrap/scss/nav';
@import '../../../node_modules/bootstrap/scss/navbar';
@import '../../../node_modules/bootstrap/scss/card';
@import '../../../node_modules/bootstrap/scss/accordion';
@import '../../../node_modules/bootstrap/scss/breadcrumb';
@import '../../../node_modules/bootstrap/scss/pagination';
@import '../../../node_modules/bootstrap/scss/badge';
@import '../../../node_modules/bootstrap/scss/alert';
@import '../../../node_modules/bootstrap/scss/progress';
@import '../../../node_modules/bootstrap/scss/list-group';
@import '../../../node_modules/bootstrap/scss/close';
@import '../../../node_modules/bootstrap/scss/toasts';
@import '../../../node_modules/bootstrap/scss/modal';
@import '../../../node_modules/bootstrap/scss/tooltip';
@import '../../../node_modules/bootstrap/scss/popover';
@import '../../../node_modules/bootstrap/scss/carousel';
@import '../../../node_modules/bootstrap/scss/spinners';
@import '../../../node_modules/bootstrap/scss/offcanvas';
@import '../../../node_modules/bootstrap/scss/placeholders';
@import '../../../node_modules/bootstrap/scss/helpers';
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,39 +0,0 @@
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src:
url('Inter-Regular.woff2?v=3.13') format('woff2'),
url('Inter-Regular.woff?v=3.13') format('woff');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src:
url('Inter-Medium.woff2?v=3.13') format('woff2'),
url('Inter-Medium.woff?v=3.13') format('woff');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src:
url('Inter-SemiBold.woff2?v=3.13') format('woff2'),
url('Inter-SemiBold.woff?v=3.13') format('woff');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src:
url('Inter-Bold.woff2?v=3.13') format('woff2'),
url('Inter-Bold.woff?v=3.13') format('woff');
}
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.
Binary file not shown.
-735
View File
@@ -1,735 +0,0 @@
// Variables
//
// Variables should follow the `$component-state-property-size` formula for
// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.
// Color system
$grays: (
'100': $gray-100,
'200': $gray-200,
'300': $gray-300,
'400': $gray-400,
'500': $gray-500,
'600': $gray-600,
'700': $gray-700,
'800': $gray-800,
'900': $gray-900
);
// scss-docs-start colors-map
$colors: (
'blue': $blue,
'indigo': $indigo,
'purple': $purple,
'pink': $pink,
'red': $red,
'orange': $orange,
'yellow': $yellow,
'green': $green,
'teal': $teal,
'cyan': $cyan,
'black': $black,
'white': $white,
'gray': $gray-600,
'gray-dark': $gray-800
);
// scss-docs-end colors-map
$primary: $blue; // change
$secondary: $secondary; // change
$success: $green; // change
$info: $cyan; // change
$warning: $yellow; // change
$danger: $red; // change
$light: $gray-100; // change
$dark: $dark; // change
// scss-docs-start theme-colors-map
$theme-colors: (
'primary': $primary,
'secondary': $secondary,
'success': $success,
'info': $info,
'warning': $warning,
'danger': $danger,
'light': $light,
'dark': $dark
);
// scss-docs-end theme-colors-map
// scss-docs-start theme-colors-rgb
$theme-colors-rgb: map-loop($theme-colors, to-rgb, '$value');
// scss-docs-end theme-colors-rgb
// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.
// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast
$min-contrast-ratio: 1.55;
// Customize the light and dark text colors for use in our color contrast function.
$color-contrast-dark: $body-color;
$color-contrast-light: $white;
// fusv-disable
$blues: (
'blue-100': $blue-100,
'blue-200': $blue-200,
'blue-300': $blue-300,
'blue-400': $blue-400,
'blue-500': $blue-500,
'blue-600': $blue-600,
'blue-700': $blue-700,
'blue-800': $blue-800,
'blue-900': $blue-900
);
// Characters which are escaped by the escape-svg function
$escaped-characters: (('<', '%3c'), ('>', '%3e'), ('#', '%23'), ('(', '%28'), (')', '%29'));
$variable-prefix: bs-; // Deprecated in v5.2.0 for the shorter `$prefix`
$prefix: $variable-prefix;
// Gradient
$gradient: linear-gradient(180deg, rgba($white, 0.15), rgba($white, 0));
// Spacing
$spacer: 1rem;
$spacers: (
0: 0,
1: $spacer * 0.25,
2: $spacer * 0.5,
3: $spacer,
4: $spacer * 1.5,
5: $spacer * 3
);
// scss-docs-end spacer-variables-maps
// Position
//
// Define the edge positioning anchors of the position utilities.
// scss-docs-start position-map
$position-values: (
0: 0,
50: 50%,
100: 100%
);
// scss-docs-end position-map
// Body
//
// Settings for the `<body>` element.
$body-bg: #fafafb; // change
$body-color: $gray-900; // change
$body-text-align: null;
// Links
//
// Style anchor elements.
$link-color: $primary;
$link-decoration: none;
$link-shade-percentage: 20%;
$link-hover-color: shift-color($link-color, $link-shade-percentage);
$link-hover-decoration: underline;
$stretched-link-pseudo-element: after;
$stretched-link-z-index: 1;
// Paragraphs
//
// Style p element.
$paragraph-margin-bottom: 1rem;
// Grid breakpoints
//
// Define the minimum dimensions at which your layout will change,
// adapting to different screen sizes, for use in media queries.
// scss-docs-start grid-breakpoints
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
);
// scss-docs-end grid-breakpoints
@include _assert-ascending($grid-breakpoints, '$grid-breakpoints');
@include _assert-starts-at-zero($grid-breakpoints, '$grid-breakpoints');
// Grid containers
//
// Define the maximum width of `.container` for different screen sizes.
// scss-docs-start container-max-widths
$container-max-widths: (
sm: 540px,
md: 720px,
lg: 960px,
xl: 1140px,
xxl: 1320px
);
// scss-docs-end container-max-widths
@include _assert-ascending($container-max-widths, '$container-max-widths');
// Grid columns
//
// Set the number of columns and specify the width of the gutters.
$grid-columns: 12;
$grid-gutter-width: 1.5rem;
$grid-row-columns: 6;
// Container padding
$container-padding-x: $grid-gutter-width;
// Components
//
// Define common padding and border radius sizes and more.
// scss-docs-start border-variables
$border-width: 1px;
$border-widths: (
0: 0,
1: 1px,
2: 2px,
3: 3px,
4: 4px,
5: 5px
);
$border-style: solid;
$border-color: #e6ebf1;
$border-color-translucent: rgba($black, 0.175);
$border-radius: 4px; // change
$border-radius-lg: 6px; // change
$border-radius-sm: 2px; // change
$border-radius-pill: 50rem;
// scss-docs-end border-radius-variables
$box-shadow-sm: 0 0.125rem 0.25rem rgba($black, 0.075);
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15);
$box-shadow-lg: 0 1rem 3rem rgba($black, 0.175);
$box-shadow-inset: inset 0 1px 2px rgba($black, 0.075);
$component-active-color: $white;
$component-active-bg: var(--bs-primary);
// scss-docs-start caret-variables
$caret-width: 0.3em;
$caret-vertical-align: $caret-width * 0.85;
$caret-spacing: $caret-width * 0.85;
// scss-docs-end caret-variables
$transition-base: all 0.2s ease-in-out;
$transition-fade: opacity 0.15s linear;
// scss-docs-start collapse-transition
$transition-collapse: height 0.35s ease;
$transition-collapse-width: width 0.35s ease;
// stylelint-disable function-disallowed-list
// scss-docs-start aspect-ratios
$aspect-ratios: (
'1x1': 100%,
'4x3': calc(3 / 4 * 100%),
'16x9': calc(9 / 16 * 100%),
'21x9': calc(9 / 21 * 100%)
);
// scss-docs-end aspect-ratios
// stylelint-enable function-disallowed-list
// Typography
//
// Font, line-height, and color for body text, headings, and more.
// stylelint-disable value-keyword-case
$font-family-sans-serif: 'Public Sans', sans-serif; // change
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
// stylelint-enable value-keyword-case
$font-family-base: var(--#{$variable-prefix}font-sans-serif);
$font-family-code: var(--#{$variable-prefix}font-monospace);
$font-size-root: null;
$font-size-base: 0.875rem;
$font-size-sm: $font-size-base * 0.875;
$font-size-lg: $font-size-base * 1.25;
$font-weight-lighter: lighter;
$font-weight-light: 300;
$font-weight-normal: 400;
$font-weight-bold: 700;
$font-weight-bolder: bolder;
$font-weight-base: $font-weight-normal;
$line-height-base: 1.5;
$line-height-sm: 1.25;
$line-height-lg: 2;
$h1-font-size: 40px; // change
$h2-font-size: 30px; // change
$h3-font-size: 24px; // change
$h4-font-size: 20px; // change
$h5-font-size: 16px; // change
$h6-font-size: 14px; // change
// scss-docs-start font-sizes
$font-sizes: (
1: $h1-font-size,
2: $h2-font-size,
3: $h3-font-size,
4: $h4-font-size,
5: $h5-font-size,
6: $h6-font-size
);
// scss-docs-end font-sizes
// scss-docs-end font-sizes
h1,
h2 {
font-weight: 700;
}
$headings-margin-bottom: calc($spacer / 2);
$headings-font-family: null;
$headings-font-style: null;
$headings-font-weight: 600;
$headings-line-height: 1.2;
$headings-color: #262626;
$label-color: $gray-900;
// scss-docs-start display-headings
$display-font-sizes: (
1: 5rem,
2: 4.5rem,
3: 4rem,
4: 3.5rem,
5: 3rem,
6: 2.5rem
);
$display-font-weight: 300;
$display-line-height: $headings-line-height;
// scss-docs-end display-headings
$lead-font-size: $font-size-base * 1.25;
$lead-font-weight: 300;
$small-font-size: 80%;
$sub-sup-font-size: 0.75em;
$text-muted: $gray-600;
$hr-margin-y: $spacer;
$hr-color: inherit;
$hr-height: $border-width;
$hr-opacity: 0.13;
$legend-margin-bottom: 0.5rem;
$legend-font-size: 1.5rem;
$legend-font-weight: null;
$mark-padding: 0.2em;
$dt-font-weight: $font-weight-bold;
$nested-kbd-font-weight: $font-weight-bold;
$list-inline-padding: 0.5rem;
$mark-bg: #fcf8e3;
// Tables
//
// Customizes the `.table` component with basic values, each used across all table variations.
// scss-docs-start table-variables
$table-cell-padding-y: 0.9rem;
$table-cell-padding-x: 0.75rem;
$table-cell-padding-y-sm: 0.3rem;
$table-cell-padding-x-sm: 0.3rem;
$table-cell-vertical-align: top;
$table-color: $body-color;
$table-bg: transparent;
$table-accent-bg: transparent;
$table-th-font-weight: null;
$table-striped-color: $table-color;
$table-striped-bg-factor: 0.05;
$table-striped-bg: rgba($black, $table-striped-bg-factor);
$table-active-color: $table-color;
$table-active-bg-factor: 0.1;
$table-active-bg: rgba($black, $table-active-bg-factor);
$table-hover-color: $table-color;
$table-hover-bg-factor: 0.02;
$table-hover-bg: rgba($primary, $table-hover-bg-factor);
$table-border-factor: 0.1;
$table-border-width: $border-width;
$table-border-color: $border-color;
$table-striped-order: odd;
$table-group-seperator-color: currentColor;
$table-caption-color: $text-muted;
$table-bg-scale: -80%;
$table-variants: (
'primary': shift-color($primary, $table-bg-scale),
'secondary': shift-color($secondary, $table-bg-scale),
'success': shift-color($success, $table-bg-scale),
'info': shift-color($info, $table-bg-scale),
'warning': shift-color($warning, $table-bg-scale),
'danger': shift-color($danger, $table-bg-scale),
'light': $light,
'dark': $dark
);
// scss-docs-end table-variables
// Buttons + Forms
//
// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.
$input-btn-padding-y: 0.407rem;
$input-btn-padding-x: 1rem;
$input-btn-font-family: null;
$input-btn-font-size: 0.875rem;
$input-btn-line-height: $line-height-base;
$input-btn-focus-width: 0.2rem;
$input-btn-focus-color-opacity: 0.25;
$input-btn-focus-color: rgba($component-active-bg, $input-btn-focus-color-opacity);
$input-btn-focus-blur: 0;
$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color;
$input-btn-padding-y-sm: 0.25rem;
$input-btn-padding-x-sm: 0.5rem;
$input-btn-font-size-sm: $font-size-sm;
$input-btn-padding-y-lg: 1rem;
$input-btn-padding-x-lg: 1.3rem;
$input-btn-font-size-lg: $font-size-lg;
$input-btn-border-width: 1px;
// Buttons
//
// For each of Bootstrap's buttons, define text, background, and border color.
$btn-padding-y: $input-btn-padding-y;
$btn-padding-x: $input-btn-padding-x;
$btn-font-family: $input-btn-font-family;
$btn-font-size: $input-btn-font-size;
$btn-line-height: $input-btn-line-height;
$btn-white-space: null; // Set to `nowrap` to prevent text wrapping
$btn-padding-y-sm: $input-btn-padding-y-sm;
$btn-padding-x-sm: $input-btn-padding-x-sm;
$btn-font-size-sm: $input-btn-font-size-sm;
$btn-padding-y-lg: $input-btn-padding-y-lg;
$btn-padding-x-lg: $input-btn-padding-x-lg;
$btn-font-size-lg: $input-btn-font-size-lg;
$btn-border-width: $input-btn-border-width;
$btn-font-weight: 400;
$btn-box-shadow:
inset 0 1px 0 rgba($white, 0.15),
0 1px 1px rgba($black, 0.075);
$btn-focus-width: $input-btn-focus-width;
$btn-focus-box-shadow: $input-btn-focus-box-shadow;
$btn-disabled-opacity: 0.65;
$btn-active-box-shadow: inset 0 3px 5px rgba($black, 0.125);
$btn-link-color: $link-color;
$btn-link-hover-color: $link-hover-color;
$btn-link-disabled-color: $gray-600;
// Allows for customizing button radius independently from global border radius
$btn-border-radius: 4px;
$btn-border-radius-sm: 2px;
$btn-border-radius-lg: 6px;
$btn-transition:
color 0.15s ease-in-out,
background-color 0.15s ease-in-out,
border-color 0.15s ease-in-out,
box-shadow 0.15s ease-in-out;
$btn-hover-bg-shade-amount: 15%;
$btn-hover-bg-tint-amount: 15%;
$btn-hover-border-shade-amount: 20%;
$btn-hover-border-tint-amount: 10%;
$btn-active-bg-shade-amount: 20%;
$btn-active-bg-tint-amount: 20%;
$btn-active-border-shade-amount: 25%;
$btn-active-border-tint-amount: 10%;
// scss-docs-end btn-variables
// Forms
$form-text-margin-top: 0.25rem;
$form-text-font-size: $small-font-size;
$form-text-font-style: null;
$form-text-font-weight: null;
$form-text-color: $text-muted;
$form-label-margin-bottom: 0.5rem;
$form-label-font-size: null;
$form-label-font-style: null;
$form-label-font-weight: null;
$form-label-color: $label-color;
$input-padding-y: 0.65rem;
$input-padding-x: 0.75rem;
$input-font-family: $input-btn-font-family;
$input-font-size: $input-btn-font-size;
$input-font-weight: $font-weight-base;
$input-line-height: $input-btn-line-height;
$input-padding-y-sm: 0.375rem;
$input-padding-x-sm: 0.7rem;
$input-font-size-sm: $input-btn-font-size-sm;
$input-padding-y-lg: 0.775rem;
$input-padding-x-lg: 0.85rem;
$input-font-size-lg: $input-btn-font-size-lg;
$input-bg: $white;
$input-disabled-bg: $gray-200;
$input-disabled-border-color: null;
$input-color: $body-color;
$input-border-color: $gray-400;
$input-border-width: 1px;
$input-box-shadow: inset 0 1px 1px rgba($black, 0.075);
$input-border-radius: 4px;
$input-border-radius-sm: 2px;
$input-border-radius-lg: 6px;
$input-focus-bg: $input-bg;
$input-focus-border-color: $primary;
$input-focus-color: $input-color;
$input-focus-width: $input-btn-focus-width;
$input-focus-box-shadow: 0 0 0 2px rgba($component-active-bg, 0.2);
$input-placeholder-color: $gray-600;
$input-plaintext-color: $headings-color;
$input-height-border: $input-border-width * 2;
$input-height-inner: add($input-line-height * 1em, calc($input-padding-y * 2));
$input-height-inner-half: add($input-line-height * 0.5em, $input-padding-y);
$input-height-inner-quarter: add($input-line-height * 0.25em, calc($input-padding-y / 2));
$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false));
$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false));
$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false));
$input-transition:
border-color 0.15s ease-in-out,
box-shadow 0.15s ease-in-out;
$form-color-width: 3rem;
// scss-docs-end form-input-variables
// scss-docs-end form-validation-states
// Z-index master list
$zindex-dropdown: 1026;
$zindex-sticky: 1020;
$zindex-fixed: 1030;
// Navs
$nav-link-padding-y: 0.5rem;
$nav-link-padding-x: 1rem;
$nav-link-font-size: null;
$nav-link-font-weight: null;
$nav-link-color: null;
$nav-link-hover-color: null;
$nav-link-transition:
color 0.15s ease-in-out,
background-color 0.15s ease-in-out,
border-color 0.15s ease-in-out;
$nav-link-disabled-color: $gray-600;
$nav-tabs-border-color: $gray-300;
$nav-tabs-border-width: $border-width;
$nav-tabs-border-radius: $border-radius;
$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color;
$nav-tabs-link-active-color: $gray-700;
$nav-tabs-link-active-bg: $white; // change
$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg;
$nav-pills-border-radius: $border-radius;
$nav-pills-link-active-color: $component-active-color;
$nav-pills-link-active-bg: $component-active-bg;
// Navbar
$navbar-padding-y: calc(#{$spacer} / 2);
$navbar-padding-x: null;
$navbar-nav-link-padding-x: 0.5rem;
$navbar-brand-font-size: $font-size-lg;
// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link
$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2;
$navbar-brand-height: $navbar-brand-font-size * $line-height-base;
$navbar-brand-padding-y: calc(($nav-link-height - $navbar-brand-height) / 2);
$navbar-brand-margin-end: 1rem;
$navbar-toggler-padding-y: 0.25rem;
$navbar-toggler-padding-x: 0.75rem;
$navbar-toggler-font-size: $font-size-lg;
$navbar-toggler-border-radius: $btn-border-radius;
$navbar-toggler-focus-width: $btn-focus-width;
$navbar-toggler-transition: box-shadow 0.15s ease-in-out;
$navbar-dark-color: rgba($white, 0.9);
$navbar-dark-hover-color: rgba($white, 0.75);
$navbar-dark-active-color: $white;
$navbar-dark-disabled-color: rgba($white, 0.25);
$navbar-dark-toggler-border-color: rgba($white, 0.1);
$navbar-light-color: rgba($black, 0.55);
$navbar-light-hover-color: rgba($black, 0.7);
$navbar-light-active-color: rgba($black, 0.9);
$navbar-light-disabled-color: rgba($black, 0.3);
$navbar-light-toggler-border-color: rgba($black, 0.1);
$navbar-light-brand-color: $navbar-light-active-color;
$navbar-light-brand-hover-color: $navbar-light-active-color;
$navbar-dark-brand-color: $navbar-dark-active-color;
$navbar-dark-brand-hover-color: $navbar-dark-active-color;
// Dropdowns
$dropdown-font-size: $font-size-base;
$dropdown-color: $body-color;
$dropdown-bg: $white;
// scss-docs-start placeholders
$placeholder-opacity-max: 0.5;
$placeholder-opacity-min: 0.2;
// scss-docs-end placeholders
// Cards
$card-spacer-y: 25px; // change
$card-spacer-x: 25px; // change
$card-title-spacer-y: calc($spacer / 2);
$card-border-width: 1px; // change
$card-border-radius: $border-radius;
$card-border-color: $border-color;
$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width});
$card-cap-padding-y: 25px;
$card-cap-padding-x: 25px;
$card-cap-bg: transparent;
$card-cap-color: null;
$card-height: null;
$card-color: null;
$card-bg: $white;
$card-img-overlay-padding: 1.25rem;
$card-group-margin: calc($grid-gutter-width / 2);
// Badges
$badge-font-size: 0.75em;
$badge-font-weight: 500;
$badge-color: $white;
$badge-padding-y: 0.35em;
$badge-padding-x: 0.5em;
$badge-border-radius: 2px;
// List group
$list-group-color: null;
$list-group-bg: $white;
$list-group-border-color: $border-color;
$list-group-border-width: $border-width;
$list-group-border-radius: $border-radius;
$list-group-item-padding-y: calc($card-spacer-y / 1.5);
$list-group-item-padding-x: $card-spacer-x;
$list-group-item-bg-scale: -80%;
$list-group-item-color-scale: 40%;
$list-group-hover-bg: $gray-100;
$list-group-active-color: $component-active-color;
$list-group-active-bg: $component-active-bg;
$list-group-active-border-color: $list-group-active-bg;
$list-group-disabled-color: $gray-600;
$list-group-disabled-bg: $list-group-bg;
$list-group-action-color: $gray-700;
$list-group-action-hover-color: $list-group-action-color;
$list-group-action-active-color: $body-color;
$list-group-action-active-bg: $gray-200;
// Figures
$figure-caption-font-size: 90%;
$figure-caption-color: $gray-600;
// Breadcrumbs
$breadcrumb-font-size: null;
$breadcrumb-padding-y: 2;
$breadcrumb-padding-x: 0;
$breadcrumb-item-padding: 0.5rem;
$breadcrumb-margin-bottom: 1rem;
$breadcrumb-bg: null;
$breadcrumb-divider-color: $gray-600;
$breadcrumb-active-color: $gray-600;
$breadcrumb-divider: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='14' height='14' stroke='#{$gray-600}' stroke-width='2' fill='none' stroke-linecap='round' stroke-linejoin='round' class='css-i6dzq1'%3E%3Cpolyline points='9 18 15 12 9 6'%3E%3C/polyline%3E%3C/svg%3E");
$breadcrumb-divider-flipped: $breadcrumb-divider;
$breadcrumb-border-radius: null;
// Close
$btn-close-width: 1em;
$btn-close-height: $btn-close-width;
$btn-close-padding-x: 0.25em;
$btn-close-padding-y: $btn-close-padding-x;
$btn-close-color: $black;
$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' fill='#{$btn-close-color}' viewBox='0 0 16 16'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>");
$btn-close-focus-shadow: $input-btn-focus-box-shadow;
$btn-close-opacity: 0.5;
$btn-close-hover-opacity: 0.75;
$btn-close-focus-opacity: 1;
$btn-close-disabled-opacity: 0.25;
$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%);
// Code
$code-font-size: 87.5%;
$code-color: $pink;
$kbd-padding-y: 0.2rem;
$kbd-padding-x: 0.4rem;
$kbd-font-size: $code-font-size;
$kbd-color: $white;
$kbd-bg: $body-color;
$pre-color: null;
// scss-docs-start theme-colors-rgb
$theme-colors-rgb: map-loop($theme-colors, to-rgb, '$value');
@@ -1,44 +0,0 @@
// =======================================
// List of variables for Preset color
// =======================================
// Gray color
$white: #ffffff;
$gray-100: #fafafa;
$gray-200: #f5f5f5;
$gray-300: #f0f0f0;
$gray-400: #d9d9d9;
$gray-500: #bfbfbf;
$gray-600: #8c8c8c;
$gray-700: #595959;
$gray-800: #262626;
$gray-900: #141414;
$black: #000000;
$blue: #1677ff;
$indigo: #6610f2;
$purple: #6f42c1;
$pink: #e83e8c;
$red: #ff4d4f;
$orange: #fd7e14;
$yellow: #faad14;
$green: #52c41a;
$teal: #20c997;
$cyan: #13c2c2;
$blue-100: tint-color($blue, 80%);
$blue-200: tint-color($blue, 60%);
$blue-300: tint-color($blue, 40%);
$blue-400: tint-color($blue, 20%);
$blue-500: $blue;
$blue-600: shade-color($blue, 20%);
$blue-700: shade-color($blue, 40%);
$blue-800: shade-color($blue, 60%);
$blue-900: shade-color($blue, 80%);
$preset-colors: (
preset-1: (
primary: #1890ff
)
);
$dark-bg-color: #1a1a1a;
@@ -1,111 +0,0 @@
// =======================================
// List of variables for layout
// =======================================
:root {
// body
--#{$variable-prefix}body-bg: #{$body-bg};
--bs-body-bg-rgb: #{to-rgb($body-bg)};
--pc-heading-color: #{$gray-800};
--pc-active-background: #{$gray-200};
// Navbar
--pc-sidebar-background: #{$white};
--pc-sidebar-color: #262626;
--pc-sidebar-color-rgb: #{to-rgb(#262626)};
--pc-sidebar-active-color: var(--bs-primary);
--pc-sidebar-shadow: none;
--pc-sidebar-caption-color: #{$gray-700};
// header
--pc-header-background: #{$white};
--pc-header-color: #262626;
--pc-header-shadow: 0 1px 0 0px rgb(240 240 240);
// card
--pc-card-box-shadow: none;
// horizontal menu
--pc-header-submenu-background: #{$white};
--pc-header-submenu-color: #{$gray-600};
}
$header-height: 60px;
$sidebar-width: 260px;
$sidebar-collapsed-width: 60px;
$sidebar-collapsed-active-width: 300px;
$sidebar-tab-width: 75px;
$sidebar-tab-navbar-width: 320px;
// horizontal menu
$topbar-height: 60px;
$soft-bg-level: -90%;
// =====================================
// Variables for dark layouts
// =====================================
$dark-layout-color: #121212;
$dark-layout-color-light: #1e1e1e;
// header
$dark-header-color: #d6d6d6;
$dark-header-shadow: 0 1px 20px 0 rgba(69, 90, 100, 0.08);
// Menu
$dark-sidebar-color: #bfbfbf;
$dark-sidebar-caption: #d6d6d6;
$dark-sidebar-shadow: 0 1px 20px 0 rgba(69, 90, 100, 0.08);
// card block
$dark-card-shadow: inset 0 0 0 1px #262626;
// =====================================
// Variables for bootstrap color
// =====================================
$blue: $blue-500;
$secondary: $gray-600;
$indigo: $indigo-500;
$purple: $purple-500;
$pink: $pink-500;
$red: $red-500;
$orange: $orange-500;
$yellow: $yellow-500;
$green: $green-500;
$teal: $teal-500;
$cyan: $cyan-500;
$dark: #262626;
$primary-text: $blue-600;
$secondary-text: $gray-600;
$success-text: $green-600;
$info-text: $cyan-700;
$warning-text: $yellow-700;
$danger-text: $red-600;
$light-text: $gray-600;
$dark-text: $gray-700;
$primary-bg-subtle: $blue-100;
$secondary-bg-subtle: $gray-100;
$success-bg-subtle: $green-100;
$info-bg-subtle: $cyan-100;
$warning-bg-subtle: $yellow-100;
$danger-bg-subtle: $red-100;
$light-bg-subtle: mix($gray-100, $white);
$dark-bg-subtle: $gray-400;
$primary-border-subtle: $blue-200;
$secondary-border-subtle: $gray-200;
$success-border-subtle: $green-200;
$info-border-subtle: $cyan-200;
$warning-border-subtle: $yellow-200;
$danger-border-subtle: $red-200;
$light-border-subtle: $gray-200;
$dark-border-subtle: $gray-500;
$preset-colors: (
preset-1: (
primary: #1677ff
)
);
@@ -1,18 +0,0 @@
.avatar {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: $border-radius;
font: {
size: 18px;
weight: 600;
}
width: 48px;
height: 48px;
&.avatar-s {
width: 40px;
height: 40px;
font-size: 14px;
}
}
@@ -1,13 +0,0 @@
// ============================
// Badge css start
// ============================
.badge {
@each $color, $value in $theme-colors {
&.bg-light-#{$color} {
background: shift-color($value, $soft-bg-level);
color: $value;
border-color: shift-color($value, $soft-bg-level);
}
}
}
@@ -1,125 +0,0 @@
// ============================
// Button css start
// ============================
.btn {
font-size: 14px;
i {
font-size: 18px;
}
svg {
width: 18px;
height: 18px;
}
&[class*='btn-link-'],
&[class*='btn-light-'] {
box-shadow: none;
}
&[class*='btn-outline-']:not(:hover) {
box-shadow: none;
}
&.btn-shadow {
box-shadow: 0 6px 7px -1px rgba(80, 86, 175, 0.3);
}
&.btn-sm {
i {
font-size: 14px;
}
}
}
@each $color, $value in $theme-colors {
.btn-light-#{$color} {
background: shift-color($value, $soft-bg-level);
color: $value;
border-color: shift-color($value, $soft-bg-level);
.material-icons-two-tone {
background-color: $value;
}
&:hover {
background: $value;
color: #fff;
border-color: $value;
.material-icons-two-tone {
background-color: #fff;
}
}
&.focus,
&:focus {
background: $value;
color: #fff;
border-color: $value;
.material-icons-two-tone {
background-color: #fff;
}
}
&:not(:disabled):not(.disabled).active,
&:not(:disabled):not(.disabled):active,
.show > &.dropdown-toggle {
background: $value;
color: #fff;
border-color: $value;
.material-icons-two-tone {
background-color: #fff;
}
}
}
.btn-check:active,
.btn-check:checked {
+ .btn-light-#{$color} {
background: $value;
color: #fff;
border-color: $value;
.material-icons-two-tone {
background-color: #fff;
}
}
}
.btn-link-#{$color} {
background: transparent;
color: $value;
border-color: transparent;
.material-icons-two-tone {
background-color: $value;
}
&:hover {
background: shift-color($value, $soft-bg-level);
color: $value;
border-color: shift-color($value, $soft-bg-level);
}
&.focus,
&:focus {
background: shift-color($value, $soft-bg-level);
color: $value;
border-color: shift-color($value, $soft-bg-level);
}
&:not(:disabled):not(.disabled).active,
&:not(:disabled):not(.disabled):active,
.show > &.dropdown-toggle {
background: shift-color($value, $soft-bg-level);
color: $value;
border-color: shift-color($value, $soft-bg-level);
}
}
.btn-check:active,
.btn-check:checked {
+ .btn-link-#{$color} {
background: shift-color($value, $soft-bg-level);
color: $value;
border-color: shift-color($value, $soft-bg-level);
}
}
}
@@ -1,58 +0,0 @@
.card {
margin-bottom: 24px;
transition: box-shadow 0.2s ease-in-out;
.card-header {
border-bottom: 1px solid $border-color;
h5 {
margin-bottom: 0;
color: $headings-color;
font-size: 0.875rem;
font-weight: 600;
+ p,
+ small {
margin-top: 10px;
&:last-child {
margin-bottom: 0;
}
}
}
}
.card-footer {
transition: box-shadow 0.2s ease-in-out;
border-top: 1px solid $border-color;
}
&:hover {
.card-footer[class*='bg-'] {
box-shadow: none;
}
}
.card-body {
&.pc-component {
position: relative;
padding: 25px;
border: 1px solid rgba(215, 223, 233, 0.5);
}
}
}
@include media-breakpoint-down(sm) {
.card {
margin-bottom: 20px;
.card-header {
padding: 20px;
h5 {
font-size: 0.875rem;
}
}
.card-body {
padding: 20px;
}
}
}
@@ -1,8 +0,0 @@
@import 'avatar';
@import 'button';
@import 'badge';
@import 'dropdown';
@import 'table';
@import 'tabs';
@import 'card';
@import 'form';
@@ -1,85 +0,0 @@
.dropdown-toggle {
&.arrow-none {
&:after {
display: none;
}
}
}
.pc-header {
.dropdown-menu {
animation: 0.3s ease-in-out 0s normal forwards 0.3s fadeIn;
}
}
@keyframes fadeIn {
from {
transform: translate3d(0, 8px, 0);
opacity: 0;
}
to {
transform: translate3d(0, 0, 0);
opacity: 1;
}
}
.dropdown .dropdown-item {
display: flex;
align-items: center;
&.active,
&:active,
&:focus,
&:hover {
background: var(--pc-active-background);
color: var(--bs-dropdown-link-color);
i {
&.material-icons-two-tone {
background-color: $dropdown-link-hover-color;
}
}
}
}
.dropdown-menu {
--bs-dropdown-zindex: 8;
box-shadow: 0 4px 24px 0 rgba(62, 57, 107, 0.18);
border: none;
.dropdown-item {
padding: 10px 25px;
i {
font-size: 18px;
margin-right: 10px;
&.material-icons-two-tone {
vertical-align: bottom;
font-size: 22px;
background-color: var(--pc-header-color);
}
}
svg {
width: 18px;
height: 18px;
margin-right: 10px;
}
.float-right {
svg {
width: 14px;
height: 14px;
}
}
}
}
.dropdown-menu-dark {
.dropdown-item {
&.active,
&:active {
color: var(--bs-dropdown-link-hover-color);
background-color: var(--bs-dropdown-link-hover-bg);
}
}
}
@@ -1,255 +0,0 @@
.form-group {
margin-bottom: 1rem;
label {
font-size: 14px;
font-weight: 500;
}
}
select.form-control,
.form-control {
&:hover {
background-color: $gray-100;
}
&[readonly] {
opacity: 0.6;
}
}
.input-group-text svg {
width: 18px;
height: 18px;
}
.form-control-color-picker {
height: 43px;
padding: 0.5rem;
}
select.form-control {
appearance: none;
background: #{$input-bg}
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='currentColor' stroke-width='2' fill='none' stroke-linecap='round' stroke-linejoin='round' class='css-i6dzq1'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E")
no-repeat right 0.75rem center/18px 25px;
&[data-multiselectsplitter-firstselect-selector],
&[data-multiselectsplitter-secondselect-selector] {
background: none;
}
}
.form-floating {
> label {
top: 1px;
}
> .form-control:focus,
> .form-control:not(:placeholder-shown),
> .form-select {
~ label {
color: $gray-600;
}
}
> .form-control:focus {
~ label {
color: $component-active-bg;
}
}
> input {
color: $body-color;
}
}
.user-card {
.form-search {
position: relative;
i {
position: absolute;
top: 12px;
left: 15px;
font-size: 14px;
}
.form-control {
padding-left: 42px;
background: transparent;
}
}
.btn {
i {
font-size: inherit;
}
span {
white-space: pre;
}
}
}
.form-check {
label {
cursor: pointer;
input {
cursor: pointer;
}
}
}
@each $color, $value in $theme-colors {
.form-check {
.form-check-input {
&.input-#{$color} {
&:checked {
border-color: $value;
background-color: $value;
}
}
&.input-light-#{$color} {
&:checked {
border-color: shift-color($value, $soft-bg-level);
background-color: shift-color($value, $soft-bg-level);
&[type='checkbox'] {
background-image: escape-svg(
url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$value}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/></svg>")
);
}
&[type='radio'] {
background-image: escape-svg(
url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#{$value}'/></svg>")
);
}
}
}
&.input-#{$color},
&.input-light-#{$color} {
&:focus {
&[type='checkbox'],
&[type='radio'] {
box-shadow: 0 0 0 0.2rem rgba($value, 0.25);
border-color: $value;
}
}
}
}
&.form-switch {
.form-check-input.input-light-#{$color} {
&:checked {
background-image: escape-svg(
url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$value}'/></svg>")
);
}
}
}
}
}
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child),
.input-group > .input-group-append:not(:last-child) > .btn,
.input-group > .input-group-append:not(:last-child) > .input-group-text,
.input-group > .input-group-prepend > .btn,
.input-group > .input-group-prepend > .input-group-text {
border-right: none;
}
// sticky header start
.sticky-action {
top: $header-height;
position: sticky;
z-index: 1020;
background: var(--bs-card-bg);
border-radius: var(--bs-card-border-radius);
}
// sticky header end
// switch v1 start
.switch-demo {
.custom-switch-v1 {
margin-bottom: 4px;
}
}
.custom-switch-v1 {
&.form-switch {
padding-left: 2.9em;
.form-check-input {
height: 20px;
width: 35px;
margin-left: -2.9em;
background-image: escape-svg(
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='4.1' fill='#{$form-switch-color}'/%3e%3c/svg%3e")
);
transition: 0.35s cubic-bezier(0.54, 1.6, 0.5, 1);
//box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
&[class*='input-light-'] {
border: none;
}
&:focus {
box-shadow: none;
border-color: rgba(0, 0, 0, 0.25);
}
&:checked {
background-image: escape-svg(
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='4.1' fill='%23ffffff'/%3e%3c/svg%3e")
);
}
}
@each $color, $value in $theme-colors {
.form-check-input.input-light-#{$color} {
&:checked {
background-image: escape-svg(
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='4.1' fill='#{$value}'/%3e%3c/svg%3e")
);
}
}
}
}
// ===========
.custom-control-label {
&::before {
transition: 0.2s cubic-bezier(0.24, 0, 0.5, 1);
height: 20px;
width: 35px;
border-radius: 0.8rem;
top: 0;
left: -2.55rem;
}
&::after {
top: calc(0.15625rem - 2px);
left: calc(-2.25rem - 4px);
height: 19px;
width: 19px;
border-radius: 0.7rem;
box-shadow:
0 0 0 1px rgba(0, 0, 0, 0.1),
0 4px 0 0 rgba(0, 0, 0, 0.04),
0 4px 9px rgba(0, 0, 0, 0.13),
0 3px 3px rgba(0, 0, 0, 0.05);
transition: 0.35s cubic-bezier(0.54, 1.6, 0.5, 1);
}
}
.custom-control-input {
&:checked ~ .custom-control-label::after {
transform: translateX(0.95rem);
}
}
// ===========
}
// switch v1 end
@@ -1,39 +0,0 @@
.table {
&.table-align-center {
td,
th {
vertical-align: middle;
}
}
thead th {
padding: 0.9rem 0.75rem;
}
td,
th {
vertical-align: middle;
&:first-child {
padding-left: 24px;
}
&:last-child {
padding-right: 24px;
}
}
&.table-borderless {
td,
th {
border: none !important;
}
}
thead th {
background-color: $gray-100;
border-top: 1px solid $gray-300;
border-bottom: 2px solid $gray-300;
font-size: 12px;
}
}
.table-hover tbody tr:hover {
// background-color: transparentize($primary, 0.97);
background-color: $gray-200;
}
@@ -1,57 +0,0 @@
.tabs-border {
&.nav-tabs {
.nav-item {
margin-bottom: 0;
}
.nav-link {
border: none;
background:
no-repeat center bottom,
center 100%;
background-size:
0 100%,
100% 100%;
transition: background 0.3s ease-out;
background-image: linear-gradient(to top, theme-color('primary') 2px, rgba(255, 255, 255, 0) 2px);
&.active {
background-size:
100% 100%,
100% 100%;
}
}
}
}
.tabs-light {
&.nav-pill {
+ .tab-content {
border-top: 1px solid $border-color;
}
.nav-item {
margin-bottom: 0;
.nav-link {
color: $primary;
background: shift-color($primary, $soft-bg-level);
border-radius: 4px;
transition: background 0.3s ease-out;
}
+ .nav-item {
margin-left: 10px;
}
}
.nav-link {
border: none;
&.active {
color: $white;
background: $primary;
}
}
}
}
-233
View File
@@ -1,233 +0,0 @@
/** =====================
2. Custom css start
========================== **/
* {
&:focus {
outline: none;
}
}
.accordion {
--#{$prefix}accordion-color: #{$body-color};
}
a {
color: $black;
&:hover {
outline: none;
text-decoration: none;
}
&:not([href]) {
color: inherit;
}
}
p {
font-size: 14px;
}
h6,
.h6,
h5,
.h5,
h4,
.h4,
h3,
.h3,
h2,
.h2,
h1,
.h1 {
color: var(--pc-heading-color);
}
b,
strong {
font-weight: 600;
}
.breadcrumb-default-icon {
.breadcrumb-item + .breadcrumb-item::before {
position: relative;
top: 2px;
}
}
.btn-page {
.btn {
margin-right: 5px;
margin-bottom: 5px;
}
.btn-group {
.btn {
margin-right: 0;
margin-bottom: 0;
&:last-child {
border-left: none;
}
}
label {
&:first-of-type {
border-right: none;
}
}
}
}
.material-icons-two-tone {
background-color: $body-color;
-webkit-text-fill-color: transparent;
vertical-align: text-bottom;
-webkit-background-clip: text;
&.text-white {
background-color: $white;
}
}
.img-radius {
border-radius: 50%;
}
.pc-icon {
&:not([class*='wid-']) {
width: 22px;
}
&:not([class*='hei-']) {
height: 22px;
}
}
/* ========================================================
=============== document ======================
========================================================
Grid examples
*/
// modal box select
.ng-dropdown-panel.ng-select-bottom {
z-index: 1099;
}
/* ================================ Blockquote Start ===================== */
@media (min-width: 1600px) {
.container {
max-width: 1540px;
}
}
.media {
display: flex;
.media-body {
flex-grow: 1;
}
}
.blockquote {
padding: 0.5rem 1rem;
}
/* ================================ Blockquote End ===================== */
.color-card {
.card-body {
margin: var(--bs-card-spacer-y) var(--bs-card-spacer-x);
background: rgba(107, 117, 125, 0.08);
border-radius: $border-radius;
}
}
.color-block {
border-radius: $border-radius;
margin: 4px 0;
@each $name, $value in $more-colors {
$i: 100;
@while $i<=900 {
&.bg-#{$name}-#{$i} {
color: color-contrast(map-get($value, $i));
}
&.text-#{$name}-#{$i} {
background-color: color-contrast(map-get($value, $i));
}
$i: $i + 100;
}
}
}
.row {
> div {
.color-block {
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
}
}
.pagination {
.page-item {
.page-link {
border-radius: 0;
}
&:first-child {
.page-link {
border-radius: var(--bs-pagination-border-radius) 0 0 var(--bs-pagination-border-radius);
}
}
&:last-child {
.page-link {
border-radius: 0 var(--bs-pagination-border-radius) var(--bs-pagination-border-radius) 0;
}
}
}
}
.form-search {
position: relative;
i {
position: absolute;
top: 12px;
left: 15px;
font-size: 20px;
}
.form-control {
padding-left: 50px;
}
&.product-search {
i {
font-size: 13px;
color: rgba(0, 0, 0, 0.54);
top: 12px;
}
.form-control {
padding-left: 35px;
}
}
}
// offcanvas page css
.customer-body {
height: calc(100% - 60px);
}
.offcanvas-top,
.offcanvas-bottom {
min-height: 240px;
}
-184
View File
@@ -1,184 +0,0 @@
/** =====================
Generic-class css start
========================== **/
/*====== Padding , Margin css starts ======*/
$i: 0;
@while $i<=50 {
.p {
&-#{$i} {
padding: #{$i}px;
}
&-t-#{$i} {
padding-top: #{$i}px;
}
&-b-#{$i} {
padding-bottom: #{$i}px;
}
&-l-#{$i} {
padding-left: #{$i}px;
}
&-r-#{$i} {
padding-right: #{$i}px;
}
}
.m {
&-#{$i} {
margin: #{$i}px;
}
&-t-#{$i} {
margin-top: #{$i}px;
}
&-b-#{$i} {
margin-bottom: #{$i}px;
}
&-l-#{$i} {
margin-left: #{$i}px;
}
&-r-#{$i} {
margin-right: #{$i}px;
}
}
$i: $i + 5;
}
/*====== Padding , Margin css ends ======*/
/*====== Font-size css starts ======*/
$i: 6;
@while $i<=80 {
.f-#{$i} {
font-size: #{$i}px;
}
$i: $i + 2;
}
/*====== Font-size css ends ======*/
/*====== Font-weight css starts ======*/
$i: 100;
@while $i<=900 {
.f-w-#{$i} {
font-weight: #{$i};
}
$i: $i + 100;
}
/*====== Font-weight css ends ======*/
/*====== width, Height css starts ======*/
$i: 10;
@while $i<=150 {
.wid-#{$i} {
width: #{$i}px;
}
.hei-#{$i} {
height: #{$i}px;
}
$i: $i + 5;
}
/*====== width, Height css ends ======*/
/*====== border-width css starts ======*/
$i: 1;
@while $i<=8 {
.b-wid-#{$i} {
border-width: #{$i}px;
}
$i: $i + 1;
}
/*====== border-width css ends ======*/
/*====== background starts ======*/
.text-header {
color: var(--bs-heading-color);
}
.bg-body {
background: var(--bs-body-bg);
}
@each $color, $value in $theme-colors {
.bg-light-#{$color} {
background: shift-color($value, $soft-bg-level);
color: $value;
}
.icon-svg-#{$color} {
fill: shift-color($value, $soft-bg-level);
stroke: $value;
}
.material-icons-two-tone {
&.text-#{$color} {
background-color: $value;
}
}
.text-hover-#{$color}:hover {
color: $value !important;
}
}
/*====== background ends ======*/
/*====== border color css starts ======*/
@each $color, $value in $theme-colors {
.b-#{$color} {
border: 1px solid $value;
}
.border-bottom-#{$color} td {
border-bottom: 1px solid $value;
}
.border-bottom-#{$color} th {
border-bottom: 1px solid $value !important;
}
.fill-#{$color} {
fill: $value;
}
}
/*====== border color css ends ======*/
/*====== text-color, background color css starts ======*/
.text-sm {
font-size: 0.75rem !important;
}
/*====== more bootstrap colors start ======*/
$more-colors: (
'blue': (
100: $blue-100,
200: $blue-200,
300: $blue-300,
400: $blue-400,
500: $blue-500,
600: $blue-600,
700: $blue-700,
800: $blue-800,
900: $blue-900
),
'gray': (
100: $gray-100,
200: $gray-200,
300: $gray-300,
400: $gray-400,
500: $gray-500,
600: $gray-600,
700: $gray-700,
800: $gray-800,
900: $gray-900
)
);
@each $name, $value in $more-colors {
$i: 100;
@while $i<=900 {
.bg-#{$name}-#{$i} {
background: map-get($value, $i);
}
.text-#{$name}-#{$i} {
color: map-get($value, $i);
}
$i: $i + 100;
}
}
/*====== more bootstrap colors end ======*/
@@ -1,65 +0,0 @@
.page-header {
display: flex;
align-items: center;
top: $header-height;
left: $sidebar-width;
right: 0;
z-index: 1023;
min-height: 55px;
padding: 0px 0px 13px 0px;
background: transparent;
border-radius: $border-radius;
.page-block {
width: 100%;
}
.page-header-title {
display: inline-block;
}
h5 {
margin-bottom: 0;
margin-right: 8px;
padding-right: 8px;
font-weight: 500;
}
.breadcrumb {
padding: 0;
display: inline-flex;
margin-bottom: 0;
background: transparent;
font-size: 13px;
a {
color: var(--pc-sidebar-color);
}
.breadcrumb-item {
.home {
color: $gray-600;
font-size: 14px;
}
a:hover {
color: $primary;
}
+ .breadcrumb-item::before {
position: relative;
top: 2px;
}
&:last-child {
opacity: 0.75;
}
}
svg {
width: 14px;
height: 14px;
vertical-align: baseline;
}
}
}
@@ -1,23 +0,0 @@
.pc-footer {
position: relative;
z-index: 995;
margin-left: $sidebar-width;
margin-top: $header-height;
padding: 15px 0;
background: rgb(250, 250, 251);
padding: 12px 48px;
.footer-wrapper {
padding-left: 20px;
padding-right: 20px;
}
.footer-link {
.list-inline-item:not(:last-child) {
margin-right: 0.9rem;
}
}
@media (max-width: 1024px) {
margin-left: 0;
}
}
@@ -1,338 +0,0 @@
.pc-sidebar {
background: var(--pc-sidebar-background);
width: $sidebar-width;
position: fixed;
top: 0;
bottom: 0;
overflow: hidden;
z-index: 1026;
box-shadow: var(--pc-sidebar-shadow);
display: block;
height: 100vh;
color: var(--pc-sidebar-color);
border-right: 1px solid rgb(240, 240, 240);
a {
color: #262626;
cursor: pointer;
}
.navbar-wrapper {
width: 100%;
height: 100%;
}
ul {
list-style: none;
padding-left: 0;
margin-bottom: 0;
}
.m-header {
height: $header-height;
display: flex;
align-items: center;
padding: 16px 24px;
position: relative;
.logo-sm {
display: none;
}
}
.nav-card {
background: $gray-100;
}
.user-profile-section {
padding: 10px 24px;
border-top: 2px solid rgb(240, 240, 240);
.dropdown-toggle::after {
display: none;
}
.user-images {
position: relative;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
border-radius: 50%;
overflow: hidden;
width: 46px;
height: 46px;
img {
width: 100%;
height: 100%;
text-align: center;
object-fit: cover;
color: transparent;
text-indent: 10000px;
}
}
}
&.navbar-collapsed {
width: 0px;
height: 100%;
transition: all 0.3s ease-in-out;
~ app-nav-bar .pc-header {
left: 0px;
}
~ .pc-footer {
margin-left: 20px;
}
~ .pc-container {
margin-left: 0px;
}
.navbar-wrapper {
.m-header {
left: -260px;
}
}
}
.navbar-content {
// position: relative;
// height: calc(100vh - 60px);
padding: 16px 0;
.coded-inner-navbar {
flex-direction: column;
app-nav-item > li.active:after {
top: 0 !important;
height: 100% !important;
}
li {
&.coded-hasmenu {
position: relative;
padding-bottom: 2px;
> a {
&:after {
content: '\e844';
font-family: 'feather';
font-size: 15px;
border: none;
position: absolute;
top: 11px;
right: 20px;
transition: 0.3s ease-in-out;
}
}
.coded-submenu {
opacity: 0;
visibility: hidden;
transform-origin: 50% 50%;
transition:
transform 0.3s,
opacity 0.3s;
transform-style: preserve-3d;
transform: rotateX(-90deg);
position: absolute;
display: block;
> app-nav-item li {
> a {
text-align: left;
padding: 12px 30px 12px 55px;
margin: 0;
display: block;
&:before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 2px;
height: 100%;
}
}
}
> app-nav-collapse li {
> a {
text-align: left;
padding: 12px 30px 12px 55px;
margin: 0;
display: block;
}
.coded-submenu > {
app-nav-item li {
> a {
padding: 12px 30px 12px 75px;
}
}
}
}
}
&.coded-trigger {
> a {
&:after {
transform: rotate(90deg);
}
}
> .coded-submenu {
position: relative;
opacity: 1;
visibility: visible;
transform: rotateX(0deg);
}
}
}
&.coded-menu-caption {
font-size: 0.75rem;
font-weight: 500;
padding: 12px 24px 12px;
text-transform: capitalize;
position: relative;
color: $gray-600;
&.first-group {
padding: 0px 24px 12px;
}
}
> a {
padding: 12px 16px 12px 28px;
display: flex;
align-items: center;
border-radius: 5px;
position: relative;
.coded-mtext {
position: relative;
}
> .coded-micon {
font-size: 16px;
margin-right: 8px;
height: 16px;
display: inline-block;
text-align: center;
i {
display: flex;
}
+ .coded-mtext {
position: relative;
vertical-align: middle;
text-align: center;
}
}
}
}
app-nav-item {
li {
> a {
> .coded-micon {
margin-right: 12px;
}
}
}
}
> app-nav-group > app-nav-item {
li {
position: relative;
&:before {
content: '';
position: absolute;
top: 0;
right: 0;
width: 2px;
height: 100%;
}
}
}
}
}
.version {
display: flex;
flex-direction: row;
justify-content: center;
margin-bottom: 16px;
cursor: pointer;
label {
overflow: hidden;
text-overflow: ellipsis;
padding-left: 8px;
padding-right: 8px;
white-space: nowrap;
background-color: rgb(250, 250, 250);
color: rgb(158, 158, 158);
border-radius: 16px;
}
}
}
@media (min-width: 1025px) {
.pc-sidebar {
transition: width 0.15s ease;
~ .pc-header {
transition: left 0.15s ease;
}
~ .pc-footer,
~ .pc-container {
transition: margin-left 0.15s ease;
}
&.pc-sidebar-hide {
width: 0;
~ .pc-header {
left: 0;
}
~ .pc-footer,
~ .pc-container {
margin-left: 0px;
}
}
}
}
@media (max-width: 1024px) {
.pc-header .pc-h-item.pc-sidebar-collapse {
display: none;
}
.pc-sidebar {
left: -#{$sidebar-width};
box-shadow: none;
top: 0;
transition: all 0.15s ease-in-out;
&.mob-open {
left: 0;
.navbar-wrapper {
position: relative;
z-index: 5;
background: inherit;
}
~ .pc-container {
.pc-menu-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 1025;
}
}
}
}
}
@@ -1,465 +0,0 @@
.pc-header {
background: var(--pc-header-background);
color: var(--pc-header-color);
min-height: $header-height;
border-bottom: 1px solid rgb(240, 240, 240);
position: fixed;
left: $sidebar-width;
right: 0;
z-index: 1025;
display: flex;
ul {
margin-bottom: 0;
display: inline-flex;
}
.m-header {
height: $header-height;
display: flex;
align-items: center;
justify-content: space-between;
width: $sidebar-width;
padding: 16px 10px 16px 24px;
}
.header-wrapper {
display: flex;
padding: 0 25px 0px 12px;
flex-grow: 1;
justify-content: space-between;
@include media-breakpoint-down(sm) {
padding: 0 15px;
}
}
.header-search {
position: relative;
.form-control {
border-radius: $border-radius;
padding: 0.344rem 1.8rem;
width: 200px;
max-width: 100%;
font-size: 0.75rem;
@media (max-width: 1024px) {
width: 100%;
}
}
.search {
position: absolute;
top: 5px;
left: 11px;
width: 12px;
height: 12px;
}
.btn-search {
position: absolute;
top: 7px;
right: 9px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: $border-radius;
}
}
.pc-h-item {
min-height: $header-height;
display: flex;
align-items: center;
position: relative;
}
.pc-head-link {
margin: 0 8px;
position: relative;
font-weight: 500;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: $border-radius;
color: var(--pc-header-color);
overflow: hidden;
&.dropdown-toggle::after {
display: none;
}
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1;
background: var(--pc-active-background);
border-radius: 50%;
transform: scale(0);
transition: all 0.08s cubic-bezier(0.37, 0.24, 0.53, 0.99);
}
> img,
> span,
> svg,
> i {
position: relative;
z-index: 5;
transition: all 0.08s cubic-bezier(0.37, 0.24, 0.53, 0.99);
}
> i {
color: var(--pc-header-color);
font-size: 16px;
}
> svg {
width: 20px;
height: 20px;
}
&.active,
&:active,
&:focus,
&:hover {
text-decoration: none;
color: var(--pc-header-color);
> svg,
> i {
color: var(--pc-header-color);
}
&::before {
border-radius: 0;
transform: scale(1);
}
.hamburger {
.hamburger-inner {
background-color: $secondary;
&::after,
&::before {
background-color: $secondary;
}
}
}
i.material-icons-two-tone {
background-color: $secondary;
}
}
.pc-h-badge {
display: flex;
flex-flow: wrap;
place-content: center;
font-weight: 500;
font-size: 0.75rem;
line-height: 1;
transition: transform 225ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
transform-origin: 100% 0%;
min-width: 16px;
height: 16px;
padding: 4px;
position: absolute;
top: 2px;
right: 2px;
border-radius: 50%;
z-index: 9;
&.dots {
width: 9px;
height: 9px;
top: 7px;
right: 16px;
padding: 0;
}
}
.user-desc,
.user-name {
display: block;
line-height: 1;
}
.user-name {
margin-bottom: 5px;
font: {
size: 15px;
weight: 600;
}
}
.user-desc {
font: {
size: 12px;
weight: 400;
}
color: var(--pc-header-color);
}
.settings {
animation: anim-rotate 2s infinite linear;
}
}
.pc-h-dropdown {
transform: none !important;
top: 100% !important;
&.dropdown-menu-end {
right: 0 !important;
left: auto !important;
}
}
.drp-search {
min-width: 20rem;
}
.user-avatar {
width: 40px;
border-radius: 50%;
}
.header-user-profile {
.pc-head-link {
width: auto;
padding: 7px;
> span > i {
font-size: 22px;
margin-right: 8px;
}
.user-avatar {
width: 34px;
}
@include media-breakpoint-down(sm) {
width: 40px;
.user-avatar {
margin-right: 0;
}
> span,
> span > i {
display: none;
}
}
}
}
.dropdown-user-profile {
min-width: 290px;
max-width: 100%;
.drp-tabs {
border-bottom: 0;
display: flex;
margin-bottom: 10px;
.nav-item {
margin-bottom: -0px;
.nav-link {
position: relative;
padding: 0.7rem;
font-weight: 500;
color: $body-color;
display: flex;
align-items: center;
justify-content: center;
i {
font-size: 18px;
margin: 0 4px;
}
.material-icons-two-tone {
font-size: 20px;
}
&:after {
content: '';
background: $primary;
position: absolute;
transition: all 0.3s ease-in-out;
left: 50%;
right: 50%;
bottom: -1px;
height: 2px;
border-radius: 2px 2px 0 0;
}
}
}
.nav-link:hover {
border-color: transparent;
color: $primary;
.material-icons-two-tone {
background-color: $primary;
}
}
.nav-item.show .nav-link,
.nav-link.active {
border-color: transparent;
color: $primary;
.material-icons-two-tone {
background-color: $primary;
}
&:after {
left: 0;
right: 0;
}
}
}
.tab-content {
.dropdown-item {
i {
font-size: 14px;
}
svg {
margin-right: 0px;
width: 14px;
height: 14px;
}
}
}
}
.dropdown-notification {
min-width: 420px;
max-width: 100%;
.list-group-item-action {
&:active,
&:hover,
&:focus {
background: shift-color($primary, $soft-bg-level);
}
.user-avatar,
h5 {
cursor: pointer;
}
}
.badge {
font-size: 0.8125rem;
padding: 0.43em 1em;
}
.user-avatar {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
font-size: 20px;
}
.notification-file {
display: flex;
align-items: center;
i {
font-size: 20px;
margin-right: 16px;
}
}
@media (max-width: 575.98px) {
min-width: 100%;
}
}
}
@keyframes anim-rotate {
0% {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
@media (min-width: 1025px) {
.pc-header .pc-h-item.pc-sidebar-popup {
display: none;
}
}
@media (max-width: 1024px) {
.pc-header {
top: 0;
left: 0;
transition: all 0.15s ease-in-out;
.m-header {
display: none;
}
.pc-head-link {
.user-desc,
.user-name {
display: none;
}
}
.pc-mob-drp {
&.mob-drp-active {
.pc-h-item {
display: block;
min-height: auto;
position: relative;
.pc-head-link {
display: block;
margin: 5px 10px !important;
}
.dropdown-menu {
position: relative !important;
width: 100%;
float: none;
box-shadow: none;
}
}
ul {
display: block;
}
}
}
}
}
@include media-breakpoint-down(sm) {
.pc-header {
.pc-head-link {
padding: 0.65rem;
margin: 0 5px;
}
.pc-h-item {
position: static;
.pc-h-dropdown {
left: 0 !important;
right: 0 !important;
}
}
}
}
@@ -1,41 +0,0 @@
body {
background-color: $white;
}
.pc-container {
$temp: $header-height + 53;
position: relative;
top: $header-height;
margin-left: $sidebar-width;
min-height: calc(100vh - #{$temp});
background: rgba(250, 250, 251, 0.7);
.coded-content {
padding-left: 48px;
padding-right: 48px;
padding-top: 24px;
@include media-breakpoint-down(xl) {
&.container {
max-width: 100%;
}
}
@include media-breakpoint-down(md) {
padding-left: 32px;
padding-right: 32px;
padding-top: 16px;
}
}
.page-header + .row {
padding-top: 24px;
}
.page-header + .coded-content {
padding-top: calc(30px + 55px);
}
@media (max-width: 1024px) {
margin-left: 0px;
margin-right: 0px;
}
}
@@ -1,87 +0,0 @@
@import '../settings/color-variables.scss';
:root {
@each $name, $value in $preset-colors {
$pc-primary: map-get($value, 'primary');
$color-rgb: to-rgb($pc-primary);
--bs-blue: #{$pc-primary};
--bs-primary-rgb: #{$color-rgb};
}
}
.pc-sidebar {
.coded-inner-navbar {
> app-nav-group {
> app-nav-collapse {
.coded-hasmenu {
&.active,
&:focus,
&:hover {
> a {
background: rgba(var(--bs-primary-rgb), 0.1);
}
&.coded-trigger {
> a {
color: var(--bs-blue);
background: none;
}
.coded-submenu {
> app-nav-item {
li {
&.active,
&:focus,
&:hover {
> a {
background: rgba(var(--bs-primary-rgb), 0.1);
}
}
}
}
}
}
}
}
.coded-submenu > app-nav-item li {
&.active {
> a {
background: rgba(var(--bs-primary-rgb), 0.1);
color: var(--bs-blue);
&:before {
background: var(--bs-blue);
}
}
}
}
}
> app-nav-item {
li {
&.nav-item {
&.active,
&:focus,
&:hover {
background: rgba(var(--bs-primary-rgb), 0.1);
}
&.active {
> a {
color: var(--bs-blue);
.coded-micon {
color: var(--bs-blue);
}
}
&:before {
background: var(--bs-blue);
}
}
}
}
}
}
}
}
+40 -39
View File
@@ -1,42 +1,4 @@
/* You can add global styles to this file, and also import other style files */
/**======================================================================
=========================================================================
Template Name: MAntis Angular - Angular Admin Template
Author: codedThemes
Support: https://codedthemes.support-hub.io/
File: style.css
=========================================================================
=================================================================================== */
// main framework
@import '../node_modules/bootstrap/scss/functions';
@import '../node_modules/bootstrap/scss/variables';
@import '../node_modules/bootstrap/scss/variables-dark';
@import 'scss/settings/color-variables';
@import 'scss/settings/theme-variables';
@import 'scss/settings/bootstrap-variables';
// bootstrap import
@import 'scss/bootstrap/bootstrap.scss';
@import '../node_modules/bootstrap/scss/utilities';
@import '../node_modules/bootstrap/scss/utilities/api';
// main framework
@import 'scss/themes/generic.scss';
@import 'scss/themes/general.scss';
@import 'scss/themes/components/components.scss';
// theme
@import 'scss/themes/layouts/menu/sidebar.scss';
@import 'scss/themes/layouts/navbar/navbar.scss';
@import 'scss/themes/layouts/pc-common.scss';
@import 'scss/themes/layouts/breadcrumb/breadcrumb.scss';
@import 'scss/themes/layouts/footer/footer.scss';
@import 'scss/themes/preset-style.scss';
@use '@angular/material' as mat;
//markdown styles
@import 'bootstrap/dist/css/bootstrap.min.css';
@@ -64,4 +26,43 @@ body {
scroll-padding-inline: 40%;
}
//---------------
.pc-sidebar{
top: 65px;
overflow-y: auto;
background-color: rgba(153, 153, 153, 0.16);
backdrop-filter: blur(8px);
background: var(--pc-sidebar-background);
width: 260px;
position: fixed;
bottom: 0;
z-index: 1026;
box-shadow: var(--pc-sidebar-shadow);
display: block;
height: 100vh;
color: var(--pc-sidebar-color);
border-right: 1px solid rgb(240, 240, 240);
}
.pc-container{
top: 0;
padding-left: 5px;
padding-right: 5px;
position: relative;
margin-left: 260px;
min-height: calc(100vh - 113px);
background: #fafafbb3;
}
html {
color-scheme: light dark;
@include mat.theme((
color: mat.$azure-palette,
typography: Jersey 20 Charted,
density: 0
));
}