From af343770c18c8fb13e5df04fb3cad81675697a58 Mon Sep 17 00:00:00 2001 From: Myx Date: Fri, 25 Oct 2024 23:40:27 +0200 Subject: [PATCH] QR CODE GENERATOR --- tools/package-lock.json | 158 ++- tools/package.json | 3 +- tools/src/app/app.component.scss | 4 + tools/src/app/app.component.ts | 10 +- tools/src/app/app.routes.ts | 6 + tools/src/app/header/header.component.html | 2 +- tools/src/app/header/header.component.scss | 4 - tools/src/app/header/header.component.ts | 27 +- .../dual-textarea.component.html | 1 + .../dual-textarea.component.scss | 15 +- .../logo-full-orange-beta-vectorized.svg | 1061 +++++++++++++++++ tools/src/styles.scss | 6 +- .../color-picker/color-picker.component.scss | 4 + .../client-side/guid/guid.component.scss | 1 + .../qr-code-generator.component.html | 89 ++ .../qr-code-generator.component.scss | 103 ++ .../qr-code-generator.component.spec.ts | 28 + .../qr-code-generator.component.ts | 177 +++ 18 files changed, 1654 insertions(+), 45 deletions(-) create mode 100644 tools/src/assets/logo-full-orange-beta-vectorized.svg create mode 100644 tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.html create mode 100644 tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.scss create mode 100644 tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.spec.ts create mode 100644 tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.ts diff --git a/tools/package-lock.json b/tools/package-lock.json index 2c55d5c..d97b5b6 100644 --- a/tools/package-lock.json +++ b/tools/package-lock.json @@ -20,8 +20,9 @@ "@ng-icons/core": "^29.5.1", "@ng-icons/css.gg": "^29.5.1", "@ng-icons/heroicons": "^29.5.1", + "angularx-qrcode": "^18.0.2", "primeicons": "^7.0.0", - "primeng": "^18.0.0-beta.2", + "primeng": "^18.0.0-beta.3", "rxjs": "~7.8.0", "tailwindcss-primeui": "^0.3.4", "tslib": "^2.3.0", @@ -3271,20 +3272,20 @@ } }, "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==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@primeuix/styled/-/styled-0.2.0.tgz", + "integrity": "sha512-3Q6bDrmwTW88tzJsFIFenC0VyXLj0+/wYw+TZnJ/4CCDfehR4WfTs4EZdpuFtYqvmbpJ6zWXAiwSCNdSYTZkyA==", "dependencies": { - "@primeuix/utils": "^0.0.6" + "@primeuix/utils": "^0.2.0" }, "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==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@primeuix/utils/-/utils-0.2.0.tgz", + "integrity": "sha512-AaDIeRFlsbkVTk2s0mlEjnGSLi31X669NVwo+n+AVAnBdDiQznjipNTpHbOobVBtjOKZize74PChK6uoaSBRUw==", "engines": { "node": ">=12.11.0" } @@ -4176,6 +4177,18 @@ "ajv": "^8.8.2" } }, + "node_modules/angularx-qrcode": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/angularx-qrcode/-/angularx-qrcode-18.0.2.tgz", + "integrity": "sha512-G/VZ25t31c63T3g8zQ4JjZcHcXXoFXC7Y1GicSBHTloOHATZO5o1VoUGW+TsFLg0K41n/6X8hdgDhmyi5AeqLQ==", + "dependencies": { + "qrcode": "1.5.3", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": "^18.1.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -4755,7 +4768,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, "engines": { "node": ">=6" } @@ -5501,6 +5513,14 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/default-gateway": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", @@ -5588,6 +5608,11 @@ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "peer": true }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -5716,6 +5741,11 @@ "node": ">= 4" } }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -6332,7 +6362,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -6505,7 +6534,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -7994,7 +8022,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -9183,7 +9210,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "dependencies": { "p-try": "^2.0.0" }, @@ -9198,7 +9224,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -9247,7 +9272,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "engines": { "node": ">=6" } @@ -9385,7 +9409,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "engines": { "node": ">=8" } @@ -9577,6 +9600,14 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/postcss": { "version": "8.4.35", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", @@ -9831,11 +9862,11 @@ "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==", + "version": "18.0.0-beta.3", + "resolved": "https://registry.npmjs.org/primeng/-/primeng-18.0.0-beta.3.tgz", + "integrity": "sha512-nX2sxTHRiggoaDrgFsnAfIihVFvZR4RfpH9JwOy4BL7wQ8cG0SYvSf1E5TTorJOED9/nPwrtVGUoHrDUsiNX+A==", "dependencies": { - "@primeuix/styled": "0.0.6", + "@primeuix/styled": "0.2.0", "tslib": "^2.3.0" }, "peerDependencies": { @@ -9924,6 +9955,71 @@ "node": ">=0.9" } }, + "node_modules/qrcode": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", + "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", + "dependencies": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -10214,7 +10310,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -10228,6 +10323,11 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -10748,6 +10848,11 @@ "node": ">= 0.8" } }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -12721,6 +12826,11 @@ "which": "bin/which" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -12731,7 +12841,6 @@ "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -12792,7 +12901,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -12807,7 +12915,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -12818,8 +12925,7 @@ "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/wrappy": { "version": "1.0.2", diff --git a/tools/package.json b/tools/package.json index ba4d03e..ed00d7a 100644 --- a/tools/package.json +++ b/tools/package.json @@ -22,8 +22,9 @@ "@ng-icons/core": "^29.5.1", "@ng-icons/css.gg": "^29.5.1", "@ng-icons/heroicons": "^29.5.1", + "angularx-qrcode": "^18.0.2", "primeicons": "^7.0.0", - "primeng": "^18.0.0-beta.2", + "primeng": "^18.0.0-beta.3", "rxjs": "~7.8.0", "tailwindcss-primeui": "^0.3.4", "tslib": "^2.3.0", diff --git a/tools/src/app/app.component.scss b/tools/src/app/app.component.scss index 72a1a2b..4cc1b9c 100644 --- a/tools/src/app/app.component.scss +++ b/tools/src/app/app.component.scss @@ -3,6 +3,10 @@ justify-content: center; } +.darkmode { + background-color: #121212; +} + ::ng-deep { .p-panel { border-radius: unset !important; diff --git a/tools/src/app/app.component.ts b/tools/src/app/app.component.ts index 94ba31d..4e7e120 100644 --- a/tools/src/app/app.component.ts +++ b/tools/src/app/app.component.ts @@ -1,9 +1,9 @@ -import { Component } from '@angular/core'; +import { Component, OnInit } 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'; import { FooterComponent } from './footer/footer.component'; +import { Lara } from 'primeng/themes/lara'; @Component({ selector: 'app-root', @@ -12,7 +12,7 @@ import { FooterComponent } from './footer/footer.component'; templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) -export class AppComponent { +export class AppComponent implements OnInit{ title = 'tools'; constructor(private config: PrimeNGConfig) { @@ -21,4 +21,8 @@ export class AppComponent { darkModeSelector: '.darkmode' }); } + ngOnInit(): void { + const element = document.querySelector('html'); + element?.classList.toggle('darkmode'); + } } \ No newline at end of file diff --git a/tools/src/app/app.routes.ts b/tools/src/app/app.routes.ts index b41f564..8a4a247 100644 --- a/tools/src/app/app.routes.ts +++ b/tools/src/app/app.routes.ts @@ -8,6 +8,7 @@ import { DdsToPngComponent } from '../tools/client-side/dds-to-png/dds-to-png.co import { ImageConverterComponent } from '../tools/server-side/image-converter/image-converter.component'; import { WordCounterComponent } from '../tools/client-side/word-counter/word-counter.component'; import { ColorPickerComponent } from '../tools/client-side/color-picker/color-picker.component'; +import { QrCodeGeneratorComponent } from '../tools/client-side/qr-code-generator/qr-code-generator.component'; export const routes: Routes = [ { @@ -50,6 +51,11 @@ export const routes: Routes = [ pathMatch: 'full', component: WordCounterComponent }, + { + path: 'qr-code-generator', + pathMatch: 'full', + component: QrCodeGeneratorComponent + }, { path: 'color-picker', pathMatch: 'full', diff --git a/tools/src/app/header/header.component.html b/tools/src/app/header/header.component.html index 81ecad5..3a623ae 100644 --- a/tools/src/app/header/header.component.html +++ b/tools/src/app/header/header.component.html @@ -1,5 +1,5 @@ - logo + Bytefy Logotype diff --git a/tools/src/app/header/header.component.scss b/tools/src/app/header/header.component.scss index bf5a2f1..3877c96 100644 --- a/tools/src/app/header/header.component.scss +++ b/tools/src/app/header/header.component.scss @@ -2,10 +2,6 @@ width: 140px; } -.darkMode { - filter: invert(1); -} - ::ng-deep .p-megamenu-col-12 { flex-direction: row !important; display: flex !important; diff --git a/tools/src/app/header/header.component.ts b/tools/src/app/header/header.component.ts index 305873e..3b7bca4 100644 --- a/tools/src/app/header/header.component.ts +++ b/tools/src/app/header/header.component.ts @@ -17,7 +17,7 @@ export class HeaderComponent implements OnInit { isDarkMode: boolean = true; ngOnInit() { - this.isDarkMode = window?.matchMedia?.('(prefers-color-scheme:dark)')?.matches; + this.isDarkMode = window?.matchMedia?.('(prefers-color-scheme:dark)')?.matches; this.items = [ { @@ -95,7 +95,30 @@ export class HeaderComponent implements OnInit { } ] ] - } + }, + { + label: 'Generators', + icon: 'pi pi-box', + items: [ + [ + { + label: 'Generators', + items: [ + { + label: 'QR Code Generator', + routerLink: 'qr-code-generator', + routerLinkActiveOptions: { exact: true } + }, + { + label: 'Guid Generator', + routerLink: 'guid', + routerLinkActiveOptions: { exact: true } + } + ] + } + ] + ] + } ] } } \ No newline at end of file diff --git a/tools/src/app/shared/dual-textarea/dual-textarea.component.html b/tools/src/app/shared/dual-textarea/dual-textarea.component.html index b62efc4..ba09c68 100644 --- a/tools/src/app/shared/dual-textarea/dual-textarea.component.html +++ b/tools/src/app/shared/dual-textarea/dual-textarea.component.html @@ -3,6 +3,7 @@ + + +
+

Size of QR Code

+ + +

Image in QR code

+ + +

Error correction level

+ + + {{item.level}} + + + +

Color

+ + +

Background color

+ +
+
+
+ + \ No newline at end of file diff --git a/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.scss b/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.scss new file mode 100644 index 0000000..91b63d5 --- /dev/null +++ b/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.scss @@ -0,0 +1,103 @@ +:host { + display: flex; + justify-content: center; + margin-top: 20px; + width: 96vw; + + .miniButtons { + margin: 0px 4px; + } + + .wrapper { + display: flex; + flex-direction: column; + background-color: #000000; + } + + a.disabled { + pointer-events: none; + cursor: default; + } + + .card { + display: flex; + flex-direction: column; + width: 1140px; + } + + .center { + display: flex; + justify-content: center; + } + + .p-toolbar-group-end, .p-toolbar-group-center, .p-toolbar-group-start { + width: 300px; + ::ng-deep { + .p-button { + height: 39px !important; + } + } + } + + .p-toolbar-group-end { + display: flex; + justify-content: flex-end; + } + + .p-toolbar-group-center .p-inputtext { + width: calc(100% - 44px); + } + + qrcode { + display: flex; + justify-content: center; + } + + .vertical { + display: flex; + flex-direction: column; + } + + ::ng-deep .p-panel-header { + justify-content: unset !important; + + * { + margin-right: 5px; + } + } + + @media only screen and (max-width: 1021px) { + .p-toolbar-group-end, .p-toolbar-group-start { + width: unset; + + ::ng-deep { + .p-button { + height: 40px !important; + } + p-button { + height: 40px !important; + margin: 0px 4px 0px 0px !important; + } + } + } + + .p-toolbar-group-end { + display: flex; + justify-content: flex-start; + + ::ng-deep { + p-button { + margin: 0px 0px 0px 0px !important; + } + } + } + + .p-toolbar-group-center { + width: 100%; + + .p-inputtext { + width: calc(100% - 44px); + } + } + } +} \ No newline at end of file diff --git a/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.spec.ts b/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.spec.ts new file mode 100644 index 0000000..e3311d3 --- /dev/null +++ b/tools/src/tools/client-side/qr-code-generator/qr-code-generator.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 { QrCodeGeneratorComponent } from './qr-code-generator.component'; + +describe('QrCodeGeneratorComponent', () => { + let component: QrCodeGeneratorComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ QrCodeGeneratorComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(QrCodeGeneratorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.ts b/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.ts new file mode 100644 index 0000000..fe3b648 --- /dev/null +++ b/tools/src/tools/client-side/qr-code-generator/qr-code-generator.component.ts @@ -0,0 +1,177 @@ +import { Component, OnInit, Renderer2 } from '@angular/core'; +import { QRCodeModule } from 'angularx-qrcode'; +import { AccordionModule } from 'primeng/accordion'; +import { PanelModule } from 'primeng/panel'; +import { TagModule } from 'primeng/tag'; +import { InputTextModule } from 'primeng/inputtext'; +import { ButtonModule } from 'primeng/button'; +import { ToolbarModule } from 'primeng/toolbar'; +import { CommonModule } from '@angular/common'; +import { InputTextareaModule } from 'primeng/inputtextarea'; +import { FloatLabelModule } from 'primeng/floatlabel'; +import { FileUploadModule } from 'primeng/fileupload'; +import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; +import { MessageModule } from 'primeng/message'; +import { SelectButtonChangeEvent, SelectButtonModule } from 'primeng/selectbutton'; +import { ColorPickerChangeEvent, ColorPickerModule } from 'primeng/colorpicker'; + +export interface QrCodeError { + error: boolean; + message: string; +} + +@Component({ + selector: 'app-qr-code-generator', + templateUrl: './qr-code-generator.component.html', + styleUrls: ['./qr-code-generator.component.scss'], + standalone: true, + imports: [ + QRCodeModule, + AccordionModule, + PanelModule, + TagModule, + InputTextModule, + ButtonModule, + ToolbarModule, + CommonModule, + FloatLabelModule, + InputTextareaModule, + FileUploadModule, + MessageModule, + SelectButtonModule, + ColorPickerModule + ] +}) +export class QrCodeGeneratorComponent implements OnInit { + qrCodeData: string = 'bytefy.net'; + isBeta = true; + extendedInput = false; + activeTabs: number[] = [1]; + expandIcon = 'pi pi-angle-up'; + inputedValue: string = ''; + qrCodeImageUrl: SafeUrl = ''; + unsafeUrl: string = ''; + downloadEnabled = false; + error: QrCodeError = { + error: false, + message: '' + }; + colorCode: string = '#000000'; + backgroundColorCode: string = '#ffffff'; + level: "L" | "M" | "Q" | "H" | "low" | "medium" | "quartile" | "high" = 'H'; + innerQrCodeimage: string = ''; + qrCodeSize: number = 300; + correctionLevel: any[] = [ + { level: 'L' }, + { level: 'M' }, + { level: 'Q' }, + { level: 'H' } + ]; + isMobile: boolean = false; + + constructor(private renderer: Renderer2, private sanitizer: DomSanitizer) {} + + ngOnInit(): void { + this.isMobile = window.innerWidth < 1021; + window.addEventListener('resize', () => { + this.isMobile = window.innerWidth < 1021; + }); + } + + onImageLinkInputChanged(event: Event): void { + this.innerQrCodeimage = (event.target as HTMLInputElement).value; + } + + onLevelSelected(level: SelectButtonChangeEvent): void { + this.level = level.value; + } + + onFileSelected(event: Event): void { + const file = (event.target as HTMLInputElement).files?.item(0); + + if (!file) { + return; + } + + const reader = new FileReader(); + reader.onload = () => { + this.qrCodeData = reader.result as string; + this.validateInput(); + }; + reader.readAsText(file); + } + + onDataTextInputChanged(event: Event): void { + const input = (event.target as HTMLInputElement).value; + this.qrCodeData = input + this.inputedValue = input; + + this.validateInput(); + } + + onSizeInputChanged(event: Event): void { + let size = parseInt((event.target as HTMLInputElement).value, 10); + + if(size <= 1000){ + this.qrCodeSize = size; + this.error.error = false; + } + else + this.error = { + error: true, + message: 'Too large image size, change the field "Size of QR Code". Maximum value is 1000.' + }; + } + + onColorChanged(event: ColorPickerChangeEvent): void { + this.colorCode = event.value.toString(); + } + + onBackgroundColorChanged(event: ColorPickerChangeEvent): void { + this.backgroundColorCode = event.value.toString(); + } + + onExpandButtonClick(): void { + this.extendedInput = !this.extendedInput; + this.expandIcon = this.extendedInput ? 'pi pi-angle-down' : 'pi pi-angle-up'; + } + + onCodeUrlChanged(url: SafeUrl): void { + this.qrCodeImageUrl = url; + } + + onPrintButtonClick(): void { + const iframe = this.renderer.createElement('iframe'); + this.renderer.setStyle(iframe, 'position', 'absolute'); + this.renderer.setStyle(iframe, 'width', '0'); + this.renderer.setStyle(iframe, 'height', '0'); + this.renderer.setStyle(iframe, 'border', '0'); + + document.body.appendChild(iframe); + iframe.onload = () => { + const doc = iframe.contentDocument || iframe.contentWindow?.document; + + if (doc) { + const img = doc.createElement('img'); + img.src = this.sanitizer.sanitize(4, this.qrCodeImageUrl); + + doc.body.appendChild(img); + + iframe.contentWindow?.print(); + + setTimeout(() => { + document.body.removeChild(iframe); + }, 1000); + } + }; + + iframe.srcdoc = 'Bytefy.net Print QR Code'; + } + + validateInput(): void { + this.error = { + error: this.qrCodeData.length > 1269, + message: 'File size is too large.' + }; + } +}