All files / src/components/projects project-status.ts

100% Statements 3/3
100% Branches 2/2
100% Functions 1/1
100% Lines 3/3

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72                                                                15x                               326x                                 15x            
/**
 * The one place a project status becomes a printed code.
 *
 * A status is a printed code, never a pill — `.context/mockups/_base.css`
 * §7.2. `projects-list.html` prints `published` as **LIVE** on success ink,
 * `draft` as **DRAFT** on warning ink and `archived` as **ARCHIVED** on
 * graphite (`--sc-ink: var(--foreground-muted)`, `--sc-tint:
 * var(--background-muted)`), which is `StatusBadge`'s `default` tone.
 *
 * WHY THE TONE IS PASSED EXPLICITLY
 * `status-badge.tsx` keeps a word-list fallback that maps `"archived"` to the
 * `error` family, and its own header says re-tagging a status is "a product
 * decision for the page PRs, not a side effect of a contrast fix". This is
 * that PR: the mockup is the specification, the mockup prints an archived
 * project in graphite, so every project surface reads its tone from here and
 * passes it. No new status vocabulary is introduced — three stored statuses,
 * three printed codes, one table.
 */
 
import type { StatusTone } from "../ui/status-ink";
 
/** The three values `projects.status` can hold. */
export type ProjectStatus = "draft" | "published" | "archived";
 
/** The printed code for one stored status. */
export interface ProjectStatusCode {
	/** What the code prints. Caps are applied by `StatusBadge`'s `.label` type. */
	label: string;
	/** Which ink family it is printed in. */
	tone: StatusTone;
}
 
const PROJECT_STATUS_CODES: Record<ProjectStatus, ProjectStatusCode> = {
	published: { label: "Live", tone: "success" },
	draft: { label: "Draft", tone: "warning" },
	archived: { label: "Archived", tone: "default" },
};
 
/**
 * The printed code for a project status.
 *
 * Takes a `string` rather than `ProjectStatus` because the API type is widened
 * at several call sites (`Project["status"]` arrives as `string` through the
 * admin adapter). An unknown status falls back to the draft code rather than
 * rendering an empty chip — a project with a status we cannot read is still a
 * row the pro has to be able to see.
 */
export function projectStatusCode(status: string): ProjectStatusCode {
	return (
		PROJECT_STATUS_CODES[status as ProjectStatus] ?? PROJECT_STATUS_CODES.draft
	);
}
 
/** One facet on the projects list: a `.label` code and the status it filters. */
export interface ProjectStatusFacet {
	/** `""` is the All facet — no status filter at all. */
	value: "" | ProjectStatus;
	label: string;
}
 
/**
 * The facet row, in the mockup's order: `ALL 12  LIVE 8  DRAFT 3  ARCHIVED 1`.
 * Archived is present here on purpose — it is excluded from the *default*
 * selection, not from the list, which is why unarchive used to be unreachable.
 */
export const PROJECT_STATUS_FACETS: readonly ProjectStatusFacet[] = [
	{ value: "", label: "All" },
	{ value: "published", label: "Live" },
	{ value: "draft", label: "Draft" },
	{ value: "archived", label: "Archived" },
] as const;