ContributionsPage

tcmts.share.ContributionsPage · #pkfxcnrj · term · runs on the server

is an async component

The contributions: open ones, or merged, closed or all of them.

import {
  ago, at, Avatar, contributionHref, Frame, isEvent, NavTabs, shareNow, StateBadge,
} from "#codebase/tcmts/share";

export async function ContributionsPage({ state }: { state: string }) {
  const s = shareNow();
  if (!s.signedIn) return <Frame tab="contributions" title="Sign in" children={null} />;
  const which = ["open", "merged", "closed", "all"].includes(state) ? state : "open";
  const all = s.cb.store.contributions();
  const shown = (which === "all" ? all : all.filter((c) => c.status === which)).sort((a, b) => b.updated - a.updated);
  const n = (st: string) => all.filter((c) => c.status === st).length;
  return (
    <Frame tab="contributions" title="Contributions">
      <div className="narrow">
        <div className="filters">
          <h2 className="title" style={{ marginRight: 12 }}>
            Contributions
          </h2>
          <NavTabs
            label="Contributions by state"
            selected={which}
            tabs={[
              { id: "open", label: "Open", href: at("/contributions?state=open"), count: n("open") },
              { id: "merged", label: "Merged", href: at("/contributions?state=merged"), count: n("merged") },
              { id: "closed", label: "Closed", href: at("/contributions?state=closed"), count: n("closed") },
              { id: "all", label: "All", href: at("/contributions?state=all"), count: all.length },
            ]}
          />
        </div>
        <div className="box">
          {shown.length ? (
            shown.map((c) => {
              const comments = s.cb.store.comments(c.id).filter((k) => !isEvent(k)).length;
              return (
                <div className="lrow" key={c.id}>
                  <div>
                    <a href={contributionHref(c.id)}>
                      <b>{c.title}</b>
                    </a>{" "}
                    <StateBadge c={c} />
                    <div className="muted" style={{ fontSize: 13 }}>
                      #{c.id} · <code>{c.source}</code> → <code>{c.target}</code> · <Avatar name={c.author} /> {c.author} · updated {ago(c.updated)}
                    </div>
                  </div>
                  <span className="muted">{comments ? `💬 ${comments}` : ""}</span>
                </div>
              );
            })
          ) : (
            <div className="empty">
              None {which === "all" ? "yet" : which}. <code>tcm contribute</code> proposes a branch.
            </div>
          )}
        </div>
        <div className="notice">
          <b>Proposing a change:</b> make a branch, change it, then <code>tcm contribute --title "…"</code>. It's pushed here
          {s.caller.role === "contributor" ? (
            <>
              {" "}
              as <code>{`@${s.caller.handle}/<branch>`}</code>
            </>
          ) : null}{" "}
          and reviewed on its page, definition by definition.
        </div>
      </div>
    </Frame>
  );
}

uses

used by