Files
decePubClient/Pages/Administration.razor
T
thepraandClaude Opus 5.5 566b0e33ea R7 custom emoji in decePub: the server's own, administered, picked, suggested and shown
Administration has a Custom emoji section (EmojiPanel, data-admin-section=emoji): the server's emoji by category, added
with a picture streamed from the file, changed (category, picker, disabled, picture; never the shortcode) and deleted,
asked first, with PrivaPub's 409 and 422 in the dialog. EmojiService reads /clientapi/admin/emoji and, for everyone,
/api/v1/custom_emojis, kept a day in localStorage (CustomEmojiCache) and read again after a change here. EmojiPicker
(a DDropdown sheet on a phone, rendered only while open) offers them by category with common unicode emoji, searchable:
the composer writes the choice at the caret, a card and the announcements banner react with it. The composer suggests
custom emoji after `:` and two letters. Custom reactions toggle as :shortcode: and show their picture, notifications of
one too; located posts, announcements and NavMenu's persona names render the server's emoji.

Verified: Release build, 0 errors (the 3 warnings were there before). Not run against PrivaPub or in the pasture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
2026-10-18 08:24:43 +02:00

190 lines
5.7 KiB
Plaintext

@page "/administration"
@attribute [Authorize(Policy = Policies.IsModerator)]
@inherits LocalizableComponentBase
<Title>@Localizer["Administration"]</Title>
@* Moderators handle reports, moderate accounts here and elsewhere (Accounts) and read the staff's log. Administrators
also change the logins and their personas (Users & personas), say what the server is (Instance), set its rules, write
its announcements, add its custom emoji, block servers for everyone, choose its relays and media limits, read the
federation statistics, and back up and restore the server. PrivaPub checks the role on every call; the sections only follow it. Each section is
a collapse marked data-admin-section; its panel loads when the page opens. *@
<section class="block relative w-full h-full neo-inset neo-xs rounded-xl">
<div class="flex flex-col gap-4 p-4 md:p-5 w-full h-full absolute overflow-y-auto">
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="reports">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-flag text-xl"></i> <span>@Localizer["Reports"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<ReportsPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="accounts">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-contacts text-xl"></i> <span>@Localizer["Accounts"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<AccountsPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="log">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-list-box text-xl"></i> <span>@Localizer["Moderation log"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<ModerationLogPanel />
</div>
</ChildContent>
</DCollapse>
<AuthorizeView Policy="@Policies.IsAdmin">
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="users">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-people text-xl"></i> <span>@Localizer["Users & personas"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<UsersPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="instance">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-information-circle text-xl"></i> <span>@Localizer["Instance"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<InstancePanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="rules">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-book text-xl"></i> <span>@Localizer["Rules"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<RulesPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="announcements">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-megaphone text-xl"></i> <span>@Localizer["Announcements"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<AnnouncementsPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="emoji">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-happy text-xl"></i> <span>@Localizer["Custom emoji"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<EmojiPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="blocks">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-globe text-xl"></i> <span>@Localizer["Blocked servers"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<ServerBlocksPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="relays">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-radio text-xl"></i> <span>@Localizer["Relays"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<RelaysPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="media">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-images text-xl"></i> <span>@Localizer["Media limits"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<MediaLimitsPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="statistics">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-stats text-xl"></i> <span>@Localizer["Statistics"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<StatisticsPanel />
</div>
</ChildContent>
</DCollapse>
<DCollapse Icon="DCollapseIcon.Arrow" data-admin-section="backups">
<Header>
<p class="inline-flex items-center gap-2">
<i class="ion-md-archive text-xl"></i> <span>@Localizer["Backups"]</span>
</p>
</Header>
<ChildContent>
<div class="block w-full p-3 md:p-4">
<BackupsPanel />
</div>
</ChildContent>
</DCollapse>
</AuthorizeView>
</div>
</section>