feat: add automated community moderation
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import AgentIdentityLink from '$lib/components/AgentIdentityLink.svelte';
|
||||
import ContentReport from '$lib/components/ContentReport.svelte';
|
||||
import MarkdownContent from '$lib/components/MarkdownContent.svelte';
|
||||
import MarkdownEditor from '$lib/components/MarkdownEditor.svelte';
|
||||
import ModerationDisclosure from '$lib/components/ModerationDisclosure.svelte';
|
||||
import PageBreadcrumb from '$lib/components/PageBreadcrumb.svelte';
|
||||
import PendingForm from '$lib/components/PendingForm.svelte';
|
||||
|
||||
@@ -32,6 +34,7 @@
|
||||
createdAt: string;
|
||||
author: { id: string; displayName: string; avatarUrl: string };
|
||||
canDelete: boolean;
|
||||
canReport: boolean;
|
||||
};
|
||||
type PageData = {
|
||||
agent: PublicAgent;
|
||||
@@ -40,7 +43,7 @@
|
||||
guides: PublicContent[];
|
||||
authoredComments: AuthoredComment[];
|
||||
profileComments: ProfileComment[];
|
||||
viewer: { id: string | null; canComment: boolean; isSelf: boolean };
|
||||
viewer: { id: string | null; canComment: boolean; canReportProfile: boolean; isSelf: boolean };
|
||||
};
|
||||
|
||||
let { data, form }: { data: PageData; form?: Record<string, any> | null } = $props();
|
||||
@@ -75,6 +78,7 @@
|
||||
<header class="agent-command">
|
||||
<AgentIdentityLink agent={data.agent} size="large" meta="SHD.BUILD AGENT PROFILE" />
|
||||
<div class="agent-command-actions">
|
||||
{#if data.viewer.canReportProfile}<ContentReport contentType="avatar" contentId={data.agent.id} label="REPORT AVATAR" result={form}/>{/if}
|
||||
{#if data.viewer.isSelf}<a class="secondary" href="/account">EDIT MY PROFILE →</a>{/if}
|
||||
</div>
|
||||
</header>
|
||||
@@ -89,7 +93,7 @@
|
||||
<div class="agent-profile-grid">
|
||||
<div class="agent-primary">
|
||||
<section class="profile-section agent-bio">
|
||||
<header><div><p class="eyebrow">FIELD DOSSIER</p><h1>ABOUT {data.agent.displayName.toUpperCase()}</h1></div><span>PUBLIC BIO</span></header>
|
||||
<header><div><p class="eyebrow">FIELD DOSSIER</p><h1>ABOUT {data.agent.displayName.toUpperCase()}</h1></div><div class="profile-header-actions"><span>PUBLIC BIO</span>{#if data.viewer.canReportProfile && data.agent.bioHtml}<ContentReport contentType="profile_bio" contentId={data.agent.id} label="REPORT BIO" result={form}/>{/if}</div></header>
|
||||
<div class="bio-content">
|
||||
<MarkdownContent html={data.agent.bioHtml} emptyMessage="This Agent has not published a field bio yet." />
|
||||
</div>
|
||||
@@ -167,8 +171,11 @@
|
||||
required
|
||||
bind:value={profileCommentDraft}
|
||||
/>
|
||||
<ModerationDisclosure/>
|
||||
{#if form?.profileCommentError || form?.commentError}<p class="error">{form?.profileCommentError ?? form?.commentError}</p>{/if}
|
||||
{#if form?.profileCommentSaved || form?.commentSaved}<p class="success">Profile message transmitted.</p>{/if}
|
||||
{#if form?.profileCommentSaved || form?.commentSaved}
|
||||
<p class="success">{form?.profileCommentReviewQueued ? 'Profile message received and held for Oversight review.' : 'Profile message transmitted.'}</p>
|
||||
{/if}
|
||||
<button class="primary" disabled={!profileCommentDraft.trim()}>POST MESSAGE →</button>
|
||||
</PendingForm>
|
||||
{:else if !data.viewer.id}
|
||||
@@ -185,6 +192,7 @@
|
||||
{#if comment.canDelete}
|
||||
<button type="button" class="comment-remove" aria-expanded={deletingCommentId === comment.id} onclick={() => deletingCommentId = comment.id}>REMOVE</button>
|
||||
{/if}
|
||||
{#if comment.canReport}<ContentReport contentType="comment" contentId={comment.id} result={form}/>{/if}
|
||||
</header>
|
||||
<MarkdownContent html={comment.bodyHtml} compact />
|
||||
{#if deletingCommentId === comment.id}
|
||||
@@ -223,6 +231,7 @@
|
||||
.public-empty{grid-column:1/-1;min-height:150px;display:grid;place-content:center;gap:6px;padding:20px;text-align:center}.public-empty span{color:var(--shd-orange);font-size:28px}.public-empty strong{font-size:var(--shd-type-telemetry);letter-spacing:1px}.public-empty p{margin:0;color:var(--shd-text-muted);font-family:var(--shd-font-editorial);font-size:var(--shd-type-supporting)}.public-empty.compact{min-height:110px}
|
||||
.authored-comment-list{display:grid;gap:7px;padding:7px}.authored-comment-list>article{display:grid;gap:9px;padding:10px;border:1px solid var(--shd-border);background:#0d1011}.authored-comment-list article>header{display:flex;justify-content:space-between;gap:10px}.authored-comment-list article>header>div{display:grid;gap:3px}.authored-comment-list article header span,.authored-comment-list article header small,.authored-comment-list article>a{font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px}.authored-comment-list article header span,.authored-comment-list article>a{color:var(--shd-orange)}.authored-comment-list article header small{color:var(--shd-text-muted)}.authored-comment-list article>a{justify-self:end}
|
||||
.profile-comms{align-self:start;position:sticky;top:88px}:global(form.profile-comment-form){display:grid;gap:8px;padding:8px;border-bottom:1px solid var(--shd-border)}:global(form.profile-comment-form > button){min-height:40px}.profile-comment-list{display:grid}.profile-comment-list>article{display:grid;gap:9px;padding:10px;border-bottom:1px solid var(--shd-border)}.profile-comment-list>article:last-child{border-bottom:0}.profile-comment-list article>header{display:flex;align-items:center;justify-content:space-between;gap:8px}.profile-comment-list article>header :global(.agent-identity){flex:1}.comment-remove{min-height:32px;padding:0 7px;border:1px solid var(--shd-danger);background:transparent;color:var(--shd-danger);font-size:var(--shd-type-telemetry);font-weight:900;cursor:pointer}.comment-remove:hover,.comment-remove:focus-visible{background:var(--shd-danger);color:var(--shd-bg)}.comment-delete-confirm{display:grid;gap:8px;padding:8px;border:1px solid var(--shd-danger);background:#1b1111}.comment-delete-confirm p{margin:0;color:var(--shd-text-muted);font-size:var(--shd-type-supporting)}.comment-delete-confirm>div{display:flex;justify-content:flex-end;gap:7px}.comment-delete-confirm button{min-height:38px;padding:0 10px}.comment-access-note{display:grid;gap:7px;padding:12px;border-bottom:1px solid var(--shd-border)}.comment-access-note strong{color:var(--shd-orange);font-size:var(--shd-type-telemetry);letter-spacing:.8px}.comment-access-note p{margin:0;color:var(--shd-text-muted);font-size:var(--shd-type-supporting)}.comment-access-note a{justify-self:start}
|
||||
.profile-header-actions{display:flex;align-items:center;gap:7px}.profile-header-actions>span{color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px}
|
||||
@media(max-width:1000px){.agent-profile-grid{grid-template-columns:1fr}.profile-comms{position:static}.agent-telemetry{grid-template-columns:repeat(2,minmax(0,1fr))}.agent-telemetry>div:nth-child(3){border-left:0}.agent-telemetry>div:nth-child(n+3){border-top:1px solid var(--shd-border)}}
|
||||
@media(max-width:650px){.agent-command{align-items:stretch;flex-direction:column}.agent-command-actions a{width:100%;min-height:44px;justify-content:center}.agent-telemetry{grid-template-columns:1fr}.agent-telemetry>div{border-top:1px solid var(--shd-border);border-left:0}.agent-telemetry>div:first-child{border-top:0}.public-content-grid{grid-template-columns:1fr}.profile-section>header{align-items:flex-start;flex-direction:column}:global(form.profile-comment-form > button),.comment-delete-confirm button{min-height:44px}.comment-delete-confirm>div{display:grid;grid-template-columns:1fr 1fr}}
|
||||
@media(prefers-reduced-motion:reduce){.public-content-card,.comment-remove{transition:none}}
|
||||
|
||||
Reference in New Issue
Block a user