@nbtca/prompt 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/menu.js +8 -9
- package/dist/features/calendar.js +10 -23
- package/dist/features/docs.js +137 -86
- package/dist/features/links.js +1 -2
- package/dist/features/settings.js +3 -4
- package/dist/i18n/locales/en.json +15 -13
- package/dist/i18n/locales/zh.json +17 -15
- package/package.json +1 -1
package/dist/core/menu.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { select, isCancel, outro } from '@clack/prompts';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
|
-
import {
|
|
6
|
+
import { showCalendar } from '../features/calendar.js';
|
|
7
7
|
import { showDocsMenu } from '../features/docs.js';
|
|
8
8
|
import { showServiceStatus } from '../features/status.js';
|
|
9
9
|
import { showLinksMenu } from '../features/links.js';
|
|
@@ -12,18 +12,17 @@ import { t } from '../i18n/index.js';
|
|
|
12
12
|
function getMainMenuOptions() {
|
|
13
13
|
const trans = t();
|
|
14
14
|
return [
|
|
15
|
-
{ value: 'events', label: trans.menu.events, hint: trans.menu.eventsDesc },
|
|
16
|
-
{ value: 'docs', label: trans.menu.docs, hint: trans.menu.docsDesc },
|
|
17
|
-
{ value: 'status', label: trans.menu.status, hint: trans.menu.statusDesc },
|
|
18
|
-
{ value: 'links', label: trans.menu.links, hint: trans.menu.linksDesc },
|
|
19
|
-
{ value: 'settings', label: trans.menu.settings, hint: trans.menu.settingsDesc },
|
|
15
|
+
{ value: 'events', label: trans.menu.events, hint: trans.menu.eventsDesc || undefined },
|
|
16
|
+
{ value: 'docs', label: trans.menu.docs, hint: trans.menu.docsDesc || undefined },
|
|
17
|
+
{ value: 'status', label: trans.menu.status, hint: trans.menu.statusDesc || undefined },
|
|
18
|
+
{ value: 'links', label: trans.menu.links, hint: trans.menu.linksDesc || undefined },
|
|
19
|
+
{ value: 'settings', label: trans.menu.settings, hint: trans.menu.settingsDesc || undefined },
|
|
20
20
|
];
|
|
21
21
|
}
|
|
22
22
|
export async function showMainMenu() {
|
|
23
23
|
while (true) {
|
|
24
|
-
const trans = t();
|
|
25
24
|
const action = await select({
|
|
26
|
-
message:
|
|
25
|
+
message: 'nbtca',
|
|
27
26
|
options: getMainMenuOptions(),
|
|
28
27
|
});
|
|
29
28
|
if (isCancel(action)) {
|
|
@@ -36,7 +35,7 @@ export async function showMainMenu() {
|
|
|
36
35
|
export async function runMenuAction(action) {
|
|
37
36
|
switch (action) {
|
|
38
37
|
case 'events':
|
|
39
|
-
await
|
|
38
|
+
await showCalendar();
|
|
40
39
|
break;
|
|
41
40
|
case 'docs':
|
|
42
41
|
await showDocsMenu();
|
|
@@ -139,26 +139,8 @@ export async function showEventsPreview() {
|
|
|
139
139
|
console.log();
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
/** Submenu: choose between upcoming and past events. */
|
|
143
|
-
export async function showCalendarMenu() {
|
|
144
|
-
const trans = t();
|
|
145
|
-
const choice = await select({
|
|
146
|
-
message: trans.menu.chooseAction,
|
|
147
|
-
options: [
|
|
148
|
-
{ value: 'upcoming', label: trans.menu.events, hint: trans.menu.eventsDesc },
|
|
149
|
-
{ value: 'past', label: trans.calendar.pastEvents, hint: trans.calendar.pastEventsDesc },
|
|
150
|
-
{ value: '__back__', label: c.muted(trans.common.back) },
|
|
151
|
-
],
|
|
152
|
-
});
|
|
153
|
-
if (isCancel(choice) || choice === '__back__')
|
|
154
|
-
return;
|
|
155
|
-
if (choice === 'upcoming')
|
|
156
|
-
await showCalendar();
|
|
157
|
-
else if (choice === 'past')
|
|
158
|
-
await showPastEvents();
|
|
159
|
-
}
|
|
160
142
|
/** Past events: shows historical events from the last 30 days with detail selection. */
|
|
161
|
-
|
|
143
|
+
async function showPastEvents() {
|
|
162
144
|
const trans = t();
|
|
163
145
|
const s = createSpinner(trans.calendar.pastLoading);
|
|
164
146
|
try {
|
|
@@ -228,14 +210,19 @@ export async function showCalendar() {
|
|
|
228
210
|
label: `${e.date}${e.time ? ' ' + e.time : ''} ${e.title}`,
|
|
229
211
|
hint: e.location,
|
|
230
212
|
})),
|
|
213
|
+
{ value: '__past__', label: chalk.dim(trans.calendar.pastEvents) },
|
|
231
214
|
{ value: '__back__', label: c.muted(trans.common.back) },
|
|
232
215
|
];
|
|
233
216
|
const selected = await select({ message: trans.calendar.viewDetail, options });
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
217
|
+
if (isCancel(selected) || selected === '__back__')
|
|
218
|
+
return;
|
|
219
|
+
if (selected === '__past__') {
|
|
220
|
+
await showPastEvents();
|
|
221
|
+
return;
|
|
238
222
|
}
|
|
223
|
+
const event = events[Number.parseInt(selected, 10)];
|
|
224
|
+
if (event)
|
|
225
|
+
await showEventDetail(event);
|
|
239
226
|
}
|
|
240
227
|
catch {
|
|
241
228
|
s.error(trans.calendar.error);
|
package/dist/features/docs.js
CHANGED
|
@@ -3,7 +3,7 @@ import { markedTerminal } from 'marked-terminal';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import open from 'open';
|
|
5
5
|
import { select, isCancel, confirm, text } from '@clack/prompts';
|
|
6
|
-
import { error, warning,
|
|
6
|
+
import { error, warning, createSpinner } from '../core/ui.js';
|
|
7
7
|
import { pickIcon } from '../core/icons.js';
|
|
8
8
|
import { spawn, execFileSync } from 'child_process';
|
|
9
9
|
import { URLS } from '../config/data.js';
|
|
@@ -122,6 +122,64 @@ async function fetchFileContent(path) {
|
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
124
|
// ─── Content cleaning ─────────────────────────────────────────────────────────
|
|
125
|
+
/**
|
|
126
|
+
* Line-by-line scanner that processes fenced code blocks before marked sees them:
|
|
127
|
+
* - mermaid blocks → styled blockquote placeholder with diagram type
|
|
128
|
+
* - other blocks with a language tag → prepend an inline-code label line
|
|
129
|
+
*/
|
|
130
|
+
function processFencedCodeBlocks(content) {
|
|
131
|
+
const trans = t();
|
|
132
|
+
const lines = content.split('\n');
|
|
133
|
+
const result = [];
|
|
134
|
+
let inBlock = false;
|
|
135
|
+
let fence = '';
|
|
136
|
+
let blockLang = '';
|
|
137
|
+
let blockBody = [];
|
|
138
|
+
for (const line of lines) {
|
|
139
|
+
if (!inBlock) {
|
|
140
|
+
// Accept VitePress code meta after language: ```js{1,3} or ```ts [file.ts] :line-numbers
|
|
141
|
+
const m = line.match(/^(`{3,})(\w+)?[^`\n]*$/);
|
|
142
|
+
if (m) {
|
|
143
|
+
inBlock = true;
|
|
144
|
+
fence = m[1];
|
|
145
|
+
blockLang = (m[2] ?? '').toLowerCase();
|
|
146
|
+
blockBody = [];
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
result.push(line);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
if (line.startsWith(fence) && /^`+\s*$/.test(line)) {
|
|
154
|
+
inBlock = false;
|
|
155
|
+
const body = blockBody.join('\n');
|
|
156
|
+
if (blockLang === 'mermaid') {
|
|
157
|
+
// Skip %%{ init: ... }%% config directives to find the actual diagram type
|
|
158
|
+
const meaningfulLine = body.trim().split('\n')
|
|
159
|
+
.find(l => !l.trimStart().startsWith('%%') && l.trim()) ?? '';
|
|
160
|
+
const firstToken = meaningfulLine.trim().split(/\s+/)[0] ?? 'diagram';
|
|
161
|
+
const icon = pickIcon('📊', '[diagram]');
|
|
162
|
+
result.push(`> ${icon} **${firstToken}** — _${trans.docs.mermaidHint}_`);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
if (blockLang)
|
|
166
|
+
result.push(`\`${blockLang}\``);
|
|
167
|
+
result.push(fence);
|
|
168
|
+
result.push(...blockBody);
|
|
169
|
+
result.push(fence);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
blockBody.push(line);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (inBlock) {
|
|
178
|
+
result.push(`${fence}${blockLang}`);
|
|
179
|
+
result.push(...blockBody);
|
|
180
|
+
}
|
|
181
|
+
return result.join('\n');
|
|
182
|
+
}
|
|
125
183
|
const CONTAINER_ICONS_ASCII = {
|
|
126
184
|
info: '[INFO]', tip: '[TIP]', warning: '[WARN]', danger: '[DANGER]', details: '[DETAIL]'
|
|
127
185
|
};
|
|
@@ -132,6 +190,8 @@ function cleanMarkdownContent(content, type = getTerminalType()) {
|
|
|
132
190
|
let c = content;
|
|
133
191
|
// 1. YAML frontmatter
|
|
134
192
|
c = c.replace(/^---\n[\s\S]*?\n---\n?/m, '');
|
|
193
|
+
// 1.5. Fenced code blocks: mermaid → placeholder, other langs → label prefix
|
|
194
|
+
c = processFencedCodeBlocks(c);
|
|
135
195
|
// 2. VitePress script / style blocks
|
|
136
196
|
c = c.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, '');
|
|
137
197
|
c = c.replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, '');
|
|
@@ -147,6 +207,10 @@ function cleanMarkdownContent(content, type = getTerminalType()) {
|
|
|
147
207
|
c = c.replace(/^>\s*\[!(NOTE|TIP|WARNING|CAUTION|IMPORTANT)\]\s*$/gim, (_, type) => `> **${type.charAt(0) + type.slice(1).toLowerCase()}:**`);
|
|
148
208
|
// 5. [[toc]] — no value in terminal
|
|
149
209
|
c = c.replace(/\[\[toc\]\]/gi, '');
|
|
210
|
+
// 5.5. VitePress heading anchors {#custom-id} — no value in terminal
|
|
211
|
+
c = c.replace(/^(#{1,6}\s+[^\n]*?)\s*\{#[^}]+\}\s*$/gm, '$1');
|
|
212
|
+
// 5.6. ==highlight== → bold (VitePress extended syntax)
|
|
213
|
+
c = c.replace(/==([^=\n]+)==/g, '**$1**');
|
|
150
214
|
// 6. Images — adapt to terminal capability
|
|
151
215
|
if (type === 'basic') {
|
|
152
216
|
c = c.replace(/!\[([^\]]*)\]\([^)]+\)/g, (_, alt) => `${pickIcon('📎', '[image]')} ${alt || 'image'}`);
|
|
@@ -160,8 +224,13 @@ function cleanMarkdownContent(content, type = getTerminalType()) {
|
|
|
160
224
|
// 7. HTML comments
|
|
161
225
|
c = c.replace(/<!--[\s\S]*?-->/g, '');
|
|
162
226
|
// 8. Strip HTML tags, keep inner text
|
|
227
|
+
c = c.replace(/<br\s*\/?>/gi, '\n'); // void: line break
|
|
228
|
+
c = c.replace(/<(?:hr|input|link|meta)\b[^>]*\/?>/gi, ''); // void: discard
|
|
163
229
|
c = c.replace(/<([a-z][a-z0-9]*)\b[^>]*>([\s\S]*?)<\/\1>/gi, '$2');
|
|
164
230
|
c = c.replace(/<[a-z][a-z0-9]*\b[^>]*\/>/gi, '');
|
|
231
|
+
// 8.5. Task list checkboxes
|
|
232
|
+
c = c.replace(/^(\s*[-*+] )\[x\] /gim, '$1☑ ');
|
|
233
|
+
c = c.replace(/^(\s*[-*+] )\[ \] /gm, '$1☐ ');
|
|
165
234
|
// 9. Collapse runs of 3+ blank lines
|
|
166
235
|
c = c.replace(/\n{3,}/g, '\n\n');
|
|
167
236
|
return c.trim();
|
|
@@ -195,10 +264,14 @@ function extractTOC(content) {
|
|
|
195
264
|
return (level === 3 ? ' ' : '') + text;
|
|
196
265
|
});
|
|
197
266
|
}
|
|
198
|
-
/** True if the markdown source contains a
|
|
267
|
+
/** True if the markdown source contains a pipe table. */
|
|
199
268
|
function hasMarkdownTable(content) {
|
|
200
269
|
return /^\|.+\|/m.test(content) && /^\|[-: |]+\|/m.test(content);
|
|
201
270
|
}
|
|
271
|
+
/** True if the markdown source contains a mermaid diagram block. */
|
|
272
|
+
function hasMermaidBlock(content) {
|
|
273
|
+
return /^```mermaid\b/m.test(content);
|
|
274
|
+
}
|
|
202
275
|
// ─── Document tree ────────────────────────────────────────────────────────────
|
|
203
276
|
const TOP_SECTION_ORDER = ['tutorial', 'process', 'repair', 'archived'];
|
|
204
277
|
const TOP_SECTION_SKIP = new Set(['docs', 'index.md', 'README.md']);
|
|
@@ -308,7 +381,7 @@ async function displayWithLess(rendered, title, filePath, readTime, toc) {
|
|
|
308
381
|
const footer = [
|
|
309
382
|
'',
|
|
310
383
|
rule,
|
|
311
|
-
chalk.dim(` ${trans.docs.endOfDocument}
|
|
384
|
+
chalk.dim(` ${trans.docs.endOfDocument}`),
|
|
312
385
|
'',
|
|
313
386
|
].join('\n');
|
|
314
387
|
const fullContent = header + rendered + footer;
|
|
@@ -347,11 +420,7 @@ async function showDocSection(section) {
|
|
|
347
420
|
const selected = await select({
|
|
348
421
|
message: section.label,
|
|
349
422
|
options: [
|
|
350
|
-
...files.map(f => {
|
|
351
|
-
const parts = f.path.split('/');
|
|
352
|
-
const hint = parts.length > 2 ? parts.slice(1, -1).join('/') : '';
|
|
353
|
-
return { value: f.path, label: cleanFileName(f.name), hint };
|
|
354
|
-
}),
|
|
423
|
+
...files.map(f => ({ value: f.path, label: cleanFileName(f.name) })),
|
|
355
424
|
{ value: '__back__', label: chalk.dim(trans.common.back) },
|
|
356
425
|
],
|
|
357
426
|
});
|
|
@@ -380,7 +449,7 @@ async function showArchivedSection(files) {
|
|
|
380
449
|
...sortedKeys.map(k => ({
|
|
381
450
|
value: k,
|
|
382
451
|
label: k,
|
|
383
|
-
hint:
|
|
452
|
+
hint: String(groups.get(k).length),
|
|
384
453
|
})),
|
|
385
454
|
{ value: '__back__', label: chalk.dim(trans.common.back) },
|
|
386
455
|
],
|
|
@@ -388,14 +457,18 @@ async function showArchivedSection(files) {
|
|
|
388
457
|
if (isCancel(groupKey) || groupKey === '__back__')
|
|
389
458
|
return;
|
|
390
459
|
const groupFiles = groups.get(groupKey) ?? [];
|
|
460
|
+
const subDirs = new Set(groupFiles.map(f => f.path.split('/')[2]).filter(Boolean));
|
|
391
461
|
const fileSelected = await select({
|
|
392
|
-
message: `${trans.docs.categoryArchived}
|
|
462
|
+
message: `${trans.docs.categoryArchived} · ${groupKey}`,
|
|
393
463
|
options: [
|
|
394
|
-
...groupFiles.map(f =>
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
464
|
+
...groupFiles.map(f => {
|
|
465
|
+
const sub = f.path.split('/').slice(2, -1).join('/');
|
|
466
|
+
return {
|
|
467
|
+
value: f.path,
|
|
468
|
+
label: cleanFileName(f.name),
|
|
469
|
+
hint: subDirs.size > 1 ? sub : undefined,
|
|
470
|
+
};
|
|
471
|
+
}),
|
|
399
472
|
{ value: '__back__', label: chalk.dim(trans.common.back) },
|
|
400
473
|
],
|
|
401
474
|
});
|
|
@@ -406,65 +479,54 @@ async function showArchivedSection(files) {
|
|
|
406
479
|
// ─── Document viewer ──────────────────────────────────────────────────────────
|
|
407
480
|
async function viewMarkdownFile(filePath) {
|
|
408
481
|
const trans = t();
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
renderedDoc = cachedRendered;
|
|
419
|
-
}
|
|
420
|
-
else {
|
|
421
|
-
const cleaned = cleanMarkdownContent(rawContent, getTerminalType());
|
|
422
|
-
const title = extractDocTitle(rawContent, cleaned) || cleanFileName(filePath.split('/').pop() ?? filePath);
|
|
423
|
-
const readTime = estimateReadTime(cleaned);
|
|
424
|
-
const rendered = await marked(cleaned);
|
|
425
|
-
renderedDoc = { fingerprint, cleaned, rendered, title, readTime };
|
|
426
|
-
setRender(filePath, renderedDoc);
|
|
427
|
-
}
|
|
428
|
-
s.stop(`${chalk.bold(renderedDoc.title)} ${chalk.dim(renderedDoc.readTime)}`);
|
|
429
|
-
const toc = extractTOC(renderedDoc.cleaned);
|
|
430
|
-
if (hasGlow()) {
|
|
431
|
-
await displayWithGlow(renderedDoc.cleaned);
|
|
432
|
-
}
|
|
433
|
-
else {
|
|
434
|
-
await displayWithLess(renderedDoc.rendered, renderedDoc.title, filePath, renderedDoc.readTime, toc);
|
|
435
|
-
}
|
|
436
|
-
console.log();
|
|
437
|
-
success(trans.docs.docCompleted);
|
|
438
|
-
console.log();
|
|
439
|
-
const hasTable = hasMarkdownTable(rawContent);
|
|
440
|
-
const action = await select({
|
|
441
|
-
message: trans.docs.chooseAction,
|
|
442
|
-
options: [
|
|
443
|
-
{ value: 'back', label: trans.docs.backToList },
|
|
444
|
-
{ value: 'reread', label: trans.docs.reread },
|
|
445
|
-
{ value: 'browser', label: trans.docs.openBrowser,
|
|
446
|
-
hint: hasTable ? trans.docs.tableHint : undefined },
|
|
447
|
-
],
|
|
448
|
-
});
|
|
449
|
-
if (isCancel(action) || action === 'back')
|
|
450
|
-
return;
|
|
451
|
-
if (action === 'browser') {
|
|
452
|
-
await openDocsInBrowser(filePath);
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
// 'reread' → loop
|
|
482
|
+
try {
|
|
483
|
+
ensureMarkedConfigured();
|
|
484
|
+
const s = createSpinner(`${trans.docs.loadingFile}: ${filePath}`);
|
|
485
|
+
const rawContent = await fetchFileContent(filePath);
|
|
486
|
+
const fingerprint = contentFingerprint(rawContent);
|
|
487
|
+
const cachedRendered = getFreshRender(filePath);
|
|
488
|
+
let renderedDoc;
|
|
489
|
+
if (cachedRendered && cachedRendered.fingerprint === fingerprint) {
|
|
490
|
+
renderedDoc = cachedRendered;
|
|
456
491
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
492
|
+
else {
|
|
493
|
+
const cleaned = cleanMarkdownContent(rawContent, getTerminalType());
|
|
494
|
+
const title = extractDocTitle(rawContent, cleaned) || cleanFileName(filePath.split('/').pop() ?? filePath);
|
|
495
|
+
const readTime = estimateReadTime(cleaned);
|
|
496
|
+
const rendered = await marked(cleaned);
|
|
497
|
+
renderedDoc = { fingerprint, cleaned, rendered, title, readTime };
|
|
498
|
+
setRender(filePath, renderedDoc);
|
|
499
|
+
}
|
|
500
|
+
s.stop(`${chalk.bold(renderedDoc.title)} ${chalk.dim(renderedDoc.readTime)}`);
|
|
501
|
+
const toc = extractTOC(renderedDoc.cleaned);
|
|
502
|
+
if (hasGlow()) {
|
|
503
|
+
await displayWithGlow(renderedDoc.cleaned);
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
await displayWithLess(renderedDoc.rendered, renderedDoc.title, filePath, renderedDoc.readTime, toc);
|
|
507
|
+
}
|
|
508
|
+
const needsBrowser = hasMarkdownTable(rawContent) || hasMermaidBlock(rawContent);
|
|
509
|
+
const action = await select({
|
|
510
|
+
message: trans.docs.chooseAction,
|
|
511
|
+
options: [
|
|
512
|
+
{ value: 'back', label: trans.docs.backToList },
|
|
513
|
+
{ value: 'browser', label: trans.docs.openBrowser,
|
|
514
|
+
hint: needsBrowser ? trans.docs.tableHint : undefined },
|
|
515
|
+
],
|
|
516
|
+
});
|
|
517
|
+
if (!isCancel(action) && action === 'browser') {
|
|
518
|
+
await openDocsInBrowser(filePath);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
catch (err) {
|
|
522
|
+
error(trans.docs.loadError);
|
|
523
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
524
|
+
console.log(chalk.gray(` ${trans.docs.errorHint}: ${errMsg}`));
|
|
525
|
+
setVimKeysActive(false);
|
|
526
|
+
const openBrowser = await confirm({ message: trans.docs.openBrowserPrompt });
|
|
527
|
+
setVimKeysActive(true);
|
|
528
|
+
if (!isCancel(openBrowser) && openBrowser) {
|
|
529
|
+
await openDocsInBrowser(filePath);
|
|
468
530
|
}
|
|
469
531
|
}
|
|
470
532
|
}
|
|
@@ -535,27 +597,16 @@ export async function showDocsMenu() {
|
|
|
535
597
|
const action = await select({
|
|
536
598
|
message: trans.docs.chooseCategory,
|
|
537
599
|
options: [
|
|
538
|
-
...sections.map(sec => ({
|
|
539
|
-
value: sec.key,
|
|
540
|
-
label: sec.label,
|
|
541
|
-
hint: `${sec.count} docs`,
|
|
542
|
-
})),
|
|
600
|
+
...sections.map(sec => ({ value: sec.key, label: sec.label })),
|
|
543
601
|
{ value: 'search', label: chalk.dim(trans.docs.searchPrompt.replace(':', '')) },
|
|
544
|
-
{ value: 'refresh-cache', label: chalk.dim(trans.docs.refreshCache) },
|
|
545
602
|
{ value: 'browser', label: chalk.dim(trans.docs.openBrowser) },
|
|
546
|
-
{ value: 'back', label: chalk.dim(trans.docs.returnToMenu) },
|
|
547
603
|
],
|
|
548
604
|
});
|
|
549
|
-
if (isCancel(action)
|
|
605
|
+
if (isCancel(action))
|
|
550
606
|
return;
|
|
551
607
|
if (action === 'search') {
|
|
552
608
|
await searchDocs();
|
|
553
609
|
}
|
|
554
|
-
else if (action === 'refresh-cache') {
|
|
555
|
-
clearDocsCache();
|
|
556
|
-
sections = (await loadSections()) ?? sections;
|
|
557
|
-
success(trans.docs.cacheCleared);
|
|
558
|
-
}
|
|
559
610
|
else if (action === 'browser') {
|
|
560
611
|
await openDocsInBrowser();
|
|
561
612
|
}
|
package/dist/features/links.js
CHANGED
|
@@ -28,10 +28,9 @@ export async function showLinksMenu() {
|
|
|
28
28
|
{ value: URLS.github, label: trans.links.github },
|
|
29
29
|
{ value: URLS.roadmap, label: trans.links.roadmap },
|
|
30
30
|
{ value: URLS.repair, label: trans.links.repair },
|
|
31
|
-
{ value: '__back__', label: chalk.dim(trans.common.back) },
|
|
32
31
|
],
|
|
33
32
|
});
|
|
34
|
-
if (isCancel(selected)
|
|
33
|
+
if (isCancel(selected))
|
|
35
34
|
return;
|
|
36
35
|
await openUrl(selected);
|
|
37
36
|
}
|
|
@@ -44,15 +44,14 @@ export async function showSettingsMenu() {
|
|
|
44
44
|
const action = await select({
|
|
45
45
|
message: trans.theme.chooseAction,
|
|
46
46
|
options: [
|
|
47
|
-
{ value: 'language', label: trans.language.selectLanguage
|
|
47
|
+
{ value: 'language', label: trans.language.selectLanguage, hint: currentLang === 'zh' ? trans.language.zh : trans.language.en },
|
|
48
48
|
{ value: 'icon', label: trans.theme.iconMode, hint: prefs.iconMode },
|
|
49
49
|
{ value: 'color', label: trans.theme.colorMode, hint: prefs.colorMode },
|
|
50
|
-
{ value: 'reset', label: trans.theme.
|
|
50
|
+
{ value: 'reset', label: trans.theme.resetLabel },
|
|
51
51
|
{ value: 'about', label: trans.about.title },
|
|
52
|
-
{ value: 'back', label: chalk.dim(trans.common.back) },
|
|
53
52
|
],
|
|
54
53
|
});
|
|
55
|
-
if (isCancel(action)
|
|
54
|
+
if (isCancel(action))
|
|
56
55
|
return;
|
|
57
56
|
if (action === 'about') {
|
|
58
57
|
showAbout();
|
|
@@ -12,19 +12,19 @@
|
|
|
12
12
|
},
|
|
13
13
|
"menu": {
|
|
14
14
|
"events": "Events",
|
|
15
|
-
"eventsDesc": "
|
|
15
|
+
"eventsDesc": "",
|
|
16
16
|
"docs": "Docs",
|
|
17
17
|
"docsDesc": "Knowledge base",
|
|
18
18
|
"status": "Status",
|
|
19
|
-
"statusDesc": "
|
|
19
|
+
"statusDesc": "Online status",
|
|
20
20
|
"links": "Links",
|
|
21
|
-
"linksDesc": "
|
|
21
|
+
"linksDesc": "website · GitHub · roadmap",
|
|
22
22
|
"settings": "Settings",
|
|
23
|
-
"settingsDesc": "
|
|
24
|
-
"chooseAction": "
|
|
23
|
+
"settingsDesc": "language · theme · about",
|
|
24
|
+
"chooseAction": "nbtca"
|
|
25
25
|
},
|
|
26
26
|
"about": {
|
|
27
|
-
"title": "About
|
|
27
|
+
"title": "About",
|
|
28
28
|
"project": "Project",
|
|
29
29
|
"version": "Version",
|
|
30
30
|
"description": "Description",
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"categoryTutorial": "Tutorials",
|
|
67
67
|
"categoryRepairLogs": "Repair Logs",
|
|
68
68
|
"categoryEvents": "Event Docs",
|
|
69
|
-
"categoryProcess": "Process
|
|
69
|
+
"categoryProcess": "Process",
|
|
70
70
|
"categoryRepair": "Repair",
|
|
71
71
|
"categoryArchived": "Archived",
|
|
72
72
|
"categoryReadme": "Project README",
|
|
73
|
-
"chooseCategory": "
|
|
73
|
+
"chooseCategory": "Docs",
|
|
74
74
|
"refreshCache": "Refresh cache",
|
|
75
75
|
"cacheCleared": "Documentation cache cleared",
|
|
76
76
|
"usingCachedData": "Network unavailable, using cached data",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"emptyDir": "This directory is empty",
|
|
80
80
|
"upToParent": "Up to parent directory",
|
|
81
81
|
"returnToMenu": "Return to main menu",
|
|
82
|
-
"backToList": "Back
|
|
82
|
+
"backToList": "Back",
|
|
83
83
|
"reread": "Re-read document",
|
|
84
84
|
"openBrowser": "Open in browser",
|
|
85
85
|
"loadError": "Failed to load directory",
|
|
@@ -93,8 +93,9 @@
|
|
|
93
93
|
"browserErrorHint": "Please visit manually: https://docs.nbtca.space",
|
|
94
94
|
"retry": "Retry?",
|
|
95
95
|
"tocTitle": "Table of Contents",
|
|
96
|
-
"tableHint": "tables render better in browser",
|
|
97
|
-
"
|
|
96
|
+
"tableHint": "diagrams and tables render better in browser",
|
|
97
|
+
"mermaidHint": "open in browser to view",
|
|
98
|
+
"endOfDocument": "end of document · q quit · / search",
|
|
98
99
|
"githubRateLimited": "GitHub API rate limit reached. Resets at {time}.",
|
|
99
100
|
"githubForbidden": "GitHub API access denied (403).",
|
|
100
101
|
"githubTokenHint": "Tip: set GITHUB_TOKEN for a higher rate limit.",
|
|
@@ -108,7 +109,7 @@
|
|
|
108
109
|
"loadingFile": "Loading"
|
|
109
110
|
},
|
|
110
111
|
"links": {
|
|
111
|
-
"choose": "
|
|
112
|
+
"choose": "Links",
|
|
112
113
|
"website": "Official Website",
|
|
113
114
|
"github": "GitHub",
|
|
114
115
|
"roadmap": "Roadmap",
|
|
@@ -165,12 +166,13 @@
|
|
|
165
166
|
"updated": "Theme setting updated",
|
|
166
167
|
"updatedSessionOnly": "Theme setting updated for this session only (failed to save config)",
|
|
167
168
|
"reset": "Theme settings reset",
|
|
169
|
+
"resetLabel": "Reset",
|
|
168
170
|
"resetSessionOnly": "Theme settings reset for this session only (failed to save config)",
|
|
169
171
|
"usage": "Usage: nbtca theme | nbtca theme icon <auto|ascii|unicode> | nbtca theme color <auto|on|off> | nbtca theme reset",
|
|
170
172
|
"invalidValue": "Invalid value. Use one of:"
|
|
171
173
|
},
|
|
172
174
|
"language": {
|
|
173
|
-
"selectLanguage": "
|
|
175
|
+
"selectLanguage": "Language",
|
|
174
176
|
"zh": "简体中文 (Simplified Chinese)",
|
|
175
177
|
"en": "English",
|
|
176
178
|
"changed": "Language changed successfully",
|
|
@@ -12,19 +12,19 @@
|
|
|
12
12
|
},
|
|
13
13
|
"menu": {
|
|
14
14
|
"events": "活动",
|
|
15
|
-
"eventsDesc": "
|
|
15
|
+
"eventsDesc": "",
|
|
16
16
|
"docs": "文档",
|
|
17
17
|
"docsDesc": "知识库",
|
|
18
18
|
"status": "状态",
|
|
19
|
-
"statusDesc": "
|
|
19
|
+
"statusDesc": "在线状态",
|
|
20
20
|
"links": "链接",
|
|
21
|
-
"linksDesc": "
|
|
21
|
+
"linksDesc": "官网 · GitHub · 路线图",
|
|
22
22
|
"settings": "设置",
|
|
23
|
-
"settingsDesc": "
|
|
24
|
-
"chooseAction": "
|
|
23
|
+
"settingsDesc": "语言 · 主题 · 关于",
|
|
24
|
+
"chooseAction": "nbtca"
|
|
25
25
|
},
|
|
26
26
|
"about": {
|
|
27
|
-
"title": "关于
|
|
27
|
+
"title": "关于",
|
|
28
28
|
"project": "项目",
|
|
29
29
|
"version": "版本",
|
|
30
30
|
"description": "描述",
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"categoryTutorial": "教程",
|
|
67
67
|
"categoryRepairLogs": "维修日记",
|
|
68
68
|
"categoryEvents": "活动文档",
|
|
69
|
-
"categoryProcess": "
|
|
70
|
-
"categoryRepair": "
|
|
71
|
-
"categoryArchived": "
|
|
69
|
+
"categoryProcess": "流程",
|
|
70
|
+
"categoryRepair": "维修",
|
|
71
|
+
"categoryArchived": "归档",
|
|
72
72
|
"categoryReadme": "项目说明 (README)",
|
|
73
|
-
"chooseCategory": "
|
|
73
|
+
"chooseCategory": "文档",
|
|
74
74
|
"refreshCache": "刷新缓存",
|
|
75
75
|
"cacheCleared": "文档缓存已清除",
|
|
76
76
|
"usingCachedData": "网络不可用,使用缓存数据",
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
"emptyDir": "该目录为空",
|
|
80
80
|
"upToParent": "返回上级目录",
|
|
81
81
|
"returnToMenu": "返回主菜单",
|
|
82
|
-
"backToList": "
|
|
82
|
+
"backToList": "返回",
|
|
83
83
|
"reread": "重新阅读文档",
|
|
84
84
|
"openBrowser": "在浏览器中打开",
|
|
85
85
|
"loadError": "无法加载目录",
|
|
@@ -93,8 +93,9 @@
|
|
|
93
93
|
"browserErrorHint": "请手动访问: https://docs.nbtca.space",
|
|
94
94
|
"retry": "是否重试?",
|
|
95
95
|
"tocTitle": "目录",
|
|
96
|
-
"tableHint": "
|
|
97
|
-
"
|
|
96
|
+
"tableHint": "图表与表格在浏览器中效果更佳",
|
|
97
|
+
"mermaidHint": "在浏览器中查看图表",
|
|
98
|
+
"endOfDocument": "文档结束 · q 退出 · / 搜索",
|
|
98
99
|
"githubRateLimited": "GitHub API 速率限制已达上限,将在 {time} 重置。",
|
|
99
100
|
"githubForbidden": "GitHub API 拒绝访问 (403)。",
|
|
100
101
|
"githubTokenHint": "提示: 设置 GITHUB_TOKEN 环境变量可获得更高的速率限制。",
|
|
@@ -108,7 +109,7 @@
|
|
|
108
109
|
"loadingFile": "正在加载"
|
|
109
110
|
},
|
|
110
111
|
"links": {
|
|
111
|
-
"choose": "
|
|
112
|
+
"choose": "链接",
|
|
112
113
|
"website": "官方网站",
|
|
113
114
|
"github": "GitHub",
|
|
114
115
|
"roadmap": "路线图",
|
|
@@ -165,12 +166,13 @@
|
|
|
165
166
|
"updated": "主题设置已更新",
|
|
166
167
|
"updatedSessionOnly": "主题设置仅在当前会话生效(无法写入配置文件)",
|
|
167
168
|
"reset": "主题设置已重置",
|
|
169
|
+
"resetLabel": "重置",
|
|
168
170
|
"resetSessionOnly": "主题设置仅在当前会话重置(无法写入配置文件)",
|
|
169
171
|
"usage": "用法: nbtca theme | nbtca theme icon <auto|ascii|unicode> | nbtca theme color <auto|on|off> | nbtca theme reset",
|
|
170
172
|
"invalidValue": "无效取值,可选:"
|
|
171
173
|
},
|
|
172
174
|
"language": {
|
|
173
|
-
"selectLanguage": "
|
|
175
|
+
"selectLanguage": "语言",
|
|
174
176
|
"zh": "简体中文",
|
|
175
177
|
"en": "English",
|
|
176
178
|
"changed": "语言已切换",
|