Move date rendering, nested records, icons, profile page into toolkit

This commit is contained in:
asonix 2021-01-12 22:34:25 -06:00
parent 67f3430751
commit a1e219f015
10 changed files with 515 additions and 1 deletions

View file

@ -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"] }

View file

@ -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;
}
}
}

View file

@ -15,3 +15,81 @@ pub use self::{
link::Link,
text_input::TextInput,
};
use chrono::{DateTime, Utc};
fn time_ago_long(time: DateTime<Utc>) -> 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<Utc>) -> 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<chrono::Utc>) -> String {
time.format("%B %d, %Y, %I:%M %P").to_string()
}

View file

@ -0,0 +1,15 @@
@use chrono::{DateTime, Utc};
@use crate::{Link, templates::link};
@(time: DateTime<Utc>, dark: bool)
<span class="toolkit-time__long">
@:link(&Link::current_tab("#").title(&crate::time(time)).plain(true).dark(dark), {
@crate::time_ago_long(time)
})
</span>
<span class="toolkit-time__short">
@:link(&Link::current_tab("#").title(&crate::time(time)).plain(true).dark(dark), {
@crate::time_ago_short(time)
})
</span>

View file

@ -0,0 +1,11 @@
@(dark: bool, img: Content)
@if dark {
<div class="toolkit-banner toolkit-dark">
@:img()
</div>
} else {
<div class="toolkit-banner">
@:img()
</div>
}

View file

@ -0,0 +1,31 @@
@(href: &str, small: bool, dark: bool, picture: Content)
@if small {
@if dark {
<a href="@href" class="toolkit-icon--link toolkit-icon--link__small toolkit-dark">
<div class="toolkit-icon">
@:picture()
</div>
</a>
} else {
<a href="@href" class="toolkit-icon--link toolkit-icon--link__small">
<div class="toolkit-icon">
@:picture()
</div>
</a>
}
} else {
@if dark {
<a href="@href" class="toolkit-icon--link toolkit-dark">
<div class="toolkit-icon">
@:picture()
</div>
</a>
} else {
<a href="@href" class="toolkit-icon--link">
<div class="toolkit-icon">
@:picture()
</div>
</a>
}
}

View file

@ -0,0 +1,11 @@
@(dark: bool, body: Content)
@if dark {
<div class="toolkit-nested toolkit-dark">
@:body()
</div>
} else {
<div class="toolkit-nested">
@:body()
</div>
}

View file

@ -0,0 +1,5 @@
@(body: Content)
<div class="toolkit-nested--children">
@:body()
</div>

View file

@ -0,0 +1,5 @@
@(body: Content)
<div class="toolkit-nested--node">
@:body()
</div>

View file

@ -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 {
<div class="toolkit-profile toolkit-dark">
@:banner(dark, { @:banner_img() })
<div class="toolkit-profile--content">
<div class="toolkit-profile--content--top">
@:icon(view_path, false, dark, { @:icon_img() })
<div class="toolkit-profile--meta">
<div class="toolkit-profile--meta--display">
@if let Some(display_name) = display_name {
@display_name
} else {
&nbsp;
}
</div>
<div class="toolkit-profile--meta--handle">@handle</div>
</div>
</div>
@if let Some(description) = description {
<div class="toolkit-profile--description">@description</div>
}
</div>
</div>
} else {
<div class="toolkit-profile">
@:banner(dark, { @:banner_img() })
<div class="toolkit-profile--content">
<div class="toolkit-profile--content--top">
@:icon(view_path, false, dark, { @:icon_img() })
<div class="toolkit-profile--meta">
<div class="toolkit-profile--meta--display">
@if let Some(display_name) = display_name {
@display_name
} else {
&nbsp;
}
</div>
<div class="toolkit-profile--meta--handle">@handle</div>
</div>
</div>
@if let Some(description) = description {
<div class="toolkit-profile--description">@description</div>
}
</div>
</div>
}