Add D-prefixed Blazor wrappers for every daisyUI 5 component
Components/Daisy/ wraps all 69 components in daisyUI's llms.txt, grouped by daisyUI's categories (Actions, DataDisplay, Navigation, Feedback, DataInput, Layout, Mockup), with part components where daisyUI has repeating parts (DTab, DMenuItem, DTimelineItem, ...). - Each enum maps to whole literal class names in a switch, so Tailwind's scanner generates them. Nothing is concatenated. - Value-holding fields derive from DInputBase<TValue>, Blazor's InputBase, so @bind-Value and EditForm validation work. Invalid fields get the component's *-error class. - Open and active state lives in C# (@bind-IsOpen, @bind-Active) and is rendered with daisyUI's *-open modifiers. DDropdown adds an outside-click layer and Escape. No component uses JS interop. - The one exception is DCalendar, which wraps the Cally web component, vendored as wwwroot/vendor/cally.js (0.9.2, MIT). /styleguide (not linked) renders every component in all its colours, sizes and states, with a theme and hue picker that previews without saving. neo.css follows what the styleguide showed: - select keeps daisyUI's arrow; - skeleton-text isn't sunk; - the phone mockup and dock are raised; - active menu items and OTP digits are inset; - a joined accordion is raised as one block. The primary, secondary and accent colours are deeper, so they still read as text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
8e03d12a3e
commit
90e4b9200c
127 files changed
+6962
-17
No files matched your search
@@ -0,0 +1,46 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Accordion: https://daisyui.com/components/accordion/ . Instead of daisyUI's radio group, the open item is an
|
||||
index in C# (@bind-Active, -1 = none). Each DAccordionItem registers itself through the cascading value and renders a
|
||||
DCollapse that is open only while its index is Active. The cascading value isn't fixed, so every item re-renders
|
||||
whenever the accordion does. *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
<CascadingValue Value="this">
|
||||
@ChildContent
|
||||
</CascadingValue>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
/// <summary>Index of the open item, in registration order; -1 when all are closed.</summary>
|
||||
[Parameter] public int Active { get; set; } = -1;
|
||||
[Parameter] public EventCallback<int> ActiveChanged { get; set; }
|
||||
[Parameter] public DCollapseIcon Icon { get; set; }
|
||||
/// <summary>Join the items into one block (join join-vertical, join-item).</summary>
|
||||
[Parameter] public bool Joined { get; set; }
|
||||
|
||||
readonly List<DAccordionItem> items = new();
|
||||
|
||||
string CssClass => Cx(Joined ? "join join-vertical rounded-box neo-raised" : "flex flex-col gap-2", Class);
|
||||
|
||||
internal int IndexOf(DAccordionItem item) => items.IndexOf(item);
|
||||
|
||||
internal void Add(DAccordionItem item)
|
||||
{
|
||||
items.Add(item);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
internal void Remove(DAccordionItem item)
|
||||
{
|
||||
items.Remove(item);
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
internal async Task Select(int index)
|
||||
{
|
||||
Active = index;
|
||||
await ActiveChanged.InvokeAsync(index);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
@inherits DComponentBase
|
||||
@implements IDisposable
|
||||
|
||||
@* One item of a DAccordion: a DCollapse (so collapse + neo-raised, keyboard and aria-expanded come from there) whose
|
||||
open state is the accordion's Active index. Opening it closes the others; clicking it while open closes it. *@
|
||||
<DCollapse @attributes="AdditionalAttributes" IsOpen="@IsOpen" IsOpenChanged="OnIsOpenChanged" Icon="@Parent.Icon"
|
||||
Disabled="@Disabled" HeaderClass="@HeaderClass" ContentClass="@ContentClass" Header="@Header"
|
||||
Class="@Cx(Parent.Joined ? "join-item shadow-none!" : null, Class)">
|
||||
@ChildContent
|
||||
</DCollapse>
|
||||
|
||||
@code {
|
||||
[CascadingParameter] DAccordion Parent { get; set; }
|
||||
[Parameter] public RenderFragment Header { get; set; }
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public bool Disabled { get; set; }
|
||||
[Parameter] public string HeaderClass { get; set; }
|
||||
[Parameter] public string ContentClass { get; set; }
|
||||
|
||||
bool IsOpen => Parent.Active >= 0 && Parent.Active == Parent.IndexOf(this);
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
if (Parent is null)
|
||||
throw new InvalidOperationException($"{nameof(DAccordionItem)} must be inside a {nameof(DAccordion)}.");
|
||||
Parent.Add(this);
|
||||
}
|
||||
|
||||
Task OnIsOpenChanged(bool isOpen) => Parent.Select(isOpen ? Parent.IndexOf(this) : -1);
|
||||
|
||||
public void Dispose() => Parent?.Remove(this);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Aura: https://daisyui.com/components/aura/ . ChildContent must be exactly one element (a btn, card, …).
|
||||
The light takes the text colour (Color, or any text-* in Class); a bg-* sets its background and duration-* its
|
||||
speed. daisyUI advises at most one aura per page. *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DAuraVariant Variant { get; set; }
|
||||
/// <summary>Colour of the light, as text-*; the child inherits it unless it sets its own text colour.</summary>
|
||||
[Parameter] public DColor Color { get; set; }
|
||||
[Parameter] public DSize Size { get; set; }
|
||||
|
||||
string CssClass => Cx("aura", VariantClass, ColorClass, SizeClass, Class);
|
||||
|
||||
string VariantClass => Variant switch
|
||||
{
|
||||
DAuraVariant.Dual => "aura-dual",
|
||||
DAuraVariant.Rainbow => "aura-rainbow",
|
||||
DAuraVariant.Holo => "aura-holo",
|
||||
DAuraVariant.Gold => "aura-gold",
|
||||
DAuraVariant.Silver => "aura-silver",
|
||||
DAuraVariant.Glow => "aura-glow",
|
||||
_ => null
|
||||
};
|
||||
|
||||
string ColorClass => Color switch
|
||||
{
|
||||
DColor.Neutral => "text-neutral",
|
||||
DColor.Primary => "text-primary",
|
||||
DColor.Secondary => "text-secondary",
|
||||
DColor.Accent => "text-accent",
|
||||
DColor.Info => "text-info",
|
||||
DColor.Success => "text-success",
|
||||
DColor.Warning => "text-warning",
|
||||
DColor.Error => "text-error",
|
||||
_ => null
|
||||
};
|
||||
|
||||
string SizeClass => Size switch
|
||||
{
|
||||
DSize.Xs => "aura-xs",
|
||||
DSize.Sm => "aura-sm",
|
||||
DSize.Lg => "aura-lg",
|
||||
DSize.Xl => "aura-xl",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace decePubClient.Components.Daisy.DataDisplay;
|
||||
|
||||
public enum DAuraVariant
|
||||
{
|
||||
Default,
|
||||
Dual,
|
||||
Rainbow,
|
||||
Holo,
|
||||
Gold,
|
||||
Silver,
|
||||
Glow
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Avatar: https://daisyui.com/components/avatar/ . Class goes on the inner frame, where daisyUI puts the size
|
||||
and shape (w-16 rounded-full, mask mask-squircle) and, for a placeholder, the colours (bg-neutral
|
||||
text-neutral-content); the other attributes go on the outer .avatar. Without Src the frame shows ChildContent. *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
<div class="@Class">
|
||||
@if (Src is not null)
|
||||
{
|
||||
<img src="@Src" alt="@Alt" />
|
||||
}
|
||||
else
|
||||
{
|
||||
@ChildContent
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string Src { get; set; }
|
||||
[Parameter] public string Alt { get; set; } = "";
|
||||
/// <summary>Shown in the frame when there is no Src, e.g. initials with Placeholder.</summary>
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DAvatarStatus Status { get; set; }
|
||||
/// <summary>Centre ChildContent in the frame (avatar-placeholder); give the frame a bg-* in Class.</summary>
|
||||
[Parameter] public bool Placeholder { get; set; }
|
||||
|
||||
string CssClass => Cx("avatar", StatusClass, Placeholder ? "avatar-placeholder" : null);
|
||||
|
||||
string StatusClass => Status switch
|
||||
{
|
||||
DAvatarStatus.Online => "avatar-online",
|
||||
DAvatarStatus.Offline => "avatar-offline",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace decePubClient.Components.Daisy.DataDisplay;
|
||||
|
||||
public enum DAvatarStatus
|
||||
{
|
||||
None,
|
||||
Online,
|
||||
Offline
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Avatar group: https://daisyui.com/components/avatar/ . Overlap the DAvatar children with a negative
|
||||
space-x in Class, e.g. -space-x-6. *@
|
||||
<div @attributes="AdditionalAttributes" class="@Cx("avatar-group", Class)">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Badge: https://daisyui.com/components/badge/ . Without ChildContent it is an empty dot. *@
|
||||
<span @attributes="AdditionalAttributes" class="@CssClass">@ChildContent</span>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DColor Color { get; set; }
|
||||
[Parameter] public DBadgeVariant Variant { get; set; }
|
||||
[Parameter] public DSize Size { get; set; }
|
||||
|
||||
string CssClass => Cx("badge", ColorClass, VariantClass, SizeClass, Class);
|
||||
|
||||
string ColorClass => Color switch
|
||||
{
|
||||
DColor.Neutral => "badge-neutral",
|
||||
DColor.Primary => "badge-primary",
|
||||
DColor.Secondary => "badge-secondary",
|
||||
DColor.Accent => "badge-accent",
|
||||
DColor.Info => "badge-info",
|
||||
DColor.Success => "badge-success",
|
||||
DColor.Warning => "badge-warning",
|
||||
DColor.Error => "badge-error",
|
||||
_ => null
|
||||
};
|
||||
|
||||
string VariantClass => Variant switch
|
||||
{
|
||||
DBadgeVariant.Outline => "badge-outline",
|
||||
DBadgeVariant.Dash => "badge-dash",
|
||||
DBadgeVariant.Soft => "badge-soft",
|
||||
DBadgeVariant.Ghost => "badge-ghost",
|
||||
_ => null
|
||||
};
|
||||
|
||||
string SizeClass => Size switch
|
||||
{
|
||||
DSize.Xs => "badge-xs",
|
||||
DSize.Sm => "badge-sm",
|
||||
DSize.Lg => "badge-lg",
|
||||
DSize.Xl => "badge-xl",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace decePubClient.Components.Daisy.DataDisplay;
|
||||
|
||||
public enum DBadgeVariant
|
||||
{
|
||||
Default,
|
||||
Outline,
|
||||
Dash,
|
||||
Soft,
|
||||
Ghost
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Card: https://daisyui.com/components/card/ . Figure is wrapped in <figure> before the body (after it with
|
||||
FigureLast); the body renders only when Heading, ChildContent or Actions is set. Give it a background in Class
|
||||
(bg-base-100). *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
@if (Figure is not null && !FigureLast)
|
||||
{
|
||||
<figure class="@FigureClass">@Figure</figure>
|
||||
}
|
||||
@if (Heading is not null || ChildContent is not null || Actions is not null)
|
||||
{
|
||||
<div class="@Cx("card-body", BodyClass)">
|
||||
@if (Heading is not null)
|
||||
{
|
||||
<h2 class="card-title">@Heading</h2>
|
||||
}
|
||||
@ChildContent
|
||||
@if (Actions is not null)
|
||||
{
|
||||
<div class="@Cx("card-actions", ActionsClass)">@Actions</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (Figure is not null && FigureLast)
|
||||
{
|
||||
<figure class="@FigureClass">@Figure</figure>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment Figure { get; set; }
|
||||
[Parameter] public RenderFragment Heading { get; set; }
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public RenderFragment Actions { get; set; }
|
||||
[Parameter] public DCardVariant Variant { get; set; }
|
||||
[Parameter] public DSize Size { get; set; }
|
||||
/// <summary>Figure beside the body instead of above it (card-side).</summary>
|
||||
[Parameter] public bool Side { get; set; }
|
||||
/// <summary>Figure as the background behind the body (image-full).</summary>
|
||||
[Parameter] public bool ImageFull { get; set; }
|
||||
/// <summary>Put the figure after the body: at the bottom, or on the right with Side.</summary>
|
||||
[Parameter] public bool FigureLast { get; set; }
|
||||
[Parameter] public string FigureClass { get; set; }
|
||||
[Parameter] public string BodyClass { get; set; }
|
||||
/// <summary>Extra classes on card-actions, e.g. justify-end.</summary>
|
||||
[Parameter] public string ActionsClass { get; set; }
|
||||
|
||||
string CssClass => Cx("card", VariantClass, SizeClass, Side ? "card-side" : null, ImageFull ? "image-full" : null, Class);
|
||||
|
||||
string VariantClass => Variant switch
|
||||
{
|
||||
DCardVariant.Border => "card-border",
|
||||
DCardVariant.Dash => "card-dash",
|
||||
_ => null
|
||||
};
|
||||
|
||||
string SizeClass => Size switch
|
||||
{
|
||||
DSize.Xs => "card-xs",
|
||||
DSize.Sm => "card-sm",
|
||||
DSize.Lg => "card-lg",
|
||||
DSize.Xl => "card-xl",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace decePubClient.Components.Daisy.DataDisplay;
|
||||
|
||||
public enum DCardVariant
|
||||
{
|
||||
Default,
|
||||
Border,
|
||||
Dash
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Carousel: https://daisyui.com/components/carousel/ . A scroll-snap strip of DCarouselItem children; the
|
||||
user scrolls or swipes it. Give each item w-full for one slide at a time. *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DCarouselSnap Snap { get; set; }
|
||||
[Parameter] public DDirection Direction { get; set; }
|
||||
|
||||
string CssClass => Cx("carousel", SnapClass, Direction == DDirection.Vertical ? "carousel-vertical" : null, Class);
|
||||
|
||||
string SnapClass => Snap switch
|
||||
{
|
||||
DCarouselSnap.Center => "carousel-center",
|
||||
DCarouselSnap.End => "carousel-end",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace decePubClient.Components.Daisy.DataDisplay;
|
||||
|
||||
/// <summary>Where each item snaps; <see cref="Start"/> is daisyUI's default, so it renders no class.</summary>
|
||||
public enum DCarouselSnap
|
||||
{
|
||||
Start,
|
||||
Center,
|
||||
End
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* One slide of a DCarousel. *@
|
||||
<div @attributes="AdditionalAttributes" class="@Cx("carousel-item", Class)">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Chat: https://daisyui.com/components/chat/ . One line of a conversation: an optional avatar, header and
|
||||
footer around one DChatBubble (ChildContent). Avatar renders inside <div class="chat-image avatar">, so it takes
|
||||
the avatar's frame, e.g. <div class="w-10 rounded-full"><img … /></div>. *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
@if (Avatar is not null)
|
||||
{
|
||||
<div class="chat-image avatar">@Avatar</div>
|
||||
}
|
||||
@if (Header is not null)
|
||||
{
|
||||
<div class="@Cx("chat-header", HeaderClass)">@Header</div>
|
||||
}
|
||||
@ChildContent
|
||||
@if (Footer is not null)
|
||||
{
|
||||
<div class="@Cx("chat-footer", FooterClass)">@Footer</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public RenderFragment Avatar { get; set; }
|
||||
[Parameter] public RenderFragment Header { get; set; }
|
||||
[Parameter] public RenderFragment Footer { get; set; }
|
||||
[Parameter] public DChatPlacement Placement { get; set; }
|
||||
[Parameter] public string HeaderClass { get; set; }
|
||||
[Parameter] public string FooterClass { get; set; } = "opacity-50";
|
||||
|
||||
string CssClass => Cx("chat", Placement == DChatPlacement.End ? "chat-end" : "chat-start", Class);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Chat bubble: https://daisyui.com/components/chat/ . The message of a DChat; one per DChat, since daisyUI
|
||||
places every bubble in the same grid cell. *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DColor Color { get; set; }
|
||||
|
||||
string CssClass => Cx("chat-bubble", ColorClass, Class);
|
||||
|
||||
string ColorClass => Color switch
|
||||
{
|
||||
DColor.Neutral => "chat-bubble-neutral",
|
||||
DColor.Primary => "chat-bubble-primary",
|
||||
DColor.Secondary => "chat-bubble-secondary",
|
||||
DColor.Accent => "chat-bubble-accent",
|
||||
DColor.Info => "chat-bubble-info",
|
||||
DColor.Success => "chat-bubble-success",
|
||||
DColor.Warning => "chat-bubble-warning",
|
||||
DColor.Error => "chat-bubble-error",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace decePubClient.Components.Daisy.DataDisplay;
|
||||
|
||||
/// <summary>daisyUI requires a placement, so unlike other enums both members render a class.</summary>
|
||||
public enum DChatPlacement
|
||||
{
|
||||
Start,
|
||||
End
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Collapse: https://daisyui.com/components/collapse/ . The open state lives in C# (@bind-IsOpen) and is
|
||||
rendered with collapse-open / collapse-close; clicking the header (or Enter/Space on it) toggles it. neo-raised
|
||||
gives it the neumorphic panel look (see Styles/neo.css for why it isn't a @utility override). *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
<div class="@Cx("collapse-title", Disabled ? "cursor-not-allowed" : "cursor-pointer", HeaderClass)" role="button"
|
||||
tabindex="@(Disabled ? "-1" : "0")" aria-expanded="@(IsOpen ? "true" : "false")" aria-disabled="@(Disabled ? "true" : null)"
|
||||
@onclick="Toggle" @onkeydown="OnKeyDown">
|
||||
@Header
|
||||
</div>
|
||||
<div class="@Cx("collapse-content", ContentClass)">
|
||||
@ChildContent
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment Header { get; set; }
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public bool IsOpen { get; set; }
|
||||
[Parameter] public EventCallback<bool> IsOpenChanged { get; set; }
|
||||
[Parameter] public DCollapseIcon Icon { get; set; }
|
||||
[Parameter] public bool Disabled { get; set; }
|
||||
[Parameter] public string HeaderClass { get; set; }
|
||||
[Parameter] public string ContentClass { get; set; }
|
||||
|
||||
string CssClass => Cx("collapse neo-raised", IconClass, IsOpen ? "collapse-open" : "collapse-close", Class);
|
||||
|
||||
string IconClass => Icon switch
|
||||
{
|
||||
DCollapseIcon.Arrow => "collapse-arrow",
|
||||
DCollapseIcon.Plus => "collapse-plus",
|
||||
_ => null
|
||||
};
|
||||
|
||||
async Task Toggle()
|
||||
{
|
||||
if (Disabled)
|
||||
return;
|
||||
IsOpen = !IsOpen;
|
||||
await IsOpenChanged.InvokeAsync(IsOpen);
|
||||
}
|
||||
|
||||
Task OnKeyDown(KeyboardEventArgs e) => e.Key is "Enter" or " " ? Toggle() : Task.CompletedTask;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace decePubClient.Components.Daisy.DataDisplay;
|
||||
|
||||
public enum DCollapseIcon
|
||||
{
|
||||
None,
|
||||
Arrow,
|
||||
Plus
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Countdown: https://daisyui.com/components/countdown/ . Shows one number (0-999) that rolls to each new
|
||||
Value; --value and --digits go in the inner span's style. For a clock, put several side by side with separators. *@
|
||||
<span @attributes="AdditionalAttributes" class="@Cx("countdown", Class)">
|
||||
<span style="@ValueStyle" aria-live="polite" aria-label="@Number">@Number</span>
|
||||
</span>
|
||||
|
||||
@code {
|
||||
/// <summary>The number to show, clamped to 0-999.</summary>
|
||||
[Parameter] public int Value { get; set; }
|
||||
/// <summary>Minimum digits shown (1-3); 2 pads 5 to 05.</summary>
|
||||
[Parameter] public int Digits { get; set; } = 1;
|
||||
|
||||
int Number => Math.Clamp(Value, 0, 999);
|
||||
|
||||
string ValueStyle => Digits > 1 ? $"--value:{Number}; --digits:{Math.Min(Digits, 3)};" : $"--value:{Number};";
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Diff: https://daisyui.com/components/diff/ . Item1 and Item2 overlap, and the resizer handle reveals one over
|
||||
the other; each slot takes one element (an img, or a div that fills it). Keyboard focus on the figure or on item 1
|
||||
slides the handle to either end. It has no height of its own: AspectClass (or a height in Class) gives it one. *@
|
||||
<figure @attributes="AdditionalAttributes" class="@Cx("diff", AspectClass, Class)" tabindex="0">
|
||||
<div class="diff-item-1" role="img" aria-label="@Item1Alt" tabindex="0">@Item1</div>
|
||||
<div class="diff-item-2" role="img" aria-label="@Item2Alt">@Item2</div>
|
||||
<div class="diff-resizer"></div>
|
||||
</figure>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment Item1 { get; set; }
|
||||
[Parameter] public RenderFragment Item2 { get; set; }
|
||||
/// <summary>Accessible name of item 1 (its role is img, which hides the alt of an img inside).</summary>
|
||||
[Parameter] public string Item1Alt { get; set; }
|
||||
[Parameter] public string Item2Alt { get; set; }
|
||||
/// <summary>An aspect-* class for the figure; null when Class gives it a height instead.</summary>
|
||||
[Parameter] public string AspectClass { get; set; } = "aspect-16/9";
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Hover 3D: https://daisyui.com/components/hover-3d/ . ChildContent must be one non-interactive element (a
|
||||
<figure>, a card); the eight empty divs after it are the hover zones that tilt it. With Href the whole thing is a
|
||||
link, the only way to make it clickable. *@
|
||||
@if (Href is null)
|
||||
{
|
||||
<div @attributes="AdditionalAttributes" class="@Cx("hover-3d", Class)">
|
||||
@ChildContent
|
||||
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<a @attributes="AdditionalAttributes" href="@Href" class="@Cx("hover-3d", Class)">
|
||||
@ChildContent
|
||||
<div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div>
|
||||
</a>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public string Href { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Hover gallery: https://daisyui.com/components/hover-gallery/ . Shows the first image; moving the pointer
|
||||
across it shows the others. Up to 10 images of the same size, from Images or as <img> children; cap its width in
|
||||
Class (max-w-60), or it fills the container. *@
|
||||
<figure @attributes="AdditionalAttributes" class="@Cx("hover-gallery", Class)">
|
||||
@if (Images is not null)
|
||||
{
|
||||
foreach (var src in Images.Take(10))
|
||||
{
|
||||
<img src="@src" alt="@Alt" />
|
||||
}
|
||||
}
|
||||
@ChildContent
|
||||
</figure>
|
||||
|
||||
@code {
|
||||
[Parameter] public IEnumerable<string> Images { get; set; }
|
||||
[Parameter] public string Alt { get; set; } = "";
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Kbd: https://daisyui.com/components/kbd/ *@
|
||||
<kbd @attributes="AdditionalAttributes" class="@CssClass">@ChildContent</kbd>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DSize Size { get; set; }
|
||||
|
||||
string CssClass => Cx("kbd", SizeClass, Class);
|
||||
|
||||
string SizeClass => Size switch
|
||||
{
|
||||
DSize.Xs => "kbd-xs",
|
||||
DSize.Sm => "kbd-sm",
|
||||
DSize.Lg => "kbd-lg",
|
||||
DSize.Xl => "kbd-xl",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI List: https://daisyui.com/components/list/ . Rows are DListRow children; a plain <li> works as a caption. *@
|
||||
<ul @attributes="AdditionalAttributes" class="@Cx("list", Class)">
|
||||
@ChildContent
|
||||
</ul>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* One row of a DList. Its second child fills the remaining width; put list-col-grow on another child to change that,
|
||||
and list-col-wrap on a child to move it to a second line. *@
|
||||
<li @attributes="AdditionalAttributes" class="@Cx("list-row", Class)">
|
||||
@ChildContent
|
||||
</li>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* One stat of a DStats: ChildContent is the value (stat-value); each slot renders its part only when set. *@
|
||||
<div @attributes="AdditionalAttributes" class="@Cx("stat", Class)">
|
||||
@if (Figure is not null)
|
||||
{
|
||||
<div class="@Cx("stat-figure", FigureClass)">@Figure</div>
|
||||
}
|
||||
@if (Heading is not null)
|
||||
{
|
||||
<div class="stat-title">@Heading</div>
|
||||
}
|
||||
@if (ChildContent is not null)
|
||||
{
|
||||
<div class="@Cx("stat-value", ValueClass)">@ChildContent</div>
|
||||
}
|
||||
@if (Desc is not null)
|
||||
{
|
||||
<div class="stat-desc">@Desc</div>
|
||||
}
|
||||
@if (Actions is not null)
|
||||
{
|
||||
<div class="stat-actions">@Actions</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public RenderFragment Figure { get; set; }
|
||||
[Parameter] public RenderFragment Heading { get; set; }
|
||||
[Parameter] public RenderFragment Desc { get; set; }
|
||||
[Parameter] public RenderFragment Actions { get; set; }
|
||||
/// <summary>Extra classes on stat-figure, e.g. text-primary.</summary>
|
||||
[Parameter] public string FigureClass { get; set; }
|
||||
/// <summary>Extra classes on stat-value, e.g. text-primary.</summary>
|
||||
[Parameter] public string ValueClass { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Stat: https://daisyui.com/components/stat/ . The container of DStat items; horizontal unless Direction is
|
||||
Vertical (for a responsive switch add lg:stats-horizontal in Class). *@
|
||||
<div @attributes="AdditionalAttributes" class="@CssClass">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DDirection Direction { get; set; }
|
||||
|
||||
string CssClass => Cx("stats", Direction == DDirection.Vertical ? "stats-vertical" : null, Class);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Status: https://daisyui.com/components/status/ . Give it an aria-label (online, error, …). Ping stacks an
|
||||
animate-ping copy under the dot, as in daisyUI's ping example; the attributes stay on the visible dot. *@
|
||||
@if (Ping)
|
||||
{
|
||||
<span class="inline-grid *:[grid-area:1/1]">
|
||||
<span class="@Cx(CssClass, "animate-ping")" aria-hidden="true"></span>
|
||||
<span @attributes="AdditionalAttributes" class="@CssClass"></span>
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span @attributes="AdditionalAttributes" class="@CssClass"></span>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public DColor Color { get; set; }
|
||||
[Parameter] public DSize Size { get; set; }
|
||||
[Parameter] public bool Ping { get; set; }
|
||||
|
||||
string CssClass => Cx("status", ColorClass, SizeClass, Class);
|
||||
|
||||
string ColorClass => Color switch
|
||||
{
|
||||
DColor.Neutral => "status-neutral",
|
||||
DColor.Primary => "status-primary",
|
||||
DColor.Secondary => "status-secondary",
|
||||
DColor.Accent => "status-accent",
|
||||
DColor.Info => "status-info",
|
||||
DColor.Success => "status-success",
|
||||
DColor.Warning => "status-warning",
|
||||
DColor.Error => "status-error",
|
||||
_ => null
|
||||
};
|
||||
|
||||
string SizeClass => Size switch
|
||||
{
|
||||
DSize.Xs => "status-xs",
|
||||
DSize.Sm => "status-sm",
|
||||
DSize.Lg => "status-lg",
|
||||
DSize.Xl => "status-xl",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Table: https://daisyui.com/components/table/ . ChildContent is the <thead>/<tbody>/<tfoot> markup. Class and
|
||||
the other attributes go on the <table>; with Scroll (the default) it sits in an overflow-x-auto div, whose classes
|
||||
are WrapperClass (pinned rows need it to have a height, e.g. h-96). *@
|
||||
@if (Scroll)
|
||||
{
|
||||
<div class="@Cx("overflow-x-auto", WrapperClass)">
|
||||
<table @attributes="AdditionalAttributes" class="@CssClass">@ChildContent</table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<table @attributes="AdditionalAttributes" class="@CssClass">@ChildContent</table>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DSize Size { get; set; }
|
||||
[Parameter] public bool Zebra { get; set; }
|
||||
/// <summary>Sticky thead/tfoot rows while the wrapper scrolls vertically.</summary>
|
||||
[Parameter] public bool PinRows { get; set; }
|
||||
/// <summary>Sticky <th> columns while the wrapper scrolls horizontally.</summary>
|
||||
[Parameter] public bool PinCols { get; set; }
|
||||
/// <summary>Wrap the table in an overflow-x-auto div so it scrolls on narrow screens.</summary>
|
||||
[Parameter] public bool Scroll { get; set; } = true;
|
||||
[Parameter] public string WrapperClass { get; set; }
|
||||
|
||||
string CssClass => Cx("table", Zebra ? "table-zebra" : null, PinRows ? "table-pin-rows" : null,
|
||||
PinCols ? "table-pin-cols" : null, SizeClass, Class);
|
||||
|
||||
string SizeClass => Size switch
|
||||
{
|
||||
DSize.Xs => "table-xs",
|
||||
DSize.Sm => "table-sm",
|
||||
DSize.Lg => "table-lg",
|
||||
DSize.Xl => "table-xl",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Text rotate: https://daisyui.com/components/text-rotate/ . Loops through 2-6 lines, one at a time, pausing on
|
||||
hover. The lines are Items, or <span> children in ChildContent (for per-line classes). Set the loop time with a
|
||||
duration-* in Class (default 10s). *@
|
||||
<span @attributes="AdditionalAttributes" class="@Cx("text-rotate", Class)">
|
||||
<span class="@(Centered ? "justify-items-center" : null)">
|
||||
@if (Items is not null)
|
||||
{
|
||||
foreach (var item in Items.Take(6))
|
||||
{
|
||||
<span>@item</span>
|
||||
}
|
||||
}
|
||||
@ChildContent
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@code {
|
||||
[Parameter] public IEnumerable<string> Items { get; set; }
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
/// <summary>Centre the lines horizontally.</summary>
|
||||
[Parameter] public bool Centered { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* daisyUI Timeline: https://daisyui.com/components/timeline/ . Horizontal unless Direction is Vertical (for a
|
||||
responsive switch add lg:timeline-horizontal in Class). Every DTimelineItem draws its connecting <hr> on both
|
||||
sides; the two arbitrary variants here hide the outer ends, so the line runs only between items. *@
|
||||
<ul @attributes="AdditionalAttributes" class="@CssClass">
|
||||
@ChildContent
|
||||
</ul>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public DDirection Direction { get; set; }
|
||||
/// <summary>Put every item on one side of the line (timeline-compact).</summary>
|
||||
[Parameter] public bool Compact { get; set; }
|
||||
/// <summary>Align the icon with the start of the content instead of its middle (timeline-snap-icon).</summary>
|
||||
[Parameter] public bool SnapIcon { get; set; }
|
||||
|
||||
string CssClass => Cx("timeline", Direction == DDirection.Vertical ? "timeline-vertical" : null,
|
||||
Compact ? "timeline-compact" : null, SnapIcon ? "timeline-snap-icon" : null,
|
||||
"[&>li:first-child>hr:first-child]:hidden [&>li:last-child>hr:last-child]:hidden", Class);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
@inherits DComponentBase
|
||||
|
||||
@* One event of a DTimeline: Start and End on either side of the line, Middle (an icon) on it. Each part renders only
|
||||
when set. The <hr> before and after are the line segments to the neighbouring items; colour them with
|
||||
LineBeforeClass / LineAfterClass (bg-primary). *@
|
||||
<li @attributes="AdditionalAttributes" class="@Class">
|
||||
<hr class="@LineBeforeClass" />
|
||||
@if (Start is not null)
|
||||
{
|
||||
<div class="@Cx("timeline-start", StartBox ? "timeline-box" : null, StartClass)">@Start</div>
|
||||
}
|
||||
@if (Middle is not null)
|
||||
{
|
||||
<div class="@Cx("timeline-middle", MiddleClass)">@Middle</div>
|
||||
}
|
||||
@if (End is not null)
|
||||
{
|
||||
<div class="@Cx("timeline-end", EndBox ? "timeline-box" : null, EndClass)">@End</div>
|
||||
}
|
||||
<hr class="@LineAfterClass" />
|
||||
</li>
|
||||
|
||||
@code {
|
||||
[Parameter] public RenderFragment Start { get; set; }
|
||||
[Parameter] public RenderFragment Middle { get; set; }
|
||||
[Parameter] public RenderFragment End { get; set; }
|
||||
/// <summary>Draw Start as a box (timeline-box).</summary>
|
||||
[Parameter] public bool StartBox { get; set; }
|
||||
/// <summary>Draw End as a box (timeline-box).</summary>
|
||||
[Parameter] public bool EndBox { get; set; }
|
||||
[Parameter] public string StartClass { get; set; }
|
||||
[Parameter] public string MiddleClass { get; set; }
|
||||
[Parameter] public string EndClass { get; set; }
|
||||
[Parameter] public string LineBeforeClass { get; set; }
|
||||
[Parameter] public string LineAfterClass { get; set; }
|
||||
}
|
||||
Reference in new issue
Block a user