56 lines
2.3 KiB
C#
56 lines
2.3 KiB
C#
namespace Htmx.ApiDemo.Templates.Components;
|
|
|
|
/// <summary>
|
|
/// shadcn-style Accordion. Items collapse/expand client-side via components.js.
|
|
/// Pass a list of (Title, Content) tuples; set openIndex to expand one by default (-1 = all closed).
|
|
/// </summary>
|
|
public sealed class Accordion : AccordionBase
|
|
{
|
|
private const string ChevronSvg =
|
|
"""<svg class="accordion-chevron h-4 w-4 shrink-0 transition-transform duration-200" """ +
|
|
"""xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" """ +
|
|
"""stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>""";
|
|
|
|
private readonly byte[] _idData;
|
|
private readonly byte[] _itemsData;
|
|
|
|
public Accordion(string id, IEnumerable<(string Title, string Content)> items, int openIndex = -1)
|
|
{
|
|
_idData = id.ToUtf8Bytes();
|
|
|
|
var list = items.ToList();
|
|
var sb = new System.Text.StringBuilder();
|
|
|
|
for (int i = 0; i < list.Count; i++)
|
|
{
|
|
var (title, content) = list[i];
|
|
var expanded = i == openIndex;
|
|
var height = expanded ? "auto" : "0";
|
|
var opacity = expanded ? "1" : "0";
|
|
|
|
sb.Append($"""
|
|
<div class="accordion-item border-b border-border">
|
|
<h3 class="flex">
|
|
<button type="button"
|
|
class="accordion-trigger flex flex-1 items-center justify-between py-4 font-medium
|
|
transition-all hover:underline text-left"
|
|
aria-expanded="{(expanded ? "true" : "false")}">
|
|
{title}
|
|
{ChevronSvg}
|
|
</button>
|
|
</h3>
|
|
<div class="accordion-panel overflow-hidden text-sm transition-all duration-200"
|
|
style="height:{height};opacity:{opacity}">
|
|
<div class="pb-4 pt-0">{content}</div>
|
|
</div>
|
|
</div>
|
|
""");
|
|
}
|
|
|
|
_itemsData = sb.ToString().ToUtf8Bytes();
|
|
}
|
|
|
|
protected override void RenderId(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_idData);
|
|
protected override void RenderItems(HtmxRenderContext ctx) => ctx.Writer.WriteUtf8(_itemsData);
|
|
}
|