TimeGrid sets days side by side under a column of hours. Each event is a card by its hours, clipped to each day it touches, and events that overlap share the width in lanes. A drag on empty time makes an event by quarter hours through forms::pen; a drag on an event's lower edge, on the day it ends, moves its end, each drag checked against its owner. The grid opens at half past seven, or an hour and a half before now when today is shown and that is later. CurrentTimeIndicator marks the minute now on today and moves with the clock. TimezoneOverlay adds another zone's hours beside the grid's. AllDayRow lays whole days across their columns in lanes. CalendarWeekView and CalendarDayView are one view of seven days or one: a header that steps and comes back to today, the days' names stacked so they fit narrow columns, the whole days, then the hours.
79 lines
2.2 KiB
Rust
79 lines
2.2 KiB
Rust
use gpui::{
|
|
App, ElementId, InteractiveElement, IntoElement, ParentElement, RenderOnce, Styled, Window, div,
|
|
};
|
|
use jiff::{Timestamp, tz::TimeZone};
|
|
|
|
use crate::{
|
|
theme::ActiveTheme,
|
|
typography::{format, fresh},
|
|
};
|
|
|
|
/// A line across a day of a time grid at the minute now, with a dot where it starts. It moves with the clock.
|
|
#[derive(IntoElement)]
|
|
pub struct CurrentTimeIndicator {
|
|
id: ElementId,
|
|
zone: Option<TimeZone>,
|
|
now: Option<Timestamp>,
|
|
}
|
|
|
|
impl CurrentTimeIndicator {
|
|
pub fn new(id: impl Into<ElementId>) -> Self {
|
|
Self {
|
|
id: id.into(),
|
|
zone: None,
|
|
now: None,
|
|
}
|
|
}
|
|
|
|
/// The zone its minute reads in; the system's otherwise.
|
|
pub fn zone(mut self, zone: TimeZone) -> Self {
|
|
self.zone = Some(zone);
|
|
self
|
|
}
|
|
|
|
/// The moment it marks; the clock's otherwise.
|
|
pub fn now(mut self, now: Timestamp) -> Self {
|
|
self.now = Some(now);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl RenderOnce for CurrentTimeIndicator {
|
|
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
|
let zone = self
|
|
.zone
|
|
.unwrap_or_else(|| format::system_zone("current time indicator"));
|
|
if self.now.is_none() {
|
|
fresh((self.id.clone(), "clock"), window, cx);
|
|
}
|
|
let now = self.now.unwrap_or_else(Timestamp::now).to_zoned(zone);
|
|
let minute = f32::from(now.hour()) * 60.0 + f32::from(now.minute());
|
|
let theme = cx.theme();
|
|
let (hour, dot) = (theme.calendar().hour, theme.status_dot() * 1.5);
|
|
div()
|
|
.debug_selector(|| "now-line".into())
|
|
.absolute()
|
|
.top(hour * (minute / 60.0))
|
|
.left_0()
|
|
.right_0()
|
|
.h_0()
|
|
.child(
|
|
div()
|
|
.absolute()
|
|
.left_0()
|
|
.right_0()
|
|
.border_t_2()
|
|
.border_color(theme.colors.accent),
|
|
)
|
|
.child(
|
|
div()
|
|
.absolute()
|
|
.top(dot * -0.5)
|
|
.left(dot * -0.5)
|
|
.size(dot)
|
|
.rounded_full()
|
|
.bg(theme.colors.accent),
|
|
)
|
|
}
|
|
}
|