diff options
author | Matthew Sotoudeh <matthewsot@outlook.com> | 2021-12-27 04:43:23 -0800 |
---|---|---|
committer | Matthew Sotoudeh <matthewsot@outlook.com> | 2021-12-27 04:43:23 -0800 |
commit | f0b5ed9e20eadb4595a88d1e79053c82aa2d6aa2 (patch) | |
tree | ed1ad35528134499598104f4ca437a69a663e300 | |
parent | 8c8ea69902c0bdff3d4d9c8d562689ea45da79c2 (diff) |
Also include the details
-rw-r--r-- | src/main.rs | 84 | ||||
-rw-r--r-- | stylesheet.css | 37 |
2 files changed, 107 insertions, 14 deletions
diff --git a/src/main.rs b/src/main.rs index 04d335e..e55ed85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ use std::path::Path; use std::str::FromStr; use std::convert::TryInto; use std::cmp::Ordering; +use std::collections::HashSet; +use std::collections::HashMap; use chrono::{Datelike, NaiveDate, NaiveTime, Weekday, Duration, Timelike, Local}; // use chrono::format::ParseError; @@ -31,7 +33,7 @@ fn parse_day_line(l: &str) -> Weekday { } fn parse_time(s_: &str) -> NaiveTime { - let formats = vec!["%H:%M%p", "%H:%M"]; + let formats = vec!["%l:%M%p", "%H:%M"]; let mut s = s_.to_string(); if !s.contains(":") { if s.ends_with("M") { @@ -76,10 +78,6 @@ fn parse_duration(s: &str) -> chrono::Duration { } fn handle_task_details(l: &str, t: &mut Task) { - if t.details.len() > 0 { - t.details.push(' '); - } - t.details.push_str(l.trim()); for tok in l.split(' ') { if tok.starts_with("+") { let tag = tok.get(1..).expect("Unexpected"); @@ -111,6 +109,11 @@ fn handle_task_details(l: &str, t: &mut Task) { } else { panic!("'{}' is not of the form Start+Duration or Start--End\n", timestr); } + } else { + if t.details.len() > 0 { + t.details.push(' '); + } + t.details.push_str(tok.trim()); } } } @@ -130,6 +133,13 @@ fn cmp_tasks(a: &Task, b: &Task) -> Ordering { } fn tasks_to_html(tasks: &Vec<Task>) -> String { + let public_tags = HashMap::from([ + ("busy", "I will be genuinely busy, e.g., a meeting with others."), + ("rough", "The nature of the event (e.g., a hike) makes it difficult to preduct the exact start/end times."), + ("tentative", "This event timing is only tentative."), + ("join-me", "This is an open event; if you're interested in attending with me please reach out!"), + ]); + let mut html = "<html><head><title>Calendar</title><link rel=\"stylesheet\" href=\"stylesheet.css\"></link></head><body>".to_string(); let today = Local::now().date().naive_local(); @@ -161,7 +171,8 @@ fn tasks_to_html(tasks: &Vec<Task>) -> String { html.push_str("</td>"); for day_of_week in 0..7 { // TODO: Use a smarter data structure for this. - let mut any_task = false; + let mut cell_tasks = Vec::new(); + let mut cell_public_tags = HashSet::new(); for i in week_task_ids.iter() { let task = &tasks[*i]; let task_day = task.date.weekday().num_days_from_monday(); @@ -173,15 +184,33 @@ fn tasks_to_html(tasks: &Vec<Task>) -> String { match [task.start_time, task.end_time] { [Some(start), Some(end)] => { if time >= start && time < end { - any_task = true; - break; + cell_tasks.push(i); + for tag in &task.tags { + if public_tags.contains_key(&tag.as_str()) { + cell_public_tags.insert(tag.to_string()); + } + } } } _ => continue } } - if any_task { - html.push_str("<td class=\"busy\"></td>"); + if cell_tasks.len() > 0 { + html.push_str("<td class=\"has-task"); + for tag in &cell_public_tags { + html.push_str(" tag-"); + html.push_str(tag.as_str()); + } + html.push_str("\">"); + html.push_str("<a href=\"#"); + html.push_str("task-"); + html.push_str(cell_tasks.first().expect("").to_string().as_str()); + html.push_str("\">has-task"); + for tag in &cell_public_tags { + html.push_str(", "); + html.push_str(tag.as_str()); + } + html.push_str("</a></td>"); } else { html.push_str("<td></td>"); } @@ -193,7 +222,40 @@ fn tasks_to_html(tasks: &Vec<Task>) -> String { break; } } - html.push_str("</table></body></html>"); + html.push_str("</table><ul>"); + for i in week_task_ids.iter() { + let task = &tasks[*i]; + html.push_str("<li id=\"task-"); + html.push_str(i.to_string().as_str()); + html.push_str("\">"); + html.push_str(task.date.format("%A %-m/%-d/%y ").to_string().as_str()); + match [task.start_time, task.end_time] { + [Some(start), Some(end)] => { + html.push_str(start.format("%l:%M%p").to_string().as_str()); + html.push_str(" -- "); + html.push_str(end.format("%l:%M%p").to_string().as_str()); + } + _ => (), + } + html.push_str("<ul>"); + if task.tags.contains(&"public".to_string()) { + html.push_str("<li><b>Description:</b> "); + html.push_str(task.details.as_str()); + html.push_str("</li>"); + } + for tag in &task.tags { + if public_tags.contains_key(&tag.as_str()) { + html.push_str("<li>Tagged <b>"); + html.push_str(tag.as_str()); + html.push_str(":</b> "); + html.push_str(public_tags.get(&tag.as_str()).expect("")); + html.push_str("</li>"); + } + } + html.push_str("</ul>"); + html.push_str("</li>"); + } + html.push_str("</ul></body></html>"); return html; } diff --git a/stylesheet.css b/stylesheet.css index ee55c50..03dd613 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,9 +1,40 @@ -table, th, td { +/*table, th, td {*/ +table { + border-collapse: collapse; +} +th, td { border: 1px solid black; border-collapse: collapse; + padding: 0; +} +th { + padding: 3px; +} + +.has-task { + background-color: #aaa; +} +.tag-busy { + background-color: red; +} +.tag-tentative { + /* https://www.quackit.com/css/codes/patterns/css_background_stripes.cfm */ + background-image: repeating-linear-gradient(165deg, #ccc, #ccc 10px, #dbdbdb 10px, #dbdbdb 20px); +} +.tag-rough { + border-style: dashed; + border-width: 2px; +} +.tag-join-me { + background-color: #2a2; +} +td a { + display: block; + text-decoration: none; + color: inherit; padding: 3px; } -.busy { - background-color: gray; +li:target { + background-color: #aeb; } |