spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1'use client';2import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from 'react';34interface Ctx {5 open: boolean;6 setOpen: (v: boolean) => void;7}8const SearchCtx = createContext<Ctx>({ open: false, setOpen: () => {} });910/** Global search state + ⌘K / Ctrl+K / "/" shortcuts. */11export function SearchProvider({ children }: { children: ReactNode }) {12 const [open, setOpen] = useState(false);13 useEffect(() => {14 const onKey = (e: KeyboardEvent) => {15 const target = e.target as HTMLElement | null;16 const typing = target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable);17 if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {18 e.preventDefault();19 setOpen((o) => !o);20 } else if (e.key === '/' && !typing && !e.metaKey && !e.ctrlKey && !e.altKey) {21 e.preventDefault();22 setOpen(true);23 }24 };25 window.addEventListener('keydown', onKey);26 return () => window.removeEventListener('keydown', onKey);27 }, []);28 const value = useMemo(() => ({ open, setOpen }), [open]);29 return <SearchCtx.Provider value={value}>{children}</SearchCtx.Provider>;30}3132export function useSearch() {33 return useContext(SearchCtx);34}3536export function useOpenSearch() {37 const { setOpen } = useSearch();38 return useCallback(() => setOpen(true), [setOpen]);39}40