ngx-dev-toolbar 0.0.2-1 → 0.0.2-3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/package.json +6 -3
  2. package/project.json +1 -1
  3. package/src/components/button/button.component.scss +36 -0
  4. package/src/components/button/button.component.ts +36 -0
  5. package/src/components/icons/angular-icon.component.ts +35 -0
  6. package/src/components/icons/bug-icon.component.ts +27 -0
  7. package/src/components/icons/code-icon.component.ts +24 -0
  8. package/src/components/icons/database-icon.component.ts +27 -0
  9. package/src/components/icons/gauge-icon.component.ts +27 -0
  10. package/src/components/icons/gear-icon.component.ts +27 -0
  11. package/src/components/icons/git-branch-icon.component.ts +27 -0
  12. package/src/components/icons/icon.component.ts +105 -0
  13. package/src/components/icons/icon.models.ts +21 -0
  14. package/src/components/icons/layout-icon.component.ts +24 -0
  15. package/src/components/icons/lighting-icon.component.ts +24 -0
  16. package/src/components/icons/moon-icon.component.ts +27 -0
  17. package/src/components/icons/network-icon.component.ts +27 -0
  18. package/src/components/icons/puzzle-icon.component.ts +27 -0
  19. package/src/components/icons/refresh-icon.component.ts +27 -0
  20. package/src/components/icons/star-icon.component.ts +27 -0
  21. package/src/components/icons/sun-icon.component.ts +27 -0
  22. package/src/components/icons/terminal-icon.component.ts +27 -0
  23. package/src/components/icons/toggle-left-icon.component.ts +27 -0
  24. package/src/components/icons/translate-icon.component.ts +23 -0
  25. package/src/components/icons/users-icon.component.ts +27 -0
  26. package/src/components/input/input.component.ts +66 -0
  27. package/src/components/select/select.component.scss +102 -0
  28. package/src/components/select/select.component.ts +40 -0
  29. package/src/components/tool-button/tool-button.component.scss +67 -0
  30. package/src/components/tool-button/tool-button.component.ts +126 -0
  31. package/src/components/toolbar-tool/toolbar-tool.component.scss +9 -0
  32. package/src/components/toolbar-tool/toolbar-tool.component.ts +128 -0
  33. package/src/components/toolbar-tool/toolbar-tool.models.ts +9 -0
  34. package/src/components/window/window.component.scss +99 -0
  35. package/src/components/window/window.component.ts +79 -0
  36. package/src/components/window/window.models.ts +28 -0
  37. package/src/dev-toolbar-state.service.ts +89 -0
  38. package/src/dev-toolbar.component.scss +22 -0
  39. package/src/dev-toolbar.component.ts +104 -0
  40. package/src/index.ts +6 -1
  41. package/src/models/dev-tools.interface.ts +19 -0
  42. package/src/styles.scss +363 -0
  43. package/src/tools/feature-flags-tool/feature-flags-internal.service.ts +96 -0
  44. package/src/tools/feature-flags-tool/feature-flags-tool.component.ts +262 -0
  45. package/src/tools/feature-flags-tool/feature-flags.models.ts +10 -0
  46. package/src/tools/feature-flags-tool/feature-flags.service.ts +26 -0
  47. package/src/tools/home-tool/home-tool.component.scss +61 -0
  48. package/src/tools/home-tool/home-tool.component.ts +72 -0
  49. package/src/tools/home-tool/settings.models.ts +3 -0
  50. package/src/tools/home-tool/settings.service.spec.ts +59 -0
  51. package/src/tools/home-tool/settings.service.ts +21 -0
  52. package/src/tools/language-tool/language-internal.service.ts +51 -0
  53. package/src/tools/language-tool/language-tool.component.scss +7 -0
  54. package/src/tools/language-tool/language-tool.component.ts +75 -0
  55. package/src/tools/language-tool/language.models.ts +4 -0
  56. package/src/tools/language-tool/language.service.ts +26 -0
  57. package/src/utils/storage.service.ts +19 -0
@@ -0,0 +1,27 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'ndt-terminal-icon',
5
+ standalone: true,
6
+ changeDetection: ChangeDetectionStrategy.OnPush,
7
+ template: `
8
+ <svg
9
+ [attr.fill]="fill()"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ width="24"
12
+ height="24"
13
+ viewBox="0 0 256 256"
14
+ >
15
+ <path
16
+ d="M224,56V200a8,8,0,0,1-8,8H40a8,8,0,0,1-8-8V56a8,8,0,0,1,8-8H216A8,8,0,0,1,224,56Z"
17
+ opacity="0.2"
18
+ ></path>
19
+ <path
20
+ d="M128,128a8,8,0,0,1-3,6.25l-40,32a8,8,0,1,1-10-12.5L107.19,128,75,102.25a8,8,0,1,1,10-12.5l40,32A8,8,0,0,1,128,128Zm48,24H136a8,8,0,0,0,0,16h40a8,8,0,0,0,0-16Zm56-96V200a16,16,0,0,1-16,16H40a16,16,0,0,1-16-16V56A16,16,0,0,1,40,40H216A16,16,0,0,1,232,56ZM216,200V56H40V200H216Z"
21
+ ></path>
22
+ </svg>
23
+ `,
24
+ })
25
+ export class TerminalIconComponent {
26
+ fill = input<string>('#FFFF');
27
+ }
@@ -0,0 +1,27 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'ndt-toggle-left-icon',
5
+ standalone: true,
6
+ changeDetection: ChangeDetectionStrategy.OnPush,
7
+ template: `
8
+ <svg
9
+ [attr.fill]="fill()"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ width="24"
12
+ height="24"
13
+ viewBox="0 0 256 256"
14
+ >
15
+ <path
16
+ d="M112,128A32,32,0,1,1,80,96,32,32,0,0,1,112,128Z"
17
+ opacity="0.2"
18
+ ></path>
19
+ <path
20
+ d="M176,56H80a72,72,0,0,0,0,144h96a72,72,0,0,0,0-144Zm0,128H80A56,56,0,0,1,80,72h96a56,56,0,0,1,0,112ZM80,88a40,40,0,1,0,40,40A40,40,0,0,0,80,88Zm0,64a24,24,0,1,1,24-24A24,24,0,0,1,80,152Z"
21
+ ></path>
22
+ </svg>
23
+ `,
24
+ })
25
+ export class ToggleLeftIconComponent {
26
+ fill = input<string>('#FFFF');
27
+ }
@@ -0,0 +1,23 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'ndt-translate-icon',
5
+ standalone: true,
6
+ changeDetection: ChangeDetectionStrategy.OnPush,
7
+ template: `
8
+ <svg
9
+ [attr.fill]="fill()"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ width="24"
12
+ height="24"
13
+ viewBox="0 0 256 256"
14
+ >
15
+ <path
16
+ d="M250.73,210.63l-56-112a12,12,0,0,0-21.46,0l-20.52,41A84.2,84.2,0,0,1,114,126.22,107.48,107.48,0,0,0,139.33,68H160a12,12,0,0,0,0-24H108V32a12,12,0,0,0-24,0V44H32a12,12,0,0,0,0,24h83.13A83.69,83.69,0,0,1,96,110.35,84,84,0,0,1,83.6,91a12,12,0,1,0-21.81,10A107.55,107.55,0,0,0,78,126.24,83.54,83.54,0,0,1,32,140a12,12,0,0,0,0,24,107.47,107.47,0,0,0,64-21.07,108.4,108.4,0,0,0,45.39,19.44l-24.13,48.26a12,12,0,1,0,21.46,10.73L151.41,196h65.17l12.68,25.36a12,12,0,1,0,21.47-10.73ZM163.41,172,184,130.83,204.58,172Z"
17
+ ></path>
18
+ </svg>
19
+ `,
20
+ })
21
+ export class TranslateIconComponent {
22
+ fill = input<string>('#FFFF');
23
+ }
@@ -0,0 +1,27 @@
1
+ import { ChangeDetectionStrategy, Component, input } from '@angular/core';
2
+
3
+ @Component({
4
+ selector: 'ndt-users-icon',
5
+ standalone: true,
6
+ changeDetection: ChangeDetectionStrategy.OnPush,
7
+ template: `
8
+ <svg
9
+ [attr.fill]="fill()"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ width="24"
12
+ height="24"
13
+ viewBox="0 0 256 256"
14
+ >
15
+ <path
16
+ d="M224,128a95.76,95.76,0,0,1-31.8,71.37A72,72,0,0,0,128,160a40,40,0,1,0-40-40,40,40,0,0,0,40,40,72,72,0,0,0-64.2,39.37h0A96,96,0,1,1,224,128Z"
17
+ opacity="0.2"
18
+ ></path>
19
+ <path
20
+ d="M128,24A104,104,0,1,0,232,128,104.11,104.11,0,0,0,128,24ZM74.08,197.5a64,64,0,0,1,107.84,0,87.83,87.83,0,0,1-107.84,0ZM96,120a32,32,0,1,1,32,32A32,32,0,0,1,96,120Zm97.76,66.41a79.66,79.66,0,0,0-36.06-28.75,48,48,0,1,0-59.4,0,79.66,79.66,0,0,0-36.06,28.75,88,88,0,1,1,131.52,0Z"
21
+ ></path>
22
+ </svg>
23
+ `,
24
+ })
25
+ export class UsersIconComponent {
26
+ fill = input<string>('#FFFF');
27
+ }
@@ -0,0 +1,66 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ input,
5
+ model,
6
+ } from '@angular/core';
7
+ import { FormsModule } from '@angular/forms';
8
+
9
+ @Component({
10
+ selector: 'ndt-input',
11
+ standalone: true,
12
+ imports: [FormsModule],
13
+ template: `
14
+ <input
15
+ [attr.aria-label]="ariaLabel()"
16
+ [type]="type()"
17
+ [class]="inputClass()"
18
+ [ngModel]="value()"
19
+ [placeholder]="placeholder()"
20
+ (ngModelChange)="value.set($event)"
21
+ />
22
+ `,
23
+ styles: [
24
+ `
25
+ :host {
26
+ display: block;
27
+ }
28
+
29
+ .input {
30
+ width: 100%;
31
+ padding: var(--devtools-spacing-sm) var(--devtools-spacing-md);
32
+ border: 1px solid var(--devtools-border-primary);
33
+ border-radius: var(--devtools-border-radius-small);
34
+ background-color: var(--devtools-bg-primary);
35
+ color: var(--devtools-text-primary);
36
+ font-size: var(--devtools-font-size-sm);
37
+ transition: var(--devtools-transition-default);
38
+
39
+ &::placeholder {
40
+ color: var(--devtools-text-muted);
41
+ }
42
+
43
+ &:focus {
44
+ outline: none;
45
+ border-color: var(--devtools-primary);
46
+ box-shadow: 0 0 0 1px var(--devtools-primary);
47
+ }
48
+
49
+ &:disabled {
50
+ background-color: var(--devtools-background-secondary);
51
+ cursor: not-allowed;
52
+ color: var(--devtools-text-muted);
53
+ }
54
+ }
55
+ `,
56
+ ],
57
+ changeDetection: ChangeDetectionStrategy.OnPush,
58
+ })
59
+ export class DevToolbarInputComponent {
60
+ value = model.required<string>();
61
+
62
+ type = input<string>('text');
63
+ placeholder = input<string>('');
64
+ ariaLabel = input<string>('');
65
+ inputClass = input<string>('input');
66
+ }
@@ -0,0 +1,102 @@
1
+ @use '../../styles' as devtools;
2
+
3
+ select.select {
4
+ width: 100%;
5
+ cursor: pointer;
6
+ min-width: 100px;
7
+ display: flex;
8
+ align-items: center;
9
+ padding: var(--devtools-spacing-sm) var(--devtools-spacing-md);
10
+ border: 1px solid var(--devtools-border-primary);
11
+ border-radius: var(--devtools-border-radius-small);
12
+ background-color: var(--devtools-bg-primary);
13
+ color: var(--devtools-text-primary);
14
+ font-size: var(--devtools-font-size-sm);
15
+ gap: var(--devtools-spacing-xs);
16
+ appearance: none;
17
+ background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23666666%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
18
+ background-repeat: no-repeat;
19
+ background-position: right var(--devtools-spacing-sm) center;
20
+ background-size: 0.65em auto;
21
+ padding-right: 2.5em;
22
+ transition: var(--devtools-transition-default);
23
+
24
+ &.small {
25
+ padding: calc(var(--devtools-spacing-xs) / 2) var(--devtools-spacing-sm);
26
+ font-size: var(--devtools-font-size-sm);
27
+ height: 24px;
28
+ padding-right: 2em;
29
+ }
30
+
31
+ &:hover {
32
+ background-color: var(--devtools-background-hover);
33
+ }
34
+
35
+ &:focus {
36
+ outline: none;
37
+ border-color: var(--devtools-primary);
38
+ box-shadow: 0 0 0 1px var(--devtools-primary);
39
+ }
40
+
41
+ &:disabled {
42
+ opacity: 0.6;
43
+ cursor: not-allowed;
44
+ background-color: var(--devtools-background-disabled);
45
+ }
46
+
47
+ &:invalid {
48
+ border-color: var(--devtools-border-error, #ff4444);
49
+ }
50
+
51
+ option {
52
+ background-color: var(--devtools-bg-primary);
53
+ color: var(--devtools-text-primary);
54
+ padding: var(--devtools-spacing-sm);
55
+ font-size: var(--devtools-font-size-sm);
56
+
57
+ &:hover,
58
+ &:focus {
59
+ background-color: var(--devtools-background-hover);
60
+ }
61
+ }
62
+ }
63
+
64
+ /* Style for Firefox */
65
+ @-moz-document url-prefix() {
66
+ select.select {
67
+ text-indent: 0.01px;
68
+ text-overflow: '';
69
+ padding-right: 2.5em;
70
+
71
+ option {
72
+ background-color: var(--devtools-bg-primary) !important;
73
+ color: var(--devtools-text-primary) !important;
74
+ }
75
+ }
76
+ }
77
+
78
+ /* Style for Webkit browsers */
79
+ select.select::-ms-expand {
80
+ display: none;
81
+ }
82
+
83
+ /* Additional browser-specific overrides */
84
+ select::-ms-expand {
85
+ display: none;
86
+ }
87
+
88
+ /* For Webkit browsers (Chrome, Safari) */
89
+ select.select:-webkit-autofill,
90
+ select.select:-webkit-autofill:hover,
91
+ select.select:-webkit-autofill:focus {
92
+ -webkit-box-shadow: 0 0 0px 1000px var(--devtools-bg-primary) inset !important;
93
+ -webkit-text-fill-color: var(--devtools-text-primary) !important;
94
+ }
95
+
96
+ /* For Firefox */
97
+ @-moz-document url-prefix() {
98
+ .select option {
99
+ background-color: var(--devtools-bg-primary) !important;
100
+ color: var(--devtools-text-primary) !important;
101
+ }
102
+ }
@@ -0,0 +1,40 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ Component,
4
+ input,
5
+ model,
6
+ } from '@angular/core';
7
+ import { FormsModule } from '@angular/forms';
8
+
9
+ export interface SelectOption {
10
+ value: string;
11
+ label: string;
12
+ }
13
+
14
+ @Component({
15
+ selector: 'ndt-select',
16
+ standalone: true,
17
+ imports: [FormsModule],
18
+ template: `
19
+ <select
20
+ class="select"
21
+ [attr.aria-label]="ariaLabel()"
22
+ [class.small]="size() === 'small'"
23
+ [ngModel]="value()"
24
+ (ngModelChange)="value.set($event)"
25
+ >
26
+ @for (option of options(); track option.value) {
27
+ <option role="option" [value]="option.value">{{ option.label }}</option>
28
+ }
29
+ </select>
30
+ `,
31
+ styleUrls: ['./select.component.scss'],
32
+ changeDetection: ChangeDetectionStrategy.OnPush,
33
+ })
34
+ export class DevToolbarSelectComponent {
35
+ value = model<string>();
36
+ options = input.required<SelectOption[]>();
37
+ ariaLabel = input<string>('');
38
+ label = input<string>('');
39
+ size = input<'small' | 'medium'>('medium');
40
+ }
@@ -0,0 +1,67 @@
1
+ @use '../../styles' as devtools;
2
+ @use 'sass:map';
3
+ $dimensions: devtools.$dimensions;
4
+
5
+ .tool-button {
6
+ display: flex;
7
+ justify-content: center;
8
+ align-items: center;
9
+ width: map.get($dimensions, toolbar-button-width);
10
+ height: map.get($dimensions, toolbar-height);
11
+ border: 0;
12
+ background: transparent;
13
+ color: var(--devtools-text-primary);
14
+ transition: var(--devtools-transition-default);
15
+ cursor: pointer;
16
+ opacity: 0.5;
17
+ position: relative;
18
+
19
+ &--active {
20
+ background: var(--devtools-hover-bg);
21
+ opacity: 1;
22
+ }
23
+
24
+ &:hover {
25
+ background: var(--devtools-hover-bg);
26
+ opacity: 1;
27
+ }
28
+
29
+ ::ng-deep svg {
30
+ width: 24px;
31
+ height: 24px;
32
+ display: block;
33
+ margin: auto;
34
+ }
35
+
36
+ &__badge {
37
+ position: absolute;
38
+ top: -0.25rem;
39
+ right: -0.25rem;
40
+ background-color: var(--devtools-hover-danger);
41
+ color: var(--devtools-text-primary);
42
+ border-radius: var(--devtools-border-radius-full);
43
+ min-width: 1rem;
44
+ height: 1rem;
45
+ font-size: 0.75rem;
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ padding: 0.125rem;
50
+ }
51
+ }
52
+
53
+ .tooltip {
54
+ position: absolute;
55
+ bottom: calc(100% + 1.2rem);
56
+ left: 50%;
57
+ transform: translateX(-50%);
58
+ background: var(--devtools-bg-primary);
59
+ color: var(--devtools-text-primary);
60
+ padding: 0.5rem 0.75rem;
61
+ border-radius: var(--devtools-border-radius-medium);
62
+ font-size: 0.75rem;
63
+ white-space: nowrap;
64
+ pointer-events: none;
65
+ z-index: 1000;
66
+ box-shadow: var(--devtools-shadow-tooltip);
67
+ }
@@ -0,0 +1,126 @@
1
+ import {
2
+ animate,
3
+ state,
4
+ style,
5
+ transition,
6
+ trigger,
7
+ } from '@angular/animations';
8
+ import {
9
+ ChangeDetectionStrategy,
10
+ Component,
11
+ ElementRef,
12
+ computed,
13
+ inject,
14
+ input,
15
+ output,
16
+ signal,
17
+ } from '@angular/core';
18
+ import { DevToolbarStateService } from '../../dev-toolbar-state.service';
19
+
20
+ @Component({
21
+ selector: 'ndt-tool-button',
22
+ standalone: true,
23
+ template: `
24
+ <button
25
+ class="tool-button"
26
+ [class.tool-button--active]="isActive()"
27
+ [class.tool-button--focus]="isFocused()"
28
+ (mouseenter)="onMouseEnter()"
29
+ (focusin)="onFocus()"
30
+ (focusout)="onBlur()"
31
+ (mouseleave)="onMouseLeave()"
32
+ (keydown.escape)="onEscape()"
33
+ >
34
+ @if (isTooltipVisible()) {
35
+ <span
36
+ class="tooltip"
37
+ [@tooltipAnimation]="tooltipState ? 'visible' : 'hidden'"
38
+ >
39
+ {{ tooltip() }}
40
+ </span>
41
+ }
42
+ <ng-content />
43
+ </button>
44
+ `,
45
+ styleUrls: ['./tool-button.component.scss'],
46
+ animations: [
47
+ trigger('tooltipAnimation', [
48
+ state(
49
+ 'hidden',
50
+ style({
51
+ opacity: 0,
52
+ transform: 'translateX(-50%) translateY(1rem)',
53
+ })
54
+ ),
55
+ state(
56
+ 'visible',
57
+ style({
58
+ opacity: 1,
59
+ transform: 'translateX(-50%) translateY(0)',
60
+ })
61
+ ),
62
+ transition('hidden => visible', [animate('200ms ease-out')]),
63
+ transition('visible => hidden', [animate('150ms ease-in')]),
64
+ ]),
65
+ ],
66
+ changeDetection: ChangeDetectionStrategy.OnPush,
67
+ })
68
+ export class DevToolbarToolButtonComponent {
69
+ // Injects
70
+ private readonly state = inject(DevToolbarStateService);
71
+ private readonly elementRef = inject(ElementRef);
72
+
73
+ // Inputs
74
+ readonly title = input.required<string>();
75
+ readonly toolId = input.required<string>();
76
+
77
+ // Outputs
78
+ readonly open = output<void>();
79
+
80
+ // Signals
81
+ readonly isActive = computed(
82
+ () => this.state.activeToolId() === this.toolId()
83
+ );
84
+ readonly isToolbarVisible = this.state.isVisible;
85
+
86
+ readonly isFocused = signal(false);
87
+ readonly tooltip = computed(
88
+ () =>
89
+ this.elementRef.nativeElement.parentElement?.getAttribute(
90
+ 'data-tooltip'
91
+ ) ?? ''
92
+ );
93
+ readonly isTooltipVisible = computed(
94
+ () => this.tooltip() && !this.isActive()
95
+ );
96
+
97
+ // Properties
98
+ protected tooltipState = false;
99
+ private readonly hideDelay = 3000;
100
+
101
+ // Public methods
102
+ onClick(): void {
103
+ this.isFocused.set(false);
104
+ this.open.emit();
105
+ }
106
+
107
+ onMouseEnter(): void {
108
+ this.tooltipState = true;
109
+ }
110
+
111
+ onMouseLeave(): void {
112
+ this.tooltipState = false;
113
+ }
114
+
115
+ onEscape(): void {
116
+ this.isFocused.set(false);
117
+ }
118
+
119
+ onFocus(): void {
120
+ this.isFocused.set(true);
121
+ }
122
+
123
+ onBlur(): void {
124
+ this.isFocused.set(false);
125
+ }
126
+ }
@@ -0,0 +1,9 @@
1
+ @use '../../styles' as devtools;
2
+
3
+ .tool {
4
+ position: relative;
5
+ }
6
+
7
+ .trigger {
8
+ cursor: pointer;
9
+ }
@@ -0,0 +1,128 @@
1
+ import { CdkConnectedOverlay, OverlayModule } from '@angular/cdk/overlay';
2
+ import {
3
+ ChangeDetectionStrategy,
4
+ Component,
5
+ ContentChild,
6
+ ElementRef,
7
+ ViewChild,
8
+ computed,
9
+ inject,
10
+ input,
11
+ } from '@angular/core';
12
+ import { DevToolbarStateService } from '../../dev-toolbar-state.service';
13
+ import { DevToolbarIconComponent } from '../icons/icon.component';
14
+ import { IconName } from '../icons/icon.models';
15
+ import { DevToolbarToolButtonComponent } from '../tool-button/tool-button.component';
16
+ import { DevToolbarWindowComponent } from '../window/window.component';
17
+ import { WindowConfig } from '../window/window.models';
18
+
19
+ @Component({
20
+ selector: 'ndt-toolbar-tool',
21
+ standalone: true,
22
+ imports: [
23
+ CdkConnectedOverlay,
24
+ OverlayModule,
25
+ DevToolbarWindowComponent,
26
+ DevToolbarToolButtonComponent,
27
+ DevToolbarIconComponent,
28
+ ],
29
+ template: `
30
+ <div #trigger="cdkOverlayOrigin" class="dev-toolbar-tool" cdkOverlayOrigin>
31
+ <div
32
+ class="dev-toolbar-tool__icon"
33
+ (click)="onOpen()"
34
+ (keydown.enter)="onOpen()"
35
+ (keydown.space)="onOpen()"
36
+ tabindex="0"
37
+ >
38
+ <div [attr.data-tooltip]="title()">
39
+ @if (icon()) {
40
+ <ndt-tool-button [title]="title()" [toolId]="windowConfig().id">
41
+ <ndt-icon [name]="icon()" />
42
+ </ndt-tool-button>
43
+ } @else {
44
+ <ng-content select="ndt-tool-button"></ng-content>
45
+ }
46
+ </div>
47
+ </div>
48
+
49
+ @if (isActive()) {
50
+ <ng-template
51
+ #contentTemplate
52
+ [cdkConnectedOverlayOrigin]="trigger"
53
+ [cdkConnectedOverlayOpen]="isActive()"
54
+ [cdkConnectedOverlayPositions]="positions()"
55
+ [cdkConnectedOverlayWidth]="width()"
56
+ [cdkConnectedOverlayHeight]="height()"
57
+ cdkConnectedOverlay
58
+ >
59
+ <ndt-window [config]="windowConfig()" (close)="onClose()">
60
+ <ng-content />
61
+ </ndt-window>
62
+ </ng-template>
63
+ }
64
+ </div>
65
+ `,
66
+ styleUrl: './toolbar-tool.component.scss',
67
+ changeDetection: ChangeDetectionStrategy.OnPush,
68
+ })
69
+ export class DevToolbarToolComponent {
70
+ state = inject(DevToolbarStateService);
71
+ @ViewChild('trigger') trigger!: ElementRef;
72
+
73
+ @ContentChild(DevToolbarToolButtonComponent)
74
+ buttonComponent!: DevToolbarToolButtonComponent;
75
+
76
+ windowConfig = input.required<WindowConfig>();
77
+ icon = input.required<IconName>();
78
+ title = input.required<string>();
79
+ isActive = computed(
80
+ () => this.state.activeToolId() === this.windowConfig().id
81
+ );
82
+ height = computed(() => {
83
+ switch (this.windowConfig().size) {
84
+ case 'small':
85
+ return 320;
86
+ case 'medium':
87
+ return 480;
88
+ case 'tall':
89
+ return 620;
90
+ case 'large':
91
+ return 620;
92
+ default:
93
+ return 480;
94
+ }
95
+ });
96
+
97
+ width = computed(() => {
98
+ switch (this.windowConfig().size) {
99
+ case 'small':
100
+ return 320;
101
+ case 'medium':
102
+ return 480;
103
+ case 'tall':
104
+ return 480;
105
+ case 'large':
106
+ return 620;
107
+ default:
108
+ return 400;
109
+ }
110
+ });
111
+ positions = computed(() => [
112
+ {
113
+ originX: 'center' as const,
114
+ originY: 'center' as const,
115
+ overlayX: 'center' as const,
116
+ overlayY: 'center' as const,
117
+ offsetY: -(Math.ceil(this.height() / 2) + 36),
118
+ },
119
+ ]);
120
+
121
+ onOpen(): void {
122
+ this.state.setActiveTool(this.windowConfig().id);
123
+ }
124
+
125
+ onClose(): void {
126
+ this.state.setActiveTool(null);
127
+ }
128
+ }
@@ -0,0 +1,9 @@
1
+ import { IconName } from '../icons/icon.models';
2
+ import { WindowConfig } from '../window/window.models';
3
+
4
+ export interface DevToolbarToolConfig {
5
+ icon: IconName;
6
+ name: string;
7
+ windowConfig: WindowConfig;
8
+ isBeta?: boolean;
9
+ }