Improve life calendar and add it to header
This commit is contained in:
@ -9,8 +9,10 @@ use crate::auth::MasterPassword;
|
||||
use crate::database::migrations::migrate;
|
||||
use crate::database::unversioned::global::schema_version;
|
||||
use crate::database::SCHEMA_VERSION;
|
||||
use crate::routes::pages::weeks::BirthDate;
|
||||
use crate::util::EventNotifier;
|
||||
use bincode::{deserialize, serialize};
|
||||
use chrono::NaiveDate;
|
||||
use dotenv::dotenv;
|
||||
use rocket_contrib::serve::StaticFiles;
|
||||
use rocket_contrib::templates::Template;
|
||||
@ -29,6 +31,10 @@ async fn main() -> io::Result<()> {
|
||||
})
|
||||
.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)?;
|
||||
match sled.insert(
|
||||
serialize(schema_version::K).unwrap(),
|
||||
@ -56,6 +62,7 @@ async fn main() -> io::Result<()> {
|
||||
}))
|
||||
.manage(sled)
|
||||
.manage(master_pass)
|
||||
.manage(birth_date)
|
||||
.manage(EventNotifier::new())
|
||||
.mount("/static", StaticFiles::from("static"))
|
||||
.mount(
|
||||
|
||||
@ -1,30 +1,49 @@
|
||||
use crate::auth::Authorized;
|
||||
use crate::status_json::StatusJson;
|
||||
use chrono::{Duration, Local, NaiveDate};
|
||||
use rocket::get;
|
||||
use itertools::Itertools;
|
||||
use rocket::{get, State};
|
||||
use rocket_contrib::templates::Template;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::borrow::Cow;
|
||||
use std::iter::{once, repeat};
|
||||
|
||||
pub struct BirthDate(pub NaiveDate);
|
||||
|
||||
#[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>;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct WeekCtx<'a> {
|
||||
border_color: Color<'a>,
|
||||
fill_color: Option<Color<'a>>,
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
struct Style<'a> {
|
||||
border: Color<'a>,
|
||||
fill: Option<Color<'a>>,
|
||||
}
|
||||
|
||||
impl<'a, T> From<T> for WeekCtx<'a>
|
||||
where
|
||||
T: Into<Cow<'a, str>>,
|
||||
{
|
||||
fn from(color: T) -> Self {
|
||||
WeekCtx {
|
||||
border_color: color.into(),
|
||||
fill_color: None,
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
struct PeriodCtx<'a> {
|
||||
style: Style<'a>,
|
||||
weeks: Vec<()>,
|
||||
}
|
||||
|
||||
impl<'a> Style<'a> {
|
||||
fn border<C>(border: C) -> Self
|
||||
where
|
||||
C: Into<Cow<'a, str>>,
|
||||
{
|
||||
Style {
|
||||
border: border.into(),
|
||||
fill: 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)]
|
||||
struct Ctx<'a> {
|
||||
weeks_left: i64,
|
||||
weeks: Vec<WeekCtx<'a>>,
|
||||
periods: Vec<PeriodCtx<'a>>,
|
||||
}
|
||||
|
||||
let now = Local::now().date();
|
||||
|
||||
// TODO: change this
|
||||
let birth_date = NaiveDate::from_ymd(1999, 01, 01);
|
||||
let birth_date = birth_date.0;
|
||||
|
||||
let lived: Duration = now.naive_local() - birth_date;
|
||||
let one_year = Duration::days(365);
|
||||
@ -51,40 +68,41 @@ pub fn weeks(_auth: Authorized) -> Result<Template, StatusJson> {
|
||||
|
||||
let color_birth = "green";
|
||||
let color_child = "#ff0";
|
||||
let color_teen = "#f0f";
|
||||
let color_adult = "#f33";
|
||||
let color_teen = "#f33";
|
||||
let color_adult = "#f0f";
|
||||
let color_today = "wheat";
|
||||
let color_future = "#eee";
|
||||
|
||||
let context = Ctx {
|
||||
weeks_left: life_expectancy - lived.num_weeks(),
|
||||
weeks: once(WeekCtx {
|
||||
border_color: color_birth.into(),
|
||||
fill_color: Some(color_birth.into()),
|
||||
})
|
||||
// childhood
|
||||
.chain((1..childhood_end).map(|_| color_child.into()))
|
||||
// teens
|
||||
.chain((childhood_end..teenage_end).map(|_| color_teen.into()))
|
||||
// adulthood
|
||||
.chain((teenage_end..).map(|_| color_adult.into()))
|
||||
// take from above for lived number of weeks
|
||||
.take(lived.num_weeks() as usize - 1)
|
||||
// add a week for this week
|
||||
.chain(once(WeekCtx {
|
||||
border_color: color_today.into(),
|
||||
fill_color: Some(color_today.into()),
|
||||
}))
|
||||
// fill remaining weeks until death
|
||||
.chain(repeat(color_future.into()))
|
||||
.take((life_expectancy - uncertainty * 2) as usize)
|
||||
// add some fading around expected life span
|
||||
.chain((0..uncertainty).rev().map(|i| {
|
||||
let m = u8::MAX as i64;
|
||||
let alpha = ((m * i) / (uncertainty)) as u8;
|
||||
format!("#eeeeee{:02x}", alpha).into()
|
||||
}))
|
||||
.collect(),
|
||||
periods: once(Style::fill(color_birth, color_birth))
|
||||
// childhood
|
||||
.chain((1..childhood_end).map(|_| Style::border(color_child)))
|
||||
// teens
|
||||
.chain((childhood_end..teenage_end).map(|_| Style::border(color_teen)))
|
||||
// adulthood
|
||||
.chain((teenage_end..).map(|_| Style::border(color_adult)))
|
||||
// take from above for lived number of weeks
|
||||
.take(lived.num_weeks() as usize - 1)
|
||||
// add a week for this week
|
||||
.chain(once(Style::fill(color_today, color_today)))
|
||||
// fill remaining weeks until death
|
||||
.chain(repeat(Style::border(color_future)))
|
||||
.take((life_expectancy - uncertainty * 2) as usize)
|
||||
// add some fading around expected life span
|
||||
.chain((0..uncertainty).rev().map(|i| {
|
||||
let m = u8::MAX as i64;
|
||||
let alpha = ((m * i) / (uncertainty)) as u8;
|
||||
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(),
|
||||
};
|
||||
|
||||
Ok(Template::render("weeks", &context))
|
||||
|
||||
@ -241,20 +241,26 @@ ul.striped_list > li:nth-child(odd) ul li:nth-child(odd) { background-color:#30
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.life_calendar > p {
|
||||
.life_calendar > span {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.life_calendar > span > p {
|
||||
height: 0.5em;
|
||||
width: 0.5em;
|
||||
margin: 0.1em;
|
||||
border: solid 0.05em;
|
||||
border-radius: 0.5em;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.life_calendar_ticker {
|
||||
position: relative;
|
||||
top: -20rem;
|
||||
top: -16rem;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
font-size: 10rem;
|
||||
font-family: "Ubuntu Mono";
|
||||
}
|
||||
|
||||
.life_calendar_ticker > h1 {
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
<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="/history">🕮</a>
|
||||
<a title="Session List" href="/history">🕮</a>
|
||||
-
|
||||
<a title="Source Code" href="https://git.nubo.sh/hulthe/stl">🖹</a>
|
||||
</h1>
|
||||
|
||||
@ -5,7 +5,11 @@
|
||||
{{> header}}
|
||||
|
||||
<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 class="life_calendar_ticker">
|
||||
<h2>circa</h2>
|
||||
|
||||
Reference in New Issue
Block a user