From d10386074323f4eb75530a82f5af39cbe37a393c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=CC=82=CC=80ng=20Cu=CC=81c=20Le=CC=82=20Thi=CC=A3?= Date: Tue, 26 May 2026 14:19:11 +0700 Subject: [PATCH 1/2] enhace mobile view --- .DS_Store | Bin 10244 -> 8196 bytes collab-guard/README.md | 26 +- collab-guard/devvit.json | 14 +- collab-guard/package.json | 2 +- .../src/client/components/AutoModBuilder.tsx | 632 ++++++++----- .../src/client/components/Sidebar.tsx | 161 +++- .../src/client/components/SidebarLayout.tsx | 63 +- .../src/client/components/ThemeToggle.tsx | 43 +- collab-guard/src/client/components/TopBar.tsx | 376 +++++--- .../ai-activity/AiModToolActivityPage.tsx | 19 +- .../components/collab-queue-dashboard.tsx | 871 ++++++++++-------- .../consensus-review/ConsensusReviewPanel.tsx | 22 +- .../src/client/components/dashboard-queue.ts | 10 + .../components/queue/QueueFilterBar.tsx | 40 +- .../settings/AiModToolOnboardingBanner.tsx | 2 +- .../components/settings/SettingsPage.tsx | 72 +- .../settings/SettingsSectionNav.tsx | 77 +- .../sections/AiModToolActivityFeed.tsx | 25 +- .../settings/sections/AiModToolSettings.tsx | 140 ++- .../sections/CoreSettingsSections.tsx | 102 +- .../settings/sections/GentleNudgeSettings.tsx | 23 +- .../components/shared/CaseActionBar.tsx | 4 +- .../src/client/components/shared/index.ts | 17 + .../client/components/shared/page-layout.tsx | 81 ++ .../src/client/entries/game/index.html | 4 +- .../src/client/entries/splash/index.html | 4 +- .../src/client/entries/splash/index.tsx | 30 +- collab-guard/src/client/hooks/index.ts | 1 + .../src/client/hooks/use-media-query.ts | 25 + collab-guard/src/client/index.css | 14 + collab-guard/src/server/agent/ai-config.ts | 21 +- .../src/server/agent/call-structured.ts | 3 +- .../src/server/core/ai-content-score.ts | 2 +- collab-guard/src/server/core/ai-keys.test.ts | 38 + collab-guard/src/server/core/ai-keys.ts | 63 ++ collab-guard/src/server/core/ai-mod-check.ts | 2 +- collab-guard/src/server/core/ai-tldr.ts | 2 +- collab-guard/src/server/core/menu.ts | 44 + collab-guard/src/server/routes/api.ts | 2 +- collab-guard/src/server/routes/forms.ts | 52 ++ collab-guard/src/server/routes/menu.ts | 68 ++ collab-guard/src/shared/app-meta.ts | 2 +- 42 files changed, 2118 insertions(+), 1081 deletions(-) create mode 100644 collab-guard/src/client/components/shared/page-layout.tsx create mode 100644 collab-guard/src/client/hooks/use-media-query.ts create mode 100644 collab-guard/src/server/core/ai-keys.test.ts create mode 100644 collab-guard/src/server/core/ai-keys.ts diff --git a/.DS_Store b/.DS_Store index a484cc31dafa51338ec33a3be5ca44ff775e208d..edc31540571da7e1d85f394a72c901a1e3bb7a60 100644 GIT binary patch delta 120 zcmZn(XmOBWU|?W$DortDU;r^WfEYvza8E20o2aMAsI)O)H$S7&W*&iHrpZ4=Bq!ez zxxSfG>;mKDdI_VAW!snpnSsiIK!O`cxPo+UEd0(qnO`N4gArmL!{m6Lsgt*hD?zku GW&!{RsvDL7 literal 10244 zcmeHM&1(}u6n|S&O>I%pi(lAK5k#$?->a{2hv;Mu%NWsgsk|(%vltmVqb(ymwzg ztu#PI8kGBYFNYp3rh~Xzf2f8}5pB2F)|2-}$5bD^NJlkBy-X(ODu2nD+3WRN-oEaL z(<&@LYiwAIw(Jw!VEt$X_7Y9%bB6%;bM#5vfu4c5dF@^4Lt_2@=;@Km?-ka-cGRn) zjO#b>?dykY#je6f!!$)X6Q$Dv4T+NHLTDRU>Da5NKZ*Es+tbSrW&?JGABnrRmVurs z7>rg1cuK%kCXdExFciZb=*bxBVRIHUGESbUS;vcZ4NWuBmaotheq@x}?u{Jq=f%*d z&dleQxrc}56c0kfjIJL8&~hN1L`)vJ^XFFc`BOKJeu>r4m1uX&e0&-9CGlQ*9N;y4 z$T_K{BQfvVdy6r1hMcDf$^&&FJQu23?}w^YXiMDiwJhpSBEK5Er$5uN|k&hkU<`-{4?7i_qk4E^(0S3=Pp1m@F97*yQk}ozY>Z5Di3k} zGH%kVPXi*ER*{vF7o})ss4A66V=N@*rcLelfH_7>qJMYoTH_VH^2cgc(^Oj)bCNs(jn@kR z=Q^0)MFN$nn&{ekeDNM-T3@_qX*}%m31OmF1E+qZU3c8QUxamI2FvWnhUJ z;J1IY6rcZh;{CkF|NlzK-Yf%_f&Y^MCz0vNVB>+q_V|X^alBR&_2c5kdKE2|32v;y z&l4>1g^%O6^JhHU&5|2Fr+rz`5>L?n_@4oha|8L}ZTJ7`oKEhlgFU?D$?pFt`S0%k Fe*& = { civility_reminder: 'Civility reminder', }; +const TEMPLATE_HELP: Record = { + new_account_filter: 'Filter or report posts from accounts below a minimum age.', + low_karma_filter: 'Filter or report posts from low combined-karma accounts.', + high_report_alert: 'Alert moderators when content reaches a report threshold.', + required_flair: 'Require post flair or leave a reminder when flair is missing.', + banned_domain_filter: 'Filter or report links to disallowed domains.', + civility_reminder: 'Leave a constructive reminder when watch phrases appear.', +}; + +const SIMULATOR_TEMPLATES = new Set([ + 'required_flair', + 'banned_domain_filter', + 'civility_reminder', +]); + const DEFAULT_CONFIG: Record = { new_account_filter: { itemType: 'any', @@ -54,16 +70,6 @@ const DEFAULT_CONFIG: Record = { }, }; -const TEMPLATE_HELP: Record = { - new_account_filter: 'Drafts a conservative age-based participation filter.', - low_karma_filter: 'Drafts a conservative karma-based participation filter.', - high_report_alert: 'Alerts moderators when content receives enough reports.', - required_flair: 'Requires post flair or leaves a reminder for missing flair.', - banned_domain_filter: 'Filters or reports links to domains the subreddit disallows.', - civility_reminder: - 'Leaves a non-punitive reminder when configured phrases appear.', -}; - const setConfigValue = ( config: AutoModRuleFormConfig, key: string, @@ -73,32 +79,54 @@ const setConfigValue = ( [key]: value, }); -const SimulatorResult = ({ - result, -}: { - result: AutoModSimulationResult; -}) => ( -
-

- {result.status === 'match' - ? 'Match' - : result.status === 'unsupported' - ? 'Simulator not available' - : 'No match'} -

-

{result.explanation}

- {result.condition &&

Condition: {result.condition}

} -
+type FieldProps = { + label: string; + hint?: string; + children: ReactNode; +}; + +const Field = ({ label, hint, children }: FieldProps) => ( + ); +const selectClass = + 'cg-control w-full border border-input bg-background px-3 py-2 text-sm text-foreground outline-none focus:border-ring'; + +const textAreaClass = + 'cg-control w-full border border-input bg-background px-3 py-2 text-sm text-foreground outline-none focus:border-ring'; + +const SimulatorResult = ({ result }: { result: AutoModSimulationResult }) => { + const tone = + result.status === 'match' + ? 'border-amber-300/50 bg-amber-500/10 text-amber-950 dark:text-amber-100' + : result.status === 'unsupported' + ? 'border-border bg-muted/40 text-muted-foreground' + : 'border-emerald-300/50 bg-emerald-500/10 text-emerald-950 dark:text-emerald-100'; + + const title = + result.status === 'match' + ? 'Match' + : result.status === 'unsupported' + ? 'Simulator not available' + : 'No match'; + + return ( +
+

{title}

+

{result.explanation}

+ {result.condition ? ( +

Condition: {result.condition}

+ ) : null} +
+ ); +}; + export const AutoModBuilder = () => { const [template, setTemplate] = useState('required_flair'); @@ -108,6 +136,7 @@ export const AutoModBuilder = () => { const [sampleText, setSampleText] = useState(''); const [simulationResult, setSimulationResult] = useState(null); + const [copyState, setCopyState] = useState<'idle' | 'copied' | 'error'>('idle'); const generatedYaml = useMemo(() => { try { @@ -117,10 +146,13 @@ export const AutoModBuilder = () => { } }, [formConfig, template]); + const yamlError = generatedYaml.startsWith('Unsupported') || generatedYaml.includes('Unable'); + const updateTemplate = (nextTemplate: AutoModRuleTemplate) => { setTemplate(nextTemplate); setFormConfig(DEFAULT_CONFIG[nextTemplate]); setSimulationResult(null); + setCopyState('idle'); }; const updateField = (key: string, value: string | number) => { @@ -128,220 +160,356 @@ export const AutoModBuilder = () => { setSimulationResult(null); }; - const commonTargetField = ( - + ); - return ( -
-
-

AutoMod Builder

-

- Draft safe AutoModerator YAML. CollabGuard does not apply rules - automatically; copy and review before deploying. -

-
+ const actionField = (options: Array<{ value: string; label: string }>) => ( + + + + ); -
-
- -

- {TEMPLATE_HELP[template]} -

- - {template !== 'required_flair' && commonTargetField} - - {template === 'required_flair' && ( - <> - -