xw-devtool-cli 1.0.44 → 1.0.45
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 +616 -615
- package/README_EN.md +2 -2
- package/package.json +1 -1
- package/src/commands/clock.js +12 -5
- package/src/commands/countdown.js +51 -15
- package/src/commands/stopwatch.js +12 -5
- package/src/locales/en.js +6 -2
- package/src/locales/zh.js +6 -2
package/README_EN.md
CHANGED
|
@@ -30,7 +30,7 @@ Key features include: Base64 encoding/decoding, image format conversion, image <
|
|
|
30
30
|
- **Timestamp**: Quickly get current millisecond timestamp.
|
|
31
31
|
- **Calculation**: Calculate date differences or offsets (Add/Subtract).
|
|
32
32
|
- **Console Clock**: Show real-time current time in terminal, press `Enter` or `Q` to go back.
|
|
33
|
-
- **Countdown Timer**:
|
|
33
|
+
- **Countdown Timer**: Select seconds/minutes/hours first, then enter the value to start; once it reaches zero, it keeps counting with a negative sign (such as `-00:00:05`).
|
|
34
34
|
- **Stopwatch**: Start from `00:00:00` and count up every second in terminal.
|
|
35
35
|
- **Dev Tools**:
|
|
36
36
|
- **URL Encode/Decode**
|
|
@@ -234,7 +234,7 @@ s. Settings (Language)
|
|
|
234
234
|
|
|
235
235
|
### Countdown Timer
|
|
236
236
|
- Select `Countdown Timer` in the menu.
|
|
237
|
-
-
|
|
237
|
+
- Select unit first (Seconds / Minutes / Hours), then enter the value.
|
|
238
238
|
- After reaching zero, the timer continues with a negative sign (for example `-00:00:01`).
|
|
239
239
|
- Press `Enter` or `Q` to go back.
|
|
240
240
|
|
package/package.json
CHANGED
package/src/commands/clock.js
CHANGED
|
@@ -62,17 +62,24 @@ function fitText(text, width) {
|
|
|
62
62
|
|
|
63
63
|
function renderClockBlock() {
|
|
64
64
|
const { timeText, dateText } = getNowDisplay(getLocale());
|
|
65
|
-
const
|
|
65
|
+
const contentLines = [
|
|
66
|
+
i18next.t('clock.title'),
|
|
67
|
+
'',
|
|
68
|
+
`${i18next.t('clock.now')}${timeText}`,
|
|
69
|
+
dateText,
|
|
70
|
+
i18next.t('clock.exitTip')
|
|
71
|
+
];
|
|
72
|
+
const innerWidth = Math.max(34, ...contentLines.map((text) => getDisplayWidth(text)));
|
|
66
73
|
const top = `┌${'─'.repeat(innerWidth + 2)}┐`;
|
|
67
74
|
const bottom = `└${'─'.repeat(innerWidth + 2)}┘`;
|
|
68
75
|
const line = (text) => `│ ${fitText(text, innerWidth)} │`;
|
|
69
76
|
return [
|
|
70
77
|
top,
|
|
71
|
-
line(
|
|
78
|
+
line(contentLines[0]),
|
|
72
79
|
line(''),
|
|
73
|
-
line(
|
|
74
|
-
line(
|
|
75
|
-
line(
|
|
80
|
+
line(contentLines[2]),
|
|
81
|
+
line(contentLines[3]),
|
|
82
|
+
line(contentLines[4]),
|
|
76
83
|
bottom
|
|
77
84
|
];
|
|
78
85
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
2
|
import readline from 'readline';
|
|
3
3
|
import i18next from '../i18n.js';
|
|
4
|
+
import { selectFromMenu } from '../utils/menu.js';
|
|
4
5
|
|
|
5
6
|
function getCharDisplayWidth(char) {
|
|
6
7
|
if (/[\u0000-\u001f\u007f]/.test(char)) {
|
|
@@ -50,7 +51,7 @@ function formatSeconds(seconds) {
|
|
|
50
51
|
return `${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
function
|
|
54
|
+
function parseAmount(input) {
|
|
54
55
|
const value = Number(input);
|
|
55
56
|
if (!Number.isFinite(value) || value < 0) {
|
|
56
57
|
return null;
|
|
@@ -60,43 +61,78 @@ function parseMinutes(input) {
|
|
|
60
61
|
|
|
61
62
|
function renderCountdownBlock(totalSeconds, elapsedSeconds) {
|
|
62
63
|
const remainSeconds = totalSeconds - elapsedSeconds;
|
|
63
|
-
const
|
|
64
|
+
const contentLines = [
|
|
65
|
+
i18next.t('countdown.title'),
|
|
66
|
+
'',
|
|
67
|
+
`${i18next.t('countdown.remaining')}${formatSeconds(remainSeconds)}`,
|
|
68
|
+
`${i18next.t('countdown.total')}${formatSeconds(totalSeconds)}`,
|
|
69
|
+
`${i18next.t('countdown.status')}${remainSeconds < 0 ? i18next.t('countdown.statusOvertime') : i18next.t('countdown.statusCounting')}`,
|
|
70
|
+
i18next.t('countdown.exitTip')
|
|
71
|
+
];
|
|
72
|
+
const innerWidth = Math.max(34, ...contentLines.map((text) => getDisplayWidth(text)));
|
|
64
73
|
const top = `┌${'─'.repeat(innerWidth + 2)}┐`;
|
|
65
74
|
const bottom = `└${'─'.repeat(innerWidth + 2)}┘`;
|
|
66
75
|
const line = (text) => `│ ${fitText(text, innerWidth)} │`;
|
|
67
|
-
const status = remainSeconds < 0 ? i18next.t('countdown.statusOvertime') : i18next.t('countdown.statusCounting');
|
|
68
76
|
|
|
69
77
|
return [
|
|
70
78
|
top,
|
|
71
|
-
line(
|
|
79
|
+
line(contentLines[0]),
|
|
72
80
|
line(''),
|
|
73
|
-
line(
|
|
74
|
-
line(
|
|
75
|
-
line(
|
|
76
|
-
line(
|
|
81
|
+
line(contentLines[2]),
|
|
82
|
+
line(contentLines[3]),
|
|
83
|
+
line(contentLines[4]),
|
|
84
|
+
line(contentLines[5]),
|
|
77
85
|
bottom
|
|
78
86
|
];
|
|
79
87
|
}
|
|
80
88
|
|
|
81
89
|
export async function countdownHandler() {
|
|
82
|
-
const
|
|
90
|
+
const unitOptions = [
|
|
91
|
+
{ name: i18next.t('countdown.unitSecond'), value: 'second' },
|
|
92
|
+
{ name: i18next.t('countdown.unitMinute'), value: 'minute' },
|
|
93
|
+
{ name: i18next.t('countdown.unitHour'), value: 'hour' }
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
const unit = await selectFromMenu(
|
|
97
|
+
i18next.t('countdown.selectUnit'),
|
|
98
|
+
unitOptions,
|
|
99
|
+
true,
|
|
100
|
+
i18next.t('common.back')
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
if (unit === '__BACK__') {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const unitNameMap = {
|
|
108
|
+
second: i18next.t('countdown.unitSecond'),
|
|
109
|
+
minute: i18next.t('countdown.unitMinute'),
|
|
110
|
+
hour: i18next.t('countdown.unitHour')
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const { amountInput } = await inquirer.prompt([
|
|
83
114
|
{
|
|
84
115
|
type: 'input',
|
|
85
|
-
name: '
|
|
86
|
-
message: i18next.t('countdown.inputPrompt'),
|
|
116
|
+
name: 'amountInput',
|
|
117
|
+
message: i18next.t('countdown.inputPrompt', { unit: unitNameMap[unit] }),
|
|
87
118
|
default: '1',
|
|
88
119
|
validate: (input) => {
|
|
89
|
-
const value =
|
|
120
|
+
const value = parseAmount(input);
|
|
90
121
|
if (value === null) {
|
|
91
|
-
return i18next.t('countdown.
|
|
122
|
+
return i18next.t('countdown.invalidAmount');
|
|
92
123
|
}
|
|
93
124
|
return true;
|
|
94
125
|
}
|
|
95
126
|
}
|
|
96
127
|
]);
|
|
97
128
|
|
|
98
|
-
const
|
|
99
|
-
const
|
|
129
|
+
const amount = parseAmount(amountInput);
|
|
130
|
+
const multiplierMap = {
|
|
131
|
+
second: 1,
|
|
132
|
+
minute: 60,
|
|
133
|
+
hour: 3600
|
|
134
|
+
};
|
|
135
|
+
const totalSeconds = Math.round(amount * multiplierMap[unit]);
|
|
100
136
|
|
|
101
137
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
102
138
|
console.log(i18next.t('countdown.nonTtyTip', { value: formatSeconds(totalSeconds) }));
|
|
@@ -47,18 +47,25 @@ function formatSeconds(seconds) {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
function renderStopwatchBlock(elapsedSeconds) {
|
|
50
|
-
const
|
|
50
|
+
const contentLines = [
|
|
51
|
+
i18next.t('stopwatch.title'),
|
|
52
|
+
'',
|
|
53
|
+
`${i18next.t('stopwatch.elapsed')}${formatSeconds(elapsedSeconds)}`,
|
|
54
|
+
`${i18next.t('stopwatch.status')}${i18next.t('stopwatch.statusRunning')}`,
|
|
55
|
+
i18next.t('stopwatch.exitTip')
|
|
56
|
+
];
|
|
57
|
+
const innerWidth = Math.max(34, ...contentLines.map((text) => getDisplayWidth(text)));
|
|
51
58
|
const top = `┌${'─'.repeat(innerWidth + 2)}┐`;
|
|
52
59
|
const bottom = `└${'─'.repeat(innerWidth + 2)}┘`;
|
|
53
60
|
const line = (text) => `│ ${fitText(text, innerWidth)} │`;
|
|
54
61
|
|
|
55
62
|
return [
|
|
56
63
|
top,
|
|
57
|
-
line(
|
|
64
|
+
line(contentLines[0]),
|
|
58
65
|
line(''),
|
|
59
|
-
line(
|
|
60
|
-
line(
|
|
61
|
-
line(
|
|
66
|
+
line(contentLines[2]),
|
|
67
|
+
line(contentLines[3]),
|
|
68
|
+
line(contentLines[4]),
|
|
62
69
|
bottom
|
|
63
70
|
];
|
|
64
71
|
}
|
package/src/locales/en.js
CHANGED
|
@@ -142,8 +142,12 @@ export default {
|
|
|
142
142
|
},
|
|
143
143
|
countdown: {
|
|
144
144
|
title: 'Countdown Timer',
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
selectUnit: 'Select countdown unit',
|
|
146
|
+
unitSecond: 'Seconds',
|
|
147
|
+
unitMinute: 'Minutes',
|
|
148
|
+
unitHour: 'Hours',
|
|
149
|
+
inputPrompt: 'Enter countdown {{unit}} value:',
|
|
150
|
+
invalidAmount: 'Please enter a number greater than or equal to 0',
|
|
147
151
|
remaining: 'Remaining: ',
|
|
148
152
|
total: 'Total: ',
|
|
149
153
|
status: 'Status: ',
|
package/src/locales/zh.js
CHANGED
|
@@ -142,8 +142,12 @@ export default {
|
|
|
142
142
|
},
|
|
143
143
|
countdown: {
|
|
144
144
|
title: '倒计时工具',
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
selectUnit: '请选择倒计时单位',
|
|
146
|
+
unitSecond: '秒',
|
|
147
|
+
unitMinute: '分钟',
|
|
148
|
+
unitHour: '小时',
|
|
149
|
+
inputPrompt: '请输入倒计时{{unit}}数值:',
|
|
150
|
+
invalidAmount: '请输入大于等于 0 的数字',
|
|
147
151
|
remaining: '剩余时间: ',
|
|
148
152
|
total: '倒计总时: ',
|
|
149
153
|
status: '当前状态: ',
|