perf(web): the command palette and the bell load once the page is up

They come with @defer (on idle; on interaction): their code, their
stores and the bell's queries and live subscription leave the start,
and main no longer carries anything of the tracker's presenters or
application. Meanwhile the header shows a still copy of each with the
same box, so nothing moves when they arrive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-16 08:55:19 +02:00
parent f448207e88
commit 9ccc3b5967
4 changed files with 46 additions and 4 deletions

View File

@@ -10,6 +10,7 @@ import {
import { filter, map } from 'rxjs'; import { filter, map } from 'rxjs';
import { AuthFacade } from '@task-stream/web/identity/application'; import { AuthFacade } from '@task-stream/web/identity/application';
import { UserMenuComponent } from '@task-stream/web/identity/presenters'; import { UserMenuComponent } from '@task-stream/web/identity/presenters';
import { PiIconButtonComponent } from '@pi/ui';
import { AppShellComponent } from '@task-stream/web/shared/ui'; import { AppShellComponent } from '@task-stream/web/shared/ui';
import { import {
CommandPalette, CommandPalette,
@@ -27,7 +28,24 @@ import {
UserMenuComponent, UserMenuComponent,
NotificationsBell, NotificationsBell,
CommandPalette, CommandPalette,
PiIconButtonComponent,
], ],
styles: `
/* The palette's button, still: same box, so nothing moves when it loads. */
.ts-shell-search {
display: inline-flex;
gap: 0.375rem;
align-items: center;
border: 0;
background: none;
font: inherit;
cursor: pointer;
kbd {
font-size: 0.6875rem;
opacity: 0.7;
}
}
`,
template: ` template: `
<ts-app-shell> <ts-app-shell>
@if (auth.isAuthenticated()) { @if (auth.isAuthenticated()) {
@@ -62,8 +80,30 @@ import {
@if (auth.isAuthenticated()) { @if (auth.isAuthenticated()) {
<!-- One projectable node per @if branch, or neither reaches the slot. --> <!-- One projectable node per @if branch, or neither reaches the slot. -->
<ng-container shellUser> <ng-container shellUser>
<ts-command-palette /> <!-- Palette and bell load once the page is up: their code and their
<ts-notifications-bell /> queries stay out of the start. Meanwhile, a still copy. -->
@defer (on idle; on interaction) {
<ts-command-palette />
} @placeholder {
<button
type="button"
class="ts-nav-link ts-shell-search"
tabindex="-1"
aria-hidden="true"
>
Buscar <kbd>⌘K</kbd>
</button>
}
@defer (on idle; on interaction) {
<ts-notifications-bell />
} @placeholder {
<pi-icon-button
icon="bell"
color="grey"
appearance="ghost"
aria-label="Notificaciones"
/>
}
<ts-user-menu /> <ts-user-menu />
</ng-container> </ng-container>
} @else if (auth.settled() && !onLogin()) { } @else if (auth.settled() && !onLogin()) {

View File

@@ -122,8 +122,10 @@ Qué gana la página:
| `ListFacade` | `ListStore` | ruta `list` | Todos los tickets del proyecto en filas: filtros (enviados a la API), cambios de estado, prioridad y persona en la fila, edición en bloque; se recarga tras cada cambio propio y con los de otros | | `ListFacade` | `ListStore` | ruta `list` | Todos los tickets del proyecto en filas: filtros (enviados a la API), cambios de estado, prioridad y persona en la fila, edición en bloque; se recarga tras cada cambio propio y con los de otros |
| `IssueFacade` | `IssueStore` | ruta `issues/:issueKey` | Ticket, comentarios en vivo, historial y todas sus acciones | | `IssueFacade` | `IssueStore` | ruta `issues/:issueKey` | Ticket, comentarios en vivo, historial y todas sus acciones |
En la raíz solo queda lo que usa la cabecera desde el arranque: la sesión (`AuthFacade`), mis proyectos para la paleta En la raíz solo queda lo que usa la cabecera: la sesión (`AuthFacade`), mis proyectos para la paleta de comandos
de comandos (`ProjectsFacade`) y la campana (`InboxFacade`, `PushFacade`). Lo demás es de su página: (`ProjectsFacade`) y la campana (`InboxFacade`, `PushFacade`). La paleta y la campana se cargan con `@defer (on idle;
on interaction)`: su código y sus consultas no están en el arranque, y mientras tanto la cabecera muestra una copia
quieta con la misma caja, así que nada se mueve al llegar. Lo demás es de su página:
- Las de una página que se vuelve a visitar a menudo (portada, Explorar, el formulario de propuestas) van en los - Las de una página que se vuelve a visitar a menudo (portada, Explorar, el formulario de propuestas) van en los
`providers` de su ruta (`provideHomeFacade()`, `provideMyHomeFacade()`, `provideMyViewsFacade()`, `providers` de su ruta (`provideHomeFacade()`, `provideMyHomeFacade()`, `provideMyViewsFacade()`,

Binary file not shown.

Binary file not shown.