@flyingrobots/bijou-tui 4.4.0 → 4.4.1
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/README.md +52 -622
- package/dist/app-frame-actions.d.ts.map +1 -1
- package/dist/app-frame-actions.js +4 -1
- package/dist/app-frame-actions.js.map +1 -1
- package/dist/app-frame-i18n.d.ts.map +1 -1
- package/dist/app-frame-i18n.js +4 -0
- package/dist/app-frame-i18n.js.map +1 -1
- package/dist/app-frame-render.d.ts +8 -8
- package/dist/app-frame-render.d.ts.map +1 -1
- package/dist/app-frame-render.js +82 -23
- package/dist/app-frame-render.js.map +1 -1
- package/dist/app-frame-types.d.ts +3 -0
- package/dist/app-frame-types.d.ts.map +1 -1
- package/dist/app-frame-types.js.map +1 -1
- package/dist/app-frame.d.ts +27 -1
- package/dist/app-frame.d.ts.map +1 -1
- package/dist/app-frame.js +234 -62
- package/dist/app-frame.js.map +1 -1
- package/dist/command-palette.d.ts +5 -3
- package/dist/command-palette.d.ts.map +1 -1
- package/dist/command-palette.js +5 -3
- package/dist/command-palette.js.map +1 -1
- package/dist/focus-area.d.ts.map +1 -1
- package/dist/focus-area.js +18 -30
- package/dist/focus-area.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +13 -8
- package/dist/overlay.js.map +1 -1
- package/dist/shell-quit.d.ts +1 -1
- package/dist/shell-quit.d.ts.map +1 -1
- package/dist/shell-quit.js +14 -3
- package/dist/shell-quit.js.map +1 -1
- package/package.json +3 -3
package/dist/app-frame.js
CHANGED
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
* Provides tabs, pane focus/scroll isolation, shell key handling, help,
|
|
5
5
|
* panel-scoped overlay context, and optional frame-level command palette.
|
|
6
6
|
*/
|
|
7
|
-
import { createSurface, preparePreferenceSections, preferenceListSurface, resolvePreferenceRowLayout, resolveClock, resolveSafeCtx, } from '@flyingrobots/bijou';
|
|
7
|
+
import { cloneContextWithResolvedTheme, createResolved, createSurface, setDefaultContext, preparePreferenceSections, preferenceListSurface, resolvePreferenceRowLayout, resolveClock, resolveSafeCtx, } from '@flyingrobots/bijou';
|
|
8
8
|
import { helpViewSurface } from './help.js';
|
|
9
9
|
import { createKeyMap } from './keybindings.js';
|
|
10
10
|
import { isKeyMsg, isMouseMsg, isResizeMsg } from './types.js';
|
|
11
11
|
import { quit } from './commands.js';
|
|
12
12
|
import { compositeSurfaceInto, drawer, modal } from './overlay.js';
|
|
13
13
|
import { isShellQuitConfirmAccept, isShellQuitConfirmDismiss, isShellQuitRequest, renderShellQuitOverlay, shouldUseShellQuitConfirm, } from './shell-quit.js';
|
|
14
|
-
import {
|
|
14
|
+
import { commandPaletteSurface, commandPaletteKeyMap, } from './command-palette.js';
|
|
15
15
|
import { createPagerStateForSurface, pagerSurface, } from './pager.js';
|
|
16
16
|
import { restoreLayoutState } from './layout-preset.js';
|
|
17
17
|
import { countNotificationHistory, createNotificationState, dismissNotification, hitTestNotificationStack, notificationsNeedTick, pushNotification, renderNotificationHistorySurface, renderNotificationReviewEntrySurface, renderNotificationStack, tickNotifications, trimNotificationsToViewport, } from './notification.js';
|
|
@@ -134,6 +134,81 @@ function createFrameNotificationTickCmd() {
|
|
|
134
134
|
});
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
|
+
function cloneShellThemeContext(ctx, resolvedTheme) {
|
|
138
|
+
return cloneContextWithResolvedTheme(ctx, resolvedTheme);
|
|
139
|
+
}
|
|
140
|
+
function resolveShellThemeOptionsText(shellThemes, i18n) {
|
|
141
|
+
const labels = shellThemes.map((theme) => theme.label);
|
|
142
|
+
if (labels.length === 0)
|
|
143
|
+
return '';
|
|
144
|
+
if (i18n == null)
|
|
145
|
+
return labels.join(', ');
|
|
146
|
+
return i18n.formatList(labels, i18n.locale);
|
|
147
|
+
}
|
|
148
|
+
function resolveCurrentShellTheme(shellThemes, activeShellThemeId) {
|
|
149
|
+
return shellThemes.find((theme) => theme.id === activeShellThemeId) ?? shellThemes[0];
|
|
150
|
+
}
|
|
151
|
+
function resolveNextShellTheme(shellThemes, activeShellThemeId) {
|
|
152
|
+
if (shellThemes.length === 0)
|
|
153
|
+
return undefined;
|
|
154
|
+
const currentIndex = Math.max(0, shellThemes.findIndex((theme) => theme.id === activeShellThemeId));
|
|
155
|
+
return shellThemes[(currentIndex + 1) % shellThemes.length];
|
|
156
|
+
}
|
|
157
|
+
function resolveShellThemeForContext(shellThemes, ctx) {
|
|
158
|
+
if (ctx == null)
|
|
159
|
+
return undefined;
|
|
160
|
+
return shellThemes.find((theme) => theme.resolvedTheme.theme === ctx.theme.theme);
|
|
161
|
+
}
|
|
162
|
+
function mergeShellThemeSettings(settings, shellThemes, activeShellThemeId, i18n) {
|
|
163
|
+
if (shellThemes.length < 2)
|
|
164
|
+
return settings;
|
|
165
|
+
const currentTheme = resolveCurrentShellTheme(shellThemes, activeShellThemeId);
|
|
166
|
+
const nextTheme = resolveNextShellTheme(shellThemes, activeShellThemeId);
|
|
167
|
+
if (currentTheme == null || nextTheme == null)
|
|
168
|
+
return settings;
|
|
169
|
+
const row = {
|
|
170
|
+
id: FRAME_SHELL_THEME_ROW_ID,
|
|
171
|
+
label: frameMessage(i18n, 'settings.shellTheme.label', 'Shell theme'),
|
|
172
|
+
description: currentTheme.description ?? frameMessage(i18n, 'settings.shellTheme.description', 'Current theme: {theme}. Options: {options}.', {
|
|
173
|
+
theme: currentTheme.label,
|
|
174
|
+
options: resolveShellThemeOptionsText(shellThemes, i18n),
|
|
175
|
+
}),
|
|
176
|
+
valueLabel: currentTheme.label,
|
|
177
|
+
kind: 'choice',
|
|
178
|
+
feedback: {
|
|
179
|
+
title: frameMessage(i18n, 'settings.title', 'Settings'),
|
|
180
|
+
message: frameMessage(i18n, 'settings.shellTheme.feedback', 'Shell theme set to {theme}.', { theme: nextTheme.label }),
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
const shellSectionTitle = frameMessage(i18n, 'settings.section.shell', 'Shell');
|
|
184
|
+
if (settings == null) {
|
|
185
|
+
return {
|
|
186
|
+
title: frameMessage(i18n, 'settings.title', 'Settings'),
|
|
187
|
+
sections: [{ id: 'shell', title: shellSectionTitle, rows: [row] }],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
const shellSectionIndex = settings.sections.findIndex((section) => section.id === 'shell');
|
|
191
|
+
if (shellSectionIndex >= 0) {
|
|
192
|
+
const shellSection = settings.sections[shellSectionIndex];
|
|
193
|
+
const existingRowIndex = shellSection.rows.findIndex((existingRow) => existingRow.id === FRAME_SHELL_THEME_ROW_ID);
|
|
194
|
+
const nextRows = existingRowIndex >= 0
|
|
195
|
+
? shellSection.rows.map((existingRow, index) => (index === existingRowIndex ? row : existingRow))
|
|
196
|
+
: [...shellSection.rows, row];
|
|
197
|
+
return {
|
|
198
|
+
...settings,
|
|
199
|
+
sections: settings.sections.map((section, index) => (index === shellSectionIndex
|
|
200
|
+
? { ...shellSection, rows: nextRows }
|
|
201
|
+
: section)),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
...settings,
|
|
206
|
+
sections: [
|
|
207
|
+
{ id: 'shell', title: shellSectionTitle, rows: [row] },
|
|
208
|
+
...settings.sections,
|
|
209
|
+
],
|
|
210
|
+
};
|
|
211
|
+
}
|
|
137
212
|
// Factory
|
|
138
213
|
// ---------------------------------------------------------------------------
|
|
139
214
|
/**
|
|
@@ -155,8 +230,57 @@ export function createFramedApp(options) {
|
|
|
155
230
|
if (!pagesById.has(defaultPageId)) {
|
|
156
231
|
throw new Error(`createFramedApp: defaultPageId "${defaultPageId}" not found in pages`);
|
|
157
232
|
}
|
|
233
|
+
const defaultFrameCtx = options.ctx ?? resolveSafeCtx();
|
|
234
|
+
if (options.shellThemes != null && options.shellThemes.length > 0 && defaultFrameCtx == null) {
|
|
235
|
+
throw new Error('createFramedApp: shellThemes requires options.ctx or a default Bijou context');
|
|
236
|
+
}
|
|
237
|
+
const resolvedShellThemes = options.shellThemes?.map((theme) => ({
|
|
238
|
+
id: theme.id,
|
|
239
|
+
label: theme.label,
|
|
240
|
+
description: theme.description,
|
|
241
|
+
shellTheme: theme,
|
|
242
|
+
resolvedTheme: createResolved(theme.theme, defaultFrameCtx.theme.noColor, defaultFrameCtx.theme.colorScheme),
|
|
243
|
+
})) ?? [];
|
|
244
|
+
const enableShellThemeSettings = resolvedShellThemes.length > 1;
|
|
245
|
+
const initialShellTheme = resolveShellThemeForContext(resolvedShellThemes, defaultFrameCtx)
|
|
246
|
+
?? resolvedShellThemes[0];
|
|
247
|
+
const usesAmbientDefaultContext = options.ctx == null && defaultFrameCtx != null;
|
|
248
|
+
let frameCtx = options.ctx;
|
|
249
|
+
let frameCtxShellThemeId = resolveShellThemeForContext(resolvedShellThemes, frameCtx)?.id;
|
|
250
|
+
function resolveFrameCtx() {
|
|
251
|
+
return frameCtx ?? options.ctx ?? resolveSafeCtx();
|
|
252
|
+
}
|
|
253
|
+
function resolveFrameThemeCtx(activeShellThemeId) {
|
|
254
|
+
const baseCtx = resolveFrameCtx();
|
|
255
|
+
if (defaultFrameCtx == null)
|
|
256
|
+
return baseCtx;
|
|
257
|
+
const activeTheme = resolveCurrentShellTheme(resolvedShellThemes, activeShellThemeId);
|
|
258
|
+
if (activeTheme == null)
|
|
259
|
+
return baseCtx;
|
|
260
|
+
if (frameCtx != null && frameCtxShellThemeId === activeTheme.id) {
|
|
261
|
+
return frameCtx;
|
|
262
|
+
}
|
|
263
|
+
if (resolveShellThemeForContext(resolvedShellThemes, baseCtx)?.id === activeTheme.id) {
|
|
264
|
+
return baseCtx;
|
|
265
|
+
}
|
|
266
|
+
return cloneShellThemeContext(defaultFrameCtx, activeTheme.resolvedTheme);
|
|
267
|
+
}
|
|
268
|
+
function publishShellThemeContext(nextTheme) {
|
|
269
|
+
if (defaultFrameCtx == null)
|
|
270
|
+
return resolveFrameCtx();
|
|
271
|
+
frameCtx = cloneShellThemeContext(defaultFrameCtx, nextTheme.resolvedTheme);
|
|
272
|
+
frameCtxShellThemeId = nextTheme.id;
|
|
273
|
+
if (usesAmbientDefaultContext) {
|
|
274
|
+
setDefaultContext(frameCtx);
|
|
275
|
+
}
|
|
276
|
+
options.onShellThemeChange?.({
|
|
277
|
+
shellTheme: nextTheme.shellTheme,
|
|
278
|
+
ctx: frameCtx,
|
|
279
|
+
});
|
|
280
|
+
return frameCtx;
|
|
281
|
+
}
|
|
158
282
|
const frameKeys = createFrameKeyMap({
|
|
159
|
-
enableSettings: options.settings != null,
|
|
283
|
+
enableSettings: options.settings != null || enableShellThemeSettings,
|
|
160
284
|
enableNotifications: options.notificationCenter != null || options.runtimeNotifications !== false,
|
|
161
285
|
i18n: options.i18n,
|
|
162
286
|
});
|
|
@@ -221,30 +345,35 @@ export function createFramedApp(options) {
|
|
|
221
345
|
// --- settings ---
|
|
222
346
|
'settings-focus-move': (model, cmd) => {
|
|
223
347
|
const c = cmd;
|
|
224
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
348
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
225
349
|
return layout != null ? moveSettingsFocus(model, layout, c.delta) : model;
|
|
226
350
|
},
|
|
227
351
|
'settings-scroll': (model, cmd) => {
|
|
228
352
|
const c = cmd;
|
|
229
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
353
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
230
354
|
return layout != null ? scrollSettingsBy(model, layout, c.delta) : model;
|
|
231
355
|
},
|
|
232
356
|
'settings-scroll-to': (model, cmd) => {
|
|
233
357
|
const c = cmd;
|
|
234
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
358
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
235
359
|
if (layout == null)
|
|
236
360
|
return model;
|
|
237
361
|
return { ...model, settingsScrollY: c.position === 'top' ? 0 : layout.maxScrollY };
|
|
238
362
|
},
|
|
239
363
|
'activate-settings-row': (model, cmd, teaCmds) => {
|
|
240
364
|
const c = cmd;
|
|
241
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
365
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
242
366
|
if (layout == null)
|
|
243
367
|
return model;
|
|
244
368
|
const hitRow = layout.rows.find((r) => r.index === c.rowIndex);
|
|
245
369
|
if (hitRow == null)
|
|
246
370
|
return model;
|
|
247
371
|
const focusedModel = { ...model, settingsFocusIndex: hitRow.index };
|
|
372
|
+
if (hitRow.behavior === 'cycle-shell-theme') {
|
|
373
|
+
const [nextModel, cmds] = cycleShellThemeSetting(focusedModel, hitRow.row);
|
|
374
|
+
teaCmds.push(...cmds);
|
|
375
|
+
return nextModel;
|
|
376
|
+
}
|
|
248
377
|
if (hitRow.row.action === undefined || hitRow.row.enabled === false || hitRow.row.kind === 'info') {
|
|
249
378
|
return focusedModel;
|
|
250
379
|
}
|
|
@@ -255,18 +384,18 @@ export function createFramedApp(options) {
|
|
|
255
384
|
// --- notification center ---
|
|
256
385
|
'notification-center-scroll': (model, cmd) => {
|
|
257
386
|
const c = cmd;
|
|
258
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
387
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
259
388
|
return layout != null ? scrollNotificationCenterBy(model, layout, c.delta) : model;
|
|
260
389
|
},
|
|
261
390
|
'notification-center-scroll-to': (model, cmd) => {
|
|
262
391
|
const c = cmd;
|
|
263
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
392
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
264
393
|
if (layout == null)
|
|
265
394
|
return model;
|
|
266
395
|
return { ...model, notificationCenterScrollY: c.position === 'top' ? 0 : layout.maxScrollY };
|
|
267
396
|
},
|
|
268
397
|
'cycle-notification-filter': (model, _cmd, teaCmds) => {
|
|
269
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
398
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
270
399
|
if (layout == null)
|
|
271
400
|
return model;
|
|
272
401
|
const [nextModel, cmds] = cycleNotificationCenterFilter(model, layout);
|
|
@@ -277,7 +406,7 @@ export function createFramedApp(options) {
|
|
|
277
406
|
'help-scroll': (model, cmd) => {
|
|
278
407
|
const c = cmd;
|
|
279
408
|
const activePage = pagesById.get(model.activePageId);
|
|
280
|
-
const overlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById);
|
|
409
|
+
const overlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById, resolvedShellThemes);
|
|
281
410
|
const viewportHeight = Math.max(1, overlay.body.height - 1);
|
|
282
411
|
const delta = c.action === 'down' ? 3
|
|
283
412
|
: c.action === 'up' ? -3
|
|
@@ -337,7 +466,7 @@ export function createFramedApp(options) {
|
|
|
337
466
|
const c = cmd;
|
|
338
467
|
if (!frameNotificationOptions.enabled)
|
|
339
468
|
return model;
|
|
340
|
-
const nowMs = resolveClock(
|
|
469
|
+
const nowMs = resolveClock(resolveFrameCtx()).now();
|
|
341
470
|
const [nextModel, cmds] = applyFrameNotificationState(model, dismissNotification(model.runtimeNotifications, c.notificationId, nowMs), nowMs);
|
|
342
471
|
teaCmds.push(...cmds);
|
|
343
472
|
return nextModel;
|
|
@@ -436,7 +565,7 @@ export function createFramedApp(options) {
|
|
|
436
565
|
return [obs];
|
|
437
566
|
}
|
|
438
567
|
function handleSettingsLayerKeyCommands(msg, model) {
|
|
439
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
568
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
440
569
|
if (layout == null)
|
|
441
570
|
return undefined;
|
|
442
571
|
const obs = { type: 'observed-key', msg, route: 'frame' };
|
|
@@ -489,7 +618,10 @@ export function createFramedApp(options) {
|
|
|
489
618
|
if (!msg.ctrl && !msg.alt && (msg.key === 'enter' || msg.key === 'space')) {
|
|
490
619
|
const rowIndex = clampSettingsFocus(model, layout);
|
|
491
620
|
const row = layout.rows[rowIndex];
|
|
492
|
-
if (row
|
|
621
|
+
if (row != null
|
|
622
|
+
&& row.row.enabled !== false
|
|
623
|
+
&& row.row.kind !== 'info'
|
|
624
|
+
&& (row.behavior === 'cycle-shell-theme' || row.row.action !== undefined)) {
|
|
493
625
|
return [obs, { type: 'activate-settings-row', rowIndex: row.index }];
|
|
494
626
|
}
|
|
495
627
|
return [obs];
|
|
@@ -497,7 +629,7 @@ export function createFramedApp(options) {
|
|
|
497
629
|
return [obs];
|
|
498
630
|
}
|
|
499
631
|
function handleNotificationCenterLayerKeyCommands(msg, model) {
|
|
500
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
632
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
501
633
|
if (layout == null)
|
|
502
634
|
return undefined;
|
|
503
635
|
const obs = { type: 'observed-key', msg, route: 'frame' };
|
|
@@ -651,13 +783,14 @@ export function createFramedApp(options) {
|
|
|
651
783
|
const bodyRect = resolveBodyRect(model, options);
|
|
652
784
|
const maxState = model.maximizedPaneByPage[model.activePageId];
|
|
653
785
|
const maximizedPaneId = maxState?.maximizedPaneId;
|
|
786
|
+
const themedFrameCtx = resolveFrameThemeCtx(model.activeShellThemeId);
|
|
654
787
|
const renderResult = maximizedPaneId
|
|
655
|
-
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, paneScratchPool)
|
|
656
|
-
: renderPageContent(model.activePageId, model, bodyRect, pagesById);
|
|
788
|
+
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, paneScratchPool, themedFrameCtx)
|
|
789
|
+
: renderPageContent(model.activePageId, model, bodyRect, pagesById, themedFrameCtx);
|
|
657
790
|
return renderResult.paneRects;
|
|
658
791
|
}
|
|
659
792
|
function buildWorkspaceLayoutTree(model) {
|
|
660
|
-
const header = resolveHeaderLine(model, options, pagesById, headerScratch);
|
|
793
|
+
const header = resolveHeaderLine(model, options, pagesById, headerScratch, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
661
794
|
headerScratch = header.surface;
|
|
662
795
|
const tabChildren = header.tabTargets.map((target) => createShellRetainedLayoutNode(`tab:${target.pageId}`, {
|
|
663
796
|
row: 0,
|
|
@@ -698,7 +831,9 @@ export function createFramedApp(options) {
|
|
|
698
831
|
}
|
|
699
832
|
function resolveFrameMouseRuntimeLayouts(model) {
|
|
700
833
|
let layouts = EMPTY_RUNTIME_LAYOUTS;
|
|
701
|
-
const settingsLayout = model.settingsOpen
|
|
834
|
+
const settingsLayout = model.settingsOpen
|
|
835
|
+
? resolveSettingsLayout(model, options, pagesById, resolvedShellThemes)
|
|
836
|
+
: undefined;
|
|
702
837
|
if (settingsLayout != null) {
|
|
703
838
|
layouts = retainRuntimeLayout(layouts, {
|
|
704
839
|
viewId: 'settings',
|
|
@@ -710,7 +845,9 @@ export function createFramedApp(options) {
|
|
|
710
845
|
}, buildSettingsRowChildren(model, settingsLayout)),
|
|
711
846
|
});
|
|
712
847
|
}
|
|
713
|
-
const notificationCenterLayout = model.notificationCenterOpen
|
|
848
|
+
const notificationCenterLayout = model.notificationCenterOpen
|
|
849
|
+
? resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId))
|
|
850
|
+
: undefined;
|
|
714
851
|
if (notificationCenterLayout != null) {
|
|
715
852
|
layouts = retainRuntimeLayout(layouts, {
|
|
716
853
|
viewId: 'notification-center',
|
|
@@ -790,7 +927,7 @@ export function createFramedApp(options) {
|
|
|
790
927
|
screenHeight: model.rows,
|
|
791
928
|
margin: frameNotificationOptions.margin,
|
|
792
929
|
gap: frameNotificationOptions.gap,
|
|
793
|
-
ctx:
|
|
930
|
+
ctx: resolveFrameThemeCtx(model.activeShellThemeId) ?? undefined,
|
|
794
931
|
}, msg.col, msg.row);
|
|
795
932
|
if (notificationTarget?.kind === 'dismiss') {
|
|
796
933
|
cmds.push({ type: 'dismiss-notification', notificationId: notificationTarget.item.id });
|
|
@@ -872,7 +1009,7 @@ export function createFramedApp(options) {
|
|
|
872
1009
|
return helpLineOverride ?? mergeBindingSources(frameKeys, options.globalKeys, activeInputArea?.helpSource ?? activeInputArea?.keyMap, activePage.helpSource ?? activePage.keyMap);
|
|
873
1010
|
}
|
|
874
1011
|
function resolveLayerMetadata(model, activePage, activeInputArea, modalKeyMap) {
|
|
875
|
-
const settings = resolveFrameSettings(model, options, pagesById);
|
|
1012
|
+
const settings = resolveFrameSettings(model, options, pagesById, resolvedShellThemes);
|
|
876
1013
|
const notificationCenter = resolveFrameNotificationCenter(model, options, pagesById);
|
|
877
1014
|
const workspaceHintSource = resolveWorkspaceHintSource(model, activePage, activeInputArea);
|
|
878
1015
|
const workspaceHelpSource = resolveWorkspaceHelpSource(activePage, activeInputArea);
|
|
@@ -982,19 +1119,15 @@ export function createFramedApp(options) {
|
|
|
982
1119
|
}
|
|
983
1120
|
return [nextModel, []];
|
|
984
1121
|
}
|
|
985
|
-
function
|
|
986
|
-
if (row.action === undefined || row.enabled === false || row.kind === 'info') {
|
|
987
|
-
return [model, []];
|
|
988
|
-
}
|
|
989
|
-
const cmds = [emitMsgForPage(model.activePageId, row.action)];
|
|
1122
|
+
function pushSettingsFeedback(model, row) {
|
|
990
1123
|
if (!frameNotificationOptions.enabled) {
|
|
991
|
-
return [model,
|
|
1124
|
+
return [model, []];
|
|
992
1125
|
}
|
|
993
1126
|
const feedback = row.feedback ?? {
|
|
994
1127
|
title: 'Setting updated',
|
|
995
1128
|
message: `${row.label} updated.`,
|
|
996
1129
|
};
|
|
997
|
-
const nowMs = resolveClock(
|
|
1130
|
+
const nowMs = resolveClock(resolveFrameCtx()).now();
|
|
998
1131
|
const notifications = pushNotification(model.runtimeNotifications, {
|
|
999
1132
|
title: feedback.title ?? 'Setting updated',
|
|
1000
1133
|
message: feedback.message,
|
|
@@ -1005,9 +1138,28 @@ export function createFramedApp(options) {
|
|
|
1005
1138
|
durationMs: feedback.durationMs ?? 2_500,
|
|
1006
1139
|
overflow: frameNotificationOptions.overflow,
|
|
1007
1140
|
}, nowMs);
|
|
1008
|
-
|
|
1141
|
+
return applyFrameNotificationState(model, notifications, nowMs);
|
|
1142
|
+
}
|
|
1143
|
+
function activateSettingsRow(model, row) {
|
|
1144
|
+
if (row.action === undefined || row.enabled === false || row.kind === 'info') {
|
|
1145
|
+
return [model, []];
|
|
1146
|
+
}
|
|
1147
|
+
const cmds = [emitMsgForPage(model.activePageId, row.action)];
|
|
1148
|
+
const [nextModel, notificationCmds] = pushSettingsFeedback(model, row);
|
|
1009
1149
|
return [nextModel, [...cmds, ...notificationCmds]];
|
|
1010
1150
|
}
|
|
1151
|
+
function cycleShellThemeSetting(model, row) {
|
|
1152
|
+
const nextTheme = resolveNextShellTheme(resolvedShellThemes, model.activeShellThemeId);
|
|
1153
|
+
if (nextTheme == null) {
|
|
1154
|
+
return [model, []];
|
|
1155
|
+
}
|
|
1156
|
+
publishShellThemeContext(nextTheme);
|
|
1157
|
+
const [nextModel, notificationCmds] = pushSettingsFeedback({
|
|
1158
|
+
...model,
|
|
1159
|
+
activeShellThemeId: nextTheme.id,
|
|
1160
|
+
}, row);
|
|
1161
|
+
return [nextModel, notificationCmds];
|
|
1162
|
+
}
|
|
1011
1163
|
const app = {
|
|
1012
1164
|
init() {
|
|
1013
1165
|
const pageModels = {};
|
|
@@ -1044,7 +1196,11 @@ export function createFramedApp(options) {
|
|
|
1044
1196
|
runtimeNotifications: createNotificationState(),
|
|
1045
1197
|
runtimeNotificationHistoryFilter: 'ALL',
|
|
1046
1198
|
runtimeNotificationLoopActive: false,
|
|
1199
|
+
activeShellThemeId: initialShellTheme?.id,
|
|
1047
1200
|
};
|
|
1201
|
+
if (initialShellTheme != null) {
|
|
1202
|
+
publishShellThemeContext(initialShellTheme);
|
|
1203
|
+
}
|
|
1048
1204
|
for (const pageId of pageOrder) {
|
|
1049
1205
|
model = syncPageFrameState(model, pageId, pagesById);
|
|
1050
1206
|
}
|
|
@@ -1159,11 +1315,12 @@ export function createFramedApp(options) {
|
|
|
1159
1315
|
return updateTargetPage(model, model.activePageId, msg);
|
|
1160
1316
|
},
|
|
1161
1317
|
view(model) {
|
|
1318
|
+
const themedFrameCtx = resolveFrameThemeCtx(model.activeShellThemeId);
|
|
1162
1319
|
const { activePage, layerStack, activeLayer, } = resolvePresentedLayerContext(model);
|
|
1163
|
-
const headerResult = resolveHeaderLine(model, options, pagesById, headerScratch);
|
|
1320
|
+
const headerResult = resolveHeaderLine(model, options, pagesById, headerScratch, themedFrameCtx);
|
|
1164
1321
|
headerScratch = headerResult.surface;
|
|
1165
1322
|
const header = headerResult.surface;
|
|
1166
|
-
helpLineScratch = renderHelpLine(model, activeLayer, options.i18n, resolveNotificationFooterCue(model, options, pagesById), helpLineScratch);
|
|
1323
|
+
helpLineScratch = renderHelpLine(model, activeLayer, options.i18n, resolveNotificationFooterCue(model, options, pagesById), helpLineScratch, themedFrameCtx);
|
|
1167
1324
|
const helpLine = helpLineScratch;
|
|
1168
1325
|
const bodyRect = resolveBodyRect(model, options);
|
|
1169
1326
|
// Check for maximized pane — if set, render only that pane at full body rect
|
|
@@ -1182,20 +1339,20 @@ export function createFramedApp(options) {
|
|
|
1182
1339
|
const activeTransition = model.activeTransition ?? options.transition;
|
|
1183
1340
|
if (model.previousPageId != null && model.transitionProgress < 1 && activeTransition && activeTransition !== 'none') {
|
|
1184
1341
|
const activeBodyResult = maximizedPaneId
|
|
1185
|
-
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, paneScratchPool)
|
|
1186
|
-
: renderPageContent(model.activePageId, model, bodyRect, pagesById);
|
|
1342
|
+
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, paneScratchPool, themedFrameCtx)
|
|
1343
|
+
: renderPageContent(model.activePageId, model, bodyRect, pagesById, themedFrameCtx);
|
|
1187
1344
|
activeResult = activeBodyResult;
|
|
1188
1345
|
bodySurface = activeBodyResult.surface;
|
|
1189
|
-
const ctx =
|
|
1346
|
+
const ctx = themedFrameCtx;
|
|
1190
1347
|
if (ctx) {
|
|
1191
|
-
const prevResult = renderPageContent(model.previousPageId, model, bodyRect, pagesById);
|
|
1348
|
+
const prevResult = renderPageContent(model.previousPageId, model, bodyRect, pagesById, themedFrameCtx);
|
|
1192
1349
|
bodySurface = renderTransition(prevResult.surface, activeBodyResult.surface, activeTransition, model.transitionProgress, bodyRect.width, bodyRect.height, ctx, model.transitionFrame);
|
|
1193
1350
|
}
|
|
1194
1351
|
}
|
|
1195
1352
|
else {
|
|
1196
1353
|
activeResult = maximizedPaneId
|
|
1197
|
-
? renderMaximizedPaneInto(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, frameSurface, bodyRect.row, bodyRect.col, paneScratchPool)
|
|
1198
|
-
: renderPageContentInto(model.activePageId, model, bodyRect, pagesById, frameSurface, bodyRect.row, bodyRect.col, paneScratchPool);
|
|
1354
|
+
? renderMaximizedPaneInto(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, frameSurface, bodyRect.row, bodyRect.col, paneScratchPool, themedFrameCtx)
|
|
1355
|
+
: renderPageContentInto(model.activePageId, model, bodyRect, pagesById, frameSurface, bodyRect.row, bodyRect.col, paneScratchPool, themedFrameCtx);
|
|
1199
1356
|
}
|
|
1200
1357
|
const overlays = [];
|
|
1201
1358
|
if (options.overlayFactory != null) {
|
|
@@ -1207,7 +1364,7 @@ export function createFramedApp(options) {
|
|
|
1207
1364
|
}));
|
|
1208
1365
|
}
|
|
1209
1366
|
if (frameNotificationOptions.enabled) {
|
|
1210
|
-
const ctx =
|
|
1367
|
+
const ctx = themedFrameCtx;
|
|
1211
1368
|
overlays.push(...renderNotificationStack(model.runtimeNotifications, {
|
|
1212
1369
|
screenWidth: model.columns,
|
|
1213
1370
|
screenHeight: model.rows,
|
|
@@ -1218,20 +1375,20 @@ export function createFramedApp(options) {
|
|
|
1218
1375
|
}
|
|
1219
1376
|
if (model.settingsOpen) {
|
|
1220
1377
|
const settingsLayer = layerStack.find((layer) => layer.kind === 'settings');
|
|
1221
|
-
const settingsOverlay = renderSettingsDrawer(model, options, pagesById, settingsLayer?.title);
|
|
1378
|
+
const settingsOverlay = renderSettingsDrawer(model, options, pagesById, resolvedShellThemes, settingsLayer?.title, themedFrameCtx);
|
|
1222
1379
|
if (settingsOverlay != null) {
|
|
1223
1380
|
overlays.push(settingsOverlay);
|
|
1224
1381
|
}
|
|
1225
1382
|
}
|
|
1226
1383
|
if (model.notificationCenterOpen) {
|
|
1227
1384
|
const notificationLayer = layerStack.find((layer) => layer.kind === 'notification-center');
|
|
1228
|
-
const notificationCenterOverlay = renderNotificationCenterDrawer(model, options, pagesById, notificationLayer?.title);
|
|
1385
|
+
const notificationCenterOverlay = renderNotificationCenterDrawer(model, options, pagesById, notificationLayer?.title, themedFrameCtx);
|
|
1229
1386
|
if (notificationCenterOverlay != null) {
|
|
1230
1387
|
overlays.push(notificationCenterOverlay);
|
|
1231
1388
|
}
|
|
1232
1389
|
}
|
|
1233
1390
|
if (model.helpOpen) {
|
|
1234
|
-
const helpOverlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById);
|
|
1391
|
+
const helpOverlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById, resolvedShellThemes);
|
|
1235
1392
|
overlays.push(modal({
|
|
1236
1393
|
title: activeLayer.kind === 'help'
|
|
1237
1394
|
? (activeLayer.title ?? frameMessage(options.i18n, 'help.title', 'Keyboard Help'))
|
|
@@ -1240,6 +1397,9 @@ export function createFramedApp(options) {
|
|
|
1240
1397
|
hint: typeof activeLayer.hintSource === 'string'
|
|
1241
1398
|
? activeLayer.hintSource
|
|
1242
1399
|
: frameMessage(options.i18n, 'help.hint', 'j/k scroll • d/u page • g/G top/bottom • mouse wheel • ?/Esc close'),
|
|
1400
|
+
borderToken: themedFrameCtx?.border('primary'),
|
|
1401
|
+
bgToken: themedFrameCtx?.surface('elevated'),
|
|
1402
|
+
ctx: themedFrameCtx,
|
|
1243
1403
|
width: helpOverlay.body.width + 4,
|
|
1244
1404
|
screenWidth: model.columns,
|
|
1245
1405
|
screenHeight: model.rows,
|
|
@@ -1247,7 +1407,11 @@ export function createFramedApp(options) {
|
|
|
1247
1407
|
}
|
|
1248
1408
|
if (model.commandPalette != null) {
|
|
1249
1409
|
const paletteWidth = Math.max(20, Math.min(80, model.columns - 4));
|
|
1250
|
-
const paletteBody =
|
|
1410
|
+
const paletteBody = commandPaletteSurface(model.commandPalette, {
|
|
1411
|
+
width: Math.max(16, paletteWidth - 4),
|
|
1412
|
+
ctx: themedFrameCtx,
|
|
1413
|
+
showScrollbar: false,
|
|
1414
|
+
});
|
|
1251
1415
|
const paletteLayer = activeLayer.kind === 'search' || activeLayer.kind === 'command-palette'
|
|
1252
1416
|
? activeLayer
|
|
1253
1417
|
: undefined;
|
|
@@ -1257,13 +1421,16 @@ export function createFramedApp(options) {
|
|
|
1257
1421
|
hint: typeof paletteLayer?.hintSource === 'string'
|
|
1258
1422
|
? paletteLayer.hintSource
|
|
1259
1423
|
: frameMessage(options.i18n, 'palette.hint', 'Enter select • Esc close'),
|
|
1424
|
+
borderToken: themedFrameCtx?.border('primary'),
|
|
1425
|
+
bgToken: themedFrameCtx?.surface('elevated'),
|
|
1426
|
+
ctx: themedFrameCtx,
|
|
1260
1427
|
width: paletteWidth,
|
|
1261
1428
|
screenWidth: model.columns,
|
|
1262
1429
|
screenHeight: model.rows,
|
|
1263
1430
|
}));
|
|
1264
1431
|
}
|
|
1265
1432
|
if (model.quitConfirmOpen) {
|
|
1266
|
-
overlays.push(renderShellQuitOverlay(model.columns, model.rows, options.i18n));
|
|
1433
|
+
overlays.push(renderShellQuitOverlay(model.columns, model.rows, options.i18n, themedFrameCtx));
|
|
1267
1434
|
}
|
|
1268
1435
|
if (bodySurface != null && bodyRect.width > 0 && bodyRect.height > 0) {
|
|
1269
1436
|
frameSurface.blit(bodySurface, bodyRect.col, bodyRect.row);
|
|
@@ -1292,11 +1459,11 @@ function focusPane(model, paneId) {
|
|
|
1292
1459
|
function resolveBodyRect(model, options) {
|
|
1293
1460
|
return frameBodyRect(model.columns, model.rows, options.bodyTopRows ?? 1, options.bodyBottomRows ?? 1);
|
|
1294
1461
|
}
|
|
1295
|
-
function renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById) {
|
|
1462
|
+
function renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById, shellThemes) {
|
|
1296
1463
|
const activePageModel = model.pageModels[model.activePageId];
|
|
1297
1464
|
const activeInputArea = findInputAreaByPaneId(resolveInputAreas(activePage, activePageModel), model.focusedPaneByPage[model.activePageId]);
|
|
1298
1465
|
const modalKeyMap = activePage.modalKeyMap?.(activePageModel);
|
|
1299
|
-
const settings = resolveFrameSettings(model, options, pagesById);
|
|
1466
|
+
const settings = resolveFrameSettings(model, options, pagesById, shellThemes);
|
|
1300
1467
|
const notificationCenter = resolveFrameNotificationCenter(model, options, pagesById);
|
|
1301
1468
|
const workspaceHintSource = options.helpLineSource?.({
|
|
1302
1469
|
model,
|
|
@@ -1389,13 +1556,15 @@ function isHelpScrollAction(action) {
|
|
|
1389
1556
|
|| action.type === 'top'
|
|
1390
1557
|
|| action.type === 'bottom';
|
|
1391
1558
|
}
|
|
1392
|
-
|
|
1559
|
+
const FRAME_SHELL_THEME_ROW_ID = '__frame-shell-theme__';
|
|
1560
|
+
function resolveFrameSettings(model, options, pagesById, shellThemes) {
|
|
1393
1561
|
const activePage = pagesById.get(model.activePageId);
|
|
1394
|
-
|
|
1562
|
+
const provided = options.settings?.({
|
|
1395
1563
|
model,
|
|
1396
1564
|
activePage,
|
|
1397
1565
|
pageModel: model.pageModels[model.activePageId],
|
|
1398
1566
|
});
|
|
1567
|
+
return mergeShellThemeSettings(provided, shellThemes, model.activeShellThemeId, options.i18n);
|
|
1399
1568
|
}
|
|
1400
1569
|
function resolveFrameNotificationCenter(model, options, pagesById) {
|
|
1401
1570
|
const activePage = pagesById.get(model.activePageId);
|
|
@@ -1430,8 +1599,8 @@ function resolveFrameNotificationCenter(model, options, pagesById) {
|
|
|
1430
1599
|
activeFilter: model.runtimeNotificationHistoryFilter,
|
|
1431
1600
|
};
|
|
1432
1601
|
}
|
|
1433
|
-
function resolveSettingsLayout(model, options, pagesById) {
|
|
1434
|
-
const settings = resolveFrameSettings(model, options, pagesById);
|
|
1602
|
+
function resolveSettingsLayout(model, options, pagesById, shellThemes) {
|
|
1603
|
+
const settings = resolveFrameSettings(model, options, pagesById, shellThemes);
|
|
1435
1604
|
if (settings == null)
|
|
1436
1605
|
return undefined;
|
|
1437
1606
|
const sections = settings.sections.filter((section) => section.rows.length > 0);
|
|
@@ -1460,6 +1629,7 @@ function resolveSettingsLayout(model, options, pagesById) {
|
|
|
1460
1629
|
line,
|
|
1461
1630
|
height: rowLayout.height,
|
|
1462
1631
|
row,
|
|
1632
|
+
behavior: row.id === FRAME_SHELL_THEME_ROW_ID ? 'cycle-shell-theme' : undefined,
|
|
1463
1633
|
});
|
|
1464
1634
|
line += rowLayout.height;
|
|
1465
1635
|
if (rowIndex < section.rows.length - 1) {
|
|
@@ -1490,7 +1660,7 @@ function resolveNotificationCenterDrawerWidth(columns) {
|
|
|
1490
1660
|
const boundedColumns = Math.max(28, columns);
|
|
1491
1661
|
return Math.min(Math.max(32, Math.floor(boundedColumns * 0.34)), Math.max(32, boundedColumns - 4), 52);
|
|
1492
1662
|
}
|
|
1493
|
-
function resolveNotificationCenterLayout(model, options, pagesById) {
|
|
1663
|
+
function resolveNotificationCenterLayout(model, options, pagesById, ctx) {
|
|
1494
1664
|
const center = resolveFrameNotificationCenter(model, options, pagesById);
|
|
1495
1665
|
if (center == null)
|
|
1496
1666
|
return undefined;
|
|
@@ -1498,7 +1668,7 @@ function resolveNotificationCenterLayout(model, options, pagesById) {
|
|
|
1498
1668
|
const anchor = frameEndAnchor(options.i18n);
|
|
1499
1669
|
const startCol = anchor === 'left' ? 0 : Math.max(0, model.columns - drawerWidth);
|
|
1500
1670
|
const contentWidth = Math.max(18, drawerWidth - 4);
|
|
1501
|
-
const content = renderNotificationCenterSurface(center, contentWidth, options.i18n);
|
|
1671
|
+
const content = renderNotificationCenterSurface(center, contentWidth, options.i18n, ctx);
|
|
1502
1672
|
const contentHeight = Math.max(1, model.rows - 2);
|
|
1503
1673
|
const pagerState = createPagerStateForSurface(content, {
|
|
1504
1674
|
width: contentWidth,
|
|
@@ -1588,12 +1758,12 @@ function cycleNotificationCenterFilter(model, layout) {
|
|
|
1588
1758
|
notificationCenterScrollY: 0,
|
|
1589
1759
|
}, []];
|
|
1590
1760
|
}
|
|
1591
|
-
function renderSettingsDrawer(model, options, pagesById, titleOverride) {
|
|
1592
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
1761
|
+
function renderSettingsDrawer(model, options, pagesById, shellThemes, titleOverride, ctx) {
|
|
1762
|
+
const layout = resolveSettingsLayout(model, options, pagesById, shellThemes);
|
|
1593
1763
|
if (layout == null)
|
|
1594
1764
|
return undefined;
|
|
1595
1765
|
const scrollY = clampSettingsScroll(model, layout);
|
|
1596
|
-
const content = renderSettingsSurface(layout, model);
|
|
1766
|
+
const content = renderSettingsSurface(layout, model, ctx);
|
|
1597
1767
|
const pagerState = createPagerStateForSurface(content, {
|
|
1598
1768
|
width: layout.contentWidth,
|
|
1599
1769
|
height: layout.contentHeight,
|
|
@@ -1615,14 +1785,14 @@ function renderSettingsDrawer(model, options, pagesById, titleOverride) {
|
|
|
1615
1785
|
content: body,
|
|
1616
1786
|
borderToken: layout.settings.borderToken,
|
|
1617
1787
|
bgToken: layout.settings.bgToken,
|
|
1618
|
-
ctx
|
|
1788
|
+
ctx,
|
|
1619
1789
|
width: layout.drawerWidth,
|
|
1620
1790
|
screenWidth: model.columns,
|
|
1621
1791
|
screenHeight: model.rows,
|
|
1622
1792
|
});
|
|
1623
1793
|
}
|
|
1624
|
-
function renderNotificationCenterDrawer(model, options, pagesById, titleOverride) {
|
|
1625
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
1794
|
+
function renderNotificationCenterDrawer(model, options, pagesById, titleOverride, ctx) {
|
|
1795
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, ctx);
|
|
1626
1796
|
if (layout == null)
|
|
1627
1797
|
return undefined;
|
|
1628
1798
|
const pagerState = createPagerStateForSurface(layout.content, {
|
|
@@ -1644,17 +1814,20 @@ function renderNotificationCenterDrawer(model, options, pagesById, titleOverride
|
|
|
1644
1814
|
anchor: layout.anchor,
|
|
1645
1815
|
title: titleOverride ?? `${layout.center.title} • ${frameNotificationFilterLabel(options.i18n, layout.center.activeFilter)}`,
|
|
1646
1816
|
content: body,
|
|
1817
|
+
borderToken: ctx?.border('primary'),
|
|
1818
|
+
bgToken: ctx?.surface('elevated'),
|
|
1819
|
+
ctx,
|
|
1647
1820
|
width: layout.drawerWidth,
|
|
1648
1821
|
screenWidth: model.columns,
|
|
1649
1822
|
screenHeight: model.rows,
|
|
1650
1823
|
});
|
|
1651
1824
|
}
|
|
1652
|
-
function renderSettingsSurface(layout, model) {
|
|
1825
|
+
function renderSettingsSurface(layout, model, ctx) {
|
|
1653
1826
|
const focusedIndex = clampSettingsFocus(model, layout);
|
|
1654
1827
|
return preferenceListSurface(layout.preferenceSections, {
|
|
1655
1828
|
width: layout.contentWidth,
|
|
1656
1829
|
selectedRowId: layout.rows[focusedIndex]?.row.id,
|
|
1657
|
-
ctx
|
|
1830
|
+
ctx,
|
|
1658
1831
|
theme: layout.settings.listTheme,
|
|
1659
1832
|
});
|
|
1660
1833
|
}
|
|
@@ -1684,8 +1857,7 @@ function resolveNotificationFooterCue(model, options, pagesById) {
|
|
|
1684
1857
|
const archivedCount = countNotificationHistory(center.state, center.activeFilter);
|
|
1685
1858
|
return frameNotificationCue(options.i18n, liveCount, archivedCount);
|
|
1686
1859
|
}
|
|
1687
|
-
function renderNotificationCenterSurface(center, width, i18n) {
|
|
1688
|
-
const ctx = resolveSafeCtx() ?? undefined;
|
|
1860
|
+
function renderNotificationCenterSurface(center, width, i18n, ctx) {
|
|
1689
1861
|
const rows = [
|
|
1690
1862
|
insetLineSurface(`Live: ${center.state.items.length} • Archived: ${center.state.history.length}`, width),
|
|
1691
1863
|
insetLineSurface(`Filter: ${frameNotificationFilterLabel(i18n, center.activeFilter)}`, width),
|