feat: add browser environment support with access token authentication

Enable the web client to run in plain browser environments alongside Telegram Mini App support:

- Server: Add CLI_API_TOKEN authentication path as alternative to Telegram initData
- Client: Add useAuthSource hook to detect and manage Telegram vs browser auth sources
- Client: Add usePlatform hook for platform abstraction with graceful haptic feedback degradation
- Client: Add LoginPrompt component for browser access token login
- Client: Extend useTheme to fall back to system prefers-color-scheme in browser
- Client: Migrate all direct HapticFeedback calls to use usePlatform hook
This commit is contained in:
weishu
2025-12-18 12:45:49 +08:00
parent 5fe1256e11
commit cf2b96b566
14 changed files with 552 additions and 96 deletions
@@ -14,7 +14,7 @@ import type { Suggestion } from '@/hooks/useActiveSuggestions'
import { useActiveWord } from '@/hooks/useActiveWord'
import { useActiveSuggestions } from '@/hooks/useActiveSuggestions'
import { applySuggestion } from '@/utils/applySuggestion'
import { getTelegramWebApp } from '@/hooks/useTelegram'
import { usePlatform } from '@/hooks/usePlatform'
import { FloatingOverlay } from '@/components/ChatInput/FloatingOverlay'
import { Autocomplete } from '@/components/ChatInput/Autocomplete'
import { StatusBar } from '@/components/AssistantChat/StatusBar'
@@ -95,6 +95,7 @@ export function HappyComposer(props: {
})
}, [composerText])
const { haptic: platformHaptic } = usePlatform()
const activeWord = useActiveWord(inputState.text, inputState.selection, autocompletePrefixes)
const [suggestions, selectedIndex, moveUp, moveDown, clearSuggestions] = useActiveSuggestions(
activeWord,
@@ -103,15 +104,14 @@ export function HappyComposer(props: {
)
const haptic = useCallback((type: 'light' | 'success' | 'error' = 'light') => {
const tg = getTelegramWebApp()
if (type === 'light') {
tg?.HapticFeedback?.impactOccurred('light')
platformHaptic.impact('light')
} else if (type === 'success') {
tg?.HapticFeedback?.notificationOccurred('success')
platformHaptic.notification('success')
} else {
tg?.HapticFeedback?.notificationOccurred('error')
platformHaptic.notification('error')
}
}, [])
}, [platformHaptic])
const handleSuggestionSelect = useCallback((index: number) => {
const suggestion = suggestions[index]