@atelic-action/artifact 4.2.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -17
- package/package.json +4 -4
- package/src/documents/FirstCall.tsx +6 -6
- package/src/documents/Note.tsx +2 -2
- package/src/documents/Report.tsx +2 -2
- package/src/documents/{Read.tsx → TheRead.tsx} +251 -76
- package/src/documents/{Writeup.tsx → Topic.tsx} +59 -362
- package/src/documents/documents.css +35 -34
- package/src/documents/index.ts +24 -2
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
The documents the practice hands or sends a business, as a published package and as the site a business's folder is cut from. This repo is two things at once:
|
|
4
4
|
|
|
5
|
-
- **The package**, `@atelic-action/artifact` on npm: the composed documents (the
|
|
5
|
+
- **The package**, `@atelic-action/artifact` on npm: the composed documents (the read, the monthly page, the note, the first call sheet, and the sealed document), each with its prop types and its default labels, and the stylesheet they wear. It ships `src/documents/` and nothing else, as source, the way `@atelic-action/ui` does, and depends on that package for every piece a document is built from.
|
|
6
6
|
- **The seed**: the routes, the content stubs, the config, the stub files the host finds by path, and the tests a new folder of `atelic-action/artifacts` is cut from, and the template site that shows every document on fictional content.
|
|
7
7
|
|
|
8
8
|
Three layers, each a version the next depends on (ATE-671): `@atelic-action/ui` holds the pieces, this package holds the documents built from them, and each business's folder holds only its content, routes, and config. A document fix reaches a folder by bumping this package; a piece fix by bumping ui here, then this package in the folder.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Five artifacts live in the template site: the **read** at `/the-read`, the graded document a business gets from the practice, built from one snapshot at one of two depths (a prospect's, from public readings alone; a customer's, from their own consoles as well), a web page first with its printed copy derived from it, the grades explained by cause with the plan in order between the scorecard and the cards; the **proposal** at `/proposal`, sealed into the page and opened by the reader's own email address; the **monthly page** at `/report`, what an Operate client gets each month on one letter sheet; the **note** at `/notes`, the first touch for a business whose site publishes no email address, set as a short page; and the **first call sheet** at `/first-call`, the desk's page for the first call with a business that booked off a cold first touch, used to guide the call and not sent for now, written so it could be shared with them later. The bare host sends a reader to the read. Every artifact prerenders to static HTML, stays out of every index, and carries the practice's brand by default.
|
|
11
11
|
|
|
12
12
|
The method behind them (the seven sections, the four grades from A to D, the rented line, what moved, and when an artifact is private) is the practice repo's `FOOTPRINT.md`. This repo builds to it and never restates it.
|
|
13
13
|
|
|
@@ -21,19 +21,18 @@ Every export of the package, all from the one entry, `@atelic-action/artifact`.
|
|
|
21
21
|
|
|
22
22
|
| Export | What it is | Route |
|
|
23
23
|
|---|---|---|
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
31
|
-
| `ReadTier`, `ReadSection`, `ReadChange`, `ReadStep`, `ReadPlan`, `ReadClose`, `ReadLink`, `ReadParagraph` | The shapes a read's content is written in. `ReadSection` is a `WriteupTopic` plus `gist`, `changes`, and `recommend`; its `why` and a finding's `body` take a paragraph (a string, or runs of text and links) as well as a node, so a routine can still write a read as JSON | none |
|
|
24
|
+
| `TheRead`, `TheReadProps` | The graded document a business gets, built from one snapshot: the dated lede; the scorecard, a `ReportCard` with each row a link to its card and the earlier letter beside a row that moved, with an optional `note` callout over it for what the read leaves out; the plan, numbered and in order, between the scorecard and the cards, so the whole program reads before any one card's detail; then the tiers, each section on the card (the trade name linked to its definition, the one liner, the grade, the why line as the summary, the blocks, and the sources at the foot) plus the read's own today and after (a two column table) and what we recommend (a checklist), a tier opening on a `markets` table of letters and closing on the `rented` line when it has them; the closing line and the sign off. `access` says which depth it is (`"public"`, from public readings alone, or `"private"`, from the owner's consoles too), and a public read with no note gets the `publicNote` label over its scorecard. `print` adds the lockup and the twin's QR to the printed copy. A beat with no data is left out | `/the-read` |
|
|
25
|
+
| `readLabels`, `ReadLabels` | The fixed words the read sets (Prepared for, the scorecard's screen reader words, Before, Rented, Today, After, Recommendations, the plan's heading, the public note), each overridable through `labels` | `/the-read` |
|
|
26
|
+
| `ReadAccess`, `ReadTier`, `ReadSection`, `ReadChange`, `ReadRecommendation`, `ReadMarkets`, `ReadMarketRow`, `ReadRented`, `ReadStep`, `ReadPlan`, `ReadClose`, `ReadPrint`, `ReadLink`, `ReadParagraph` | The shapes a read's content is written in. `ReadSection` is a `ReadTopic` plus `gist`, `before`, `changes`, and `recommend`; its `why`, a finding's `body`, a market row's `read`, and the rented `text` take a paragraph (a string, or runs of text and links) as well as a node, so a routine can write a read as JSON | none |
|
|
27
|
+
| `Topic` | The section card on its own: the trade name linked to its definition, the one liner, the grade, the why line, the blocks, and the sources, with an `extra` slot after the blocks. The read renders every section through it | `/the-read` |
|
|
28
|
+
| `ratingCell` | A star rating table cell for a `table` block, sorted by its figure | `/the-read` |
|
|
29
|
+
| `ReadTopic`, `ReadBlock`, `ReadInnerBlock`, `ReadChecks`, `ReadTable`, `ReadBar`, `ReadScale`, `ReadStats`, `ReadColumns`, `ReadFindings`, `ReadShots`, `ReadMore`, `ReadBullet`, `ReadSource`, `ReadMark`, `ReadCell`, `ReadSorted`, `ReadTone` | The shapes a section card and its blocks are written in | none |
|
|
30
|
+
| `WriteupGrade`, `WriteupPerson`, `WriteupShot` | The grade letter, the sign off person, and the owner's screen, shared by every document, all three re exported from ui under ui's names | none |
|
|
32
31
|
| `Report`, `ReportProps` | The monthly page: the four questions, the seven grades now and before, the sign off, on one letter sheet | `/report` |
|
|
33
32
|
| `ReportLead`, `ReportLeads`, `ReportGradeRow` | The shapes a monthly page's content is written in | none |
|
|
34
33
|
| `Note`, `NoteProps` | The first touch set as a page: the opener, two lanes of findings, where the work would start, the close | `/notes` |
|
|
35
34
|
| `NoteLane`, `NoteFinding`, `NoteStart`, `NoteStep`, `NoteClose`, `NoteLink`, `NoteParagraph` | The shapes a note's content is written in | none |
|
|
36
|
-
| `FirstCall`, `FirstCallProps` | The desk's sheet for the first call with a business that booked off a cold first touch: the brief with a picture beside it, the open as numbered steps, one unit per topic (a TL;DR, then show, ask, and move, each show line linked live with its picture opening the full capture), and the close, which always ends on who else decides. Not sent for now, but open like the host and shareable later, so it carries no desk instruction; it lives beside the
|
|
35
|
+
| `FirstCall`, `FirstCallProps` | The desk's sheet for the first call with a business that booked off a cold first touch: the brief with a picture beside it, the open as numbered steps, one unit per topic (a TL;DR, then show, ask, and move, each show line linked live with its picture opening the full capture), and the close, which always ends on who else decides. Not sent for now, but open like the host and shareable later, so it carries no desk instruction; it lives beside the read | `/first-call` |
|
|
37
36
|
| `firstCallLabels`, `FirstCallLabels` | The fixed words the sheet sets (Show, Ask, Move, the close's who else decides beat, and the rest), each overridable through `labels` | `/first-call` |
|
|
38
37
|
| `firstCallSectionIds` | The ids the page takes for itself (the shell's `main`, the brief, the open, the close), which a unit's `id` must not repeat; the content test checks it | none |
|
|
39
38
|
| `FirstCallFact`, `FirstCallStep`, `FirstCallShow`, `FirstCallUnit`, `FirstCallParagraph` | The shapes a first call sheet's content is written in, all plain data, so a skill writes the sheet as JSON | none |
|
|
@@ -49,10 +48,10 @@ What a document is built from stays in `@atelic-action/ui`, and this package imp
|
|
|
49
48
|
bun add @atelic-action/artifact @atelic-action/ui
|
|
50
49
|
```
|
|
51
50
|
|
|
52
|
-
Peer dependencies: `@atelic-action/ui` at `^3.
|
|
51
|
+
Peer dependencies: `@atelic-action/ui` at `^3.4.0`, `react` at `^19.0.0`, and `lucide-react` at `^1.23.0`. The package ships TSX and CSS as source, compiled inside the site's own Vite like ui's; a site whose `vite.config.ts` is one `artifactConfig` call from `@atelic-action/ui/vite` needs nothing more, for the build, the prerender, and the dev server alike. The default labels a document sets live in the document: the read's `readLabels` and the sealed document's gate copy are overridden through props, and the monthly page's four questions are fixed on purpose, since they are its contract with the Statement of Work.
|
|
53
52
|
|
|
54
53
|
```tsx
|
|
55
|
-
import {
|
|
54
|
+
import { TheRead } from "@atelic-action/artifact";
|
|
56
55
|
import { buildPageHead } from "@atelic-action/ui/artifact";
|
|
57
56
|
```
|
|
58
57
|
|
|
@@ -66,7 +65,7 @@ The documents' sheet goes after every ui sheet and before the site's `theme.css`
|
|
|
66
65
|
4. `@atelic-action/artifact/styles/documents.css`
|
|
67
66
|
5. The site's `theme.css`, last
|
|
68
67
|
|
|
69
|
-
Every rule in the sheet sits in the `atelic-ui` layer and under the `.atelic-ui` root class, exactly as ui's sheets do, so any rule a site writes outside a layer still wins over it. The sheet holds two `@page` rules, the monthly page's and then the
|
|
68
|
+
Every rule in the sheet sits in the `atelic-ui` layer and under the `.atelic-ui` root class, exactly as ui's sheets do, so any rule a site writes outside a layer still wins over it. The sheet holds two `@page` rules, the monthly page's and then the read's, and the later one wins for every page a site prints; their order is load bearing.
|
|
70
69
|
|
|
71
70
|
From 1.2.0 the two sheets do not overlap: ui 2.0.0's `artifact.css` holds only the pieces, and this sheet holds only the documents and both `@page` rules. A site on ui 1.x stays on artifact 1.1.x, which carries the shot's rules and the shell's print rules itself.
|
|
72
71
|
|
|
@@ -96,10 +95,10 @@ No environment variables required. Visit [http://localhost:5173](http://localhos
|
|
|
96
95
|
|
|
97
96
|
A business's artifacts live in one folder of `atelic-action/artifacts`, named by the business's short name and served at `<short>.atelic.me` as its own Vercel project with the folder as its root directory, one path per artifact. That host is the business's one address with the practice: the website build, when one is previewed, sits on it at `/proto`, proxied from its own project ([DEPLOY.md](DEPLOY.md), The Website Build Under /proto). Cut it from this one with `git subtree add --prefix=<short> https://github.com/atelic-action/artifact.git main`, run in `artifacts`. A cut is a site, not the package, so it then takes the package from npm instead of carrying its source: delete `src/documents/` and `tst/documents/`, give `package.json` the folder's own name and drop the package's fields (`version`, `files`, `exports`, `sideEffects`, `peerDependencies`), and run `bun add @atelic-action/artifact`. The routes and content already import the documents by the package's name, so nothing else changes. Nothing is pulled forward from here afterward: a document reaches the folder with `bun update @atelic-action/artifact`, and everything else with logic in it is `@atelic-action/ui`'s and arrives with `bun update @atelic-action/ui` ([CLAUDE.md](CLAUDE.md), What a Cut Takes From Here). Delete the artifacts the engagement does not need (the route, the content module, and the prerender entry), then touch four surfaces:
|
|
98
97
|
|
|
99
|
-
1. **Content**, in `src/content/`. One module per artifact: the real read, every number dated and defensible in the room, graded and shaped by the practice's `FOOTPRINT.md` and written to its pitch surface rules (`Brand/voice.md`, Pitch Surfaces 15 to 21). In `
|
|
98
|
+
1. **Content**, in `src/content/`. One module per artifact: the real read, every number dated and defensible in the room, graded and shaped by the practice's `FOOTPRINT.md` and written to its pitch surface rules (`Brand/voice.md`, Pitch Surfaces 15 to 21). In `the-read.tsx`, `access` says whether anything came from the owner's own consoles and the content test holds it to the host's; print flows the page across as many letter pages as it needs, and `theReadStops` names the header's stops.
|
|
100
99
|
2. **Images**, split by what they are. Logos are brand marks and go in `public/brand/` (the recipient's logo, e.g. `public/brand/<name>.svg`), which the access wall leaves open so the header and the login page can draw them. The owner's own screens (the full screenshot for the click through and a tight crop for the column) and the QR for the twin, pointing at the bare host (`qr "https://<short>.atelic.me" > public/images/qr.png` with the `qrcode` package), go in `public/images/`, which the wall holds on a private artifact. A cut made before this split moves its recipient logo from `public/images/` to `public/brand/` and repoints `recipient.logo.src`.
|
|
101
100
|
3. **Config**, in `src/site.config.ts`. `url` is the host, `access` is `"public"` or `"private"` (private when anything came from the owner's own consoles), `recipient` is the business it was prepared for (with its `logo` under `/brand/`), `sender` is the practice, and `analytics` is the HubSpot loader so an open reports to the CRM, with `identify` naming who each link identifies so the open lands on that person's contact (`bun run reader <email>` mints a reader, sealed so no address ships in the page's script, and prints their link; a private artifact needs nobody listed, because the wall identifies whoever signs in; [DEPLOY.md](DEPLOY.md), Who Opened It).
|
|
102
|
-
4. **The printed copy**: `bun build`, then `bun run print dist/client public/
|
|
101
|
+
4. **The printed copy**: `bun build`, then `bun run print dist/client public/the-read.pdf`, which prints with every collapsible open and reports the sheet count, or `bun run print dist/client <out.pdf> 1 /report` for the monthly page, which fails if it misses its one sheet. Commit the read's PDF beside the page, and file a dated copy in the client's folder of the practice repo.
|
|
103
102
|
|
|
104
103
|
A private artifact deploys only behind the armed wall, which holds the screenshots, the PDF, and the built content chunks as well as the pages, and `bun run check:wall <short>.atelic.me` must pass before any link goes out ([ACCESS-GATE.md](ACCESS-GATE.md)).
|
|
105
104
|
|
|
@@ -128,7 +127,7 @@ The theme stays the practice's (Geist, ink, the orange) unless the artifact shou
|
|
|
128
127
|
| `bun build` | Access guard + typecheck + build + prerender every page |
|
|
129
128
|
| `bun test` / `bun test:run` | Tests (watch / once) |
|
|
130
129
|
| `bun lint` / `bun lint:fix` | Biome check / auto fix |
|
|
131
|
-
| `bun run print <url or dist/client> <out.pdf> [sheets] [page]` | Prints a page (the
|
|
130
|
+
| `bun run print <url or dist/client> <out.pdf> [sheets] [page]` | Prints a page (the read unless named) through headless Chrome, reports the sheet count, and checks it when one is given |
|
|
132
131
|
| `bun run check:wall <host> [path ...]` | Proves a private artifact's live host answers every document with the wall |
|
|
133
132
|
| `bun run seal <config.json> [out.json]` | Seals a document for its named readers ([GATE.md](GATE.md)) |
|
|
134
133
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atelic-action/artifact",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "The composed documents the Atelic practice hands or sends a business (the
|
|
3
|
+
"version": "5.0.0",
|
|
4
|
+
"description": "The composed documents the Atelic practice hands or sends a business (the read, the monthly page, the note, the first call sheet, and the sealed document), built from the pieces in @atelic-action/ui",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -37,12 +37,12 @@
|
|
|
37
37
|
"format": "biome format . --write"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@atelic-action/ui": "^3.
|
|
40
|
+
"@atelic-action/ui": "^3.4.0",
|
|
41
41
|
"lucide-react": "^1.23.0",
|
|
42
42
|
"react": "^19.0.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@atelic-action/ui": "^3.
|
|
45
|
+
"@atelic-action/ui": "^3.4.0",
|
|
46
46
|
"@biomejs/biome": "^2.0.0",
|
|
47
47
|
"@playwright/test": "^1.60.0",
|
|
48
48
|
"@sentry/react": "^10.0.0",
|
|
@@ -14,7 +14,7 @@ import type { ReactNode } from "react";
|
|
|
14
14
|
* The first call sheet: what the practice scans during the first call with a
|
|
15
15
|
* business that booked off a cold first touch. The brief, the open, then one
|
|
16
16
|
* unit per topic, each a show, an ask, and a move, then the close. It lives
|
|
17
|
-
* at `<short>.atelic.me/first-call` beside the
|
|
17
|
+
* at `<short>.atelic.me/first-call` beside the read it walks.
|
|
18
18
|
*
|
|
19
19
|
* The practice uses it to guide the call and does not send it for now, but
|
|
20
20
|
* it is open like the rest of the host and may be shared with the business
|
|
@@ -26,8 +26,8 @@ import type { ReactNode } from "react";
|
|
|
26
26
|
* Outreach/discovery.md, The First Call Set, and nothing here restates it.
|
|
27
27
|
* The document owns only the shape.
|
|
28
28
|
*
|
|
29
|
-
* It is the
|
|
30
|
-
*
|
|
29
|
+
* It is the read's sibling and wears its classes: the
|
|
30
|
+
* read's topic and findings blocks for the brief and each unit's show,
|
|
31
31
|
* the read's numbered steps for the open and the close. Its own few rules
|
|
32
32
|
* sit under fc- in documents.css. Every prop is plain data, so a skill can
|
|
33
33
|
* write a sheet as JSON. The close always ends on who else decides, the one
|
|
@@ -37,7 +37,7 @@ import type { ReactNode } from "react";
|
|
|
37
37
|
/** A paragraph: a plain string, or runs of text and links in order. */
|
|
38
38
|
export type FirstCallParagraph = ArtifactParagraph;
|
|
39
39
|
|
|
40
|
-
/** One line of the brief: who, how they booked, the listing, the
|
|
40
|
+
/** One line of the brief: who, how they booked, the listing, the read. */
|
|
41
41
|
export interface FirstCallFact {
|
|
42
42
|
label: string;
|
|
43
43
|
body: FirstCallParagraph;
|
|
@@ -151,7 +151,7 @@ function Steps({ steps }: { steps: FirstCallStep[] }) {
|
|
|
151
151
|
);
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
/** The
|
|
154
|
+
/** The read's findings block: the callouts down the left, the pictures to the right. */
|
|
155
155
|
function Findings({
|
|
156
156
|
items,
|
|
157
157
|
shots,
|
|
@@ -159,7 +159,7 @@ function Findings({
|
|
|
159
159
|
}: {
|
|
160
160
|
items: ReactNode[];
|
|
161
161
|
shots: WriteupShot[];
|
|
162
|
-
/** The block itself, as the
|
|
162
|
+
/** The block itself, as the read sets it, rather than inside a block under its heading. */
|
|
163
163
|
block?: boolean;
|
|
164
164
|
}) {
|
|
165
165
|
const classes = [block && "op-block", "op-findings", shots.length > 0 && "has-shots"];
|
package/src/documents/Note.tsx
CHANGED
|
@@ -19,8 +19,8 @@ import { Callout } from "@atelic-action/ui/components";
|
|
|
19
19
|
* what sits under the hood, where the work would start, and the close. It
|
|
20
20
|
* reads on a phone first and prints to one letter sheet.
|
|
21
21
|
*
|
|
22
|
-
* It is the
|
|
23
|
-
* ArtifactShell exactly as it wraps the
|
|
22
|
+
* It is the read's sibling, not a variant of it: a site wraps it in
|
|
23
|
+
* ArtifactShell exactly as it wraps the read, and it reuses the read's
|
|
24
24
|
* pieces where they fit (the Callout a finding is set in, the owner's screen,
|
|
25
25
|
* the sign off). Every prop is plain data, so a routine can write a note as
|
|
26
26
|
* JSON; the one exception is the sign off person's `role`, which takes a node
|
package/src/documents/Report.tsx
CHANGED
|
@@ -13,7 +13,7 @@ import type { ReactNode } from "react";
|
|
|
13
13
|
* the leads block answering the four questions the Statement of Work
|
|
14
14
|
* promises, in that order, each a figure and one plain sentence; then the
|
|
15
15
|
* seven grades with what moved since last month and since the baseline; then
|
|
16
|
-
* the sign off. It wears the
|
|
16
|
+
* the sign off. It wears the read's grade chip and sign off, and the
|
|
17
17
|
* artifact shell's header on screen; print drops the header and the credit
|
|
18
18
|
* band, so the sheet is the document alone.
|
|
19
19
|
*/
|
|
@@ -55,7 +55,7 @@ export interface ReportProps {
|
|
|
55
55
|
leads: ReportLeads;
|
|
56
56
|
/** The seven sections, in the footprint's order. */
|
|
57
57
|
grades: ReportGradeRow[];
|
|
58
|
-
/** The sign off, the same lockup the
|
|
58
|
+
/** The sign off, the same lockup the read closes on. */
|
|
59
59
|
close: { signOff: string; person: WriteupPerson };
|
|
60
60
|
}
|
|
61
61
|
|