Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
745b91e
feat: add baseline implementation
desmondinho Feb 24, 2025
e87b734
feat: add slots
desmondinho Feb 24, 2025
bccf534
feat: add basic slots styles
desmondinho Feb 24, 2025
4bb00c0
feat: add appearance params, such as `Color`, `Radius`, `Size`
desmondinho Feb 24, 2025
4ae4c96
feat: add `Bordered` and `Disabled` params
desmondinho Feb 24, 2025
52511f2
feat: add compound variants styles
desmondinho Feb 24, 2025
eb1aeb2
feat: apply slots styles
desmondinho Feb 25, 2025
eff0da4
docs: add baseline examples page
desmondinho Feb 25, 2025
ad471ec
Merge branch 'dev' into feat/avatar
desmondinho Mar 4, 2025
fc63800
feat: add `data-loaded` attribute on img
desmondinho Mar 4, 2025
044add3
feat: add `ShowFallback` parameter
desmondinho Mar 5, 2025
f00ae2c
chore: fix compound style variants
desmondinho Mar 5, 2025
ad5d629
chore: set `showFallback` on after first render
desmondinho Mar 5, 2025
e5cdbf5
feat(utils): add implicit cast to string for the `ElementClass`
desmondinho Mar 9, 2025
dda38e9
feat: add LumexAvatarGroup component
desmondinho Mar 12, 2025
9e620d2
feat: take into account when LumexAvatar is rendered inside the Lumex…
desmondinho Mar 12, 2025
d0232ae
feat: add `AvatarClasses` parameter in the avatar group component
desmondinho Mar 12, 2025
654a000
docs: add Avatar page
desmondinho Mar 12, 2025
8852c6d
build(docs): explicitly set Tailwind v4.0.9
desmondinho Mar 12, 2025
6c7ee03
test: add tests for LumexAvatar and LumexAvatarGroup components
desmondinho Mar 13, 2025
8482b6a
chore: simplify condition for fallback render
desmondinho Mar 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/LumexUI.Docs.Client/Common/Navigation/NavigationStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ public class NavigationStore
private static NavigationCategory ComponentsCategory =>
new NavigationCategory( "Components", Icons.Rounded.Joystick )
.Add( new( nameof( LumexAccordion ) ) )
.Add( new( nameof( LumexAvatar ), ComponentStatus.New ) )
.Add( new( nameof( LumexButton ) ) )
.Add( new( nameof( LumexCard ) ) )
.Add( new( nameof( LumexCheckbox ) ) )
.Add( new( nameof( LumexCheckboxGroup ) ) )
.Add( new( nameof( LumexCollapse ) ) )
.Add( new( nameof( LumexDataGrid<T> ) ) )
.Add( new( nameof( LumexDivider ) ) )
.Add( new( nameof( LumexDropdown ), ComponentStatus.New ) )
.Add( new( nameof( LumexDropdown ) ) )
.Add( new( nameof( LumexIcon ) ) )
.Add( new( nameof( LumexLink ) ) )
.Add( new( nameof( LumexListbox<T> ) ) )
Expand All @@ -40,13 +41,14 @@ public class NavigationStore
.Add( new( nameof( LumexRadioGroup<T> ) ) )
.Add( new( nameof( LumexSelect<T> ) ) )
.Add( new( nameof( LumexSwitch ) ) )
.Add( new( nameof( LumexTabs ), ComponentStatus.New ) )
.Add( new( nameof( LumexTabs ) ) )
.Add( new( nameof( LumexTextbox ) ) );

private static NavigationCategory ComponentsApiCategory =>
new NavigationCategory( "Components API", Icons.Rounded.Manufacturing )
.Add( new( nameof( LumexAccordion ) ) )
.Add( new( nameof( LumexAccordionItem ) ) )
.Add( new( nameof( LumexAvatar ) ) )
//.Add( nameof( LumexBooleanInputBase ) )
.Add( new( nameof( LumexButton ) ) )
.Add( new( nameof( LumexCard ) ) )
Expand Down
181 changes: 181 additions & 0 deletions docs/LumexUI.Docs.Client/Pages/Components/Avatar/Avatar.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
@page "/docs/components/avatar"
@layout DocsContentLayout

@using LumexUI.Docs.Client.Pages.Components.Avatar.PreviewCodes

<DocsCompositionSection Components="@_compositionComponents" />

<DocsSection Title="Usage">
<p>
The avatar component represents a user or entity
with an image, initials, or a fallback icon.
</p>
<Usage />

<DocsSection Title="Bordered">
<p>Add a border around the avatar.</p>
<Bordered />
</DocsSection>

<DocsSection Title="Sizes">
<p>Customize the size of the avatar.</p>
<Sizes />
</DocsSection>

<DocsSection Title="Radius">
<p>Adjust the border radius to create circular or squared avatars.</p>
<Radii />
</DocsSection>

<DocsSection Title="Colors">
<p>Set a background and border color for avatar.</p>
<Colors />
</DocsSection>

<DocsSection Title="Fallbacks">
<p>When an image fails to load, a default fallback is displayed. There are 2 types of fallbacks:</p>
<ul>
<li>If a <Code>Name</Code> is provided, it is used to generate initials.</li>
<li>If no <Code>Name</Code> is provided, a default avatar icon is displayed.</li>
</ul>
<p>If <Code>ShowFallback</Code> is set to <Code>false</Code>, fallbacks will not be displayed.</p>
<Fallbacks />
</DocsSection>

<DocsSection Title="Custom Fallback">
<p>Use a custom content as a fallback when an image is unavailable.</p>
<CustomFallback />
</DocsSection>

<DocsSection Title="Custom Initials">
<p>
You can customize the logic for generating initials by passing a function to the <Code>Initials</Code> parameter.
By default, the initials are created by combining the first characters of each word in the <Code>Name</Code> parameter.
</p>
</DocsSection>
</DocsSection>

<DocsSection Title="Avatar Group">
<p>The avatar group component displays multiple avatars together.</p>
<GroupUsage />

<DocsSection Title="Max Count">
<p>Limit the number of avatars displayed, grouping the rest into a counter.</p>
<GroupMaxCount />
</DocsSection>

<DocsSection Title="Custom Count">
<p>Customize how the remaining avatars count is represented.</p>
<GroupCustomCount />
</DocsSection>

<DocsSection Title="Grid">
<p>Display avatars in a structured grid layout.</p>
<GroupGrid />
</DocsSection>
</DocsSection>

<DocsSection Title="Custom Styles">
<p>
This component suppots named slots (represented as <code>data-*</code> attributes) that
allow you to apply custom CSS to specific parts of the component.
</p>
@foreach( var (componentName, slots) in _slots )
{
<h4>@componentName</h4>
<ul>
@foreach( var slot in slots )
{
<li>
<strong class="text-orange-500">@slot.Name:</strong> @slot.Description
</li>
}
</ul>
}
<p>
You can customize the component(s) by passing
any Tailwind CSS classes to the following component parameters:
</p>

<div>
<h4 class="font-semibold">Avatar</h4>
<ul>
<li><Code>Class</Code>: The CSS class names to style the avatar wrapper.</li>
<li><Code>Classes</Code>: The CSS class names to style the avatar slots.</li>
</ul>

<h4 class="font-semibold">Avatar Group</h4>
<ul>
<li><Code>Class</Code>: The CSS class names to style the avatar group wrapper.</li>
<li><Code>Classes</Code>: The CSS class names to style the avatar group slots.</li>
<li><Code>AvatarClasses</Code>: The CSS class names to style the avatars slots.</li>
</ul>
</div>
<CustomStyles />
</DocsSection>

<DocsApiSection Components="@_apiComponents" />

@code {
[CascadingParameter] private DocsContentLayout Layout { get; set; } = default!;

private readonly CompositionComponent[] _compositionComponents = new CompositionComponent[]
{
new(nameof(LumexAvatar), "A component that represents an avatar."),
new(nameof(LumexAvatarGroup), "A component that represents a group of avatars.")
};

private readonly Heading[] _headings = new Heading[]
{
new("Composition"),
new("Usage", [
new("Bordered"),
new("Sizes"),
new("Radius"),
new("Colors"),
new("Fallbacks"),
new("Custom Fallback"),
new("Custom Initials"),
]),
new("Avatar Group", [
new("Max Count"),
new("Custom Count"),
new("Grid")
]),
new("Custom Styles"),
new("API")
};

private readonly Dictionary<string, Slot[]> _slots = new()
{
[nameof(LumexAvatar)] = [
new(nameof(AvatarSlots.Base), "The main container for the avatar component."),
new(nameof(AvatarSlots.Img), "The slot that holds the avatar image."),
new(nameof(AvatarSlots.Fallback), "Displays when the image is unavailable, showing initials or an icon."),
new(nameof(AvatarSlots.Name), "Represents the text or initials displayed inside the avatar."),
new(nameof(AvatarSlots.Icon), "The slot for a custom fallback icon when no image is provided.")
],
[nameof(LumexAvatarGroup)] = [
new(nameof(AvatarGroupSlots.Base), "The main container for the avatar group."),
new(nameof(AvatarGroupSlots.Count), "Displays the number of hidden avatars when the max limit is reached.")
]
};

private readonly string[] _apiComponents = new string[]
{
nameof(LumexAvatar),
nameof(LumexAvatarGroup),
nameof(LumexIcon)
};

protected override void OnInitialized()
{
Layout.Initialize(
title: "Avatar",
category: "Components",
description: "Avatars represent a user or entity using an image, initials, or a fallback icon.",
headings: _headings,
linksProps: new ComponentLinksProps( "Avatar", isServer: false )
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="flex gap-4 items-center">
<LumexAvatar Bordered="@true" Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Bordered="@true" Name="Daniel" />
<LumexAvatar Bordered="@true" Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Bordered="@true" Name="John Doe" />
<LumexAvatar Bordered="@true" Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Bordered="@true" Name="Jane" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="flex gap-4 items-center">
<LumexAvatar Color="@ThemeColor.Default"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Color="@ThemeColor.Primary"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Color="@ThemeColor.Secondary"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Color="@ThemeColor.Success"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=11" />
<LumexAvatar Color="@ThemeColor.Warning"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=12" />
<LumexAvatar Color="@ThemeColor.Danger"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=24" />
<LumexAvatar Color="@ThemeColor.Info"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=43" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div class="flex gap-4 items-center">
<LumexAvatar Src="https://images.unsplash.com/broken">
<FallbackContent>
<LumexIcon Icon="@Icons.Rounded.PhotoCamera"
Class="animate-pulse text-default-500" />
</FallbackContent>
</LumexAvatar>
<LumexAvatar Name="John Doe" Src="https://images.unsplash.com/broken" />
<LumexAvatar ShowFallback="@false" Name="Jane" Src="https://images.unsplash.com/broken" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<LumexAvatar Icon="@Icons.Rounded.SupportAgent" Classes="@_classes" />

@code {
private AvatarSlots _classes = new()
{
Base = "bg-gradient-to-br from-warning-200 to-warning-500",
Icon = "text-black/80"
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="flex gap-4 items-center">
<LumexAvatar Src="https://images.unsplash.com/broken" />
<LumexAvatar Name="John Doe" Src="https://images.unsplash.com/broken" />
<LumexAvatar ShowFallback="@false" Name="Jane" Src="https://images.unsplash.com/broken" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<LumexAvatarGroup Max="3" Bordered="@true">
<CountContent Context="count">
<p class="text-small text-foreground font-medium ms-2">+@count others</p>
</CountContent>
<ChildContent>
<LumexAvatar Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=11" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=12" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=24" />
</ChildContent>
</LumexAvatarGroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<LumexAvatarGroup Max="7" Grid="@true" Bordered="@true">
<LumexAvatar Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=11" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=12" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=24" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=47" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=58" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=68" />
</LumexAvatarGroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<LumexAvatarGroup Max="3" Bordered="@true">
<LumexAvatar Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=11" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=12" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=24" />
</LumexAvatarGroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<LumexAvatarGroup Bordered="@true">
<LumexAvatar Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=11" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=12" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=24" />
</LumexAvatarGroup>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<div class="flex gap-4 items-center">
<LumexAvatar Radius="@Radius.Small"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Radius="@Radius.Medium"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Radius="@Radius.Large"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Radius="@Radius.Full"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=11" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div class="flex gap-4 items-center">
<LumexAvatar Class="w-6 h-6"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Size="@Size.Small"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Size="@Size.Medium"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Size="@Size.Large"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=11" />
<LumexAvatar Class="w-18 h-18"
Bordered="@true"
Src="https://i.pravatar.cc/150?img=12" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="flex gap-4 items-center">
<LumexAvatar Src="https://i.pravatar.cc/150?img=2" />
<LumexAvatar Name="Daniel" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=6" />
<LumexAvatar Name="John Doe" />
<LumexAvatar Src="https://i.pravatar.cc/150?img=9" />
<LumexAvatar Name="Jane" />
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@rendermode InteractiveWebAssembly

<PreviewCode Code="@new(name: null, snippet: "Avatar.Code.Bordered")">
<LumexUI.Docs.Client.Pages.Components.Avatar.Examples.Bordered />
</PreviewCode>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@rendermode InteractiveWebAssembly

<PreviewCode Code="@new(name: null, snippet: "Avatar.Code.Colors")">
<LumexUI.Docs.Client.Pages.Components.Avatar.Examples.Colors />
</PreviewCode>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@rendermode InteractiveWebAssembly

<PreviewCode Code="@new(name: null, snippet: "Avatar.Code.CustomFallback")">
<LumexUI.Docs.Client.Pages.Components.Avatar.Examples.CustomFallback />
</PreviewCode>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@rendermode InteractiveWebAssembly

<PreviewCode Code="@new(name: null, snippet: "Avatar.Code.CustomStyles")">
<LumexUI.Docs.Client.Pages.Components.Avatar.Examples.CustomStyles />
</PreviewCode>
Loading
Loading