From a1e219f0153128cf4688595545eb045e989e1136 Mon Sep 17 00:00:00 2001 From: asonix Date: Tue, 12 Jan 2021 22:34:25 -0600 Subject: [PATCH] Move date rendering, nested records, icons, profile page into toolkit --- toolkit/Cargo.toml | 1 + toolkit/scss/toolkit.scss | 310 +++++++++++++++++++++- toolkit/src/lib.rs | 78 ++++++ toolkit/templates/ago.rs.html | 15 ++ toolkit/templates/banner.rs.html | 11 + toolkit/templates/icon.rs.html | 31 +++ toolkit/templates/nested.rs.html | 11 + toolkit/templates/nested_children.rs.html | 5 + toolkit/templates/nested_node.rs.html | 5 + toolkit/templates/profile.rs.html | 49 ++++ 10 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 toolkit/templates/ago.rs.html create mode 100644 toolkit/templates/banner.rs.html create mode 100644 toolkit/templates/icon.rs.html create mode 100644 toolkit/templates/nested.rs.html create mode 100644 toolkit/templates/nested_children.rs.html create mode 100644 toolkit/templates/nested_node.rs.html create mode 100644 toolkit/templates/profile.rs.html diff --git a/toolkit/Cargo.toml b/toolkit/Cargo.toml index 97d4462..1c037d1 100644 --- a/toolkit/Cargo.toml +++ b/toolkit/Cargo.toml @@ -9,6 +9,7 @@ build = "src/build.rs" [dependencies] mime = "0.3.16" +chrono = "0.4.19" [build-dependencies] ructe = { version = "0.13.0", features = ["mime03", "sass"] } diff --git a/toolkit/scss/toolkit.scss b/toolkit/scss/toolkit.scss index 842baea..4696a8e 100644 --- a/toolkit/scss/toolkit.scss +++ b/toolkit/scss/toolkit.scss @@ -4,6 +4,7 @@ $white: #fff; $border-light: #e5e5e5; $light-background: #f5f5f5; $lighter-background: #f9f9f9; +$light-banner-background: #bbb; $primary: #c92a60; $primary-shadow: #c92a603b; $primary-border: #9d2a60; @@ -38,6 +39,13 @@ body { } } +img { + display: block; + width: 100%; + height: 100%; + object-fit: scale-down; +} + .toolkit-bar { background-color: $border-light; color: $dark; @@ -63,6 +71,93 @@ body { } } +.toolkit-icon--link { + display: block; + width: 128px; + height: 128px; + margin-right: 16px; + + .toolkit-icon { + border-color: $border-light; + background-color: $lighter-background; + } + &.toolkit-dark .toolkit-icon { + border-color: $dark-heading; + background-color: $dark; + } + + .toolkit-icon { + border-radius: 64px; + border-width: 3px; + border-style: solid; + height: 100%; + width: 100%; + overflow: hidden; + } + + &__small { + width: 64px; + height: 64px; + margin-right: 8px; + + .toolkit-icon { + border-radius: 32px; + } + } +} + +.toolkit-banner { + height: 300px; + width: 100%; + background-color: $light-banner-background; + + &.toolkit-dark { + background-color: $dark-heading; + } + + img { + object-fit: cover; + } +} + +.toolkit-profile { + background-color: $border-light; + color: $dark; + + &.toolkit-dark { + background-color: $dark-border; + color: $light-background; + } + + .toolkit-profile--content { + padding-bottom: 16px; + } + + .toolkit-profile--content--top { + margin-top: -86px; + display: flex; + justify-content: flex-start; + align-items: flex-start; + flex-wrap: wrap; + padding: 0 16px; + } + + .toolkit-profile--meta { + padding-top: 20px; + color: $light-background; + text-shadow: 1px 1px 1px $dark; + } + + .toolkit-profile--meta--display { + font-weight: 600; + font-size: 20px; + } + + .toolkit-profile--description { + padding: 16px; + } +} + .toolkit-link { color: $primary; &.toolkit-plain { @@ -171,7 +266,7 @@ body { .toolkit-centered { width: 100%; - max-width: 700px; + max-width: 900px; margin: 0 auto; } @@ -351,6 +446,96 @@ body { } } +.toolkit-time__long { + display: inline; +} +.toolkit-time__short { + display: none; +} + +.toolkit-nested { + .toolkit-nested--children, + .toolkit-nested--node { + border-color: $border-light; + } + &.toolkit-dark .toolkit-nested--children, + &.toolkit-dark .toolkit-nested--node { + border-color: $dark-border; + } + + .toolkit-nested--node { + border-top-width: 1px; + border-top-style: solid; + padding: 16px 0; + + &:last-child { + padding-bottom: 0; + } + } + .toolkit-nested--children { + padding-top: 16px; + margin-bottom: 16px; + } + + > .toolkit-nested--children { + padding-top: 0; + margin-bottom: 0; + + > .toolkit-nested--node:first-child { + border-top-width: 0; + padding-top: 0; + } + } + + > .toolkit-nested--children > .toolkit-nested--children, + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children, + + > .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children { + border-left-width: 4px; + border-left-style: solid; + padding-left: 16px; + } +} + +@media(max-width: 1300px) { + .toolkit-banner { + height: 233px; + } + + .toolkit-centered { + max-width: 700px; + } +} + @media(max-width: 700px) { .toolkit-input { width: 100%; @@ -382,3 +567,126 @@ body { align-items: center; } } + +@media(max-width: 700px) { + .toolkit-time__long { + display: none; + } + .toolkit-time__short { + display: inline; + } + + .toolkit-banner { + height: 33vw; + } +} + +@media(max-width: 680px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 660px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 640px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 620px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 600px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 580px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 560px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children > .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 540px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children > .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 520px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children > + .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 500px) { + .toolkit-nested > .toolkit-nested--children > .toolkit-nested--children { + border-left: 0; + padding-left: 0; + } +} + +@media(max-width: 400px) { + .toolkit-profile { + .toolkit-profile--content--top { + margin-top: -66px; + } + + .toolkit-profile--meta { + padding-top: 12px; + } + } + + .toolkit-icon--link { + width: 96px; + height: 96px; + + &__small { + width: 48px; + height: 48px; + } + } +} diff --git a/toolkit/src/lib.rs b/toolkit/src/lib.rs index e117822..bfe7787 100644 --- a/toolkit/src/lib.rs +++ b/toolkit/src/lib.rs @@ -15,3 +15,81 @@ pub use self::{ link::Link, text_input::TextInput, }; + +use chrono::{DateTime, Utc}; + +fn time_ago_long(time: DateTime) -> String { + let duration = chrono::Utc::now() - time; + if let Some(years) = + duration + .num_days() + .checked_div(365) + .and_then(|years| if years > 0 { Some(years) } else { None }) + { + if years == 1 { + format!("{} year ago", years) + } else { + format!("{} years ago", years) + } + } else if duration.num_weeks() > 0 { + if duration.num_weeks() == 1 { + format!("{} week ago", duration.num_weeks()) + } else { + format!("{} weeks ago", duration.num_weeks()) + } + } else if duration.num_days() > 0 { + if duration.num_days() == 1 { + format!("{} day ago", duration.num_days()) + } else { + format!("{} days ago", duration.num_days()) + } + } else if duration.num_hours() > 0 { + if duration.num_hours() == 1 { + format!("{} hour ago", duration.num_hours()) + } else { + format!("{} hours ago", duration.num_hours()) + } + } else if duration.num_minutes() > 0 { + if duration.num_minutes() == 1 { + format!("{} minute ago", duration.num_minutes()) + } else { + format!("{} minutes ago", duration.num_minutes()) + } + } else if duration.num_seconds() > 0 { + if duration.num_seconds() == 1 { + format!("{} second ago", duration.num_seconds()) + } else { + format!("{} seconds ago", duration.num_seconds()) + } + } else { + "now".to_owned() + } +} + +fn time_ago_short(time: DateTime) -> String { + let duration = chrono::Utc::now() - time; + if let Some(years) = + duration + .num_days() + .checked_div(365) + .and_then(|years| if years > 0 { Some(years) } else { None }) + { + format!("{}y", years) + } else if duration.num_weeks() > 0 { + format!("{}w", duration.num_weeks()) + } else if duration.num_days() > 0 { + format!("{}d", duration.num_days()) + } else if duration.num_hours() > 0 { + format!("{}h", duration.num_hours()) + } else if duration.num_minutes() > 0 { + format!("{}m", duration.num_minutes()) + } else if duration.num_seconds() > 0 { + format!("{}s", duration.num_seconds()) + } else { + "now".to_owned() + } +} + +fn time(time: chrono::DateTime) -> String { + time.format("%B %d, %Y, %I:%M %P").to_string() +} diff --git a/toolkit/templates/ago.rs.html b/toolkit/templates/ago.rs.html new file mode 100644 index 0000000..32c7818 --- /dev/null +++ b/toolkit/templates/ago.rs.html @@ -0,0 +1,15 @@ +@use chrono::{DateTime, Utc}; +@use crate::{Link, templates::link}; + +@(time: DateTime, dark: bool) + + + @:link(&Link::current_tab("#").title(&crate::time(time)).plain(true).dark(dark), { + @crate::time_ago_long(time) + }) + + + @:link(&Link::current_tab("#").title(&crate::time(time)).plain(true).dark(dark), { + @crate::time_ago_short(time) + }) + diff --git a/toolkit/templates/banner.rs.html b/toolkit/templates/banner.rs.html new file mode 100644 index 0000000..ab9e623 --- /dev/null +++ b/toolkit/templates/banner.rs.html @@ -0,0 +1,11 @@ +@(dark: bool, img: Content) + +@if dark { +
+ @:img() +
+} else { +
+ @:img() +
+} diff --git a/toolkit/templates/icon.rs.html b/toolkit/templates/icon.rs.html new file mode 100644 index 0000000..9f1522c --- /dev/null +++ b/toolkit/templates/icon.rs.html @@ -0,0 +1,31 @@ +@(href: &str, small: bool, dark: bool, picture: Content) + +@if small { + @if dark { + +
+ @:picture() +
+
+ } else { + +
+ @:picture() +
+
+ } +} else { + @if dark { + +
+ @:picture() +
+
+ } else { + +
+ @:picture() +
+
+ } +} diff --git a/toolkit/templates/nested.rs.html b/toolkit/templates/nested.rs.html new file mode 100644 index 0000000..a491d95 --- /dev/null +++ b/toolkit/templates/nested.rs.html @@ -0,0 +1,11 @@ +@(dark: bool, body: Content) + +@if dark { +
+ @:body() +
+} else { +
+ @:body() +
+} diff --git a/toolkit/templates/nested_children.rs.html b/toolkit/templates/nested_children.rs.html new file mode 100644 index 0000000..ec17c33 --- /dev/null +++ b/toolkit/templates/nested_children.rs.html @@ -0,0 +1,5 @@ +@(body: Content) + +
+ @:body() +
diff --git a/toolkit/templates/nested_node.rs.html b/toolkit/templates/nested_node.rs.html new file mode 100644 index 0000000..d313326 --- /dev/null +++ b/toolkit/templates/nested_node.rs.html @@ -0,0 +1,5 @@ +@(body: Content) + +
+ @:body() +
diff --git a/toolkit/templates/profile.rs.html b/toolkit/templates/profile.rs.html new file mode 100644 index 0000000..83abd42 --- /dev/null +++ b/toolkit/templates/profile.rs.html @@ -0,0 +1,49 @@ +@use crate::templates::{icon, banner}; + +@(view_path: &str, display_name: Option<&str>, handle: &str, description: Option<&str>, dark: bool, icon_img: Content, banner_img: Content) + +@if dark { +
+ @:banner(dark, { @:banner_img() }) +
+
+ @:icon(view_path, false, dark, { @:icon_img() }) +
+
+ @if let Some(display_name) = display_name { + @display_name + } else { +   + } +
+
@handle
+
+
+ @if let Some(description) = description { +
@description
+ } +
+
+} else { +
+ @:banner(dark, { @:banner_img() }) +
+
+ @:icon(view_path, false, dark, { @:icon_img() }) +
+
+ @if let Some(display_name) = display_name { + @display_name + } else { +   + } +
+
@handle
+
+
+ @if let Some(description) = description { +
@description
+ } +
+
+}