@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 CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { select, isCancel, outro } from '@clack/prompts';
5
5
  import chalk from 'chalk';
6
- import { showCalendarMenu } from '../features/calendar.js';
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: trans.menu.chooseAction,
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 showCalendarMenu();
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
- export async function showPastEvents() {
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 (!isCancel(selected) && selected !== '__back__') {
235
- const event = events[Number.parseInt(selected, 10)];
236
- if (event)
237
- await showEventDetail(event);
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);
@@ -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, success, createSpinner } from '../core/ui.js';
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 table (pipe-delimited with separator row). */
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} · / to search`),
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: `${groups.get(k).length} docs`,
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} / ${groupKey}`,
462
+ message: `${trans.docs.categoryArchived} · ${groupKey}`,
393
463
  options: [
394
- ...groupFiles.map(f => ({
395
- value: f.path,
396
- label: cleanFileName(f.name),
397
- hint: f.path.split('/').slice(2, -1).join('/'),
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
- while (true) {
410
- try {
411
- ensureMarkedConfigured();
412
- const s = createSpinner(`${trans.docs.loadingFile}: ${filePath}`);
413
- const rawContent = await fetchFileContent(filePath);
414
- const fingerprint = contentFingerprint(rawContent);
415
- const cachedRendered = getFreshRender(filePath);
416
- let renderedDoc;
417
- if (cachedRendered && cachedRendered.fingerprint === fingerprint) {
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
- catch (err) {
458
- error(trans.docs.loadError);
459
- const errMsg = err instanceof Error ? err.message : String(err);
460
- console.log(chalk.gray(` ${trans.docs.errorHint}: ${errMsg}`));
461
- setVimKeysActive(false);
462
- const openBrowser = await confirm({ message: trans.docs.openBrowserPrompt });
463
- setVimKeysActive(true);
464
- if (!isCancel(openBrowser) && openBrowser) {
465
- await openDocsInBrowser(filePath);
466
- }
467
- return;
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) || action === 'back')
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
  }
@@ -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) || selected === '__back__')
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.replace(':', ''), hint: currentLang === 'zh' ? trans.language.zh : trans.language.en },
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.reset },
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) || action === 'back')
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": "Upcoming activities",
15
+ "eventsDesc": "",
16
16
  "docs": "Docs",
17
17
  "docsDesc": "Knowledge base",
18
18
  "status": "Status",
19
- "statusDesc": "Service health",
19
+ "statusDesc": "Online status",
20
20
  "links": "Links",
21
- "linksDesc": "Website, GitHub, Roadmap",
21
+ "linksDesc": "website · GitHub · roadmap",
22
22
  "settings": "Settings",
23
- "settingsDesc": "Language, theme, about",
24
- "chooseAction": "Choose an action"
23
+ "settingsDesc": "language · theme · about",
24
+ "chooseAction": "nbtca"
25
25
  },
26
26
  "about": {
27
- "title": "About NBTCA",
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 Docs",
69
+ "categoryProcess": "Process",
70
70
  "categoryRepair": "Repair",
71
71
  "categoryArchived": "Archived",
72
72
  "categoryReadme": "Project README",
73
- "chooseCategory": "Choose a category:",
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 to docs list",
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
- "endOfDocument": "End of document - Press q to quit",
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": "Open a link:",
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": "Select a language:",
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": "官网、GitHub、路线图",
21
+ "linksDesc": "官网 · GitHub · 路线图",
22
22
  "settings": "设置",
23
- "settingsDesc": "语言、主题、关于",
24
- "chooseAction": "选择一个操作"
23
+ "settingsDesc": "语言 · 主题 · 关于",
24
+ "chooseAction": "nbtca"
25
25
  },
26
26
  "about": {
27
- "title": "关于 NBTCA",
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
- "endOfDocument": "文档结束 - 按 q 退出",
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": "语言已切换",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nbtca/prompt",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {