@uniflowed/router 0.0.0-alpha.11 → 0.0.0-alpha.12
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/internal/runtime.js +76 -6
- package/package.json +2 -2
package/internal/runtime.js
CHANGED
|
@@ -167,17 +167,51 @@ export type Metadata = {
|
|
|
167
167
|
*/
|
|
168
168
|
readonly canonical?: string,
|
|
169
169
|
readonly openGraph?: {
|
|
170
|
+
/**
|
|
171
|
+
* The title a share card shows.
|
|
172
|
+
*
|
|
173
|
+
* Falls back to `title`, because a page that has said what it is called
|
|
174
|
+
* has said what its card is called — and a site made to write it twice
|
|
175
|
+
* writes it twice once and then lets them drift.
|
|
176
|
+
*/
|
|
170
177
|
readonly title?: string,
|
|
178
|
+
/** The description a share card shows. Falls back to `description`. */
|
|
171
179
|
readonly description?: string,
|
|
180
|
+
/**
|
|
181
|
+
* The Open Graph object type. `website` unless a page says otherwise.
|
|
182
|
+
*
|
|
183
|
+
* Defaulted rather than omitted because `og:type` is one of the four
|
|
184
|
+
* properties Open Graph requires, and a document without it is not an
|
|
185
|
+
* Open Graph document at all — so leaving it to every project to remember
|
|
186
|
+
* is leaving most of them without one.
|
|
187
|
+
*/
|
|
188
|
+
readonly type?: string,
|
|
189
|
+
/**
|
|
190
|
+
* The name of the site the page belongs to, which a card prints above the
|
|
191
|
+
* title. Declared once on the root layout.
|
|
192
|
+
*/
|
|
193
|
+
readonly siteName?: string,
|
|
172
194
|
readonly images?: $ReadOnlyArray<string>,
|
|
195
|
+
/**
|
|
196
|
+
* What the card's image shows, for a reader who cannot see it.
|
|
197
|
+
*
|
|
198
|
+
* One description rather than one per image: a card shows one image, and
|
|
199
|
+
* the array exists so a site can offer a crawler a choice of sizes rather
|
|
200
|
+
* than so it can show several.
|
|
201
|
+
*/
|
|
202
|
+
readonly imageAlt?: string,
|
|
173
203
|
},
|
|
174
204
|
readonly twitter?: {
|
|
175
205
|
readonly card?: TwitterCard,
|
|
176
206
|
readonly site?: string,
|
|
177
207
|
readonly creator?: string,
|
|
208
|
+
/** Falls back to `openGraph.title`, and then to `title`. */
|
|
178
209
|
readonly title?: string,
|
|
210
|
+
/** Falls back to `openGraph.description`, and then to `description`. */
|
|
179
211
|
readonly description?: string,
|
|
180
212
|
readonly images?: $ReadOnlyArray<string>,
|
|
213
|
+
/** Falls back to `openGraph.imageAlt`. */
|
|
214
|
+
readonly imageAlt?: string,
|
|
181
215
|
},
|
|
182
216
|
};
|
|
183
217
|
|
|
@@ -1610,6 +1644,24 @@ function absoluteUrl(value: string, base: void | string): string {
|
|
|
1610
1644
|
component Head(metadata: Metadata) {
|
|
1611
1645
|
const { title, description, metadataBase, canonical, openGraph, twitter } = metadata;
|
|
1612
1646
|
const href = canonical != null ? absoluteUrl(canonical, metadataBase) : null;
|
|
1647
|
+
// A page that said what it is called has said what its card is called. Every
|
|
1648
|
+
// site that had to write both wrote the same string twice, and the second
|
|
1649
|
+
// one is the one that goes stale — the docs site shipped thirty pages whose
|
|
1650
|
+
// share cards carried an image and no title at all.
|
|
1651
|
+
//
|
|
1652
|
+
// `??`, not `||`: an empty string is a decision, and a page that deliberately
|
|
1653
|
+
// has no card title should get none rather than the document's.
|
|
1654
|
+
const cardTitle = openGraph?.title ?? title;
|
|
1655
|
+
const cardDescription = openGraph?.description ?? description;
|
|
1656
|
+
// `og:type` is one of the four properties Open Graph requires. A default is
|
|
1657
|
+
// the difference between a document with a card and a document without one,
|
|
1658
|
+
// and `website` is right for everything that is not an article or a video.
|
|
1659
|
+
const cardType = openGraph?.type ?? "website";
|
|
1660
|
+
// Only when the card was asked for. A page with no `twitter.card` gets no
|
|
1661
|
+
// Twitter tags at all, which is what a site that never wanted one meant.
|
|
1662
|
+
const twitterTitle = twitter != null ? (twitter.title ?? cardTitle) : null;
|
|
1663
|
+
const twitterDescription = twitter != null ? (twitter.description ?? cardDescription) : null;
|
|
1664
|
+
const twitterImageAlt = twitter != null ? (twitter.imageAlt ?? openGraph?.imageAlt) : null;
|
|
1613
1665
|
return (
|
|
1614
1666
|
<>
|
|
1615
1667
|
{title != null ? <title>{title}</title> : null}
|
|
@@ -1619,30 +1671,48 @@ component Head(metadata: Metadata) {
|
|
|
1619
1671
|
words, so one declaration answers both rather than asking a project
|
|
1620
1672
|
to write the same URL twice and keep them in step. */}
|
|
1621
1673
|
{href != null ? <meta property="og:url" content={href} /> : null}
|
|
1622
|
-
{
|
|
1623
|
-
{
|
|
1624
|
-
<meta property="og:description" content={
|
|
1674
|
+
{cardTitle != null ? <meta property="og:title" content={cardTitle} /> : null}
|
|
1675
|
+
{cardDescription != null ? (
|
|
1676
|
+
<meta property="og:description" content={cardDescription} />
|
|
1677
|
+
) : null}
|
|
1678
|
+
{/* Only alongside something else. A document with `og:type` and nothing
|
|
1679
|
+
more is not a card; it is one meta tag saying the page is a page. */}
|
|
1680
|
+
{cardTitle != null || cardDescription != null || openGraph?.images != null ? (
|
|
1681
|
+
<meta property="og:type" content={cardType} />
|
|
1682
|
+
) : null}
|
|
1683
|
+
{openGraph?.siteName != null ? (
|
|
1684
|
+
<meta property="og:site_name" content={openGraph.siteName} />
|
|
1625
1685
|
) : null}
|
|
1626
1686
|
{openGraph?.images != null
|
|
1627
1687
|
? openGraph.images.map((image) => (
|
|
1628
1688
|
<meta key={image} property="og:image" content={absoluteUrl(image, metadataBase)} />
|
|
1629
1689
|
))
|
|
1630
1690
|
: null}
|
|
1691
|
+
{openGraph?.imageAlt != null && openGraph?.images != null ? (
|
|
1692
|
+
<meta property="og:image:alt" content={openGraph.imageAlt} />
|
|
1693
|
+
) : null}
|
|
1631
1694
|
{/* `name`, not `property`: Open Graph is RDFa and Twitter's cards are
|
|
1632
1695
|
not, and a `property="twitter:card"` is ignored by the crawler that
|
|
1633
1696
|
reads it. */}
|
|
1634
1697
|
{twitter?.card != null ? <meta name="twitter:card" content={twitter.card} /> : null}
|
|
1635
1698
|
{twitter?.site != null ? <meta name="twitter:site" content={twitter.site} /> : null}
|
|
1636
1699
|
{twitter?.creator != null ? <meta name="twitter:creator" content={twitter.creator} /> : null}
|
|
1637
|
-
{
|
|
1638
|
-
|
|
1639
|
-
|
|
1700
|
+
{/* X reads the `og:` tags when these are absent, so these are not
|
|
1701
|
+
required — and every validator asks for them anyway, which is a good
|
|
1702
|
+
enough reason when the value is one the page has already given. They
|
|
1703
|
+
fall back through the card's title to the document's. */}
|
|
1704
|
+
{twitterTitle != null ? <meta name="twitter:title" content={twitterTitle} /> : null}
|
|
1705
|
+
{twitterDescription != null ? (
|
|
1706
|
+
<meta name="twitter:description" content={twitterDescription} />
|
|
1640
1707
|
) : null}
|
|
1641
1708
|
{twitter?.images != null
|
|
1642
1709
|
? twitter.images.map((image) => (
|
|
1643
1710
|
<meta key={image} name="twitter:image" content={absoluteUrl(image, metadataBase)} />
|
|
1644
1711
|
))
|
|
1645
1712
|
: null}
|
|
1713
|
+
{twitterImageAlt != null && twitter?.images != null ? (
|
|
1714
|
+
<meta name="twitter:image:alt" content={twitterImageAlt} />
|
|
1715
|
+
) : null}
|
|
1646
1716
|
</>
|
|
1647
1717
|
);
|
|
1648
1718
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniflowed/router",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.12",
|
|
4
4
|
"description": "The file-system router for Flow React applications: matching, layouts, loaders, navigation, server rendering and hydration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,6 +31,6 @@
|
|
|
31
31
|
"react-dom": ">=19"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@uniflowed/server": "0.0.0-alpha.
|
|
34
|
+
"@uniflowed/server": "0.0.0-alpha.12"
|
|
35
35
|
}
|
|
36
36
|
}
|