mirror of
https://github.com/Polaris-Entertainment/bytefy.git
synced 2026-07-08 16:45:09 +00:00
Add image service
This commit is contained in:
4
tools/src/app/app.component.html
Normal file
4
tools/src/app/app.component.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<app-header></app-header>
|
||||
<div class="main-content">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
9
tools/src/app/app.component.scss
Normal file
9
tools/src/app/app.component.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
// .main-content {
|
||||
// display: flex;
|
||||
// flex-direction: row;
|
||||
// }
|
||||
|
||||
// router-outlet {
|
||||
// flex: 1;
|
||||
// padding: 20px;
|
||||
// }
|
||||
29
tools/src/app/app.component.spec.ts
Normal file
29
tools/src/app/app.component.spec.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AppComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have the 'tools' title`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('tools');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, tools');
|
||||
});
|
||||
});
|
||||
20
tools/src/app/app.component.ts
Normal file
20
tools/src/app/app.component.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
import { PrimeNGConfig } from 'primeng/api';
|
||||
import { Lara } from 'primeng/themes/lara';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
imports: [RouterOutlet, HeaderComponent],
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'tools';
|
||||
|
||||
constructor(private config: PrimeNGConfig) {
|
||||
this.config.theme.set({ preset: Lara });
|
||||
}
|
||||
}
|
||||
18
tools/src/app/app.config.ts
Normal file
18
tools/src/app/app.config.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { ApplicationConfig } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||
import { provideNgIconsConfig } from '@ng-icons/core';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideRouter(routes),
|
||||
provideAnimationsAsync("animations"),
|
||||
provideNgIconsConfig({
|
||||
size: '1.5em',
|
||||
}),
|
||||
provideHttpClient()
|
||||
]
|
||||
};
|
||||
41
tools/src/app/app.routes.ts
Normal file
41
tools/src/app/app.routes.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { AsciiToTextComponent } from '../tools/ascii-to-text/ascii-to-text.component';
|
||||
import { GuidComponent } from '../tools/guid/guid.component';
|
||||
import { Base64ConverterComponent } from '../tools/base64-converter/base64-converter.component';
|
||||
import { JwtToJsonComponent } from '../tools/jwt-to-json/jwt-to-json.component';
|
||||
import { TextToCronComponent } from '../tools/text-to-cron/text-to-cron.component';
|
||||
import { DdsToPngComponent } from '../tools/dds-to-png/dds-to-png.component';
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: 'ascii-to-text',
|
||||
pathMatch: 'full',
|
||||
component: AsciiToTextComponent
|
||||
},
|
||||
{
|
||||
path: 'guid',
|
||||
pathMatch: 'full',
|
||||
component: GuidComponent
|
||||
},
|
||||
{
|
||||
path: 'base64-converter',
|
||||
pathMatch: 'full',
|
||||
component: Base64ConverterComponent
|
||||
},
|
||||
{
|
||||
path: 'jwt-decoder',
|
||||
pathMatch: 'full',
|
||||
component: JwtToJsonComponent
|
||||
},
|
||||
{
|
||||
path: 'text-to-cron',
|
||||
pathMatch: 'full',
|
||||
component: TextToCronComponent
|
||||
},
|
||||
{
|
||||
path: 'dds-to-png',
|
||||
pathMatch: 'full',
|
||||
component: DdsToPngComponent
|
||||
}
|
||||
];
|
||||
|
||||
1
tools/src/app/header/header.component.html
Normal file
1
tools/src/app/header/header.component.html
Normal file
@@ -0,0 +1 @@
|
||||
<p-megamenu [model]="items" />
|
||||
0
tools/src/app/header/header.component.scss
Normal file
0
tools/src/app/header/header.component.scss
Normal file
28
tools/src/app/header/header.component.spec.ts
Normal file
28
tools/src/app/header/header.component.spec.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/* tslint:disable:no-unused-variable */
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { DebugElement } from '@angular/core';
|
||||
|
||||
import { HeaderComponent } from './header.component';
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
let fixture: ComponentFixture<HeaderComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ HeaderComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
76
tools/src/app/header/header.component.ts
Normal file
76
tools/src/app/header/header.component.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MegaMenuItem } from 'primeng/api';
|
||||
import { MegaMenuModule } from 'primeng/megamenu';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AvatarModule } from 'primeng/avatar';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
standalone: true,
|
||||
imports: [MegaMenuModule, ButtonModule, CommonModule, AvatarModule]
|
||||
})
|
||||
export class HeaderComponent implements OnInit {
|
||||
items: MegaMenuItem[] | undefined;
|
||||
|
||||
ngOnInit() {
|
||||
this.items = [
|
||||
{
|
||||
label: 'Text Tools',
|
||||
icon: 'pi pi-box',
|
||||
items: [
|
||||
[
|
||||
{
|
||||
items: [
|
||||
{
|
||||
label: 'Ascii to text',
|
||||
routerLink: 'ascii-to-text',
|
||||
routerLinkActiveOptions: { exact: true }
|
||||
},
|
||||
{
|
||||
label: 'Guid Generator',
|
||||
routerLink: 'guid',
|
||||
routerLinkActiveOptions: { exact: true }
|
||||
},
|
||||
{
|
||||
label: 'Base64 Converter',
|
||||
routerLink: 'base64-converter',
|
||||
routerLinkActiveOptions: { exact: true }
|
||||
},
|
||||
{
|
||||
label: 'Jwt decoder',
|
||||
routerLink: 'jwt-decoder',
|
||||
routerLinkActiveOptions: { exact: true }
|
||||
},
|
||||
{
|
||||
label: 'Text to Cron Expression',
|
||||
routerLink: 'text-to-cron',
|
||||
routerLinkActiveOptions: { exact: true }
|
||||
}
|
||||
],
|
||||
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Conversion',
|
||||
icon: 'pi pi-box',
|
||||
items: [
|
||||
[
|
||||
{
|
||||
items: [
|
||||
{
|
||||
label: 'DDS to PNG',
|
||||
routerLink: 'dds-to-png',
|
||||
routerLinkActiveOptions: { exact: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="card flex justify-center">
|
||||
<p-panel [header]="title">
|
||||
<textarea
|
||||
(keyup)="onTopChange($event)"
|
||||
[disabled]="topDisabled"
|
||||
pTextarea
|
||||
[value]="topValue"
|
||||
[placeholder]="topPlaceholder">
|
||||
</textarea>
|
||||
<div>
|
||||
<i class="pi pi-arrow-right-arrow-left" style="font-size: 1rem"></i>
|
||||
</div>
|
||||
<textarea
|
||||
(keyup)="onBottomChange($event)"
|
||||
[disabled]="bottomDisabled"
|
||||
pTextarea
|
||||
[value]="bottomValue"
|
||||
[placeholder]="bottomPlaceholder">
|
||||
</textarea>
|
||||
</p-panel>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
:host {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
width: 98vw;
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 1140px;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 1140px;
|
||||
|
||||
.conversion {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 70vh;
|
||||
|
||||
p-floatlabel {
|
||||
width: 30vw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 175px;
|
||||
padding: 12px 20px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
resize: none;
|
||||
background-color: var(--primary-contrast);
|
||||
color: var(--text-color)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, Input, Output, EventEmitter, input } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { FloatLabelModule } from 'primeng/floatlabel';
|
||||
import { InputTextareaModule } from 'primeng/inputtextarea';
|
||||
import { PanelModule } from 'primeng/panel';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dual-textarea',
|
||||
templateUrl: 'dual-textarea.component.html',
|
||||
styleUrls: ['dual-textarea.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
FloatLabelModule,
|
||||
InputTextareaModule,
|
||||
FormsModule,
|
||||
PanelModule,
|
||||
CommonModule
|
||||
]
|
||||
|
||||
})
|
||||
export class DualTextareaComponent {
|
||||
@Input() topDisabled: boolean = false;
|
||||
@Input() bottomDisabled: boolean = false;
|
||||
@Input() title: string = 'Dual Textarea';
|
||||
@Input() topPlaceholder: string = 'Left Textarea';
|
||||
@Input() bottomPlaceholder: string = 'Right Textarea';
|
||||
@Input() topValue: string = '';
|
||||
@Input() bottomValue: string = '';
|
||||
@Output() topChange = new EventEmitter<string>();
|
||||
@Output() bottomChange = new EventEmitter<string>();
|
||||
|
||||
onTopChange(event: Event): void {
|
||||
const input = (event.target as HTMLTextAreaElement).value;
|
||||
this.topChange.emit(input);
|
||||
}
|
||||
|
||||
onBottomChange(event: Event): void {
|
||||
const input = (event.target as HTMLTextAreaElement).value;
|
||||
this.bottomChange.emit(input);
|
||||
}
|
||||
}
|
||||
29
tools/src/app/shared/upload/file-converter.component.html
Normal file
29
tools/src/app/shared/upload/file-converter.component.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<div class="card flex justify-center">
|
||||
<p-panel [header]="title">
|
||||
<p-fileUpload
|
||||
name="file"
|
||||
url="./upload"
|
||||
(onSelect)="onFileSelect($event)"
|
||||
[auto]="true"
|
||||
[accept]="accept"
|
||||
[previewWidth]="isPreview ? '50px' : '0px'"
|
||||
>
|
||||
</p-fileUpload>
|
||||
<p-table [value]="processedFiles" *ngIf="processedFiles.length != 0">
|
||||
<ng-template pTemplate="header">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Format</th>
|
||||
<th>Download</th>
|
||||
</tr>
|
||||
</ng-template>
|
||||
<ng-template pTemplate="body" let-file>
|
||||
<tr>
|
||||
<td>{{file.name}}</td>
|
||||
<td>{{file.format}}</td>
|
||||
<td><a [href]="file.link" download>{{file.name}}</a></td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
||||
</p-panel>
|
||||
</div>
|
||||
20
tools/src/app/shared/upload/file-converter.component.scss
Normal file
20
tools/src/app/shared/upload/file-converter.component.scss
Normal file
@@ -0,0 +1,20 @@
|
||||
:host {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
width: 98vw;
|
||||
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 1140px;
|
||||
}
|
||||
|
||||
.conversion {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
53
tools/src/app/shared/upload/file-converter.component.ts
Normal file
53
tools/src/app/shared/upload/file-converter.component.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { FileSelectEvent, FileUploadModule } from 'primeng/fileupload';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { PanelModule } from 'primeng/panel';
|
||||
import { TableModule } from 'primeng/table';
|
||||
|
||||
interface ProcessedFile {
|
||||
name: string;
|
||||
link: string;
|
||||
format: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-file-converter',
|
||||
templateUrl: 'file-converter.component.html',
|
||||
styleUrls: ['file-converter.component.scss'],
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
FileUploadModule,
|
||||
ButtonModule,
|
||||
PanelModule,
|
||||
TableModule
|
||||
]
|
||||
})
|
||||
export class FileConverterComponent {
|
||||
_fileFormats: string[] = [];
|
||||
accept: string = '';
|
||||
|
||||
@Output() fileSelected = new EventEmitter<File[]>();
|
||||
@Input() isPreview: boolean = true;
|
||||
@Input () title: string = 'File Converter';
|
||||
@Input() processedFiles: ProcessedFile[] = [];
|
||||
@Input()
|
||||
set fileFormats(formats: string[]) {
|
||||
this._fileFormats = formats;
|
||||
this.accept = formats.join(',');
|
||||
}
|
||||
|
||||
get fileFormats(): string[] {
|
||||
return this._fileFormats;
|
||||
}
|
||||
|
||||
selectedFile: File[] | null = null;
|
||||
|
||||
onFileSelect(event: FileSelectEvent): void {
|
||||
this.selectedFile = event.files;
|
||||
this.fileSelected.emit(this.selectedFile!);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user