Tidying up the feed feature
This commit is contained in:
parent
9c3f578eb6
commit
93b49f2533
10 changed files with 159 additions and 95 deletions
|
@ -1,5 +1,5 @@
|
|||
namespace Neighbourhood.omg.lol {
|
||||
public static class FeatureFlags {
|
||||
public static bool Following { get; } = false;
|
||||
public static bool Following { get; } = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -198,16 +198,18 @@ namespace Neighbourhood.omg.lol {
|
|||
}
|
||||
|
||||
public bool IsFollowing(string address) => Following?.Contains(address) ?? false;
|
||||
public void Follow(string address) {
|
||||
public async Task Follow(string address) {
|
||||
if (Following == null) Following = new List<string>();
|
||||
Following.Add(address);
|
||||
Preferences.Default.Set("following", JsonSerializer.Serialize(Following));
|
||||
await GetFeed(forceRefresh: true);
|
||||
}
|
||||
|
||||
public void Unfollow(string address) {
|
||||
public async Task Unfollow(string address) {
|
||||
if (Following == null) Following = new List<string>();
|
||||
Following.Remove(address);
|
||||
Preferences.Default.Set("following", JsonSerializer.Serialize(Following));
|
||||
await GetFeed(forceRefresh: true);
|
||||
}
|
||||
|
||||
public async Task<MarkupString?> GetBio(string address, bool forceRefresh = false) {
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
<i class="emoji medium" data-emoji="👋">👋</i>
|
||||
<span>Hey, @(State.Name ?? "there").</span>
|
||||
</a>
|
||||
<a class="m s row" href="/directory">
|
||||
<a class="s row" href="/now">
|
||||
<i class="square fa-duotone fa-seedling"></i>
|
||||
<span>Now.garden</span>
|
||||
</a>
|
||||
<a class="s row" href="/directory">
|
||||
<i class="square fa-duotone fa-address-book"></i>
|
||||
<span>Address Directory</span>
|
||||
<span>Directory</span>
|
||||
</a>
|
||||
@foreach (AddressResponseData address in State.AddressList ?? new List<AddressResponseData>()) {
|
||||
<a class="row @(address == State.SelectedAddress ? "active" : "")" @onclick="() => State.SelectedAddress = address">
|
||||
|
@ -32,13 +36,7 @@
|
|||
</a>
|
||||
}
|
||||
}
|
||||
@if (FeatureFlags.Following && State.IsAuthorized) {
|
||||
<a class="m s row" href="/feed">
|
||||
<i class="square fa-solid fa-list-timeline"></i>
|
||||
<span>Feed</span>
|
||||
</a>
|
||||
<FollowingList class="m s"></FollowingList>
|
||||
}
|
||||
|
||||
@if (State.IsAuthorized) {
|
||||
<a class="row" @onclick='() => AuthStateProvider.Logout()'>
|
||||
<i class="fa-solid fa-door-open"></i>
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
@inject State State
|
||||
|
||||
@if (State.Following != null) {
|
||||
<details class="@(@class)">
|
||||
<summary class="none">
|
||||
<a class="row">
|
||||
<i class="square fa-solid fa-caret-down"></i>
|
||||
<span>Following</span>
|
||||
</a>
|
||||
</summary>
|
||||
@foreach (string address in State.Following) {
|
||||
<a class="transparent button horizontal-padding indent row" href="/person/@address">
|
||||
<img class="tiny circle avatar" src="https://profiles.cache.lol/@address/picture" />
|
||||
<span class="address"><i class="fa-solid fa-fw fa-at tiny"></i>@address</span>
|
||||
</a>
|
||||
}
|
||||
</details>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public string? @class { get; set; }
|
||||
}
|
|
@ -11,24 +11,26 @@
|
|||
<i class="square fa-light fa-comment-dots"></i>
|
||||
<div class="label">Eph.emer.al</div>
|
||||
</NavLink>
|
||||
<NavLink class="nav-link" href="/now">
|
||||
@if (FeatureFlags.Following && State.IsAuthorized) {
|
||||
<NavLink class="nav-link" href="/feed">
|
||||
<i class="square fa-solid fa-list-timeline"></i>
|
||||
<div class="label">Timeline</div>
|
||||
</NavLink>
|
||||
<NavLink class="l m nav-link" href="/now">
|
||||
<i class="square fa-duotone fa-seedling"></i>
|
||||
<div class="label">Now.garden</div>
|
||||
</NavLink>
|
||||
|
||||
|
||||
<NavLink class="l nav-link" href="/directory">
|
||||
<i class="square fa-duotone fa-address-book"></i>
|
||||
<div class="label">Address Directory</div>
|
||||
</NavLink>
|
||||
@if (FeatureFlags.Following) {
|
||||
<AuthorizeView>
|
||||
<Authorized>
|
||||
<NavLink class="l nav-link" href="/feed">
|
||||
<i class="square fa-solid fa-list-timeline"></i>
|
||||
<div class="label">Feed</div>
|
||||
</NavLink>
|
||||
<FollowingList class="l"></FollowingList>
|
||||
</Authorized>
|
||||
</AuthorizeView>
|
||||
}
|
||||
else {
|
||||
<NavLink class="nav-link" href="/now">
|
||||
<i class="square fa-duotone fa-seedling"></i>
|
||||
<div class="label">Now.garden</div>
|
||||
</NavLink>
|
||||
}
|
||||
|
||||
|
||||
|
||||
<NavLink class="l m nav-link" href="/directory">
|
||||
<i class="square fa-duotone fa-address-book"></i>
|
||||
<div class="label">Directory</div>
|
||||
</NavLink>
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
@if (messages != null) {
|
||||
foreach (MarkupString message in messages) {
|
||||
<article class="ephemeral center">
|
||||
<article class="ephemeral">
|
||||
@message
|
||||
</article>
|
||||
}
|
||||
|
|
|
@ -2,29 +2,85 @@
|
|||
@implements IDisposable
|
||||
@inject IJSRuntime JS
|
||||
@inject State State
|
||||
@inject NavigationManager Nav
|
||||
|
||||
<RefreshButton></RefreshButton>
|
||||
|
||||
<PageHeading title="Feed" icon="fa-solid fa-list-timeline">
|
||||
<PageHeading title="Timeline" icon="fa-solid fa-list-timeline">
|
||||
<Description>A feed of all the statuses and pics of the people you follow.</Description>
|
||||
</PageHeading>
|
||||
|
||||
@if (feed != null) foreach (StatusOrPic item in feed) {
|
||||
@if(!(State.Following?.Any() ?? false)) {
|
||||
<PageHeading title="" icon="fa-light fa-face-sad-sweat">
|
||||
<Description>
|
||||
It looks like you're not following anyone yet.
|
||||
</Description>
|
||||
</PageHeading>
|
||||
<p class="center-align">Check out the <a href="/directory">Directory</a> (or other parts of the app) to find awesome people to follow.</p>
|
||||
}
|
||||
else {
|
||||
<div class="responsive">
|
||||
<div class="tabs scroll">
|
||||
<a data-ui="#feed" class="active">
|
||||
<i class="fa-solid fa-list-timeline"></i>
|
||||
<span>Timeline</span>
|
||||
</a>
|
||||
<a data-ui="#following">
|
||||
<i class="fa-duotone fa-address-book"></i>
|
||||
<span>Following</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="responsive page-container">
|
||||
<div id="feed" class="page no-padding active">
|
||||
@if (feed != null){
|
||||
foreach (StatusOrPic item in feed) {
|
||||
if (item.IsStatus) {
|
||||
<StatusCard Status="@item.Status"></StatusCard>
|
||||
}
|
||||
else if (item.IsPic) {
|
||||
<PicCard Pic="@item.Pic"></PicCard>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
<LoadingCard id="feedLoading" icon="fa-solid fa-list-timeline"></LoadingCard>
|
||||
</div>
|
||||
|
||||
<LoadingCard id="feedLoading" icon="fa-solid fa-list-timeline"></LoadingCard>
|
||||
<div id="following" class="page no-padding">
|
||||
<ul>
|
||||
@foreach (string address in State.Following ?? new List<string>()) {
|
||||
string displayAddress = address;
|
||||
string linkAddress = address;
|
||||
@* if (group.Key == "😀") {
|
||||
try {
|
||||
linkAddress = idn.GetAscii(address);
|
||||
displayAddress = $"{address} {linkAddress}";
|
||||
}
|
||||
catch (Exception) { }
|
||||
} *@
|
||||
<li class="vertical-margin row padding surface-container">
|
||||
<img class="round" src="https://profiles.cache.lol/@linkAddress/picture">
|
||||
<div class="max">
|
||||
<a href="/person/@linkAddress" class="address"><i class="fa-solid fa-fw fa-at tiny"></i>@displayAddress</a>
|
||||
</div>
|
||||
<button id="follow-button" @onclick="() => UnfollowClick(address)">
|
||||
<i class="fa-solid fa-minus"></i> Unfollow
|
||||
</button>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private IOrderedEnumerable<StatusOrPic>? feed;
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await base.OnInitializedAsync();
|
||||
string fragment = new Uri(Nav.Uri).Fragment;
|
||||
await JS.InvokeVoidAsync("ui", fragment);
|
||||
if (feed == null || feed.Count() == 0) feed = await State.GetFeed();
|
||||
State.PropertyChanged += StateChanged;
|
||||
State.CanRefresh = true;
|
||||
|
@ -41,6 +97,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
public async Task UnfollowClick(string address) {
|
||||
await State.Unfollow(address);
|
||||
feed = await State.GetFeed(forceRefresh: true);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
State.PropertyChanged -= StateChanged;
|
||||
State.CanRefresh = false;
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
@if (FeatureFlags.Following) {
|
||||
<div class="row center-align">
|
||||
@if (State.IsFollowing(Address)) {
|
||||
<button id="follow-button" @onclick="() => {State.Unfollow(Address);InvokeAsync(StateHasChanged);}">
|
||||
<button id="follow-button" @onclick="async() => {await State.Unfollow(Address);await InvokeAsync(StateHasChanged);}">
|
||||
<i class="fa-solid fa-minus"></i> Unfollow
|
||||
</button>
|
||||
}
|
||||
else {
|
||||
<button id="follow-button" @onclick="() => {State.Follow(Address);InvokeAsync(StateHasChanged);}">
|
||||
<button id="follow-button" @onclick="async() => {await State.Follow(Address);await InvokeAsync(StateHasChanged);}">
|
||||
<i class="fa-solid fa-plus"></i> Follow
|
||||
</button>
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
@inject IJSRuntime JS
|
||||
|
||||
<article class="no-padding">
|
||||
<article class="pic no-padding">
|
||||
<img src="@Pic!.Url" loading="lazy">
|
||||
<div class="padding">
|
||||
<div class="padding row">
|
||||
<div class="emoji" data-emoji="🖼️">🖼️</div>
|
||||
<div class="max">
|
||||
<nav>
|
||||
<a class="author" href="/person/@Pic.Address#pics">
|
||||
<i class="fa-solid fa-fw fa-at"></i>@Pic.Address
|
||||
</a>
|
||||
<span class="max"></span>
|
||||
<a class="chip transparent-border right">
|
||||
<i class="fa fa-clock"></i> @Pic.RelativeTime
|
||||
</a>
|
||||
</nav>
|
||||
@if(!string.IsNullOrWhiteSpace(Pic.Description)){
|
||||
<p>@((MarkupString)Pic.DescriptionHtml)</p>
|
||||
|
@ -22,6 +21,9 @@
|
|||
</div>
|
||||
}
|
||||
<nav>
|
||||
<a class="chip transparent-border">
|
||||
<i class="fa fa-clock"></i> @Pic.RelativeTime
|
||||
</a>
|
||||
<div class="max"></div>
|
||||
@if(Editable) {
|
||||
<button @onclick="EditPic"><i class="fa-solid fa-pencil"></i> Edit</button>
|
||||
|
@ -31,6 +33,7 @@
|
|||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
@code {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
--background: var(--gray-8);
|
||||
--shadow: var(--black);
|
||||
--button-shadow: var(--gray-7);
|
||||
--max-article-size: 75rem;
|
||||
}
|
||||
|
||||
body.dark {
|
||||
|
@ -83,7 +84,7 @@ img {
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.status .emoji {
|
||||
:is(.status,.pic) .emoji {
|
||||
margin-bottom: auto;
|
||||
inline-size: 5.5rem;
|
||||
block-size: 5.5rem;
|
||||
|
@ -92,7 +93,7 @@ img {
|
|||
text-indent: -10px;
|
||||
}
|
||||
|
||||
.status .emoji, #status-emoji, #new-status-emoji {
|
||||
:is(.status,.pic) .emoji, #status-emoji, #new-status-emoji {
|
||||
margin-bottom: auto;
|
||||
inline-size: 3.5rem;
|
||||
block-size: 3.5rem;
|
||||
|
@ -101,6 +102,10 @@ img {
|
|||
text-indent: -6px;
|
||||
}
|
||||
|
||||
:not(#feed)>.pic .emoji{
|
||||
display:none;
|
||||
}
|
||||
|
||||
:is(h1, h2, h3, h4, h5, h6) :is(i.fa-at, i:only-child){
|
||||
margin-right: 0;
|
||||
inline-size: auto;
|
||||
|
@ -296,6 +301,10 @@ article.ephemeral {
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
#now-garden{
|
||||
gap:1rem;
|
||||
}
|
||||
|
||||
#now-garden > :not(.now) {
|
||||
position: absolute;
|
||||
}
|
||||
|
@ -476,3 +485,14 @@ menu > details .row, menu > li > details .row {
|
|||
menu > details > a:is(:hover,:focus,.active), menu > details > summary:is(:hover,:focus,.active) {
|
||||
background-color: var(--active);
|
||||
}
|
||||
|
||||
article {
|
||||
width: 100%;
|
||||
max-width: var(--max-article-size);
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
article.now {
|
||||
margin: 0;
|
||||
width:auto;
|
||||
}
|
Loading…
Reference in a new issue