@nbtca/prompt 1.0.22 → 1.0.24
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/config/data.js +5 -1
- package/dist/config/paths.js +5 -0
- package/dist/config/preferences.js +1 -8
- package/dist/core/icons.js +18 -5
- package/dist/core/logo.js +1 -2
- package/dist/core/menu.js +7 -122
- package/dist/core/text.js +9 -3
- package/dist/core/ui.js +0 -1
- package/dist/core/vim-keys.js +6 -5
- package/dist/features/calendar.js +50 -9
- package/dist/features/docs.js +128 -49
- package/dist/features/links.js +42 -0
- package/dist/features/settings.js +120 -0
- package/dist/features/status.js +19 -26
- package/dist/features/theme.js +9 -101
- package/dist/features/update.js +74 -0
- package/dist/i18n/index.js +7 -16
- package/dist/i18n/locales/en.json +43 -54
- package/dist/i18n/locales/zh.json +43 -54
- package/dist/index.js +107 -67
- package/dist/logo/ascii-logo.txt +12 -6
- package/dist/logo/logo.txt +12 -2
- package/dist/main.js +14 -5
- package/package.json +4 -1
- package/dist/config/data.d.ts +0 -23
- package/dist/config/data.d.ts.map +0 -1
- package/dist/config/data.js.map +0 -1
- package/dist/config/preferences.d.ts +0 -14
- package/dist/config/preferences.d.ts.map +0 -1
- package/dist/config/preferences.js.map +0 -1
- package/dist/config/theme.d.ts +0 -23
- package/dist/config/theme.d.ts.map +0 -1
- package/dist/config/theme.js +0 -25
- package/dist/config/theme.js.map +0 -1
- package/dist/core/icons.d.ts +0 -3
- package/dist/core/icons.d.ts.map +0 -1
- package/dist/core/icons.js.map +0 -1
- package/dist/core/logo.d.ts +0 -9
- package/dist/core/logo.d.ts.map +0 -1
- package/dist/core/logo.js.map +0 -1
- package/dist/core/menu.d.ts +0 -14
- package/dist/core/menu.d.ts.map +0 -1
- package/dist/core/menu.js.map +0 -1
- package/dist/core/text.d.ts +0 -7
- package/dist/core/text.d.ts.map +0 -1
- package/dist/core/text.js.map +0 -1
- package/dist/core/ui.d.ts +0 -38
- package/dist/core/ui.d.ts.map +0 -1
- package/dist/core/ui.js.map +0 -1
- package/dist/core/vim-keys.d.ts +0 -8
- package/dist/core/vim-keys.d.ts.map +0 -1
- package/dist/core/vim-keys.js.map +0 -1
- package/dist/features/calendar.d.ts +0 -29
- package/dist/features/calendar.d.ts.map +0 -1
- package/dist/features/calendar.js.map +0 -1
- package/dist/features/docs.d.ts +0 -8
- package/dist/features/docs.d.ts.map +0 -1
- package/dist/features/docs.js.map +0 -1
- package/dist/features/repair.d.ts +0 -10
- package/dist/features/repair.d.ts.map +0 -1
- package/dist/features/repair.js +0 -29
- package/dist/features/repair.js.map +0 -1
- package/dist/features/status.d.ts +0 -31
- package/dist/features/status.d.ts.map +0 -1
- package/dist/features/status.js.map +0 -1
- package/dist/features/theme.d.ts +0 -8
- package/dist/features/theme.d.ts.map +0 -1
- package/dist/features/theme.js.map +0 -1
- package/dist/features/website.d.ts +0 -30
- package/dist/features/website.d.ts.map +0 -1
- package/dist/features/website.js +0 -48
- package/dist/features/website.js.map +0 -1
- package/dist/i18n/index.d.ts +0 -209
- package/dist/i18n/index.d.ts.map +0 -1
- package/dist/i18n/index.js.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/main.d.ts +0 -12
- package/dist/main.d.ts.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/types.d.ts +0 -48
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -6
- package/dist/types.js.map +0 -1
package/dist/config/data.js
CHANGED
|
@@ -26,6 +26,11 @@ export const URLS = {
|
|
|
26
26
|
calendar: 'https://ical.nbtca.space',
|
|
27
27
|
email: 'contact@nbtca.space',
|
|
28
28
|
};
|
|
29
|
+
export const GITHUB_REPO = {
|
|
30
|
+
owner: 'nbtca',
|
|
31
|
+
repo: 'documents',
|
|
32
|
+
branch: 'main',
|
|
33
|
+
};
|
|
29
34
|
export const APP_INFO = {
|
|
30
35
|
name: 'Prompt',
|
|
31
36
|
version: readPackageVersion(),
|
|
@@ -35,4 +40,3 @@ export const APP_INFO = {
|
|
|
35
40
|
license: 'MIT',
|
|
36
41
|
repository: 'https://github.com/nbtca/prompt'
|
|
37
42
|
};
|
|
38
|
-
//# sourceMappingURL=data.js.map
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { getConfigDir } from './paths.js';
|
|
3
4
|
const DEFAULT_PREFERENCES = {
|
|
4
5
|
iconMode: 'auto',
|
|
5
6
|
colorMode: 'auto',
|
|
6
7
|
};
|
|
7
|
-
function getConfigDir() {
|
|
8
|
-
const homeDir = process.env['HOME'] || process.env['USERPROFILE'] || '';
|
|
9
|
-
return path.join(homeDir, '.nbtca');
|
|
10
|
-
}
|
|
11
8
|
function getPreferencesPath() {
|
|
12
9
|
return path.join(getConfigDir(), 'preferences.json');
|
|
13
10
|
}
|
|
@@ -20,9 +17,6 @@ function ensureConfigDir() {
|
|
|
20
17
|
export function loadPreferences() {
|
|
21
18
|
try {
|
|
22
19
|
const prefPath = getPreferencesPath();
|
|
23
|
-
if (!fs.existsSync(prefPath)) {
|
|
24
|
-
return { ...DEFAULT_PREFERENCES };
|
|
25
|
-
}
|
|
26
20
|
const raw = JSON.parse(fs.readFileSync(prefPath, 'utf-8'));
|
|
27
21
|
const iconMode = raw.iconMode === 'ascii' || raw.iconMode === 'unicode' || raw.iconMode === 'auto'
|
|
28
22
|
? raw.iconMode
|
|
@@ -87,4 +81,3 @@ export function applyColorModePreference(forcePlain) {
|
|
|
87
81
|
delete process.env['NO_COLOR'];
|
|
88
82
|
}
|
|
89
83
|
}
|
|
90
|
-
//# sourceMappingURL=preferences.js.map
|
package/dist/core/icons.js
CHANGED
|
@@ -3,18 +3,31 @@ function localeSupportsUnicode() {
|
|
|
3
3
|
const locale = `${process.env['LC_ALL'] || ''} ${process.env['LANG'] || ''}`.toLowerCase();
|
|
4
4
|
return locale.includes('utf-8') || locale.includes('utf8');
|
|
5
5
|
}
|
|
6
|
+
let cachedUseUnicode = null;
|
|
6
7
|
export function useUnicodeIcons() {
|
|
8
|
+
if (cachedUseUnicode !== null)
|
|
9
|
+
return cachedUseUnicode;
|
|
7
10
|
const configured = resolveIconMode();
|
|
8
|
-
if (configured === 'ascii')
|
|
11
|
+
if (configured === 'ascii') {
|
|
12
|
+
cachedUseUnicode = false;
|
|
9
13
|
return false;
|
|
10
|
-
|
|
14
|
+
}
|
|
15
|
+
if (configured === 'unicode') {
|
|
16
|
+
cachedUseUnicode = true;
|
|
11
17
|
return true;
|
|
18
|
+
}
|
|
12
19
|
const term = (process.env['TERM'] || '').toLowerCase();
|
|
13
|
-
if (!process.stdout.isTTY || term === 'dumb')
|
|
20
|
+
if (!process.stdout.isTTY || term === 'dumb') {
|
|
21
|
+
cachedUseUnicode = false;
|
|
14
22
|
return false;
|
|
15
|
-
|
|
23
|
+
}
|
|
24
|
+
cachedUseUnicode = localeSupportsUnicode();
|
|
25
|
+
return cachedUseUnicode;
|
|
26
|
+
}
|
|
27
|
+
/** Invalidate the cached icon mode (call after theme changes). */
|
|
28
|
+
export function resetIconCache() {
|
|
29
|
+
cachedUseUnicode = null;
|
|
16
30
|
}
|
|
17
31
|
export function pickIcon(unicodeIcon, asciiIcon) {
|
|
18
32
|
return useUnicodeIcons() ? unicodeIcon : asciiIcon;
|
|
19
33
|
}
|
|
20
|
-
//# sourceMappingURL=icons.js.map
|
package/dist/core/logo.js
CHANGED
|
@@ -36,7 +36,7 @@ function printDescription() {
|
|
|
36
36
|
/**
|
|
37
37
|
* Attempt to read and display logo file
|
|
38
38
|
*/
|
|
39
|
-
export
|
|
39
|
+
export function printLogo() {
|
|
40
40
|
if (!process.stdout.isTTY) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
@@ -68,4 +68,3 @@ export async function printLogo() {
|
|
|
68
68
|
printDescription();
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
-
//# sourceMappingURL=logo.js.map
|
package/dist/core/menu.js
CHANGED
|
@@ -1,39 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Minimalist menu system
|
|
3
|
-
* Modern @clack/prompts select() with emoji icons and hint text
|
|
4
3
|
*/
|
|
5
|
-
import { select, isCancel, outro
|
|
4
|
+
import { select, isCancel, outro } from '@clack/prompts';
|
|
6
5
|
import chalk from 'chalk';
|
|
7
6
|
import { showCalendar } from '../features/calendar.js';
|
|
8
|
-
import { openRepairService } from '../features/repair.js';
|
|
9
7
|
import { showDocsMenu } from '../features/docs.js';
|
|
10
8
|
import { showServiceStatus } from '../features/status.js';
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { pickIcon } from './icons.js';
|
|
15
|
-
import { padEndV } from './text.js';
|
|
16
|
-
import { APP_INFO, URLS } from '../config/data.js';
|
|
17
|
-
import { t, getCurrentLanguage, setLanguage, clearTranslationCache } from '../i18n/index.js';
|
|
18
|
-
/**
|
|
19
|
-
* Get main menu options — 6 items
|
|
20
|
-
*/
|
|
9
|
+
import { showLinksMenu } from '../features/links.js';
|
|
10
|
+
import { showSettingsMenu } from '../features/settings.js';
|
|
11
|
+
import { t } from '../i18n/index.js';
|
|
21
12
|
function getMainMenuOptions() {
|
|
22
13
|
const trans = t();
|
|
23
14
|
return [
|
|
24
15
|
{ value: 'events', label: trans.menu.events, hint: trans.menu.eventsDesc },
|
|
25
|
-
{ value: 'repair', label: trans.menu.repair, hint: trans.menu.repairDesc },
|
|
26
16
|
{ value: 'docs', label: trans.menu.docs, hint: trans.menu.docsDesc },
|
|
27
17
|
{ value: 'status', label: trans.menu.status, hint: trans.menu.statusDesc },
|
|
28
18
|
{ value: 'links', label: trans.menu.links, hint: trans.menu.linksDesc },
|
|
29
|
-
{ value: '
|
|
30
|
-
{ value: 'theme', label: trans.menu.theme, hint: trans.menu.themeDesc },
|
|
31
|
-
{ value: 'language', label: trans.menu.language, hint: trans.menu.languageDesc },
|
|
19
|
+
{ value: 'settings', label: trans.menu.settings, hint: trans.menu.settingsDesc },
|
|
32
20
|
];
|
|
33
21
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Display main menu — loops until user exits via Ctrl+C
|
|
36
|
-
*/
|
|
37
22
|
export async function showMainMenu() {
|
|
38
23
|
while (true) {
|
|
39
24
|
const trans = t();
|
|
@@ -46,22 +31,13 @@ export async function showMainMenu() {
|
|
|
46
31
|
process.exit(0);
|
|
47
32
|
}
|
|
48
33
|
await runMenuAction(action);
|
|
49
|
-
printNewLine();
|
|
50
|
-
printDivider();
|
|
51
|
-
printNewLine();
|
|
52
34
|
}
|
|
53
35
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Handle user action
|
|
56
|
-
*/
|
|
57
36
|
export async function runMenuAction(action) {
|
|
58
37
|
switch (action) {
|
|
59
38
|
case 'events':
|
|
60
39
|
await showCalendar();
|
|
61
40
|
break;
|
|
62
|
-
case 'repair':
|
|
63
|
-
await openRepairService();
|
|
64
|
-
break;
|
|
65
41
|
case 'docs':
|
|
66
42
|
await showDocsMenu();
|
|
67
43
|
break;
|
|
@@ -71,99 +47,8 @@ export async function runMenuAction(action) {
|
|
|
71
47
|
case 'links':
|
|
72
48
|
await showLinksMenu();
|
|
73
49
|
break;
|
|
74
|
-
case '
|
|
75
|
-
await
|
|
76
|
-
break;
|
|
77
|
-
case 'github':
|
|
78
|
-
await openGithub();
|
|
50
|
+
case 'settings':
|
|
51
|
+
await showSettingsMenu();
|
|
79
52
|
break;
|
|
80
|
-
case 'roadmap':
|
|
81
|
-
await openRoadmap();
|
|
82
|
-
break;
|
|
83
|
-
case 'about':
|
|
84
|
-
showAbout();
|
|
85
|
-
break;
|
|
86
|
-
case 'theme':
|
|
87
|
-
await showThemeMenu();
|
|
88
|
-
break;
|
|
89
|
-
case 'language':
|
|
90
|
-
await showLanguageMenu();
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Links submenu — website, GitHub, roadmap
|
|
96
|
-
*/
|
|
97
|
-
async function showLinksMenu() {
|
|
98
|
-
const trans = t();
|
|
99
|
-
const link = await select({
|
|
100
|
-
message: trans.menu.chooseLink,
|
|
101
|
-
options: [
|
|
102
|
-
{ value: 'website', label: trans.menu.website, hint: 'nbtca.space' },
|
|
103
|
-
{ value: 'github', label: 'GitHub', hint: 'github.com/nbtca' },
|
|
104
|
-
{ value: 'roadmap', label: trans.menu.roadmap, hint: trans.menu.roadmapDesc },
|
|
105
|
-
],
|
|
106
|
-
});
|
|
107
|
-
if (isCancel(link))
|
|
108
|
-
return;
|
|
109
|
-
switch (link) {
|
|
110
|
-
case 'website':
|
|
111
|
-
await openHomepage();
|
|
112
|
-
break;
|
|
113
|
-
case 'github':
|
|
114
|
-
await openGithub();
|
|
115
|
-
break;
|
|
116
|
-
case 'roadmap':
|
|
117
|
-
await openRoadmap();
|
|
118
|
-
break;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Display about information using clack note() box
|
|
123
|
-
*/
|
|
124
|
-
function showAbout() {
|
|
125
|
-
const trans = t();
|
|
126
|
-
const pad = 12;
|
|
127
|
-
const row = (label, value) => `${chalk.dim(padEndV(label, pad))}${value}`;
|
|
128
|
-
const link = (label, url) => row(label, chalk.cyan(url));
|
|
129
|
-
const content = [
|
|
130
|
-
row(trans.about.project, APP_INFO.name),
|
|
131
|
-
row(trans.about.version, `v${APP_INFO.version}`),
|
|
132
|
-
row(trans.about.description, APP_INFO.fullDescription),
|
|
133
|
-
'',
|
|
134
|
-
link(trans.about.github, APP_INFO.repository),
|
|
135
|
-
link(trans.about.website, URLS.homepage),
|
|
136
|
-
link(trans.about.email, URLS.email),
|
|
137
|
-
'',
|
|
138
|
-
row(trans.about.license, `MIT ${pickIcon('·', '|')} Author: m1ngsama`),
|
|
139
|
-
].join('\n');
|
|
140
|
-
note(content, trans.about.title);
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Display language selection menu
|
|
144
|
-
*/
|
|
145
|
-
async function showLanguageMenu() {
|
|
146
|
-
const trans = t();
|
|
147
|
-
const currentLang = getCurrentLanguage();
|
|
148
|
-
const language = await select({
|
|
149
|
-
message: trans.language.selectLanguage,
|
|
150
|
-
options: [
|
|
151
|
-
{ value: 'zh', label: trans.language.zh, hint: currentLang === 'zh' ? `${pickIcon('✓', '*')} current` : undefined },
|
|
152
|
-
{ value: 'en', label: trans.language.en, hint: currentLang === 'en' ? `${pickIcon('✓', '*')} current` : undefined },
|
|
153
|
-
],
|
|
154
|
-
initialValue: currentLang,
|
|
155
|
-
});
|
|
156
|
-
if (isCancel(language))
|
|
157
|
-
return;
|
|
158
|
-
if (language !== currentLang) {
|
|
159
|
-
const persisted = setLanguage(language);
|
|
160
|
-
clearTranslationCache();
|
|
161
|
-
if (persisted) {
|
|
162
|
-
success(t().language.changed);
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
warning(t().language.changedSessionOnly);
|
|
166
|
-
}
|
|
167
53
|
}
|
|
168
54
|
}
|
|
169
|
-
//# sourceMappingURL=menu.js.map
|
package/dist/core/text.js
CHANGED
|
@@ -13,10 +13,17 @@ function charWidth(ch) {
|
|
|
13
13
|
(cp >= 0xFFE0 && cp <= 0xFFE6) // Fullwidth Signs
|
|
14
14
|
) ? 2 : 1;
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
16
|
+
/** Strip ANSI escape sequences from a string. */
|
|
17
|
+
// eslint-disable-next-line no-control-regex
|
|
18
|
+
const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
19
|
+
export function stripAnsi(str) {
|
|
20
|
+
return str.replace(ANSI_RE, '');
|
|
21
|
+
}
|
|
22
|
+
/** Total visual width of a string (CJK characters count as 2, ANSI codes ignored). */
|
|
17
23
|
export function visualWidth(str) {
|
|
24
|
+
const plain = stripAnsi(str);
|
|
18
25
|
let w = 0;
|
|
19
|
-
for (const ch of
|
|
26
|
+
for (const ch of plain)
|
|
20
27
|
w += charWidth(ch);
|
|
21
28
|
return w;
|
|
22
29
|
}
|
|
@@ -40,4 +47,3 @@ export function truncate(str, maxWidth) {
|
|
|
40
47
|
}
|
|
41
48
|
return str.slice(0, i) + '...';
|
|
42
49
|
}
|
|
43
|
-
//# sourceMappingURL=text.js.map
|
package/dist/core/ui.js
CHANGED
package/dist/core/vim-keys.js
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
* before readline processes them. This avoids patching the keypress layer which
|
|
5
5
|
* breaks in Node.js v25+ (emitKeys generator crash).
|
|
6
6
|
*/
|
|
7
|
-
// Maps single-byte vim keys to terminal escape sequences
|
|
7
|
+
// Maps single-byte vim keys to terminal escape sequences (ranger-style hjkl)
|
|
8
8
|
const VIM_TO_SEQ = {
|
|
9
|
+
h: Buffer.from('\u0003'), // back/cancel (ranger: go to parent)
|
|
9
10
|
j: Buffer.from('\u001b[B'), // down arrow
|
|
10
11
|
k: Buffer.from('\u001b[A'), // up arrow
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
l: Buffer.from('\r'), // enter/confirm (ranger: open/enter)
|
|
13
|
+
g: Buffer.from('\u001b[H'), // home (first item)
|
|
14
|
+
G: Buffer.from('\u001b[F'), // end (last item)
|
|
15
|
+
q: Buffer.from('\u0003'), // quit
|
|
14
16
|
};
|
|
15
17
|
export function enableVimKeys() {
|
|
16
18
|
const stdin = process.stdin;
|
|
@@ -29,4 +31,3 @@ export function enableVimKeys() {
|
|
|
29
31
|
return originalEmit(event, ...args);
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
|
-
//# sourceMappingURL=vim-keys.js.map
|
|
@@ -5,16 +5,18 @@
|
|
|
5
5
|
import axios from 'axios';
|
|
6
6
|
import ICAL from 'ical.js';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
|
-
import {
|
|
8
|
+
import { select, isCancel } from '@clack/prompts';
|
|
9
|
+
import { info, createSpinner } from '../core/ui.js';
|
|
9
10
|
import { pickIcon } from '../core/icons.js';
|
|
10
11
|
import { padEndV, truncate } from '../core/text.js';
|
|
11
12
|
import { t } from '../i18n/index.js';
|
|
13
|
+
import { APP_INFO, URLS } from '../config/data.js';
|
|
12
14
|
export async function fetchEvents() {
|
|
13
15
|
try {
|
|
14
16
|
const response = await axios.get('https://ical.nbtca.space', {
|
|
15
17
|
timeout: 5000,
|
|
16
18
|
headers: {
|
|
17
|
-
'User-Agent':
|
|
19
|
+
'User-Agent': `NBTCA-CLI/${APP_INFO.version}`
|
|
18
20
|
}
|
|
19
21
|
});
|
|
20
22
|
const jcalData = ICAL.parse(response.data);
|
|
@@ -28,13 +30,14 @@ export async function fetchEvents() {
|
|
|
28
30
|
const startDate = event.startDate.toJSDate();
|
|
29
31
|
if (startDate >= now && startDate <= thirtyDaysLater) {
|
|
30
32
|
const trans = t();
|
|
31
|
-
const untitledEvent = trans.calendar.
|
|
32
|
-
const tbdLocation = trans.calendar.
|
|
33
|
+
const untitledEvent = trans.calendar.untitledEvent;
|
|
34
|
+
const tbdLocation = trans.calendar.tbdLocation;
|
|
33
35
|
events.push({
|
|
34
36
|
date: formatDate(startDate),
|
|
35
37
|
time: formatTime(startDate),
|
|
36
38
|
title: event.summary || untitledEvent,
|
|
37
39
|
location: event.location || tbdLocation,
|
|
40
|
+
description: event.description || '',
|
|
38
41
|
startDate
|
|
39
42
|
});
|
|
40
43
|
}
|
|
@@ -42,8 +45,9 @@ export async function fetchEvents() {
|
|
|
42
45
|
events.sort((a, b) => a.startDate.getTime() - b.startDate.getTime());
|
|
43
46
|
return events;
|
|
44
47
|
}
|
|
45
|
-
catch {
|
|
46
|
-
|
|
48
|
+
catch (err) {
|
|
49
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
50
|
+
throw new Error(`${t().calendar.error}: ${detail}`);
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
export function serializeEvents(events) {
|
|
@@ -52,6 +56,7 @@ export function serializeEvents(events) {
|
|
|
52
56
|
time: event.time,
|
|
53
57
|
title: event.title,
|
|
54
58
|
location: event.location,
|
|
59
|
+
description: event.description,
|
|
55
60
|
startDateISO: event.startDate.toISOString()
|
|
56
61
|
}));
|
|
57
62
|
}
|
|
@@ -108,14 +113,31 @@ export function renderEventsTable(events, options) {
|
|
|
108
113
|
lines.push(dim(bottom));
|
|
109
114
|
return lines.join('\n');
|
|
110
115
|
}
|
|
111
|
-
|
|
116
|
+
function displayEvents(events) {
|
|
112
117
|
if (events.length === 0) {
|
|
113
118
|
info(t().calendar.noEvents);
|
|
114
119
|
return;
|
|
115
120
|
}
|
|
116
121
|
console.log();
|
|
117
122
|
console.log(renderEventsTable(events, { color: true }));
|
|
118
|
-
|
|
123
|
+
console.log(chalk.dim(` ${pickIcon('📅', '[ical]')} ${t().calendar.subscribeHint}: ${URLS.calendar}`));
|
|
124
|
+
console.log();
|
|
125
|
+
}
|
|
126
|
+
async function showEventDetail(event) {
|
|
127
|
+
const trans = t();
|
|
128
|
+
console.log();
|
|
129
|
+
console.log(chalk.bold.cyan(` ${event.title}`));
|
|
130
|
+
console.log(chalk.dim(` ${event.date} ${event.time} ${pickIcon('·', '|')} ${event.location}`));
|
|
131
|
+
if (event.description) {
|
|
132
|
+
console.log();
|
|
133
|
+
const lines = event.description.trim().split('\n');
|
|
134
|
+
for (const line of lines) {
|
|
135
|
+
console.log(chalk.white(` ${line}`));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.log(chalk.dim(` ${trans.calendar.noDescription}`));
|
|
140
|
+
}
|
|
119
141
|
console.log();
|
|
120
142
|
}
|
|
121
143
|
export async function showCalendar() {
|
|
@@ -125,6 +147,26 @@ export async function showCalendar() {
|
|
|
125
147
|
const events = await fetchEvents();
|
|
126
148
|
s.stop(`${events.length} ${trans.calendar.eventsFound}`);
|
|
127
149
|
displayEvents(events);
|
|
150
|
+
if (events.length > 0) {
|
|
151
|
+
const options = [
|
|
152
|
+
...events.map((e, i) => ({
|
|
153
|
+
value: String(i),
|
|
154
|
+
label: `${e.date} ${e.time} ${e.title}`,
|
|
155
|
+
hint: e.location,
|
|
156
|
+
})),
|
|
157
|
+
{ value: '__back__', label: chalk.dim(trans.common.back) },
|
|
158
|
+
];
|
|
159
|
+
const selected = await select({
|
|
160
|
+
message: trans.calendar.viewDetail,
|
|
161
|
+
options,
|
|
162
|
+
});
|
|
163
|
+
if (!isCancel(selected) && selected !== '__back__') {
|
|
164
|
+
const idx = Number.parseInt(selected, 10);
|
|
165
|
+
const event = events[idx];
|
|
166
|
+
if (event)
|
|
167
|
+
await showEventDetail(event);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
128
170
|
}
|
|
129
171
|
catch {
|
|
130
172
|
s.error(trans.calendar.error);
|
|
@@ -132,4 +174,3 @@ export async function showCalendar() {
|
|
|
132
174
|
console.log();
|
|
133
175
|
}
|
|
134
176
|
}
|
|
135
|
-
//# sourceMappingURL=calendar.js.map
|