feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(webkit): add a side prop so a trailing panel is Sidebar too - #901

Draft
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop
Draft

feat(webkit): add a side prop so a trailing panel is Sidebar too#901
gabriel-lisboa-azion wants to merge 7 commits into
mainfrom
feat/sidebar-side-prop

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • Adds side: 'start' | 'end' (default 'start', so every existing consumer is unaffected). An explorer layout — a log with a detail panel, a database browser with a schema panel — needs a resizable, hideable panel on the right.
  • useSidebarRail derives a direction() of +1/-1 and every horizontal decision multiplies by it, so the trailing panel inherits the same clamping, phase-aware transition, inert collapsed state and testids instead of being re-implemented beside the leading one.
  • Adds data-side on the root, a Trailing story putting both edges on one page, and spec + catalog updates.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/sidebar → passes.
  2. pnpm storybook:dev → Components/Layout/Sidebar → Trailing. The right-hand panel's border and drag handle are on its left edge; dragging left grows it; collapsing sends it out to the right; the collapse glyph and arrow keys mirror. The leading rail on the same page behaves exactly as before.
  3. Existing Sidebar stories are unchanged (no side passed → start).

Notes

  • Additive; no breaking change.

An explorer layout — a log with a detail panel, a database browser with a schema
panel — puts a resizable, hideable panel on the right. The only thing that
differs there is the direction of every horizontal decision: which edge the
border and the handle sit on, which way a drag grows the panel, which way it
leaves, and which way the collapse glyph points.
`side: 'end'` mirrors all of them from a single sign. `useSidebarRail` derives a
`direction()` of +1 or -1 and every place that reads a horizontal direction
multiplies by it, so a trailing panel inherits the same clamping, the same
phase-aware transition, the same `inert` collapsed state and the same testids
instead of being re-implemented beside the leading one — which is exactly how the
two would drift.
Defaults to `start`, so every existing consumer is unaffected. Adds `data-side`
on the root and a Trailing story that puts both edges on one page, since a mirror
is only demonstrable against the thing it mirrors.
…story
Adds the 6 snapshots for the new Trailing story across the mode matrix.
Generated by the Storybook Regenerate Baseline workflow on this branch's HEAD —
baselines are ubuntu-only, so a local run would not match the folder the visual
gate compares against.
No existing snapshot is modified or deleted: `side` defaults to `start`, so the
other Sidebar stories render exactly as before.
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
…y comments
Drops the prose comments the side-prop work added across the sidebar: the edge
map and arrow-key notes in `sidebar.vue`, the direction and leave-transform
notes in `use-sidebar-rail.ts`, the footer-region note in `sidebar-footer.vue`,
the mirror notes in the test, and the trailing-panel note in the story.
The JSDoc stays: `side` on the prop table and on `UseSidebarRailOptions`
document the public surface and feed the Storybook prop table and editor hover.
Also reflows `FOOTER_REGION_CLASS` onto one line, which is what Prettier wants
and what `webkit:format:check` was failing on.
* chore(webkit): centre the sidebar footer in a fixed band
Give the rail's footer region the header bar's 56px height and make it do the
centring itself, so a rail closed by a footer and a page closed by a bar share
one horizontal.
`items-center` only binds on a flex box, so the region becomes `flex`; on the
block box it was, the property emitted and did nothing. The padding drops to
horizontal only for the same reason the height is fixed: `p-(--spacing-md)`
leaves a 24px content box inside a 56px band, which the collapse trigger alone
(`IconButton size="small"`, 28px) overflows.
* fix(webkit): fill the sidebar footer band so its controls sit at the trailing edge
The band holding the footer slot and the collapse trigger was a shrink-to-fit
flex item inside the region this branch turned into a flex box, so both packed
against the rail's leading edge: the `flex-1` inside the slot had no space to
distribute, and the no-slot `justify-end` was inert for the same reason. The
band now fills the region (`min-w-0 flex-1`), and the slot wrapper takes
`min-w-0 flex-1` whether or not the rail is collapsible.
Drops the band's own `border-t` + `pt-(--spacing-md)` with it. The region owns
the separator, so the band's border drew a second line inside the band; and the
top padding pushed the 28px content off the 56px band's centre, which the fixed
height already answers.
Measured in the sample console at 1440px: on a 300px rail the account menu ends
at 248 and the collapse trigger at 284 — flush with the region's 16px inset.
gabriel-lisboa-azion added a commit that referenced this pull request Aug 31, 2026
…he footer (#937)
The rule above the sidebar footer was drawn by `SidebarFooter`, conditionally on
the rail not being collapsible. Two things were wrong with that.
It stopped at that component's box. The footer REGION spans the rail
edge-to-edge, so a rule drawn inside `SidebarFooter` sat short of both edges and
read as a border around the footer's content rather than as the rail's own
division — and a rail whose footer is only the collapse control got no rule at
all, because `SidebarFooter` was not rendered.
And it made the separator a property of the slot's content instead of the
layout, so whether the rail had a division depended on which component the
consumer happened to put in it.
The rule moves to `FOOTER_REGION_CLASS`, which is the region, unconditionally.
The region takes full padding to sit under it (`p-` rather than `px-`/`pb-`),
and `SidebarFooter` goes back to laying out its own content and nothing else.
Stacked on #901 because both edit `sidebar.vue`, and because shipping the
`sidebar-footer.vue` half alone would remove the separator entirely — nothing
else draws it.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@gabriel-lisboa-azion@isaque-bock-azion