Tint home greeting glyph by time of day
The design's home hero pairs the greeting with a Sunrise glyph in the warm horizon orange (#e89a6e). Previously we showed `IconName::Sun` in `ACCENT_LIGHT` regardless of phase, so an evening user saw a noon sun next to "Good evening, Alex". Promote the day phase to a `DayPhase` enum so hero.rs can pick the glyph + tint per phase: warm orange Sun in the morning, amber Sun in the afternoon, cool violet Moon in the evening. Tests now compare against the enum instead of the former `&'static str` wrapper. Bonus: third quick-launch pill swaps from "Open History" (Undo2) to "Open Notion" (BookOpen → notion.so) to match the design's third pill. cargo test --workspace: 440 passed, 0 failed.
This commit is contained in:
@@ -12,21 +12,28 @@ use crate::shell::chrome::SERIF_FAMILY;
|
|||||||
use super::style::{
|
use super::style::{
|
||||||
ARROW_CHIP_BG, PILL_BG, PILL_BG_HOVER, SEARCH_BG, card_shadow, soft_shadow,
|
ARROW_CHIP_BG, PILL_BG, PILL_BG_HOVER, SEARCH_BG, card_shadow, soft_shadow,
|
||||||
};
|
};
|
||||||
|
use super::time::DayPhase;
|
||||||
|
|
||||||
pub(crate) fn render_hero(greeting: String, cx: &mut Context<ElyShell>) -> AnyElement {
|
pub(crate) fn render_hero(
|
||||||
|
greeting: String,
|
||||||
|
phase: DayPhase,
|
||||||
|
cx: &mut Context<ElyShell>,
|
||||||
|
) -> AnyElement {
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.flex_col()
|
.flex_col()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap(px(14.0))
|
.gap(px(14.0))
|
||||||
.child(render_greeting_row(greeting))
|
.child(render_greeting_row(greeting, phase))
|
||||||
.child(render_serif_headline())
|
.child(render_serif_headline())
|
||||||
.child(render_search_bar(cx))
|
.child(render_search_bar(cx))
|
||||||
.child(render_suggestion_pills(cx))
|
.child(render_suggestion_pills(cx))
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_greeting_row(text: String) -> AnyElement {
|
fn render_greeting_row(text: String, phase: DayPhase) -> AnyElement {
|
||||||
|
let (icon, color) = phase_glyph(phase);
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
@@ -35,13 +42,25 @@ fn render_greeting_row(text: String) -> AnyElement {
|
|||||||
.text_color(rgb(colors::INK_3))
|
.text_color(rgb(colors::INK_3))
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.text_color(rgb(colors::ACCENT_LIGHT))
|
.text_color(rgb(color))
|
||||||
.child(IconName::Sun),
|
.child(icon),
|
||||||
)
|
)
|
||||||
.child(text)
|
.child(text)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pair the greeting glyph to the time of day. Morning gets the warm
|
||||||
|
/// horizon orange the design uses for the Sunrise icon (#e89a6e); afternoon
|
||||||
|
/// keeps the same Sun glyph in a higher-key amber; evening swaps to the
|
||||||
|
/// Moon in the cool slate-violet that bookends the wallpaper themes.
|
||||||
|
fn phase_glyph(phase: DayPhase) -> (IconName, u32) {
|
||||||
|
match phase {
|
||||||
|
DayPhase::Morning => (IconName::Sun, 0xe89a6e),
|
||||||
|
DayPhase::Afternoon => (IconName::Sun, 0xf5b563),
|
||||||
|
DayPhase::Evening => (IconName::Moon, 0x7c6cf7),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn render_serif_headline() -> AnyElement {
|
fn render_serif_headline() -> AnyElement {
|
||||||
div()
|
div()
|
||||||
.font_family(SERIF_FAMILY)
|
.font_family(SERIF_FAMILY)
|
||||||
@@ -117,11 +136,11 @@ fn render_suggestion_pills(cx: &mut Context<ElyShell>) -> AnyElement {
|
|||||||
|shell, window, cx| shell.cycle_to_next_space(window, cx),
|
|shell, window, cx| shell.cycle_to_next_space(window, cx),
|
||||||
))
|
))
|
||||||
.child(render_pill(
|
.child(render_pill(
|
||||||
"pill-open-history",
|
"pill-open-notion",
|
||||||
IconName::Undo2,
|
IconName::BookOpen,
|
||||||
"Open History",
|
"Open Notion",
|
||||||
cx,
|
cx,
|
||||||
|shell, window, cx| shell.open_internal_tab("ely://history", window, cx),
|
|shell, window, cx| shell.open_internal_tab("https://www.notion.so", window, cx),
|
||||||
))
|
))
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ pub(crate) fn render_home_page(
|
|||||||
snapshot: &BrowserSnapshot,
|
snapshot: &BrowserSnapshot,
|
||||||
cx: &mut Context<ElyShell>,
|
cx: &mut Context<ElyShell>,
|
||||||
) -> AnyElement {
|
) -> AnyElement {
|
||||||
let greeting = time::greeting_for_now(SystemTime::now(), &snapshot.active_profile_name);
|
let now = SystemTime::now();
|
||||||
|
let greeting = time::greeting_for_now(now, &snapshot.active_profile_name);
|
||||||
|
let phase = time::day_phase_for(now);
|
||||||
|
|
||||||
div()
|
div()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
@@ -31,7 +33,7 @@ pub(crate) fn render_home_page(
|
|||||||
.pb(px(28.0))
|
.pb(px(28.0))
|
||||||
.flex()
|
.flex()
|
||||||
.flex_col()
|
.flex_col()
|
||||||
.child(hero::render_hero(greeting, cx))
|
.child(hero::render_hero(greeting, phase, cx))
|
||||||
.child(div().mt(px(48.0)).child(favorites::render_favorites_grid(snapshot, cx)))
|
.child(div().mt(px(48.0)).child(favorites::render_favorites_grid(snapshot, cx)))
|
||||||
.child(div().mt(px(16.0)).child(recap::render_recap(snapshot, cx))),
|
.child(div().mt(px(16.0)).child(recap::render_recap(snapshot, cx))),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,15 +1,43 @@
|
|||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
pub(crate) fn greeting_for_now(now: SystemTime, name: &str) -> String {
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
let phase = match now.duration_since(UNIX_EPOCH) {
|
pub(crate) enum DayPhase {
|
||||||
Ok(duration) => {
|
Morning,
|
||||||
let local_seconds = duration.as_secs() as i64;
|
Afternoon,
|
||||||
let day_seconds = local_seconds.rem_euclid(86_400);
|
Evening,
|
||||||
let hour = (day_seconds / 3_600) as u32;
|
|
||||||
day_phase(hour)
|
|
||||||
}
|
}
|
||||||
Err(_) => "today",
|
|
||||||
|
impl DayPhase {
|
||||||
|
fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
DayPhase::Morning => "morning",
|
||||||
|
DayPhase::Afternoon => "afternoon",
|
||||||
|
DayPhase::Evening => "evening",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn day_phase_for(now: SystemTime) -> DayPhase {
|
||||||
|
let hour = match now.duration_since(UNIX_EPOCH) {
|
||||||
|
Ok(duration) => {
|
||||||
|
let day_seconds = (duration.as_secs() as i64).rem_euclid(86_400);
|
||||||
|
(day_seconds / 3_600) as u32
|
||||||
|
}
|
||||||
|
Err(_) => 12,
|
||||||
};
|
};
|
||||||
|
day_phase_from_hour(hour)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn day_phase_from_hour(hour_utc: u32) -> DayPhase {
|
||||||
|
match hour_utc {
|
||||||
|
5..=11 => DayPhase::Morning,
|
||||||
|
12..=17 => DayPhase::Afternoon,
|
||||||
|
_ => DayPhase::Evening,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn greeting_for_now(now: SystemTime, name: &str) -> String {
|
||||||
|
let phase = day_phase_for(now).as_str();
|
||||||
|
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
format!("Good {phase}")
|
format!("Good {phase}")
|
||||||
@@ -18,13 +46,6 @@ pub(crate) fn greeting_for_now(now: SystemTime, name: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn day_phase(hour_utc: u32) -> &'static str {
|
|
||||||
match hour_utc {
|
|
||||||
5..=11 => "morning",
|
|
||||||
12..=17 => "afternoon",
|
|
||||||
_ => "evening",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn relative_time_label(now: SystemTime, then: SystemTime) -> String {
|
pub(crate) fn relative_time_label(now: SystemTime, then: SystemTime) -> String {
|
||||||
let elapsed = match now.duration_since(then) {
|
let elapsed = match now.duration_since(then) {
|
||||||
@@ -53,22 +74,22 @@ pub(crate) fn relative_time_label(now: SystemTime, then: SystemTime) -> String {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{day_phase, greeting_for_now, relative_time_label};
|
use super::{DayPhase, day_phase_from_hour, greeting_for_now, relative_time_label};
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn day_phase_assigns_morning_to_seven_am() {
|
fn day_phase_assigns_morning_to_seven_am() {
|
||||||
assert_eq!(day_phase(7), "morning");
|
assert_eq!(day_phase_from_hour(7), DayPhase::Morning);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn day_phase_assigns_afternoon_to_one_pm() {
|
fn day_phase_assigns_afternoon_to_one_pm() {
|
||||||
assert_eq!(day_phase(13), "afternoon");
|
assert_eq!(day_phase_from_hour(13), DayPhase::Afternoon);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn day_phase_assigns_evening_to_eleven_pm() {
|
fn day_phase_assigns_evening_to_eleven_pm() {
|
||||||
assert_eq!(day_phase(23), "evening");
|
assert_eq!(day_phase_from_hour(23), DayPhase::Evening);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user