Finished the directory
This commit is contained in:
parent
d0ac64e1be
commit
e9716b4157
4 changed files with 85 additions and 11 deletions
|
@ -1,4 +1,6 @@
|
||||||
@page "/directory"
|
@page "/directory"
|
||||||
|
@using System.Text.RegularExpressions
|
||||||
|
@using System.Globalization
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
@inject IJSRuntime JS
|
@inject IJSRuntime JS
|
||||||
@inject State State
|
@inject State State
|
||||||
|
@ -9,34 +11,74 @@
|
||||||
<Description>Welcome to the <a href="https://home.omg.lol/directory">omg.lol member directory</a>! Everyone here is awesome. <i class="fa-solid fa-sparkles"></i></Description>
|
<Description>Welcome to the <a href="https://home.omg.lol/directory">omg.lol member directory</a>! Everyone here is awesome. <i class="fa-solid fa-sparkles"></i></Description>
|
||||||
</PageHeading>
|
</PageHeading>
|
||||||
|
|
||||||
<div id="directory" class="responsive">
|
@if (groupedAddresses != null) {
|
||||||
|
IdnMapping idn = new IdnMapping();
|
||||||
@if (addresses != null) {
|
<article id="directoryIndex" class="responsive">
|
||||||
@* TODO: Display avatar and address name, grouped by starting letter? *@
|
<nav class="wrap">
|
||||||
}
|
@foreach (var group in groupedAddresses) {
|
||||||
|
<a @onclick='()=>{JS.InvokeVoidAsync("scrollToId", $"index-{group.Key}");}' class="button circle transparent address">@group.Key</a>
|
||||||
|
}
|
||||||
|
</nav>
|
||||||
|
</article>
|
||||||
|
<article id="directory" class="responsive">
|
||||||
|
@foreach(var group in groupedAddresses) {
|
||||||
|
<h3 class="address" id="index-@group.Key">— @group.Key —</h3>
|
||||||
|
<ul>
|
||||||
|
@foreach(string address in group) {
|
||||||
|
string displayAddress = address;
|
||||||
|
string linkAddress = address;
|
||||||
|
if (group.Key == "😀") {
|
||||||
|
try {
|
||||||
|
linkAddress = idn.GetAscii(address);
|
||||||
|
displayAddress = $"{address} {linkAddress}";
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
<li>
|
||||||
|
<a class="chip medium no-border no-margin" href="/person/@address">
|
||||||
|
<img class="circle avatar responsive" src="https://profiles.cache.lol/@linkAddress/picture">
|
||||||
|
<span>@displayAddress</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
</article>
|
||||||
|
}
|
||||||
|
else {
|
||||||
<LoadingCard id="address-loading" icon="fa-duotone fa-address-book"></LoadingCard>
|
<LoadingCard id="address-loading" icon="fa-duotone fa-address-book"></LoadingCard>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<string>? addresses;
|
private List<string>? addresses;
|
||||||
|
private IOrderedEnumerable<IGrouping<string, string>>? groupedAddresses;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync() {
|
protected override async Task OnInitializedAsync() {
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
if (addresses == null || addresses.Count == 0) addresses = await State.GetDirectory();
|
if (addresses == null || addresses.Count == 0){
|
||||||
|
addresses = await State.GetDirectory();
|
||||||
|
GroupAddresses();
|
||||||
|
}
|
||||||
State.PropertyChanged += StateChanged;
|
State.PropertyChanged += StateChanged;
|
||||||
State.CanRefresh = true;
|
State.CanRefresh = true;
|
||||||
await InvokeAsync(StateHasChanged);
|
await InvokeAsync(StateHasChanged);
|
||||||
await JS.InvokeVoidAsync("removeElementById", "address-loading");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void StateChanged(object? sender, PropertyChangedEventArgs e) {
|
private async void StateChanged(object? sender, PropertyChangedEventArgs e) {
|
||||||
if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) {
|
if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) {
|
||||||
addresses = await State.GetDirectory(true);
|
addresses = await State.GetDirectory(true);
|
||||||
|
GroupAddresses();
|
||||||
State.IsRefreshing = false;
|
State.IsRefreshing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void GroupAddresses() {
|
||||||
|
groupedAddresses = addresses?.GroupBy(s => {
|
||||||
|
if (Regex.IsMatch(s, "^[0-9]", RegexOptions.IgnoreCase)) return "#";
|
||||||
|
else if (Regex.IsMatch(s, "^[a-z]", RegexOptions.IgnoreCase)) return s.First().ToString().ToUpper();
|
||||||
|
else return "😀";
|
||||||
|
}).OrderBy(g => g.Key);
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
State.PropertyChanged -= StateChanged;
|
State.PropertyChanged -= StateChanged;
|
||||||
State.CanRefresh = false;
|
State.CanRefresh = false;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using Microsoft.AspNetCore.Components;
|
using Microsoft.AspNetCore.Components;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace Neighbourhood.omg.lol.Models {
|
namespace Neighbourhood.omg.lol.Models {
|
||||||
|
@ -146,7 +147,11 @@ namespace Neighbourhood.omg.lol.Models {
|
||||||
|
|
||||||
public async Task<List<string>?> GetDirectory(bool forceRefresh = false) {
|
public async Task<List<string>?> GetDirectory(bool forceRefresh = false) {
|
||||||
if (forceRefresh || this.AddressDirectory == null || this.AddressDirectory.Count == 0) {
|
if (forceRefresh || this.AddressDirectory == null || this.AddressDirectory.Count == 0) {
|
||||||
this.AddressDirectory = await api.Directory();
|
IdnMapping idn = new IdnMapping();
|
||||||
|
this.AddressDirectory = (await api.Directory()).Select(s => {
|
||||||
|
if (s.StartsWith("xn--")) return idn.GetUnicode(s);
|
||||||
|
else return s;
|
||||||
|
}).ToList();
|
||||||
}
|
}
|
||||||
return this.AddressDirectory;
|
return this.AddressDirectory;
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,4 +400,20 @@ a.row.indent {
|
||||||
:is(button,.button,.chip).large.small > .responsive {
|
:is(button,.button,.chip).large.small > .responsive {
|
||||||
inline-size: 3rem;
|
inline-size: 3rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#directory{
|
||||||
|
column-width: 14rem;
|
||||||
|
}
|
||||||
|
#directory a {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
article#directory ul{
|
||||||
|
list-style:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#directoryIndex a {
|
||||||
|
font-size: 1.5rem;
|
||||||
}
|
}
|
|
@ -11,4 +11,15 @@ async function delay(t) {
|
||||||
|
|
||||||
async function removeElementById(id) {
|
async function removeElementById(id) {
|
||||||
document.getElementById(id)?.remove()
|
document.getElementById(id)?.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
function scrollToId(id) {
|
||||||
|
const element = document.getElementById(id);
|
||||||
|
if (element instanceof HTMLElement) {
|
||||||
|
element.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "start",
|
||||||
|
inline: "nearest"
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue