Add feed sidebar navigation #8
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