PeoplePage

tcmts.share.PeoplePage · #u4mjhieo · term · runs on the server

is an async component

Who works on the codebase here: its maintainer and the contributors the maintainer has added, with what each has done here; and how to become one.

import { ago, at, Avatar, CopyButton, Frame, shareNow } from "#codebase/tcmts/share";

export async function PeoplePage() {
  const s = shareNow();
  if (!s.signedIn) return <Frame tab="people" title="Sign in" children={null} />;
  const all = s.cb.store.contributions();
  const count = (n: number, one: string, many = `${one}s`) => (
    <span>
      <b>{n}</b> {n === 1 ? one : many}
    </span>
  );
  return (
    <Frame tab="people" title="People">
      <div className="narrow">
        <div className="filters" style={{ marginBottom: 14 }}>
          <h2 className="title">People</h2>
          <span className="right muted">
            the maintainer{s.users.length ? ` and ${s.users.length} contributor${s.users.length === 1 ? "" : "s"}` : ""}
          </span>
        </div>
        <div className="box people">
          <div className="person">
            <Avatar name="maintainer" large />
            <div>
              <b>Maintainer</b>
              <div className="what">Holds the server's token: pushes any branch, merges contributions, makes releases.</div>
            </div>
            <div className="stats">
              {count(all.filter((c) => c.status === "merged").length, "merged", "merged")}
              {count(s.cb.store.releases().length, "release")}
            </div>
          </div>
          {s.users.map((u) => {
            const theirs = all.filter((c) => c.author === `@${u.handle}`);
            const open = theirs.filter((c) => c.status === "open").length;
            return (
              <div className="person" key={u.handle}>
                <Avatar name={u.handle} large />
                <div>
                  <b>{`@${u.handle}`}</b>
                  <span className="pill">contributor</span>
                  <div className="what">
                    Added {ago(u.added)} · pushes branches under <code>{`@${u.handle}/`}</code>
                  </div>
                </div>
                <div className="stats">
                  {count(theirs.length, "contribution")}
                  {open ? count(open, "open", "open") : null}
                </div>
              </div>
            );
          })}
        </div>
        <div className="box">
          <div className="boxhead">
            <b>Contribute</b>
            <span className="muted">changes are proposed here and reviewed definition by definition</span>
          </div>
          <div className="boxbody">
            <ol className="howto">
              <li>
                <span>
                  Ask the maintainer for a token. They make one with <code>tcm user add &lt;your handle&gt;</code>.
                </span>
              </li>
              <li>
                <span>Point your codebase at this server with it:</span>
                <div className="cmd">
                  <pre className="code">{`tcm remote add origin ${s.origin} --token <token>`}</pre>
                  <CopyButton text={`tcm remote add origin ${s.origin} --token `} label="Copy" />
                </div>
              </li>
              <li>
                <span>
                  Make a branch, change it, and propose it. It's pushed as <code>@&lt;handle&gt;/&lt;branch&gt;</code> and
                  listed under <a href={at("/contributions")}>Contributions</a>.
                </span>
                <div className="cmd">
                  <pre className="code">tcm contribute --title "…"</pre>
                </div>
              </li>
            </ol>
          </div>
        </div>
      </div>
    </Frame>
  );
}

uses

used by