Changed Home Page to SSR (fixes #1)

This commit is contained in:
Mia Rose Winter 2024-02-21 22:51:11 +01:00
parent 16fde0644c
commit 587b073b20
Signed by: miawinter
GPG key ID: 4B6F6A83178F595E
2 changed files with 87 additions and 76 deletions

View file

@ -0,0 +1,24 @@
@typeparam T
@foreach (var item in Items) {
@ChildContent(item)
}
@code {
[SupplyParameterFromQuery]
public int Page { get; set; } = 0;
[Parameter]
public required RenderFragment<T> ChildContent { get; set; }
[Parameter]
public required Func<int, int, ValueTask<IEnumerable<T>>> LoadCallback { get; set; }
[Parameter]
public int ItemsPerPage { get; set; } = 10;
private List<T> Items { get; } = [];
protected override async Task OnInitializedAsync() {
foreach (var i in await LoadCallback(Page * ItemsPerPage, ItemsPerPage)) Items.Add(i);
}
}

View file

@ -4,13 +4,12 @@
@using Wave.Data @using Wave.Data
@using Wave.Utilities @using Wave.Utilities
@rendermode InteractiveServer
@attribute [StreamRendering]
@inject IOptions<Customization> Customizations @inject IOptions<Customization> Customizations
@inject IOptions<Features> Features @inject IOptions<Features> Features
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IDbContextFactory<ApplicationDbContext> ContextFactory; @inject IDbContextFactory<ApplicationDbContext> ContextFactory;
@inject IStringLocalizer<Home> Localizer @inject IStringLocalizer<Home> Localizer
@inject IMessageDisplay Message
<HeadContent> <HeadContent>
<meta property="og:type" content="website"> <meta property="og:type" content="website">
@ -62,100 +61,88 @@
} }
</section> </section>
<!-- TODO: somehow get status message --> @if (Featured is {} featured) {
<article class="mb-6">
@if (Busy) { <ArticleLink Article="featured">
<div class="flex place-content-center h-full text-primary"> <div class="hero bg-secondary text-secondary-content border-l-8 border-current shadow rounded-box">
<span class="loading loading-spinner loading-lg"></span> <div class="hero-content">
</div> <div class="flex flex-col space-y-6 my-3">
} else { <h2 class="text-2xl lg:text-4xl">
@if (Articles.FirstOrDefault() is {} featured) { @featured.Title
<article class="mb-6"> <p class="flex flex-wrap gap-2">
<ArticleLink Article="featured"> @foreach (var category in featured.Categories.OrderBy(c => c.Color)) {
<div class="hero bg-secondary text-secondary-content border-l-8 border-current shadow rounded-box"> <span class="badge badge-@CategoryUtilities.GetCssClassPostfixForColor(category.Color)">
<div class="hero-content"> @category.Name
<div class="flex flex-col space-y-6 my-3"> </span>
<h2 class="text-2xl lg:text-4xl"> }
@featured.Title
<p class="flex flex-wrap gap-2">
@foreach (var category in featured.Categories.OrderBy(c => c.Color)) {
<span class="badge badge-@CategoryUtilities.GetCssClassPostfixForColor(category.Color)">
@category.Name
</span>
}
</p>
</h2>
<p class="line-clamp-6">
<small class="text-sm">@featured.PublishDate.ToString("g")</small><br/>
@featured.Body[..Math.Min(1000, featured.Body.Length)]
</p> </p>
<div class="flex"> </h2>
<ProfilePill Profile="featured.Author" DisableProfileLink="true" /> <p class="line-clamp-6">
</div> <small class="text-sm">@featured.PublishDate.ToString("g")</small><br/>
@featured.Body[..Math.Min(1000, featured.Body.Length)]
</p>
<div class="flex">
<ProfilePill Profile="featured.Author" DisableProfileLink="true" />
</div> </div>
</div> </div>
</div> </div>
</ArticleLink> </div>
</article> </ArticleLink>
} else { </article>
<h2 class="text-2xl lg:text-4xl mb-6">@Localizer["NoArticles_Title"]</h2> } else {
<p>@Localizer["NoArticles_Message"]</p> <h2 class="text-2xl lg:text-4xl mb-6">@Localizer["NoArticles_Title"]</h2>
} <p>@Localizer["NoArticles_Message"]</p>
<ArticleTileArray>
@foreach (var article in Articles.Skip(1)) {
<ArticleTile Article="article" />
}
</ArticleTileArray>
} }
@if (HasMore) { <ArticleTileArray>
<div class="flex place-content-center"> <PageComponent LoadCallback="LoadArticles">
<button class="btn btn-wide" @onclick="More">@Localizer["More"]</button> <ArticleTile Article="context" />
</PageComponent>
</ArticleTileArray>
<div class="grid place-content-center my-3">
<div class="join">
<a class="join-item btn" href="/?page=@(Page-1)" disabled="@(Page < 1)">«</a>
<button class="join-item btn">Page @(Page+1)</button>
<a class="join-item btn" href="/?page=@(Page+1)" disabled="@(Page >= TotalPages-1)">»</a>
</div> </div>
} </div>
@code { @code {
[CascadingParameter(Name = "TitlePrefix")] [CascadingParameter(Name = "TitlePrefix")]
private string TitlePrefix { get; set; } = default!; private string TitlePrefix { get; set; } = default!;
[SupplyParameterFromQuery]
public int Page { get; set; } = 0;
private List<Article> Articles { get; } = []; private int TotalPages { get; set; } = 1;
private bool HasMore { get; set; }
private bool Busy { get; set; } = true;
protected override async Task OnAfterRenderAsync(bool firstRender) { private Article? Featured { get; set; }
if (firstRender) {
try {
await using var context = await ContextFactory.CreateDbContextAsync();
var query = context.Set<Article>() protected override async Task OnInitializedAsync() {
.Include(a => a.Author).Include(a => a.Categories)
.OrderByDescending(a => a.PublishDate);
var articles = await query.Take(11).ToListAsync();
HasMore = (await query.CountAsync()) > 11;
Articles.AddRange(articles);
} finally {
Busy = false;
await InvokeAsync(StateHasChanged);
}
}
}
private async Task More() {
try { try {
Busy = HasMore = true;
await using var context = await ContextFactory.CreateDbContextAsync(); await using var context = await ContextFactory.CreateDbContextAsync();
var query = context.Set<Article>() var query = context.Set<Article>()
.Include(a => a.Author).Include(a => a.Categories) .Include(a => a.Author).Include(a => a.Categories)
.OrderByDescending(a => a.PublishDate) .OrderByDescending(a => a.PublishDate).ThenBy(a => a.Id);
.Skip(Articles.Count);
var articles = await query.Take(10).ToListAsync(); Featured = await query.FirstOrDefaultAsync();
Articles.AddRange(articles); TotalPages = (int) Math.Ceiling((await query.CountAsync() - 1) / 10.0);
HasMore = (await query.CountAsync()) > 10; } catch {
} finally { Message.ShowError(Localizer["Articles_Load_Error"]);
Busy = false;
} }
} }
private async ValueTask<IEnumerable<Article>> LoadArticles(int page, int count) {
try {
await using var context = await ContextFactory.CreateDbContextAsync();
return await context.Set<Article>()
.Include(a => a.Author).Include(a => a.Categories)
.OrderByDescending(a => a.PublishDate).ThenBy(a => a.Id)
.Skip(page + 1).Take(count).ToListAsync();
} catch {
Message.ShowError(Localizer["Articles_Load_Error"]);
return [];
}
}
} }