/** Compose the default text for a challenge post. */ export function composeChallengePost( opponentHandle: string, gameUrl: string, ): string { return `I'm challenging @${opponentHandle} to a game of chess on checkmate.blue!\n\n${gameUrl}`; } /** Compose the default text for a game result post. */ export function composeGameResultPost( myColor: 'white' | 'black', result: { result: '1-0' | '0-1' | '1/2-1/2'; reason: string }, opponentHandle: string, moveCount: number, gameUrl: string, ): string { const opponent = `@${opponentHandle}`; const moveSuffix = moveCount > 10 ? ` in ${moveCount} moves` : ''; const iWin = (result.result === '1-0' && myColor === 'white') || (result.result === '0-1' && myColor === 'black'); const isDraw = result.result === '1/2-1/2'; let text: string; if (iWin && result.reason === 'checkmate') { text = `Checkmate! I won against ${opponent} on checkmate.blue${moveSuffix}`; } else if (iWin && result.reason === 'resignation') { text = `Victory! ${opponent} resigned our game on checkmate.blue${moveSuffix}`; } else if (iWin) { text = `I won against ${opponent} on checkmate.blue${moveSuffix}`; } else if (isDraw) { const drawReasons: Record = { stalemate: 'Stalemate', agreement: 'Draw by agreement', repetition: 'Draw by repetition', fifty_moves: 'Draw by 50-move rule', insufficient: 'Draw by insufficient material', }; const label = drawReasons[result.reason] ?? 'Draw'; text = `${label} with ${opponent} on checkmate.blue${moveSuffix}`; } else { if (result.reason === 'checkmate') { text = `Got checkmated by ${opponent} on checkmate.blue -- good game!${moveSuffix}`; } else { text = `Good game against ${opponent} on checkmate.blue${moveSuffix}`; } } return `${text}\n\n${gameUrl}`; } /** Count graphemes accurately (handles emoji, combining characters). */ export function graphemeCount(text: string): number { const segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' }); let count = 0; for (const _ of segmenter.segment(text)) count++; return count; } /** Open the Bluesky compose page with pre-populated text. */ export function openBlueskyCompose(text: string): void { const url = `https://bsky.app/intent/compose?text=${encodeURIComponent(text)}`; window.open(url, '_blank'); }