Fix article list not scrolling: duplicate <main> broke the scroll area
Articles past the first screenful were unreachable — not clipped by
accident, genuinely inaccessible, since the page itself couldn't
scroll either (the sidebar wrapper is overflow: hidden by design, so
the intended scroll boundary is internal to the main content pane).
Root cause: SidebarInset already renders a <main> (class
dx-sidebar-inset, a properly height-bound flex column — main{
height:900px in a 900px viewport, flex-direction:column}), but I'd
also written an explicit `main { ... }` as ITS child, producing a
`<main><main>...</main></main>` (confirmed via a headless Playwright
probe against the live dev server, not just DevTools guesswork). The
inner <main> is just a plain flex item with the default flex: 0 1 auto,
so it sized to its own content (6500+px) instead of being constrained
by the outer one's box, and the ScrollArea inside it had nothing
bounded to scroll within.
Removed the redundant inner <main> — SidebarInset's children (the
content-header div and ScrollArea) now sit directly in its own <main>,
which is the actual flex column that needs to size them. Also pinned
ScrollArea's direction to Vertical (it defaults to Both, which was
adding an unnecessary horizontal scrollbar) and moved the sizing rule
in app.css off a class ScrollArea silently drops (confirmed via the
same probe — a caller-supplied `class` never reaches ScrollArea's
rendered DOM, only its own internal one does) onto its stable
data-scroll-direction attribute instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PqTJmazHBQK878vjQ4JnnF
This commit is contained in:
parent
44e2fb4d4e
commit
f0e42e2ad5
2 changed files with 35 additions and 29 deletions
|
|
@ -2,7 +2,14 @@ body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; height: 10
|
|||
.app-shell { display: flex; height: 100vh; }
|
||||
.content-header { display: flex; align-items: center; gap: 0.75rem; padding: 1.5rem 1.5rem 0.5rem; }
|
||||
.content-header h2 { margin: 0; }
|
||||
.article-scroll-area { flex: 1; min-height: 0; padding: 0 1.5rem 1.5rem; }
|
||||
/* Target the primitive's own stable data attribute, not a class we pass in:
|
||||
ScrollArea sets its own `class` after spreading our attributes, so a
|
||||
caller-supplied class never reaches the DOM (confirmed by inspecting the
|
||||
live element — it only ever carries "dx-scroll-area-auto-hide"). Without
|
||||
this, the scroll div has no bounded height, so it just grows to fit every
|
||||
article (nothing to scroll) while its ancestor's overflow: hidden clips
|
||||
everything past the viewport instead. */
|
||||
main > [data-scroll-direction] { flex: 1; min-height: 0; padding: 0 1.5rem 1.5rem; }
|
||||
.article-list { list-style: none; padding: 0; margin: 0; }
|
||||
.article-row { border-bottom: 1px solid #ddd; padding: 1rem 0; display: flex; flex-direction: column; align-items: flex-start; gap: 0.5rem; }
|
||||
.article-row-header { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.5rem; }
|
||||
|
|
|
|||
|
|
@ -85,37 +85,36 @@ pub fn App() -> Element {
|
|||
}
|
||||
}
|
||||
SidebarInset {
|
||||
main {
|
||||
div { class: "content-header",
|
||||
SidebarTrigger {}
|
||||
h2 {
|
||||
{
|
||||
let heading = match selected_feed.read().as_ref() {
|
||||
None => "All articles".to_string(),
|
||||
Some(id) => feeds
|
||||
.read()
|
||||
.as_ref()
|
||||
.and_then(|r| r.as_ref().ok())
|
||||
.and_then(|feeds| feeds.iter().find(|f| &f.id == id))
|
||||
.map(|f| f.title.clone())
|
||||
.unwrap_or_else(|| "Feed".to_string()),
|
||||
};
|
||||
rsx! { "{heading}" }
|
||||
}
|
||||
div { class: "content-header",
|
||||
SidebarTrigger {}
|
||||
h2 {
|
||||
{
|
||||
let heading = match selected_feed.read().as_ref() {
|
||||
None => "All articles".to_string(),
|
||||
Some(id) => feeds
|
||||
.read()
|
||||
.as_ref()
|
||||
.and_then(|r| r.as_ref().ok())
|
||||
.and_then(|feeds| feeds.iter().find(|f| &f.id == id))
|
||||
.map(|f| f.title.clone())
|
||||
.unwrap_or_else(|| "Feed".to_string()),
|
||||
};
|
||||
rsx! { "{heading}" }
|
||||
}
|
||||
}
|
||||
ScrollArea { class: "article-scroll-area",
|
||||
match articles.read().as_ref() {
|
||||
Some(Ok(articles)) => rsx! {
|
||||
ul { class: "article-list",
|
||||
for article in articles.iter() {
|
||||
ArticleRow { article: article.clone() }
|
||||
}
|
||||
}
|
||||
ScrollArea {
|
||||
direction: dioxus_primitives::scroll_area::ScrollDirection::Vertical,
|
||||
match articles.read().as_ref() {
|
||||
Some(Ok(articles)) => rsx! {
|
||||
ul { class: "article-list",
|
||||
for article in articles.iter() {
|
||||
ArticleRow { article: article.clone() }
|
||||
}
|
||||
},
|
||||
Some(Err(err)) => rsx! { p { class: "error", "Failed to load articles: {err}" } },
|
||||
None => rsx! { p { "Loading..." } },
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(Err(err)) => rsx! { p { class: "error", "Failed to load articles: {err}" } },
|
||||
None => rsx! { p { "Loading..." } },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue