@mannisto/astro-metadata 1.0.0-alpha.1 → 1.0.0-alpha.3

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 CHANGED
@@ -1,22 +1,21 @@
1
1
  # Astro Metadata
2
2
 
3
- ![banner](./assets/default/banner.png)
3
+ ![banner](./assets/default/banner.jpg)
4
4
 
5
5
  ![npm version](https://img.shields.io/npm/v/@mannisto/astro-metadata)
6
- ![license](https://img.shields.io/npm/l/@mannisto/astro-metadata)
6
+ ![license](https://img.shields.io/badge/license-MIT-green)
7
7
  ![astro peer dependency](https://img.shields.io/npm/dependency-version/@mannisto/astro-metadata/peer/astro)
8
8
 
9
9
  Astro components for managing your page head — metadata, social sharing, favicons, and SEO.
10
10
 
11
- ---
12
11
 
13
12
  ## Table of contents
14
13
 
15
14
  - [Installation](#installation)
16
- - [Patterns](#patterns)
17
- - [1. Head component](#1-head-component)
18
- - [2. Individual components](#2-individual-components)
19
- - [3. Metadata utility](#3-metadata-utility)
15
+ - [Usage](#usage)
16
+ - [Head component](#1-head-component)
17
+ - [Individual components](#2-individual-components)
18
+ - [Metadata utility](#3-metadata-utility)
20
19
  - [Components](#components)
21
20
  - [Canonical](#canonical)
22
21
  - [Description](#description)
@@ -31,16 +30,20 @@ Astro components for managing your page head — metadata, social sharing, favic
31
30
  - [Twitter](#twitter)
32
31
  - [License](#license)
33
32
 
34
- ---
35
33
 
36
34
  ## Installation
37
35
  ```bash
36
+ # pnpm
38
37
  pnpm add @mannisto/astro-metadata
39
- ```
40
38
 
41
- ---
39
+ # npm
40
+ npm install @mannisto/astro-metadata
42
41
 
43
- ## Patterns
42
+ # yarn
43
+ yarn add @mannisto/astro-metadata
44
+ ```
45
+
46
+ ## Usage
44
47
 
45
48
  There are three ways to use this package. Pick what suits your project, or combine them freely.
46
49
 
@@ -49,6 +52,7 @@ There are three ways to use this package. Pick what suits your project, or combi
49
52
  The simplest approach. Use `Head` in your layout and pass props down from your pages. Charset and viewport are included automatically.
50
53
  ```astro
51
54
  ---
55
+
52
56
  // layouts/Layout.astro
53
57
  import { Head } from "@mannisto/astro-metadata"
54
58
  import type { HeadProps } from "@mannisto/astro-metadata"
@@ -56,6 +60,7 @@ import type { HeadProps } from "@mannisto/astro-metadata"
56
60
  interface Props extends HeadProps {}
57
61
 
58
62
  const { title, description, ...rest } = Astro.props
63
+
59
64
  ---
60
65
 
61
66
  <html>
@@ -70,10 +75,13 @@ const { title, description, ...rest } = Astro.props
70
75
  </body>
71
76
  </html>
72
77
  ```
78
+
73
79
  ```astro
74
80
  ---
81
+
75
82
  // pages/index.astro
76
83
  import Layout from "../layouts/Layout.astro"
84
+
77
85
  ---
78
86
 
79
87
  <Layout title="Home" description="Welcome to my site">
@@ -83,14 +91,16 @@ import Layout from "../layouts/Layout.astro"
83
91
 
84
92
  Best for simple sites where pages pass metadata as props to their layout.
85
93
 
86
- ---
87
94
 
88
95
  ### 2. Individual components
89
96
 
90
97
  Use components directly inside your own `<head>`. Useful when you only need specific pieces, or want full control over the structure.
98
+
91
99
  ```astro
92
100
  ---
101
+
93
102
  import { Title, Description, OpenGraph, Favicon } from "@mannisto/astro-metadata"
103
+
94
104
  ---
95
105
 
96
106
  <html>
@@ -102,14 +112,19 @@ import { Title, Description, OpenGraph, Favicon } from "@mannisto/astro-metadata
102
112
  <OpenGraph
103
113
  title="My Page"
104
114
  description="Welcome to my site"
105
- image={{ url: "/og.jpg", alt: "My Site", width: 1200, height: 630 }}
115
+ image={{
116
+ url: "/og.jpg",
117
+ alt: "My Site",
118
+ width: 1200,
119
+ height: 630,
120
+ }}
106
121
  />
107
122
  <Favicon
108
123
  icons={{
109
124
  default: {
110
125
  ico: { path: "/favicon.ico" },
111
126
  svg: { path: "/favicon.svg" },
112
- }
127
+ },
113
128
  }}
114
129
  />
115
130
  </head>
@@ -121,13 +136,14 @@ import { Title, Description, OpenGraph, Favicon } from "@mannisto/astro-metadata
121
136
 
122
137
  Best for when you want to compose only what you need, or when `Head` is too opinionated for your setup.
123
138
 
124
- ---
125
139
 
126
140
  ### 3. Metadata utility
127
141
 
128
142
  Set metadata in your page, resolve it in your layout. Eliminates prop drilling through nested layout layers.
143
+
129
144
  ```astro
130
145
  ---
146
+
131
147
  // pages/about.astro
132
148
  import { Metadata } from "@mannisto/astro-metadata"
133
149
  import Layout from "../layouts/Layout.astro"
@@ -136,17 +152,23 @@ Metadata.set({
136
152
  title: "About",
137
153
  description: "Learn more about us",
138
154
  openGraph: {
139
- image: { url: "/og/about.jpg", alt: "About" }
140
- }
155
+ image: {
156
+ url: "/og/about.jpg",
157
+ alt: "About",
158
+ },
159
+ },
141
160
  })
161
+
142
162
  ---
143
163
 
144
164
  <Layout>
145
165
  <h1>About</h1>
146
166
  </Layout>
147
167
  ```
168
+
148
169
  ```astro
149
170
  ---
171
+
150
172
  // layouts/Layout.astro
151
173
  import { Head, Metadata } from "@mannisto/astro-metadata"
152
174
 
@@ -155,6 +177,7 @@ const meta = Metadata.resolve({
155
177
  description: "Default description",
156
178
  titleTemplate: "%s | My Site",
157
179
  })
180
+
158
181
  ---
159
182
 
160
183
  <html>
@@ -169,13 +192,14 @@ const meta = Metadata.resolve({
169
192
 
170
193
  Best for sites with deeply nested layouts, or when you want to keep metadata co-located with page content.
171
194
 
172
- ---
173
195
 
174
196
  ## Components
175
197
 
176
- ### Canonical
198
+ <details>
199
+ <summary><strong>Canonical</strong></summary>
177
200
 
178
201
  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.
202
+
179
203
  ```astro
180
204
  <Canonical value="https://example.com/page" />
181
205
  ```
@@ -184,9 +208,12 @@ Renders a canonical link tag. Falls back to `Astro.url.href` when no value is pr
184
208
  |------|------|-------------|
185
209
  | `value` | `string` | Canonical URL. Defaults to `Astro.url.href`. |
186
210
 
187
- ---
211
+ </details>
212
+
213
+
214
+ <details>
215
+ <summary><strong>Description</strong></summary>
188
216
 
189
- ### Description
190
217
  ```astro
191
218
  <Description value="Welcome to my site" />
192
219
  ```
@@ -195,11 +222,14 @@ Renders a canonical link tag. Falls back to `Astro.url.href` when no value is pr
195
222
  |------|------|-------------|
196
223
  | `value` | `string` | Page description |
197
224
 
198
- ---
225
+ </details>
226
+
199
227
 
200
- ### Favicon
228
+ <details>
229
+ <summary><strong>Favicon</strong></summary>
201
230
 
202
231
  Favicon support with dark and light mode variants, multiple formats, and optional cache busting.
232
+
203
233
  ```astro
204
234
  <Favicon
205
235
  icons={{
@@ -245,36 +275,55 @@ Favicon support with dark and light mode variants, multiple formats, and optiona
245
275
  | `path` | `string` | Path to the file |
246
276
  | `size` | `number` | Size in pixels. Rendered as `NxN` in the `sizes` attribute. |
247
277
 
248
- ---
278
+ </details>
249
279
 
250
- ### Head
251
280
 
252
- Wraps the entire page head and composes all sub-components internally. Charset and viewport are always included.
281
+ <details>
282
+ <summary><strong>Head</strong></summary>
283
+
284
+ Wraps the entire page head and composes all sub-components internally. Charset and viewport are always included and can be overridden if needed.
285
+
253
286
  ```astro
254
287
  <Head
255
288
  title="Home"
256
289
  titleTemplate="%s | My Site"
257
290
  description="Welcome to my site"
258
- openGraph={{ image: { url: "/og.jpg", alt: "My Site", width: 1200, height: 630 } }}
259
- favicon={{ icons: { default: { ico: { path: "/favicon.ico" } } } }}
291
+ openGraph={{
292
+ image: {
293
+ url: "/og.jpg",
294
+ alt: "My Site",
295
+ width: 1200,
296
+ height: 630,
297
+ },
298
+ }}
299
+ favicon={{
300
+ icons: {
301
+ default: {
302
+ ico: { path: "/favicon.ico" },
303
+ },
304
+ },
305
+ }}
260
306
  />
261
307
  ```
262
308
 
263
- | Prop | Type | Description |
264
- |------|------|-------------|
265
- | `title` | `string` | Page title. Required. |
266
- | `titleTemplate` | `` `${string}%s${string}` `` | Title template. Must contain `%s`, e.g. `"%s \| My Site"` |
267
- | `description` | `string` | Page description |
268
- | `canonical` | `string` | Canonical URL. Defaults to `Astro.url.href` |
269
- | `keywords` | `string[]` | List of keywords |
270
- | `robots` | `RobotsProps` | Robots directives |
271
- | `openGraph` | `OpenGraphProps` | Open Graph tags |
272
- | `twitter` | `TwitterProps` | Twitter card tags |
273
- | `favicon` | `FaviconProps` | Favicon configuration |
274
- | `schema` | `SchemaProps` | JSON-LD structured data |
275
- | `languageAlternates` | `LanguageAlternate[]` | Hreflang alternate links |
309
+ | Prop | Type | Default | Description |
310
+ |------|------|---------|-------------|
311
+ | `title` | `string` | — | Page title. Required. |
312
+ | `titleTemplate` | `` `${string}%s${string}` `` | — | Title template. Must contain `%s`, e.g. `"%s \| My Site"` |
313
+ | `description` | `string` | — | Page description |
314
+ | `canonical` | `string` | `Astro.url.href` | Canonical URL |
315
+ | `keywords` | `string[]` | — | List of keywords |
316
+ | `charset` | `string` | `"UTF-8"` | Document charset |
317
+ | `viewport` | `string` | `"width=device-width, initial-scale=1.0"` | Viewport meta content |
318
+ | `robots` | `RobotsProps` | | Robots directives |
319
+ | `openGraph` | `OpenGraphProps` | | Open Graph tags |
320
+ | `twitter` | `TwitterProps` | | Twitter card tags |
321
+ | `favicon` | `FaviconProps` | | Favicon configuration |
322
+ | `schema` | `SchemaProps` | — | JSON-LD structured data |
323
+ | `languageAlternates` | `LanguageAlternate[]` | — | Hreflang alternate links |
276
324
 
277
325
  #### Slots
326
+
278
327
  ```astro
279
328
  <Head title="My Site">
280
329
  <!-- Renders before charset and viewport -->
@@ -285,9 +334,12 @@ Wraps the entire page head and composes all sub-components internally. Charset a
285
334
  </Head>
286
335
  ```
287
336
 
288
- ---
337
+ </details>
338
+
339
+
340
+ <details>
341
+ <summary><strong>Keywords</strong></summary>
289
342
 
290
- ### Keywords
291
343
  ```astro
292
344
  <Keywords value={["astro", "seo", "metadata"]} />
293
345
  ```
@@ -296,17 +348,20 @@ Wraps the entire page head and composes all sub-components internally. Charset a
296
348
  |------|------|-------------|
297
349
  | `value` | `string[]` | List of keywords |
298
350
 
299
- ---
351
+ </details>
352
+
300
353
 
301
- ### LanguageAlternates
354
+ <details>
355
+ <summary><strong>LanguageAlternates</strong></summary>
302
356
 
303
357
  Renders `<link rel="alternate" hreflang>` tags for multilingual sites. Tells search engines which language version to serve for a given region.
358
+
304
359
  ```astro
305
360
  <LanguageAlternates
306
361
  alternates={[
307
- { href: "https://example.com/en", hreflang: "en" },
308
- { href: "https://example.com/fi", hreflang: "fi" },
309
- { href: "https://example.com", hreflang: "x-default" },
362
+ { href: "https://example.com/en", hreflang: "en" },
363
+ { href: "https://example.com/fi", hreflang: "fi" },
364
+ { href: "https://example.com", hreflang: "x-default" },
310
365
  ]}
311
366
  />
312
367
  ```
@@ -317,16 +372,23 @@ Renders `<link rel="alternate" hreflang>` tags for multilingual sites. Tells sea
317
372
  | `alternates[].href` | `string` | Full URL of the alternate page |
318
373
  | `alternates[].hreflang` | `string` | Language or region code, e.g. `en`, `fi`, `en-US`, `x-default` |
319
374
 
320
- ---
375
+ </details>
321
376
 
322
- ### OpenGraph
377
+
378
+ <details>
379
+ <summary><strong>OpenGraph</strong></summary>
323
380
 
324
381
  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.
325
382
  ```astro
326
383
  <OpenGraph
327
384
  title="My Page"
328
385
  description="Welcome to my site"
329
- image={{ url: "/og.jpg", alt: "My Site", width: 1200, height: 630 }}
386
+ image={{
387
+ url: "/og.jpg",
388
+ alt: "My Site",
389
+ width: 1200,
390
+ height: 630,
391
+ }}
330
392
  url="https://example.com"
331
393
  siteName="My Site"
332
394
  locale="en_US"
@@ -346,9 +408,11 @@ Renders Open Graph meta tags for rich previews when your pages are shared on soc
346
408
  | `siteName` | `string` | — | Name of the site |
347
409
  | `locale` | `string` | — | Locale, e.g. `en_US` |
348
410
 
349
- ---
411
+ </details>
412
+
350
413
 
351
- ### Robots
414
+ <details>
415
+ <summary><strong>Robots</strong></summary>
352
416
 
353
417
  Controls how search engines crawl and index your page. Defaults to `index, follow`.
354
418
  ```astro
@@ -366,9 +430,11 @@ Controls how search engines crawl and index your page. Defaults to `index, follo
366
430
  | `noSnippet` | `boolean` | — | Prevent text snippets in search results |
367
431
  | `extra` | `string` | — | Additional directives, e.g. `"max-snippet:-1, max-image-preview:large"` |
368
432
 
369
- ---
433
+ </details>
434
+
370
435
 
371
- ### Schema
436
+ <details>
437
+ <summary><strong>Schema</strong></summary>
372
438
 
373
439
  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.
374
440
  ```astro
@@ -386,14 +452,16 @@ Outputs a `<script type="application/ld+json">` tag for structured data. Use it
386
452
  |------|------|-------------|
387
453
  | `schema` | `Record<string, unknown>` | JSON-LD object |
388
454
 
389
- ---
455
+ </details>
456
+
390
457
 
391
- ### Title
458
+ <details>
459
+ <summary><strong>Title</strong></summary>
392
460
 
393
461
  Renders the `<title>` tag. The template must contain `%s`, which is replaced with the page title — TypeScript enforces this at the type level.
462
+
394
463
  ```astro
395
464
  <Title value="My Page" template="%s | My Site" />
396
- <!-- <title>My Page | My Site</title> -->
397
465
  ```
398
466
 
399
467
  | Prop | Type | Description |
@@ -401,17 +469,23 @@ Renders the `<title>` tag. The template must contain `%s`, which is replaced wit
401
469
  | `value` | `string` | Page title. Required. |
402
470
  | `template` | `` `${string}%s${string}` `` | Template string. Must contain `%s`. |
403
471
 
404
- ---
472
+ </details>
405
473
 
406
- ### Twitter
474
+
475
+ <details>
476
+ <summary><strong>Twitter</strong></summary>
407
477
 
408
478
  Renders Twitter card meta tags for rich previews on X. When used inside `Head`, `title` and `description` fall back to the page values automatically.
479
+
409
480
  ```astro
410
481
  <Twitter
411
482
  card="summary_large_image"
412
483
  site="@mysite"
413
484
  creator="@myhandle"
414
- image={{ url: "/og.jpg", alt: "My Site" }}
485
+ image={{
486
+ url: "/og.jpg",
487
+ alt: "My Site",
488
+ }}
415
489
  />
416
490
  ```
417
491
 
@@ -425,8 +499,8 @@ Renders Twitter card meta tags for rich previews on X. When used inside `Head`,
425
499
  | `site` | `string` | — | Twitter handle of the site, e.g. `@mysite` |
426
500
  | `creator` | `string` | — | Twitter handle of the content author |
427
501
 
428
- ---
502
+ </details>
429
503
 
430
504
  ## License
431
505
 
432
- MIT
506
+ 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-alpha.1",
3
+ "version": "1.0.0-alpha.3",
4
4
  "type": "module",
5
5
  "description": "Astro components for managing your page head — metadata, social sharing, favicons, and SEO.",
6
6
  "license": "MIT",
@@ -1,5 +1,4 @@
1
1
  ---
2
-
3
2
  import type { ComponentProps } from "astro/types"
4
3
  import Title from "./Title.astro"
5
4
  import Description from "./Description.astro"
@@ -13,17 +12,19 @@ import Schema from "./Schema.astro"
13
12
  import LanguageAlternates from "./LanguageAlternates.astro"
14
13
 
15
14
  export type Props = {
16
- title : string
17
- titleTemplate? : `${string}%s${string}`
18
- description? : string
19
- canonical? : string
20
- keywords? : string[]
21
- robots? : ComponentProps<typeof Robots>
22
- openGraph? : ComponentProps<typeof OpenGraph>
23
- twitter? : ComponentProps<typeof Twitter>
24
- favicon? : ComponentProps<typeof Favicon>
25
- schema? : ComponentProps<typeof Schema>
26
- languageAlternates? : ComponentProps<typeof LanguageAlternates>["alternates"]
15
+ title : string
16
+ titleTemplate? : `${string}%s${string}`
17
+ description? : string
18
+ canonical? : string
19
+ keywords? : string[]
20
+ charset? : string
21
+ viewport? : string
22
+ robots? : ComponentProps<typeof Robots>
23
+ openGraph? : ComponentProps<typeof OpenGraph>
24
+ twitter? : ComponentProps<typeof Twitter>
25
+ favicon? : ComponentProps<typeof Favicon>
26
+ schema? : ComponentProps<typeof Schema>
27
+ languageAlternates? : ComponentProps<typeof LanguageAlternates>["alternates"]
27
28
  }
28
29
 
29
30
  const {
@@ -32,6 +33,8 @@ const {
32
33
  description,
33
34
  canonical,
34
35
  keywords,
36
+ charset = "UTF-8",
37
+ viewport = "width=device-width, initial-scale=1.0",
35
38
  robots,
36
39
  openGraph,
37
40
  twitter,
@@ -39,14 +42,13 @@ const {
39
42
  schema,
40
43
  languageAlternates,
41
44
  } = Astro.props
42
-
43
45
  ---
44
46
 
45
47
  <head>
46
48
  <slot name="top" />
47
49
 
48
- <meta charset="UTF-8" />
49
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
50
+ <meta charset={charset} />
51
+ <meta name="viewport" content={viewport} />
50
52
 
51
53
  <Title value={title} template={titleTemplate} />
52
54
  <Description value={description} />