181 lines
5.4 KiB
TypeScript
181 lines
5.4 KiB
TypeScript
import { Component, ChangeDetectionStrategy, input, output, inject, effect } from '@angular/core';
|
|
import { CommonModule } from '@angular/common';
|
|
import { GraphConfig } from '../graph-settings.types';
|
|
import { GraphSettingsService } from '../graph-settings.service';
|
|
import { GraphSettingsAccordionComponent } from '../../../components/graph-settings/graph-settings-accordion.component';
|
|
|
|
@Component({
|
|
selector: 'app-graph-settings-panel',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
GraphSettingsAccordionComponent
|
|
],
|
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
template: `
|
|
<div class="settings-panel">
|
|
@if (isOpen()) {
|
|
<div class="backdrop" (click)="close.emit()"></div>
|
|
|
|
<div class="panel-content">
|
|
<div class="panel-header">
|
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">Graph settings</h2>
|
|
<div class="flex items-center gap-2">
|
|
<!-- Expand all -->
|
|
<button
|
|
type="button"
|
|
class="btn-standard-icon"
|
|
title="Expand all"
|
|
(click)="accordion?.expandAll()">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 12h16M12 4v16" />
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Collapse all -->
|
|
<button
|
|
type="button"
|
|
class="btn-standard-icon"
|
|
title="Collapse all"
|
|
(click)="accordion?.collapseAll()">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 12h16" />
|
|
</svg>
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
(click)="onResetAll()"
|
|
class="btn-standard-icon"
|
|
title="Reset all settings">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
</svg>
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
(click)="close.emit()"
|
|
(keydown.escape)="close.emit()"
|
|
class="btn-standard-icon"
|
|
aria-label="Close settings"
|
|
title="Close">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel-body">
|
|
<ov-graph-settings-accordion
|
|
#accordion
|
|
[config]="config()"
|
|
(configChange)="onConfigChange($event)"
|
|
(animateRequested)="animateRequested.emit()">
|
|
</ov-graph-settings-accordion>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
`,
|
|
styles: [`
|
|
.settings-panel {
|
|
position: fixed;
|
|
inset: 0;
|
|
z-index: 2000;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.backdrop {
|
|
position: fixed;
|
|
inset: 0;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
z-index: 1990;
|
|
pointer-events: auto;
|
|
}
|
|
|
|
.panel-content {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 100%;
|
|
max-width: 400px;
|
|
background-color: white;
|
|
box-shadow: -4px 0 6px -1px rgba(0, 0, 0, 0.1), -2px 0 4px -1px rgba(0, 0, 0, 0.06);
|
|
display: flex;
|
|
flex-direction: column;
|
|
z-index: 2001;
|
|
transform: translateX(0);
|
|
pointer-events: auto;
|
|
}
|
|
|
|
:host-context(.dark) .panel-content {
|
|
background-color: #1F2937;
|
|
}
|
|
|
|
.panel-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 1rem 1.5rem;
|
|
border-bottom: 1px solid #E5E7EB;
|
|
}
|
|
|
|
:host-context(.dark) .panel-header {
|
|
border-bottom-color: #374151;
|
|
}
|
|
|
|
.panel-body {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 1rem;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.panel-content {
|
|
max-width: 100%;
|
|
}
|
|
}
|
|
`]
|
|
})
|
|
export class GraphSettingsPanelComponent {
|
|
isOpen = input.required<boolean>();
|
|
close = output<void>();
|
|
animateRequested = output<void>();
|
|
|
|
private settingsService = inject(GraphSettingsService);
|
|
|
|
config = this.settingsService.config;
|
|
|
|
constructor() {
|
|
// Listen to Escape key globally when panel is open
|
|
effect(() => {
|
|
if (!this.isOpen()) {
|
|
return;
|
|
}
|
|
|
|
const handler = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') {
|
|
this.close.emit();
|
|
}
|
|
};
|
|
|
|
document.addEventListener('keydown', handler);
|
|
|
|
return () => document.removeEventListener('keydown', handler);
|
|
});
|
|
}
|
|
|
|
onConfigChange(patch: Partial<GraphConfig>): void {
|
|
this.settingsService.save(patch);
|
|
}
|
|
|
|
onResetAll(): void {
|
|
if (confirm('Reset all graph settings to defaults?')) {
|
|
this.settingsService.resetToDefaults();
|
|
}
|
|
}
|
|
}
|