web: task row state coloring and key prefix highlighting
- Split task keys into bold prefix (accent color) + dimmed remainder
- Add dot indicators (●) to section labels (In Progress, Queued)
- Fade icebox tasks to 80% opacity
- Done tasks remain at 75% opacity
change znxwwoptrrnwnuzloqupnvqplqsossvz
commit 9e1d2b244d71e463789733a6ce795beb5b58068d
author Alpha Chen <alpha@kejadlen.dev>
date
parent opwpwlun
diff --git a/src/bin/ranger/commands/serve.rs b/src/bin/ranger/commands/serve.rs
index 636c8b9..5113e22 100644
--- a/src/bin/ranger/commands/serve.rs
+++ b/src/bin/ranger/commands/serve.rs
@@ -53,7 +53,8 @@ async fn index(State(state): State<AppState>) -> Html<String> {
 }
 
 struct TaskView {
-    short_key: String,
+    key_prefix: String,
+    key_rest: String,
     title: String,
     description: Option<String>,
     has_subtasks: bool,
@@ -140,7 +141,7 @@ fn render_backlog_panel(in_progress: &[TaskView], queued: &[TaskView]) -> String
     } else {
         if !in_progress.is_empty() {
             html.push_str(
-                r#"<div class="section-label section-label-in-progress">In Progress</div>"#,
+                r#"<div class="section-label section-label-in-progress"><span class="dot">●</span> In Progress</div>"#,
             );
             html.push_str(r#"<div class="state-in-progress">"#);
             for task in in_progress {
@@ -150,7 +151,7 @@ fn render_backlog_panel(in_progress: &[TaskView], queued: &[TaskView]) -> String
         }
 
         if !queued.is_empty() {
-            html.push_str(r#"<div class="section-label section-label-queued">Queued</div>"#);
+            html.push_str(r#"<div class="section-label section-label-queued"><span class="dot">●</span> Queued</div>"#);
             html.push_str(r#"<div class="state-queued">"#);
             for task in queued {
                 html.push_str(&render_task(task));
@@ -210,8 +211,9 @@ fn render_task(task: &TaskView) -> String {
     html.push_str(r#"<div class="task">"#);
     html.push_str(r#"<div class="task-header">"#);
     html.push_str(&format!(
-        r#"<span class="key">{}</span>"#,
-        html_escape(&task.short_key)
+        r#"<span class="key"><span class="key-prefix">{}</span><span class="key-rest">{}</span></span>"#,
+        html_escape(&task.key_prefix),
+        html_escape(&task.key_rest)
     ));
     html.push_str(&format!(
         r#"<span class="title">{}</span>"#,
@@ -239,16 +241,9 @@ async fn to_task_views(
     let mut views = Vec::with_capacity(tasks.len());
     for task in tasks {
         let prefix_len = prefixes.get(&task.key).copied().unwrap_or(8);
-        let short_key = task.key[..8.min(task.key.len())].to_string();
-        let short_key = format!(
-            "{}{}",
-            &short_key[..prefix_len.min(short_key.len())],
-            if prefix_len < short_key.len() {
-                &short_key[prefix_len..]
-            } else {
-                ""
-            }
-        );
+        let display_len = 8.min(task.key.len());
+        let key_prefix = task.key[..prefix_len.min(display_len)].to_string();
+        let key_rest = task.key[prefix_len.min(display_len)..display_len].to_string();
 
         // Check for subtasks
         let subtasks: Vec<Task> = sqlx::query_as(
@@ -267,7 +262,8 @@ async fn to_task_views(
             .count();
 
         views.push(TaskView {
-            short_key,
+            key_prefix,
+            key_rest,
             title: task.title.clone(),
             description: task.description.clone(),
             has_subtasks,
diff --git a/static/style.css b/static/style.css
index 77e771b..24d46a7 100644
--- a/static/style.css
+++ b/static/style.css
@@ -155,6 +155,10 @@ header .counts {
   margin-top: 0;
 }
 
+.section-label .dot {
+  margin-right: 4px;
+}
+
 .section-label-in-progress { color: var(--color-in-progress); }
 .section-label-queued      { color: var(--color-queued); }
 .section-label-done        { color: var(--color-done); }
@@ -179,10 +183,19 @@ header .counts {
 .task .key {
   font-family: var(--font-mono);
   font-size: var(--step-mono);
-  color: var(--color-accent);
   flex-shrink: 0;
 }
 
+.task .key-prefix {
+  color: var(--color-accent);
+  font-weight: 700;
+}
+
+.task .key-rest {
+  color: var(--color-text-muted);
+  font-weight: 400;
+}
+
 .task .title {
   font-size: var(--step-0);
   font-weight: 500;
@@ -216,6 +229,11 @@ header .counts {
   opacity: 0.75;
 }
 
+/* Icebox tasks slightly faded */
+.state-icebox .task {
+  opacity: 0.8;
+}
+
 
 /* === Empty states === */
 .empty {