glacier-web-cli 0.5.0

Command-line tool for creating and running Glacier applications.
{% props year: i64, month: i64, selected: i64 = 0, range_start: i64 = 0, range_end: i64 = 0, name: String = "", nav_path: String = "" %}
{#- Days of this month: `selected`, or `range_start`..`range_end`. With `name`, days submit their ISO date under it; with `nav_path`, the arrows link to `?month=YYYY-MM`. -#}
{%- let (caption, prev_month, next_month, weeks) = {
  use ::glacier::chrono::{Datelike, Days, Months, NaiveDate};
  let first = NaiveDate::from_ymd_opt(year as i32, month as u32, 1).expect("a valid year and month");
  let next = first + Months::new(1);
  let start = first - Days::new(first.weekday().num_days_from_monday() as u64);
  let count = ((next - start).num_days() + 6) / 7 * 7;
  let today = ::glacier::time::today();
  let days: Vec<_> = (0..count as u64).map(|n| {
    let date = start + Days::new(n);
    let inside = date.month() as i64 == month;
    let day = date.day() as i64;
    let range = if !inside || range_start == 0 { "" } else if day == range_start { "start" } else if day == range_end { "end" } else if day > range_start && day < range_end { "middle" } else { "" };
    (date.format("%-d %B %Y").to_string(), date.format("%Y-%m-%d").to_string(), day, !inside, date == today, inside && day == selected, range)
  }).collect();
  let weeks: Vec<Vec<_>> = days.chunks(7).map(|week| week.to_vec()).collect();
  (first.format("%B %Y").to_string(), (first - Months::new(1)).format("%Y-%m").to_string(), next.format("%Y-%m").to_string(), weeks)
} %}
<div class="ui-calendar" data-ui="calendar" data-mode="{% if range_start > 0 %}range{% else %}single{% end %}" data-week-start="1">
  <div class="ui-calendar-head">
    {%- if nav_path.is_empty() %}
    <button class="ui-calendar-nav" type="button" data-dir="prev" aria-label="Previous month"><svg class="ui-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg></button>
    {%- else %}
    <a class="ui-calendar-nav" data-dir="prev" aria-label="Previous month" href="{{ nav_path }}?month={{ prev_month }}"><svg class="ui-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg></a>
    {%- end %}
    <div class="ui-calendar-caption" aria-live="polite">{{ caption }}</div>
    {%- if nav_path.is_empty() %}
    <button class="ui-calendar-nav" type="button" data-dir="next" aria-label="Next month"><svg class="ui-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg></button>
    {%- else %}
    <a class="ui-calendar-nav" data-dir="next" aria-label="Next month" href="{{ nav_path }}?month={{ next_month }}"><svg class="ui-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg></a>
    {%- end %}
  </div>
  <table role="grid" aria-label="{{ caption }}">
    <thead><tr><th scope="col" abbr="Monday">Mo</th><th scope="col" abbr="Tuesday">Tu</th><th scope="col" abbr="Wednesday">We</th><th scope="col" abbr="Thursday">Th</th><th scope="col" abbr="Friday">Fr</th><th scope="col" abbr="Saturday">Sa</th><th scope="col" abbr="Sunday">Su</th></tr></thead>
    <tbody>
      {%- for week in weeks.iter() %}
      <tr>
        {%- for (label, iso, day, outside, today, chosen, range) in week.iter() %}
        <td{% if !range.is_empty() %} data-range="{{ range }}"{% end %}><button class="ui-day"{% if name.is_empty() %} type="button"{% else %} type="submit" name="{{ name }}" value="{{ iso }}"{% end %} aria-label="{{ label }}"{% if *outside %} data-outside{% end %}{% if *today %} data-today{% end %}{% if *chosen %} aria-selected="true"{% end %}{% if *range == "start" || *range == "end" %} data-range="{{ range }}"{% end %}>{{ day }}</button></td>
        {%- end %}
      </tr>
      {%- end %}
    </tbody>
  </table>
</div>