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