diff --git a/angular.json b/angular.json
index 2afa324..3e24d02 100644
--- a/angular.json
+++ b/angular.json
@@ -7,7 +7,7 @@
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
- "style": "sass"
+ "style": "scss"
}
},
"root": "",
@@ -20,17 +20,18 @@
"outputPath": "dist/tools",
"index": "src/index.html",
"browser": "src/main.ts",
+ "aot": true,
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
- "inlineStyleLanguage": "sass",
+ "inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
- "src/styles.sass"
+ "src/styles.scss"
],
"scripts": []
},
@@ -84,13 +85,13 @@
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
- "inlineStyleLanguage": "sass",
+ "inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
- "src/styles.sass"
+ "src/styles.scss"
],
"scripts": []
}
diff --git a/package-lock.json b/package-lock.json
index 4e78418..146660b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@angular/animations": "^17.3.0",
+ "@angular/cdk": "^17.3.10",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/core": "^17.3.0",
@@ -16,7 +17,13 @@
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
+ "@ng-icons/core": "^29.5.1",
+ "@ng-icons/css.gg": "^29.5.1",
+ "@ng-icons/heroicons": "^29.5.1",
+ "primeicons": "^7.0.0",
+ "primeng": "^18.0.0-beta.2",
"rxjs": "~7.8.0",
+ "tailwindcss-primeui": "^0.3.4",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
},
@@ -275,6 +282,22 @@
"@angular/core": "17.3.12"
}
},
+ "node_modules/@angular/cdk": {
+ "version": "17.3.10",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.3.10.tgz",
+ "integrity": "sha512-b1qktT2c1TTTe5nTji/kFAVW92fULK0YhYAvJ+BjZTPKu2FniZNe8o4qqQ0pUuvtMu+ZQxp/QqFYoidIVCjScg==",
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "optionalDependencies": {
+ "parse5": "^7.1.2"
+ },
+ "peerDependencies": {
+ "@angular/common": "^17.0.0 || ^18.0.0",
+ "@angular/core": "^17.0.0 || ^18.0.0",
+ "rxjs": "^6.5.3 || ^7.4.0"
+ }
+ },
"node_modules/@angular/cli": {
"version": "17.3.10",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.3.10.tgz",
@@ -2878,6 +2901,35 @@
"node": ">= 0.4"
}
},
+ "node_modules/@ng-icons/core": {
+ "version": "29.5.1",
+ "resolved": "https://registry.npmjs.org/@ng-icons/core/-/core-29.5.1.tgz",
+ "integrity": "sha512-wPpNqgoAlbJ0QAxfH2EAfT10ohtwXLQSXoWQ4a1tEhqXOn5kUAA8MqGgl5kILkiVCd8vvvPckLrt84LXQPWVCQ==",
+ "dependencies": {
+ "tslib": "^2.2.0"
+ },
+ "peerDependencies": {
+ "@angular/common": ">=18.0.0",
+ "@angular/core": ">=18.0.0",
+ "rxjs": "^6.5.3 || ^7.4.0"
+ }
+ },
+ "node_modules/@ng-icons/css.gg": {
+ "version": "29.5.1",
+ "resolved": "https://registry.npmjs.org/@ng-icons/css.gg/-/css.gg-29.5.1.tgz",
+ "integrity": "sha512-kHHBF6dNI/59qNFPpSd8WAyKpvPfdV4lYwmLM9hAnmTU845YDefc4wVW4/xaXG1j9dQxeQzOl9+/O0i/aUbUbA==",
+ "dependencies": {
+ "tslib": "^2.2.0"
+ }
+ },
+ "node_modules/@ng-icons/heroicons": {
+ "version": "29.5.1",
+ "resolved": "https://registry.npmjs.org/@ng-icons/heroicons/-/heroicons-29.5.1.tgz",
+ "integrity": "sha512-pcOpbZ32+TlMZRxmNAHXYHxTw8fkYEiLrPUbcA3YcbzFv8VzJ+FcnosyM70mGixkSjvf+tsERp63rvpJBUBP+w==",
+ "dependencies": {
+ "tslib": "^2.2.0"
+ }
+ },
"node_modules/@ngtools/webpack": {
"version": "17.3.10",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.3.10.tgz",
@@ -3222,6 +3274,25 @@
"node": ">=14"
}
},
+ "node_modules/@primeuix/styled": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.0.6.tgz",
+ "integrity": "sha512-bOya+/7WzCeF8D4N0BgGNk3Xe4F4PLEGu7V+btRlUOoEbda2uhp4nqqj2fOdzSERmjEUkkYds8dIVgVM56w1NA==",
+ "dependencies": {
+ "@primeuix/utils": "^0.0.6"
+ },
+ "engines": {
+ "node": ">=12.11.0"
+ }
+ },
+ "node_modules/@primeuix/utils": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.0.6.tgz",
+ "integrity": "sha512-7RQ2/LkZpSbi08NAlfZfajqBtWFM2csimf+xk97EoQDhpouzzbHFwf6WFbAyniZC9aPGJ+m+2qgyLxvYzA0x3g==",
+ "engines": {
+ "node": ">=12.11.0"
+ }
+ },
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.24.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz",
@@ -5719,7 +5790,7 @@
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=0.12"
},
@@ -9248,7 +9319,7 @@
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"entities": "^4.4.0"
},
@@ -9626,6 +9697,27 @@
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true
},
+ "node_modules/primeicons": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz",
+ "integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw=="
+ },
+ "node_modules/primeng": {
+ "version": "18.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/primeng/-/primeng-18.0.0-beta.2.tgz",
+ "integrity": "sha512-zCC36qtQsruPObuB/awdxHX0KvuRXa0Ebew0jTGNwal8YpJenF6ytxB4UIn6BetnuCYDuRAXW5zklxveIgxXiw==",
+ "dependencies": {
+ "@primeuix/styled": "0.0.6",
+ "tslib": "^2.3.0"
+ },
+ "peerDependencies": {
+ "@angular/common": "^17.0.0 || ^18.0.0",
+ "@angular/core": "^17.0.0 || ^18.0.0",
+ "@angular/forms": "^17.0.0 || ^18.0.0",
+ "rxjs": "^6.0.0 || ^7.8.1",
+ "zone.js": "~0.14.0"
+ }
+ },
"node_modules/proc-log": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz",
@@ -11001,6 +11093,14 @@
"node": ">=0.10"
}
},
+ "node_modules/tailwindcss-primeui": {
+ "version": "0.3.4",
+ "resolved": "https://registry.npmjs.org/tailwindcss-primeui/-/tailwindcss-primeui-0.3.4.tgz",
+ "integrity": "sha512-5+Qfoe5Kpq2Iwrd6umBUb3rQH6b7+pL4jxJUId0Su5agUM6TwCyH5Pyl9R0y3QQB3IRuTxBNmeS11B41f+30zw==",
+ "peerDependencies": {
+ "tailwindcss": ">=3.1.0"
+ }
+ },
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
diff --git a/package.json b/package.json
index 264ad3c..ba4d03e 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"private": true,
"dependencies": {
"@angular/animations": "^17.3.0",
+ "@angular/cdk": "^17.3.10",
"@angular/common": "^17.3.0",
"@angular/compiler": "^17.3.0",
"@angular/core": "^17.3.0",
@@ -18,7 +19,13 @@
"@angular/platform-browser": "^17.3.0",
"@angular/platform-browser-dynamic": "^17.3.0",
"@angular/router": "^17.3.0",
+ "@ng-icons/core": "^29.5.1",
+ "@ng-icons/css.gg": "^29.5.1",
+ "@ng-icons/heroicons": "^29.5.1",
+ "primeicons": "^7.0.0",
+ "primeng": "^18.0.0-beta.2",
"rxjs": "~7.8.0",
+ "tailwindcss-primeui": "^0.3.4",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
},
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 36093e1..572f3e9 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,336 +1,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Hello, {{ title }}
-
Congratulations! Your app is running. 🎉
-
-
-
-
- @for (item of [
- { title: 'Explore the Docs', link: 'https://angular.dev' },
- { title: 'Learn with Tutorials', link: 'https://angular.dev/tutorials' },
- { title: 'CLI Docs', link: 'https://angular.dev/tools/cli' },
- { title: 'Angular Language Service', link: 'https://angular.dev/tools/language-service' },
- { title: 'Angular DevTools', link: 'https://angular.dev/tools/devtools' },
- ]; track item.title) {
-
- {{ item.title }}
-
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/src/app/app.component.scss b/src/app/app.component.scss
new file mode 100644
index 0000000..4f82470
--- /dev/null
+++ b/src/app/app.component.scss
@@ -0,0 +1,9 @@
+// .main-content {
+// display: flex;
+// flex-direction: row;
+// }
+
+// router-outlet {
+// flex: 1;
+// padding: 20px;
+// }
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 253be95..e39c111 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,13 +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],
+ imports: [RouterOutlet, HeaderComponent],
templateUrl: './app.component.html',
- styleUrl: './app.component.sass'
+ styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'tools';
-}
+
+ constructor(private config: PrimeNGConfig) {
+ this.config.theme.set({ preset: Lara });
+ }
+}
\ No newline at end of file
diff --git a/src/app/app.config.ts b/src/app/app.config.ts
index 6c6ef60..c7c6d0d 100644
--- a/src/app/app.config.ts
+++ b/src/app/app.config.ts
@@ -2,7 +2,13 @@ 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';
export const appConfig: ApplicationConfig = {
- providers: [provideRouter(routes)]
+ providers: [provideRouter(routes),
+ provideAnimationsAsync("animations"),
+ provideNgIconsConfig({
+ size: '1.5em',
+ }),]
};
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts
index dc39edb..6b236ed 100644
--- a/src/app/app.routes.ts
+++ b/src/app/app.routes.ts
@@ -1,3 +1,36 @@
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';
+
+// create route to the ascii-to-text 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
+ }
+];
-export const routes: Routes = [];
diff --git a/src/app/header/header.component.html b/src/app/header/header.component.html
new file mode 100644
index 0000000..cec2a9e
--- /dev/null
+++ b/src/app/header/header.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/app.component.sass b/src/app/header/header.component.scss
similarity index 100%
rename from src/app/app.component.sass
rename to src/app/header/header.component.scss
diff --git a/src/app/header/header.component.spec.ts b/src/app/header/header.component.spec.ts
new file mode 100644
index 0000000..00b8bf6
--- /dev/null
+++ b/src/app/header/header.component.spec.ts
@@ -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;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ HeaderComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(HeaderComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts
new file mode 100644
index 0000000..9ce2320
--- /dev/null
+++ b/src/app/header/header.component.ts
@@ -0,0 +1,59 @@
+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 }
+ },
+ ],
+
+ }
+ ]
+ ]
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/src/app/shared/dual-textarea/dual-textarea.component.html b/src/app/shared/dual-textarea/dual-textarea.component.html
new file mode 100644
index 0000000..9cc93e7
--- /dev/null
+++ b/src/app/shared/dual-textarea/dual-textarea.component.html
@@ -0,0 +1,21 @@
+
\ No newline at end of file
diff --git a/src/app/shared/dual-textarea/dual-textarea.component.scss b/src/app/shared/dual-textarea/dual-textarea.component.scss
new file mode 100644
index 0000000..8e2fa27
--- /dev/null
+++ b/src/app/shared/dual-textarea/dual-textarea.component.scss
@@ -0,0 +1,36 @@
+:host {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ width: 98vw;
+
+ .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: 540px;
+ 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)
+ }
+}
\ No newline at end of file
diff --git a/src/app/shared/dual-textarea/dual-textarea.component.ts b/src/app/shared/dual-textarea/dual-textarea.component.ts
new file mode 100644
index 0000000..f4c7147
--- /dev/null
+++ b/src/app/shared/dual-textarea/dual-textarea.component.ts
@@ -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();
+ @Output() bottomChange = new EventEmitter();
+
+ 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);
+ }
+}
\ No newline at end of file
diff --git a/src/main.ts b/src/main.ts
index 35b00f3..17447a5 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -2,5 +2,4 @@ import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
-bootstrapApplication(AppComponent, appConfig)
- .catch((err) => console.error(err));
+bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
diff --git a/src/styles.sass b/src/styles.scss
similarity index 68%
rename from src/styles.sass
rename to src/styles.scss
index 90d4ee0..f8ffa76 100644
--- a/src/styles.sass
+++ b/src/styles.scss
@@ -1 +1,2 @@
/* You can add global styles to this file, and also import other style files */
+@import "primeicons/primeicons.css";
diff --git a/src/tools/ascii-to-text/ascii-to-text.component.html b/src/tools/ascii-to-text/ascii-to-text.component.html
new file mode 100644
index 0000000..1d6b455
--- /dev/null
+++ b/src/tools/ascii-to-text/ascii-to-text.component.html
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/src/tools/ascii-to-text/ascii-to-text.component.scss b/src/tools/ascii-to-text/ascii-to-text.component.scss
new file mode 100644
index 0000000..7724082
--- /dev/null
+++ b/src/tools/ascii-to-text/ascii-to-text.component.scss
@@ -0,0 +1,34 @@
+:host {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ width: 98vw;
+
+ .wrapper {
+ display: flex;
+ flex-direction: column;
+ width: 1140;
+
+ .conversion {
+ justify-content: center;
+ display: flex;
+ align-items: center;
+ height: 70vh;
+
+ p-floatlabel {
+ width: 30vw;
+ }
+
+ textarea {
+ width: 100%;
+ height: 50vh;
+ padding: 12px 20px;
+ box-sizing: border-box;
+ border-radius: 4px;
+ font-size: 16px;
+ resize: none;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/tools/ascii-to-text/ascii-to-text.component.ts b/src/tools/ascii-to-text/ascii-to-text.component.ts
new file mode 100644
index 0000000..1a2d847
--- /dev/null
+++ b/src/tools/ascii-to-text/ascii-to-text.component.ts
@@ -0,0 +1,39 @@
+import { Component } from '@angular/core';
+import { DualTextareaComponent } from '../../app/shared/dual-textarea/dual-textarea.component';
+
+@Component({
+ selector: 'app-ascii-to-text',
+ templateUrl: './ascii-to-text.component.html',
+ styleUrls: ['./ascii-to-text.component.scss'],
+ standalone: true,
+ imports: [DualTextareaComponent]
+})
+export class AsciiToTextComponent {
+ convertedText: string = '';
+ convertedAscii: string = '';
+
+ onAsciiChange(input: string): void {
+ this.convertedText = this.convertAsciiToText(input);
+ }
+
+ convertAsciiToText(ascii: string): string {
+ return ascii
+ .split(' ')
+ .map(char => String.fromCharCode(parseInt(char, 10)))
+ .join('');
+ }
+
+ onTextChange(input: string): void {
+ this.convertedAscii = this.convertTextToAscii(input);
+ }
+
+ convertTextToAscii(text: string): string {
+ return text
+ .split('')
+ .map(char => {
+ const asciiValue = char.charCodeAt(0).toString();
+ return asciiValue.padStart(3, '0');
+ })
+ .join(' ');
+ }
+}
\ No newline at end of file
diff --git a/src/tools/base64-converter/base64-converter.component.html b/src/tools/base64-converter/base64-converter.component.html
new file mode 100644
index 0000000..9d253d1
--- /dev/null
+++ b/src/tools/base64-converter/base64-converter.component.html
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/src/tools/base64-converter/base64-converter.component.scss b/src/tools/base64-converter/base64-converter.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/tools/base64-converter/base64-converter.component.spec.ts b/src/tools/base64-converter/base64-converter.component.spec.ts
new file mode 100644
index 0000000..4a38c2d
--- /dev/null
+++ b/src/tools/base64-converter/base64-converter.component.spec.ts
@@ -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 { Base64ConverterComponent } from './base64-converter.component';
+
+describe('Base64ConverterComponent', () => {
+ let component: Base64ConverterComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ Base64ConverterComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(Base64ConverterComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/tools/base64-converter/base64-converter.component.ts b/src/tools/base64-converter/base64-converter.component.ts
new file mode 100644
index 0000000..2897182
--- /dev/null
+++ b/src/tools/base64-converter/base64-converter.component.ts
@@ -0,0 +1,24 @@
+import { Component } from '@angular/core';
+import { DualTextareaComponent } from '../../app/shared/dual-textarea/dual-textarea.component';
+
+@Component({
+ selector: 'app-base64-converter',
+ templateUrl: './base64-converter.component.html',
+ styleUrls: ['./base64-converter.component.scss'],
+ standalone: true,
+ imports: [DualTextareaComponent]
+})
+export class Base64ConverterComponent {
+ convertedBase64: string = '';
+ convertedText: string = '';
+
+ base64Encoded(event: string): void {
+ this.convertedBase64 = btoa(event);
+ this.convertedText = event;
+ }
+
+ base64Decoded(event: string): void {
+ this.convertedText = atob(event);
+ this.convertedBase64 = event;
+ }
+}
\ No newline at end of file
diff --git a/src/tools/guid/guid.component.html b/src/tools/guid/guid.component.html
new file mode 100644
index 0000000..b61258f
--- /dev/null
+++ b/src/tools/guid/guid.component.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/tools/guid/guid.component.scss b/src/tools/guid/guid.component.scss
new file mode 100644
index 0000000..4c761e2
--- /dev/null
+++ b/src/tools/guid/guid.component.scss
@@ -0,0 +1,30 @@
+:host {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: 100vh;
+ width: 98vw;
+
+ p-panel {
+ width: 576px;
+ }
+
+ .guid-row {
+ padding: 8px 0px;
+ border-bottom: solid 1px var(--p-button-text-secondary-color);
+ }
+
+ p-floatlabel {
+ width: 30vw;
+ }
+
+ ng-icon {
+ color: var(--p-button-text-secondary-color)
+ }
+
+ .icon-wrapper{
+ display: flex;
+ align-items: center;
+ margin: 10px 0px;
+ }
+}
\ No newline at end of file
diff --git a/src/tools/guid/guid.component.ts b/src/tools/guid/guid.component.ts
new file mode 100644
index 0000000..54cc1e4
--- /dev/null
+++ b/src/tools/guid/guid.component.ts
@@ -0,0 +1,100 @@
+import { Component, OnInit } from '@angular/core';
+import { InputTextareaModule } from 'primeng/inputtextarea';
+import { FormsModule } from '@angular/forms';
+import { FloatLabelModule } from 'primeng/floatlabel';
+import { RadioButtonModule, } from 'primeng/radiobutton';
+import { CommonModule } from '@angular/common';
+import { ToggleButtonModule } from 'primeng/togglebutton';
+import { Clipboard } from '@angular/cdk/clipboard';
+import { ButtonModule } from 'primeng/button';
+import { PanelModule } from 'primeng/panel';
+import { NgIconComponent, provideIcons } from '@ng-icons/core';
+import { cssFormatUppercase } from '@ng-icons/css.gg';
+import { DividerModule } from 'primeng/divider';
+import { TooltipModule } from 'primeng/tooltip';
+
+interface setting {
+ name: string;
+ code: string;
+}
+
+@Component({
+ selector: 'app-guid',
+ templateUrl: './guid.component.html',
+ styleUrls: ['./guid.component.scss'],
+ standalone: true,
+ viewProviders: [provideIcons({cssFormatUppercase})],
+ imports: [
+ NgIconComponent,
+ PanelModule,
+ DividerModule,
+ FloatLabelModule,
+ InputTextareaModule,
+ FormsModule,
+ RadioButtonModule,
+ CommonModule,
+ ToggleButtonModule,
+ ButtonModule,
+ TooltipModule
+ ]
+})
+export class GuidComponent implements OnInit {
+ settings: setting[] | undefined;
+ selectedGuid: setting | undefined;
+ guid: string = '';
+ isUppercase: boolean = false;
+
+ constructor(private clipboard: Clipboard) { }
+
+ ngOnInit() {
+ this.generateGuid(false);
+ this.setGuids();
+ }
+
+ onCopyToClipboard(): void {
+ this.clipboard.copy(this.selectedGuid?.name!);
+ }
+
+ onCasingChange(): void {
+ this.isUppercase = !this.isUppercase;
+
+ if (this.isUppercase) {
+ this.guid = this.guid.toUpperCase();
+ } else {
+ this.guid = this.guid.toLowerCase();
+ }
+
+ this.setGuids();
+ }
+
+ generateGuid(input: boolean) {
+ this.guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(character) {
+ const randomValue = Math.random() * 16 | 0;
+ const value = character === 'x' ? randomValue : (randomValue & 0x3 | 0x8);
+ return value.toString(16);
+ });
+
+ if (this.isUppercase) {
+ this.guid = this.guid.toUpperCase();
+ } else {
+ this.guid = this.guid.toLowerCase();
+ }
+
+ if (input)
+ this.setGuids();
+ }
+
+ setGuids() {
+ this.settings = [
+ { name: this.guid, code: '00' },
+ { name: `"${this.guid}"`, code: '01' },
+ { name: `{${this.guid}}`, code: '02' },
+ { name: `new Guid("${this.guid}")`, code: '03' },
+ { name: `[Guid("${this.guid}")]`, code: '04' },
+ ];
+
+ if (this.settings!.length > 0) {
+ this.selectedGuid = this.settings![0];
+ }
+ }
+}
diff --git a/src/tools/jwt-to-json/jwt-to-json.component.html b/src/tools/jwt-to-json/jwt-to-json.component.html
new file mode 100644
index 0000000..6fb9cc8
--- /dev/null
+++ b/src/tools/jwt-to-json/jwt-to-json.component.html
@@ -0,0 +1,8 @@
+
+
\ No newline at end of file
diff --git a/src/tools/jwt-to-json/jwt-to-json.component.scss b/src/tools/jwt-to-json/jwt-to-json.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/tools/jwt-to-json/jwt-to-json.component.spec.ts b/src/tools/jwt-to-json/jwt-to-json.component.spec.ts
new file mode 100644
index 0000000..14b5a44
--- /dev/null
+++ b/src/tools/jwt-to-json/jwt-to-json.component.spec.ts
@@ -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 { JwtToJsonComponent } from './jwt-to-json.component';
+
+describe('JwtToJsonComponent', () => {
+ let component: JwtToJsonComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ JwtToJsonComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(JwtToJsonComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/tools/jwt-to-json/jwt-to-json.component.ts b/src/tools/jwt-to-json/jwt-to-json.component.ts
new file mode 100644
index 0000000..79a2f41
--- /dev/null
+++ b/src/tools/jwt-to-json/jwt-to-json.component.ts
@@ -0,0 +1,43 @@
+import { Component } from '@angular/core';
+import { DualTextareaComponent } from '../../app/shared/dual-textarea/dual-textarea.component';
+
+@Component({
+ selector: 'app-jwt-to-json',
+ templateUrl: './jwt-to-json.component.html',
+ styleUrls: ['./jwt-to-json.component.scss'],
+ standalone: true,
+ imports: [DualTextareaComponent]
+})
+export class JwtToJsonComponent {
+ readableToken: string = '';
+
+ decodeBase64Url(base64Url: string): string {
+ const base64 = base64Url
+ .replace(/-/g, '+')
+ .replace(/_/g, '/');
+
+ const jsonPayload = decodeURIComponent(
+ atob(base64)
+ .split('')
+ .map(char => '%' + ('00' + char.charCodeAt(0).toString(16)).slice(-2))
+ .join('')
+ );
+
+ return jsonPayload;
+ }
+
+ decodeJwtToken(token: string): void {
+ const parts = token.split('.');
+
+ if (parts.length !== 3) {
+ throw new Error('Invalid JWT Token');
+ }
+
+ const payload = this.decodeBase64Url(parts[1]);
+ try {
+ this.readableToken = JSON.stringify(JSON.parse(payload), null, 2);
+ } catch (error) {
+ this.readableToken = 'Invalid JWT Token';
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/tools/text-to-cron/text-to-cron.component.html b/src/tools/text-to-cron/text-to-cron.component.html
new file mode 100644
index 0000000..1c8aae6
--- /dev/null
+++ b/src/tools/text-to-cron/text-to-cron.component.html
@@ -0,0 +1,10 @@
+
+
+
+Still in beta, don't rely on this tool!
\ No newline at end of file
diff --git a/src/tools/text-to-cron/text-to-cron.component.scss b/src/tools/text-to-cron/text-to-cron.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/src/tools/text-to-cron/text-to-cron.component.spec.ts b/src/tools/text-to-cron/text-to-cron.component.spec.ts
new file mode 100644
index 0000000..e38d889
--- /dev/null
+++ b/src/tools/text-to-cron/text-to-cron.component.spec.ts
@@ -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 { TextToCronComponent } from './text-to-cron.component';
+
+describe('TextToCronComponent', () => {
+ let component: TextToCronComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ TextToCronComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TextToCronComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/tools/text-to-cron/text-to-cron.component.ts b/src/tools/text-to-cron/text-to-cron.component.ts
new file mode 100644
index 0000000..8b839d7
--- /dev/null
+++ b/src/tools/text-to-cron/text-to-cron.component.ts
@@ -0,0 +1,50 @@
+import { Component } from '@angular/core';
+import { DualTextareaComponent } from '../../app/shared/dual-textarea/dual-textarea.component';
+
+@Component({
+ selector: 'app-text-to-cron',
+ templateUrl: './text-to-cron.component.html',
+ styleUrls: ['./text-to-cron.component.scss'],
+ standalone: true,
+ imports: [DualTextareaComponent]
+})
+export class TextToCronComponent {
+
+ cronExpression: string = '';
+
+ getCronExpression(description: string): string {
+ let minute = "*";
+ let hour = "*";
+ let dayOfMonth = "*";
+ let month = "*";
+ let dayOfWeek = "*";
+
+ description = description.toLowerCase().trim();
+
+ const parts = description.split(" ");
+ parts.forEach((part, index) => {
+ if (part === "minute" || part === "minutes") {
+ if (index > 0 && !isNaN(parseInt(parts[index - 1]))) {
+ minute = `*/${parts[index - 1]}`;
+ }
+ } else if (part === "hour" || part === "hours") {
+ if (index > 0 && !isNaN(parseInt(parts[index - 1]))) {
+ hour = `*/${parts[index - 1]}`;
+ }
+ } else if (part === "day" && parts[index + 1] === "of") {
+ if (parts[index + 2] === "month" && index > 0 && !isNaN(parseInt(parts[index - 1]))) {
+ dayOfMonth = `${parts[index - 1]}`;
+ } else if (parts[index + 2] === "week" && index > 0 && !isNaN(parseInt(parts[index - 1]))) {
+ dayOfWeek = `${parts[index - 1]}`;
+ }
+ } else if (part === "month" || part === "months") {
+ if (index > 0 && !isNaN(parseInt(parts[index - 1]))) {
+ month = `*/${parts[index - 1]}`;
+ }
+ }
+ });
+
+ this.cronExpression = `${minute} ${hour} ${dayOfMonth} ${month} ${dayOfWeek}`;
+ return `${minute} ${hour} ${dayOfMonth} ${month} ${dayOfWeek}`;
+ }
+}