109 lines
4.2 KiB
Rust
109 lines
4.2 KiB
Rust
//! Publication detail: right pane showing full reference fields.
|
|
|
|
use leptos::prelude::*;
|
|
|
|
use brittle_model::Reference;
|
|
|
|
/// Right pane: displays the fields of the currently selected reference.
|
|
///
|
|
/// When `reference` is `None`, a placeholder is shown.
|
|
#[component]
|
|
pub fn PubDetail(reference: RwSignal<Option<Reference>>) -> impl IntoView {
|
|
use leptos::either::Either;
|
|
|
|
view! {
|
|
<div class="pub-detail-pane">
|
|
{move || match reference.get() {
|
|
None => Either::Left(view! {
|
|
<div class="empty-state">"Select a publication to see details"</div>
|
|
}),
|
|
Some(r) => Either::Right(view! {
|
|
<div class="detail-content">
|
|
<h2 class="detail-title">
|
|
{r.fields.get("title").cloned().unwrap_or_else(|| "[no title]".into())}
|
|
</h2>
|
|
<dl class="detail-fields">
|
|
// Entry type + cite key
|
|
<dt>"Type"</dt>
|
|
<dd>{r.entry_type.to_string()}</dd>
|
|
|
|
<dt>"Cite key"</dt>
|
|
<dd class="mono">{r.cite_key.clone()}</dd>
|
|
|
|
// Authors
|
|
{if r.authors.is_empty() {
|
|
None
|
|
} else {
|
|
let names = r.authors.iter()
|
|
.map(|p| p.display_name())
|
|
.collect::<Vec<_>>()
|
|
.join("; ");
|
|
Some(view! {
|
|
<dt>"Authors"</dt>
|
|
<dd>{names}</dd>
|
|
})
|
|
}}
|
|
|
|
// Editors
|
|
{if r.editors.is_empty() {
|
|
None
|
|
} else {
|
|
let names = r.editors.iter()
|
|
.map(|p| p.display_name())
|
|
.collect::<Vec<_>>()
|
|
.join("; ");
|
|
Some(view! {
|
|
<dt>"Editors"</dt>
|
|
<dd>{names}</dd>
|
|
})
|
|
}}
|
|
|
|
// Prioritised well-known fields
|
|
{PRIORITY_FIELDS.iter().filter_map(|&key| {
|
|
r.fields.get(key).map(|val| view! {
|
|
<dt>{field_label(key)}</dt>
|
|
<dd>{val.clone()}</dd>
|
|
})
|
|
}).collect::<Vec<_>>()}
|
|
|
|
// Remaining fields in alphabetical order
|
|
{r.fields.iter()
|
|
.filter(|(k, _)| !PRIORITY_FIELDS.contains(&k.as_str())
|
|
&& *k != "title")
|
|
.map(|(k, v)| view! {
|
|
<dt>{field_label(k)}</dt>
|
|
<dd>{v.clone()}</dd>
|
|
})
|
|
.collect::<Vec<_>>()
|
|
}
|
|
</dl>
|
|
<p class="detail-timestamps">
|
|
"Modified: "{r.modified_at.format("%Y-%m-%d %H:%M UTC").to_string()}
|
|
</p>
|
|
</div>
|
|
}),
|
|
}}
|
|
</div>
|
|
}
|
|
}
|
|
|
|
/// Fields shown before the alphabetical remainder (excluding "title").
|
|
const PRIORITY_FIELDS: &[&str] = &["year", "journal", "booktitle", "volume", "doi", "abstract"];
|
|
|
|
/// Pretty-print a BibTeX field key.
|
|
fn field_label(key: &str) -> String {
|
|
match key {
|
|
"doi" => "DOI".into(),
|
|
"isbn" => "ISBN".into(),
|
|
"issn" => "ISSN".into(),
|
|
"url" => "URL".into(),
|
|
_ => {
|
|
let mut s = key.replace('_', " ");
|
|
if let Some(c) = s.get_mut(0..1) {
|
|
c.make_ascii_uppercase();
|
|
}
|
|
s
|
|
}
|
|
}
|
|
}
|