diff --git a/.gitignore b/.gitignore index 0f3e46d..5fb88fa 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ Thumbs.db .nx/cache +.nx/workspace-data # env *.env* diff --git a/.prettierignore b/.prettierignore index d155fdb..e26f0b3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,5 @@ # Add files here to ignore them from prettier formatting /dist /coverage -/.nx/cache \ No newline at end of file +/.nx/cache +/.nx/workspace-data \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 148f004..bdf7b11 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,7 +6,7 @@ "**/CVS": true, "**/.DS_Store": true, "**/Thumbs.db": true, - "**/node_modules": true, + // "**/node_modules": true, "**/.angular": true } } diff --git a/apps/NwaifuWeb/src/app/app.routes.ts b/apps/NwaifuWeb/src/app/app.routes.ts index 337bc63..00aafe1 100644 --- a/apps/NwaifuWeb/src/app/app.routes.ts +++ b/apps/NwaifuWeb/src/app/app.routes.ts @@ -1,6 +1,6 @@ import { Routes } from "@angular/router"; import { MainPageComponent } from './pages/main/main.component'; -import { SecondComponent } from './pages/second/second.component'; +import { NitroplusComponent } from './pages/nitroplus-translator/nitroplus-translator.component'; export const routes: Routes = [ { @@ -11,8 +11,8 @@ export const routes: Routes = [ component: MainPageComponent }, { - path: 'second', - component: SecondComponent + path: 'translator', + component: NitroplusComponent } ] }, diff --git a/apps/NwaifuWeb/src/app/modules/desktop-icon/desktop-icon.component.ts b/apps/NwaifuWeb/src/app/modules/desktop-icon/desktop-icon.component.ts index bb10804..d824f70 100644 --- a/apps/NwaifuWeb/src/app/modules/desktop-icon/desktop-icon.component.ts +++ b/apps/NwaifuWeb/src/app/modules/desktop-icon/desktop-icon.component.ts @@ -13,4 +13,5 @@ export class DesktopIconComponent { @Input() image: string = ''; @Input() alt: string = ''; @Input() name: string = ''; + @Input({required: false}) click: ()=>void = ()=>{}; } diff --git a/apps/NwaifuWeb/src/app/pages/main/main.component.html b/apps/NwaifuWeb/src/app/pages/main/main.component.html index c4c9f25..5deb67b 100644 --- a/apps/NwaifuWeb/src/app/pages/main/main.component.html +++ b/apps/NwaifuWeb/src/app/pages/main/main.component.html @@ -1,3 +1,5 @@ - +
+ +
diff --git a/apps/NwaifuWeb/src/app/pages/main/main.component.less b/apps/NwaifuWeb/src/app/pages/main/main.component.less index e69de29..9aab23e 100644 --- a/apps/NwaifuWeb/src/app/pages/main/main.component.less +++ b/apps/NwaifuWeb/src/app/pages/main/main.component.less @@ -0,0 +1,9 @@ +.icons { + margin: 2rem 3rem; + position: absolute; +} +:host { + display: block; + width: 100%; + height: 100%; +} diff --git a/apps/NwaifuWeb/src/app/pages/main/main.component.ts b/apps/NwaifuWeb/src/app/pages/main/main.component.ts index d126033..5c340f9 100644 --- a/apps/NwaifuWeb/src/app/pages/main/main.component.ts +++ b/apps/NwaifuWeb/src/app/pages/main/main.component.ts @@ -1,5 +1,6 @@ import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; +import { RouterLink } from '@angular/router'; import { DesktopIconComponent } from '../../modules/desktop-icon/desktop-icon.component'; import { DockComponent } from '../../modules/dock/dock.component'; import { ModalComponent } from '../../modules/modal/modal.component'; @@ -8,7 +9,7 @@ import { ModalComponent } from '../../modules/modal/modal.component'; selector: 'app-main-page', templateUrl: './main.component.html', styleUrls: ['./main.component.less'], - imports: [DockComponent, ModalComponent, CommonModule, DesktopIconComponent], + imports: [DockComponent, ModalComponent, CommonModule, DesktopIconComponent, RouterLink], standalone: true }) export class MainPageComponent {} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.html b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.html new file mode 100644 index 0000000..2040557 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.html @@ -0,0 +1,6 @@ +

Всего: {{ elements_data.length }}

+
+ @for(item of elements_data; track $index) { + + } +
diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.scss b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.scss new file mode 100644 index 0000000..e9d9f05 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.scss @@ -0,0 +1,25 @@ +#elements { + display: flex; + flex-direction: column; + gap: 3rem; + align-items: center; + margin-inline: 2rem; +} + +// fix scroll on router click +:host { + overflow-y: scroll; + height: fit-content; +} + +h1 { + color: #efdee0; + text-align: center; + margin: 1rem 2rem; +} +app-translate-block { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.ts new file mode 100644 index 0000000..a6e130c --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/text_list/text_list.component.ts @@ -0,0 +1,24 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input, QueryList, ViewChildren } from '@angular/core'; +import { TranslateData } from '../../dto/translate_data.dto'; +import { TranslateBlockComponent } from '../translate_block/translate_block.component'; + +@Component({ + selector: 'app-text-list', + templateUrl: './text_list.component.html', + styleUrls: ['./text_list.component.scss'], + standalone: true, + imports: [CommonModule, TranslateBlockComponent], +}) +export class TextListComponent { + @ViewChildren('translateBlock') translate_blocks: QueryList | null = null; + elements_data: TranslateData[] = []; + @Input() set elements(el: TranslateData[]) { + this.elements_data = el; + localStorage.setItem('translations', JSON.stringify(this.elements_data)); + } + + get elements() { + return this.elements_data; + } +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.html b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.html new file mode 100644 index 0000000..7c60d57 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.html @@ -0,0 +1,18 @@ +
+

{{ index + 1 }}

+
+ {{ item.english_text }} + {{ item.translated_text }} +
+
+ Translate + Edit + Clear +
+
diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.scss b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.scss new file mode 100644 index 0000000..6c2a4ac --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.scss @@ -0,0 +1,39 @@ +.element { + display: flex; + background-color: #413738; + padding: 3rem 5rem; + border-radius: 30px; + flex-direction: row; + width: 100%; + max-width: 1200px; + align-items: center; + gap: 2rem; + justify-content: space-between; + h2 { + color: #efdee0; + } + .fields { + display: flex; + flex-direction: column; + gap: 1rem; + width: 100%; + max-width: 1200px; + } +} + +@media (max-width: 768px) { + .element { + flex-direction: column; + } +} + +.btns { + display: flex; + flex-direction: column; + gap: 1rem; + align-items: center; + padding-inline: 1rem; + nwui-button { + width: 100%; + } +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.ts new file mode 100644 index 0000000..58520b1 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/components/translate_block/translate_block.component.ts @@ -0,0 +1,75 @@ +import { CommonModule } from '@angular/common'; +import { Component, Input, OnInit, ViewChild } from '@angular/core'; +import { NWUIButtonComponent, NWUITextAreaComponent } from '@nwaifu-ui'; +import { LocalStorageKeys } from '../../consts'; +import { TranslateData } from '../../dto/translate_data.dto'; +import { ETranslateService } from '../../services/translate.enums'; +import { TranslateService } from '../../services/translate.service'; + +@Component({ + selector: 'app-translate-block', + templateUrl: './translate_block.component.html', + styleUrls: ['./translate_block.component.scss'], + standalone: true, + imports: [CommonModule, NWUIButtonComponent, NWUITextAreaComponent], + providers: [TranslateService], +}) +export class TranslateBlockComponent implements OnInit { + @ViewChild('translatedText') translatedText: NWUITextAreaComponent | null = null; + @Input({ required: true }) item: TranslateData = { english_text: '', translated_text: '' }; + @Input({ required: true }) index = 0; + translateLoading = false; + isEditing = false; + + saveChanges() { + const data: TranslateData[] = JSON.parse(localStorage.getItem(LocalStorageKeys.TRANSLATIONS) ?? '[]'); + if (!data.length) { + alert('No data'); + return; + } + data[this.index] = this.item; + localStorage.setItem('translations', JSON.stringify(data)); + } + + ngOnInit(): void { + this.isEditing = this.item.translated_text === ''; + } + + constructor(private translateService: TranslateService) {} + + private sendToTranslate(service: ETranslateService = ETranslateService.GOOGLE) { + this.translateLoading = true; + this.translateService.translate(this.item.english_text, service).subscribe((text) => { + if (this.translatedText) if (this.translatedText.ref) this.translatedText.ref.nativeElement.textContent = text; + this.item.translated_text = text; + this.isEditing = false; + this.translateLoading = false; + this.saveChanges(); + }); + } + + sendToGoogleTranslate() { + this.sendToTranslate(ETranslateService.GOOGLE); + } + + sendToDeeplTranslate() { + this.sendToTranslate(ETranslateService.DEEPL); + } + + sendToPromptTranslate() { + this.sendToTranslate(ETranslateService.PROMPT); + } + + saveTranslate(text: string) { + this.isEditing = false; + if (this.translatedText) if (this.translatedText.ref) this.translatedText.ref.nativeElement.textContent = ''; + this.item.translated_text = text; + this.saveChanges(); + } + clear() { + this.item.translated_text = ''; + this.isEditing = true; + if (this.translatedText) if (this.translatedText.ref) this.translatedText.ref.nativeElement.textContent = ''; + this.saveChanges(); + } +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/consts.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/consts.ts new file mode 100644 index 0000000..c55e089 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/consts.ts @@ -0,0 +1,4 @@ +export enum LocalStorageKeys { + TRANSLATIONS = 'translations', + ORIGINAL_FILE = 'original_file', +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/dto/translate_data.dto.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/dto/translate_data.dto.ts new file mode 100644 index 0000000..9e4ed71 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/dto/translate_data.dto.ts @@ -0,0 +1,9 @@ +export interface TranslateData { + english_text: string; + translated_text: string; +} +export interface NpsFile { + file_name: string; + original_text: string; + translated_text?: string; +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/lib/file_tools.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/lib/file_tools.ts new file mode 100644 index 0000000..7e3c721 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/lib/file_tools.ts @@ -0,0 +1,6 @@ +import { LocalStorageKeys } from '../consts'; +import { NpsFile } from '../dto/translate_data.dto'; + +export function saveOriginalFile(file: NpsFile) { + localStorage.setItem(LocalStorageKeys.ORIGINAL_FILE, JSON.stringify(file)); +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/lib/parser.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/lib/parser.ts new file mode 100644 index 0000000..17e399a --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/lib/parser.ts @@ -0,0 +1,15 @@ +import { TranslateData } from '../dto/translate_data.dto'; + +export function parse(text: string): TranslateData[] { + const replaced_text = text + .replace('/<[kK]{1}>/gm', '\n') + .replace(/(<[^>]*>|\/\/.*)/gm, '') + .replace(/\s*\n\s*/gm, '\n'); + const result = replaced_text + .split('\n') + .map((line) => line.trim()) + .filter((line) => line.length > 0) + .map((line) => ({ english_text: line, translated_text: '' })); + console.log(result); + return result; +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.html b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.html new file mode 100644 index 0000000..9d6327c --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.html @@ -0,0 +1,21 @@ +
+ + Upload + + + + Save + + @if (this.elements.length){ + + Clear translations + + + Translate all + + + Clear + + } +
+ diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.less b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.less new file mode 100644 index 0000000..3a1b149 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.less @@ -0,0 +1,14 @@ +.btns { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + nwui-button { + margin: 2rem; + } +} +:host { + background-color: #191113; + display: block; + min-height: calc(100vh - 2rem); +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.ts new file mode 100644 index 0000000..c81af26 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/nitroplus-translator.component.ts @@ -0,0 +1,108 @@ +import { CommonModule } from '@angular/common'; +import { Component, OnInit, ViewChild } from '@angular/core'; +import { NWUIButtonComponent } from '@nwaifu-ui'; +import { TextListComponent } from './components/text_list/text_list.component'; +import { LocalStorageKeys } from './consts'; +import { NpsFile, TranslateData } from './dto/translate_data.dto'; +import { saveOriginalFile } from './lib/file_tools'; +import { parse } from './lib/parser'; +@Component({ + standalone: true, + imports: [TextListComponent, CommonModule, NWUIButtonComponent], + selector: 'app-nitroplus', + templateUrl: './nitroplus-translator.component.html', + styleUrl: './nitroplus-translator.component.less', +}) +export class NitroplusComponent implements OnInit { + title = 'NitroPlusTranslator'; + elements: TranslateData[] = []; + @ViewChild('fileInput') fileInput: HTMLInputElement | null = null; + @ViewChild(TextListComponent) text_list: TextListComponent | null = null; + + ngOnInit(): void { + const data = localStorage.getItem(LocalStorageKeys.TRANSLATIONS); + if (data) { + try { + this.elements = JSON.parse(data); + } catch (e) { + console.error(e); + alert('Error while loading'); + localStorage.removeItem(LocalStorageKeys.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()); + const original_file: NpsFile = { + file_name: file.name, + original_text: reader.result.toString(), + }; + saveOriginalFile(original_file); + target.value = ''; + } + }; + reader.readAsText(file); + } + } + } + + onFileLoaded(text: string) { + const parsed = parse(text); + this.elements = parsed; + } + + onClearClicked() { + this.elements = []; + localStorage.removeItem(LocalStorageKeys.TRANSLATIONS); + } + + onSaveClicked() { + const original_file: NpsFile = JSON.parse( + localStorage.getItem(LocalStorageKeys.ORIGINAL_FILE) ?? '{"file_name":"", "original_text":""}', + ); + if (original_file.file_name && original_file.original_text) { + const data: TranslateData[] = JSON.parse(localStorage.getItem(LocalStorageKeys.TRANSLATIONS) ?? '[]'); + if (!data.length) { + alert('No data'); + return; + } + original_file.translated_text = original_file.original_text; + data.forEach((el) => { + original_file.translated_text = original_file.translated_text?.replace(el.english_text, el.translated_text); + }); + + const element = document.createElement('a'); + const file = new Blob([original_file.translated_text], { type: 'text/plain' }); + element.href = URL.createObjectURL(file); + element.download = original_file.file_name; + element.click(); + } + } + + //TODO: Dialog windows for clear op + clearAllTranslations() { + if (this.text_list) + if (this.text_list.translate_blocks) { + this.text_list.translate_blocks.filter((item) => item.item.translated_text).forEach((item) => item.clear()); + } + } + + getAllTranslations() { + if (this.text_list) + if (this.text_list.translate_blocks) + this.text_list.translate_blocks.forEach((item) => item.sendToGoogleTranslate()); + } + + get has_translations(): boolean { + return this.elements.some((i) => i.translated_text); + } +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.dto.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.dto.ts new file mode 100644 index 0000000..550d3c5 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.dto.ts @@ -0,0 +1 @@ +export type GoogleTranslateResponse = Array>; diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.enums.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.enums.ts new file mode 100644 index 0000000..ebf02ef --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.enums.ts @@ -0,0 +1,5 @@ +export enum ETranslateService { + GOOGLE = 'google', + DEEPL = 'deepl', + PROMPT = 'prompt', +} diff --git a/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.service.ts b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.service.ts new file mode 100644 index 0000000..ca5c693 --- /dev/null +++ b/apps/NwaifuWeb/src/app/pages/nitroplus-translator/services/translate.service.ts @@ -0,0 +1,34 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, map } from 'rxjs'; +import { GoogleTranslateResponse } from './translate.dto'; +import { ETranslateService } from './translate.enums'; + +@Injectable({ providedIn: 'root' }) +export class TranslateService { + constructor(private http: HttpClient) {} + + private googleTranslate(text: string): Observable { + return this.http + .get( + 'https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=ru&dt=t&q=' + encodeURIComponent(text), + ) + .pipe( + map((response) => { + let result = ''; + response[0].forEach((el) => { + result += el[0] + ' '; + }); + return result; + }), + ); + } + translate(text: string, service: ETranslateService = ETranslateService.GOOGLE): Observable { + switch (service) { + case ETranslateService.GOOGLE: + return this.googleTranslate(text); + default: + return this.googleTranslate(text); + } + } +} diff --git a/apps/NwaifuWeb/src/app/pages/second/second.component.html b/apps/NwaifuWeb/src/app/pages/second/second.component.html deleted file mode 100644 index e583759..0000000 --- a/apps/NwaifuWeb/src/app/pages/second/second.component.html +++ /dev/null @@ -1 +0,0 @@ -

Test

diff --git a/apps/NwaifuWeb/src/app/pages/second/second.component.less b/apps/NwaifuWeb/src/app/pages/second/second.component.less deleted file mode 100644 index e69de29..0000000 diff --git a/apps/NwaifuWeb/src/app/pages/second/second.component.ts b/apps/NwaifuWeb/src/app/pages/second/second.component.ts deleted file mode 100644 index bb9e7d5..0000000 --- a/apps/NwaifuWeb/src/app/pages/second/second.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-second', - templateUrl: './second.component.html', - styleUrls: ['./second.component.less'], - standalone: true, - imports: [CommonModule] -}) -export class SecondComponent { -} diff --git a/apps/NwaifuWeb/src/index.html b/apps/NwaifuWeb/src/index.html index 0a020d7..a516642 100644 --- a/apps/NwaifuWeb/src/index.html +++ b/apps/NwaifuWeb/src/index.html @@ -6,6 +6,7 @@ + diff --git a/apps/NwaifuWeb/src/styles.less b/apps/NwaifuWeb/src/styles.less index 722c3c2..307b72a 100644 --- a/apps/NwaifuWeb/src/styles.less +++ b/apps/NwaifuWeb/src/styles.less @@ -27,6 +27,7 @@ } html { position: relative; + height: 100%; } body { width: 100%; diff --git a/apps/NwaifuWeb/tsconfig.app.json b/apps/NwaifuWeb/tsconfig.app.json index b4f8687..fff4a41 100644 --- a/apps/NwaifuWeb/tsconfig.app.json +++ b/apps/NwaifuWeb/tsconfig.app.json @@ -1,9 +1,10 @@ { - "extends": "../../tsconfig.base.json", + "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../../dist/out-tsc", "types": [] }, "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"] + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] } diff --git a/apps/NwaifuWeb/tsconfig.editor.json b/apps/NwaifuWeb/tsconfig.editor.json new file mode 100644 index 0000000..a8ac182 --- /dev/null +++ b/apps/NwaifuWeb/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/NwaifuWeb/tsconfig.json b/apps/NwaifuWeb/tsconfig.json new file mode 100644 index 0000000..4acc9dd --- /dev/null +++ b/apps/NwaifuWeb/tsconfig.json @@ -0,0 +1,33 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..6506630 Binary files /dev/null and b/bun.lockb differ diff --git a/migrations.json b/migrations.json new file mode 100644 index 0000000..34d2c61 --- /dev/null +++ b/migrations.json @@ -0,0 +1,64 @@ +{ + "migrations": [ + { + "cli": "nx", + "version": "19.2.0-beta.2", + "description": "Updates the default workspace data directory to .nx/workspace-data", + "implementation": "./src/migrations/update-19-2-0/move-workspace-data-directory", + "package": "nx", + "name": "19-2-0-move-graph-cache-directory" + }, + { + "cli": "nx", + "version": "19.2.2-beta.0", + "description": "Updates the nx wrapper.", + "implementation": "./src/migrations/update-17-3-0/update-nxw", + "package": "nx", + "name": "19-2-2-update-nx-wrapper" + }, + { + "version": "19.2.4-beta.0", + "description": "Set project name in nx.json explicitly", + "implementation": "./src/migrations/update-19-2-4/set-project-name", + "x-repair-skip": true, + "package": "nx", + "name": "19-2-4-set-project-name" + }, + { + "cli": "nx", + "version": "19.1.0-beta.2", + "requires": { + "@angular/core": ">=18.0.0" + }, + "description": "Update the @angular/cli package version to ~18.0.0.", + "factory": "./src/migrations/update-19-1-0/update-angular-cli", + "package": "@nx/angular", + "name": "update-angular-cli-version-18-0-0" + }, + { + "cli": "nx", + "version": "19.2.1-beta.0", + "requires": { + "@angular-eslint/eslint-plugin": ">=18.0.0" + }, + "description": "Installs the '@typescript-eslint/utils' package when having installed '@angular-eslint/eslint-plugin' or '@angular-eslint/eslint-plugin-template' with version >=18.0.0.", + "factory": "./src/migrations/update-19-2-1/add-typescript-eslint-utils", + "package": "@nx/angular", + "name": "add-typescript-eslint-utils" + }, + { + "version": "18.0.0", + "description": "Updates two-way bindings that have an invalid expression to use the longform expression instead.", + "factory": "./migrations/invalid-two-way-bindings/bundle", + "package": "@angular/core", + "name": "invalid-two-way-bindings" + }, + { + "version": "18.0.0", + "description": "Replace deprecated HTTP related modules with provider functions", + "factory": "./migrations/http-providers/bundle", + "package": "@angular/core", + "name": "migration-http-providers" + } + ] +} \ No newline at end of file diff --git a/nwaifu-ui/.eslintrc.json b/nwaifu-ui/.eslintrc.json new file mode 100644 index 0000000..50cbc22 --- /dev/null +++ b/nwaifu-ui/.eslintrc.json @@ -0,0 +1,46 @@ +{ + "extends": [ + "../.eslintrc.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": {} + } + ] +} 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/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/nwaifu-ui/src/lib/components/button/button.component.scss b/nwaifu-ui/src/lib/components/button/button.component.scss new file mode 100644 index 0000000..76dc2f7 --- /dev/null +++ b/nwaifu-ui/src/lib/components/button/button.component.scss @@ -0,0 +1,23 @@ +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; + width: 100%; + &: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..1ecf567 --- /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 NWUIButtonComponent { + @Input() disabled = false; + @Input() type = 'button'; +} 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..770f736 --- /dev/null +++ b/nwaifu-ui/src/lib/components/index.ts @@ -0,0 +1,2 @@ +export * from './button'; +export * from './textarea'; diff --git a/nwaifu-ui/src/lib/components/textarea/index.ts b/nwaifu-ui/src/lib/components/textarea/index.ts new file mode 100644 index 0000000..8457e35 --- /dev/null +++ b/nwaifu-ui/src/lib/components/textarea/index.ts @@ -0,0 +1 @@ +export * from './textarea.component'; diff --git a/nwaifu-ui/src/lib/components/textarea/textarea.component.html b/nwaifu-ui/src/lib/components/textarea/textarea.component.html new file mode 100644 index 0000000..611e770 --- /dev/null +++ b/nwaifu-ui/src/lib/components/textarea/textarea.component.html @@ -0,0 +1,5 @@ +
+ @if(!value) { + + } +
diff --git a/nwaifu-ui/src/lib/components/textarea/textarea.component.scss b/nwaifu-ui/src/lib/components/textarea/textarea.component.scss new file mode 100644 index 0000000..3eeba0f --- /dev/null +++ b/nwaifu-ui/src/lib/components/textarea/textarea.component.scss @@ -0,0 +1,20 @@ +.nwui-textarea { + border-radius: 8px; + height: auto; + color: #efdee0; + outline: none; + padding-inline: 2rem 1rem; + background-color: transparent; + border: 2px solid #e4bdc3; + font-size: 1rem; + font-weight: inherit; + min-height: 3rem; + line-height: 3rem; + &:focus { + border: 2px solid #efdee0; + } + &.disabled { + opacity: 0.5; + } + word-wrap: break-word; +} diff --git a/nwaifu-ui/src/lib/components/textarea/textarea.component.ts b/nwaifu-ui/src/lib/components/textarea/textarea.component.ts new file mode 100644 index 0000000..a560f69 --- /dev/null +++ b/nwaifu-ui/src/lib/components/textarea/textarea.component.ts @@ -0,0 +1,35 @@ +import { CommonModule } from '@angular/common'; +import { AfterViewInit, Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; + +@Component({ + selector: 'nwui-textarea', + imports: [CommonModule], + standalone: true, + styleUrls: ['./textarea.component.scss'], + templateUrl: './textarea.component.html', + // changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class NWUITextAreaComponent implements AfterViewInit { + @Input() disabled = false; + @Input() value = ''; + @Input() contenteditable = true; + @Output() leave = new EventEmitter(); + @ViewChild('ref') ref: ElementRef | null = null; + + get className(): string { + return `nwui-textarea ${this.disabled && !this.contenteditable ? 'disabled' : ''}`; + } + + leaveFn() { + if (this.ref) { + const target = this.ref.nativeElement; + const text = target.textContent || ''; + if (this.leave) this.leave.emit(text); + target.textContent = text; + } + } + + ngAfterViewInit(): void { + if (this.ref && this.value) this.ref.nativeElement.textContent = this.value; + } +} 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/tsconfig.json b/nwaifu-ui/tsconfig.json new file mode 100644 index 0000000..1913c1f --- /dev/null +++ b/nwaifu-ui/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "esModuleInterop": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.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/package.json b/package.json index 1ded4cb..5e35f00 100644 --- a/package.json +++ b/package.json @@ -11,44 +11,47 @@ }, "private": true, "dependencies": { - "@angular/animations": "^17.2.0", - "@angular/common": "^17.2.0", - "@angular/compiler": "^17.2.0", - "@angular/core": "^17.2.0", - "@angular/forms": "^17.2.0", - "@angular/platform-browser": "^17.2.0", - "@angular/platform-browser-dynamic": "^17.2.0", - "@angular/router": "^17.2.0", + "@angular/animations": "18.0.3", + "@angular/common": "18.0.3", + "@angular/compiler": "18.0.3", + "@angular/core": "18.0.3", + "@angular/forms": "18.0.3", + "@angular/platform-browser": "18.0.3", + "@angular/platform-browser-dynamic": "18.0.3", + "@angular/router": "18.0.3", "@fortawesome/angular-fontawesome": "0.14.1", "@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/free-brands-svg-icons": "^6.4.2", "@fortawesome/free-regular-svg-icons": "^6.4.2", "@fortawesome/free-solid-svg-icons": "^6.4.2", "@ngneat/dialog": "5.0.0", + "@nx/eslint-plugin": "^19.3.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" }, "devDependencies": { - "@angular-devkit/build-angular": "^17.2.2", - "@angular-devkit/core": "^17.2.2", - "@angular-devkit/schematics": "^17.2.2", - "@angular-eslint/eslint-plugin": "17.2.1", - "@angular-eslint/eslint-plugin-template": "17.2.1", - "@angular-eslint/template-parser": "17.2.1", - "@angular/cli": "^17.2.2", - "@angular/compiler-cli": "^17.2.0", - "@nx/angular": "19.0.2", - "@nx/eslint": "19.0.2", - "@nx/js": "19.0.2", - "@nx/workspace": "19.0.2", - "@schematics/angular": "^17.2.2", - "@swc-node/register": "~1.8.0", - "@swc/core": "~1.3.85", - "@swc/helpers": "~0.5.2", + "@angular-devkit/build-angular": "18.0.5", + "@angular-devkit/core": "18.0.5", + "@angular-devkit/schematics": "18.0.5", + "@angular-eslint/eslint-plugin": "18.0.1", + "@angular-eslint/eslint-plugin-template": "18.0.1", + "@angular-eslint/template-parser": "18.0.1", + "@angular/cli": "~18.0.0", + "@angular/compiler-cli": "18.0.3", + "@nx/angular": "19.3.0", + "@nx/eslint": "19.3.0", + "@nx/js": "19.3.0", + "@nx/workspace": "19.3.0", + "@schematics/angular": "18.0.5", + "@swc-node/register": "1.9.2", + "@swc/core": "1.5.7", + "@swc/helpers": "0.5.11", + "@types/bun": "latest", "@types/jasmine": "~5.1.0", "@typescript-eslint/eslint-plugin": "6.19.0", "@typescript-eslint/parser": "6.19.0", + "@typescript-eslint/utils": "^8.0.0-alpha.28", "autoprefixer": "^10.4.18", "eslint": "~8.57.0", "jasmine-core": "~5.1.0", @@ -57,10 +60,10 @@ "karma-coverage": "~2.2.0", "karma-jasmine": "~5.1.0", "karma-jasmine-html-reporter": "~2.1.0", - "nx": "19.0.2", - "postcss": "^8.4.35", - "prettier": "^2.6.2", + "nx": "19.3.0", + "postcss": "^8.4.38", + "prettier": "^3.3.2", "tailwindcss": "^3.4.1", - "typescript": "~5.3.2" + "typescript": "~5.4.5" } } diff --git a/tsconfig.base.json b/tsconfig.base.json index 90e46ea..6b2eacc 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,33 +1,24 @@ { "compileOnSave": false, "compilerOptions": { - "outDir": "./dist/out-tsc", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "skipLibCheck": true, - "esModuleInterop": true, "sourceMap": true, "declaration": false, + "moduleResolution": "Node", + "emitDecoratorMetadata": true, "experimentalDecorators": true, - "moduleResolution": "node", "importHelpers": true, - "target": "ES2022", - "module": "ES2022", - "useDefineForClassFields": false, - "lib": ["ES2022", "dom"], - "paths": {}, + "target": "ES2015", + "module": "ESNext", + "lib": ["es2020", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "paths": { + "@nwaifu-ui": [ + "nwaifu-ui/src/index.ts" + ] + }, "baseUrl": ".", "rootDir": "." }, - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - }, "exclude": ["node_modules", "tmp"] }