90 lines
4.1 KiB
C#
90 lines
4.1 KiB
C#
namespace Htmx.ApiDemo.Templates.Components;
|
|
|
|
/// <summary>
|
|
/// shadcn-style TimePicker. Syncs hour+minute inputs to a hidden HH:MM field via inline JS.
|
|
/// </summary>
|
|
public sealed class TimePicker : TimePickerBase
|
|
{
|
|
private readonly byte[] _uniqueIdData;
|
|
private readonly byte[] _nameData;
|
|
private readonly byte[] _use12hData;
|
|
private readonly byte[] _labelData;
|
|
private readonly byte[] _descriptionData;
|
|
private readonly byte[] _defaultHourData;
|
|
private readonly byte[] _defaultMinuteData;
|
|
private readonly byte[] _defaultValueData;
|
|
private readonly byte[] _hourMinData;
|
|
private readonly byte[] _hourMaxData;
|
|
private readonly byte[] _amPmToggleData;
|
|
|
|
public TimePicker(
|
|
string name = "time",
|
|
TimeOnly? selected = null,
|
|
string label = "",
|
|
string description = "",
|
|
bool use12h = false)
|
|
{
|
|
var time = selected ?? TimeOnly.FromDateTime(DateTime.Now);
|
|
var uid = Guid.NewGuid().ToString("N")[..8]; // short unique suffix
|
|
|
|
_uniqueIdData = uid.ToUtf8Bytes();
|
|
_nameData = name.ToUtf8Bytes();
|
|
_use12hData = (use12h ? "true" : "false").ToUtf8Bytes();
|
|
_defaultValueData = time.ToString("HH:mm").ToUtf8Bytes();
|
|
|
|
_labelData = string.IsNullOrEmpty(label)
|
|
? []
|
|
: $"""<span class="text-sm font-medium leading-none">{label}</span>""".ToUtf8Bytes();
|
|
|
|
_descriptionData = string.IsNullOrEmpty(description)
|
|
? []
|
|
: $"""<p class="text-xs text-muted-foreground">{description}</p>""".ToUtf8Bytes();
|
|
|
|
if (use12h)
|
|
{
|
|
int hour12 = time.Hour % 12;
|
|
if (hour12 == 0) hour12 = 12;
|
|
bool isPm = time.Hour >= 12;
|
|
|
|
_defaultHourData = hour12.ToString().ToUtf8Bytes();
|
|
_defaultMinuteData = time.Minute.ToString("D2").ToUtf8Bytes();
|
|
_hourMinData = "1".ToUtf8Bytes();
|
|
_hourMaxData = "12".ToUtf8Bytes();
|
|
_amPmToggleData = BuildAmPmToggle(isPm);
|
|
}
|
|
else
|
|
{
|
|
_defaultHourData = time.Hour.ToString("D2").ToUtf8Bytes();
|
|
_defaultMinuteData = time.Minute.ToString("D2").ToUtf8Bytes();
|
|
_hourMinData = "0".ToUtf8Bytes();
|
|
_hourMaxData = "23".ToUtf8Bytes();
|
|
_amPmToggleData = [];
|
|
}
|
|
}
|
|
|
|
private static byte[] BuildAmPmToggle(bool isPm)
|
|
{
|
|
var amSel = isPm ? "" : " selected";
|
|
var pmSel = isPm ? " selected" : "";
|
|
return $"""
|
|
<select class="timepicker-ampm h-10 rounded-md border border-input bg-background px-2 text-sm
|
|
focus:outline-none focus:ring-2 focus:ring-ring">
|
|
<option value="AM"{amSel}>AM</option>
|
|
<option value="PM"{pmSel}>PM</option>
|
|
</select>
|
|
""".ToUtf8Bytes();
|
|
}
|
|
|
|
protected override void RenderUniqueId(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_uniqueIdData);
|
|
protected override void RenderName(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_nameData);
|
|
protected override void RenderUse12h(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_use12hData);
|
|
protected override void RenderLabel(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_labelData);
|
|
protected override void RenderDescription(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_descriptionData);
|
|
protected override void RenderDefaultHour(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_defaultHourData);
|
|
protected override void RenderDefaultMinute(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_defaultMinuteData);
|
|
protected override void RenderDefaultValue(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_defaultValueData);
|
|
protected override void RenderHourMin(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_hourMinData);
|
|
protected override void RenderHourMax(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_hourMaxData);
|
|
protected override void RenderAmPmToggle(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_amPmToggleData);
|
|
}
|