[frontend] Bind the Timeline Intersection Observer to the scroller and increase root margin
This commit is contained in:
parent
35de6a472c
commit
04e3ed0195
10 changed files with 60 additions and 27 deletions
|
@ -1,22 +1,32 @@
|
|||
@using Iceshrimp.Shared.Schemas
|
||||
@using Ljbc1994.Blazor.IntersectionObserver
|
||||
@using Ljbc1994.Blazor.IntersectionObserver.API
|
||||
@using Ljbc1994.Blazor.IntersectionObserver.Components
|
||||
@inject IJSRuntime Js
|
||||
<IntersectionObserve OnChange="@(entry => Change(Note.Id, entry))">
|
||||
@if(_init) // FIXME: We need to wait for the Component to render once before initializing the Intersection Observer.
|
||||
// With the <IntersectionObserver> Component this is AFAIK only possible by not rendering it until then.
|
||||
// The proper fix for this is to change to the Service Pattern.
|
||||
// But that requires the IntersectionObserver Library to be modified to return what element an observation update is for.
|
||||
{
|
||||
<IntersectionObserve Options="new IntersectionObserverOptions(){ Root = Scroller, RootMargin = margin}" OnChange="@(entry => Change(entry))">
|
||||
<div class="tgt" @ref="context.Ref.Current">
|
||||
@if (_isIntersecting)
|
||||
{
|
||||
<TimelineNote Note="Note" />
|
||||
}else {
|
||||
<div class="placeholder" style="height: @(Height ?? 150)px"></div>
|
||||
<div class="placeholder" style="height: @(Height ?? 150)px"></div>
|
||||
}
|
||||
</div>
|
||||
</IntersectionObserve>
|
||||
}
|
||||
@code {
|
||||
[Parameter] public required NoteResponse Note { get; set; }
|
||||
private IJSObjectReference? _module;
|
||||
private int? Height { get; set; } = null;
|
||||
private bool _isIntersecting = true;
|
||||
[Parameter][EditorRequired] public required NoteResponse Note { get; set; }
|
||||
[Parameter][EditorRequired] public ElementReference Scroller { get; set; }
|
||||
private IJSObjectReference? _module;
|
||||
private int? Height { get; set; } = null;
|
||||
private bool _isIntersecting = true;
|
||||
private string margin = "200%";
|
||||
private bool _init = false;
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
|
@ -24,12 +34,22 @@
|
|||
{
|
||||
_module = await Js.InvokeAsync<IJSObjectReference>("import",
|
||||
"./Components/LazyNote.razor.js");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Change(string id, IntersectionObserverEntry entry)
|
||||
protected override void OnAfterRender(bool firstRender)
|
||||
{
|
||||
if (id == Note.Id && entry.IsIntersecting == false)
|
||||
if (firstRender)
|
||||
{
|
||||
_init = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async Task Change (IntersectionObserverEntry entry)
|
||||
{
|
||||
if (entry.IsIntersecting == false)
|
||||
{
|
||||
Height = await GetHeight();
|
||||
_isIntersecting = false;
|
||||
|
@ -37,7 +57,7 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (id == Note.Id && entry.IsIntersecting)
|
||||
if (entry.IsIntersecting)
|
||||
{
|
||||
_isIntersecting = true;
|
||||
}
|
||||
|
|
5
Iceshrimp.Frontend/Components/RecursiveNote.razor
Normal file
5
Iceshrimp.Frontend/Components/RecursiveNote.razor
Normal file
|
@ -0,0 +1,5 @@
|
|||
<h3>RecursiveNote</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
0
Iceshrimp.Frontend/Components/RecursiveNote.razor.css
Normal file
0
Iceshrimp.Frontend/Components/RecursiveNote.razor.css
Normal file
|
@ -6,13 +6,15 @@
|
|||
@inject ApiService ApiService
|
||||
@if (_init)
|
||||
{
|
||||
@foreach (var note in Timeline)
|
||||
{
|
||||
<LazyNote Note="note" />
|
||||
}
|
||||
<IntersectionObserve OnChange="entry => OnEnd(entry)">
|
||||
<div @ref="context.Ref.Current" class="end">END!</div>
|
||||
</IntersectionObserve>
|
||||
<div @ref="Scroller" class="scroller">
|
||||
@foreach (var note in Timeline)
|
||||
{
|
||||
<LazyNote Scroller="Scroller" Note="note" />
|
||||
}
|
||||
<IntersectionObserve OnChange="entry => OnEnd(entry)">
|
||||
<div @ref="context.Ref.Current" class="end">END!</div>
|
||||
</IntersectionObserve>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -25,6 +27,7 @@ else
|
|||
private string? MaxId { get; set; }
|
||||
private string? MinId { get; set; }
|
||||
private bool LockFetch { get; set; }
|
||||
public ElementReference Scroller { get; set; }
|
||||
|
||||
private async Task Initialize()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
.scroller {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: scroll;
|
||||
max-height: 100vh;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
|
@ -73,5 +73,6 @@ internal class SessionService
|
|||
LocalStorage.SetItem("last_user", user.Id);
|
||||
((IJSInProcessRuntime)Js).InvokeVoid("eval",
|
||||
$"document.cookie = \"session={user.Id}; expires=Fri, 31 Dec 9999 23:59:59 GMT; SameSite=Strict\"");
|
||||
// Security implications of this need a second pass? user.Id should never be user controllable, but still.
|
||||
}
|
||||
}
|
6
Iceshrimp.Frontend/Pages/SingleNote.razor
Normal file
6
Iceshrimp.Frontend/Pages/SingleNote.razor
Normal file
|
@ -0,0 +1,6 @@
|
|||
@page "/SingleNote"
|
||||
<h3>SingleNote</h3>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
0
Iceshrimp.Frontend/Pages/SingleNote.razor.css
Normal file
0
Iceshrimp.Frontend/Pages/SingleNote.razor.css
Normal file
|
@ -1,8 +1,6 @@
|
|||
@page "/"
|
||||
@using Iceshrimp.Frontend.Components
|
||||
<div class="scroller">
|
||||
<TimelineComponent />
|
||||
</div>
|
||||
<TimelineComponent />
|
||||
|
||||
@code {
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
.scroller {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: scroll;
|
||||
max-height: 100vh;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
Loading…
Add table
Reference in a new issue