@mannisto/astro-metadata 1.0.0-beta.3 → 1.0.0-beta.4

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.
Files changed (2) hide show
  1. package/README.md +49 -403
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -12,22 +12,22 @@ Astro components for managing your page head — metadata, social sharing, favic
12
12
 
13
13
  - [Installation](#installation)
14
14
  - [Usage](#usage)
15
- - [Head component](#1-head-component)
16
- - [Individual components](#2-individual-components)
17
- - [Metadata utility](#3-metadata-utility)
18
- - [Components](#components)
19
- - [Canonical](#canonical)
20
- - [Description](#description)
21
- - [Favicon](#favicon)
22
- - [Head](#head)
23
- - [Keywords](#keywords)
24
- - [LanguageAlternates](#languagealternates)
25
- - [OpenGraph](#opengraph)
26
- - [Robots](#robots)
27
- - [Schema](#schema)
28
- - [Title](#title)
29
- - [Twitter](#twitter)
30
- - [Contributing](#contributing)
15
+ - [Head component](docs/usage/head.md)
16
+ - [Metadata API](docs/usage/metadata.md)
17
+ - [Individual components](docs/usage/components.md)
18
+ - Components
19
+ - [Canonical](docs/components/canonical.md)
20
+ - [Description](docs/components/description.md)
21
+ - [Favicon](docs/components/favicon.md)
22
+ - [Head](docs/components/head.md)
23
+ - [Keywords](docs/components/keywords.md)
24
+ - [LanguageAlternates](docs/components/language-alternates.md)
25
+ - [OpenGraph](docs/components/open-graph.md)
26
+ - [Robots](docs/components/robots.md)
27
+ - [Schema](docs/components/schema.md)
28
+ - [Title](docs/components/title.md)
29
+ - [Twitter](docs/components/twitter.md)
30
+ - [Contributing](CONTRIBUTING.md)
31
31
  - [License](#license)
32
32
 
33
33
  ## Installation
@@ -47,102 +47,43 @@ yarn add @mannisto/astro-metadata
47
47
 
48
48
  There are three ways to use this package. Pick what suits your project, or combine them freely.
49
49
 
50
- ### 1. Head component
50
+ ### Head component
51
51
 
52
- The simplest approach. Use `Head` in your layout and pass props down from your pages. Charset and viewport are included automatically.
52
+ The simplest approach use `Head` in your layout and pass props down from pages.
53
53
 
54
54
  ```astro
55
55
  ---
56
- // layouts/Layout.astro
57
56
  import { Head } from "@mannisto/astro-metadata"
58
- import type { HeadProps } from "@mannisto/astro-metadata"
59
-
60
- interface Props extends HeadProps {}
61
-
62
- const { title, description, ...rest } = Astro.props
63
- ---
64
-
65
- <html>
66
- <Head title={title} description={description} titleTemplate="%s | My Site" {...rest} />
67
- <body>
68
- <slot />
69
- </body>
70
- </html>
71
- ```
72
-
73
- ```astro
74
- ---
75
- // pages/index.astro
76
- import Layout from "../layouts/Layout.astro"
77
- ---
78
-
79
- <Layout title="Home" description="Welcome to my site">
80
- <h1>Hello</h1>
81
- </Layout>
82
- ```
83
-
84
- Best for simple sites where pages pass metadata as props to their layout.
85
-
86
- ### 2. Individual components
87
-
88
- Use components directly inside your own `<head>`. Useful when you only need specific pieces, or want full control over the structure.
89
-
90
- ```astro
91
- ---
92
- import { Title, Description, OpenGraph, Favicon } from "@mannisto/astro-metadata"
93
57
  ---
94
58
 
95
59
  <html>
96
- <head>
97
- <meta charset="UTF-8" />
98
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
99
- <Title value="My Page" template="%s | My Site" />
100
- <Description value="Welcome to my site" />
101
- <OpenGraph
102
- title="My Page"
103
- description="Welcome to my site"
104
- image={{
105
- url: "/og.jpg",
106
- alt: "My Site",
107
- width: 1200,
108
- height: 630,
109
- }}
110
- />
111
- <Favicon icons={[{ path: "/favicon.ico" }, { path: "/favicon.svg" }]} />
112
- </head>
60
+ <Head
61
+ title="Home"
62
+ titleTemplate="%s | My Site"
63
+ description="Welcome to my site"
64
+ />
113
65
  <body>
114
66
  <slot />
115
67
  </body>
116
68
  </html>
117
69
  ```
118
70
 
119
- Best for when you want to compose only what you need, or when `Head` is too opinionated for your setup.
71
+ [Full guide →](docs/usage/head.md)
120
72
 
121
- ### 3. Metadata utility
73
+ ### Metadata API
122
74
 
123
- Set metadata in your page, resolve it in your layout. Eliminates prop drilling through nested layout layers.
75
+ Set metadata in pages, resolve in layouts no prop drilling.
124
76
 
125
77
  ```astro
126
78
  ---
127
79
  // pages/about.astro
128
80
  import { Metadata } from "@mannisto/astro-metadata"
129
- import Layout from "../layouts/Layout.astro"
130
81
 
131
82
  Metadata.set({
132
83
  title: "About",
133
84
  description: "Learn more about us",
134
- openGraph: {
135
- image: {
136
- url: "/og/about.jpg",
137
- alt: "About",
138
- },
139
- },
140
85
  })
141
86
  ---
142
-
143
- <Layout>
144
- <h1>About</h1>
145
- </Layout>
146
87
  ```
147
88
 
148
89
  ```astro
@@ -152,7 +93,6 @@ import { Head, Metadata } from "@mannisto/astro-metadata"
152
93
 
153
94
  const meta = Metadata.resolve({
154
95
  title: "My Site",
155
- description: "Default description",
156
96
  titleTemplate: "%s | My Site",
157
97
  })
158
98
  ---
@@ -165,330 +105,36 @@ const meta = Metadata.resolve({
165
105
  </html>
166
106
  ```
167
107
 
168
- `Metadata.resolve()` merges page values over your layout defaults — whatever the page sets wins, everything else falls back gracefully.
169
-
170
- Best for sites with deeply nested layouts, or when you want to keep metadata co-located with page content.
171
-
172
- ## Components
173
-
174
- ### Canonical
175
-
176
- Renders a canonical link tag. Falls back to `Astro.url.href` when no value is provided, so every page gets a canonical tag with zero configuration.
177
-
178
- ```astro
179
- <Canonical value="https://example.com/page" />
180
- ```
181
-
182
- | Prop | Type | Description |
183
- | ------- | -------- | -------------------------------------------- |
184
- | `value` | `string` | Canonical URL. Defaults to `Astro.url.href`. |
185
-
186
- ### Description
187
-
188
- ```astro
189
- <Description value="Welcome to my site" />
190
- ```
191
-
192
- | Prop | Type | Description |
193
- | ------- | -------- | ---------------- |
194
- | `value` | `string` | Page description |
195
-
196
- ### Favicon
197
-
198
- Favicon support with light and dark mode variants, automatic MIME type detection, and automatic sorting.
199
-
200
- ```astro
201
- <Favicon
202
- icons={[
203
- { path: "/favicon.ico" },
204
- { path: "/favicon.svg" },
205
- { path: "/favicon-96x96.png", size: 96 },
206
- { path: "/apple-touch-icon.png", size: 180, apple: true },
207
- { path: "/favicon-dark.svg", theme: "dark" },
208
- { path: "/favicon-light.svg", theme: "light" },
209
- ]}
210
- manifest="/site.webmanifest"
211
- />
212
- ```
213
-
214
- Icons are automatically sorted in the recommended browser order: `ico` → `png` → `svg` → `apple` → themed variants. Pass `sort={false}` to preserve the original order.
215
-
216
- | Prop | Type | Default | Description |
217
- | ---------- | --------------- | ------- | --------------------------------------- |
218
- | `icons` | `FaviconFile[]` | — | List of favicon files |
219
- | `manifest` | `string` | — | Path to web app manifest |
220
- | `sort` | `boolean` | `true` | Sort icons in recommended browser order |
221
-
222
- #### FaviconFile
223
-
224
- | Prop | Type | Description |
225
- | ------- | ------------------- | ----------------------------------------------------------- |
226
- | `path` | `string` | Path to the file. MIME type is detected automatically. |
227
- | `size` | `number` | Size in pixels. Rendered as `NxN` in the `sizes` attribute. |
228
- | `theme` | `"light" \| "dark"` | Adds a `prefers-color-scheme` media query |
229
- | `apple` | `boolean` | Renders as `<link rel="apple-touch-icon">` |
230
-
231
- ### Head
232
-
233
- Wraps the entire page head and composes all sub-components internally. Charset and viewport are always included and can be overridden if needed.
234
-
235
- ```astro
236
- <Head
237
- title="Home"
238
- titleTemplate="%s | My Site"
239
- description="Welcome to my site"
240
- openGraph={{
241
- image: {
242
- url: "/og.jpg",
243
- alt: "My Site",
244
- width: 1200,
245
- height: 630,
246
- },
247
- }}
248
- favicon={{
249
- icons: [{ path: "/favicon.ico" }, { path: "/favicon.svg" }],
250
- }}
251
- />
252
- ```
253
-
254
- | Prop | Type | Default | Description |
255
- | -------------------- | ---------------------------- | ----------------------------------------- | --------------------------------------------------------- |
256
- | `title` | `string` | — | Page title. Required. |
257
- | `titleTemplate` | `` `${string}%s${string}` `` | — | Title template. Must contain `%s`, e.g. `"%s \| My Site"` |
258
- | `description` | `string` | — | Page description |
259
- | `canonical` | `string` | `Astro.url.href` | Canonical URL |
260
- | `keywords` | `string[]` | — | List of keywords |
261
- | `charset` | `string` | `"UTF-8"` | Document charset |
262
- | `viewport` | `string` | `"width=device-width, initial-scale=1.0"` | Viewport meta content |
263
- | `robots` | `RobotsProps` | — | Robots directives |
264
- | `openGraph` | `OpenGraphProps` | — | Open Graph tags |
265
- | `twitter` | `TwitterProps` | — | Twitter card tags |
266
- | `favicon` | `FaviconProps` | — | Favicon configuration |
267
- | `schema` | `SchemaProps` | — | JSON-LD structured data |
268
- | `languageAlternates` | `LanguageAlternate[]` | — | Hreflang alternate links |
269
-
270
- #### Slots
271
-
272
- ```astro
273
- <Head title="My Site">
274
- <!-- Renders before charset and viewport -->
275
- <meta slot="top" http-equiv="X-UA-Compatible" content="IE=edge" />
276
-
277
- <!-- Renders at the end of <head> -->
278
- <script src={analyticsUrl}></script>
279
- </Head>
280
- ```
281
-
282
- ### Keywords
283
-
284
- ```astro
285
- <Keywords value={["astro", "seo", "metadata"]} />
286
- ```
287
-
288
- | Prop | Type | Description |
289
- | ------- | ---------- | ---------------- |
290
- | `value` | `string[]` | List of keywords |
291
-
292
- ### LanguageAlternates
293
-
294
- Renders `<link rel="alternate" hreflang>` tags for multilingual sites. Tells search engines which language version to serve for a given region.
295
-
296
- ```astro
297
- <LanguageAlternates
298
- alternates={[
299
- { href: "https://example.com/en", hreflang: "en" },
300
- { href: "https://example.com/fi", hreflang: "fi" },
301
- { href: "https://example.com", hreflang: "x-default" },
302
- ]}
303
- />
304
- ```
305
-
306
- | Prop | Type | Description |
307
- | ----------------------- | --------------------- | -------------------------------------------------------------- |
308
- | `alternates` | `LanguageAlternate[]` | List of alternate language pages |
309
- | `alternates[].href` | `string` | Full URL of the alternate page |
310
- | `alternates[].hreflang` | `string` | Language or region code, e.g. `en`, `fi`, `en-US`, `x-default` |
311
-
312
- ### OpenGraph
313
-
314
- Renders Open Graph meta tags for rich previews when your pages are shared on social platforms. When used inside `Head`, `title`, `description` and `url` fall back to the page values automatically.
315
-
316
- ```astro
317
- <OpenGraph
318
- title="My Page"
319
- description="Welcome to my site"
320
- url="https://example.com"
321
- type="website"
322
- siteName="My Site"
323
- locale="en_US"
324
- localeAlternate={["fi_FI", "fr_FR"]}
325
- image={{
326
- url: "/og.jpg",
327
- secureUrl: "https://example.com/og.jpg",
328
- type: "image/jpeg",
329
- alt: "My Site",
330
- width: 1200,
331
- height: 630,
332
- }}
333
- video={{
334
- url: "https://example.com/video.mp4",
335
- secureUrl: "https://example.com/video.mp4",
336
- type: "video/mp4",
337
- width: 1280,
338
- height: 720,
339
- }}
340
- audio={{
341
- url: "https://example.com/audio.mp3",
342
- secureUrl: "https://example.com/audio.mp3",
343
- type: "audio/mpeg",
344
- }}
345
- />
346
- ```
347
-
348
- | Prop | Type | Default | Description |
349
- | ----------------- | ---------------- | ----------- | -------------------------------------------- |
350
- | `title` | `string` | — | OG title |
351
- | `description` | `string` | — | OG description |
352
- | `url` | `string` | — | Canonical URL for the OG object |
353
- | `type` | `string` | `"website"` | OG type |
354
- | `siteName` | `string` | — | Name of the site |
355
- | `locale` | `string` | — | Locale, e.g. `en_US` |
356
- | `localeAlternate` | `string[]` | — | Alternate locales, e.g. `["fi_FI", "fr_FR"]` |
357
- | `image` | `OpenGraphImage` | — | Image metadata |
358
- | `video` | `OpenGraphVideo` | — | Video metadata |
359
- | `audio` | `OpenGraphAudio` | — | Audio metadata |
360
-
361
- #### OpenGraphImage
362
-
363
- | Prop | Type | Description |
364
- | ----------- | -------- | ------------------------------------------ |
365
- | `url` | `string` | Image URL. Required if image is set. |
366
- | `secureUrl` | `string` | HTTPS image URL |
367
- | `type` | `string` | MIME type, e.g. `"image/jpeg"` |
368
- | `alt` | `string` | Image alt text |
369
- | `width` | `number` | Image width in pixels. Recommended: `1200` |
370
- | `height` | `number` | Image height in pixels. Recommended: `630` |
371
-
372
- #### OpenGraphVideo
373
-
374
- | Prop | Type | Description |
375
- | ----------- | -------- | ------------------------------------ |
376
- | `url` | `string` | Video URL. Required if video is set. |
377
- | `secureUrl` | `string` | HTTPS video URL |
378
- | `type` | `string` | MIME type, e.g. `"video/mp4"` |
379
- | `width` | `number` | Video width in pixels |
380
- | `height` | `number` | Video height in pixels |
381
-
382
- #### OpenGraphAudio
383
-
384
- | Prop | Type | Description |
385
- | ----------- | -------- | ------------------------------------ |
386
- | `url` | `string` | Audio URL. Required if audio is set. |
387
- | `secureUrl` | `string` | HTTPS audio URL |
388
- | `type` | `string` | MIME type, e.g. `"audio/mpeg"` |
389
-
390
- ### Robots
391
-
392
- Controls how search engines crawl and index your page. Defaults to `index, follow`.
393
-
394
- ```astro
395
- <Robots archive={false} extra="max-snippet:-1, max-image-preview:large, max-video-preview:-1" />
396
- ```
397
-
398
- | Prop | Type | Default | Description |
399
- | --------- | --------- | ------- | ----------------------------------------------------------------------- |
400
- | `index` | `boolean` | `true` | Allow indexing |
401
- | `follow` | `boolean` | `true` | Allow following links |
402
- | `archive` | `boolean` | `true` | Allow search engines to cache the page |
403
- | `snippet` | `boolean` | `true` | Allow text snippets in search results |
404
- | `extra` | `string` | — | Additional directives, e.g. `"max-snippet:-1, max-image-preview:large"` |
405
-
406
- ### Schema
407
-
408
- Outputs a `<script type="application/ld+json">` tag for structured data. Use it to help search engines understand your content and qualify for rich results.
409
-
410
- ```astro
411
- <Schema
412
- schema={{
413
- "@context": "https://schema.org",
414
- "@type": "Person",
415
- name: "Ere Männistö",
416
- url: "https://example.com",
417
- }}
418
- />
419
- ```
420
-
421
- | Prop | Type | Description |
422
- | -------- | ------------------------- | -------------- |
423
- | `schema` | `Record<string, unknown>` | JSON-LD object |
108
+ [Full guide →](docs/usage/metadata.md)
424
109
 
425
- ### Title
110
+ ### Individual components
426
111
 
427
- Renders the `<title>` tag. The template must contain `%s`, which is replaced with the page title — TypeScript enforces this at the type level.
112
+ Use components directly in your `<head>` for full control.
428
113
 
429
114
  ```astro
430
- <Title value="My Page" template="%s | My Site" />
431
- ```
432
-
433
- | Prop | Type | Description |
434
- | ---------- | ---------------------------- | ----------------------------------- |
435
- | `value` | `string` | Page title. Required. |
436
- | `template` | `` `${string}%s${string}` `` | Template string. Must contain `%s`. |
437
-
438
- ### Twitter
439
-
440
- Renders Twitter card meta tags for rich previews on X. When used inside `Head`, `title` and `description` fall back to the page values automatically.
115
+ ---
116
+ import { Title, Description, OpenGraph } from "@mannisto/astro-metadata"
117
+ ---
441
118
 
442
- ```astro
443
- <Twitter
444
- card="summary_large_image"
445
- site="@mysite"
446
- creator="@myhandle"
447
- url="https://example.com"
448
- image={{
449
- url: "/og.jpg",
450
- alt: "My Site",
451
- }}
452
- />
119
+ <html>
120
+ <head>
121
+ <meta charset="UTF-8" />
122
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
123
+ <Title value="My Page" template="%s | My Site" />
124
+ <Description value="Welcome to my site" />
125
+ <OpenGraph
126
+ title="My Page"
127
+ image={{ url: "/og.jpg", alt: "My Site" }}
128
+ />
129
+ </head>
130
+ <body>
131
+ <slot />
132
+ </body>
133
+ </html>
453
134
  ```
454
135
 
455
- | Prop | Type | Default | Description |
456
- | ------------- | --------------------------------------------------------- | ----------------------- | ------------------------------------------ |
457
- | `title` | `string` | — | Card title |
458
- | `description` | `string` | — | Card description |
459
- | `url` | `string` | — | Canonical URL for the card |
460
- | `card` | `"summary" \| "summary_large_image" \| "player" \| "app"` | `"summary_large_image"` | Card type |
461
- | `site` | `string` | — | Twitter handle of the site, e.g. `@mysite` |
462
- | `creator` | `string` | — | Twitter handle of the content author |
463
- | `image.url` | `string` | — | Image URL. Required if image is set. |
464
- | `image.alt` | `string` | — | Image alt text |
465
-
466
- ## Contributing
467
-
468
- Clone the repo and run `pnpm run init` to install dependencies, link the local package to the fixture project, and set up Playwright. Then use `pnpm test:unit`, `pnpm test:e2e`, or `pnpm test:all` to run tests, and `pnpm check` / `pnpm format` for linting and formatting. All PRs must pass `pnpm check` — enforced via GitHub Actions.
469
-
470
- ### Project structure
471
-
472
- ```
473
- astro-metadata/
474
- src/
475
- components/
476
- lib/
477
- tests/
478
- e2e/
479
- components/
480
- fixtures/
481
- unit/
482
- metadata.test.ts
483
- scripts/
484
- init.sh
485
- index.ts
486
- playwright.config.ts
487
- vitest.config.ts
488
- biome.json
489
- prettier.config.ts
490
- ```
136
+ [Full guide →](docs/usage/components.md)
491
137
 
492
138
  ## License
493
139
 
494
- MIT © [Ere Männistö](https://github.com/eremannisto)
140
+ MIT © [Ere Männistö](https://github.com/eremannisto)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mannisto/astro-metadata",
3
- "version": "1.0.0-beta.3",
3
+ "version": "1.0.0-beta.4",
4
4
  "description": "Astro components for managing your page head — metadata, social sharing, favicons, and SEO.",
5
5
  "license": "MIT",
6
6
  "type": "module",