Skip to content

Commit f785a90

Browse files
authored
v2.0.0 preview.3 (#206)
* fix(theme): remove extra shade (950) from the color scales for consistency in dark mode (#199) * fix(theme): remove extra key (950) from the color scales for consistency in dark mode * build(docs): explicitly set Tailwind v4.0.9 * feat(components): introduce Avatar and AvatarGroup components (#201) * feat: add baseline implementation * feat: add slots * feat: add basic slots styles * feat: add appearance params, such as `Color`, `Radius`, `Size` * feat: add `Bordered` and `Disabled` params * feat: add compound variants styles * feat: apply slots styles * docs: add baseline examples page * feat: add `data-loaded` attribute on img * feat: add `ShowFallback` parameter * chore: fix compound style variants * chore: set `showFallback` on after first render * feat(utils): add implicit cast to string for the `ElementClass` * feat: add LumexAvatarGroup component * feat: take into account when LumexAvatar is rendered inside the LumexAvatarGroup * feat: add `AvatarClasses` parameter in the avatar group component * docs: add Avatar page * build(docs): explicitly set Tailwind v4.0.9 * test: add tests for LumexAvatar and LumexAvatarGroup components * chore: simplify condition for fallback render * fix(docs): replace usages of `-foreground-950` CSS classes with `-foreground-900` * fix(docs): remove `dark:prose-invert` CSS class until dark theme is properly configured * feat(components): introduce Skeleton component (#202) * feat(skeleton): add baseline implementation of the component * feat(skeleton): add slots and styles * feat(skeleton): add XML summaries * fix(skeleton): return back `after` pseudo CSS classes to prevent flickering on state change * docs(skeleton): add Skeleton page * test(skeleton): add tests * docs(skeleton): fix Loading example button text * fix(navbar): add a check before toggling navbar menu on navigation (#204) * v2.0.0-preview.3
1 parent 36ba323 commit f785a90

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+2083
-93
lines changed

docs/LumexUI.Docs.Client/Common/Navigation/NavigationStore.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,15 @@ public class NavigationStore
2323
private static NavigationCategory ComponentsCategory =>
2424
new NavigationCategory( "Components", Icons.Rounded.Joystick )
2525
.Add( new( nameof( LumexAccordion ) ) )
26+
.Add( new( nameof( LumexAvatar ), ComponentStatus.New ) )
2627
.Add( new( nameof( LumexButton ) ) )
2728
.Add( new( nameof( LumexCard ) ) )
2829
.Add( new( nameof( LumexCheckbox ) ) )
2930
.Add( new( nameof( LumexCheckboxGroup ) ) )
3031
.Add( new( nameof( LumexCollapse ) ) )
3132
.Add( new( nameof( LumexDataGrid<T> ) ) )
3233
.Add( new( nameof( LumexDivider ) ) )
33-
.Add( new( nameof( LumexDropdown ), ComponentStatus.New ) )
34+
.Add( new( nameof( LumexDropdown ) ) )
3435
.Add( new( nameof( LumexIcon ) ) )
3536
.Add( new( nameof( LumexLink ) ) )
3637
.Add( new( nameof( LumexListbox<T> ) ) )
@@ -39,14 +40,17 @@ public class NavigationStore
3940
.Add( new( nameof( LumexPopover ) ) )
4041
.Add( new( nameof( LumexRadioGroup<T> ) ) )
4142
.Add( new( nameof( LumexSelect<T> ) ) )
43+
.Add( new( nameof( LumexSkeleton ), ComponentStatus.New ) )
4244
.Add( new( nameof( LumexSwitch ) ) )
43-
.Add( new( nameof( LumexTabs ), ComponentStatus.New ) )
45+
.Add( new( nameof( LumexTabs ) ) )
4446
.Add( new( nameof( LumexTextbox ) ) );
4547

4648
private static NavigationCategory ComponentsApiCategory =>
4749
new NavigationCategory( "Components API", Icons.Rounded.Manufacturing )
4850
.Add( new( nameof( LumexAccordion ) ) )
4951
.Add( new( nameof( LumexAccordionItem ) ) )
52+
.Add( new( nameof( LumexAvatar ) ) )
53+
.Add( new( nameof( LumexAvatarGroup ) ) )
5054
//.Add( nameof( LumexBooleanInputBase ) )
5155
.Add( new( nameof( LumexButton ) ) )
5256
.Add( new( nameof( LumexCard ) ) )
@@ -82,6 +86,7 @@ public class NavigationStore
8286
.Add( new( nameof( LumexPopoverTrigger ) ) )
8387
.Add( new( nameof( LumexSelect<T> ) ) )
8488
.Add( new( nameof( LumexSelectItem<T> ) ) )
89+
.Add( new( nameof( LumexSkeleton ) ) )
8590
.Add( new( nameof( LumexSwitch ) ) )
8691
.Add( new( nameof( LumexTab ) ) )
8792
.Add( new( nameof( LumexTabs ) ) )

docs/LumexUI.Docs.Client/Components/ColorSwatches.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
<LumexButton Color="@ThemeColor.None"
1616
Class="w-full min-w-fit h-auto p-0 justify-start gap-x-3 overflow-visible rounded-small sm:block sm:space-y-1">
17-
<div class="relative w-12 h-12 rounded-md ring ring-inset ring-foreground-950/10 sm:w-full"
17+
<div class="relative w-12 h-12 rounded-md ring ring-inset ring-foreground-900/15 sm:w-full"
1818
style="background-color: @(color.Value + (isDivider ? "26" : default))">
1919

2020
<span class="absolute top-1 right-1.5 font-medium text-[0.625rem] leading-none"

docs/LumexUI.Docs.Client/Components/DocsSection.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
Color="@ThemeColor.None"
99
Class="border-none">
1010
@Title
11-
<span class="flex items-center justify-center size-6 ml-2 rounded-md text-foreground-400 shadow-xs ring ring-foreground-950/5 hover:ring-orange-200 hover:bg-orange-50 hover:text-orange-500">
11+
<span class="flex items-center justify-center size-6 ml-2 rounded-md text-foreground-400 shadow-xs ring ring-foreground-900/10 hover:ring-orange-200 hover:bg-orange-50 hover:text-orange-500">
1212
<LumexIcon Icon="@Icons.Rounded.Link"
1313
Size="@new("16")" />
1414
</span>

docs/LumexUI.Docs.Client/Components/InstallationSteps.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
{
66
foreach( var step in Steps )
77
{
8-
<li class="relative pl-10 pb-8 xl:grid xl:grid-cols-5 xl:gap-10 before:absolute before:content-[counter(step)] before:left-0 before:flex before:items-center before:justify-center before:size-6 before:text-[0.625rem] before:font-bold before:text-zinc-700 before:rounded-md before:shadow-xs before:ring before:ring-foreground-950/5 after:absolute after:top-8 after:bottom-0 after:left-3 after:w-px after:bg-divider" style="counter-increment: step;">
8+
<li class="relative pl-10 pb-8 xl:grid xl:grid-cols-5 xl:gap-10 before:absolute before:content-[counter(step)] before:left-0 before:flex before:items-center before:justify-center before:size-6 before:text-[0.625rem] before:font-bold before:text-zinc-700 before:rounded-md before:shadow-xs before:ring before:ring-foreground-900/10 after:absolute after:top-8 after:bottom-0 after:left-3 after:w-px after:bg-divider" style="counter-increment: step;">
99
<div class="mb-6 xl:mb-0 xl:col-span-2">
1010
<h4 class="text-sm leading-6 font-semibold mb-2">
1111
@step.Title
1212
</h4>
13-
<div class="prose prose-zinc prose-sm dark:prose-invert">
13+
<div class="prose prose-zinc prose-sm">
1414
@step.Body
1515
</div>
1616
</div>

docs/LumexUI.Docs.Client/Components/Layouts/DocsContentLayout.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
Description="@_description"
1212
LinksProps="@_linksProps" />
1313

14-
<main class="mt-8 prose prose-zinc dark:prose-invert">
14+
<main class="mt-8 prose prose-zinc">
1515
<LumexDivider />
1616

1717
@Body

docs/LumexUI.Docs.Client/Components/Layouts/InstallationLayout.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
Description="Follow the steps below to get started with LumexUI quickly!" />
1111

1212
<main class="mt-8">
13-
<div class="mb-8 prose prose-zinc dark:prose-invert">
13+
<div class="mb-8 prose prose-zinc">
1414
<DocsSection Title="Prerequisites">
1515
<p>Before you begin, ensure that you have the following:</p>
1616
<ul>

docs/LumexUI.Docs.Client/Components/Preview.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
private readonly Slots _slots = new()
2626
{
2727
Preview = "relative flex flex-wrap items-center gap-4",
28-
PreviewWrapper = "relative p-8 rounded-xl bg-zinc-50 ring ring-foreground-950/5 not-prose",
28+
PreviewWrapper = "relative p-8 rounded-xl bg-zinc-50 ring ring-foreground-900/10 not-prose",
2929
Background = "absolute inset-0 [mask-image:radial-gradient(#fff_0%,transparent_100%)]",
3030
};
3131

docs/LumexUI.Docs.Client/Components/PreviewCode.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public partial class PreviewCode
1616
private string? BaseClass => ElementClass.Empty()
1717
.Add( "rounded-2xl" )
1818
.Add( "ring" )
19-
.Add( "ring-foreground-950/5" )
19+
.Add( "ring-foreground-900/10" )
2020
.Add( "shadow-xs" )
2121
.Add( "overflow-hidden" )
2222
.Add( Class )
@@ -25,7 +25,7 @@ public partial class PreviewCode
2525
private string ToolbarClass => ElementClass.Empty()
2626
.Add( "p-2" )
2727
.Add( "border-t" )
28-
.Add( "border-foreground-950/5" )
28+
.Add( "border-foreground-900/10" )
2929
.Add( "border-b", when: _expanded )
3030
.Add( "rounded-b-xl", when: !_expanded )
3131
.ToString();

docs/LumexUI.Docs.Client/Components/QuickLink.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
@Description
1919
</p>
2020
</div>
21-
<div class="absolute -z-10 -inset-3 rounded-2xl bg-gray-50 peer-hover:ring peer-hover:ring-foreground-950/5"></div>
21+
<div class="absolute -z-10 -inset-3 rounded-2xl bg-gray-50 peer-hover:ring peer-hover:ring-foreground-900/10"></div>
2222
</li>
2323

2424
@code {
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
@page "/docs/components/avatar"
2+
@layout DocsContentLayout
3+
4+
@using LumexUI.Docs.Client.Pages.Components.Avatar.PreviewCodes
5+
6+
<DocsCompositionSection Components="@_compositionComponents" />
7+
8+
<DocsSection Title="Usage">
9+
<p>
10+
The avatar component represents a user or entity
11+
with an image, initials, or a fallback icon.
12+
</p>
13+
<Usage />
14+
15+
<DocsSection Title="Bordered">
16+
<p>Add a border around the avatar.</p>
17+
<Bordered />
18+
</DocsSection>
19+
20+
<DocsSection Title="Sizes">
21+
<p>Customize the size of the avatar.</p>
22+
<Sizes />
23+
</DocsSection>
24+
25+
<DocsSection Title="Radius">
26+
<p>Adjust the border radius to create circular or squared avatars.</p>
27+
<Radii />
28+
</DocsSection>
29+
30+
<DocsSection Title="Colors">
31+
<p>Set a background and border color for avatar.</p>
32+
<Colors />
33+
</DocsSection>
34+
35+
<DocsSection Title="Fallbacks">
36+
<p>When an image fails to load, a default fallback is displayed. There are 2 types of fallbacks:</p>
37+
<ul>
38+
<li>If a <Code>Name</Code> is provided, it is used to generate initials.</li>
39+
<li>If no <Code>Name</Code> is provided, a default avatar icon is displayed.</li>
40+
</ul>
41+
<p>If <Code>ShowFallback</Code> is set to <Code>false</Code>, fallbacks will not be displayed.</p>
42+
<Fallbacks />
43+
</DocsSection>
44+
45+
<DocsSection Title="Custom Fallback">
46+
<p>Use a custom content as a fallback when an image is unavailable.</p>
47+
<CustomFallback />
48+
</DocsSection>
49+
50+
<DocsSection Title="Custom Initials">
51+
<p>
52+
You can customize the logic for generating initials by passing a function to the <Code>Initials</Code> parameter.
53+
By default, the initials are created by combining the first characters of each word in the <Code>Name</Code> parameter.
54+
</p>
55+
</DocsSection>
56+
</DocsSection>
57+
58+
<DocsSection Title="Avatar Group">
59+
<p>The avatar group component displays multiple avatars together.</p>
60+
<GroupUsage />
61+
62+
<DocsSection Title="Max Count">
63+
<p>Limit the number of avatars displayed, grouping the rest into a counter.</p>
64+
<GroupMaxCount />
65+
</DocsSection>
66+
67+
<DocsSection Title="Custom Count">
68+
<p>Customize how the remaining avatars count is represented.</p>
69+
<GroupCustomCount />
70+
</DocsSection>
71+
72+
<DocsSection Title="Grid">
73+
<p>Display avatars in a structured grid layout.</p>
74+
<GroupGrid />
75+
</DocsSection>
76+
</DocsSection>
77+
78+
<DocsSection Title="Custom Styles">
79+
<p>
80+
This component suppots named slots (represented as <code>data-*</code> attributes) that
81+
allow you to apply custom CSS to specific parts of the component.
82+
</p>
83+
@foreach( var (componentName, slots) in _slots )
84+
{
85+
<h4>@componentName</h4>
86+
<ul>
87+
@foreach( var slot in slots )
88+
{
89+
<li>
90+
<strong class="text-orange-500">@slot.Name:</strong> @slot.Description
91+
</li>
92+
}
93+
</ul>
94+
}
95+
<p>
96+
You can customize the component(s) by passing
97+
any Tailwind CSS classes to the following component parameters:
98+
</p>
99+
100+
<div>
101+
<h4 class="font-semibold">Avatar</h4>
102+
<ul>
103+
<li><Code>Class</Code>: The CSS class names to style the avatar wrapper.</li>
104+
<li><Code>Classes</Code>: The CSS class names to style the avatar slots.</li>
105+
</ul>
106+
107+
<h4 class="font-semibold">Avatar Group</h4>
108+
<ul>
109+
<li><Code>Class</Code>: The CSS class names to style the avatar group wrapper.</li>
110+
<li><Code>Classes</Code>: The CSS class names to style the avatar group slots.</li>
111+
<li><Code>AvatarClasses</Code>: The CSS class names to style the avatars slots.</li>
112+
</ul>
113+
</div>
114+
<CustomStyles />
115+
</DocsSection>
116+
117+
<DocsApiSection Components="@_apiComponents" />
118+
119+
@code {
120+
[CascadingParameter] private DocsContentLayout Layout { get; set; } = default!;
121+
122+
private readonly CompositionComponent[] _compositionComponents = new CompositionComponent[]
123+
{
124+
new(nameof(LumexAvatar), "A component that represents an avatar."),
125+
new(nameof(LumexAvatarGroup), "A component that represents a group of avatars.")
126+
};
127+
128+
private readonly Heading[] _headings = new Heading[]
129+
{
130+
new("Composition"),
131+
new("Usage", [
132+
new("Bordered"),
133+
new("Sizes"),
134+
new("Radius"),
135+
new("Colors"),
136+
new("Fallbacks"),
137+
new("Custom Fallback"),
138+
new("Custom Initials"),
139+
]),
140+
new("Avatar Group", [
141+
new("Max Count"),
142+
new("Custom Count"),
143+
new("Grid")
144+
]),
145+
new("Custom Styles"),
146+
new("API")
147+
};
148+
149+
private readonly Dictionary<string, Slot[]> _slots = new()
150+
{
151+
[nameof(LumexAvatar)] = [
152+
new(nameof(AvatarSlots.Base), "The main container for the avatar component."),
153+
new(nameof(AvatarSlots.Img), "The slot that holds the avatar image."),
154+
new(nameof(AvatarSlots.Fallback), "Displays when the image is unavailable, showing initials or an icon."),
155+
new(nameof(AvatarSlots.Name), "Represents the text or initials displayed inside the avatar."),
156+
new(nameof(AvatarSlots.Icon), "The slot for a custom fallback icon when no image is provided.")
157+
],
158+
[nameof(LumexAvatarGroup)] = [
159+
new(nameof(AvatarGroupSlots.Base), "The main container for the avatar group."),
160+
new(nameof(AvatarGroupSlots.Count), "Displays the number of hidden avatars when the max limit is reached.")
161+
]
162+
};
163+
164+
private readonly string[] _apiComponents = new string[]
165+
{
166+
nameof(LumexAvatar),
167+
nameof(LumexAvatarGroup),
168+
nameof(LumexIcon)
169+
};
170+
171+
protected override void OnInitialized()
172+
{
173+
Layout.Initialize(
174+
title: "Avatar",
175+
category: "Components",
176+
description: "Avatars represent a user or entity using an image, initials, or a fallback icon.",
177+
headings: _headings,
178+
linksProps: new ComponentLinksProps( "Avatar", isServer: false )
179+
);
180+
}
181+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div class="flex gap-4 items-center">
2+
<LumexAvatar Bordered="@true" Src="https://i.pravatar.cc/150?img=2" />
3+
<LumexAvatar Bordered="@true" Name="Daniel" />
4+
<LumexAvatar Bordered="@true" Src="https://i.pravatar.cc/150?img=6" />
5+
<LumexAvatar Bordered="@true" Name="John Doe" />
6+
<LumexAvatar Bordered="@true" Src="https://i.pravatar.cc/150?img=9" />
7+
<LumexAvatar Bordered="@true" Name="Jane" />
8+
</div>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<div class="flex gap-4 items-center">
2+
<LumexAvatar Color="@ThemeColor.Default"
3+
Bordered="@true"
4+
Src="https://i.pravatar.cc/150?img=2" />
5+
<LumexAvatar Color="@ThemeColor.Primary"
6+
Bordered="@true"
7+
Src="https://i.pravatar.cc/150?img=6" />
8+
<LumexAvatar Color="@ThemeColor.Secondary"
9+
Bordered="@true"
10+
Src="https://i.pravatar.cc/150?img=9" />
11+
<LumexAvatar Color="@ThemeColor.Success"
12+
Bordered="@true"
13+
Src="https://i.pravatar.cc/150?img=11" />
14+
<LumexAvatar Color="@ThemeColor.Warning"
15+
Bordered="@true"
16+
Src="https://i.pravatar.cc/150?img=12" />
17+
<LumexAvatar Color="@ThemeColor.Danger"
18+
Bordered="@true"
19+
Src="https://i.pravatar.cc/150?img=24" />
20+
<LumexAvatar Color="@ThemeColor.Info"
21+
Bordered="@true"
22+
Src="https://i.pravatar.cc/150?img=43" />
23+
</div>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<div class="flex gap-4 items-center">
2+
<LumexAvatar Src="https://images.unsplash.com/broken">
3+
<FallbackContent>
4+
<LumexIcon Icon="@Icons.Rounded.PhotoCamera"
5+
Class="animate-pulse text-default-500" />
6+
</FallbackContent>
7+
</LumexAvatar>
8+
<LumexAvatar Name="John Doe" Src="https://images.unsplash.com/broken" />
9+
<LumexAvatar ShowFallback="@false" Name="Jane" Src="https://images.unsplash.com/broken" />
10+
</div>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<LumexAvatar Icon="@Icons.Rounded.SupportAgent" Classes="@_classes" />
2+
3+
@code {
4+
private AvatarSlots _classes = new()
5+
{
6+
Base = "bg-gradient-to-br from-warning-200 to-warning-500",
7+
Icon = "text-black/80"
8+
};
9+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="flex gap-4 items-center">
2+
<LumexAvatar Src="https://images.unsplash.com/broken" />
3+
<LumexAvatar Name="John Doe" Src="https://images.unsplash.com/broken" />
4+
<LumexAvatar ShowFallback="@false" Name="Jane" Src="https://images.unsplash.com/broken" />
5+
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<LumexAvatarGroup Max="3" Bordered="@true">
2+
<CountContent Context="count">
3+
<p class="text-small text-foreground font-medium ms-2">+@count others</p>
4+
</CountContent>
5+
<ChildContent>
6+
<LumexAvatar Src="https://i.pravatar.cc/150?img=2" />
7+
<LumexAvatar Src="https://i.pravatar.cc/150?img=6" />
8+
<LumexAvatar Src="https://i.pravatar.cc/150?img=9" />
9+
<LumexAvatar Src="https://i.pravatar.cc/150?img=11" />
10+
<LumexAvatar Src="https://i.pravatar.cc/150?img=12" />
11+
<LumexAvatar Src="https://i.pravatar.cc/150?img=24" />
12+
</ChildContent>
13+
</LumexAvatarGroup>

0 commit comments

Comments
 (0)