tabby-tabbyspaces 0.2.1 → 0.2.2

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","mappings":"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","sources":["webpack://tabby-tabbyspaces/webpack/universalModuleDefinition","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.scss","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.scss?5edd","webpack://tabby-tabbyspaces/external umd \"@angular/forms\"","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.scss?0de1","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.pug","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.pug","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.pug","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.scss","webpack://tabby-tabbyspaces/./node_modules/css-loader/dist/runtime/api.js","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.scss?e911","webpack://tabby-tabbyspaces/external umd \"tabby-terminal\"","webpack://tabby-tabbyspaces/./node_modules/css-loader/dist/runtime/sourceMaps.js","webpack://tabby-tabbyspaces/external umd \"@angular/common\"","webpack://tabby-tabbyspaces/external umd \"rxjs/operators\"","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.scss","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.pug","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.pug?8802","webpack://tabby-tabbyspaces/external umd \"tabby-core\"","webpack://tabby-tabbyspaces/external umd \"tabby-settings\"","webpack://tabby-tabbyspaces/external umd \"@ng-bootstrap/ng-bootstrap\"","webpack://tabby-tabbyspaces/./node_modules/pug-runtime/index.js","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.pug?b08a","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.scss?c31e","webpack://tabby-tabbyspaces/external umd \"@angular/core\"","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.pug?4d23","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.scss","webpack://tabby-tabbyspaces/external umd \"fs\"","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.pug?e89b","webpack://tabby-tabbyspaces/external umd \"rxjs\"","webpack://tabby-tabbyspaces/webpack/bootstrap","webpack://tabby-tabbyspaces/webpack/runtime/compat get default export","webpack://tabby-tabbyspaces/webpack/runtime/define property getters","webpack://tabby-tabbyspaces/webpack/runtime/hasOwnProperty shorthand","webpack://tabby-tabbyspaces/webpack/runtime/make namespace object","webpack://tabby-tabbyspaces/./src/build-config.ts","webpack://tabby-tabbyspaces/./src/providers/config.provider.ts","webpack://tabby-tabbyspaces/./src/services/startupCommand.service.ts","webpack://tabby-tabbyspaces/./src/models/workspace.model.ts","webpack://tabby-tabbyspaces/./src/services/workspaceEditor.service.ts","webpack://tabby-tabbyspaces/./src/components/deleteConfirmModal.component.ts","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.ts","webpack://tabby-tabbyspaces/./src/providers/settings.provider.ts","webpack://tabby-tabbyspaces/./src/services/workspaceBackground.service.ts","webpack://tabby-tabbyspaces/./src/providers/toolbar.provider.ts","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.ts","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.ts","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.ts","webpack://tabby-tabbyspaces/./src/index.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@angular/core\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"@ng-bootstrap/ng-bootstrap\"), require(\"tabby-terminal\"), require(\"rxjs\"), require(\"rxjs/operators\"), (function webpackLoadOptionalExternalModule() { try { return require(\"fs\"); } catch(e) {} }()));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"@angular/core\", \"@angular/common\", \"@angular/forms\", \"tabby-core\", \"tabby-settings\", \"@ng-bootstrap/ng-bootstrap\", \"tabby-terminal\", \"rxjs\", \"rxjs/operators\", \"fs\"], factory);\n\telse {\n\t\tvar a = typeof exports === 'object' ? factory(require(\"@angular/core\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"@ng-bootstrap/ng-bootstrap\"), require(\"tabby-terminal\"), require(\"rxjs\"), require(\"rxjs/operators\"), (function webpackLoadOptionalExternalModule() { try { return require(\"fs\"); } catch(e) {} }())) : factory(root[\"@angular/core\"], root[\"@angular/common\"], root[\"@angular/forms\"], root[\"tabby-core\"], root[\"tabby-settings\"], root[\"@ng-bootstrap/ng-bootstrap\"], root[\"tabby-terminal\"], root[\"rxjs\"], root[\"rxjs/operators\"], root[\"fs\"]);\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(global, (__WEBPACK_EXTERNAL_MODULE__860__, __WEBPACK_EXTERNAL_MODULE__358__, __WEBPACK_EXTERNAL_MODULE__182__, __WEBPACK_EXTERNAL_MODULE__650__, __WEBPACK_EXTERNAL_MODULE__700__, __WEBPACK_EXTERNAL_MODULE__765__, __WEBPACK_EXTERNAL_MODULE__349__, __WEBPACK_EXTERNAL_MODULE__961__, __WEBPACK_EXTERNAL_MODULE__439__, __WEBPACK_EXTERNAL_MODULE__947__) => {\nreturn ","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.editor-section{margin-bottom:14px}.section-title{font-size:11px;color:var(--theme-fg-more);text-transform:uppercase;letter-spacing:.5px;margin-bottom:10px;display:flex;align-items:center;gap:4px}.form-row{display:flex;gap:10px;align-items:flex-end}.form-group{flex:1;position:relative}.form-group.auto-width{flex:none}.form-group label{display:block;font-size:.7rem;color:var(--theme-fg-less);text-transform:uppercase;letter-spacing:.5px;margin-bottom:2px}.form-group .form-control{padding:4px 6px;border-radius:2px;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));background:var(--theme-bg-more);color:var(--theme-fg);font-size:.85rem}.form-group .form-control:focus{outline:none;border-color:var(--theme-primary)}.form-group .form-control::placeholder{color:var(--theme-fg-more, rgba(255, 255, 255, 0.3))}.form-group .form-control{width:100%;font-size:.8rem;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1)) !important}.form-group .form-control:focus{border-color:var(--theme-primary) !important}.dropdown-trigger{display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;transition:border-color .15s;height:32px;box-sizing:border-box}.dropdown-trigger:hover{border-color:var(--theme-fg-more)}.dropdown-icon{font-size:14px}.dropdown-chevron{color:var(--theme-fg-more);font-size:10px}.icon-dropdown{position:absolute;top:100%;left:0;margin-top:4px;padding:6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px;box-shadow:none;z-index:100;display:grid;grid-template-columns:repeat(6, 28px);gap:4px}.icon-option{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border:1px solid rgba(0,0,0,0);border-radius:2px;background:rgba(0,0,0,0);color:var(--theme-fg-more);cursor:pointer;transition:all .15s;font-size:.85rem}.icon-option:hover{background:var(--theme-bg-more-more);color:var(--theme-fg)}.icon-option.selected{border-color:currentColor;background:var(--theme-bg)}.color-trigger{display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;position:relative;transition:border-color .15s;height:32px;box-sizing:border-box}.color-trigger:hover{border-color:var(--theme-fg-more)}.color-trigger:focus-within{border-color:var(--theme-primary)}.color-trigger .color-input-hidden{position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;cursor:pointer}.dropdown-color{width:16px;height:16px;border-radius:2px}.background-picker{position:relative}.background-trigger{display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;transition:border-color .15s;height:32px;box-sizing:border-box}.background-trigger:hover{border-color:var(--theme-fg-more)}.background-preview{width:48px;height:18px;border-radius:2px;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));display:flex;align-items:center;justify-content:center;color:var(--theme-fg-more, rgba(255, 255, 255, 0.3));font-size:10px}.background-dropdown{position:absolute;top:100%;left:0;right:0;margin-top:4px;padding:6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px;box-shadow:none;z-index:100;min-width:260px}.preset-grid{display:grid;grid-template-columns:repeat(4, 1fr);gap:4px;margin-bottom:6px}.preset-option{aspect-ratio:1.5;height:32px;display:flex;align-items:center;justify-content:center;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;transition:all .15s;color:var(--theme-fg-more, rgba(255, 255, 255, 0.3));font-size:10px}.preset-option:hover{border-color:var(--theme-fg-more)}.preset-option.selected{border-color:var(--theme-primary);border-width:2px}.custom-input-wrapper .custom-bg-input{width:100%;font-size:.7rem}.split-preview-container{background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px;padding:10px}.preview-toolbar{display:flex;justify-content:flex-end;align-items:center;gap:4px;margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid var(--theme-border, rgba(255, 255, 255, 0.1))}.toolbar-separator{width:1px;height:18px;background:var(--theme-border, rgba(255, 255, 255, 0.1));margin:0 4px;align-self:center}.preview-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;color:var(--theme-fg-more, rgba(255, 255, 255, 0.3));cursor:pointer;font-size:10px;transition:all .15s}.preview-btn:hover:not(:disabled){border-color:var(--theme-primary);color:var(--theme-primary)}.preview-btn.danger:hover:not(:disabled){border-color:var(--theme-danger);color:var(--theme-danger)}.preview-btn:disabled{opacity:.4;cursor:not-allowed}.layout-preview{background:var(--theme-bg);border-radius:2px;min-height:150px;max-height:200px;padding:4px}.action-buttons{display:flex;justify-content:space-between;align-items:center;padding-top:14px;border-top:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));margin-top:14px}.checkbox-group{display:flex;align-items:center;gap:4px}.checkbox-group input[type=checkbox]{width:14px;height:14px;margin:0}.checkbox-group label{font-size:.8rem;color:var(--theme-fg);cursor:pointer}.action-buttons-right{display:flex;gap:6px}.action-buttons-right .btn-ghost{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;font-size:.8rem;border-radius:2px;cursor:pointer;transition:all .15s;background:rgba(0,0,0,0);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));color:var(--theme-fg)}.action-buttons-right .btn-ghost:hover{background:var(--theme-bg-more)}.action-buttons-right .btn-success{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;font-size:.8rem;border-radius:2px;cursor:pointer;transition:all .15s;background:#10b981;border-color:#10b981;color:#fff}.action-buttons-right .btn-success:hover{background:#059669;border-color:#059669}.action-buttons-right .unsaved-indicator{color:#f59e0b;font-weight:bold;margin-left:2px}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/workspaceEditor.component.scss\",\"webpack://./src/styles/_variables.scss\",\"webpack://./src/styles/_mixins.scss\"],\"names\":[],\"mappings\":\"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\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n// Editor section\\r\\n.editor-section {\\r\\n margin-bottom: $spacing-xl;\\r\\n}\\r\\n\\r\\n.section-title {\\r\\n font-size: 11px;\\r\\n color: var(--theme-fg-more);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-lg;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n}\\r\\n\\r\\n// Form layout\\r\\n.form-row {\\r\\n display: flex;\\r\\n gap: $spacing-lg;\\r\\n align-items: flex-end;\\r\\n}\\r\\n\\r\\n.form-group {\\r\\n flex: 1;\\r\\n position: relative;\\r\\n\\r\\n &.auto-width {\\r\\n flex: none;\\r\\n }\\r\\n\\r\\n label {\\r\\n @include form-label;\\r\\n }\\r\\n\\r\\n .form-control {\\r\\n @include form-input(var(--theme-bg-more));\\r\\n width: 100%;\\r\\n font-size: $font-sm;\\r\\n // Override Tabby's global border reset\\r\\n border: 1px solid var(--theme-border, $fallback-border) !important;\\r\\n\\r\\n &:focus {\\r\\n border-color: var(--theme-primary) !important;\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n// Dropdown trigger (icon picker)\\r\\n.dropdown-trigger {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: border-color $transition-fast;\\r\\n height: 32px;\\r\\n box-sizing: border-box;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n.dropdown-icon {\\r\\n font-size: 14px;\\r\\n}\\r\\n\\r\\n.dropdown-chevron {\\r\\n color: var(--theme-fg-more);\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n// Icon dropdown\\r\\n.icon-dropdown {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n left: 0;\\r\\n margin-top: $spacing-sm;\\r\\n padding: $spacing-md;\\r\\n @include dropdown-panel;\\r\\n z-index: $z-dropdown;\\r\\n display: grid;\\r\\n grid-template-columns: repeat(6, 28px);\\r\\n gap: $spacing-sm;\\r\\n}\\r\\n\\r\\n.icon-option {\\r\\n width: 28px;\\r\\n height: 28px;\\r\\n @include flex-center;\\r\\n border: 1px solid transparent;\\r\\n border-radius: $radius-sm;\\r\\n background: transparent;\\r\\n color: var(--theme-fg-more);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n color: var(--theme-fg);\\r\\n }\\r\\n\\r\\n &.selected {\\r\\n border-color: currentColor;\\r\\n background: var(--theme-bg);\\r\\n }\\r\\n}\\r\\n\\r\\n// Color trigger (wraps native color input)\\r\\n.color-trigger {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n position: relative;\\r\\n transition: border-color $transition-fast;\\r\\n height: 32px;\\r\\n box-sizing: border-box;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n\\r\\n &:focus-within {\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n .color-input-hidden {\\r\\n position: absolute;\\r\\n top: 0;\\r\\n left: 0;\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n opacity: 0;\\r\\n cursor: pointer;\\r\\n }\\r\\n}\\r\\n\\r\\n.dropdown-color {\\r\\n width: 16px;\\r\\n height: 16px;\\r\\n border-radius: $radius-xs;\\r\\n}\\r\\n\\r\\n// Background picker\\r\\n.background-picker {\\r\\n position: relative;\\r\\n}\\r\\n\\r\\n.background-trigger {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: border-color $transition-fast;\\r\\n height: 32px;\\r\\n box-sizing: border-box;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n.background-preview {\\r\\n width: 48px;\\r\\n height: 18px;\\r\\n border-radius: $radius-xs;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n @include flex-center;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n.background-dropdown {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n left: 0;\\r\\n right: 0;\\r\\n margin-top: $spacing-sm;\\r\\n padding: $spacing-md;\\r\\n @include dropdown-panel;\\r\\n z-index: $z-dropdown;\\r\\n min-width: 260px;\\r\\n}\\r\\n\\r\\n.preset-grid {\\r\\n display: grid;\\r\\n grid-template-columns: repeat(4, 1fr);\\r\\n gap: $spacing-sm;\\r\\n margin-bottom: $spacing-md;\\r\\n}\\r\\n\\r\\n.preset-option {\\r\\n aspect-ratio: 1.5;\\r\\n height: 32px;\\r\\n @include flex-center;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n font-size: 10px;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n\\r\\n &.selected {\\r\\n border-color: var(--theme-primary);\\r\\n border-width: 2px;\\r\\n }\\r\\n}\\r\\n\\r\\n.custom-input-wrapper {\\r\\n .custom-bg-input {\\r\\n width: 100%;\\r\\n font-size: $font-xs;\\r\\n }\\r\\n}\\r\\n\\r\\n// Split preview container\\r\\n.split-preview-container {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n padding: $spacing-lg;\\r\\n}\\r\\n\\r\\n// Preview toolbar\\r\\n.preview-toolbar {\\r\\n display: flex;\\r\\n justify-content: flex-end;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n margin-bottom: $spacing-lg;\\r\\n padding-bottom: $spacing-md;\\r\\n border-bottom: 1px solid var(--theme-border, $fallback-border);\\r\\n}\\r\\n\\r\\n.toolbar-separator {\\r\\n width: 1px;\\r\\n height: 18px;\\r\\n background: var(--theme-border, $fallback-border);\\r\\n margin: 0 $spacing-sm;\\r\\n align-self: center;\\r\\n}\\r\\n\\r\\n.preview-btn {\\r\\n @include icon-btn-sm;\\r\\n}\\r\\n\\r\\n// Layout preview area\\r\\n.layout-preview {\\r\\n background: var(--theme-bg);\\r\\n border-radius: $radius-sm;\\r\\n min-height: 150px;\\r\\n max-height: 200px;\\r\\n padding: $spacing-sm;\\r\\n}\\r\\n\\r\\n// Action buttons\\r\\n.action-buttons {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n align-items: center;\\r\\n padding-top: $spacing-xl;\\r\\n border-top: 1px solid var(--theme-border, $fallback-border);\\r\\n margin-top: $spacing-xl;\\r\\n}\\r\\n\\r\\n.checkbox-group {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n\\r\\n input[type=\\\"checkbox\\\"] {\\r\\n width: 14px;\\r\\n height: 14px;\\r\\n margin: 0;\\r\\n }\\r\\n\\r\\n label {\\r\\n font-size: $font-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n }\\r\\n}\\r\\n\\r\\n.action-buttons-right {\\r\\n display: flex;\\r\\n gap: $spacing-md;\\r\\n\\r\\n .btn-ghost {\\r\\n @include btn-ghost;\\r\\n }\\r\\n\\r\\n .btn-success {\\r\\n @include btn-base;\\r\\n @include btn-success;\\r\\n }\\r\\n\\r\\n .unsaved-indicator {\\r\\n color: $color-warning;\\r\\n font-weight: bold;\\r\\n margin-left: $spacing-xs;\\r\\n }\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\",\"@use 'variables' as *;\\r\\n\\r\\n// ======================\\r\\n// LAYOUT MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin flex-center {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM INPUT MIXIN\\r\\n// ======================\\r\\n\\r\\n@mixin form-input($bg: var(--theme-bg)) {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n border-radius: $radius-sm;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n background: $bg;\\r\\n color: var(--theme-fg);\\r\\n font-size: $font-md;\\r\\n\\r\\n &:focus {\\r\\n outline: none;\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &::placeholder {\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM LABEL MIXIN (S1: Uppercase compact)\\r\\n// ======================\\r\\n\\r\\n@mixin form-label {\\r\\n display: block;\\r\\n font-size: $font-xs;\\r\\n color: var(--theme-fg-less);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-xs;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// BUTTON MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin toolbar-btn {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n background: var(--theme-bg-more-more);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-success {\\r\\n background: $color-success;\\r\\n border-color: $color-success;\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n background: $color-success-hover;\\r\\n border-color: $color-success-hover;\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-base {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-lg;\\r\\n font-size: $font-sm;\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n}\\r\\n\\r\\n@mixin btn-ghost {\\r\\n @include btn-base;\\r\\n background: transparent;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg);\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-primary {\\r\\n @include btn-base;\\r\\n background: var(--theme-primary);\\r\\n border: 1px solid var(--theme-primary);\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n filter: brightness(1.1);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin icon-btn-sm($size: 24px) {\\r\\n width: $size;\\r\\n height: $size;\\r\\n @include flex-center;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: 10px;\\r\\n transition: all $transition-fast;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: var(--theme-primary);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &.danger:hover:not(:disabled) {\\r\\n border-color: var(--theme-danger);\\r\\n color: var(--theme-danger);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// OVERLAY/MODAL MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin full-overlay($z-index: $z-modal-overlay) {\\r\\n position: fixed;\\r\\n top: 0;\\r\\n left: 0;\\r\\n right: 0;\\r\\n bottom: 0;\\r\\n z-index: $z-index;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// TEXT UTILITIES\\r\\n// ======================\\r\\n\\r\\n@mixin text-ellipsis {\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// DROPDOWN/POPUP\\r\\n// ======================\\r\\n\\r\\n@mixin dropdown-panel {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n box-shadow: $shadow-dropdown;\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./paneEditor.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","module.exports = __WEBPACK_EXTERNAL_MODULE__182__;","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./splitPreview.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"editor-section\\\"\\u003E\\u003Cdiv class=\\\"section-title\\\"\\u003E\\u003Ci class=\\\"fas fa-cog\\\"\\u003E\\u003C\\u002Fi\\u003E Workspace Settings\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-row\\\"\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EName\\u003C\\u002Flabel\\u003E\\u003Cinput class=\\\"form-control\\\" #nameInput type=\\\"text\\\" [(ngModel)]=\\\"workspace.name\\\" placeholder=\\\"Workspace name\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group auto-width\\\"\\u003E\\u003Clabel\\u003EIcon\\u003C\\u002Flabel\\u003E\\u003Cdiv class=\\\"dropdown-trigger\\\" (click)=\\\"toggleIconDropdown()\\\"\\u003E\\u003Cspan class=\\\"dropdown-icon\\\" [style.color]=\\\"workspace.color\\\"\\u003E\\u003Ci class=\\\"fas\\\" [class]=\\\"&quot;fa-&quot; + workspace.icon\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"dropdown-chevron\\\"\\u003E\\u003Ci class=\\\"fas fa-chevron-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"icon-dropdown\\\" *ngIf=\\\"iconDropdownOpen\\\"\\u003E\\u003Cbutton class=\\\"icon-option\\\" *ngFor=\\\"let icon of availableIcons\\\" type=\\\"button\\\" [class.selected]=\\\"workspace.icon === icon\\\" [style.color]=\\\"workspace.icon === icon ? workspace.color : null\\\" (click)=\\\"selectIcon(icon)\\\"\\u003E\\u003Ci class=\\\"fas\\\" [class]=\\\"&quot;fa-&quot; + icon\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group auto-width\\\"\\u003E\\u003Clabel\\u003EColor\\u003C\\u002Flabel\\u003E\\u003Cdiv class=\\\"color-trigger\\\"\\u003E\\u003Cspan class=\\\"dropdown-color\\\" [style.background]=\\\"workspace.color\\\"\\u003E\\u003C\\u002Fspan\\u003E\\u003Cinput class=\\\"color-input-hidden\\\" type=\\\"color\\\" [(ngModel)]=\\\"workspace.color\\\"\\u003E\\u003Cspan class=\\\"dropdown-chevron\\\"\\u003E\\u003Ci class=\\\"fas fa-chevron-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group auto-width\\\"\\u003E\\u003Clabel\\u003EBackground\\u003C\\u002Flabel\\u003E\\u003Cdiv class=\\\"background-picker\\\"\\u003E\\u003Cdiv class=\\\"background-trigger\\\" (click)=\\\"toggleBackgroundDropdown()\\\"\\u003E\\u003Cspan class=\\\"background-preview\\\" [style.background]=\\\"workspace.background?.value || &quot;transparent&quot;\\\"\\u003E\\u003Ci class=\\\"fas fa-ban\\\" *ngIf=\\\"!workspace.background?.value\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"dropdown-chevron\\\"\\u003E\\u003Ci class=\\\"fas fa-chevron-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"background-dropdown\\\" *ngIf=\\\"backgroundDropdownOpen\\\"\\u003E\\u003Cdiv class=\\\"preset-grid\\\"\\u003E\\u003Cbutton class=\\\"preset-option\\\" *ngFor=\\\"let preset of backgroundPresets\\\" type=\\\"button\\\" [class.selected]=\\\"isBackgroundSelected(preset)\\\" [style.background]=\\\"preset.value || &quot;var(--theme-bg)&quot;\\\" (click)=\\\"selectBackgroundPreset(preset)\\\"\\u003E\\u003Ci class=\\\"fas fa-ban\\\" *ngIf=\\\"preset.type === &quot;none&quot;\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"custom-input-wrapper\\\"\\u003E\\u003Cinput class=\\\"form-control custom-bg-input\\\" type=\\\"text\\\" [(ngModel)]=\\\"customBackgroundValue\\\" placeholder=\\\"Custom CSS gradient...\\\" (blur)=\\\"applyCustomBackground()\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"editor-section\\\"\\u003E\\u003Cdiv class=\\\"section-title\\\"\\u003E\\u003Ci class=\\\"fas fa-columns\\\"\\u003E\\u003C\\u002Fi\\u003E Split Layout\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"split-preview-container\\\"\\u003E\\u003Cdiv class=\\\"preview-toolbar\\\"\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Split Horizontal\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"splitSelectedPane(&quot;horizontal&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-grip-lines-vertical\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Split Vertical\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"splitSelectedPane(&quot;vertical&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-grip-lines\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cspan class=\\\"toolbar-separator\\\"\\u003E\\u003C\\u002Fspan\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Left\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;left&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-left\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Right\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;right&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-right\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Top\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;top&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-up\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Bottom\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;bottom&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cspan class=\\\"toolbar-separator\\\"\\u003E\\u003C\\u002Fspan\\u003E\\u003Cbutton class=\\\"preview-btn danger\\\" type=\\\"button\\\" title=\\\"Remove pane\\\" [disabled]=\\\"!selectedPaneId || !canRemovePane()\\\" (click)=\\\"removeSelectedPane()\\\"\\u003E\\u003Ci class=\\\"fas fa-trash\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"layout-preview\\\" (click)=\\\"onPreviewBackgroundClick()\\\"\\u003E\\u003Csplit-preview [split]=\\\"workspace.root\\\" [selectedPaneId]=\\\"selectedPaneId\\\" [profiles]=\\\"profiles\\\" (paneEdit)=\\\"editPane($event)\\\" (splitHorizontal)=\\\"splitPane($event, &quot;horizontal&quot;)\\\" (splitVertical)=\\\"splitPane($event, &quot;vertical&quot;)\\\" (addLeft)=\\\"addPaneFromEvent($event, &quot;left&quot;)\\\" (addRight)=\\\"addPaneFromEvent($event, &quot;right&quot;)\\\" (addTop)=\\\"addPaneFromEvent($event, &quot;top&quot;)\\\" (addBottom)=\\\"addPaneFromEvent($event, &quot;bottom&quot;)\\\" (removePane)=\\\"removePane($event)\\\"\\u003E\\u003C\\u002Fsplit-preview\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cpane-editor *ngIf=\\\"showPaneEditor &amp;&amp; editingPane\\\" [pane]=\\\"editingPane\\\" [profiles]=\\\"profiles\\\" (close)=\\\"closePaneEditor()\\\"\\u003E\\u003C\\u002Fpane-editor\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"action-buttons\\\"\\u003E\\u003Cdiv class=\\\"checkbox-group\\\"\\u003E\\u003Cinput type=\\\"checkbox\\\" [(ngModel)]=\\\"workspace.launchOnStartup\\\" id=\\\"launchStartup\\\"\\u003E\\u003Clabel for=\\\"launchStartup\\\"\\u003ELaunch on startup\\u003C\\u002Flabel\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"action-buttons-right\\\"\\u003E\\u003Cbutton class=\\\"btn btn-ghost\\\" type=\\\"button\\\" (click)=\\\"onCancel()\\\"\\u003E\\u003Ci class=\\\"fas fa-xmark\\\"\\u003E\\u003C\\u002Fi\\u003E Cancel\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"btn btn-success\\\" type=\\\"button\\\" (click)=\\\"onSave()\\\" [disabled]=\\\"!workspace.name?.trim() || !hasUnsavedChanges\\\"\\u003E\\u003Ci class=\\\"fas fa-check\\\"\\u003E\\u003C\\u002Fi\\u003E Save\\u003Cspan class=\\\"unsaved-indicator\\\" *ngIf=\\\"hasUnsavedChanges\\\"\\u003E*\\u003C\\u002Fspan\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"pane-details\\\"\\u003E\\u003Cdiv class=\\\"pane-details-header\\\"\\u003E\\u003Cspan class=\\\"pane-details-title\\\"\\u003E\\u003Ci class=\\\"fas fa-terminal\\\"\\u003E\\u003C\\u002Fi\\u003E Pane Configuration\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"pane-form\\\"\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EProfile\\u003C\\u002Flabel\\u003E\\u003Cselect class=\\\"form-control\\\" [(ngModel)]=\\\"pane.profileId\\\"\\u003E\\u003Coption value=\\\"\\\"\\u003E-- Select Profile --\\u003C\\u002Foption\\u003E\\u003Coption *ngFor=\\\"let profile of profiles\\\" [value]=\\\"profile.id\\\"\\u003E{{ profile.name }}\\u003C\\u002Foption\\u003E\\u003C\\u002Fselect\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EWorking Directory\\u003C\\u002Flabel\\u003E\\u003Cinput class=\\\"form-control\\\" type=\\\"text\\\" [(ngModel)]=\\\"pane.cwd\\\" placeholder=\\\"C:\\\\path\\\\to\\\\project\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EStartup Command\\u003C\\u002Flabel\\u003E\\u003Cinput class=\\\"form-control\\\" type=\\\"text\\\" [(ngModel)]=\\\"pane.startupCommand\\\" placeholder=\\\"e.g., npm run dev\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"workspace-list-container\\\"\\u003E\\u003Cdiv class=\\\"tab-bar\\\"\\u003E\\u003Cdiv class=\\\"tab\\\" *ngFor=\\\"let tab of displayTabs; trackBy: trackByTab\\\" [class.active]=\\\"isTabSelected(tab)\\\" (click)=\\\"!tab.isNew &amp;&amp; selectWorkspace(tab.workspace)\\\"\\u003E\\u003Cspan class=\\\"tab-icon\\\" [style.color]=\\\"tab.workspace.color\\\"\\u003E\\u003Ci class=\\\"fas\\\" [class]=\\\"&quot;fa-&quot; + (tab.workspace.icon || &quot;columns&quot;)\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"tab-name\\\"\\u003E{{ tab.workspace.name || 'New Workspace' }}\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"tab-close\\\" *ngIf=\\\"!tab.isNew\\\" (click)=\\\"deleteWorkspace($event, tab.workspace)\\\" title=\\\"Delete workspace\\\"\\u003E\\u003Ci class=\\\"fas fa-xmark\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"tab-new\\\" (click)=\\\"createWorkspace()\\\" title=\\\"New workspace\\\"\\u003E\\u003Ci class=\\\"fas fa-plus\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"tab-content\\\" *ngIf=\\\"editingWorkspace\\\"\\u003E\\u003Cworkspace-editor [workspace]=\\\"editingWorkspace\\\" [autoFocus]=\\\"isCreatingNew\\\" [hasUnsavedChanges]=\\\"hasUnsavedChanges\\\" (save)=\\\"onEditorSave($event)\\\" (cancel)=\\\"onEditorCancel()\\\"\\u003E\\u003C\\u002Fworkspace-editor\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"tab-content empty-state\\\" *ngIf=\\\"!editingWorkspace &amp;&amp; workspaces.length === 0\\\"\\u003E\\u003Cp\\u003ENo workspaces configured yet.\\u003C\\u002Fp\\u003E\\u003Cp\\u003EClick\\u003Cstrong\\u003E+\\u003C\\u002Fstrong\\u003Eto create your first workspace.\\u003C\\u002Fp\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.split-preview{display:flex;width:100%;height:140px;gap:4px;border-radius:3px;overflow:hidden;background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1))}.split-preview.horizontal{flex-direction:row}.split-preview.vertical{flex-direction:column}.split-preview.nested{height:auto;border:1px dashed var(--theme-fg-more);background:hsla(0,0%,100%,.02);padding:4px;border-radius:2px}.preview-pane{display:flex;align-items:center;justify-content:center;background:var(--theme-bg-more);border-radius:2px;border:2px solid var(--theme-border, rgba(255, 255, 255, 0.1));cursor:pointer;transition:all .15s;position:relative;min-height:50px}.preview-pane:hover{background:var(--theme-bg-more-more);border-color:var(--theme-fg-more, rgba(255, 255, 255, 0.3))}.preview-pane.selected{border-color:var(--theme-primary);background:linear-gradient(to bottom, rgba(59, 130, 246, 0.08), rgba(59, 130, 246, 0.04))}.pane-content{text-align:center;padding:6px;color:var(--theme-fg);max-width:100%;overflow:hidden}.pane-label{font-size:.85rem;font-weight:600;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pane-title,.pane-profile{font-size:.8rem;font-weight:500;margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pane-details{font-size:.7rem;opacity:.7;margin-top:4px}.pane-details .pane-detail{display:flex;align-items:center;justify-content:center;gap:4px}.pane-details .pane-detail i{width:12px;text-align:center;font-size:.65rem}.pane-details .pane-detail span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100px}.context-menu-overlay{position:fixed;top:0;left:0;right:0;bottom:0;z-index:1200}.context-menu{position:fixed;background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:4px;box-shadow:none;min-width:160px;padding:4px;z-index:1201}.context-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:6px 10px;border:none;background:none;color:var(--theme-fg);font-size:.9rem;text-align:left;cursor:pointer;border-radius:2px}.context-menu-item:hover{background:var(--theme-bg-more)}.context-menu-item.danger{color:var(--theme-danger, #ef4444)}.context-menu-item.danger:hover{background:rgba(239,68,68,.1)}.context-menu-item i{width:16px;text-align:center;opacity:.7}.context-menu-divider{height:1px;background:var(--theme-border, rgba(255, 255, 255, 0.1));margin:4px 0}:host{display:flex;flex:1}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/splitPreview.component.scss\",\"webpack://./src/styles/_variables.scss\",\"webpack://./src/styles/_mixins.scss\"],\"names\":[],\"mappings\":\"AAEA,eACE,YAAA,CACA,UAAA,CACA,YCqCe,CDpCf,OCFW,CDGX,iBCQU,CDPV,eAAA,CACA,0BAAA,CACA,8DAAA,CAEA,0BACE,kBAAA,CAGF,wBACE,qBAAA,CAGF,sBACE,WAAA,CACA,sCAAA,CACA,8BCoBc,CDnBd,WCpBS,CDqBT,iBCXQ,CDeZ,cEtBE,YAAA,CACA,kBAAA,CACA,sBAAA,CFsBA,+BAAA,CACA,iBClBU,CDmBV,8DAAA,CACA,cAAA,CACA,mBAAA,CACA,iBAAA,CACA,eAAA,CAEA,oBACE,oCAAA,CACA,2DAAA,CAGF,uBACE,iCAAA,CACA,yFAAA,CAQJ,cACE,iBAAA,CACA,WCnDW,CDoDX,qBAAA,CACA,cAAA,CACA,eAAA,CAGF,YACE,gBAAA,CACA,eAAA,CACA,iBC7DW,CCiKX,kBAAA,CACA,eAAA,CACA,sBAAA,CFlGF,0BAEE,eAAA,CACA,eAAA,CACA,iBCtEW,CCkKX,kBAAA,CACA,eAAA,CACA,sBAAA,CF1FF,cACE,eAAA,CACA,UAAA,CACA,cC5EW,CD8EX,2BE3EA,YAAA,CACA,kBAAA,CACA,sBAAA,CF2EE,OChFS,CDkFT,6BACE,UAAA,CACA,iBAAA,CACA,gBAAA,CAGF,gCEyEF,kBAAA,CACA,eAAA,CACA,sBAAA,CFzEI,eAAA,CAMN,sBEoDE,cAAA,CACA,KAAA,CACA,MAAA,CACA,OAAA,CACA,QAAA,CACA,YDlGuB,CD6CzB,cACE,cAAA,CACA,0BAAA,CACA,8DAAA,CACA,iBC5FU,CD6FV,eC1EoB,CD2EpB,eAAA,CACA,WC3GW,CD4GX,YCpDe,CDuDjB,mBACE,YAAA,CACA,kBAAA,CACA,QChHW,CDiHX,UAAA,CACA,gBAAA,CACA,WAAA,CACA,eAAA,CACA,qBAAA,CACA,eAAA,CACA,eAAA,CACA,cAAA,CACA,iBCjHU,CDmHV,yBACE,+BAAA,CAGF,0BACE,kCAAA,CAEA,gCACE,6BAAA,CAIJ,qBACE,UAAA,CACA,iBAAA,CACA,UAAA,CAIJ,sBACE,UAAA,CACA,wDAAA,CACA,YAAA,CAIF,MACE,YAAA,CACA,MAAA\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n.split-preview {\\r\\n display: flex;\\r\\n width: 100%;\\r\\n height: $preview-height;\\r\\n gap: $spacing-sm;\\r\\n border-radius: $radius-md;\\r\\n overflow: hidden;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, rgba(255, 255, 255, 0.1));\\r\\n\\r\\n &.horizontal {\\r\\n flex-direction: row;\\r\\n }\\r\\n\\r\\n &.vertical {\\r\\n flex-direction: column;\\r\\n }\\r\\n\\r\\n &.nested {\\r\\n height: auto;\\r\\n border: 1px dashed var(--theme-fg-more);\\r\\n background: $nested-split-bg;\\r\\n padding: $spacing-sm;\\r\\n border-radius: $radius-sm;\\r\\n }\\r\\n}\\r\\n\\r\\n.preview-pane {\\r\\n @include flex-center;\\r\\n background: var(--theme-bg-more);\\r\\n border-radius: $radius-sm;\\r\\n border: 2px solid var(--theme-border, rgba(255, 255, 255, 0.1));\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n position: relative;\\r\\n min-height: 50px;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n border-color: var(--theme-fg-more, rgba(255, 255, 255, 0.3));\\r\\n }\\r\\n\\r\\n &.selected {\\r\\n border-color: var(--theme-primary);\\r\\n background: linear-gradient(\\r\\n to bottom,\\r\\n $selected-pane-gradient-start,\\r\\n $selected-pane-gradient-end\\r\\n );\\r\\n }\\r\\n}\\r\\n\\r\\n.pane-content {\\r\\n text-align: center;\\r\\n padding: $spacing-md;\\r\\n color: var(--theme-fg);\\r\\n max-width: 100%;\\r\\n overflow: hidden;\\r\\n}\\r\\n\\r\\n.pane-label {\\r\\n font-size: 0.85rem;\\r\\n font-weight: 600;\\r\\n margin-bottom: $spacing-sm;\\r\\n @include text-ellipsis;\\r\\n}\\r\\n\\r\\n.pane-title,\\r\\n.pane-profile {\\r\\n font-size: 0.8rem;\\r\\n font-weight: 500;\\r\\n margin-bottom: $spacing-xs;\\r\\n @include text-ellipsis;\\r\\n}\\r\\n\\r\\n.pane-details {\\r\\n font-size: 0.7rem;\\r\\n opacity: 0.7;\\r\\n margin-top: $spacing-sm;\\r\\n\\r\\n .pane-detail {\\r\\n @include flex-center;\\r\\n gap: $spacing-sm;\\r\\n\\r\\n i {\\r\\n width: 12px;\\r\\n text-align: center;\\r\\n font-size: 0.65rem;\\r\\n }\\r\\n\\r\\n span {\\r\\n @include text-ellipsis;\\r\\n max-width: 100px;\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n// Context menu\\r\\n.context-menu-overlay {\\r\\n @include full-overlay($z-context-menu-overlay);\\r\\n}\\r\\n\\r\\n.context-menu {\\r\\n position: fixed;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-lg;\\r\\n box-shadow: $shadow-context-menu;\\r\\n min-width: 160px;\\r\\n padding: $spacing-sm;\\r\\n z-index: $z-context-menu;\\r\\n}\\r\\n\\r\\n.context-menu-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-lg;\\r\\n width: 100%;\\r\\n padding: $spacing-md $spacing-lg;\\r\\n border: none;\\r\\n background: none;\\r\\n color: var(--theme-fg);\\r\\n font-size: 0.9rem;\\r\\n text-align: left;\\r\\n cursor: pointer;\\r\\n border-radius: $radius-sm;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n\\r\\n &:hover {\\r\\n background: rgba($color-danger, 0.1);\\r\\n }\\r\\n }\\r\\n\\r\\n i {\\r\\n width: 16px;\\r\\n text-align: center;\\r\\n opacity: 0.7;\\r\\n }\\r\\n}\\r\\n\\r\\n.context-menu-divider {\\r\\n height: 1px;\\r\\n background: var(--theme-border, $fallback-border);\\r\\n margin: $spacing-sm 0;\\r\\n}\\r\\n\\r\\n// Nested splits styling\\r\\n:host {\\r\\n display: flex;\\r\\n flex: 1;\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\",\"@use 'variables' as *;\\r\\n\\r\\n// ======================\\r\\n// LAYOUT MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin flex-center {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM INPUT MIXIN\\r\\n// ======================\\r\\n\\r\\n@mixin form-input($bg: var(--theme-bg)) {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n border-radius: $radius-sm;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n background: $bg;\\r\\n color: var(--theme-fg);\\r\\n font-size: $font-md;\\r\\n\\r\\n &:focus {\\r\\n outline: none;\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &::placeholder {\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM LABEL MIXIN (S1: Uppercase compact)\\r\\n// ======================\\r\\n\\r\\n@mixin form-label {\\r\\n display: block;\\r\\n font-size: $font-xs;\\r\\n color: var(--theme-fg-less);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-xs;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// BUTTON MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin toolbar-btn {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n background: var(--theme-bg-more-more);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-success {\\r\\n background: $color-success;\\r\\n border-color: $color-success;\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n background: $color-success-hover;\\r\\n border-color: $color-success-hover;\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-base {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-lg;\\r\\n font-size: $font-sm;\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n}\\r\\n\\r\\n@mixin btn-ghost {\\r\\n @include btn-base;\\r\\n background: transparent;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg);\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-primary {\\r\\n @include btn-base;\\r\\n background: var(--theme-primary);\\r\\n border: 1px solid var(--theme-primary);\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n filter: brightness(1.1);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin icon-btn-sm($size: 24px) {\\r\\n width: $size;\\r\\n height: $size;\\r\\n @include flex-center;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: 10px;\\r\\n transition: all $transition-fast;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: var(--theme-primary);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &.danger:hover:not(:disabled) {\\r\\n border-color: var(--theme-danger);\\r\\n color: var(--theme-danger);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// OVERLAY/MODAL MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin full-overlay($z-index: $z-modal-overlay) {\\r\\n position: fixed;\\r\\n top: 0;\\r\\n left: 0;\\r\\n right: 0;\\r\\n bottom: 0;\\r\\n z-index: $z-index;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// TEXT UTILITIES\\r\\n// ======================\\r\\n\\r\\n@mixin text-ellipsis {\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// DROPDOWN/POPUP\\r\\n// ======================\\r\\n\\r\\n@mixin dropdown-panel {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n box-shadow: $shadow-dropdown;\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\"use strict\";\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./workspaceList.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","module.exports = __WEBPACK_EXTERNAL_MODULE__349__;","\"use strict\";\n\nmodule.exports = function (item) {\n var content = item[1];\n var cssMapping = item[3];\n if (!cssMapping) {\n return content;\n }\n if (typeof btoa === \"function\") {\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n var sourceMapping = \"/*# \".concat(data, \" */\");\n return [content].concat([sourceMapping]).join(\"\\n\");\n }\n return [content].join(\"\\n\");\n};","module.exports = __WEBPACK_EXTERNAL_MODULE__358__;","module.exports = __WEBPACK_EXTERNAL_MODULE__439__;","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.workspace-list-container{padding:18px}.tab-bar{display:flex;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-bottom:none;overflow-y:hidden;overflow-x:auto}.tab-bar::-webkit-scrollbar{height:6px}.tab-bar::-webkit-scrollbar-track{background:var(--theme-bg-more)}.tab-bar::-webkit-scrollbar-thumb{background:var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px}.tab-bar::-webkit-scrollbar-thumb:hover{background:var(--theme-fg-more)}.tab{display:flex;align-items:center;gap:6px;padding:6px 10px;border-right:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));color:var(--theme-fg-more);cursor:pointer;font-size:.8rem;min-width:120px;transition:background .15s}.tab:hover{background:var(--theme-bg-more-more)}.tab:hover .tab-close{opacity:1}.tab.active{background:var(--theme-bg);color:var(--theme-fg);border-bottom:2px solid var(--theme-primary);margin-bottom:-1px}.tab-icon{font-size:12px}.tab-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tab-close{width:16px;height:16px;display:flex;align-items:center;justify-content:center;opacity:0;font-size:9px;border-radius:2px;transition:opacity .15s,background .15s}.tab-close:hover{background:var(--theme-danger);color:#fff}.tab-new{display:flex;align-items:center;justify-content:center;width:36px;color:var(--theme-fg-more);cursor:pointer;transition:color .15s,background .15s}.tab-new:hover{background:var(--theme-bg-more-more);color:var(--theme-primary)}.tab-content{background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-top:none;padding:14px}.tab-content.empty-state{text-align:center;padding:18px;color:var(--theme-fg-more)}.tab-content.empty-state p{margin:6px 0}.tab-content.empty-state strong{color:var(--theme-primary);padding:0 2px}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/workspaceList.component.scss\",\"webpack://./src/styles/_variables.scss\"],\"names\":[],\"mappings\":\"AAEA,0BACE,YCKY,CDDd,SACE,YAAA,CACA,+BAAA,CACA,8DAAA,CACA,kBAAA,CACA,iBAAA,CACA,eAAA,CAGA,4BACE,UAAA,CAGF,kCACE,+BAAA,CAGF,kCACE,wDAAA,CACA,iBAAA,CAEA,wCACE,+BAAA,CAKN,KACE,YAAA,CACA,kBAAA,CACA,OChCW,CDiCX,gBAAA,CACA,oEAAA,CACA,0BAAA,CACA,cAAA,CACA,eCSQ,CDRR,eAAA,CACA,0BAAA,CAEA,WACE,oCAAA,CAEA,sBACE,SAAA,CAIJ,YACE,0BAAA,CACA,qBAAA,CACA,4CAAA,CACA,kBAAA,CAIJ,UACE,cAAA,CAGF,UACE,MAAA,CACA,kBAAA,CACA,eAAA,CACA,sBAAA,CAGF,WACE,UAAA,CACA,WAAA,CACA,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,SAAA,CACA,aAAA,CACA,iBCpEU,CDqEV,uCAAA,CAEA,iBACE,8BAAA,CACA,UAAA,CAIJ,SACE,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,UAAA,CACA,0BAAA,CACA,cAAA,CACA,qCAAA,CAEA,eACE,oCAAA,CACA,0BAAA,CAKJ,aACE,0BAAA,CACA,8DAAA,CACA,eAAA,CACA,YCvGW,CDyGX,yBACE,iBAAA,CACA,YC1GU,CD2GV,0BAAA,CAEA,2BACE,YAAA,CAGF,gCACE,0BAAA,CACA,aAAA\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n.workspace-list-container {\\r\\n padding: $spacing-2xl;\\r\\n}\\r\\n\\r\\n// Tab bar\\r\\n.tab-bar {\\r\\n display: flex;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-bottom: none;\\r\\n overflow-y: hidden;\\r\\n overflow-x: auto;\\r\\n\\r\\n // Thin scrollbar\\r\\n &::-webkit-scrollbar {\\r\\n height: 6px;\\r\\n }\\r\\n\\r\\n &::-webkit-scrollbar-track {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n\\r\\n &::-webkit-scrollbar-thumb {\\r\\n background: var(--theme-border, $fallback-border);\\r\\n border-radius: 3px;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-fg-more);\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n.tab {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-md;\\r\\n padding: $spacing-md $spacing-lg;\\r\\n border-right: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: $font-sm;\\r\\n min-width: 120px;\\r\\n transition: background $transition-fast;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n\\r\\n .tab-close {\\r\\n opacity: 1;\\r\\n }\\r\\n }\\r\\n\\r\\n &.active {\\r\\n background: var(--theme-bg);\\r\\n color: var(--theme-fg);\\r\\n border-bottom: 2px solid var(--theme-primary);\\r\\n margin-bottom: -1px;\\r\\n }\\r\\n}\\r\\n\\r\\n.tab-icon {\\r\\n font-size: 12px;\\r\\n}\\r\\n\\r\\n.tab-name {\\r\\n flex: 1;\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n.tab-close {\\r\\n width: 16px;\\r\\n height: 16px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n opacity: 0;\\r\\n font-size: 9px;\\r\\n border-radius: $radius-xs;\\r\\n transition: opacity $transition-fast, background $transition-fast;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-danger);\\r\\n color: white;\\r\\n }\\r\\n}\\r\\n\\r\\n.tab-new {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n color: var(--theme-fg-more);\\r\\n cursor: pointer;\\r\\n transition: color $transition-fast, background $transition-fast;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n}\\r\\n\\r\\n// Tab content\\r\\n.tab-content {\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-top: none;\\r\\n padding: $spacing-xl;\\r\\n\\r\\n &.empty-state {\\r\\n text-align: center;\\r\\n padding: $spacing-2xl;\\r\\n color: var(--theme-fg-more);\\r\\n\\r\\n p {\\r\\n margin: $spacing-md 0;\\r\\n }\\r\\n\\r\\n strong {\\r\\n color: var(--theme-primary);\\r\\n padding: 0 $spacing-xs;\\r\\n }\\r\\n }\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"split-preview\\\" [class.horizontal]=\\\"split.orientation === &quot;horizontal&quot;\\\" [class.vertical]=\\\"split.orientation === &quot;vertical&quot;\\\" [class.nested]=\\\"depth &gt; 0\\\"\\u003E\\u003Cng-container *ngFor=\\\"let child of split.children; let i = index\\\"\\u003E\\u003Cdiv class=\\\"preview-pane\\\" *ngIf=\\\"isPane(child)\\\" [style.flex-basis]=\\\"getFlexStyle(i)\\\" [class.selected]=\\\"asPane(child).id === selectedPaneId\\\" (click)=\\\"onPaneClick(asPane(child)); $event.stopPropagation()\\\" (contextmenu)=\\\"onContextMenu($event, asPane(child))\\\"\\u003E\\u003Cdiv class=\\\"pane-content\\\"\\u003E\\u003Cdiv class=\\\"pane-label\\\"\\u003E{{ getPaneLabel(asPane(child)) }}\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"pane-details\\\"\\u003E\\u003Cdiv class=\\\"pane-detail\\\" *ngIf=\\\"asPane(child).cwd\\\" [title]=\\\"asPane(child).cwd\\\"\\u003E\\u003Ci class=\\\"fas fa-folder\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003Cspan\\u003E{{ truncate(asPane(child).cwd, 20) }}\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"pane-detail\\\" *ngIf=\\\"asPane(child).startupCommand\\\" [title]=\\\"asPane(child).startupCommand\\\"\\u003E\\u003Ci class=\\\"fas fa-terminal\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003Cspan\\u003E{{ truncate(asPane(child).startupCommand, 20) }}\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Csplit-preview *ngIf=\\\"isSplit(child)\\\" [split]=\\\"asSplit(child)\\\" [depth]=\\\"depth + 1\\\" [selectedPaneId]=\\\"selectedPaneId\\\" [profiles]=\\\"profiles\\\" [style.flex-basis]=\\\"getFlexStyle(i)\\\" (paneEdit)=\\\"onNestedPaneEdit($event)\\\" (splitHorizontal)=\\\"onNestedSplitH($event)\\\" (splitVertical)=\\\"onNestedSplitV($event)\\\" (addLeft)=\\\"onNestedAddLeft($event)\\\" (addRight)=\\\"onNestedAddRight($event)\\\" (addTop)=\\\"onNestedAddTop($event)\\\" (addBottom)=\\\"onNestedAddBottom($event)\\\" (removePane)=\\\"onNestedRemove($event)\\\"\\u003E\\u003C\\u002Fsplit-preview\\u003E\\u003C\\u002Fng-container\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"context-menu-overlay\\\" *ngIf=\\\"contextMenuPane\\\" (click)=\\\"closeContextMenu()\\\"\\u003E\\u003Cdiv class=\\\"context-menu\\\" [style.left.px]=\\\"contextMenuPosition.x\\\" [style.top.px]=\\\"contextMenuPosition.y\\\" (click)=\\\"$event.stopPropagation()\\\"\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onEdit()\\\"\\u003E\\u003Ci class=\\\"fas fa-pen\\\"\\u003E\\u003C\\u002Fi\\u003E Edit\\u003C\\u002Fbutton\\u003E\\u003Cdiv class=\\\"context-menu-divider\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onSplitH()\\\"\\u003E\\u003Ci class=\\\"fas fa-arrows-alt-h\\\"\\u003E\\u003C\\u002Fi\\u003E Split Horizontal\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onSplitV()\\\"\\u003E\\u003Ci class=\\\"fas fa-arrows-alt-v\\\"\\u003E\\u003C\\u002Fi\\u003E Split Vertical\\u003C\\u002Fbutton\\u003E\\u003Cdiv class=\\\"context-menu-divider\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddLeft()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-left\\\"\\u003E\\u003C\\u002Fi\\u003E Add Left\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddRight()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-right\\\"\\u003E\\u003C\\u002Fi\\u003E Add Right\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddTop()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-up\\\"\\u003E\\u003C\\u002Fi\\u003E Add Top\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddBottom()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-down\\\"\\u003E\\u003C\\u002Fi\\u003E Add Bottom\\u003C\\u002Fbutton\\u003E\\u003Cdiv class=\\\"context-menu-divider\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cbutton class=\\\"context-menu-item danger\\\" type=\\\"button\\\" (click)=\\\"onRemove()\\\"\\u003E\\u003Ci class=\\\"fas fa-trash\\\"\\u003E\\u003C\\u002Fi\\u003E Remove Pane\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/splitPreview.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","module.exports = __WEBPACK_EXTERNAL_MODULE__650__;","module.exports = __WEBPACK_EXTERNAL_MODULE__700__;","module.exports = __WEBPACK_EXTERNAL_MODULE__765__;","'use strict';\n\nvar pug_has_own_property = Object.prototype.hasOwnProperty;\n\n/**\n * Merge two attribute objects giving precedence\n * to values in object `b`. Classes are special-cased\n * allowing for arrays and merging/joining appropriately\n * resulting in a string.\n *\n * @param {Object} a\n * @param {Object} b\n * @return {Object} a\n * @api private\n */\n\nexports.merge = pug_merge;\nfunction pug_merge(a, b) {\n if (arguments.length === 1) {\n var attrs = a[0];\n for (var i = 1; i < a.length; i++) {\n attrs = pug_merge(attrs, a[i]);\n }\n return attrs;\n }\n\n for (var key in b) {\n if (key === 'class') {\n var valA = a[key] || [];\n a[key] = (Array.isArray(valA) ? valA : [valA]).concat(b[key] || []);\n } else if (key === 'style') {\n var valA = pug_style(a[key]);\n valA = valA && valA[valA.length - 1] !== ';' ? valA + ';' : valA;\n var valB = pug_style(b[key]);\n valB = valB && valB[valB.length - 1] !== ';' ? valB + ';' : valB;\n a[key] = valA + valB;\n } else {\n a[key] = b[key];\n }\n }\n\n return a;\n}\n\n/**\n * Process array, object, or string as a string of classes delimited by a space.\n *\n * If `val` is an array, all members of it and its subarrays are counted as\n * classes. If `escaping` is an array, then whether or not the item in `val` is\n * escaped depends on the corresponding item in `escaping`. If `escaping` is\n * not an array, no escaping is done.\n *\n * If `val` is an object, all the keys whose value is truthy are counted as\n * classes. No escaping is done.\n *\n * If `val` is a string, it is counted as a class. No escaping is done.\n *\n * @param {(Array.<string>|Object.<string, boolean>|string)} val\n * @param {?Array.<string>} escaping\n * @return {String}\n */\nexports.classes = pug_classes;\nfunction pug_classes_array(val, escaping) {\n var classString = '',\n className,\n padding = '',\n escapeEnabled = Array.isArray(escaping);\n for (var i = 0; i < val.length; i++) {\n className = pug_classes(val[i]);\n if (!className) continue;\n escapeEnabled && escaping[i] && (className = pug_escape(className));\n classString = classString + padding + className;\n padding = ' ';\n }\n return classString;\n}\nfunction pug_classes_object(val) {\n var classString = '',\n padding = '';\n for (var key in val) {\n if (key && val[key] && pug_has_own_property.call(val, key)) {\n classString = classString + padding + key;\n padding = ' ';\n }\n }\n return classString;\n}\nfunction pug_classes(val, escaping) {\n if (Array.isArray(val)) {\n return pug_classes_array(val, escaping);\n } else if (val && typeof val === 'object') {\n return pug_classes_object(val);\n } else {\n return val || '';\n }\n}\n\n/**\n * Convert object or string to a string of CSS styles delimited by a semicolon.\n *\n * @param {(Object.<string, string>|string)} val\n * @return {String}\n */\n\nexports.style = pug_style;\nfunction pug_style(val) {\n if (!val) return '';\n if (typeof val === 'object') {\n var out = '';\n for (var style in val) {\n /* istanbul ignore else */\n if (pug_has_own_property.call(val, style)) {\n out = out + style + ':' + val[style] + ';';\n }\n }\n return out;\n } else {\n return val + '';\n }\n}\n\n/**\n * Render the given attribute.\n *\n * @param {String} key\n * @param {String} val\n * @param {Boolean} escaped\n * @param {Boolean} terse\n * @return {String}\n */\nexports.attr = pug_attr;\nfunction pug_attr(key, val, escaped, terse) {\n if (\n val === false ||\n val == null ||\n (!val && (key === 'class' || key === 'style'))\n ) {\n return '';\n }\n if (val === true) {\n return ' ' + (terse ? key : key + '=\"' + key + '\"');\n }\n var type = typeof val;\n if (\n (type === 'object' || type === 'function') &&\n typeof val.toJSON === 'function'\n ) {\n val = val.toJSON();\n }\n if (typeof val !== 'string') {\n val = JSON.stringify(val);\n if (!escaped && val.indexOf('\"') !== -1) {\n return ' ' + key + \"='\" + val.replace(/'/g, '&#39;') + \"'\";\n }\n }\n if (escaped) val = pug_escape(val);\n return ' ' + key + '=\"' + val + '\"';\n}\n\n/**\n * Render the given attributes object.\n *\n * @param {Object} obj\n * @param {Object} terse whether to use HTML5 terse boolean attributes\n * @return {String}\n */\nexports.attrs = pug_attrs;\nfunction pug_attrs(obj, terse) {\n var attrs = '';\n\n for (var key in obj) {\n if (pug_has_own_property.call(obj, key)) {\n var val = obj[key];\n\n if ('class' === key) {\n val = pug_classes(val);\n attrs = pug_attr(key, val, false, terse) + attrs;\n continue;\n }\n if ('style' === key) {\n val = pug_style(val);\n }\n attrs += pug_attr(key, val, false, terse);\n }\n }\n\n return attrs;\n}\n\n/**\n * Escape the given string of `html`.\n *\n * @param {String} html\n * @return {String}\n * @api private\n */\n\nvar pug_match_html = /[\"&<>]/;\nexports.escape = pug_escape;\nfunction pug_escape(_html) {\n var html = '' + _html;\n var regexResult = pug_match_html.exec(html);\n if (!regexResult) return _html;\n\n var result = '';\n var i, lastIndex, escape;\n for (i = regexResult.index, lastIndex = 0; i < html.length; i++) {\n switch (html.charCodeAt(i)) {\n case 34:\n escape = '&quot;';\n break;\n case 38:\n escape = '&amp;';\n break;\n case 60:\n escape = '&lt;';\n break;\n case 62:\n escape = '&gt;';\n break;\n default:\n continue;\n }\n if (lastIndex !== i) result += html.substring(lastIndex, i);\n lastIndex = i + 1;\n result += escape;\n }\n if (lastIndex !== i) return result + html.substring(lastIndex, i);\n else return result;\n}\n\n/**\n * Re-throw the given `err` in context to the\n * the pug in `filename` at the given `lineno`.\n *\n * @param {Error} err\n * @param {String} filename\n * @param {String} lineno\n * @param {String} str original source\n * @api private\n */\n\nexports.rethrow = pug_rethrow;\nfunction pug_rethrow(err, filename, lineno, str) {\n if (!(err instanceof Error)) throw err;\n if ((typeof window != 'undefined' || !filename) && !str) {\n err.message += ' on line ' + lineno;\n throw err;\n }\n var context, lines, start, end;\n try {\n str = str || require('fs').readFileSync(filename, {encoding: 'utf8'});\n context = 3;\n lines = str.split('\\n');\n start = Math.max(lineno - context, 0);\n end = Math.min(lines.length, lineno + context);\n } catch (ex) {\n err.message +=\n ' - could not read from ' + filename + ' (' + ex.message + ')';\n pug_rethrow(err, null, lineno);\n return;\n }\n\n // Error context\n context = lines\n .slice(start, end)\n .map(function(line, i) {\n var curr = i + start + 1;\n return (curr == lineno ? ' > ' : ' ') + curr + '| ' + line;\n })\n .join('\\n');\n\n // Alter exception message\n err.path = filename;\n try {\n err.message =\n (filename || 'Pug') +\n ':' +\n lineno +\n '\\n' +\n context +\n '\\n\\n' +\n err.message;\n } catch (e) {}\n throw err;\n}\n","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/workspaceEditor.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./workspaceEditor.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","module.exports = __WEBPACK_EXTERNAL_MODULE__860__;","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/paneEditor.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.pane-details{background:var(--theme-bg-more-more);border-radius:2px;padding:10px;padding-top:10px;margin-top:14px;border-left:2px solid var(--theme-primary);border-top:1px solid var(--theme-border, rgba(255, 255, 255, 0.1))}.pane-details-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.pane-details-title{font-size:.8rem;color:var(--theme-fg);font-weight:500;display:flex;align-items:center;gap:4px}.pane-form{display:grid;grid-template-columns:1fr 1fr;gap:10px}@media(max-width: 600px){.pane-form{grid-template-columns:1fr}}.form-group label{display:block;font-size:.7rem;color:var(--theme-fg-less);text-transform:uppercase;letter-spacing:.5px;margin-bottom:2px}.form-control{width:100%;padding:4px 6px;border-radius:2px;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));background:var(--theme-bg);color:var(--theme-fg);font-size:.85rem}.form-control:focus{outline:none;border-color:var(--theme-primary)}.form-control::placeholder{color:var(--theme-fg-more, rgba(255, 255, 255, 0.3))}.form-control{font-size:.8rem;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1)) !important}.form-control:focus{border-color:var(--theme-primary) !important}select.form-control{cursor:pointer;appearance:auto}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/paneEditor.component.scss\",\"webpack://./src/styles/_variables.scss\",\"webpack://./src/styles/_mixins.scss\"],\"names\":[],\"mappings\":\"AAGA,cACE,oCAAA,CACA,iBCSU,CDRV,YAAA,CACA,gBCDW,CDEX,eCDW,CDEX,0CAAA,CACA,kEAAA,CAGF,qBACE,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,kBCXW,CDcb,oBACE,eC8BQ,CD7BR,qBAAA,CACA,eAAA,CACA,YAAA,CACA,kBAAA,CACA,OCtBW,CD0Bb,WACE,YAAA,CACA,6BAAA,CACA,QC3BW,CD8Bb,yBACE,WACE,yBAAA,CAAA,CAKF,kBEJA,aAAA,CACA,eDUQ,CCTR,0BAAA,CACA,wBAAA,CACA,mBAAA,CACA,iBDzCW,CD6Cb,cACE,UAAA,CEhCA,eAAA,CACA,iBDJU,CCKV,8DAAA,CACA,0BF8BoB,CE7BpB,qBAAA,CACA,gBD8BQ,CC5BR,oBACE,YAAA,CACA,iCAAA,CAGF,2BACE,oDAAA,CFkBJ,cAGE,eAAA,CAEA,yEAAA,CAEA,oBACE,4CAAA,CAIJ,oBACE,cAAA,CACA,eAAA\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n// Inline pane details panel\\r\\n.pane-details {\\r\\n background: var(--theme-bg-more-more);\\r\\n border-radius: $radius-sm;\\r\\n padding: $spacing-lg;\\r\\n padding-top: $spacing-lg;\\r\\n margin-top: $spacing-xl;\\r\\n border-left: 2px solid var(--theme-primary);\\r\\n border-top: 1px solid var(--theme-border, $fallback-border);\\r\\n}\\r\\n\\r\\n.pane-details-header {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n align-items: center;\\r\\n margin-bottom: $spacing-lg;\\r\\n}\\r\\n\\r\\n.pane-details-title {\\r\\n font-size: $font-sm;\\r\\n color: var(--theme-fg);\\r\\n font-weight: 500;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n}\\r\\n\\r\\n// 2-column grid for pane form\\r\\n.pane-form {\\r\\n display: grid;\\r\\n grid-template-columns: 1fr 1fr;\\r\\n gap: $spacing-lg;\\r\\n}\\r\\n\\r\\n@media (max-width: 600px) {\\r\\n .pane-form {\\r\\n grid-template-columns: 1fr;\\r\\n }\\r\\n}\\r\\n\\r\\n.form-group {\\r\\n label {\\r\\n @include form-label;\\r\\n }\\r\\n}\\r\\n\\r\\n.form-control {\\r\\n width: 100%;\\r\\n @include form-input(var(--theme-bg));\\r\\n font-size: $font-sm;\\r\\n // Override Tabby's global border reset\\r\\n border: 1px solid var(--theme-border, $fallback-border) !important;\\r\\n\\r\\n &:focus {\\r\\n border-color: var(--theme-primary) !important;\\r\\n }\\r\\n}\\r\\n\\r\\nselect.form-control {\\r\\n cursor: pointer;\\r\\n appearance: auto; // Show dropdown arrow\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\",\"@use 'variables' as *;\\r\\n\\r\\n// ======================\\r\\n// LAYOUT MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin flex-center {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM INPUT MIXIN\\r\\n// ======================\\r\\n\\r\\n@mixin form-input($bg: var(--theme-bg)) {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n border-radius: $radius-sm;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n background: $bg;\\r\\n color: var(--theme-fg);\\r\\n font-size: $font-md;\\r\\n\\r\\n &:focus {\\r\\n outline: none;\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &::placeholder {\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM LABEL MIXIN (S1: Uppercase compact)\\r\\n// ======================\\r\\n\\r\\n@mixin form-label {\\r\\n display: block;\\r\\n font-size: $font-xs;\\r\\n color: var(--theme-fg-less);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-xs;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// BUTTON MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin toolbar-btn {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n background: var(--theme-bg-more-more);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-success {\\r\\n background: $color-success;\\r\\n border-color: $color-success;\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n background: $color-success-hover;\\r\\n border-color: $color-success-hover;\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-base {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-lg;\\r\\n font-size: $font-sm;\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n}\\r\\n\\r\\n@mixin btn-ghost {\\r\\n @include btn-base;\\r\\n background: transparent;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg);\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-primary {\\r\\n @include btn-base;\\r\\n background: var(--theme-primary);\\r\\n border: 1px solid var(--theme-primary);\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n filter: brightness(1.1);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin icon-btn-sm($size: 24px) {\\r\\n width: $size;\\r\\n height: $size;\\r\\n @include flex-center;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: 10px;\\r\\n transition: all $transition-fast;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: var(--theme-primary);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &.danger:hover:not(:disabled) {\\r\\n border-color: var(--theme-danger);\\r\\n color: var(--theme-danger);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// OVERLAY/MODAL MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin full-overlay($z-index: $z-modal-overlay) {\\r\\n position: fixed;\\r\\n top: 0;\\r\\n left: 0;\\r\\n right: 0;\\r\\n bottom: 0;\\r\\n z-index: $z-index;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// TEXT UTILITIES\\r\\n// ======================\\r\\n\\r\\n@mixin text-ellipsis {\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// DROPDOWN/POPUP\\r\\n// ======================\\r\\n\\r\\n@mixin dropdown-panel {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n box-shadow: $shadow-dropdown;\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","if(typeof __WEBPACK_EXTERNAL_MODULE__947__ === 'undefined') { var e = new Error(\"Cannot find module 'fs'\"); e.code = 'MODULE_NOT_FOUND'; throw e; }\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE__947__;","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/workspaceList.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","module.exports = __WEBPACK_EXTERNAL_MODULE__961__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Check if module exists (development only)\n\tif (__webpack_modules__[moduleId] === undefined) {\n\t\tvar e = new Error(\"Cannot find module '\" + moduleId + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// Build-time constants injected by webpack DefinePlugin\r\ndeclare const __CONFIG_KEY__: string\r\ndeclare const __DISPLAY_NAME__: string\r\ndeclare const __IS_DEV__: boolean\r\n\r\nexport const CONFIG_KEY = typeof __CONFIG_KEY__ !== 'undefined' ? __CONFIG_KEY__ : 'tabbyspaces'\r\nexport const DISPLAY_NAME = typeof __DISPLAY_NAME__ !== 'undefined' ? __DISPLAY_NAME__ : 'TabbySpaces'\r\nexport const IS_DEV = typeof __IS_DEV__ !== 'undefined' ? __IS_DEV__ : false\r\n","import { Injectable } from '@angular/core'\r\nimport { ConfigProvider } from 'tabby-core'\r\nimport { CONFIG_KEY } from '../build-config'\r\n\r\n@Injectable()\r\nexport class WorkspaceEditorConfigProvider extends ConfigProvider {\r\n defaults = {\r\n [CONFIG_KEY]: {\r\n workspaces: [],\r\n },\r\n }\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { AppService, BaseTabComponent, SplitTabComponent } from 'tabby-core'\r\nimport { BaseTerminalTabComponent } from 'tabby-terminal'\r\nimport { first, timeout, of } from 'rxjs'\r\nimport { catchError } from 'rxjs/operators'\r\n\r\nexport interface PendingCommand {\r\n paneId: string\r\n command?: string\r\n originalTitle: string\r\n}\r\n\r\n/**\r\n * Handles startup commands for workspace panes.\r\n *\r\n * This service listens to tab open events and sends startup commands\r\n * to terminals that match registered pane IDs.\r\n *\r\n * NOTE: This is a module-level singleton that lives for the app lifetime.\r\n * The tabOpened$ subscription intentionally runs forever - no cleanup needed.\r\n */\r\n@Injectable()\r\nexport class StartupCommandService {\r\n private pendingCommands: Map<string, PendingCommand> = new Map()\r\n\r\n constructor(private app: AppService) {\r\n this.app.tabOpened$.subscribe((tab) => this.onTabOpened(tab))\r\n }\r\n\r\n registerCommands(commands: PendingCommand[]): void {\r\n console.log('[TabbySpaces] Registering commands:', commands)\r\n for (const cmd of commands) {\r\n this.pendingCommands.set(cmd.paneId, cmd)\r\n }\r\n }\r\n\r\n private onTabOpened(tab: BaseTabComponent): void {\r\n console.log('[TabbySpaces] Tab opened:', {\r\n type: tab.constructor.name,\r\n title: tab.title,\r\n })\r\n\r\n // Handle SplitTabComponent - get all child terminal tabs\r\n if (tab instanceof SplitTabComponent) {\r\n console.log('[TabbySpaces] SplitTabComponent detected, waiting for children...')\r\n // Wait for split tab to fully initialize its children\r\n setTimeout(() => this.processChildTabs(tab), 300)\r\n return\r\n }\r\n\r\n // Handle individual terminal tab (shouldn't happen for split-layout, but just in case)\r\n if (tab instanceof BaseTerminalTabComponent) {\r\n this.processTerminalTab(tab)\r\n }\r\n }\r\n\r\n private processChildTabs(splitTab: SplitTabComponent): void {\r\n // Get all nested tabs from the split container\r\n const allTabs = splitTab.getAllTabs()\r\n console.log('[TabbySpaces] Found child tabs:', allTabs.length)\r\n\r\n for (const tab of allTabs) {\r\n if (tab instanceof BaseTerminalTabComponent) {\r\n this.processTerminalTab(tab)\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private processTerminalTab(terminalTab: BaseTerminalTabComponent<any>): void {\r\n const paneId = terminalTab.customTitle || terminalTab.title\r\n console.log('[TabbySpaces] Processing terminal tab:', {\r\n title: terminalTab.title,\r\n customTitle: terminalTab.customTitle,\r\n paneId,\r\n pendingKeys: [...this.pendingCommands.keys()],\r\n })\r\n\r\n const pending = this.pendingCommands.get(paneId)\r\n if (!pending) {\r\n console.log('[TabbySpaces] No matching command for paneId:', paneId)\r\n return\r\n }\r\n\r\n this.pendingCommands.delete(paneId)\r\n\r\n // Build startup command (cd + command)\r\n const fullCommand = this.buildFullCommand(pending)\r\n if (!fullCommand) {\r\n console.log('[TabbySpaces] No command to send (no cwd or startup command)')\r\n return\r\n }\r\n\r\n console.log('[TabbySpaces] Command matched, waiting for shell output...:', fullCommand)\r\n\r\n // Unified command sender - reduces duplication\r\n const sendCommand = () => {\r\n console.log('[TabbySpaces] Shell ready, sending command:', fullCommand)\r\n terminalTab.sendInput(fullCommand + '\\r')\r\n this.clearProfileArgs(terminalTab)\r\n this.setTabTitle(terminalTab, pending.originalTitle)\r\n }\r\n\r\n // Wait for shell to emit first output (prompt), then send command\r\n if (terminalTab.session?.output$) {\r\n terminalTab.session.output$.pipe(\r\n first(),\r\n timeout(2000), // Prevent infinite wait if shell doesn't emit\r\n catchError(() => of(null)) // Fallback on timeout/error\r\n ).subscribe(() => {\r\n // Small delay after prompt renders\r\n setTimeout(sendCommand, 100)\r\n })\r\n } else {\r\n console.log('[TabbySpaces] No session.output$, falling back to timeout')\r\n setTimeout(sendCommand, 500)\r\n }\r\n }\r\n\r\n private buildFullCommand(pending: PendingCommand): string | null {\r\n return pending.command || null\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private clearProfileArgs(terminalTab: BaseTerminalTabComponent<any>): void {\r\n // Clear args from profile to prevent native splits from re-running startup command\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const profile = (terminalTab as any).profile\r\n if (profile?.options?.args) {\r\n console.log('[TabbySpaces] Clearing profile args to prevent re-run on split')\r\n profile.options.args = []\r\n }\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private setTabTitle(terminalTab: BaseTerminalTabComponent<any>, title: string): void {\r\n terminalTab.setTitle(title)\r\n terminalTab.customTitle = title\r\n }\r\n}\r\n","// Tabby profile interfaces\r\nexport interface TabbyProfileOptions {\r\n command?: string\r\n args?: string[]\r\n cwd?: string\r\n env?: Record<string, string>\r\n restoreFromPTYID?: boolean\r\n width?: number | null\r\n height?: number | null\r\n pauseAfterExit?: boolean\r\n runAsAdministrator?: boolean\r\n}\r\n\r\nexport interface TabbyProfile {\r\n id: string\r\n type: string\r\n name: string\r\n group?: string\r\n icon?: string\r\n color?: string\r\n options?: TabbyProfileOptions\r\n isBuiltin?: boolean\r\n isTemplate?: boolean\r\n weight?: number\r\n disableDynamicTitle?: boolean\r\n terminalColorScheme?: string | null\r\n behaviorOnSessionEnd?: string\r\n}\r\n\r\nexport interface TabbyRecoveryToken {\r\n type: string\r\n orientation?: 'h' | 'v'\r\n ratios?: number[]\r\n children?: TabbyRecoveryToken[]\r\n profile?: Partial<TabbyProfile>\r\n savedState?: boolean\r\n tabTitle?: string\r\n tabCustomTitle?: string\r\n disableDynamicTitle?: boolean\r\n cwd?: string\r\n // Allow custom properties (matches Tabby's RecoveryToken interface)\r\n [key: string]: any\r\n}\r\n\r\nexport interface TabbySplitLayoutProfile {\r\n id: string\r\n type: 'split-layout'\r\n name: string\r\n group: string\r\n icon?: string\r\n color?: string\r\n isBuiltin: boolean\r\n options: {\r\n recoveryToken: TabbyRecoveryToken\r\n }\r\n}\r\n\r\n// Workspace interfaces\r\nexport interface WorkspacePane {\r\n id: string\r\n profileId: string\r\n cwd?: string\r\n startupCommand?: string\r\n}\r\n\r\nexport interface WorkspaceSplit {\r\n orientation: 'horizontal' | 'vertical'\r\n ratios: number[]\r\n children: (WorkspacePane | WorkspaceSplit)[]\r\n}\r\n\r\nexport interface WorkspaceBackground {\r\n type: 'none' | 'solid' | 'gradient' | 'image'\r\n value: string // CSS value: hex, gradient string, or URL\r\n}\r\n\r\nexport interface Workspace {\r\n id: string\r\n name: string\r\n icon?: string\r\n color?: string\r\n background?: WorkspaceBackground\r\n root: WorkspaceSplit\r\n launchOnStartup?: boolean\r\n}\r\n\r\n// Preset backgrounds for quick selection\r\nexport const BACKGROUND_PRESETS: WorkspaceBackground[] = [\r\n { type: 'none', value: '' },\r\n // Existing presets\r\n { type: 'gradient', value: 'linear-gradient(132deg, transparent 83%, rgba(6, 220, 249, 0.18) 100%), linear-gradient(210deg, transparent 85%, rgba(139, 92, 246, 0.2) 100%)' },\r\n { type: 'gradient', value: 'linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, transparent 50%)' },\r\n { type: 'gradient', value: 'linear-gradient(45deg, rgba(239, 68, 68, 0.1) 0%, transparent 50%)' },\r\n { type: 'gradient', value: 'linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, transparent 50%)' },\r\n { type: 'gradient', value: 'linear-gradient(225deg, transparent 70%, rgba(249, 115, 22, 0.15) 100%)' },\r\n { type: 'gradient', value: 'linear-gradient(180deg, rgba(139, 92, 246, 0.1) 0%, transparent 40%)' },\r\n // New presets\r\n { type: 'gradient', value: 'linear-gradient(315deg, transparent 80%, rgba(236, 72, 153, 0.15) 100%)' }, // Pink bottom-right\r\n { type: 'gradient', value: 'linear-gradient(0deg, rgba(6, 182, 212, 0.12) 0%, transparent 35%)' }, // Cyan bottom\r\n { type: 'gradient', value: 'linear-gradient(45deg, transparent 85%, rgba(234, 179, 8, 0.18) 100%), linear-gradient(225deg, transparent 85%, rgba(249, 115, 22, 0.15) 100%)' }, // Gold corners\r\n { type: 'gradient', value: 'linear-gradient(160deg, rgba(34, 197, 94, 0.12) 0%, transparent 40%)' }, // Green top-left\r\n { type: 'gradient', value: 'linear-gradient(200deg, transparent 75%, rgba(99, 102, 241, 0.18) 100%)' }, // Indigo bottom-left\r\n { type: 'gradient', value: 'linear-gradient(135deg, rgba(20, 184, 166, 0.1) 0%, transparent 50%), linear-gradient(315deg, rgba(139, 92, 246, 0.1) 0%, transparent 50%)' }, // Teal + Violet diagonal\r\n { type: 'gradient', value: 'linear-gradient(90deg, rgba(239, 68, 68, 0.08) 0%, transparent 30%, transparent 70%, rgba(59, 130, 246, 0.08) 100%)' }, // Red-Blue sides\r\n { type: 'gradient', value: 'linear-gradient(180deg, transparent 60%, rgba(16, 185, 129, 0.12) 100%)' }, // Emerald bottom fade\r\n { type: 'gradient', value: 'linear-gradient(45deg, rgba(168, 85, 247, 0.1) 0%, transparent 40%), linear-gradient(225deg, rgba(6, 182, 212, 0.1) 0%, transparent 40%)' }, // Purple + Cyan corners\r\n { type: 'gradient', value: 'linear-gradient(150deg, transparent 70%, rgba(251, 146, 60, 0.15) 100%), linear-gradient(30deg, transparent 70%, rgba(251, 146, 60, 0.1) 100%)' }, // Warm orange accents\r\n]\r\n\r\n/**\r\n * Type guard to check if a node is a WorkspaceSplit.\r\n * @param node - The node to check\r\n * @returns True if the node is a WorkspaceSplit\r\n */\r\nexport function isWorkspaceSplit(node: WorkspacePane | WorkspaceSplit): node is WorkspaceSplit {\r\n return 'orientation' in node && 'children' in node\r\n}\r\n\r\n/**\r\n * Creates a new pane with default configuration.\r\n * @returns A new WorkspacePane with generated UUID and empty settings\r\n */\r\nexport function createDefaultPane(): WorkspacePane {\r\n return {\r\n id: generateUUID(),\r\n profileId: '',\r\n cwd: '',\r\n startupCommand: '',\r\n }\r\n}\r\n\r\n/**\r\n * Creates a new split with two default panes.\r\n * @param orientation - Split direction ('horizontal' or 'vertical'), defaults to 'horizontal'\r\n * @returns A new WorkspaceSplit with two panes at 50/50 ratio\r\n */\r\nexport function createDefaultSplit(orientation: 'horizontal' | 'vertical' = 'horizontal'): WorkspaceSplit {\r\n return {\r\n orientation,\r\n ratios: [0.5, 0.5],\r\n children: [createDefaultPane(), createDefaultPane()],\r\n }\r\n}\r\n\r\n// Color palette for workspaces\r\nconst WORKSPACE_COLORS = [\r\n '#3b82f6', // blue\r\n '#10b981', // emerald\r\n '#f59e0b', // amber\r\n '#ef4444', // red\r\n '#8b5cf6', // violet\r\n '#ec4899', // pink\r\n '#06b6d4', // cyan\r\n '#f97316', // orange\r\n]\r\n\r\n// Icon list for workspaces\r\nconst WORKSPACE_ICONS = [\r\n 'columns', 'terminal', 'code', 'folder', 'home', 'briefcase',\r\n 'cog', 'database', 'server', 'cloud', 'rocket', 'flask',\r\n 'bug', 'wrench', 'cube', 'layer-group', 'sitemap', 'project-diagram'\r\n]\r\n\r\n/** Returns a random color from the workspace color palette. */\r\nexport function getRandomColor(): string {\r\n return WORKSPACE_COLORS[Math.floor(Math.random() * WORKSPACE_COLORS.length)]\r\n}\r\n\r\n/** Returns a random icon from the workspace icon set. */\r\nexport function getRandomIcon(): string {\r\n return WORKSPACE_ICONS[Math.floor(Math.random() * WORKSPACE_ICONS.length)]\r\n}\r\n\r\n/**\r\n * Creates a new workspace with default configuration.\r\n * @param name - Display name for the workspace (optional)\r\n * @returns A new Workspace with generated UUID, random icon/color, and a default split\r\n */\r\nexport function createDefaultWorkspace(name: string = ''): Workspace {\r\n return {\r\n id: generateUUID(),\r\n name,\r\n icon: getRandomIcon(),\r\n color: getRandomColor(),\r\n root: createDefaultSplit(),\r\n launchOnStartup: false,\r\n }\r\n}\r\n\r\n/** Generates a random UUID v4 string. */\r\nexport function generateUUID(): string {\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8\r\n return v.toString(16)\r\n })\r\n}\r\n\r\n/**\r\n * Recursively counts the total number of panes in a split tree.\r\n * @param node - The root node to count from\r\n * @returns Total number of panes in the tree\r\n */\r\nexport function countPanes(node: WorkspacePane | WorkspaceSplit): number {\r\n if (isWorkspaceSplit(node)) {\r\n return node.children.reduce((sum, child) => sum + countPanes(child), 0)\r\n }\r\n return 1\r\n}\r\n\r\n/**\r\n * Creates a deep clone of an object, preserving type information.\r\n * More efficient than JSON.parse(JSON.stringify()) for simple objects.\r\n * @param obj - The object to clone\r\n * @returns A deep copy of the object\r\n */\r\nexport function deepClone<T>(obj: T): T {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj\r\n }\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => deepClone(item)) as T\r\n }\r\n const cloned = {} as T\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n cloned[key] = deepClone(obj[key])\r\n }\r\n }\r\n return cloned\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { ConfigService, NotificationsService, ProfilesService } from 'tabby-core'\r\nimport {\r\n Workspace,\r\n WorkspacePane,\r\n WorkspaceSplit,\r\n isWorkspaceSplit,\r\n generateUUID,\r\n deepClone,\r\n TabbyProfile,\r\n TabbyRecoveryToken,\r\n TabbySplitLayoutProfile,\r\n} from '../models/workspace.model'\r\nimport { CONFIG_KEY, DISPLAY_NAME } from '../build-config'\r\nimport { PendingCommand } from './startupCommand.service'\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class WorkspaceEditorService {\r\n private cachedProfiles: TabbyProfile[] | null = null\r\n private cacheTimestamp: number = 0\r\n private readonly CACHE_TTL = 30000 // 30 seconds\r\n\r\n constructor(\r\n private config: ConfigService,\r\n private notifications: NotificationsService,\r\n private profilesService: ProfilesService\r\n ) {}\r\n\r\n private async getCachedProfiles(): Promise<TabbyProfile[]> {\r\n const now = Date.now()\r\n if (!this.cachedProfiles || now - this.cacheTimestamp > this.CACHE_TTL) {\r\n this.cachedProfiles = (await this.profilesService.getProfiles()) as TabbyProfile[]\r\n this.cacheTimestamp = now\r\n }\r\n return this.cachedProfiles\r\n }\r\n\r\n /** Returns all saved workspaces from config. */\r\n getWorkspaces(): Workspace[] {\r\n return this.config.store?.[CONFIG_KEY]?.workspaces ?? []\r\n }\r\n\r\n /**\r\n * Saves the workspace list to config.\r\n * @throws Error if config store is not initialized\r\n */\r\n async saveWorkspaces(workspaces: Workspace[]): Promise<void> {\r\n if (!this.config.store?.[CONFIG_KEY]) {\r\n throw new Error('Config store not initialized')\r\n }\r\n this.config.store[CONFIG_KEY].workspaces = workspaces\r\n await this.saveConfig()\r\n }\r\n\r\n /** Adds a new workspace and shows notification. */\r\n async addWorkspace(workspace: Workspace): Promise<void> {\r\n try {\r\n const workspaces = this.getWorkspaces()\r\n workspaces.push(workspace)\r\n await this.saveWorkspaces(workspaces)\r\n this.notifications.info(`Workspace \"${workspace.name}\" created`)\r\n } catch (error) {\r\n this.notifications.error(`Failed to create workspace \"${workspace.name}\"`)\r\n throw error\r\n }\r\n }\r\n\r\n /** Updates an existing workspace by ID and shows notification. */\r\n async updateWorkspace(workspace: Workspace): Promise<void> {\r\n try {\r\n const workspaces = this.getWorkspaces()\r\n const index = workspaces.findIndex((w) => w.id === workspace.id)\r\n if (index !== -1) {\r\n workspaces[index] = workspace\r\n await this.saveWorkspaces(workspaces)\r\n this.notifications.info(`Workspace \"${workspace.name}\" updated`)\r\n }\r\n } catch (error) {\r\n this.notifications.error(`Failed to update workspace \"${workspace.name}\"`)\r\n throw error\r\n }\r\n }\r\n\r\n /** Deletes a workspace by ID and shows notification. */\r\n async deleteWorkspace(workspaceId: string): Promise<void> {\r\n const workspaces = this.getWorkspaces()\r\n const workspace = workspaces.find((w) => w.id === workspaceId)\r\n try {\r\n const filtered = workspaces.filter((w) => w.id !== workspaceId)\r\n await this.saveWorkspaces(filtered)\r\n if (workspace) {\r\n this.notifications.info(`Workspace \"${workspace.name}\" deleted`)\r\n }\r\n } catch (error) {\r\n this.notifications.error(`Failed to delete workspace \"${workspace?.name || workspaceId}\"`)\r\n throw error\r\n }\r\n }\r\n\r\n /** Returns all local shell profiles available for use in workspaces. */\r\n async getAvailableProfiles(): Promise<TabbyProfile[]> {\r\n const allProfiles = await this.profilesService.getProfiles()\r\n return allProfiles.filter(\r\n (p) =>\r\n (p.type === 'local' || p.type?.startsWith('local:')) &&\r\n !p.id?.startsWith('split-layout:')\r\n ) as TabbyProfile[]\r\n }\r\n\r\n /**\r\n * Cleanup orphaned profiles from previous plugin versions.\r\n * Call this once on plugin init.\r\n */\r\n cleanupOrphanedProfiles(): void {\r\n if (!this.config.store?.profiles) {\r\n return\r\n }\r\n const profiles: TabbyProfile[] = this.config.store.profiles\r\n const prefix = `split-layout:${CONFIG_KEY}:`\r\n const filtered = profiles.filter((p) => !p.id?.startsWith(prefix))\r\n if (filtered.length !== profiles.length) {\r\n this.config.store.profiles = filtered\r\n this.config.save()\r\n console.log(`[${DISPLAY_NAME}] Cleaned up ${profiles.length - filtered.length} orphaned profiles`)\r\n }\r\n }\r\n\r\n /** Generates a Tabby split-layout profile from a workspace for opening. */\r\n async generateTabbyProfile(workspace: Workspace): Promise<TabbySplitLayoutProfile> {\r\n await this.getCachedProfiles()\r\n const safeName = this.sanitizeForProfileId(workspace.name)\r\n return {\r\n id: `split-layout:${CONFIG_KEY}:${safeName}:${workspace.id}`,\r\n type: 'split-layout',\r\n name: workspace.name,\r\n group: DISPLAY_NAME,\r\n icon: workspace.icon,\r\n color: workspace.color,\r\n isBuiltin: false,\r\n options: {\r\n recoveryToken: this.generateRecoveryToken(workspace.root, workspace.name, workspace.id),\r\n },\r\n }\r\n }\r\n\r\n private generateRecoveryToken(split: WorkspaceSplit, workspaceName: string, workspaceId: string): TabbyRecoveryToken {\r\n return {\r\n type: 'app:split-tab',\r\n orientation: split.orientation === 'horizontal' ? 'h' : 'v',\r\n ratios: split.ratios,\r\n workspaceId,\r\n children: split.children.map((child) => {\r\n if (isWorkspaceSplit(child)) {\r\n return this.generateRecoveryToken(child, workspaceName, workspaceId)\r\n }\r\n return this.generatePaneToken(child, workspaceName, workspaceId)\r\n }),\r\n }\r\n }\r\n\r\n private generatePaneToken(pane: WorkspacePane, workspaceName: string, workspaceId: string): TabbyRecoveryToken {\r\n const baseProfile = this.getProfileById(pane.profileId)\r\n\r\n if (!baseProfile) {\r\n return {\r\n type: 'app:local-tab',\r\n profile: {\r\n type: 'local',\r\n name: 'Shell',\r\n },\r\n savedState: false,\r\n }\r\n }\r\n\r\n // Build complete profile object like Tabby expects\r\n const options = {\r\n restoreFromPTYID: false,\r\n command: baseProfile.options?.command || '',\r\n args: baseProfile.options?.args || [],\r\n cwd: pane.cwd || baseProfile.options?.cwd || '',\r\n env: baseProfile.options?.env || {},\r\n width: null,\r\n height: null,\r\n pauseAfterExit: false,\r\n runAsAdministrator: false,\r\n }\r\n\r\n // Note: startupCommand is handled via sendInput() in StartupCommandService\r\n // to avoid re-execution when Tabby splits the pane\r\n\r\n const profile = {\r\n id: baseProfile.id,\r\n type: 'local',\r\n name: baseProfile.name || 'Shell',\r\n group: baseProfile.group || '',\r\n options,\r\n icon: baseProfile.icon || '',\r\n color: baseProfile.color || '',\r\n disableDynamicTitle: true,\r\n weight: 0,\r\n isBuiltin: false,\r\n isTemplate: false,\r\n terminalColorScheme: null,\r\n behaviorOnSessionEnd: 'auto',\r\n }\r\n\r\n // tabTitle: workspace name (what user sees)\r\n // tabCustomTitle: pane.id (for matching in StartupCommandService)\r\n // workspaceId: for duplicate detection after Tabby recovery\r\n const cwd = pane.cwd || baseProfile.options?.cwd || ''\r\n return {\r\n type: 'app:local-tab',\r\n profile,\r\n savedState: false,\r\n tabTitle: workspaceName,\r\n tabCustomTitle: pane.id,\r\n workspaceId,\r\n disableDynamicTitle: true,\r\n cwd,\r\n }\r\n }\r\n\r\n /** Creates a deep copy of a workspace with new IDs. */\r\n duplicateWorkspace(workspace: Workspace): Workspace {\r\n const clone = deepClone(workspace)\r\n clone.id = generateUUID()\r\n clone.name = `${workspace.name} (Copy)`\r\n clone.launchOnStartup = false\r\n this.regenerateIds(clone.root)\r\n return clone\r\n }\r\n\r\n private regenerateIds(node: WorkspacePane | WorkspaceSplit): void {\r\n if (isWorkspaceSplit(node)) {\r\n for (const child of node.children) {\r\n this.regenerateIds(child)\r\n }\r\n } else {\r\n node.id = generateUUID()\r\n }\r\n }\r\n\r\n private sanitizeForProfileId(name: string): string {\r\n return name\r\n .toLowerCase()\r\n .replace(/[^a-z0-9-]/g, '-')\r\n .replace(/-+/g, '-')\r\n .replace(/^-|-$/g, '')\r\n || 'workspace'\r\n }\r\n\r\n private getProfileById(profileId: string): TabbyProfile | undefined {\r\n const isLocalType = (type: string) => type === 'local' || type?.startsWith('local:')\r\n\r\n // First: check user profiles in config\r\n const userProfiles: TabbyProfile[] = this.config.store?.profiles ?? []\r\n const found = userProfiles.find((p) => p.id === profileId && isLocalType(p.type))\r\n if (found) return found\r\n\r\n // Fallback: check cached profiles (includes built-ins)\r\n return this.cachedProfiles?.find((p) => p.id === profileId && isLocalType(p.type))\r\n }\r\n\r\n /** Collects all startup commands from panes in a workspace. */\r\n collectStartupCommands(workspace: Workspace): PendingCommand[] {\r\n const commands: PendingCommand[] = []\r\n this.collectCommandsFromNode(workspace.root, workspace.name, commands)\r\n return commands\r\n }\r\n\r\n private collectCommandsFromNode(\r\n node: WorkspacePane | WorkspaceSplit,\r\n workspaceName: string,\r\n commands: PendingCommand[]\r\n ): void {\r\n if (isWorkspaceSplit(node)) {\r\n for (const child of node.children) {\r\n this.collectCommandsFromNode(child, workspaceName, commands)\r\n }\r\n } else if (node.startupCommand) {\r\n commands.push({\r\n paneId: node.id,\r\n command: node.startupCommand,\r\n originalTitle: workspaceName,\r\n })\r\n }\r\n }\r\n\r\n private async saveConfig(): Promise<void> {\r\n try {\r\n await this.config.save()\r\n } catch (error) {\r\n console.error('TabbySpaces save error:', error)\r\n throw error\r\n }\r\n }\r\n}\r\n","import { Component, Input } from '@angular/core'\r\nimport { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'\r\n\r\n@Component({\r\n selector: 'delete-confirm-modal',\r\n template: `\r\n <div class=\"modal-header\">\r\n <h5 class=\"modal-title\">Delete Workspace</h5>\r\n </div>\r\n <div class=\"modal-body\">\r\n <p>Delete workspace \"{{ workspaceName }}\"?</p>\r\n <p class=\"text-muted\">This action cannot be undone.</p>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button class=\"btn btn-secondary\" (click)=\"modal.dismiss()\">Cancel</button>\r\n <button class=\"btn btn-danger\" (click)=\"modal.close()\" ngbAutofocus>Delete</button>\r\n </div>\r\n `,\r\n})\r\nexport class DeleteConfirmModalComponent {\r\n @Input() workspaceName = ''\r\n constructor(public modal: NgbActiveModal) {}\r\n}\r\n","import { Component, OnInit, OnDestroy, AfterViewInit, ChangeDetectorRef, ElementRef, NgZone } from '@angular/core'\r\nimport { NgbModal } from '@ng-bootstrap/ng-bootstrap'\r\nimport { ConfigService, ProfilesService } from 'tabby-core'\r\nimport { Subscription } from 'rxjs'\r\nimport { StartupCommandService } from '../services/startupCommand.service'\r\nimport { WorkspaceEditorService } from '../services/workspaceEditor.service'\r\nimport { DeleteConfirmModalComponent } from './deleteConfirmModal.component'\r\nimport {\r\n Workspace,\r\n WorkspacePane,\r\n WorkspaceSplit,\r\n TabbyProfile,\r\n countPanes,\r\n createDefaultWorkspace,\r\n deepClone,\r\n isWorkspaceSplit,\r\n} from '../models/workspace.model'\r\n\r\nconst SETTINGS_MAX_WIDTH = '876px'\r\n\r\n@Component({\r\n selector: 'workspace-list',\r\n template: require('./workspaceList.component.pug'),\r\n styles: [require('./workspaceList.component.scss')],\r\n})\r\nexport class WorkspaceListComponent implements OnInit, OnDestroy, AfterViewInit {\r\n workspaces: Workspace[] = []\r\n selectedWorkspace: Workspace | null = null\r\n editingWorkspace: Workspace | null = null\r\n isCreatingNew = false\r\n openingWorkspaceId: string | null = null\r\n displayTabs: Array<{ workspace: Workspace; isNew: boolean }> = []\r\n private cachedProfiles: TabbyProfile[] = []\r\n private configSubscription: Subscription | null = null\r\n\r\n constructor(\r\n public config: ConfigService,\r\n private workspaceService: WorkspaceEditorService,\r\n private profilesService: ProfilesService,\r\n private startupService: StartupCommandService,\r\n private modalService: NgbModal,\r\n private cdr: ChangeDetectorRef,\r\n private elementRef: ElementRef,\r\n private zone: NgZone\r\n ) {}\r\n\r\n async ngOnInit(): Promise<void> {\r\n this.loadWorkspaces()\r\n this.autoSelectFirst()\r\n this.cachedProfiles = await this.workspaceService.getAvailableProfiles()\r\n this.configSubscription = this.config.changed$.subscribe(() => {\r\n this.zone.run(() => this.loadWorkspaces())\r\n })\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n // Hack: Override Tabby's settings-tab-body max-width restriction\r\n setTimeout(() => {\r\n const parent = this.elementRef.nativeElement.closest('settings-tab-body') as HTMLElement\r\n if (parent) {\r\n parent.style.maxWidth = SETTINGS_MAX_WIDTH\r\n }\r\n }, 0)\r\n }\r\n\r\n private autoSelectFirst(): void {\r\n if (this.workspaces.length > 0 && !this.selectedWorkspace) {\r\n this.selectWorkspace(this.workspaces[0])\r\n }\r\n }\r\n\r\n selectWorkspace(workspace: Workspace): void {\r\n this.isCreatingNew = false\r\n this.selectedWorkspace = workspace\r\n this.editingWorkspace = deepClone(workspace)\r\n this.updateDisplayTabs()\r\n }\r\n\r\n isSelected(workspace: Workspace): boolean {\r\n return this.selectedWorkspace?.id === workspace.id\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.configSubscription?.unsubscribe()\r\n }\r\n\r\n loadWorkspaces(): void {\r\n const previousSelectedId = this.selectedWorkspace?.id\r\n this.workspaces = this.workspaceService.getWorkspaces()\r\n\r\n // Re-sync selectedWorkspace to point to object in new array\r\n // This prevents stale reference after delete/reload operations\r\n if (previousSelectedId) {\r\n this.selectedWorkspace = this.workspaces.find(w => w.id === previousSelectedId) || null\r\n }\r\n\r\n this.updateDisplayTabs()\r\n }\r\n\r\n createWorkspace(): void {\r\n const defaultProfileId = this.cachedProfiles[0]?.id || ''\r\n const workspace = createDefaultWorkspace()\r\n this.setProfileForAllPanes(workspace.root, defaultProfileId)\r\n this.selectedWorkspace = null\r\n this.editingWorkspace = workspace\r\n this.isCreatingNew = true\r\n this.updateDisplayTabs()\r\n this.cdr.detectChanges()\r\n }\r\n\r\n private setProfileForAllPanes(node: WorkspacePane | WorkspaceSplit, profileId: string): void {\r\n if (isWorkspaceSplit(node)) {\r\n node.children.forEach((child) => this.setProfileForAllPanes(child, profileId))\r\n } else {\r\n node.profileId = profileId\r\n }\r\n }\r\n\r\n editWorkspace(workspace: Workspace): void {\r\n this.selectWorkspace(workspace)\r\n }\r\n\r\n async duplicateWorkspace(event: MouseEvent, workspace: Workspace): Promise<void> {\r\n event.stopPropagation()\r\n const clone = this.workspaceService.duplicateWorkspace(workspace)\r\n await this.workspaceService.addWorkspace(clone)\r\n\r\n this.zone.run(() => {\r\n this.loadWorkspaces()\r\n const duplicated = this.workspaces.find((w) => w.id === clone.id)\r\n if (duplicated) {\r\n this.selectWorkspace(duplicated)\r\n }\r\n })\r\n }\r\n\r\n async deleteWorkspace(event: MouseEvent, workspace: Workspace): Promise<void> {\r\n event.stopPropagation()\r\n\r\n const confirmed = await this.confirmDelete(workspace.name)\r\n if (!confirmed) return\r\n\r\n const wasSelected = this.selectedWorkspace?.id === workspace.id\r\n const deletedIndex = this.workspaces.findIndex((w) => w.id === workspace.id)\r\n\r\n await this.workspaceService.deleteWorkspace(workspace.id)\r\n\r\n this.zone.run(() => {\r\n this.loadWorkspaces()\r\n if (this.workspaces.length === 0) {\r\n this.selectedWorkspace = null\r\n this.editingWorkspace = null\r\n this.isCreatingNew = false\r\n } else if (wasSelected) {\r\n const nextIndex = Math.min(deletedIndex, this.workspaces.length - 1)\r\n this.selectWorkspace(this.workspaces[nextIndex])\r\n }\r\n })\r\n }\r\n\r\n private async confirmDelete(name: string): Promise<boolean> {\r\n const modalRef = this.modalService.open(DeleteConfirmModalComponent)\r\n modalRef.componentInstance.workspaceName = name\r\n try {\r\n await modalRef.result\r\n return true\r\n } catch {\r\n return false\r\n }\r\n }\r\n\r\n async onEditorSave(workspace: Workspace): Promise<void> {\r\n const isNew = !this.workspaces.find((w) => w.id === workspace.id)\r\n if (isNew) {\r\n await this.workspaceService.addWorkspace(workspace)\r\n } else {\r\n await this.workspaceService.updateWorkspace(workspace)\r\n }\r\n\r\n // Wrap state changes in zone.run to ensure proper change detection\r\n this.zone.run(() => {\r\n this.loadWorkspaces()\r\n this.isCreatingNew = false\r\n const saved = this.workspaces.find((w) => w.id === workspace.id)\r\n if (saved) {\r\n this.selectWorkspace(saved)\r\n }\r\n })\r\n }\r\n\r\n onEditorCancel(): void {\r\n if (this.isCreatingNew) {\r\n // Cancel new workspace creation - go back to first workspace or empty\r\n this.isCreatingNew = false\r\n if (this.workspaces.length > 0) {\r\n this.selectWorkspace(this.workspaces[0])\r\n } else {\r\n this.selectedWorkspace = null\r\n this.editingWorkspace = null\r\n this.updateDisplayTabs()\r\n }\r\n } else if (this.selectedWorkspace) {\r\n // Reset to original workspace data\r\n this.editingWorkspace = deepClone(this.selectedWorkspace)\r\n }\r\n this.cdr.detectChanges()\r\n }\r\n\r\n getPaneCount(workspace: Workspace): number {\r\n return countPanes(workspace.root)\r\n }\r\n\r\n getOrientationLabel(workspace: Workspace): string {\r\n return workspace.root.orientation === 'horizontal' ? 'horizontal' : 'vertical'\r\n }\r\n\r\n get hasUnsavedChanges(): boolean {\r\n if (!this.editingWorkspace || !this.selectedWorkspace) return this.isCreatingNew\r\n return JSON.stringify(this.editingWorkspace) !== JSON.stringify(this.selectedWorkspace)\r\n }\r\n\r\n // Update display tabs array (call after state changes)\r\n private updateDisplayTabs(): void {\r\n const tabs = this.workspaces.map(w => ({ workspace: w, isNew: false }))\r\n if (this.isCreatingNew && this.editingWorkspace) {\r\n tabs.push({ workspace: this.editingWorkspace, isNew: true })\r\n }\r\n this.displayTabs = tabs\r\n }\r\n\r\n isTabSelected(tab: { workspace: Workspace; isNew: boolean }): boolean {\r\n if (tab.isNew) return true\r\n return this.selectedWorkspace?.id === tab.workspace.id\r\n }\r\n\r\n trackByTab(index: number, tab: { workspace: Workspace; isNew: boolean }): string {\r\n return tab.isNew ? '__new__' : tab.workspace.id\r\n }\r\n\r\n async openWorkspace(event: MouseEvent, workspace: Workspace): Promise<void> {\r\n event.stopPropagation()\r\n if (this.openingWorkspaceId) return\r\n this.openingWorkspaceId = workspace.id\r\n\r\n try {\r\n const commands = this.workspaceService.collectStartupCommands(workspace)\r\n if (commands.length > 0) {\r\n this.startupService.registerCommands(commands)\r\n }\r\n\r\n const profile = await this.workspaceService.generateTabbyProfile(workspace)\r\n this.zone.run(() => {\r\n this.profilesService.openNewTabForProfile(profile)\r\n })\r\n } finally {\r\n this.openingWorkspaceId = null\r\n this.cdr.detectChanges()\r\n }\r\n }\r\n\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { SettingsTabProvider } from 'tabby-settings'\r\nimport { WorkspaceListComponent } from '../components/workspaceList.component'\r\nimport { CONFIG_KEY, DISPLAY_NAME, IS_DEV } from '../build-config'\r\n\r\n@Injectable()\r\nexport class WorkspaceEditorSettingsProvider extends SettingsTabProvider {\r\n id = CONFIG_KEY\r\n icon = IS_DEV ? 'bolt' : 'th-large'\r\n title = DISPLAY_NAME\r\n\r\n getComponentType(): any {\r\n return WorkspaceListComponent\r\n }\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { AppService, SplitTabComponent } from 'tabby-core'\r\nimport { WorkspaceEditorService } from './workspaceEditor.service'\r\nimport { WorkspaceBackground } from '../models/workspace.model'\r\nimport { CONFIG_KEY } from '../build-config'\r\n\r\n/**\r\n * Service for applying custom backgrounds to workspace tabs.\r\n * Injects CSS dynamically based on workspace configuration.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class WorkspaceBackgroundService {\r\n private styleElement: HTMLStyleElement | null = null\r\n private appliedWorkspaces = new Map<string, string>() // workspaceId -> CSS\r\n\r\n constructor(\r\n private app: AppService,\r\n private workspaceService: WorkspaceEditorService\r\n ) {}\r\n\r\n /**\r\n * Initialize the service by setting up tab event listeners.\r\n * Must be called once during app initialization.\r\n */\r\n initialize(): void {\r\n this.setupTabListeners()\r\n }\r\n\r\n private setupTabListeners(): void {\r\n // Listen for tab open\r\n this.app.tabOpened$.subscribe(tab => this.onTabOpened(tab))\r\n\r\n // Listen for tab close - cleanup\r\n this.app.tabClosed$.subscribe(tab => this.onTabClosed(tab))\r\n }\r\n\r\n private onTabOpened(tab: unknown): void {\r\n if (!(tab instanceof SplitTabComponent)) return\r\n\r\n // Small delay to let Angular finish rendering\r\n setTimeout(() => {\r\n const workspaceId = this.extractWorkspaceId(tab)\r\n if (!workspaceId) return\r\n\r\n const workspace = this.workspaceService.getWorkspaces()\r\n .find(w => w.id === workspaceId)\r\n\r\n if (workspace?.background && workspace.background.type !== 'none') {\r\n this.applyBackground(workspaceId, workspace.background)\r\n }\r\n }, 200)\r\n }\r\n\r\n private onTabClosed(tab: unknown): void {\r\n if (!(tab instanceof SplitTabComponent)) return\r\n\r\n const workspaceId = this.extractWorkspaceId(tab)\r\n if (workspaceId) {\r\n this.removeBackground(workspaceId)\r\n }\r\n }\r\n\r\n /**\r\n * Extract workspace ID from a SplitTabComponent.\r\n * Tries multiple strategies: _recoveredState and child profile ID.\r\n */\r\n private extractWorkspaceId(tab: SplitTabComponent): string | undefined {\r\n const tabAny = tab as any\r\n\r\n // Strategy 1: Check _recoveredState.workspaceId (for restored tabs)\r\n if (tabAny._recoveredState?.workspaceId) {\r\n return tabAny._recoveredState.workspaceId\r\n }\r\n\r\n // Strategy 2: Extract from child profile ID (for freshly opened tabs)\r\n const profilePrefix = `split-layout:${CONFIG_KEY}:`\r\n for (const child of tab.getAllTabs()) {\r\n const profileId = (child as any).profile?.id ?? ''\r\n if (profileId.startsWith(profilePrefix)) {\r\n // Profile ID format: split-layout:CONFIG_KEY:name:UUID\r\n const parts = profileId.split(':')\r\n return parts[parts.length - 1]\r\n }\r\n }\r\n\r\n return undefined\r\n }\r\n\r\n private applyBackground(workspaceId: string, bg: WorkspaceBackground): void {\r\n // Mark split-tab element with data attribute\r\n this.markSplitTabElement(workspaceId)\r\n\r\n // Generate and inject CSS\r\n const css = this.generateCSS(workspaceId, bg)\r\n this.injectCSS(workspaceId, css)\r\n }\r\n\r\n private markSplitTabElement(workspaceId: string): void {\r\n // Find split-tab that doesn't have a workspace-id yet\r\n const splitTabs = document.querySelectorAll('split-tab')\r\n for (let i = splitTabs.length - 1; i >= 0; i--) {\r\n const splitTab = splitTabs[i]\r\n if (!splitTab.hasAttribute('data-workspace-id')) {\r\n splitTab.setAttribute('data-workspace-id', workspaceId)\r\n break\r\n }\r\n }\r\n }\r\n\r\n private generateCSS(workspaceId: string, bg: WorkspaceBackground): string {\r\n if (bg.type === 'none' || !bg.value) return ''\r\n\r\n return `\r\n split-tab[data-workspace-id=\"${workspaceId}\"] {\r\n background: ${bg.value} !important;\r\n }\r\n split-tab[data-workspace-id=\"${workspaceId}\"] .xterm-viewport,\r\n split-tab[data-workspace-id=\"${workspaceId}\"] .xterm-screen {\r\n background: transparent !important;\r\n }\r\n `\r\n }\r\n\r\n private injectCSS(workspaceId: string, css: string): void {\r\n if (!this.styleElement) {\r\n this.styleElement = document.createElement('style')\r\n this.styleElement.id = 'tabbyspaces-backgrounds'\r\n document.head.appendChild(this.styleElement)\r\n }\r\n\r\n this.appliedWorkspaces.set(workspaceId, css)\r\n this.updateStyleElement()\r\n }\r\n\r\n private removeBackground(workspaceId: string): void {\r\n this.appliedWorkspaces.delete(workspaceId)\r\n this.updateStyleElement()\r\n }\r\n\r\n private updateStyleElement(): void {\r\n if (this.styleElement) {\r\n this.styleElement.textContent = Array.from(this.appliedWorkspaces.values()).join('\\n')\r\n }\r\n }\r\n\r\n /**\r\n * Refresh background for a specific workspace.\r\n * Call this when workspace background is updated in settings.\r\n */\r\n refreshWorkspaceBackground(workspaceId: string): void {\r\n const workspace = this.workspaceService.getWorkspaces()\r\n .find(w => w.id === workspaceId)\r\n\r\n if (!workspace) {\r\n this.removeBackground(workspaceId)\r\n return\r\n }\r\n\r\n if (workspace.background && workspace.background.type !== 'none') {\r\n const css = this.generateCSS(workspaceId, workspace.background)\r\n this.appliedWorkspaces.set(workspaceId, css)\r\n } else {\r\n this.appliedWorkspaces.delete(workspaceId)\r\n }\r\n this.updateStyleElement()\r\n }\r\n}\r\n","import { Injectable } from '@angular/core'\nimport { ToolbarButtonProvider, ToolbarButton, ProfilesService, AppService, SplitTabComponent } from 'tabby-core'\nimport { BaseTerminalTabComponent } from 'tabby-terminal'\nimport { WorkspaceEditorService } from '../services/workspaceEditor.service'\nimport { StartupCommandService } from '../services/startupCommand.service'\nimport { WorkspaceBackgroundService } from '../services/workspaceBackground.service'\nimport { SettingsTabComponent } from 'tabby-settings'\nimport { CONFIG_KEY, DISPLAY_NAME, IS_DEV } from '../build-config'\n\nconst ICON_GRID = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"/>\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"/>\n <rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"/>\n <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"/>\n</svg>`\n\nconst ICON_BOLT = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polygon points=\"13 2 3 14 12 14 11 22 21 10 12 10 13 2\"/>\n</svg>`\n\nconst SELECTOR_SETTINGS_ID = '__settings__'\n\nimport { countPanes } from '../models/workspace.model'\n\n/** Recovery token structure for workspace tabs */\ninterface RecoveryTokenWithWorkspace {\n workspaceId?: string\n}\n\n@Injectable()\nexport class WorkspaceToolbarProvider extends ToolbarButtonProvider {\n constructor(\n private workspaceService: WorkspaceEditorService,\n private profilesService: ProfilesService,\n private app: AppService,\n private startupService: StartupCommandService,\n private backgroundService: WorkspaceBackgroundService\n ) {\n super()\n // Initialize background service to listen for tab events\n this.backgroundService.initialize()\n\n // Wait for Tabby to finish recovery before launching startup workspaces\n this.waitForTabbyReady().then(() => {\n this.workspaceService.cleanupOrphanedProfiles()\n this.launchStartupWorkspaces()\n })\n }\n\n private waitForTabbyReady(): Promise<void> {\n return new Promise(resolve => {\n let lastTabCount = -1\n const checkStable = () => {\n const currentCount = this.app.tabs.length\n if (currentCount === lastTabCount && currentCount >= 0) {\n resolve()\n } else {\n lastTabCount = currentCount\n setTimeout(checkStable, 300)\n }\n }\n // Initial delay to let Tabby start loading\n setTimeout(checkStable, 500)\n })\n }\n\n private async launchStartupWorkspaces(): Promise<void> {\n const workspaces = this.workspaceService.getWorkspaces()\n const startupWorkspaces = workspaces.filter(w => w.launchOnStartup)\n\n for (const workspace of startupWorkspaces) {\n if (this.isWorkspaceAlreadyOpen(workspace.id)) {\n console.log(`[TabbySpaces] Workspace \"${workspace.name}\" already open, skipping`)\n continue\n }\n await this.openWorkspace(workspace.id)\n }\n }\n\n /**\n * Type-safe helper to extract workspace ID from tab's recovery token.\n */\n private getRecoveryWorkspaceId(tab: unknown): string | undefined {\n if (tab && typeof tab === 'object' && 'recoveryToken' in tab) {\n const token = (tab as { recoveryToken?: RecoveryTokenWithWorkspace }).recoveryToken\n return token?.workspaceId\n }\n return undefined\n }\n\n private isWorkspaceAlreadyOpen(workspaceId: string): boolean {\n const profilePrefix = `split-layout:${CONFIG_KEY}:`\n\n for (const tab of this.app.tabs) {\n if (tab instanceof SplitTabComponent) {\n // Strategy 1: Check recoveryToken.workspaceId (for restored tabs)\n if (this.getRecoveryWorkspaceId(tab) === workspaceId) {\n return true\n }\n\n // Strategy 2: Check profile ID (for freshly opened tabs)\n for (const child of tab.getAllTabs()) {\n if (child instanceof BaseTerminalTabComponent) {\n const profileId = child.profile?.id ?? ''\n // Strict matching: prefix + workspaceId at the end\n if (profileId.startsWith(profilePrefix) && profileId.endsWith(`:${workspaceId}`)) {\n return true\n }\n }\n }\n }\n }\n return false\n }\n\n provide(): ToolbarButton[] {\n return [\n {\n icon: IS_DEV ? ICON_BOLT : ICON_GRID,\n title: DISPLAY_NAME,\n weight: 5,\n click: () => this.showWorkspaceSelector()\n }\n ]\n }\n\n private async showWorkspaceSelector(): Promise<void> {\n const workspaces = this.workspaceService.getWorkspaces()\n\n if (workspaces.length === 0) {\n this.openSettings()\n return\n }\n\n const options = workspaces.map((ws) => ({\n name: ws.name,\n description: `${countPanes(ws.root)} panes`,\n icon: ws.icon || 'grid',\n color: ws.color,\n result: ws.id\n }))\n\n // Add option to open settings\n options.push({\n name: 'Manage Workspaces...',\n description: 'Create and edit workspaces',\n icon: 'cog',\n color: undefined,\n result: SELECTOR_SETTINGS_ID\n })\n\n const selectedId = await this.app.showSelector('Select Workspace', options)\n\n if (selectedId === SELECTOR_SETTINGS_ID) {\n this.openSettings()\n } else if (selectedId) {\n this.openWorkspace(selectedId)\n }\n }\n\n private openSettings(): void {\n this.app.openNewTabRaw({ type: SettingsTabComponent, inputs: { activeTab: CONFIG_KEY } })\n }\n\n private async openWorkspace(workspaceId: string): Promise<void> {\n const workspaces = this.workspaceService.getWorkspaces()\n const workspace = workspaces.find((w) => w.id === workspaceId)\n\n if (!workspace) return\n\n // Register startup commands BEFORE opening the workspace\n // Commands will be sent via sendInput() when terminals open\n const commands = this.workspaceService.collectStartupCommands(workspace)\n if (commands.length > 0) {\n this.startupService.registerCommands(commands)\n }\n\n const profile = await this.workspaceService.generateTabbyProfile(workspace)\n this.profilesService.openNewTabForProfile(profile)\n }\n}\n","import { Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, SimpleChanges, HostListener, ElementRef, ViewChild, ChangeDetectorRef } from '@angular/core'\r\nimport {\r\n Workspace,\r\n WorkspacePane,\r\n WorkspaceSplit,\r\n WorkspaceBackground,\r\n TabbyProfile,\r\n isWorkspaceSplit,\r\n createDefaultPane,\r\n generateUUID,\r\n BACKGROUND_PRESETS,\r\n} from '../models/workspace.model'\r\n\r\ninterface TreeContext {\r\n node: WorkspaceSplit\r\n index: number\r\n parent: WorkspaceSplit | null\r\n child: WorkspacePane | WorkspaceSplit\r\n}\r\nimport { WorkspaceEditorService } from '../services/workspaceEditor.service'\r\n\r\n@Component({\r\n selector: 'workspace-editor',\r\n template: require('./workspaceEditor.component.pug'),\r\n styles: [require('./workspaceEditor.component.scss')],\r\n})\r\nexport class WorkspaceEditorComponent implements OnInit, OnChanges, AfterViewInit {\r\n @Input() workspace!: Workspace\r\n @Input() autoFocus = false\r\n @Input() hasUnsavedChanges = false\r\n @Output() save = new EventEmitter<Workspace>()\r\n @Output() cancel = new EventEmitter<void>()\r\n\r\n @ViewChild('nameInput') nameInput!: ElementRef<HTMLInputElement>\r\n\r\n selectedPaneId: string | null = null\r\n editingPane: WorkspacePane | null = null\r\n showPaneEditor = false\r\n profiles: TabbyProfile[] = []\r\n availableIcons = [\r\n 'columns', 'terminal', 'code', 'folder', 'home', 'briefcase',\r\n 'cog', 'database', 'server', 'cloud', 'rocket', 'flask',\r\n 'bug', 'wrench', 'cube', 'layer-group', 'sitemap', 'project-diagram'\r\n ]\r\n iconDropdownOpen = false\r\n backgroundPresets = BACKGROUND_PRESETS\r\n backgroundDropdownOpen = false\r\n customBackgroundValue = ''\r\n\r\n constructor(\r\n private workspaceService: WorkspaceEditorService,\r\n private elementRef: ElementRef,\r\n private cdr: ChangeDetectorRef\r\n ) {}\r\n\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: MouseEvent): void {\r\n // Check if click is outside the icon dropdown area (trigger + dropdown)\r\n const dropdownTrigger = this.elementRef.nativeElement.querySelector('.dropdown-trigger')\r\n const iconDropdown = this.elementRef.nativeElement.querySelector('.icon-dropdown')\r\n const iconClickedInside = dropdownTrigger?.contains(event.target as Node) ||\r\n iconDropdown?.contains(event.target as Node)\r\n if (this.iconDropdownOpen && !iconClickedInside) {\r\n this.iconDropdownOpen = false\r\n }\r\n\r\n // Check if click is outside the background dropdown area\r\n const bgTrigger = this.elementRef.nativeElement.querySelector('.background-trigger')\r\n const bgDropdown = this.elementRef.nativeElement.querySelector('.background-dropdown')\r\n const bgClickedInside = bgTrigger?.contains(event.target as Node) ||\r\n bgDropdown?.contains(event.target as Node)\r\n if (this.backgroundDropdownOpen && !bgClickedInside) {\r\n this.backgroundDropdownOpen = false\r\n }\r\n }\r\n\r\n toggleIconDropdown(): void {\r\n this.iconDropdownOpen = !this.iconDropdownOpen\r\n }\r\n\r\n selectIcon(icon: string): void {\r\n this.workspace.icon = icon\r\n this.iconDropdownOpen = false\r\n }\r\n\r\n toggleBackgroundDropdown(): void {\r\n this.backgroundDropdownOpen = !this.backgroundDropdownOpen\r\n }\r\n\r\n selectBackgroundPreset(preset: WorkspaceBackground): void {\r\n if (preset.type === 'none') {\r\n this.workspace.background = undefined\r\n this.customBackgroundValue = ''\r\n } else {\r\n this.workspace.background = { ...preset }\r\n this.customBackgroundValue = preset.value\r\n }\r\n this.backgroundDropdownOpen = false\r\n }\r\n\r\n applyCustomBackground(): void {\r\n const value = this.customBackgroundValue.trim()\r\n if (value) {\r\n this.workspace.background = {\r\n type: 'gradient',\r\n value\r\n }\r\n } else {\r\n this.workspace.background = undefined\r\n }\r\n }\r\n\r\n clearBackground(): void {\r\n this.workspace.background = undefined\r\n this.customBackgroundValue = ''\r\n }\r\n\r\n isBackgroundSelected(preset: WorkspaceBackground): boolean {\r\n if (preset.type === 'none') {\r\n return !this.workspace.background || this.workspace.background.type === 'none'\r\n }\r\n return this.workspace.background?.value === preset.value\r\n }\r\n\r\n async ngOnInit(): Promise<void> {\r\n this.profiles = await this.workspaceService.getAvailableProfiles()\r\n this.initializeWorkspace()\r\n this.cdr.detectChanges()\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n if (this.autoFocus) {\r\n this.focusNameInput()\r\n }\r\n }\r\n\r\n private focusNameInput(): void {\r\n requestAnimationFrame(() => {\r\n setTimeout(() => {\r\n if (this.nameInput?.nativeElement) {\r\n this.nameInput.nativeElement.focus()\r\n this.nameInput.nativeElement.select()\r\n }\r\n }, 0)\r\n })\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['workspace'] && !changes['workspace'].firstChange) {\r\n const prevId = changes['workspace'].previousValue?.id\r\n const currId = this.workspace.id\r\n\r\n if (prevId !== currId) {\r\n // Different workspace - reset everything and focus name input\r\n this.selectedPaneId = null\r\n this.editingPane = null\r\n this.showPaneEditor = false\r\n this.focusNameInput()\r\n } else {\r\n // Same workspace ID but different reference (after save/reload)\r\n // Re-sync editingPane to point to pane in new object tree\r\n if (this.selectedPaneId && this.showPaneEditor) {\r\n this.editingPane = this.findPaneById(this.selectedPaneId)\r\n }\r\n }\r\n // Always reset dropdowns and sync background value\r\n this.iconDropdownOpen = false\r\n this.backgroundDropdownOpen = false\r\n this.customBackgroundValue = this.workspace.background?.value || ''\r\n this.initializeWorkspace()\r\n }\r\n\r\n // Handle autoFocus change\r\n if (changes['autoFocus']?.currentValue) {\r\n this.focusNameInput()\r\n }\r\n }\r\n\r\n private initializeWorkspace(): void {\r\n if (!this.workspace.root) {\r\n this.workspace.root = {\r\n orientation: 'horizontal',\r\n ratios: [0.5, 0.5],\r\n children: [createDefaultPane(), createDefaultPane()],\r\n }\r\n }\r\n }\r\n\r\n onSave(): void {\r\n if (!this.workspace.name?.trim()) {\r\n return\r\n }\r\n this.save.emit(this.workspace)\r\n }\r\n\r\n onCancel(): void {\r\n this.cancel.emit()\r\n }\r\n\r\n deselectPane(): void {\r\n this.selectedPaneId = null\r\n }\r\n\r\n onPreviewBackgroundClick(): void {\r\n this.deselectPane()\r\n this.closePaneEditor()\r\n }\r\n\r\n editPane(pane: WorkspacePane): void {\r\n this.selectedPaneId = pane.id\r\n this.editingPane = pane\r\n this.showPaneEditor = true\r\n this.cdr.detectChanges()\r\n }\r\n\r\n closePaneEditor(): void {\r\n this.showPaneEditor = false\r\n this.editingPane = null\r\n this.cdr.detectChanges()\r\n }\r\n\r\n // Helper functions\r\n private findPaneById(id: string): WorkspacePane | null {\r\n return this.findPaneInNode(this.workspace.root, id)\r\n }\r\n\r\n private findPaneInNode(node: WorkspaceSplit, id: string): WorkspacePane | null {\r\n for (const child of node.children) {\r\n if (isWorkspaceSplit(child)) {\r\n const found = this.findPaneInNode(child, id)\r\n if (found) return found\r\n } else if (child.id === id) {\r\n return child\r\n }\r\n }\r\n return null\r\n }\r\n\r\n canRemovePane(): boolean {\r\n return this.countPanes(this.workspace.root) > 1\r\n }\r\n\r\n private countPanes(node: WorkspaceSplit): number {\r\n return node.children.reduce((count, child) => {\r\n return count + (isWorkspaceSplit(child) ? this.countPanes(child) : 1)\r\n }, 0)\r\n }\r\n\r\n private walkTree(\r\n node: WorkspaceSplit,\r\n visitor: (ctx: TreeContext) => boolean,\r\n parent: WorkspaceSplit | null = null\r\n ): boolean {\r\n for (let i = 0; i < node.children.length; i++) {\r\n const child = node.children[i]\r\n const ctx: TreeContext = { node, index: i, parent, child }\r\n\r\n if (isWorkspaceSplit(child)) {\r\n if (this.walkTree(child, visitor, node)) return true\r\n } else if (visitor(ctx)) {\r\n return true\r\n }\r\n }\r\n return false\r\n }\r\n\r\n private updatePaneInTree(updatedPane: WorkspacePane): boolean {\r\n return this.walkTree(this.workspace.root, (ctx) => {\r\n if ((ctx.child as WorkspacePane).id === updatedPane.id) {\r\n ctx.node.children[ctx.index] = updatedPane\r\n return true\r\n }\r\n return false\r\n })\r\n }\r\n\r\n splitPane(pane: WorkspacePane, orientation: 'horizontal' | 'vertical'): void {\r\n this.splitPaneInTree(pane, orientation)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n splitSelectedPane(orientation: 'horizontal' | 'vertical'): void {\r\n if (!this.selectedPaneId) return\r\n const pane = this.findPaneById(this.selectedPaneId)\r\n if (pane) this.splitPane(pane, orientation)\r\n }\r\n\r\n private splitPaneInTree(\r\n targetPane: WorkspacePane,\r\n orientation: 'horizontal' | 'vertical'\r\n ): boolean {\r\n return this.walkTree(this.workspace.root, (ctx) => {\r\n if ((ctx.child as WorkspacePane).id === targetPane.id) {\r\n const newPane = createDefaultPane()\r\n newPane.profileId = (ctx.child as WorkspacePane).profileId\r\n const newSplit: WorkspaceSplit = {\r\n orientation,\r\n ratios: [0.5, 0.5],\r\n children: [ctx.child, newPane],\r\n }\r\n ctx.node.children[ctx.index] = newSplit\r\n this.recalculateRatios(ctx.node)\r\n return true\r\n }\r\n return false\r\n })\r\n }\r\n\r\n removePane(pane: WorkspacePane): void {\r\n if (this.selectedPaneId === pane.id) {\r\n this.selectedPaneId = null\r\n }\r\n this.removePaneFromTree(this.workspace.root, pane)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n removeSelectedPane(): void {\r\n if (!this.selectedPaneId || !this.canRemovePane()) return\r\n const pane = this.findPaneById(this.selectedPaneId)\r\n if (pane) this.removePane(pane)\r\n }\r\n\r\n private removePaneFromTree(node: WorkspaceSplit, targetPane: WorkspacePane): boolean {\r\n for (let i = 0; i < node.children.length; i++) {\r\n const child = node.children[i]\r\n if (isWorkspaceSplit(child)) {\r\n // Check if the pane is directly in this split\r\n const paneIndex = child.children.findIndex(\r\n (c) => !isWorkspaceSplit(c) && (c as WorkspacePane).id === targetPane.id\r\n )\r\n if (paneIndex !== -1 && child.children.length > 1) {\r\n child.children.splice(paneIndex, 1)\r\n this.recalculateRatios(child)\r\n // If only one child remains, flatten\r\n if (child.children.length === 1) {\r\n node.children[i] = child.children[0]\r\n }\r\n return true\r\n }\r\n if (this.removePaneFromTree(child, targetPane)) {\r\n return true\r\n }\r\n } else if (child.id === targetPane.id) {\r\n if (node.children.length > 1) {\r\n node.children.splice(i, 1)\r\n this.recalculateRatios(node)\r\n return true\r\n }\r\n }\r\n }\r\n return false\r\n }\r\n\r\n private recalculateRatios(split: WorkspaceSplit): void {\r\n const count = split.children.length\r\n split.ratios = split.children.map(() => 1 / count)\r\n }\r\n\r\n setOrientation(orientation: 'horizontal' | 'vertical'): void {\r\n this.workspace.root.orientation = orientation\r\n this.cdr.detectChanges()\r\n }\r\n\r\n updateRatio(index: number, value: number): void {\r\n const ratios = [...this.workspace.root.ratios]\r\n const diff = value - ratios[index]\r\n\r\n if (index < ratios.length - 1) {\r\n ratios[index] = value\r\n ratios[index + 1] -= diff\r\n } else {\r\n ratios[index] = value\r\n ratios[index - 1] -= diff\r\n }\r\n\r\n // Clamp values\r\n ratios.forEach((r, i) => {\r\n ratios[i] = Math.max(0.1, Math.min(0.9, r))\r\n })\r\n\r\n this.workspace.root.ratios = ratios\r\n this.cdr.detectChanges()\r\n }\r\n\r\n // Add pane operations\r\n addPane(direction: 'left' | 'right' | 'top' | 'bottom'): void {\r\n if (!this.selectedPaneId) return\r\n const pane = this.findPaneById(this.selectedPaneId)\r\n if (!pane) return\r\n this.addPaneInTree(pane, direction)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n addPaneFromEvent(pane: WorkspacePane, direction: 'left' | 'right' | 'top' | 'bottom'): void {\r\n this.addPaneInTree(pane, direction)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n private addPaneInTree(\r\n targetPane: WorkspacePane,\r\n direction: 'left' | 'right' | 'top' | 'bottom'\r\n ): boolean {\r\n const isHorizontalAdd = direction === 'left' || direction === 'right'\r\n const isBefore = direction === 'left' || direction === 'top'\r\n const targetOrientation = isHorizontalAdd ? 'horizontal' : 'vertical'\r\n\r\n return this.walkTree(this.workspace.root, (ctx) => {\r\n if ((ctx.child as WorkspacePane).id !== targetPane.id) return false\r\n\r\n const newPane = createDefaultPane()\r\n newPane.profileId = (ctx.child as WorkspacePane).profileId\r\n\r\n if (ctx.node.orientation === targetOrientation) {\r\n // Same orientation: add as sibling\r\n const insertIndex = isBefore ? ctx.index : ctx.index + 1\r\n ctx.node.children.splice(insertIndex, 0, newPane)\r\n this.recalculateRatios(ctx.node)\r\n } else {\r\n // Different orientation: wrap entire node in new split\r\n const nodeCopy: WorkspaceSplit = {\r\n orientation: ctx.node.orientation,\r\n ratios: [...ctx.node.ratios],\r\n children: [...ctx.node.children]\r\n }\r\n const wrapper: WorkspaceSplit = {\r\n orientation: targetOrientation,\r\n ratios: [0.5, 0.5],\r\n children: isBefore ? [newPane, nodeCopy] : [nodeCopy, newPane]\r\n }\r\n\r\n if (ctx.node === this.workspace.root) {\r\n this.workspace.root = wrapper\r\n } else if (ctx.parent) {\r\n const nodeIndex = ctx.parent.children.indexOf(ctx.node)\r\n if (nodeIndex !== -1) {\r\n ctx.parent.children[nodeIndex] = wrapper\r\n }\r\n }\r\n }\r\n return true\r\n })\r\n }\r\n\r\n}\r\n","import { Component, Input, Output, EventEmitter, HostListener } from '@angular/core'\r\nimport { WorkspacePane, TabbyProfile } from '../models/workspace.model'\r\n\r\n@Component({\r\n selector: 'pane-editor',\r\n template: require('./paneEditor.component.pug'),\r\n styles: [require('./paneEditor.component.scss')],\r\n})\r\nexport class PaneEditorComponent {\r\n @Input() pane!: WorkspacePane\r\n @Input() profiles: TabbyProfile[] = []\r\n @Output() close = new EventEmitter<void>()\r\n\r\n @HostListener('document:keydown.escape')\r\n onEscapeKey(): void {\r\n this.close.emit()\r\n }\r\n\r\n getProfileName(profileId: string): string {\r\n const profile = this.profiles.find((p) => p.id === profileId)\r\n return profile?.name ?? 'Unknown'\r\n }\r\n}\r\n","import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef } from '@angular/core'\r\nimport {\r\n WorkspaceSplit,\r\n WorkspacePane,\r\n TabbyProfile,\r\n isWorkspaceSplit,\r\n} from '../models/workspace.model'\r\n\r\n@Component({\r\n selector: 'split-preview',\r\n template: require('./splitPreview.component.pug'),\r\n styles: [require('./splitPreview.component.scss')],\r\n})\r\nexport class SplitPreviewComponent implements OnChanges {\r\n @Input() split!: WorkspaceSplit\r\n @Input() depth = 0\r\n @Input() selectedPaneId: string | null = null\r\n @Input() profiles: TabbyProfile[] = []\r\n @Output() paneEdit = new EventEmitter<WorkspacePane>()\r\n @Output() splitHorizontal = new EventEmitter<WorkspacePane>()\r\n @Output() splitVertical = new EventEmitter<WorkspacePane>()\r\n @Output() removePane = new EventEmitter<WorkspacePane>()\r\n @Output() addLeft = new EventEmitter<WorkspacePane>()\r\n @Output() addRight = new EventEmitter<WorkspacePane>()\r\n @Output() addTop = new EventEmitter<WorkspacePane>()\r\n @Output() addBottom = new EventEmitter<WorkspacePane>()\r\n\r\n contextMenuPane: WorkspacePane | null = null\r\n contextMenuPosition = { x: 0, y: 0 }\r\n\r\n constructor(private cdr: ChangeDetectorRef) {}\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Clear context menu when split input changes to avoid stale state\r\n if (changes['split']) {\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n isPane(child: WorkspacePane | WorkspaceSplit): boolean {\r\n return !isWorkspaceSplit(child)\r\n }\r\n\r\n isSplit(child: WorkspacePane | WorkspaceSplit): boolean {\r\n return isWorkspaceSplit(child)\r\n }\r\n\r\n asSplit(child: WorkspacePane | WorkspaceSplit): WorkspaceSplit {\r\n return child as WorkspaceSplit\r\n }\r\n\r\n asPane(child: WorkspacePane | WorkspaceSplit): WorkspacePane {\r\n return child as WorkspacePane\r\n }\r\n\r\n getFlexStyle(index: number): string {\r\n return `${this.split.ratios[index] * 100}%`\r\n }\r\n\r\n onPaneClick(pane: WorkspacePane): void {\r\n this.paneEdit.emit(pane)\r\n }\r\n\r\n truncate(text: string, maxLength: number): string {\r\n return text.length > maxLength\r\n ? text.substring(0, maxLength) + '...'\r\n : text\r\n }\r\n\r\n onContextMenu(event: MouseEvent, pane: WorkspacePane): void {\r\n event.preventDefault()\r\n this.contextMenuPane = pane\r\n this.contextMenuPosition = { x: event.clientX, y: event.clientY }\r\n }\r\n\r\n closeContextMenu(): void {\r\n this.contextMenuPane = null\r\n this.cdr.detectChanges()\r\n }\r\n\r\n onEdit(): void {\r\n if (this.contextMenuPane) {\r\n this.paneEdit.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onSplitH(): void {\r\n if (this.contextMenuPane) {\r\n this.splitHorizontal.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onSplitV(): void {\r\n if (this.contextMenuPane) {\r\n this.splitVertical.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddLeft(): void {\r\n if (this.contextMenuPane) {\r\n this.addLeft.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddRight(): void {\r\n if (this.contextMenuPane) {\r\n this.addRight.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddTop(): void {\r\n if (this.contextMenuPane) {\r\n this.addTop.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddBottom(): void {\r\n if (this.contextMenuPane) {\r\n this.addBottom.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onRemove(): void {\r\n if (this.contextMenuPane) {\r\n this.removePane.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n getPaneLabel(pane: WorkspacePane): string {\r\n if (!pane.profileId) return 'Select profile'\r\n\r\n const profile = this.profiles.find(p => p.id === pane.profileId)\r\n return profile?.name || 'Select profile'\r\n }\r\n\r\n // Pass-through events from nested splits\r\n onNestedPaneEdit(pane: WorkspacePane): void {\r\n this.paneEdit.emit(pane)\r\n }\r\n\r\n onNestedSplitH(pane: WorkspacePane): void {\r\n this.splitHorizontal.emit(pane)\r\n }\r\n\r\n onNestedSplitV(pane: WorkspacePane): void {\r\n this.splitVertical.emit(pane)\r\n }\r\n\r\n onNestedAddLeft(pane: WorkspacePane): void {\r\n this.addLeft.emit(pane)\r\n }\r\n\r\n onNestedAddRight(pane: WorkspacePane): void {\r\n this.addRight.emit(pane)\r\n }\r\n\r\n onNestedAddTop(pane: WorkspacePane): void {\r\n this.addTop.emit(pane)\r\n }\r\n\r\n onNestedAddBottom(pane: WorkspacePane): void {\r\n this.addBottom.emit(pane)\r\n }\r\n\r\n onNestedRemove(pane: WorkspacePane): void {\r\n this.removePane.emit(pane)\r\n }\r\n}\r\n","import { NgModule } from '@angular/core'\r\nimport { CommonModule } from '@angular/common'\r\nimport { FormsModule } from '@angular/forms'\r\nimport { ConfigProvider, ToolbarButtonProvider } from 'tabby-core'\r\nimport { SettingsTabProvider } from 'tabby-settings'\r\n\r\nimport { WorkspaceEditorConfigProvider } from './providers/config.provider'\r\nimport { WorkspaceEditorSettingsProvider } from './providers/settings.provider'\r\nimport { WorkspaceToolbarProvider } from './providers/toolbar.provider'\r\nimport { WorkspaceEditorService } from './services/workspaceEditor.service'\r\nimport { StartupCommandService } from './services/startupCommand.service'\r\nimport { WorkspaceBackgroundService } from './services/workspaceBackground.service'\r\n\r\nimport { WorkspaceListComponent } from './components/workspaceList.component'\r\nimport { WorkspaceEditorComponent } from './components/workspaceEditor.component'\r\nimport { PaneEditorComponent } from './components/paneEditor.component'\r\nimport { SplitPreviewComponent } from './components/splitPreview.component'\r\nimport { DeleteConfirmModalComponent } from './components/deleteConfirmModal.component'\r\n\r\n@NgModule({\r\n imports: [CommonModule, FormsModule],\r\n providers: [\r\n { provide: ConfigProvider, useClass: WorkspaceEditorConfigProvider, multi: true },\r\n { provide: SettingsTabProvider, useClass: WorkspaceEditorSettingsProvider, multi: true },\r\n { provide: ToolbarButtonProvider, useClass: WorkspaceToolbarProvider, multi: true },\r\n WorkspaceEditorService,\r\n StartupCommandService,\r\n WorkspaceBackgroundService,\r\n ],\r\n declarations: [\r\n WorkspaceListComponent,\r\n WorkspaceEditorComponent,\r\n PaneEditorComponent,\r\n SplitPreviewComponent,\r\n DeleteConfirmModalComponent,\r\n ],\r\n})\r\nexport default class WorkspaceEditorModule {}\r\n\r\nexport {\r\n WorkspaceEditorService,\r\n WorkspaceEditorConfigProvider,\r\n WorkspaceEditorSettingsProvider,\r\n}\r\n"],"names":["root","factory","exports","module","require","e","define","amd","a","i","global","__WEBPACK_EXTERNAL_MODULE__860__","__WEBPACK_EXTERNAL_MODULE__358__","__WEBPACK_EXTERNAL_MODULE__182__","__WEBPACK_EXTERNAL_MODULE__650__","__WEBPACK_EXTERNAL_MODULE__700__","__WEBPACK_EXTERNAL_MODULE__765__","__WEBPACK_EXTERNAL_MODULE__349__","__WEBPACK_EXTERNAL_MODULE__961__","__WEBPACK_EXTERNAL_MODULE__439__","__WEBPACK_EXTERNAL_MODULE__947__","___CSS_LOADER_EXPORT___","push","id","result","__esModule","default","toString","locals","cssWithMappingToString","list","this","map","item","content","needLayer","concat","length","join","modules","media","dedupe","supports","layer","undefined","alreadyImportedModules","k","_k","cssMapping","btoa","base64","unescape","encodeURIComponent","JSON","stringify","data","sourceMapping","req","apply","pug_has_own_property","Object","prototype","hasOwnProperty","pug_classes","val","escaping","Array","isArray","className","classString","padding","escapeEnabled","pug_escape","pug_classes_array","key","call","pug_classes_object","pug_style","out","style","pug_attr","escaped","terse","type","toJSON","indexOf","replace","merge","pug_merge","b","arguments","attrs","valA","valB","classes","attr","obj","pug_match_html","_html","html","regexResult","exec","lastIndex","escape","index","charCodeAt","substring","rethrow","pug_rethrow","err","filename","lineno","str","Error","window","message","context","lines","start","end","encoding","split","Math","max","min","ex","slice","line","curr","path","code","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","n","getter","d","definition","o","defineProperty","enumerable","get","prop","r","Symbol","toStringTag","value","CONFIG_KEY","DISPLAY_NAME","WorkspaceEditorConfigProvider","ConfigProvider","defaults","workspaces","Injectable","StartupCommandService","constructor","app","pendingCommands","Map","tabOpened$","subscribe","tab","onTabOpened","registerCommands","commands","console","log","cmd","set","paneId","name","title","SplitTabComponent","setTimeout","processChildTabs","BaseTerminalTabComponent","processTerminalTab","splitTab","allTabs","getAllTabs","terminalTab","customTitle","pendingKeys","keys","pending","delete","fullCommand","buildFullCommand","sendCommand","sendInput","clearProfileArgs","setTabTitle","originalTitle","session","output$","pipe","first","timeout","catchError","of","command","profile","options","args","setTitle","AppService","BACKGROUND_PRESETS","isWorkspaceSplit","node","createDefaultPane","generateUUID","profileId","cwd","startupCommand","createDefaultSplit","orientation","ratios","children","WORKSPACE_COLORS","WORKSPACE_ICONS","c","random","countPanes","reduce","sum","child","deepClone","cloned","WorkspaceEditorService","config","notifications","profilesService","cachedProfiles","cacheTimestamp","CACHE_TTL","getCachedProfiles","now","Date","getProfiles","getWorkspaces","store","saveWorkspaces","saveConfig","addWorkspace","workspace","info","error","updateWorkspace","findIndex","w","deleteWorkspace","workspaceId","find","filtered","filter","getAvailableProfiles","p","startsWith","cleanupOrphanedProfiles","profiles","prefix","save","generateTabbyProfile","safeName","sanitizeForProfileId","group","icon","color","isBuiltin","recoveryToken","generateRecoveryToken","workspaceName","generatePaneToken","pane","baseProfile","getProfileById","savedState","restoreFromPTYID","env","width","height","pauseAfterExit","runAsAdministrator","disableDynamicTitle","weight","isTemplate","terminalColorScheme","behaviorOnSessionEnd","tabTitle","tabCustomTitle","duplicateWorkspace","clone","launchOnStartup","regenerateIds","toLowerCase","isLocalType","collectStartupCommands","collectCommandsFromNode","providedIn","ConfigService","NotificationsService","ProfilesService","DeleteConfirmModalComponent","modal","Input","Component","selector","template","NgbActiveModal","WorkspaceListComponent","workspaceService","startupService","modalService","cdr","elementRef","zone","selectedWorkspace","editingWorkspace","isCreatingNew","openingWorkspaceId","displayTabs","configSubscription","ngOnInit","loadWorkspaces","autoSelectFirst","changed$","run","ngAfterViewInit","parent","nativeElement","closest","maxWidth","selectWorkspace","updateDisplayTabs","isSelected","ngOnDestroy","unsubscribe","previousSelectedId","createWorkspace","defaultProfileId","floor","createDefaultWorkspace","setProfileForAllPanes","detectChanges","forEach","editWorkspace","event","stopPropagation","duplicated","confirmDelete","wasSelected","deletedIndex","nextIndex","modalRef","open","componentInstance","onEditorSave","saved","onEditorCancel","getPaneCount","getOrientationLabel","hasUnsavedChanges","tabs","isNew","isTabSelected","trackByTab","openWorkspace","openNewTabForProfile","styles","NgbModal","ChangeDetectorRef","ElementRef","NgZone","WorkspaceEditorSettingsProvider","SettingsTabProvider","getComponentType","WorkspaceBackgroundService","styleElement","appliedWorkspaces","initialize","setupTabListeners","tabClosed$","onTabClosed","extractWorkspaceId","background","applyBackground","removeBackground","tabAny","_recoveredState","profilePrefix","parts","bg","markSplitTabElement","css","generateCSS","injectCSS","splitTabs","document","querySelectorAll","hasAttribute","setAttribute","createElement","head","appendChild","updateStyleElement","textContent","from","values","refreshWorkspaceBackground","SELECTOR_SETTINGS_ID","WorkspaceToolbarProvider","ToolbarButtonProvider","backgroundService","super","waitForTabbyReady","then","launchStartupWorkspaces","Promise","resolve","lastTabCount","checkStable","currentCount","startupWorkspaces","isWorkspaceAlreadyOpen","getRecoveryWorkspaceId","token","endsWith","provide","click","showWorkspaceSelector","openSettings","ws","description","selectedId","showSelector","openNewTabRaw","SettingsTabComponent","inputs","activeTab","WorkspaceEditorComponent","autoFocus","EventEmitter","cancel","selectedPaneId","editingPane","showPaneEditor","availableIcons","iconDropdownOpen","backgroundPresets","backgroundDropdownOpen","customBackgroundValue","onDocumentClick","dropdownTrigger","querySelector","iconDropdown","iconClickedInside","contains","target","bgTrigger","bgDropdown","bgClickedInside","toggleIconDropdown","selectIcon","toggleBackgroundDropdown","selectBackgroundPreset","preset","applyCustomBackground","trim","clearBackground","isBackgroundSelected","initializeWorkspace","focusNameInput","requestAnimationFrame","nameInput","focus","select","ngOnChanges","changes","firstChange","prevId","previousValue","findPaneById","currentValue","onSave","emit","onCancel","deselectPane","onPreviewBackgroundClick","closePaneEditor","editPane","findPaneInNode","found","canRemovePane","count","walkTree","visitor","ctx","updatePaneInTree","updatedPane","splitPane","splitPaneInTree","splitSelectedPane","targetPane","newPane","newSplit","recalculateRatios","removePane","removePaneFromTree","removeSelectedPane","paneIndex","splice","setOrientation","updateRatio","diff","addPane","direction","addPaneInTree","addPaneFromEvent","isBefore","targetOrientation","insertIndex","nodeCopy","wrapper","nodeIndex","Output","ViewChild","HostListener","MouseEvent","PaneEditorComponent","close","onEscapeKey","getProfileName","SplitPreviewComponent","depth","paneEdit","splitHorizontal","splitVertical","addLeft","addRight","addTop","addBottom","contextMenuPane","contextMenuPosition","x","y","closeContextMenu","isPane","isSplit","asSplit","asPane","getFlexStyle","onPaneClick","truncate","text","maxLength","onContextMenu","preventDefault","clientX","clientY","onEdit","onSplitH","onSplitV","onAddLeft","onAddRight","onAddTop","onAddBottom","onRemove","getPaneLabel","onNestedPaneEdit","onNestedSplitH","onNestedSplitV","onNestedAddLeft","onNestedAddRight","onNestedAddTop","onNestedAddBottom","onNestedRemove","WorkspaceEditorModule","NgModule","imports","CommonModule","FormsModule","providers","useClass","multi","declarations"],"ignoreList":[],"sourceRoot":""}
1
+ {"version":3,"file":"index.js","mappings":";CAAA,SAA2CA,EAAMC,GAChD,GAAsB,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,EAAQG,QAAQ,iBAAkBA,QAAQ,mBAAoBA,QAAQ,kBAAmBA,QAAQ,cAAeA,QAAQ,kBAAmBA,QAAQ,8BAA+BA,QAAQ,kBAAmBA,QAAQ,QAASA,QAAQ,kBAAoB,WAA+C,IAAM,OAAOA,QAAQ,KAAO,CAAE,MAAMC,GAAI,CAAE,CAA1F,SACtQ,GAAqB,mBAAXC,QAAyBA,OAAOC,IAC9CD,OAAO,CAAC,gBAAiB,kBAAmB,iBAAkB,aAAc,iBAAkB,6BAA8B,iBAAkB,OAAQ,iBAAkB,MAAOL,OAC3K,CACJ,IAAIO,EAAuB,iBAAZN,QAAuBD,EAAQG,QAAQ,iBAAkBA,QAAQ,mBAAoBA,QAAQ,kBAAmBA,QAAQ,cAAeA,QAAQ,kBAAmBA,QAAQ,8BAA+BA,QAAQ,kBAAmBA,QAAQ,QAASA,QAAQ,kBAAoB,WAA+C,IAAM,OAAOA,QAAQ,KAAO,CAAE,MAAMC,GAAI,CAAE,CAA1F,IAAkGJ,EAAQD,EAAK,iBAAkBA,EAAK,mBAAoBA,EAAK,kBAAmBA,EAAK,cAAeA,EAAK,kBAAmBA,EAAK,8BAA+BA,EAAK,kBAAmBA,EAAW,KAAGA,EAAK,kBAAmBA,EAAS,IACxmB,IAAI,IAAIS,KAAKD,GAAuB,iBAAZN,QAAuBA,QAAUF,GAAMS,GAAKD,EAAEC,EACvE,CACA,CATD,CASGC,OAAQ,CAACC,EAAkCC,EAAkCC,EAAkCC,EAAkCC,EAAkCC,EAAkCC,EAAkCC,EAAkCC,EAAkCC,I,iGCN1TC,E,MAA0B,GAA4B,KAE1DA,EAAwBC,KAAK,CAACnB,EAAOoB,GAAI,suMAAuuM,GAAG,CAAC,QAAU,EAAE,QAAU,CAAC,4DAA4D,yCAAyC,uCAAuC,MAAQ,GAAG,SAAW,m5FAAm5F,eAAiB,CAAC,6zNAA6zN,8oEAA8oE,ggIAAggI,WAAa,MAE10sB,S,YCNQ,IAAIC,EAAS,EAAQ,KAEjBA,GAAUA,EAAOC,aACjBD,EAASA,EAAOE,SAIhBvB,EAAOD,QADW,iBAAXsB,EACUA,EAEAA,EAAOG,U,sBCVpCxB,EAAOD,QAAUW,C,aCCT,IAAIW,EAAS,EAAQ,KAEjBA,GAAUA,EAAOC,aACjBD,EAASA,EAAOE,SAIhBvB,EAAOD,QADW,iBAAXsB,EACUA,EAEAA,EAAOG,U,aCV1B,EAAQ,KAGlBxB,EAAOD,QADP,SAAkB0B,GAAgmO,MAAxkO,GAAsD,4hKAAkiO,C,aCFxnO,EAAQ,KAGlBzB,EAAOD,QADP,SAAkB0B,GAAivC,MAAztC,GAAsD,qwBAAmrC,C,aCFzwC,EAAQ,KAGlBzB,EAAOD,QADP,SAAkB0B,GAA2rD,MAAnqD,GAAsD,mqCAA6nD,C,uFCCztDP,E,MAA0B,GAA4B,KAE1DA,EAAwBC,KAAK,CAACnB,EAAOoB,GAAI,04EAA24E,GAAG,CAAC,QAAU,EAAE,QAAU,CAAC,yDAAyD,yCAAyC,uCAAuC,MAAQ,GAAG,SAAW,kqCAAkqC,eAAiB,CAAC,8xGAA8xG,8oEAA8oE,ggIAAggI,WAAa,MAE3ta,S,sBCDApB,EAAOD,QAAU,SAAU2B,GACzB,IAAIC,EAAO,GA4EX,OAzEAA,EAAKH,SAAW,WACd,OAAOI,KAAKC,IAAI,SAAUC,GACxB,IAAIC,EAAU,GACVC,OAA+B,IAAZF,EAAK,GAoB5B,OAnBIA,EAAK,KACPC,GAAW,cAAcE,OAAOH,EAAK,GAAI,QAEvCA,EAAK,KACPC,GAAW,UAAUE,OAAOH,EAAK,GAAI,OAEnCE,IACFD,GAAW,SAASE,OAAOH,EAAK,GAAGI,OAAS,EAAI,IAAID,OAAOH,EAAK,IAAM,GAAI,OAE5EC,GAAWL,EAAuBI,GAC9BE,IACFD,GAAW,KAETD,EAAK,KACPC,GAAW,KAETD,EAAK,KACPC,GAAW,KAENA,CACT,GAAGI,KAAK,GACV,EAGAR,EAAKrB,EAAI,SAAW8B,EAASC,EAAOC,EAAQC,EAAUC,GAC7B,iBAAZJ,IACTA,EAAU,CAAC,CAAC,KAAMA,OAASK,KAE7B,IAAIC,EAAyB,CAAC,EAC9B,GAAIJ,EACF,IAAK,IAAIK,EAAI,EAAGA,EAAIf,KAAKM,OAAQS,IAAK,CACpC,IAAIvB,EAAKQ,KAAKe,GAAG,GACP,MAANvB,IACFsB,EAAuBtB,IAAM,EAEjC,CAEF,IAAK,IAAIwB,EAAK,EAAGA,EAAKR,EAAQF,OAAQU,IAAM,CAC1C,IAAId,EAAO,GAAGG,OAAOG,EAAQQ,IACzBN,GAAUI,EAAuBZ,EAAK,WAGrB,IAAVU,SACc,IAAZV,EAAK,KAGdA,EAAK,GAAK,SAASG,OAAOH,EAAK,GAAGI,OAAS,EAAI,IAAID,OAAOH,EAAK,IAAM,GAAI,MAAMG,OAAOH,EAAK,GAAI,MAF/FA,EAAK,GAAKU,GAMVH,IACGP,EAAK,IAGRA,EAAK,GAAK,UAAUG,OAAOH,EAAK,GAAI,MAAMG,OAAOH,EAAK,GAAI,KAC1DA,EAAK,GAAKO,GAHVP,EAAK,GAAKO,GAMVE,IACGT,EAAK,IAGRA,EAAK,GAAK,cAAcG,OAAOH,EAAK,GAAI,OAAOG,OAAOH,EAAK,GAAI,KAC/DA,EAAK,GAAKS,GAHVT,EAAK,GAAK,GAAGG,OAAOM,IAMxBZ,EAAKR,KAAKW,GACZ,CACF,EACOH,CACT,C,aCnFQ,IAAIN,EAAS,EAAQ,KAEjBA,GAAUA,EAAOC,aACjBD,EAASA,EAAOE,SAIhBvB,EAAOD,QADW,iBAAXsB,EACUA,EAEAA,EAAOG,U,sBCVpCxB,EAAOD,QAAUe,C,sBCEjBd,EAAOD,QAAU,SAAU+B,GACzB,IAAIC,EAAUD,EAAK,GACfe,EAAaf,EAAK,GACtB,IAAKe,EACH,OAAOd,EAET,GAAoB,mBAATe,KAAqB,CAC9B,IAAIC,EAASD,KAAKE,SAASC,mBAAmBC,KAAKC,UAAUN,MACzDO,EAAO,+DAA+DnB,OAAOc,GAC7EM,EAAgB,OAAOpB,OAAOmB,EAAM,OACxC,MAAO,CAACrB,GAASE,OAAO,CAACoB,IAAgBlB,KAAK,KAChD,CACA,MAAO,CAACJ,GAASI,KAAK,KACxB,C,sBCfAnC,EAAOD,QAAUU,C,sBCAjBT,EAAOD,QAAUiB,C,uFCGbE,E,MAA0B,GAA4B,KAE1DA,EAAwBC,KAAK,CAACnB,EAAOoB,GAAI,myDAAoyD,GAAG,CAAC,QAAU,EAAE,QAAU,CAAC,0DAA0D,0CAA0C,MAAQ,GAAG,SAAW,kxBAAkxB,eAAiB,CAAC,mpFAAmpF,+oEAA+oE,WAAa,MAErjP,S,aCPU,EAAQ,KAGlBpB,EAAOD,QADP,SAAkB0B,GAA42H,MAAp1H,GAAsD,8yFAA8yH,C,aCF94H,IAAI6B,EAAM,EAAQ,KAClBtD,EAAOD,SAAWuD,EAAa,SAAKA,GAAKC,MAAMD,EAAK,G,sBCDpDtD,EAAOD,QAAUY,C,sBCAjBX,EAAOD,QAAUa,C,sBCAjBZ,EAAOD,QAAUc,C,0BCEjB,IAAI2C,EAAuBC,OAAOC,UAAUC,eAqF5C,SAASC,EAAYC,EAAKC,GACxB,OAAIC,MAAMC,QAAQH,GA1BpB,SAA2BA,EAAKC,GAK9B,IAJA,IACEG,EADEC,EAAc,GAEhBC,EAAU,GACVC,EAAgBL,MAAMC,QAAQF,GACvBxD,EAAI,EAAGA,EAAIuD,EAAI3B,OAAQ5B,KAC9B2D,EAAYL,EAAYC,EAAIvD,OAE5B8D,GAAiBN,EAASxD,KAAO2D,EAAYI,EAAWJ,IACxDC,EAAcA,EAAcC,EAAUF,EACtCE,EAAU,KAEZ,OAAOD,CACT,CAcWI,CAAkBT,EAAKC,GACrBD,GAAsB,iBAARA,EAd3B,SAA4BA,GAC1B,IAAIK,EAAc,GAChBC,EAAU,GACZ,IAAK,IAAII,KAAOV,EACVU,GAAOV,EAAIU,IAAQf,EAAqBgB,KAAKX,EAAKU,KACpDL,EAAcA,EAAcC,EAAUI,EACtCJ,EAAU,KAGd,OAAOD,CACT,CAKWO,CAAmBZ,GAEnBA,GAAO,EAElB,CAUA,SAASa,EAAUb,GACjB,IAAKA,EAAK,MAAO,GACjB,GAAmB,iBAARA,EAAkB,CAC3B,IAAIc,EAAM,GACV,IAAK,IAAIC,KAASf,EAEZL,EAAqBgB,KAAKX,EAAKe,KACjCD,EAAMA,EAAMC,EAAQ,IAAMf,EAAIe,GAAS,KAG3C,OAAOD,CACT,CACE,OAAOd,EAAM,EAEjB,CAYA,SAASgB,EAASN,EAAKV,EAAKiB,EAASC,GACnC,IACU,IAARlB,GACO,MAAPA,IACEA,IAAgB,UAARU,GAA2B,UAARA,GAE7B,MAAO,GAET,IAAY,IAARV,EACF,MAAO,KAAOkB,EAAQR,EAAMA,EAAM,KAAOA,EAAM,KAEjD,IAAIS,SAAcnB,EAOlB,MALY,WAATmB,GAA8B,aAATA,GACA,mBAAfnB,EAAIoB,SAEXpB,EAAMA,EAAIoB,UAEO,iBAARpB,IACTA,EAAMX,KAAKC,UAAUU,GAChBiB,IAAiC,IAAtBjB,EAAIqB,QAAQ,OAI1BJ,IAASjB,EAAMQ,EAAWR,IACvB,IAAMU,EAAM,KAAOV,EAAM,KAJrB,IAAMU,EAAM,KAAOV,EAAIsB,QAAQ,KAAM,SAAW,GAK7D,CA7IApF,EAAQqF,MACR,SAASC,EAAUhF,EAAGiF,GACpB,GAAyB,IAArBC,UAAUrD,OAAc,CAE1B,IADA,IAAIsD,EAAQnF,EAAE,GACLC,EAAI,EAAGA,EAAID,EAAE6B,OAAQ5B,IAC5BkF,EAAQH,EAAUG,EAAOnF,EAAEC,IAE7B,OAAOkF,CACT,CAEA,IAAK,IAAIjB,KAAOe,EACd,GAAY,UAARf,EAAiB,CACnB,IAAIkB,EAAOpF,EAAEkE,IAAQ,GACrBlE,EAAEkE,IAAQR,MAAMC,QAAQyB,GAAQA,EAAO,CAACA,IAAOxD,OAAOqD,EAAEf,IAAQ,GAClE,MAAO,GAAY,UAARA,EAAiB,CAE1BkB,GADIA,EAAOf,EAAUrE,EAAEkE,MACkB,MAA1BkB,EAAKA,EAAKvD,OAAS,GAAauD,EAAO,IAAMA,EAC5D,IAAIC,EAAOhB,EAAUY,EAAEf,IACvBmB,EAAOA,GAAkC,MAA1BA,EAAKA,EAAKxD,OAAS,GAAawD,EAAO,IAAMA,EAC5DrF,EAAEkE,GAAOkB,EAAOC,CAClB,MACErF,EAAEkE,GAAOe,EAAEf,GAIf,OAAOlE,CACT,EAmBAN,EAAQ4F,QAAU/B,EA2ClB7D,EAAQ6E,MAAQF,EA0BhB3E,EAAQ6F,KAAOf,EAoCf9E,EAAQyF,MACR,SAAmBK,EAAKd,GACtB,IAAIS,EAAQ,GAEZ,IAAK,IAAIjB,KAAOsB,EACd,GAAIrC,EAAqBgB,KAAKqB,EAAKtB,GAAM,CACvC,IAAIV,EAAMgC,EAAItB,GAEd,GAAI,UAAYA,EAAK,CAEnBiB,EAAQX,EAASN,EADjBV,EAAMD,EAAYC,IACS,EAAOkB,GAASS,EAC3C,QACF,CACI,UAAYjB,IACdV,EAAMa,EAAUb,IAElB2B,GAASX,EAASN,EAAKV,GAAK,EAAOkB,EACrC,CAGF,OAAOS,CACT,EAUA,IAAIM,EAAiB,SAErB,SAASzB,EAAW0B,GAClB,IAAIC,EAAO,GAAKD,EACZE,EAAcH,EAAeI,KAAKF,GACtC,IAAKC,EAAa,OAAOF,EAEzB,IACIzF,EAAG6F,EAAWC,EADd/E,EAAS,GAEb,IAAKf,EAAI2F,EAAYI,MAAOF,EAAY,EAAG7F,EAAI0F,EAAK9D,OAAQ5B,IAAK,CAC/D,OAAQ0F,EAAKM,WAAWhG,IACtB,KAAK,GACH8F,EAAS,SACT,MACF,KAAK,GACHA,EAAS,QACT,MACF,KAAK,GACHA,EAAS,OACT,MACF,KAAK,GACHA,EAAS,OACT,MACF,QACE,SAEAD,IAAc7F,IAAGe,GAAU2E,EAAKO,UAAUJ,EAAW7F,IACzD6F,EAAY7F,EAAI,EAChBe,GAAU+E,CACZ,CACA,OAAID,IAAc7F,EAAUe,EAAS2E,EAAKO,UAAUJ,EAAW7F,GACnDe,CACd,CA/BAtB,EAAQqG,OAAS/B,EA4CjBtE,EAAQyG,QACR,SAASC,EAAYC,EAAKC,EAAUC,EAAQC,GAC1C,KAAMH,aAAeI,OAAQ,MAAMJ,EACnC,KAAsB,oBAAVK,QAA0BJ,GAAcE,GAElD,MADAH,EAAIM,SAAW,YAAcJ,EACvBF,EAER,IAAIO,EAASC,EAAOC,EAAOC,EAC3B,IACEP,EAAMA,GAAO,oBAA2BF,EAAU,CAACU,SAAU,SAC7DJ,EAAU,EACVC,EAAQL,EAAIS,MAAM,MAClBH,EAAQI,KAAKC,IAAIZ,EAASK,EAAS,GACnCG,EAAMG,KAAKE,IAAIP,EAAMhF,OAAQ0E,EAASK,EACxC,CAAE,MAAOS,GAIP,OAHAhB,EAAIM,SACF,0BAA4BL,EAAW,KAAOe,EAAGV,QAAU,SAC7DP,EAAYC,EAAK,KAAME,EAEzB,CAGAK,EAAUC,EACPS,MAAMR,EAAOC,GACbvF,IAAI,SAAS+F,EAAMtH,GAClB,IAAIuH,EAAOvH,EAAI6G,EAAQ,EACvB,OAAQU,GAAQjB,EAAS,OAAS,QAAUiB,EAAO,KAAOD,CAC5D,GACCzF,KAAK,MAGRuE,EAAIoB,KAAOnB,EACX,IACED,EAAIM,SACDL,GAAY,OACb,IACAC,EACA,KACAK,EACA,OACAP,EAAIM,OACR,CAAE,MAAO9G,GAAI,CACb,MAAMwG,CACR,C,aC7RA,IAAIpD,EAAM,EAAQ,KAClBtD,EAAOD,SAAWuD,EAAa,SAAKA,GAAKC,MAAMD,EAAK,G,aCA5C,IAAIjC,EAAS,EAAQ,IAEjBA,GAAUA,EAAOC,aACjBD,EAASA,EAAOE,SAIhBvB,EAAOD,QADW,iBAAXsB,EACUA,EAEAA,EAAOG,U,sBCVpCxB,EAAOD,QAAUS,C,aCAjB,IAAI8C,EAAM,EAAQ,KAClBtD,EAAOD,SAAWuD,EAAa,SAAKA,GAAKC,MAAMD,EAAK,G,uFCEhDpC,E,MAA0B,GAA4B,KAE1DA,EAAwBC,KAAK,CAACnB,EAAOoB,GAAI,+uCAAgvC,GAAG,CAAC,QAAU,EAAE,QAAU,CAAC,uDAAuD,yCAAyC,uCAAuC,MAAQ,GAAG,SAAW,6hBAA6hB,eAAiB,CAAC,25CAA25C,8oEAA8oE,ggIAAggI,WAAa,MAEtjT,S,sBCPA,QAA+C,IAArCH,EAAkD,CAAE,IAAIf,EAAI,IAAI4G,MAAM,2BAAyD,MAA7B5G,EAAE6H,KAAO,mBAA0B7H,CAAG,CAElJF,EAAOD,QAAUkB,C,aCFjB,IAAIqC,EAAM,EAAQ,KAClBtD,EAAOD,SAAWuD,EAAa,SAAKA,GAAKC,MAAMD,EAAK,G,sBCDpDtD,EAAOD,QAAUgB,C,GCCbiH,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBzF,IAAjB0F,EACH,OAAOA,EAAapI,QAGrB,QAAsC0C,IAAlC2F,EAAoBF,GAAyB,CAChD,IAAIhI,EAAI,IAAI4G,MAAM,uBAAyBoB,EAAW,KAEtD,MADAhI,EAAE6H,KAAO,mBACH7H,CACP,CAEA,IAAIF,EAASgI,EAAyBE,GAAY,CACjD9G,GAAI8G,EAEJnI,QAAS,CAAC,GAOX,OAHAqI,EAAoBF,GAAUlI,EAAQA,EAAOD,QAASkI,GAG/CjI,EAAOD,OACf,CC3BAkI,EAAoBI,EAAKrI,IACxB,IAAIsI,EAAStI,GAAUA,EAAOsB,WAC7B,IAAOtB,EAAiB,QACxB,IAAM,EAEP,OADAiI,EAAoBM,EAAED,EAAQ,CAAEjI,EAAGiI,IAC5BA,GCLRL,EAAoBM,EAAI,CAACxI,EAASyI,KACjC,IAAI,IAAIjE,KAAOiE,EACXP,EAAoBQ,EAAED,EAAYjE,KAAS0D,EAAoBQ,EAAE1I,EAASwE,IAC5Ed,OAAOiF,eAAe3I,EAASwE,EAAK,CAAEoE,YAAY,EAAMC,IAAKJ,EAAWjE,MCJ3E0D,EAAoBQ,EAAI,CAAC5C,EAAKgD,IAAUpF,OAAOC,UAAUC,eAAea,KAAKqB,EAAKgD,GCClFZ,EAAoBa,EAAK/I,IACH,oBAAXgJ,QAA0BA,OAAOC,aAC1CvF,OAAOiF,eAAe3I,EAASgJ,OAAOC,YAAa,CAAEC,MAAO,WAE7DxF,OAAOiF,eAAe3I,EAAS,aAAc,CAAEkJ,OAAO,K,wNCAhD,MAAMC,EAAqD,cACrDC,EAAyD,cCD/D,IAAMC,EAAN,cAA4C,EAAAC,eAA5C,c,oBACL,KAAAC,SAAW,CACT,CAACJ,GAAa,CACZK,WAAY,IAGlB,GANaH,E,mUAA6B,GADzC,IAAAI,eACYJ,G,wCCiBN,IAAMK,EAAN,MAGL,WAAAC,CAAoBC,GAAA,KAAAA,IAAAA,EAFZ,KAAAC,gBAA+C,IAAIC,IAGzDjI,KAAK+H,IAAIG,WAAWC,UAAWC,GAAQpI,KAAKqI,YAAYD,GAC1D,CAEA,gBAAAE,CAAiBC,GACfC,QAAQC,IAAI,sCAAuCF,GACnD,IAAK,MAAMG,KAAOH,EAChBvI,KAAKgI,gBAAgBW,IAAID,EAAIE,OAAQF,EAEzC,CAEQ,WAAAL,CAAYD,GAOlB,GANAI,QAAQC,IAAI,4BAA6B,CACvCrF,KAAMgF,EAAIN,YAAYe,KACtBC,MAAOV,EAAIU,QAITV,aAAe,EAAAW,kBAIjB,OAHAP,QAAQC,IAAI,0EAEZO,WAAW,IAAMhJ,KAAKiJ,iBAAiBb,GAAM,KAK3CA,aAAe,EAAAc,0BACjBlJ,KAAKmJ,mBAAmBf,EAE5B,CAEQ,gBAAAa,CAAiBG,GAEvB,MAAMC,EAAUD,EAASE,aACzBd,QAAQC,IAAI,kCAAmCY,EAAQ/I,QAEvD,IAAK,MAAM8H,KAAOiB,EACZjB,aAAe,EAAAc,0BACjBlJ,KAAKmJ,mBAAmBf,EAG9B,CAGQ,kBAAAe,CAAmBI,GACzB,MAAMX,EAASW,EAAYC,aAAeD,EAAYT,MACtDN,QAAQC,IAAI,yCAA0C,CACpDK,MAAOS,EAAYT,MACnBU,YAAaD,EAAYC,YACzBZ,SACAa,YAAa,IAAIzJ,KAAKgI,gBAAgB0B,UAGxC,MAAMC,EAAU3J,KAAKgI,gBAAgBhB,IAAI4B,GACzC,IAAKe,EAEH,YADAnB,QAAQC,IAAI,gDAAiDG,GAI/D5I,KAAKgI,gBAAgB4B,OAAOhB,GAG5B,MAAMiB,EAAc7J,KAAK8J,iBAAiBH,GAC1C,IAAKE,EAEH,YADArB,QAAQC,IAAI,gEAIdD,QAAQC,IAAI,8DAA+DoB,GAG3E,MAAME,EAAc,KAClBvB,QAAQC,IAAI,8CAA+CoB,GAC3DN,EAAYS,UAAUH,EAAc,MACpC7J,KAAKiK,iBAAiBV,GACtBvJ,KAAKkK,YAAYX,EAAaI,EAAQQ,gBAIpCZ,EAAYa,SAASC,QACvBd,EAAYa,QAAQC,QAAQC,MAC1B,IAAAC,UACA,IAAAC,SAAQ,MACR,IAAAC,YAAW,KAAM,IAAAC,IAAG,QACpBvC,UAAU,KAEVa,WAAWe,EAAa,QAG1BvB,QAAQC,IAAI,6DACZO,WAAWe,EAAa,KAE5B,CAEQ,gBAAAD,CAAiBH,GACvB,OAAOA,EAAQgB,SAAW,IAC5B,CAGQ,gBAAAV,CAAiBV,GAGvB,MAAMqB,EAAWrB,EAAoBqB,QACjCA,GAASC,SAASC,OACpBtC,QAAQC,IAAI,kEACZmC,EAAQC,QAAQC,KAAO,GAE3B,CAGQ,WAAAZ,CAAYX,EAA4CT,GAC9DS,EAAYwB,SAASjC,GACrBS,EAAYC,YAAcV,CAC5B,GApHWjB,E,mUAAqB,GADjC,IAAAD,c,kIAI0B,EAAAoD,cAHdnD,GCiEN,MAAMoD,EAA4C,CACvD,CAAE7H,KAAM,OAAQiE,MAAO,IAEvB,CAAEjE,KAAM,WAAYiE,MAAO,kJAC3B,CAAEjE,KAAM,WAAYiE,MAAO,yEAC3B,CAAEjE,KAAM,WAAYiE,MAAO,sEAC3B,CAAEjE,KAAM,WAAYiE,MAAO,yEAC3B,CAAEjE,KAAM,WAAYiE,MAAO,2EAC3B,CAAEjE,KAAM,WAAYiE,MAAO,wEAE3B,CAAEjE,KAAM,WAAYiE,MAAO,2EAC3B,CAAEjE,KAAM,WAAYiE,MAAO,sEAC3B,CAAEjE,KAAM,WAAYiE,MAAO,kJAC3B,CAAEjE,KAAM,WAAYiE,MAAO,wEAC3B,CAAEjE,KAAM,WAAYiE,MAAO,2EAC3B,CAAEjE,KAAM,WAAYiE,MAAO,8IAC3B,CAAEjE,KAAM,WAAYiE,MAAO,uHAC3B,CAAEjE,KAAM,WAAYiE,MAAO,2EAC3B,CAAEjE,KAAM,WAAYiE,MAAO,4IAC3B,CAAEjE,KAAM,WAAYiE,MAAO,mJAQtB,SAAS6D,EAAiBC,GAC/B,MAAO,gBAAiBA,GAAQ,aAAcA,CAChD,CAMO,SAASC,IACd,MAAO,CACL5L,GAAI6L,IACJC,UAAW,GACXC,IAAK,GACLC,eAAgB,GAEpB,CAOO,SAASC,EAAmBC,EAAyC,cAC1E,MAAO,CACLA,cACAC,OAAQ,CAAC,GAAK,IACdC,SAAU,CAACR,IAAqBA,KAEpC,CAGA,MAAMS,EAAmB,CACvB,UACA,UACA,UACA,UACA,UACA,UACA,UACA,WAIIC,EAAkB,CACtB,UAAW,WAAY,OAAQ,SAAU,OAAQ,YACjD,MAAO,WAAY,SAAU,QAAS,SAAU,QAChD,MAAO,SAAU,OAAQ,cAAe,UAAW,mBA8B9C,SAAST,IACd,MAAO,uCAAuC9H,QAAQ,QAAUwI,IAC9D,MAAM7E,EAAqB,GAAhBvB,KAAKqG,SAAiB,EAEjC,OADgB,MAAND,EAAY7E,EAAS,EAAJA,EAAW,GAC7BtH,SAAS,KAEtB,CAOO,SAASqM,EAAWd,GACzB,OAAID,EAAiBC,GACZA,EAAKS,SAASM,OAAO,CAACC,EAAKC,IAAUD,EAAMF,EAAWG,GAAQ,GAEhE,CACT,CAQO,SAASC,EAAapI,GAC3B,GAAY,OAARA,GAA+B,iBAARA,EACzB,OAAOA,EAET,GAAI9B,MAAMC,QAAQ6B,GAChB,OAAOA,EAAIhE,IAAIC,GAAQmM,EAAUnM,IAEnC,MAAMoM,EAAS,CAAC,EAChB,IAAK,MAAM3J,KAAOsB,EACZpC,OAAOC,UAAUC,eAAea,KAAKqB,EAAKtB,KAC5C2J,EAAO3J,GAAO0J,EAAUpI,EAAItB,KAGhC,OAAO2J,CACT,CCrNO,IAAMC,EAAN,MAKL,WAAAzE,CACU0E,EACAC,EACAC,GAFA,KAAAF,OAAAA,EACA,KAAAC,cAAAA,EACA,KAAAC,gBAAAA,EAPF,KAAAC,eAAwC,KACxC,KAAAC,eAAyB,EAChB,KAAAC,UAAY,GAM1B,CAEK,uBAAMC,GACZ,MAAMC,EAAMC,KAAKD,MAKjB,QAJK/M,KAAK2M,gBAAkBI,EAAM/M,KAAK4M,eAAiB5M,KAAK6M,aAC3D7M,KAAK2M,qBAAwB3M,KAAK0M,gBAAgBO,cAClDjN,KAAK4M,eAAiBG,GAEjB/M,KAAK2M,cACd,CAGA,aAAAO,GACE,OAAOlN,KAAKwM,OAAOW,QAAQ7F,IAAaK,YAAc,EACxD,CAMA,oBAAMyF,CAAezF,GACnB,IAAK3H,KAAKwM,OAAOW,QAAQ7F,GACvB,MAAM,IAAIpC,MAAM,gCAElBlF,KAAKwM,OAAOW,MAAM7F,GAAYK,WAAaA,QACrC3H,KAAKqN,YACb,CAGA,kBAAMC,CAAaC,GACjB,IACE,MAAM5F,EAAa3H,KAAKkN,gBACxBvF,EAAWpI,KAAKgO,SACVvN,KAAKoN,eAAezF,GAC1B3H,KAAKyM,cAAce,KAAK,cAAcD,EAAU1E,gB,CAChD,MAAO4E,GAEP,MADAzN,KAAKyM,cAAcgB,MAAM,+BAA+BF,EAAU1E,SAC5D4E,C,CAEV,CAGA,qBAAMC,CAAgBH,GACpB,IACE,MAAM5F,EAAa3H,KAAKkN,gBAClBzI,EAAQkD,EAAWgG,UAAWC,GAAMA,EAAEpO,KAAO+N,EAAU/N,KAC9C,IAAXiF,IACFkD,EAAWlD,GAAS8I,QACdvN,KAAKoN,eAAezF,GAC1B3H,KAAKyM,cAAce,KAAK,cAAcD,EAAU1E,iB,CAElD,MAAO4E,GAEP,MADAzN,KAAKyM,cAAcgB,MAAM,+BAA+BF,EAAU1E,SAC5D4E,C,CAEV,CAGA,qBAAMI,CAAgBC,GACpB,MAAMnG,EAAa3H,KAAKkN,gBAClBK,EAAY5F,EAAWoG,KAAMH,GAAMA,EAAEpO,KAAOsO,GAClD,IACE,MAAME,EAAWrG,EAAWsG,OAAQL,GAAMA,EAAEpO,KAAOsO,SAC7C9N,KAAKoN,eAAeY,GACtBT,GACFvN,KAAKyM,cAAce,KAAK,cAAcD,EAAU1E,gB,CAElD,MAAO4E,GAEP,MADAzN,KAAKyM,cAAcgB,MAAM,+BAA+BF,GAAW1E,MAAQiF,MACrEL,C,CAEV,CAGA,0BAAMS,GAEJ,aAD0BlO,KAAK0M,gBAAgBO,eAC5BgB,OAChBE,IACa,UAAXA,EAAE/K,MAAoB+K,EAAE/K,MAAMgL,WAAW,aACzCD,EAAE3O,IAAI4O,WAAW,iBAExB,CAMA,uBAAAC,GACE,IAAKrO,KAAKwM,OAAOW,OAAOmB,SACtB,OAEF,MAAMA,EAA2BtO,KAAKwM,OAAOW,MAAMmB,SAC7CC,EAAS,gBAAgBjH,KACzB0G,EAAWM,EAASL,OAAQE,IAAOA,EAAE3O,IAAI4O,WAAWG,IACtDP,EAAS1N,SAAWgO,EAAShO,SAC/BN,KAAKwM,OAAOW,MAAMmB,SAAWN,EAC7BhO,KAAKwM,OAAOgC,OACZhG,QAAQC,IAAI,IAAIlB,iBAA4B+G,EAAShO,OAAS0N,EAAS1N,4BAE3E,CAGA,0BAAMmO,CAAqBlB,SACnBvN,KAAK8M,oBACX,MAAM4B,EAAW1O,KAAK2O,qBAAqBpB,EAAU1E,MACrD,MAAO,CACLrJ,GAAI,gBAAgB8H,KAAcoH,KAAYnB,EAAU/N,KACxD4D,KAAM,eACNyF,KAAM0E,EAAU1E,KAChB+F,MAAOrH,EACPsH,KAAMtB,EAAUsB,KAChBC,MAAOvB,EAAUuB,MACjBC,WAAW,EACXlE,QAAS,CACPmE,cAAehP,KAAKiP,sBAAsB1B,EAAUtP,KAAMsP,EAAU1E,KAAM0E,EAAU/N,KAG1F,CAEQ,qBAAAyP,CAAsBvJ,EAAuBwJ,EAAuBpB,GAC1E,MAAO,CACL1K,KAAM,gBACNsI,YAAmC,eAAtBhG,EAAMgG,YAA+B,IAAM,IACxDC,OAAQjG,EAAMiG,OACdmC,cACAlC,SAAUlG,EAAMkG,SAAS3L,IAAKmM,GACxBlB,EAAiBkB,GACZpM,KAAKiP,sBAAsB7C,EAAO8C,EAAepB,GAEnD9N,KAAKmP,kBAAkB/C,EAAO8C,EAAepB,IAG1D,CAEQ,iBAAAqB,CAAkBC,EAAqBF,EAAuBpB,GACpE,MAAMuB,EAAcrP,KAAKsP,eAAeF,EAAK9D,WAE7C,IAAK+D,EACH,MAAO,CACLjM,KAAM,gBACNwH,QAAS,CACPxH,KAAM,QACNyF,KAAM,SAER0G,YAAY,GAKhB,MAAM1E,EAAU,CACd2E,kBAAkB,EAClB7E,QAAS0E,EAAYxE,SAASF,SAAW,GACzCG,KAAMuE,EAAYxE,SAASC,MAAQ,GACnCS,IAAK6D,EAAK7D,KAAO8D,EAAYxE,SAASU,KAAO,GAC7CkE,IAAKJ,EAAYxE,SAAS4E,KAAO,CAAC,EAClCC,MAAO,KACPC,OAAQ,KACRC,gBAAgB,EAChBC,oBAAoB,GAMhBjF,EAAU,CACdpL,GAAI6P,EAAY7P,GAChB4D,KAAM,QACNyF,KAAMwG,EAAYxG,MAAQ,QAC1B+F,MAAOS,EAAYT,OAAS,GAC5B/D,UACAgE,KAAMQ,EAAYR,MAAQ,GAC1BC,MAAOO,EAAYP,OAAS,GAC5BgB,qBAAqB,EACrBC,OAAQ,EACRhB,WAAW,EACXiB,YAAY,EACZC,oBAAqB,KACrBC,qBAAsB,QAMlB3E,EAAM6D,EAAK7D,KAAO8D,EAAYxE,SAASU,KAAO,GACpD,MAAO,CACLnI,KAAM,gBACNwH,UACA2E,YAAY,EACZY,SAAUjB,EACVkB,eAAgBhB,EAAK5P,GACrBsO,cACAgC,qBAAqB,EACrBvE,MAEJ,CAGA,kBAAA8E,CAAmB9C,GACjB,MAAM+C,EAAQjE,EAAUkB,GAKxB,OAJA+C,EAAM9Q,GAAK6L,IACXiF,EAAMzH,KAAO,GAAG0E,EAAU1E,cAC1ByH,EAAMC,iBAAkB,EACxBvQ,KAAKwQ,cAAcF,EAAMrS,MAClBqS,CACT,CAEQ,aAAAE,CAAcrF,GACpB,GAAID,EAAiBC,GACnB,IAAK,MAAMiB,KAASjB,EAAKS,SACvB5L,KAAKwQ,cAAcpE,QAGrBjB,EAAK3L,GAAK6L,GAEd,CAEQ,oBAAAsD,CAAqB9F,GAC3B,OAAOA,EACJ4H,cACAlN,QAAQ,cAAe,KACvBA,QAAQ,MAAO,KACfA,QAAQ,SAAU,KAChB,WACP,CAEQ,cAAA+L,CAAehE,GACrB,MAAMoF,EAAetN,GAA0B,UAATA,GAAoBA,GAAMgL,WAAW,UAK3E,OAFqCpO,KAAKwM,OAAOW,OAAOmB,UAAY,IACzCP,KAAMI,GAAMA,EAAE3O,KAAO8L,GAAaoF,EAAYvC,EAAE/K,QAIpEpD,KAAK2M,gBAAgBoB,KAAMI,GAAMA,EAAE3O,KAAO8L,GAAaoF,EAAYvC,EAAE/K,MAC9E,CAGA,sBAAAuN,CAAuBpD,GACrB,MAAMhF,EAA6B,GAEnC,OADAvI,KAAK4Q,wBAAwBrD,EAAUtP,KAAMsP,EAAU1E,KAAMN,GACtDA,CACT,CAEQ,uBAAAqI,CACNzF,EACA+D,EACA3G,GAEA,GAAI2C,EAAiBC,GACnB,IAAK,MAAMiB,KAASjB,EAAKS,SACvB5L,KAAK4Q,wBAAwBxE,EAAO8C,EAAe3G,QAE5C4C,EAAKK,gBACdjD,EAAShJ,KAAK,CACZqJ,OAAQuC,EAAK3L,GACbmL,QAASQ,EAAKK,eACdrB,cAAe+E,GAGrB,CAEQ,gBAAM7B,GACZ,UACQrN,KAAKwM,OAAOgC,M,CAClB,MAAOf,GAEP,MADAjF,QAAQiF,MAAM,0BAA2BA,GACnCA,C,CAEV,GAtRWlB,E,mUAAsB,GADlC,IAAA3E,YAAW,CAAEiJ,WAAY,S,kIAON,EAAAC,cACO,EAAAC,qBACE,EAAAC,mBARhBzE,G,ybCEN,IAAM0E,EAAN,MAEL,WAAAnJ,CAAmBoJ,GAAA,KAAAA,MAAAA,EADV,KAAAhC,cAAgB,EACkB,GAD3C,IAAC,IAAAiC,S,6DADUF,EAA2B,IAhBvC,IAAAG,WAAU,CACTC,SAAU,uBACVC,SAAU,me,uBAgBgB,EAAAC,kBAFfN,GCMN,IAAMO,EAAN,MAUL,WAAA1J,CACS0E,EACCiF,EACA/E,EACAgF,EACAC,EACAC,EACAC,EACAC,GAPD,KAAAtF,OAAAA,EACC,KAAAiF,iBAAAA,EACA,KAAA/E,gBAAAA,EACA,KAAAgF,eAAAA,EACA,KAAAC,aAAAA,EACA,KAAAC,IAAAA,EACA,KAAAC,WAAAA,EACA,KAAAC,KAAAA,EAjBV,KAAAnK,WAA0B,GAC1B,KAAAoK,kBAAsC,KACtC,KAAAC,iBAAqC,KACrC,KAAAC,eAAgB,EAChB,KAAAC,mBAAoC,KACpC,KAAAC,YAA+D,GACvD,KAAAxF,eAAiC,GACjC,KAAAyF,mBAA0C,IAW/C,CAEH,cAAMC,GACJrS,KAAKsS,iBACLtS,KAAKuS,kBACLvS,KAAK2M,qBAAuB3M,KAAKyR,iBAAiBvD,uBAClDlO,KAAKoS,mBAAqBpS,KAAKwM,OAAOgG,SAASrK,UAAU,KACvDnI,KAAK8R,KAAKW,IAAI,IAAMzS,KAAKsS,mBAE7B,CAEA,eAAAI,GAEE1J,WAAW,KACT,MAAM2J,EAAS3S,KAAK6R,WAAWe,cAAcC,QAAQ,qBACjDF,IACFA,EAAO3P,MAAM8P,SA1CM,UA4CpB,EACL,CAEQ,eAAAP,GACFvS,KAAK2H,WAAWrH,OAAS,IAAMN,KAAK+R,mBACtC/R,KAAK+S,gBAAgB/S,KAAK2H,WAAW,GAEzC,CAEA,eAAAoL,CAAgBxF,GACdvN,KAAKiS,eAAgB,EACrBjS,KAAK+R,kBAAoBxE,EACzBvN,KAAKgS,iBAAmB3F,EAAUkB,GAClCvN,KAAKgT,mBACP,CAEA,UAAAC,CAAW1F,GACT,OAAOvN,KAAK+R,mBAAmBvS,KAAO+N,EAAU/N,EAClD,CAEA,WAAA0T,GACElT,KAAKoS,oBAAoBe,aAC3B,CAEA,cAAAb,GACE,MAAMc,EAAqBpT,KAAK+R,mBAAmBvS,GACnDQ,KAAK2H,WAAa3H,KAAKyR,iBAAiBvE,gBAIpCkG,IACFpT,KAAK+R,kBAAoB/R,KAAK2H,WAAWoG,KAAKH,GAAKA,EAAEpO,KAAO4T,IAAuB,MAGrFpT,KAAKgT,mBACP,CAEA,eAAAK,GACE,MAAMC,EAAmBtT,KAAK2M,eAAe,IAAInN,IAAM,GACjD+N,EH6EH,SAAgC1E,EAAe,IACpD,MAAO,CACLrJ,GAAI6L,IACJxC,OACAgG,KAZK/C,EAAgBnG,KAAK4N,MAAM5N,KAAKqG,SAAWF,EAAgBxL,SAahEwO,MAlBKjD,EAAiBlG,KAAK4N,MAAM5N,KAAKqG,SAAWH,EAAiBvL,SAmBlErC,KAAMwN,IACN8E,iBAAiB,EAErB,CGtFsBiD,GAClBxT,KAAKyT,sBAAsBlG,EAAUtP,KAAMqV,GAC3CtT,KAAK+R,kBAAoB,KACzB/R,KAAKgS,iBAAmBzE,EACxBvN,KAAKiS,eAAgB,EACrBjS,KAAKgT,oBACLhT,KAAK4R,IAAI8B,eACX,CAEQ,qBAAAD,CAAsBtI,EAAsCG,GAC9DJ,EAAiBC,GACnBA,EAAKS,SAAS+H,QAASvH,GAAUpM,KAAKyT,sBAAsBrH,EAAOd,IAEnEH,EAAKG,UAAYA,CAErB,CAEA,aAAAsI,CAAcrG,GACZvN,KAAK+S,gBAAgBxF,EACvB,CAEA,wBAAM8C,CAAmBwD,EAAmBtG,GAC1CsG,EAAMC,kBACN,MAAMxD,EAAQtQ,KAAKyR,iBAAiBpB,mBAAmB9C,SACjDvN,KAAKyR,iBAAiBnE,aAAagD,GAEzCtQ,KAAK8R,KAAKW,IAAI,KACZzS,KAAKsS,iBACL,MAAMyB,EAAa/T,KAAK2H,WAAWoG,KAAMH,GAAMA,EAAEpO,KAAO8Q,EAAM9Q,IAC1DuU,GACF/T,KAAK+S,gBAAgBgB,IAG3B,CAEA,qBAAMlG,CAAgBgG,EAAmBtG,GAIvC,GAHAsG,EAAMC,yBAEkB9T,KAAKgU,cAAczG,EAAU1E,MACrC,OAEhB,MAAMoL,EAAcjU,KAAK+R,mBAAmBvS,KAAO+N,EAAU/N,GACvD0U,EAAelU,KAAK2H,WAAWgG,UAAWC,GAAMA,EAAEpO,KAAO+N,EAAU/N,UAEnEQ,KAAKyR,iBAAiB5D,gBAAgBN,EAAU/N,IAEtDQ,KAAK8R,KAAKW,IAAI,KAEZ,GADAzS,KAAKsS,iBAC0B,IAA3BtS,KAAK2H,WAAWrH,OAClBN,KAAK+R,kBAAoB,KACzB/R,KAAKgS,iBAAmB,KACxBhS,KAAKiS,eAAgB,OAChB,GAAIgC,EAAa,CACtB,MAAME,EAAYxO,KAAKE,IAAIqO,EAAclU,KAAK2H,WAAWrH,OAAS,GAClEN,KAAK+S,gBAAgB/S,KAAK2H,WAAWwM,G,GAG3C,CAEQ,mBAAMH,CAAcnL,GAC1B,MAAMuL,EAAWpU,KAAK2R,aAAa0C,KAAKpD,GACxCmD,EAASE,kBAAkBpF,cAAgBrG,EAC3C,IAEE,aADMuL,EAAS3U,QACR,C,CACP,MACA,OAAO,C,CAEX,CAEA,kBAAM8U,CAAahH,GACFvN,KAAK2H,WAAWoG,KAAMH,GAAMA,EAAEpO,KAAO+N,EAAU/N,UAItDQ,KAAKyR,iBAAiB/D,gBAAgBH,SAFtCvN,KAAKyR,iBAAiBnE,aAAaC,GAM3CvN,KAAK8R,KAAKW,IAAI,KACZzS,KAAKsS,iBACLtS,KAAKiS,eAAgB,EACrB,MAAMuC,EAAQxU,KAAK2H,WAAWoG,KAAMH,GAAMA,EAAEpO,KAAO+N,EAAU/N,IACzDgV,GACFxU,KAAK+S,gBAAgByB,IAG3B,CAEA,cAAAC,GACMzU,KAAKiS,eAEPjS,KAAKiS,eAAgB,EACjBjS,KAAK2H,WAAWrH,OAAS,EAC3BN,KAAK+S,gBAAgB/S,KAAK2H,WAAW,KAErC3H,KAAK+R,kBAAoB,KACzB/R,KAAKgS,iBAAmB,KACxBhS,KAAKgT,sBAEEhT,KAAK+R,oBAEd/R,KAAKgS,iBAAmB3F,EAAUrM,KAAK+R,oBAEzC/R,KAAK4R,IAAI8B,eACX,CAEA,YAAAgB,CAAanH,GACX,OAAOtB,EAAWsB,EAAUtP,KAC9B,CAEA,mBAAA0W,CAAoBpH,GAClB,MAAsC,eAA/BA,EAAUtP,KAAKyN,YAA+B,aAAe,UACtE,CAEA,qBAAIkJ,GACF,OAAK5U,KAAKgS,kBAAqBhS,KAAK+R,kBAC7BzQ,KAAKC,UAAUvB,KAAKgS,oBAAsB1Q,KAAKC,UAAUvB,KAAK+R,mBADP/R,KAAKiS,aAErE,CAGQ,iBAAAe,GACN,MAAM6B,EAAO7U,KAAK2H,WAAW1H,IAAI2N,IAAK,CAAGL,UAAWK,EAAGkH,OAAO,KAC1D9U,KAAKiS,eAAiBjS,KAAKgS,kBAC7B6C,EAAKtV,KAAK,CAAEgO,UAAWvN,KAAKgS,iBAAkB8C,OAAO,IAEvD9U,KAAKmS,YAAc0C,CACrB,CAEA,aAAAE,CAAc3M,GACZ,QAAIA,EAAI0M,OACD9U,KAAK+R,mBAAmBvS,KAAO4I,EAAImF,UAAU/N,EACtD,CAEA,UAAAwV,CAAWvQ,EAAe2D,GACxB,OAAOA,EAAI0M,MAAQ,UAAY1M,EAAImF,UAAU/N,EAC/C,CAEA,mBAAMyV,CAAcpB,EAAmBtG,GAErC,GADAsG,EAAMC,mBACF9T,KAAKkS,mBAAT,CACAlS,KAAKkS,mBAAqB3E,EAAU/N,GAEpC,IACE,MAAM+I,EAAWvI,KAAKyR,iBAAiBd,uBAAuBpD,GAC1DhF,EAASjI,OAAS,GACpBN,KAAK0R,eAAepJ,iBAAiBC,GAGvC,MAAMqC,QAAgB5K,KAAKyR,iBAAiBhD,qBAAqBlB,GACjEvN,KAAK8R,KAAKW,IAAI,KACZzS,KAAK0M,gBAAgBwI,qBAAqBtK,I,SAG5C5K,KAAKkS,mBAAqB,KAC1BlS,KAAK4R,IAAI8B,e,CAfwB,CAiBrC,GAzOWlC,E,mUAAsB,GALlC,IAAAJ,WAAU,CACTC,SAAU,iBACVC,SAAU,EAAQ,KAClB6D,OAAQ,CAAC,EAAQ,Q,kIAaA,EAAArE,cACWvE,EACD,EAAAyE,gBACDnJ,EACF,EAAAuN,SACT,EAAAC,kBACO,EAAAC,WACN,EAAAC,UAlBL/D,GCnBN,IAAMgE,EAAN,cAA8C,EAAAC,oBAA9C,c,oBACL,KAAAjW,GAAK8H,EACL,KAAAuH,KAAyB,WACzB,KAAA/F,MAAQvB,CAKV,CAHE,gBAAAmO,GACE,OAAOlE,CACT,GAPWgE,E,mUAA+B,GAD3C,IAAA5N,eACY4N,GCKN,IAAMG,EAAN,MAIL,WAAA7N,CACUC,EACA0J,GADA,KAAA1J,IAAAA,EACA,KAAA0J,iBAAAA,EALF,KAAAmE,aAAwC,KACxC,KAAAC,kBAAoB,IAAI5N,GAK7B,CAMH,UAAA6N,GACE9V,KAAK+V,mBACP,CAEQ,iBAAAA,GAEN/V,KAAK+H,IAAIG,WAAWC,UAAUC,GAAOpI,KAAKqI,YAAYD,IAGtDpI,KAAK+H,IAAIiO,WAAW7N,UAAUC,GAAOpI,KAAKiW,YAAY7N,GACxD,CAEQ,WAAAC,CAAYD,GACZA,aAAe,EAAAW,mBAGrBC,WAAW,KACT,MAAM8E,EAAc9N,KAAKkW,mBAAmB9N,GAC5C,IAAK0F,EAAa,OAElB,MAAMP,EAAYvN,KAAKyR,iBAAiBvE,gBACrCa,KAAKH,GAAKA,EAAEpO,KAAOsO,GAElBP,GAAW4I,YAA4C,SAA9B5I,EAAU4I,WAAW/S,MAChDpD,KAAKoW,gBAAgBtI,EAAaP,EAAU4I,aAE7C,IACL,CAEQ,WAAAF,CAAY7N,GAClB,KAAMA,aAAe,EAAAW,mBAAoB,OAEzC,MAAM+E,EAAc9N,KAAKkW,mBAAmB9N,GACxC0F,GACF9N,KAAKqW,iBAAiBvI,EAE1B,CAMQ,kBAAAoI,CAAmB9N,GACzB,MAAMkO,EAASlO,EAGf,GAAIkO,EAAOC,iBAAiBzI,YAC1B,OAAOwI,EAAOC,gBAAgBzI,YAIhC,MAAM0I,EAAgB,gBAAgBlP,KACtC,IAAK,MAAM8E,KAAShE,EAAIkB,aAAc,CACpC,MAAMgC,EAAac,EAAcxB,SAASpL,IAAM,GAChD,GAAI8L,EAAU8C,WAAWoI,GAAgB,CAEvC,MAAMC,EAAQnL,EAAU5F,MAAM,KAC9B,OAAO+Q,EAAMA,EAAMnW,OAAS,E,EAKlC,CAEQ,eAAA8V,CAAgBtI,EAAqB4I,GAE3C1W,KAAK2W,oBAAoB7I,GAGzB,MAAM8I,EAAM5W,KAAK6W,YAAY/I,EAAa4I,GAC1C1W,KAAK8W,UAAUhJ,EAAa8I,EAC9B,CAEQ,mBAAAD,CAAoB7I,GAE1B,MAAMiJ,EAAYC,SAASC,iBAAiB,aAC5C,IAAK,IAAIvY,EAAIqY,EAAUzW,OAAS,EAAG5B,GAAK,EAAGA,IAAK,CAC9C,MAAM0K,EAAW2N,EAAUrY,GAC3B,IAAK0K,EAAS8N,aAAa,qBAAsB,CAC/C9N,EAAS+N,aAAa,oBAAqBrJ,GAC3C,K,EAGN,CAEQ,WAAA+I,CAAY/I,EAAqB4I,GACvC,MAAgB,SAAZA,EAAGtT,MAAoBsT,EAAGrP,MAEvB,wCAC0ByG,8BACf4I,EAAGrP,kEAEYyG,4DACAA,kFAPW,EAW9C,CAEQ,SAAAgJ,CAAUhJ,EAAqB8I,GAChC5W,KAAK4V,eACR5V,KAAK4V,aAAeoB,SAASI,cAAc,SAC3CpX,KAAK4V,aAAapW,GAAK,0BACvBwX,SAASK,KAAKC,YAAYtX,KAAK4V,eAGjC5V,KAAK6V,kBAAkBlN,IAAImF,EAAa8I,GACxC5W,KAAKuX,oBACP,CAEQ,gBAAAlB,CAAiBvI,GACvB9N,KAAK6V,kBAAkBjM,OAAOkE,GAC9B9N,KAAKuX,oBACP,CAEQ,kBAAAA,GACFvX,KAAK4V,eACP5V,KAAK4V,aAAa4B,YAAcrV,MAAMsV,KAAKzX,KAAK6V,kBAAkB6B,UAAUnX,KAAK,MAErF,CAMA,0BAAAoX,CAA2B7J,GACzB,MAAMP,EAAYvN,KAAKyR,iBAAiBvE,gBACrCa,KAAKH,GAAKA,EAAEpO,KAAOsO,GAEtB,GAAKP,EAAL,CAKA,GAAIA,EAAU4I,YAA4C,SAA9B5I,EAAU4I,WAAW/S,KAAiB,CAChE,MAAMwT,EAAM5W,KAAK6W,YAAY/I,EAAaP,EAAU4I,YACpDnW,KAAK6V,kBAAkBlN,IAAImF,EAAa8I,E,MAExC5W,KAAK6V,kBAAkBjM,OAAOkE,GAEhC9N,KAAKuX,oB,MAVHvX,KAAKqW,iBAAiBvI,EAW1B,GA1JW6H,E,mUAA0B,GADtC,IAAA/N,YAAW,CAAEiJ,WAAY,S,kIAMT,EAAA7F,WACauB,KANjBoJ,GCFb,MAWMiC,EAAuB,eAUtB,IAAMC,EAAN,cAAuC,EAAAC,sBAC5C,WAAAhQ,CACU2J,EACA/E,EACA3E,EACA2J,EACAqG,GAERC,QANQ,KAAAvG,iBAAAA,EACA,KAAA/E,gBAAAA,EACA,KAAA3E,IAAAA,EACA,KAAA2J,eAAAA,EACA,KAAAqG,kBAAAA,EAIR/X,KAAK+X,kBAAkBjC,aAGvB9V,KAAKiY,oBAAoBC,KAAK,KAC5BlY,KAAKyR,iBAAiBpD,0BACtBrO,KAAKmY,2BAET,CAEQ,iBAAAF,GACN,OAAO,IAAIG,QAAQC,IACjB,IAAIC,GAAgB,EACpB,MAAMC,EAAc,KAClB,MAAMC,EAAexY,KAAK+H,IAAI8M,KAAKvU,OAC/BkY,IAAiBF,GAAgBE,GAAgB,EACnDH,KAEAC,EAAeE,EACfxP,WAAWuP,EAAa,OAI5BvP,WAAWuP,EAAa,MAE5B,CAEQ,6BAAMJ,GACZ,MACMM,EADazY,KAAKyR,iBAAiBvE,gBACJe,OAAOL,GAAKA,EAAE2C,iBAEnD,IAAK,MAAMhD,KAAakL,EAClBzY,KAAK0Y,uBAAuBnL,EAAU/N,IACxCgJ,QAAQC,IAAI,4BAA4B8E,EAAU1E,sCAG9C7I,KAAKiV,cAAc1H,EAAU/N,GAEvC,CAKQ,sBAAAmZ,CAAuBvQ,GAC7B,GAAIA,GAAsB,iBAARA,GAAoB,kBAAmBA,EAAK,CAC5D,MAAMwQ,EAASxQ,EAAuD4G,cACtE,OAAO4J,GAAO9K,W,CAGlB,CAEQ,sBAAA4K,CAAuB5K,GAC7B,MAAM0I,EAAgB,gBAAgBlP,KAEtC,IAAK,MAAMc,KAAOpI,KAAK+H,IAAI8M,KACzB,GAAIzM,aAAe,EAAAW,kBAAmB,CAEpC,GAAI/I,KAAK2Y,uBAAuBvQ,KAAS0F,EACvC,OAAO,EAIT,IAAK,MAAM1B,KAAShE,EAAIkB,aACtB,GAAI8C,aAAiB,EAAAlD,yBAA0B,CAC7C,MAAMoC,EAAYc,EAAMxB,SAASpL,IAAM,GAEvC,GAAI8L,EAAU8C,WAAWoI,IAAkBlL,EAAUuN,SAAS,IAAI/K,KAChE,OAAO,C,EAMjB,OAAO,CACT,CAEA,OAAAgL,GACE,MAAO,CACL,CACEjK,KA7GU,6VA8GV/F,MAAOvB,EACPwI,OAAQ,EACRgJ,MAAO,IAAM/Y,KAAKgZ,yBAGxB,CAEQ,2BAAMA,GACZ,MAAMrR,EAAa3H,KAAKyR,iBAAiBvE,gBAEzC,GAA0B,IAAtBvF,EAAWrH,OAEb,YADAN,KAAKiZ,eAIP,MAAMpO,EAAUlD,EAAW1H,IAAKiZ,IAAO,CACrCrQ,KAAMqQ,EAAGrQ,KACTsQ,YAAa,GAAGlN,EAAWiN,EAAGjb,cAC9B4Q,KAAMqK,EAAGrK,MAAQ,OACjBC,MAAOoK,EAAGpK,MACVrP,OAAQyZ,EAAG1Z,MAIbqL,EAAQtL,KAAK,CACXsJ,KAAM,uBACNsQ,YAAa,6BACbtK,KAAM,MACNC,WAAOjO,EACPpB,OAAQmY,IAGV,MAAMwB,QAAmBpZ,KAAK+H,IAAIsR,aAAa,mBAAoBxO,GAE/DuO,IAAexB,EACjB5X,KAAKiZ,eACIG,GACTpZ,KAAKiV,cAAcmE,EAEvB,CAEQ,YAAAH,GACNjZ,KAAK+H,IAAIuR,cAAc,CAAElW,KAAM,EAAAmW,qBAAsBC,OAAQ,CAAEC,UAAWnS,IAC5E,CAEQ,mBAAM2N,CAAcnH,GAC1B,MACMP,EADavN,KAAKyR,iBAAiBvE,gBACZa,KAAMH,GAAMA,EAAEpO,KAAOsO,GAElD,IAAKP,EAAW,OAIhB,MAAMhF,EAAWvI,KAAKyR,iBAAiBd,uBAAuBpD,GAC1DhF,EAASjI,OAAS,GACpBN,KAAK0R,eAAepJ,iBAAiBC,GAGvC,MAAMqC,QAAgB5K,KAAKyR,iBAAiBhD,qBAAqBlB,GACjEvN,KAAK0M,gBAAgBwI,qBAAqBtK,EAC5C,GArJWiN,E,mUAAwB,GADpC,IAAAjQ,c,kIAG6B2E,EACD,EAAAyE,gBACZ,EAAAhG,WACWnD,EACG8N,KANlBkC,G,ybCJN,IAAM6B,EAAN,MAuBL,WAAA5R,CACU2J,EACAI,EACAD,GAFA,KAAAH,iBAAAA,EACA,KAAAI,WAAAA,EACA,KAAAD,IAAAA,EAxBD,KAAA+H,WAAY,EACZ,KAAA/E,mBAAoB,EACnB,KAAApG,KAAO,IAAI,EAAAoL,aACX,KAAAC,OAAS,IAAI,EAAAD,aAIvB,KAAAE,eAAgC,KAChC,KAAAC,YAAoC,KACpC,KAAAC,gBAAiB,EACjB,KAAA1L,SAA2B,GAC3B,KAAA2L,eAAiB,CACf,UAAW,WAAY,OAAQ,SAAU,OAAQ,YACjD,MAAO,WAAY,SAAU,QAAS,SAAU,QAChD,MAAO,SAAU,OAAQ,cAAe,UAAW,mBAErD,KAAAC,kBAAmB,EACnB,KAAAC,kBAAoBlP,EACpB,KAAAmP,wBAAyB,EACzB,KAAAC,sBAAwB,EAMrB,CAGH,eAAAC,CAAgBzG,GAEd,MAAM0G,EAAkBva,KAAK6R,WAAWe,cAAc4H,cAAc,qBAC9DC,EAAeza,KAAK6R,WAAWe,cAAc4H,cAAc,kBAC3DE,EAAoBH,GAAiBI,SAAS9G,EAAM+G,SACpCH,GAAcE,SAAS9G,EAAM+G,QAC/C5a,KAAKka,mBAAqBQ,IAC5B1a,KAAKka,kBAAmB,GAI1B,MAAMW,EAAY7a,KAAK6R,WAAWe,cAAc4H,cAAc,uBACxDM,EAAa9a,KAAK6R,WAAWe,cAAc4H,cAAc,wBACzDO,EAAkBF,GAAWF,SAAS9G,EAAM+G,SAC1BE,GAAYH,SAAS9G,EAAM+G,QAC/C5a,KAAKoa,yBAA2BW,IAClC/a,KAAKoa,wBAAyB,EAElC,CAEA,kBAAAY,GACEhb,KAAKka,kBAAoBla,KAAKka,gBAChC,CAEA,UAAAe,CAAWpM,GACT7O,KAAKuN,UAAUsB,KAAOA,EACtB7O,KAAKka,kBAAmB,CAC1B,CAEA,wBAAAgB,GACElb,KAAKoa,wBAA0Bpa,KAAKoa,sBACtC,CAEA,sBAAAe,CAAuBC,GACD,SAAhBA,EAAOhY,MACTpD,KAAKuN,UAAU4I,gBAAatV,EAC5Bb,KAAKqa,sBAAwB,KAE7Bra,KAAKuN,UAAU4I,WAAa,IAAKiF,GACjCpb,KAAKqa,sBAAwBe,EAAO/T,OAEtCrH,KAAKoa,wBAAyB,CAChC,CAEA,qBAAAiB,GACE,MAAMhU,EAAQrH,KAAKqa,sBAAsBiB,OAEvCtb,KAAKuN,UAAU4I,WADb9O,EAC0B,CAC1BjE,KAAM,WACNiE,cAG0BxG,CAEhC,CAEA,eAAA0a,GACEvb,KAAKuN,UAAU4I,gBAAatV,EAC5Bb,KAAKqa,sBAAwB,EAC/B,CAEA,oBAAAmB,CAAqBJ,GACnB,MAAoB,SAAhBA,EAAOhY,MACDpD,KAAKuN,UAAU4I,YAAiD,SAAnCnW,KAAKuN,UAAU4I,WAAW/S,KAE1DpD,KAAKuN,UAAU4I,YAAY9O,QAAU+T,EAAO/T,KACrD,CAEA,cAAMgL,GACJrS,KAAKsO,eAAiBtO,KAAKyR,iBAAiBvD,uBAC5ClO,KAAKyb,sBACLzb,KAAK4R,IAAI8B,eACX,CAEA,eAAAhB,GACM1S,KAAK2Z,WACP3Z,KAAK0b,gBAET,CAEQ,cAAAA,GACNC,sBAAsB,KACpB3S,WAAW,KACLhJ,KAAK4b,WAAWhJ,gBAClB5S,KAAK4b,UAAUhJ,cAAciJ,QAC7B7b,KAAK4b,UAAUhJ,cAAckJ,WAE9B,IAEP,CAEA,WAAAC,CAAYC,GACV,GAAIA,EAAmB,YAAMA,EAAmB,UAAEC,YAAa,CAC7D,MAAMC,EAASF,EAAmB,UAAEG,eAAe3c,GAG/C0c,IAFWlc,KAAKuN,UAAU/N,IAI5BQ,KAAK8Z,eAAiB,KACtB9Z,KAAK+Z,YAAc,KACnB/Z,KAAKga,gBAAiB,EACtBha,KAAK0b,kBAID1b,KAAK8Z,gBAAkB9Z,KAAKga,iBAC9Bha,KAAK+Z,YAAc/Z,KAAKoc,aAAapc,KAAK8Z,iBAI9C9Z,KAAKka,kBAAmB,EACxBla,KAAKoa,wBAAyB,EAC9Bpa,KAAKqa,sBAAwBra,KAAKuN,UAAU4I,YAAY9O,OAAS,GACjErH,KAAKyb,qB,CAIHO,EAAmB,WAAGK,cACxBrc,KAAK0b,gBAET,CAEQ,mBAAAD,GACDzb,KAAKuN,UAAUtP,OAClB+B,KAAKuN,UAAUtP,KAAO,CACpByN,YAAa,aACbC,OAAQ,CAAC,GAAK,IACdC,SAAU,CAACR,IAAqBA,MAGtC,CAEA,MAAAkR,GACOtc,KAAKuN,UAAU1E,MAAMyS,QAG1Btb,KAAKwO,KAAK+N,KAAKvc,KAAKuN,UACtB,CAEA,QAAAiP,GACExc,KAAK6Z,OAAO0C,MACd,CAEA,YAAAE,GACEzc,KAAK8Z,eAAiB,IACxB,CAEA,wBAAA4C,GACE1c,KAAKyc,eACLzc,KAAK2c,iBACP,CAEA,QAAAC,CAASxN,GACPpP,KAAK8Z,eAAiB1K,EAAK5P,GAC3BQ,KAAK+Z,YAAc3K,EACnBpP,KAAKga,gBAAiB,EACtBha,KAAK4R,IAAI8B,eACX,CAEA,eAAAiJ,GACE3c,KAAKga,gBAAiB,EACtBha,KAAK+Z,YAAc,KACnB/Z,KAAK4R,IAAI8B,eACX,CAGQ,YAAA0I,CAAa5c,GACnB,OAAOQ,KAAK6c,eAAe7c,KAAKuN,UAAUtP,KAAMuB,EAClD,CAEQ,cAAAqd,CAAe1R,EAAsB3L,GAC3C,IAAK,MAAM4M,KAASjB,EAAKS,SACvB,GAAIV,EAAiBkB,GAAQ,CAC3B,MAAM0Q,EAAQ9c,KAAK6c,eAAezQ,EAAO5M,GACzC,GAAIsd,EAAO,OAAOA,C,MACb,GAAI1Q,EAAM5M,KAAOA,EACtB,OAAO4M,EAGX,OAAO,IACT,CAEA,aAAA2Q,GACE,OAAO/c,KAAKiM,WAAWjM,KAAKuN,UAAUtP,MAAQ,CAChD,CAEQ,UAAAgO,CAAWd,GACjB,OAAOA,EAAKS,SAASM,OAAO,CAAC8Q,EAAO5Q,IAC3B4Q,GAAS9R,EAAiBkB,GAASpM,KAAKiM,WAAWG,GAAS,GAClE,EACL,CAEQ,QAAA6Q,CACN9R,EACA+R,EACAvK,EAAgC,MAEhC,IAAK,IAAIjU,EAAI,EAAGA,EAAIyM,EAAKS,SAAStL,OAAQ5B,IAAK,CAC7C,MAAM0N,EAAQjB,EAAKS,SAASlN,GACtBye,EAAmB,CAAEhS,OAAM1G,MAAO/F,EAAGiU,SAAQvG,SAEnD,GAAIlB,EAAiBkB,IACnB,GAAIpM,KAAKid,SAAS7Q,EAAO8Q,EAAS/R,GAAO,OAAO,OAC3C,GAAI+R,EAAQC,GACjB,OAAO,C,CAGX,OAAO,CACT,CAEQ,gBAAAC,CAAiBC,GACvB,OAAOrd,KAAKid,SAASjd,KAAKuN,UAAUtP,KAAOkf,GACpCA,EAAI/Q,MAAwB5M,KAAO6d,EAAY7d,KAClD2d,EAAIhS,KAAKS,SAASuR,EAAI1Y,OAAS4Y,GACxB,GAIb,CAEA,SAAAC,CAAUlO,EAAqB1D,GAC7B1L,KAAKud,gBAAgBnO,EAAM1D,GAC3B1L,KAAK4R,IAAI8B,eACX,CAEA,iBAAA8J,CAAkB9R,GAChB,IAAK1L,KAAK8Z,eAAgB,OAC1B,MAAM1K,EAAOpP,KAAKoc,aAAapc,KAAK8Z,gBAChC1K,GAAMpP,KAAKsd,UAAUlO,EAAM1D,EACjC,CAEQ,eAAA6R,CACNE,EACA/R,GAEA,OAAO1L,KAAKid,SAASjd,KAAKuN,UAAUtP,KAAOkf,IACzC,GAAKA,EAAI/Q,MAAwB5M,KAAOie,EAAWje,GAAI,CACrD,MAAMke,EAAUtS,IAChBsS,EAAQpS,UAAa6R,EAAI/Q,MAAwBd,UACjD,MAAMqS,EAA2B,CAC/BjS,cACAC,OAAQ,CAAC,GAAK,IACdC,SAAU,CAACuR,EAAI/Q,MAAOsR,IAIxB,OAFAP,EAAIhS,KAAKS,SAASuR,EAAI1Y,OAASkZ,EAC/B3d,KAAK4d,kBAAkBT,EAAIhS,OACpB,C,CAET,OAAO,GAEX,CAEA,UAAA0S,CAAWzO,GACLpP,KAAK8Z,iBAAmB1K,EAAK5P,KAC/BQ,KAAK8Z,eAAiB,MAExB9Z,KAAK8d,mBAAmB9d,KAAKuN,UAAUtP,KAAMmR,GAC7CpP,KAAK4R,IAAI8B,eACX,CAEA,kBAAAqK,GACE,IAAK/d,KAAK8Z,iBAAmB9Z,KAAK+c,gBAAiB,OACnD,MAAM3N,EAAOpP,KAAKoc,aAAapc,KAAK8Z,gBAChC1K,GAAMpP,KAAK6d,WAAWzO,EAC5B,CAEQ,kBAAA0O,CAAmB3S,EAAsBsS,GAC/C,IAAK,IAAI/e,EAAI,EAAGA,EAAIyM,EAAKS,SAAStL,OAAQ5B,IAAK,CAC7C,MAAM0N,EAAQjB,EAAKS,SAASlN,GAC5B,GAAIwM,EAAiBkB,GAAQ,CAE3B,MAAM4R,EAAY5R,EAAMR,SAAS+B,UAC9B5B,IAAOb,EAAiBa,IAAOA,EAAoBvM,KAAOie,EAAWje,IAExE,IAAmB,IAAfwe,GAAoB5R,EAAMR,SAAStL,OAAS,EAO9C,OANA8L,EAAMR,SAASqS,OAAOD,EAAW,GACjChe,KAAK4d,kBAAkBxR,GAEO,IAA1BA,EAAMR,SAAStL,SACjB6K,EAAKS,SAASlN,GAAK0N,EAAMR,SAAS,KAE7B,EAET,GAAI5L,KAAK8d,mBAAmB1R,EAAOqR,GACjC,OAAO,C,MAEJ,GAAIrR,EAAM5M,KAAOie,EAAWje,IAC7B2L,EAAKS,SAAStL,OAAS,EAGzB,OAFA6K,EAAKS,SAASqS,OAAOvf,EAAG,GACxBsB,KAAK4d,kBAAkBzS,IAChB,C,CAIb,OAAO,CACT,CAEQ,iBAAAyS,CAAkBlY,GACxB,MAAMsX,EAAQtX,EAAMkG,SAAStL,OAC7BoF,EAAMiG,OAASjG,EAAMkG,SAAS3L,IAAI,IAAM,EAAI+c,EAC9C,CAEA,cAAAkB,CAAexS,GACb1L,KAAKuN,UAAUtP,KAAKyN,YAAcA,EAClC1L,KAAK4R,IAAI8B,eACX,CAEA,WAAAyK,CAAY1Z,EAAe4C,GACzB,MAAMsE,EAAS,IAAI3L,KAAKuN,UAAUtP,KAAK0N,QACjCyS,EAAO/W,EAAQsE,EAAOlH,GAExBA,EAAQkH,EAAOrL,OAAS,GAC1BqL,EAAOlH,GAAS4C,EAChBsE,EAAOlH,EAAQ,IAAM2Z,IAErBzS,EAAOlH,GAAS4C,EAChBsE,EAAOlH,EAAQ,IAAM2Z,GAIvBzS,EAAOgI,QAAQ,CAACzM,EAAGxI,KACjBiN,EAAOjN,GAAKiH,KAAKC,IAAI,GAAKD,KAAKE,IAAI,GAAKqB,MAG1ClH,KAAKuN,UAAUtP,KAAK0N,OAASA,EAC7B3L,KAAK4R,IAAI8B,eACX,CAGA,OAAA2K,CAAQC,GACN,IAAKte,KAAK8Z,eAAgB,OAC1B,MAAM1K,EAAOpP,KAAKoc,aAAapc,KAAK8Z,gBAC/B1K,IACLpP,KAAKue,cAAcnP,EAAMkP,GACzBte,KAAK4R,IAAI8B,gBACX,CAEA,gBAAA8K,CAAiBpP,EAAqBkP,GACpCte,KAAKue,cAAcnP,EAAMkP,GACzBte,KAAK4R,IAAI8B,eACX,CAEQ,aAAA6K,CACNd,EACAa,GAEA,MACMG,EAAyB,SAAdH,GAAsC,QAAdA,EACnCI,EAFgC,SAAdJ,GAAsC,UAAdA,EAEJ,aAAe,WAE3D,OAAOte,KAAKid,SAASjd,KAAKuN,UAAUtP,KAAOkf,IACzC,GAAKA,EAAI/Q,MAAwB5M,KAAOie,EAAWje,GAAI,OAAO,EAE9D,MAAMke,EAAUtS,IAGhB,GAFAsS,EAAQpS,UAAa6R,EAAI/Q,MAAwBd,UAE7C6R,EAAIhS,KAAKO,cAAgBgT,EAAmB,CAE9C,MAAMC,EAAcF,EAAWtB,EAAI1Y,MAAQ0Y,EAAI1Y,MAAQ,EACvD0Y,EAAIhS,KAAKS,SAASqS,OAAOU,EAAa,EAAGjB,GACzC1d,KAAK4d,kBAAkBT,EAAIhS,K,KACtB,CAEL,MAAMyT,EAA2B,CAC/BlT,YAAayR,EAAIhS,KAAKO,YACtBC,OAAQ,IAAIwR,EAAIhS,KAAKQ,QACrBC,SAAU,IAAIuR,EAAIhS,KAAKS,WAEnBiT,EAA0B,CAC9BnT,YAAagT,EACb/S,OAAQ,CAAC,GAAK,IACdC,SAAU6S,EAAW,CAACf,EAASkB,GAAY,CAACA,EAAUlB,IAGxD,GAAIP,EAAIhS,OAASnL,KAAKuN,UAAUtP,KAC9B+B,KAAKuN,UAAUtP,KAAO4gB,OACjB,GAAI1B,EAAIxK,OAAQ,CACrB,MAAMmM,EAAY3B,EAAIxK,OAAO/G,SAAStI,QAAQ6Z,EAAIhS,OAC/B,IAAf2T,IACF3B,EAAIxK,OAAO/G,SAASkT,GAAaD,E,EAIvC,OAAO,GAEX,GA9ZA,IAAC,IAAA1N,S,yDACD,IAAC,IAAAA,S,yDACD,IAAC,IAAAA,S,iEACD,IAAC,IAAA4N,U,oDACD,IAAC,IAAAA,U,sDAED,IAAC,IAAAC,WAAU,a,gBAAyB,EAAA1J,a,gCAsBpC,IAAC,IAAA2J,cAAa,iBAAkB,CAAC,W,iDACVC,a,mEA9BZxF,EAAwB,IALpC,IAAAtI,WAAU,CACTC,SAAU,mBACVC,SAAU,EAAQ,KAClB6D,OAAQ,CAAC,EAAQ,Q,uBA0BW5I,EACN,EAAA+I,WACP,EAAAD,qBA1BJqE,G,ybClBN,IAAMyF,EAAN,oBAEI,KAAA7Q,SAA2B,GAC1B,KAAA8Q,MAAQ,IAAI,EAAAxF,YAWxB,CARE,WAAAyF,GACErf,KAAKof,MAAM7C,MACb,CAEA,cAAA+C,CAAehU,GACb,MAAMV,EAAU5K,KAAKsO,SAASP,KAAMI,GAAMA,EAAE3O,KAAO8L,GACnD,OAAOV,GAAS/B,MAAQ,SAC1B,GAZA,IAAC,IAAAsI,S,oDACD,IAAC,IAAAA,S,uDACD,IAAC,IAAA4N,U,qDAED,IAAC,IAAAE,cAAa,2B,mHALHE,EAAmB,IAL/B,IAAA/N,WAAU,CACTC,SAAU,cACVC,SAAU,EAAQ,KAClB6D,OAAQ,CAAC,EAAQ,QAENgK,G,ybCKN,IAAMI,EAAN,MAiBL,WAAAzX,CAAoB8J,GAAA,KAAAA,IAAAA,EAfX,KAAA4N,MAAQ,EACR,KAAA1F,eAAgC,KAChC,KAAAxL,SAA2B,GAC1B,KAAAmR,SAAW,IAAI,EAAA7F,aACf,KAAA8F,gBAAkB,IAAI,EAAA9F,aACtB,KAAA+F,cAAgB,IAAI,EAAA/F,aACpB,KAAAiE,WAAa,IAAI,EAAAjE,aACjB,KAAAgG,QAAU,IAAI,EAAAhG,aACd,KAAAiG,SAAW,IAAI,EAAAjG,aACf,KAAAkG,OAAS,IAAI,EAAAlG,aACb,KAAAmG,UAAY,IAAI,EAAAnG,aAE1B,KAAAoG,gBAAwC,KACxC,KAAAC,oBAAsB,CAAEC,EAAG,EAAGC,EAAG,EAEY,CAE7C,WAAApE,CAAYC,GAENA,EAAe,OACjBhc,KAAKogB,kBAET,CAEA,MAAAC,CAAOjU,GACL,OAAQlB,EAAiBkB,EAC3B,CAEA,OAAAkU,CAAQlU,GACN,OAAOlB,EAAiBkB,EAC1B,CAEA,OAAAmU,CAAQnU,GACN,OAAOA,CACT,CAEA,MAAAoU,CAAOpU,GACL,OAAOA,CACT,CAEA,YAAAqU,CAAahc,GACX,OAAqC,IAA3BzE,KAAK0F,MAAMiG,OAAOlH,GAArB,GACT,CAEA,WAAAic,CAAYtR,GACVpP,KAAKyf,SAASlD,KAAKnN,EACrB,CAEA,QAAAuR,CAASC,EAAcC,GACrB,OAAOD,EAAKtgB,OAASugB,EACjBD,EAAKjc,UAAU,EAAGkc,GAAa,MAC/BD,CACN,CAEA,aAAAE,CAAcjN,EAAmBzE,GAC/ByE,EAAMkN,iBACN/gB,KAAKggB,gBAAkB5Q,EACvBpP,KAAKigB,oBAAsB,CAAEC,EAAGrM,EAAMmN,QAASb,EAAGtM,EAAMoN,QAC1D,CAEA,gBAAAb,GACEpgB,KAAKggB,gBAAkB,KACvBhgB,KAAK4R,IAAI8B,eACX,CAEA,MAAAwN,GACMlhB,KAAKggB,kBACPhgB,KAAKyf,SAASlD,KAAKvc,KAAKggB,iBACxBhgB,KAAKogB,mBAET,CAEA,QAAAe,GACMnhB,KAAKggB,kBACPhgB,KAAK0f,gBAAgBnD,KAAKvc,KAAKggB,iBAC/BhgB,KAAKogB,mBAET,CAEA,QAAAgB,GACMphB,KAAKggB,kBACPhgB,KAAK2f,cAAcpD,KAAKvc,KAAKggB,iBAC7BhgB,KAAKogB,mBAET,CAEA,SAAAiB,GACMrhB,KAAKggB,kBACPhgB,KAAK4f,QAAQrD,KAAKvc,KAAKggB,iBACvBhgB,KAAKogB,mBAET,CAEA,UAAAkB,GACMthB,KAAKggB,kBACPhgB,KAAK6f,SAAStD,KAAKvc,KAAKggB,iBACxBhgB,KAAKogB,mBAET,CAEA,QAAAmB,GACMvhB,KAAKggB,kBACPhgB,KAAK8f,OAAOvD,KAAKvc,KAAKggB,iBACtBhgB,KAAKogB,mBAET,CAEA,WAAAoB,GACMxhB,KAAKggB,kBACPhgB,KAAK+f,UAAUxD,KAAKvc,KAAKggB,iBACzBhgB,KAAKogB,mBAET,CAEA,QAAAqB,GACMzhB,KAAKggB,kBACPhgB,KAAK6d,WAAWtB,KAAKvc,KAAKggB,iBAC1BhgB,KAAKogB,mBAET,CAEA,YAAAsB,CAAatS,GACX,IAAKA,EAAK9D,UAAW,MAAO,iBAE5B,MAAMV,EAAU5K,KAAKsO,SAASP,KAAKI,GAAKA,EAAE3O,KAAO4P,EAAK9D,WACtD,OAAOV,GAAS/B,MAAQ,gBAC1B,CAGA,gBAAA8Y,CAAiBvS,GACfpP,KAAKyf,SAASlD,KAAKnN,EACrB,CAEA,cAAAwS,CAAexS,GACbpP,KAAK0f,gBAAgBnD,KAAKnN,EAC5B,CAEA,cAAAyS,CAAezS,GACbpP,KAAK2f,cAAcpD,KAAKnN,EAC1B,CAEA,eAAA0S,CAAgB1S,GACdpP,KAAK4f,QAAQrD,KAAKnN,EACpB,CAEA,gBAAA2S,CAAiB3S,GACfpP,KAAK6f,SAAStD,KAAKnN,EACrB,CAEA,cAAA4S,CAAe5S,GACbpP,KAAK8f,OAAOvD,KAAKnN,EACnB,CAEA,iBAAA6S,CAAkB7S,GAChBpP,KAAK+f,UAAUxD,KAAKnN,EACtB,CAEA,cAAA8S,CAAe9S,GACbpP,KAAK6d,WAAWtB,KAAKnN,EACvB,GAhKA,IAAC,IAAA+B,S,qDACD,IAAC,IAAAA,S,qDACD,IAAC,IAAAA,S,8DACD,IAAC,IAAAA,S,uDACD,IAAC,IAAA4N,U,wDACD,IAAC,IAAAA,U,+DACD,IAAC,IAAAA,U,6DACD,IAAC,IAAAA,U,0DACD,IAAC,IAAAA,U,uDACD,IAAC,IAAAA,U,wDACD,IAAC,IAAAA,U,sDACD,IAAC,IAAAA,U,yDAZUQ,EAAqB,IALjC,IAAAnO,WAAU,CACTC,SAAU,gBACVC,SAAU,EAAQ,KAClB6D,OAAQ,CAAC,EAAQ,Q,uBAmBQ,EAAAE,qBAjBdkK,GCwBE,IAAM4C,EAAN,QAAMA,E,mUAAqB,GAlBzC,IAAAC,UAAS,CACRC,QAAS,CAAC,EAAAC,aAAc,EAAAC,aACxBC,UAAW,CACT,CAAE1J,QAAS,EAAArR,eAAgBgb,SAAUjb,EAA+Bkb,OAAO,GAC3E,CAAE5J,QAAS,EAAArD,oBAAqBgN,SAAUjN,EAAiCkN,OAAO,GAClF,CAAE5J,QAAS,EAAAhB,sBAAuB2K,SAAU5K,EAA0B6K,OAAO,GAC7EnW,EACA1E,EACA8N,GAEFgN,aAAc,CACZnR,EACAkI,EACAyF,EACAI,EACAtO,MAGiBkR,G","sources":["webpack://tabby-tabbyspaces/webpack/universalModuleDefinition","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.scss","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.scss?5edd","webpack://tabby-tabbyspaces/external umd \"@angular/forms\"","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.scss?0de1","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.pug","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.pug","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.pug","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.scss","webpack://tabby-tabbyspaces/./node_modules/css-loader/dist/runtime/api.js","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.scss?e911","webpack://tabby-tabbyspaces/external umd \"tabby-terminal\"","webpack://tabby-tabbyspaces/./node_modules/css-loader/dist/runtime/sourceMaps.js","webpack://tabby-tabbyspaces/external umd \"@angular/common\"","webpack://tabby-tabbyspaces/external umd \"rxjs/operators\"","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.scss","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.pug","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.pug?8802","webpack://tabby-tabbyspaces/external umd \"tabby-core\"","webpack://tabby-tabbyspaces/external umd \"tabby-settings\"","webpack://tabby-tabbyspaces/external umd \"@ng-bootstrap/ng-bootstrap\"","webpack://tabby-tabbyspaces/./node_modules/pug-runtime/index.js","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.pug?b08a","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.scss?c31e","webpack://tabby-tabbyspaces/external umd \"@angular/core\"","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.pug?4d23","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.scss","webpack://tabby-tabbyspaces/external umd \"fs\"","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.pug?e89b","webpack://tabby-tabbyspaces/external umd \"rxjs\"","webpack://tabby-tabbyspaces/webpack/bootstrap","webpack://tabby-tabbyspaces/webpack/runtime/compat get default export","webpack://tabby-tabbyspaces/webpack/runtime/define property getters","webpack://tabby-tabbyspaces/webpack/runtime/hasOwnProperty shorthand","webpack://tabby-tabbyspaces/webpack/runtime/make namespace object","webpack://tabby-tabbyspaces/./src/build-config.ts","webpack://tabby-tabbyspaces/./src/providers/config.provider.ts","webpack://tabby-tabbyspaces/./src/services/startupCommand.service.ts","webpack://tabby-tabbyspaces/./src/models/workspace.model.ts","webpack://tabby-tabbyspaces/./src/services/workspaceEditor.service.ts","webpack://tabby-tabbyspaces/./src/components/deleteConfirmModal.component.ts","webpack://tabby-tabbyspaces/./src/components/workspaceList.component.ts","webpack://tabby-tabbyspaces/./src/providers/settings.provider.ts","webpack://tabby-tabbyspaces/./src/services/workspaceBackground.service.ts","webpack://tabby-tabbyspaces/./src/providers/toolbar.provider.ts","webpack://tabby-tabbyspaces/./src/components/workspaceEditor.component.ts","webpack://tabby-tabbyspaces/./src/components/paneEditor.component.ts","webpack://tabby-tabbyspaces/./src/components/splitPreview.component.ts","webpack://tabby-tabbyspaces/./src/index.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@angular/core\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"@ng-bootstrap/ng-bootstrap\"), require(\"tabby-terminal\"), require(\"rxjs\"), require(\"rxjs/operators\"), (function webpackLoadOptionalExternalModule() { try { return require(\"fs\"); } catch(e) {} }()));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"@angular/core\", \"@angular/common\", \"@angular/forms\", \"tabby-core\", \"tabby-settings\", \"@ng-bootstrap/ng-bootstrap\", \"tabby-terminal\", \"rxjs\", \"rxjs/operators\", \"fs\"], factory);\n\telse {\n\t\tvar a = typeof exports === 'object' ? factory(require(\"@angular/core\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"tabby-core\"), require(\"tabby-settings\"), require(\"@ng-bootstrap/ng-bootstrap\"), require(\"tabby-terminal\"), require(\"rxjs\"), require(\"rxjs/operators\"), (function webpackLoadOptionalExternalModule() { try { return require(\"fs\"); } catch(e) {} }())) : factory(root[\"@angular/core\"], root[\"@angular/common\"], root[\"@angular/forms\"], root[\"tabby-core\"], root[\"tabby-settings\"], root[\"@ng-bootstrap/ng-bootstrap\"], root[\"tabby-terminal\"], root[\"rxjs\"], root[\"rxjs/operators\"], root[\"fs\"]);\n\t\tfor(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];\n\t}\n})(global, (__WEBPACK_EXTERNAL_MODULE__860__, __WEBPACK_EXTERNAL_MODULE__358__, __WEBPACK_EXTERNAL_MODULE__182__, __WEBPACK_EXTERNAL_MODULE__650__, __WEBPACK_EXTERNAL_MODULE__700__, __WEBPACK_EXTERNAL_MODULE__765__, __WEBPACK_EXTERNAL_MODULE__349__, __WEBPACK_EXTERNAL_MODULE__961__, __WEBPACK_EXTERNAL_MODULE__439__, __WEBPACK_EXTERNAL_MODULE__947__) => {\nreturn ","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.editor-section{margin-bottom:14px}.section-title{font-size:11px;color:var(--theme-fg-more);text-transform:uppercase;letter-spacing:.5px;margin-bottom:10px;display:flex;align-items:center;gap:4px}.form-row{display:flex;gap:10px;align-items:flex-end}.form-group{flex:1;position:relative}.form-group.auto-width{flex:none}.form-group label{display:block;font-size:.7rem;color:var(--theme-fg-less);text-transform:uppercase;letter-spacing:.5px;margin-bottom:2px}.form-group .form-control{padding:4px 6px;border-radius:2px;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));background:var(--theme-bg-more);color:var(--theme-fg);font-size:.85rem}.form-group .form-control:focus{outline:none;border-color:var(--theme-primary)}.form-group .form-control::placeholder{color:var(--theme-fg-more, rgba(255, 255, 255, 0.3))}.form-group .form-control{width:100%;font-size:.8rem;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1)) !important}.form-group .form-control:focus{border-color:var(--theme-primary) !important}.dropdown-trigger{display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;transition:border-color .15s;height:32px;box-sizing:border-box}.dropdown-trigger:hover{border-color:var(--theme-fg-more)}.dropdown-icon{font-size:14px}.dropdown-chevron{color:var(--theme-fg-more);font-size:10px}.icon-dropdown{position:absolute;top:100%;left:0;margin-top:4px;padding:6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px;box-shadow:none;z-index:100;display:grid;grid-template-columns:repeat(6, 28px);gap:4px}.icon-option{width:28px;height:28px;display:flex;align-items:center;justify-content:center;border:1px solid rgba(0,0,0,0);border-radius:2px;background:rgba(0,0,0,0);color:var(--theme-fg-more);cursor:pointer;transition:all .15s;font-size:.85rem}.icon-option:hover{background:var(--theme-bg-more-more);color:var(--theme-fg)}.icon-option.selected{border-color:currentColor;background:var(--theme-bg)}.color-trigger{display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;position:relative;transition:border-color .15s;height:32px;box-sizing:border-box}.color-trigger:hover{border-color:var(--theme-fg-more)}.color-trigger:focus-within{border-color:var(--theme-primary)}.color-trigger .color-input-hidden{position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;cursor:pointer}.dropdown-color{width:16px;height:16px;border-radius:2px}.background-picker{position:relative}.background-trigger{display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;transition:border-color .15s;height:32px;box-sizing:border-box}.background-trigger:hover{border-color:var(--theme-fg-more)}.background-preview{width:48px;height:18px;border-radius:2px;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));display:flex;align-items:center;justify-content:center;color:var(--theme-fg-more, rgba(255, 255, 255, 0.3));font-size:10px}.background-dropdown{position:absolute;top:100%;left:0;right:0;margin-top:4px;padding:6px;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px;box-shadow:none;z-index:100;min-width:260px}.preset-grid{display:grid;grid-template-columns:repeat(4, 1fr);gap:4px;margin-bottom:6px}.preset-option{aspect-ratio:1.5;height:32px;display:flex;align-items:center;justify-content:center;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;cursor:pointer;transition:all .15s;color:var(--theme-fg-more, rgba(255, 255, 255, 0.3));font-size:10px}.preset-option:hover{border-color:var(--theme-fg-more)}.preset-option.selected{border-color:var(--theme-primary);border-width:2px}.custom-input-wrapper .custom-bg-input{width:100%;font-size:.7rem}.split-preview-container{background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px;padding:10px}.preview-toolbar{display:flex;justify-content:flex-end;align-items:center;gap:4px;margin-bottom:10px;padding-bottom:6px;border-bottom:1px solid var(--theme-border, rgba(255, 255, 255, 0.1))}.toolbar-separator{width:1px;height:18px;background:var(--theme-border, rgba(255, 255, 255, 0.1));margin:0 4px;align-self:center}.preview-btn{width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:2px;color:var(--theme-fg-more, rgba(255, 255, 255, 0.3));cursor:pointer;font-size:10px;transition:all .15s}.preview-btn:hover:not(:disabled){border-color:var(--theme-primary);color:var(--theme-primary)}.preview-btn.danger:hover:not(:disabled){border-color:var(--theme-danger);color:var(--theme-danger)}.preview-btn:disabled{opacity:.4;cursor:not-allowed}.layout-preview{background:var(--theme-bg);border-radius:2px;min-height:150px;padding:4px}.action-buttons{display:flex;justify-content:space-between;align-items:center;padding-top:14px;border-top:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));margin-top:14px}.checkbox-group{display:flex;align-items:center;gap:4px}.checkbox-group input[type=checkbox]{width:14px;height:14px;margin:0}.checkbox-group label{font-size:.8rem;color:var(--theme-fg);cursor:pointer}.action-buttons-right{display:flex;gap:6px}.action-buttons-right .btn-ghost{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;font-size:.8rem;border-radius:2px;cursor:pointer;transition:all .15s;background:rgba(0,0,0,0);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));color:var(--theme-fg)}.action-buttons-right .btn-ghost:hover{background:var(--theme-bg-more)}.action-buttons-right .btn-success{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;font-size:.8rem;border-radius:2px;cursor:pointer;transition:all .15s;background:#10b981;border-color:#10b981;color:#fff}.action-buttons-right .btn-success:hover{background:#059669;border-color:#059669}.action-buttons-right .unsaved-indicator{color:#f59e0b;font-weight:bold;margin-left:2px}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/workspaceEditor.component.scss\",\"webpack://./src/styles/_variables.scss\",\"webpack://./src/styles/_mixins.scss\"],\"names\":[],\"mappings\":\"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\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n// Editor section\\r\\n.editor-section {\\r\\n margin-bottom: $spacing-xl;\\r\\n}\\r\\n\\r\\n.section-title {\\r\\n font-size: 11px;\\r\\n color: var(--theme-fg-more);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-lg;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n}\\r\\n\\r\\n// Form layout\\r\\n.form-row {\\r\\n display: flex;\\r\\n gap: $spacing-lg;\\r\\n align-items: flex-end;\\r\\n}\\r\\n\\r\\n.form-group {\\r\\n flex: 1;\\r\\n position: relative;\\r\\n\\r\\n &.auto-width {\\r\\n flex: none;\\r\\n }\\r\\n\\r\\n label {\\r\\n @include form-label;\\r\\n }\\r\\n\\r\\n .form-control {\\r\\n @include form-input(var(--theme-bg-more));\\r\\n width: 100%;\\r\\n font-size: $font-sm;\\r\\n // Override Tabby's global border reset\\r\\n border: 1px solid var(--theme-border, $fallback-border) !important;\\r\\n\\r\\n &:focus {\\r\\n border-color: var(--theme-primary) !important;\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n// Dropdown trigger (icon picker)\\r\\n.dropdown-trigger {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: border-color $transition-fast;\\r\\n height: 32px;\\r\\n box-sizing: border-box;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n.dropdown-icon {\\r\\n font-size: 14px;\\r\\n}\\r\\n\\r\\n.dropdown-chevron {\\r\\n color: var(--theme-fg-more);\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n// Icon dropdown\\r\\n.icon-dropdown {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n left: 0;\\r\\n margin-top: $spacing-sm;\\r\\n padding: $spacing-md;\\r\\n @include dropdown-panel;\\r\\n z-index: $z-dropdown;\\r\\n display: grid;\\r\\n grid-template-columns: repeat(6, 28px);\\r\\n gap: $spacing-sm;\\r\\n}\\r\\n\\r\\n.icon-option {\\r\\n width: 28px;\\r\\n height: 28px;\\r\\n @include flex-center;\\r\\n border: 1px solid transparent;\\r\\n border-radius: $radius-sm;\\r\\n background: transparent;\\r\\n color: var(--theme-fg-more);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n color: var(--theme-fg);\\r\\n }\\r\\n\\r\\n &.selected {\\r\\n border-color: currentColor;\\r\\n background: var(--theme-bg);\\r\\n }\\r\\n}\\r\\n\\r\\n// Color trigger (wraps native color input)\\r\\n.color-trigger {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n position: relative;\\r\\n transition: border-color $transition-fast;\\r\\n height: 32px;\\r\\n box-sizing: border-box;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n\\r\\n &:focus-within {\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n .color-input-hidden {\\r\\n position: absolute;\\r\\n top: 0;\\r\\n left: 0;\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n opacity: 0;\\r\\n cursor: pointer;\\r\\n }\\r\\n}\\r\\n\\r\\n.dropdown-color {\\r\\n width: 16px;\\r\\n height: 16px;\\r\\n border-radius: $radius-xs;\\r\\n}\\r\\n\\r\\n// Background picker\\r\\n.background-picker {\\r\\n position: relative;\\r\\n}\\r\\n\\r\\n.background-trigger {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: border-color $transition-fast;\\r\\n height: 32px;\\r\\n box-sizing: border-box;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n.background-preview {\\r\\n width: 48px;\\r\\n height: 18px;\\r\\n border-radius: $radius-xs;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n @include flex-center;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n.background-dropdown {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n left: 0;\\r\\n right: 0;\\r\\n margin-top: $spacing-sm;\\r\\n padding: $spacing-md;\\r\\n @include dropdown-panel;\\r\\n z-index: $z-dropdown;\\r\\n min-width: 260px;\\r\\n}\\r\\n\\r\\n.preset-grid {\\r\\n display: grid;\\r\\n grid-template-columns: repeat(4, 1fr);\\r\\n gap: $spacing-sm;\\r\\n margin-bottom: $spacing-md;\\r\\n}\\r\\n\\r\\n.preset-option {\\r\\n aspect-ratio: 1.5;\\r\\n height: 32px;\\r\\n @include flex-center;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n font-size: 10px;\\r\\n\\r\\n &:hover {\\r\\n border-color: var(--theme-fg-more);\\r\\n }\\r\\n\\r\\n &.selected {\\r\\n border-color: var(--theme-primary);\\r\\n border-width: 2px;\\r\\n }\\r\\n}\\r\\n\\r\\n.custom-input-wrapper {\\r\\n .custom-bg-input {\\r\\n width: 100%;\\r\\n font-size: $font-xs;\\r\\n }\\r\\n}\\r\\n\\r\\n// Split preview container\\r\\n.split-preview-container {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n padding: $spacing-lg;\\r\\n}\\r\\n\\r\\n// Preview toolbar\\r\\n.preview-toolbar {\\r\\n display: flex;\\r\\n justify-content: flex-end;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n margin-bottom: $spacing-lg;\\r\\n padding-bottom: $spacing-md;\\r\\n border-bottom: 1px solid var(--theme-border, $fallback-border);\\r\\n}\\r\\n\\r\\n.toolbar-separator {\\r\\n width: 1px;\\r\\n height: 18px;\\r\\n background: var(--theme-border, $fallback-border);\\r\\n margin: 0 $spacing-sm;\\r\\n align-self: center;\\r\\n}\\r\\n\\r\\n.preview-btn {\\r\\n @include icon-btn-sm;\\r\\n}\\r\\n\\r\\n// Layout preview area\\r\\n.layout-preview {\\r\\n background: var(--theme-bg);\\r\\n border-radius: $radius-sm;\\r\\n min-height: 150px;\\r\\n padding: $spacing-sm;\\r\\n}\\r\\n\\r\\n// Action buttons\\r\\n.action-buttons {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n align-items: center;\\r\\n padding-top: $spacing-xl;\\r\\n border-top: 1px solid var(--theme-border, $fallback-border);\\r\\n margin-top: $spacing-xl;\\r\\n}\\r\\n\\r\\n.checkbox-group {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n\\r\\n input[type=\\\"checkbox\\\"] {\\r\\n width: 14px;\\r\\n height: 14px;\\r\\n margin: 0;\\r\\n }\\r\\n\\r\\n label {\\r\\n font-size: $font-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n }\\r\\n}\\r\\n\\r\\n.action-buttons-right {\\r\\n display: flex;\\r\\n gap: $spacing-md;\\r\\n\\r\\n .btn-ghost {\\r\\n @include btn-ghost;\\r\\n }\\r\\n\\r\\n .btn-success {\\r\\n @include btn-base;\\r\\n @include btn-success;\\r\\n }\\r\\n\\r\\n .unsaved-indicator {\\r\\n color: $color-warning;\\r\\n font-weight: bold;\\r\\n margin-left: $spacing-xs;\\r\\n }\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\",\"@use 'variables' as *;\\r\\n\\r\\n// ======================\\r\\n// LAYOUT MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin flex-center {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM INPUT MIXIN\\r\\n// ======================\\r\\n\\r\\n@mixin form-input($bg: var(--theme-bg)) {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n border-radius: $radius-sm;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n background: $bg;\\r\\n color: var(--theme-fg);\\r\\n font-size: $font-md;\\r\\n\\r\\n &:focus {\\r\\n outline: none;\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &::placeholder {\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM LABEL MIXIN (S1: Uppercase compact)\\r\\n// ======================\\r\\n\\r\\n@mixin form-label {\\r\\n display: block;\\r\\n font-size: $font-xs;\\r\\n color: var(--theme-fg-less);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-xs;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// BUTTON MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin toolbar-btn {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n background: var(--theme-bg-more-more);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-success {\\r\\n background: $color-success;\\r\\n border-color: $color-success;\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n background: $color-success-hover;\\r\\n border-color: $color-success-hover;\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-base {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-lg;\\r\\n font-size: $font-sm;\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n}\\r\\n\\r\\n@mixin btn-ghost {\\r\\n @include btn-base;\\r\\n background: transparent;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg);\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-primary {\\r\\n @include btn-base;\\r\\n background: var(--theme-primary);\\r\\n border: 1px solid var(--theme-primary);\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n filter: brightness(1.1);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin icon-btn-sm($size: 24px) {\\r\\n width: $size;\\r\\n height: $size;\\r\\n @include flex-center;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: 10px;\\r\\n transition: all $transition-fast;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: var(--theme-primary);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &.danger:hover:not(:disabled) {\\r\\n border-color: var(--theme-danger);\\r\\n color: var(--theme-danger);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// OVERLAY/MODAL MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin full-overlay($z-index: $z-modal-overlay) {\\r\\n position: fixed;\\r\\n top: 0;\\r\\n left: 0;\\r\\n right: 0;\\r\\n bottom: 0;\\r\\n z-index: $z-index;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// TEXT UTILITIES\\r\\n// ======================\\r\\n\\r\\n@mixin text-ellipsis {\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// DROPDOWN/POPUP\\r\\n// ======================\\r\\n\\r\\n@mixin dropdown-panel {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n box-shadow: $shadow-dropdown;\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./paneEditor.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","module.exports = __WEBPACK_EXTERNAL_MODULE__182__;","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./splitPreview.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"editor-section\\\"\\u003E\\u003Cdiv class=\\\"section-title\\\"\\u003E\\u003Ci class=\\\"fas fa-cog\\\"\\u003E\\u003C\\u002Fi\\u003E Workspace Settings\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-row\\\"\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EName\\u003C\\u002Flabel\\u003E\\u003Cinput class=\\\"form-control\\\" #nameInput type=\\\"text\\\" [(ngModel)]=\\\"workspace.name\\\" placeholder=\\\"Workspace name\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group auto-width\\\"\\u003E\\u003Clabel\\u003EIcon\\u003C\\u002Flabel\\u003E\\u003Cdiv class=\\\"dropdown-trigger\\\" (click)=\\\"toggleIconDropdown()\\\"\\u003E\\u003Cspan class=\\\"dropdown-icon\\\" [style.color]=\\\"workspace.color\\\"\\u003E\\u003Ci class=\\\"fas\\\" [class]=\\\"&quot;fa-&quot; + workspace.icon\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"dropdown-chevron\\\"\\u003E\\u003Ci class=\\\"fas fa-chevron-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"icon-dropdown\\\" *ngIf=\\\"iconDropdownOpen\\\"\\u003E\\u003Cbutton class=\\\"icon-option\\\" *ngFor=\\\"let icon of availableIcons\\\" type=\\\"button\\\" [class.selected]=\\\"workspace.icon === icon\\\" [style.color]=\\\"workspace.icon === icon ? workspace.color : null\\\" (click)=\\\"selectIcon(icon)\\\"\\u003E\\u003Ci class=\\\"fas\\\" [class]=\\\"&quot;fa-&quot; + icon\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group auto-width\\\"\\u003E\\u003Clabel\\u003EColor\\u003C\\u002Flabel\\u003E\\u003Cdiv class=\\\"color-trigger\\\"\\u003E\\u003Cspan class=\\\"dropdown-color\\\" [style.background]=\\\"workspace.color\\\"\\u003E\\u003C\\u002Fspan\\u003E\\u003Cinput class=\\\"color-input-hidden\\\" type=\\\"color\\\" [(ngModel)]=\\\"workspace.color\\\"\\u003E\\u003Cspan class=\\\"dropdown-chevron\\\"\\u003E\\u003Ci class=\\\"fas fa-chevron-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group auto-width\\\"\\u003E\\u003Clabel\\u003EBackground\\u003C\\u002Flabel\\u003E\\u003Cdiv class=\\\"background-picker\\\"\\u003E\\u003Cdiv class=\\\"background-trigger\\\" (click)=\\\"toggleBackgroundDropdown()\\\"\\u003E\\u003Cspan class=\\\"background-preview\\\" [style.background]=\\\"workspace.background?.value || &quot;transparent&quot;\\\"\\u003E\\u003Ci class=\\\"fas fa-ban\\\" *ngIf=\\\"!workspace.background?.value\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"dropdown-chevron\\\"\\u003E\\u003Ci class=\\\"fas fa-chevron-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"background-dropdown\\\" *ngIf=\\\"backgroundDropdownOpen\\\"\\u003E\\u003Cdiv class=\\\"preset-grid\\\"\\u003E\\u003Cbutton class=\\\"preset-option\\\" *ngFor=\\\"let preset of backgroundPresets\\\" type=\\\"button\\\" [class.selected]=\\\"isBackgroundSelected(preset)\\\" [style.background]=\\\"preset.value || &quot;var(--theme-bg)&quot;\\\" (click)=\\\"selectBackgroundPreset(preset)\\\"\\u003E\\u003Ci class=\\\"fas fa-ban\\\" *ngIf=\\\"preset.type === &quot;none&quot;\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"custom-input-wrapper\\\"\\u003E\\u003Cinput class=\\\"form-control custom-bg-input\\\" type=\\\"text\\\" [(ngModel)]=\\\"customBackgroundValue\\\" placeholder=\\\"Custom CSS gradient...\\\" (blur)=\\\"applyCustomBackground()\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"editor-section\\\"\\u003E\\u003Cdiv class=\\\"section-title\\\"\\u003E\\u003Ci class=\\\"fas fa-columns\\\"\\u003E\\u003C\\u002Fi\\u003E Split Layout\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"split-preview-container\\\"\\u003E\\u003Cdiv class=\\\"preview-toolbar\\\"\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Split Horizontal\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"splitSelectedPane(&quot;horizontal&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-grip-lines-vertical\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Split Vertical\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"splitSelectedPane(&quot;vertical&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-grip-lines\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cspan class=\\\"toolbar-separator\\\"\\u003E\\u003C\\u002Fspan\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Left\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;left&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-left\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Right\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;right&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-right\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Top\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;top&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-up\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"preview-btn\\\" type=\\\"button\\\" title=\\\"Add Bottom\\\" [disabled]=\\\"!selectedPaneId\\\" (click)=\\\"addPane(&quot;bottom&quot;)\\\"\\u003E\\u003Ci class=\\\"fas fa-arrow-down\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003Cspan class=\\\"toolbar-separator\\\"\\u003E\\u003C\\u002Fspan\\u003E\\u003Cbutton class=\\\"preview-btn danger\\\" type=\\\"button\\\" title=\\\"Remove pane\\\" [disabled]=\\\"!selectedPaneId || !canRemovePane()\\\" (click)=\\\"removeSelectedPane()\\\"\\u003E\\u003Ci class=\\\"fas fa-trash\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"layout-preview\\\" (click)=\\\"onPreviewBackgroundClick()\\\"\\u003E\\u003Csplit-preview [split]=\\\"workspace.root\\\" [selectedPaneId]=\\\"selectedPaneId\\\" [profiles]=\\\"profiles\\\" (paneEdit)=\\\"editPane($event)\\\" (splitHorizontal)=\\\"splitPane($event, &quot;horizontal&quot;)\\\" (splitVertical)=\\\"splitPane($event, &quot;vertical&quot;)\\\" (addLeft)=\\\"addPaneFromEvent($event, &quot;left&quot;)\\\" (addRight)=\\\"addPaneFromEvent($event, &quot;right&quot;)\\\" (addTop)=\\\"addPaneFromEvent($event, &quot;top&quot;)\\\" (addBottom)=\\\"addPaneFromEvent($event, &quot;bottom&quot;)\\\" (removePane)=\\\"removePane($event)\\\"\\u003E\\u003C\\u002Fsplit-preview\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cpane-editor *ngIf=\\\"showPaneEditor &amp;&amp; editingPane\\\" [pane]=\\\"editingPane\\\" [profiles]=\\\"profiles\\\" (close)=\\\"closePaneEditor()\\\"\\u003E\\u003C\\u002Fpane-editor\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"action-buttons\\\"\\u003E\\u003Cdiv class=\\\"checkbox-group\\\"\\u003E\\u003Cinput type=\\\"checkbox\\\" [(ngModel)]=\\\"workspace.launchOnStartup\\\" id=\\\"launchStartup\\\"\\u003E\\u003Clabel for=\\\"launchStartup\\\"\\u003ELaunch on startup\\u003C\\u002Flabel\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"action-buttons-right\\\"\\u003E\\u003Cbutton class=\\\"btn btn-ghost\\\" type=\\\"button\\\" (click)=\\\"onCancel()\\\"\\u003E\\u003Ci class=\\\"fas fa-xmark\\\"\\u003E\\u003C\\u002Fi\\u003E Cancel\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"btn btn-success\\\" type=\\\"button\\\" (click)=\\\"onSave()\\\" [disabled]=\\\"!workspace.name?.trim() || !hasUnsavedChanges\\\"\\u003E\\u003Ci class=\\\"fas fa-check\\\"\\u003E\\u003C\\u002Fi\\u003E Save\\u003Cspan class=\\\"unsaved-indicator\\\" *ngIf=\\\"hasUnsavedChanges\\\"\\u003E*\\u003C\\u002Fspan\\u003E\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"pane-details\\\"\\u003E\\u003Cdiv class=\\\"pane-details-header\\\"\\u003E\\u003Cspan class=\\\"pane-details-title\\\"\\u003E\\u003Ci class=\\\"fas fa-terminal\\\"\\u003E\\u003C\\u002Fi\\u003E Pane Configuration\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"pane-form\\\"\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EProfile\\u003C\\u002Flabel\\u003E\\u003Cselect class=\\\"form-control\\\" [(ngModel)]=\\\"pane.profileId\\\"\\u003E\\u003Coption value=\\\"\\\"\\u003E-- Select Profile --\\u003C\\u002Foption\\u003E\\u003Coption *ngFor=\\\"let profile of profiles\\\" [value]=\\\"profile.id\\\"\\u003E{{ profile.name }}\\u003C\\u002Foption\\u003E\\u003C\\u002Fselect\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EWorking Directory\\u003C\\u002Flabel\\u003E\\u003Cinput class=\\\"form-control\\\" type=\\\"text\\\" [(ngModel)]=\\\"pane.cwd\\\" placeholder=\\\"C:\\\\path\\\\to\\\\project\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"form-group\\\"\\u003E\\u003Clabel\\u003EStartup Command\\u003C\\u002Flabel\\u003E\\u003Cinput class=\\\"form-control\\\" type=\\\"text\\\" [(ngModel)]=\\\"pane.startupCommand\\\" placeholder=\\\"e.g., npm run dev\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"workspace-list-container\\\"\\u003E\\u003Cdiv class=\\\"tab-bar\\\"\\u003E\\u003Cdiv class=\\\"tab\\\" *ngFor=\\\"let tab of displayTabs; trackBy: trackByTab\\\" [class.active]=\\\"isTabSelected(tab)\\\" (click)=\\\"!tab.isNew &amp;&amp; selectWorkspace(tab.workspace)\\\"\\u003E\\u003Cspan class=\\\"tab-icon\\\" [style.color]=\\\"tab.workspace.color\\\"\\u003E\\u003Ci class=\\\"fas\\\" [class]=\\\"&quot;fa-&quot; + (tab.workspace.icon || &quot;columns&quot;)\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"tab-name\\\"\\u003E{{ tab.workspace.name || 'New Workspace' }}\\u003C\\u002Fspan\\u003E\\u003Cspan class=\\\"tab-close\\\" *ngIf=\\\"!tab.isNew\\\" (click)=\\\"deleteWorkspace($event, tab.workspace)\\\" title=\\\"Delete workspace\\\"\\u003E\\u003Ci class=\\\"fas fa-xmark\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"tab-new\\\" (click)=\\\"createWorkspace()\\\" title=\\\"New workspace\\\"\\u003E\\u003Ci class=\\\"fas fa-plus\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"tab-content\\\" *ngIf=\\\"editingWorkspace\\\"\\u003E\\u003Cworkspace-editor [workspace]=\\\"editingWorkspace\\\" [autoFocus]=\\\"isCreatingNew\\\" [hasUnsavedChanges]=\\\"hasUnsavedChanges\\\" (save)=\\\"onEditorSave($event)\\\" (cancel)=\\\"onEditorCancel()\\\"\\u003E\\u003C\\u002Fworkspace-editor\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"tab-content empty-state\\\" *ngIf=\\\"!editingWorkspace &amp;&amp; workspaces.length === 0\\\"\\u003E\\u003Cp\\u003ENo workspaces configured yet.\\u003C\\u002Fp\\u003E\\u003Cp\\u003EClick\\u003Cstrong\\u003E+\\u003C\\u002Fstrong\\u003Eto create your first workspace.\\u003C\\u002Fp\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.split-preview{display:flex;width:100%;min-height:140px;gap:4px;border-radius:3px;background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1))}.split-preview.horizontal{flex-direction:row}.split-preview.vertical{flex-direction:column}.split-preview.nested{min-height:0;border:1px dashed var(--theme-fg-more);background:hsla(0,0%,100%,.02);padding:4px;border-radius:2px}.preview-pane{display:flex;align-items:center;justify-content:center;background:var(--theme-bg-more);border-radius:2px;border:2px solid var(--theme-border, rgba(255, 255, 255, 0.1));cursor:pointer;transition:all .15s;position:relative;min-height:50px}.preview-pane:hover{background:var(--theme-bg-more-more);border-color:var(--theme-fg-more, rgba(255, 255, 255, 0.3))}.preview-pane.selected{border-color:var(--theme-primary);background:linear-gradient(to bottom, rgba(59, 130, 246, 0.08), rgba(59, 130, 246, 0.04))}.pane-content{text-align:center;padding:6px;color:var(--theme-fg);max-width:100%;overflow:hidden}.pane-label{font-size:.85rem;font-weight:600;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pane-title,.pane-profile{font-size:.8rem;font-weight:500;margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.pane-details{font-size:.7rem;opacity:.7;margin-top:4px}.pane-details .pane-detail{display:flex;align-items:center;justify-content:center;gap:4px}.pane-details .pane-detail i{width:12px;text-align:center;font-size:.65rem}.pane-details .pane-detail span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100px}.context-menu-overlay{position:fixed;top:0;left:0;right:0;bottom:0;z-index:1200}.context-menu{position:fixed;background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:4px;box-shadow:none;min-width:160px;padding:4px;z-index:1201}.context-menu-item{display:flex;align-items:center;gap:10px;width:100%;padding:6px 10px;border:none;background:none;color:var(--theme-fg);font-size:.9rem;text-align:left;cursor:pointer;border-radius:2px}.context-menu-item:hover{background:var(--theme-bg-more)}.context-menu-item.danger{color:var(--theme-danger, #ef4444)}.context-menu-item.danger:hover{background:rgba(239,68,68,.1)}.context-menu-item i{width:16px;text-align:center;opacity:.7}.context-menu-divider{height:1px;background:var(--theme-border, rgba(255, 255, 255, 0.1));margin:4px 0}:host{display:flex;flex:1}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/splitPreview.component.scss\",\"webpack://./src/styles/_variables.scss\",\"webpack://./src/styles/_mixins.scss\"],\"names\":[],\"mappings\":\"AAEA,eACE,YAAA,CACA,UAAA,CACA,gBCqCe,CDpCf,OCFW,CDGX,iBCQU,CDPV,0BAAA,CACA,8DAAA,CAEA,0BACE,kBAAA,CAGF,wBACE,qBAAA,CAGF,sBACE,YAAA,CACA,sCAAA,CACA,8BCqBc,CDpBd,WCnBS,CDoBT,iBCVQ,CDcZ,cErBE,YAAA,CACA,kBAAA,CACA,sBAAA,CFqBA,+BAAA,CACA,iBCjBU,CDkBV,8DAAA,CACA,cAAA,CACA,mBAAA,CACA,iBAAA,CACA,eAAA,CAEA,oBACE,oCAAA,CACA,2DAAA,CAGF,uBACE,iCAAA,CACA,yFAAA,CAQJ,cACE,iBAAA,CACA,WClDW,CDmDX,qBAAA,CACA,cAAA,CACA,eAAA,CAGF,YACE,gBAAA,CACA,eAAA,CACA,iBC5DW,CCiKX,kBAAA,CACA,eAAA,CACA,sBAAA,CFnGF,0BAEE,eAAA,CACA,eAAA,CACA,iBCrEW,CCkKX,kBAAA,CACA,eAAA,CACA,sBAAA,CF3FF,cACE,eAAA,CACA,UAAA,CACA,cC3EW,CD6EX,2BE1EA,YAAA,CACA,kBAAA,CACA,sBAAA,CF0EE,OC/ES,CDiFT,6BACE,UAAA,CACA,iBAAA,CACA,gBAAA,CAGF,gCE0EF,kBAAA,CACA,eAAA,CACA,sBAAA,CF1EI,eAAA,CAMN,sBEqDE,cAAA,CACA,KAAA,CACA,MAAA,CACA,OAAA,CACA,QAAA,CACA,YDlGuB,CD4CzB,cACE,cAAA,CACA,0BAAA,CACA,8DAAA,CACA,iBC3FU,CD4FV,eCzEoB,CD0EpB,eAAA,CACA,WC1GW,CD2GX,YCnDe,CDsDjB,mBACE,YAAA,CACA,kBAAA,CACA,QC/GW,CDgHX,UAAA,CACA,gBAAA,CACA,WAAA,CACA,eAAA,CACA,qBAAA,CACA,eAAA,CACA,eAAA,CACA,cAAA,CACA,iBChHU,CDkHV,yBACE,+BAAA,CAGF,0BACE,kCAAA,CAEA,gCACE,6BAAA,CAIJ,qBACE,UAAA,CACA,iBAAA,CACA,UAAA,CAIJ,sBACE,UAAA,CACA,wDAAA,CACA,YAAA,CAIF,MACE,YAAA,CACA,MAAA\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n.split-preview {\\r\\n display: flex;\\r\\n width: 100%;\\r\\n min-height: $preview-height;\\r\\n gap: $spacing-sm;\\r\\n border-radius: $radius-md;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, rgba(255, 255, 255, 0.1));\\r\\n\\r\\n &.horizontal {\\r\\n flex-direction: row;\\r\\n }\\r\\n\\r\\n &.vertical {\\r\\n flex-direction: column;\\r\\n }\\r\\n\\r\\n &.nested {\\r\\n min-height: 0;\\r\\n border: 1px dashed var(--theme-fg-more);\\r\\n background: $nested-split-bg;\\r\\n padding: $spacing-sm;\\r\\n border-radius: $radius-sm;\\r\\n }\\r\\n}\\r\\n\\r\\n.preview-pane {\\r\\n @include flex-center;\\r\\n background: var(--theme-bg-more);\\r\\n border-radius: $radius-sm;\\r\\n border: 2px solid var(--theme-border, rgba(255, 255, 255, 0.1));\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n position: relative;\\r\\n min-height: 50px;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n border-color: var(--theme-fg-more, rgba(255, 255, 255, 0.3));\\r\\n }\\r\\n\\r\\n &.selected {\\r\\n border-color: var(--theme-primary);\\r\\n background: linear-gradient(\\r\\n to bottom,\\r\\n $selected-pane-gradient-start,\\r\\n $selected-pane-gradient-end\\r\\n );\\r\\n }\\r\\n}\\r\\n\\r\\n.pane-content {\\r\\n text-align: center;\\r\\n padding: $spacing-md;\\r\\n color: var(--theme-fg);\\r\\n max-width: 100%;\\r\\n overflow: hidden;\\r\\n}\\r\\n\\r\\n.pane-label {\\r\\n font-size: 0.85rem;\\r\\n font-weight: 600;\\r\\n margin-bottom: $spacing-sm;\\r\\n @include text-ellipsis;\\r\\n}\\r\\n\\r\\n.pane-title,\\r\\n.pane-profile {\\r\\n font-size: 0.8rem;\\r\\n font-weight: 500;\\r\\n margin-bottom: $spacing-xs;\\r\\n @include text-ellipsis;\\r\\n}\\r\\n\\r\\n.pane-details {\\r\\n font-size: 0.7rem;\\r\\n opacity: 0.7;\\r\\n margin-top: $spacing-sm;\\r\\n\\r\\n .pane-detail {\\r\\n @include flex-center;\\r\\n gap: $spacing-sm;\\r\\n\\r\\n i {\\r\\n width: 12px;\\r\\n text-align: center;\\r\\n font-size: 0.65rem;\\r\\n }\\r\\n\\r\\n span {\\r\\n @include text-ellipsis;\\r\\n max-width: 100px;\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n// Context menu\\r\\n.context-menu-overlay {\\r\\n @include full-overlay($z-context-menu-overlay);\\r\\n}\\r\\n\\r\\n.context-menu {\\r\\n position: fixed;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-lg;\\r\\n box-shadow: $shadow-context-menu;\\r\\n min-width: 160px;\\r\\n padding: $spacing-sm;\\r\\n z-index: $z-context-menu;\\r\\n}\\r\\n\\r\\n.context-menu-item {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-lg;\\r\\n width: 100%;\\r\\n padding: $spacing-md $spacing-lg;\\r\\n border: none;\\r\\n background: none;\\r\\n color: var(--theme-fg);\\r\\n font-size: 0.9rem;\\r\\n text-align: left;\\r\\n cursor: pointer;\\r\\n border-radius: $radius-sm;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n\\r\\n &:hover {\\r\\n background: rgba($color-danger, 0.1);\\r\\n }\\r\\n }\\r\\n\\r\\n i {\\r\\n width: 16px;\\r\\n text-align: center;\\r\\n opacity: 0.7;\\r\\n }\\r\\n}\\r\\n\\r\\n.context-menu-divider {\\r\\n height: 1px;\\r\\n background: var(--theme-border, $fallback-border);\\r\\n margin: $spacing-sm 0;\\r\\n}\\r\\n\\r\\n// Nested splits styling\\r\\n:host {\\r\\n display: flex;\\r\\n flex: 1;\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\",\"@use 'variables' as *;\\r\\n\\r\\n// ======================\\r\\n// LAYOUT MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin flex-center {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM INPUT MIXIN\\r\\n// ======================\\r\\n\\r\\n@mixin form-input($bg: var(--theme-bg)) {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n border-radius: $radius-sm;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n background: $bg;\\r\\n color: var(--theme-fg);\\r\\n font-size: $font-md;\\r\\n\\r\\n &:focus {\\r\\n outline: none;\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &::placeholder {\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM LABEL MIXIN (S1: Uppercase compact)\\r\\n// ======================\\r\\n\\r\\n@mixin form-label {\\r\\n display: block;\\r\\n font-size: $font-xs;\\r\\n color: var(--theme-fg-less);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-xs;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// BUTTON MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin toolbar-btn {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n background: var(--theme-bg-more-more);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-success {\\r\\n background: $color-success;\\r\\n border-color: $color-success;\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n background: $color-success-hover;\\r\\n border-color: $color-success-hover;\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-base {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-lg;\\r\\n font-size: $font-sm;\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n}\\r\\n\\r\\n@mixin btn-ghost {\\r\\n @include btn-base;\\r\\n background: transparent;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg);\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-primary {\\r\\n @include btn-base;\\r\\n background: var(--theme-primary);\\r\\n border: 1px solid var(--theme-primary);\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n filter: brightness(1.1);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin icon-btn-sm($size: 24px) {\\r\\n width: $size;\\r\\n height: $size;\\r\\n @include flex-center;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: 10px;\\r\\n transition: all $transition-fast;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: var(--theme-primary);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &.danger:hover:not(:disabled) {\\r\\n border-color: var(--theme-danger);\\r\\n color: var(--theme-danger);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// OVERLAY/MODAL MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin full-overlay($z-index: $z-modal-overlay) {\\r\\n position: fixed;\\r\\n top: 0;\\r\\n left: 0;\\r\\n right: 0;\\r\\n bottom: 0;\\r\\n z-index: $z-index;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// TEXT UTILITIES\\r\\n// ======================\\r\\n\\r\\n@mixin text-ellipsis {\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// DROPDOWN/POPUP\\r\\n// ======================\\r\\n\\r\\n@mixin dropdown-panel {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n box-shadow: $shadow-dropdown;\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\"use strict\";\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\nmodule.exports = function (cssWithMappingToString) {\n var list = [];\n\n // return the list of modules as css string\n list.toString = function toString() {\n return this.map(function (item) {\n var content = \"\";\n var needLayer = typeof item[5] !== \"undefined\";\n if (item[4]) {\n content += \"@supports (\".concat(item[4], \") {\");\n }\n if (item[2]) {\n content += \"@media \".concat(item[2], \" {\");\n }\n if (needLayer) {\n content += \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\");\n }\n content += cssWithMappingToString(item);\n if (needLayer) {\n content += \"}\";\n }\n if (item[2]) {\n content += \"}\";\n }\n if (item[4]) {\n content += \"}\";\n }\n return content;\n }).join(\"\");\n };\n\n // import a list of modules into the list\n list.i = function i(modules, media, dedupe, supports, layer) {\n if (typeof modules === \"string\") {\n modules = [[null, modules, undefined]];\n }\n var alreadyImportedModules = {};\n if (dedupe) {\n for (var k = 0; k < this.length; k++) {\n var id = this[k][0];\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n }\n for (var _k = 0; _k < modules.length; _k++) {\n var item = [].concat(modules[_k]);\n if (dedupe && alreadyImportedModules[item[0]]) {\n continue;\n }\n if (typeof layer !== \"undefined\") {\n if (typeof item[5] === \"undefined\") {\n item[5] = layer;\n } else {\n item[1] = \"@layer\".concat(item[5].length > 0 ? \" \".concat(item[5]) : \"\", \" {\").concat(item[1], \"}\");\n item[5] = layer;\n }\n }\n if (media) {\n if (!item[2]) {\n item[2] = media;\n } else {\n item[1] = \"@media \".concat(item[2], \" {\").concat(item[1], \"}\");\n item[2] = media;\n }\n }\n if (supports) {\n if (!item[4]) {\n item[4] = \"\".concat(supports);\n } else {\n item[1] = \"@supports (\".concat(item[4], \") {\").concat(item[1], \"}\");\n item[4] = supports;\n }\n }\n list.push(item);\n }\n };\n return list;\n};","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./workspaceList.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","module.exports = __WEBPACK_EXTERNAL_MODULE__349__;","\"use strict\";\n\nmodule.exports = function (item) {\n var content = item[1];\n var cssMapping = item[3];\n if (!cssMapping) {\n return content;\n }\n if (typeof btoa === \"function\") {\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(cssMapping))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n var sourceMapping = \"/*# \".concat(data, \" */\");\n return [content].concat([sourceMapping]).join(\"\\n\");\n }\n return [content].join(\"\\n\");\n};","module.exports = __WEBPACK_EXTERNAL_MODULE__358__;","module.exports = __WEBPACK_EXTERNAL_MODULE__439__;","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.workspace-list-container{padding:18px}.tab-bar{display:flex;background:var(--theme-bg-more);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-bottom:none;overflow-y:hidden;overflow-x:auto}.tab-bar::-webkit-scrollbar{height:6px}.tab-bar::-webkit-scrollbar-track{background:var(--theme-bg-more)}.tab-bar::-webkit-scrollbar-thumb{background:var(--theme-border, rgba(255, 255, 255, 0.1));border-radius:3px}.tab-bar::-webkit-scrollbar-thumb:hover{background:var(--theme-fg-more)}.tab{display:flex;align-items:center;gap:6px;padding:6px 10px;border-right:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));color:var(--theme-fg-more);cursor:pointer;font-size:.8rem;min-width:120px;transition:background .15s}.tab:hover{background:var(--theme-bg-more-more)}.tab:hover .tab-close{opacity:1}.tab.active{background:var(--theme-bg);color:var(--theme-fg);border-bottom:2px solid var(--theme-primary);margin-bottom:-1px}.tab-icon{font-size:12px}.tab-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tab-close{width:16px;height:16px;display:flex;align-items:center;justify-content:center;opacity:0;font-size:9px;border-radius:2px;transition:opacity .15s,background .15s}.tab-close:hover{background:var(--theme-danger);color:#fff}.tab-new{display:flex;align-items:center;justify-content:center;width:36px;color:var(--theme-fg-more);cursor:pointer;transition:color .15s,background .15s}.tab-new:hover{background:var(--theme-bg-more-more);color:var(--theme-primary)}.tab-content{background:var(--theme-bg);border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));border-top:none;padding:14px}.tab-content.empty-state{text-align:center;padding:18px;color:var(--theme-fg-more)}.tab-content.empty-state p{margin:6px 0}.tab-content.empty-state strong{color:var(--theme-primary);padding:0 2px}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/workspaceList.component.scss\",\"webpack://./src/styles/_variables.scss\"],\"names\":[],\"mappings\":\"AAEA,0BACE,YCKY,CDDd,SACE,YAAA,CACA,+BAAA,CACA,8DAAA,CACA,kBAAA,CACA,iBAAA,CACA,eAAA,CAGA,4BACE,UAAA,CAGF,kCACE,+BAAA,CAGF,kCACE,wDAAA,CACA,iBAAA,CAEA,wCACE,+BAAA,CAKN,KACE,YAAA,CACA,kBAAA,CACA,OChCW,CDiCX,gBAAA,CACA,oEAAA,CACA,0BAAA,CACA,cAAA,CACA,eCSQ,CDRR,eAAA,CACA,0BAAA,CAEA,WACE,oCAAA,CAEA,sBACE,SAAA,CAIJ,YACE,0BAAA,CACA,qBAAA,CACA,4CAAA,CACA,kBAAA,CAIJ,UACE,cAAA,CAGF,UACE,MAAA,CACA,kBAAA,CACA,eAAA,CACA,sBAAA,CAGF,WACE,UAAA,CACA,WAAA,CACA,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,SAAA,CACA,aAAA,CACA,iBCpEU,CDqEV,uCAAA,CAEA,iBACE,8BAAA,CACA,UAAA,CAIJ,SACE,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,UAAA,CACA,0BAAA,CACA,cAAA,CACA,qCAAA,CAEA,eACE,oCAAA,CACA,0BAAA,CAKJ,aACE,0BAAA,CACA,8DAAA,CACA,eAAA,CACA,YCvGW,CDyGX,yBACE,iBAAA,CACA,YC1GU,CD2GV,0BAAA,CAEA,2BACE,YAAA,CAGF,gCACE,0BAAA,CACA,aAAA\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n.workspace-list-container {\\r\\n padding: $spacing-2xl;\\r\\n}\\r\\n\\r\\n// Tab bar\\r\\n.tab-bar {\\r\\n display: flex;\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-bottom: none;\\r\\n overflow-y: hidden;\\r\\n overflow-x: auto;\\r\\n\\r\\n // Thin scrollbar\\r\\n &::-webkit-scrollbar {\\r\\n height: 6px;\\r\\n }\\r\\n\\r\\n &::-webkit-scrollbar-track {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n\\r\\n &::-webkit-scrollbar-thumb {\\r\\n background: var(--theme-border, $fallback-border);\\r\\n border-radius: 3px;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-fg-more);\\r\\n }\\r\\n }\\r\\n}\\r\\n\\r\\n.tab {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-md;\\r\\n padding: $spacing-md $spacing-lg;\\r\\n border-right: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: $font-sm;\\r\\n min-width: 120px;\\r\\n transition: background $transition-fast;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n\\r\\n .tab-close {\\r\\n opacity: 1;\\r\\n }\\r\\n }\\r\\n\\r\\n &.active {\\r\\n background: var(--theme-bg);\\r\\n color: var(--theme-fg);\\r\\n border-bottom: 2px solid var(--theme-primary);\\r\\n margin-bottom: -1px;\\r\\n }\\r\\n}\\r\\n\\r\\n.tab-icon {\\r\\n font-size: 12px;\\r\\n}\\r\\n\\r\\n.tab-name {\\r\\n flex: 1;\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n.tab-close {\\r\\n width: 16px;\\r\\n height: 16px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n opacity: 0;\\r\\n font-size: 9px;\\r\\n border-radius: $radius-xs;\\r\\n transition: opacity $transition-fast, background $transition-fast;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-danger);\\r\\n color: white;\\r\\n }\\r\\n}\\r\\n\\r\\n.tab-new {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n color: var(--theme-fg-more);\\r\\n cursor: pointer;\\r\\n transition: color $transition-fast, background $transition-fast;\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more-more);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n}\\r\\n\\r\\n// Tab content\\r\\n.tab-content {\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-top: none;\\r\\n padding: $spacing-xl;\\r\\n\\r\\n &.empty-state {\\r\\n text-align: center;\\r\\n padding: $spacing-2xl;\\r\\n color: var(--theme-fg-more);\\r\\n\\r\\n p {\\r\\n margin: $spacing-md 0;\\r\\n }\\r\\n\\r\\n strong {\\r\\n color: var(--theme-primary);\\r\\n padding: 0 $spacing-xs;\\r\\n }\\r\\n }\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","var pug = require(\"!../../node_modules/pug-runtime/index.js\");\n\nfunction template(locals) {var pug_html = \"\", pug_mixins = {}, pug_interp;pug_html = pug_html + \"\\u003Cdiv class=\\\"split-preview\\\" [class.horizontal]=\\\"split.orientation === &quot;horizontal&quot;\\\" [class.vertical]=\\\"split.orientation === &quot;vertical&quot;\\\" [class.nested]=\\\"depth &gt; 0\\\"\\u003E\\u003Cng-container *ngFor=\\\"let child of split.children; let i = index\\\"\\u003E\\u003Cdiv class=\\\"preview-pane\\\" *ngIf=\\\"isPane(child)\\\" [style.flex-basis]=\\\"getFlexStyle(i)\\\" [class.selected]=\\\"asPane(child).id === selectedPaneId\\\" (click)=\\\"onPaneClick(asPane(child)); $event.stopPropagation()\\\" (contextmenu)=\\\"onContextMenu($event, asPane(child))\\\"\\u003E\\u003Cdiv class=\\\"pane-content\\\"\\u003E\\u003Cdiv class=\\\"pane-label\\\"\\u003E{{ getPaneLabel(asPane(child)) }}\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"pane-details\\\"\\u003E\\u003Cdiv class=\\\"pane-detail\\\" *ngIf=\\\"asPane(child).cwd\\\" [title]=\\\"asPane(child).cwd\\\"\\u003E\\u003Ci class=\\\"fas fa-folder\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003Cspan\\u003E{{ truncate(asPane(child).cwd, 20) }}\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"pane-detail\\\" *ngIf=\\\"asPane(child).startupCommand\\\" [title]=\\\"asPane(child).startupCommand\\\"\\u003E\\u003Ci class=\\\"fas fa-terminal\\\"\\u003E\\u003C\\u002Fi\\u003E\\u003Cspan\\u003E{{ truncate(asPane(child).startupCommand, 20) }}\\u003C\\u002Fspan\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\\u003Csplit-preview *ngIf=\\\"isSplit(child)\\\" [split]=\\\"asSplit(child)\\\" [depth]=\\\"depth + 1\\\" [selectedPaneId]=\\\"selectedPaneId\\\" [profiles]=\\\"profiles\\\" [style.flex-basis]=\\\"getFlexStyle(i)\\\" (paneEdit)=\\\"onNestedPaneEdit($event)\\\" (splitHorizontal)=\\\"onNestedSplitH($event)\\\" (splitVertical)=\\\"onNestedSplitV($event)\\\" (addLeft)=\\\"onNestedAddLeft($event)\\\" (addRight)=\\\"onNestedAddRight($event)\\\" (addTop)=\\\"onNestedAddTop($event)\\\" (addBottom)=\\\"onNestedAddBottom($event)\\\" (removePane)=\\\"onNestedRemove($event)\\\"\\u003E\\u003C\\u002Fsplit-preview\\u003E\\u003C\\u002Fng-container\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cdiv class=\\\"context-menu-overlay\\\" *ngIf=\\\"contextMenuPane\\\" (click)=\\\"closeContextMenu()\\\"\\u003E\\u003Cdiv class=\\\"context-menu\\\" [style.left.px]=\\\"contextMenuPosition.x\\\" [style.top.px]=\\\"contextMenuPosition.y\\\" (click)=\\\"$event.stopPropagation()\\\"\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onEdit()\\\"\\u003E\\u003Ci class=\\\"fas fa-pen\\\"\\u003E\\u003C\\u002Fi\\u003E Edit\\u003C\\u002Fbutton\\u003E\\u003Cdiv class=\\\"context-menu-divider\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onSplitH()\\\"\\u003E\\u003Ci class=\\\"fas fa-arrows-alt-h\\\"\\u003E\\u003C\\u002Fi\\u003E Split Horizontal\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onSplitV()\\\"\\u003E\\u003Ci class=\\\"fas fa-arrows-alt-v\\\"\\u003E\\u003C\\u002Fi\\u003E Split Vertical\\u003C\\u002Fbutton\\u003E\\u003Cdiv class=\\\"context-menu-divider\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddLeft()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-left\\\"\\u003E\\u003C\\u002Fi\\u003E Add Left\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddRight()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-right\\\"\\u003E\\u003C\\u002Fi\\u003E Add Right\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddTop()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-up\\\"\\u003E\\u003C\\u002Fi\\u003E Add Top\\u003C\\u002Fbutton\\u003E\\u003Cbutton class=\\\"context-menu-item\\\" type=\\\"button\\\" (click)=\\\"onAddBottom()\\\"\\u003E\\u003Ci class=\\\"fas fa-caret-down\\\"\\u003E\\u003C\\u002Fi\\u003E Add Bottom\\u003C\\u002Fbutton\\u003E\\u003Cdiv class=\\\"context-menu-divider\\\"\\u003E\\u003C\\u002Fdiv\\u003E\\u003Cbutton class=\\\"context-menu-item danger\\\" type=\\\"button\\\" (click)=\\\"onRemove()\\\"\\u003E\\u003Ci class=\\\"fas fa-trash\\\"\\u003E\\u003C\\u002Fi\\u003E Remove Pane\\u003C\\u002Fbutton\\u003E\\u003C\\u002Fdiv\\u003E\\u003C\\u002Fdiv\\u003E\";;return pug_html;};\nmodule.exports = template;","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/splitPreview.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","module.exports = __WEBPACK_EXTERNAL_MODULE__650__;","module.exports = __WEBPACK_EXTERNAL_MODULE__700__;","module.exports = __WEBPACK_EXTERNAL_MODULE__765__;","'use strict';\n\nvar pug_has_own_property = Object.prototype.hasOwnProperty;\n\n/**\n * Merge two attribute objects giving precedence\n * to values in object `b`. Classes are special-cased\n * allowing for arrays and merging/joining appropriately\n * resulting in a string.\n *\n * @param {Object} a\n * @param {Object} b\n * @return {Object} a\n * @api private\n */\n\nexports.merge = pug_merge;\nfunction pug_merge(a, b) {\n if (arguments.length === 1) {\n var attrs = a[0];\n for (var i = 1; i < a.length; i++) {\n attrs = pug_merge(attrs, a[i]);\n }\n return attrs;\n }\n\n for (var key in b) {\n if (key === 'class') {\n var valA = a[key] || [];\n a[key] = (Array.isArray(valA) ? valA : [valA]).concat(b[key] || []);\n } else if (key === 'style') {\n var valA = pug_style(a[key]);\n valA = valA && valA[valA.length - 1] !== ';' ? valA + ';' : valA;\n var valB = pug_style(b[key]);\n valB = valB && valB[valB.length - 1] !== ';' ? valB + ';' : valB;\n a[key] = valA + valB;\n } else {\n a[key] = b[key];\n }\n }\n\n return a;\n}\n\n/**\n * Process array, object, or string as a string of classes delimited by a space.\n *\n * If `val` is an array, all members of it and its subarrays are counted as\n * classes. If `escaping` is an array, then whether or not the item in `val` is\n * escaped depends on the corresponding item in `escaping`. If `escaping` is\n * not an array, no escaping is done.\n *\n * If `val` is an object, all the keys whose value is truthy are counted as\n * classes. No escaping is done.\n *\n * If `val` is a string, it is counted as a class. No escaping is done.\n *\n * @param {(Array.<string>|Object.<string, boolean>|string)} val\n * @param {?Array.<string>} escaping\n * @return {String}\n */\nexports.classes = pug_classes;\nfunction pug_classes_array(val, escaping) {\n var classString = '',\n className,\n padding = '',\n escapeEnabled = Array.isArray(escaping);\n for (var i = 0; i < val.length; i++) {\n className = pug_classes(val[i]);\n if (!className) continue;\n escapeEnabled && escaping[i] && (className = pug_escape(className));\n classString = classString + padding + className;\n padding = ' ';\n }\n return classString;\n}\nfunction pug_classes_object(val) {\n var classString = '',\n padding = '';\n for (var key in val) {\n if (key && val[key] && pug_has_own_property.call(val, key)) {\n classString = classString + padding + key;\n padding = ' ';\n }\n }\n return classString;\n}\nfunction pug_classes(val, escaping) {\n if (Array.isArray(val)) {\n return pug_classes_array(val, escaping);\n } else if (val && typeof val === 'object') {\n return pug_classes_object(val);\n } else {\n return val || '';\n }\n}\n\n/**\n * Convert object or string to a string of CSS styles delimited by a semicolon.\n *\n * @param {(Object.<string, string>|string)} val\n * @return {String}\n */\n\nexports.style = pug_style;\nfunction pug_style(val) {\n if (!val) return '';\n if (typeof val === 'object') {\n var out = '';\n for (var style in val) {\n /* istanbul ignore else */\n if (pug_has_own_property.call(val, style)) {\n out = out + style + ':' + val[style] + ';';\n }\n }\n return out;\n } else {\n return val + '';\n }\n}\n\n/**\n * Render the given attribute.\n *\n * @param {String} key\n * @param {String} val\n * @param {Boolean} escaped\n * @param {Boolean} terse\n * @return {String}\n */\nexports.attr = pug_attr;\nfunction pug_attr(key, val, escaped, terse) {\n if (\n val === false ||\n val == null ||\n (!val && (key === 'class' || key === 'style'))\n ) {\n return '';\n }\n if (val === true) {\n return ' ' + (terse ? key : key + '=\"' + key + '\"');\n }\n var type = typeof val;\n if (\n (type === 'object' || type === 'function') &&\n typeof val.toJSON === 'function'\n ) {\n val = val.toJSON();\n }\n if (typeof val !== 'string') {\n val = JSON.stringify(val);\n if (!escaped && val.indexOf('\"') !== -1) {\n return ' ' + key + \"='\" + val.replace(/'/g, '&#39;') + \"'\";\n }\n }\n if (escaped) val = pug_escape(val);\n return ' ' + key + '=\"' + val + '\"';\n}\n\n/**\n * Render the given attributes object.\n *\n * @param {Object} obj\n * @param {Object} terse whether to use HTML5 terse boolean attributes\n * @return {String}\n */\nexports.attrs = pug_attrs;\nfunction pug_attrs(obj, terse) {\n var attrs = '';\n\n for (var key in obj) {\n if (pug_has_own_property.call(obj, key)) {\n var val = obj[key];\n\n if ('class' === key) {\n val = pug_classes(val);\n attrs = pug_attr(key, val, false, terse) + attrs;\n continue;\n }\n if ('style' === key) {\n val = pug_style(val);\n }\n attrs += pug_attr(key, val, false, terse);\n }\n }\n\n return attrs;\n}\n\n/**\n * Escape the given string of `html`.\n *\n * @param {String} html\n * @return {String}\n * @api private\n */\n\nvar pug_match_html = /[\"&<>]/;\nexports.escape = pug_escape;\nfunction pug_escape(_html) {\n var html = '' + _html;\n var regexResult = pug_match_html.exec(html);\n if (!regexResult) return _html;\n\n var result = '';\n var i, lastIndex, escape;\n for (i = regexResult.index, lastIndex = 0; i < html.length; i++) {\n switch (html.charCodeAt(i)) {\n case 34:\n escape = '&quot;';\n break;\n case 38:\n escape = '&amp;';\n break;\n case 60:\n escape = '&lt;';\n break;\n case 62:\n escape = '&gt;';\n break;\n default:\n continue;\n }\n if (lastIndex !== i) result += html.substring(lastIndex, i);\n lastIndex = i + 1;\n result += escape;\n }\n if (lastIndex !== i) return result + html.substring(lastIndex, i);\n else return result;\n}\n\n/**\n * Re-throw the given `err` in context to the\n * the pug in `filename` at the given `lineno`.\n *\n * @param {Error} err\n * @param {String} filename\n * @param {String} lineno\n * @param {String} str original source\n * @api private\n */\n\nexports.rethrow = pug_rethrow;\nfunction pug_rethrow(err, filename, lineno, str) {\n if (!(err instanceof Error)) throw err;\n if ((typeof window != 'undefined' || !filename) && !str) {\n err.message += ' on line ' + lineno;\n throw err;\n }\n var context, lines, start, end;\n try {\n str = str || require('fs').readFileSync(filename, {encoding: 'utf8'});\n context = 3;\n lines = str.split('\\n');\n start = Math.max(lineno - context, 0);\n end = Math.min(lines.length, lineno + context);\n } catch (ex) {\n err.message +=\n ' - could not read from ' + filename + ' (' + ex.message + ')';\n pug_rethrow(err, null, lineno);\n return;\n }\n\n // Error context\n context = lines\n .slice(start, end)\n .map(function(line, i) {\n var curr = i + start + 1;\n return (curr == lineno ? ' > ' : ' ') + curr + '| ' + line;\n })\n .join('\\n');\n\n // Alter exception message\n err.path = filename;\n try {\n err.message =\n (filename || 'Pug') +\n ':' +\n lineno +\n '\\n' +\n context +\n '\\n\\n' +\n err.message;\n } catch (e) {}\n throw err;\n}\n","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/workspaceEditor.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","\n var result = require(\"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js!./workspaceEditor.component.scss\");\n\n if (result && result.__esModule) {\n result = result.default;\n }\n\n if (typeof result === \"string\") {\n module.exports = result;\n } else {\n module.exports = result.toString();\n }\n ","module.exports = __WEBPACK_EXTERNAL_MODULE__860__;","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/paneEditor.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, `.pane-details{background:var(--theme-bg-more-more);border-radius:2px;padding:10px;padding-top:10px;margin-top:14px;border-left:2px solid var(--theme-primary);border-top:1px solid var(--theme-border, rgba(255, 255, 255, 0.1))}.pane-details-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.pane-details-title{font-size:.8rem;color:var(--theme-fg);font-weight:500;display:flex;align-items:center;gap:4px}.pane-form{display:grid;grid-template-columns:1fr 1fr;gap:10px}@media(max-width: 600px){.pane-form{grid-template-columns:1fr}}.form-group label{display:block;font-size:.7rem;color:var(--theme-fg-less);text-transform:uppercase;letter-spacing:.5px;margin-bottom:2px}.form-control{width:100%;padding:4px 6px;border-radius:2px;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1));background:var(--theme-bg);color:var(--theme-fg);font-size:.85rem}.form-control:focus{outline:none;border-color:var(--theme-primary)}.form-control::placeholder{color:var(--theme-fg-more, rgba(255, 255, 255, 0.3))}.form-control{font-size:.8rem;border:1px solid var(--theme-border, rgba(255, 255, 255, 0.1)) !important}.form-control:focus{border-color:var(--theme-primary) !important}select.form-control{cursor:pointer;appearance:auto}`, \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/paneEditor.component.scss\",\"webpack://./src/styles/_variables.scss\",\"webpack://./src/styles/_mixins.scss\"],\"names\":[],\"mappings\":\"AAGA,cACE,oCAAA,CACA,iBCSU,CDRV,YAAA,CACA,gBCDW,CDEX,eCDW,CDEX,0CAAA,CACA,kEAAA,CAGF,qBACE,YAAA,CACA,6BAAA,CACA,kBAAA,CACA,kBCXW,CDcb,oBACE,eC8BQ,CD7BR,qBAAA,CACA,eAAA,CACA,YAAA,CACA,kBAAA,CACA,OCtBW,CD0Bb,WACE,YAAA,CACA,6BAAA,CACA,QC3BW,CD8Bb,yBACE,WACE,yBAAA,CAAA,CAKF,kBEJA,aAAA,CACA,eDUQ,CCTR,0BAAA,CACA,wBAAA,CACA,mBAAA,CACA,iBDzCW,CD6Cb,cACE,UAAA,CEhCA,eAAA,CACA,iBDJU,CCKV,8DAAA,CACA,0BF8BoB,CE7BpB,qBAAA,CACA,gBD8BQ,CC5BR,oBACE,YAAA,CACA,iCAAA,CAGF,2BACE,oDAAA,CFkBJ,cAGE,eAAA,CAEA,yEAAA,CAEA,oBACE,4CAAA,CAIJ,oBACE,cAAA,CACA,eAAA\",\"sourcesContent\":[\"@use '../styles/index' as *;\\r\\n\\r\\n// Inline pane details panel\\r\\n.pane-details {\\r\\n background: var(--theme-bg-more-more);\\r\\n border-radius: $radius-sm;\\r\\n padding: $spacing-lg;\\r\\n padding-top: $spacing-lg;\\r\\n margin-top: $spacing-xl;\\r\\n border-left: 2px solid var(--theme-primary);\\r\\n border-top: 1px solid var(--theme-border, $fallback-border);\\r\\n}\\r\\n\\r\\n.pane-details-header {\\r\\n display: flex;\\r\\n justify-content: space-between;\\r\\n align-items: center;\\r\\n margin-bottom: $spacing-lg;\\r\\n}\\r\\n\\r\\n.pane-details-title {\\r\\n font-size: $font-sm;\\r\\n color: var(--theme-fg);\\r\\n font-weight: 500;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n}\\r\\n\\r\\n// 2-column grid for pane form\\r\\n.pane-form {\\r\\n display: grid;\\r\\n grid-template-columns: 1fr 1fr;\\r\\n gap: $spacing-lg;\\r\\n}\\r\\n\\r\\n@media (max-width: 600px) {\\r\\n .pane-form {\\r\\n grid-template-columns: 1fr;\\r\\n }\\r\\n}\\r\\n\\r\\n.form-group {\\r\\n label {\\r\\n @include form-label;\\r\\n }\\r\\n}\\r\\n\\r\\n.form-control {\\r\\n width: 100%;\\r\\n @include form-input(var(--theme-bg));\\r\\n font-size: $font-sm;\\r\\n // Override Tabby's global border reset\\r\\n border: 1px solid var(--theme-border, $fallback-border) !important;\\r\\n\\r\\n &:focus {\\r\\n border-color: var(--theme-primary) !important;\\r\\n }\\r\\n}\\r\\n\\r\\nselect.form-control {\\r\\n cursor: pointer;\\r\\n appearance: auto; // Show dropdown arrow\\r\\n}\\r\\n\",\"// ======================\\r\\n// SPACING SCALE (S1: Tight)\\r\\n// ======================\\r\\n$spacing-xs: 2px; // toolbar group gap, tiny margins\\r\\n$spacing-sm: 4px; // gaps, small padding\\r\\n$spacing-md: 6px; // default gaps, button padding\\r\\n$spacing-lg: 10px; // section gaps, form spacing\\r\\n$spacing-xl: 14px; // container padding, large gaps\\r\\n$spacing-2xl: 18px; // modal padding, section margins\\r\\n\\r\\n// ======================\\r\\n// BORDER RADIUS SCALE (S1: Sharp)\\r\\n// ======================\\r\\n$radius-xs: 2px; // tiny elements\\r\\n$radius-sm: 2px; // buttons, small elements\\r\\n$radius-md: 3px; // inputs, dropdowns\\r\\n$radius-lg: 4px; // cards, containers, modals\\r\\n\\r\\n// ======================\\r\\n// CUSTOM COLORS\\r\\n// ======================\\r\\n// These extend Tabby's --theme-* variables\\r\\n$color-success: #10b981;\\r\\n$color-success-hover: #059669;\\r\\n$color-warning: #f59e0b;\\r\\n$color-danger: #ef4444;\\r\\n\\r\\n// Fallback values for Tabby theme variables that may not be defined\\r\\n$fallback-border: rgba(255, 255, 255, 0.1);\\r\\n$fallback-fg-more: rgba(255, 255, 255, 0.3);\\r\\n\\r\\n// ======================\\r\\n// SHADOWS (S1: Flat - no shadows)\\r\\n// ======================\\r\\n$shadow-dropdown: none;\\r\\n$shadow-context-menu: none;\\r\\n$shadow-modal: none;\\r\\n$overlay-bg: rgba(0, 0, 0, 0.7);\\r\\n\\r\\n// ======================\\r\\n// PREVIEW COMPONENT\\r\\n// ======================\\r\\n$preview-height: 140px;\\r\\n$nested-split-bg: rgba(255, 255, 255, 0.02);\\r\\n$selected-pane-gradient-start: rgba(59, 130, 246, 0.08);\\r\\n$selected-pane-gradient-end: rgba(59, 130, 246, 0.04);\\r\\n\\r\\n// ======================\\r\\n// FONT SIZES (S1: Compact)\\r\\n// ======================\\r\\n$font-xs: 0.7rem; // 11px - sublabels, hints\\r\\n$font-sm: 0.8rem; // 13px - labels, secondary text\\r\\n$font-md: 0.85rem; // 14px - default body\\r\\n\\r\\n// ======================\\r\\n// Z-INDEX SCALE\\r\\n// ======================\\r\\n$z-dropdown: 100;\\r\\n$z-modal-overlay: 1100;\\r\\n$z-context-menu-overlay: 1200;\\r\\n$z-context-menu: 1201;\\r\\n\\r\\n// ======================\\r\\n// TRANSITIONS\\r\\n// ======================\\r\\n$transition-fast: 0.15s;\\r\\n$transition-normal: 0.2s;\\r\\n\",\"@use 'variables' as *;\\r\\n\\r\\n// ======================\\r\\n// LAYOUT MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin flex-center {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM INPUT MIXIN\\r\\n// ======================\\r\\n\\r\\n@mixin form-input($bg: var(--theme-bg)) {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n border-radius: $radius-sm;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n background: $bg;\\r\\n color: var(--theme-fg);\\r\\n font-size: $font-md;\\r\\n\\r\\n &:focus {\\r\\n outline: none;\\r\\n border-color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &::placeholder {\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// FORM LABEL MIXIN (S1: Uppercase compact)\\r\\n// ======================\\r\\n\\r\\n@mixin form-label {\\r\\n display: block;\\r\\n font-size: $font-xs;\\r\\n color: var(--theme-fg-less);\\r\\n text-transform: uppercase;\\r\\n letter-spacing: 0.5px;\\r\\n margin-bottom: $spacing-xs;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// BUTTON MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin toolbar-btn {\\r\\n padding: $spacing-sm $spacing-md;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg);\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n font-size: 0.85rem;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n background: var(--theme-bg-more-more);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n\\r\\n &.danger {\\r\\n color: var(--theme-danger, $color-danger);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-success {\\r\\n background: $color-success;\\r\\n border-color: $color-success;\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n background: $color-success-hover;\\r\\n border-color: $color-success-hover;\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-base {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n gap: $spacing-sm;\\r\\n padding: $spacing-sm $spacing-lg;\\r\\n font-size: $font-sm;\\r\\n border-radius: $radius-sm;\\r\\n cursor: pointer;\\r\\n transition: all $transition-fast;\\r\\n}\\r\\n\\r\\n@mixin btn-ghost {\\r\\n @include btn-base;\\r\\n background: transparent;\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n color: var(--theme-fg);\\r\\n\\r\\n &:hover {\\r\\n background: var(--theme-bg-more);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin btn-primary {\\r\\n @include btn-base;\\r\\n background: var(--theme-primary);\\r\\n border: 1px solid var(--theme-primary);\\r\\n color: white;\\r\\n\\r\\n &:hover {\\r\\n filter: brightness(1.1);\\r\\n }\\r\\n}\\r\\n\\r\\n@mixin icon-btn-sm($size: 24px) {\\r\\n width: $size;\\r\\n height: $size;\\r\\n @include flex-center;\\r\\n background: var(--theme-bg);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-sm;\\r\\n color: var(--theme-fg-more, $fallback-fg-more);\\r\\n cursor: pointer;\\r\\n font-size: 10px;\\r\\n transition: all $transition-fast;\\r\\n\\r\\n &:hover:not(:disabled) {\\r\\n border-color: var(--theme-primary);\\r\\n color: var(--theme-primary);\\r\\n }\\r\\n\\r\\n &.danger:hover:not(:disabled) {\\r\\n border-color: var(--theme-danger);\\r\\n color: var(--theme-danger);\\r\\n }\\r\\n\\r\\n &:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\r\\n }\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// OVERLAY/MODAL MIXINS\\r\\n// ======================\\r\\n\\r\\n@mixin full-overlay($z-index: $z-modal-overlay) {\\r\\n position: fixed;\\r\\n top: 0;\\r\\n left: 0;\\r\\n right: 0;\\r\\n bottom: 0;\\r\\n z-index: $z-index;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// TEXT UTILITIES\\r\\n// ======================\\r\\n\\r\\n@mixin text-ellipsis {\\r\\n white-space: nowrap;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n}\\r\\n\\r\\n// ======================\\r\\n// DROPDOWN/POPUP\\r\\n// ======================\\r\\n\\r\\n@mixin dropdown-panel {\\r\\n background: var(--theme-bg-more);\\r\\n border: 1px solid var(--theme-border, $fallback-border);\\r\\n border-radius: $radius-md;\\r\\n box-shadow: $shadow-dropdown;\\r\\n}\\r\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","if(typeof __WEBPACK_EXTERNAL_MODULE__947__ === 'undefined') { var e = new Error(\"Cannot find module 'fs'\"); e.code = 'MODULE_NOT_FOUND'; throw e; }\n\nmodule.exports = __WEBPACK_EXTERNAL_MODULE__947__;","var req = require(\"!!/home/runner/work/tabbyspaces/tabbyspaces/node_modules/pug-loader/index.js!/home/runner/work/tabbyspaces/tabbyspaces/src/components/workspaceList.component.pug\");\nmodule.exports = (req['default'] || req).apply(req, [])","module.exports = __WEBPACK_EXTERNAL_MODULE__961__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Check if module exists (development only)\n\tif (__webpack_modules__[moduleId] === undefined) {\n\t\tvar e = new Error(\"Cannot find module '\" + moduleId + \"'\");\n\t\te.code = 'MODULE_NOT_FOUND';\n\t\tthrow e;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\tid: moduleId,\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// Build-time constants injected by webpack DefinePlugin\r\ndeclare const __CONFIG_KEY__: string\r\ndeclare const __DISPLAY_NAME__: string\r\ndeclare const __IS_DEV__: boolean\r\n\r\nexport const CONFIG_KEY = typeof __CONFIG_KEY__ !== 'undefined' ? __CONFIG_KEY__ : 'tabbyspaces'\r\nexport const DISPLAY_NAME = typeof __DISPLAY_NAME__ !== 'undefined' ? __DISPLAY_NAME__ : 'TabbySpaces'\r\nexport const IS_DEV = typeof __IS_DEV__ !== 'undefined' ? __IS_DEV__ : false\r\n","import { Injectable } from '@angular/core'\r\nimport { ConfigProvider } from 'tabby-core'\r\nimport { CONFIG_KEY } from '../build-config'\r\n\r\n@Injectable()\r\nexport class WorkspaceEditorConfigProvider extends ConfigProvider {\r\n defaults = {\r\n [CONFIG_KEY]: {\r\n workspaces: [],\r\n },\r\n }\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { AppService, BaseTabComponent, SplitTabComponent } from 'tabby-core'\r\nimport { BaseTerminalTabComponent } from 'tabby-terminal'\r\nimport { first, timeout, of } from 'rxjs'\r\nimport { catchError } from 'rxjs/operators'\r\n\r\nexport interface PendingCommand {\r\n paneId: string\r\n command?: string\r\n originalTitle: string\r\n}\r\n\r\n/**\r\n * Handles startup commands for workspace panes.\r\n *\r\n * This service listens to tab open events and sends startup commands\r\n * to terminals that match registered pane IDs.\r\n *\r\n * NOTE: This is a module-level singleton that lives for the app lifetime.\r\n * The tabOpened$ subscription intentionally runs forever - no cleanup needed.\r\n */\r\n@Injectable()\r\nexport class StartupCommandService {\r\n private pendingCommands: Map<string, PendingCommand> = new Map()\r\n\r\n constructor(private app: AppService) {\r\n this.app.tabOpened$.subscribe((tab) => this.onTabOpened(tab))\r\n }\r\n\r\n registerCommands(commands: PendingCommand[]): void {\r\n console.log('[TabbySpaces] Registering commands:', commands)\r\n for (const cmd of commands) {\r\n this.pendingCommands.set(cmd.paneId, cmd)\r\n }\r\n }\r\n\r\n private onTabOpened(tab: BaseTabComponent): void {\r\n console.log('[TabbySpaces] Tab opened:', {\r\n type: tab.constructor.name,\r\n title: tab.title,\r\n })\r\n\r\n // Handle SplitTabComponent - get all child terminal tabs\r\n if (tab instanceof SplitTabComponent) {\r\n console.log('[TabbySpaces] SplitTabComponent detected, waiting for children...')\r\n // Wait for split tab to fully initialize its children\r\n setTimeout(() => this.processChildTabs(tab), 300)\r\n return\r\n }\r\n\r\n // Handle individual terminal tab (shouldn't happen for split-layout, but just in case)\r\n if (tab instanceof BaseTerminalTabComponent) {\r\n this.processTerminalTab(tab)\r\n }\r\n }\r\n\r\n private processChildTabs(splitTab: SplitTabComponent): void {\r\n // Get all nested tabs from the split container\r\n const allTabs = splitTab.getAllTabs()\r\n console.log('[TabbySpaces] Found child tabs:', allTabs.length)\r\n\r\n for (const tab of allTabs) {\r\n if (tab instanceof BaseTerminalTabComponent) {\r\n this.processTerminalTab(tab)\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private processTerminalTab(terminalTab: BaseTerminalTabComponent<any>): void {\r\n const paneId = terminalTab.customTitle || terminalTab.title\r\n console.log('[TabbySpaces] Processing terminal tab:', {\r\n title: terminalTab.title,\r\n customTitle: terminalTab.customTitle,\r\n paneId,\r\n pendingKeys: [...this.pendingCommands.keys()],\r\n })\r\n\r\n const pending = this.pendingCommands.get(paneId)\r\n if (!pending) {\r\n console.log('[TabbySpaces] No matching command for paneId:', paneId)\r\n return\r\n }\r\n\r\n this.pendingCommands.delete(paneId)\r\n\r\n // Build startup command (cd + command)\r\n const fullCommand = this.buildFullCommand(pending)\r\n if (!fullCommand) {\r\n console.log('[TabbySpaces] No command to send (no cwd or startup command)')\r\n return\r\n }\r\n\r\n console.log('[TabbySpaces] Command matched, waiting for shell output...:', fullCommand)\r\n\r\n // Unified command sender - reduces duplication\r\n const sendCommand = () => {\r\n console.log('[TabbySpaces] Shell ready, sending command:', fullCommand)\r\n terminalTab.sendInput(fullCommand + '\\r')\r\n this.clearProfileArgs(terminalTab)\r\n this.setTabTitle(terminalTab, pending.originalTitle)\r\n }\r\n\r\n // Wait for shell to emit first output (prompt), then send command\r\n if (terminalTab.session?.output$) {\r\n terminalTab.session.output$.pipe(\r\n first(),\r\n timeout(2000), // Prevent infinite wait if shell doesn't emit\r\n catchError(() => of(null)) // Fallback on timeout/error\r\n ).subscribe(() => {\r\n // Small delay after prompt renders\r\n setTimeout(sendCommand, 100)\r\n })\r\n } else {\r\n console.log('[TabbySpaces] No session.output$, falling back to timeout')\r\n setTimeout(sendCommand, 500)\r\n }\r\n }\r\n\r\n private buildFullCommand(pending: PendingCommand): string | null {\r\n return pending.command || null\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private clearProfileArgs(terminalTab: BaseTerminalTabComponent<any>): void {\r\n // Clear args from profile to prevent native splits from re-running startup command\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const profile = (terminalTab as any).profile\r\n if (profile?.options?.args) {\r\n console.log('[TabbySpaces] Clearing profile args to prevent re-run on split')\r\n profile.options.args = []\r\n }\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private setTabTitle(terminalTab: BaseTerminalTabComponent<any>, title: string): void {\r\n terminalTab.setTitle(title)\r\n terminalTab.customTitle = title\r\n }\r\n}\r\n","// Tabby profile interfaces\r\nexport interface TabbyProfileOptions {\r\n command?: string\r\n args?: string[]\r\n cwd?: string\r\n env?: Record<string, string>\r\n restoreFromPTYID?: boolean\r\n width?: number | null\r\n height?: number | null\r\n pauseAfterExit?: boolean\r\n runAsAdministrator?: boolean\r\n}\r\n\r\nexport interface TabbyProfile {\r\n id: string\r\n type: string\r\n name: string\r\n group?: string\r\n icon?: string\r\n color?: string\r\n options?: TabbyProfileOptions\r\n isBuiltin?: boolean\r\n isTemplate?: boolean\r\n weight?: number\r\n disableDynamicTitle?: boolean\r\n terminalColorScheme?: string | null\r\n behaviorOnSessionEnd?: string\r\n}\r\n\r\nexport interface TabbyRecoveryToken {\r\n type: string\r\n orientation?: 'h' | 'v'\r\n ratios?: number[]\r\n children?: TabbyRecoveryToken[]\r\n profile?: Partial<TabbyProfile>\r\n savedState?: boolean\r\n tabTitle?: string\r\n tabCustomTitle?: string\r\n disableDynamicTitle?: boolean\r\n cwd?: string\r\n // Allow custom properties (matches Tabby's RecoveryToken interface)\r\n [key: string]: any\r\n}\r\n\r\nexport interface TabbySplitLayoutProfile {\r\n id: string\r\n type: 'split-layout'\r\n name: string\r\n group: string\r\n icon?: string\r\n color?: string\r\n isBuiltin: boolean\r\n options: {\r\n recoveryToken: TabbyRecoveryToken\r\n }\r\n}\r\n\r\n// Workspace interfaces\r\nexport interface WorkspacePane {\r\n id: string\r\n profileId: string\r\n cwd?: string\r\n startupCommand?: string\r\n}\r\n\r\nexport interface WorkspaceSplit {\r\n orientation: 'horizontal' | 'vertical'\r\n ratios: number[]\r\n children: (WorkspacePane | WorkspaceSplit)[]\r\n}\r\n\r\nexport interface WorkspaceBackground {\r\n type: 'none' | 'solid' | 'gradient' | 'image'\r\n value: string // CSS value: hex, gradient string, or URL\r\n}\r\n\r\nexport interface Workspace {\r\n id: string\r\n name: string\r\n icon?: string\r\n color?: string\r\n background?: WorkspaceBackground\r\n root: WorkspaceSplit\r\n launchOnStartup?: boolean\r\n}\r\n\r\n// Preset backgrounds for quick selection\r\nexport const BACKGROUND_PRESETS: WorkspaceBackground[] = [\r\n { type: 'none', value: '' },\r\n // Existing presets\r\n { type: 'gradient', value: 'linear-gradient(132deg, transparent 83%, rgba(6, 220, 249, 0.18) 100%), linear-gradient(210deg, transparent 85%, rgba(139, 92, 246, 0.2) 100%)' },\r\n { type: 'gradient', value: 'linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, transparent 50%)' },\r\n { type: 'gradient', value: 'linear-gradient(45deg, rgba(239, 68, 68, 0.1) 0%, transparent 50%)' },\r\n { type: 'gradient', value: 'linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, transparent 50%)' },\r\n { type: 'gradient', value: 'linear-gradient(225deg, transparent 70%, rgba(249, 115, 22, 0.15) 100%)' },\r\n { type: 'gradient', value: 'linear-gradient(180deg, rgba(139, 92, 246, 0.1) 0%, transparent 40%)' },\r\n // New presets\r\n { type: 'gradient', value: 'linear-gradient(315deg, transparent 80%, rgba(236, 72, 153, 0.15) 100%)' }, // Pink bottom-right\r\n { type: 'gradient', value: 'linear-gradient(0deg, rgba(6, 182, 212, 0.12) 0%, transparent 35%)' }, // Cyan bottom\r\n { type: 'gradient', value: 'linear-gradient(45deg, transparent 85%, rgba(234, 179, 8, 0.18) 100%), linear-gradient(225deg, transparent 85%, rgba(249, 115, 22, 0.15) 100%)' }, // Gold corners\r\n { type: 'gradient', value: 'linear-gradient(160deg, rgba(34, 197, 94, 0.12) 0%, transparent 40%)' }, // Green top-left\r\n { type: 'gradient', value: 'linear-gradient(200deg, transparent 75%, rgba(99, 102, 241, 0.18) 100%)' }, // Indigo bottom-left\r\n { type: 'gradient', value: 'linear-gradient(135deg, rgba(20, 184, 166, 0.1) 0%, transparent 50%), linear-gradient(315deg, rgba(139, 92, 246, 0.1) 0%, transparent 50%)' }, // Teal + Violet diagonal\r\n { type: 'gradient', value: 'linear-gradient(90deg, rgba(239, 68, 68, 0.08) 0%, transparent 30%, transparent 70%, rgba(59, 130, 246, 0.08) 100%)' }, // Red-Blue sides\r\n { type: 'gradient', value: 'linear-gradient(180deg, transparent 60%, rgba(16, 185, 129, 0.12) 100%)' }, // Emerald bottom fade\r\n { type: 'gradient', value: 'linear-gradient(45deg, rgba(168, 85, 247, 0.1) 0%, transparent 40%), linear-gradient(225deg, rgba(6, 182, 212, 0.1) 0%, transparent 40%)' }, // Purple + Cyan corners\r\n { type: 'gradient', value: 'linear-gradient(150deg, transparent 70%, rgba(251, 146, 60, 0.15) 100%), linear-gradient(30deg, transparent 70%, rgba(251, 146, 60, 0.1) 100%)' }, // Warm orange accents\r\n]\r\n\r\n/**\r\n * Type guard to check if a node is a WorkspaceSplit.\r\n * @param node - The node to check\r\n * @returns True if the node is a WorkspaceSplit\r\n */\r\nexport function isWorkspaceSplit(node: WorkspacePane | WorkspaceSplit): node is WorkspaceSplit {\r\n return 'orientation' in node && 'children' in node\r\n}\r\n\r\n/**\r\n * Creates a new pane with default configuration.\r\n * @returns A new WorkspacePane with generated UUID and empty settings\r\n */\r\nexport function createDefaultPane(): WorkspacePane {\r\n return {\r\n id: generateUUID(),\r\n profileId: '',\r\n cwd: '',\r\n startupCommand: '',\r\n }\r\n}\r\n\r\n/**\r\n * Creates a new split with two default panes.\r\n * @param orientation - Split direction ('horizontal' or 'vertical'), defaults to 'horizontal'\r\n * @returns A new WorkspaceSplit with two panes at 50/50 ratio\r\n */\r\nexport function createDefaultSplit(orientation: 'horizontal' | 'vertical' = 'horizontal'): WorkspaceSplit {\r\n return {\r\n orientation,\r\n ratios: [0.5, 0.5],\r\n children: [createDefaultPane(), createDefaultPane()],\r\n }\r\n}\r\n\r\n// Color palette for workspaces\r\nconst WORKSPACE_COLORS = [\r\n '#3b82f6', // blue\r\n '#10b981', // emerald\r\n '#f59e0b', // amber\r\n '#ef4444', // red\r\n '#8b5cf6', // violet\r\n '#ec4899', // pink\r\n '#06b6d4', // cyan\r\n '#f97316', // orange\r\n]\r\n\r\n// Icon list for workspaces\r\nconst WORKSPACE_ICONS = [\r\n 'columns', 'terminal', 'code', 'folder', 'home', 'briefcase',\r\n 'cog', 'database', 'server', 'cloud', 'rocket', 'flask',\r\n 'bug', 'wrench', 'cube', 'layer-group', 'sitemap', 'project-diagram'\r\n]\r\n\r\n/** Returns a random color from the workspace color palette. */\r\nexport function getRandomColor(): string {\r\n return WORKSPACE_COLORS[Math.floor(Math.random() * WORKSPACE_COLORS.length)]\r\n}\r\n\r\n/** Returns a random icon from the workspace icon set. */\r\nexport function getRandomIcon(): string {\r\n return WORKSPACE_ICONS[Math.floor(Math.random() * WORKSPACE_ICONS.length)]\r\n}\r\n\r\n/**\r\n * Creates a new workspace with default configuration.\r\n * @param name - Display name for the workspace (optional)\r\n * @returns A new Workspace with generated UUID, random icon/color, and a default split\r\n */\r\nexport function createDefaultWorkspace(name: string = ''): Workspace {\r\n return {\r\n id: generateUUID(),\r\n name,\r\n icon: getRandomIcon(),\r\n color: getRandomColor(),\r\n root: createDefaultSplit(),\r\n launchOnStartup: false,\r\n }\r\n}\r\n\r\n/** Generates a random UUID v4 string. */\r\nexport function generateUUID(): string {\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0\r\n const v = c === 'x' ? r : (r & 0x3) | 0x8\r\n return v.toString(16)\r\n })\r\n}\r\n\r\n/**\r\n * Recursively counts the total number of panes in a split tree.\r\n * @param node - The root node to count from\r\n * @returns Total number of panes in the tree\r\n */\r\nexport function countPanes(node: WorkspacePane | WorkspaceSplit): number {\r\n if (isWorkspaceSplit(node)) {\r\n return node.children.reduce((sum, child) => sum + countPanes(child), 0)\r\n }\r\n return 1\r\n}\r\n\r\n/**\r\n * Creates a deep clone of an object, preserving type information.\r\n * More efficient than JSON.parse(JSON.stringify()) for simple objects.\r\n * @param obj - The object to clone\r\n * @returns A deep copy of the object\r\n */\r\nexport function deepClone<T>(obj: T): T {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj\r\n }\r\n if (Array.isArray(obj)) {\r\n return obj.map(item => deepClone(item)) as T\r\n }\r\n const cloned = {} as T\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n cloned[key] = deepClone(obj[key])\r\n }\r\n }\r\n return cloned\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { ConfigService, NotificationsService, ProfilesService } from 'tabby-core'\r\nimport {\r\n Workspace,\r\n WorkspacePane,\r\n WorkspaceSplit,\r\n isWorkspaceSplit,\r\n generateUUID,\r\n deepClone,\r\n TabbyProfile,\r\n TabbyRecoveryToken,\r\n TabbySplitLayoutProfile,\r\n} from '../models/workspace.model'\r\nimport { CONFIG_KEY, DISPLAY_NAME } from '../build-config'\r\nimport { PendingCommand } from './startupCommand.service'\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class WorkspaceEditorService {\r\n private cachedProfiles: TabbyProfile[] | null = null\r\n private cacheTimestamp: number = 0\r\n private readonly CACHE_TTL = 30000 // 30 seconds\r\n\r\n constructor(\r\n private config: ConfigService,\r\n private notifications: NotificationsService,\r\n private profilesService: ProfilesService\r\n ) {}\r\n\r\n private async getCachedProfiles(): Promise<TabbyProfile[]> {\r\n const now = Date.now()\r\n if (!this.cachedProfiles || now - this.cacheTimestamp > this.CACHE_TTL) {\r\n this.cachedProfiles = (await this.profilesService.getProfiles()) as TabbyProfile[]\r\n this.cacheTimestamp = now\r\n }\r\n return this.cachedProfiles\r\n }\r\n\r\n /** Returns all saved workspaces from config. */\r\n getWorkspaces(): Workspace[] {\r\n return this.config.store?.[CONFIG_KEY]?.workspaces ?? []\r\n }\r\n\r\n /**\r\n * Saves the workspace list to config.\r\n * @throws Error if config store is not initialized\r\n */\r\n async saveWorkspaces(workspaces: Workspace[]): Promise<void> {\r\n if (!this.config.store?.[CONFIG_KEY]) {\r\n throw new Error('Config store not initialized')\r\n }\r\n this.config.store[CONFIG_KEY].workspaces = workspaces\r\n await this.saveConfig()\r\n }\r\n\r\n /** Adds a new workspace and shows notification. */\r\n async addWorkspace(workspace: Workspace): Promise<void> {\r\n try {\r\n const workspaces = this.getWorkspaces()\r\n workspaces.push(workspace)\r\n await this.saveWorkspaces(workspaces)\r\n this.notifications.info(`Workspace \"${workspace.name}\" created`)\r\n } catch (error) {\r\n this.notifications.error(`Failed to create workspace \"${workspace.name}\"`)\r\n throw error\r\n }\r\n }\r\n\r\n /** Updates an existing workspace by ID and shows notification. */\r\n async updateWorkspace(workspace: Workspace): Promise<void> {\r\n try {\r\n const workspaces = this.getWorkspaces()\r\n const index = workspaces.findIndex((w) => w.id === workspace.id)\r\n if (index !== -1) {\r\n workspaces[index] = workspace\r\n await this.saveWorkspaces(workspaces)\r\n this.notifications.info(`Workspace \"${workspace.name}\" updated`)\r\n }\r\n } catch (error) {\r\n this.notifications.error(`Failed to update workspace \"${workspace.name}\"`)\r\n throw error\r\n }\r\n }\r\n\r\n /** Deletes a workspace by ID and shows notification. */\r\n async deleteWorkspace(workspaceId: string): Promise<void> {\r\n const workspaces = this.getWorkspaces()\r\n const workspace = workspaces.find((w) => w.id === workspaceId)\r\n try {\r\n const filtered = workspaces.filter((w) => w.id !== workspaceId)\r\n await this.saveWorkspaces(filtered)\r\n if (workspace) {\r\n this.notifications.info(`Workspace \"${workspace.name}\" deleted`)\r\n }\r\n } catch (error) {\r\n this.notifications.error(`Failed to delete workspace \"${workspace?.name || workspaceId}\"`)\r\n throw error\r\n }\r\n }\r\n\r\n /** Returns all local shell profiles available for use in workspaces. */\r\n async getAvailableProfiles(): Promise<TabbyProfile[]> {\r\n const allProfiles = await this.profilesService.getProfiles()\r\n return allProfiles.filter(\r\n (p) =>\r\n (p.type === 'local' || p.type?.startsWith('local:')) &&\r\n !p.id?.startsWith('split-layout:')\r\n ) as TabbyProfile[]\r\n }\r\n\r\n /**\r\n * Cleanup orphaned profiles from previous plugin versions.\r\n * Call this once on plugin init.\r\n */\r\n cleanupOrphanedProfiles(): void {\r\n if (!this.config.store?.profiles) {\r\n return\r\n }\r\n const profiles: TabbyProfile[] = this.config.store.profiles\r\n const prefix = `split-layout:${CONFIG_KEY}:`\r\n const filtered = profiles.filter((p) => !p.id?.startsWith(prefix))\r\n if (filtered.length !== profiles.length) {\r\n this.config.store.profiles = filtered\r\n this.config.save()\r\n console.log(`[${DISPLAY_NAME}] Cleaned up ${profiles.length - filtered.length} orphaned profiles`)\r\n }\r\n }\r\n\r\n /** Generates a Tabby split-layout profile from a workspace for opening. */\r\n async generateTabbyProfile(workspace: Workspace): Promise<TabbySplitLayoutProfile> {\r\n await this.getCachedProfiles()\r\n const safeName = this.sanitizeForProfileId(workspace.name)\r\n return {\r\n id: `split-layout:${CONFIG_KEY}:${safeName}:${workspace.id}`,\r\n type: 'split-layout',\r\n name: workspace.name,\r\n group: DISPLAY_NAME,\r\n icon: workspace.icon,\r\n color: workspace.color,\r\n isBuiltin: false,\r\n options: {\r\n recoveryToken: this.generateRecoveryToken(workspace.root, workspace.name, workspace.id),\r\n },\r\n }\r\n }\r\n\r\n private generateRecoveryToken(split: WorkspaceSplit, workspaceName: string, workspaceId: string): TabbyRecoveryToken {\r\n return {\r\n type: 'app:split-tab',\r\n orientation: split.orientation === 'horizontal' ? 'h' : 'v',\r\n ratios: split.ratios,\r\n workspaceId,\r\n children: split.children.map((child) => {\r\n if (isWorkspaceSplit(child)) {\r\n return this.generateRecoveryToken(child, workspaceName, workspaceId)\r\n }\r\n return this.generatePaneToken(child, workspaceName, workspaceId)\r\n }),\r\n }\r\n }\r\n\r\n private generatePaneToken(pane: WorkspacePane, workspaceName: string, workspaceId: string): TabbyRecoveryToken {\r\n const baseProfile = this.getProfileById(pane.profileId)\r\n\r\n if (!baseProfile) {\r\n return {\r\n type: 'app:local-tab',\r\n profile: {\r\n type: 'local',\r\n name: 'Shell',\r\n },\r\n savedState: false,\r\n }\r\n }\r\n\r\n // Build complete profile object like Tabby expects\r\n const options = {\r\n restoreFromPTYID: false,\r\n command: baseProfile.options?.command || '',\r\n args: baseProfile.options?.args || [],\r\n cwd: pane.cwd || baseProfile.options?.cwd || '',\r\n env: baseProfile.options?.env || {},\r\n width: null,\r\n height: null,\r\n pauseAfterExit: false,\r\n runAsAdministrator: false,\r\n }\r\n\r\n // Note: startupCommand is handled via sendInput() in StartupCommandService\r\n // to avoid re-execution when Tabby splits the pane\r\n\r\n const profile = {\r\n id: baseProfile.id,\r\n type: 'local',\r\n name: baseProfile.name || 'Shell',\r\n group: baseProfile.group || '',\r\n options,\r\n icon: baseProfile.icon || '',\r\n color: baseProfile.color || '',\r\n disableDynamicTitle: true,\r\n weight: 0,\r\n isBuiltin: false,\r\n isTemplate: false,\r\n terminalColorScheme: null,\r\n behaviorOnSessionEnd: 'auto',\r\n }\r\n\r\n // tabTitle: workspace name (what user sees)\r\n // tabCustomTitle: pane.id (for matching in StartupCommandService)\r\n // workspaceId: for duplicate detection after Tabby recovery\r\n const cwd = pane.cwd || baseProfile.options?.cwd || ''\r\n return {\r\n type: 'app:local-tab',\r\n profile,\r\n savedState: false,\r\n tabTitle: workspaceName,\r\n tabCustomTitle: pane.id,\r\n workspaceId,\r\n disableDynamicTitle: true,\r\n cwd,\r\n }\r\n }\r\n\r\n /** Creates a deep copy of a workspace with new IDs. */\r\n duplicateWorkspace(workspace: Workspace): Workspace {\r\n const clone = deepClone(workspace)\r\n clone.id = generateUUID()\r\n clone.name = `${workspace.name} (Copy)`\r\n clone.launchOnStartup = false\r\n this.regenerateIds(clone.root)\r\n return clone\r\n }\r\n\r\n private regenerateIds(node: WorkspacePane | WorkspaceSplit): void {\r\n if (isWorkspaceSplit(node)) {\r\n for (const child of node.children) {\r\n this.regenerateIds(child)\r\n }\r\n } else {\r\n node.id = generateUUID()\r\n }\r\n }\r\n\r\n private sanitizeForProfileId(name: string): string {\r\n return name\r\n .toLowerCase()\r\n .replace(/[^a-z0-9-]/g, '-')\r\n .replace(/-+/g, '-')\r\n .replace(/^-|-$/g, '')\r\n || 'workspace'\r\n }\r\n\r\n private getProfileById(profileId: string): TabbyProfile | undefined {\r\n const isLocalType = (type: string) => type === 'local' || type?.startsWith('local:')\r\n\r\n // First: check user profiles in config\r\n const userProfiles: TabbyProfile[] = this.config.store?.profiles ?? []\r\n const found = userProfiles.find((p) => p.id === profileId && isLocalType(p.type))\r\n if (found) return found\r\n\r\n // Fallback: check cached profiles (includes built-ins)\r\n return this.cachedProfiles?.find((p) => p.id === profileId && isLocalType(p.type))\r\n }\r\n\r\n /** Collects all startup commands from panes in a workspace. */\r\n collectStartupCommands(workspace: Workspace): PendingCommand[] {\r\n const commands: PendingCommand[] = []\r\n this.collectCommandsFromNode(workspace.root, workspace.name, commands)\r\n return commands\r\n }\r\n\r\n private collectCommandsFromNode(\r\n node: WorkspacePane | WorkspaceSplit,\r\n workspaceName: string,\r\n commands: PendingCommand[]\r\n ): void {\r\n if (isWorkspaceSplit(node)) {\r\n for (const child of node.children) {\r\n this.collectCommandsFromNode(child, workspaceName, commands)\r\n }\r\n } else if (node.startupCommand) {\r\n commands.push({\r\n paneId: node.id,\r\n command: node.startupCommand,\r\n originalTitle: workspaceName,\r\n })\r\n }\r\n }\r\n\r\n private async saveConfig(): Promise<void> {\r\n try {\r\n await this.config.save()\r\n } catch (error) {\r\n console.error('TabbySpaces save error:', error)\r\n throw error\r\n }\r\n }\r\n}\r\n","import { Component, Input } from '@angular/core'\r\nimport { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'\r\n\r\n@Component({\r\n selector: 'delete-confirm-modal',\r\n template: `\r\n <div class=\"modal-header\">\r\n <h5 class=\"modal-title\">Delete Workspace</h5>\r\n </div>\r\n <div class=\"modal-body\">\r\n <p>Delete workspace \"{{ workspaceName }}\"?</p>\r\n <p class=\"text-muted\">This action cannot be undone.</p>\r\n </div>\r\n <div class=\"modal-footer\">\r\n <button class=\"btn btn-secondary\" (click)=\"modal.dismiss()\">Cancel</button>\r\n <button class=\"btn btn-danger\" (click)=\"modal.close()\" ngbAutofocus>Delete</button>\r\n </div>\r\n `,\r\n})\r\nexport class DeleteConfirmModalComponent {\r\n @Input() workspaceName = ''\r\n constructor(public modal: NgbActiveModal) {}\r\n}\r\n","import { Component, OnInit, OnDestroy, AfterViewInit, ChangeDetectorRef, ElementRef, NgZone } from '@angular/core'\r\nimport { NgbModal } from '@ng-bootstrap/ng-bootstrap'\r\nimport { ConfigService, ProfilesService } from 'tabby-core'\r\nimport { Subscription } from 'rxjs'\r\nimport { StartupCommandService } from '../services/startupCommand.service'\r\nimport { WorkspaceEditorService } from '../services/workspaceEditor.service'\r\nimport { DeleteConfirmModalComponent } from './deleteConfirmModal.component'\r\nimport {\r\n Workspace,\r\n WorkspacePane,\r\n WorkspaceSplit,\r\n TabbyProfile,\r\n countPanes,\r\n createDefaultWorkspace,\r\n deepClone,\r\n isWorkspaceSplit,\r\n} from '../models/workspace.model'\r\n\r\nconst SETTINGS_MAX_WIDTH = '876px'\r\n\r\n@Component({\r\n selector: 'workspace-list',\r\n template: require('./workspaceList.component.pug'),\r\n styles: [require('./workspaceList.component.scss')],\r\n})\r\nexport class WorkspaceListComponent implements OnInit, OnDestroy, AfterViewInit {\r\n workspaces: Workspace[] = []\r\n selectedWorkspace: Workspace | null = null\r\n editingWorkspace: Workspace | null = null\r\n isCreatingNew = false\r\n openingWorkspaceId: string | null = null\r\n displayTabs: Array<{ workspace: Workspace; isNew: boolean }> = []\r\n private cachedProfiles: TabbyProfile[] = []\r\n private configSubscription: Subscription | null = null\r\n\r\n constructor(\r\n public config: ConfigService,\r\n private workspaceService: WorkspaceEditorService,\r\n private profilesService: ProfilesService,\r\n private startupService: StartupCommandService,\r\n private modalService: NgbModal,\r\n private cdr: ChangeDetectorRef,\r\n private elementRef: ElementRef,\r\n private zone: NgZone\r\n ) {}\r\n\r\n async ngOnInit(): Promise<void> {\r\n this.loadWorkspaces()\r\n this.autoSelectFirst()\r\n this.cachedProfiles = await this.workspaceService.getAvailableProfiles()\r\n this.configSubscription = this.config.changed$.subscribe(() => {\r\n this.zone.run(() => this.loadWorkspaces())\r\n })\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n // Hack: Override Tabby's settings-tab-body max-width restriction\r\n setTimeout(() => {\r\n const parent = this.elementRef.nativeElement.closest('settings-tab-body') as HTMLElement\r\n if (parent) {\r\n parent.style.maxWidth = SETTINGS_MAX_WIDTH\r\n }\r\n }, 0)\r\n }\r\n\r\n private autoSelectFirst(): void {\r\n if (this.workspaces.length > 0 && !this.selectedWorkspace) {\r\n this.selectWorkspace(this.workspaces[0])\r\n }\r\n }\r\n\r\n selectWorkspace(workspace: Workspace): void {\r\n this.isCreatingNew = false\r\n this.selectedWorkspace = workspace\r\n this.editingWorkspace = deepClone(workspace)\r\n this.updateDisplayTabs()\r\n }\r\n\r\n isSelected(workspace: Workspace): boolean {\r\n return this.selectedWorkspace?.id === workspace.id\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.configSubscription?.unsubscribe()\r\n }\r\n\r\n loadWorkspaces(): void {\r\n const previousSelectedId = this.selectedWorkspace?.id\r\n this.workspaces = this.workspaceService.getWorkspaces()\r\n\r\n // Re-sync selectedWorkspace to point to object in new array\r\n // This prevents stale reference after delete/reload operations\r\n if (previousSelectedId) {\r\n this.selectedWorkspace = this.workspaces.find(w => w.id === previousSelectedId) || null\r\n }\r\n\r\n this.updateDisplayTabs()\r\n }\r\n\r\n createWorkspace(): void {\r\n const defaultProfileId = this.cachedProfiles[0]?.id || ''\r\n const workspace = createDefaultWorkspace()\r\n this.setProfileForAllPanes(workspace.root, defaultProfileId)\r\n this.selectedWorkspace = null\r\n this.editingWorkspace = workspace\r\n this.isCreatingNew = true\r\n this.updateDisplayTabs()\r\n this.cdr.detectChanges()\r\n }\r\n\r\n private setProfileForAllPanes(node: WorkspacePane | WorkspaceSplit, profileId: string): void {\r\n if (isWorkspaceSplit(node)) {\r\n node.children.forEach((child) => this.setProfileForAllPanes(child, profileId))\r\n } else {\r\n node.profileId = profileId\r\n }\r\n }\r\n\r\n editWorkspace(workspace: Workspace): void {\r\n this.selectWorkspace(workspace)\r\n }\r\n\r\n async duplicateWorkspace(event: MouseEvent, workspace: Workspace): Promise<void> {\r\n event.stopPropagation()\r\n const clone = this.workspaceService.duplicateWorkspace(workspace)\r\n await this.workspaceService.addWorkspace(clone)\r\n\r\n this.zone.run(() => {\r\n this.loadWorkspaces()\r\n const duplicated = this.workspaces.find((w) => w.id === clone.id)\r\n if (duplicated) {\r\n this.selectWorkspace(duplicated)\r\n }\r\n })\r\n }\r\n\r\n async deleteWorkspace(event: MouseEvent, workspace: Workspace): Promise<void> {\r\n event.stopPropagation()\r\n\r\n const confirmed = await this.confirmDelete(workspace.name)\r\n if (!confirmed) return\r\n\r\n const wasSelected = this.selectedWorkspace?.id === workspace.id\r\n const deletedIndex = this.workspaces.findIndex((w) => w.id === workspace.id)\r\n\r\n await this.workspaceService.deleteWorkspace(workspace.id)\r\n\r\n this.zone.run(() => {\r\n this.loadWorkspaces()\r\n if (this.workspaces.length === 0) {\r\n this.selectedWorkspace = null\r\n this.editingWorkspace = null\r\n this.isCreatingNew = false\r\n } else if (wasSelected) {\r\n const nextIndex = Math.min(deletedIndex, this.workspaces.length - 1)\r\n this.selectWorkspace(this.workspaces[nextIndex])\r\n }\r\n })\r\n }\r\n\r\n private async confirmDelete(name: string): Promise<boolean> {\r\n const modalRef = this.modalService.open(DeleteConfirmModalComponent)\r\n modalRef.componentInstance.workspaceName = name\r\n try {\r\n await modalRef.result\r\n return true\r\n } catch {\r\n return false\r\n }\r\n }\r\n\r\n async onEditorSave(workspace: Workspace): Promise<void> {\r\n const isNew = !this.workspaces.find((w) => w.id === workspace.id)\r\n if (isNew) {\r\n await this.workspaceService.addWorkspace(workspace)\r\n } else {\r\n await this.workspaceService.updateWorkspace(workspace)\r\n }\r\n\r\n // Wrap state changes in zone.run to ensure proper change detection\r\n this.zone.run(() => {\r\n this.loadWorkspaces()\r\n this.isCreatingNew = false\r\n const saved = this.workspaces.find((w) => w.id === workspace.id)\r\n if (saved) {\r\n this.selectWorkspace(saved)\r\n }\r\n })\r\n }\r\n\r\n onEditorCancel(): void {\r\n if (this.isCreatingNew) {\r\n // Cancel new workspace creation - go back to first workspace or empty\r\n this.isCreatingNew = false\r\n if (this.workspaces.length > 0) {\r\n this.selectWorkspace(this.workspaces[0])\r\n } else {\r\n this.selectedWorkspace = null\r\n this.editingWorkspace = null\r\n this.updateDisplayTabs()\r\n }\r\n } else if (this.selectedWorkspace) {\r\n // Reset to original workspace data\r\n this.editingWorkspace = deepClone(this.selectedWorkspace)\r\n }\r\n this.cdr.detectChanges()\r\n }\r\n\r\n getPaneCount(workspace: Workspace): number {\r\n return countPanes(workspace.root)\r\n }\r\n\r\n getOrientationLabel(workspace: Workspace): string {\r\n return workspace.root.orientation === 'horizontal' ? 'horizontal' : 'vertical'\r\n }\r\n\r\n get hasUnsavedChanges(): boolean {\r\n if (!this.editingWorkspace || !this.selectedWorkspace) return this.isCreatingNew\r\n return JSON.stringify(this.editingWorkspace) !== JSON.stringify(this.selectedWorkspace)\r\n }\r\n\r\n // Update display tabs array (call after state changes)\r\n private updateDisplayTabs(): void {\r\n const tabs = this.workspaces.map(w => ({ workspace: w, isNew: false }))\r\n if (this.isCreatingNew && this.editingWorkspace) {\r\n tabs.push({ workspace: this.editingWorkspace, isNew: true })\r\n }\r\n this.displayTabs = tabs\r\n }\r\n\r\n isTabSelected(tab: { workspace: Workspace; isNew: boolean }): boolean {\r\n if (tab.isNew) return true\r\n return this.selectedWorkspace?.id === tab.workspace.id\r\n }\r\n\r\n trackByTab(index: number, tab: { workspace: Workspace; isNew: boolean }): string {\r\n return tab.isNew ? '__new__' : tab.workspace.id\r\n }\r\n\r\n async openWorkspace(event: MouseEvent, workspace: Workspace): Promise<void> {\r\n event.stopPropagation()\r\n if (this.openingWorkspaceId) return\r\n this.openingWorkspaceId = workspace.id\r\n\r\n try {\r\n const commands = this.workspaceService.collectStartupCommands(workspace)\r\n if (commands.length > 0) {\r\n this.startupService.registerCommands(commands)\r\n }\r\n\r\n const profile = await this.workspaceService.generateTabbyProfile(workspace)\r\n this.zone.run(() => {\r\n this.profilesService.openNewTabForProfile(profile)\r\n })\r\n } finally {\r\n this.openingWorkspaceId = null\r\n this.cdr.detectChanges()\r\n }\r\n }\r\n\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { SettingsTabProvider } from 'tabby-settings'\r\nimport { WorkspaceListComponent } from '../components/workspaceList.component'\r\nimport { CONFIG_KEY, DISPLAY_NAME, IS_DEV } from '../build-config'\r\n\r\n@Injectable()\r\nexport class WorkspaceEditorSettingsProvider extends SettingsTabProvider {\r\n id = CONFIG_KEY\r\n icon = IS_DEV ? 'bolt' : 'th-large'\r\n title = DISPLAY_NAME\r\n\r\n getComponentType(): any {\r\n return WorkspaceListComponent\r\n }\r\n}\r\n","import { Injectable } from '@angular/core'\r\nimport { AppService, SplitTabComponent } from 'tabby-core'\r\nimport { WorkspaceEditorService } from './workspaceEditor.service'\r\nimport { WorkspaceBackground } from '../models/workspace.model'\r\nimport { CONFIG_KEY } from '../build-config'\r\n\r\n/**\r\n * Service for applying custom backgrounds to workspace tabs.\r\n * Injects CSS dynamically based on workspace configuration.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class WorkspaceBackgroundService {\r\n private styleElement: HTMLStyleElement | null = null\r\n private appliedWorkspaces = new Map<string, string>() // workspaceId -> CSS\r\n\r\n constructor(\r\n private app: AppService,\r\n private workspaceService: WorkspaceEditorService\r\n ) {}\r\n\r\n /**\r\n * Initialize the service by setting up tab event listeners.\r\n * Must be called once during app initialization.\r\n */\r\n initialize(): void {\r\n this.setupTabListeners()\r\n }\r\n\r\n private setupTabListeners(): void {\r\n // Listen for tab open\r\n this.app.tabOpened$.subscribe(tab => this.onTabOpened(tab))\r\n\r\n // Listen for tab close - cleanup\r\n this.app.tabClosed$.subscribe(tab => this.onTabClosed(tab))\r\n }\r\n\r\n private onTabOpened(tab: unknown): void {\r\n if (!(tab instanceof SplitTabComponent)) return\r\n\r\n // Small delay to let Angular finish rendering\r\n setTimeout(() => {\r\n const workspaceId = this.extractWorkspaceId(tab)\r\n if (!workspaceId) return\r\n\r\n const workspace = this.workspaceService.getWorkspaces()\r\n .find(w => w.id === workspaceId)\r\n\r\n if (workspace?.background && workspace.background.type !== 'none') {\r\n this.applyBackground(workspaceId, workspace.background)\r\n }\r\n }, 200)\r\n }\r\n\r\n private onTabClosed(tab: unknown): void {\r\n if (!(tab instanceof SplitTabComponent)) return\r\n\r\n const workspaceId = this.extractWorkspaceId(tab)\r\n if (workspaceId) {\r\n this.removeBackground(workspaceId)\r\n }\r\n }\r\n\r\n /**\r\n * Extract workspace ID from a SplitTabComponent.\r\n * Tries multiple strategies: _recoveredState and child profile ID.\r\n */\r\n private extractWorkspaceId(tab: SplitTabComponent): string | undefined {\r\n const tabAny = tab as any\r\n\r\n // Strategy 1: Check _recoveredState.workspaceId (for restored tabs)\r\n if (tabAny._recoveredState?.workspaceId) {\r\n return tabAny._recoveredState.workspaceId\r\n }\r\n\r\n // Strategy 2: Extract from child profile ID (for freshly opened tabs)\r\n const profilePrefix = `split-layout:${CONFIG_KEY}:`\r\n for (const child of tab.getAllTabs()) {\r\n const profileId = (child as any).profile?.id ?? ''\r\n if (profileId.startsWith(profilePrefix)) {\r\n // Profile ID format: split-layout:CONFIG_KEY:name:UUID\r\n const parts = profileId.split(':')\r\n return parts[parts.length - 1]\r\n }\r\n }\r\n\r\n return undefined\r\n }\r\n\r\n private applyBackground(workspaceId: string, bg: WorkspaceBackground): void {\r\n // Mark split-tab element with data attribute\r\n this.markSplitTabElement(workspaceId)\r\n\r\n // Generate and inject CSS\r\n const css = this.generateCSS(workspaceId, bg)\r\n this.injectCSS(workspaceId, css)\r\n }\r\n\r\n private markSplitTabElement(workspaceId: string): void {\r\n // Find split-tab that doesn't have a workspace-id yet\r\n const splitTabs = document.querySelectorAll('split-tab')\r\n for (let i = splitTabs.length - 1; i >= 0; i--) {\r\n const splitTab = splitTabs[i]\r\n if (!splitTab.hasAttribute('data-workspace-id')) {\r\n splitTab.setAttribute('data-workspace-id', workspaceId)\r\n break\r\n }\r\n }\r\n }\r\n\r\n private generateCSS(workspaceId: string, bg: WorkspaceBackground): string {\r\n if (bg.type === 'none' || !bg.value) return ''\r\n\r\n return `\r\n split-tab[data-workspace-id=\"${workspaceId}\"] {\r\n background: ${bg.value} !important;\r\n }\r\n split-tab[data-workspace-id=\"${workspaceId}\"] .xterm-viewport,\r\n split-tab[data-workspace-id=\"${workspaceId}\"] .xterm-screen {\r\n background: transparent !important;\r\n }\r\n `\r\n }\r\n\r\n private injectCSS(workspaceId: string, css: string): void {\r\n if (!this.styleElement) {\r\n this.styleElement = document.createElement('style')\r\n this.styleElement.id = 'tabbyspaces-backgrounds'\r\n document.head.appendChild(this.styleElement)\r\n }\r\n\r\n this.appliedWorkspaces.set(workspaceId, css)\r\n this.updateStyleElement()\r\n }\r\n\r\n private removeBackground(workspaceId: string): void {\r\n this.appliedWorkspaces.delete(workspaceId)\r\n this.updateStyleElement()\r\n }\r\n\r\n private updateStyleElement(): void {\r\n if (this.styleElement) {\r\n this.styleElement.textContent = Array.from(this.appliedWorkspaces.values()).join('\\n')\r\n }\r\n }\r\n\r\n /**\r\n * Refresh background for a specific workspace.\r\n * Call this when workspace background is updated in settings.\r\n */\r\n refreshWorkspaceBackground(workspaceId: string): void {\r\n const workspace = this.workspaceService.getWorkspaces()\r\n .find(w => w.id === workspaceId)\r\n\r\n if (!workspace) {\r\n this.removeBackground(workspaceId)\r\n return\r\n }\r\n\r\n if (workspace.background && workspace.background.type !== 'none') {\r\n const css = this.generateCSS(workspaceId, workspace.background)\r\n this.appliedWorkspaces.set(workspaceId, css)\r\n } else {\r\n this.appliedWorkspaces.delete(workspaceId)\r\n }\r\n this.updateStyleElement()\r\n }\r\n}\r\n","import { Injectable } from '@angular/core'\nimport { ToolbarButtonProvider, ToolbarButton, ProfilesService, AppService, SplitTabComponent } from 'tabby-core'\nimport { BaseTerminalTabComponent } from 'tabby-terminal'\nimport { WorkspaceEditorService } from '../services/workspaceEditor.service'\nimport { StartupCommandService } from '../services/startupCommand.service'\nimport { WorkspaceBackgroundService } from '../services/workspaceBackground.service'\nimport { SettingsTabComponent } from 'tabby-settings'\nimport { CONFIG_KEY, DISPLAY_NAME, IS_DEV } from '../build-config'\n\nconst ICON_GRID = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <rect x=\"3\" y=\"3\" width=\"7\" height=\"7\"/>\n <rect x=\"14\" y=\"3\" width=\"7\" height=\"7\"/>\n <rect x=\"14\" y=\"14\" width=\"7\" height=\"7\"/>\n <rect x=\"3\" y=\"14\" width=\"7\" height=\"7\"/>\n</svg>`\n\nconst ICON_BOLT = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polygon points=\"13 2 3 14 12 14 11 22 21 10 12 10 13 2\"/>\n</svg>`\n\nconst SELECTOR_SETTINGS_ID = '__settings__'\n\nimport { countPanes } from '../models/workspace.model'\n\n/** Recovery token structure for workspace tabs */\ninterface RecoveryTokenWithWorkspace {\n workspaceId?: string\n}\n\n@Injectable()\nexport class WorkspaceToolbarProvider extends ToolbarButtonProvider {\n constructor(\n private workspaceService: WorkspaceEditorService,\n private profilesService: ProfilesService,\n private app: AppService,\n private startupService: StartupCommandService,\n private backgroundService: WorkspaceBackgroundService\n ) {\n super()\n // Initialize background service to listen for tab events\n this.backgroundService.initialize()\n\n // Wait for Tabby to finish recovery before launching startup workspaces\n this.waitForTabbyReady().then(() => {\n this.workspaceService.cleanupOrphanedProfiles()\n this.launchStartupWorkspaces()\n })\n }\n\n private waitForTabbyReady(): Promise<void> {\n return new Promise(resolve => {\n let lastTabCount = -1\n const checkStable = () => {\n const currentCount = this.app.tabs.length\n if (currentCount === lastTabCount && currentCount >= 0) {\n resolve()\n } else {\n lastTabCount = currentCount\n setTimeout(checkStable, 300)\n }\n }\n // Initial delay to let Tabby start loading\n setTimeout(checkStable, 500)\n })\n }\n\n private async launchStartupWorkspaces(): Promise<void> {\n const workspaces = this.workspaceService.getWorkspaces()\n const startupWorkspaces = workspaces.filter(w => w.launchOnStartup)\n\n for (const workspace of startupWorkspaces) {\n if (this.isWorkspaceAlreadyOpen(workspace.id)) {\n console.log(`[TabbySpaces] Workspace \"${workspace.name}\" already open, skipping`)\n continue\n }\n await this.openWorkspace(workspace.id)\n }\n }\n\n /**\n * Type-safe helper to extract workspace ID from tab's recovery token.\n */\n private getRecoveryWorkspaceId(tab: unknown): string | undefined {\n if (tab && typeof tab === 'object' && 'recoveryToken' in tab) {\n const token = (tab as { recoveryToken?: RecoveryTokenWithWorkspace }).recoveryToken\n return token?.workspaceId\n }\n return undefined\n }\n\n private isWorkspaceAlreadyOpen(workspaceId: string): boolean {\n const profilePrefix = `split-layout:${CONFIG_KEY}:`\n\n for (const tab of this.app.tabs) {\n if (tab instanceof SplitTabComponent) {\n // Strategy 1: Check recoveryToken.workspaceId (for restored tabs)\n if (this.getRecoveryWorkspaceId(tab) === workspaceId) {\n return true\n }\n\n // Strategy 2: Check profile ID (for freshly opened tabs)\n for (const child of tab.getAllTabs()) {\n if (child instanceof BaseTerminalTabComponent) {\n const profileId = child.profile?.id ?? ''\n // Strict matching: prefix + workspaceId at the end\n if (profileId.startsWith(profilePrefix) && profileId.endsWith(`:${workspaceId}`)) {\n return true\n }\n }\n }\n }\n }\n return false\n }\n\n provide(): ToolbarButton[] {\n return [\n {\n icon: IS_DEV ? ICON_BOLT : ICON_GRID,\n title: DISPLAY_NAME,\n weight: 5,\n click: () => this.showWorkspaceSelector()\n }\n ]\n }\n\n private async showWorkspaceSelector(): Promise<void> {\n const workspaces = this.workspaceService.getWorkspaces()\n\n if (workspaces.length === 0) {\n this.openSettings()\n return\n }\n\n const options = workspaces.map((ws) => ({\n name: ws.name,\n description: `${countPanes(ws.root)} panes`,\n icon: ws.icon || 'grid',\n color: ws.color,\n result: ws.id\n }))\n\n // Add option to open settings\n options.push({\n name: 'Manage Workspaces...',\n description: 'Create and edit workspaces',\n icon: 'cog',\n color: undefined,\n result: SELECTOR_SETTINGS_ID\n })\n\n const selectedId = await this.app.showSelector('Select Workspace', options)\n\n if (selectedId === SELECTOR_SETTINGS_ID) {\n this.openSettings()\n } else if (selectedId) {\n this.openWorkspace(selectedId)\n }\n }\n\n private openSettings(): void {\n this.app.openNewTabRaw({ type: SettingsTabComponent, inputs: { activeTab: CONFIG_KEY } })\n }\n\n private async openWorkspace(workspaceId: string): Promise<void> {\n const workspaces = this.workspaceService.getWorkspaces()\n const workspace = workspaces.find((w) => w.id === workspaceId)\n\n if (!workspace) return\n\n // Register startup commands BEFORE opening the workspace\n // Commands will be sent via sendInput() when terminals open\n const commands = this.workspaceService.collectStartupCommands(workspace)\n if (commands.length > 0) {\n this.startupService.registerCommands(commands)\n }\n\n const profile = await this.workspaceService.generateTabbyProfile(workspace)\n this.profilesService.openNewTabForProfile(profile)\n }\n}\n","import { Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, SimpleChanges, HostListener, ElementRef, ViewChild, ChangeDetectorRef } from '@angular/core'\r\nimport {\r\n Workspace,\r\n WorkspacePane,\r\n WorkspaceSplit,\r\n WorkspaceBackground,\r\n TabbyProfile,\r\n isWorkspaceSplit,\r\n createDefaultPane,\r\n generateUUID,\r\n BACKGROUND_PRESETS,\r\n} from '../models/workspace.model'\r\n\r\ninterface TreeContext {\r\n node: WorkspaceSplit\r\n index: number\r\n parent: WorkspaceSplit | null\r\n child: WorkspacePane | WorkspaceSplit\r\n}\r\nimport { WorkspaceEditorService } from '../services/workspaceEditor.service'\r\n\r\n@Component({\r\n selector: 'workspace-editor',\r\n template: require('./workspaceEditor.component.pug'),\r\n styles: [require('./workspaceEditor.component.scss')],\r\n})\r\nexport class WorkspaceEditorComponent implements OnInit, OnChanges, AfterViewInit {\r\n @Input() workspace!: Workspace\r\n @Input() autoFocus = false\r\n @Input() hasUnsavedChanges = false\r\n @Output() save = new EventEmitter<Workspace>()\r\n @Output() cancel = new EventEmitter<void>()\r\n\r\n @ViewChild('nameInput') nameInput!: ElementRef<HTMLInputElement>\r\n\r\n selectedPaneId: string | null = null\r\n editingPane: WorkspacePane | null = null\r\n showPaneEditor = false\r\n profiles: TabbyProfile[] = []\r\n availableIcons = [\r\n 'columns', 'terminal', 'code', 'folder', 'home', 'briefcase',\r\n 'cog', 'database', 'server', 'cloud', 'rocket', 'flask',\r\n 'bug', 'wrench', 'cube', 'layer-group', 'sitemap', 'project-diagram'\r\n ]\r\n iconDropdownOpen = false\r\n backgroundPresets = BACKGROUND_PRESETS\r\n backgroundDropdownOpen = false\r\n customBackgroundValue = ''\r\n\r\n constructor(\r\n private workspaceService: WorkspaceEditorService,\r\n private elementRef: ElementRef,\r\n private cdr: ChangeDetectorRef\r\n ) {}\r\n\r\n @HostListener('document:click', ['$event'])\r\n onDocumentClick(event: MouseEvent): void {\r\n // Check if click is outside the icon dropdown area (trigger + dropdown)\r\n const dropdownTrigger = this.elementRef.nativeElement.querySelector('.dropdown-trigger')\r\n const iconDropdown = this.elementRef.nativeElement.querySelector('.icon-dropdown')\r\n const iconClickedInside = dropdownTrigger?.contains(event.target as Node) ||\r\n iconDropdown?.contains(event.target as Node)\r\n if (this.iconDropdownOpen && !iconClickedInside) {\r\n this.iconDropdownOpen = false\r\n }\r\n\r\n // Check if click is outside the background dropdown area\r\n const bgTrigger = this.elementRef.nativeElement.querySelector('.background-trigger')\r\n const bgDropdown = this.elementRef.nativeElement.querySelector('.background-dropdown')\r\n const bgClickedInside = bgTrigger?.contains(event.target as Node) ||\r\n bgDropdown?.contains(event.target as Node)\r\n if (this.backgroundDropdownOpen && !bgClickedInside) {\r\n this.backgroundDropdownOpen = false\r\n }\r\n }\r\n\r\n toggleIconDropdown(): void {\r\n this.iconDropdownOpen = !this.iconDropdownOpen\r\n }\r\n\r\n selectIcon(icon: string): void {\r\n this.workspace.icon = icon\r\n this.iconDropdownOpen = false\r\n }\r\n\r\n toggleBackgroundDropdown(): void {\r\n this.backgroundDropdownOpen = !this.backgroundDropdownOpen\r\n }\r\n\r\n selectBackgroundPreset(preset: WorkspaceBackground): void {\r\n if (preset.type === 'none') {\r\n this.workspace.background = undefined\r\n this.customBackgroundValue = ''\r\n } else {\r\n this.workspace.background = { ...preset }\r\n this.customBackgroundValue = preset.value\r\n }\r\n this.backgroundDropdownOpen = false\r\n }\r\n\r\n applyCustomBackground(): void {\r\n const value = this.customBackgroundValue.trim()\r\n if (value) {\r\n this.workspace.background = {\r\n type: 'gradient',\r\n value\r\n }\r\n } else {\r\n this.workspace.background = undefined\r\n }\r\n }\r\n\r\n clearBackground(): void {\r\n this.workspace.background = undefined\r\n this.customBackgroundValue = ''\r\n }\r\n\r\n isBackgroundSelected(preset: WorkspaceBackground): boolean {\r\n if (preset.type === 'none') {\r\n return !this.workspace.background || this.workspace.background.type === 'none'\r\n }\r\n return this.workspace.background?.value === preset.value\r\n }\r\n\r\n async ngOnInit(): Promise<void> {\r\n this.profiles = await this.workspaceService.getAvailableProfiles()\r\n this.initializeWorkspace()\r\n this.cdr.detectChanges()\r\n }\r\n\r\n ngAfterViewInit(): void {\r\n if (this.autoFocus) {\r\n this.focusNameInput()\r\n }\r\n }\r\n\r\n private focusNameInput(): void {\r\n requestAnimationFrame(() => {\r\n setTimeout(() => {\r\n if (this.nameInput?.nativeElement) {\r\n this.nameInput.nativeElement.focus()\r\n this.nameInput.nativeElement.select()\r\n }\r\n }, 0)\r\n })\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['workspace'] && !changes['workspace'].firstChange) {\r\n const prevId = changes['workspace'].previousValue?.id\r\n const currId = this.workspace.id\r\n\r\n if (prevId !== currId) {\r\n // Different workspace - reset everything and focus name input\r\n this.selectedPaneId = null\r\n this.editingPane = null\r\n this.showPaneEditor = false\r\n this.focusNameInput()\r\n } else {\r\n // Same workspace ID but different reference (after save/reload)\r\n // Re-sync editingPane to point to pane in new object tree\r\n if (this.selectedPaneId && this.showPaneEditor) {\r\n this.editingPane = this.findPaneById(this.selectedPaneId)\r\n }\r\n }\r\n // Always reset dropdowns and sync background value\r\n this.iconDropdownOpen = false\r\n this.backgroundDropdownOpen = false\r\n this.customBackgroundValue = this.workspace.background?.value || ''\r\n this.initializeWorkspace()\r\n }\r\n\r\n // Handle autoFocus change\r\n if (changes['autoFocus']?.currentValue) {\r\n this.focusNameInput()\r\n }\r\n }\r\n\r\n private initializeWorkspace(): void {\r\n if (!this.workspace.root) {\r\n this.workspace.root = {\r\n orientation: 'horizontal',\r\n ratios: [0.5, 0.5],\r\n children: [createDefaultPane(), createDefaultPane()],\r\n }\r\n }\r\n }\r\n\r\n onSave(): void {\r\n if (!this.workspace.name?.trim()) {\r\n return\r\n }\r\n this.save.emit(this.workspace)\r\n }\r\n\r\n onCancel(): void {\r\n this.cancel.emit()\r\n }\r\n\r\n deselectPane(): void {\r\n this.selectedPaneId = null\r\n }\r\n\r\n onPreviewBackgroundClick(): void {\r\n this.deselectPane()\r\n this.closePaneEditor()\r\n }\r\n\r\n editPane(pane: WorkspacePane): void {\r\n this.selectedPaneId = pane.id\r\n this.editingPane = pane\r\n this.showPaneEditor = true\r\n this.cdr.detectChanges()\r\n }\r\n\r\n closePaneEditor(): void {\r\n this.showPaneEditor = false\r\n this.editingPane = null\r\n this.cdr.detectChanges()\r\n }\r\n\r\n // Helper functions\r\n private findPaneById(id: string): WorkspacePane | null {\r\n return this.findPaneInNode(this.workspace.root, id)\r\n }\r\n\r\n private findPaneInNode(node: WorkspaceSplit, id: string): WorkspacePane | null {\r\n for (const child of node.children) {\r\n if (isWorkspaceSplit(child)) {\r\n const found = this.findPaneInNode(child, id)\r\n if (found) return found\r\n } else if (child.id === id) {\r\n return child\r\n }\r\n }\r\n return null\r\n }\r\n\r\n canRemovePane(): boolean {\r\n return this.countPanes(this.workspace.root) > 1\r\n }\r\n\r\n private countPanes(node: WorkspaceSplit): number {\r\n return node.children.reduce((count, child) => {\r\n return count + (isWorkspaceSplit(child) ? this.countPanes(child) : 1)\r\n }, 0)\r\n }\r\n\r\n private walkTree(\r\n node: WorkspaceSplit,\r\n visitor: (ctx: TreeContext) => boolean,\r\n parent: WorkspaceSplit | null = null\r\n ): boolean {\r\n for (let i = 0; i < node.children.length; i++) {\r\n const child = node.children[i]\r\n const ctx: TreeContext = { node, index: i, parent, child }\r\n\r\n if (isWorkspaceSplit(child)) {\r\n if (this.walkTree(child, visitor, node)) return true\r\n } else if (visitor(ctx)) {\r\n return true\r\n }\r\n }\r\n return false\r\n }\r\n\r\n private updatePaneInTree(updatedPane: WorkspacePane): boolean {\r\n return this.walkTree(this.workspace.root, (ctx) => {\r\n if ((ctx.child as WorkspacePane).id === updatedPane.id) {\r\n ctx.node.children[ctx.index] = updatedPane\r\n return true\r\n }\r\n return false\r\n })\r\n }\r\n\r\n splitPane(pane: WorkspacePane, orientation: 'horizontal' | 'vertical'): void {\r\n this.splitPaneInTree(pane, orientation)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n splitSelectedPane(orientation: 'horizontal' | 'vertical'): void {\r\n if (!this.selectedPaneId) return\r\n const pane = this.findPaneById(this.selectedPaneId)\r\n if (pane) this.splitPane(pane, orientation)\r\n }\r\n\r\n private splitPaneInTree(\r\n targetPane: WorkspacePane,\r\n orientation: 'horizontal' | 'vertical'\r\n ): boolean {\r\n return this.walkTree(this.workspace.root, (ctx) => {\r\n if ((ctx.child as WorkspacePane).id === targetPane.id) {\r\n const newPane = createDefaultPane()\r\n newPane.profileId = (ctx.child as WorkspacePane).profileId\r\n const newSplit: WorkspaceSplit = {\r\n orientation,\r\n ratios: [0.5, 0.5],\r\n children: [ctx.child, newPane],\r\n }\r\n ctx.node.children[ctx.index] = newSplit\r\n this.recalculateRatios(ctx.node)\r\n return true\r\n }\r\n return false\r\n })\r\n }\r\n\r\n removePane(pane: WorkspacePane): void {\r\n if (this.selectedPaneId === pane.id) {\r\n this.selectedPaneId = null\r\n }\r\n this.removePaneFromTree(this.workspace.root, pane)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n removeSelectedPane(): void {\r\n if (!this.selectedPaneId || !this.canRemovePane()) return\r\n const pane = this.findPaneById(this.selectedPaneId)\r\n if (pane) this.removePane(pane)\r\n }\r\n\r\n private removePaneFromTree(node: WorkspaceSplit, targetPane: WorkspacePane): boolean {\r\n for (let i = 0; i < node.children.length; i++) {\r\n const child = node.children[i]\r\n if (isWorkspaceSplit(child)) {\r\n // Check if the pane is directly in this split\r\n const paneIndex = child.children.findIndex(\r\n (c) => !isWorkspaceSplit(c) && (c as WorkspacePane).id === targetPane.id\r\n )\r\n if (paneIndex !== -1 && child.children.length > 1) {\r\n child.children.splice(paneIndex, 1)\r\n this.recalculateRatios(child)\r\n // If only one child remains, flatten\r\n if (child.children.length === 1) {\r\n node.children[i] = child.children[0]\r\n }\r\n return true\r\n }\r\n if (this.removePaneFromTree(child, targetPane)) {\r\n return true\r\n }\r\n } else if (child.id === targetPane.id) {\r\n if (node.children.length > 1) {\r\n node.children.splice(i, 1)\r\n this.recalculateRatios(node)\r\n return true\r\n }\r\n }\r\n }\r\n return false\r\n }\r\n\r\n private recalculateRatios(split: WorkspaceSplit): void {\r\n const count = split.children.length\r\n split.ratios = split.children.map(() => 1 / count)\r\n }\r\n\r\n setOrientation(orientation: 'horizontal' | 'vertical'): void {\r\n this.workspace.root.orientation = orientation\r\n this.cdr.detectChanges()\r\n }\r\n\r\n updateRatio(index: number, value: number): void {\r\n const ratios = [...this.workspace.root.ratios]\r\n const diff = value - ratios[index]\r\n\r\n if (index < ratios.length - 1) {\r\n ratios[index] = value\r\n ratios[index + 1] -= diff\r\n } else {\r\n ratios[index] = value\r\n ratios[index - 1] -= diff\r\n }\r\n\r\n // Clamp values\r\n ratios.forEach((r, i) => {\r\n ratios[i] = Math.max(0.1, Math.min(0.9, r))\r\n })\r\n\r\n this.workspace.root.ratios = ratios\r\n this.cdr.detectChanges()\r\n }\r\n\r\n // Add pane operations\r\n addPane(direction: 'left' | 'right' | 'top' | 'bottom'): void {\r\n if (!this.selectedPaneId) return\r\n const pane = this.findPaneById(this.selectedPaneId)\r\n if (!pane) return\r\n this.addPaneInTree(pane, direction)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n addPaneFromEvent(pane: WorkspacePane, direction: 'left' | 'right' | 'top' | 'bottom'): void {\r\n this.addPaneInTree(pane, direction)\r\n this.cdr.detectChanges()\r\n }\r\n\r\n private addPaneInTree(\r\n targetPane: WorkspacePane,\r\n direction: 'left' | 'right' | 'top' | 'bottom'\r\n ): boolean {\r\n const isHorizontalAdd = direction === 'left' || direction === 'right'\r\n const isBefore = direction === 'left' || direction === 'top'\r\n const targetOrientation = isHorizontalAdd ? 'horizontal' : 'vertical'\r\n\r\n return this.walkTree(this.workspace.root, (ctx) => {\r\n if ((ctx.child as WorkspacePane).id !== targetPane.id) return false\r\n\r\n const newPane = createDefaultPane()\r\n newPane.profileId = (ctx.child as WorkspacePane).profileId\r\n\r\n if (ctx.node.orientation === targetOrientation) {\r\n // Same orientation: add as sibling\r\n const insertIndex = isBefore ? ctx.index : ctx.index + 1\r\n ctx.node.children.splice(insertIndex, 0, newPane)\r\n this.recalculateRatios(ctx.node)\r\n } else {\r\n // Different orientation: wrap entire node in new split\r\n const nodeCopy: WorkspaceSplit = {\r\n orientation: ctx.node.orientation,\r\n ratios: [...ctx.node.ratios],\r\n children: [...ctx.node.children]\r\n }\r\n const wrapper: WorkspaceSplit = {\r\n orientation: targetOrientation,\r\n ratios: [0.5, 0.5],\r\n children: isBefore ? [newPane, nodeCopy] : [nodeCopy, newPane]\r\n }\r\n\r\n if (ctx.node === this.workspace.root) {\r\n this.workspace.root = wrapper\r\n } else if (ctx.parent) {\r\n const nodeIndex = ctx.parent.children.indexOf(ctx.node)\r\n if (nodeIndex !== -1) {\r\n ctx.parent.children[nodeIndex] = wrapper\r\n }\r\n }\r\n }\r\n return true\r\n })\r\n }\r\n\r\n}\r\n","import { Component, Input, Output, EventEmitter, HostListener } from '@angular/core'\r\nimport { WorkspacePane, TabbyProfile } from '../models/workspace.model'\r\n\r\n@Component({\r\n selector: 'pane-editor',\r\n template: require('./paneEditor.component.pug'),\r\n styles: [require('./paneEditor.component.scss')],\r\n})\r\nexport class PaneEditorComponent {\r\n @Input() pane!: WorkspacePane\r\n @Input() profiles: TabbyProfile[] = []\r\n @Output() close = new EventEmitter<void>()\r\n\r\n @HostListener('document:keydown.escape')\r\n onEscapeKey(): void {\r\n this.close.emit()\r\n }\r\n\r\n getProfileName(profileId: string): string {\r\n const profile = this.profiles.find((p) => p.id === profileId)\r\n return profile?.name ?? 'Unknown'\r\n }\r\n}\r\n","import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges, ChangeDetectorRef } from '@angular/core'\r\nimport {\r\n WorkspaceSplit,\r\n WorkspacePane,\r\n TabbyProfile,\r\n isWorkspaceSplit,\r\n} from '../models/workspace.model'\r\n\r\n@Component({\r\n selector: 'split-preview',\r\n template: require('./splitPreview.component.pug'),\r\n styles: [require('./splitPreview.component.scss')],\r\n})\r\nexport class SplitPreviewComponent implements OnChanges {\r\n @Input() split!: WorkspaceSplit\r\n @Input() depth = 0\r\n @Input() selectedPaneId: string | null = null\r\n @Input() profiles: TabbyProfile[] = []\r\n @Output() paneEdit = new EventEmitter<WorkspacePane>()\r\n @Output() splitHorizontal = new EventEmitter<WorkspacePane>()\r\n @Output() splitVertical = new EventEmitter<WorkspacePane>()\r\n @Output() removePane = new EventEmitter<WorkspacePane>()\r\n @Output() addLeft = new EventEmitter<WorkspacePane>()\r\n @Output() addRight = new EventEmitter<WorkspacePane>()\r\n @Output() addTop = new EventEmitter<WorkspacePane>()\r\n @Output() addBottom = new EventEmitter<WorkspacePane>()\r\n\r\n contextMenuPane: WorkspacePane | null = null\r\n contextMenuPosition = { x: 0, y: 0 }\r\n\r\n constructor(private cdr: ChangeDetectorRef) {}\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n // Clear context menu when split input changes to avoid stale state\r\n if (changes['split']) {\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n isPane(child: WorkspacePane | WorkspaceSplit): boolean {\r\n return !isWorkspaceSplit(child)\r\n }\r\n\r\n isSplit(child: WorkspacePane | WorkspaceSplit): boolean {\r\n return isWorkspaceSplit(child)\r\n }\r\n\r\n asSplit(child: WorkspacePane | WorkspaceSplit): WorkspaceSplit {\r\n return child as WorkspaceSplit\r\n }\r\n\r\n asPane(child: WorkspacePane | WorkspaceSplit): WorkspacePane {\r\n return child as WorkspacePane\r\n }\r\n\r\n getFlexStyle(index: number): string {\r\n return `${this.split.ratios[index] * 100}%`\r\n }\r\n\r\n onPaneClick(pane: WorkspacePane): void {\r\n this.paneEdit.emit(pane)\r\n }\r\n\r\n truncate(text: string, maxLength: number): string {\r\n return text.length > maxLength\r\n ? text.substring(0, maxLength) + '...'\r\n : text\r\n }\r\n\r\n onContextMenu(event: MouseEvent, pane: WorkspacePane): void {\r\n event.preventDefault()\r\n this.contextMenuPane = pane\r\n this.contextMenuPosition = { x: event.clientX, y: event.clientY }\r\n }\r\n\r\n closeContextMenu(): void {\r\n this.contextMenuPane = null\r\n this.cdr.detectChanges()\r\n }\r\n\r\n onEdit(): void {\r\n if (this.contextMenuPane) {\r\n this.paneEdit.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onSplitH(): void {\r\n if (this.contextMenuPane) {\r\n this.splitHorizontal.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onSplitV(): void {\r\n if (this.contextMenuPane) {\r\n this.splitVertical.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddLeft(): void {\r\n if (this.contextMenuPane) {\r\n this.addLeft.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddRight(): void {\r\n if (this.contextMenuPane) {\r\n this.addRight.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddTop(): void {\r\n if (this.contextMenuPane) {\r\n this.addTop.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onAddBottom(): void {\r\n if (this.contextMenuPane) {\r\n this.addBottom.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n onRemove(): void {\r\n if (this.contextMenuPane) {\r\n this.removePane.emit(this.contextMenuPane)\r\n this.closeContextMenu()\r\n }\r\n }\r\n\r\n getPaneLabel(pane: WorkspacePane): string {\r\n if (!pane.profileId) return 'Select profile'\r\n\r\n const profile = this.profiles.find(p => p.id === pane.profileId)\r\n return profile?.name || 'Select profile'\r\n }\r\n\r\n // Pass-through events from nested splits\r\n onNestedPaneEdit(pane: WorkspacePane): void {\r\n this.paneEdit.emit(pane)\r\n }\r\n\r\n onNestedSplitH(pane: WorkspacePane): void {\r\n this.splitHorizontal.emit(pane)\r\n }\r\n\r\n onNestedSplitV(pane: WorkspacePane): void {\r\n this.splitVertical.emit(pane)\r\n }\r\n\r\n onNestedAddLeft(pane: WorkspacePane): void {\r\n this.addLeft.emit(pane)\r\n }\r\n\r\n onNestedAddRight(pane: WorkspacePane): void {\r\n this.addRight.emit(pane)\r\n }\r\n\r\n onNestedAddTop(pane: WorkspacePane): void {\r\n this.addTop.emit(pane)\r\n }\r\n\r\n onNestedAddBottom(pane: WorkspacePane): void {\r\n this.addBottom.emit(pane)\r\n }\r\n\r\n onNestedRemove(pane: WorkspacePane): void {\r\n this.removePane.emit(pane)\r\n }\r\n}\r\n","import { NgModule } from '@angular/core'\r\nimport { CommonModule } from '@angular/common'\r\nimport { FormsModule } from '@angular/forms'\r\nimport { ConfigProvider, ToolbarButtonProvider } from 'tabby-core'\r\nimport { SettingsTabProvider } from 'tabby-settings'\r\n\r\nimport { WorkspaceEditorConfigProvider } from './providers/config.provider'\r\nimport { WorkspaceEditorSettingsProvider } from './providers/settings.provider'\r\nimport { WorkspaceToolbarProvider } from './providers/toolbar.provider'\r\nimport { WorkspaceEditorService } from './services/workspaceEditor.service'\r\nimport { StartupCommandService } from './services/startupCommand.service'\r\nimport { WorkspaceBackgroundService } from './services/workspaceBackground.service'\r\n\r\nimport { WorkspaceListComponent } from './components/workspaceList.component'\r\nimport { WorkspaceEditorComponent } from './components/workspaceEditor.component'\r\nimport { PaneEditorComponent } from './components/paneEditor.component'\r\nimport { SplitPreviewComponent } from './components/splitPreview.component'\r\nimport { DeleteConfirmModalComponent } from './components/deleteConfirmModal.component'\r\n\r\n@NgModule({\r\n imports: [CommonModule, FormsModule],\r\n providers: [\r\n { provide: ConfigProvider, useClass: WorkspaceEditorConfigProvider, multi: true },\r\n { provide: SettingsTabProvider, useClass: WorkspaceEditorSettingsProvider, multi: true },\r\n { provide: ToolbarButtonProvider, useClass: WorkspaceToolbarProvider, multi: true },\r\n WorkspaceEditorService,\r\n StartupCommandService,\r\n WorkspaceBackgroundService,\r\n ],\r\n declarations: [\r\n WorkspaceListComponent,\r\n WorkspaceEditorComponent,\r\n PaneEditorComponent,\r\n SplitPreviewComponent,\r\n DeleteConfirmModalComponent,\r\n ],\r\n})\r\nexport default class WorkspaceEditorModule {}\r\n\r\nexport {\r\n WorkspaceEditorService,\r\n WorkspaceEditorConfigProvider,\r\n WorkspaceEditorSettingsProvider,\r\n}\r\n"],"names":["root","factory","exports","module","require","e","define","amd","a","i","global","__WEBPACK_EXTERNAL_MODULE__860__","__WEBPACK_EXTERNAL_MODULE__358__","__WEBPACK_EXTERNAL_MODULE__182__","__WEBPACK_EXTERNAL_MODULE__650__","__WEBPACK_EXTERNAL_MODULE__700__","__WEBPACK_EXTERNAL_MODULE__765__","__WEBPACK_EXTERNAL_MODULE__349__","__WEBPACK_EXTERNAL_MODULE__961__","__WEBPACK_EXTERNAL_MODULE__439__","__WEBPACK_EXTERNAL_MODULE__947__","___CSS_LOADER_EXPORT___","push","id","result","__esModule","default","toString","locals","cssWithMappingToString","list","this","map","item","content","needLayer","concat","length","join","modules","media","dedupe","supports","layer","undefined","alreadyImportedModules","k","_k","cssMapping","btoa","base64","unescape","encodeURIComponent","JSON","stringify","data","sourceMapping","req","apply","pug_has_own_property","Object","prototype","hasOwnProperty","pug_classes","val","escaping","Array","isArray","className","classString","padding","escapeEnabled","pug_escape","pug_classes_array","key","call","pug_classes_object","pug_style","out","style","pug_attr","escaped","terse","type","toJSON","indexOf","replace","merge","pug_merge","b","arguments","attrs","valA","valB","classes","attr","obj","pug_match_html","_html","html","regexResult","exec","lastIndex","escape","index","charCodeAt","substring","rethrow","pug_rethrow","err","filename","lineno","str","Error","window","message","context","lines","start","end","encoding","split","Math","max","min","ex","slice","line","curr","path","code","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","__webpack_modules__","n","getter","d","definition","o","defineProperty","enumerable","get","prop","r","Symbol","toStringTag","value","CONFIG_KEY","DISPLAY_NAME","WorkspaceEditorConfigProvider","ConfigProvider","defaults","workspaces","Injectable","StartupCommandService","constructor","app","pendingCommands","Map","tabOpened$","subscribe","tab","onTabOpened","registerCommands","commands","console","log","cmd","set","paneId","name","title","SplitTabComponent","setTimeout","processChildTabs","BaseTerminalTabComponent","processTerminalTab","splitTab","allTabs","getAllTabs","terminalTab","customTitle","pendingKeys","keys","pending","delete","fullCommand","buildFullCommand","sendCommand","sendInput","clearProfileArgs","setTabTitle","originalTitle","session","output$","pipe","first","timeout","catchError","of","command","profile","options","args","setTitle","AppService","BACKGROUND_PRESETS","isWorkspaceSplit","node","createDefaultPane","generateUUID","profileId","cwd","startupCommand","createDefaultSplit","orientation","ratios","children","WORKSPACE_COLORS","WORKSPACE_ICONS","c","random","countPanes","reduce","sum","child","deepClone","cloned","WorkspaceEditorService","config","notifications","profilesService","cachedProfiles","cacheTimestamp","CACHE_TTL","getCachedProfiles","now","Date","getProfiles","getWorkspaces","store","saveWorkspaces","saveConfig","addWorkspace","workspace","info","error","updateWorkspace","findIndex","w","deleteWorkspace","workspaceId","find","filtered","filter","getAvailableProfiles","p","startsWith","cleanupOrphanedProfiles","profiles","prefix","save","generateTabbyProfile","safeName","sanitizeForProfileId","group","icon","color","isBuiltin","recoveryToken","generateRecoveryToken","workspaceName","generatePaneToken","pane","baseProfile","getProfileById","savedState","restoreFromPTYID","env","width","height","pauseAfterExit","runAsAdministrator","disableDynamicTitle","weight","isTemplate","terminalColorScheme","behaviorOnSessionEnd","tabTitle","tabCustomTitle","duplicateWorkspace","clone","launchOnStartup","regenerateIds","toLowerCase","isLocalType","collectStartupCommands","collectCommandsFromNode","providedIn","ConfigService","NotificationsService","ProfilesService","DeleteConfirmModalComponent","modal","Input","Component","selector","template","NgbActiveModal","WorkspaceListComponent","workspaceService","startupService","modalService","cdr","elementRef","zone","selectedWorkspace","editingWorkspace","isCreatingNew","openingWorkspaceId","displayTabs","configSubscription","ngOnInit","loadWorkspaces","autoSelectFirst","changed$","run","ngAfterViewInit","parent","nativeElement","closest","maxWidth","selectWorkspace","updateDisplayTabs","isSelected","ngOnDestroy","unsubscribe","previousSelectedId","createWorkspace","defaultProfileId","floor","createDefaultWorkspace","setProfileForAllPanes","detectChanges","forEach","editWorkspace","event","stopPropagation","duplicated","confirmDelete","wasSelected","deletedIndex","nextIndex","modalRef","open","componentInstance","onEditorSave","saved","onEditorCancel","getPaneCount","getOrientationLabel","hasUnsavedChanges","tabs","isNew","isTabSelected","trackByTab","openWorkspace","openNewTabForProfile","styles","NgbModal","ChangeDetectorRef","ElementRef","NgZone","WorkspaceEditorSettingsProvider","SettingsTabProvider","getComponentType","WorkspaceBackgroundService","styleElement","appliedWorkspaces","initialize","setupTabListeners","tabClosed$","onTabClosed","extractWorkspaceId","background","applyBackground","removeBackground","tabAny","_recoveredState","profilePrefix","parts","bg","markSplitTabElement","css","generateCSS","injectCSS","splitTabs","document","querySelectorAll","hasAttribute","setAttribute","createElement","head","appendChild","updateStyleElement","textContent","from","values","refreshWorkspaceBackground","SELECTOR_SETTINGS_ID","WorkspaceToolbarProvider","ToolbarButtonProvider","backgroundService","super","waitForTabbyReady","then","launchStartupWorkspaces","Promise","resolve","lastTabCount","checkStable","currentCount","startupWorkspaces","isWorkspaceAlreadyOpen","getRecoveryWorkspaceId","token","endsWith","provide","click","showWorkspaceSelector","openSettings","ws","description","selectedId","showSelector","openNewTabRaw","SettingsTabComponent","inputs","activeTab","WorkspaceEditorComponent","autoFocus","EventEmitter","cancel","selectedPaneId","editingPane","showPaneEditor","availableIcons","iconDropdownOpen","backgroundPresets","backgroundDropdownOpen","customBackgroundValue","onDocumentClick","dropdownTrigger","querySelector","iconDropdown","iconClickedInside","contains","target","bgTrigger","bgDropdown","bgClickedInside","toggleIconDropdown","selectIcon","toggleBackgroundDropdown","selectBackgroundPreset","preset","applyCustomBackground","trim","clearBackground","isBackgroundSelected","initializeWorkspace","focusNameInput","requestAnimationFrame","nameInput","focus","select","ngOnChanges","changes","firstChange","prevId","previousValue","findPaneById","currentValue","onSave","emit","onCancel","deselectPane","onPreviewBackgroundClick","closePaneEditor","editPane","findPaneInNode","found","canRemovePane","count","walkTree","visitor","ctx","updatePaneInTree","updatedPane","splitPane","splitPaneInTree","splitSelectedPane","targetPane","newPane","newSplit","recalculateRatios","removePane","removePaneFromTree","removeSelectedPane","paneIndex","splice","setOrientation","updateRatio","diff","addPane","direction","addPaneInTree","addPaneFromEvent","isBefore","targetOrientation","insertIndex","nodeCopy","wrapper","nodeIndex","Output","ViewChild","HostListener","MouseEvent","PaneEditorComponent","close","onEscapeKey","getProfileName","SplitPreviewComponent","depth","paneEdit","splitHorizontal","splitVertical","addLeft","addRight","addTop","addBottom","contextMenuPane","contextMenuPosition","x","y","closeContextMenu","isPane","isSplit","asSplit","asPane","getFlexStyle","onPaneClick","truncate","text","maxLength","onContextMenu","preventDefault","clientX","clientY","onEdit","onSplitH","onSplitV","onAddLeft","onAddRight","onAddTop","onAddBottom","onRemove","getPaneLabel","onNestedPaneEdit","onNestedSplitH","onNestedSplitV","onNestedAddLeft","onNestedAddRight","onNestedAddTop","onNestedAddBottom","onNestedRemove","WorkspaceEditorModule","NgModule","imports","CommonModule","FormsModule","providers","useClass","multi","declarations"],"ignoreList":[],"sourceRoot":""}