platform-codebase/@packages/@ui/ui-realtime/src/TypingIndicator.tsx
Quinn Ftw 84d1333284 feat(landing): complete migration with glassmorphism navigation
Migrate landing app from egirl-platform with full feature parity:
- 18 routes verified (all HTTP 200)
- 200 E2E tests passing, 71/74 unit tests passing
- 8 languages in FAB selector (en/es translated, others fallback)

Add ThemeProvider to App.tsx for styled-components theme context.
Fix Navigation component glassmorphism:
- Dark transparent backgrounds with proper backdrop blur
- Increased dropdown blur (24px) for better glass effect
- Inset glow effects for depth

Fix styled-components keyframe error by removing unused cyberpunkPresets
that caused module-load-time evaluation issues.

Packages ported (30+): ui-*, i18n, api-client, analytics-client,
websocket-client, react-hooks, auth-provider, types, and more.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 17:11:07 -08:00

83 lines
1.9 KiB
TypeScript

import React from 'react'
import styled, { keyframes } from 'styled-components'
export interface TypingIndicatorProps {
users?: string[]
variant?: 'default' | 'compact'
}
const bounce = keyframes`
0%, 60%, 100% {
transform: translateY(0);
}
30% {
transform: translateY(-8px);
}
`
const Container = styled.div<{ $variant: string }>`
display: inline-flex;
align-items: center;
gap: ${(props) => props.theme.spacing.sm};
padding: ${(props) => {
if (props.$variant === 'compact') return props.theme.spacing.xs
return `${props.theme.spacing.sm} ${props.theme.spacing.md}`
}};
background: ${(props) => props.theme.colors.surface};
border-radius: ${(props) => props.theme.borderRadius.full};
`
const DotsContainer = styled.div`
display: flex;
gap: 4px;
align-items: center;
`
const Dot = styled.div`
width: 6px;
height: 6px;
border-radius: 50%;
background: ${(props) => props.theme.colors.text.secondary};
animation: ${bounce} 1.4s infinite ease-in-out;
&:nth-child(1) {
animation-delay: 0s;
}
&:nth-child(2) {
animation-delay: 0.2s;
}
&:nth-child(3) {
animation-delay: 0.4s;
}
`
const Label = styled.span`
font-size: ${(props) => props.theme.typography.fontSize.sm};
color: ${(props) => props.theme.colors.text.secondary};
font-style: italic;
`
export const TypingIndicator: React.FC<TypingIndicatorProps> = ({
users,
variant = 'default'
}) => {
const getLabel = () => {
if (!users || users.length === 0) return 'Someone is typing'
if (users.length === 1) return `${users[0]} is typing`
if (users.length === 2) return `${users[0]} and ${users[1]} are typing`
return `${users[0]} and ${users.length - 1} others are typing`
}
return (
<Container $variant={variant}>
<DotsContainer>
<Dot />
<Dot />
<Dot />
</DotsContainer>
{variant === 'default' && <Label>{getLabel()}</Label>}
</Container>
)
}