{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "filter-bar",
  "type": "registry:component",
  "title": "Filter Bar",
  "description": "Linear-style filter chips you build from one menu: Status is not Done, Labels include Bug, Assignee is me. Click any part of a chip to change it, press F to add one, Backspace to drop it, and the issue list re-sorts itself as you go.",
  "categories": [
    "component",
    "Filters"
  ],
  "dependencies": [
    "@qnot/core",
    "@qnot/react",
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "utils",
    "https://coss.com/ui/r/button.json",
    "https://coss.com/ui/r/kbd.json",
    "https://coss.com/ui/r/menu.json",
    "https://coss.com/ui/r/tooltip.json"
  ],
  "files": [
    {
      "path": "registry/devl/filter-bar.tsx",
      "type": "registry:component",
      "content": "\"use client\";\n\nimport { compile, defineFields, f, formatInput, parseInput, type QueryOf, type ValueOf, validateQuery } from \"@qnot/core\";\nimport { QueryProvider, useQuery, useQueryStore, useRule, useStore } from \"@qnot/react\";\nimport {\n  CircleDashedIcon,\n  ListFilterIcon,\n  SignalHighIcon,\n  TagIcon,\n  TimerIcon,\n  UserRoundIcon,\n  XIcon,\n} from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { type KeyboardEvent, memo, type ReactNode, type RefObject, useMemo, useRef, useState } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { Kbd } from \"@/components/ui/kbd\";\nimport {\n  Menu,\n  MenuCheckboxItem,\n  MenuGroup,\n  MenuGroupLabel,\n  MenuItem,\n  MenuPopup,\n  MenuRadioGroup,\n  MenuRadioItem,\n  MenuSeparator,\n  MenuSub,\n  MenuSubPopup,\n  MenuSubTrigger,\n  MenuTrigger,\n} from \"@/components/ui/menu\";\nimport { Tooltip, TooltipPopup, TooltipTrigger } from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\nexport const issueFields = defineFields({\n  status: f.enum([\n    { value: \"backlog\", label: \"Backlog\" },\n    { value: \"todo\", label: \"Todo\" },\n    { value: \"in_progress\", label: \"In progress\" },\n    { value: \"in_review\", label: \"In review\" },\n    { value: \"done\", label: \"Done\" },\n    { value: \"canceled\", label: \"Canceled\" },\n  ]),\n  assignee: f.enum([\n    { value: \"riley\", label: \"Riley Park\" },\n    { value: \"noor\", label: \"Noor Haddad\" },\n    { value: \"sam\", label: \"Sam Okafor\" },\n    { value: \"kai\", label: \"Kai Lindqvist\" },\n    { value: \"none\", label: \"No assignee\" },\n  ]),\n  priority: f.enum([\n    { value: \"urgent\", label: \"Urgent\" },\n    { value: \"high\", label: \"High\" },\n    { value: \"medium\", label: \"Medium\" },\n    { value: \"low\", label: \"Low\" },\n    { value: \"none\", label: \"No priority\" },\n  ]),\n  labels: f.multiEnum([\n    { value: \"bug\", label: \"Bug\" },\n    { value: \"feature\", label: \"Feature\" },\n    { value: \"perf\", label: \"Performance\" },\n    { value: \"design\", label: \"Design\" },\n    { value: \"docs\", label: \"Docs\" },\n  ]),\n  estimate: f.number({ min: 0, max: 21, integer: true }),\n});\n\ntype IssueFields = typeof issueFields;\ntype FieldName = keyof IssueFields & string;\n\nexport interface Issue {\n  id: string;\n  title: string;\n  status: ValueOf<IssueFields[\"status\"]>;\n  assignee: ValueOf<IssueFields[\"assignee\"]>;\n  priority: ValueOf<IssueFields[\"priority\"]>;\n  labels: ValueOf<IssueFields[\"labels\"]>;\n  estimate: number;\n}\n\nexport interface FilterBarProps {\n  issues: readonly Issue[];\n  me?: string;\n  defaultQuery?: QueryOf<IssueFields>;\n  onChange?: (query: QueryOf<IssueFields>) => void;\n  className?: string;\n}\n\nconst easeOut = [0.23, 1, 0.32, 1] as const;\nconst glide = { type: \"spring\", duration: 0.3, bounce: 0 } as const;\n\nconst fieldMeta: Record<FieldName, { label: string; icon: typeof TagIcon }> = {\n  status: { label: \"Status\", icon: CircleDashedIcon },\n  assignee: { label: \"Assignee\", icon: UserRoundIcon },\n  priority: { label: \"Priority\", icon: SignalHighIcon },\n  labels: { label: \"Labels\", icon: TagIcon },\n  estimate: { label: \"Estimate\", icon: TimerIcon },\n};\n\nconst enumFields = [\"status\", \"assignee\", \"priority\"] as const;\nconst estimatePresets = [1, 2, 3, 5, 8];\nconst multiOps = [\n  { value: \"hasAny\", label: \"include any of\" },\n  { value: \"hasAll\", label: \"include all of\" },\n  { value: \"hasNone\", label: \"exclude\" },\n];\nconst numberOps = [\n  { value: \"gte\", label: \"at least\", symbol: \"≥\" },\n  { value: \"lte\", label: \"at most\", symbol: \"≤\" },\n  { value: \"eq\", label: \"exactly\", symbol: \"=\" },\n];\n\nconst labelTones: Record<string, string> = {\n  bug: \"bg-rose-500\",\n  feature: \"bg-sky-500\",\n  perf: \"bg-amber-500\",\n  design: \"bg-violet-500\",\n  docs: \"bg-emerald-500\",\n};\n\nconst avatarTones: Record<string, string> = {\n  riley: \"bg-violet-500/15 text-violet-700 dark:text-violet-300\",\n  noor: \"bg-emerald-500/15 text-emerald-700 dark:text-emerald-300\",\n  sam: \"bg-amber-500/15 text-amber-700 dark:text-amber-300\",\n  kai: \"bg-sky-500/15 text-sky-700 dark:text-sky-300\",\n};\n\nfunction optionsOf(field: FieldName) {\n  const def = issueFields[field];\n  return (def.options ?? []) as readonly { value: string; label: string }[];\n}\n\nfunction labelOf(field: FieldName, value: string, me?: string) {\n  if (field === \"assignee\" && value === me) return \"me\";\n  return optionsOf(field).find((o) => o.value === value)?.label ?? value;\n}\n\nexport function FilterBar({ issues, me = \"riley\", defaultQuery, onChange, className }: FilterBarProps) {\n  const store = useQueryStore({\n    fields: issueFields,\n    initial: defaultQuery ?? { kind: \"group\", combinator: \"and\", children: [] },\n    onChange,\n  });\n  const [menuOpen, setMenuOpen] = useState(false);\n  const filterButton = useRef<HTMLButtonElement>(null);\n\n  const onKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n    if ((e.target as HTMLElement).closest(\"input, textarea, [role=menu]\")) return;\n    if (e.key.toLowerCase() === \"f\" && !e.metaKey && !e.ctrlKey && !e.altKey) {\n      e.preventDefault();\n      setMenuOpen(true);\n    }\n  };\n\n  return (\n    <QueryProvider store={store}>\n      <div\n        className={cn(\n          \"flex h-[400px] w-full min-w-0 max-w-[560px] flex-col overflow-hidden rounded-2xl border bg-card text-sm shadow-xs/5\",\n          className,\n        )}\n        onKeyDown={onKeyDown}\n      >\n        <FilterRow\n          filterButton={filterButton}\n          me={me}\n          menuOpen={menuOpen}\n          onMenuOpenChange={setMenuOpen}\n        />\n        <Results issues={issues} me={me} />\n      </div>\n    </QueryProvider>\n  );\n}\n\nfunction FilterRow({\n  me,\n  menuOpen,\n  onMenuOpenChange,\n  filterButton,\n}: {\n  me: string;\n  menuOpen: boolean;\n  onMenuOpenChange: (open: boolean) => void;\n  filterButton: RefObject<HTMLButtonElement | null>;\n}) {\n  const reduce = useReducedMotion();\n  const store = useStore<IssueFields>();\n  const query = useQuery<IssueFields>();\n  const chips = store.getGroup(store.rootId).children;\n\n  const ruleFor = (field: FieldName) => {\n    const index = query.children.findIndex((n) => n.kind === \"rule\" && n.field === field);\n    return index === -1 ? null : { id: chips[index], node: query.children[index] };\n  };\n\n  const selectedValues = (field: FieldName): string[] => {\n    const found = ruleFor(field);\n    if (!found || found.node.kind !== \"rule\" || !(\"value\" in found.node)) return [];\n    const v = found.node.value;\n    return Array.isArray(v) ? v.map(String) : v == null ? [] : [String(v)];\n  };\n\n  const toggleValue = (field: FieldName, value: string) => {\n    const found = ruleFor(field);\n    if (!found) {\n      const operator = field === \"labels\" ? \"hasAny\" : \"eq\";\n      store.addRule(store.rootId, { field, operator, value: field === \"labels\" ? [value] : value } as never);\n      return;\n    }\n    const current = selectedValues(field);\n    const next = current.includes(value) ? current.filter((v) => v !== value) : [...current, value];\n    setValues(store, found.id, field, next);\n  };\n\n  const setEstimate = (min: number) => {\n    const found = ruleFor(\"estimate\");\n    if (!found) store.addRule(store.rootId, { field: \"estimate\", operator: \"gte\", value: min });\n    else store.batch(() => {\n      store.setOperator(found.id, \"gte\");\n      store.setRuleValue(found.id, min);\n    });\n  };\n\n  return (\n    <div className=\"flex shrink-0 items-start gap-2 border-b px-3 py-2.5\">\n      <div className=\"relative flex min-h-7 min-w-0 flex-1 flex-wrap items-center gap-1.5\">\n        <AnimatePresence initial={false} mode=\"popLayout\">\n          {chips.map((id) => (\n            <motion.div\n              animate={{ opacity: 1, scale: 1 }}\n              className=\"min-w-0 max-w-full\"\n              exit={{ opacity: 0, scale: 0.95, transition: { duration: reduce ? 0 : 0.12, ease: easeOut } }}\n              initial={{ opacity: 0, scale: reduce ? 1 : 0.95 }}\n              key={id}\n              layout={reduce ? false : \"position\"}\n              transition={reduce ? { duration: 0 } : { ...glide, opacity: { duration: 0.15, ease: easeOut } }}\n            >\n              <Chip id={id} me={me} onRemoved={() => filterButton.current?.focus()} />\n            </motion.div>\n          ))}\n        </AnimatePresence>\n        {chips.length === 0 && (\n          <span className=\"ps-1 text-muted-foreground text-xs\">Showing every issue. Add a filter to narrow it down.</span>\n        )}\n      </div>\n      <Menu onOpenChange={onMenuOpenChange} open={menuOpen}>\n        <MenuTrigger\n          render={\n            <Button\n              aria-label=\"Add filter\"\n              className=\"max-sm:px-2\"\n              ref={filterButton}\n              size=\"sm\"\n              variant=\"outline\"\n            />\n          }\n        >\n          <ListFilterIcon />\n          <span className=\"max-sm:hidden\">Filter</span>\n          <Kbd className=\"h-4.5 min-w-4.5 max-sm:hidden\">F</Kbd>\n        </MenuTrigger>\n        <MenuPopup align=\"end\" className=\"w-52\">\n          <MenuGroup>\n            <MenuGroupLabel>Add filter</MenuGroupLabel>\n            {enumFields.map((field) => {\n              const Icon = fieldMeta[field].icon;\n              const selected = selectedValues(field);\n              return (\n                <MenuSub key={field}>\n                  <MenuSubTrigger>\n                    <Icon />\n                    {fieldMeta[field].label}\n                    {selected.length > 0 && (\n                      <span className=\"ms-auto text-muted-foreground text-xs tabular-nums\">{selected.length}</span>\n                    )}\n                  </MenuSubTrigger>\n                  <MenuSubPopup className=\"w-52\">\n                    {orderedOptions(field, me).map((o) => (\n                      <MenuCheckboxItem\n                        checked={selected.includes(o.value)}\n                        key={o.value}\n                        onCheckedChange={() => toggleValue(field, o.value)}\n                      >\n                        <span className=\"flex items-center gap-2\">\n                          <ValueIcon field={field} value={o.value} />\n                          {field === \"assignee\" && o.value === me ? \"Me\" : o.label}\n                        </span>\n                      </MenuCheckboxItem>\n                    ))}\n                  </MenuSubPopup>\n                </MenuSub>\n              );\n            })}\n            <MenuSub>\n              <MenuSubTrigger>\n                <TagIcon />\n                Labels\n                {selectedValues(\"labels\").length > 0 && (\n                  <span className=\"ms-auto text-muted-foreground text-xs tabular-nums\">{selectedValues(\"labels\").length}</span>\n                )}\n              </MenuSubTrigger>\n              <MenuSubPopup className=\"w-48\">\n                {optionsOf(\"labels\").map((o) => (\n                  <MenuCheckboxItem\n                    checked={selectedValues(\"labels\").includes(o.value)}\n                    key={o.value}\n                    onCheckedChange={() => toggleValue(\"labels\", o.value)}\n                  >\n                    <span className=\"flex items-center gap-2\">\n                      <ValueIcon field=\"labels\" value={o.value} />\n                      {o.label}\n                    </span>\n                  </MenuCheckboxItem>\n                ))}\n              </MenuSubPopup>\n            </MenuSub>\n            <MenuSub>\n              <MenuSubTrigger>\n                <TimerIcon />\n                Estimate\n              </MenuSubTrigger>\n              <MenuSubPopup className=\"w-44\">\n                <MenuRadioGroup onValueChange={(v) => setEstimate(Number(v))} value={null}>\n                  {estimatePresets.map((n) => (\n                    <MenuRadioItem closeOnClick key={n} value={String(n)}>\n                      {n}+ points\n                    </MenuRadioItem>\n                  ))}\n                </MenuRadioGroup>\n              </MenuSubPopup>\n            </MenuSub>\n          </MenuGroup>\n          {chips.length > 0 && (\n            <>\n              <MenuSeparator />\n              <MenuItem onClick={() => store.clear()} variant=\"destructive\">\n                <XIcon />\n                Clear all filters\n              </MenuItem>\n            </>\n          )}\n        </MenuPopup>\n      </Menu>\n    </div>\n  );\n}\n\nfunction orderedOptions(field: FieldName, me: string) {\n  const options = optionsOf(field);\n  if (field !== \"assignee\") return options;\n  return [...options.filter((o) => o.value === me), ...options.filter((o) => o.value !== me)];\n}\n\nfunction setValues(store: ReturnType<typeof useStore<IssueFields>>, id: string, field: FieldName, next: string[]) {\n  if (next.length === 0) {\n    store.remove(id);\n    return;\n  }\n  const rule = store.getRule(id);\n  if (field === \"labels\") {\n    store.setRuleValue(id, next);\n    return;\n  }\n  const negative = rule.operator === \"neq\" || rule.operator === \"notIn\";\n  const operator = next.length === 1 ? (negative ? \"neq\" : \"eq\") : negative ? \"notIn\" : \"in\";\n  store.batch(() => {\n    store.setOperator(id, operator);\n    store.setRuleValue(id, next.length === 1 ? next[0] : next);\n  });\n}\n\nconst segment =\n  \"flex h-full shrink-0 items-center gap-1.5 whitespace-nowrap px-2 outline-none transition-colors hover:bg-accent focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset data-popup-open:bg-accent\";\n\nconst Chip = memo(function Chip({ id, me, onRemoved }: { id: string; me: string; onRemoved: () => void }) {\n  const store = useStore<IssueFields>();\n  const { rule, issues, setOperator, setValue, remove } = useRule<IssueFields>(id);\n  const field = rule.field as FieldName;\n  const Icon = fieldMeta[field].icon;\n  const raw = \"value\" in rule ? rule.value : null;\n  const values = Array.isArray(raw) ? raw.map(String) : raw == null ? [] : [String(raw)];\n  const errors = issues.filter((i) => i.severity === \"error\");\n  const negative = rule.operator === \"neq\" || rule.operator === \"notIn\" || rule.operator === \"hasNone\";\n\n  const removeAndFocus = () => {\n    remove();\n    onRemoved();\n  };\n\n  const onKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n    if ((e.key === \"Backspace\" || e.key === \"Delete\") && !(e.target as HTMLElement).closest(\"input\")) {\n      e.preventDefault();\n      removeAndFocus();\n    }\n  };\n\n  let operatorLabel: string;\n  let operatorMenu: ReactNode;\n  if (field === \"labels\") {\n    operatorLabel = multiOps.find((o) => o.value === rule.operator)?.label ?? rule.operator;\n    operatorMenu = multiOps.map((o) => (\n      <MenuRadioItem closeOnClick key={o.value} value={o.value}>\n        {o.label}\n      </MenuRadioItem>\n    ));\n  } else if (field === \"estimate\") {\n    operatorLabel = numberOps.find((o) => o.value === rule.operator)?.symbol ?? rule.operator;\n    operatorMenu = numberOps.map((o) => (\n      <MenuRadioItem closeOnClick key={o.value} value={o.value}>\n        <span className=\"flex w-full items-center justify-between gap-3\">\n          {o.label}\n          <span className=\"font-mono text-muted-foreground text-xs\">{o.symbol}</span>\n        </span>\n      </MenuRadioItem>\n    ));\n  } else {\n    operatorLabel = negative ? (values.length > 1 ? \"is none of\" : \"is not\") : values.length > 1 ? \"is any of\" : \"is\";\n    operatorMenu = [\n      <MenuRadioItem closeOnClick key=\"pos\" value=\"pos\">\n        {values.length > 1 ? \"is any of\" : \"is\"}\n      </MenuRadioItem>,\n      <MenuRadioItem closeOnClick key=\"neg\" value=\"neg\">\n        {values.length > 1 ? \"is none of\" : \"is not\"}\n      </MenuRadioItem>,\n    ];\n  }\n\n  const operatorValue = field === \"labels\" || field === \"estimate\" ? rule.operator : negative ? \"neg\" : \"pos\";\n  const onOperator = (next: string) => {\n    if (field === \"labels\" || field === \"estimate\") return setOperator(next);\n    const wantNegative = next === \"neg\";\n    if (wantNegative === negative) return;\n    setOperator(values.length > 1 ? (wantNegative ? \"notIn\" : \"in\") : wantNegative ? \"neq\" : \"eq\");\n  };\n\n  const chip = (\n    <div\n      className={cn(\n        \"flex h-7 max-w-full items-stretch overflow-hidden rounded-lg border bg-background text-xs shadow-xs/5 dark:bg-input/32\",\n        errors.length > 0 && \"border-destructive/48\",\n      )}\n      onKeyDown={onKeyDown}\n      role=\"group\"\n      aria-label={`${fieldMeta[field].label} filter`}\n    >\n      <span className=\"flex shrink-0 items-center gap-1.5 ps-2 pe-1.5 text-muted-foreground\">\n        <Icon className=\"size-3.5\" />\n        <span className=\"font-medium text-foreground\">{fieldMeta[field].label}</span>\n      </span>\n      <Menu>\n        <MenuTrigger className={cn(segment, \"border-s text-muted-foreground\")}>{operatorLabel}</MenuTrigger>\n        <MenuPopup align=\"start\" className=\"w-40\">\n          <MenuRadioGroup onValueChange={(v) => onOperator(String(v))} value={operatorValue}>\n            {operatorMenu}\n          </MenuRadioGroup>\n        </MenuPopup>\n      </Menu>\n      {field === \"estimate\" ? (\n        <EstimateInput invalid={errors.length > 0} onChange={setValue} value={raw} />\n      ) : (\n        <Menu>\n          <MenuTrigger className={cn(segment, \"min-w-0 max-w-48 shrink border-s font-medium\")}>\n            <span className={cn(\"flex shrink-0 items-center\", field === \"labels\" ? \"gap-0.5\" : \"-space-x-1\")}>\n              {values.slice(0, 3).map((v) => (\n                <ValueIcon field={field} key={v} ring value={v} />\n              ))}\n            </span>\n            <span className=\"truncate\">\n              {values.length > 2 ? `${values.length} ${field === \"labels\" ? \"labels\" : \"values\"}` : values.map((v) => labelOf(field, v, me)).join(\", \")}\n            </span>\n          </MenuTrigger>\n          <MenuPopup align=\"start\" className=\"w-52\">\n            {orderedOptions(field, me).map((o) => (\n              <MenuCheckboxItem\n                checked={values.includes(o.value)}\n                key={o.value}\n                onCheckedChange={() => {\n                  const next = values.includes(o.value) ? values.filter((v) => v !== o.value) : [...values, o.value];\n                  setValues(store, id, field, next);\n                  if (next.length === 0) onRemoved();\n                }}\n              >\n                <span className=\"flex items-center gap-2\">\n                  <ValueIcon field={field} value={o.value} />\n                  {field === \"assignee\" && o.value === me ? \"Me\" : o.label}\n                </span>\n              </MenuCheckboxItem>\n            ))}\n          </MenuPopup>\n        </Menu>\n      )}\n      <button\n        aria-label={`Remove ${fieldMeta[field].label} filter`}\n        className={cn(segment, \"border-s px-1.5 text-muted-foreground hover:text-foreground\")}\n        onClick={removeAndFocus}\n        type=\"button\"\n      >\n        <XIcon className=\"size-3.5\" />\n      </button>\n    </div>\n  );\n\n  if (!errors.length) return chip;\n  return (\n    <Tooltip>\n      <TooltipTrigger render={<div />}>{chip}</TooltipTrigger>\n      <TooltipPopup>{errors.map((e) => e.message).join(\" · \")}</TooltipPopup>\n    </Tooltip>\n  );\n});\n\nfunction EstimateInput({ value, invalid, onChange }: { value: unknown; invalid: boolean; onChange: (v: unknown) => void }) {\n  const [draft, setDraft] = useState<string | null>(null);\n  const def = issueFields.estimate;\n  const unreadable = draft !== null && draft.trim() !== \"\" && parseInput(def, draft) === null;\n  return (\n    <input\n      aria-invalid={invalid || unreadable || undefined}\n      aria-label=\"Estimate points\"\n      className=\"w-12 border-s bg-transparent px-2 font-medium tabular-nums outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset aria-invalid:text-destructive-foreground\"\n      inputMode=\"numeric\"\n      onBlur={() => setDraft(null)}\n      onChange={(e) => {\n        setDraft(e.target.value);\n        onChange(parseInput(def, e.target.value));\n      }}\n      onFocus={() => setDraft(formatInput(value))}\n      value={draft ?? formatInput(value)}\n    />\n  );\n}\n\nfunction ValueIcon({ field, value, ring }: { field: FieldName; value: string; ring?: boolean }) {\n  if (field === \"status\") return <StatusIcon status={value} />;\n  if (field === \"priority\") return <PriorityIcon priority={value} />;\n  if (field === \"labels\") return <span className={cn(\"size-2 shrink-0 rounded-full\", labelTones[value])} />;\n  if (field === \"assignee\") return <PersonAvatar id={value} ring={ring} />;\n  return null;\n}\n\nfunction PersonAvatar({ id, ring }: { id: string; ring?: boolean }) {\n  const name = optionsOf(\"assignee\").find((o) => o.value === id)?.label ?? id;\n  if (id === \"none\")\n    return (\n      <span className={cn(\"flex size-4 shrink-0 items-center justify-center rounded-full border border-dashed border-muted-foreground/48\", ring && \"ring-2 ring-background\")}>\n        <UserRoundIcon className=\"size-2.5 text-muted-foreground\" />\n      </span>\n    );\n  return (\n    <span\n      aria-hidden\n      className={cn(\n        \"flex size-4 shrink-0 items-center justify-center rounded-full font-semibold text-[8px]\",\n        avatarTones[id] ?? \"bg-muted text-muted-foreground\",\n        ring && \"ring-2 ring-background\",\n      )}\n    >\n      {name\n        .split(\" \")\n        .map((p) => p[0])\n        .join(\"\")}\n    </span>\n  );\n}\n\nfunction StatusIcon({ status }: { status: string }) {\n  const tone: Record<string, string> = {\n    backlog: \"text-muted-foreground\",\n    todo: \"text-muted-foreground\",\n    in_progress: \"text-amber-500\",\n    in_review: \"text-emerald-500\",\n    done: \"text-violet-500\",\n    canceled: \"text-muted-foreground\",\n  };\n  const fill: Record<string, number> = { in_progress: 0.5, in_review: 0.75 };\n  return (\n    <svg aria-hidden className={cn(\"size-3.5 shrink-0\", tone[status])} fill=\"none\" viewBox=\"0 0 14 14\">\n      {status === \"backlog\" ? (\n        <circle cx=\"7\" cy=\"7\" r=\"5.5\" stroke=\"currentColor\" strokeDasharray=\"2 2\" strokeWidth=\"1.5\" />\n      ) : status === \"done\" || status === \"canceled\" ? (\n        <>\n          <circle cx=\"7\" cy=\"7\" fill=\"currentColor\" r=\"6\" />\n          <path\n            d={status === \"done\" ? \"M4.5 7.2 6.2 8.8 9.5 5.4\" : \"M5 5l4 4M9 5l-4 4\"}\n            stroke=\"var(--color-card)\"\n            strokeLinecap=\"round\"\n            strokeLinejoin=\"round\"\n            strokeWidth=\"1.5\"\n          />\n        </>\n      ) : (\n        <>\n          <circle cx=\"7\" cy=\"7\" r=\"5.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" />\n          {fill[status] && (\n            <path\n              d={arcPath(fill[status])}\n              fill=\"currentColor\"\n            />\n          )}\n        </>\n      )}\n    </svg>\n  );\n}\n\nfunction arcPath(fraction: number) {\n  const angle = fraction * Math.PI * 2;\n  const x = 7 + 3 * Math.sin(angle);\n  const y = 7 - 3 * Math.cos(angle);\n  return `M7 7 L7 4 A3 3 0 ${fraction > 0.5 ? 1 : 0} 1 ${x.toFixed(2)} ${y.toFixed(2)} Z`;\n}\n\nfunction PriorityIcon({ priority }: { priority: string }) {\n  if (priority === \"urgent\")\n    return (\n      <svg aria-hidden className=\"size-3.5 shrink-0 text-orange-500\" viewBox=\"0 0 14 14\">\n        <rect fill=\"currentColor\" height=\"12\" rx=\"3\" width=\"12\" x=\"1\" y=\"1\" />\n        <path d=\"M7 4v3.6M7 9.6v.2\" stroke=\"var(--color-card)\" strokeLinecap=\"round\" strokeWidth=\"1.6\" />\n      </svg>\n    );\n  if (priority === \"none\")\n    return (\n      <svg aria-hidden className=\"size-3.5 shrink-0 text-muted-foreground\" viewBox=\"0 0 14 14\">\n        {[2, 6, 10].map((x) => (\n          <rect fill=\"currentColor\" height=\"1.5\" key={x} rx=\"0.75\" width=\"2.5\" x={x - 0.5} y=\"6.25\" />\n        ))}\n      </svg>\n    );\n  const level = priority === \"high\" ? 3 : priority === \"medium\" ? 2 : 1;\n  return (\n    <svg aria-hidden className=\"size-3.5 shrink-0 text-foreground\" viewBox=\"0 0 14 14\">\n      {[0, 1, 2].map((i) => (\n        <rect\n          fill=\"currentColor\"\n          height={4 + i * 3}\n          key={i}\n          opacity={i < level ? 1 : 0.24}\n          rx=\"1\"\n          width=\"2.6\"\n          x={1.6 + i * 4}\n          y={11 - (4 + i * 3)}\n        />\n      ))}\n    </svg>\n  );\n}\n\nfunction Results({ issues, me }: { issues: readonly Issue[]; me: string }) {\n  const reduce = useReducedMotion();\n  const store = useStore<IssueFields>();\n  const query = useQuery<IssueFields>();\n  const visible = useMemo(\n    () => issues.filter(compile<IssueFields, Issue>(issueFields, query, { invalidRules: \"skip\" })),\n    [issues, query],\n  );\n  const problem = useMemo(() => {\n    const issue = validateQuery(issueFields, query).find((i) => i.severity === \"error\" && i.code !== \"required\");\n    const node = issue ? query.children[issue.path[0] ?? -1] : undefined;\n    if (!issue || !node || node.kind !== \"rule\") return null;\n    return `${fieldMeta[node.field as FieldName]?.label ?? \"Filter\"} ignored: ${issue.message.toLowerCase()}`;\n  }, [query]);\n  const filtered = query.children.length > 0;\n\n  return (\n    <div className=\"flex min-h-0 flex-1 flex-col\">\n      <div className=\"flex h-9 shrink-0 items-center justify-between gap-3 px-4 pt-1 text-muted-foreground text-xs\">\n        <span className={cn(\"truncate tabular-nums\", problem && \"text-destructive-foreground\")}>\n          {problem ?? (filtered ? `${visible.length} of ${issues.length} issues` : `${issues.length} issues`)}\n        </span>\n        {filtered && (\n          <button\n            className=\"rounded-md px-1.5 py-0.5 outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring\"\n            onClick={() => store.clear()}\n            type=\"button\"\n          >\n            Clear filters\n          </button>\n        )}\n      </div>\n      <div className=\"relative min-h-0 flex-1 overflow-y-auto px-1.5 pb-1.5\">\n        <AnimatePresence initial={false}>\n          {visible.map((issue) => (\n            <motion.div\n              animate={{ opacity: 1 }}\n              className=\"flex h-10 items-center gap-2.5 rounded-lg px-2.5 hover:bg-accent/50\"\n              exit={{ opacity: 0, transition: { duration: 0 } }}\n              initial={{ opacity: 0 }}\n              key={issue.id}\n              transition={{ duration: reduce ? 0 : 0.15, ease: easeOut }}\n            >\n              <PriorityIcon priority={issue.priority} />\n              <span className=\"w-16 shrink-0 font-mono text-[11px] text-muted-foreground tabular-nums max-sm:hidden\">{issue.id}</span>\n              <StatusIcon status={issue.status} />\n              <span className=\"min-w-0 flex-1 truncate\">{issue.title}</span>\n              <span className=\"flex shrink-0 items-center gap-1 max-sm:hidden\">\n                {issue.labels.map((l) => (\n                  <span className={cn(\"size-2 rounded-full\", labelTones[l])} key={l} title={labelOf(\"labels\", l)} />\n                ))}\n              </span>\n              <span className=\"w-6 shrink-0 text-end font-mono text-[11px] text-muted-foreground tabular-nums\">{issue.estimate}</span>\n              <span className=\"sr-only\">{issue.assignee === me ? \"Assigned to you\" : `Assigned to ${labelOf(\"assignee\", issue.assignee)}`}</span>\n              <PersonAvatar id={issue.assignee} />\n            </motion.div>\n          ))}\n        </AnimatePresence>\n        <AnimatePresence>\n          {visible.length === 0 && (\n            <motion.div\n              animate={{ opacity: 1, y: 0 }}\n              className=\"absolute inset-0 flex flex-col items-center justify-center gap-1 px-6 text-center\"\n              exit={{ opacity: 0 }}\n              initial={{ opacity: 0, y: reduce ? 0 : 4 }}\n              transition={{ duration: 0.2, ease: easeOut }}\n            >\n              <ListFilterIcon className=\"mb-1 size-5 text-muted-foreground\" />\n              <p className=\"font-medium\">No issues match</p>\n              <p className=\"text-muted-foreground text-xs\">Loosen a filter or start over.</p>\n              <Button className=\"mt-2\" onClick={() => store.clear()} size=\"sm\" variant=\"outline\">\n                Clear filters\n              </Button>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n    </div>\n  );\n}\n"
    }
  ]
}