[frontend] Refactor EmojiPicker and it's usages, add globally accessible components
This commit is contained in:
parent
641c6578e6
commit
52dca9f3be
12 changed files with 105 additions and 54 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
export function openDialog(element) {
|
||||
element.showModal()
|
||||
element.show()
|
||||
}
|
||||
|
||||
export function closeDialog(element) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
14
Iceshrimp.Frontend/Components/EmojiPicker.razor.js
Normal file
14
Iceshrimp.Frontend/Components/EmojiPicker.razor.js
Normal 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();
|
||||
}
|
4
Iceshrimp.Frontend/Components/GlobalComponents.razor
Normal file
4
Iceshrimp.Frontend/Components/GlobalComponents.razor
Normal file
|
@ -0,0 +1,4 @@
|
|||
<EmojiPicker></EmojiPicker>
|
||||
@code {
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
7
Iceshrimp.Frontend/Core/Services/GlobalComponentSvc.cs
Normal file
7
Iceshrimp.Frontend/Core/Services/GlobalComponentSvc.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
using Iceshrimp.Frontend.Components;
|
||||
namespace Iceshrimp.Frontend.Core.Services;
|
||||
|
||||
public class GlobalComponentSvc
|
||||
{
|
||||
public EmojiPicker? EmojiPicker { get; set; }
|
||||
}
|
|
@ -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/>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue