autumn_plugin_vanilla/behaviors/
local_time.rs1use autumn_web::Markup;
2use autumn_web::html;
3use autumn_web::reexports::chrono::{DateTime, SecondsFormat, TimeZone, Utc};
4
5use super::{Behavior, marker};
6use crate::markup::{Attributes, common, element};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
30#[must_use]
31pub struct LocalTime {
32 at: DateTime<Utc>,
33 format: TimeFormat,
34 fallback: Option<String>,
35 extra: Attributes,
36}
37
38#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
40#[non_exhaustive]
41pub enum TimeFormat {
42 #[default]
44 DateTime,
45 Date,
47 Time,
49 Relative,
51}
52
53impl TimeFormat {
54 #[must_use]
56 pub const fn name(self) -> &'static str {
57 match self {
58 Self::DateTime => "datetime",
59 Self::Date => "date",
60 Self::Time => "time",
61 Self::Relative => "relative",
62 }
63 }
64
65 const fn pattern(self) -> &'static str {
67 match self {
68 Self::Date => "%Y-%m-%d",
69 Self::Time => "%H:%M UTC",
70 Self::DateTime | Self::Relative => "%Y-%m-%d %H:%M UTC",
71 }
72 }
73}
74
75impl LocalTime {
76 pub fn new<Tz: TimeZone>(at: &DateTime<Tz>) -> Self {
78 Self {
79 at: at.with_timezone(&Utc),
80 format: TimeFormat::DateTime,
81 fallback: None,
82 extra: Vec::new(),
83 }
84 }
85
86 pub const fn format(mut self, format: TimeFormat) -> Self {
88 self.format = format;
89 self
90 }
91
92 pub fn fallback(mut self, text: impl Into<String>) -> Self {
95 self.fallback = Some(text.into());
96 self
97 }
98
99 #[must_use]
101 pub fn attributes(&self) -> Attributes {
102 let mut attributes = vec![
103 (
104 "datetime",
105 self.at.to_rfc3339_opts(SecondsFormat::Secs, true),
106 ),
107 marker(Behavior::LocalTime),
108 ];
109 if self.format != TimeFormat::DateTime {
110 attributes.push(("data-vanilla-local-time", self.format.name().to_owned()));
111 }
112 attributes.extend(self.extra.iter().cloned());
113 attributes
114 }
115
116 #[must_use]
118 pub fn render(&self) -> Markup {
119 let text = self
120 .fallback
121 .clone()
122 .unwrap_or_else(|| self.at.format(self.format.pattern()).to_string());
123 element("time", &self.attributes(), html! { (text) })
124 }
125}
126
127common!(LocalTime);
128
129impl maud::Render for LocalTime {
130 fn render(&self) -> Markup {
131 Self::render(self)
132 }
133}