R1 cleanup: collAnon and dead code gone, no IndexedDB, honest PWA files
Build / Build (push) Successful in 51s

Starts the completion program (SocialPub docs/ROADMAP.md, "Owner decisions on finishing everything", 2026-10-17).

- The localizer's namespace is decePubClient.Services; collAnon is gone from the repo.
- Dead code: PagesBase, VConstants, SettingsOptions, ViewLanguage, unused APIs routes, InstanceService.Self,
  RequestStats.LastOf/AverageMs, PostAnon/DeleteTotallyAnon, unused AppStatusService methods and their main.js helpers
  (the app badge stays for Web Push), ExtensionMethods/SUtility leftovers (Markdig and BlazorZXingJs packages go),
  unused PublicCacheData/PageSettings/AppConfiguration fields, commented-out code.
- The client log in IndexedDB, which nothing ever read, goes with the whole IndexedDB layer (DnetIndexedDb, IStorage):
  logs go to the browser console; main.js deletes the old "data" database once.
- The solution names the real ClientModels project. Unused vendor assets (fontawesome, solid, open-iconic, rxjs) go.
- robots.txt disallows everything; manifest.json and index.html say decePub; the service worker's cache name follows
  each publish's assets version, so old caches are purged.
- MessageType is Visibility (member names kept: they are resx keys); ExpandMessage.razor is Thread.razor (same route).
- i18n: dead keys removed, Italian "camera" is "punto di vista", DInputBase/DCalendar validation messages come from
  ErrorMessages, DataTransfer's spinner has its label.
- CLAUDE.md follows: client storage, JS interop, PWA, the D fields' messages.

Verified: dotnet build decePubClient.csproj and decePubClient.sln -c Release (0 errors, no new warnings); a Pasture
publish served by the pasture's decepub peer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-17 02:56:57 +02:00
1 parent e4414f1ac9
commit fd2f2e7c65
79 files changed
+155 -6673

No files matched your search

+21 -21
View File
@@ -167,17 +167,17 @@
@if (!form.IsLocated && GroupId is null && Editing is null)
{
<DDropdown @bind-IsOpen="form.IsScopeOptionsOpen" TriggerClass="@(form.IsScopeOptionsOpen ? "btn btn-sm btn-active" : "btn btn-sm")" SheetOnNarrow="true"
ContentClass="mt-2 flex flex-col gap-2 p-2 rounded-box" title="@Localizer["Message scope type: {0}", Localizer[form.MessageType.ToString()]]"
aria-label="@Localizer["Message scope type: {0}", Localizer[form.MessageType.ToString()]]">
ContentClass="mt-2 flex flex-col gap-2 p-2 rounded-box" title="@Localizer["Message scope type: {0}", Localizer[form.Visibility.ToString()]]"
aria-label="@Localizer["Message scope type: {0}", Localizer[form.Visibility.ToString()]]">
<Trigger>
<i class="@form.MessageType.GetMessageTypeIcon() text-base" aria-hidden="true"></i>
<i class="@form.Visibility.GetVisibilityIcon() text-base" aria-hidden="true"></i>
</Trigger>
<ChildContent>
@foreach (var messageType in Enum.GetValues<MessageType>())
@foreach (var visibility in Enum.GetValues<Visibility>())
{
<DButton Size="DSize.Sm" class="justify-start whitespace-nowrap" Active="form.MessageType == messageType" OnClick="() => SetMessageType(messageType)">
<i class="@messageType.GetMessageTypeIcon() text-base" aria-hidden="true"></i>
<span>@Localizer[messageType.ToString()]</span>
<DButton Size="DSize.Sm" class="justify-start whitespace-nowrap" Active="form.Visibility == visibility" OnClick="() => SetVisibility(visibility)">
<i class="@visibility.GetVisibilityIcon() text-base" aria-hidden="true"></i>
<span>@Localizer[visibility.ToString()]</span>
</DButton>
}
</ChildContent>
@@ -391,11 +391,11 @@
: System.Globalization.CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
// a new post starts with the visibility the persona chose in Settings
MessageType DefaultVisibility => CascadingState.Persona?.Source?.Privacy switch
Visibility DefaultVisibility => CascadingState.Persona?.Source?.Privacy switch
{
"private" => MessageType.FollowersOnly,
"unlisted" => MessageType.Unlisted,
_ => MessageType.Public
"private" => Visibility.FollowersOnly,
"unlisted" => Visibility.Unlisted,
_ => Visibility.Public
};
DTextarea<string> textarea;
@@ -413,7 +413,7 @@
protected override async Task OnInitializedAsync()
{
form.GroupId = GroupId;
form.MessageType = DefaultVisibility;
form.Visibility = DefaultVisibility;
form.Language = DefaultLanguage;
form.Sensitive = CascadingState.Persona?.Source?.Sensitive == true;
form.QuotedStatusId = Quoting?.Id;
@@ -446,12 +446,12 @@
return;
form.InReplyToId = InReplyTo.Id;
form.MessageType = InReplyTo.Visibility switch
form.Visibility = InReplyTo.Visibility switch
{
"direct" => MessageType.Direct,
"private" => MessageType.FollowersOnly,
"unlisted" => MessageType.Unlisted,
_ => MessageType.Public
"direct" => Visibility.Direct,
"private" => Visibility.FollowersOnly,
"unlisted" => Visibility.Unlisted,
_ => Visibility.Public
};
// a reply is written in its thread's language, as a rule
form.Language = InReplyTo.Language is { Length: 2 } language && Languages.All.Any(l => l.Code == language) ? language : form.Language;
@@ -462,9 +462,9 @@
form.Content = string.Join(' ', mentions) is { Length: > 0 } prefix ? prefix + " " : null;
}
void SetMessageType(MessageType messageType)
void SetVisibility(Visibility visibility)
{
form.MessageType = messageType;
form.Visibility = visibility;
form.IsScopeOptionsOpen = false;
}
@@ -688,14 +688,14 @@
if (result.Data is ScheduledStatus scheduled)
{
Toast.AddResponseSuccess(Localizer["Scheduled for {0}.", scheduled.ScheduledAt.ToLocalTime().ToString(SUtility.dateTimeFormatExt)]);
form = new() { GroupId = GroupId, MessageType = DefaultVisibility, Language = DefaultLanguage };
form = new() { GroupId = GroupId, Visibility = DefaultVisibility, Language = DefaultLanguage };
await OnPublished.InvokeAsync(null);
return;
}
Toast.AddResponseSuccess(form.IsLocated ? Localizer["Located post published."] : Localizer["Published."]);
var published = result.Data as FeedPost;
form = new() { GroupId = GroupId, MessageType = DefaultVisibility, Language = DefaultLanguage };
form = new() { GroupId = GroupId, Visibility = DefaultVisibility, Language = DefaultLanguage };
await OnPublished.InvokeAsync(published);
}
+4 -4
View File
@@ -1129,10 +1129,10 @@
string VisibilityText(string visibility) => visibility switch
{
"public" => Localizer[MessageType.Public.ToString()],
"unlisted" => Localizer[MessageType.Unlisted.ToString()],
"private" => Localizer[MessageType.FollowersOnly.ToString()],
"direct" => Localizer[MessageType.Direct.ToString()],
"public" => Localizer[Visibility.Public.ToString()],
"unlisted" => Localizer[Visibility.Unlisted.ToString()],
"private" => Localizer[Visibility.FollowersOnly.ToString()],
"direct" => Localizer[Visibility.Direct.ToString()],
_ => Localizer["Located"]
};
+3 -1
View File
@@ -1,5 +1,7 @@
using System.Globalization;
using decePubClient.Resources;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
@@ -39,7 +41,7 @@ public abstract class DInputBase<TValue> : InputBase<TValue>
return true;
}
validationErrorMessage = $"The {DisplayName ?? FieldIdentifier.FieldName} field is not valid.";
validationErrorMessage = string.Format(ErrorMessages.InvalidValue, DisplayName ?? FieldIdentifier.FieldName);
return false;
}
}
+1 -1
View File
@@ -32,7 +32,7 @@
result = date;
return true;
}
validationErrorMessage = $"The {DisplayName ?? FieldIdentifier.FieldName} field is not a valid date.";
validationErrorMessage = string.Format(ErrorMessages.InvalidDate, DisplayName ?? FieldIdentifier.FieldName);
return false;
}
+1 -1
View File
@@ -14,7 +14,7 @@
data-export-kind="@data">
@if (exporting == data)
{
<DLoading Size="DSize.Xs" />
<DLoading Size="DSize.Xs" LabelText="@Localizer["loading"]" />
}
else
{
+2 -2
View File
@@ -84,7 +84,7 @@ else
<legend class="text-sm font-semibold pb-1">@Localizer["New posts"]</legend>
<label class="flex flex-col gap-1 text-sm">
<span>@Localizer["Visibility"]</span>
<DSelect TValue="MessageType" Size="DSize.Sm" @bind-Value="form.Privacy" data-profile-privacy>
<DSelect TValue="Visibility" Size="DSize.Sm" @bind-Value="form.Privacy" data-profile-privacy>
@foreach (var type in Visibilities)
{
<option value="@type">@Localizer[type.ToString()]</option>
@@ -130,7 +130,7 @@ else
[Inject] AuthService AuthService { get; set; }
[Inject] ILoggingService Logger { get; set; }
static readonly MessageType[] Visibilities = [MessageType.Public, MessageType.Unlisted, MessageType.FollowersOnly];
static readonly Visibility[] Visibilities = [Visibility.Public, Visibility.Unlisted, Visibility.FollowersOnly];
Account account;
ProfileForm form = new();