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"]
}