From 8cd5dd1f8e5256e5777ea7bea2a92ad20c4758a0 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Sat, 9 Mar 2024 18:16:20 +0300 Subject: [PATCH 1/3] Added info modal window --- package.json | 1 + pnpm-lock.yaml | 18 ++++++++++-- src/app/app.component.html | 1 + src/app/app.component.less | 5 ++-- src/app/app.component.ts | 3 +- src/app/modules/modal/modal.component.html | 1 + src/app/modules/modal/modal.component.less | 0 src/app/modules/modal/modal.component.ts | 29 ++++++++++++++++++++ src/app/modules/panel/panel.component.less | 1 + src/app/modules/window/window.component.html | 10 +++++++ src/app/modules/window/window.component.less | 24 ++++++++++++++++ src/app/modules/window/window.component.ts | 19 +++++++++++++ src/styles.less | 21 ++++++++++++++ 13 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 src/app/modules/modal/modal.component.html create mode 100644 src/app/modules/modal/modal.component.less create mode 100644 src/app/modules/modal/modal.component.ts create mode 100644 src/app/modules/window/window.component.html create mode 100644 src/app/modules/window/window.component.less create mode 100644 src/app/modules/window/window.component.ts diff --git a/package.json b/package.json index 0dc91bf..9d625ee 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@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", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b26c8b9..45ad71a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ dependencies: '@fortawesome/free-solid-svg-icons': specifier: ^6.4.2 version: 6.5.1 + '@ngneat/dialog': + specifier: 5.0.0 + version: 5.0.0(@angular/core@17.2.3) rxjs: specifier: ~7.8.0 version: 7.8.1 @@ -2433,6 +2436,15 @@ packages: call-bind: 1.0.7 dev: true + /@ngneat/dialog@5.0.0(@angular/core@17.2.3): + resolution: {integrity: sha512-+qLGaLcNXQ5PVtlv4htqHsJ4JV9TZ+wy89rtYMsno/jZuB63usMITPEB7TgtEPgpbyDDcYVagA6eQqYMEgZPOA==} + peerDependencies: + '@angular/core': '>=17.0.0' + dependencies: + '@angular/core': 17.2.3(rxjs@7.8.1)(zone.js@0.14.4) + tslib: 2.3.1 + dev: false + /@ngtools/webpack@17.2.2(@angular/compiler-cli@17.2.3)(typescript@5.3.3)(webpack@5.90.1): resolution: {integrity: sha512-HgvClGO6WVq4VA5d0ZvlDG5hrj8lQzRH99Gt87URm7G8E5XkatysdOsMqUQsJz+OwFWhP4PvTRWVblpBDiDl/A==} engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -5893,8 +5905,6 @@ packages: peerDependenciesMeta: webpack: optional: true - webpack-sources: - optional: true dependencies: webpack: 5.90.1(esbuild@0.20.0) webpack-sources: 3.2.3 @@ -8054,6 +8064,10 @@ packages: strip-bom: 3.0.0 dev: true + /tslib@2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + dev: false + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} diff --git a/src/app/app.component.html b/src/app/app.component.html index 72a5291..5496f27 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -2,5 +2,6 @@
+
diff --git a/src/app/app.component.less b/src/app/app.component.less index ff8bb98..7e65688 100644 --- a/src/app/app.component.less +++ b/src/app/app.component.less @@ -2,6 +2,7 @@ display: block; width: 100%; height: calc(100% - 2rem); - background: url("../assets/img/wallpaper.png"); - background-size: cover; + background-image: url("../assets/img/wallpaper.png"); + background-repeat: no-repeat; + background-size: 100% 100%; } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 0b7248f..44b6132 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,12 +1,13 @@ import { Component } from "@angular/core"; import { RouterOutlet } from "@angular/router"; import { DockComponent } from "./modules/dock/dock.component"; +import { ModalComponent } from "./modules/modal/modal.component"; import { PanelComponent } from "./modules/panel/panel.component"; @Component({ selector: "app-root", standalone: true, - imports: [RouterOutlet, PanelComponent, DockComponent], + imports: [RouterOutlet, PanelComponent, DockComponent, ModalComponent], templateUrl: "./app.component.html", styleUrl: "./app.component.less", }) diff --git a/src/app/modules/modal/modal.component.html b/src/app/modules/modal/modal.component.html new file mode 100644 index 0000000..c69b526 --- /dev/null +++ b/src/app/modules/modal/modal.component.html @@ -0,0 +1 @@ + diff --git a/src/app/modules/modal/modal.component.less b/src/app/modules/modal/modal.component.less new file mode 100644 index 0000000..e69de29 diff --git a/src/app/modules/modal/modal.component.ts b/src/app/modules/modal/modal.component.ts new file mode 100644 index 0000000..48e75e3 --- /dev/null +++ b/src/app/modules/modal/modal.component.ts @@ -0,0 +1,29 @@ +import { CommonModule } from "@angular/common"; +import { AfterViewInit, Component, ElementRef, ViewChild } from "@angular/core"; +import { DialogRef, DialogService } from "@ngneat/dialog"; +import { WindowComponent } from "../window/window.component"; + +@Component({ + selector: "app-modal", + templateUrl: "./modal.component.html", + styleUrls: ["./modal.component.less"], + imports: [CommonModule], + standalone: true, +}) +export class ModalComponent implements AfterViewInit { + dialogRef: DialogRef | undefined = undefined; + @ViewChild("modal") modal: ElementRef | undefined = undefined; + constructor(private dialogService: DialogService, private ref: ElementRef) {} + ngAfterViewInit(): void { + this.dialogRef = this.dialogService.open(WindowComponent, { + resizable: true, + draggable: true, + backdrop: false, + closeButton: false, + container: this.modal ?? this.ref, + enableClose: false, + dragConstraint: "constrain", + id: "info-modal", + }); + } +} diff --git a/src/app/modules/panel/panel.component.less b/src/app/modules/panel/panel.component.less index 9238921..6eafcac 100644 --- a/src/app/modules/panel/panel.component.less +++ b/src/app/modules/panel/panel.component.less @@ -1,4 +1,5 @@ .panel { + z-index: 99999; position: relative; left: 0; top: 0; diff --git a/src/app/modules/window/window.component.html b/src/app/modules/window/window.component.html new file mode 100644 index 0000000..1239aa1 --- /dev/null +++ b/src/app/modules/window/window.component.html @@ -0,0 +1,10 @@ +
+ Info +
+ + +
+
+
+

Hello

+
diff --git a/src/app/modules/window/window.component.less b/src/app/modules/window/window.component.less new file mode 100644 index 0000000..59f4306 --- /dev/null +++ b/src/app/modules/window/window.component.less @@ -0,0 +1,24 @@ +.panel { + width: 100%; + display: flex; + height: 3rem; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 0 1rem; + background-color: var(--black); + color: var(--white); + span { + font-size: 600; + } + .btns { + display: flex; + flex-direction: row; + justify-content: flex-end; + align-items: center; + gap: 1rem; + } +} +.content { + margin: 1rem; +} diff --git a/src/app/modules/window/window.component.ts b/src/app/modules/window/window.component.ts new file mode 100644 index 0000000..df6ec48 --- /dev/null +++ b/src/app/modules/window/window.component.ts @@ -0,0 +1,19 @@ +import { CommonModule } from "@angular/common"; +import { ChangeDetectionStrategy, Component } from "@angular/core"; +import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; +import { faBars, faXmark } from "@fortawesome/free-solid-svg-icons"; +import { DialogRef } from "@ngneat/dialog"; + +@Component({ + selector: "app-window", + standalone: true, + imports: [CommonModule, FontAwesomeModule], + templateUrl: "./window.component.html", + styleUrls: ["./window.component.less"], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class WindowComponent { + faClose = faXmark; + faMenu = faBars; + constructor(public ref: DialogRef) {} +} diff --git a/src/styles.less b/src/styles.less index 20a20f3..220ca4a 100644 --- a/src/styles.less +++ b/src/styles.less @@ -35,3 +35,24 @@ body { top: 0; left: 0; } +ngneat-dialog { + .ngneat-dialog-backdrop { + pointer-events: none; + .ngneat-dialog-content { + pointer-events: all; + border-radius: 10px; + span { + font-weight: 600; + user-select: none; + } + .btns { + fa-icon { + cursor: pointer; + } + } + .ngneat-drag-marker { + height: 3rem; + } + } + } +} -- 2.49.1 From a9436a5af721675dadcfd6278339ad97f3c158ab Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Sat, 9 Mar 2024 18:25:06 +0300 Subject: [PATCH 2/3] Min sizes --- src/app/modules/modal/modal.component.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/modules/modal/modal.component.ts b/src/app/modules/modal/modal.component.ts index 48e75e3..48fd4ae 100644 --- a/src/app/modules/modal/modal.component.ts +++ b/src/app/modules/modal/modal.component.ts @@ -24,6 +24,8 @@ export class ModalComponent implements AfterViewInit { enableClose: false, dragConstraint: "constrain", id: "info-modal", + minWidth: "300px", + minHeight: "10rem", }); } } -- 2.49.1 From 90582949d5e0197150c136a1ce58d5477f4f1b53 Mon Sep 17 00:00:00 2001 From: Sergey Elpashev Date: Sun, 10 Mar 2024 00:14:00 +0300 Subject: [PATCH 3/3] Added i18n translations --- src/app/app.component.ts | 3 +- src/app/app.config.ts | 24 ++++++++++-- src/app/modules/dock/dock.component.ts | 6 +-- src/app/modules/link/link.component.html | 2 +- src/app/modules/link/link.component.ts | 3 +- src/app/modules/panel/panel.component.html | 14 ++++++- src/app/modules/panel/panel.component.less | 40 ++++++++++++++++++++ src/app/modules/panel/panel.component.ts | 38 +++++++++++++++++-- src/app/modules/window/window.component.html | 4 +- src/app/modules/window/window.component.ts | 9 +++-- src/app/pipes/translation.pipe.ts | 14 +++++++ src/app/services/translate.service.ts | 30 +++++++++++++++ src/assets/i18n/en.json | 8 ++++ src/assets/i18n/ja.json | 8 ++++ src/assets/i18n/ru.json | 8 ++++ 15 files changed, 191 insertions(+), 20 deletions(-) create mode 100644 src/app/pipes/translation.pipe.ts create mode 100644 src/app/services/translate.service.ts create mode 100644 src/assets/i18n/en.json create mode 100644 src/assets/i18n/ja.json create mode 100644 src/assets/i18n/ru.json diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 44b6132..876f596 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,4 @@ import { Component } from "@angular/core"; -import { RouterOutlet } from "@angular/router"; import { DockComponent } from "./modules/dock/dock.component"; import { ModalComponent } from "./modules/modal/modal.component"; import { PanelComponent } from "./modules/panel/panel.component"; @@ -7,7 +6,7 @@ import { PanelComponent } from "./modules/panel/panel.component"; @Component({ selector: "app-root", standalone: true, - imports: [RouterOutlet, PanelComponent, DockComponent, ModalComponent], + imports: [PanelComponent, DockComponent, ModalComponent], templateUrl: "./app.component.html", styleUrl: "./app.component.less", }) diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 6c6ef60..2af3ac9 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,8 +1,24 @@ -import { ApplicationConfig } from '@angular/core'; -import { provideRouter } from '@angular/router'; +import { APP_INITIALIZER, ApplicationConfig } from "@angular/core"; +import { provideRouter } from "@angular/router"; -import { routes } from './app.routes'; +import { provideHttpClient } from "@angular/common/http"; +import { routes } from "./app.routes"; +import { TranslateService } from "./services/translate.service"; + +export function setupTranslateServiceFactory(service: TranslateService) { + return () => service.use("en"); +} export const appConfig: ApplicationConfig = { - providers: [provideRouter(routes)] + providers: [ + provideRouter(routes), + provideHttpClient(), + TranslateService, + { + provide: APP_INITIALIZER, + useFactory: setupTranslateServiceFactory, + deps: [TranslateService], + multi: true, + }, + ], }; diff --git a/src/app/modules/dock/dock.component.ts b/src/app/modules/dock/dock.component.ts index 24a7212..a1a7a3b 100644 --- a/src/app/modules/dock/dock.component.ts +++ b/src/app/modules/dock/dock.component.ts @@ -16,19 +16,19 @@ export class DockComponent { id: 0, svg: "../../../assets/svg/logo-telegram.svg", url: "https://t.me/neur0w0men", - text: "Telegram channel", + text: "TELEGRAM_LABEL", }, { id: 1, svg: "../../../assets/svg/logo-github.svg", url: "https://github.com/MrSedan", - text: "Admin's GitHub", + text: "GITHUB_LABEL", }, { id: 2, svg: "../../../assets/svg/logo-gitea.svg", url: "https://git.nwaifu.su", - text: "Gitea", + text: "GITEA_LABEL", }, ]; } diff --git a/src/app/modules/link/link.component.html b/src/app/modules/link/link.component.html index 522d164..580ecaa 100644 --- a/src/app/modules/link/link.component.html +++ b/src/app/modules/link/link.component.html @@ -1,4 +1,4 @@ - {{ text }} + {{ text | translate }} diff --git a/src/app/modules/link/link.component.ts b/src/app/modules/link/link.component.ts index 31036bc..fe786e9 100644 --- a/src/app/modules/link/link.component.ts +++ b/src/app/modules/link/link.component.ts @@ -1,10 +1,11 @@ import { CommonModule } from "@angular/common"; import { Component, Input } from "@angular/core"; +import { TranslationPipe } from "../../pipes/translation.pipe"; @Component({ standalone: true, selector: "app-link", - imports: [CommonModule], + imports: [CommonModule, TranslationPipe], templateUrl: "./link.component.html", styleUrls: ["./link.component.less"], }) diff --git a/src/app/modules/panel/panel.component.html b/src/app/modules/panel/panel.component.html index 0da7a76..0350ee5 100644 --- a/src/app/modules/panel/panel.component.html +++ b/src/app/modules/panel/panel.component.html @@ -7,7 +7,14 @@ {{ time }}
- en + {{ getLang() }} @@ -15,3 +22,8 @@
+
+

en - English

+

ru - Русский

+

ja - 日本語

+
diff --git a/src/app/modules/panel/panel.component.less b/src/app/modules/panel/panel.component.less index 6eafcac..94daf1d 100644 --- a/src/app/modules/panel/panel.component.less +++ b/src/app/modules/panel/panel.component.less @@ -63,3 +63,43 @@ cursor: pointer; } } +.lang-choose { + position: absolute; + display: none; + &.active { + display: flex; + } + top: 0; + flex-direction: column; + justify-content: space-around; + gap: 0; + background-color: var(--black); + margin-block-start: 3rem; + z-index: 9999; + margin-inline-end: 1rem; + color: var(--white); + padding: 1rem 0; + border-radius: 15px; + &::before { + content: ""; + position: absolute; + left: 50%; + transform: translateX(-50%) rotate(45deg); + vertical-align: middle; + top: -0.5rem; + width: 0; + height: 0; + border: 10px solid var(--black); + } + p { + line-height: 2rem; + width: 100%; + padding: 0.5rem 1rem; + user-select: none; + -webkit-user-select: none; + cursor: pointer; + &:hover { + background-color: #000; + } + } +} diff --git a/src/app/modules/panel/panel.component.ts b/src/app/modules/panel/panel.component.ts index 50737c4..09f5f0d 100644 --- a/src/app/modules/panel/panel.component.ts +++ b/src/app/modules/panel/panel.component.ts @@ -1,9 +1,10 @@ import { CommonModule } from "@angular/common"; -import { Component } from "@angular/core"; +import { Component, ElementRef, HostListener, ViewChild } from "@angular/core"; import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; import { faGithub } from "@fortawesome/free-brands-svg-icons"; import { faPowerOff, faVolumeHigh } from "@fortawesome/free-solid-svg-icons"; import { PanelSevice } from "../../services/panel.service"; +import { TranslateService } from "../../services/translate.service"; @Component({ standalone: true, @@ -17,7 +18,11 @@ export class PanelComponent { faGithub = faGithub; faVolume = faVolumeHigh; faPower = faPowerOff; - constructor(private panelService: PanelSevice) { + showLangModalBool = false; + @ViewChild("lang_modal") langModal: ElementRef | null = null; + @ViewChild("lang_btn") langBtn: ElementRef | null = null; + + constructor(private panelService: PanelSevice, private translateService: TranslateService) { this.time = this.getTime(); setInterval(() => { this.time = this.getTime(); @@ -26,7 +31,7 @@ export class PanelComponent { private getTime() { const time = this.panelService.getTime(); - return time.toLocaleDateString("en-US", { + return time.toLocaleDateString(this.translateService.translate("TIME_SCHEMA"), { month: "short", day: "numeric", hour: "numeric", @@ -37,4 +42,31 @@ export class PanelComponent { goToSource() { window.open("https://git.nwaifu.su/neuro_llc/NwaifuWeb", "_blank"); } + + @HostListener("window:resize") + private moveLangModal() { + if (!this.langModal || !this.langBtn) { + return; + } + + const x = this.langBtn.nativeElement.getBoundingClientRect().x; + this.langModal.nativeElement.style.left = `calc(${x}px - 3.5rem)`; + } + + toggleModal() { + if (this.langModal) { + this.langModal.nativeElement.classList.toggle("active"); + if (this.langModal.nativeElement.classList.contains("active")) { + this.moveLangModal(); + } + } + } + + useLang(lang: string) { + this.translateService.use(lang); + } + + getLang() { + return this.translateService.lang; + } } diff --git a/src/app/modules/window/window.component.html b/src/app/modules/window/window.component.html index 1239aa1..bd377db 100644 --- a/src/app/modules/window/window.component.html +++ b/src/app/modules/window/window.component.html @@ -1,10 +1,10 @@
- Info + {{ modal_title | translate }}
-

Hello

+

{{ modal_text | translate }}

diff --git a/src/app/modules/window/window.component.ts b/src/app/modules/window/window.component.ts index df6ec48..db5642a 100644 --- a/src/app/modules/window/window.component.ts +++ b/src/app/modules/window/window.component.ts @@ -1,18 +1,21 @@ import { CommonModule } from "@angular/common"; -import { ChangeDetectionStrategy, Component } from "@angular/core"; +import { Component } from "@angular/core"; import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; import { faBars, faXmark } from "@fortawesome/free-solid-svg-icons"; import { DialogRef } from "@ngneat/dialog"; +import { TranslationPipe } from "../../pipes/translation.pipe"; @Component({ selector: "app-window", standalone: true, - imports: [CommonModule, FontAwesomeModule], + imports: [CommonModule, FontAwesomeModule, TranslationPipe], templateUrl: "./window.component.html", styleUrls: ["./window.component.less"], - changeDetection: ChangeDetectionStrategy.OnPush, + // changeDetection: ChangeDetectionStrategy.OnPush, }) export class WindowComponent { + modal_text = "MODAL_TEXT"; + modal_title = "MODAL_TITLE"; faClose = faXmark; faMenu = faBars; constructor(public ref: DialogRef) {} diff --git a/src/app/pipes/translation.pipe.ts b/src/app/pipes/translation.pipe.ts new file mode 100644 index 0000000..de13ada --- /dev/null +++ b/src/app/pipes/translation.pipe.ts @@ -0,0 +1,14 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { TranslateService } from "../services/translate.service"; + +@Pipe({ + name: "translate", + standalone: true, + pure: false, +}) +export class TranslationPipe implements PipeTransform { + constructor(private translateService: TranslateService) {} + transform(key: string) { + return this.translateService.data[key] ?? key; + } +} diff --git a/src/app/services/translate.service.ts b/src/app/services/translate.service.ts new file mode 100644 index 0000000..94c5502 --- /dev/null +++ b/src/app/services/translate.service.ts @@ -0,0 +1,30 @@ +import { HttpClient } from "@angular/common/http"; +import { Injectable } from "@angular/core"; + +@Injectable({ providedIn: "root" }) +export class TranslateService { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data: Record = {}; + lang = "en"; + constructor(private http: HttpClient) {} + use(lang: string): Promise { + this.lang = lang ?? "en"; + return new Promise((resolve) => { + const langPath = `assets/i18n/${lang ?? "en"}.json`; + this.http.get(langPath).subscribe({ + next: (response) => { + this.data = response ?? {}; + resolve(this.data); + }, + error: () => { + this.data = {}; + resolve(this.data); + }, + }); + }); + } + + translate(key: string) { + return this.data[key] ?? key; + } +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json new file mode 100644 index 0000000..6ccb062 --- /dev/null +++ b/src/assets/i18n/en.json @@ -0,0 +1,8 @@ +{ + "MODAL_TITLE": "Info", + "TIME_SCHEMA": "en-US", + "MODAL_TEXT": "Hello, World!", + "TELEGRAM_LABEL": "Telegram channel", + "GITHUB_LABEL": "Admin's Github", + "GITEA_LABEL": "Neuro LLC Gitea" +} diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json new file mode 100644 index 0000000..94ee720 --- /dev/null +++ b/src/assets/i18n/ja.json @@ -0,0 +1,8 @@ +{ + "MODAL_TITLE": "情報", + "TIME_SCHEMA": "ja-JP", + "MODAL_TEXT": "こんにちは、世界!", + "TELEGRAM_LABEL": "Telegramチャンネル", + "GITHUB_LABEL": "管理者Github", + "GITEA_LABEL": "Neuro LLC Gitea" +} diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json new file mode 100644 index 0000000..1c67830 --- /dev/null +++ b/src/assets/i18n/ru.json @@ -0,0 +1,8 @@ +{ + "MODAL_TITLE": "Информация", + "TIME_SCHEMA": "ru-RU", + "MODAL_TEXT": "Здравствуйте, мир!", + "TELEGRAM_LABEL": "Телеграм канал", + "GITHUB_LABEL": "Github админа", + "GITEA_LABEL": "Neuro LLC Gitea" +} -- 2.49.1