@nbtca/prompt 1.4.1 → 1.5.0
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/LICENSE +1 -1
- package/README.md +27 -58
- package/SECURITY.md +16 -45
- package/dist/app/app.js +53 -55
- package/dist/app/chrome.js +67 -50
- package/dist/app/fields/list-field.js +12 -25
- package/dist/app/fields/text-field.js +3 -8
- package/dist/app/frame.js +2 -21
- package/dist/app/keys.js +10 -2
- package/dist/app/views/docs-render.js +31 -24
- package/dist/app/views/docs.js +211 -67
- package/dist/app/views/events-render.js +19 -26
- package/dist/app/views/events.js +44 -31
- package/dist/app/views/home.js +33 -76
- package/dist/app/views/schedule-grid-cursor.js +9 -18
- package/dist/app/views/schedule-render.js +47 -71
- package/dist/app/views/schedule.js +158 -90
- package/dist/app/views/settings-render.js +8 -19
- package/dist/app/views/settings.js +93 -18
- package/dist/auth/cookie-transport.js +31 -32
- package/dist/auth/errors.js +3 -1
- package/dist/auth/nbt-auth.js +42 -25
- package/dist/auth/session-store.js +17 -9
- package/dist/config/data.js +10 -13
- package/dist/config/preferences.js +14 -7
- package/dist/core/calendar-day.js +37 -0
- package/dist/core/capabilities.js +6 -3
- package/dist/core/components/confirm.js +9 -8
- package/dist/core/components/menu.js +41 -16
- package/dist/core/components/messages.js +12 -4
- package/dist/core/components/painter.js +3 -1
- package/dist/core/components/spinner.js +17 -6
- package/dist/core/components/text-input.js +24 -18
- package/dist/core/icons.js +2 -2
- package/dist/core/logo.js +25 -21
- package/dist/core/motion.js +25 -19
- package/dist/core/text.js +182 -75
- package/dist/core/theme.js +0 -28
- package/dist/core/transitions.js +2 -2
- package/dist/core/ui.js +15 -30
- package/dist/core/vim-keys.js +9 -15
- package/dist/features/about.js +23 -0
- package/dist/features/calendar-heatmap.js +16 -40
- package/dist/features/calendar-query.js +1 -2
- package/dist/features/calendar.js +12 -185
- package/dist/features/docs.js +439 -320
- package/dist/features/schedule-render.js +65 -102
- package/dist/features/schedule-store.js +51 -9
- package/dist/features/schedule-view.js +46 -220
- package/dist/features/status.js +44 -59
- package/dist/features/student-timetable.js +73 -95
- package/dist/features/theme.js +6 -5
- package/dist/features/timetable-sanitize.js +40 -0
- package/dist/features/update.js +9 -37
- package/dist/i18n/index.js +87 -65
- package/dist/i18n/locales/en.json +1 -1
- package/dist/i18n/locales/zh.json +1 -1
- package/dist/index.js +85 -64
- package/dist/logo/ca-dotmatrix.txt +16 -18
- package/dist/main.js +7 -48
- package/package.json +30 -18
- package/bin/nbtca-welcome.js +0 -2
- package/dist/core/components/screen.js +0 -18
- package/dist/core/menu.js +0 -71
- package/dist/features/links.js +0 -39
- package/dist/features/schedule-query.js +0 -47
- package/dist/features/settings.js +0 -130
- package/dist/logo/ca-logo.png +0 -0
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
const DAY_MS = 86400000;
|
|
2
|
-
export function currentWeekNumber(weekOneMonday, now) {
|
|
3
|
-
const base = new Date(`${weekOneMonday}T00:00:00`);
|
|
4
|
-
const days = Math.floor((now.getTime() - base.getTime()) / DAY_MS);
|
|
5
|
-
return Math.floor(days / 7) + 1;
|
|
6
|
-
}
|
|
7
|
-
export function campusWeekday(now) {
|
|
8
|
-
return ((now.getDay() + 6) % 7) + 1;
|
|
9
|
-
}
|
|
10
|
-
export function meetingsInWeek(meetings, week) {
|
|
11
|
-
return meetings.filter((mtg) => mtg.weeks.includes(week));
|
|
12
|
-
}
|
|
13
|
-
export function meetingsOnDay(meetings, weekday, week) {
|
|
14
|
-
return meetings
|
|
15
|
-
.filter((mtg) => mtg.weekday === weekday && mtg.weeks.includes(week))
|
|
16
|
-
.sort((a, b) => a.startPeriod - b.startPeriod);
|
|
17
|
-
}
|
|
18
|
-
export function periodStartDate(weekOneMonday, week, weekday, period, periods) {
|
|
19
|
-
const p = periods.find((x) => x.period === period);
|
|
20
|
-
if (!p)
|
|
21
|
-
return null;
|
|
22
|
-
const base = new Date(`${weekOneMonday}T00:00:00`);
|
|
23
|
-
const date = new Date(base.getTime() + ((week - 1) * 7 + (weekday - 1)) * DAY_MS);
|
|
24
|
-
const parts = p.start.split(':');
|
|
25
|
-
date.setHours(Number.parseInt(parts[0] ?? '0', 10), Number.parseInt(parts[1] ?? '0', 10), 0, 0);
|
|
26
|
-
return date;
|
|
27
|
-
}
|
|
28
|
-
export function nextMeeting(meetings, periods, weekOneMonday, now) {
|
|
29
|
-
let best = null;
|
|
30
|
-
for (const meeting of meetings) {
|
|
31
|
-
for (const week of meeting.weeks) {
|
|
32
|
-
const start = periodStartDate(weekOneMonday, week, meeting.weekday, meeting.startPeriod, periods);
|
|
33
|
-
if (start && start.getTime() > now.getTime() && (!best || start.getTime() < best.start.getTime())) {
|
|
34
|
-
best = { meeting, start };
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return best;
|
|
39
|
-
}
|
|
40
|
-
/** The meeting occupying a grid cell, whether it starts there or is a later
|
|
41
|
-
* period of a meeting that started earlier the same day -- one condition
|
|
42
|
-
* (`startPeriod <= period <= endPeriod`) covers both cases, matching
|
|
43
|
-
* renderWeekGrid's own starting/continuing lookup so "does this cell have a
|
|
44
|
-
* meeting" and "what does the grid actually draw there" never disagree. */
|
|
45
|
-
export function meetingAtCursor(meetings, week, cursor) {
|
|
46
|
-
return meetingsInWeek(meetings, week).find((m) => m.weekday === cursor.weekday && m.startPeriod <= cursor.period && cursor.period <= m.endPeriod) ?? null;
|
|
47
|
-
}
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unified settings — language, theme, about
|
|
3
|
-
*/
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
import { applyColorModePreference, loadPreferences, resetPreferences, setColorMode, setIconMode, } from '../config/preferences.js';
|
|
6
|
-
import { pickIcon } from '../core/icons.js';
|
|
7
|
-
import { resetIconCache } from '../core/icons.js';
|
|
8
|
-
import { padEndV } from '../core/text.js';
|
|
9
|
-
import { success, warning } from '../core/ui.js';
|
|
10
|
-
import { APP_INFO, URLS } from '../config/data.js';
|
|
11
|
-
import { t, getCurrentLanguage, setLanguage, clearTranslationCache } from '../i18n/index.js';
|
|
12
|
-
import { runMenu, menuFooter } from '../core/components/menu.js';
|
|
13
|
-
import { note } from '../core/components/note.js';
|
|
14
|
-
import { enterScreen, breadcrumb } from '../core/transitions.js';
|
|
15
|
-
function notifyResult(saved, successMsg, warningMsg) {
|
|
16
|
-
if (saved) {
|
|
17
|
-
success(successMsg);
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
warning(warningMsg);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
function showAbout() {
|
|
24
|
-
const trans = t();
|
|
25
|
-
const pad = 12;
|
|
26
|
-
const row = (label, value) => `${chalk.dim(padEndV(label, pad))}${value}`;
|
|
27
|
-
const link = (label, url) => row(label, chalk.cyan(url));
|
|
28
|
-
const content = [
|
|
29
|
-
row(trans.about.project, APP_INFO.name),
|
|
30
|
-
row(trans.about.version, `v${APP_INFO.version}`),
|
|
31
|
-
row(trans.about.description, trans.about.descriptionText),
|
|
32
|
-
'',
|
|
33
|
-
link(trans.about.github, APP_INFO.repository),
|
|
34
|
-
link(trans.about.website, URLS.homepage),
|
|
35
|
-
link(trans.about.email, URLS.email),
|
|
36
|
-
'',
|
|
37
|
-
row(trans.about.license, `MIT ${pickIcon('·', '|')} ${trans.about.author}: m1ngsama`),
|
|
38
|
-
].join('\n');
|
|
39
|
-
note(content, trans.about.title);
|
|
40
|
-
}
|
|
41
|
-
export async function showSettingsMenu() {
|
|
42
|
-
await enterScreen(breadcrumb(t().menu.settings));
|
|
43
|
-
while (true) {
|
|
44
|
-
const trans = t();
|
|
45
|
-
const prefs = loadPreferences();
|
|
46
|
-
const currentLang = getCurrentLanguage();
|
|
47
|
-
const footer = menuFooter();
|
|
48
|
-
const action = await runMenu({
|
|
49
|
-
title: trans.theme.chooseAction,
|
|
50
|
-
options: [
|
|
51
|
-
{ value: 'language', label: trans.language.selectLanguage, hint: currentLang === 'zh' ? trans.language.zh : trans.language.en },
|
|
52
|
-
{ value: 'icon', label: trans.theme.iconMode, hint: prefs.iconMode },
|
|
53
|
-
{ value: 'color', label: trans.theme.colorMode, hint: prefs.colorMode },
|
|
54
|
-
{ value: 'reset', label: trans.theme.resetLabel },
|
|
55
|
-
{ value: 'about', label: trans.about.title },
|
|
56
|
-
],
|
|
57
|
-
footer,
|
|
58
|
-
});
|
|
59
|
-
if (action === null)
|
|
60
|
-
return;
|
|
61
|
-
if (action === 'about') {
|
|
62
|
-
showAbout();
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (action === 'language') {
|
|
66
|
-
const langOptions = [
|
|
67
|
-
{ value: 'zh', label: trans.language.zh, hint: currentLang === 'zh' ? trans.common.current : undefined },
|
|
68
|
-
{ value: 'en', label: trans.language.en, hint: currentLang === 'en' ? trans.common.current : undefined },
|
|
69
|
-
];
|
|
70
|
-
const language = await runMenu({
|
|
71
|
-
title: trans.language.selectLanguage,
|
|
72
|
-
options: langOptions,
|
|
73
|
-
footer,
|
|
74
|
-
initialIndex: Math.max(0, langOptions.findIndex(o => o.value === currentLang)),
|
|
75
|
-
});
|
|
76
|
-
if (language === null)
|
|
77
|
-
continue;
|
|
78
|
-
if (language !== currentLang) {
|
|
79
|
-
const saved = setLanguage(language);
|
|
80
|
-
clearTranslationCache();
|
|
81
|
-
notifyResult(saved, t().language.changed, t().language.changedSessionOnly);
|
|
82
|
-
}
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
if (action === 'icon') {
|
|
86
|
-
const iconOptions = [
|
|
87
|
-
{ value: 'auto', label: trans.theme.modeAuto, hint: prefs.iconMode === 'auto' ? trans.common.current : undefined },
|
|
88
|
-
{ value: 'ascii', label: trans.theme.modeAscii, hint: prefs.iconMode === 'ascii' ? trans.common.current : undefined },
|
|
89
|
-
{ value: 'unicode', label: trans.theme.modeUnicode, hint: prefs.iconMode === 'unicode' ? trans.common.current : undefined },
|
|
90
|
-
];
|
|
91
|
-
const mode = await runMenu({
|
|
92
|
-
title: trans.theme.chooseIconMode,
|
|
93
|
-
options: iconOptions,
|
|
94
|
-
footer,
|
|
95
|
-
initialIndex: Math.max(0, iconOptions.findIndex(o => o.value === prefs.iconMode)),
|
|
96
|
-
});
|
|
97
|
-
if (mode === null)
|
|
98
|
-
continue;
|
|
99
|
-
const saved = setIconMode(mode);
|
|
100
|
-
resetIconCache();
|
|
101
|
-
notifyResult(saved, trans.theme.updated, trans.theme.updatedSessionOnly);
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
if (action === 'color') {
|
|
105
|
-
const colorOptions = [
|
|
106
|
-
{ value: 'auto', label: trans.theme.modeAuto, hint: prefs.colorMode === 'auto' ? trans.common.current : undefined },
|
|
107
|
-
{ value: 'on', label: trans.theme.modeOn, hint: prefs.colorMode === 'on' ? trans.common.current : undefined },
|
|
108
|
-
{ value: 'off', label: trans.theme.modeOff, hint: prefs.colorMode === 'off' ? trans.common.current : undefined },
|
|
109
|
-
];
|
|
110
|
-
const mode = await runMenu({
|
|
111
|
-
title: trans.theme.chooseColorMode,
|
|
112
|
-
options: colorOptions,
|
|
113
|
-
footer,
|
|
114
|
-
initialIndex: Math.max(0, colorOptions.findIndex(o => o.value === prefs.colorMode)),
|
|
115
|
-
});
|
|
116
|
-
if (mode === null)
|
|
117
|
-
continue;
|
|
118
|
-
const saved = setColorMode(mode);
|
|
119
|
-
applyColorModePreference(false);
|
|
120
|
-
notifyResult(saved, trans.theme.updated, trans.theme.updatedSessionOnly);
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
if (action === 'reset') {
|
|
124
|
-
const saved = resetPreferences();
|
|
125
|
-
resetIconCache();
|
|
126
|
-
applyColorModePreference(false);
|
|
127
|
-
notifyResult(saved, trans.theme.reset, trans.theme.resetSessionOnly);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
package/dist/logo/ca-logo.png
DELETED
|
Binary file
|