[frontend] Refactor EmojiPicker and it's usages, add globally accessible components

This commit is contained in:
Lilian 2024-07-12 23:32:50 +02:00
parent 641c6578e6
commit 52dca9f3be
No known key found for this signature in database
12 changed files with 105 additions and 54 deletions

View file

@ -10,7 +10,9 @@
@inject ComposeService ComposeService
@inject SessionService SessionService
@inject IStringLocalizer<Localization> Loc;
<dialog class="compose" @ref="Dialog">
@inject GlobalComponentSvc GlobalComponentSvc
<dialog class="dialog" @ref="Dialog">
<div class="compose">
<div class="header">
<button @onclick="CloseDialog">
<Icon Name="Icons.X"/>
@ -31,7 +33,7 @@
<input @bind="NoteDraft.Cw" class="input cw-field" placeholder="Content Warning"/>
<hr class="separator"/>
}
<textarea @ref="Textarea" @bind="NoteDraft.Text" class="textarea" placeholder="@TextPlaceholder" rows="5" cols="35"></textarea>
<textarea @ref="Textarea" @bind="NoteDraft.Text" class="textarea" placeholder="@TextPlaceholder" rows="5" cols="35" autofocus="autofocus"></textarea>
<div class="footer">
<button class="footer-btn" @onclick="OpenUpload">
<Icon Name="Icons.Upload" Size="1.3rem"></Icon>
@ -39,17 +41,18 @@
<button class="footer-btn" @onclick="ToggleCw">
<Icon Name="Icons.EyeSlash" Size="1.3rem"></Icon>
</button>
<button class="footer-btn" @onclick="ToggleEmojiPicker">
<button @ref="EmojiButton" class="footer-btn positioned" @onclick="ToggleEmojiPicker">
<Icon Name="Icons.Smiley" Size="1.3rem"></Icon>
<EmojiPicker OnEmojiSelect="AddEmoji" />
</button>
<div class="file-input">
<InputFile @ref="UploadInput" OnChange="Upload">Upload!</InputFile>
</div>
</div>
<div @onclick="CloseDialog" class="backdrop"></div>
</div>
</dialog>
@code {
private ElementReference Dialog { get; set; }
private IJSObjectReference _module = null!;
@ -58,7 +61,7 @@
private NoteBase? ReplyOrQuote { get; set; }
private string? TextPlaceholder { get; set; }
private ElementReference Textarea { get; set; }
private EmojiPicker EmojiPicker { get; set; } = null!;
private ElementReference EmojiButton { get; set; }
private NoteCreateRequest NoteDraft { get; set; } = new()
{
@ -251,8 +254,7 @@
private void ToggleEmojiPicker()
{
_ = EmojiPicker.Toggle();
StateHasChanged();
GlobalComponentSvc.EmojiPicker?.Open(EmojiButton, new EventCallback<EmojiResponse>(this, AddEmoji));
}
private async Task AddEmoji(EmojiResponse emoji)

View file

@ -4,11 +4,24 @@
margin: 0 auto;
top: 10%;
padding: 1rem;
position: relative;
width: 45rem;
}
.compose::backdrop {
background-color: black;
.dialog {
width: 100vw;
height: 100vh;
top: 0;
left: 0;
position: fixed;
margin: auto;
background-color: unset;
z-index: +1;
}
.backdrop {
opacity: 50%;
background-color: black;
}
.header {
@ -20,6 +33,7 @@
background-color: var(--background-color);
border: none;
outline: none;
width: 100%;
}
.input {
@ -61,11 +75,16 @@
padding: 0.5rem;
}
.positioned {
position: relative;
top: 0;
}
.backdrop {
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
z-index: -1
z-index: -2
}

View file

@ -1,5 +1,5 @@
export function openDialog(element) {
element.showModal()
element.show()
}
export function closeDialog(element) {

View file

@ -1,10 +1,11 @@
@using Iceshrimp.Frontend.Core.Services
@using Iceshrimp.Shared.Schemas.Web
@inject EmojiService EmojiService
@inject GlobalComponentSvc GlobalComponentSvc
@inject IJSRuntime Js
@if (_display)
{
<div @ref="EmojiPickerRef" @onfocusout="Close" class="emoji-picker @(Fixed ? "fixed" : "")" tabindex="0">
<dialog class="dialog" @ref="EmojiPickerRef">
<div class="emoji-picker" style="--top: @(_top)px; --left: @(_left)px">
@foreach (var el in EmojiList)
{
<div class="emoji">
@ -12,45 +13,43 @@
</div>
}
</div>
}
<ClosingBackdrop OnClose="Close"></ClosingBackdrop>
</dialog>
@code {
[Parameter] public bool Fixed { get; set; }
[Parameter] [EditorRequired] public required EventCallback<EmojiResponse> OnEmojiSelect { get; set; }
private EventCallback<EmojiResponse> OnEmojiSelect { get; set; }
private List<EmojiResponse> EmojiList { get; set; } = [];
private bool _display = false;
private ElementReference EmojiPickerRef { get; set; }
private float _top;
private float _left;
private IJSInProcessObjectReference _module = null!;
protected override async Task OnInitializedAsync()
{
GlobalComponentSvc.EmojiPicker = this;
EmojiList = await EmojiService.GetEmoji();
_module = (IJSInProcessObjectReference)await Js.InvokeAsync<IJSObjectReference>("import",
"./Components/EmojiPicker.razor.js");
}
private async void Select(EmojiResponse emoji)
{
await OnEmojiSelect.InvokeAsync(emoji);
_display = false;
StateHasChanged();
}
private void Close()
{
_display = false;
_module.InvokeVoid("closeDialog", EmojiPickerRef);
}
public void Open(ElementReference root, EventCallback<EmojiResponse> func)
{
OnEmojiSelect = func;
var pos = _module.Invoke<List<float>>("getPosition", root);
_left = pos[0];
_top = pos[1];
StateHasChanged();
}
protected override void OnAfterRender(bool firstRender)
{
if (_display)
{
EmojiPickerRef.FocusAsync();
}
}
public async Task Toggle()
{
_display = !_display;
await InvokeAsync(StateHasChanged);
_module.InvokeVoid("openDialog", EmojiPickerRef);
}
}

View file

@ -1,4 +1,6 @@
.emoji-picker {
--top: 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));
@ -10,9 +12,12 @@
min-width: 15rem;
min-height: 10rem;
overflow: scroll;
z-index: 100;
top: 2.5rem;
left: -6rem;
top: calc(var(--top) + 2.5rem);
left: calc(var(--left) - 5.5rem);
}
.dialog {
z-index: +2;
}
.emoji {
@ -22,4 +27,3 @@
width: 2rem;
}
}

View file

@ -0,0 +1,14 @@
export function getPosition(ref){
let rect = ref.getBoundingClientRect()
let x = rect.x + window.scrollX;
let y = rect.y + window.scrollY;
return [x, y]
}
export function openDialog(ref){
ref.show();
}
export function closeDialog(ref){
ref.close();
}

View file

@ -0,0 +1,4 @@
<EmojiPicker></EmojiPicker>
@code {
}

View file

@ -6,6 +6,7 @@
@inject IStringLocalizer<Localization> Loc;
@inject IJSRuntime Js;
@inject SessionService Session;
@inject GlobalComponentSvc GlobalComponentSvc
<div class="note-footer">
@if (Reactions.Count > 0)
@ -48,9 +49,8 @@
<span class="like-count">@Likes</span>
}
</button>
<button class="btn positioned" @onclick="ToggleEmojiPicker" @onclick:stopPropagation="true">
<button @ref="EmojiButton" class="btn" @onclick="ToggleEmojiPicker" @onclick:stopPropagation="true">
<Icon Name="Icons.Smiley" Size="1.3em"/>
<EmojiPicker @ref="EmojiPicker" OnEmojiSelect="React"/>
</button>
<button class="btn" @onclick="Quote" @onclick:stopPropagation="true">
<Icon Name="Icons.Quotes" Size="1.3em"/>
@ -80,8 +80,8 @@
[Parameter] [EditorRequired] public required bool IsLiked { get; set; }
[Parameter] [EditorRequired] public required int Renotes { get; set; }
[Parameter] public bool RenotePossible { get; set; }
private EmojiPicker EmojiPicker { get; set; } = null!;
private Menu Menu { get; set; } = null!;
private ElementReference EmojiButton { get; set; }
[CascadingParameter] Note Note { get; set; } = null!;
@ -111,9 +111,9 @@
Note.DoQuote();
}
private async Task ToggleEmojiPicker()
private void ToggleEmojiPicker()
{
await EmojiPicker.Toggle();
GlobalComponentSvc.EmojiPicker?.Open(EmojiButton, new EventCallback<EmojiResponse>(this, React));
}
private void React(EmojiResponse emoji)

View file

@ -0,0 +1,7 @@
using Iceshrimp.Frontend.Components;
namespace Iceshrimp.Frontend.Core.Services;
public class GlobalComponentSvc
{
public EmojiPicker? EmojiPicker { get; set; }
}

View file

@ -6,6 +6,7 @@
@implements IDisposable
@inject NavigationManager Navigation;
<GlobalComponents></GlobalComponents>
<div @ref="SidebarElementRef" @onfocusout="Close" class="sidebar @(_open ? "open" : "")" tabindex=0>
<div class="header">
<account-dropdown/>

View file

@ -84,7 +84,7 @@
position: fixed;
width: 15rem;
height: 100vh;
z-index: 200;
z-index: +3;
background-color: var(--foreground-color);
}
@ -116,6 +116,6 @@
bottom: 0;
left: 0;
background-color: var(--foreground-color);
z-index: 999;
z-index: +4;
}
}

View file

@ -25,6 +25,7 @@ builder.Services.AddSingleton<StateService>();
builder.Services.AddSingleton<EmojiService>();
builder.Services.AddSingleton<VersionService>();
builder.Services.AddSingleton<MessageService>();
builder.Services.AddSingleton<GlobalComponentSvc>();
builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddBlazoredLocalStorageAsSingleton();