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::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(
|
||||||
|
|||||||
@ -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(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user