web: show description preview, improve task layout with aligned subtitle and expanded body
diff --git a/src/bin/ranger/commands/serve.rs b/src/bin/ranger/commands/serve.rs
index 98b5e6b..0977844 100644
--- a/src/bin/ranger/commands/serve.rs
+++ b/src/bin/ranger/commands/serve.rs
@@ -364,44 +364,68 @@ fn render_column_panel(
}
}
+fn truncate_desc(s: &str, max: usize) -> String {
+ let first_line = s.lines().next().unwrap_or(s);
+ if first_line.len() <= max {
+ first_line.to_string()
+ } else {
+ format!("{}…", &first_line[..max])
+ }
+}
+
fn render_task(task: &TaskView) -> Markup {
let has_details = task.description.is_some();
html! {
@if has_details {
details.task draggable="true" data-key=(task.key) {
- summary.task-header tabindex="0" {
- span.key {
- span.key-prefix { (task.key_prefix) }
- span.key-rest { (task.key_rest) }
- }
- span.title { (task.title) }
- @if !task.tags.is_empty() {
- span.tags {
- @for tag in &task.tags {
- span.tag { (tag) }
+ summary tabindex="0" {
+ div.task-row {
+ span.key {
+ span.key-prefix { (task.key_prefix) }
+ span.key-rest { (task.key_rest) }
+ }
+ div.task-content {
+ div.task-title-row {
+ span.title { (task.title) }
+ @if !task.tags.is_empty() {
+ span.tags {
+ @for tag in &task.tags {
+ span.tag { (tag) }
+ }
+ }
+ }
+ }
+ @if let Some(desc) = &task.description {
+ div.subtitle { (truncate_desc(desc, 80)) }
}
}
}
- span.expand-icon { "›" }
}
- div.task-body {
- @if let Some(desc) = &task.description {
- div.desc { (desc) }
+ @if let Some(desc) = &task.description {
+ div.task-row {
+ span.key-spacer {}
+ div.task-content {
+ div.desc { (desc) }
+ }
}
}
}
} @else {
div.task data-key=(task.key) tabindex="0" {
- div.task-header {
+ div.task-row {
span.key {
span.key-prefix { (task.key_prefix) }
span.key-rest { (task.key_rest) }
}
- span.title { (task.title) }
- @if !task.tags.is_empty() {
- span.tags {
- @for tag in &task.tags {
- span.tag { (tag) }
+ div.task-content {
+ div.task-title-row {
+ span.title { (task.title) }
+ @if !task.tags.is_empty() {
+ span.tags {
+ @for tag in &task.tags {
+ span.tag { (tag) }
+ }
+ }
}
}
}
diff --git a/static/style.css b/static/style.css
index f2998d1..924e987 100644
--- a/static/style.css
+++ b/static/style.css
@@ -290,13 +290,30 @@ details.task > summary::marker {
content: "";
}
-.task .task-header,
-.task > summary.task-header {
+.task-row {
display: flex;
align-items: baseline;
gap: 8px;
}
+.task-content {
+ flex: 1;
+ min-width: 0;
+}
+
+.task-title-row {
+ display: flex;
+ align-items: baseline;
+ gap: 8px;
+}
+
+.key-spacer {
+ width: 8ch;
+ flex-shrink: 0;
+ font-family: var(--font-mono);
+ font-size: var(--step-mono);
+}
+
.task .key {
font-family: var(--font-mono);
font-size: var(--step-mono);
@@ -321,25 +338,26 @@ details.task > summary::marker {
min-width: 0;
}
-/* === Expand icon === */
-.task .expand-icon {
+
+
+/* === Description subtitle === */
+.task .subtitle {
font-size: var(--step-mono);
- color: #7a7868;
- margin-left: auto;
- flex-shrink: 0;
- transition: transform 0.15s ease;
- display: inline-block;
+ color: var(--color-text-muted);
+ line-height: 1.4;
+ padding-top: 2px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
-details.task[open] > summary .expand-icon {
- transform: rotate(90deg);
+details.task[open] > summary .subtitle {
+ display: none;
}
/* === Task body (expanded) === */
-.task-body {
- padding: 6px 0 2px 0;
- margin-top: 4px;
- border-top: 1px solid rgba(0, 0, 0, 0.1);
+details.task > .task-row {
+ padding-top: 4px;
}
.task .desc {