tabby-tabbyspaces 0.0.1 → 0.2.0

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 (78) hide show
  1. package/.claude/settings.local.json +29 -2
  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 +92 -20
  7. package/CLAUDE.md +196 -15
  8. package/CONTRIBUTING.md +3 -1
  9. package/README.md +80 -61
  10. package/RELEASE.md +91 -0
  11. package/TODO.md +77 -0
  12. package/dist/build-config.d.ts +3 -3
  13. package/dist/components/deleteConfirmModal.component.d.ts +7 -0
  14. package/dist/components/deleteConfirmModal.component.d.ts.map +1 -0
  15. package/dist/components/paneEditor.component.d.ts +9 -13
  16. package/dist/components/paneEditor.component.d.ts.map +1 -1
  17. package/dist/components/splitPreview.component.d.ts +50 -35
  18. package/dist/components/splitPreview.component.d.ts.map +1 -1
  19. package/dist/components/workspaceEditor.component.d.ts +61 -28
  20. package/dist/components/workspaceEditor.component.d.ts.map +1 -1
  21. package/dist/components/workspaceList.component.d.ts +56 -27
  22. package/dist/components/workspaceList.component.d.ts.map +1 -1
  23. package/dist/index.d.ts +6 -6
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +1 -1
  26. package/dist/index.js.LICENSE.txt +1 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/models/workspace.model.d.ts +118 -76
  29. package/dist/models/workspace.model.d.ts.map +1 -1
  30. package/dist/package.json +26 -0
  31. package/dist/providers/config.provider.d.ts +8 -8
  32. package/dist/providers/settings.provider.d.ts +7 -7
  33. package/dist/providers/settings.provider.d.ts.map +1 -1
  34. package/dist/providers/toolbar.provider.d.ts +23 -12
  35. package/dist/providers/toolbar.provider.d.ts.map +1 -1
  36. package/dist/services/startupCommand.service.d.ts +28 -0
  37. package/dist/services/startupCommand.service.d.ts.map +1 -0
  38. package/dist/services/workspaceBackground.service.d.ts +38 -0
  39. package/dist/services/workspaceBackground.service.d.ts.map +1 -0
  40. package/dist/services/workspaceEditor.service.d.ts +46 -24
  41. package/dist/services/workspaceEditor.service.d.ts.map +1 -1
  42. package/docs/DESIGN.md +57 -0
  43. package/docs/SESSION-2026-01-14-S1-DESIGN.md +134 -0
  44. package/docs/marketing_status.md +92 -0
  45. package/mockups/index.html +162 -0
  46. package/mockups/s1-tight-sharp.html +522 -0
  47. package/mockups/shared/base.css +216 -0
  48. package/mockups/v06-tabbed.html +643 -0
  49. package/package.json +3 -7
  50. package/screenshots/editor.png +0 -0
  51. package/screenshots/pane-edit.png +0 -0
  52. package/scripts/build-dev.js +2 -1
  53. package/scripts/build-prod.js +40 -0
  54. package/src/components/deleteConfirmModal.component.ts +23 -0
  55. package/src/components/paneEditor.component.pug +27 -43
  56. package/src/components/paneEditor.component.scss +37 -85
  57. package/src/components/paneEditor.component.ts +6 -16
  58. package/src/components/splitPreview.component.pug +36 -5
  59. package/src/components/splitPreview.component.scss +78 -45
  60. package/src/components/splitPreview.component.ts +83 -18
  61. package/src/components/workspaceEditor.component.pug +162 -74
  62. package/src/components/workspaceEditor.component.scss +261 -108
  63. package/src/components/workspaceEditor.component.ts +294 -31
  64. package/src/components/workspaceList.component.pug +32 -41
  65. package/src/components/workspaceList.component.scss +89 -74
  66. package/src/components/workspaceList.component.ts +181 -44
  67. package/src/index.ts +6 -0
  68. package/src/models/workspace.model.ts +113 -8
  69. package/src/providers/settings.provider.ts +2 -2
  70. package/src/providers/toolbar.provider.ts +113 -13
  71. package/src/services/startupCommand.service.ts +140 -0
  72. package/src/services/workspaceBackground.service.ts +167 -0
  73. package/src/services/workspaceEditor.service.ts +134 -65
  74. package/src/styles/_index.scss +3 -0
  75. package/src/styles/_mixins.scss +180 -0
  76. package/src/styles/_variables.scss +67 -0
  77. package/RELEASE_PLAN.md +0 -161
  78. package/screenshots/workspace-edit.png +0 -0
@@ -0,0 +1,40 @@
1
+ const { execSync } = require('child_process')
2
+ const fs = require('fs')
3
+ const path = require('path')
4
+
5
+ const rootDir = path.resolve(__dirname, '..')
6
+ const distDir = path.join(rootDir, 'dist')
7
+
8
+ // 1. Clean dist
9
+ if (fs.existsSync(distDir)) {
10
+ fs.rmSync(distDir, { recursive: true })
11
+ }
12
+
13
+ // 2. Run webpack
14
+ console.log('Building production version...')
15
+ const webpackCli = path.join(rootDir, 'node_modules', 'webpack-cli', 'bin', 'cli.js')
16
+ execSync(`node "${webpackCli}" --mode production`, {
17
+ cwd: rootDir,
18
+ stdio: 'inherit'
19
+ })
20
+
21
+ // 3. Create package.json
22
+ const pkg = require(path.join(rootDir, 'package.json'))
23
+ const prodPkg = {
24
+ name: pkg.name,
25
+ version: pkg.version,
26
+ description: pkg.description,
27
+ main: 'index.js',
28
+ keywords: pkg.keywords,
29
+ peerDependencies: pkg.peerDependencies,
30
+ author: pkg.author,
31
+ license: pkg.license,
32
+ tabbyPlugin: pkg.tabbyPlugin
33
+ }
34
+
35
+ fs.writeFileSync(
36
+ path.join(distDir, 'package.json'),
37
+ JSON.stringify(prodPkg, null, 2)
38
+ )
39
+
40
+ console.log('Production build complete: dist/')
@@ -0,0 +1,23 @@
1
+ import { Component, Input } from '@angular/core'
2
+ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
3
+
4
+ @Component({
5
+ selector: 'delete-confirm-modal',
6
+ template: `
7
+ <div class="modal-header">
8
+ <h5 class="modal-title">Delete Workspace</h5>
9
+ </div>
10
+ <div class="modal-body">
11
+ <p>Delete workspace "{{ workspaceName }}"?</p>
12
+ <p class="text-muted">This action cannot be undone.</p>
13
+ </div>
14
+ <div class="modal-footer">
15
+ <button class="btn btn-secondary" (click)="modal.dismiss()">Cancel</button>
16
+ <button class="btn btn-danger" (click)="modal.close()" ngbAutofocus>Delete</button>
17
+ </div>
18
+ `,
19
+ })
20
+ export class DeleteConfirmModalComponent {
21
+ @Input() workspaceName = ''
22
+ constructor(public modal: NgbActiveModal) {}
23
+ }
@@ -1,46 +1,30 @@
1
- .pane-editor-overlay((click)='onCancel()')
2
- .pane-editor-modal((click)='$event.stopPropagation()')
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 } 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,24 +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>()
12
+ @Output() close = new EventEmitter<void>()
14
13
 
15
- editedPane!: WorkspacePane
16
-
17
- ngOnInit(): void {
18
- this.editedPane = { ...this.pane }
19
- }
20
-
21
- onSave(): void {
22
- this.save.emit(this.editedPane)
23
- }
24
-
25
- onCancel(): void {
26
- this.cancel.emit()
14
+ @HostListener('document:keydown.escape')
15
+ onEscapeKey(): void {
16
+ this.close.emit()
27
17
  }
28
18
 
29
19
  getProfileName(profileId: string): string {
@@ -1,25 +1,39 @@
1
- .split-preview([class.horizontal]='split.orientation === "horizontal"', [class.vertical]='split.orientation === "vertical"')
1
+ .split-preview([class.horizontal]='split.orientation === "horizontal"', [class.vertical]='split.orientation === "vertical"', [class.nested]='depth > 0')
2
2
  ng-container(*ngFor='let child of split.children; let i = index')
3
3
  //- Pane
4
4
  .preview-pane(
5
5
  *ngIf='isPane(child)',
6
6
  [style.flex-basis]='getFlexStyle(i)',
7
- (click)='onPaneClick(asPane(child))',
7
+ [class.selected]='asPane(child).id === selectedPaneId',
8
+ (click)='onPaneClick(asPane(child)); $event.stopPropagation()',
8
9
  (contextmenu)='onContextMenu($event, asPane(child))'
9
10
  )
10
11
  .pane-content
11
- .pane-label {{ getPaneLabel(asPane(child)) }}
12
- .pane-hint Click to edit
12
+ .pane-label
13
+ | {{ getPaneLabel(asPane(child)) }}
14
+ .pane-details
15
+ .pane-detail(*ngIf='asPane(child).cwd', [title]='asPane(child).cwd')
16
+ i.fas.fa-folder
17
+ span {{ truncate(asPane(child).cwd, 20) }}
18
+ .pane-detail(*ngIf='asPane(child).startupCommand', [title]='asPane(child).startupCommand')
19
+ i.fas.fa-terminal
20
+ span {{ truncate(asPane(child).startupCommand, 20) }}
13
21
 
14
22
  //- Nested split
15
23
  split-preview(
16
24
  *ngIf='isSplit(child)',
17
25
  [split]='asSplit(child)',
18
26
  [depth]='depth + 1',
27
+ [selectedPaneId]='selectedPaneId',
28
+ [profiles]='profiles',
19
29
  [style.flex-basis]='getFlexStyle(i)',
20
- (paneClick)='onNestedPaneClick($event)',
30
+ (paneEdit)='onNestedPaneEdit($event)',
21
31
  (splitHorizontal)='onNestedSplitH($event)',
22
32
  (splitVertical)='onNestedSplitV($event)',
33
+ (addLeft)='onNestedAddLeft($event)',
34
+ (addRight)='onNestedAddRight($event)',
35
+ (addTop)='onNestedAddTop($event)',
36
+ (addBottom)='onNestedAddBottom($event)',
23
37
  (removePane)='onNestedRemove($event)'
24
38
  )
25
39
 
@@ -33,6 +47,10 @@
33
47
  [style.top.px]='contextMenuPosition.y',
34
48
  (click)='$event.stopPropagation()'
35
49
  )
50
+ button.context-menu-item(type='button', (click)='onEdit()')
51
+ i.fas.fa-pen
52
+ | Edit
53
+ .context-menu-divider
36
54
  button.context-menu-item(type='button', (click)='onSplitH()')
37
55
  i.fas.fa-arrows-alt-h
38
56
  | Split Horizontal
@@ -40,6 +58,19 @@
40
58
  i.fas.fa-arrows-alt-v
41
59
  | Split Vertical
42
60
  .context-menu-divider
61
+ button.context-menu-item(type='button', (click)='onAddLeft()')
62
+ i.fas.fa-caret-left
63
+ | Add Left
64
+ button.context-menu-item(type='button', (click)='onAddRight()')
65
+ i.fas.fa-caret-right
66
+ | Add Right
67
+ button.context-menu-item(type='button', (click)='onAddTop()')
68
+ i.fas.fa-caret-up
69
+ | Add Top
70
+ button.context-menu-item(type='button', (click)='onAddBottom()')
71
+ i.fas.fa-caret-down
72
+ | Add Bottom
73
+ .context-menu-divider
43
74
  button.context-menu-item.danger(type='button', (click)='onRemove()')
44
75
  i.fas.fa-trash
45
76
  | Remove Pane
@@ -1,12 +1,14 @@
1
+ @use '../styles/index' as *;
2
+
1
3
  .split-preview {
2
4
  display: flex;
3
5
  width: 100%;
4
- min-height: 200px;
5
- gap: 4px;
6
- border-radius: 8px;
6
+ height: $preview-height;
7
+ gap: $spacing-sm;
8
+ border-radius: $radius-md;
7
9
  overflow: hidden;
8
- background: var(--theme-bg-more);
9
- border: 1px solid var(--theme-border);
10
+ background: var(--theme-bg);
11
+ border: 1px solid var(--theme-border, rgba(255, 255, 255, 0.1));
10
12
 
11
13
  &.horizontal {
12
14
  flex-direction: row;
@@ -15,94 +17,125 @@
15
17
  &.vertical {
16
18
  flex-direction: column;
17
19
  }
20
+
21
+ &.nested {
22
+ height: auto;
23
+ border: 1px dashed var(--theme-fg-more);
24
+ background: $nested-split-bg;
25
+ padding: $spacing-sm;
26
+ border-radius: $radius-sm;
27
+ }
18
28
  }
19
29
 
20
30
  .preview-pane {
21
- display: flex;
22
- align-items: center;
23
- justify-content: center;
24
- background: var(--theme-bg-more-more);
25
- border-radius: 4px;
31
+ @include flex-center;
32
+ background: var(--theme-bg-more);
33
+ border-radius: $radius-sm;
34
+ border: 2px solid var(--theme-border, rgba(255, 255, 255, 0.1));
26
35
  cursor: pointer;
27
- transition: all 0.2s;
36
+ transition: all $transition-fast;
28
37
  position: relative;
29
- min-height: 80px;
38
+ min-height: 50px;
30
39
 
31
40
  &:hover {
32
- background: var(--theme-primary);
33
-
34
- .pane-content {
35
- color: white;
36
- }
41
+ background: var(--theme-bg-more-more);
42
+ border-color: var(--theme-fg-more, rgba(255, 255, 255, 0.3));
43
+ }
37
44
 
38
- .pane-hint {
39
- opacity: 1;
40
- }
45
+ &.selected {
46
+ border-color: var(--theme-primary);
47
+ background: linear-gradient(
48
+ to bottom,
49
+ $selected-pane-gradient-start,
50
+ $selected-pane-gradient-end
51
+ );
41
52
  }
42
53
  }
43
54
 
44
55
  .pane-content {
45
56
  text-align: center;
46
- padding: 12px;
57
+ padding: $spacing-md;
47
58
  color: var(--theme-fg);
59
+ max-width: 100%;
60
+ overflow: hidden;
48
61
  }
49
62
 
50
63
  .pane-label {
51
- font-size: 0.9rem;
64
+ font-size: 0.85rem;
65
+ font-weight: 600;
66
+ margin-bottom: $spacing-sm;
67
+ @include text-ellipsis;
68
+ }
69
+
70
+ .pane-title,
71
+ .pane-profile {
72
+ font-size: 0.8rem;
52
73
  font-weight: 500;
53
- margin-bottom: 4px;
74
+ margin-bottom: $spacing-xs;
75
+ @include text-ellipsis;
54
76
  }
55
77
 
56
- .pane-hint {
57
- font-size: 0.75rem;
58
- opacity: 0.5;
59
- transition: opacity 0.2s;
78
+ .pane-details {
79
+ font-size: 0.7rem;
80
+ opacity: 0.7;
81
+ margin-top: $spacing-sm;
82
+
83
+ .pane-detail {
84
+ @include flex-center;
85
+ gap: $spacing-sm;
86
+
87
+ i {
88
+ width: 12px;
89
+ text-align: center;
90
+ font-size: 0.65rem;
91
+ }
92
+
93
+ span {
94
+ @include text-ellipsis;
95
+ max-width: 100px;
96
+ }
97
+ }
60
98
  }
61
99
 
62
100
  // Context menu
63
101
  .context-menu-overlay {
64
- position: fixed;
65
- top: 0;
66
- left: 0;
67
- right: 0;
68
- bottom: 0;
69
- z-index: 1200;
102
+ @include full-overlay($z-context-menu-overlay);
70
103
  }
71
104
 
72
105
  .context-menu {
73
106
  position: fixed;
74
107
  background: var(--theme-bg);
75
- border: 1px solid var(--theme-border);
76
- border-radius: 8px;
77
- 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;
78
111
  min-width: 160px;
79
- padding: 4px;
80
- z-index: 1201;
112
+ padding: $spacing-sm;
113
+ z-index: $z-context-menu;
81
114
  }
82
115
 
83
116
  .context-menu-item {
84
117
  display: flex;
85
118
  align-items: center;
86
- gap: 10px;
119
+ gap: $spacing-lg;
87
120
  width: 100%;
88
- padding: 8px 12px;
121
+ padding: $spacing-md $spacing-lg;
89
122
  border: none;
90
123
  background: none;
91
124
  color: var(--theme-fg);
92
125
  font-size: 0.9rem;
93
126
  text-align: left;
94
127
  cursor: pointer;
95
- border-radius: 4px;
128
+ border-radius: $radius-sm;
96
129
 
97
130
  &:hover {
98
131
  background: var(--theme-bg-more);
99
132
  }
100
133
 
101
134
  &.danger {
102
- color: var(--theme-danger, #ef4444);
135
+ color: var(--theme-danger, $color-danger);
103
136
 
104
137
  &:hover {
105
- background: rgba(239, 68, 68, 0.1);
138
+ background: rgba($color-danger, 0.1);
106
139
  }
107
140
  }
108
141
 
@@ -115,8 +148,8 @@
115
148
 
116
149
  .context-menu-divider {
117
150
  height: 1px;
118
- background: var(--theme-border);
119
- margin: 4px 0;
151
+ background: var(--theme-border, $fallback-border);
152
+ margin: $spacing-sm 0;
120
153
  }
121
154
 
122
155
  // Nested splits styling