79 lines
4.9 KiB
Svelte
79 lines
4.9 KiB
Svelte
<script lang="ts">
|
|
import PendingForm from '$lib/components/PendingForm.svelte';
|
|
|
|
let {
|
|
contentType,
|
|
contentId,
|
|
label = 'REPORT',
|
|
result,
|
|
plain = false,
|
|
menuItem = false,
|
|
itemId = ''
|
|
}: {
|
|
contentType: 'comment' | 'profile_bio' | 'guide' | 'avatar';
|
|
contentId: string;
|
|
label?: string;
|
|
result?: Record<string, unknown> | null;
|
|
plain?: boolean;
|
|
menuItem?: boolean;
|
|
itemId?: string;
|
|
} = $props();
|
|
|
|
const categories = [
|
|
{ value: 'spam', label: 'SPAM OR PROMOTION' },
|
|
{ value: 'harassment', label: 'HARASSMENT OR BULLYING' },
|
|
{ value: 'hate', label: 'HATEFUL CONTENT' },
|
|
{ value: 'sexual', label: 'SEXUAL CONTENT' },
|
|
{ value: 'violence', label: 'VIOLENCE OR THREATS' },
|
|
{ value: 'self_harm', label: 'SELF-HARM' },
|
|
{ value: 'privacy', label: 'PRIVATE INFORMATION' },
|
|
{ value: 'other', label: 'OTHER POLICY CONCERN' }
|
|
];
|
|
const matchesResult = $derived(
|
|
String(result?.userReportContentId ?? '') === contentId
|
|
&& String(result?.userReportContentType ?? '') === contentType
|
|
);
|
|
let reportOpen = $state(false);
|
|
|
|
function closeReport() {
|
|
reportOpen = false;
|
|
}
|
|
</script>
|
|
|
|
<details bind:open={reportOpen} class="content-report" class:plain class:menu-item={menuItem}>
|
|
<summary role={menuItem ? 'button' : undefined}>{label}</summary>
|
|
{#if reportOpen}
|
|
<div class="content-report-panel">
|
|
<strong>REQUEST OVERSIGHT REVIEW</strong>
|
|
<p>Send this content to Community Oversight. A report does not remove it automatically.</p>
|
|
<PendingForm action="?/reportContent" toast={false}>
|
|
{#snippet children(pending)}
|
|
<input type="hidden" name="contentType" value={contentType}/>
|
|
<input type="hidden" name="contentId" value={contentId}/>
|
|
{#if itemId}<input type="hidden" name="itemId" value={itemId}/>{/if}
|
|
<label class="field">CONCERN
|
|
<select name="category" required>
|
|
{#each categories as category}<option value={category.value}>{category.label}</option>{/each}
|
|
</select>
|
|
</label>
|
|
<label class="field">DETAILS — OPTIONAL
|
|
<textarea name="details" maxlength="500" rows="3" placeholder="Give Oversight useful context without repeating sensitive information."></textarea>
|
|
</label>
|
|
{#if matchesResult && result?.userReportError}<p class="error">{String(result.userReportError)}</p>{/if}
|
|
{#if matchesResult && result?.userReportSaved}<p class="success">Report sent to Community Oversight.</p>{/if}
|
|
<div class="content-report-actions">
|
|
<button type="button" class="secondary" onclick={closeReport}>CANCEL</button>
|
|
<button class="primary" disabled={pending} aria-busy={pending}>{pending ? 'SENDING…' : 'SEND REPORT →'}</button>
|
|
</div>
|
|
{/snippet}
|
|
</PendingForm>
|
|
</div>
|
|
{/if}
|
|
</details>
|
|
|
|
<style>
|
|
.content-report{position:relative}.content-report summary{list-style:none;min-height:32px;display:inline-flex;align-items:center;padding:0 7px;border:1px solid var(--shd-border);color:var(--shd-text-muted);font-size:var(--shd-type-telemetry);font-weight:900;letter-spacing:.7px;cursor:pointer}.content-report summary::-webkit-details-marker{display:none}.content-report summary:hover,.content-report summary:focus-visible{border-color:var(--shd-danger);color:var(--shd-danger)}.content-report[open] summary{border-color:var(--shd-orange);color:var(--shd-orange)}.content-report.plain summary{min-height:32px;padding:0;border:0;background:transparent}.content-report.plain summary:hover,.content-report.plain summary:focus-visible{color:var(--shd-danger);text-decoration:underline;text-underline-offset:3px}.content-report.plain[open] summary{color:var(--shd-orange)}.content-report.menu-item summary{border:0}.content-report.menu-item summary:hover,.content-report.menu-item summary:focus-visible{color:var(--shd-orange);text-decoration:none}.content-report-panel{position:absolute;z-index:8;top:calc(100% + 6px);right:0;width:min(380px,calc(100vw - 32px));display:grid;gap:8px;padding:10px;border:1px solid var(--shd-border-strong);background:var(--shd-surface);box-shadow:0 18px 46px #000a}.content-report.plain:not(.menu-item) .content-report-panel{right:auto;left:0}.content-report-panel>strong{color:var(--shd-orange);font-size:var(--shd-type-telemetry);letter-spacing:.8px}.content-report-panel>p{margin:0;color:var(--shd-text-muted);font-size:var(--shd-type-supporting)}.content-report-panel :global(form fieldset){display:grid;gap:8px}.content-report-panel :global(.field){margin:0}.content-report-panel textarea{min-height:80px}.content-report-actions{display:flex;justify-content:flex-end;gap:7px}.content-report-actions button{min-height:40px}
|
|
@media(max-width:650px){.content-report-panel{position:fixed;top:auto;right:16px;bottom:16px;left:16px;width:auto}.content-report summary{min-height:44px}.content-report-actions{display:grid;grid-template-columns:1fr 1fr}.content-report-actions button{width:100%;min-height:44px}}
|
|
@media(prefers-reduced-motion:reduce){.content-report summary{transition:none}}
|
|
</style>
|