inup 1.4.1 → 1.4.3
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 +30 -114
- package/dist/cli.js +0 -8
- package/dist/config/constants.js +2 -24
- package/dist/core/package-detector.js +2 -5
- package/dist/core/upgrade-runner.js +2 -5
- package/dist/interactive-ui.js +74 -52
- package/dist/services/jsdelivr-registry.js +77 -88
- package/dist/ui/index.js +18 -14
- package/dist/ui/input-handler.js +50 -0
- package/dist/ui/renderer/index.js +7 -2
- package/dist/ui/renderer/modal.js +16 -7
- package/dist/ui/renderer/package-list.js +125 -70
- package/dist/ui/renderer/theme-selector.js +83 -0
- package/dist/ui/state/filter-manager.js +55 -4
- package/dist/ui/state/state-manager.js +37 -4
- package/dist/ui/state/theme-manager.js +87 -0
- package/dist/ui/themes-colors.js +179 -0
- package/dist/ui/themes.js +27 -0
- package/dist/ui/utils/version.js +23 -0
- package/dist/utils/config.js +57 -0
- package/dist/utils/filesystem.js +2 -16
- package/package.json +23 -19
|
@@ -10,11 +10,32 @@ exports.renderInterface = renderInterface;
|
|
|
10
10
|
exports.renderPackagesTable = renderPackagesTable;
|
|
11
11
|
const chalk_1 = __importDefault(require("chalk"));
|
|
12
12
|
const utils_1 = require("../utils");
|
|
13
|
+
const themes_colors_1 = require("../themes-colors");
|
|
14
|
+
/**
|
|
15
|
+
* Get type badge for dependency type (theme-aware)
|
|
16
|
+
*/
|
|
17
|
+
function getTypeBadge(type) {
|
|
18
|
+
switch (type) {
|
|
19
|
+
case 'devDependencies':
|
|
20
|
+
return (0, themes_colors_1.getThemeColor)('textSecondary')('[D]');
|
|
21
|
+
case 'peerDependencies':
|
|
22
|
+
return (0, themes_colors_1.getThemeColor)('textSecondary')('[P]');
|
|
23
|
+
case 'optionalDependencies':
|
|
24
|
+
return (0, themes_colors_1.getThemeColor)('textSecondary')('[O]');
|
|
25
|
+
case 'dependencies':
|
|
26
|
+
default:
|
|
27
|
+
return ''; // No badge for regular dependencies
|
|
28
|
+
}
|
|
29
|
+
}
|
|
13
30
|
/**
|
|
14
31
|
* Render a single package line
|
|
32
|
+
* @param state Package selection state
|
|
33
|
+
* @param index Index in the list
|
|
34
|
+
* @param isCurrentRow Whether this is the current/highlighted row
|
|
35
|
+
* @param terminalWidth Terminal width for dynamic truncation (default 80)
|
|
15
36
|
*/
|
|
16
|
-
function renderPackageLine(state, index, isCurrentRow) {
|
|
17
|
-
const prefix = isCurrentRow ?
|
|
37
|
+
function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80) {
|
|
38
|
+
const prefix = isCurrentRow ? (0, themes_colors_1.getThemeColor)('success')('❯ ') : ' ';
|
|
18
39
|
// Package name with special formatting for scoped packages (@author/package)
|
|
19
40
|
let packageName;
|
|
20
41
|
if (state.name.startsWith('@')) {
|
|
@@ -23,94 +44,111 @@ function renderPackageLine(state, index, isCurrentRow) {
|
|
|
23
44
|
const author = parts[0]; // @author
|
|
24
45
|
const packagePart = parts.slice(1).join('/'); // package name
|
|
25
46
|
if (isCurrentRow) {
|
|
26
|
-
packageName = chalk_1.default.
|
|
47
|
+
packageName = chalk_1.default.bold((0, themes_colors_1.getThemeColor)('packageAuthor')(author)) + (0, themes_colors_1.getThemeColor)('packageName')('/' + packagePart);
|
|
27
48
|
}
|
|
28
49
|
else {
|
|
29
|
-
packageName = chalk_1.default.white
|
|
50
|
+
packageName = chalk_1.default.bold.white(author) + chalk_1.default.white('/' + packagePart);
|
|
30
51
|
}
|
|
31
52
|
}
|
|
32
53
|
else {
|
|
33
|
-
packageName = isCurrentRow ?
|
|
54
|
+
packageName = isCurrentRow ? (0, themes_colors_1.getThemeColor)('packageName')(state.name) : chalk_1.default.white(state.name);
|
|
34
55
|
}
|
|
35
56
|
}
|
|
36
57
|
else {
|
|
37
|
-
packageName = isCurrentRow ?
|
|
58
|
+
packageName = isCurrentRow ? (0, themes_colors_1.getThemeColor)('packageName')(state.name) : chalk_1.default.white(state.name);
|
|
38
59
|
}
|
|
39
60
|
// Determine which dot should be filled (only one per package)
|
|
40
61
|
const isCurrentSelected = state.selectedOption === 'none';
|
|
41
62
|
const isRangeSelected = state.selectedOption === 'range';
|
|
42
63
|
const isLatestSelected = state.selectedOption === 'latest';
|
|
43
64
|
// Current version dot and version (show original specifier with prefix)
|
|
44
|
-
const currentDot = isCurrentSelected ?
|
|
65
|
+
const currentDot = isCurrentSelected ? (0, themes_colors_1.getThemeColor)('dot')('●') : (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
|
|
45
66
|
const currentVersion = chalk_1.default.white(state.currentVersionSpecifier);
|
|
46
67
|
// Range version dot and version
|
|
47
68
|
let rangeDot = '';
|
|
48
69
|
let rangeVersionText = '';
|
|
49
|
-
let rangeDashes = '';
|
|
50
70
|
if (state.hasRangeUpdate) {
|
|
51
|
-
rangeDot = isRangeSelected ?
|
|
71
|
+
rangeDot = isRangeSelected ? (0, themes_colors_1.getThemeColor)('dot')('●') : (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
|
|
52
72
|
const rangeVersionWithPrefix = utils_1.VersionUtils.applyVersionPrefix(state.currentVersionSpecifier, state.rangeVersion);
|
|
53
|
-
rangeVersionText =
|
|
54
|
-
rangeDashes = '';
|
|
73
|
+
rangeVersionText = (0, themes_colors_1.getThemeColor)('versionRange')(rangeVersionWithPrefix);
|
|
55
74
|
}
|
|
56
75
|
else {
|
|
57
|
-
rangeDot =
|
|
76
|
+
rangeDot = (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
|
|
58
77
|
rangeVersionText = '';
|
|
59
|
-
rangeDashes = chalk_1.default.gray('─');
|
|
60
78
|
}
|
|
61
79
|
// Latest version dot and version
|
|
62
80
|
let latestDot = '';
|
|
63
81
|
let latestVersionText = '';
|
|
64
|
-
let latestDashes = '';
|
|
65
82
|
if (state.hasMajorUpdate) {
|
|
66
|
-
latestDot = isLatestSelected ?
|
|
83
|
+
latestDot = isLatestSelected ? (0, themes_colors_1.getThemeColor)('dot')('●') : (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
|
|
67
84
|
const latestVersionWithPrefix = utils_1.VersionUtils.applyVersionPrefix(state.currentVersionSpecifier, state.latestVersion);
|
|
68
|
-
latestVersionText =
|
|
69
|
-
latestDashes = '';
|
|
85
|
+
latestVersionText = (0, themes_colors_1.getThemeColor)('versionLatest')(latestVersionWithPrefix);
|
|
70
86
|
}
|
|
71
87
|
else {
|
|
72
|
-
latestDot =
|
|
88
|
+
latestDot = (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
|
|
73
89
|
latestVersionText = '';
|
|
74
|
-
latestDashes = chalk_1.default.gray('─');
|
|
75
90
|
}
|
|
76
|
-
//
|
|
77
|
-
|
|
91
|
+
// Column widths with capped package name width
|
|
92
|
+
// Layout: prefix(2) + name + dashes + spacing(3) + current(16) + spacing(3) + range(16) + spacing(3) + latest(16)
|
|
78
93
|
const currentColumnWidth = 16; // Increased to accommodate ^ and ~ prefixes
|
|
79
94
|
const rangeColumnWidth = 16; // Increased to accommodate ^ and ~ prefixes
|
|
80
95
|
const latestColumnWidth = 16; // Increased to accommodate ^ and ~ prefixes
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
const
|
|
96
|
+
const spacingWidth = 3;
|
|
97
|
+
// Package name width: max 50 chars (after which ellipsis kicks in), but scales down on small terminals
|
|
98
|
+
const maxPackageNameWidth = 50;
|
|
99
|
+
const minPackageNameWidth = 24;
|
|
100
|
+
const otherColumnsWidth = currentColumnWidth + rangeColumnWidth + latestColumnWidth + spacingWidth * 3;
|
|
101
|
+
const prefixWidth = 2;
|
|
102
|
+
const availableForPackageName = terminalWidth - prefixWidth - otherColumnsWidth - 1;
|
|
103
|
+
const packageNameWidth = Math.min(maxPackageNameWidth, Math.max(minPackageNameWidth, availableForPackageName));
|
|
104
|
+
// Apply ellipsis truncation if package name exceeds available width
|
|
105
|
+
const badgeWidth = state.type === 'dependencies' ? 0 : 3; // [X] without leading space
|
|
106
|
+
const truncatedName = utils_1.VersionUtils.truncateMiddle(state.name, packageNameWidth - 1 - badgeWidth); // -1 for space after name, -badgeWidth for badge
|
|
107
|
+
// Helper function to determine if dashes should be shown based on available padding
|
|
108
|
+
// Only show dashes if there's significant padding (> 2 chars) to fill
|
|
109
|
+
const shouldShowDashes = (paddingAmount) => paddingAmount > 2;
|
|
85
110
|
const dashColor = isCurrentRow ? chalk_1.default.white : chalk_1.default.gray;
|
|
86
|
-
|
|
87
|
-
|
|
111
|
+
// Use truncated name if it differs from original, otherwise use colored packageName
|
|
112
|
+
const displayName = truncatedName !== state.name ? truncatedName : packageName;
|
|
113
|
+
// Package name with dashes and badge at the end
|
|
114
|
+
const typeBadge = getTypeBadge(state.type);
|
|
115
|
+
const nameLength = utils_1.VersionUtils.getVisualLength(truncatedName);
|
|
116
|
+
const namePadding = Math.max(0, packageNameWidth - nameLength - 1 - badgeWidth); // -1 for space after package name, -badgeWidth for badge at end
|
|
117
|
+
const nameDashes = shouldShowDashes(namePadding) ? dashColor('-').repeat(namePadding) : ' '.repeat(namePadding);
|
|
118
|
+
// Place badge at the end of dashes: name ------[D]
|
|
119
|
+
const packageNameSection = typeBadge
|
|
120
|
+
? `${displayName} ${nameDashes}${typeBadge}`
|
|
121
|
+
: `${displayName} ${nameDashes}`;
|
|
122
|
+
// Current version section with dashes only if needed
|
|
88
123
|
const currentSection = `${currentDot} ${currentVersion}`;
|
|
89
|
-
const currentSectionLength = utils_1.VersionUtils.getVisualLength(currentSection) + 1; // +1 for space before
|
|
124
|
+
const currentSectionLength = utils_1.VersionUtils.getVisualLength(currentSection) + 1; // +1 for space before padding
|
|
90
125
|
const currentPadding = Math.max(0, currentColumnWidth - currentSectionLength);
|
|
91
|
-
const
|
|
92
|
-
|
|
126
|
+
const currentPaddingText = shouldShowDashes(currentPadding) ? dashColor('-').repeat(currentPadding) : ' '.repeat(currentPadding);
|
|
127
|
+
const currentWithPadding = currentSection + ' ' + currentPaddingText;
|
|
128
|
+
// Range version section with dashes only if needed
|
|
93
129
|
let rangeSection = '';
|
|
94
130
|
if (state.hasRangeUpdate) {
|
|
95
131
|
rangeSection = `${rangeDot} ${rangeVersionText}`;
|
|
96
|
-
const rangeSectionLength = utils_1.VersionUtils.getVisualLength(rangeSection) + 1; // +1 for space before
|
|
132
|
+
const rangeSectionLength = utils_1.VersionUtils.getVisualLength(rangeSection) + 1; // +1 for space before padding
|
|
97
133
|
const rangePadding = Math.max(0, rangeColumnWidth - rangeSectionLength);
|
|
98
|
-
|
|
134
|
+
const rangePaddingText = shouldShowDashes(rangePadding) ? dashColor('-').repeat(rangePadding) : ' '.repeat(rangePadding);
|
|
135
|
+
rangeSection += ' ' + rangePaddingText;
|
|
99
136
|
}
|
|
100
137
|
else {
|
|
101
|
-
// Empty slot -
|
|
138
|
+
// Empty slot - maintain column width
|
|
102
139
|
rangeSection = ' '.repeat(rangeColumnWidth);
|
|
103
140
|
}
|
|
104
|
-
// Latest version section with
|
|
141
|
+
// Latest version section with dashes only if needed
|
|
105
142
|
let latestSection = '';
|
|
106
143
|
if (state.hasMajorUpdate) {
|
|
107
144
|
latestSection = `${latestDot} ${latestVersionText}`;
|
|
108
|
-
const latestSectionLength = utils_1.VersionUtils.getVisualLength(latestSection) + 1; // +1 for space before
|
|
145
|
+
const latestSectionLength = utils_1.VersionUtils.getVisualLength(latestSection) + 1; // +1 for space before padding
|
|
109
146
|
const latestPadding = Math.max(0, latestColumnWidth - latestSectionLength);
|
|
110
|
-
|
|
147
|
+
const latestPaddingText = shouldShowDashes(latestPadding) ? dashColor('-').repeat(latestPadding) : ' '.repeat(latestPadding);
|
|
148
|
+
latestSection += ' ' + latestPaddingText;
|
|
111
149
|
}
|
|
112
150
|
else {
|
|
113
|
-
// Empty slot -
|
|
151
|
+
// Empty slot - maintain column width
|
|
114
152
|
latestSection = ' '.repeat(latestColumnWidth);
|
|
115
153
|
}
|
|
116
154
|
// Build line with fixed column widths
|
|
@@ -133,7 +171,7 @@ function renderSpacer() {
|
|
|
133
171
|
/**
|
|
134
172
|
* Render the main interface
|
|
135
173
|
*/
|
|
136
|
-
function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems,
|
|
174
|
+
function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, activeFilterLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter, terminalWidth = 80) {
|
|
137
175
|
const output = [];
|
|
138
176
|
// Header section (same for initial and incremental render)
|
|
139
177
|
if (packageManager) {
|
|
@@ -148,42 +186,59 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
148
186
|
// Each character in "inup" gets a different color
|
|
149
187
|
const inupColors = [chalk_1.default.red, chalk_1.default.yellow, chalk_1.default.blue, chalk_1.default.magenta];
|
|
150
188
|
const coloredInup = inupColors.map((color, i) => color.bold('inup'[i])).join('');
|
|
151
|
-
const headerLine = ' ' + chalk_1.default.bold(pmColor('🚀')) + ' ' + coloredInup +
|
|
152
|
-
|
|
189
|
+
const headerLine = ' ' + chalk_1.default.bold(pmColor('🚀')) + ' ' + coloredInup + (0, themes_colors_1.getThemeColor)('textSecondary')(` (${packageManager.displayName})`);
|
|
190
|
+
// Show filter state (always show, including "All")
|
|
191
|
+
const fullHeaderLine = activeFilterLabel
|
|
192
|
+
? headerLine + (0, themes_colors_1.getThemeColor)('textSecondary')(' - ') + (0, themes_colors_1.getThemeColor)('primary')(activeFilterLabel)
|
|
193
|
+
: headerLine;
|
|
194
|
+
// Pad to terminal width to clear any leftover characters
|
|
195
|
+
const headerPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(fullHeaderLine));
|
|
196
|
+
output.push(fullHeaderLine + ' '.repeat(headerPadding));
|
|
153
197
|
}
|
|
154
198
|
else {
|
|
155
199
|
const headerLine = ' ' + chalk_1.default.bold.blue('🚀 ') + chalk_1.default.bold.red('i') + chalk_1.default.bold.yellow('n') + chalk_1.default.bold.blue('u') + chalk_1.default.bold.magenta('p');
|
|
156
|
-
|
|
200
|
+
// Show filter state (always show, including "All")
|
|
201
|
+
const fullHeaderLine = activeFilterLabel
|
|
202
|
+
? headerLine + (0, themes_colors_1.getThemeColor)('textSecondary')(' - ') + (0, themes_colors_1.getThemeColor)('primary')(activeFilterLabel)
|
|
203
|
+
: headerLine;
|
|
204
|
+
// Pad to terminal width to clear any leftover characters
|
|
205
|
+
const headerPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(fullHeaderLine));
|
|
206
|
+
output.push(fullHeaderLine + ' '.repeat(headerPadding));
|
|
157
207
|
}
|
|
158
208
|
output.push('');
|
|
159
209
|
if (filterMode) {
|
|
160
210
|
// Show filter input with cursor when actively filtering
|
|
161
|
-
const filterDisplay = ' ' + chalk_1.default.bold.white('Search: ') +
|
|
162
|
-
|
|
211
|
+
const filterDisplay = ' ' + chalk_1.default.bold.white('Search: ') + (0, themes_colors_1.getThemeColor)('primary')(filterQuery || '') + (0, themes_colors_1.getThemeColor)('border')('█');
|
|
212
|
+
// Pad to terminal width to clear any leftover characters from backspace
|
|
213
|
+
const padding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(filterDisplay));
|
|
214
|
+
output.push(filterDisplay + ' '.repeat(padding));
|
|
163
215
|
}
|
|
164
216
|
else {
|
|
165
217
|
// Show instructions when not filtering
|
|
166
218
|
output.push(' ' +
|
|
167
219
|
chalk_1.default.bold.white('/ ') +
|
|
168
|
-
|
|
220
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Search') +
|
|
169
221
|
' ' +
|
|
170
222
|
chalk_1.default.bold.white('↑/↓ ') +
|
|
171
|
-
|
|
223
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Move') +
|
|
172
224
|
' ' +
|
|
173
225
|
chalk_1.default.bold.white('←/→ ') +
|
|
174
|
-
|
|
226
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Select') +
|
|
227
|
+
' ' +
|
|
228
|
+
chalk_1.default.bold.white('D/P/O ') +
|
|
229
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Filter') +
|
|
175
230
|
' ' +
|
|
176
231
|
chalk_1.default.bold.white('I ') +
|
|
177
|
-
|
|
232
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Info') +
|
|
178
233
|
' ' +
|
|
179
234
|
chalk_1.default.bold.white('M ') +
|
|
180
|
-
|
|
235
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Minor') +
|
|
181
236
|
' ' +
|
|
182
237
|
chalk_1.default.bold.white('L ') +
|
|
183
|
-
|
|
238
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('All') +
|
|
184
239
|
' ' +
|
|
185
240
|
chalk_1.default.bold.white('U ') +
|
|
186
|
-
|
|
241
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('None'));
|
|
187
242
|
}
|
|
188
243
|
// Show status line with item range
|
|
189
244
|
const totalPackages = states.length;
|
|
@@ -196,42 +251,42 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
196
251
|
if (filterMode) {
|
|
197
252
|
// In filter mode, show ESC to exit filter
|
|
198
253
|
if (totalPackages === 0) {
|
|
199
|
-
statusLine =
|
|
254
|
+
statusLine = (0, themes_colors_1.getThemeColor)('warning')(`No matches found`) +
|
|
200
255
|
' ' +
|
|
201
|
-
|
|
202
|
-
|
|
256
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
|
|
257
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Clear filter');
|
|
203
258
|
}
|
|
204
259
|
else if (totalVisualItems > maxVisibleItems) {
|
|
205
|
-
statusLine =
|
|
260
|
+
statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
|
|
206
261
|
' ' +
|
|
207
|
-
|
|
208
|
-
|
|
262
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
|
|
263
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Clear filter');
|
|
209
264
|
}
|
|
210
265
|
else {
|
|
211
|
-
statusLine =
|
|
266
|
+
statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing all ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
|
|
212
267
|
' ' +
|
|
213
|
-
|
|
214
|
-
|
|
268
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
|
|
269
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Clear filter');
|
|
215
270
|
}
|
|
216
271
|
}
|
|
217
272
|
else if (totalPackages < totalBeforeFilter) {
|
|
218
273
|
// Filter is applied but not in filter mode
|
|
219
274
|
if (totalVisualItems > maxVisibleItems) {
|
|
220
|
-
statusLine =
|
|
275
|
+
statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
|
|
221
276
|
' ' +
|
|
222
|
-
|
|
223
|
-
|
|
277
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('/ ') +
|
|
278
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Edit filter') +
|
|
224
279
|
' ' +
|
|
225
|
-
|
|
226
|
-
|
|
280
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Enter ') +
|
|
281
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Confirm') +
|
|
227
282
|
' ' +
|
|
228
|
-
|
|
229
|
-
|
|
283
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
|
|
284
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('Cancel');
|
|
230
285
|
}
|
|
231
286
|
else {
|
|
232
|
-
statusLine =
|
|
287
|
+
statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing all ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
|
|
233
288
|
' ' +
|
|
234
|
-
|
|
289
|
+
(0, themes_colors_1.getThemeColor)('textSecondary')('/ ') +
|
|
235
290
|
chalk_1.default.gray('Edit filter') +
|
|
236
291
|
' ' +
|
|
237
292
|
chalk_1.default.gray('Enter ') +
|
|
@@ -276,7 +331,7 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
276
331
|
output.push(renderSpacer());
|
|
277
332
|
}
|
|
278
333
|
else if (item.type === 'package') {
|
|
279
|
-
const line = renderPackageLine(item.state, item.originalIndex, item.originalIndex === currentRow);
|
|
334
|
+
const line = renderPackageLine(item.state, item.originalIndex, item.originalIndex === currentRow, terminalWidth);
|
|
280
335
|
output.push(line);
|
|
281
336
|
}
|
|
282
337
|
}
|
|
@@ -284,7 +339,7 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
|
|
|
284
339
|
else {
|
|
285
340
|
// Fallback to flat rendering (legacy mode)
|
|
286
341
|
for (let i = scrollOffset; i < Math.min(scrollOffset + maxVisibleItems, states.length); i++) {
|
|
287
|
-
const line = renderPackageLine(states[i], i, i === currentRow);
|
|
342
|
+
const line = renderPackageLine(states[i], i, i === currentRow, terminalWidth);
|
|
288
343
|
output.push(line);
|
|
289
344
|
}
|
|
290
345
|
}
|
|
@@ -0,0 +1,83 @@
|
|
|
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.renderThemeSelectorModal = renderThemeSelectorModal;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const themes_1 = require("../themes");
|
|
9
|
+
/**
|
|
10
|
+
* Get the visual length of a string (ignoring ANSI color codes)
|
|
11
|
+
* Accounts for wide characters like emojis
|
|
12
|
+
*/
|
|
13
|
+
function getVisualLength(str) {
|
|
14
|
+
const cleaned = str.replace(/\u001b\[[0-9;]*m/g, '');
|
|
15
|
+
let length = 0;
|
|
16
|
+
for (const char of cleaned) {
|
|
17
|
+
const code = char.charCodeAt(0);
|
|
18
|
+
// Emoji ranges: 0x1F000–0x1F9FF (and other ranges)
|
|
19
|
+
if (code >= 0x1F000 || code >= 0x2600) {
|
|
20
|
+
length += 2;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
length += 1;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return length;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Render the theme selector modal
|
|
30
|
+
*/
|
|
31
|
+
function renderThemeSelectorModal(currentTheme, previewTheme, terminalWidth = 80, terminalHeight = 24) {
|
|
32
|
+
const maxModalWidth = 76; // Fixed width that fits comfortably in 80-char terminal
|
|
33
|
+
const padding = Math.max(0, Math.floor((terminalWidth - maxModalWidth) / 2));
|
|
34
|
+
const lines = [];
|
|
35
|
+
const contentWidth = maxModalWidth - 4; // Account for '│ ' on left and ' │' on right
|
|
36
|
+
// Helper to pad content to exact width
|
|
37
|
+
const createLine = (content) => {
|
|
38
|
+
const visualLen = getVisualLength(content);
|
|
39
|
+
const spacesNeeded = Math.max(0, contentWidth - visualLen);
|
|
40
|
+
const line = ' '.repeat(padding) + chalk_1.default.gray('│') + ' ' + content + ' '.repeat(spacesNeeded) + ' ' + chalk_1.default.gray('│');
|
|
41
|
+
return line;
|
|
42
|
+
};
|
|
43
|
+
// Top padding to center vertically
|
|
44
|
+
const topPadding = Math.max(1, Math.floor((terminalHeight - themes_1.themeNames.length - 8) / 2));
|
|
45
|
+
for (let i = 0; i < topPadding; i++) {
|
|
46
|
+
lines.push('');
|
|
47
|
+
}
|
|
48
|
+
// Top border
|
|
49
|
+
lines.push(' '.repeat(padding) + chalk_1.default.gray('╭' + '─'.repeat(maxModalWidth - 2) + '╮'));
|
|
50
|
+
// Title
|
|
51
|
+
const title = chalk_1.default.cyan('🎨 Select Theme');
|
|
52
|
+
lines.push(createLine(title));
|
|
53
|
+
// Separator
|
|
54
|
+
lines.push(' '.repeat(padding) + chalk_1.default.gray('├' + '─'.repeat(maxModalWidth - 2) + '┤'));
|
|
55
|
+
// Theme options
|
|
56
|
+
for (const themeName of themes_1.themeNames) {
|
|
57
|
+
const isSelected = themeName === previewTheme;
|
|
58
|
+
const isCurrent = themeName === currentTheme;
|
|
59
|
+
const themeObj = themes_1.themes[themeName];
|
|
60
|
+
// Build the theme line
|
|
61
|
+
let themeLine = '';
|
|
62
|
+
if (isSelected) {
|
|
63
|
+
themeLine = chalk_1.default.green('● ');
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
themeLine = chalk_1.default.gray('○ ');
|
|
67
|
+
}
|
|
68
|
+
themeLine += themeObj.name;
|
|
69
|
+
if (isCurrent) {
|
|
70
|
+
themeLine += chalk_1.default.gray(' (current)');
|
|
71
|
+
}
|
|
72
|
+
lines.push(createLine(themeLine));
|
|
73
|
+
}
|
|
74
|
+
// Separator before instructions
|
|
75
|
+
lines.push(' '.repeat(padding) + chalk_1.default.gray('├' + '─'.repeat(maxModalWidth - 2) + '┤'));
|
|
76
|
+
// Instructions
|
|
77
|
+
const instruction = chalk_1.default.gray('↑/↓ to navigate • Enter to confirm • Esc to cancel');
|
|
78
|
+
lines.push(createLine(instruction));
|
|
79
|
+
// Bottom border
|
|
80
|
+
lines.push(' '.repeat(padding) + chalk_1.default.gray('╰' + '─'.repeat(maxModalWidth - 2) + '╯'));
|
|
81
|
+
return lines;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=theme-selector.js.map
|
|
@@ -6,6 +6,10 @@ class FilterManager {
|
|
|
6
6
|
this.state = {
|
|
7
7
|
filterMode: false,
|
|
8
8
|
filterQuery: '',
|
|
9
|
+
showDependencies: true,
|
|
10
|
+
showDevDependencies: true,
|
|
11
|
+
showPeerDependencies: true,
|
|
12
|
+
showOptionalDependencies: true,
|
|
9
13
|
};
|
|
10
14
|
}
|
|
11
15
|
getState() {
|
|
@@ -36,12 +40,59 @@ class FilterManager {
|
|
|
36
40
|
this.state.filterQuery = this.state.filterQuery.slice(0, -1);
|
|
37
41
|
}
|
|
38
42
|
}
|
|
43
|
+
toggleDependencyType(type) {
|
|
44
|
+
switch (type) {
|
|
45
|
+
case 'dependencies':
|
|
46
|
+
this.state.showDependencies = !this.state.showDependencies;
|
|
47
|
+
break;
|
|
48
|
+
case 'devDependencies':
|
|
49
|
+
this.state.showDevDependencies = !this.state.showDevDependencies;
|
|
50
|
+
break;
|
|
51
|
+
case 'peerDependencies':
|
|
52
|
+
this.state.showPeerDependencies = !this.state.showPeerDependencies;
|
|
53
|
+
break;
|
|
54
|
+
case 'optionalDependencies':
|
|
55
|
+
this.state.showOptionalDependencies = !this.state.showOptionalDependencies;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
getActiveFilterLabel() {
|
|
60
|
+
const activeTypes = [];
|
|
61
|
+
if (this.state.showDependencies)
|
|
62
|
+
activeTypes.push('Deps');
|
|
63
|
+
if (this.state.showDevDependencies)
|
|
64
|
+
activeTypes.push('Dev');
|
|
65
|
+
if (this.state.showPeerDependencies)
|
|
66
|
+
activeTypes.push('Peer');
|
|
67
|
+
if (this.state.showOptionalDependencies)
|
|
68
|
+
activeTypes.push('Optional');
|
|
69
|
+
if (activeTypes.length === 0)
|
|
70
|
+
return 'None';
|
|
71
|
+
return activeTypes.join(', ');
|
|
72
|
+
}
|
|
39
73
|
getFilteredStates(allStates) {
|
|
40
|
-
|
|
41
|
-
|
|
74
|
+
let filtered = allStates;
|
|
75
|
+
// Apply text filter
|
|
76
|
+
if (this.state.filterQuery) {
|
|
77
|
+
const query = this.state.filterQuery.toLowerCase();
|
|
78
|
+
filtered = filtered.filter((state) => state.name.toLowerCase().includes(query));
|
|
42
79
|
}
|
|
43
|
-
|
|
44
|
-
|
|
80
|
+
// Apply dependency type filter
|
|
81
|
+
filtered = filtered.filter((state) => {
|
|
82
|
+
switch (state.type) {
|
|
83
|
+
case 'dependencies':
|
|
84
|
+
return this.state.showDependencies;
|
|
85
|
+
case 'devDependencies':
|
|
86
|
+
return this.state.showDevDependencies;
|
|
87
|
+
case 'peerDependencies':
|
|
88
|
+
return this.state.showPeerDependencies;
|
|
89
|
+
case 'optionalDependencies':
|
|
90
|
+
return this.state.showOptionalDependencies;
|
|
91
|
+
default:
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return filtered;
|
|
45
96
|
}
|
|
46
97
|
}
|
|
47
98
|
exports.FilterManager = FilterManager;
|
|
@@ -4,6 +4,7 @@ exports.StateManager = void 0;
|
|
|
4
4
|
const navigation_manager_1 = require("./navigation-manager");
|
|
5
5
|
const modal_manager_1 = require("./modal-manager");
|
|
6
6
|
const filter_manager_1 = require("./filter-manager");
|
|
7
|
+
const theme_manager_1 = require("./theme-manager");
|
|
7
8
|
class StateManager {
|
|
8
9
|
constructor(initialRow = 0, terminalHeight = 24) {
|
|
9
10
|
this.headerLines = 5; // title (with label) + empty + 1 instruction line + status + empty
|
|
@@ -11,6 +12,7 @@ class StateManager {
|
|
|
11
12
|
this.navigationManager = new navigation_manager_1.NavigationManager(initialRow, maxVisibleItems);
|
|
12
13
|
this.modalManager = new modal_manager_1.ModalManager();
|
|
13
14
|
this.filterManager = new filter_manager_1.FilterManager();
|
|
15
|
+
this.themeManager = new theme_manager_1.ThemeManager();
|
|
14
16
|
this.displayState = {
|
|
15
17
|
maxVisibleItems,
|
|
16
18
|
terminalHeight,
|
|
@@ -26,6 +28,7 @@ class StateManager {
|
|
|
26
28
|
const navState = this.navigationManager.getState();
|
|
27
29
|
const modalState = this.modalManager.getState();
|
|
28
30
|
const filterState = this.filterManager.getState();
|
|
31
|
+
const themeState = this.themeManager.getState();
|
|
29
32
|
return {
|
|
30
33
|
currentRow: navState.currentRow,
|
|
31
34
|
previousRow: navState.previousRow,
|
|
@@ -41,6 +44,8 @@ class StateManager {
|
|
|
41
44
|
isLoadingModalInfo: modalState.isLoadingModalInfo,
|
|
42
45
|
filterMode: filterState.filterMode,
|
|
43
46
|
filterQuery: filterState.filterQuery,
|
|
47
|
+
showThemeModal: themeState.showThemeModal,
|
|
48
|
+
currentTheme: themeState.currentTheme,
|
|
44
49
|
};
|
|
45
50
|
}
|
|
46
51
|
setRenderableItems(items) {
|
|
@@ -158,13 +163,13 @@ class StateManager {
|
|
|
158
163
|
// Filter delegation
|
|
159
164
|
enterFilterMode() {
|
|
160
165
|
this.filterManager.enterFilterMode();
|
|
161
|
-
|
|
166
|
+
// Use incremental render for search mode toggle (no blink)
|
|
162
167
|
}
|
|
163
168
|
exitFilterMode() {
|
|
164
169
|
this.filterManager.exitFilterMode();
|
|
165
170
|
this.navigationManager.setCurrentRow(0);
|
|
166
171
|
this.navigationManager.setScrollOffset(0);
|
|
167
|
-
|
|
172
|
+
// Use incremental render for search mode toggle (no blink)
|
|
168
173
|
}
|
|
169
174
|
updateFilterQuery(query) {
|
|
170
175
|
this.filterManager.updateFilterQuery(query);
|
|
@@ -175,17 +180,25 @@ class StateManager {
|
|
|
175
180
|
this.filterManager.appendToFilterQuery(char);
|
|
176
181
|
this.navigationManager.setCurrentRow(0);
|
|
177
182
|
this.navigationManager.setScrollOffset(0);
|
|
178
|
-
this.renderState.forceFullRender = true;
|
|
179
183
|
}
|
|
180
184
|
deleteFromFilterQuery() {
|
|
181
185
|
this.filterManager.deleteFromFilterQuery();
|
|
182
186
|
this.navigationManager.setCurrentRow(0);
|
|
183
187
|
this.navigationManager.setScrollOffset(0);
|
|
184
|
-
this.renderState.forceFullRender = true;
|
|
185
188
|
}
|
|
186
189
|
getFilteredStates(allStates) {
|
|
187
190
|
return this.filterManager.getFilteredStates(allStates);
|
|
188
191
|
}
|
|
192
|
+
toggleDependencyTypeFilter(type) {
|
|
193
|
+
this.filterManager.toggleDependencyType(type);
|
|
194
|
+
// Reset navigation when filter changes
|
|
195
|
+
this.navigationManager.setCurrentRow(0);
|
|
196
|
+
this.navigationManager.setScrollOffset(0);
|
|
197
|
+
// Use incremental render (no blink)
|
|
198
|
+
}
|
|
199
|
+
getActiveFilterLabel() {
|
|
200
|
+
return this.filterManager.getActiveFilterLabel();
|
|
201
|
+
}
|
|
189
202
|
// Display and render state management
|
|
190
203
|
updateTerminalHeight(newHeight) {
|
|
191
204
|
const newMaxVisibleItems = Math.max(5, newHeight - this.headerLines - 2);
|
|
@@ -210,6 +223,26 @@ class StateManager {
|
|
|
210
223
|
this.navigationManager.resetForResize(totalItems);
|
|
211
224
|
this.renderState.forceFullRender = true;
|
|
212
225
|
}
|
|
226
|
+
// Theme delegation
|
|
227
|
+
toggleThemeModal() {
|
|
228
|
+
this.themeManager.toggleThemeModal();
|
|
229
|
+
this.renderState.forceFullRender = true;
|
|
230
|
+
}
|
|
231
|
+
closeThemeModal() {
|
|
232
|
+
this.themeManager.closeThemeModal();
|
|
233
|
+
this.renderState.forceFullRender = true;
|
|
234
|
+
}
|
|
235
|
+
previewTheme(themeName) {
|
|
236
|
+
this.themeManager.previewTheme(themeName);
|
|
237
|
+
this.renderState.forceFullRender = true;
|
|
238
|
+
}
|
|
239
|
+
confirmTheme() {
|
|
240
|
+
this.themeManager.confirmTheme();
|
|
241
|
+
this.renderState.forceFullRender = true;
|
|
242
|
+
}
|
|
243
|
+
getThemeManager() {
|
|
244
|
+
return this.themeManager;
|
|
245
|
+
}
|
|
213
246
|
}
|
|
214
247
|
exports.StateManager = StateManager;
|
|
215
248
|
//# sourceMappingURL=state-manager.js.map
|