beatufitull front end for ozone modration ,, wit catpucoin and ebergarden !
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

allow self login and yumyyy ui and qol updates

+43 -20
+2 -1
.env.example
··· 2 2 PUBLIC_LABELER_URL="https://..." 3 3 PUBLIC_PDS_URL="https://..." 4 4 PUBLIC_AUTHENTICATION="oauth" # either "oauth" or "password" 5 - PUBLIC_ENABLE_ADS_DEFAULT=true 5 + PUBLIC_ENABLE_ADS_DEFAULT=true 6 + PUBLIC_ALLOW_SELF_LOGIN=true # if the labeler itself can login
+2 -2
src/components/ui/Checkbox.svelte
··· 48 48 <CheckIcon class="h-3 w-3" /> 49 49 </span> 50 50 {#if label} 51 - <span class="text-sm font-medium text-ctp-subtext0 group-hover:text-ctp-text">{label}</span> 51 + <span class="text-sm text-ctp-subtext0 group-hover:text-ctp-text">{label}</span> 52 52 {:else} 53 - <span class="text-sm font-medium text-ctp-subtext0 group-hover:text-ctp-text"><slot /></span> 53 + <span class="text-sm text-ctp-subtext0 group-hover:text-ctp-text"><slot /></span> 54 54 {/if} 55 55 </label>
+23 -5
src/components/view/Actions.svelte
··· 10 10 import type { DropdownOption } from '$lib/types'; 11 11 import type { RepoRef } from '@atproto/api/dist/client/types/com/atproto/admin/defs'; 12 12 import type { $Typed, ComAtprotoRepoStrongRef } from '@atproto/api'; 13 + import { SvelteSet } from 'svelte/reactivity'; 13 14 14 15 let { 15 16 initialSelectedLabelVals = [], 16 17 onRefresh, 17 - ref 18 + ref, 19 + isOpen = false 18 20 }: { 19 21 initialSelectedLabelVals?: string[]; 22 + isOpen?: boolean; 20 23 ref: $Typed<RepoRef> | $Typed<ComAtprotoRepoStrongRef.Main>; 21 24 onRefresh: () => Promise<void>; 22 25 } = $props(); ··· 31 34 32 35 type LabelAction = (typeof labelActionOptions)[number]['value']; 33 36 34 - let selectedLabelVals = $state(new Set<string>()); 37 + let selectedLabelVals = $derived(new Set<string>()); 35 38 let reason = $state(''); 36 39 let isSubmitting = $state(false); 37 40 let labelAction = $state<LabelAction>('labels'); 41 + let resolveOnSubmit = $state(isOpen); 38 42 39 43 $effect(() => { 40 44 selectedLabelVals = new Set(initialSelectedLabelVals); ··· 54 58 }); 55 59 56 60 function onToggleLabel(labelVal: string) { 57 - const next = new Set(selectedLabelVals); 61 + const next = new SvelteSet(selectedLabelVals); 58 62 if (next.has(labelVal)) { 59 63 next.delete(labelVal); 60 64 } else { ··· 148 152 try { 149 153 if (labelAction === 'labels') { 150 154 await submitLabels(reason, getLabelDiff()); 155 + 156 + if (resolveOnSubmit) { 157 + await acknowledge(reason); 158 + } 151 159 } else if (labelAction === 'acknowledge') { 152 160 await acknowledge(reason); 153 161 } ··· 171 179 /> 172 180 {#if labelAction == 'labels'} 173 181 <div class="flex flex-wrap gap-2 rounded-lg"> 174 - {#each labelerConfig.data?.labels as label} 182 + {#each labelerConfig.data?.labels as label (label.val)} 175 183 {@const isSelected = selectedLabelVals.has(label.val)} 176 184 <div 177 - class={`rounded-lg border border-ctp-surface1 bg-ctp-surface0 px-2.5 py-1.5 transition-colors hover:border-ctp-surface2`} 185 + class="rounded-lg border border-ctp-surface1 bg-ctp-surface0 px-2.5 py-1.5 transition-colors hover:border-ctp-surface2" 178 186 > 179 187 <Checkbox 180 188 checked={isSelected} ··· 191 199 value={reason} 192 200 on:input={(event) => onReasonChange((event.currentTarget as HTMLInputElement).value)} 193 201 /> 202 + {#if isOpen} 203 + <div> 204 + <Checkbox 205 + checked={resolveOnSubmit} 206 + on:change={() => (resolveOnSubmit = !resolveOnSubmit)} 207 + label="Acknowledge on submit" 208 + className="font-normal" 209 + /> 210 + </div> 211 + {/if} 194 212 <Button 195 213 variant="primary" 196 214 fullWidth={true}
+3 -1
src/components/view/Post.svelte
··· 1 1 <script lang="ts"> 2 2 import { createQuery } from '@tanstack/svelte-query'; 3 3 import { AppBskyFeedPost, AtUri } from '@atproto/api'; 4 - import { LoaderCircle, MessageCircle, MessageCircleMore } from 'lucide-svelte'; 4 + import { LoaderCircle, MessageCircleMore } from 'lucide-svelte'; 5 5 import Modal from '../Modal.svelte'; 6 6 import Tabs from '../ui/Tabs.svelte'; 7 7 import { session } from '$lib/stores/auth'; ··· 132 132 </div> 133 133 134 134 <Actions 135 + isOpen={postQuery.data.moderation.subjectStatus?.reviewState != 136 + 'tools.ozone.moderation.defs#reviewClosed'} 135 137 initialSelectedLabelVals={postQuery.data.labels?.map((label) => label.val) ?? []} 136 138 ref={{ 137 139 $type: 'com.atproto.repo.strongRef',
+5
src/lib/api/ozone.ts
··· 40 40 export function getAdsDefault() { 41 41 const adsDefault = env.PUBLIC_ENABLE_ADS_DEFAULT as string | boolean | undefined 42 42 return adsDefault === 'true' || adsDefault === true 43 + } 44 + 45 + export function getAllowSelfLogin() { 46 + const allowSelfLogin = env.PUBLIC_ALLOW_SELF_LOGIN as string | boolean | undefined 47 + return allowSelfLogin === 'true' || allowSelfLogin === true 43 48 }
-8
src/routes/+page.svelte
··· 54 54 function openPost(uri: string) { 55 55 navigateView('post', uri); 56 56 } 57 - function getCollectionName(report: Report) { 58 - try { 59 - return report.subject.handle ? 'Post' : 'unknown'; 60 - } catch (e) { 61 - console.error('Invalid report:', report); 62 - return 'unknown'; 63 - } 64 - } 65 57 66 58 type State = 67 59 | 'tools.ozone.moderation.defs#reviewOpen'
+8 -3
src/routes/login/+page.svelte
··· 1 1 <script lang="ts"> 2 2 import { error, isLoading } from '$lib/stores/auth'; 3 3 import { authorize } from '$lib/oauth.client'; 4 - import { getAuthenticationMethod, getLabelerDid, getPdsUrl } from '$lib/api/ozone'; 4 + import { 5 + getAllowSelfLogin, 6 + getAuthenticationMethod, 7 + getLabelerDid, 8 + getPdsUrl 9 + } from '$lib/api/ozone'; 5 10 import { Agent, AtpAgent } from '@atproto/api'; 6 11 import Button from '../../components/ui/Button.svelte'; 7 12 import Input from '../../components/ui/Input.svelte'; ··· 41 46 ? handleInput.trim() 42 47 : (await agent.com.atproto.identity.resolveHandle({ handle: handleInput.trim() })).data.did; 43 48 44 - if (did == getLabelerDid()) { 49 + if (did == getLabelerDid() && !getAllowSelfLogin()) { 45 50 error.set('Labeler account cannot be used to log in'); 46 51 isLoading.set(false); 47 52 return; ··· 194 199 {:else if suggestions.length === 0} 195 200 <p class="px-3 py-2 text-sm text-ctp-subtext1">no suggestions found</p> 196 201 {:else} 197 - {#each suggestions as suggestion} 202 + {#each suggestions as suggestion (suggestion.did)} 198 203 <button 199 204 type="button" 200 205 class="block w-full cursor-pointer px-3 py-2 text-left text-sm text-ctp-text hover:bg-ctp-surface0"