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

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
74 lines · 2.6 KB Raw History
import { ChevronLeftIcon } from 'lucide-react';
import { Link } from '#/components/atoms/link.jsx';
import { MEASURE } from '#/lib/layout.js';
import { cn } from '#/lib/utils.js';

/**
 * What a detail screen is about, fixed above its body: the title, one line
 * of facts under it, and the one action on the right. A
 * pull request, a commit, an issue and a run all open on this, so a reader
 * meets one heading at one size wherever they land.
 *
 * The heading sits in the reading column unless `wide`, for a screen whose
 * body takes the window. `rule` closes it with a rule, drawn to the column
 * or, wide, to the window. `back` names where the reader came from, on a line
 * above the title, for a page whose parent is not the section tab: a commit
 * reached from a pull request, a form. `meta` is the line under the title:
 * who, when, which sha. `children` is anything else the head carries, such
 * as the tabs a pull request opens on.
 * @param {{title: import('react').ReactNode, back?: {href: string, label: string}, meta?: import('react').ReactNode, actions?: import('react').ReactNode, wide?: boolean, rule?: boolean, className?: string, children?: import('react').ReactNode}} props
 */
export function PageHead({
  title,
  back,
  meta,
  actions,
  wide = false,
  rule = false,
  className,
  children,
}) {
  return (
    <div
      className={cn(
        'shrink-0 px-(--gutter) pt-4',
        wide && 'pb-3.5',
        wide && rule && 'border-border border-b',
        className,
      )}
    >
      <div
        className={cn(
          !wide && `${MEASURE} pb-3.5`,
          !wide && rule && 'border-border border-b',
        )}
      >
        {back && (
          <Link
            href={back.href}
            className="mb-1.5 flex max-w-full items-center gap-1 text-[12.5px] text-muted-foreground no-underline hover:text-foreground hover:no-underline"
          >
            <ChevronLeftIcon className="size-3.5 shrink-0" />
            <span className="truncate">{back.label}</span>
          </Link>
        )}
        <div className="flex flex-wrap items-start justify-between gap-x-4 gap-y-2">
          <h2 className="min-w-0 flex-1 break-words font-semibold text-[18px] leading-snug tracking-[-0.01em]">
            {title}
          </h2>
          {actions && (
            <div className="flex min-w-0 shrink-0 items-center gap-2">
              {actions}
            </div>
          )}
        </div>
        {meta && (
          <div className="mt-2 flex flex-wrap items-center gap-x-2.5 gap-y-1.5 text-[12.5px] text-faint">
            {meta}
          </div>
        )}
        {children}
      </div>
    </div>
  );
}