use autumn_web::Markup;
use autumn_web::html;
use autumn_web::reexports::chrono::{DateTime, SecondsFormat, TimeZone, Utc};
use super::{Behavior, marker};
use crate::markup::{Attributes, common, element};
#[derive(Debug, Clone, PartialEq, Eq)]
#[must_use]
pub struct LocalTime {
at: DateTime<Utc>,
format: TimeFormat,
fallback: Option<String>,
extra: Attributes,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum TimeFormat {
#[default]
DateTime,
Date,
Time,
Relative,
}
impl TimeFormat {
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::DateTime => "datetime",
Self::Date => "date",
Self::Time => "time",
Self::Relative => "relative",
}
}
const fn pattern(self) -> &'static str {
match self {
Self::Date => "%Y-%m-%d",
Self::Time => "%H:%M UTC",
Self::DateTime | Self::Relative => "%Y-%m-%d %H:%M UTC",
}
}
}
impl LocalTime {
pub fn new<Tz: TimeZone>(at: &DateTime<Tz>) -> Self {
Self {
at: at.with_timezone(&Utc),
format: TimeFormat::DateTime,
fallback: None,
extra: Vec::new(),
}
}
pub const fn format(mut self, format: TimeFormat) -> Self {
self.format = format;
self
}
pub fn fallback(mut self, text: impl Into<String>) -> Self {
self.fallback = Some(text.into());
self
}
#[must_use]
pub fn attributes(&self) -> Attributes {
let mut attributes = vec![
(
"datetime",
self.at.to_rfc3339_opts(SecondsFormat::Secs, true),
),
marker(Behavior::LocalTime),
];
if self.format != TimeFormat::DateTime {
attributes.push(("data-vanilla-local-time", self.format.name().to_owned()));
}
attributes.extend(self.extra.iter().cloned());
attributes
}
#[must_use]
pub fn render(&self) -> Markup {
let text = self
.fallback
.clone()
.unwrap_or_else(|| self.at.format(self.format.pattern()).to_string());
element("time", &self.attributes(), html! { (text) })
}
}
common!(LocalTime);
impl maud::Render for LocalTime {
fn render(&self) -> Markup {
Self::render(self)
}
}