PackagePage

tcmts.studio.PackagePage · #ed7mpkag · term · runs on the server

is an async component

A package at one range (range, else the newest the codebase runs): what it is, its README, its API (each export by name, its kind and doc, its signature folded under it), and what in the codebase uses it; beside them its version, license, homepage and types, and Upgrade (within its ranges, as tcm upgrade).

import { packageList, packagePage } from "#codebase/tcmts/cli/package_pages";
import { at, codeHref, Fold, Html, markdownHtml, servedCodebase, shareNow } from "#codebase/tcmts/share";
import { StudioFrame, studioShare, UpgradeButton } from "#codebase/tcmts/studio";

export async function PackagePage({ name, range }: { name: string; range: string }) {
  studioShare();
  const s = shareNow();
  if (!s.signedIn)
    return (
      <StudioFrame tab="packages" title="Sign in">
        {null}
      </StudioFrame>
    );
  const entry = packageList(s.cb).find((p) => p.name === name);
  const r = entry?.ranges.find((x) => x.range === range) ?? entry?.ranges[0];
  if (!entry || !r)
    return (
      <StudioFrame tab="packages" title={name}>
        <div className="empty">The codebase doesn't run {name}.</div>
      </StudioFrame>
    );
  const p = packagePage(s.cb, name, r.range);
  const own = s.cb === servedCodebase().cb;
  return (
    <StudioFrame tab="packages" title={`${name} · packages`}>
      <div className="crumbs">
        <a href={at("/packages")}>Packages</a> <span className="muted">/</span>
      </div>
      <div className="page cols-2">
        <div>
          <div className="pagehead">
            <h2 className="title mono">{name}</h2>
            <span className="muted">{`range ${p.range}, locked at ${p.version}`}</span>
            {own && (
              <span className="right">
                <UpgradeButton name={name} />
              </span>
            )}
          </div>
          {p.description && (
            <p className="lede" style={{ marginBottom: 14 }}>
              {p.description}
            </p>
          )}
          {p.readme && (
            <div className="box">
              <div className="boxhead">
                <b>README</b>
              </div>
              <Html className="boxbody md" html={markdownHtml(s.cb, p.readme)} />
            </div>
          )}
          <div className="box">
            <div className="boxhead">
              <b>API</b>
              <span className="count">{p.api.length}</span>
            </div>
            {p.api.length ? (
              p.api.map((e) => (
                <div className="relline apiline" key={e.name}>
                  <Fold
                    head={
                      <>
                        <b className="mono">{e.name}</b>
                        <span className="muted">{e.kind}</span>
                        {e.doc && <span className="relsum muted">{e.doc.split("\n")[0]}</span>}
                      </>
                    }
                  >
                    <Html className="boxbody apisig" html={`<pre class="code">${e.html}</pre>`} />
                    {e.doc.includes("\n") && (
                      <div className="boxbody md" style={{ paddingTop: 0 }}>
                        {e.doc}
                      </div>
                    )}
                  </Fold>
                </div>
              ))
            ) : (
              <div className="empty">Nothing it exports could be read.</div>
            )}
          </div>
        </div>
        <aside className="side">
          <div className="sect">
            <h4>Used by</h4>
            {p.users.length ? (
              p.users.map((u) => (
                <div key={u.path}>
                  <a className="mono" href={codeHref(u.path)}>
                    {u.path}
                  </a>
                </div>
              ))
            ) : (
              <span className="muted">Nothing named.</span>
            )}
          </div>
          <div className="sect">
            <h4>About it</h4>
            <dl className="kv">
              {p.license && (
                <>
                  <dt>license</dt>
                  <dd>{p.license}</dd>
                </>
              )}
              {p.homepage && (
                <>
                  <dt>homepage</dt>
                  <dd>
                    <a href={p.homepage} target="_blank" rel="noreferrer">
                      {p.homepage.replace(/^https?:\/\//, "")}
                    </a>
                  </dd>
                </>
              )}
              {p.types && (
                <>
                  <dt>types</dt>
                  <dd className="mono">{p.types}</dd>
                </>
              )}
              {p.integrity && (
                <>
                  <dt>tarball</dt>
                  <dd className="mono" title={p.integrity}>
                    {`${p.integrity.slice(0, 20)}…`}
                  </dd>
                </>
              )}
            </dl>
          </div>
          {p.otherRanges.length > 0 && (
            <div className="sect">
              <h4>Other ranges</h4>
              {p.otherRanges.map((o) => (
                <div key={o}>
                  <a
                    href={at(
                      `/packages/${encodeURIComponent(name)}?range=${encodeURIComponent(o)}`,
                    )}
                  >
                    {o}
                  </a>
                </div>
              ))}
            </div>
          )}
        </aside>
      </div>
    </StudioFrame>
  );
}

uses

used by