tabby-tabbyspaces 0.1.0 → 0.2.1

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 (76) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/.github/workflows/ci.yml +26 -0
  3. package/.github/workflows/claude-code-review.yml +44 -0
  4. package/.github/workflows/claude.yml +81 -0
  5. package/.github/workflows/release.yml +30 -0
  6. package/CHANGELOG.md +46 -0
  7. package/CLAUDE.md +33 -0
  8. package/CONTRIBUTING.md +3 -1
  9. package/README.md +21 -18
  10. package/TODO.md +5 -0
  11. package/dist/build-config.d.ts +3 -3
  12. package/dist/components/deleteConfirmModal.component.d.ts +7 -0
  13. package/dist/components/deleteConfirmModal.component.d.ts.map +1 -0
  14. package/dist/components/paneEditor.component.d.ts +9 -18
  15. package/dist/components/paneEditor.component.d.ts.map +1 -1
  16. package/dist/components/splitPreview.component.d.ts +50 -50
  17. package/dist/components/splitPreview.component.d.ts.map +1 -1
  18. package/dist/components/workspaceEditor.component.d.ts +61 -54
  19. package/dist/components/workspaceEditor.component.d.ts.map +1 -1
  20. package/dist/components/workspaceList.component.d.ts +56 -39
  21. package/dist/components/workspaceList.component.d.ts.map +1 -1
  22. package/dist/index.d.ts +6 -6
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +1 -1
  25. package/dist/index.js.LICENSE.txt +1 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/models/workspace.model.d.ts +118 -78
  28. package/dist/models/workspace.model.d.ts.map +1 -1
  29. package/dist/package.json +1 -1
  30. package/dist/providers/config.provider.d.ts +8 -8
  31. package/dist/providers/settings.provider.d.ts +7 -7
  32. package/dist/providers/toolbar.provider.d.ts +23 -15
  33. package/dist/providers/toolbar.provider.d.ts.map +1 -1
  34. package/dist/services/startupCommand.service.d.ts +27 -19
  35. package/dist/services/startupCommand.service.d.ts.map +1 -1
  36. package/dist/services/workspaceBackground.service.d.ts +38 -0
  37. package/dist/services/workspaceBackground.service.d.ts.map +1 -0
  38. package/dist/services/workspaceEditor.service.d.ts +46 -32
  39. package/dist/services/workspaceEditor.service.d.ts.map +1 -1
  40. package/docs/DESIGN.md +57 -0
  41. package/docs/SESSION-2026-01-14-S1-DESIGN.md +134 -0
  42. package/mockups/index.html +162 -0
  43. package/mockups/s1-tight-sharp.html +522 -0
  44. package/mockups/shared/base.css +216 -0
  45. package/mockups/v06-tabbed.html +643 -0
  46. package/package.json +2 -1
  47. package/screenshots/editor.png +0 -0
  48. package/scripts/build-dev.js +2 -1
  49. package/scripts/build-prod.js +2 -1
  50. package/src/components/deleteConfirmModal.component.ts +23 -0
  51. package/src/components/paneEditor.component.pug +27 -43
  52. package/src/components/paneEditor.component.scss +37 -85
  53. package/src/components/paneEditor.component.ts +4 -32
  54. package/src/components/splitPreview.component.pug +0 -9
  55. package/src/components/splitPreview.component.scss +46 -70
  56. package/src/components/splitPreview.component.ts +15 -25
  57. package/src/components/workspaceEditor.component.pug +140 -112
  58. package/src/components/workspaceEditor.component.scss +270 -202
  59. package/src/components/workspaceEditor.component.ts +161 -85
  60. package/src/components/workspaceList.component.pug +31 -51
  61. package/src/components/workspaceList.component.scss +86 -77
  62. package/src/components/workspaceList.component.ts +89 -34
  63. package/src/index.ts +4 -0
  64. package/src/models/workspace.model.ts +80 -2
  65. package/src/providers/toolbar.provider.ts +78 -9
  66. package/src/services/startupCommand.service.ts +30 -32
  67. package/src/services/workspaceBackground.service.ts +167 -0
  68. package/src/services/workspaceEditor.service.ts +77 -40
  69. package/src/styles/_index.scss +3 -0
  70. package/src/styles/_mixins.scss +180 -0
  71. package/src/styles/_variables.scss +67 -0
  72. package/TEST_MCP.md +0 -176
  73. package/cdp-click.js +0 -22
  74. package/cdp-test.js +0 -28
  75. package/screenshots/pane-edit.png +0 -0
  76. package/test_cdp.py +0 -50
@@ -1,46 +1,30 @@
1
- .pane-editor-overlay((click)='onOverlayClick($event)')
2
- .pane-editor-modal(#modal)
3
- .modal-header
4
- h4 Edit Pane
5
- button.btn.btn-link.close-btn(type='button', (click)='onCancel()')
6
- i.fas.fa-times
1
+ //- Inline pane editor panel (no modal overlay)
2
+ .pane-details
3
+ .pane-details-header
4
+ span.pane-details-title
5
+ i.fas.fa-terminal
6
+ | Pane Configuration
7
7
 
8
- .modal-body
9
- .form-group
10
- label Base Profile
11
- select.form-control([(ngModel)]='editedPane.profileId')
12
- option(value='') -- Select Profile --
13
- option(*ngFor='let profile of profiles', [value]='profile.id')
14
- | {{ profile.name }}
8
+ .pane-form
9
+ .form-group
10
+ label Profile
11
+ select.form-control([(ngModel)]='pane.profileId')
12
+ option(value='') -- Select Profile --
13
+ option(*ngFor='let profile of profiles', [value]='profile.id')
14
+ | {{ profile.name }}
15
15
 
16
- .form-group
17
- label Working Directory
18
- input.form-control(
19
- type='text',
20
- [(ngModel)]='editedPane.cwd',
21
- placeholder='C:\\path\\to\\project'
22
- )
16
+ .form-group
17
+ label Working Directory
18
+ input.form-control(
19
+ type='text',
20
+ [(ngModel)]='pane.cwd',
21
+ placeholder='C:\\path\\to\\project'
22
+ )
23
23
 
24
- .form-group
25
- label Startup Command
26
- input.form-control(
27
- type='text',
28
- [(ngModel)]='editedPane.startupCommand',
29
- placeholder='e.g., npm run dev'
30
- )
31
- small.help-text
32
- | Command to execute when the pane opens. For Nushell, use commands like: uv run serve
33
-
34
- .form-group
35
- label Pane Title (optional)
36
- input.form-control(
37
- type='text',
38
- [(ngModel)]='editedPane.title',
39
- placeholder='Custom tab title'
40
- )
41
-
42
- .modal-footer
43
- button.btn.btn-secondary(type='button', (click)='onCancel()') Cancel
44
- button.btn.btn-primary(type='button', (click)='onSave()')
45
- i.fas.fa-check
46
- | Apply
24
+ .form-group
25
+ label Startup Command
26
+ input.form-control(
27
+ type='text',
28
+ [(ngModel)]='pane.startupCommand',
29
+ placeholder='e.g., npm run dev'
30
+ )
@@ -1,112 +1,64 @@
1
- .pane-editor-overlay {
2
- position: fixed;
3
- top: 0;
4
- left: 0;
5
- right: 0;
6
- bottom: 0;
7
- background: rgba(0, 0, 0, 0.7);
8
- display: flex;
9
- align-items: center;
10
- justify-content: center;
11
- z-index: 1100;
1
+ @use '../styles/index' as *;
2
+
3
+ // Inline pane details panel
4
+ .pane-details {
5
+ background: var(--theme-bg-more-more);
6
+ border-radius: $radius-sm;
7
+ padding: $spacing-lg;
8
+ padding-top: $spacing-lg;
9
+ margin-top: $spacing-xl;
10
+ border-left: 2px solid var(--theme-primary);
11
+ border-top: 1px solid var(--theme-border, $fallback-border);
12
12
  }
13
13
 
14
- .pane-editor-modal {
15
- background: var(--theme-bg);
16
- border-radius: 12px;
17
- width: 90%;
18
- max-width: 500px;
19
- max-height: 80vh;
20
- overflow: hidden;
14
+ .pane-details-header {
21
15
  display: flex;
22
- flex-direction: column;
23
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
16
+ justify-content: space-between;
17
+ align-items: center;
18
+ margin-bottom: $spacing-lg;
24
19
  }
25
20
 
26
- .modal-header {
21
+ .pane-details-title {
22
+ font-size: $font-sm;
23
+ color: var(--theme-fg);
24
+ font-weight: 500;
27
25
  display: flex;
28
- justify-content: space-between;
29
26
  align-items: center;
30
- padding: 16px 20px;
31
- border-bottom: 1px solid var(--theme-border);
32
-
33
- h4 {
34
- margin: 0;
35
- font-size: 1.15rem;
36
- }
37
-
38
- .close-btn {
39
- font-size: 1.15rem;
40
- color: var(--theme-fg-more);
41
- padding: 4px 8px;
42
-
43
- &:hover {
44
- color: var(--theme-fg);
45
- }
46
- }
27
+ gap: $spacing-sm;
47
28
  }
48
29
 
49
- .modal-body {
50
- padding: 20px;
51
- overflow-y: auto;
52
- flex: 1;
30
+ // 2-column grid for pane form
31
+ .pane-form {
32
+ display: grid;
33
+ grid-template-columns: 1fr 1fr;
34
+ gap: $spacing-lg;
53
35
  }
54
36
 
55
- .form-group {
56
- margin-bottom: 16px;
57
-
58
- &:last-child {
59
- margin-bottom: 0;
37
+ @media (max-width: 600px) {
38
+ .pane-form {
39
+ grid-template-columns: 1fr;
60
40
  }
41
+ }
61
42
 
43
+ .form-group {
62
44
  label {
63
- display: block;
64
- margin-bottom: 6px;
65
- font-size: 0.9rem;
66
- color: var(--theme-fg-more);
45
+ @include form-label;
67
46
  }
68
47
  }
69
48
 
70
49
  .form-control {
71
50
  width: 100%;
72
- padding: 10px 12px;
73
- border-radius: 6px;
74
- border: 1px solid var(--theme-border);
75
- background: var(--theme-bg-more);
76
- color: var(--theme-fg);
77
- font-size: 0.95rem;
51
+ @include form-input(var(--theme-bg));
52
+ font-size: $font-sm;
53
+ // Override Tabby's global border reset
54
+ border: 1px solid var(--theme-border, $fallback-border) !important;
78
55
 
79
56
  &:focus {
80
- outline: none;
81
- border-color: var(--theme-primary);
57
+ border-color: var(--theme-primary) !important;
82
58
  }
83
59
  }
84
60
 
85
61
  select.form-control {
86
62
  cursor: pointer;
87
- }
88
-
89
- .input-with-button {
90
- display: flex;
91
- gap: 8px;
92
-
93
- input {
94
- flex: 1;
95
- }
96
- }
97
-
98
- .help-text {
99
- display: block;
100
- margin-top: 4px;
101
- font-size: 0.8rem;
102
- color: var(--theme-fg-more);
103
- opacity: 0.8;
104
- }
105
-
106
- .modal-footer {
107
- display: flex;
108
- justify-content: flex-end;
109
- gap: 12px;
110
- padding: 16px 20px;
111
- border-top: 1px solid var(--theme-border);
63
+ appearance: auto; // Show dropdown arrow
112
64
  }
@@ -1,4 +1,4 @@
1
- import { Component, Input, Output, EventEmitter, OnInit, HostListener, ElementRef, ViewChild } from '@angular/core'
1
+ import { Component, Input, Output, EventEmitter, HostListener } from '@angular/core'
2
2
  import { WorkspacePane, TabbyProfile } from '../models/workspace.model'
3
3
 
4
4
  @Component({
@@ -6,42 +6,14 @@ import { WorkspacePane, TabbyProfile } from '../models/workspace.model'
6
6
  template: require('./paneEditor.component.pug'),
7
7
  styles: [require('./paneEditor.component.scss')],
8
8
  })
9
- export class PaneEditorComponent implements OnInit {
9
+ export class PaneEditorComponent {
10
10
  @Input() pane!: WorkspacePane
11
11
  @Input() profiles: TabbyProfile[] = []
12
- @Output() save = new EventEmitter<WorkspacePane>()
13
- @Output() cancel = new EventEmitter<void>()
14
- @ViewChild('modal', { static: true }) modalRef!: ElementRef<HTMLElement>
15
-
16
- editedPane!: WorkspacePane
17
- private pointerDownInsideModal = false
18
-
19
- ngOnInit(): void {
20
- this.editedPane = { ...this.pane }
21
- }
12
+ @Output() close = new EventEmitter<void>()
22
13
 
23
14
  @HostListener('document:keydown.escape')
24
15
  onEscapeKey(): void {
25
- this.cancel.emit()
26
- }
27
-
28
- @HostListener('document:pointerdown', ['$event'])
29
- onDocumentPointerDown(event: PointerEvent): void {
30
- this.pointerDownInsideModal = this.modalRef.nativeElement.contains(event.target as Node)
31
- }
32
-
33
- onOverlayClick(event: MouseEvent): void {
34
- if (!this.pointerDownInsideModal && event.target === event.currentTarget) {
35
- this.cancel.emit()
36
- }
37
- }
38
-
39
- onSave(): void {
40
- this.save.emit(this.editedPane)
41
- }
42
-
43
- onCancel(): void {
44
- this.cancel.emit()
16
+ this.close.emit()
45
17
  }
46
18
 
47
19
  getProfileName(profileId: string): string {
@@ -6,7 +6,6 @@
6
6
  [style.flex-basis]='getFlexStyle(i)',
7
7
  [class.selected]='asPane(child).id === selectedPaneId',
8
8
  (click)='onPaneClick(asPane(child)); $event.stopPropagation()',
9
- (dblclick)='onEditClick($event, asPane(child))',
10
9
  (contextmenu)='onContextMenu($event, asPane(child))'
11
10
  )
12
11
  .pane-content
@@ -20,13 +19,6 @@
20
19
  i.fas.fa-terminal
21
20
  span {{ truncate(asPane(child).startupCommand, 20) }}
22
21
 
23
- button.pane-edit-btn(
24
- type='button',
25
- (click)='onEditClick($event, asPane(child))',
26
- title='Edit pane'
27
- )
28
- i.fas.fa-pen
29
-
30
22
  //- Nested split
31
23
  split-preview(
32
24
  *ngIf='isSplit(child)',
@@ -35,7 +27,6 @@
35
27
  [selectedPaneId]='selectedPaneId',
36
28
  [profiles]='profiles',
37
29
  [style.flex-basis]='getFlexStyle(i)',
38
- (paneSelect)='onNestedPaneSelect($event)',
39
30
  (paneEdit)='onNestedPaneEdit($event)',
40
31
  (splitHorizontal)='onNestedSplitH($event)',
41
32
  (splitVertical)='onNestedSplitV($event)',
@@ -1,12 +1,14 @@
1
+ @use '../styles/index' as *;
2
+
1
3
  .split-preview {
2
4
  display: flex;
3
5
  width: 100%;
4
- height: 140px;
5
- gap: 4px;
6
- border-radius: 6px;
6
+ height: $preview-height;
7
+ gap: $spacing-sm;
8
+ border-radius: $radius-md;
7
9
  overflow: hidden;
8
10
  background: var(--theme-bg);
9
- border: 1px solid var(--theme-border);
11
+ border: 1px solid var(--theme-border, rgba(255, 255, 255, 0.1));
10
12
 
11
13
  &.horizontal {
12
14
  flex-direction: row;
@@ -19,62 +21,68 @@
19
21
  &.nested {
20
22
  height: auto;
21
23
  border: 1px dashed var(--theme-fg-more);
22
- background: rgba(255, 255, 255, 0.02);
23
- padding: 4px;
24
- border-radius: 4px;
24
+ background: $nested-split-bg;
25
+ padding: $spacing-sm;
26
+ border-radius: $radius-sm;
25
27
  }
26
28
  }
27
29
 
28
30
  .preview-pane {
29
- display: flex;
30
- align-items: center;
31
- justify-content: center;
31
+ @include flex-center;
32
32
  background: var(--theme-bg-more);
33
- border-radius: 4px;
34
- border: 2px solid transparent;
33
+ border-radius: $radius-sm;
34
+ border: 2px solid var(--theme-border, rgba(255, 255, 255, 0.1));
35
35
  cursor: pointer;
36
- transition: all 0.15s;
36
+ transition: all $transition-fast;
37
37
  position: relative;
38
38
  min-height: 50px;
39
39
 
40
40
  &:hover {
41
41
  background: var(--theme-bg-more-more);
42
+ border-color: var(--theme-fg-more, rgba(255, 255, 255, 0.3));
42
43
  }
43
44
 
44
45
  &.selected {
45
46
  border-color: var(--theme-primary);
46
- background: var(--theme-bg-more-more);
47
+ background: linear-gradient(
48
+ to bottom,
49
+ $selected-pane-gradient-start,
50
+ $selected-pane-gradient-end
51
+ );
47
52
  }
48
53
  }
49
54
 
50
55
  .pane-content {
51
56
  text-align: center;
52
- padding: 8px;
57
+ padding: $spacing-md;
53
58
  color: var(--theme-fg);
54
59
  max-width: 100%;
55
60
  overflow: hidden;
56
61
  }
57
62
 
63
+ .pane-label {
64
+ font-size: 0.85rem;
65
+ font-weight: 600;
66
+ margin-bottom: $spacing-sm;
67
+ @include text-ellipsis;
68
+ }
69
+
58
70
  .pane-title,
59
71
  .pane-profile {
60
72
  font-size: 0.8rem;
61
73
  font-weight: 500;
62
- margin-bottom: 2px;
63
- white-space: nowrap;
64
- overflow: hidden;
65
- text-overflow: ellipsis;
74
+ margin-bottom: $spacing-xs;
75
+ @include text-ellipsis;
66
76
  }
67
77
 
68
78
  .pane-details {
69
79
  font-size: 0.7rem;
70
80
  opacity: 0.7;
71
- margin-top: 4px;
81
+ margin-top: $spacing-sm;
72
82
 
73
83
  .pane-detail {
74
- display: flex;
75
- align-items: center;
76
- justify-content: center;
77
- gap: 4px;
84
+ @include flex-center;
85
+ gap: $spacing-sm;
78
86
 
79
87
  i {
80
88
  width: 12px;
@@ -83,83 +91,51 @@
83
91
  }
84
92
 
85
93
  span {
86
- overflow: hidden;
87
- text-overflow: ellipsis;
88
- white-space: nowrap;
94
+ @include text-ellipsis;
89
95
  max-width: 100px;
90
96
  }
91
97
  }
92
98
  }
93
99
 
94
- .pane-edit-btn {
95
- position: absolute;
96
- top: 4px;
97
- right: 4px;
98
- padding: 4px 6px;
99
- background: var(--theme-bg);
100
- border: 1px solid var(--theme-border);
101
- border-radius: 4px;
102
- color: var(--theme-fg);
103
- cursor: pointer;
104
- font-size: 0.7rem;
105
- transition: all 0.15s;
106
- opacity: 0;
107
-
108
- &:hover {
109
- background: var(--theme-primary);
110
- color: white;
111
- border-color: var(--theme-primary);
112
- }
113
- }
114
-
115
- .preview-pane:hover .pane-edit-btn {
116
- opacity: 1;
117
- }
118
-
119
100
  // Context menu
120
101
  .context-menu-overlay {
121
- position: fixed;
122
- top: 0;
123
- left: 0;
124
- right: 0;
125
- bottom: 0;
126
- z-index: 1200;
102
+ @include full-overlay($z-context-menu-overlay);
127
103
  }
128
104
 
129
105
  .context-menu {
130
106
  position: fixed;
131
107
  background: var(--theme-bg);
132
- border: 1px solid var(--theme-border);
133
- border-radius: 8px;
134
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
108
+ border: 1px solid var(--theme-border, $fallback-border);
109
+ border-radius: $radius-lg;
110
+ box-shadow: $shadow-context-menu;
135
111
  min-width: 160px;
136
- padding: 4px;
137
- z-index: 1201;
112
+ padding: $spacing-sm;
113
+ z-index: $z-context-menu;
138
114
  }
139
115
 
140
116
  .context-menu-item {
141
117
  display: flex;
142
118
  align-items: center;
143
- gap: 10px;
119
+ gap: $spacing-lg;
144
120
  width: 100%;
145
- padding: 8px 12px;
121
+ padding: $spacing-md $spacing-lg;
146
122
  border: none;
147
123
  background: none;
148
124
  color: var(--theme-fg);
149
125
  font-size: 0.9rem;
150
126
  text-align: left;
151
127
  cursor: pointer;
152
- border-radius: 4px;
128
+ border-radius: $radius-sm;
153
129
 
154
130
  &:hover {
155
131
  background: var(--theme-bg-more);
156
132
  }
157
133
 
158
134
  &.danger {
159
- color: var(--theme-danger, #ef4444);
135
+ color: var(--theme-danger, $color-danger);
160
136
 
161
137
  &:hover {
162
- background: rgba(239, 68, 68, 0.1);
138
+ background: rgba($color-danger, 0.1);
163
139
  }
164
140
  }
165
141
 
@@ -172,8 +148,8 @@
172
148
 
173
149
  .context-menu-divider {
174
150
  height: 1px;
175
- background: var(--theme-border);
176
- margin: 4px 0;
151
+ background: var(--theme-border, $fallback-border);
152
+ margin: $spacing-sm 0;
177
153
  }
178
154
 
179
155
  // Nested splits styling
@@ -1,4 +1,4 @@
1
- import { Component, Input, Output, EventEmitter } from '@angular/core'
1
+ import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef } from '@angular/core'
2
2
  import {
3
3
  WorkspaceSplit,
4
4
  WorkspacePane,
@@ -11,12 +11,11 @@ import {
11
11
  template: require('./splitPreview.component.pug'),
12
12
  styles: [require('./splitPreview.component.scss')],
13
13
  })
14
- export class SplitPreviewComponent {
14
+ export class SplitPreviewComponent implements OnChanges {
15
15
  @Input() split!: WorkspaceSplit
16
16
  @Input() depth = 0
17
17
  @Input() selectedPaneId: string | null = null
18
18
  @Input() profiles: TabbyProfile[] = []
19
- @Output() paneSelect = new EventEmitter<WorkspacePane>()
20
19
  @Output() paneEdit = new EventEmitter<WorkspacePane>()
21
20
  @Output() splitHorizontal = new EventEmitter<WorkspacePane>()
22
21
  @Output() splitVertical = new EventEmitter<WorkspacePane>()
@@ -29,6 +28,15 @@ export class SplitPreviewComponent {
29
28
  contextMenuPane: WorkspacePane | null = null
30
29
  contextMenuPosition = { x: 0, y: 0 }
31
30
 
31
+ constructor(private cdr: ChangeDetectorRef) {}
32
+
33
+ ngOnChanges(changes: SimpleChanges): void {
34
+ // Clear context menu when split input changes to avoid stale state
35
+ if (changes['split']) {
36
+ this.closeContextMenu()
37
+ }
38
+ }
39
+
32
40
  isPane(child: WorkspacePane | WorkspaceSplit): boolean {
33
41
  return !isWorkspaceSplit(child)
34
42
  }
@@ -50,11 +58,6 @@ export class SplitPreviewComponent {
50
58
  }
51
59
 
52
60
  onPaneClick(pane: WorkspacePane): void {
53
- this.paneSelect.emit(pane)
54
- }
55
-
56
- onEditClick(event: MouseEvent, pane: WorkspacePane): void {
57
- event.stopPropagation()
58
61
  this.paneEdit.emit(pane)
59
62
  }
60
63
 
@@ -72,6 +75,7 @@ export class SplitPreviewComponent {
72
75
 
73
76
  closeContextMenu(): void {
74
77
  this.contextMenuPane = null
78
+ this.cdr.detectChanges()
75
79
  }
76
80
 
77
81
  onEdit(): void {
@@ -131,27 +135,13 @@ export class SplitPreviewComponent {
131
135
  }
132
136
 
133
137
  getPaneLabel(pane: WorkspacePane): string {
134
- // Base label is always the profile name
135
- let profileName = ''
136
- if (pane.profileId) {
137
- const profile = this.profiles.find(p => p.id === pane.profileId)
138
- if (profile?.name) profileName = profile.name
139
- }
140
-
141
- if (!profileName) return 'Select profile'
138
+ if (!pane.profileId) return 'Select profile'
142
139
 
143
- // Format: "Title - Profile" or just "Profile"
144
- if (pane.title) {
145
- return `${pane.title} - ${profileName}`
146
- }
147
- return profileName
140
+ const profile = this.profiles.find(p => p.id === pane.profileId)
141
+ return profile?.name || 'Select profile'
148
142
  }
149
143
 
150
144
  // Pass-through events from nested splits
151
- onNestedPaneSelect(pane: WorkspacePane): void {
152
- this.paneSelect.emit(pane)
153
- }
154
-
155
145
  onNestedPaneEdit(pane: WorkspacePane): void {
156
146
  this.paneEdit.emit(pane)
157
147
  }