@materialwebunofficial/antigravity-themes 1.0.0 → 1.0.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/README.md +57 -24
- package/bin/cli.mjs +107 -35
- package/lib/autostart.mjs +22 -2
- package/lib/paths.mjs +7 -0
- package/package.json +2 -2
- package/src/code-tools.js +10 -4
- package/src/context-card.js +17 -11
- package/src/theme-host.js +241 -46
- package/themes/index.json +12 -6
- package/themes/matte.css +210 -12
- package/themes/md3e.css +221 -27
- package/themes/nordic.css +370 -0
- package/themes/paper.css +414 -0
package/src/theme-host.js
CHANGED
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
//
|
|
1
|
+
// AGY theme host: applies one theme from a bundle, remembers the choice, and
|
|
2
2
|
// adds a "Theme" menu to the title bar (Ctrl+Shift+F12 cycles themes; not
|
|
3
|
-
// Ctrl+Alt+<letter>: Windows reads Ctrl+Alt as AltGr,
|
|
4
|
-
//
|
|
3
|
+
// Ctrl+Alt+<letter>: Windows reads Ctrl+Alt as AltGr, and on the Turkish Q
|
|
4
|
+
// layout AltGr+T types "₺"). In MD3E the title bar's menus and Theme fold
|
|
5
5
|
// into one app menu button (the package's <md-menu>).
|
|
6
6
|
//
|
|
7
|
-
// Context-free on purpose: it only touches the DOM and document.cookie
|
|
8
|
-
//
|
|
7
|
+
// Context-free on purpose: it only touches the DOM and document.cookie, so it
|
|
8
|
+
// runs the same when inject.mjs evaluates it in the page and when a preload
|
|
9
|
+
// calls it from Electron's isolated world.
|
|
9
10
|
function agyThemeHost(bundle) {
|
|
10
11
|
// Bump when this file's code changes. A same-version host only takes the
|
|
11
12
|
// new bundle; an older one would keep running its old code through
|
|
12
13
|
// update(), so it is disposed and replaced (same task: no flash).
|
|
13
|
-
const HOST_VERSION =
|
|
14
|
+
const HOST_VERSION = 20; // also bump when a module it starts (context-card, turn-tokens, loading-/progress-indicator, code-tools) changes: the host starts them once
|
|
14
15
|
const existing = window.__agyThemeHost;
|
|
15
16
|
if (existing?.version === HOST_VERSION) return existing.update(bundle);
|
|
16
17
|
existing?.dispose();
|
|
17
18
|
|
|
18
19
|
const COOKIE = 'agy-theme';
|
|
19
|
-
const readChoice = () =>
|
|
20
|
+
const readChoice = () => {
|
|
21
|
+
try {
|
|
22
|
+
return (document.cookie.match(/(?:^|;\s*)agy-theme=([^;]+)/) || [])[1];
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
20
27
|
const saveChoice = (key) => {
|
|
21
|
-
|
|
28
|
+
try {
|
|
29
|
+
document.cookie = `${COOKIE}=${key}; Max-Age=31536000; Path=/; SameSite=Strict; Secure`;
|
|
30
|
+
} catch {}
|
|
22
31
|
};
|
|
23
32
|
|
|
24
33
|
let options = new Map();
|
|
@@ -88,21 +97,29 @@ function agyThemeHost(bundle) {
|
|
|
88
97
|
ensureFonts();
|
|
89
98
|
watchMode();
|
|
90
99
|
syncMode();
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
if (current.theme === 'antigravity') {
|
|
101
|
+
root.removeAttribute('data-agy-theme');
|
|
102
|
+
root.removeAttribute('data-agy-seed');
|
|
103
|
+
const style = document.getElementById('agy-theme-css');
|
|
104
|
+
if (style) style.textContent = '';
|
|
105
|
+
} else {
|
|
106
|
+
root.setAttribute('data-agy-theme', current.theme);
|
|
107
|
+
if (current.seed) root.setAttribute('data-agy-seed', current.seed);
|
|
108
|
+
else root.removeAttribute('data-agy-seed');
|
|
109
|
+
let style = document.getElementById('agy-theme-css');
|
|
110
|
+
if (!style) {
|
|
111
|
+
style = document.createElement('style');
|
|
112
|
+
style.id = 'agy-theme-css';
|
|
113
|
+
}
|
|
114
|
+
const css = bundle.themes[current.theme] || '';
|
|
115
|
+
if (style.textContent !== css) style.textContent = css;
|
|
116
|
+
// Last in <head> so equal-specificity ties go to the theme
|
|
117
|
+
const parent = document.head || root;
|
|
118
|
+
if (style.parentNode !== parent || style !== parent.lastElementChild) parent.appendChild(style);
|
|
98
119
|
}
|
|
99
|
-
const css = bundle.themes[current.theme] || '';
|
|
100
|
-
if (style.textContent !== css) style.textContent = css;
|
|
101
|
-
// Last in <head> so equal-specificity ties go to the theme
|
|
102
|
-
const parent = document.head || root;
|
|
103
|
-
if (style.parentNode !== parent || style !== parent.lastElementChild) parent.appendChild(style);
|
|
104
120
|
announceTheme();
|
|
105
121
|
renderMenu();
|
|
122
|
+
if (appMenuBuilt) buildAppMenu(false);
|
|
106
123
|
if (current.theme !== 'md3e') closeAppMenu();
|
|
107
124
|
// Themes change the title bar's padding and font: re-anchor the menu
|
|
108
125
|
requestAnimationFrame(() => { position(); syncTitleBarOverlay(); });
|
|
@@ -186,15 +203,25 @@ function agyThemeHost(bundle) {
|
|
|
186
203
|
box-shadow: 0 16px 40px -12px rgb(0 0 0 / 0.75);
|
|
187
204
|
}
|
|
188
205
|
.menu[hidden] { display: none; }
|
|
189
|
-
[role="menuitemradio"] {
|
|
206
|
+
[role="menuitemradio"], .menu-sub-trigger {
|
|
190
207
|
display: flex; align-items: center; gap: 10px; height: 32px; padding: 0 10px;
|
|
191
208
|
border-radius: 8px; font: inherit; color: inherit; cursor: default; outline: none;
|
|
192
209
|
}
|
|
193
|
-
[role="menuitemradio"]:hover, [role="menuitemradio"]:focus-visible
|
|
210
|
+
[role="menuitemradio"]:hover, [role="menuitemradio"]:focus-visible,
|
|
211
|
+
.menu-sub-trigger:hover, .menu-sub-wrapper:hover .menu-sub-trigger { background: var(--secondary, #333); }
|
|
194
212
|
.swatch { width: 12px; height: 12px; border-radius: 999px; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.2); }
|
|
195
213
|
.name { flex: 1; }
|
|
196
214
|
.check { visibility: hidden; }
|
|
197
215
|
[aria-checked="true"] .check { visibility: visible; }
|
|
216
|
+
.chevron { color: var(--muted-foreground, #999); font-size: 13px; margin-left: auto; }
|
|
217
|
+
.menu-sub-wrapper { position: relative; }
|
|
218
|
+
.menu-sub-flyout {
|
|
219
|
+
display: none; position: absolute; top: -6px; left: calc(100% + 4px); min-width: 170px; padding: 6px;
|
|
220
|
+
border: 1px solid var(--border, #333); border-radius: 12px;
|
|
221
|
+
background: var(--card, #1c1c1f); color: var(--foreground, #eee);
|
|
222
|
+
box-shadow: 0 16px 40px -12px rgb(0 0 0 / 0.75);
|
|
223
|
+
}
|
|
224
|
+
.menu-sub-wrapper:hover .menu-sub-flyout { display: block; }
|
|
198
225
|
.hint { padding: 6px 10px 2px; color: var(--muted-foreground, #999); font-size: 11px; }
|
|
199
226
|
|
|
200
227
|
/* MD3E: the md-menu anatomy of md3e.css section 50 (one
|
|
@@ -241,10 +268,13 @@ function agyThemeHost(bundle) {
|
|
|
241
268
|
|
|
242
269
|
/* MD3E app menu: an xsmall M3 icon button (32px, 20px icon); the
|
|
243
270
|
<md-menu> it opens draws itself */
|
|
244
|
-
.appmenu { display: none; }
|
|
271
|
+
.appmenu { display: none; min-width: 220px; }
|
|
245
272
|
:host-context([data-agy-theme="md3e"][data-agy-appmenu]) .trigger,
|
|
246
273
|
:host-context([data-agy-theme="md3e"][data-agy-appmenu]) .menu { display: none !important; }
|
|
247
274
|
:host-context([data-agy-theme="md3e"][data-agy-appmenu]) .appmenu { display: block; }
|
|
275
|
+
.appmenu md-menu {
|
|
276
|
+
min-width: 220px;
|
|
277
|
+
}
|
|
248
278
|
.appmenu-trigger {
|
|
249
279
|
display: grid; place-items: center; width: 32px; height: 32px; padding: 0; border: 0;
|
|
250
280
|
border-radius: 9999px; background: transparent; color: var(--md-sys-color-on-surface-variant);
|
|
@@ -266,18 +296,27 @@ function agyThemeHost(bundle) {
|
|
|
266
296
|
trigger.addEventListener('click', () => (menu.hidden ? openMenu() : closeMenu()));
|
|
267
297
|
menu.addEventListener('click', (e) => {
|
|
268
298
|
const item = e.target.closest('[role="menuitemradio"]');
|
|
269
|
-
if (item) { select(item.dataset.key); closeMenu(); }
|
|
299
|
+
if (item) { select(item.dataset.key); closeMenu(); return; }
|
|
300
|
+
const subTrig = e.target.closest('.menu-sub-trigger');
|
|
301
|
+
if (subTrig) {
|
|
302
|
+
const activeSeed = [...options.values()].find((o) => o.theme === 'md3e' && o.key === current?.key);
|
|
303
|
+
select(activeSeed ? activeSeed.key : 'md3e-teal');
|
|
304
|
+
closeMenu();
|
|
305
|
+
}
|
|
270
306
|
});
|
|
271
307
|
menu.addEventListener('keydown', onMenuKey);
|
|
272
308
|
document.body.appendChild(hostEl);
|
|
273
309
|
renderMenu();
|
|
310
|
+
if (appMenuBuilt) buildAppMenu(false);
|
|
274
311
|
position();
|
|
275
312
|
}
|
|
276
313
|
|
|
277
314
|
function renderMenu() {
|
|
278
315
|
if (!menu) return;
|
|
279
316
|
menu.innerHTML = '';
|
|
317
|
+
// Standalone options
|
|
280
318
|
for (const o of options.values()) {
|
|
319
|
+
if (o.theme === 'md3e') continue;
|
|
281
320
|
const item = document.createElement('div');
|
|
282
321
|
item.setAttribute('role', 'menuitemradio');
|
|
283
322
|
item.setAttribute('aria-checked', String(o.key === current?.key));
|
|
@@ -288,6 +327,38 @@ function agyThemeHost(bundle) {
|
|
|
288
327
|
item.querySelector('.name').textContent = o.name;
|
|
289
328
|
menu.appendChild(item);
|
|
290
329
|
}
|
|
330
|
+
// Group MD3E into single entry with submenu flyout
|
|
331
|
+
const md3eOptions = [...options.values()].filter((o) => o.theme === 'md3e');
|
|
332
|
+
if (md3eOptions.length) {
|
|
333
|
+
const isMd3eActive = current?.theme === 'md3e';
|
|
334
|
+
const subWrapper = document.createElement('div');
|
|
335
|
+
subWrapper.className = 'menu-sub-wrapper';
|
|
336
|
+
const subTrigger = document.createElement('div');
|
|
337
|
+
subTrigger.className = 'menu-sub-trigger';
|
|
338
|
+
subTrigger.setAttribute('role', 'button');
|
|
339
|
+
subTrigger.tabIndex = -1;
|
|
340
|
+
subTrigger.innerHTML = '<span class="swatch" style="background:#a5faf9"></span><span class="name">Material 3 Expressive</span><span class="check">✓</span><span class="chevron">›</span>';
|
|
341
|
+
if (!isMd3eActive) subTrigger.querySelector('.check').style.visibility = 'hidden';
|
|
342
|
+
else subTrigger.querySelector('.check').style.visibility = 'visible';
|
|
343
|
+
subWrapper.appendChild(subTrigger);
|
|
344
|
+
|
|
345
|
+
const flyout = document.createElement('div');
|
|
346
|
+
flyout.className = 'menu-sub-flyout';
|
|
347
|
+
flyout.setAttribute('role', 'menu');
|
|
348
|
+
for (const o of md3eOptions) {
|
|
349
|
+
const item = document.createElement('div');
|
|
350
|
+
item.setAttribute('role', 'menuitemradio');
|
|
351
|
+
item.setAttribute('aria-checked', String(o.key === current?.key));
|
|
352
|
+
item.tabIndex = -1;
|
|
353
|
+
item.dataset.key = o.key;
|
|
354
|
+
item.innerHTML = '<span class="swatch"></span><span class="name"></span><span class="check">✓</span>';
|
|
355
|
+
item.querySelector('.swatch').style.background = o.swatch || 'transparent';
|
|
356
|
+
item.querySelector('.name').textContent = o.name;
|
|
357
|
+
flyout.appendChild(item);
|
|
358
|
+
}
|
|
359
|
+
subWrapper.appendChild(flyout);
|
|
360
|
+
menu.appendChild(subWrapper);
|
|
361
|
+
}
|
|
291
362
|
const hint = document.createElement('div');
|
|
292
363
|
hint.className = 'hint';
|
|
293
364
|
hint.textContent = 'Ctrl+Shift+F12: next theme';
|
|
@@ -344,8 +415,25 @@ function agyThemeHost(bundle) {
|
|
|
344
415
|
return sub;
|
|
345
416
|
}
|
|
346
417
|
|
|
418
|
+
function patchComponentSheets() {
|
|
419
|
+
try {
|
|
420
|
+
const dummyItem = document.createElement('md-menu-item');
|
|
421
|
+
if (dummyItem.shadowRoot?.adoptedStyleSheets?.length) {
|
|
422
|
+
const s = dummyItem.shadowRoot.adoptedStyleSheets[0];
|
|
423
|
+
s.insertRule('.text { white-space: nowrap !important; overflow-wrap: normal !important; max-width: none !important; }', 0);
|
|
424
|
+
s.insertRule('.item { min-width: 220px !important; max-width: 320px !important; }', 0);
|
|
425
|
+
}
|
|
426
|
+
const dummyMenu = document.createElement('md-menu');
|
|
427
|
+
if (dummyMenu.shadowRoot?.adoptedStyleSheets?.length) {
|
|
428
|
+
const ms = dummyMenu.shadowRoot.adoptedStyleSheets[0];
|
|
429
|
+
ms.insertRule('.menu { min-width: 220px !important; max-width: 320px !important; will-change: transform, opacity !important; }', 0);
|
|
430
|
+
}
|
|
431
|
+
} catch {}
|
|
432
|
+
}
|
|
433
|
+
|
|
347
434
|
function mountAppMenu() {
|
|
348
435
|
if (!customElements.get('md-menu')) return;
|
|
436
|
+
patchComponentSheets();
|
|
349
437
|
appMenu = document.createElement('md-menu');
|
|
350
438
|
appMenu.className = 'appmenu';
|
|
351
439
|
appMenu.setAttribute('label', 'Application menu');
|
|
@@ -356,13 +444,9 @@ function agyThemeHost(bundle) {
|
|
|
356
444
|
appTrigger.title = 'Menu';
|
|
357
445
|
appTrigger.appendChild(glyph('menu'));
|
|
358
446
|
appMenu.appendChild(appTrigger);
|
|
359
|
-
//
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
appTrigger.addEventListener('pointerenter', buildAppMenu);
|
|
363
|
-
appTrigger.addEventListener('focus', buildAppMenu);
|
|
364
|
-
appTrigger.addEventListener('click', buildAppMenu);
|
|
365
|
-
appTrigger.addEventListener('keydown', (e) => { if (e.key === 'ArrowDown' || e.key === 'ArrowUp') buildAppMenu(); });
|
|
447
|
+
// these run before the menu's own handlers on its trigger slot
|
|
448
|
+
appTrigger.addEventListener('click', () => buildAppMenu(false));
|
|
449
|
+
appTrigger.addEventListener('keydown', (e) => { if (e.key === 'ArrowDown' || e.key === 'ArrowUp') buildAppMenu(false); });
|
|
366
450
|
appMenu.addEventListener('select', onAppMenuSelect);
|
|
367
451
|
shadow.appendChild(appMenu);
|
|
368
452
|
document.documentElement.setAttribute('data-agy-appmenu', '');
|
|
@@ -381,15 +465,55 @@ function agyThemeHost(bundle) {
|
|
|
381
465
|
return menus;
|
|
382
466
|
}
|
|
383
467
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
468
|
+
function fixItemStyle(el) {
|
|
469
|
+
if (!el || !el.shadowRoot) return;
|
|
470
|
+
try {
|
|
471
|
+
let s = el.shadowRoot.querySelector('#agy-item-fix');
|
|
472
|
+
if (!s) {
|
|
473
|
+
s = document.createElement('style');
|
|
474
|
+
s.id = 'agy-item-fix';
|
|
475
|
+
s.textContent = `
|
|
476
|
+
.text { white-space: nowrap !important; overflow-wrap: normal !important; max-width: none !important; }
|
|
477
|
+
.item { min-width: 220px !important; max-width: 320px !important; }
|
|
478
|
+
`;
|
|
479
|
+
el.shadowRoot.appendChild(s);
|
|
480
|
+
}
|
|
481
|
+
} catch {}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function fixMenuStyle(menu) {
|
|
485
|
+
if (!menu || !menu.shadowRoot) return;
|
|
486
|
+
try {
|
|
487
|
+
let s = menu.shadowRoot.querySelector('#agy-menu-fix');
|
|
488
|
+
if (!s) {
|
|
489
|
+
s = document.createElement('style');
|
|
490
|
+
s.id = 'agy-menu-fix';
|
|
491
|
+
s.textContent = `
|
|
492
|
+
.menu { min-width: 220px !important; max-width: 320px !important; will-change: transform, opacity !important; }
|
|
493
|
+
`;
|
|
494
|
+
menu.shadowRoot.appendChild(s);
|
|
495
|
+
}
|
|
496
|
+
} catch {}
|
|
497
|
+
for (const it of menu.querySelectorAll('md-menu-item')) fixItemStyle(it);
|
|
498
|
+
for (const sub of menu.querySelectorAll('md-menu')) fixMenuStyle(sub);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
let appMenuBuilt = false;
|
|
502
|
+
function buildAppMenu(force = false) {
|
|
503
|
+
const forced = force === true;
|
|
504
|
+
if (!appMenu || (!forced && appMenu.open)) return;
|
|
505
|
+
if (appMenuBuilt && !forced) {
|
|
506
|
+
window.__buildAppMenuHitCache = (window.__buildAppMenuHitCache || 0) + 1;
|
|
507
|
+
for (const item of appMenu.querySelectorAll('md-menu-item[value^="theme:"]')) {
|
|
508
|
+
const val = item.getAttribute('value') || '';
|
|
509
|
+
item.selected = (val === `theme:${current?.key}`);
|
|
510
|
+
}
|
|
511
|
+
fixMenuStyle(appMenu);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
window.__buildAppMenuFullBuild = (window.__buildAppMenuFullBuild || 0) + 1;
|
|
515
|
+
appMenus = readAppMenus();
|
|
516
|
+
if (!appMenus.length && !forced) return;
|
|
393
517
|
const items = appMenus.map((m, i) => {
|
|
394
518
|
const top = menuItem(m.title);
|
|
395
519
|
top.append(glyph(MENU_GLYPHS[m.title] || 'info', 'start'), submenu(m.title, m.options.map((o, j) => menuItem(String(o.label), {
|
|
@@ -400,23 +524,46 @@ function agyThemeHost(bundle) {
|
|
|
400
524
|
}))));
|
|
401
525
|
return top;
|
|
402
526
|
});
|
|
403
|
-
// Theme:
|
|
527
|
+
// Theme: standalone themes, MD3E submenu, and Next theme
|
|
404
528
|
const choices = document.createElement('md-menu-group');
|
|
405
529
|
for (const o of options.values()) {
|
|
530
|
+
if (o.theme === 'md3e') continue;
|
|
406
531
|
const item = menuItem(o.name, { value: `theme:${o.key}`, 'selection-mode': 'single', selected: o.key === current?.key, 'selected-icon': 'check' });
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
532
|
+
if (o.swatch && o.swatch !== 'transparent') {
|
|
533
|
+
const swatch = document.createElement('span');
|
|
534
|
+
swatch.className = 'swatch';
|
|
535
|
+
swatch.slot = 'end';
|
|
536
|
+
swatch.style.background = o.swatch;
|
|
537
|
+
item.appendChild(swatch);
|
|
538
|
+
}
|
|
412
539
|
choices.appendChild(item);
|
|
413
540
|
}
|
|
541
|
+
const md3eItems = [];
|
|
542
|
+
for (const o of options.values()) {
|
|
543
|
+
if (o.theme !== 'md3e') continue;
|
|
544
|
+
const item = menuItem(o.name, { value: `theme:${o.key}`, 'selection-mode': 'single', selected: o.key === current?.key, 'selected-icon': 'check' });
|
|
545
|
+
if (o.swatch) {
|
|
546
|
+
const swatch = document.createElement('span');
|
|
547
|
+
swatch.className = 'swatch';
|
|
548
|
+
swatch.slot = 'end';
|
|
549
|
+
swatch.style.background = o.swatch;
|
|
550
|
+
item.appendChild(swatch);
|
|
551
|
+
}
|
|
552
|
+
md3eItems.push(item);
|
|
553
|
+
}
|
|
554
|
+
if (md3eItems.length) {
|
|
555
|
+
const md3eMenu = menuItem('Material 3 Expressive');
|
|
556
|
+
md3eMenu.append(glyph('palette', 'start'), submenu('Material 3 Expressive', md3eItems));
|
|
557
|
+
choices.appendChild(md3eMenu);
|
|
558
|
+
}
|
|
414
559
|
const cycle = document.createElement('md-menu-group');
|
|
415
560
|
cycle.appendChild(menuItem('Next theme', { value: 'theme:next', 'trailing-text': 'Ctrl+Shift+F12' }));
|
|
416
561
|
const theme = menuItem('Theme');
|
|
417
562
|
theme.append(glyph('palette', 'start'), submenu('Theme', [choices, cycle]));
|
|
418
563
|
for (const el of [...appMenu.children]) if (el !== appTrigger) el.remove();
|
|
419
564
|
appMenu.append(...items, theme);
|
|
565
|
+
appMenuBuilt = true;
|
|
566
|
+
fixMenuStyle(appMenu);
|
|
420
567
|
}
|
|
421
568
|
|
|
422
569
|
function onAppMenuSelect(e) {
|
|
@@ -642,6 +789,48 @@ function agyThemeHost(bundle) {
|
|
|
642
789
|
window.addEventListener('focus', syncTitleBarOverlay);
|
|
643
790
|
document.fonts?.addEventListener('loadingdone', position);
|
|
644
791
|
|
|
792
|
+
// ---- Virtual list layout guard --------------------------------------------
|
|
793
|
+
// Antigravity virtualizes the sidebar and auxiliary panels with TanStack
|
|
794
|
+
// Virtual. On mounting long lists (e.g. 299 diffs in Review or 95 sidebar
|
|
795
|
+
// items), TanStack Virtual synchronously reads offsetHeight on every
|
|
796
|
+
// [data-index] element while dirtying container styles between each item.
|
|
797
|
+
// In a large conversation, each forced reflow costs 80-100ms, causing a 2s+
|
|
798
|
+
// freeze upon entry. This guard serves known fixed heights or cached values
|
|
799
|
+
// for virtual rows, preventing layout thrashing while letting ResizeObserver
|
|
800
|
+
// handle real dynamic size changes asynchronously on idle frames.
|
|
801
|
+
const origOffsetHeight = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'offsetHeight')?.get;
|
|
802
|
+
const virtualHeightCache = new WeakMap();
|
|
803
|
+
if (origOffsetHeight) {
|
|
804
|
+
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
|
|
805
|
+
get() {
|
|
806
|
+
if (this.hasAttribute('data-index')) {
|
|
807
|
+
const cached = virtualHeightCache.get(this);
|
|
808
|
+
if (cached !== undefined) return cached;
|
|
809
|
+
if (this.firstElementChild?.classList.contains('sticky')) {
|
|
810
|
+
virtualHeightCache.set(this, 33);
|
|
811
|
+
return 33;
|
|
812
|
+
}
|
|
813
|
+
if (this.classList.contains('bg-sidebar') || this.querySelector('h2')) {
|
|
814
|
+
virtualHeightCache.set(this, 24);
|
|
815
|
+
return 24;
|
|
816
|
+
}
|
|
817
|
+
if (this.querySelector('.agy-sidebar-row') || this.classList.contains('pb-[1px]')) {
|
|
818
|
+
virtualHeightCache.set(this, 33);
|
|
819
|
+
return 33;
|
|
820
|
+
}
|
|
821
|
+
if (!this.textContent.trim()) {
|
|
822
|
+
virtualHeightCache.set(this, 16);
|
|
823
|
+
return 16;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
const val = origOffsetHeight.call(this);
|
|
827
|
+
if (this.hasAttribute('data-index')) virtualHeightCache.set(this, val);
|
|
828
|
+
return val;
|
|
829
|
+
},
|
|
830
|
+
configurable: true,
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
|
|
645
834
|
// Start the Overview panel's Context card; every theme gets it
|
|
646
835
|
const contextCard = typeof agyContextCard === 'function' ? agyContextCard() : null;
|
|
647
836
|
// ...and the token line under each finished turn
|
|
@@ -668,6 +857,12 @@ function agyThemeHost(bundle) {
|
|
|
668
857
|
loadingIndicator?.dispose();
|
|
669
858
|
progressIndicators?.dispose();
|
|
670
859
|
codeTools?.dispose();
|
|
860
|
+
if (origOffsetHeight) {
|
|
861
|
+
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
|
|
862
|
+
get: origOffsetHeight,
|
|
863
|
+
configurable: true,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
671
866
|
document.querySelectorAll('[data-agy-ghost]').forEach((g) => g.remove());
|
|
672
867
|
document.getElementById('agy-theme-css')?.remove();
|
|
673
868
|
document.documentElement?.removeAttribute('data-agy-theme');
|
package/themes/index.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"default": "matte",
|
|
3
3
|
"themes": {
|
|
4
|
+
"antigravity": [],
|
|
4
5
|
"matte": ["matte.css"],
|
|
6
|
+
"paper": ["paper.css"],
|
|
7
|
+
"nordic": ["nordic.css"],
|
|
5
8
|
"md3e": ["md3e-tokens.css", "md3e.css", "md3e-icons.css"]
|
|
6
9
|
},
|
|
7
10
|
"fonts": {
|
|
@@ -11,11 +14,14 @@
|
|
|
11
14
|
},
|
|
12
15
|
"ripple": ["md3e"],
|
|
13
16
|
"options": [
|
|
14
|
-
{ "key": "
|
|
15
|
-
{ "key": "
|
|
16
|
-
{ "key": "
|
|
17
|
-
{ "key": "
|
|
18
|
-
{ "key": "md3e-
|
|
19
|
-
{ "key": "md3e-
|
|
17
|
+
{ "key": "antigravity", "name": "Antigravity (Varsayılan)", "theme": "antigravity", "swatch": "transparent" },
|
|
18
|
+
{ "key": "matte", "name": "Matte", "theme": "matte", "swatch": "#ededee" },
|
|
19
|
+
{ "key": "paper", "name": "E-Ink / Paper", "theme": "paper", "swatch": "#e5e5e5" },
|
|
20
|
+
{ "key": "nordic", "name": "Nordic Frost", "theme": "nordic", "swatch": "#88c0d0" },
|
|
21
|
+
{ "key": "md3e-teal", "name": "Teal", "theme": "md3e", "seed": "teal", "swatch": "#a5faf9" },
|
|
22
|
+
{ "key": "md3e-ocean", "name": "Ocean", "theme": "md3e", "seed": "ocean", "swatch": "#9ecefe" },
|
|
23
|
+
{ "key": "md3e-forest", "name": "Forest", "theme": "md3e", "seed": "forest", "swatch": "#c8f2ae" },
|
|
24
|
+
{ "key": "md3e-amber", "name": "Amber", "theme": "md3e", "seed": "amber", "swatch": "#fecd79" },
|
|
25
|
+
{ "key": "md3e-coral", "name": "Coral", "theme": "md3e", "seed": "coral", "swatch": "#ffa6a8" }
|
|
20
26
|
]
|
|
21
27
|
}
|