Repository navigation
fix(web): glass sidebar peek with a tail, off the stage edge #273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1410,31 +1410,154 @@ | |
| Collapsed-sidebar peek. Hovering the floating toggle drops the real panel | ||
| down beneath it as a card (custom/sidebarPeek.ts stamps the wrapper). The | ||
| panel stays collapsed — the gap spacer is already zero — so only the | ||
| container moves: in from off-canvas, 8px off the window edges, its top 4px | ||
| under the toggle's glyph box. Opaque fill, no backdrop blur: a blur this | ||
| size over a streaming transcript would repaint every token. | ||
| container moves: in from off-canvas, 14px in from the window's left so it | ||
| does not line up with the stage card's 8px edge, with a tail up to the | ||
| toggle's glyph. No backdrop blur: a blur this size over a streaming | ||
| transcript would repaint every token. Under Glass the stage is cut away | ||
| beneath it instead (below). | ||
| "dismissed" drops the slide transition, so dismissing it vanishes like a | ||
| menu instead of sliding out at full height. Stacking and the title-bar drag | ||
| release are the narrow overlay's rules above. */ | ||
| release are the narrow overlay's rules above. | ||
|
|
||
| The geometry sits on the wrapper because the Glass cutout on the inset | ||
| reads it too. The tail centres on the floating toggle (AppSidebarLayout's | ||
| controls row: its left inset, ml-px, half the control), clear of the | ||
| card's corner radius. */ | ||
| :root[data-fork="noahhendrickson-t3code"] | ||
| [data-slot="sidebar-wrapper"][data-sidebar-state="collapsed"][data-fork-sidebar-peek="open"] { | ||
| --fork-peek-left: 14px; | ||
| --fork-peek-bottom: 8px; | ||
| --fork-peek-radius: 12px; | ||
| --fork-peek-tail-width: 18px; | ||
| --fork-peek-tail-height: 8px; | ||
| --fork-peek-top: calc( | ||
| var(--workspace-controls-top) + | ||
| (var(--workspace-topbar-height) + var(--workspace-titlebar-control-size)) / 2 + 3px + | ||
| var(--fork-peek-tail-height) | ||
| ); | ||
| --fork-peek-tail-left: max( | ||
| var(--fork-peek-radius), | ||
| calc( | ||
| var(--workspace-controls-left) + 1px + var(--workspace-titlebar-control-size) / 2 - | ||
| var(--fork-peek-tail-width) / 2 - var(--fork-peek-left) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| /* No border or shadow of its own: both are the ::after below, so they can | ||
| leave a gap where the tail joins and the tail reads as one shape with the | ||
| card. The inner panel clips the rows to the corners instead of the | ||
| container, which has to let the tail out. */ | ||
| :root[data-fork="noahhendrickson-t3code"] | ||
| [data-slot="sidebar-wrapper"][data-sidebar-state="collapsed"][data-fork-sidebar-peek="open"] | ||
| [data-slot="sidebar"][data-collapsible="offcanvas"][data-side="left"] | ||
| [data-slot="sidebar-container"] { | ||
| top: calc( | ||
| var(--workspace-controls-top) + | ||
| (var(--workspace-topbar-height) + var(--workspace-titlebar-control-size)) / 2 + 4px | ||
| ); | ||
| bottom: 8px; | ||
| left: 8px; | ||
| --fork-peek-edge: var(--fork-popup-border, var(--sidebar-border)); | ||
| top: var(--fork-peek-top); | ||
| bottom: var(--fork-peek-bottom); | ||
| left: var(--fork-peek-left); | ||
| height: auto; | ||
| translate: 0 0; | ||
| overflow: visible; | ||
| border-width: 0; | ||
| border-radius: var(--fork-peek-radius); | ||
| transition: none; | ||
| } | ||
|
|
||
| :root[data-fork="noahhendrickson-t3code"] | ||
| [data-slot="sidebar-wrapper"][data-sidebar-state="collapsed"][data-fork-sidebar-peek="open"] | ||
| [data-slot="sidebar-container"] | ||
| > [data-slot="sidebar-inner"] { | ||
| border-radius: inherit; | ||
| overflow: hidden; | ||
| border: 1px solid var(--fork-popup-border, var(--sidebar-border)); | ||
| border-radius: 12px; | ||
| } | ||
|
|
||
| :root[data-fork="noahhendrickson-t3code"] | ||
| [data-slot="sidebar-wrapper"][data-sidebar-state="collapsed"][data-fork-sidebar-peek="open"] | ||
| [data-slot="sidebar-container"]::after { | ||
| content: ""; | ||
| position: absolute; | ||
| inset: 0; | ||
| z-index: 50; | ||
| border: 1px solid var(--fork-peek-edge); | ||
| border-radius: inherit; | ||
| box-shadow: | ||
| 0 12px 32px rgb(0 0 0 / 0.32), | ||
| 0 2px 8px rgb(0 0 0 / 0.2); | ||
| transition: none; | ||
| pointer-events: none; | ||
| /* Everything but the edge under the tail's base and the shadow under the | ||
| tail itself, which would darken a translucent tail. */ | ||
| mask-image: | ||
| linear-gradient(#000 0 0), linear-gradient(#000 0 0), | ||
| linear-gradient(to bottom right, transparent 50%, #000 50%), | ||
| linear-gradient(to bottom left, transparent 50%, #000 50%); | ||
| mask-position: | ||
| -48px -48px, | ||
| calc(var(--fork-peek-tail-left) + 1px) 0, | ||
| var(--fork-peek-tail-left) calc(var(--fork-peek-tail-height) * -1), | ||
| calc(var(--fork-peek-tail-left) + var(--fork-peek-tail-width) / 2) | ||
| calc(var(--fork-peek-tail-height) * -1); | ||
| mask-size: | ||
| calc(100% + 96px) calc(100% + 96px), | ||
| calc(var(--fork-peek-tail-width) - 2px) 1px, | ||
| calc(var(--fork-peek-tail-width) / 2) var(--fork-peek-tail-height), | ||
| calc(var(--fork-peek-tail-width) / 2) var(--fork-peek-tail-height); | ||
| mask-repeat: no-repeat; | ||
| mask-clip: no-clip; | ||
| mask-composite: subtract, add, add, add; | ||
| } | ||
|
|
||
| /* The tail. Each half is a diagonal gradient: the panel's fill below the | ||
| slant with the outline's 1px edge laid over it, so it composites like the | ||
| card's own edge does over the inner fill, translucent under Glass included. | ||
| It takes hits, so the pointer crossing from the toggle stays on the card. */ | ||
| :root[data-fork="noahhendrickson-t3code"] | ||
| [data-slot="sidebar-wrapper"][data-sidebar-state="collapsed"][data-fork-sidebar-peek="open"] | ||
| [data-slot="sidebar-container"]::before { | ||
| --fork-peek-tail-edge: | ||
| transparent calc(50% - 0.25px), var(--fork-peek-edge) calc(50% + 0.25px) calc(50% + 0.75px), | ||
| transparent calc(50% + 1.25px); | ||
| --fork-peek-tail-fill: transparent calc(50% - 0.25px), var(--sidebar) calc(50% + 0.25px); | ||
| content: ""; | ||
| position: absolute; | ||
| top: calc(var(--fork-peek-tail-height) * -1); | ||
| left: var(--fork-peek-tail-left); | ||
| width: var(--fork-peek-tail-width); | ||
| height: var(--fork-peek-tail-height); | ||
| background: | ||
| linear-gradient(to bottom right, var(--fork-peek-tail-edge)) left top / 50% 100% no-repeat, | ||
| linear-gradient(to bottom left, var(--fork-peek-tail-edge)) right top / 50% 100% no-repeat, | ||
| linear-gradient(to bottom right, var(--fork-peek-tail-fill)) left top / 50% 100% no-repeat, | ||
| linear-gradient(to bottom left, var(--fork-peek-tail-fill)) right top / 50% 100% no-repeat; | ||
| } | ||
|
|
||
| /* Glass: the card wears the docked panel's own tint (theme.custom.palettes.css), | ||
| so the stage beneath it is cut away, card and tail, the way | ||
| custom/forkGlassPopupCutout.ts cuts #root under a popup. The inset spans the | ||
| window while collapsed, so its box is the viewport. The mask makes the inset | ||
| a stacking context, which keeps its z-indexed layers under the card. */ | ||
| :root[data-fork="noahhendrickson-t3code"][data-fork-sidebar-vibrancy="true"].dark[data-fork-theme="cool-darker"] | ||
| [data-slot="sidebar-wrapper"][data-sidebar-state="collapsed"][data-fork-sidebar-peek="open"] | ||
| [data-slot="sidebar-inset"] { | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Under Glass, the hole shows up before the card does. The inset mask switches on at full strength when So every time the peek opens with animations on, the transcript disappears in the card-and-tail shape and leaves bare window material. The card then fades in over that gap, starting 4px above it, so the hole's edges and the tail cutout visibly fail to line up for the first ~120ms. Possible fixes: drop the animation under the vibrancy selector, or animate the inset's mask in step with the card (for example, fade the subtracted layer's alpha over the same 120ms).
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 923e2f8. Under Glass the card now opens without |
||
| --fork-peek-tail-x: calc(var(--fork-peek-left) + var(--fork-peek-tail-left)); | ||
| --fork-peek-tail-top: calc(var(--fork-peek-top) - var(--fork-peek-tail-height)); | ||
| mask-image: | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [P2] Preserve the floating browser controls above the hosted webview With a local desktop browser tab floating over the chat, opening the Glass sidebar peek applies this mask and creates a stacking context around the entire inset.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 923e2f8. The cutout is skipped while |
||
| linear-gradient(#000 0 0), | ||
| url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' rx='12'/%3E%3C/svg%3E"), | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Related: because the mask makes the inset a stacking context while the peek is open, the comment above the z-index 45 rule ("Raising the panel, rather than isolating the inset…") is no longer strictly true in that state. In practice it's harmless: the lightbox can't open while you're hovering the toggle. Still, a single clause there noting the exception would keep that comment accurate.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 923e2f8. Both shapes are one SVG token each ( |
||
| linear-gradient(to bottom right, transparent 50%, #000 50%), | ||
| linear-gradient(to bottom left, transparent 50%, #000 50%); | ||
| mask-position: | ||
| 0 0, | ||
| var(--fork-peek-left) var(--fork-peek-top), | ||
| var(--fork-peek-tail-x) var(--fork-peek-tail-top), | ||
| calc(var(--fork-peek-tail-x) + var(--fork-peek-tail-width) / 2) var(--fork-peek-tail-top); | ||
| mask-size: | ||
| 100% 100%, | ||
| var(--sidebar-width) calc(100% - var(--fork-peek-top) - var(--fork-peek-bottom)), | ||
| calc(var(--fork-peek-tail-width) / 2) var(--fork-peek-tail-height), | ||
| calc(var(--fork-peek-tail-width) / 2) var(--fork-peek-tail-height); | ||
| mask-repeat: no-repeat; | ||
| mask-composite: subtract, add, add, add; | ||
| } | ||
|
|
||
| :root[data-fork="noahhendrickson-t3code"] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -679,9 +679,7 @@ | |
|
|
||
| /* Figma's 6% white, under the panel's real glass only. */ | ||
| &[data-fork-sidebar-vibrancy="true"].dark[data-fork-theme="cool-darker"] | ||
| [data-slot="sidebar-wrapper"]:not([data-fork-sidebar-overlay="true"]):not( | ||
| [data-sidebar-state="collapsed"][data-fork-sidebar-peek="open"] | ||
| ) | ||
| [data-slot="sidebar-wrapper"]:not([data-fork-sidebar-overlay="true"]) | ||
|
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Active rows render differently depending on the chat column's width. The palettes docked block now has a separate peek arm, so the peek keeps the tint when With Glass, a narrow chat column ( Adding the same
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 923e2f8. This rule now takes both arms of the docked predicate, so the active rows get 6% white whenever the tint applies. glass-surfaces is back in the manifest's |
||
| [data-sidebar-version="v2"] | ||
| :is([data-thread-item] > [aria-current="page"], [data-fork-chrome-row][data-active="true"]) { | ||
| background-color: rgb(255 255 255 / 6%); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Off macOS, the tail misses the toggle glyph. The tail only lines up when
--workspace-controls-leftis the traffic-light inset. With the default0.75rem(web, Windows, Linux, and macOS fullscreen), the inner calc gives 12 + 1 + 14 − 9 − 14 = 4px, somax()falls back to the 12px radius.The tail then covers window x 26–44 with its apex at 35. The toggle glyph is centred at 12 + 1 + 14 = 27, so the apex is 8px off centre, right at the glyph's edge. That contradicts the header comment's "The tail centres on the floating toggle".
The clamp makes sense, since the tail can't sit inside the 12px corner. But the geometry needs a non-mac answer: for example, derive
--fork-peek-leftfrom the toggle so the tail can stay centred, or shrink the radius at the tail corner. Otherwise, at least correct the comment.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 923e2f8. Instead of clamping the tail, the card moves:
--fork-peek-left: min(14px, toggle-x − radius − tail/2), and the tail is alwaystoggle-x − tail/2 − left. In Chromium at controls-left 12px the card sits at 6px with the tail centred on 27, and at the mac inset it's still 14px with the tail on 100.