From 99ff14d420dcf52421a2dbe2fec496402051fd9c Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Wed, 17 Dec 2025 01:08:39 -0500 Subject: [PATCH 1/3] style(ui): improve button variants for better UX --- ui/src/components/cliproxy/provider-editor.tsx | 6 +++--- ui/src/pages/cliproxy.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/components/cliproxy/provider-editor.tsx b/ui/src/components/cliproxy/provider-editor.tsx index 3d8379bd..8d76b44d 100644 --- a/ui/src/components/cliproxy/provider-editor.tsx +++ b/ui/src/components/cliproxy/provider-editor.tsx @@ -343,9 +343,9 @@ export function ProviderEditor({ ))} + + +

+ {privacyMode + ? 'Privacy mode ON - Click to show data' + : 'Privacy mode OFF - Click to hide data'} +

+
+ + ); +} diff --git a/ui/src/components/quick-setup-wizard.tsx b/ui/src/components/quick-setup-wizard.tsx index dfc3d6b4..1fc36d70 100644 --- a/ui/src/components/quick-setup-wizard.tsx +++ b/ui/src/components/quick-setup-wizard.tsx @@ -39,6 +39,8 @@ import { import { useCliproxyAuth, useCreateVariant, useStartAuth } from '@/hooks/use-cliproxy'; import type { AuthStatus, OAuthAccount } from '@/lib/api-client'; import { MODEL_CATALOGS } from '@/lib/model-catalogs'; +import { cn } from '@/lib/utils'; +import { usePrivacy, PRIVACY_BLUR_CLASS } from '@/contexts/privacy-context'; interface QuickSetupWizardProps { open: boolean; @@ -68,6 +70,7 @@ export function QuickSetupWizard({ open, onClose }: QuickSetupWizardProps) { const { data: authData, refetch } = useCliproxyAuth(); const createMutation = useCreateVariant(); const startAuthMutation = useStartAuth(); + const { privacyMode } = usePrivacy(); // Get auth status for selected provider const providerAuth = authData?.authStatus.find( @@ -347,7 +350,9 @@ export function QuickSetupWizard({ open, onClose }: QuickSetupWizardProps) {
-
{acc.email || acc.id}
+
+ {acc.email || acc.id} +
{acc.isDefault && (
Default account
)} @@ -403,7 +408,12 @@ export function QuickSetupWizard({ open, onClose }: QuickSetupWizardProps) { {selectedAccount && (
- Using: {selectedAccount.email || selectedAccount.id} + + Using:{' '} + + {selectedAccount.email || selectedAccount.id} + +
)} diff --git a/ui/src/contexts/privacy-context.tsx b/ui/src/contexts/privacy-context.tsx new file mode 100644 index 00000000..98cc98fb --- /dev/null +++ b/ui/src/contexts/privacy-context.tsx @@ -0,0 +1,54 @@ +/** + * Privacy Context - Global demo mode for censoring personal information + * Provides blur effect on emails, account IDs, and other PII + * Persists state to localStorage + */ + +/* eslint-disable react-refresh/only-export-components */ +import { createContext, useContext, useState, useEffect, type ReactNode } from 'react'; + +interface PrivacyContextValue { + /** Whether privacy/demo mode is enabled */ + privacyMode: boolean; + /** Toggle privacy mode on/off */ + togglePrivacyMode: () => void; +} + +const PrivacyContext = createContext(null); + +const STORAGE_KEY = 'ccs-privacy-mode'; + +export function PrivacyProvider({ children }: { children: ReactNode }) { + const [privacyMode, setPrivacyMode] = useState(() => { + // Initialize from localStorage + if (typeof window !== 'undefined') { + return localStorage.getItem(STORAGE_KEY) === 'true'; + } + return false; + }); + + // Persist to localStorage when changed + useEffect(() => { + localStorage.setItem(STORAGE_KEY, String(privacyMode)); + }, [privacyMode]); + + const togglePrivacyMode = () => setPrivacyMode((prev) => !prev); + + return ( + + {children} + + ); +} + +export function usePrivacy() { + const context = useContext(PrivacyContext); + if (!context) { + throw new Error('usePrivacy must be used within a PrivacyProvider'); + } + return context; +} + +/** CSS class for blurring sensitive content */ +export const PRIVACY_BLUR_CLASS = + 'blur-[4px] select-none hover:blur-none transition-all duration-200';