Add post and event cards, shared calendar sheet and per-event ICS; rework past events and next-event card
This commit is contained in:
1 parent
d328adac5c
commit
b2dc033de1
33 files changed
+1150
-206
No files matched your search
@@ -7,8 +7,10 @@ namespace Elternbeirat.Web.Features.Events;
|
||||
/// Formats the date range of an <see cref="Event"/> for display in German.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Shared by the full event list and the home-page events embed, so both render
|
||||
/// dates the same way.
|
||||
/// Shared by the full event list, the home-page events embed and the next-event
|
||||
/// card, so all render dates the same way: <see cref="Range"/> as the full date,
|
||||
/// the <c>Sheet…</c> methods and <see cref="Span"/> for the calendar sheet and the
|
||||
/// time line beside it, <see cref="PastDays"/> and <see cref="PastTime"/> for the list of past events.
|
||||
/// <para>
|
||||
/// This is the event counterpart to
|
||||
/// <see cref="Posts.PostDateFormat"/>, which formats a plain
|
||||
@@ -27,6 +29,11 @@ public static class EventDateFormat
|
||||
/// </summary>
|
||||
private const string ShortDate = "d. MMMM yyyy";
|
||||
|
||||
/// <summary>
|
||||
/// Date format for the list of past events, which is grouped by year.
|
||||
/// </summary>
|
||||
private const string DayMonth = "d. MMMM";
|
||||
|
||||
/// <summary>
|
||||
/// Formats the date range of an event.
|
||||
/// </summary>
|
||||
@@ -54,13 +61,136 @@ public static class EventDateFormat
|
||||
(var start, null, var hasTime)
|
||||
=> Stamp(start, LongDate, hasTime),
|
||||
(var start, { } end, true) when end.Date == start.Date
|
||||
=> $"{start.ToString(LongDate, Cultures.German)}, {start.ToString("HH:mm", Cultures.German)}–{end.ToString("HH:mm", Cultures.German)} Uhr",
|
||||
=> $"{start.ToString(LongDate, Cultures.German)}, {Clock(start)}–{Clock(end)} Uhr",
|
||||
(var start, { } end, false) when end.Date == start.Date
|
||||
=> Stamp(start, LongDate, withTime: false),
|
||||
(var start, { } end, var hasTime)
|
||||
=> $"{Stamp(start, LongDate, hasTime)} – {Stamp(end, ShortDate, hasTime)}",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The short month for the top band of a calendar sheet.
|
||||
/// </summary>
|
||||
/// <param name="value">The event's start.</param>
|
||||
/// <returns>The German short month without its period, e.g. <c>Okt</c> or <c>März</c>.</returns>
|
||||
/// <remarks>
|
||||
/// Returned in normal case; the sheet's CSS sets it in capitals. The period of the
|
||||
/// abbreviation (<c>Okt.</c>) is dropped because on a sheet it reads as a stray dot.
|
||||
/// </remarks>
|
||||
/// <seealso cref="CalendarSheet"/>
|
||||
public static string SheetMonth(DateTime value)
|
||||
=> value.ToString("MMM", Cultures.German).TrimEnd('.');
|
||||
|
||||
/// <summary>
|
||||
/// The day of the month for the large number on a calendar sheet.
|
||||
/// </summary>
|
||||
/// <param name="value">The event's start.</param>
|
||||
/// <returns>The day without a leading zero, e.g. <c>8</c>.</returns>
|
||||
public static string SheetDay(DateTime value)
|
||||
=> value.Day.ToString(Cultures.German);
|
||||
|
||||
/// <summary>
|
||||
/// The short weekday for the bottom of a calendar sheet.
|
||||
/// </summary>
|
||||
/// <param name="value">The event's start.</param>
|
||||
/// <returns>The German short weekday without its period, e.g. <c>Do</c>.</returns>
|
||||
public static string SheetWeekday(DateTime value)
|
||||
=> value.ToString("ddd", Cultures.German).TrimEnd('.');
|
||||
|
||||
/// <summary>
|
||||
/// The time line beside a calendar sheet: what the sheet itself cannot show.
|
||||
/// </summary>
|
||||
/// <param name="event">The event to format.</param>
|
||||
/// <returns>
|
||||
/// Depending on <see cref="Event.End"/> and <see cref="Event.HasTime"/>:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>No end: <c>19:30 Uhr</c></description></item>
|
||||
/// <item><description>Same day: <c>19:30–21:00 Uhr</c></description></item>
|
||||
/// <item><description>Several days: <c>09:00 Uhr bis Sonntag, 11. Oktober 2026, 13:00 Uhr</c></description></item>
|
||||
/// <item><description>Several days, no time: <c>bis Sonntag, 11. Oktober 2026</c></description></item>
|
||||
/// <item><description>One day, no time: an empty string; the sheet says it all.</description></item>
|
||||
/// </list>
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The sheet shows the start day only, so a multi-day event must name its last
|
||||
/// day here, with the weekday, as the sheet does for the first one.
|
||||
/// </remarks>
|
||||
public static string Span(Event @event)
|
||||
=> (@event.Start, @event.End, @event.HasTime) switch
|
||||
{
|
||||
(var start, { } end, var hasTime) when end.Date != start.Date
|
||||
=> (hasTime ? Clock(start) + " Uhr " : "") + "bis " + Stamp(end, LongDate, hasTime),
|
||||
(var start, null, true)
|
||||
=> $"{Clock(start)} Uhr",
|
||||
(var start, { } end, true)
|
||||
=> $"{Clock(start)}–{Clock(end)} Uhr",
|
||||
_ => "",
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The day column of a past event in the folded-up list on the events page.
|
||||
/// </summary>
|
||||
/// <param name="event">The event to format.</param>
|
||||
/// <returns>
|
||||
/// Day and full month, depending on <see cref="Event.End"/>:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>One day: <c>13. November</c></description></item>
|
||||
/// <item><description>Several days in one month: <c>8.–9. Februar</c></description></item>
|
||||
/// <item><description>Across a month: <c>30. Januar – 2. Februar</c></description></item>
|
||||
/// <item><description>Across a year: <c>30. Dezember – 2. Januar 2027</c></description></item>
|
||||
/// </list>
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The list is grouped by the start year under its own small heading, so the
|
||||
/// year is only named where the end leaves that year. The weekday is left out
|
||||
/// to keep the column short; the time follows the title (<see cref="PastTime"/>).
|
||||
/// </remarks>
|
||||
public static string PastDays(Event @event)
|
||||
=> (@event.Start, @event.End) switch
|
||||
{
|
||||
(var start, { } end) when end.Year != start.Year
|
||||
=> $"{start.ToString(DayMonth, Cultures.German)} – {end.ToString(ShortDate, Cultures.German)}",
|
||||
(var start, { } end) when end.Month != start.Month
|
||||
=> $"{start.ToString(DayMonth, Cultures.German)} – {end.ToString(DayMonth, Cultures.German)}",
|
||||
(var start, { } end) when end.Day != start.Day
|
||||
=> $"{start.Day.ToString(Cultures.German)}.–{end.ToString(DayMonth, Cultures.German)}",
|
||||
(var start, _)
|
||||
=> start.ToString(DayMonth, Cultures.German),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The time after the title of a past event in the folded-up list.
|
||||
/// </summary>
|
||||
/// <param name="event">The event to format.</param>
|
||||
/// <returns>
|
||||
/// Depending on <see cref="Event.HasTime"/> and <see cref="Event.End"/>:
|
||||
/// <list type="bullet">
|
||||
/// <item><description>No time: an empty string; nothing is shown.</description></item>
|
||||
/// <item><description>No end: <c>19:00 Uhr</c></description></item>
|
||||
/// <item><description>Same day: <c>19:00–21:00 Uhr</c></description></item>
|
||||
/// <item><description>Several days: the start time only, <c>09:00 Uhr</c></description></item>
|
||||
/// </list>
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// For several days the day column already shows the span; a time range beside
|
||||
/// it would read as the daily hours, so only the start time is given.
|
||||
/// </remarks>
|
||||
public static string PastTime(Event @event)
|
||||
=> (@event.HasTime, @event.End) switch
|
||||
{
|
||||
(false, _) => "",
|
||||
(true, { } end) when end.Date != @event.Start.Date => $"{Clock(@event.Start)} Uhr",
|
||||
_ => Span(@event),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Formats the clock time of a point in time.
|
||||
/// </summary>
|
||||
/// <param name="value">The date and time.</param>
|
||||
/// <returns>The time as e.g. <c>19:30</c>.</returns>
|
||||
private static string Clock(DateTime value)
|
||||
=> value.ToString("HH:mm", Cultures.German);
|
||||
|
||||
/// <summary>
|
||||
/// Formats a single point in time as a date with an optional time.
|
||||
/// </summary>
|
||||
|
||||
Reference in new issue
Block a user