Improve life calendar and add it to header

This commit is contained in:
2021-05-31 23:19:41 +02:00
parent 6f984ed6fb
commit 653853b4f6
5 changed files with 91 additions and 52 deletions

View File

@ -9,8 +9,10 @@ use crate::auth::MasterPassword;
use crate::database::migrations::migrate; use crate::database::migrations::migrate;
use crate::database::unversioned::global::schema_version; use crate::database::unversioned::global::schema_version;
use crate::database::SCHEMA_VERSION; use crate::database::SCHEMA_VERSION;
use crate::routes::pages::weeks::BirthDate;
use crate::util::EventNotifier; use crate::util::EventNotifier;
use bincode::{deserialize, serialize}; use bincode::{deserialize, serialize};
use chrono::NaiveDate;
use dotenv::dotenv; use dotenv::dotenv;
use rocket_contrib::serve::StaticFiles; use rocket_contrib::serve::StaticFiles;
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
@ -29,6 +31,10 @@ async fn main() -> io::Result<()> {
}) })
.into(); .into();
let birth_date: BirthDate = env::var("BIRTH_DATE")
.map(|s| BirthDate(s.parse().expect("failed to parse BIRTH_DATE")))
.unwrap_or_else(|_| BirthDate(NaiveDate::from_ymd(2000, 1, 1)));
let mut sled = sled::open(db_path)?; let mut sled = sled::open(db_path)?;
match sled.insert( match sled.insert(
serialize(schema_version::K).unwrap(), serialize(schema_version::K).unwrap(),
@ -56,6 +62,7 @@ async fn main() -> io::Result<()> {
})) }))
.manage(sled) .manage(sled)
.manage(master_pass) .manage(master_pass)
.manage(birth_date)
.manage(EventNotifier::new()) .manage(EventNotifier::new())
.mount("/static", StaticFiles::from("static")) .mount("/static", StaticFiles::from("static"))
.mount( .mount(

View File

@ -1,30 +1,49 @@
use crate::auth::Authorized; use crate::auth::Authorized;
use crate::status_json::StatusJson; use crate::status_json::StatusJson;
use chrono::{Duration, Local, NaiveDate}; use chrono::{Duration, Local, NaiveDate};
use rocket::get; use itertools::Itertools;
use rocket::{get, State};
use rocket_contrib::templates::Template; use rocket_contrib::templates::Template;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::borrow::Cow; use std::borrow::Cow;
use std::iter::{once, repeat}; use std::iter::{once, repeat};
pub struct BirthDate(pub NaiveDate);
#[get("/weeks")] #[get("/weeks")]
pub fn weeks(_auth: Authorized) -> Result<Template, StatusJson> { pub fn weeks(_auth: Authorized, birth_date: State<BirthDate>) -> Result<Template, StatusJson> {
type Color<'a> = Cow<'a, str>; type Color<'a> = Cow<'a, str>;
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct WeekCtx<'a> { struct Style<'a> {
border_color: Color<'a>, border: Color<'a>,
fill_color: Option<Color<'a>>, fill: Option<Color<'a>>,
} }
impl<'a, T> From<T> for WeekCtx<'a> #[derive(Debug, Clone, Serialize, Deserialize)]
struct PeriodCtx<'a> {
style: Style<'a>,
weeks: Vec<()>,
}
impl<'a> Style<'a> {
fn border<C>(border: C) -> Self
where where
T: Into<Cow<'a, str>>, C: Into<Cow<'a, str>>,
{ {
fn from(color: T) -> Self { Style {
WeekCtx { border: border.into(),
border_color: color.into(), fill: None,
fill_color: None, }
}
fn fill<C>(border: C, fill: C) -> Self
where
C: Into<Cow<'a, str>>,
{
Style {
border: border.into(),
fill: Some(fill.into()),
} }
} }
} }
@ -32,13 +51,11 @@ pub fn weeks(_auth: Authorized) -> Result<Template, StatusJson> {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
struct Ctx<'a> { struct Ctx<'a> {
weeks_left: i64, weeks_left: i64,
weeks: Vec<WeekCtx<'a>>, periods: Vec<PeriodCtx<'a>>,
} }
let now = Local::now().date(); let now = Local::now().date();
let birth_date = birth_date.0;
// TODO: change this
let birth_date = NaiveDate::from_ymd(1999, 01, 01);
let lived: Duration = now.naive_local() - birth_date; let lived: Duration = now.naive_local() - birth_date;
let one_year = Duration::days(365); let one_year = Duration::days(365);
@ -51,39 +68,40 @@ pub fn weeks(_auth: Authorized) -> Result<Template, StatusJson> {
let color_birth = "green"; let color_birth = "green";
let color_child = "#ff0"; let color_child = "#ff0";
let color_teen = "#f0f"; let color_teen = "#f33";
let color_adult = "#f33"; let color_adult = "#f0f";
let color_today = "wheat"; let color_today = "wheat";
let color_future = "#eee"; let color_future = "#eee";
let context = Ctx { let context = Ctx {
weeks_left: life_expectancy - lived.num_weeks(), weeks_left: life_expectancy - lived.num_weeks(),
weeks: once(WeekCtx { periods: once(Style::fill(color_birth, color_birth))
border_color: color_birth.into(),
fill_color: Some(color_birth.into()),
})
// childhood // childhood
.chain((1..childhood_end).map(|_| color_child.into())) .chain((1..childhood_end).map(|_| Style::border(color_child)))
// teens // teens
.chain((childhood_end..teenage_end).map(|_| color_teen.into())) .chain((childhood_end..teenage_end).map(|_| Style::border(color_teen)))
// adulthood // adulthood
.chain((teenage_end..).map(|_| color_adult.into())) .chain((teenage_end..).map(|_| Style::border(color_adult)))
// take from above for lived number of weeks // take from above for lived number of weeks
.take(lived.num_weeks() as usize - 1) .take(lived.num_weeks() as usize - 1)
// add a week for this week // add a week for this week
.chain(once(WeekCtx { .chain(once(Style::fill(color_today, color_today)))
border_color: color_today.into(),
fill_color: Some(color_today.into()),
}))
// fill remaining weeks until death // fill remaining weeks until death
.chain(repeat(color_future.into())) .chain(repeat(Style::border(color_future)))
.take((life_expectancy - uncertainty * 2) as usize) .take((life_expectancy - uncertainty * 2) as usize)
// add some fading around expected life span // add some fading around expected life span
.chain((0..uncertainty).rev().map(|i| { .chain((0..uncertainty).rev().map(|i| {
let m = u8::MAX as i64; let m = u8::MAX as i64;
let alpha = ((m * i) / (uncertainty)) as u8; let alpha = ((m * i) / (uncertainty)) as u8;
format!("#eeeeee{:02x}", alpha).into() Style::border(format!("#eeeeee{:02x}", alpha))
})) }))
// group weeks by color to save space
.group_by(|style| style.clone())
.into_iter()
.map(|(style, weeks)| PeriodCtx {
style,
weeks: vec![(); weeks.count()],
})
.collect(), .collect(),
}; };

View File

@ -241,20 +241,26 @@ ul.striped_list > li:nth-child(odd) ul li:nth-child(odd) { background-color:#30
margin: auto; margin: auto;
} }
.life_calendar > p { .life_calendar > span {
display: contents;
}
.life_calendar > span > p {
height: 0.5em; height: 0.5em;
width: 0.5em; width: 0.5em;
margin: 0.1em; margin: 0.1em;
border: solid 0.05em; border: solid 0.05em;
border-radius: 0.5em; border-radius: 0.5em;
background-color: inherit;
} }
.life_calendar_ticker { .life_calendar_ticker {
position: relative; position: relative;
top: -20rem; top: -16rem;
width: 100%; width: 100%;
text-align: center; text-align: center;
font-size: 10rem; font-size: 10rem;
font-family: "Ubuntu Mono";
} }
.life_calendar_ticker > h1 { .life_calendar_ticker > h1 {

View File

@ -1,7 +1,11 @@
<h1 class="title"> <h1 class="title">
<a href="/stats">🗠</a> <a title="Life Calendar" href="/weeks">🕱</a>
-
<a title="Session Stats" href="/stats">🗠</a>
- -
<a href="/">stl</a> <a href="/">stl</a>
- -
<a href="/history">🕮</a> <a title="Session List" href="/history">🕮</a>
-
<a title="Source Code" href="https://git.nubo.sh/hulthe/stl">🖹</a>
</h1> </h1>

View File

@ -5,7 +5,11 @@
{{> header}} {{> header}}
<div class="life_calendar"> <div class="life_calendar">
{{#each weeks}}<p style="color: {{this.border_color}}{{#if this.fill_color}}; background-color: {{this.fill_color}}{{/if}}"></p>{{/each}} {{#each periods}}
<span style="color: {{this.style.border}}{{#if this.style.fill}}; background-color: {{this.style.fill}}{{/if}}">
{{#each weeks}}<p></p>{{/each}}
</span>
{{/each}}
</div> </div>
<div class="life_calendar_ticker"> <div class="life_calendar_ticker">
<h2>circa</h2> <h2>circa</h2>