@flyingrobots/bijou-tui 4.2.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 -617
- 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 +11 -9
- package/dist/app-frame-render.d.ts.map +1 -1
- package/dist/app-frame-render.js +102 -39
- 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 +244 -63
- package/dist/app-frame.js.map +1 -1
- package/dist/canvas.d.ts.map +1 -1
- package/dist/canvas.js +25 -4
- package/dist/canvas.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/css/text-style.d.ts +6 -0
- package/dist/css/text-style.d.ts.map +1 -1
- package/dist/css/text-style.js +59 -15
- package/dist/css/text-style.js.map +1 -1
- package/dist/flex.d.ts.map +1 -1
- package/dist/flex.js +28 -4
- package/dist/flex.js.map +1 -1
- package/dist/focus-area.d.ts.map +1 -1
- package/dist/focus-area.js +18 -3
- 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/notification.d.ts.map +1 -1
- package/dist/notification.js +56 -16
- package/dist/notification.js.map +1 -1
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +103 -21
- package/dist/overlay.js.map +1 -1
- package/dist/pipeline/middleware/grayscale.d.ts +3 -0
- package/dist/pipeline/middleware/grayscale.d.ts.map +1 -1
- package/dist/pipeline/middleware/grayscale.js +63 -10
- package/dist/pipeline/middleware/grayscale.js.map +1 -1
- package/dist/pipeline/pipeline.d.ts +7 -0
- package/dist/pipeline/pipeline.d.ts.map +1 -1
- package/dist/pipeline/pipeline.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +33 -1
- package/dist/runtime.js.map +1 -1
- package/dist/screen.d.ts +5 -1
- package/dist/screen.d.ts.map +1 -1
- package/dist/screen.js +6 -2
- package/dist/screen.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/dist/transition-shaders.d.ts.map +1 -1
- package/dist/transition-shaders.js +6 -1
- package/dist/transition-shaders.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';
|
|
@@ -22,7 +22,7 @@ import { createFrameKeyMap, frameBodyRect, mergeBindingSources, } from './app-fr
|
|
|
22
22
|
import { activeFrameLayer, describeFrameLayerStack, describeFrameRuntimeViewStack, } from './app-frame-layers.js';
|
|
23
23
|
import { applyRuntimeCommandBuffer, bufferRuntimeRouteResult, createRuntimeBuffers, createRuntimeRetainedLayouts, retainRuntimeLayout, routeRuntimeInput, } from './runtime-engine.js';
|
|
24
24
|
import { frameEndAnchor, frameMessage, frameNotificationCue, frameNotificationFilterLabel, frameStartAnchor, } from './app-frame-i18n.js';
|
|
25
|
-
import { resolveHeaderLine, renderHelpLine, renderPageContent, renderPageContentInto, renderMaximizedPane, renderMaximizedPaneInto, renderTransition, } from './app-frame-render.js';
|
|
25
|
+
import { resolveHeaderLine, renderHelpLine, renderPageContent, renderPageContentInto, renderMaximizedPane, renderMaximizedPaneInto, renderTransition, createFramePaneScratchPool, } from './app-frame-render.js';
|
|
26
26
|
import { applyFrameAction, scrollFocusedPane, switchTab, syncPageFrameState, } from './app-frame-actions.js';
|
|
27
27
|
import { handlePaletteKey, openCommandPalette, openSearchPalette, } from './app-frame-palette.js';
|
|
28
28
|
export { activeFrameLayer, describeFrameLayerStack, describeFrameRuntimeViewStack, underlyingFrameLayer, } from './app-frame-layers.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,13 +230,65 @@ 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
|
});
|
|
163
287
|
const frameNotificationOptions = resolveFrameNotificationOptions(options);
|
|
164
288
|
let composedFrameScratch = null;
|
|
289
|
+
let headerScratch;
|
|
290
|
+
let helpLineScratch;
|
|
291
|
+
const paneScratchPool = createFramePaneScratchPool();
|
|
165
292
|
const paletteKeys = commandPaletteKeyMap({
|
|
166
293
|
focusNext: { type: 'cp-next' },
|
|
167
294
|
focusPrev: { type: 'cp-prev' },
|
|
@@ -218,30 +345,35 @@ export function createFramedApp(options) {
|
|
|
218
345
|
// --- settings ---
|
|
219
346
|
'settings-focus-move': (model, cmd) => {
|
|
220
347
|
const c = cmd;
|
|
221
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
348
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
222
349
|
return layout != null ? moveSettingsFocus(model, layout, c.delta) : model;
|
|
223
350
|
},
|
|
224
351
|
'settings-scroll': (model, cmd) => {
|
|
225
352
|
const c = cmd;
|
|
226
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
353
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
227
354
|
return layout != null ? scrollSettingsBy(model, layout, c.delta) : model;
|
|
228
355
|
},
|
|
229
356
|
'settings-scroll-to': (model, cmd) => {
|
|
230
357
|
const c = cmd;
|
|
231
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
358
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
232
359
|
if (layout == null)
|
|
233
360
|
return model;
|
|
234
361
|
return { ...model, settingsScrollY: c.position === 'top' ? 0 : layout.maxScrollY };
|
|
235
362
|
},
|
|
236
363
|
'activate-settings-row': (model, cmd, teaCmds) => {
|
|
237
364
|
const c = cmd;
|
|
238
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
365
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
239
366
|
if (layout == null)
|
|
240
367
|
return model;
|
|
241
368
|
const hitRow = layout.rows.find((r) => r.index === c.rowIndex);
|
|
242
369
|
if (hitRow == null)
|
|
243
370
|
return model;
|
|
244
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
|
+
}
|
|
245
377
|
if (hitRow.row.action === undefined || hitRow.row.enabled === false || hitRow.row.kind === 'info') {
|
|
246
378
|
return focusedModel;
|
|
247
379
|
}
|
|
@@ -252,18 +384,18 @@ export function createFramedApp(options) {
|
|
|
252
384
|
// --- notification center ---
|
|
253
385
|
'notification-center-scroll': (model, cmd) => {
|
|
254
386
|
const c = cmd;
|
|
255
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
387
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
256
388
|
return layout != null ? scrollNotificationCenterBy(model, layout, c.delta) : model;
|
|
257
389
|
},
|
|
258
390
|
'notification-center-scroll-to': (model, cmd) => {
|
|
259
391
|
const c = cmd;
|
|
260
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
392
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
261
393
|
if (layout == null)
|
|
262
394
|
return model;
|
|
263
395
|
return { ...model, notificationCenterScrollY: c.position === 'top' ? 0 : layout.maxScrollY };
|
|
264
396
|
},
|
|
265
397
|
'cycle-notification-filter': (model, _cmd, teaCmds) => {
|
|
266
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
398
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
267
399
|
if (layout == null)
|
|
268
400
|
return model;
|
|
269
401
|
const [nextModel, cmds] = cycleNotificationCenterFilter(model, layout);
|
|
@@ -274,7 +406,7 @@ export function createFramedApp(options) {
|
|
|
274
406
|
'help-scroll': (model, cmd) => {
|
|
275
407
|
const c = cmd;
|
|
276
408
|
const activePage = pagesById.get(model.activePageId);
|
|
277
|
-
const overlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById);
|
|
409
|
+
const overlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById, resolvedShellThemes);
|
|
278
410
|
const viewportHeight = Math.max(1, overlay.body.height - 1);
|
|
279
411
|
const delta = c.action === 'down' ? 3
|
|
280
412
|
: c.action === 'up' ? -3
|
|
@@ -334,7 +466,7 @@ export function createFramedApp(options) {
|
|
|
334
466
|
const c = cmd;
|
|
335
467
|
if (!frameNotificationOptions.enabled)
|
|
336
468
|
return model;
|
|
337
|
-
const nowMs = resolveClock(
|
|
469
|
+
const nowMs = resolveClock(resolveFrameCtx()).now();
|
|
338
470
|
const [nextModel, cmds] = applyFrameNotificationState(model, dismissNotification(model.runtimeNotifications, c.notificationId, nowMs), nowMs);
|
|
339
471
|
teaCmds.push(...cmds);
|
|
340
472
|
return nextModel;
|
|
@@ -433,7 +565,7 @@ export function createFramedApp(options) {
|
|
|
433
565
|
return [obs];
|
|
434
566
|
}
|
|
435
567
|
function handleSettingsLayerKeyCommands(msg, model) {
|
|
436
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
568
|
+
const layout = resolveSettingsLayout(model, options, pagesById, resolvedShellThemes);
|
|
437
569
|
if (layout == null)
|
|
438
570
|
return undefined;
|
|
439
571
|
const obs = { type: 'observed-key', msg, route: 'frame' };
|
|
@@ -486,7 +618,10 @@ export function createFramedApp(options) {
|
|
|
486
618
|
if (!msg.ctrl && !msg.alt && (msg.key === 'enter' || msg.key === 'space')) {
|
|
487
619
|
const rowIndex = clampSettingsFocus(model, layout);
|
|
488
620
|
const row = layout.rows[rowIndex];
|
|
489
|
-
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)) {
|
|
490
625
|
return [obs, { type: 'activate-settings-row', rowIndex: row.index }];
|
|
491
626
|
}
|
|
492
627
|
return [obs];
|
|
@@ -494,7 +629,7 @@ export function createFramedApp(options) {
|
|
|
494
629
|
return [obs];
|
|
495
630
|
}
|
|
496
631
|
function handleNotificationCenterLayerKeyCommands(msg, model) {
|
|
497
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
632
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
498
633
|
if (layout == null)
|
|
499
634
|
return undefined;
|
|
500
635
|
const obs = { type: 'observed-key', msg, route: 'frame' };
|
|
@@ -648,13 +783,15 @@ export function createFramedApp(options) {
|
|
|
648
783
|
const bodyRect = resolveBodyRect(model, options);
|
|
649
784
|
const maxState = model.maximizedPaneByPage[model.activePageId];
|
|
650
785
|
const maximizedPaneId = maxState?.maximizedPaneId;
|
|
786
|
+
const themedFrameCtx = resolveFrameThemeCtx(model.activeShellThemeId);
|
|
651
787
|
const renderResult = maximizedPaneId
|
|
652
|
-
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId)
|
|
653
|
-
: renderPageContent(model.activePageId, model, bodyRect, pagesById);
|
|
788
|
+
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, paneScratchPool, themedFrameCtx)
|
|
789
|
+
: renderPageContent(model.activePageId, model, bodyRect, pagesById, themedFrameCtx);
|
|
654
790
|
return renderResult.paneRects;
|
|
655
791
|
}
|
|
656
792
|
function buildWorkspaceLayoutTree(model) {
|
|
657
|
-
const header = resolveHeaderLine(model, options, pagesById);
|
|
793
|
+
const header = resolveHeaderLine(model, options, pagesById, headerScratch, resolveFrameThemeCtx(model.activeShellThemeId));
|
|
794
|
+
headerScratch = header.surface;
|
|
658
795
|
const tabChildren = header.tabTargets.map((target) => createShellRetainedLayoutNode(`tab:${target.pageId}`, {
|
|
659
796
|
row: 0,
|
|
660
797
|
col: target.startCol,
|
|
@@ -694,7 +831,9 @@ export function createFramedApp(options) {
|
|
|
694
831
|
}
|
|
695
832
|
function resolveFrameMouseRuntimeLayouts(model) {
|
|
696
833
|
let layouts = EMPTY_RUNTIME_LAYOUTS;
|
|
697
|
-
const settingsLayout = model.settingsOpen
|
|
834
|
+
const settingsLayout = model.settingsOpen
|
|
835
|
+
? resolveSettingsLayout(model, options, pagesById, resolvedShellThemes)
|
|
836
|
+
: undefined;
|
|
698
837
|
if (settingsLayout != null) {
|
|
699
838
|
layouts = retainRuntimeLayout(layouts, {
|
|
700
839
|
viewId: 'settings',
|
|
@@ -706,7 +845,9 @@ export function createFramedApp(options) {
|
|
|
706
845
|
}, buildSettingsRowChildren(model, settingsLayout)),
|
|
707
846
|
});
|
|
708
847
|
}
|
|
709
|
-
const notificationCenterLayout = model.notificationCenterOpen
|
|
848
|
+
const notificationCenterLayout = model.notificationCenterOpen
|
|
849
|
+
? resolveNotificationCenterLayout(model, options, pagesById, resolveFrameThemeCtx(model.activeShellThemeId))
|
|
850
|
+
: undefined;
|
|
710
851
|
if (notificationCenterLayout != null) {
|
|
711
852
|
layouts = retainRuntimeLayout(layouts, {
|
|
712
853
|
viewId: 'notification-center',
|
|
@@ -786,7 +927,7 @@ export function createFramedApp(options) {
|
|
|
786
927
|
screenHeight: model.rows,
|
|
787
928
|
margin: frameNotificationOptions.margin,
|
|
788
929
|
gap: frameNotificationOptions.gap,
|
|
789
|
-
ctx:
|
|
930
|
+
ctx: resolveFrameThemeCtx(model.activeShellThemeId) ?? undefined,
|
|
790
931
|
}, msg.col, msg.row);
|
|
791
932
|
if (notificationTarget?.kind === 'dismiss') {
|
|
792
933
|
cmds.push({ type: 'dismiss-notification', notificationId: notificationTarget.item.id });
|
|
@@ -868,7 +1009,7 @@ export function createFramedApp(options) {
|
|
|
868
1009
|
return helpLineOverride ?? mergeBindingSources(frameKeys, options.globalKeys, activeInputArea?.helpSource ?? activeInputArea?.keyMap, activePage.helpSource ?? activePage.keyMap);
|
|
869
1010
|
}
|
|
870
1011
|
function resolveLayerMetadata(model, activePage, activeInputArea, modalKeyMap) {
|
|
871
|
-
const settings = resolveFrameSettings(model, options, pagesById);
|
|
1012
|
+
const settings = resolveFrameSettings(model, options, pagesById, resolvedShellThemes);
|
|
872
1013
|
const notificationCenter = resolveFrameNotificationCenter(model, options, pagesById);
|
|
873
1014
|
const workspaceHintSource = resolveWorkspaceHintSource(model, activePage, activeInputArea);
|
|
874
1015
|
const workspaceHelpSource = resolveWorkspaceHelpSource(activePage, activeInputArea);
|
|
@@ -978,19 +1119,15 @@ export function createFramedApp(options) {
|
|
|
978
1119
|
}
|
|
979
1120
|
return [nextModel, []];
|
|
980
1121
|
}
|
|
981
|
-
function
|
|
982
|
-
if (row.action === undefined || row.enabled === false || row.kind === 'info') {
|
|
983
|
-
return [model, []];
|
|
984
|
-
}
|
|
985
|
-
const cmds = [emitMsgForPage(model.activePageId, row.action)];
|
|
1122
|
+
function pushSettingsFeedback(model, row) {
|
|
986
1123
|
if (!frameNotificationOptions.enabled) {
|
|
987
|
-
return [model,
|
|
1124
|
+
return [model, []];
|
|
988
1125
|
}
|
|
989
1126
|
const feedback = row.feedback ?? {
|
|
990
1127
|
title: 'Setting updated',
|
|
991
1128
|
message: `${row.label} updated.`,
|
|
992
1129
|
};
|
|
993
|
-
const nowMs = resolveClock(
|
|
1130
|
+
const nowMs = resolveClock(resolveFrameCtx()).now();
|
|
994
1131
|
const notifications = pushNotification(model.runtimeNotifications, {
|
|
995
1132
|
title: feedback.title ?? 'Setting updated',
|
|
996
1133
|
message: feedback.message,
|
|
@@ -1001,9 +1138,28 @@ export function createFramedApp(options) {
|
|
|
1001
1138
|
durationMs: feedback.durationMs ?? 2_500,
|
|
1002
1139
|
overflow: frameNotificationOptions.overflow,
|
|
1003
1140
|
}, nowMs);
|
|
1004
|
-
|
|
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);
|
|
1005
1149
|
return [nextModel, [...cmds, ...notificationCmds]];
|
|
1006
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
|
+
}
|
|
1007
1163
|
const app = {
|
|
1008
1164
|
init() {
|
|
1009
1165
|
const pageModels = {};
|
|
@@ -1040,7 +1196,11 @@ export function createFramedApp(options) {
|
|
|
1040
1196
|
runtimeNotifications: createNotificationState(),
|
|
1041
1197
|
runtimeNotificationHistoryFilter: 'ALL',
|
|
1042
1198
|
runtimeNotificationLoopActive: false,
|
|
1199
|
+
activeShellThemeId: initialShellTheme?.id,
|
|
1043
1200
|
};
|
|
1201
|
+
if (initialShellTheme != null) {
|
|
1202
|
+
publishShellThemeContext(initialShellTheme);
|
|
1203
|
+
}
|
|
1044
1204
|
for (const pageId of pageOrder) {
|
|
1045
1205
|
model = syncPageFrameState(model, pageId, pagesById);
|
|
1046
1206
|
}
|
|
@@ -1155,14 +1315,20 @@ export function createFramedApp(options) {
|
|
|
1155
1315
|
return updateTargetPage(model, model.activePageId, msg);
|
|
1156
1316
|
},
|
|
1157
1317
|
view(model) {
|
|
1318
|
+
const themedFrameCtx = resolveFrameThemeCtx(model.activeShellThemeId);
|
|
1158
1319
|
const { activePage, layerStack, activeLayer, } = resolvePresentedLayerContext(model);
|
|
1159
|
-
const
|
|
1160
|
-
|
|
1320
|
+
const headerResult = resolveHeaderLine(model, options, pagesById, headerScratch, themedFrameCtx);
|
|
1321
|
+
headerScratch = headerResult.surface;
|
|
1322
|
+
const header = headerResult.surface;
|
|
1323
|
+
helpLineScratch = renderHelpLine(model, activeLayer, options.i18n, resolveNotificationFooterCue(model, options, pagesById), helpLineScratch, themedFrameCtx);
|
|
1324
|
+
const helpLine = helpLineScratch;
|
|
1161
1325
|
const bodyRect = resolveBodyRect(model, options);
|
|
1162
1326
|
// Check for maximized pane — if set, render only that pane at full body rect
|
|
1163
1327
|
const maxState = model.maximizedPaneByPage[model.activePageId];
|
|
1164
1328
|
const maximizedPaneId = maxState?.maximizedPaneId;
|
|
1165
1329
|
const frameSurface = getComposedFrameScratch(model.columns, model.rows);
|
|
1330
|
+
// clear() is load-bearing: it resets dim flags left by overlay compositing
|
|
1331
|
+
// on the previous frame. Do not skip or defer this call.
|
|
1166
1332
|
frameSurface.clear();
|
|
1167
1333
|
frameSurface.blit(header, 0, 0);
|
|
1168
1334
|
if (model.rows > 1) {
|
|
@@ -1173,20 +1339,20 @@ export function createFramedApp(options) {
|
|
|
1173
1339
|
const activeTransition = model.activeTransition ?? options.transition;
|
|
1174
1340
|
if (model.previousPageId != null && model.transitionProgress < 1 && activeTransition && activeTransition !== 'none') {
|
|
1175
1341
|
const activeBodyResult = maximizedPaneId
|
|
1176
|
-
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId)
|
|
1177
|
-
: renderPageContent(model.activePageId, model, bodyRect, pagesById);
|
|
1342
|
+
? renderMaximizedPane(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, paneScratchPool, themedFrameCtx)
|
|
1343
|
+
: renderPageContent(model.activePageId, model, bodyRect, pagesById, themedFrameCtx);
|
|
1178
1344
|
activeResult = activeBodyResult;
|
|
1179
1345
|
bodySurface = activeBodyResult.surface;
|
|
1180
|
-
const ctx =
|
|
1346
|
+
const ctx = themedFrameCtx;
|
|
1181
1347
|
if (ctx) {
|
|
1182
|
-
const prevResult = renderPageContent(model.previousPageId, model, bodyRect, pagesById);
|
|
1348
|
+
const prevResult = renderPageContent(model.previousPageId, model, bodyRect, pagesById, themedFrameCtx);
|
|
1183
1349
|
bodySurface = renderTransition(prevResult.surface, activeBodyResult.surface, activeTransition, model.transitionProgress, bodyRect.width, bodyRect.height, ctx, model.transitionFrame);
|
|
1184
1350
|
}
|
|
1185
1351
|
}
|
|
1186
1352
|
else {
|
|
1187
1353
|
activeResult = maximizedPaneId
|
|
1188
|
-
? renderMaximizedPaneInto(model.activePageId, model, bodyRect, pagesById, maximizedPaneId, frameSurface)
|
|
1189
|
-
: renderPageContentInto(model.activePageId, model, bodyRect, pagesById, frameSurface);
|
|
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);
|
|
1190
1356
|
}
|
|
1191
1357
|
const overlays = [];
|
|
1192
1358
|
if (options.overlayFactory != null) {
|
|
@@ -1198,7 +1364,7 @@ export function createFramedApp(options) {
|
|
|
1198
1364
|
}));
|
|
1199
1365
|
}
|
|
1200
1366
|
if (frameNotificationOptions.enabled) {
|
|
1201
|
-
const ctx =
|
|
1367
|
+
const ctx = themedFrameCtx;
|
|
1202
1368
|
overlays.push(...renderNotificationStack(model.runtimeNotifications, {
|
|
1203
1369
|
screenWidth: model.columns,
|
|
1204
1370
|
screenHeight: model.rows,
|
|
@@ -1209,20 +1375,20 @@ export function createFramedApp(options) {
|
|
|
1209
1375
|
}
|
|
1210
1376
|
if (model.settingsOpen) {
|
|
1211
1377
|
const settingsLayer = layerStack.find((layer) => layer.kind === 'settings');
|
|
1212
|
-
const settingsOverlay = renderSettingsDrawer(model, options, pagesById, settingsLayer?.title);
|
|
1378
|
+
const settingsOverlay = renderSettingsDrawer(model, options, pagesById, resolvedShellThemes, settingsLayer?.title, themedFrameCtx);
|
|
1213
1379
|
if (settingsOverlay != null) {
|
|
1214
1380
|
overlays.push(settingsOverlay);
|
|
1215
1381
|
}
|
|
1216
1382
|
}
|
|
1217
1383
|
if (model.notificationCenterOpen) {
|
|
1218
1384
|
const notificationLayer = layerStack.find((layer) => layer.kind === 'notification-center');
|
|
1219
|
-
const notificationCenterOverlay = renderNotificationCenterDrawer(model, options, pagesById, notificationLayer?.title);
|
|
1385
|
+
const notificationCenterOverlay = renderNotificationCenterDrawer(model, options, pagesById, notificationLayer?.title, themedFrameCtx);
|
|
1220
1386
|
if (notificationCenterOverlay != null) {
|
|
1221
1387
|
overlays.push(notificationCenterOverlay);
|
|
1222
1388
|
}
|
|
1223
1389
|
}
|
|
1224
1390
|
if (model.helpOpen) {
|
|
1225
|
-
const helpOverlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById);
|
|
1391
|
+
const helpOverlay = renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById, resolvedShellThemes);
|
|
1226
1392
|
overlays.push(modal({
|
|
1227
1393
|
title: activeLayer.kind === 'help'
|
|
1228
1394
|
? (activeLayer.title ?? frameMessage(options.i18n, 'help.title', 'Keyboard Help'))
|
|
@@ -1231,6 +1397,9 @@ export function createFramedApp(options) {
|
|
|
1231
1397
|
hint: typeof activeLayer.hintSource === 'string'
|
|
1232
1398
|
? activeLayer.hintSource
|
|
1233
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,
|
|
1234
1403
|
width: helpOverlay.body.width + 4,
|
|
1235
1404
|
screenWidth: model.columns,
|
|
1236
1405
|
screenHeight: model.rows,
|
|
@@ -1238,7 +1407,11 @@ export function createFramedApp(options) {
|
|
|
1238
1407
|
}
|
|
1239
1408
|
if (model.commandPalette != null) {
|
|
1240
1409
|
const paletteWidth = Math.max(20, Math.min(80, model.columns - 4));
|
|
1241
|
-
const paletteBody =
|
|
1410
|
+
const paletteBody = commandPaletteSurface(model.commandPalette, {
|
|
1411
|
+
width: Math.max(16, paletteWidth - 4),
|
|
1412
|
+
ctx: themedFrameCtx,
|
|
1413
|
+
showScrollbar: false,
|
|
1414
|
+
});
|
|
1242
1415
|
const paletteLayer = activeLayer.kind === 'search' || activeLayer.kind === 'command-palette'
|
|
1243
1416
|
? activeLayer
|
|
1244
1417
|
: undefined;
|
|
@@ -1248,13 +1421,16 @@ export function createFramedApp(options) {
|
|
|
1248
1421
|
hint: typeof paletteLayer?.hintSource === 'string'
|
|
1249
1422
|
? paletteLayer.hintSource
|
|
1250
1423
|
: frameMessage(options.i18n, 'palette.hint', 'Enter select • Esc close'),
|
|
1424
|
+
borderToken: themedFrameCtx?.border('primary'),
|
|
1425
|
+
bgToken: themedFrameCtx?.surface('elevated'),
|
|
1426
|
+
ctx: themedFrameCtx,
|
|
1251
1427
|
width: paletteWidth,
|
|
1252
1428
|
screenWidth: model.columns,
|
|
1253
1429
|
screenHeight: model.rows,
|
|
1254
1430
|
}));
|
|
1255
1431
|
}
|
|
1256
1432
|
if (model.quitConfirmOpen) {
|
|
1257
|
-
overlays.push(renderShellQuitOverlay(model.columns, model.rows, options.i18n));
|
|
1433
|
+
overlays.push(renderShellQuitOverlay(model.columns, model.rows, options.i18n, themedFrameCtx));
|
|
1258
1434
|
}
|
|
1259
1435
|
if (bodySurface != null && bodyRect.width > 0 && bodyRect.height > 0) {
|
|
1260
1436
|
frameSurface.blit(bodySurface, bodyRect.col, bodyRect.row);
|
|
@@ -1283,11 +1459,11 @@ function focusPane(model, paneId) {
|
|
|
1283
1459
|
function resolveBodyRect(model, options) {
|
|
1284
1460
|
return frameBodyRect(model.columns, model.rows, options.bodyTopRows ?? 1, options.bodyBottomRows ?? 1);
|
|
1285
1461
|
}
|
|
1286
|
-
function renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById) {
|
|
1462
|
+
function renderHelpOverlay(model, activePage, frameKeys, paletteKeys, options, pagesById, shellThemes) {
|
|
1287
1463
|
const activePageModel = model.pageModels[model.activePageId];
|
|
1288
1464
|
const activeInputArea = findInputAreaByPaneId(resolveInputAreas(activePage, activePageModel), model.focusedPaneByPage[model.activePageId]);
|
|
1289
1465
|
const modalKeyMap = activePage.modalKeyMap?.(activePageModel);
|
|
1290
|
-
const settings = resolveFrameSettings(model, options, pagesById);
|
|
1466
|
+
const settings = resolveFrameSettings(model, options, pagesById, shellThemes);
|
|
1291
1467
|
const notificationCenter = resolveFrameNotificationCenter(model, options, pagesById);
|
|
1292
1468
|
const workspaceHintSource = options.helpLineSource?.({
|
|
1293
1469
|
model,
|
|
@@ -1380,13 +1556,15 @@ function isHelpScrollAction(action) {
|
|
|
1380
1556
|
|| action.type === 'top'
|
|
1381
1557
|
|| action.type === 'bottom';
|
|
1382
1558
|
}
|
|
1383
|
-
|
|
1559
|
+
const FRAME_SHELL_THEME_ROW_ID = '__frame-shell-theme__';
|
|
1560
|
+
function resolveFrameSettings(model, options, pagesById, shellThemes) {
|
|
1384
1561
|
const activePage = pagesById.get(model.activePageId);
|
|
1385
|
-
|
|
1562
|
+
const provided = options.settings?.({
|
|
1386
1563
|
model,
|
|
1387
1564
|
activePage,
|
|
1388
1565
|
pageModel: model.pageModels[model.activePageId],
|
|
1389
1566
|
});
|
|
1567
|
+
return mergeShellThemeSettings(provided, shellThemes, model.activeShellThemeId, options.i18n);
|
|
1390
1568
|
}
|
|
1391
1569
|
function resolveFrameNotificationCenter(model, options, pagesById) {
|
|
1392
1570
|
const activePage = pagesById.get(model.activePageId);
|
|
@@ -1421,8 +1599,8 @@ function resolveFrameNotificationCenter(model, options, pagesById) {
|
|
|
1421
1599
|
activeFilter: model.runtimeNotificationHistoryFilter,
|
|
1422
1600
|
};
|
|
1423
1601
|
}
|
|
1424
|
-
function resolveSettingsLayout(model, options, pagesById) {
|
|
1425
|
-
const settings = resolveFrameSettings(model, options, pagesById);
|
|
1602
|
+
function resolveSettingsLayout(model, options, pagesById, shellThemes) {
|
|
1603
|
+
const settings = resolveFrameSettings(model, options, pagesById, shellThemes);
|
|
1426
1604
|
if (settings == null)
|
|
1427
1605
|
return undefined;
|
|
1428
1606
|
const sections = settings.sections.filter((section) => section.rows.length > 0);
|
|
@@ -1451,6 +1629,7 @@ function resolveSettingsLayout(model, options, pagesById) {
|
|
|
1451
1629
|
line,
|
|
1452
1630
|
height: rowLayout.height,
|
|
1453
1631
|
row,
|
|
1632
|
+
behavior: row.id === FRAME_SHELL_THEME_ROW_ID ? 'cycle-shell-theme' : undefined,
|
|
1454
1633
|
});
|
|
1455
1634
|
line += rowLayout.height;
|
|
1456
1635
|
if (rowIndex < section.rows.length - 1) {
|
|
@@ -1481,7 +1660,7 @@ function resolveNotificationCenterDrawerWidth(columns) {
|
|
|
1481
1660
|
const boundedColumns = Math.max(28, columns);
|
|
1482
1661
|
return Math.min(Math.max(32, Math.floor(boundedColumns * 0.34)), Math.max(32, boundedColumns - 4), 52);
|
|
1483
1662
|
}
|
|
1484
|
-
function resolveNotificationCenterLayout(model, options, pagesById) {
|
|
1663
|
+
function resolveNotificationCenterLayout(model, options, pagesById, ctx) {
|
|
1485
1664
|
const center = resolveFrameNotificationCenter(model, options, pagesById);
|
|
1486
1665
|
if (center == null)
|
|
1487
1666
|
return undefined;
|
|
@@ -1489,7 +1668,7 @@ function resolveNotificationCenterLayout(model, options, pagesById) {
|
|
|
1489
1668
|
const anchor = frameEndAnchor(options.i18n);
|
|
1490
1669
|
const startCol = anchor === 'left' ? 0 : Math.max(0, model.columns - drawerWidth);
|
|
1491
1670
|
const contentWidth = Math.max(18, drawerWidth - 4);
|
|
1492
|
-
const content = renderNotificationCenterSurface(center, contentWidth, options.i18n);
|
|
1671
|
+
const content = renderNotificationCenterSurface(center, contentWidth, options.i18n, ctx);
|
|
1493
1672
|
const contentHeight = Math.max(1, model.rows - 2);
|
|
1494
1673
|
const pagerState = createPagerStateForSurface(content, {
|
|
1495
1674
|
width: contentWidth,
|
|
@@ -1579,12 +1758,12 @@ function cycleNotificationCenterFilter(model, layout) {
|
|
|
1579
1758
|
notificationCenterScrollY: 0,
|
|
1580
1759
|
}, []];
|
|
1581
1760
|
}
|
|
1582
|
-
function renderSettingsDrawer(model, options, pagesById, titleOverride) {
|
|
1583
|
-
const layout = resolveSettingsLayout(model, options, pagesById);
|
|
1761
|
+
function renderSettingsDrawer(model, options, pagesById, shellThemes, titleOverride, ctx) {
|
|
1762
|
+
const layout = resolveSettingsLayout(model, options, pagesById, shellThemes);
|
|
1584
1763
|
if (layout == null)
|
|
1585
1764
|
return undefined;
|
|
1586
1765
|
const scrollY = clampSettingsScroll(model, layout);
|
|
1587
|
-
const content = renderSettingsSurface(layout, model);
|
|
1766
|
+
const content = renderSettingsSurface(layout, model, ctx);
|
|
1588
1767
|
const pagerState = createPagerStateForSurface(content, {
|
|
1589
1768
|
width: layout.contentWidth,
|
|
1590
1769
|
height: layout.contentHeight,
|
|
@@ -1606,14 +1785,14 @@ function renderSettingsDrawer(model, options, pagesById, titleOverride) {
|
|
|
1606
1785
|
content: body,
|
|
1607
1786
|
borderToken: layout.settings.borderToken,
|
|
1608
1787
|
bgToken: layout.settings.bgToken,
|
|
1609
|
-
ctx
|
|
1788
|
+
ctx,
|
|
1610
1789
|
width: layout.drawerWidth,
|
|
1611
1790
|
screenWidth: model.columns,
|
|
1612
1791
|
screenHeight: model.rows,
|
|
1613
1792
|
});
|
|
1614
1793
|
}
|
|
1615
|
-
function renderNotificationCenterDrawer(model, options, pagesById, titleOverride) {
|
|
1616
|
-
const layout = resolveNotificationCenterLayout(model, options, pagesById);
|
|
1794
|
+
function renderNotificationCenterDrawer(model, options, pagesById, titleOverride, ctx) {
|
|
1795
|
+
const layout = resolveNotificationCenterLayout(model, options, pagesById, ctx);
|
|
1617
1796
|
if (layout == null)
|
|
1618
1797
|
return undefined;
|
|
1619
1798
|
const pagerState = createPagerStateForSurface(layout.content, {
|
|
@@ -1635,17 +1814,20 @@ function renderNotificationCenterDrawer(model, options, pagesById, titleOverride
|
|
|
1635
1814
|
anchor: layout.anchor,
|
|
1636
1815
|
title: titleOverride ?? `${layout.center.title} • ${frameNotificationFilterLabel(options.i18n, layout.center.activeFilter)}`,
|
|
1637
1816
|
content: body,
|
|
1817
|
+
borderToken: ctx?.border('primary'),
|
|
1818
|
+
bgToken: ctx?.surface('elevated'),
|
|
1819
|
+
ctx,
|
|
1638
1820
|
width: layout.drawerWidth,
|
|
1639
1821
|
screenWidth: model.columns,
|
|
1640
1822
|
screenHeight: model.rows,
|
|
1641
1823
|
});
|
|
1642
1824
|
}
|
|
1643
|
-
function renderSettingsSurface(layout, model) {
|
|
1825
|
+
function renderSettingsSurface(layout, model, ctx) {
|
|
1644
1826
|
const focusedIndex = clampSettingsFocus(model, layout);
|
|
1645
1827
|
return preferenceListSurface(layout.preferenceSections, {
|
|
1646
1828
|
width: layout.contentWidth,
|
|
1647
1829
|
selectedRowId: layout.rows[focusedIndex]?.row.id,
|
|
1648
|
-
ctx
|
|
1830
|
+
ctx,
|
|
1649
1831
|
theme: layout.settings.listTheme,
|
|
1650
1832
|
});
|
|
1651
1833
|
}
|
|
@@ -1675,8 +1857,7 @@ function resolveNotificationFooterCue(model, options, pagesById) {
|
|
|
1675
1857
|
const archivedCount = countNotificationHistory(center.state, center.activeFilter);
|
|
1676
1858
|
return frameNotificationCue(options.i18n, liveCount, archivedCount);
|
|
1677
1859
|
}
|
|
1678
|
-
function renderNotificationCenterSurface(center, width, i18n) {
|
|
1679
|
-
const ctx = resolveSafeCtx() ?? undefined;
|
|
1860
|
+
function renderNotificationCenterSurface(center, width, i18n, ctx) {
|
|
1680
1861
|
const rows = [
|
|
1681
1862
|
insetLineSurface(`Live: ${center.state.items.length} • Archived: ${center.state.history.length}`, width),
|
|
1682
1863
|
insetLineSurface(`Filter: ${frameNotificationFilterLabel(i18n, center.activeFilter)}`, width),
|