[frontend/components] Refactor EmojiPicker to categorize emojis and allow search
This commit is contained in:
parent
ea461d139b
commit
3dfc7c6b63
2 changed files with 48 additions and 7 deletions
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue