chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
import { Select } from '@base-ui/react/select';
import { CheckIcon, ChevronsUpDownIcon, GitBranchIcon } from 'lucide-react';
import { branchRefs, shortRef, tagRefs } from '#/lib/git.js';
import { cn } from '#/lib/utils.js';
/**
* The branch and tag switcher. Both groups come from the repository record,
* so opening the menu costs nothing. Choosing a ref lands on that ref's root:
* the path in view may not exist on it.
*
* `tags` off leaves the tags out, for a caller asking which branch rather
* than which ref. A repository with nothing to choose between renders none
* of this.
*/
export function RefSelect({ repo, value, onSelect, tags = true, className }) {
const branches = branchRefs(repo).map((ref) => shortRef(ref.name));
const tagNames = tags ? tagRefs(repo).map((ref) => shortRef(ref.name)) : [];
if (branches.length + tagNames.length === 0) return null;
const groups = [
['Branches', branches],
['Tags', tagNames],
].filter(([, names]) => names.length > 0);
return (
<Select.Root value={value} onValueChange={onSelect}>
<Select.Trigger
className={cn(
'inline-flex h-9 cursor-pointer items-center gap-2 rounded-xl border border-input bg-background px-3 text-sm outline-none transition-colors',
'hover:bg-accent focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
className,
)}
>
<GitBranchIcon className="size-3.5 shrink-0 text-faint" />
<Select.Value className="max-w-40 truncate font-mono text-[13px]" />
<Select.Icon>
<ChevronsUpDownIcon className="size-3.5 shrink-0 text-faint" />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Positioner
className="z-50"
sideOffset={6}
alignItemWithTrigger={false}
>
<Select.Popup className="max-h-80 min-w-[var(--anchor-width)] overflow-y-auto rounded-xl border border-border bg-card p-1 shadow-lg outline-none">
{groups.map(([label, names]) => (
<Select.Group key={label}>
<Select.GroupLabel className="px-2 py-1.5 text-[11px] text-faint uppercase tracking-wide">
{label}
</Select.GroupLabel>
{names.map((name) => (
<Select.Item
key={name}
value={name}
className="flex cursor-pointer items-center gap-2 rounded-lg py-1.5 pr-2 pl-2 font-mono text-[13px] outline-none data-[highlighted]:bg-accent"
>
{/* The indicator renders only for the selected item, so
the fixed box keeps every label on one edge. */}
<span className="flex size-3.5 shrink-0 items-center">
<Select.ItemIndicator>
<CheckIcon className="size-3.5 text-key" />
</Select.ItemIndicator>
</span>
<Select.ItemText className="truncate">
{name}
</Select.ItemText>
</Select.Item>
))}
</Select.Group>
))}
</Select.Popup>
</Select.Positioner>
</Select.Portal>
</Select.Root>
);
}