({
session,
error,
})
| 252 | } |
| 253 | |
| 254 | export const WaitingRoomScreen: React.FC<WaitingRoomScreenProps> = ({ |
| 255 | session, |
| 256 | error, |
| 257 | }) => { |
| 258 | const theme = useTheme() |
| 259 | const renderer = useRenderer() |
| 260 | const { terminalWidth, terminalHeight, contentMaxWidth } = |
| 261 | useTerminalDimensions() |
| 262 | |
| 263 | // Progressive disclosure as the terminal gets shorter. The picker is the |
| 264 | // only thing the user must be able to reach, so chrome is shed first: |
| 265 | // tall (>=26): full ASCII logo + roomy spacing, content anchored low |
| 266 | // medium (>=18): one-line text logo, tightened spacing, content up top |
| 267 | // short (<18) : no logo at all |
| 268 | // tiny (<15) : also drop the ad banner |
| 269 | // Section headers always show — the picker scrolls within whatever rows |
| 270 | // remain (see selectorMaxHeight below), so there's no need to hide them. |
| 271 | const logoMode: 'full' | 'text' | 'none' = |
| 272 | terminalHeight >= 26 ? 'full' : terminalHeight >= 19 ? 'text' : 'none' |
| 273 | const compact = terminalHeight < 22 |
| 274 | const showAds = terminalHeight >= 16 |
| 275 | const textMarginBottom = compact ? 0 : 1 |
| 276 | const logoLines = logoMode === 'full' ? 6 : logoMode === 'text' ? 1 : 0 |
| 277 | |
| 278 | const [sheenPosition, setSheenPosition] = useState(0) |
| 279 | const blockColor = getLogoBlockColor(theme.name) |
| 280 | const accentColor = getLogoAccentColor(theme.name) |
| 281 | const { applySheenToChar } = useSheenAnimation({ |
| 282 | logoColor: theme.foreground, |
| 283 | accentColor, |
| 284 | blockColor, |
| 285 | terminalWidth: renderer?.width ?? terminalWidth, |
| 286 | sheenPosition, |
| 287 | setSheenPosition, |
| 288 | }) |
| 289 | const { component: logoComponent } = useLogo({ |
| 290 | availableWidth: contentMaxWidth, |
| 291 | accentColor, |
| 292 | blockColor, |
| 293 | applySheenToChar, |
| 294 | // 'text' forces the one-line variant; 'none' is handled by not rendering. |
| 295 | maxHeight: logoMode === 'full' ? undefined : 1, |
| 296 | }) |
| 297 | |
| 298 | // Always enable ads in the waiting room — this is where monetization lives. |
| 299 | // forceStart bypasses the "wait for first user message" gate inside the hook, |
| 300 | // which would otherwise block ads here since no conversation exists yet. |
| 301 | // The server tries Gravity first, then falls back to ZeroClick and Carbon. |
| 302 | const { ads, recordClick, recordImpression } = useGravityAd({ |
| 303 | enabled: true, |
| 304 | forceStart: true, |
| 305 | provider: 'gravity', |
| 306 | surface: 'waiting_room', |
| 307 | }) |
| 308 | |
| 309 | useFreebuffCtrlCExit() |
| 310 | |
| 311 | const [exitHover, setExitHover] = useState(false) |
nothing calls this directly
no test coverage detected