61 lines · 2.6 KB
import { issueStateTone } from "~/ui/tones";
import { createFileRoute, Link } from "@tanstack/react-router";
import { getMilestone } from "~/fns/milestones";
import { ProgressBar } from "~/components/ProgressBar";
import { Badge } from "~/ui/Badge";
import { EmptyState } from "~/ui/EmptyState";
import { Markdown } from "~/ui/Markdown";
import { Panel } from "~/ui/Panel";
import { RelativeTime } from "~/ui/RelativeTime";
import { Heading } from "~/ui/Heading";

export const Route = createFileRoute("/$owner/$repo/milestones/$id")({
  loader: ({ params }) => getMilestone({ data: { owner: params.owner, repo: params.repo, id: params.id } }),
  component: MilestonePage,
});

function MilestonePage() {
  const { milestone, issues } = Route.useLoaderData();
  const params = Route.useParams();
  return (
    <div className="space-y-5">
      <header className="space-y-3 border-b border-kumo-hairline pb-4">
        <div className="flex items-center gap-3">
          <Heading size="xl">{milestone.title}</Heading>
          <Badge tone={issueStateTone(milestone.state)}>{milestone.state}</Badge>
        </div>
        <p className="text-sm text-kumo-subtle">
          {milestone.dueOn ? `Due ${new Date(milestone.dueOn).toLocaleDateString()}` : "No due date"}
        </p>
        <div className="max-w-md">
          <ProgressBar done={milestone.closedCount} total={milestone.openCount + milestone.closedCount} />
        </div>
        {milestone.description && <Markdown html={milestone.html} />}
      </header>
      <Panel title={`${issues.length} items`}>
        {issues.length === 0 ? (
          <EmptyState title="Nothing in this milestone yet" icon="milestone" />
        ) : (
          <ul className="divide-y divide-kumo-hairline">
            {issues.map((issue) => (