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. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
108 lines
3.8 KiB
Rust
108 lines
3.8 KiB
Rust
use ely_gpui_component::{
|
|
calendar::Event,
|
|
theme::{ActiveTheme, TextSize},
|
|
};
|
|
use gpui::{
|
|
AnyElement, App, Entity, IntoElement, ParentElement, SharedString, Styled, Window, div,
|
|
};
|
|
use jiff::{Timestamp, ToSpan, civil::Date, tz::TimeZone};
|
|
|
|
mod months;
|
|
mod times;
|
|
|
|
use super::Page;
|
|
use crate::{script::Step, ui::keep};
|
|
|
|
pub const PAGE: Page = Page {
|
|
number: 30,
|
|
slug: "calendar",
|
|
title: "Calendar",
|
|
summary: "Days, weeks, months and years, and what happens in them.",
|
|
render,
|
|
script: SCRIPT,
|
|
};
|
|
|
|
const SCRIPT: &[Step] = &[
|
|
Step::DownAt("calendar-month", 285.0, 230.0),
|
|
Step::UpAt("calendar-month", 285.0, 230.0),
|
|
Step::Key("right"),
|
|
Step::Key("down"),
|
|
Step::Wait(150),
|
|
Step::Shot("month-cursor"),
|
|
Step::Key("pagedown"),
|
|
Step::Wait(200),
|
|
Step::Shot("month-next"),
|
|
Step::Key("pageup"),
|
|
Step::DownAt("calendar-year", 150.0, 150.0),
|
|
Step::UpAt("calendar-year", 150.0, 150.0),
|
|
Step::Key("right"),
|
|
Step::Wait(150),
|
|
Step::Shot("year-cursor"),
|
|
Step::DownAt("calendar-week", 560.0, 300.0),
|
|
Step::DragTo("calendar-week", 560.0, 380.0),
|
|
Step::Wait(150),
|
|
Step::Shot("week-drafting"),
|
|
Step::UpAt("calendar-week", 560.0, 380.0),
|
|
Step::Wait(200),
|
|
Step::Shot("week-made"),
|
|
];
|
|
|
|
/// What a demo says it did, under it.
|
|
fn quiet(text: SharedString, cx: &App) -> impl IntoElement + use<> {
|
|
let theme = cx.theme();
|
|
div()
|
|
.text_size(theme.text_size(TextSize::Sm))
|
|
.text_color(theme.colors.fg_muted)
|
|
.child(text)
|
|
}
|
|
|
|
/// The gallery's zone and today in it.
|
|
fn here() -> (TimeZone, Date) {
|
|
let zone = TimeZone::try_system().expect("the gallery reads the system time zone");
|
|
let today = Timestamp::now().to_zoned(zone.clone()).date();
|
|
(zone, today)
|
|
}
|
|
|
|
/// The page's events, which a drag on the week or day adds to.
|
|
fn plan(window: &mut Window, cx: &mut App) -> Entity<Vec<Event>> {
|
|
let (zone, today) = here();
|
|
keep("calendar-events", || events(today, &zone), window, cx)
|
|
}
|
|
|
|
/// A studio's weeks around today: meetings, a crowded day, an offsite, a trip past a weekend, a night shoot past midnight.
|
|
fn events(today: Date, zone: &TimeZone) -> Vec<Event> {
|
|
let day = |offset: i64| today.checked_add(offset.days()).expect("a day nearby");
|
|
let at = |offset: i64, hour: i8, minute: i8| {
|
|
day(offset)
|
|
.at(hour, minute, 0, 0)
|
|
.to_zoned(zone.clone())
|
|
.expect("the zone holds the hour")
|
|
.timestamp()
|
|
};
|
|
vec![
|
|
Event::timed("standup", "Studio stand-up", at(0, 9, 30), at(0, 9, 45), 0),
|
|
Event::timed("review", "Design review", at(0, 11, 0), at(0, 12, 0), 3).place("Model room"),
|
|
Event::timed("lunch", "Lunch with Ana", at(0, 12, 30), at(0, 13, 30), 5),
|
|
Event::timed("samples", "Plaster samples", at(0, 15, 0), at(0, 16, 0), 2),
|
|
Event::timed("client", "Client call", at(0, 17, 0), at(0, 17, 30), 1),
|
|
Event::timed("crit", "Crit", at(-3, 14, 0), at(-3, 15, 30), 3).place("Studio 2"),
|
|
Event::timed("print", "Print run", at(-9, 10, 0), at(-9, 11, 0), 2),
|
|
Event::all_day("offsite", "Studio offsite", day(2), day(4), 4),
|
|
Event::timed("night", "Night shoot", at(5, 21, 0), at(6, 2, 0), 6).place("Atrium"),
|
|
Event::all_day("trip", "Site visit · Lisbon", day(9), day(13), 7),
|
|
Event::timed("models", "Model photos", at(11, 10, 0), at(11, 12, 0), 0),
|
|
Event::all_day("launch", "Launch", day(18), day(18), 1),
|
|
]
|
|
}
|
|
|
|
fn render(window: &mut Window, cx: &mut App) -> AnyElement {
|
|
div()
|
|
.child(months::month(window, cx))
|
|
.child(months::mini(window, cx))
|
|
.child(times::week(window, cx))
|
|
.child(times::day(window, cx))
|
|
.child(months::year(window, cx))
|
|
.child(months::marks(cx))
|
|
.into_any_element()
|
|
}
|