Ben Senescu efef3894cb
Add shared search tabs to domain overview and backlinks (#192)
* Add shared search tabs to domain and backlinks

* refactor: share search tab framework with keywords

* fix: normalize backlinks tab validation target
2026-05-18 14:51:43 -04:00

75 lines
2.3 KiB
TypeScript

import { X } from "lucide-react";
import type { ReactNode } from "react";
import type { SearchTab } from "./types";
export type { SearchTab } from "./types";
type Props = {
activeTabId: string | null;
tabs: SearchTab[];
onSelect: (tab: SearchTab) => void;
onClose: (tabId: string) => void;
renderLeading?: (tab: SearchTab, active: boolean) => ReactNode;
};
export function SearchTabStrip({
activeTabId,
tabs,
onSelect,
onClose,
renderLeading,
}: Props) {
if (tabs.length === 0) return null;
return (
<div className="rounded-xl border border-base-300 bg-base-100 p-1">
<div
role="tablist"
className="flex min-w-0 items-stretch gap-1 overflow-x-auto"
>
{tabs.map((tab) => {
const active = tab.id === activeTabId;
return (
<div
key={tab.id}
role="tab"
aria-selected={active}
tabIndex={0}
onClick={() => onSelect(tab)}
onKeyDown={(event) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
onSelect(tab);
}
}}
className={`group flex shrink-0 cursor-pointer items-center gap-1.5 rounded-md px-2.5 py-1.5 text-sm transition ${
active
? "bg-base-300 text-base-content shadow-sm"
: "text-base-content/80 hover:bg-base-200"
}`}
>
{renderLeading ? renderLeading(tab, active) : null}
<span
className="max-w-[10rem] truncate font-medium"
title={tab.label}
>
{tab.label}
</span>
<button
type="button"
className="rounded p-0.5 text-base-content/50 opacity-60 transition hover:bg-base-content/10 hover:text-base-content hover:opacity-100 group-hover:opacity-100"
onClick={(event) => {
event.stopPropagation();
onClose(tab.id);
}}
aria-label={`Close ${tab.label} tab`}
>
<X className="size-3.5" />
</button>
</div>
);
})}
</div>
</div>
);
}