diff --git a/README.md b/README.md
index d056edf..56a6dcb 100644
--- a/README.md
+++ b/README.md
@@ -242,7 +242,7 @@ Feature priorities might change.
- [ ] Support WAV audio tracks
- [ ] Filters and effects
- [ ] MCP Support
-- [ ] Add support for OpenAI's open source models (`gpt-oss-20b` and `gpt-oss-120b`)
+- [X] Add support for OpenAI's open source models (`gpt-oss-20b` and `gpt-oss-120b`)
- [ ] Automatically compact conversations when the context window runs low on space
## Help Needed
diff --git a/eslint.config.js b/eslint.config.js
index fd7545f..8e7e63c 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -21,7 +21,8 @@ export default tseslint.config([
},
rules: {
'@typescript-eslint/no-unused-vars': 'warn', // Downgrade from error to warning
- 'no-unused-vars': 'warn' // Also set the base rule to warn
+ 'no-unused-vars': 'warn', // Also set the base rule to warn
+ 'semi': ['error', 'always'],
}
},
])
diff --git a/package-lock.json b/package-lock.json
index 76bc26e..9ebe900 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,16 @@
{
"name": "K.G.Studio",
- "version": "0.8.0-build.20260123",
+ "version": "0.9.0-build.20260406",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "K.G.Studio",
- "version": "0.8.0-build.20260123",
+ "version": "0.9.0-build.20260406",
"dependencies": {
"class-transformer": "^0.5.1",
"idb": "^8.0.3",
+ "jszip": "^3.10.1",
"openai": "^6.33.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
@@ -3805,7 +3806,6 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/cosmiconfig": {
@@ -5387,6 +5387,12 @@
"node": ">= 4"
}
},
+ "node_modules/immediate": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+ "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+ "license": "MIT"
+ },
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@@ -5441,7 +5447,6 @@
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true,
"license": "ISC"
},
"node_modules/ini": {
@@ -5656,7 +5661,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/isexe": {
@@ -5931,6 +5935,18 @@
"node": "*"
}
},
+ "node_modules/jszip": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz",
+ "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==",
+ "license": "(MIT OR GPL-3.0-or-later)",
+ "dependencies": {
+ "lie": "~3.3.0",
+ "pako": "~1.0.2",
+ "readable-stream": "~2.3.6",
+ "setimmediate": "^1.0.5"
+ }
+ },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -5965,6 +5981,15 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/lie": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+ "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+ "license": "MIT",
+ "dependencies": {
+ "immediate": "~3.0.5"
+ }
+ },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -11030,6 +11055,12 @@
"dev": true,
"license": "BlueOak-1.0.0"
},
+ "node_modules/pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "license": "(MIT AND Zlib)"
+ },
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
@@ -11377,7 +11408,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true,
"license": "MIT"
},
"node_modules/property-information": {
@@ -11792,7 +11822,6 @@
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
@@ -12156,7 +12185,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true,
"license": "MIT"
},
"node_modules/safer-buffer": {
@@ -12529,6 +12557,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -12836,7 +12870,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
@@ -13674,7 +13707,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true,
"license": "MIT"
},
"node_modules/validate-npm-package-license": {
diff --git a/package.json b/package.json
index 50f19a3..50c926f 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"dependencies": {
"class-transformer": "^0.5.1",
"idb": "^8.0.3",
+ "jszip": "^3.10.1",
"openai": "^6.33.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
diff --git a/src/App.css b/src/App.css
index 5bbb13e..0c36aff 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,15 +1,3 @@
-:root {
- --time-signature-numerator: 4;
- --max-number-of-bars: 32;
- --track-grid-bar-width: 40px;
- --region-piano-key-width: 60px;
- --region-piano-key-height: 20px;
- --region-grid-beat-width: 40px;
- --region-grid-bar-width: calc(var(--region-grid-beat-width) * var(--time-signature-numerator));
- --chat-box-width: 350px;
- --instrument-selection-width: 300px;
-}
-
/* Reset default styles */
* {
margin: 0;
@@ -50,991 +38,6 @@ body {
overflow: hidden;
}
-/* Toolbar */
-.toolbar {
- display: flex;
- justify-content: space-between;
- align-items: center;
- background-color: #2d2d2d;
- height: 50px;
- padding: 0 10px;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.toolbar-left, .toolbar-center, .toolbar-right {
- display: flex;
- align-items: center;
-}
-
-.toolbar-left {
- display: flex;
- align-items: center;
-}
-
-.logo-container {
- margin-right: 10px;
- display: flex;
- align-items: center;
-}
-
-.logo {
- height: 30px;
- width: auto;
-}
-
-.project-name {
- font-size: 14px;
- color: #e0e0e0;
- margin-right: 20px;
- display: flex;
- align-items: center;
- pointer-events: auto;
-}
-
-.toolbar button {
- background: transparent;
- border: none;
- color: #e0e0e0;
- margin: 0 5px;
- padding: 5px;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
- border-radius: 3px;
- font-size: 14px;
- pointer-events: auto;
-}
-
-.toolbar button:hover {
- background-color: #3a3a3a;
-}
-
-.toolbar button:disabled {
- color: #666;
- cursor: not-allowed;
-}
-
-.record-btn {
- color: #ff4444;
-}
-
-.toolbar-separator {
- width: 1px;
- height: 20px;
- background-color: #555;
- margin: 0 10px;
-}
-
-.transport-control {
- display: flex;
- align-items: center;
- margin: 0 10px;
- pointer-events: auto;
-}
-
-.transport-item {
- margin: 0 5px;
- padding: 2px 2px;
- background-color: #3a3a3a;
- border-radius: 3px;
- font-size: 12px;
-}
-
-/* Fixed-width font for time display to prevent layout shifts */
-.current-time {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- padding: 2px 4px;
-}
-
-/* Clickable BPM styling */
-.current-bpm {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- cursor: pointer;
- transition: background-color 0.2s ease;
- padding: 2px 4px;
- border-radius: 2px;
-}
-
-.current-bpm:hover {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-/* Clickable time signature styling */
-.current-time-signature {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- cursor: pointer;
- transition: background-color 0.2s ease;
- padding: 2px 4px;
- border-radius: 2px;
-}
-
-.current-time-signature:hover {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-.current-key-signature {
- font-family: 'Courier New', 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
- font-weight: normal;
- letter-spacing: 0.5px;
- cursor: pointer;
- transition: background-color 0.2s ease;
- padding: 2px 4px;
- border-radius: 2px;
-}
-
-.current-key-signature:hover {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-.export-dropdown .quant-dropdown {
- width: 250px;
- left: 0;
-}
-
-/* Main content */
-.main-content {
- display: flex;
- flex-direction: column;
- flex: 1;
- overflow: auto; /* Main scrollable container */
- position: relative;
-}
-
-.main-content-wrapper {
- display: flex;
- flex-direction: column;
- min-width: calc(200px + var(--max-number-of-bars) * var(--track-grid-bar-width)); /* info width + grid width */
- min-height: fit-content;
- position: relative;
-}
-
-.top-left-spacer {
- position: fixed;
- top: 50px;
- left: 0;
- width: 200px;
- height: 20px;
- background-color: #2d2d2d;
- border-bottom: 1px solid #3a3a3a;
- border-right: 1px solid #3a3a3a;
- z-index: 1002; /* Higher than other elements to ensure it's always visible */
-}
-
-/* Offset spacer when instrument selection panel is visible on the left */
-.main-content.has-left-instrument .top-left-spacer {
- left: 300px;
-}
-
-.bar-numbers {
- position: sticky;
- top: 0;
- height: 20px;
- display: flex;
- border-bottom: 1px solid #3a3a3a;
- background-color: #2d2d2d;
- z-index: 20;
- margin-left: 200px; /* Offset for info-container */
- width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Exact width for 32 bars */
- cursor: pointer; /* Show pointer cursor on hover to indicate interactivity */
-}
-
-.bar-numbers:hover {
- cursor: url("data:image/svg+xml,%3csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M4 6h8l-4 4-4-4z' fill='%23e0e0e0'/%3e%3c/svg%3e") 8 8, pointer;
-}
-
-.bar-number-cell {
- min-width: var(--track-grid-bar-width);
- width: var(--track-grid-bar-width);
- flex-shrink: 0;
- flex-grow: 0;
- height: 20px;
- text-align: center;
- font-size: 12px;
- border-right: 1px solid #3a3a3a;
- color: #999;
- display: flex;
- align-items: center;
- justify-content: center;
- box-sizing: border-box;
-}
-
-.bar-number-cell.looped {
- background-color: #e1ae01;
- color: #1e1e1e;
-}
-
-.main-content-body {
- display: flex;
- min-height: fit-content;
-}
-
-.info-container {
- position: sticky;
- left: 0;
- width: 200px;
- z-index: 1002;
- background-color: #2d2d2d;
- align-self: flex-start;
-}
-
-/* Shift the bar numbers and info panel when instrument selection is present */
-/* No need to shift bar numbers or info container; they live inside main content.
- Only shift the fixed spacer when the left panel is present. */
-
-.track-top-spacer {
- height: 20px;
- border-bottom: 1px solid #3a3a3a;
- background-color: #2d2d2d;
- position: sticky;
- top: 0;
- z-index: 15;
-}
-
-.grid-container {
- margin-left: 0; /* No need for margin since we're using flex */
- min-width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Ensure minimum width */
- min-height: fit-content;
- position: relative; /* Required for absolute positioned playhead */
-}
-
-.track-grid {
- display: block;
- height: 120px;
- min-width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* 32 bars * --track-grid-bar-width */
- background-size: var(--track-grid-bar-width) 120px;
- background-image:
- /* Vertical lines for bars */
- linear-gradient(to right,
- transparent calc(var(--track-grid-bar-width) - 1px), #3a3a3a calc(var(--track-grid-bar-width) - 1px), #3a3a3a var(--track-grid-bar-width)
- );
- position: relative;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.track-grid.pencil-cursor {
- cursor: crosshair;
-}
-
-.track-control {
- padding: 5px;
- background-color: #2d2d2d;
- border-top: 1px solid #3a3a3a;
-}
-
-.track-control button {
- background: transparent;
- border: none;
- color: #999;
- cursor: pointer;
- padding: 5px;
- width: 100%;
- text-align: left;
- font-size: 12px;
-}
-
-.track-control button:hover {
- color: #e0e0e0;
-}
-
-.track {
- display: flex;
- height: 120px;
- position: relative;
- border-bottom: none;
-}
-
-.track-info {
- width: 200px;
- height: 120px;
- padding: 15px;
- background-color: #2d2d2d;
- display: flex;
- flex-direction: column;
- border-right: 1px solid #3a3a3a;
- border-bottom: 1px solid #3a3a3a;
- flex-shrink: 0;
- box-sizing: border-box;
- cursor: grab;
- position: relative;
-}
-
-.track-info:active {
- cursor: grabbing;
-}
-
-.track-info.selected {
- background-color: #363636;
-}
-
-/* Drag and drop styles */
-.track-info.drag-over {
- border-top: 2px solid #7b68ee;
-}
-
-.track-grid.drag-over {
- border-top: 2px solid #7b68ee;
-}
-
-/* Dragging state */
-.track-info.dragging {
- opacity: 0.5;
- background-color: #444;
-}
-
-.track-grid.dragging {
- opacity: 0.5;
- background-color: #333;
-}
-
-/* Remove drag indicator since hover cursor is sufficient */
-
-.track-name {
- font-size: 12px;
- cursor: pointer;
- position: relative;
-}
-
-.track-name:hover {
- color: #7b68ee;
-}
-
-.track-name:hover::before {
- content: "✎";
- position: absolute;
- right: 0px;
- font-size: 16px;
- opacity: 1;
-}
-
-.track-controls {
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
-}
-
-.track-name-and-volume {
- display: flex;
- flex-direction: row;
- flex: 1;
- align-items: flex-start;
- gap: 8px;
-}
-
-.instrument-image {
- flex-shrink: 0;
- margin-top: -10px;
- margin-left: -10px;
-}
-
-.instrument-image img {
- display: block;
- border-radius: 4px;
-}
-
-.track-name-and-controls {
- display: flex;
- flex-direction: column;
- flex: 1;
- min-width: 0;
-}
-
-.volume-slider {
- margin-bottom: 15px;
- width: 100%;
- display: flex;
- align-items: center;
- gap: 6px;
-}
-
-.volume-slider input[type="range"] {
- flex: 1;
- min-width: 0;
- height: 6px;
-}
-
-.volume-slider .reset-volume {
- flex-shrink: 0;
- width: 16px;
- height: 16px;
- border-radius: 8px;
- background: #3a3a3a;
- color: #e0e0e0;
- /* border: 1px solid #444; */
- display: inline-flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- font-size: 10px;
-}
-
-.volume-slider .reset-volume:hover {
- background: #4a4a4a;
-}
-
-.pan-controls {
- display: flex;
-}
-
-.pan-controls button {
- background: #3a3a3a;
- border: none;
- color: #e0e0e0;
- margin-right: 5px;
- width: 24px;
- height: 24px;
- font-size: 12px;
- border-radius: 2px;
- cursor: pointer;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.pan-controls button.solo.active {
- background: #c8a400; /* yellow */
- color: #101010;
-}
-
-.pan-controls button.mute.active {
- background: #d32f2f; /* red */
- color: #ffffff;
-}
-
-/* Status bar */
-.status-bar {
- display: flex;
- justify-content: space-between;
- align-items: center;
- background-color: #2d2d2d;
- padding: 5px 10px;
- font-size: 12px;
- color: #999;
- border-top: 1px solid #3a3a3a;
- height: 30px;
-}
-
-.status-right span {
- margin-left: 15px;
-}
-
-/* For the piano roll (to be implemented later) */
-.piano-roll {
- background-color: #7b68ee;
- height: 100%;
-}
-
-/* Piano Roll Panel */
-.piano-roll-panel {
- position: fixed;
- background-color: #2d2d2d;
- border: 1px solid #3a3a3a;
- box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
- display: flex;
- flex-direction: column;
- overflow: hidden;
-}
-
-/* Piano notes */
-.piano-note {
- position: absolute;
- background-color: #ff5555; /* Red color */
- border: 1px solid #999;
- border-radius: 2px;
- z-index: 10;
- cursor: pointer;
- user-select: none;
- box-sizing: border-box;
-}
-
-.piano-note:hover {
- filter: brightness(1.1);
- box-shadow: 0 0 5px rgba(255, 85, 85, 0.5);
-}
-
-.piano-note.dragging {
- opacity: 0.8;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
- z-index: 100;
- cursor: grabbing;
-}
-
-.piano-note.resizing {
- opacity: 0.8;
- box-shadow: 0 0 10px rgba(255, 85, 85, 0.7);
- z-index: 100;
-}
-
-.piano-note.selected {
- border: 2px solid white;
- z-index: 50;
-}
-
-.piano-roll-header {
- height: 30px;
- background-color: #1e1e1e;
- border-bottom: 1px solid #3a3a3a;
- display: flex;
- align-items: center;
- padding: 0 10px;
- cursor: move;
- user-select: none;
-}
-
-/* Piano roll toolbar */
-.piano-roll-toolbar {
- height: 30px;
- background-color: #252525;
- border-bottom: 1px solid #3a3a3a;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0 10px;
- user-select: none;
- position: relative;
- z-index: 100; /* Ensure toolbar and its dropdowns appear above piano roll content */
-}
-
-/* Override pointer-events for piano roll toolbar sections */
-.piano-roll-toolbar .toolbar-left,
-.piano-roll-toolbar .toolbar-right {
- pointer-events: auto;
-}
-
-.piano-roll-toolbar .quant-button {
- font-size: 10px;
-}
-
-.piano-roll-toolbar .toolbar-left .quant-button {
- margin-left: 0px;
- margin-right: 5px;
-}
-
-.piano-roll-toolbar .toolbar-left .quant-dropdown {
- left: 0;
-}
-
-/* Generic button blink effect */
-.quant-button.button-blink {
- animation: buttonBlink 0.2s ease-in-out;
-}
-
-@keyframes buttonBlink {
- 0% { background-color: #333; }
- 50% { background-color: #555; }
- 100% { background-color: #333; }
-}
-
-.toolbar-left, .toolbar-right {
- display: flex;
- align-items: center;
- z-index: 1;
- pointer-events: none;
-}
-
-.toolbar-left {
- width: 20%;
- justify-content: flex-start;
-}
-
-.toolbar-right {
- width: 33%;
- justify-content: flex-end;
- z-index: 1500;
-}
-
-.toolbar-center {
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 1005;
- margin-left: -50px;
-}
-
-.tool-button {
- width: 30px;
- height: 30px;
- background-color: transparent;
- border: none;
- border-radius: 3px;
- color: #999;
- font-size: 14px;
- display: flex;
- align-items: center;
- justify-content: center;
- cursor: pointer;
- margin: 0 2px;
-}
-
-.tool-button:hover {
- background-color: #3a3a3a;
- color: #e0e0e0;
-}
-
-.tool-button.active {
- background-color: #4a4a4a;
- color: #e0e0e0;
-}
-
-.chatbox-export-dropdown .quant-dropdown {
- width: 250px;
- left: -200px;
-}
-
-.key-signature-dropdown .quant-dropdown {
- width: 100px;
- left: 0;
-}
-
-.quant-button {
- background-color: #333;
- border: 1px solid #444;
- border-radius: 3px;
- color: #e0e0e0;
- font-size: 12px;
- padding: 3px 8px;
- margin-left: 5px;
- cursor: pointer;
- display: flex;
- align-items: center;
- gap: 5px;
-}
-
-.quant-button:hover {
- background-color: #444;
-}
-
-.quant-dropdown-container {
- position: relative;
- display: inline-block;
- z-index: 1500;
-}
-
-.quant-dropdown {
- position: absolute;
- top: 100%;
- right: 0;
- background-color: #2d2d2d;
- border: 1px solid #444;
- border-radius: 3px;
- width: 100px;
- z-index: 1500;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
- margin-top: 2px;
- max-height: 200px;
- overflow-y: auto;
-}
-
-.quant-option {
- padding: 6px 10px;
- font-size: 12px;
- color: #e0e0e0;
- cursor: pointer;
- transition: background-color 0.2s;
-}
-
-.quant-option:hover {
- background-color: #444;
-}
-
-.quant-option.active {
- background-color: #4a6b8a;
-}
-
-.piano-roll-title {
- flex: 1;
- text-align: center;
- font-size: 14px;
- color: #e0e0e0;
- text-transform: uppercase;
- cursor: pointer;
- padding: 5px;
- border-radius: 3px;
-}
-
-.close-button {
- background: transparent;
- border: none;
- color: #e0e0e0;
- cursor: pointer;
- font-size: 14px;
- padding: 5px;
-}
-
-.close-button:hover {
- color: #ff4444;
-}
-
-.piano-roll-content {
- display: flex;
- flex-direction: column;
- flex: 1;
- overflow: auto;
-}
-
-.piano-grid-header {
- display: grid;
- grid-template-columns: repeat(var(--max-number-of-bars), var(--region-grid-bar-width));
- width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width) - 1px);
- min-width: 100%;
- height: 20px;
- border-bottom: 1px solid #3a3a3a;
- background-color: #1e1e1e;
- padding-left: calc(var(--region-piano-key-width) - 1px);
- box-sizing: border-box;
- position: sticky;
- top: 0;
- z-index: 20;
- cursor: pointer; /* Show pointer cursor on hover to indicate interactivity */
-}
-
-.piano-grid-header:hover {
- cursor: url("data:image/svg+xml,%3csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M4 6h8l-4 4-4-4z' fill='%23e0e0e0'/%3e%3c/svg%3e") 8 8, pointer;
-}
-
-.piano-bar-number {
- border-left: 1px solid #3a3a3a;
- padding-left: 10px;
- font-size: 10px;
-}
-
-.piano-roll-body {
- display: flex;
- min-height: calc(8 * 12 * var(--region-piano-key-height)); /* 8 octaves * 12 notes * piano key height */
- width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width) + var(--region-piano-key-width)); /* 32 bars * 160px width + piano keys width */
-}
-
-.piano-keys-container {
- width: var(--region-piano-key-width);
- flex-shrink: 0;
- overflow: hidden;
- border-right: 1px solid #3a3a3a;
- background-color: #252525;
- position: sticky;
- left: 0;
- z-index: 10;
-}
-
-.piano-grid-container {
- flex: 1;
- min-width: calc(var(--max-number-of-bars) * var(--region-grid-bar-width));
- min-height: calc(8 * 12 * var(--region-piano-key-height));
- z-index: 5;
-}
-
-.piano-octave {
- display: flex;
- flex-direction: column;
-}
-
-.piano-key {
- width: var(--region-piano-key-width);
- height: var(--region-piano-key-height);
- box-sizing: border-box;
- display: flex;
- align-items: center;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.piano-key.natural {
- background-color: #e0e0e0;
- color: #222;
-}
-
-.piano-key.sharp {
- background-color: #222;
- color: #e0e0e0;
-}
-
-.key-label {
- font-size: 10px;
- padding-left: 5px;
-}
-
-.piano-grid {
- width: 100%;
- height: 100%;
- position: relative;
- background-size: var(--region-grid-beat-width) var(--region-piano-key-height), 100% 100%;
- /* background-image is now set dynamically via React inline styles in PianoGrid component */
-}
-
-.piano-grid.pencil-cursor {
- cursor: crosshair;
-}
-
-/* Piano Grid Cursor Highlights */
-.piano-grid-pitch-highlight {
- position: absolute;
- left: 0;
- right: 0;
- background-color: rgba(123, 104, 238, 0.15);
- border-top: 1px solid rgba(123, 104, 238, 0.3);
- border-bottom: 1px solid rgba(123, 104, 238, 0.3);
- pointer-events: none;
- z-index: 1;
- transition: opacity 0.1s ease;
-}
-
-.piano-grid-beat-highlight {
- position: absolute;
- top: 0;
- bottom: 0;
- background-color: rgba(123, 104, 238, 0.1);
- border-left: 1px solid rgba(123, 104, 238, 0.25);
- border-right: 1px solid rgba(123, 104, 238, 0.25);
- pointer-events: none;
- z-index: 1;
- transition: opacity 0.1s ease;
-}
-
-.piano-grid-chord-highlight {
- position: absolute;
- background-color: rgba(255, 77, 77, 0.25);
- border: 1px solid rgba(255, 77, 77, 0.8);
- pointer-events: none;
- z-index: 2;
- transition: opacity 0.1s ease;
-}
-
-.resize-handle {
- position: absolute;
- right: 5px;
- bottom: 5px;
- width: 20px;
- height: 20px;
- cursor: nwse-resize;
- color: #999;
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 100;
-}
-
-/* Track Region Styles */
-.track-region {
- position: absolute;
- background-color: #4a6b8a;
- border: 2px solid #5a7b9a;
- border-radius: 3px;
- height: calc(100%);
- margin: 0px;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- cursor: pointer;
- user-select: none;
- transition: box-shadow 0.1s ease;
- will-change: transform;
-}
-
-.track-region:hover {
- box-shadow: 0 0 0 1px #7a9bba;
-}
-
-.track-region.selected {
- /* box-shadow: 0 0 0 2px #ffffff, 0 0 8px rgba(255, 255, 255, 0.3); */ /* let's only apply a border */
- border-color: #ffffff;
-}
-
-.track-region.dragging {
- opacity: 0.8;
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
- z-index: 100;
- pointer-events: none;
- transform-origin: center center;
- animation: pulse 1.5s infinite;
- cursor: grabbing;
- transition: none; /* Remove transition during drag for immediate response */
-}
-
-@keyframes pulse {
- 0% {
- box-shadow: 0 0 0 0 rgba(122, 155, 186, 0.7);
- }
- 70% {
- box-shadow: 0 0 0 5px rgba(122, 155, 186, 0);
- }
- 100% {
- box-shadow: 0 0 0 0 rgba(122, 155, 186, 0);
- }
-}
-
-.region-header {
- background-color: #5a7b9a;
- color: #fff;
- padding: 2px 6px;
- font-size: 11px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- cursor: move;
- height: 18px;
- user-select: none;
-}
-
-.track-region:hover .region-header {
- background-color: #6a8baa;
-}
-
-.region-content {
- height: calc(100% - 18px);
- background-color: #87CEFA; /* Light blue */
- width: 100%;
- position: relative; /* Allow overlayed controls */
-}
-
-/* Region pencil trigger inside content */
-.region-pencil-btn {
- position: absolute;
- top: 4px;
- left: 4px;
- background: rgba(0, 0, 0, 0.25);
- color: #fff;
- border: 1px solid rgba(255, 255, 255, 0.2);
- border-radius: 3px;
- padding: 2px;
- margin: 0;
- cursor: pointer;
- z-index: 2;
- display: inline-flex;
- align-items: center;
- justify-content: center;
-}
-
-.region-pencil-btn:hover {
- background: rgba(0, 0, 0, 0.35);
-}
-
-/* Instrument dropdown specific styles */
-.instrument-dropdown .quant-dropdown {
- min-width: 80px;
- width: auto;
- right: auto;
- left: 0;
-}
-
-/* Settings dropdown specific styles */
-.settings-dropdown .quant-dropdown {
- min-width: 100px;
- width: auto;
- right: auto;
- left: 0;
-}
-
/* Update structure in JSX to match this pattern:
@@ -1046,1032 +49,3 @@ body {
*/
-
-/* ChatBox */
-.chatbox {
- display: flex;
- flex-direction: column;
- width: var(--chat-box-width);
- background-color: #2d2d2d;
- border-left: 1px solid #3a3a3a;
- flex-shrink: 0;
-}
-
-.chatbox.is-hidden {
- display: none;
-}
-
-/* Instrument Selection Panel */
-.instrument-selection {
- display: flex;
- flex-direction: column;
- width: var(--instrument-selection-width);
- background-color: #2d2d2d;
- border-right: 1px solid #3a3a3a;
- flex-shrink: 0;
- position: relative;
-}
-
-.instrument-selection-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- height: 40px;
- padding: 0 12px;
- background-color: transparent;
- border: none;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- z-index: 2;
-}
-
-.instrument-selection-header h3 {
- color: #e0e0e0;
- font-size: 12px;
- font-weight: bold;
-}
-
-.instrument-selection-close-btn {
- background: transparent;
- border: none;
- color: #e0e0e0;
- cursor: pointer;
- padding: 4px;
- border-radius: 3px;
-}
-
-.instrument-selection-close-btn:hover {
- background-color: #4a4a4a;
-}
-
-.instrument-selection-top {
- height: 300px;
- position: relative;
- border-bottom: 1px solid #3a3a3a;
- overflow: hidden;
- background-image:
- linear-gradient(rgba(0,0,0,0.35), rgba(0,0,0,0.35)),
- url('/resources/instrument_bg.png');
- background-size: cover; /* fill while keeping aspect ratio */
- background-position: center;
-}
-
-.instrument-preview {
- position: absolute;
- inset: 0;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.instrument-preview img {
- width: 256px;
- height: 256px;
- object-fit: contain;
- border-radius: 6px;
- opacity: 1;
-}
-
-.instrument-name-overlay {
- position: absolute;
- bottom: 16px;
- left: 0;
- right: 0;
- text-align: center;
- font-size: 12px;
- color: #e0e0e0;
- text-shadow: 0 1px 2px rgba(0,0,0,0.6);
- z-index: 1;
- font-size: 16px;
- font-weight: bold;
-}
-
-.instrument-selection-bottom {
- flex: 1;
- display: grid;
- grid-template-columns: 1fr 1fr;
- min-height: 0; /* allow children to scroll */
-}
-
-.instrument-groups, .instrument-list {
- overflow: hidden;
-}
-
-/* vertical divider between groups and instruments */
-.instrument-groups {
- border-right: 1px solid #3a3a3a;
-}
-
-.instrument-groups-list, .instrument-instruments-list {
- height: 100%;
- overflow-y: auto;
-}
-
-.instrument-group-item, .instrument-instrument-item {
- padding: 8px 12px;
- /* remove per-item separators */
- border-bottom: none;
- cursor: pointer;
- font-size: 12px;
- color: #e0e0e0;
-}
-
-.instrument-group-item:hover, .instrument-instrument-item:hover {
- background-color: #3a3a3a;
-}
-
-.instrument-group-item.active, .instrument-instrument-item.active {
- background-color: #4a4a4a;
-}
-
-.chatbox-header {
- display: flex;
- align-items: center;
- justify-content: space-between; /* left title, right actions */
- background-color: #3a3a3a;
- height: 40px;
- border-bottom: 1px solid #4a4a4a;
- padding: 0 15px;
-}
-
-.chatbox-actions {
- display: flex;
- gap: 8px;
- align-items: center;
-}
-
-.chatbox-action-btn {
- background: transparent;
- border: none;
- cursor: pointer;
- padding: 4px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- color: #e0e0e0;
- font-size: 14px;
-}
-
-.chatbox-action-btn:hover {
- background-color: #4a4a4a;
- border-radius: 3px;
-}
-
-/* ChatBox export button wrapper and dropdown positioning */
-.chatbox-export-wrapper {
- position: relative;
- display: inline-block;
-}
-
-.chatbox-export-btn {
- display: flex;
- align-items: center;
- gap: 4px;
-}
-
-.chatbox-export-dropdown-anchor {
- position: absolute;
- top: 100%;
- left: 0;
- z-index: 10000;
-}
-
-.chatbox-header h3 {
- color: #e0e0e0;
- font-size: 12px;
- font-weight: bold;
- margin: 0;
-}
-
-.chatbox-content {
- flex: 1;
- padding: 15px;
- color: #e0e0e0;
- font-size: 12px;
- overflow-y: auto;
-}
-
-/* Chat Messages */
-.chatbox-messages {
- flex: 1;
- padding: 10px;
- overflow-y: auto;
- display: flex;
- flex-direction: column;
- gap: 12px;
-}
-
-.message-container {
- width: 100%;
- word-wrap: break-word;
-}
-
-.message-user {
- width: 100%;
-}
-
-.message-assistant {
- width: 100%;
-}
-
-.message-content {
- padding: 8px 12px;
- border-radius: 8px;
- font-size: 12px;
- line-height: 1.4;
-}
-
-/* User message styling - lighter background like input */
-.message-user .message-content {
- background-color: #3a3a3a;
- color: #e0e0e0;
- border: 1px solid #4a4a4a;
-}
-
-/* Assistant message styling - transparent */
-.message-assistant .message-content {
- background-color: transparent;
- color: #e0e0e0;
- border: 1px solid #2a2a2a;
-}
-
-/* Input Area */
-.chatbox-input-area {
- padding: 10px;
-}
-
-.chatbox-input {
- width: 100%;
- padding: 8px 12px;
- background-color: #4a4a4a;
- border: 1px solid #5a5a5a;
- border-radius: 6px;
- color: #e0e0e0;
- font-size: 12px;
- outline: none;
- resize: none;
- min-height: 36px;
- max-height: 120px;
-}
-
-.chatbox-input:focus {
- border-color: #6a6a6a;
- background-color: #4a4a4a;
-}
-
-.chatbox-input::placeholder {
- color: #999;
-}
-
-
-/* Markdown styling in messages */
-.message-content h1,
-.message-content h2,
-.message-content h3 {
- margin: 8px 0 4px 0;
- color: #e0e0e0;
-}
-
-.message-content h3 {
- font-size: 14px;
-}
-
-.message-content p {
- margin: 4px 0;
-}
-
-.message-content ul,
-.message-content ol {
- margin: 4px 0;
- padding-left: 16px;
-}
-
-.message-content li {
- margin: 2px 0;
-}
-
-.message-content code {
- background-color: #2a2a2a;
- padding: 2px 4px;
- border-radius: 3px;
- font-family: 'Courier New', Courier, monospace;
- font-size: 11px;
-}
-
-.message-content pre {
- background-color: #1a1a1a;
- padding: 8px;
- border-radius: 6px;
- overflow-x: auto;
- margin: 8px 0;
-}
-
-.message-content blockquote {
- border-left: 3px solid #5a5a5a;
- padding-left: 12px;
- margin: 8px 0;
- color: #ccc;
-}
-
-.message-content table {
- border-collapse: collapse;
- width: 100%;
- margin: 8px 0;
- font-size: 11px;
-}
-
-.message-content th,
-.message-content td {
- border: 1px solid #4a4a4a;
- padding: 4px 8px;
- text-align: left;
-}
-
-.message-content th {
- background-color: #3a3a3a;
- font-weight: bold;
-}
-
-textarea {
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- font-size: 12px;
- line-height: 1.4;
-}
-
-/* Abort link styling */
-.abort-link {
- background: none !important;
- border: none !important;
- color: #7b68ee !important;
- text-decoration: underline !important;
- cursor: pointer !important;
- padding: 0 !important;
- font: inherit !important;
- font-size: 12px !important;
-}
-
-.abort-link:hover {
- color: #9b88ff !important;
- text-decoration: none !important;
-}
-
-/* Tool XML Expander */
-.tool-xml-expander {
- margin-bottom: 8px;
-}
-
-.tool-xml-expander-header {
- color: #e0e0e0;
- cursor: pointer;
- user-select: none;
- padding: 4px 8px;
- /* background-color: #f5f5f5; */
- border: 1px solid #2a2a2a;
- border-radius: 4px;
- display: flex;
- align-items: center;
- gap: 8px;
-}
-
-.tool-xml-expander-arrow {
- font-size: 12px;
- color: #666;
-}
-
-.tool-xml-expander-title {
- /* font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace; */
- font-size: 12px;
- font-weight: bold;
- color: #e0e0e0;
-}
-
-.tool-xml-expander-content {
- margin-top: 4px;
- padding: 8px;
- background-color: #f9f9f9;
- border: 1px solid #ddd;
- border-radius: 4px;
- font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace;
- font-size: 12px;
- white-space: pre-wrap;
- overflow: auto;
- max-height: 200px;
- color: #333;
-}
-
-/* Settings Panel Styles */
-.settings-panel {
- width: 100%;
- height: 100%;
- background-color: #1e1e1e;
- display: flex;
- flex-direction: column;
-}
-
-.settings-container {
- display: flex;
- height: 100%;
- overflow: hidden;
-}
-
-/* Settings Sidebar */
-.settings-sidebar {
- width: 250px;
- background-color: #2d2d2d;
- border-right: 1px solid #3a3a3a;
- display: flex;
- flex-direction: column;
-}
-
-.settings-sidebar-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20px;
- border-bottom: 1px solid #3a3a3a;
-}
-
-.settings-sidebar-header h2 {
- color: #e0e0e0;
- font-size: 18px;
- font-weight: 600;
- margin: 0;
-}
-
-.settings-close-btn {
- background: transparent;
- border: none;
- color: #e0e0e0;
- cursor: pointer;
- padding: 5px;
- border-radius: 3px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 16px;
-}
-
-.settings-close-btn:hover {
- background-color: #3a3a3a;
- color: #fff;
-}
-
-.settings-nav {
- display: flex;
- flex-direction: column;
- padding: 10px;
-}
-
-.settings-nav-item {
- background: transparent;
- border: none;
- color: #b0b0b0;
- padding: 12px 16px;
- text-align: left;
- cursor: pointer;
- border-radius: 4px;
- margin-bottom: 2px;
- font-size: 14px;
- font-weight: 500;
- transition: all 0.2s ease;
-}
-
-.settings-nav-item:hover {
- background-color: #3a3a3a;
- color: #e0e0e0;
-}
-
-.settings-nav-item.active {
- background-color: #4a4a4a;
- color: #fff;
-}
-
-/* Settings Content */
-.settings-content {
- flex: 1;
- overflow-y: auto;
- background-color: #1e1e1e;
- display: flex;
- justify-content: center;
-}
-
-.settings-section {
- padding: 30px;
- width: 800px;
-}
-
-.settings-section-header {
- margin-bottom: 30px;
- border-bottom: 1px solid #3a3a3a;
- padding-bottom: 15px;
-}
-
-.settings-section-header h3 {
- color: #fff;
- font-size: 24px;
- font-weight: 600;
- margin: 0;
-}
-
-.settings-section-content {
- display: flex;
- flex-direction: column;
- gap: 30px;
- padding-bottom: 30px;
-}
-
-.settings-group {
- background-color: #2d2d2d;
- border-radius: 8px;
- padding: 20px;
- border: 1px solid #3a3a3a;
-}
-
-.settings-group h4 {
- color: #fff;
- font-size: 16px;
- font-weight: 600;
- margin: 0 0 15px 0;
-}
-
-.settings-group-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 15px;
-}
-
-.settings-group-header h4 {
- margin: 0;
-}
-
-.settings-description {
- color: #b0b0b0;
- font-size: 14px;
- line-height: 1.5;
- margin-bottom: 15px;
-}
-
-.settings-item {
- margin-bottom: 15px;
-}
-
-.settings-item:last-child {
- margin-bottom: 0;
-}
-
-.settings-label {
- display: block;
- color: #e0e0e0;
- font-size: 14px;
- font-weight: 500;
- margin-bottom: 5px;
-}
-
-.settings-input, .settings-select, .settings-textarea {
- width: 100%;
- /* max-width: 300px; */
- padding: 8px 12px;
- background-color: #3a3a3a;
- border: 1px solid #555;
- border-radius: 4px;
- color: #e0e0e0;
- font-size: 14px;
- transition: border-color 0.2s ease;
- font-family: inherit;
-}
-
-.settings-input:focus, .settings-select:focus, .settings-textarea:focus {
- outline: none;
- border-color: #5a9fd4;
- box-shadow: 0 0 0 2px rgba(90, 159, 212, 0.2);
-}
-
-.settings-textarea {
- max-width: 600px;
- resize: vertical;
- min-height: 120px;
-}
-
-.settings-input[type="number"] {
- max-width: 100px;
-}
-
-/* Custom Checkbox */
-.settings-checkbox-container {
- display: flex;
- align-items: center;
- cursor: pointer;
- color: #e0e0e0;
- font-size: 14px;
- user-select: none;
-}
-
-.settings-checkbox-container input[type="checkbox"] {
- display: none;
-}
-
-.settings-checkmark {
- width: 18px;
- height: 18px;
- background-color: #3a3a3a;
- border: 1px solid #555;
- border-radius: 3px;
- margin-right: 10px;
- position: relative;
- transition: all 0.2s ease;
-}
-
-.settings-checkbox-container input[type="checkbox"]:checked + .settings-checkmark {
- background-color: #5a9fd4;
- border-color: #5a9fd4;
-}
-
-.settings-checkbox-container input[type="checkbox"]:checked + .settings-checkmark::after {
- content: '';
- position: absolute;
- left: 5px;
- top: 2px;
- width: 6px;
- height: 10px;
- border: solid white;
- border-width: 0 2px 2px 0;
- transform: rotate(45deg);
-}
-
-/* Settings Buttons */
-.settings-btn {
- background-color: #3a3a3a;
- border: 1px solid #555;
- color: #e0e0e0;
- padding: 8px 16px;
- border-radius: 4px;
- cursor: pointer;
- font-size: 14px;
- font-weight: 500;
- transition: all 0.2s ease;
- display: inline-flex;
- align-items: center;
- gap: 6px;
-}
-
-.settings-btn:hover {
- background-color: #4a4a4a;
- border-color: #666;
-}
-
-.settings-btn-primary {
- background-color: #5a9fd4;
- border-color: #5a9fd4;
- color: #fff;
-}
-
-.settings-btn-primary:hover {
- background-color: #4a8fc4;
- border-color: #4a8fc4;
-}
-
-.settings-btn-danger {
- background-color: #d45a5a;
- border-color: #d45a5a;
- color: #fff;
-}
-
-.settings-btn-danger:hover {
- background-color: #c44a4a;
- border-color: #c44a4a;
-}
-
-.settings-btn-danger:disabled {
- background-color: #555;
- border-color: #555;
- color: #888;
- cursor: not-allowed;
-}
-
-.settings-btn-small {
- padding: 6px 10px;
- font-size: 12px;
-}
-
-/* Settings Help Links */
-.settings-help-links {
- display: flex;
- gap: 16px;
- margin-bottom: 8px;
-}
-
-button.settings-help {
- color: #5a9fd4;
- text-decoration: underline;
- cursor: pointer;
- font-size: 14px;
- background: none;
- border: none;
- padding: 0;
- font-family: inherit;
-}
-
-button.settings-help:hover {
- color: #7bbfef;
-}
-
-/* Settings Validation Errors */
-.settings-validation-errors {
- margin-top: 8px;
- padding: 8px;
- background-color: rgba(211, 90, 90, 0.1);
- border: 1px solid #d35a5a;
- border-radius: 4px;
- max-height: 200px;
- overflow-y: auto;
-}
-
-.settings-validation-error {
- color: #ff6b6b;
- font-size: 12px;
- line-height: 1.4;
- margin-bottom: 4px;
-}
-
-.settings-validation-error:last-child {
- margin-bottom: 0;
-}
-
-/* Templates List */
-.templates-list {
- display: flex;
- flex-direction: column;
- gap: 10px;
- margin-top: 15px;
-}
-
-.template-item {
- background-color: #3a3a3a;
- border: 1px solid #555;
- border-radius: 6px;
- padding: 15px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- transition: border-color 0.2s ease;
-}
-
-.template-item:hover {
- border-color: #666;
-}
-
-.template-info {
- flex: 1;
-}
-
-.template-name {
- color: #fff;
- font-size: 16px;
- font-weight: 600;
- margin: 0 0 5px 0;
-}
-
-.template-description {
- color: #b0b0b0;
- font-size: 14px;
- margin: 0 0 5px 0;
-}
-
-.template-tracks {
- color: #888;
- font-size: 12px;
- font-weight: 500;
-}
-
-.template-actions {
- display: flex;
- gap: 8px;
-}
-
-/* File Import Modal */
-.file-import-overlay {
- position: fixed;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background-color: rgba(0, 0, 0, 0.7);
- display: flex;
- align-items: center;
- justify-content: center;
- z-index: 10001;
- backdrop-filter: blur(2px);
-}
-
-.file-import-modal {
- background-color: #2d2d2d;
- border: 1px solid #3a3a3a;
- border-radius: 8px;
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
- width: 90%;
- max-width: 500px;
- max-height: 80vh;
- overflow: hidden;
- animation: fileImportFadeIn 0.2s ease-out;
-}
-
-@keyframes fileImportFadeIn {
- from {
- opacity: 0;
- transform: scale(0.95) translateY(-10px);
- }
- to {
- opacity: 1;
- transform: scale(1) translateY(0);
- }
-}
-
-.file-import-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 20px;
- border-bottom: 1px solid #3a3a3a;
- background-color: #252525;
-}
-
-.file-import-title {
- color: #e0e0e0;
- font-size: 18px;
- font-weight: 600;
- margin: 0;
-}
-
-.file-import-close-btn {
- background: transparent;
- border: none;
- color: #b0b0b0;
- cursor: pointer;
- padding: 8px;
- border-radius: 4px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 16px;
- transition: all 0.2s ease;
-}
-
-.file-import-close-btn:hover {
- background-color: #3a3a3a;
- color: #e0e0e0;
-}
-
-.file-import-drop-zone {
- padding: 40px 20px;
- margin: 20px;
- border: 2px dashed #555;
- border-radius: 8px;
- background-color: #1e1e1e;
- transition: all 0.3s ease;
- cursor: pointer;
-}
-
-.file-import-drop-zone:hover {
- border-color: #7b68ee;
- background-color: rgba(123, 104, 238, 0.05);
-}
-
-.file-import-drop-zone.drag-over {
- border-color: #7b68ee;
- background-color: rgba(123, 104, 238, 0.1);
- transform: scale(1.02);
-}
-
-.file-import-drop-content {
- text-align: center;
- color: #e0e0e0;
-}
-
-.file-import-icon {
- font-size: 48px;
- margin-bottom: 16px;
- opacity: 0.7;
-}
-
-.file-import-description {
- font-size: 18px;
- font-weight: 500;
- margin: 0 0 8px 0;
- color: #e0e0e0;
-}
-
-.file-import-formats {
- font-size: 14px;
- color: #b0b0b0;
- margin: 0 0 24px 0;
-}
-
-.file-import-divider {
- position: relative;
- margin: 24px 0;
- text-align: center;
-}
-
-.file-import-divider::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 1px;
- background-color: #3a3a3a;
-}
-
-.file-import-divider span {
- background-color: #1e1e1e;
- padding: 0 12px;
- color: #888;
- font-size: 12px;
- text-transform: uppercase;
- letter-spacing: 0.5px;
-}
-
-.file-import-browse-btn {
- display: inline-block;
- background-color: #5a9fd4;
- color: #fff;
- padding: 12px 24px;
- border-radius: 6px;
- font-size: 14px;
- font-weight: 500;
- cursor: pointer;
- transition: all 0.2s ease;
- border: none;
-}
-
-.file-import-browse-btn:hover {
- background-color: #4a8fc4;
- transform: translateY(-1px);
- box-shadow: 0 4px 12px rgba(90, 159, 212, 0.3);
-}
-
-/* Global Loading Overlay */
-.global-loading-overlay {
- position: fixed;
- inset: 0;
- background-color: rgba(0, 0, 0, 0.4);
- z-index: 20000;
- display: flex;
- align-items: center;
- justify-content: center;
- pointer-events: all; /* block interactions */
-}
-
-.global-loading-content {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 10px;
-}
-
-.global-loading-spinner {
- width: 40px;
- height: 40px;
- border: 4px solid rgba(255, 255, 255, 0.25);
- border-top-color: #ffffff;
- border-radius: 50%;
- animation: globalSpinner 1s linear infinite;
-}
-
-.global-loading-text {
- color: #e0e0e0;
- font-size: 14px;
-}
-
-@keyframes globalSpinner {
- to { transform: rotate(360deg); }
-}
-
-/* Processing wave animation */
-.processing-wave {
- background: linear-gradient(
- 90deg,
- rgba(135, 206, 250, 0.5) 0%,
- rgba(135, 206, 250, 0.8) 25%,
- rgb(171, 218, 250) 50%,
- rgba(135, 206, 250, 0.8) 75%,
- rgba(135, 206, 250, 0.5) 100%
- );
- background-size: 200% 100%;
- background-clip: text;
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- animation: wave 2s linear infinite;
-}
-
-@keyframes wave {
- 0% {
- background-position: 200% 0%;
- }
- 100% {
- background-position: -200% 0%;
- }
-}
diff --git a/src/App.tsx b/src/App.tsx
index feb3e0a..4f7fae2 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,10 +1,10 @@
import { useEffect } from 'react';
import './App.css';
+import './styles/shared.css';
import { useProjectStore } from './stores/projectStore';
import { useGlobalKeyboardHandler } from './hooks/useGlobalKeyboardHandler';
import Toolbar from './components/Toolbar';
import StatusBar from './components/StatusBar';
-import TrackControl from './components/TrackControl';
import MainContent from './components/MainContent';
import InstrumentSelection from './components/InstrumentSelection';
import ChatBox from './components/ChatBox';
@@ -135,14 +135,15 @@ function App() {
- {/* Track Control */}
-
{/* Status Bar */}
{/* Global Loading Overlay for instrument buffer loading */}
+
+ {/* Migration Loading Overlay */}
+
);
}
@@ -212,3 +213,22 @@ const GlobalLoadingOverlayContainer: React.FC = () => {
/>
);
};
+
+// Migration overlay — shown during one-time IndexedDB -> OPFS migration
+const MigrationOverlayContainer: React.FC = () => {
+ const [isMigrating, setIsMigrating] = useState(() => KGCore.instance().getIsMigrating());
+
+ useEffectReact(() => {
+ KGCore.instance().setMigrationStateChangeCallback(setIsMigrating);
+ return () => {
+ KGCore.instance().setMigrationStateChangeCallback(() => {});
+ };
+ }, []);
+
+ return (
+
+ );
+};
diff --git a/src/components/ChatBox.css b/src/components/ChatBox.css
new file mode 100644
index 0000000..6018761
--- /dev/null
+++ b/src/components/ChatBox.css
@@ -0,0 +1,313 @@
+/* ChatBox */
+.chatbox {
+ display: flex;
+ flex-direction: column;
+ width: var(--chat-box-width);
+ background-color: #2d2d2d;
+ border-left: 1px solid #3a3a3a;
+ flex-shrink: 0;
+}
+
+.chatbox.is-hidden {
+ display: none;
+}
+
+.chatbox-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between; /* left title, right actions */
+ background-color: #3a3a3a;
+ height: 40px;
+ border-bottom: 1px solid #4a4a4a;
+ padding: 0 15px;
+}
+
+.chatbox-actions {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+}
+
+.chatbox-action-btn {
+ background: transparent;
+ border: none;
+ cursor: pointer;
+ padding: 4px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ color: #e0e0e0;
+ font-size: 14px;
+}
+
+.chatbox-action-btn:hover {
+ background-color: #4a4a4a;
+ border-radius: 3px;
+}
+
+/* ChatBox export button wrapper and dropdown positioning */
+.chatbox-export-wrapper {
+ position: relative;
+ display: inline-block;
+}
+
+.chatbox-export-btn {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+}
+
+.chatbox-export-dropdown-anchor {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 10000;
+}
+
+.chatbox-export-dropdown .quant-dropdown {
+ width: 250px;
+ left: -200px;
+}
+
+.chatbox-header h3 {
+ color: #e0e0e0;
+ font-size: 12px;
+ font-weight: bold;
+ margin: 0;
+}
+
+.chatbox-content {
+ flex: 1;
+ padding: 15px;
+ color: #e0e0e0;
+ font-size: 12px;
+ overflow-y: auto;
+}
+
+/* Chat Messages */
+.chatbox-messages {
+ flex: 1;
+ padding: 10px;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.message-container {
+ width: 100%;
+ word-wrap: break-word;
+}
+
+.message-user {
+ width: 100%;
+}
+
+.message-assistant {
+ width: 100%;
+}
+
+.message-content {
+ padding: 8px 12px;
+ border-radius: 8px;
+ font-size: 12px;
+ line-height: 1.4;
+}
+
+/* User message styling - lighter background like input */
+.message-user .message-content {
+ background-color: #3a3a3a;
+ color: #e0e0e0;
+ border: 1px solid #4a4a4a;
+}
+
+/* Assistant message styling - transparent */
+.message-assistant .message-content {
+ background-color: transparent;
+ color: #e0e0e0;
+ border: 1px solid #2a2a2a;
+}
+
+/* Input Area */
+.chatbox-input-area {
+ padding: 10px;
+}
+
+.chatbox-input {
+ width: 100%;
+ padding: 8px 12px;
+ background-color: #4a4a4a;
+ border: 1px solid #5a5a5a;
+ border-radius: 6px;
+ color: #e0e0e0;
+ font-size: 12px;
+ outline: none;
+ resize: none;
+ min-height: 36px;
+ max-height: 120px;
+}
+
+.chatbox-input:focus {
+ border-color: #6a6a6a;
+ background-color: #4a4a4a;
+}
+
+.chatbox-input::placeholder {
+ color: #999;
+}
+
+
+/* Markdown styling in messages */
+.message-content h1,
+.message-content h2,
+.message-content h3 {
+ margin: 8px 0 4px 0;
+ color: #e0e0e0;
+}
+
+.message-content h3 {
+ font-size: 14px;
+}
+
+.message-content p {
+ margin: 4px 0;
+}
+
+.message-content ul,
+.message-content ol {
+ margin: 4px 0;
+ padding-left: 16px;
+}
+
+.message-content li {
+ margin: 2px 0;
+}
+
+.message-content code {
+ background-color: #2a2a2a;
+ padding: 2px 4px;
+ border-radius: 3px;
+ font-family: 'Courier New', Courier, monospace;
+ font-size: 11px;
+}
+
+.message-content pre {
+ background-color: #1a1a1a;
+ padding: 8px;
+ border-radius: 6px;
+ overflow-x: auto;
+ margin: 8px 0;
+}
+
+.message-content blockquote {
+ border-left: 3px solid #5a5a5a;
+ padding-left: 12px;
+ margin: 8px 0;
+ color: #ccc;
+}
+
+.message-content table {
+ border-collapse: collapse;
+ width: 100%;
+ margin: 8px 0;
+ font-size: 11px;
+}
+
+.message-content th,
+.message-content td {
+ border: 1px solid #4a4a4a;
+ padding: 4px 8px;
+ text-align: left;
+}
+
+.message-content th {
+ background-color: #3a3a3a;
+ font-weight: bold;
+}
+
+/* Abort link styling */
+.abort-link {
+ background: none !important;
+ border: none !important;
+ color: #7b68ee !important;
+ text-decoration: underline !important;
+ cursor: pointer !important;
+ padding: 0 !important;
+ font: inherit !important;
+ font-size: 12px !important;
+}
+
+.abort-link:hover {
+ color: #9b88ff !important;
+ text-decoration: none !important;
+}
+
+/* Tool XML Expander */
+.tool-xml-expander {
+ margin-bottom: 8px;
+}
+
+.tool-xml-expander-header {
+ color: #e0e0e0;
+ cursor: pointer;
+ user-select: none;
+ padding: 4px 8px;
+ /* background-color: #f5f5f5; */
+ border: 1px solid #2a2a2a;
+ border-radius: 4px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.tool-xml-expander-arrow {
+ font-size: 12px;
+ color: #666;
+}
+
+.tool-xml-expander-title {
+ /* font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace; */
+ font-size: 12px;
+ font-weight: bold;
+ color: #e0e0e0;
+}
+
+.tool-xml-expander-content {
+ margin-top: 4px;
+ padding: 8px;
+ background-color: #f9f9f9;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-family: 'Courier New', Monaco, 'Menlo', 'Ubuntu Mono', monospace;
+ font-size: 12px;
+ white-space: pre-wrap;
+ overflow: auto;
+ max-height: 200px;
+ color: #333;
+}
+
+/* Processing wave animation */
+.processing-wave {
+ background: linear-gradient(
+ 90deg,
+ rgba(135, 206, 250, 0.5) 0%,
+ rgba(135, 206, 250, 0.8) 25%,
+ rgb(171, 218, 250) 50%,
+ rgba(135, 206, 250, 0.8) 75%,
+ rgba(135, 206, 250, 0.5) 100%
+ );
+ background-size: 200% 100%;
+ background-clip: text;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ animation: wave 2s linear infinite;
+}
+
+@keyframes wave {
+ 0% {
+ background-position: 200% 0%;
+ }
+ 100% {
+ background-position: -200% 0%;
+ }
+}
diff --git a/src/components/ChatBox.tsx b/src/components/ChatBox.tsx
index 7852145..6fe7a06 100644
--- a/src/components/ChatBox.tsx
+++ b/src/components/ChatBox.tsx
@@ -1,4 +1,5 @@
import React, { useState, useRef, useEffect, memo, useCallback } from 'react';
+import './ChatBox.css';
import { FaPlus, FaBan, FaDownload } from 'react-icons/fa';
import { UserMessage, AssistantMessage } from './chat';
import { AgentCore } from '../agent/core/AgentCore';
diff --git a/src/components/InstrumentSelection.css b/src/components/InstrumentSelection.css
new file mode 100644
index 0000000..0805958
--- /dev/null
+++ b/src/components/InstrumentSelection.css
@@ -0,0 +1,123 @@
+/* Instrument Selection Panel */
+.instrument-selection {
+ display: flex;
+ flex-direction: column;
+ width: var(--instrument-selection-width);
+ background-color: #2d2d2d;
+ border-right: 1px solid #3a3a3a;
+ flex-shrink: 0;
+ position: relative;
+}
+
+.instrument-selection-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 40px;
+ padding: 0 12px;
+ background-color: transparent;
+ border: none;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 2;
+}
+
+.instrument-selection-header h3 {
+ color: #e0e0e0;
+ font-size: 12px;
+ font-weight: bold;
+}
+
+.instrument-selection-close-btn {
+ background: transparent;
+ border: none;
+ color: #e0e0e0;
+ cursor: pointer;
+ padding: 4px;
+ border-radius: 3px;
+}
+
+.instrument-selection-close-btn:hover {
+ background-color: #4a4a4a;
+}
+
+.instrument-selection-top {
+ height: 300px;
+ position: relative;
+ border-bottom: 1px solid #3a3a3a;
+ overflow: hidden;
+ background-image:
+ linear-gradient(rgba(0,0,0,0.35), rgba(0,0,0,0.35)),
+ url('/resources/instrument_bg.png');
+ background-size: cover; /* fill while keeping aspect ratio */
+ background-position: center;
+}
+
+.instrument-preview {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.instrument-preview img {
+ width: 256px;
+ height: 256px;
+ object-fit: contain;
+ border-radius: 6px;
+ opacity: 1;
+}
+
+.instrument-name-overlay {
+ position: absolute;
+ bottom: 16px;
+ left: 0;
+ right: 0;
+ text-align: center;
+ font-size: 16px;
+ color: #e0e0e0;
+ text-shadow: 0 1px 2px rgba(0,0,0,0.6);
+ z-index: 1;
+ font-weight: bold;
+}
+
+.instrument-selection-bottom {
+ flex: 1;
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ min-height: 0; /* allow children to scroll */
+}
+
+.instrument-groups, .instrument-list {
+ overflow: hidden;
+}
+
+/* vertical divider between groups and instruments */
+.instrument-groups {
+ border-right: 1px solid #3a3a3a;
+}
+
+.instrument-groups-list, .instrument-instruments-list {
+ height: 100%;
+ overflow-y: auto;
+}
+
+.instrument-group-item, .instrument-instrument-item {
+ padding: 8px 12px;
+ /* remove per-item separators */
+ border-bottom: none;
+ cursor: pointer;
+ font-size: 12px;
+ color: #e0e0e0;
+}
+
+.instrument-group-item:hover, .instrument-instrument-item:hover {
+ background-color: #3a3a3a;
+}
+
+.instrument-group-item.active, .instrument-instrument-item.active {
+ background-color: #4a4a4a;
+}
diff --git a/src/components/InstrumentSelection.tsx b/src/components/InstrumentSelection.tsx
index 454a60c..b923e5e 100644
--- a/src/components/InstrumentSelection.tsx
+++ b/src/components/InstrumentSelection.tsx
@@ -1,4 +1,5 @@
import React, { useMemo, useState, useEffect } from 'react';
+import './InstrumentSelection.css';
import { useProjectStore } from '../stores/projectStore';
import { INSTRUMENT_GROUPS, FLUIDR3_INSTRUMENT_MAP } from '../constants/generalMidiConstants';
import { KGMidiTrack, type InstrumentType } from '../core/track/KGMidiTrack';
diff --git a/src/components/MainContent.css b/src/components/MainContent.css
new file mode 100644
index 0000000..9dec725
--- /dev/null
+++ b/src/components/MainContent.css
@@ -0,0 +1,105 @@
+/* Main content */
+.main-content {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ overflow: auto; /* Main scrollable container */
+ position: relative;
+}
+
+.main-content-wrapper {
+ display: flex;
+ flex-direction: column;
+ min-width: calc(200px + var(--max-number-of-bars) * var(--track-grid-bar-width)); /* info width + grid width */
+ min-height: fit-content;
+ position: relative;
+}
+
+.top-left-spacer {
+ position: fixed;
+ top: 50px;
+ left: 0;
+ width: 200px;
+ height: 20px;
+ background-color: #2d2d2d;
+ border-bottom: 1px solid #3a3a3a;
+ border-right: 1px solid #3a3a3a;
+ z-index: 1002; /* Higher than other elements to ensure it's always visible */
+}
+
+/* Offset spacer when instrument selection panel is visible on the left */
+.main-content.has-left-instrument .top-left-spacer {
+ left: 300px;
+}
+
+.bar-numbers {
+ position: sticky;
+ top: 0;
+ height: 20px;
+ display: flex;
+ border-bottom: 1px solid #3a3a3a;
+ background-color: #2d2d2d;
+ z-index: 20;
+ margin-left: 200px; /* Offset for info-container */
+ width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Exact width for 32 bars */
+ cursor: pointer; /* Show pointer cursor on hover to indicate interactivity */
+}
+
+.bar-numbers:hover {
+ cursor: url("data:image/svg+xml,%3csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M4 6h8l-4 4-4-4z' fill='%23e0e0e0'/%3e%3c/svg%3e") 8 8, pointer;
+}
+
+.bar-number-cell {
+ min-width: var(--track-grid-bar-width);
+ width: var(--track-grid-bar-width);
+ flex-shrink: 0;
+ flex-grow: 0;
+ height: 20px;
+ text-align: center;
+ font-size: 12px;
+ border-right: 1px solid #3a3a3a;
+ color: #999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+}
+
+.bar-number-cell.looped {
+ background-color: #e1ae01;
+ color: #1e1e1e;
+}
+
+.main-content-body {
+ display: flex;
+ min-height: fit-content;
+}
+
+.info-container {
+ position: sticky;
+ left: 0;
+ width: 200px;
+ z-index: 1002;
+ background-color: #2d2d2d;
+ align-self: flex-start;
+}
+
+/* Shift the bar numbers and info panel when instrument selection is present */
+/* No need to shift bar numbers or info container; they live inside main content.
+ Only shift the fixed spacer when the left panel is present. */
+
+.track-top-spacer {
+ height: 20px;
+ border-bottom: 1px solid #3a3a3a;
+ background-color: #2d2d2d;
+ position: sticky;
+ top: 0;
+ z-index: 15;
+}
+
+.grid-container {
+ margin-left: 0; /* No need for margin since we're using flex */
+ min-width: calc(var(--max-number-of-bars) * var(--track-grid-bar-width)); /* Ensure minimum width */
+ min-height: fit-content;
+ position: relative; /* Required for absolute positioned playhead */
+}
diff --git a/src/components/MainContent.tsx b/src/components/MainContent.tsx
index 76e742c..f09f55f 100644
--- a/src/components/MainContent.tsx
+++ b/src/components/MainContent.tsx
@@ -1,4 +1,5 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
+import './MainContent.css';
import { createPortal } from 'react-dom';
import { useProjectStore } from '../stores/projectStore';
import { KGCore } from '../core/KGCore';
@@ -18,7 +19,7 @@ interface MainContentProps {
}
const MainContent: React.FC = ({
- onTrackClick = () => {} // Default to empty function if not provided
+ onTrackClick = () => { } // Default to empty function if not provided
}) => {
const {
tracks,
@@ -33,18 +34,19 @@ const MainContent: React.FC = ({
showPianoRoll,
activeRegionId,
setShowPianoRoll,
- setActiveRegionId
+ setActiveRegionId,
+ addTrack
} = useProjectStore();
-
+
// State to store regions
const [regions, setRegions] = useState([]);
-
+
// Drag state for track grid highlighting
const [draggedTrackIndex, setDraggedTrackIndex] = useState(null);
const [dragOverTrackIndex, setDragOverTrackIndex] = useState(null);
-
+
// Piano roll state is now managed by the store - removed local state
-
+
// Region selection state
const [selectedRegionId, setSelectedRegionId] = useState(null);
@@ -64,16 +66,16 @@ const MainContent: React.FC = ({
// Register the delete function with the global manager
useEffect(() => {
regionDeleteManager.registerDeleteCallback(deleteSelectedRegions);
-
+
// Cleanup on unmount
return () => {
regionDeleteManager.unregisterDeleteCallback();
};
}, [deleteSelectedRegions]);
-
+
// Refs to track pending updates for verification
const pendingUpdates = useRef