Repository navigation
feat(web): show a project's chosen or first mockup on its tile - #148
Conversation
A tile's cover was a generated pattern whatever the project looked like. A project with a mockup shows its first page, the design the person chose or the first concept filed, as a still picture read once the tile is near the screen; a project without one keeps the pattern.
|
Triage: Pass No changes needed from you. A maintainer will review this pull request. Approve held: code review has 2 findings at P2 or above open on this head. |
| if (pick === null) return null; | ||
| const filed = await readArtifact(projectId, pick.artifactId, pick.version); | ||
| const files = parseBundle(filed.content); | ||
| return files === null ? null : firstPage(files); |
There was a problem hiding this comment.
P2 · Empty first page shows 'No design to show.' instead of keeping the pattern
If the bundle has no designs/index.html and no screen fragments, firstPage returns an empty string. The component only checks html === null, so it sets data-mockup and renders GuiFrame. For an empty string, GuiFrame renders the text note 'No design to show.' on the tile instead of leaving the pattern. The PR says a project with no mockup keeps its pattern.
The chosen design or first concept is a bundle without designs/index.html (or one whose index page is empty), so firstPage returns "".
Resolve this comment. Triage will not finish while it is open.
| <ProjectCover | ||
| projectId={project.id} | ||
| pattern={cover.pattern} | ||
| style={cover.style} | ||
| aria-hidden="true" | ||
| mockup={view === "grid"} | ||
| /> |
There was a problem hiding this comment.
P2 · Tile shows the text "No design to show." when the bundle has no index page or an empty one
readCoverPage returns firstPage(files), and firstPage falls back to "" when designs/index is missing. Because "" is not null, ProjectCover sets data-mockup and renders GuiFrame. GuiFrame treats empty HTML as no design and renders a
No design to show.
inside the tile's cover, in place of the pattern the PR says should remain.A project whose chosen design or first concept has a bundle with no designs/index page (for example a concept filed before its index was written, or an empty bundle), viewed in grid mode.
Resolve this comment. Triage will not finish while it is open.
| height: 400%; | ||
| min-height: 0; | ||
| border: 0; | ||
| background: var(--wb-background); |
There was a problem hiding this comment.
P3 · Frame gets the app's theme background, so pages without their own background break in dark mode
Everywhere else .gui-frame uses #fff, which is the default for a standalone document. With var(--wb-background), a mockup that sets no body background is shown on the app's dark surface in dark mode. Its default black text is then almost unreadable, and the tile no longer matches what the themes pane shows.
Dark mode with a mockup whose first page does not set its own body background.
Resolve this comment. Triage will not finish while it is open.
| height: 400%; | ||
| min-height: 0; | ||
| border: 0; | ||
| background: var(--wb-background); |
There was a problem hiding this comment.
P3 · Opaque frame background hides the pattern while the page loads
The comment says the pattern stays visible beneath while the page loads. But the iframe is inserted as soon as the HTML arrives and its background is opaque, so a blank block covers the pattern until the scripted page renders.
Any tile whose mockup query succeeds while the iframe document is still loading or running its scripts.
Resolve this comment. Triage will not finish while it is open.
…and a white frame A bundle with no index page produced an empty first page, which the frame showed as 'No design to show.' over the tile; the tile keeps its pattern instead. The frame is white like every other mockup frame, so a page without its own background reads the same in dark mode.
| const { artifacts } = await listProjectArtifacts(projectId); | ||
| const pick = coverArtifact(artifacts); | ||
| if (pick === null) return null; | ||
| const filed = await readArtifact(projectId, pick.artifactId, pick.version); | ||
| const files = parseBundle(filed.content); |
There was a problem hiding this comment.
P2 · Each tile calls the heavy room-listing endpoint and downloads the whole design bundle
listProjectArtifacts hits the hub's service.list. That handler queries workflow runs and pending approvals across the tenant, reads failure details for failed runs, and runs approvedVersion and filedAt queries for every artifact. readArtifact then downloads the full design bundle. All of this is only to show a thumbnail, and it runs once for every grid tile that comes near the viewport.
A library with many projects in grid view, scrolled through: one full room listing and one full bundle download per tile.
Resolve this comment. Triage will not finish while it is open.
| <ProjectCover | ||
| projectId={project.id} | ||
| pattern={cover.pattern} | ||
| style={cover.style} | ||
| aria-hidden="true" | ||
| mockup={view === "grid"} |
There was a problem hiding this comment.
P2 · Tile can keep showing an old mockup after the project's design changes
The cover query's key is just the projectId, it stays fresh for 5 minutes, and nothing anywhere calls invalidate on keys.projectCover. Its key also doesn't include anything like project.lastActivityAt. So after a person picks a design or a new concept is filed, going back to the library shows the cached cover from before.
Open the library so covers load, open a project, choose a design or file a concept, then return to the library within 5 minutes. The tile still shows the earlier concept, or the plain pattern if the project had no mockup before.
Resolve this comment. Triage will not finish while it is open.
| pattern={cover.pattern} | ||
| style={cover.style} | ||
| aria-hidden="true" | ||
| mockup={view === "grid"} |
There was a problem hiding this comment.
P3 · Grid view runs a scripted iframe for every tile and never unmounts them
Each grid tile that has a mockup mounts a GuiFrame iframe with scripts on. Once a tile gets near the viewport, its iframe stays mounted even after the tile scrolls away. On a large library this means many live documents running the designs' scripts and animations at once, which costs a lot of memory and CPU.
Scroll through a library with dozens of projects in grid view.
Resolve this comment. Triage will not finish while it is open.
Closes #147
What
A project's tile shows its mockup: the first page of the design the person chose, or of the first concept filed before a choice. A project with no mockup keeps its pattern.
Why
The cover was a generated pattern whatever the project looked like. Details in #147.
Changes
apps/web/src/pages/project-cover.tsx:coverArtifactpicks the chosen design, else the first concept;ProjectCoverreads it once the tile is within a screen of the viewport, builds the first page the way the themes pane does (firstPage), and shows it in an inert scripted frame over the pattern. The list's small swatch shows the pattern only.apps/web/src/pages/project-library.tsx,project-library.css: the tile uses it; the frame lays the page out at four times the tile's width and scales it down, as the theme thumbnails do.apps/web/src/queries/keys.ts:projectCover.project-cover.test.tscovers the pick.