[frontend/components] Refactor EmojiPicker to categorize emojis and allow search

This commit is contained in:
pancakes 2024-11-08 13:40:43 +10:00 committed by Lilian
parent ea461d139b
commit 3dfc7c6b63
No known key found for this signature in database
2 changed files with 48 additions and 7 deletions

View file

@ -1,3 +1,4 @@
@using AngleSharp.Text
@using Iceshrimp.Frontend.Core.Services @using Iceshrimp.Frontend.Core.Services
@using Iceshrimp.Shared.Schemas.Web @using Iceshrimp.Shared.Schemas.Web
@inject EmojiService EmojiService @inject EmojiService EmojiService
@ -6,11 +7,20 @@
<dialog class="dialog" @ref="EmojiPickerRef"> <dialog class="dialog" @ref="EmojiPickerRef">
<div class="emoji-picker" style="--top: @(_top)px; --left: @(_left)px"> <div class="emoji-picker" style="--top: @(_top)px; --left: @(_left)px">
@foreach (var el in EmojiList) <input @bind="EmojiFilter" @bind:event="oninput" @bind:after="FilterEmojis" class="search" type="text" placeholder="Search" aria-label="search"/>
@foreach (var category in Categories)
{ {
<div class="emoji"> <details open>
<img @onclick="() => Select(el)" src="@el.PublicUrl" alt="@el.Name"/> <summary aria-label="category">@category.Key</summary>
</div> <div class="emoji-list">
@foreach (var emoji in category.Value)
{
<div class="emoji">
<img @onclick="() => Select(emoji)" src="@emoji.PublicUrl" alt="@emoji.Name" title=":@emoji.Name:" loading="lazy"/>
</div>
}
</div>
</details>
} }
</div> </div>
<ClosingBackdrop OnClose="Close"></ClosingBackdrop> <ClosingBackdrop OnClose="Close"></ClosingBackdrop>
@ -25,17 +35,22 @@
private float _left; private float _left;
private IJSInProcessObjectReference _module = null!; private IJSInProcessObjectReference _module = null!;
private string EmojiFilter { get; set; } = "";
private Dictionary<string, List<EmojiResponse>> Categories { get; set; } = [];
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
GlobalComponentSvc.EmojiPicker = this; GlobalComponentSvc.EmojiPicker = this;
EmojiList = await EmojiService.GetEmoji(); EmojiList = await EmojiService.GetEmoji();
_module = (IJSInProcessObjectReference)await Js.InvokeAsync<IJSObjectReference>("import", _module = (IJSInProcessObjectReference)await Js.InvokeAsync<IJSObjectReference>("import",
"./Components/EmojiPicker.razor.js"); "./Components/EmojiPicker.razor.js");
FilterEmojis();
} }
private async void Select(EmojiResponse emoji) private async void Select(EmojiResponse emoji)
{ {
await OnEmojiSelect.InvokeAsync(emoji); await OnEmojiSelect.InvokeAsync(emoji);
Close();
} }
private void Close() private void Close()
@ -52,4 +67,16 @@
StateHasChanged(); StateHasChanged();
_module.InvokeVoid("openDialog", EmojiPickerRef); _module.InvokeVoid("openDialog", EmojiPickerRef);
} }
private void FilterEmojis()
{
Categories = EmojiList
.Where(p => p.Name.Contains(EmojiFilter.StripLeadingTrailingSpaces()) || p.Aliases.Count(a => a.Contains(EmojiFilter.StripLeadingTrailingSpaces())) != 0)
.OrderBy(p => p.Name)
.ThenBy(p => p.Id)
.GroupBy(p => p.Category)
.OrderBy(p => string.IsNullOrEmpty(p.Key))
.ThenBy(p => p.Key)
.ToDictionary(p => p.Key ?? "Other", p => p.ToList());
}
} }

View file

@ -1,9 +1,6 @@
.emoji-picker { .emoji-picker {
--top: 0px; --top: 0px;
--left: 0px; --left: 0px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(2.5rem, 1fr));
grid-template-rows: repeat(auto-fill, minmax(2.5rem, 1fr));
position: absolute; position: absolute;
background-color: var(--foreground-color); background-color: var(--foreground-color);
border: var(--highlight-color) solid 0.1rem; border: var(--highlight-color) solid 0.1rem;
@ -11,11 +8,18 @@
border-radius: 1rem; border-radius: 1rem;
min-width: 15rem; min-width: 15rem;
min-height: 10rem; min-height: 10rem;
max-height: 20rem;
overflow: auto; overflow: auto;
top: calc(var(--top) + 2.5rem); top: calc(var(--top) + 2.5rem);
left: calc(var(--left) - 5.5rem); left: calc(var(--left) - 5.5rem);
} }
.emoji-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(2.5rem, 1fr));
grid-template-rows: repeat(auto-fill, minmax(2.5rem, 1fr));
}
.dialog { .dialog {
z-index: +12; z-index: +12;
} }
@ -27,3 +31,13 @@
width: 2rem; width: 2rem;
} }
} }
summary {
padding: 0.5rem 0;
cursor: pointer;
}
.search {
margin: 0;
padding: 0;
}