@nbtca/prompt 1.5.3 → 1.5.5
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/app/app.js +1 -1
- package/dist/app/chrome.js +25 -3
- package/dist/app/views/docs.js +32 -0
- package/dist/app/views/schedule-render.js +1 -26
- package/dist/app/views/schedule.js +3 -10
- package/package.json +1 -1
package/dist/app/app.js
CHANGED
|
@@ -76,7 +76,7 @@ export async function runApp() {
|
|
|
76
76
|
const active = nativeViews[view];
|
|
77
77
|
const tabs = getAppTabs();
|
|
78
78
|
const chrome = resolveChromeLayout(rows);
|
|
79
|
-
const header = renderHeader(tabs, view, cols, chrome.headerLines);
|
|
79
|
+
const header = renderHeader(tabs, view, cols, chrome.headerLines, active?.contextPath?.());
|
|
80
80
|
const body = active?.render(ctx) ?? [];
|
|
81
81
|
const bodyScroll = active?.capturesInput?.() ? Number.MAX_SAFE_INTEGER : scroll;
|
|
82
82
|
const height = computeBodyRows(rows, chrome.headerLines, chrome.footerLines);
|
package/dist/app/chrome.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type, space, glyph, brandMark } from '../core/theme.js';
|
|
2
2
|
import { pickIcon } from '../core/icons.js';
|
|
3
3
|
import { t } from '../i18n/index.js';
|
|
4
|
-
import { visualWidth } from '../core/text.js';
|
|
4
|
+
import { clipAnsiToVisualWidth, visualWidth } from '../core/text.js';
|
|
5
5
|
export const HEADER_LINES = 3;
|
|
6
6
|
export const FOOTER_LINES = 2;
|
|
7
7
|
export function resolveChromeLayout(rows) {
|
|
@@ -58,11 +58,33 @@ function renderTabs(views, active, cols) {
|
|
|
58
58
|
return activeNumber;
|
|
59
59
|
return type.active(String(activeIndex + 1));
|
|
60
60
|
}
|
|
61
|
-
export function
|
|
61
|
+
export function renderContextPath(segments, cols) {
|
|
62
|
+
const chevron = pickIcon('›', '>');
|
|
63
|
+
const ellipsis = pickIcon('…', '...');
|
|
64
|
+
const width = Number.isFinite(cols) ? Math.max(1, Math.floor(cols)) : Number.POSITIVE_INFINITY;
|
|
65
|
+
for (let start = 0; start < segments.length; start += 1) {
|
|
66
|
+
const shown = segments.slice(start);
|
|
67
|
+
const last = shown.length - 1;
|
|
68
|
+
const plain = [...(start > 0 ? [ellipsis] : []), ...shown].join(` ${chevron} `);
|
|
69
|
+
if (visualWidth(space.indent + plain) > width)
|
|
70
|
+
continue;
|
|
71
|
+
const styled = shown
|
|
72
|
+
.map((segment, index) => (index === last ? type.label(segment) : type.hint(segment)))
|
|
73
|
+
.join(type.hint(` ${chevron} `));
|
|
74
|
+
return space.indent + (start > 0 ? type.hint(`${ellipsis} ${chevron} `) : '') + styled;
|
|
75
|
+
}
|
|
76
|
+
const leaf = segments[segments.length - 1] ?? '';
|
|
77
|
+
const indent = visualWidth(space.indent) < width ? space.indent : '';
|
|
78
|
+
const room = Math.max(1, width - visualWidth(indent));
|
|
79
|
+
return indent + type.label(clipAnsiToVisualWidth(leaf, room));
|
|
80
|
+
}
|
|
81
|
+
export function renderHeader(views, active, cols, lineCount = HEADER_LINES, contextPath) {
|
|
62
82
|
if (lineCount === 0)
|
|
63
83
|
return [];
|
|
64
84
|
const mark = brandMark('nbtca');
|
|
65
|
-
const brand =
|
|
85
|
+
const brand = contextPath && contextPath.length > 0
|
|
86
|
+
? renderContextPath(contextPath, cols)
|
|
87
|
+
: `${visualWidth(space.indent + mark) <= cols ? space.indent : ''}${mark}`;
|
|
66
88
|
const tabs = renderTabs(views, active, cols);
|
|
67
89
|
const rule = renderRule(cols);
|
|
68
90
|
if (lineCount === 1)
|
package/dist/app/views/docs.js
CHANGED
|
@@ -29,6 +29,9 @@ const DOC_HINT_WIDTH = 44;
|
|
|
29
29
|
function isLifecycleActive(ctx, generation) {
|
|
30
30
|
return generation === lifecycleGeneration && ctx.signal?.aborted !== true;
|
|
31
31
|
}
|
|
32
|
+
function dedupeAdjacent(segments) {
|
|
33
|
+
return segments.filter((segment, index) => segment !== segments[index - 1]);
|
|
34
|
+
}
|
|
32
35
|
function backLabel() {
|
|
33
36
|
return t().common.back;
|
|
34
37
|
}
|
|
@@ -419,6 +422,35 @@ export const docsView = {
|
|
|
419
422
|
capturesInput() {
|
|
420
423
|
return state.mode === 'search';
|
|
421
424
|
},
|
|
425
|
+
contextPath() {
|
|
426
|
+
const trans = t();
|
|
427
|
+
const section = sections.find((candidate) => candidate.key === currentSectionKey);
|
|
428
|
+
const branch = currentArchivedGroupKey !== null
|
|
429
|
+
? [trans.docs.categoryArchived, currentArchivedGroupKey]
|
|
430
|
+
: section
|
|
431
|
+
? [section.label]
|
|
432
|
+
: [];
|
|
433
|
+
switch (state.mode) {
|
|
434
|
+
case 'reader':
|
|
435
|
+
case 'readerLoading':
|
|
436
|
+
return dedupeAdjacent([
|
|
437
|
+
trans.menu.docs,
|
|
438
|
+
...branch,
|
|
439
|
+
...(state.readerTitle ? [state.readerTitle] : []),
|
|
440
|
+
]);
|
|
441
|
+
case 'files':
|
|
442
|
+
case 'archivedFiles':
|
|
443
|
+
case 'archivedGroups':
|
|
444
|
+
return [trans.menu.docs, ...branch];
|
|
445
|
+
case 'sections':
|
|
446
|
+
case 'search':
|
|
447
|
+
case 'searchLoading':
|
|
448
|
+
case 'searchResults':
|
|
449
|
+
case 'loading':
|
|
450
|
+
case 'error':
|
|
451
|
+
return undefined;
|
|
452
|
+
}
|
|
453
|
+
},
|
|
422
454
|
scrollsBody() {
|
|
423
455
|
return state.mode === 'reader' && state.readerLinksField === undefined;
|
|
424
456
|
},
|
|
@@ -4,7 +4,6 @@ import { pickIcon } from '../../core/icons.js';
|
|
|
4
4
|
import { t, fmt } from '../../i18n/index.js';
|
|
5
5
|
import { renderListFieldWithContext } from '../fields/list-field.js';
|
|
6
6
|
import { renderNextClassBanner, renderWeekGrid, renderUnresolvedItems, renderTodayTimeline, weekdayShortLabel, renderTermDensity, renderMeetingDetail, renderDayTimeline, renderDaySwitcher, } from '../../features/schedule-render.js';
|
|
7
|
-
import { renderEventBrief } from '../../features/calendar.js';
|
|
8
7
|
import { sanitizeTerminalLine, visualWidth, wrapAnsiWithIndent } from '../../core/text.js';
|
|
9
8
|
import { localDayDifference, parseLocalDate, parseLocalMonday } from '../../core/calendar-day.js';
|
|
10
9
|
import { loadingLines } from '../../core/components/spinner.js';
|
|
@@ -23,10 +22,6 @@ function headingLines(label, cols) {
|
|
|
23
22
|
function hintLines(label, cols) {
|
|
24
23
|
return wrappedIndentedLines(label, cols, type.hint);
|
|
25
24
|
}
|
|
26
|
-
function wrappedRenderedLine(line, cols) {
|
|
27
|
-
const content = line.startsWith(space.indent) ? line.slice(space.indent.length) : line;
|
|
28
|
-
return wrappedIndentedLines(content, cols, (value) => value);
|
|
29
|
-
}
|
|
30
25
|
export function hubShortcuts(tt) {
|
|
31
26
|
const trans = t();
|
|
32
27
|
const shortcuts = [
|
|
@@ -212,27 +207,7 @@ function renderPublicBody(state, now, bodyRows, cols) {
|
|
|
212
207
|
}
|
|
213
208
|
}
|
|
214
209
|
lines.push('');
|
|
215
|
-
|
|
216
|
-
const rows = Number.isFinite(bodyRows)
|
|
217
|
-
? Math.max(0, Math.floor(bodyRows))
|
|
218
|
-
: Number.POSITIVE_INFINITY;
|
|
219
|
-
const fieldRows = state.publicField
|
|
220
|
-
? Math.min(3, rows, state.publicField.render(Number.POSITIVE_INFINITY, cols).length)
|
|
221
|
-
: 0;
|
|
222
|
-
if (state.publicUpcoming && state.publicUpcoming.length > 0) {
|
|
223
|
-
const activityHeading = headingLines(trans.calendar.recentActivity, cols);
|
|
224
|
-
const eventBudget = Math.max(0, rows - lines.length - activityHeading.length - 1 - loginLines.length - fieldRows);
|
|
225
|
-
const eventLines = [];
|
|
226
|
-
for (const event of state.publicUpcoming) {
|
|
227
|
-
const wrapped = wrappedRenderedLine(renderEventBrief(event, now), cols);
|
|
228
|
-
if (eventLines.length + wrapped.length > eventBudget)
|
|
229
|
-
break;
|
|
230
|
-
eventLines.push(...wrapped);
|
|
231
|
-
}
|
|
232
|
-
if (eventLines.length > 0)
|
|
233
|
-
lines.push(...activityHeading, ...eventLines, '');
|
|
234
|
-
}
|
|
235
|
-
lines.push(...loginLines);
|
|
210
|
+
lines.push(...hintLines(trans.timetable.publicLoginHint, cols), '');
|
|
236
211
|
return state.publicField
|
|
237
212
|
? renderListFieldWithContext(lines, state.publicField, bodyRows, cols)
|
|
238
213
|
: lines;
|
|
@@ -12,8 +12,8 @@ import { loginWithStudentPassword, restoreNbtSession, } from '../../auth/nbt-aut
|
|
|
12
12
|
import { createSessionStore } from '../../auth/session-store.js';
|
|
13
13
|
import { resolveTerm, relevantTerms, writePrivateIcs, isSessionExpired, JWXT_ORIGIN, safeMessage, } from '../../features/student-timetable.js';
|
|
14
14
|
import { termKey, loadWeekOne, saveWeekOne, saveTimetableCache, saveCurrentPointer, loadCurrentPointer, loadTimetableCache, clearScheduleCache, } from '../../features/schedule-store.js';
|
|
15
|
-
import { loadCalendarOrThrow
|
|
16
|
-
import { currentAcademicWindow, inferWeekOneMonday,
|
|
15
|
+
import { loadCalendarOrThrow } from '../../features/calendar.js';
|
|
16
|
+
import { currentAcademicWindow, inferWeekOneMonday, } from '@nbtca/nbtcal';
|
|
17
17
|
import { sanitizeAcademicTerm, sanitizeTimetable } from '../../features/timetable-sanitize.js';
|
|
18
18
|
import { addLocalDays, parseLocalMonday } from '../../core/calendar-day.js';
|
|
19
19
|
let state = { mode: 'loading' };
|
|
@@ -96,10 +96,8 @@ function buildPublicField() {
|
|
|
96
96
|
return new ListField({
|
|
97
97
|
title: trans.timetable.menuEntry,
|
|
98
98
|
options: [{ value: 'login', label: trans.timetable.publicLoginAction }],
|
|
99
|
-
footer: trans.menu.hintMove,
|
|
100
99
|
});
|
|
101
100
|
}
|
|
102
|
-
const PUBLIC_UPCOMING_FETCH_CAP = 15;
|
|
103
101
|
async function goToPublic(ctx, generation = lifecycleGeneration) {
|
|
104
102
|
if (!isLifecycleActive(ctx, generation))
|
|
105
103
|
return;
|
|
@@ -113,12 +111,7 @@ async function goToPublic(ctx, generation = lifecycleGeneration) {
|
|
|
113
111
|
const now = new Date();
|
|
114
112
|
const windowEvents = cal.inRange(addLocalDays(now, -400), addLocalDays(now, 400));
|
|
115
113
|
const publicWindow = currentAcademicWindow(windowEvents, now);
|
|
116
|
-
|
|
117
|
-
.upcoming({ days: 30 })
|
|
118
|
-
.filter((e) => !isAcademicBreakEvent(e))
|
|
119
|
-
.slice(0, PUBLIC_UPCOMING_FETCH_CAP)
|
|
120
|
-
.map(toDisplayEvent);
|
|
121
|
-
state = { ...state, publicWindow, publicUpcoming };
|
|
114
|
+
state = { ...state, publicWindow };
|
|
122
115
|
}
|
|
123
116
|
catch {
|
|
124
117
|
if (!isLifecycleActive(ctx, generation))
|