Implement dynamic container height adjustment in NickGeneratorComponent based on header and footer dimensions. Refactor HTML structure for improved dark mode styling and accessibility. Optimize component lifecycle by adding AfterViewInit and OnDestroy handling with a ResizeObserver.
This commit is contained in:
parent
72b9109ece
commit
e415ecc415
|
|
@ -12,96 +12,97 @@
|
||||||
</app-header>
|
</app-header>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<section class="containerNick">
|
<section class="darkmodeSection full-width">
|
||||||
<div class="controls">
|
<div class="containerNick">
|
||||||
|
<div class="controls">
|
||||||
|
|
||||||
@for (part of parts; track $index; let i = $index) {
|
@for (part of parts; track $index; let i = $index) {
|
||||||
<div class="part">
|
<div class="part">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<mat-form-field class="textField" appearance="outline">
|
<mat-form-field class="textField" appearance="outline">
|
||||||
<mat-label>Text</mat-label>
|
<mat-label>Text</mat-label>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
[value]="part.text"
|
[value]="part.text"
|
||||||
(input)="part.text = ($any($event.target).value || ''); onInputChanged()"
|
(input)="part.text = ($any($event.target).value || ''); onInputChanged()"
|
||||||
maxlength="16"
|
maxlength="16"
|
||||||
/>
|
/>
|
||||||
<mat-hint align="end">{{ part.text.length }} / 16</mat-hint>
|
<mat-hint align="end">{{ part.text.length }} / 16</mat-hint>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-checkbox
|
<mat-checkbox
|
||||||
class="checkbox"
|
class="checkbox"
|
||||||
[(ngModel)]="part.gradient"
|
[(ngModel)]="part.gradient"
|
||||||
(change)="onGradientToggle(i)"
|
(change)="onGradientToggle(i)"
|
||||||
>Gradient
|
>Gradient
|
||||||
</mat-checkbox
|
</mat-checkbox>
|
||||||
>
|
|
||||||
|
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
class="colorField"
|
class="colorField"
|
||||||
appearance="outline"
|
appearance="outline"
|
||||||
[style.visibility]="(part.continuation && i>0 && parts[i-1]?.gradient && part.gradient) ? 'hidden' : 'visible'">
|
[style.visibility]="(part.continuation && i>0 && parts[i-1]?.gradient && part.gradient) ? 'hidden' : 'visible'">
|
||||||
<mat-label>Color A</mat-label>
|
<mat-label>Color A</mat-label>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
type="color"
|
type="color"
|
||||||
[value]="part.colorA"
|
[value]="part.colorA"
|
||||||
(input)="part.colorA = $any($event.target).value; onInputChanged()"
|
(input)="part.colorA = $any($event.target).value; onInputChanged()"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
class="colorField"
|
class="colorField"
|
||||||
appearance="outline"
|
appearance="outline"
|
||||||
[style.visibility]="part.gradient ? 'visible' : 'hidden'">
|
[style.visibility]="part.gradient ? 'visible' : 'hidden'">
|
||||||
<mat-label>Color B</mat-label>
|
<mat-label>Color B</mat-label>
|
||||||
<input
|
<input
|
||||||
matInput
|
matInput
|
||||||
type="color"
|
type="color"
|
||||||
[value]="part.colorB"
|
[value]="part.colorB"
|
||||||
(input)="part.colorB = $any($event.target).value; onInputChanged()"
|
(input)="part.colorB = $any($event.target).value; onInputChanged()"
|
||||||
/>
|
/>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-checkbox
|
<mat-checkbox
|
||||||
class="checkbox"
|
class="checkbox"
|
||||||
[(ngModel)]="part.continuation"
|
[(ngModel)]="part.continuation"
|
||||||
(change)="onContinuationToggle(i)"
|
(change)="onContinuationToggle(i)"
|
||||||
[disabled]="i===0 || !part.gradient || !parts[i-1]?.gradient"
|
[disabled]="i===0 || !part.gradient || !parts[i-1]?.gradient"
|
||||||
>Continuation
|
>Continuation
|
||||||
</mat-checkbox
|
</mat-checkbox
|
||||||
>
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if (part.invalid) {
|
||||||
|
<div class="invalid">(min 1 – max 16 chars{{ part.gradient ? '' : ' for non-empty text' }})</div>
|
||||||
|
}
|
||||||
|
<mat-divider></mat-divider>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
@if (part.invalid) {
|
<div class="buttons">
|
||||||
<div class="invalid">(min 1 – max 16 chars{{ part.gradient ? '' : ' for non-empty text' }})</div>
|
<button mat-raised-button (click)="addPart()">Add Part</button>
|
||||||
}
|
<button mat-raised-button (click)="deletePart()">Remove Part</button>
|
||||||
<mat-divider></mat-divider>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
|
|
||||||
<div class="buttons">
|
@if (showCommands) {
|
||||||
<button mat-raised-button (click)="addPart()">Add Part</button>
|
<div class="commands">
|
||||||
<button mat-raised-button (click)="deletePart()">Remove Part</button>
|
<div class="commandRow">
|
||||||
|
<div class="command">{{ tryCmd }}</div>
|
||||||
|
<button mat-stroked-button (click)="copy(tryCmd, 'try')">{{ tryCommandButtonContent }}</button>
|
||||||
|
</div>
|
||||||
|
<div class="commandRow">
|
||||||
|
<div class="command">{{ requestCmd }}</div>
|
||||||
|
<button mat-stroked-button (click)="copy(requestCmd, 'request')">{{ requestCommandButtonContent }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (showPreview) {
|
||||||
|
<div class="preview" [innerHTML]="previewHtml"></div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (showCommands) {
|
|
||||||
<div class="commands">
|
|
||||||
<div class="commandRow">
|
|
||||||
<div class="command">{{ tryCmd }}</div>
|
|
||||||
<button mat-stroked-button (click)="copy(tryCmd, 'try')">{{ tryCommandButtonContent }}</button>
|
|
||||||
</div>
|
|
||||||
<div class="commandRow">
|
|
||||||
<div class="command">{{ requestCmd }}</div>
|
|
||||||
<button mat-stroked-button (click)="copy(requestCmd, 'request')">{{ requestCommandButtonContent }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
@if (showPreview) {
|
|
||||||
<div class="preview" [innerHTML]="previewHtml"></div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
/* nick-generator.component.css */
|
|
||||||
.containerNick {
|
.containerNick {
|
||||||
background-color: #292828;
|
|
||||||
padding: 40px 5%;
|
|
||||||
max-width: 1220px;
|
max-width: 1220px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.controls {
|
.controls {
|
||||||
|
|
@ -59,8 +57,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.command {
|
.command {
|
||||||
background: #1e1e1e;
|
|
||||||
color: #ffffff;
|
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
|
|
@ -68,10 +64,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview {
|
.preview {
|
||||||
background: #1e1e1e;
|
|
||||||
padding: 14px 12px;
|
padding: 14px 12px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
color: #ffffff;
|
|
||||||
font-family: 'minecraft-text', monospace;
|
font-family: 'minecraft-text', monospace;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import {Component} from '@angular/core';
|
import {AfterViewInit, Component, ElementRef, OnDestroy, Renderer2} from '@angular/core';
|
||||||
import {DomSanitizer, SafeHtml} from '@angular/platform-browser';
|
import {DomSanitizer, SafeHtml} from '@angular/platform-browser';
|
||||||
import {MatFormFieldModule} from '@angular/material/form-field';
|
import {MatFormFieldModule} from '@angular/material/form-field';
|
||||||
import {MatInputModule} from '@angular/material/input';
|
import {MatInputModule} from '@angular/material/input';
|
||||||
|
|
@ -31,7 +31,7 @@ interface Part {
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class NickGeneratorComponent {
|
export class NickGeneratorComponent implements AfterViewInit, OnDestroy {
|
||||||
parts: Part[] = [
|
parts: Part[] = [
|
||||||
{text: '', gradient: false, colorA: '#ffffff', colorB: '#ffffff', continuation: false}
|
{text: '', gradient: false, colorA: '#ffffff', colorB: '#ffffff', continuation: false}
|
||||||
];
|
];
|
||||||
|
|
@ -41,8 +41,33 @@ export class NickGeneratorComponent {
|
||||||
previewHtml: SafeHtml = '';
|
previewHtml: SafeHtml = '';
|
||||||
showPreview = false;
|
showPreview = false;
|
||||||
showCommands = false;
|
showCommands = false;
|
||||||
|
private handleResize: any;
|
||||||
|
private boundHandleResize: any;
|
||||||
|
private resizeObserver: ResizeObserver | null = null;
|
||||||
|
|
||||||
constructor(private sanitizer: DomSanitizer) {
|
|
||||||
|
constructor(private sanitizer: DomSanitizer,
|
||||||
|
private elementRef: ElementRef,
|
||||||
|
private renderer: Renderer2
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
if (this.resizeObserver) {
|
||||||
|
this.resizeObserver.disconnect();
|
||||||
|
this.resizeObserver = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.boundHandleResize) {
|
||||||
|
window.removeEventListener('resize', this.boundHandleResize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
this.setupResizeObserver();
|
||||||
|
window.addEventListener('resize', this.boundHandleResize);
|
||||||
|
this.boundHandleResize = this.handleResize.bind(this);
|
||||||
|
setTimeout(() => this.updateContainerHeight(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
addPart(): void {
|
addPart(): void {
|
||||||
|
|
@ -223,4 +248,35 @@ export class NickGeneratorComponent {
|
||||||
.replace(/</g, '<')
|
.replace(/</g, '<')
|
||||||
.replace(/>/g, '>');
|
.replace(/>/g, '>');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private updateContainerHeight() {
|
||||||
|
const headerElement = document.querySelector('app-header');
|
||||||
|
const footerElement = document.querySelector('footer');
|
||||||
|
|
||||||
|
const container = this.elementRef.nativeElement.querySelector('.containerNick');
|
||||||
|
|
||||||
|
if (headerElement && footerElement && container) {
|
||||||
|
const headerHeight = headerElement.getBoundingClientRect().height;
|
||||||
|
const footerHeight = footerElement.getBoundingClientRect().height;
|
||||||
|
|
||||||
|
const calculatedHeight = `calc(100vh - ${headerHeight}px - ${footerHeight}px)`;
|
||||||
|
this.renderer.setStyle(container, 'min-height', calculatedHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupResizeObserver() {
|
||||||
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
this.updateContainerHeight();
|
||||||
|
});
|
||||||
|
|
||||||
|
const headerElement = document.querySelector('app-header');
|
||||||
|
if (headerElement) {
|
||||||
|
this.resizeObserver.observe(headerElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
const footerElement = document.querySelector('footer');
|
||||||
|
if (footerElement) {
|
||||||
|
this.resizeObserver.observe(footerElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user