import React, { useCallback } from 'react'; import FocusTrap from 'focus-trap-react'; import { useAtom } from 'jotai'; import { Grid, SearchBar, SearchContext, SearchContextManager } from '@giphy/react-components'; import { IGif } from '@giphy/js-types'; import { Box, color, config } from 'folds'; import { useSetting } from '../state/hooks/settings'; import { settingsAtom } from '../state/settings'; import { addRecentGif, RecentGif, recentGifsAtom } from '../state/recentGifs'; const PICKER_WIDTH = 312; const PICKER_WIDTH_CSS = `min(${PICKER_WIDTH}px, calc(100vw - 16px))`; type GifPickerInnerProps = { onSelect: (url: string, width: number, height: number) => void; requestClose: () => void; lotusTerminal: boolean; }; // Small monospace section header matching the picker's `// GIF_SEARCH` treatment // (lotusTerminal) / a muted label otherwise. const RECENT_LABEL_ID = 'gif-picker-recent-label'; function SectionLabel({ text, lotusTerminal, id, }: { text: string; lotusTerminal: boolean; id?: string; }) { if (lotusTerminal) { return (
{`// ${text.toUpperCase()}`}
); } return (
{text}
); } function RecentGifs({ recents, lotusTerminal, onPick, }: { recents: RecentGif[]; lotusTerminal: boolean; onPick: (gif: RecentGif) => void; }) { return (
{recents.map((g, i) => ( ))}
); } function GifPickerInner({ onSelect, requestClose, lotusTerminal }: GifPickerInnerProps) { const { fetchGifs, searchKey, term } = React.useContext(SearchContext); const [recents, setRecents] = useAtom(recentGifsAtom); const sendGif = useCallback( (gif: RecentGif) => { setRecents((prev) => addRecentGif(prev, gif)); onSelect(gif.url, gif.width, gif.height); requestClose(); }, [onSelect, requestClose, setRecents], ); const handleClick = useCallback( (gif: IGif, e: React.SyntheticEvent) => { e.preventDefault(); const r = gif.images.downsized ?? gif.images.original; const previewUrl = gif.images.fixed_width_small_still?.url ?? gif.images.downsized_still?.url ?? gif.images.original_still?.url; sendGif({ url: r.url, width: Number(r.width) || 200, height: Number(r.height) || 200, previewUrl, }); }, [sendGif], ); const showRecents = recents.length > 0 && !(term ?? '').trim(); return ( {lotusTerminal && (
{'// GIF_SEARCH'}
)}
{showRecents && ( )}
); } type GifPickerProps = { apiKey: string; onSelect: (url: string, width: number, height: number) => void; requestClose: () => void; }; export function GifPicker({ apiKey, onSelect, requestClose }: GifPickerProps) { const [lotusTerminal] = useSetting(settingsAtom, 'lotusTerminal'); const containerStyle = lotusTerminal ? { background: 'var(--lt-bg-secondary)', border: '1px solid color-mix(in srgb, var(--lt-accent-orange) 35%, transparent)', borderRadius: '4px', overflow: 'hidden', boxShadow: '0 4px 24px color-mix(in srgb, var(--lt-accent-orange) 10%, transparent), 0 0 0 1px color-mix(in srgb, var(--lt-accent-orange) 8%, transparent)', width: PICKER_WIDTH_CSS, } : { background: color.Surface.Container, border: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`, borderRadius: config.radii.R400, overflow: 'hidden', boxShadow: color.Other.Shadow, width: PICKER_WIDTH_CSS, }; return ( ); }