~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
72 lines · 2.2 KB Raw History
import { Link } from '#/components/atoms/link.jsx';
import { cn } from '#/lib/utils.js';

/**
 * One entry in a list of things that carry a state: a pull request, an issue.
 *
 * Both lists ask a reader the same three questions in the same order, so both
 * are drawn here rather than each keeping its own sizes. The mark at the head
 * is the state, because that is the question before the words are. The title
 * is what a reader scans a column for. The line under it is who proposes
 * what, read once a title has caught the eye.
 *
 * `marks` holds the right of the title line, which is what has been said
 * about the entry. `footer` is what one entry has and the others do not, and
 * needs the width the title has rather than the width left beside it.
 */
export function ListRow({
  Icon,
  iconClassName,
  title,
  href,
  marks,
  footer,
  children,
}) {
  return (
    <div className="flex gap-2.5 border-border border-b px-4 py-3">
      <Icon className={cn('size-4 shrink-0 translate-y-0.5', iconClassName)} />
      <div className="min-w-0 flex-1">
        <div className="flex items-start justify-between gap-3">
          <Link
            href={href}
            className="min-w-0 font-medium text-[15px] text-foreground no-underline hover:underline"
          >
            {title}
          </Link>
          {marks && (
            <div className="flex shrink-0 items-center gap-2.5 text-[12.5px]">
              {marks}
            </div>
          )}
        </div>

        <div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[12.5px] text-faint">
          {children}
        </div>

        {footer}
      </div>
    </div>
  );
}

/** What separates two facts on the line under a title. */
export function Dot() {
  return <span aria-hidden="true">·</span>;
}

/**
 * One count on the right of a title, with the icon that says what was
 * counted. Nothing is drawn for a count of none.
 * @param {{Icon: Function, count: number, className?: string, title?: string}} props
 */
export function ListCount({ Icon, count, className, title }) {
  if (!count) return null;
  return (
    <span className={cn('flex items-center gap-1', className)} title={title}>
      <Icon className="size-3.5" />
      {count}
    </span>
  );
}