inup 1.4.0 → 1.4.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/README.md +31 -106
- package/dist/cli.js +0 -0
- package/dist/{constants.js → config/constants.js} +8 -3
- package/dist/config/index.js +18 -0
- package/dist/core/package-detector.js +17 -6
- package/dist/interactive-ui.js +104 -30
- package/dist/services/jsdelivr-registry.js +24 -44
- package/dist/services/npm-registry.js +45 -57
- package/dist/services/version-checker.js +2 -2
- package/dist/ui/index.js +18 -10
- package/dist/ui/input-handler.js +97 -3
- package/dist/ui/renderer/index.js +7 -2
- package/dist/ui/renderer/package-list.js +164 -80
- package/dist/ui/renderer/theme-selector.js +83 -0
- package/dist/ui/state/filter-manager.js +48 -0
- package/dist/ui/state/index.js +12 -0
- package/dist/ui/state/modal-manager.js +45 -0
- package/dist/ui/state/navigation-manager.js +154 -0
- package/dist/ui/state/state-manager.js +240 -0
- package/dist/ui/state/theme-manager.js +85 -0
- package/dist/ui/themes-colors.js +168 -0
- package/dist/ui/themes.js +27 -0
- package/dist/ui/utils/cursor.js +33 -0
- package/dist/ui/utils/index.js +8 -0
- package/dist/ui/{utils.js → utils/version.js} +24 -1
- package/dist/utils/config.js +57 -0
- package/dist/utils/version.js +11 -6
- package/package.json +16 -17
- package/dist/ui/state.js +0 -250
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NavigationManager = void 0;
|
|
4
|
+
class NavigationManager {
|
|
5
|
+
constructor(initialRow = 0, maxVisibleItems = 19) {
|
|
6
|
+
this.renderableItems = [];
|
|
7
|
+
this.headerLines = 5; // title (with label) + empty + 1 instruction line + status + empty
|
|
8
|
+
this.state = {
|
|
9
|
+
currentRow: initialRow,
|
|
10
|
+
previousRow: -1,
|
|
11
|
+
scrollOffset: 0,
|
|
12
|
+
previousScrollOffset: 0,
|
|
13
|
+
};
|
|
14
|
+
this.maxVisibleItems = maxVisibleItems;
|
|
15
|
+
}
|
|
16
|
+
getState() {
|
|
17
|
+
return { ...this.state };
|
|
18
|
+
}
|
|
19
|
+
getCurrentRow() {
|
|
20
|
+
return this.state.currentRow;
|
|
21
|
+
}
|
|
22
|
+
getScrollOffset() {
|
|
23
|
+
return this.state.scrollOffset;
|
|
24
|
+
}
|
|
25
|
+
setCurrentRow(row) {
|
|
26
|
+
this.state.previousRow = this.state.currentRow;
|
|
27
|
+
this.state.currentRow = row;
|
|
28
|
+
}
|
|
29
|
+
setScrollOffset(offset) {
|
|
30
|
+
this.state.previousScrollOffset = this.state.scrollOffset;
|
|
31
|
+
this.state.scrollOffset = offset;
|
|
32
|
+
}
|
|
33
|
+
setRenderableItems(items) {
|
|
34
|
+
this.renderableItems = items;
|
|
35
|
+
}
|
|
36
|
+
setMaxVisibleItems(maxVisible) {
|
|
37
|
+
this.maxVisibleItems = maxVisible;
|
|
38
|
+
}
|
|
39
|
+
getMaxVisibleItems() {
|
|
40
|
+
return this.maxVisibleItems;
|
|
41
|
+
}
|
|
42
|
+
// Convert package index to visual row index in renderable items
|
|
43
|
+
packageIndexToVisualIndex(packageIndex) {
|
|
44
|
+
// If no renderable items (flat mode), visual index equals package index
|
|
45
|
+
if (this.renderableItems.length === 0) {
|
|
46
|
+
return packageIndex;
|
|
47
|
+
}
|
|
48
|
+
// Otherwise search in renderable items (grouped mode)
|
|
49
|
+
for (let i = 0; i < this.renderableItems.length; i++) {
|
|
50
|
+
const item = this.renderableItems[i];
|
|
51
|
+
if (item.type === 'package' && item.originalIndex === packageIndex) {
|
|
52
|
+
return i;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
// Find the next navigable package index in the given direction
|
|
58
|
+
findNextPackageIndex(currentPackageIndex, direction, totalPackages) {
|
|
59
|
+
if (this.renderableItems.length === 0) {
|
|
60
|
+
// Fallback to simple navigation if no renderable items
|
|
61
|
+
if (direction === 'up') {
|
|
62
|
+
return currentPackageIndex <= 0 ? totalPackages - 1 : currentPackageIndex - 1;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
return currentPackageIndex >= totalPackages - 1 ? 0 : currentPackageIndex + 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Find current visual index
|
|
69
|
+
const currentVisualIndex = this.packageIndexToVisualIndex(currentPackageIndex);
|
|
70
|
+
// Get all package items with their visual indices
|
|
71
|
+
const packageItems = [];
|
|
72
|
+
for (let i = 0; i < this.renderableItems.length; i++) {
|
|
73
|
+
const item = this.renderableItems[i];
|
|
74
|
+
if (item.type === 'package') {
|
|
75
|
+
packageItems.push({ visualIndex: i, packageIndex: item.originalIndex });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (packageItems.length === 0)
|
|
79
|
+
return currentPackageIndex;
|
|
80
|
+
// Find current position in packageItems
|
|
81
|
+
const currentPos = packageItems.findIndex((p) => p.packageIndex === currentPackageIndex);
|
|
82
|
+
if (currentPos === -1)
|
|
83
|
+
return packageItems[0].packageIndex;
|
|
84
|
+
// Navigate with wrap-around at boundaries
|
|
85
|
+
if (direction === 'up') {
|
|
86
|
+
const newPos = currentPos <= 0 ? packageItems.length - 1 : currentPos - 1;
|
|
87
|
+
return packageItems[newPos].packageIndex;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const newPos = currentPos >= packageItems.length - 1 ? 0 : currentPos + 1;
|
|
91
|
+
return packageItems[newPos].packageIndex;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
navigateUp(totalItems) {
|
|
95
|
+
if (totalItems === 0)
|
|
96
|
+
return;
|
|
97
|
+
this.state.previousRow = this.state.currentRow;
|
|
98
|
+
this.state.currentRow = this.findNextPackageIndex(this.state.currentRow, 'up', totalItems);
|
|
99
|
+
this.ensureVisible(this.state.currentRow, totalItems);
|
|
100
|
+
}
|
|
101
|
+
navigateDown(totalItems) {
|
|
102
|
+
if (totalItems === 0)
|
|
103
|
+
return;
|
|
104
|
+
this.state.previousRow = this.state.currentRow;
|
|
105
|
+
this.state.currentRow = this.findNextPackageIndex(this.state.currentRow, 'down', totalItems);
|
|
106
|
+
this.ensureVisible(this.state.currentRow, totalItems);
|
|
107
|
+
}
|
|
108
|
+
ensureVisible(packageIndex, totalPackages) {
|
|
109
|
+
// Convert package index to visual index for scrolling
|
|
110
|
+
const visualIndex = this.packageIndexToVisualIndex(packageIndex);
|
|
111
|
+
const totalVisualItems = this.renderableItems.length || totalPackages;
|
|
112
|
+
// Try to show section header if the current item is just below a header
|
|
113
|
+
let targetVisualIndex = visualIndex;
|
|
114
|
+
if (visualIndex > 0) {
|
|
115
|
+
const prevItem = this.renderableItems[visualIndex - 1];
|
|
116
|
+
if (prevItem?.type === 'header') {
|
|
117
|
+
targetVisualIndex = visualIndex - 1;
|
|
118
|
+
}
|
|
119
|
+
else if (visualIndex > 1) {
|
|
120
|
+
// Also check for spacer + header combo (for first package in non-first section)
|
|
121
|
+
const prevPrevItem = this.renderableItems[visualIndex - 2];
|
|
122
|
+
if (prevItem?.type === 'spacer' && prevPrevItem?.type === 'header') {
|
|
123
|
+
// Show spacer and header if possible
|
|
124
|
+
targetVisualIndex = Math.max(0, visualIndex - 2);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Scrolling up: scroll up by 1 item
|
|
129
|
+
if (targetVisualIndex < this.state.scrollOffset) {
|
|
130
|
+
this.state.scrollOffset = targetVisualIndex;
|
|
131
|
+
}
|
|
132
|
+
// Scrolling down: scroll down by 1 item (smooth scrolling)
|
|
133
|
+
else if (visualIndex >= this.state.scrollOffset + this.maxVisibleItems) {
|
|
134
|
+
this.state.scrollOffset += 1;
|
|
135
|
+
}
|
|
136
|
+
// Ensure scrollOffset doesn't go negative or beyond bounds
|
|
137
|
+
const maxScroll = Math.max(0, totalVisualItems - this.maxVisibleItems);
|
|
138
|
+
this.state.scrollOffset = Math.max(0, Math.min(this.state.scrollOffset, maxScroll));
|
|
139
|
+
// Handle wrap-around: if we're at the last item and it's out of view, show it at bottom
|
|
140
|
+
if (visualIndex === totalVisualItems - 1 &&
|
|
141
|
+
visualIndex >= this.state.scrollOffset + this.maxVisibleItems) {
|
|
142
|
+
this.state.scrollOffset = maxScroll;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
resetForResize(totalItems) {
|
|
146
|
+
this.ensureVisible(this.state.currentRow, totalItems);
|
|
147
|
+
}
|
|
148
|
+
markRendered() {
|
|
149
|
+
this.state.previousRow = this.state.currentRow;
|
|
150
|
+
this.state.previousScrollOffset = this.state.scrollOffset;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.NavigationManager = NavigationManager;
|
|
154
|
+
//# sourceMappingURL=navigation-manager.js.map
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StateManager = void 0;
|
|
4
|
+
const navigation_manager_1 = require("./navigation-manager");
|
|
5
|
+
const modal_manager_1 = require("./modal-manager");
|
|
6
|
+
const filter_manager_1 = require("./filter-manager");
|
|
7
|
+
const theme_manager_1 = require("./theme-manager");
|
|
8
|
+
class StateManager {
|
|
9
|
+
constructor(initialRow = 0, terminalHeight = 24) {
|
|
10
|
+
this.headerLines = 5; // title (with label) + empty + 1 instruction line + status + empty
|
|
11
|
+
const maxVisibleItems = Math.max(5, terminalHeight - this.headerLines - 2);
|
|
12
|
+
this.navigationManager = new navigation_manager_1.NavigationManager(initialRow, maxVisibleItems);
|
|
13
|
+
this.modalManager = new modal_manager_1.ModalManager();
|
|
14
|
+
this.filterManager = new filter_manager_1.FilterManager();
|
|
15
|
+
this.themeManager = new theme_manager_1.ThemeManager();
|
|
16
|
+
this.displayState = {
|
|
17
|
+
maxVisibleItems,
|
|
18
|
+
terminalHeight,
|
|
19
|
+
};
|
|
20
|
+
this.renderState = {
|
|
21
|
+
forceFullRender: true,
|
|
22
|
+
renderedLines: [],
|
|
23
|
+
renderableItems: [],
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Aggregate all state for backward compatibility
|
|
27
|
+
getUIState() {
|
|
28
|
+
const navState = this.navigationManager.getState();
|
|
29
|
+
const modalState = this.modalManager.getState();
|
|
30
|
+
const filterState = this.filterManager.getState();
|
|
31
|
+
const themeState = this.themeManager.getState();
|
|
32
|
+
return {
|
|
33
|
+
currentRow: navState.currentRow,
|
|
34
|
+
previousRow: navState.previousRow,
|
|
35
|
+
scrollOffset: navState.scrollOffset,
|
|
36
|
+
previousScrollOffset: navState.previousScrollOffset,
|
|
37
|
+
maxVisibleItems: this.displayState.maxVisibleItems,
|
|
38
|
+
terminalHeight: this.displayState.terminalHeight,
|
|
39
|
+
forceFullRender: this.renderState.forceFullRender,
|
|
40
|
+
renderedLines: this.renderState.renderedLines,
|
|
41
|
+
renderableItems: this.renderState.renderableItems,
|
|
42
|
+
showInfoModal: modalState.showInfoModal,
|
|
43
|
+
infoModalRow: modalState.infoModalRow,
|
|
44
|
+
isLoadingModalInfo: modalState.isLoadingModalInfo,
|
|
45
|
+
filterMode: filterState.filterMode,
|
|
46
|
+
filterQuery: filterState.filterQuery,
|
|
47
|
+
showThemeModal: themeState.showThemeModal,
|
|
48
|
+
currentTheme: themeState.currentTheme,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
setRenderableItems(items) {
|
|
52
|
+
this.renderState.renderableItems = items;
|
|
53
|
+
this.navigationManager.setRenderableItems(items);
|
|
54
|
+
}
|
|
55
|
+
// Navigation delegation
|
|
56
|
+
navigateUp(totalItems) {
|
|
57
|
+
this.navigationManager.navigateUp(totalItems);
|
|
58
|
+
}
|
|
59
|
+
navigateDown(totalItems) {
|
|
60
|
+
this.navigationManager.navigateDown(totalItems);
|
|
61
|
+
}
|
|
62
|
+
packageIndexToVisualIndex(packageIndex) {
|
|
63
|
+
return this.navigationManager.packageIndexToVisualIndex(packageIndex);
|
|
64
|
+
}
|
|
65
|
+
// Selection logic (still in StateManager as it operates on external state)
|
|
66
|
+
updateSelection(states, direction) {
|
|
67
|
+
if (states.length === 0)
|
|
68
|
+
return;
|
|
69
|
+
const currentRow = this.navigationManager.getCurrentRow();
|
|
70
|
+
const currentState = states[currentRow];
|
|
71
|
+
if (!currentState)
|
|
72
|
+
return;
|
|
73
|
+
if (direction === 'left') {
|
|
74
|
+
// Move selection left with wraparound: latest -> range -> none -> latest
|
|
75
|
+
if (currentState.selectedOption === 'latest') {
|
|
76
|
+
if (currentState.hasRangeUpdate) {
|
|
77
|
+
currentState.selectedOption = 'range';
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
currentState.selectedOption = 'none';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (currentState.selectedOption === 'range') {
|
|
84
|
+
currentState.selectedOption = 'none';
|
|
85
|
+
}
|
|
86
|
+
else if (currentState.selectedOption === 'none') {
|
|
87
|
+
// Wrap around to the last available option
|
|
88
|
+
if (currentState.hasMajorUpdate) {
|
|
89
|
+
currentState.selectedOption = 'latest';
|
|
90
|
+
}
|
|
91
|
+
else if (currentState.hasRangeUpdate) {
|
|
92
|
+
currentState.selectedOption = 'range';
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
// Move selection right with wraparound: none -> range -> latest -> none
|
|
98
|
+
if (currentState.selectedOption === 'none') {
|
|
99
|
+
if (currentState.hasRangeUpdate) {
|
|
100
|
+
currentState.selectedOption = 'range';
|
|
101
|
+
}
|
|
102
|
+
else if (currentState.hasMajorUpdate) {
|
|
103
|
+
currentState.selectedOption = 'latest';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (currentState.selectedOption === 'range') {
|
|
107
|
+
if (currentState.hasMajorUpdate) {
|
|
108
|
+
currentState.selectedOption = 'latest';
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// Wrap around to none
|
|
112
|
+
currentState.selectedOption = 'none';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
else if (currentState.selectedOption === 'latest') {
|
|
116
|
+
// Wrap around to none
|
|
117
|
+
currentState.selectedOption = 'none';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
bulkSelectMinor(states) {
|
|
122
|
+
if (states.length === 0)
|
|
123
|
+
return;
|
|
124
|
+
states.forEach((state) => {
|
|
125
|
+
if (state.hasRangeUpdate) {
|
|
126
|
+
state.selectedOption = 'range';
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
bulkSelectLatest(states) {
|
|
131
|
+
if (states.length === 0)
|
|
132
|
+
return;
|
|
133
|
+
states.forEach((state) => {
|
|
134
|
+
if (state.hasMajorUpdate) {
|
|
135
|
+
state.selectedOption = 'latest';
|
|
136
|
+
}
|
|
137
|
+
else if (state.hasRangeUpdate) {
|
|
138
|
+
state.selectedOption = 'range';
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
bulkUnselectAll(states) {
|
|
143
|
+
if (states.length === 0)
|
|
144
|
+
return;
|
|
145
|
+
states.forEach((state) => {
|
|
146
|
+
state.selectedOption = 'none';
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// Modal delegation
|
|
150
|
+
toggleInfoModal() {
|
|
151
|
+
const currentRow = this.navigationManager.getCurrentRow();
|
|
152
|
+
this.modalManager.toggleInfoModal(currentRow);
|
|
153
|
+
this.renderState.forceFullRender = true;
|
|
154
|
+
}
|
|
155
|
+
closeInfoModal() {
|
|
156
|
+
this.modalManager.closeInfoModal();
|
|
157
|
+
this.renderState.forceFullRender = true;
|
|
158
|
+
}
|
|
159
|
+
setModalLoading(isLoading) {
|
|
160
|
+
this.modalManager.setModalLoading(isLoading);
|
|
161
|
+
this.renderState.forceFullRender = true;
|
|
162
|
+
}
|
|
163
|
+
// Filter delegation
|
|
164
|
+
enterFilterMode() {
|
|
165
|
+
this.filterManager.enterFilterMode();
|
|
166
|
+
this.renderState.forceFullRender = true;
|
|
167
|
+
}
|
|
168
|
+
exitFilterMode() {
|
|
169
|
+
this.filterManager.exitFilterMode();
|
|
170
|
+
this.navigationManager.setCurrentRow(0);
|
|
171
|
+
this.navigationManager.setScrollOffset(0);
|
|
172
|
+
this.renderState.forceFullRender = true;
|
|
173
|
+
}
|
|
174
|
+
updateFilterQuery(query) {
|
|
175
|
+
this.filterManager.updateFilterQuery(query);
|
|
176
|
+
this.navigationManager.setCurrentRow(0);
|
|
177
|
+
this.navigationManager.setScrollOffset(0);
|
|
178
|
+
}
|
|
179
|
+
appendToFilterQuery(char) {
|
|
180
|
+
this.filterManager.appendToFilterQuery(char);
|
|
181
|
+
this.navigationManager.setCurrentRow(0);
|
|
182
|
+
this.navigationManager.setScrollOffset(0);
|
|
183
|
+
this.renderState.forceFullRender = true;
|
|
184
|
+
}
|
|
185
|
+
deleteFromFilterQuery() {
|
|
186
|
+
this.filterManager.deleteFromFilterQuery();
|
|
187
|
+
this.navigationManager.setCurrentRow(0);
|
|
188
|
+
this.navigationManager.setScrollOffset(0);
|
|
189
|
+
this.renderState.forceFullRender = true;
|
|
190
|
+
}
|
|
191
|
+
getFilteredStates(allStates) {
|
|
192
|
+
return this.filterManager.getFilteredStates(allStates);
|
|
193
|
+
}
|
|
194
|
+
// Display and render state management
|
|
195
|
+
updateTerminalHeight(newHeight) {
|
|
196
|
+
const newMaxVisibleItems = Math.max(5, newHeight - this.headerLines - 2);
|
|
197
|
+
if (newHeight !== this.displayState.terminalHeight ||
|
|
198
|
+
newMaxVisibleItems !== this.displayState.maxVisibleItems) {
|
|
199
|
+
this.displayState.terminalHeight = newHeight;
|
|
200
|
+
this.displayState.maxVisibleItems = newMaxVisibleItems;
|
|
201
|
+
this.navigationManager.setMaxVisibleItems(newMaxVisibleItems);
|
|
202
|
+
return true; // Changed
|
|
203
|
+
}
|
|
204
|
+
return false; // No change
|
|
205
|
+
}
|
|
206
|
+
markRendered(renderedLines) {
|
|
207
|
+
this.renderState.renderedLines = renderedLines;
|
|
208
|
+
this.navigationManager.markRendered();
|
|
209
|
+
}
|
|
210
|
+
setInitialRender(isInitial) {
|
|
211
|
+
this.renderState.forceFullRender = isInitial;
|
|
212
|
+
}
|
|
213
|
+
resetForResize() {
|
|
214
|
+
const totalItems = this.renderState.renderableItems.length || this.displayState.maxVisibleItems;
|
|
215
|
+
this.navigationManager.resetForResize(totalItems);
|
|
216
|
+
this.renderState.forceFullRender = true;
|
|
217
|
+
}
|
|
218
|
+
// Theme delegation
|
|
219
|
+
toggleThemeModal() {
|
|
220
|
+
this.themeManager.toggleThemeModal();
|
|
221
|
+
this.renderState.forceFullRender = true;
|
|
222
|
+
}
|
|
223
|
+
closeThemeModal() {
|
|
224
|
+
this.themeManager.closeThemeModal();
|
|
225
|
+
this.renderState.forceFullRender = true;
|
|
226
|
+
}
|
|
227
|
+
previewTheme(themeName) {
|
|
228
|
+
this.themeManager.previewTheme(themeName);
|
|
229
|
+
this.renderState.forceFullRender = true;
|
|
230
|
+
}
|
|
231
|
+
confirmTheme() {
|
|
232
|
+
this.themeManager.confirmTheme();
|
|
233
|
+
this.renderState.forceFullRender = true;
|
|
234
|
+
}
|
|
235
|
+
getThemeManager() {
|
|
236
|
+
return this.themeManager;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
exports.StateManager = StateManager;
|
|
240
|
+
//# sourceMappingURL=state-manager.js.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ThemeManager = void 0;
|
|
4
|
+
exports.getThemeColors = getThemeColors;
|
|
5
|
+
exports.getCurrentThemeName = getCurrentThemeName;
|
|
6
|
+
const themes_1 = require("../themes");
|
|
7
|
+
const config_1 = require("../../utils/config");
|
|
8
|
+
// Global theme state for renderers to access
|
|
9
|
+
let globalCurrentTheme = themes_1.defaultTheme;
|
|
10
|
+
class ThemeManager {
|
|
11
|
+
constructor() {
|
|
12
|
+
// Load saved theme from config, fallback to default
|
|
13
|
+
const savedTheme = config_1.configManager.getTheme();
|
|
14
|
+
const initialTheme = savedTheme && themes_1.themeNames.includes(savedTheme) ? savedTheme : themes_1.defaultTheme;
|
|
15
|
+
this.state = {
|
|
16
|
+
showThemeModal: false,
|
|
17
|
+
currentTheme: initialTheme,
|
|
18
|
+
previewTheme: initialTheme,
|
|
19
|
+
};
|
|
20
|
+
globalCurrentTheme = initialTheme;
|
|
21
|
+
}
|
|
22
|
+
getState() {
|
|
23
|
+
return { ...this.state };
|
|
24
|
+
}
|
|
25
|
+
isThemeModalOpen() {
|
|
26
|
+
return this.state.showThemeModal;
|
|
27
|
+
}
|
|
28
|
+
getCurrentTheme() {
|
|
29
|
+
return this.state.currentTheme;
|
|
30
|
+
}
|
|
31
|
+
getPreviewTheme() {
|
|
32
|
+
return this.state.previewTheme;
|
|
33
|
+
}
|
|
34
|
+
openThemeModal() {
|
|
35
|
+
this.state.showThemeModal = true;
|
|
36
|
+
// Start preview with current theme
|
|
37
|
+
this.state.previewTheme = this.state.currentTheme;
|
|
38
|
+
}
|
|
39
|
+
closeThemeModal() {
|
|
40
|
+
this.state.showThemeModal = false;
|
|
41
|
+
// Reset preview to current theme when closing without confirmation
|
|
42
|
+
this.state.previewTheme = this.state.currentTheme;
|
|
43
|
+
}
|
|
44
|
+
previewTheme(themeName) {
|
|
45
|
+
if (themes_1.themeNames.includes(themeName)) {
|
|
46
|
+
this.state.previewTheme = themeName;
|
|
47
|
+
// Update global theme immediately for live preview in UI
|
|
48
|
+
globalCurrentTheme = themeName;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
confirmTheme() {
|
|
52
|
+
this.state.currentTheme = this.state.previewTheme;
|
|
53
|
+
globalCurrentTheme = this.state.currentTheme;
|
|
54
|
+
// Save theme to config
|
|
55
|
+
config_1.configManager.setTheme(this.state.currentTheme);
|
|
56
|
+
this.closeThemeModal();
|
|
57
|
+
}
|
|
58
|
+
setTheme(themeName) {
|
|
59
|
+
if (themes_1.themeNames.includes(themeName)) {
|
|
60
|
+
this.state.currentTheme = themeName;
|
|
61
|
+
this.state.previewTheme = themeName;
|
|
62
|
+
globalCurrentTheme = themeName;
|
|
63
|
+
// Save theme to config
|
|
64
|
+
config_1.configManager.setTheme(themeName);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
toggleThemeModal() {
|
|
68
|
+
if (this.state.showThemeModal) {
|
|
69
|
+
this.closeThemeModal();
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.openThemeModal();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.ThemeManager = ThemeManager;
|
|
77
|
+
// Helper function for renderers to get current theme colors
|
|
78
|
+
function getThemeColors() {
|
|
79
|
+
return themes_1.themes[globalCurrentTheme]?.colors || themes_1.themes[themes_1.defaultTheme].colors;
|
|
80
|
+
}
|
|
81
|
+
// Helper function to get current theme name
|
|
82
|
+
function getCurrentThemeName() {
|
|
83
|
+
return globalCurrentTheme;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=theme-manager.js.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.themeColors = void 0;
|
|
7
|
+
exports.getThemeColor = getThemeColor;
|
|
8
|
+
exports.getThemeBgColor = getThemeBgColor;
|
|
9
|
+
exports.getTerminalBgColorCode = getTerminalBgColorCode;
|
|
10
|
+
exports.getTerminalResetCode = getTerminalResetCode;
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
+
const theme_manager_1 = require("./state/theme-manager");
|
|
13
|
+
// Centralized theme color definitions - single source of truth
|
|
14
|
+
const themeColorDefinitions = {
|
|
15
|
+
default: {
|
|
16
|
+
bg: '#1a1a1a',
|
|
17
|
+
primary: 'cyan',
|
|
18
|
+
secondary: 'magenta',
|
|
19
|
+
success: 'green',
|
|
20
|
+
warning: 'yellow',
|
|
21
|
+
error: 'red',
|
|
22
|
+
border: 'gray',
|
|
23
|
+
text: 'white',
|
|
24
|
+
textSecondary: 'gray',
|
|
25
|
+
},
|
|
26
|
+
dracula: {
|
|
27
|
+
bg: '#282A36',
|
|
28
|
+
primary: '#8BE9FD',
|
|
29
|
+
secondary: '#FF79C6',
|
|
30
|
+
success: '#50FA7B',
|
|
31
|
+
warning: '#F1FA8C',
|
|
32
|
+
error: '#FF5555',
|
|
33
|
+
border: '#44475A',
|
|
34
|
+
text: '#F8F8F2',
|
|
35
|
+
textSecondary: '#6272A4',
|
|
36
|
+
},
|
|
37
|
+
vsc: {
|
|
38
|
+
bg: '#1E1E1E',
|
|
39
|
+
primary: '#4FC1FF',
|
|
40
|
+
secondary: '#4EC9B0',
|
|
41
|
+
success: '#89D185',
|
|
42
|
+
warning: '#E5C07B',
|
|
43
|
+
error: '#F48771',
|
|
44
|
+
border: '#3E3E42',
|
|
45
|
+
text: '#D4D4D4',
|
|
46
|
+
textSecondary: '#858585',
|
|
47
|
+
},
|
|
48
|
+
monokai: {
|
|
49
|
+
bg: '#272822',
|
|
50
|
+
primary: '#66D9EF',
|
|
51
|
+
secondary: '#AE81FF',
|
|
52
|
+
success: '#A6E22E',
|
|
53
|
+
warning: '#E6DB74',
|
|
54
|
+
error: '#F92672',
|
|
55
|
+
border: '#49483E',
|
|
56
|
+
text: '#F8F8F2',
|
|
57
|
+
textSecondary: '#75715E',
|
|
58
|
+
},
|
|
59
|
+
catppuccin: {
|
|
60
|
+
bg: '#1E1E2E',
|
|
61
|
+
primary: '#89B4FA',
|
|
62
|
+
secondary: '#CBA6F7',
|
|
63
|
+
success: '#A6E3A1',
|
|
64
|
+
warning: '#F9E2AF',
|
|
65
|
+
error: '#F38BA8',
|
|
66
|
+
border: '#45475A',
|
|
67
|
+
text: '#CDD6F4',
|
|
68
|
+
textSecondary: '#BAC2DE',
|
|
69
|
+
},
|
|
70
|
+
tokyonight: {
|
|
71
|
+
bg: '#1A1B26',
|
|
72
|
+
primary: '#7AA2F7',
|
|
73
|
+
secondary: '#BB9AF7',
|
|
74
|
+
success: '#9ECE6A',
|
|
75
|
+
warning: '#E0AF68',
|
|
76
|
+
error: '#F7768E',
|
|
77
|
+
border: '#414868',
|
|
78
|
+
text: '#C0CAF5',
|
|
79
|
+
textSecondary: '#A9B1D6',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
// Helper to apply color - handles both hex and named colors
|
|
83
|
+
function applyColor(color, text) {
|
|
84
|
+
if (color.startsWith('#')) {
|
|
85
|
+
return chalk_1.default.hex(color)(text);
|
|
86
|
+
}
|
|
87
|
+
return chalk_1.default[color](text);
|
|
88
|
+
}
|
|
89
|
+
const themeColorSchemes = Object.entries(themeColorDefinitions).reduce((schemes, [themeName, colors]) => {
|
|
90
|
+
schemes[themeName] = createThemeScheme(colors);
|
|
91
|
+
return schemes;
|
|
92
|
+
}, {});
|
|
93
|
+
function createThemeScheme(colors) {
|
|
94
|
+
return {
|
|
95
|
+
primary: (text) => applyColor(colors.primary, text),
|
|
96
|
+
secondary: (text) => applyColor(colors.secondary, text),
|
|
97
|
+
success: (text) => applyColor(colors.success, text),
|
|
98
|
+
warning: (text) => applyColor(colors.warning, text),
|
|
99
|
+
error: (text) => applyColor(colors.error, text),
|
|
100
|
+
border: (text) => applyColor(colors.border, text),
|
|
101
|
+
text: (text) => applyColor(colors.text, text),
|
|
102
|
+
textSecondary: (text) => applyColor(colors.textSecondary, text),
|
|
103
|
+
// Derived colors (reuse existing colors for semantic purposes)
|
|
104
|
+
packageName: (text) => applyColor(colors.primary, text),
|
|
105
|
+
packageAuthor: (text) => applyColor(colors.secondary, text),
|
|
106
|
+
versionRange: (text) => applyColor(colors.warning, text),
|
|
107
|
+
versionLatest: (text) => applyColor(colors.error, text),
|
|
108
|
+
dot: (text) => applyColor(colors.success, text),
|
|
109
|
+
dotEmpty: (text) => applyColor(colors.border, text),
|
|
110
|
+
bg: (text) => chalk_1.default.bgHex(colors.bg)(text),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
function getThemeColor(key) {
|
|
114
|
+
const themeName = (0, theme_manager_1.getCurrentThemeName)();
|
|
115
|
+
const scheme = themeColorSchemes[themeName] || themeColorSchemes.dracula;
|
|
116
|
+
return scheme[key];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get the background color hex value for the current theme
|
|
120
|
+
*/
|
|
121
|
+
function getThemeBgColor() {
|
|
122
|
+
const themeName = (0, theme_manager_1.getCurrentThemeName)();
|
|
123
|
+
return themeColorDefinitions[themeName]?.bg || themeColorDefinitions.dracula.bg;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Convert hex color to RGB
|
|
127
|
+
*/
|
|
128
|
+
function hexToRgb(hex) {
|
|
129
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
130
|
+
return result
|
|
131
|
+
? {
|
|
132
|
+
r: parseInt(result[1], 16),
|
|
133
|
+
g: parseInt(result[2], 16),
|
|
134
|
+
b: parseInt(result[3], 16),
|
|
135
|
+
}
|
|
136
|
+
: { r: 0, g: 0, b: 0 };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Get ANSI escape code to set terminal background color
|
|
140
|
+
*/
|
|
141
|
+
function getTerminalBgColorCode() {
|
|
142
|
+
const hex = getThemeBgColor();
|
|
143
|
+
const rgb = hexToRgb(hex);
|
|
144
|
+
return `\x1b[48;2;${rgb.r};${rgb.g};${rgb.b}m`;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get ANSI escape code to reset terminal colors
|
|
148
|
+
*/
|
|
149
|
+
function getTerminalResetCode() {
|
|
150
|
+
return '\x1b[0m';
|
|
151
|
+
}
|
|
152
|
+
exports.themeColors = {
|
|
153
|
+
primary: () => getThemeColor('primary'),
|
|
154
|
+
secondary: () => getThemeColor('secondary'),
|
|
155
|
+
success: () => getThemeColor('success'),
|
|
156
|
+
warning: () => getThemeColor('warning'),
|
|
157
|
+
error: () => getThemeColor('error'),
|
|
158
|
+
border: () => getThemeColor('border'),
|
|
159
|
+
text: () => getThemeColor('text'),
|
|
160
|
+
textSecondary: () => getThemeColor('textSecondary'),
|
|
161
|
+
packageName: () => getThemeColor('packageName'),
|
|
162
|
+
versionRange: () => getThemeColor('versionRange'),
|
|
163
|
+
versionLatest: () => getThemeColor('versionLatest'),
|
|
164
|
+
dot: () => getThemeColor('dot'),
|
|
165
|
+
dotEmpty: () => getThemeColor('dotEmpty'),
|
|
166
|
+
bg: () => getThemeColor('bg'),
|
|
167
|
+
};
|
|
168
|
+
//# sourceMappingURL=themes-colors.js.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.themeNames = exports.defaultTheme = exports.themes = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const themesMetadata = {
|
|
9
|
+
default: 'Default',
|
|
10
|
+
catppuccin: 'Catppuccin',
|
|
11
|
+
dracula: 'Dracula',
|
|
12
|
+
vsc: 'VS Code',
|
|
13
|
+
monokai: 'Monokai',
|
|
14
|
+
tokyonight: 'Tokyo Night',
|
|
15
|
+
onedark: 'One Dark',
|
|
16
|
+
};
|
|
17
|
+
// Theme definitions
|
|
18
|
+
exports.themes = Object.entries(themesMetadata).reduce((acc, [key, name]) => {
|
|
19
|
+
acc[key] = {
|
|
20
|
+
name,
|
|
21
|
+
colors: chalk_1.default,
|
|
22
|
+
};
|
|
23
|
+
return acc;
|
|
24
|
+
}, {});
|
|
25
|
+
exports.defaultTheme = 'default';
|
|
26
|
+
exports.themeNames = Object.keys(exports.themes);
|
|
27
|
+
//# sourceMappingURL=themes.js.map
|