@supertype.ai/foundations 0.1.26 → 0.1.28
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 +27 -49
- package/dist/seo.d.ts +4 -2
- package/dist/seo.js +14 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
# @supertype.ai/foundations
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
[](https://github.com/supertypeai/foundations/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@supertype.ai/foundations)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
[The foundations philosophy](https://supertypeai.github.io/foundations/philosophy/) lays out the Raison d'être better, but the crux is that it is a reusable design system that binds typography primitives, content blocks, the long-form essay shell, the token and theme CSS, and the build-time tooling that keep baseline quality high (SEO, OG cards, lint rules, contrast
|
|
8
|
+
checks) in a single package. Used by Supertype's own projects like [Viably work operating system](https://viably.app) and [supertype.ai](https://supertype.ai), it is also MIT-licensed and available for any Next.js 15+ project built atop Tailwind and Shadcn.
|
|
7
9
|
|
|
8
10
|
```sh
|
|
9
11
|
yarn add @supertype.ai/foundations
|
|
10
12
|
```
|
|
11
13
|
|
|
12
|
-
**Start here:** [Install](#install)
|
|
14
|
+
**Start here:** [Install](#install), then [Your first page](#your-first-page).
|
|
13
15
|
|
|
14
16
|
**Reference:** [Typography](docs/typography.md) · [Blocks](docs/blocks.md) ·
|
|
15
17
|
[The essay shell](docs/essay.md) · [Build-time tooling](docs/tooling.md) ·
|
|
@@ -18,18 +20,18 @@ yarn add @supertype.ai/foundations
|
|
|
18
20
|
**Working on the package itself:** [Contributing](docs/contributing.md), for
|
|
19
21
|
local iteration against a consumer and for releasing.
|
|
20
22
|
|
|
23
|
+
Like the project? ⭐ Star it on [GitHub](https://github.com/supertypeai/foundations)
|
|
24
|
+
|
|
21
25
|
## See it running
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
Check out: [the documentation site](https://supertypeai.github.io/foundations/), or alternatively run the example site locally:
|
|
24
28
|
|
|
25
29
|
```sh
|
|
26
30
|
yarn example:install # once, to install Next, the peers and the package
|
|
27
31
|
yarn example # then open http://localhost:3000
|
|
28
32
|
```
|
|
29
33
|
|
|
30
|
-
[`examples/site`](examples/site) renders every component along with the code, and include whole-page [recipes](examples/site/app/_recipes) to copy into your project
|
|
31
|
-
|
|
32
|
-
## Alternatively, check out: [the documentation site](https://supertypeai.github.io/foundations/)
|
|
34
|
+
[`examples/site`](examples/site) renders every component along with the code, and include whole-page [recipes](examples/site/app/_recipes) to copy into your project. Comes with the `dark` and `.editorial` switches.
|
|
33
35
|
|
|
34
36
|
## Initialization and Diagnostics
|
|
35
37
|
|
|
@@ -41,9 +43,7 @@ npx @supertype.ai/foundations doctor # checks this app against everything bel
|
|
|
41
43
|
```
|
|
42
44
|
|
|
43
45
|
`init` edits one file: the CSS entry that imports Tailwind. It adds the imports
|
|
44
|
-
you are missing and reorders anything that is out of place. Run it with `--dry-run` first to see the patch. Everything else it
|
|
45
|
-
prints for you to paste — the font binding, and the `llms.txt` line for a coding
|
|
46
|
-
agent.
|
|
46
|
+
you are missing and reorders anything that is out of place. Run it with `--dry-run` first to see the patch. Everything else it prints for you to paste (the font binding, and the `llms.txt` lines for a coding agent).
|
|
47
47
|
|
|
48
48
|
The steps performed by `init` are written out below anyway. See [the CLI](docs/cli.md) for the full list of checks and details.
|
|
49
49
|
|
|
@@ -65,7 +65,7 @@ untagged git dependency re-resolves to a different commit on any fresh install.
|
|
|
65
65
|
|
|
66
66
|
```jsonc
|
|
67
67
|
// package.json
|
|
68
|
-
"@supertype.ai/foundations": "https://github.com/supertypeai/foundations.git#v0.1.
|
|
68
|
+
"@supertype.ai/foundations": "https://github.com/supertypeai/foundations.git#v0.1.28"
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
</details>
|
|
@@ -89,8 +89,7 @@ default, so without it every class is purged and the components
|
|
|
89
89
|
render with no styles at all.
|
|
90
90
|
|
|
91
91
|
**`theme.css` is required.** `tokens.css` names the colour roles; `theme.css` is
|
|
92
|
-
what gives them values. Without it
|
|
93
|
-
resolves to nothing, so the page renders unpainted with no error. It also carries
|
|
92
|
+
what gives them values. Without it color utility can't be resolved, so the page renders unpainted with no error. It also carries
|
|
94
93
|
`--secondary-ink`, `--subtle-foreground`, the four earth tones the marker
|
|
95
94
|
highlight uses, and the `accordion-down` and `accordion-up` keyframes. Skip it
|
|
96
95
|
only if you declare every role yourself; `foundations doctor` fails when neither
|
|
@@ -114,9 +113,7 @@ const serif = Average({ variable: "--font-average", weight: "400", subsets: ["la
|
|
|
114
113
|
```
|
|
115
114
|
|
|
116
115
|
**Bind with `.variable`, never `.className`.** A className sets `font-family` on
|
|
117
|
-
the element itself and leaves the roles unresolved,
|
|
118
|
-
typeface while every `font-sans` and `font-heading` utility on it renders
|
|
119
|
-
another.
|
|
116
|
+
the element itself and leaves the roles unresolved, causing a mismatch where the page renders one typeface while every `font-sans` and `font-heading` utility on it renders another.
|
|
120
117
|
|
|
121
118
|
### 4. Check the wiring
|
|
122
119
|
|
|
@@ -195,8 +192,7 @@ Two rules cover most of the API:
|
|
|
195
192
|
`text-sm text-muted-foreground` is `<TypographyMuted>`. Using the primitives
|
|
196
193
|
keeps a size and a colour from drifting apart across a few hundred call sites.
|
|
197
194
|
- **Retune with CSS variables, not classes.** The package owns its own
|
|
198
|
-
classnames. Change a `--text
|
|
199
|
-
everything moves together.
|
|
195
|
+
classnames. Change a `--text-*`, `--heading-weight`, or a colour specification in `theme.css` to retune the whole package. Read [Tokens and theming](#tokens-and-theming) for full instructions.
|
|
200
196
|
|
|
201
197
|
---
|
|
202
198
|
|
|
@@ -205,18 +201,13 @@ Two rules cover most of the API:
|
|
|
205
201
|
`yarn example` (above) builds the package, syncs it in and starts the dev
|
|
206
202
|
server. `yarn example:build` is what CI would run.
|
|
207
203
|
|
|
208
|
-
It installs the package from a git tag rather than from the registry
|
|
209
|
-
|
|
210
|
-
it with `yarn sync`, with no workspace and no symlink. Its `global.css`
|
|
211
|
-
and `layout.tsx` are the blocks above, unchanged, so an install instruction that
|
|
212
|
-
stops being true breaks the site.
|
|
204
|
+
It installs the package from a git tag rather than from the registry and updates
|
|
205
|
+
it with `yarn sync`.
|
|
213
206
|
|
|
214
207
|
`/recipes` holds whole pages rather than single components: a marketing hero, a
|
|
215
|
-
metrics panel, pricing tiers, a docs page, an article index, and
|
|
216
|
-
that wire up MDX. Each one lives in
|
|
208
|
+
metrics panel, pricing tiers, a docs page, an article index, and examples of MDX-rendered pages. Each one lives in
|
|
217
209
|
[`app/_recipes/`](examples/site/app/_recipes) as a complete file that imports
|
|
218
210
|
only from this package, so you can paste it into your app and it compiles.
|
|
219
|
-
`yarn example:build` fails if a recipe reaches for a local helper.
|
|
220
211
|
|
|
221
212
|
---
|
|
222
213
|
|
|
@@ -253,15 +244,6 @@ package.
|
|
|
253
244
|
| `./tokens.css` `./theme.css` `./type.css` `./prose.css` `./shiki.css` | the style layer | [Tokens and theming](#tokens-and-theming) |
|
|
254
245
|
| `foundations` (bin) | `init` and `doctor` | [The CLI](docs/cli.md) |
|
|
255
246
|
|
|
256
|
-
The entries are split by what they pull in. Blocks and the MDX map stay out of
|
|
257
|
-
the root barrel so that importing a heading does not resolve `@base-ui/react` or
|
|
258
|
-
`next/image`, and `/rehype` and `/contrast` stay out of both so they can run in
|
|
259
|
-
bare Node, where React cannot be resolved.
|
|
260
|
-
|
|
261
|
-
None of the entry points can be imported from plain Node, though: typography
|
|
262
|
-
reaches `next/link` through `next-view-transitions`. Import them from a Next app,
|
|
263
|
-
or from a test runner that resolves Next — both consumers' vitest suites do.
|
|
264
|
-
|
|
265
247
|
---
|
|
266
248
|
|
|
267
249
|
## Tokens and theming
|
|
@@ -274,18 +256,18 @@ only ever one palette in play.
|
|
|
274
256
|
|
|
275
257
|
Each status hue ships twice, on the same rule as the categorical tints:
|
|
276
258
|
`--success`, `--warn` and `--info` are **fills**, held to 3:1 against the page
|
|
277
|
-
and a card
|
|
259
|
+
and a card; `--success-ink`,
|
|
278
260
|
`--warn-ink` and `--info-ink` are the same hues as **text**, held to 4.5:1.
|
|
279
261
|
`--danger` ships as an ink only. `--destructive` keeps shadcn's shape, where
|
|
280
262
|
`--destructive-foreground` is the label printed on the fill — that is what
|
|
281
263
|
`-foreground` means throughout, and `-ink` means the hue used as words.
|
|
282
|
-
`checkSignals` in `@supertype.ai/foundations/contrast` measures all
|
|
264
|
+
`checkSignals` in `@supertype.ai/foundations/contrast` measures all of them and fails if any are below the threshold.
|
|
283
265
|
|
|
284
266
|
`tokens.css` also binds the `dark:` variant to the `.dark` class. Do not skip
|
|
285
267
|
that import: Tailwind v4 otherwise follows the OS setting and quietly ignores
|
|
286
268
|
your toggle.
|
|
287
269
|
|
|
288
|
-
`theme.css` gives those roles the
|
|
270
|
+
`theme.css` gives those roles the latte and espresso palette, and adds the
|
|
289
271
|
editorial inks (`--secondary-ink`, `--subtle-foreground`, and the ochre,
|
|
290
272
|
terracotta, sage and fig pairs) along with the elevation shadows.
|
|
291
273
|
|
|
@@ -306,25 +288,21 @@ than patching the utilities:
|
|
|
306
288
|
|
|
307
289
|
`type.css` names three font roles (`--font-sans`, `--font-mono` and
|
|
308
290
|
`--font-heading`) and the weight that goes with the heading face. `.editorial`
|
|
309
|
-
gives the heading role to the serif and drops the weight to 400
|
|
310
|
-
only has one:
|
|
291
|
+
gives the heading role to the serif and drops the weight to 400.
|
|
311
292
|
|
|
312
293
|
```tsx
|
|
313
294
|
<div className="editorial">…</div> {/* or on <html> for an editorial site */}
|
|
314
295
|
```
|
|
315
296
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
surfaces set body at different sizes: 13px in the product, 18px on `.editorial`. Scope the
|
|
319
|
-
class to whichever surfaces should be editorial, whether that is a marketing and
|
|
320
|
-
docs section or the whole site.
|
|
297
|
+
Heading sizes are a _ratio_ to the body text under them, and the two
|
|
298
|
+
surfaces set body at different sizes: 13px in the product, 18px on `.editorial`. Scope the class to whichever surfaces should be editorial, whether that is a marketing and docs section or the whole site.
|
|
321
299
|
|
|
322
300
|
---
|
|
323
301
|
|
|
324
302
|
## Design rules
|
|
325
303
|
|
|
326
304
|
1. **The package owns its final classnames.** Retune with CSS custom properties
|
|
327
|
-
(the `--text
|
|
305
|
+
(the `--text-*`, `--heading-weight`, the colour tokens) rather than by
|
|
328
306
|
patching classes. A property the package declares is read by the package —
|
|
329
307
|
`test/tokens-live.test.ts` fails on one that is not, because a knob that
|
|
330
308
|
turns nothing is worse than no knob at all.
|
|
@@ -351,7 +329,7 @@ Sites running the package:
|
|
|
351
329
|
- [supertype.ai](https://supertype.ai) — Supertype, a regional-leading analytics engineering and data science consulting firm.
|
|
352
330
|
- [viably.app](https://viably.app) — Viably, an observability-first business operating system and CRM for automation-obsessed teams.
|
|
353
331
|
|
|
354
|
-
|
|
332
|
+
## 
|
|
355
333
|
|
|
356
334
|
## License
|
|
357
335
|
|
package/dist/seo.d.ts
CHANGED
|
@@ -76,9 +76,10 @@ export declare function createSeo(config: SeoConfig): {
|
|
|
76
76
|
"@type": string;
|
|
77
77
|
url: string;
|
|
78
78
|
} | undefined;
|
|
79
|
-
"@type": string;
|
|
80
79
|
name: string;
|
|
81
80
|
url: string;
|
|
81
|
+
"@id"?: string | undefined;
|
|
82
|
+
"@type": string;
|
|
82
83
|
};
|
|
83
84
|
mainEntityOfPage: {
|
|
84
85
|
"@type": string;
|
|
@@ -154,9 +155,10 @@ export declare function createSeo(config: SeoConfig): {
|
|
|
154
155
|
"@type": string;
|
|
155
156
|
url: string;
|
|
156
157
|
} | undefined;
|
|
157
|
-
"@type": string;
|
|
158
158
|
name: string;
|
|
159
159
|
url: string;
|
|
160
|
+
"@id"?: string | undefined;
|
|
161
|
+
"@type": string;
|
|
160
162
|
};
|
|
161
163
|
author?: {
|
|
162
164
|
jobTitle?: string | undefined;
|
package/dist/seo.js
CHANGED
|
@@ -7,11 +7,6 @@ export function createSeo(config) {
|
|
|
7
7
|
const { baseUrl, siteName, defaultOgImage, logoUrl, articleBasePath = "notes", publisherUrl, trailingSlash = false, } = config;
|
|
8
8
|
/** Resolves a possibly-relative URL against the site origin. */
|
|
9
9
|
const absolute = (url) => url.startsWith("http") ? url : `${baseUrl}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
10
|
-
/**
|
|
11
|
-
* Stable `@id` anchors for the site's core entities. Pages reference these
|
|
12
|
-
* rather than re-declaring an Organization node, so crawlers merge them into
|
|
13
|
-
* one entity instead of collecting near-duplicates.
|
|
14
|
-
*/
|
|
15
10
|
/**
|
|
16
11
|
* A page route in the shape this site actually serves. A URL already carrying
|
|
17
12
|
* a query, a fragment or a file extension is left alone — only a route gets
|
|
@@ -34,10 +29,24 @@ export function createSeo(config) {
|
|
|
34
29
|
...(author.jobTitle ? { jobTitle: author.jobTitle } : {}),
|
|
35
30
|
};
|
|
36
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Stable `@id` anchors for the site's core entities. Pages reference these
|
|
34
|
+
* rather than re-declaring an Organization node, so crawlers merge them into
|
|
35
|
+
* one entity instead of collecting near-duplicates.
|
|
36
|
+
*/
|
|
37
37
|
const ORG_ID = `${baseUrl}/#organization`;
|
|
38
38
|
const WEBSITE_ID = `${baseUrl}/#website`;
|
|
39
|
+
/**
|
|
40
|
+
* The publisher every Article and WebPage node points at. It carries `@id`
|
|
41
|
+
* only when the publisher is this site: without one, each page declares a
|
|
42
|
+
* fresh Organization and a crawler has no way to merge a corpus of them into
|
|
43
|
+
* the canonical entity the site emits once. A `publisherUrl` naming a
|
|
44
|
+
* different site gets no `@id` — `ORG_ID` is derived from `baseUrl`, so
|
|
45
|
+
* stamping it there would claim someone else's publisher as this one.
|
|
46
|
+
*/
|
|
39
47
|
const publisher = {
|
|
40
48
|
"@type": "Organization",
|
|
49
|
+
...(!publisherUrl || publisherUrl === baseUrl ? { "@id": ORG_ID } : {}),
|
|
41
50
|
name: siteName,
|
|
42
51
|
url: publisherUrl ?? baseUrl,
|
|
43
52
|
...(logoUrl
|