diff --git a/.eslintrc.base.json b/.eslintrc.base.json new file mode 100644 index 0000000..0be733b --- /dev/null +++ b/.eslintrc.base.json @@ -0,0 +1,42 @@ +{ + "root": true, + "ignorePatterns": ["**/*"], + "plugins": ["@nx"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": { + "@nx/enforce-module-boundaries": [ + "error", + { + "enforceBuildableLibDependency": true, + "allow": [], + "depConstraints": [ + { + "sourceTag": "*", + "onlyDependOnLibsWithTags": ["*"] + } + ] + } + ] + } + }, + { + "files": ["*.ts", "*.tsx"], + "extends": ["plugin:@nx/typescript"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "extends": ["plugin:@nx/javascript"], + "rules": {} + }, + { + "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], + "env": { + "jest": true + }, + "rules": {} + } + ] +} diff --git a/.eslintrc.json b/.eslintrc.json index 8c96fac..4eae595 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,24 +1,17 @@ { - "root": true, "ignorePatterns": ["!**/*"], - "plugins": ["@nx"], "overrides": [ { "files": ["*.ts", "*.tsx"], - "extends": ["plugin:@nx/typescript"], "rules": {} }, { "files": ["*.js", "*.jsx"], - "extends": ["plugin:@nx/javascript"], "rules": {} }, { "files": ["*.ts"], - "extends": [ - "plugin:@nx/angular", - "plugin:@angular-eslint/template/process-inline-templates" - ], + "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"], "rules": { "@angular-eslint/directive-selector": [ "error", @@ -43,5 +36,6 @@ "extends": ["plugin:@nx/angular-template"], "rules": {} } - ] + ], + "extends": ["./.eslintrc.base.json"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index a1acd47..71704c5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,8 @@ { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, - "editor.tabSize": 2 + "editor.tabSize": 2, + "cSpell.words": [ + "nwui" + ] } \ No newline at end of file diff --git a/jest.config.app.ts b/jest.config.app.ts new file mode 100644 index 0000000..f46263c --- /dev/null +++ b/jest.config.app.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +export default { + displayName: 'NitroPlusTranslator', + preset: './jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: './coverage/NitroPlusTranslator', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], + testMatch: ['/src/**/__tests__/**/*.[jt]s?(x)', '/src/**/*(*.)@(spec|test).[jt]s?(x)'], +}; diff --git a/jest.config.ts b/jest.config.ts index 6e13039..6b3f2d6 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -1,26 +1,5 @@ -/* eslint-disable */ -export default { - displayName: 'NitroPlusTranslator', - preset: './jest.preset.js', - setupFilesAfterEnv: ['/src/test-setup.ts'], - coverageDirectory: './coverage/NitroPlusTranslator', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], - testMatch: [ - '/src/**/__tests__/**/*.[jt]s?(x)', - '/src/**/*(*.)@(spec|test).[jt]s?(x)', - ], -}; +import { getJestProjectsAsync } from '@nx/jest'; + +export default async () => ({ + projects: await getJestProjectsAsync(), +}); diff --git a/nwaifu-ui/.eslintrc.json b/nwaifu-ui/.eslintrc.json new file mode 100644 index 0000000..6701115 --- /dev/null +++ b/nwaifu-ui/.eslintrc.json @@ -0,0 +1,46 @@ +{ + "extends": [ + "../.eslintrc.base.json" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts" + ], + "extends": [ + "plugin:@nx/angular", + "plugin:@angular-eslint/template/process-inline-templates" + ], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "nwui", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "nwui", + "style": "kebab-case" + } + ] + } + }, + { + "files": [ + "*.html" + ], + "extends": [ + "plugin:@nx/angular-template" + ], + "rules": {} + } + ] +} \ No newline at end of file diff --git a/nwaifu-ui/README.md b/nwaifu-ui/README.md new file mode 100644 index 0000000..d834659 --- /dev/null +++ b/nwaifu-ui/README.md @@ -0,0 +1,7 @@ +# nwaifu-ui + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test nwaifu-ui` to execute the unit tests. diff --git a/nwaifu-ui/jest.config.ts b/nwaifu-ui/jest.config.ts new file mode 100644 index 0000000..fadd88e --- /dev/null +++ b/nwaifu-ui/jest.config.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +export default { + displayName: 'nwaifu-ui', + preset: '../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../coverage/nwaifu-ui', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/nwaifu-ui/project.json b/nwaifu-ui/project.json new file mode 100644 index 0000000..988befb --- /dev/null +++ b/nwaifu-ui/project.json @@ -0,0 +1,9 @@ +{ + "name": "nwaifu-ui", + "$schema": "../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "nwaifu-ui/src", + "prefix": "nwui", + "projectType": "library", + "tags": [], + "targets": {} +} diff --git a/nwaifu-ui/src/index.ts b/nwaifu-ui/src/index.ts new file mode 100644 index 0000000..f41a696 --- /dev/null +++ b/nwaifu-ui/src/index.ts @@ -0,0 +1 @@ +export * from './lib'; diff --git a/nwaifu-ui/src/lib/components/button/button.component.html b/nwaifu-ui/src/lib/components/button/button.component.html new file mode 100644 index 0000000..2fdefa5 --- /dev/null +++ b/nwaifu-ui/src/lib/components/button/button.component.html @@ -0,0 +1 @@ + diff --git a/src/app/components/upload_btn/upload_btn.component.scss b/nwaifu-ui/src/lib/components/button/button.component.scss similarity index 61% rename from src/app/components/upload_btn/upload_btn.component.scss rename to nwaifu-ui/src/lib/components/button/button.component.scss index d68a12c..30dcfc8 100644 --- a/src/app/components/upload_btn/upload_btn.component.scss +++ b/nwaifu-ui/src/lib/components/button/button.component.scss @@ -8,7 +8,16 @@ button { border-radius: 15px; transition: ease-in-out 0.2s; margin: 2rem; - &:hover { + &:hover, + &:active { transform: scale(1.2); } + &:disabled { + opacity: 0.5; + &:hover, + &:active { + cursor: not-allowed; + transform: scale(1); + } + } } diff --git a/nwaifu-ui/src/lib/components/button/button.component.ts b/nwaifu-ui/src/lib/components/button/button.component.ts new file mode 100644 index 0000000..fc06d8d --- /dev/null +++ b/nwaifu-ui/src/lib/components/button/button.component.ts @@ -0,0 +1,15 @@ +import { CommonModule } from '@angular/common'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; + +@Component({ + selector: 'nwui-button', + templateUrl: './button.component.html', + styleUrls: ['./button.component.scss'], + standalone: true, + imports: [CommonModule], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ButtonComponent { + @Input() disabled = false; + @Input() type: string | undefined; +} diff --git a/nwaifu-ui/src/lib/components/button/index.ts b/nwaifu-ui/src/lib/components/button/index.ts new file mode 100644 index 0000000..643ee81 --- /dev/null +++ b/nwaifu-ui/src/lib/components/button/index.ts @@ -0,0 +1 @@ +export * from './button.component'; diff --git a/nwaifu-ui/src/lib/components/index.ts b/nwaifu-ui/src/lib/components/index.ts new file mode 100644 index 0000000..eaf5eea --- /dev/null +++ b/nwaifu-ui/src/lib/components/index.ts @@ -0,0 +1 @@ +export * from './button'; diff --git a/nwaifu-ui/src/lib/index.ts b/nwaifu-ui/src/lib/index.ts new file mode 100644 index 0000000..07635cb --- /dev/null +++ b/nwaifu-ui/src/lib/index.ts @@ -0,0 +1 @@ +export * from './components'; diff --git a/nwaifu-ui/src/test-setup.ts b/nwaifu-ui/src/test-setup.ts new file mode 100644 index 0000000..ab1eeeb --- /dev/null +++ b/nwaifu-ui/src/test-setup.ts @@ -0,0 +1,8 @@ +// @ts-expect-error https://thymikee.github.io/jest-preset-angular/docs/getting-started/test-environment +globalThis.ngJest = { + testEnvironmentOptions: { + errorOnUnknownElements: true, + errorOnUnknownProperties: true, + }, +}; +import 'jest-preset-angular/setup-jest'; diff --git a/nwaifu-ui/tsconfig.json b/nwaifu-ui/tsconfig.json new file mode 100644 index 0000000..292b8f8 --- /dev/null +++ b/nwaifu-ui/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/nwaifu-ui/tsconfig.lib.json b/nwaifu-ui/tsconfig.lib.json new file mode 100644 index 0000000..f5db120 --- /dev/null +++ b/nwaifu-ui/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/**/*.spec.ts", "src/test-setup.ts", "jest.config.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/nwaifu-ui/tsconfig.spec.json b/nwaifu-ui/tsconfig.spec.json new file mode 100644 index 0000000..9d8b0b8 --- /dev/null +++ b/nwaifu-ui/tsconfig.spec.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../dist/out-tsc", + "module": "commonjs", + "target": "es2016", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/nx.json b/nx.json index 2047f28..26ee4fa 100644 --- a/nx.json +++ b/nx.json @@ -49,6 +49,13 @@ "linter": "eslint", "style": "scss", "unitTestRunner": "jest" + }, + "@nx/angular:library": { + "linter": "eslint", + "unitTestRunner": "jest" + }, + "@nx/angular:component": { + "style": "css" } }, "defaultProject": "NitroPlusTranslator" diff --git a/project.json b/project.json index dfe301d..eb16ba3 100644 --- a/project.json +++ b/project.json @@ -80,7 +80,7 @@ "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectName}"], "options": { - "jestConfig": "jest.config.ts" + "jestConfig": "jest.config.app.ts" } } } diff --git a/src/app/app.component.html b/src/app/app.component.html index 990c5d5..46eaa7b 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,6 +1,11 @@
- - + + Upload + + + + Clear +
diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 0f4a490..bec11d2 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,14 +1,12 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { ClearBtnComponent } from './components/clear_btn/clear_btn.component'; +import { ButtonComponent } from '@nwaifu-ui'; import { TextListComponent } from './components/text_list/text_list.component'; -import { UploadBtnComponent } from './components/upload_btn/upload_btn.component'; import { TranslateData } from './dto/translate_data.dto'; import { parse } from './lib/parser'; - @Component({ standalone: true, - imports: [UploadBtnComponent, RouterModule, TextListComponent, ClearBtnComponent], + imports: [RouterModule, TextListComponent, ButtonComponent], selector: 'app-root', templateUrl: './app.component.html', styleUrl: './app.component.scss', @@ -16,11 +14,36 @@ import { parse } from './lib/parser'; export class AppComponent implements OnInit { title = 'NitroPlusTranslator'; elements: TranslateData[] = []; + @ViewChild('fileInput') fileInput: HTMLInputElement | null = null; ngOnInit(): void { const data = localStorage.getItem('translations'); if (data) { - this.elements = JSON.parse(data); + try { + this.elements = JSON.parse(data); + } catch (e) { + console.error(e); + alert('Error while loading'); + localStorage.removeItem('translations'); + this.elements = []; + } + } + } + + submitFile($event: Event) { + const target = $event.target as HTMLInputElement; + if (target.files) { + const file = target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = () => { + if (reader.result) { + this.onFileLoaded(reader.result.toString()); + target.value = ''; + } + }; + reader.readAsText(file); + } } } @@ -31,5 +54,6 @@ export class AppComponent implements OnInit { onClearClicked() { this.elements = []; + localStorage.removeItem('translations'); } } diff --git a/src/app/components/clear_btn/clear_btn.component.html b/src/app/components/clear_btn/clear_btn.component.html deleted file mode 100644 index ec0f6e9..0000000 --- a/src/app/components/clear_btn/clear_btn.component.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/src/app/components/clear_btn/clear_btn.component.scss b/src/app/components/clear_btn/clear_btn.component.scss deleted file mode 100644 index d68a12c..0000000 --- a/src/app/components/clear_btn/clear_btn.component.scss +++ /dev/null @@ -1,14 +0,0 @@ -button { - outline: none; - border: none; - cursor: pointer; - background-color: #5b3f45; - padding: 1em 1.5em; - color: #f5f6fa; - border-radius: 15px; - transition: ease-in-out 0.2s; - margin: 2rem; - &:hover { - transform: scale(1.2); - } -} diff --git a/src/app/components/clear_btn/clear_btn.component.ts b/src/app/components/clear_btn/clear_btn.component.ts deleted file mode 100644 index 9e639c8..0000000 --- a/src/app/components/clear_btn/clear_btn.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { Component, EventEmitter, Output } from '@angular/core'; - -@Component({ - selector: 'app-clear-btn', - templateUrl: './clear_btn.component.html', - styleUrls: ['./clear_btn.component.scss'], - standalone: true, - imports: [CommonModule], -}) -export class ClearBtnComponent { - @Output() clear = new EventEmitter(); - clear_func() { - localStorage.setItem('translations', '[]'); - this.clear.emit(); - } -} diff --git a/src/app/components/text_list/text_list.component.html b/src/app/components/text_list/text_list.component.html index af033f4..744fd31 100644 --- a/src/app/components/text_list/text_list.component.html +++ b/src/app/components/text_list/text_list.component.html @@ -2,20 +2,5 @@
@for(item of elements_data; track $index) { - }
diff --git a/src/app/components/text_list/text_list.component.ts b/src/app/components/text_list/text_list.component.ts index ef631f7..ab8899c 100644 --- a/src/app/components/text_list/text_list.component.ts +++ b/src/app/components/text_list/text_list.component.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; -import { TranslateData } from 'src/app/dto/translate_data.dto'; +import { TranslateData } from '../../dto/translate_data.dto'; import { TranslateBlockComponent } from '../translate_block/translate_block.component'; @Component({ diff --git a/src/app/components/translate_block/translate_block.component.html b/src/app/components/translate_block/translate_block.component.html index b82faf5..3ab8e45 100644 --- a/src/app/components/translate_block/translate_block.component.html +++ b/src/app/components/translate_block/translate_block.component.html @@ -5,8 +5,8 @@
- - - + Translate + +
diff --git a/src/app/components/translate_block/translate_block.component.ts b/src/app/components/translate_block/translate_block.component.ts index c5446e4..9bd7d8d 100644 --- a/src/app/components/translate_block/translate_block.component.ts +++ b/src/app/components/translate_block/translate_block.component.ts @@ -1,14 +1,15 @@ import { CommonModule } from '@angular/common'; import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { TranslateData } from 'src/app/dto/translate_data.dto'; -import { TranslatePipe } from 'src/app/pipes/translate.pipe'; +import { ButtonComponent } from '@nwaifu-ui'; +import { TranslateData } from '../../dto/translate_data.dto'; +import { TranslatePipe } from '../../pipes/translate.pipe'; @Component({ selector: 'app-translate-block', templateUrl: './translate_block.component.html', styleUrls: ['./translate_block.component.scss'], standalone: true, - imports: [CommonModule], + imports: [CommonModule, ButtonComponent], providers: [TranslatePipe], }) export class TranslateBlockComponent implements OnInit, AfterViewInit { diff --git a/src/app/components/upload_btn/upload_btn.component.html b/src/app/components/upload_btn/upload_btn.component.html deleted file mode 100644 index 843307b..0000000 --- a/src/app/components/upload_btn/upload_btn.component.html +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/src/app/components/upload_btn/upload_btn.component.ts b/src/app/components/upload_btn/upload_btn.component.ts deleted file mode 100644 index 8af4024..0000000 --- a/src/app/components/upload_btn/upload_btn.component.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { Component, ElementRef, EventEmitter, Output, ViewChild } from '@angular/core'; - -@Component({ - imports: [CommonModule], - selector: 'app-upload-btn', - styleUrl: './upload_btn.component.scss', - templateUrl: './upload_btn.component.html', - standalone: true, -}) -export class UploadBtnComponent { - @ViewChild('fileInput') fileInput: ElementRef | null = null; - @Output() fileLoaded = new EventEmitter(); - - onChange(event: Event) { - if (event.target) { - const target = event.target as HTMLInputElement; - if (target.files) { - const file: File = target.files[0]; - if (!file.name.endsWith('.nps')) { - alert('Only .nps files are allowed'); - target.value = ''; - return; - } - const reader = new FileReader(); - reader.onload = () => { - this.fileLoaded.emit(reader.result as string); - target.value = ''; - }; - reader.readAsText(file); - } - } - } -} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 0000000..3153e97 --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,30 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "rootDir": ".", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "es2022", + "module": "esnext", + "lib": [ + "es2020", + "dom" + ], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "baseUrl": ".", + "paths": { + "@nwaifu-ui": [ + "nwaifu-ui/src/index.ts" + ] + } + }, + "exclude": [ + "node_modules", + "tmp" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index fb44c4a..70eec62 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,22 +1,5 @@ { "compilerOptions": { - "rootDir": ".", - "sourceMap": true, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "importHelpers": true, - "target": "es2022", - "module": "esnext", - "lib": [ - "es2020", - "dom" - ], - "skipLibCheck": true, - "skipDefaultLibCheck": true, - "baseUrl": ".", - "paths": {}, "useDefineForClassFields": false, "forceConsistentCasingInFileNames": true, "strict": true, @@ -38,15 +21,11 @@ "path": "./tsconfig.spec.json" } ], - "compileOnSave": false, - "exclude": [ - "node_modules", - "tmp" - ], "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false, "strictInjectionParameters": true, "strictInputAccessModifiers": true, "strictTemplates": true - } -} \ No newline at end of file + }, + "extends": "./tsconfig.base.json" +}