SPB Git forge
28commits 1branches 0releases
7.7 MBsize
maindefault branch
10 days agolast push
Python 66.3% TypeScript 22.7% JavaScript 8.6% HTML 1.4% CSS 0.7%
1.3 KB · 35 lines tsx
Raw Blame History
1'use client';2import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useState } from 'react';34const Ctx = createContext<{ open: boolean; setOpen: (v: boolean) => void }>({ open: false, setOpen: () => undefined });56/** Global ⌘K / "/" search dialog state. */7export function SearchProvider({ children }: { children: ReactNode }) {8  const [open, setOpen] = useState(false);9  useEffect(() => {10    const onKey = (e: KeyboardEvent) => {11      const target = e.target as HTMLElement | null;12      const typing = target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.tagName === 'SELECT' || target.isContentEditable);13      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {14        e.preventDefault();15        setOpen((o) => !o);16      } else if (e.key === '/' && !typing && !e.metaKey && !e.ctrlKey) {17        e.preventDefault();18        setOpen(true);19      }20    };21    window.addEventListener('keydown', onKey);22    return () => window.removeEventListener('keydown', onKey);23  }, []);24  const value = useMemo(() => ({ open, setOpen }), [open]);25  return <Ctx.Provider value={value}>{children}</Ctx.Provider>;26}2728export function useSearch() {29  return useContext(Ctx);30}31export function useOpenSearch() {32  const { setOpen } = useContext(Ctx);33  return useCallback(() => setOpen(true), [setOpen]);34}35