@astro-community/astro-embed-link-preview 0.1.0

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.
@@ -0,0 +1,107 @@
1
+ ---
2
+ import { parseOpenGraph } from './lib';
3
+
4
+ export interface Props {
5
+ /** URL to fetch Open Graph data. */
6
+ id: string;
7
+ }
8
+
9
+ const { id } = Astro.props;
10
+
11
+ const meta = await parseOpenGraph(id);
12
+ const domain = meta?.url ? new URL(meta.url).hostname.replace('www.', '') : '';
13
+ ---
14
+
15
+ {
16
+ meta && meta.title ? (
17
+ <article
18
+ class:list={[
19
+ 'link-preview',
20
+ {
21
+ 'link-preview--has-video': meta.video && meta.videoType,
22
+ 'link-preview--no-media': !(
23
+ (meta.video && meta.videoType) ||
24
+ meta.image
25
+ ),
26
+ },
27
+ ]}
28
+ >
29
+ <div class="link-preview__content">
30
+ <header>
31
+ <a class="link-preview__title" href={id}>
32
+ {meta.title}
33
+ </a>{' '}
34
+ {domain && <small class="link-preview__domain">{domain}</small>}
35
+ </header>
36
+ <small class="link-preview__description">{meta.description}</small>
37
+ </div>
38
+ {meta.video && meta.videoType ? (
39
+ <video controls preload="metadata" width="1200" height="630">
40
+ <source src={meta.video} type={meta.videoType} />
41
+ </video>
42
+ ) : (
43
+ meta.image && (
44
+ <img
45
+ src={meta.image}
46
+ alt={meta.imageAlt || ''}
47
+ width="1200"
48
+ height="630"
49
+ />
50
+ )
51
+ )}
52
+ </article>
53
+ ) : (
54
+ <div class="link-preview link-preview--no-metadata">
55
+ <a href={id}>{id}</a>
56
+ </div>
57
+ )
58
+ }
59
+
60
+ <style>
61
+ /* Default styles */
62
+ .link-preview {
63
+ --lp-width: var(--link-preview-width, 30em);
64
+ --lp-pad-x: var(--link-preview-padding-inline, 0);
65
+ --lp-pad-y: var(--link-preview-padding-block, 0.5em);
66
+ --lp-corners: var(--link-preview-corners, 0);
67
+
68
+ position: relative;
69
+ width: var(--lp-width);
70
+ max-width: 100%;
71
+ display: flex;
72
+ flex-direction: column-reverse;
73
+ border-radius: var(--lp-corners);
74
+ }
75
+ .link-preview * {
76
+ margin: 0 !important;
77
+ }
78
+ .link-preview__content {
79
+ display: flex;
80
+ flex-direction: column;
81
+ padding: var(--lp-pad-y) var(--lp-pad-x);
82
+ }
83
+ .link-preview header {
84
+ display: flex;
85
+ flex-direction: column-reverse;
86
+ }
87
+
88
+ .link-preview__description {
89
+ white-space: nowrap;
90
+ overflow: hidden;
91
+ text-overflow: ellipsis;
92
+ }
93
+ .link-preview:not(.link-preview--has-video) a::after {
94
+ content: '';
95
+ position: absolute;
96
+ inset: 0;
97
+ }
98
+ .link-preview img,
99
+ .link-preview video {
100
+ aspect-ratio: 1200 / 630;
101
+ width: 100%;
102
+ height: auto;
103
+ object-fit: cover;
104
+ border-top-left-radius: var(--lp-corners);
105
+ border-top-right-radius: var(--lp-corners);
106
+ }
107
+ </style>
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # `@astro-community/astro-embed-link-preview`
2
+
3
+ This package contains a component for embedding Open Graph media and metadata previews in Astro projects.
4
+
5
+ [Read the `<LinkPreview>` component docs](https://astro-embed.netlify.app/components/link-preview/).
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default as LinkPreview } from './LinkPreview.astro';
package/lib.ts ADDED
@@ -0,0 +1,45 @@
1
+ import { safeGetDOM } from '@astro-community/astro-embed-utils';
2
+
3
+ /** Helper to get the `content` attribute of an element. */
4
+ const getContent = (el: Element | null) => el?.getAttribute('content');
5
+ /** Helper to filter out insecure or non-absolute URLs. */
6
+ const urlOrNull = (url: string | null | undefined) =>
7
+ url?.slice(0, 8) === 'https://' ? url : null;
8
+
9
+ /**
10
+ * Loads and parses an HTML page to return Open Graph metadata.
11
+ * @param pageUrl URL to parse
12
+ */
13
+ export async function parseOpenGraph(pageUrl: string) {
14
+ const html = await safeGetDOM(pageUrl);
15
+ if (!html) return;
16
+
17
+ const getMetaProperty = (prop: string) =>
18
+ getContent(html.querySelector(`meta[property=${JSON.stringify(prop)}]`));
19
+ const getMetaName = (name: string) =>
20
+ getContent(html.querySelector(`meta[name=${JSON.stringify(name)}]`));
21
+
22
+ const title =
23
+ getMetaProperty('og:title') || html.querySelector('title')?.textContent;
24
+ const description =
25
+ getMetaProperty('og:description') || getMetaName('description');
26
+ const image = urlOrNull(
27
+ getMetaProperty('og:image:secure_url') ||
28
+ getMetaProperty('og:image:url') ||
29
+ getMetaProperty('og:image')
30
+ );
31
+ const imageAlt = getMetaProperty('og:image:alt');
32
+ const video = urlOrNull(
33
+ getMetaProperty('og:video:secure_url') ||
34
+ getMetaProperty('og:video:url') ||
35
+ getMetaProperty('og:video')
36
+ );
37
+ const videoType = getMetaProperty('og:video:type');
38
+ const url =
39
+ urlOrNull(
40
+ getMetaProperty('og:url') ||
41
+ html.querySelector("link[rel='canonical']")?.getAttribute('href')
42
+ ) || pageUrl;
43
+
44
+ return { title, description, image, imageAlt, url, video, videoType };
45
+ }
package/matcher.ts ADDED
@@ -0,0 +1,7 @@
1
+ // Matches any HTTPS URL.
2
+ const urlPattern = /(https:\/\/\S+)/;
3
+
4
+ export default function urlMatcher(url: string): string | undefined {
5
+ const match = url.match(urlPattern);
6
+ return match?.[0];
7
+ }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@astro-community/astro-embed-link-preview",
3
+ "version": "0.1.0",
4
+ "description": "Component to embed a website’s OpenGraph image and metadata on your Astro site",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": "./index.ts",
8
+ "./matcher": "./matcher.ts"
9
+ },
10
+ "files": [
11
+ "lib.ts",
12
+ "index.ts",
13
+ "matcher.ts",
14
+ "LinkPreview.astro"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/delucis/astro-embed",
19
+ "directory": "packages/astro-embed-link-preview"
20
+ },
21
+ "keywords": [
22
+ "astro",
23
+ "astro-component",
24
+ "embeds",
25
+ "open-graph"
26
+ ],
27
+ "license": "MIT",
28
+ "bugs": {
29
+ "url": "https://github.com/delucis/astro-embed/issues"
30
+ },
31
+ "homepage": "https://astro-embed.netlify.app/components/link-preview/",
32
+ "dependencies": {
33
+ "@astro-community/astro-embed-utils": "^0.1.1"
34
+ }
35
+ }