Skip to content

Commit 7a528dd

Browse files
authored
Overhaul MetaHeadEmbed + Fix getShareUrl's (#5)
* Update README * Update to use PageLayout * Implement render support + overhauled embeds * Update README * Fix README * Tweak * Refactor sharing * Tweaks * Add hashtag check * Update README
1 parent ca80a22 commit 7a528dd

8 files changed

Lines changed: 229 additions & 191 deletions

File tree

README.md

Lines changed: 73 additions & 76 deletions
Large diffs are not rendered by default.

src/components/MetaHeadEmbed.tsx

Lines changed: 128 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,53 @@ import React from "react";
22

33
import isAbsoluteUrl from "is-absolute-url";
44

5+
import { commaSeparate } from "../utils";
6+
7+
export interface TwitterEmbedProps {
8+
/** Summary card size. */
9+
cardSize: "small" | "large";
10+
11+
/** A concise title for the related content. */
12+
title?: string;
13+
14+
/**
15+
* A description that concisely summarizes the content as appropriate for
16+
* presentation within a Tweet. Should not be the same as title.
17+
*/
18+
description?: string;
19+
20+
/** The Twitter @username the card should be attributed to. */
21+
siteUsername?: string;
22+
23+
/** The Twitter @username for the content creator / author. */
24+
creatorUsername?: string;
25+
26+
/**
27+
* Image to show in card. _Should_ only be used if image is different to
28+
* `MetaHeadEmbed` image.
29+
*
30+
* Should be different based on `useLargeCard`:
31+
* - For large cards, use a 2:1 aspect ratio (300x157 px minium or
32+
* 4096x4096 px maximum).
33+
* - For small cards, use a 1:1 aspect ratio (144x144 px minium or
34+
* 4096x4096 px maximum).
35+
*
36+
* Images must be less than 5MB in size.
37+
*
38+
* Supported file types; JPG, PNG, WEBP and GIF.
39+
*
40+
* Note: Only the first frame of an animated GIF will be used.
41+
*/
42+
imageUrl?: string;
43+
44+
/** Image alt for users who are visually impaired. Maximum 420 characters. */
45+
imageAlt?: string;
46+
}
47+
548
export interface MetaEmbedProps {
49+
/** Returns meta properties to be rendered. */
50+
render: (meta: React.ReactNode) => JSX.Element;
51+
652
/** Unique page title that describes the page, such as `Home`, `About` etc. */
753
pageTitle: string;
854

@@ -23,17 +69,17 @@ export interface MetaEmbedProps {
2369
/** Canonical URL of your webpage that will be used as its default app URL. */
2470
canonicalUrl?: string;
2571

26-
/** Base URL of the site, excluding trailing slash. */
27-
siteBaseUrl: string;
72+
/** Base site URL, excluding trailing slash. */
73+
baseSiteUrl: string;
2874

2975
/** The path of the page, excluding leading slash. */
3076
pagePath?: string;
3177

3278
/**
3379
* List of SEO keywords describing what your webpage does.
34-
* For example, `"your, tags"` or `["your", "tags"]`.
80+
* Example: `"your, tags"` or `["your", "tags"]`.
3581
*/
36-
keywords: string | string[];
82+
keywords?: string | string[];
3783

3884
/**
3985
* Image url of asset to share. Recommended aspect ratio for landscape is
@@ -51,24 +97,26 @@ export interface MetaEmbedProps {
5197
* Defaults to `en_US`.
5298
*/
5399
locale?: string;
100+
101+
/** Twitter embed properties */
102+
twitter?: TwitterEmbedProps;
54103
}
55104

56105
const MetaHeadEmbed = ({
106+
render,
57107
pageTitle,
58108
siteTitle,
59109
titleTemplate,
60110
description,
61111
canonicalUrl,
62-
siteBaseUrl,
112+
baseSiteUrl,
63113
pagePath,
64114
keywords,
65115
imageUrl,
66116
imageAlt,
67117
locale = "en_US",
118+
twitter,
68119
}: MetaEmbedProps) => {
69-
const joinedKeywords =
70-
typeof keywords === "string" ? keywords : keywords?.join(", ");
71-
72120
const title = titleTemplate
73121
? pageTitle === siteTitle
74122
? pageTitle
@@ -81,28 +129,78 @@ const MetaHeadEmbed = ({
81129
canonicalUrl &&
82130
(isAbsoluteUrl(canonicalUrl)
83131
? canonicalUrl
84-
: `${siteBaseUrl}/${canonicalUrl}`);
85-
86-
const pageUrl = pagePath ? `${siteBaseUrl}/${pagePath}` : siteBaseUrl;
87-
88-
return (
89-
<>
90-
<title>{title}</title>
91-
<meta name="title" content={title} />
92-
<meta name="description" content={description} />
93-
<meta name="keywords" content={joinedKeywords} />
94-
{canonicalUrl && <link rel="canonical" href={canonical} />}
95-
96-
<meta property="og:type" content="website" />
97-
<meta property="og:url" content={pageUrl} />
98-
<meta property="og:title" content={title} />
99-
<meta property="og:description" content={description} />
100-
<meta property="og:image" content={imageUrl} />
101-
<meta property="og:image:alt" content={imageAlt} />
102-
<meta property="og:site_name" content={siteTitle} />
103-
<meta property="og:locale" content={locale} />
104-
</>
105-
);
132+
: `${baseSiteUrl}/${canonicalUrl}`);
133+
134+
const pageUrl = pagePath ? `${baseSiteUrl}/${pagePath}` : baseSiteUrl;
135+
136+
const metaEmbed = [
137+
<title key="title">{title}</title>,
138+
<meta key="meta:title" name="title" content={title} />,
139+
<meta key="meta:description" name="description" content={description} />,
140+
keywords && (
141+
<meta
142+
key="meta:keywords"
143+
name="keywords"
144+
content={commaSeparate(keywords)}
145+
/>
146+
),
147+
canonicalUrl && <link key="canonical" rel="canonical" href={canonical} />,
148+
149+
<meta key="og:type" property="og:type" content="website" />,
150+
<meta key="og:url" property="og:url" content={pageUrl} />,
151+
<meta key="og:title" property="og:title" content={title} />,
152+
<meta
153+
key="og:description"
154+
property="og:description"
155+
content={description}
156+
/>,
157+
<meta key="og:image" property="og:image" content={imageUrl} />,
158+
<meta key="og:image:alt" property="og:image:alt" content={imageAlt} />,
159+
<meta key="og:site_name" property="og:site_name" content={siteTitle} />,
160+
<meta key="og:locale" property="og:locale" content={locale} />,
161+
];
162+
163+
const twitterEmbed = ({
164+
cardSize,
165+
title,
166+
description,
167+
siteUsername,
168+
creatorUsername,
169+
imageUrl,
170+
imageAlt,
171+
}: TwitterEmbedProps) => [
172+
<meta
173+
key="twitter:card"
174+
name="twitter:card"
175+
content={cardSize === "large" ? "summary_large_image" : "summary"}
176+
/>,
177+
title && <meta key="twitter:title" name="twitter:title" content={title} />,
178+
description && (
179+
<meta
180+
key="twitter:description"
181+
name="twitter:description"
182+
content={description}
183+
/>
184+
),
185+
siteUsername && (
186+
<meta key="twitter:site" name="twitter:site" content={siteUsername} />
187+
),
188+
creatorUsername && (
189+
<meta
190+
key="twitter:creator"
191+
name="twitter:creator"
192+
content={creatorUsername}
193+
/>
194+
),
195+
imageUrl && (
196+
<meta key="twitter:image" name="twitter:image" content={imageUrl} />
197+
),
198+
imageAlt && (
199+
<meta key="twitter:alt" name="twitter:image:alt" content={imageAlt} />
200+
),
201+
];
202+
203+
return render([metaEmbed, twitter && twitterEmbed({ ...twitter })]);
106204
};
107205

108206
export default MetaHeadEmbed;

src/components/TwitterHeadEmbed.tsx

Lines changed: 0 additions & 69 deletions
This file was deleted.

src/index.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
export {
2-
default as SharingHeadEmbed,
2+
default as MetaHeadEmbed,
33
MetaEmbedProps,
4-
} from "./components/MetaHeadEmbed";
5-
6-
export {
7-
default as TwitterHeadEmbed,
84
TwitterEmbedProps,
9-
} from "./components/TwitterHeadEmbed";
5+
} from "./components/MetaHeadEmbed";
106

117
export {
128
default as getLinkedinUrl,
@@ -20,4 +16,9 @@ export {
2016
FacebookProps,
2117
} from "./utils/getFacebookUrl";
2218

19+
export {
20+
default as getShareUrl,
21+
AllSocialPlatformProps,
22+
} from "./utils/getShareUrl";
23+
2324
export { SocialPlatforms } from "./types";

src/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const commaSeparate = (words?: string | string[]) =>
2+
typeof words === "string" ? words : words?.join(",");

src/utils/getFacebookUrl.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ export interface FacebookProps extends BaseShareProps {
66
quote?: string;
77

88
/** Hashtag to show in Facebook card. */
9-
hashtag: string;
9+
hashtag?: string;
1010
}
1111

1212
export const getFacebookUrl = ({ url, quote, hashtag }: FacebookProps) =>
1313
`https://www.facebook.com/sharer/sharer.php${objectToUrlParams({
1414
u: url,
1515
quote,
16-
hashtag,
16+
hashtag: hashtag?.charAt(0) === "#" ? hashtag : `#${hashtag}`,
1717
})}`;
1818

1919
export default getFacebookUrl;

src/utils/getShareUrl.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import getFacebookUrl, { FacebookProps } from "./getFacebookUrl";
33
import getLinkedinUrl, { LinkedinProps } from "./getLinkedinUrl";
44
import getTwitterUrl, { TwitterProps } from "./getTwitterUrl";
55

6-
interface Props extends FacebookProps, LinkedinProps, TwitterProps {}
6+
export type AllSocialPlatformProps = FacebookProps &
7+
LinkedinProps &
8+
TwitterProps;
79

810
export const getShareUrl = (
911
socialPlatform: SocialPlatforms,
@@ -17,7 +19,7 @@ export const getShareUrl = (
1719
text,
1820
hashtags,
1921
related,
20-
}: Props
22+
}: AllSocialPlatformProps
2123
) => {
2224
switch (socialPlatform) {
2325
case SocialPlatforms.Facebook:

src/utils/getTwitterUrl.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
import { BaseShareProps } from "../types";
2+
import { commaSeparate } from "../utils";
23
import objectToUrlParams from "./objectToUrlParams";
34

45
export interface TwitterProps extends BaseShareProps {
56
/** Text to show in card. */
67
text?: string;
78

8-
/** Hashtags to show in Twitter card. */
9-
hashtags?: string[];
9+
/**
10+
* Hashtags to show in Twitter card.
11+
* Example: `"your, tags"` or `["your", "tags"]`.
12+
*/
13+
hashtags?: string | string[];
1014

11-
/** Accounts to recommend following. */
12-
related?: string[];
15+
/**
16+
* Accounts to recommend following.
17+
* Example: `"your, tags"` or `["your", "tags"]`.
18+
*/
19+
related?: string | string[];
1320
}
1421

1522
export const getTwitterUrl = ({ url, text, hashtags, related }: TwitterProps) =>
1623
`https://twitter.com/share${objectToUrlParams({
1724
url,
1825
text,
19-
hashtags: hashtags?.join(","),
20-
related: related?.join(","),
26+
hashtags: commaSeparate(hashtags),
27+
related: commaSeparate(related),
2128
})}`;
2229

2330
export default getTwitterUrl;

0 commit comments

Comments
 (0)