Giter VIP home page Giter VIP logo

gatsby-remark-link-summary's Introduction

gatsby-remark-link-summary

npm version test License: MIT

This plugin scrapes link nodes and replaces the link nodes to summary nodes that you designed using scraped data (e.g. og:title, og:image, og:description).

Example Output

This plugin can convert text links in a markdown file to links with images as follows:

from

[--small-card--](https://www.npmjs.com/package/gatsby-remark-link-summary)
[--large-card--](https://github.com/blyoa/gatsby-remark-link-summary)

to

card with small image card with large image

Installation

npm install gatsby-remark-link-summary

Usage

// In your gatsby-config.js
plugins: [
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        {
          // put `gatsby-remark-link-summary` before `gatsby-remark-images`
          // if generated nodes by `generator` includes img elements and
          // the image nodes should be processed by `gatsby-remark-images`
          resolve: `gatsby-remark-link-summary`,
          options: {
            cacheRootDirPath: 'path/to/cache',
            destinationSubDirPath: 'path/to/sub/dir',
            sites: [
              {
                pattern: /^https:\/\/github\.com\/.*/,
                generator: async ({ metadata: { url, title, image }, cacheRemoteFile }) => {
                  const deployedPath = await cacheRemoteFile(image, true)
                  return `<a href="${url}"><img src="${deployedPath}"/></a>`
                },
                rules: [
                  require('metascraper-url')(),
                  require('metascraper-image')(),
                ],
                gotOptions: {
                  // e.g.
                  // timeout: ...
                  // retry: ...
                },
                cacheExpirationSecond: 60 * 60 * 24 * 10, // 10 days
              },
              {
                // replace link nodes that have the text "--summary-card--"
                // e.g.
                // [--summary-card--](https://example.com)
                pattern: (node) => {
                  if (node.children.length === 0) return false
                  const [firstChild] = node.children
                  return  (firstChild.type === 'text' && firstChild.value === '--summary-card--')
                  // NOTE: The URL of a link node can be obtained from `node.url`
                },
                generator: async ({ metadata: { url, title, image }, cacheRemoteFile }) => {
                  const deployedPath = await cacheRemoteFile(image, true)
                  return `<a href="${url}"><img src="${deployedPath}"/></a>`
                },
                rules: [
                  require('metascraper-url')(),
                  require('metascraper-image')(),
                ],
              },
            ],
          },
        },
      ],
    },
  },
],

Options

name type description
cacheRootDirPath string | undefined A directory to place remote files fetched by cacheRemoteFile of HTMLGeneratorParams and a catalog file about the fetched files and scraped metadata. If this option is undefined, the catalog file is not saved.
destinationSubDirPath string A subdirectory of the directory for built artifacts (i.e., the public directory) to place remote files fetched in the second argument of generator.
sites SiteOptions[] Node generator options for sites.

SiteOptions

name type description
pattern RegExp | (node: Link) => boolean A target link node to be substituted. RegExp specifies URLs of the link node to be substituted, and the function returns whether the link node should be substituted or not. Link is the type defined in mdast package.
generator (params: HTMLGeneratorParams) => string | Node | Promise<string | Node> A function to generate the node that substitute a link node.
rules Rule[] Rules for metascraper.
gotOptions Options[] | undefined Options for got.
cacheExpirationSecond number | undefined The expiration second of scraped metadata and fetched remote files. The metadata and the path to the fetched remote file are reused until this expiration second reaches.

If this option is undefined, the fetched metadata and the fetched remote files never expire.

HTMLGeneratorParams

name type description
metadata Record<string, string> Metadata scraped by metascraper.
orignalNode Link An original link node that generator substitutes.
cacheRemoteFile (fileURL: string, persistent?: boolean) => Promise<string> A function to fetch a remote file and returns the path to the fetched file in destinationSubDirPath. fileURL is the URL of the remote file. When persistent is true, the fetched file is also saved in cachedRootDirPath.

Example Settings

Card With Small Image

card with small image

gatsby-config.js

const descriptionRule = require("metascraper-description")
const imageRule = require("metascraper-image")
const titleRule = require("metascraper-title")
const urlRule = require("metascraper-url")

module.exports = {
  // snip...
  plugins: [
    // snip...
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-link-summary`,
            options: {
              cacheRootDirPath: "cache/link-summary",
              destinationSubDirPath: "link-summary",
              sites: [
                {
                  pattern: /^https:\/\/www\.npmjs\.com\/.*/,
                  generator: async ({
                    metadata: { image, url, title, description },
                    cacheRemoteFile,
                  }) => {
                    const filePath = await cacheRemoteFile(image, true)
                    return `
                      <div class="summary-card">
                        <a href="${url}">
                          <img
                            class="summary-card__image"
                            src="${filePath}"
                          />
                          <div class="summary-card__description">
                            <div class="summary-card__description__title"
                              >${title}</div
                            >
                            <div class="summary-card__description__summary"
                              >${description}</div
                            >
                            <div class="summary-card__description__url"
                              >${url}</div
                            >
                          </div>
                        </a>
                      </div>
                    `
                  },
                  rules: [
                    urlRule(),
                    titleRule(),
                    imageRule(),
                    descriptionRule(),
                  ],
                },
              ],
            },
          },
          // snip...
        ],
      },
    },
    // snip...
  ],
}

your-style-file.css

/* import css, e.g. from gatsby-browser.js */
.summary-card {
  line-height: 1.5;
}

.summary-card a {
  color: inherit;
  text-decoration: none;
  display: flex;
  flex-direction: row-reverse;
  align-items: center;
  border: 1px solid #e5e5e5;
  border-radius: 3px;
}

.summary-card__image {
  width: 14rem;
  height: 10rem;
  object-fit: cover;
  border-inline-start: 1px solid #e5e5e5;
}

.summary-card__description {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 0 1.2rem;
  overflow: hidden;
}

.summary-card__description__title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  font-weight: 700;
  max-height: calc(2rem * 1.5);
  overflow: hidden;
}

.summary-card__description__summary {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  margin-block-start: 0.4rem;
  font-size: 0.8rem;
  max-height: calc(1.6rem * 1.5);
  overflow: hidden;
  color: #a3a3a3;
}

.summary-card__description__url {
  margin-block-start: 0.6rem;
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  color: #a3a3a3;
}

Card With Large Image

card with large image

gatsby-config.js

const descriptionRule = require("metascraper-description")
const imageRule = require("metascraper-image")
const titleRule = require("metascraper-title")
const urlRule = require("metascraper-url")

module.exports = {
  // snip...
  plugins: [
    // snip...
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-link-summary`,
            options: {
              cacheRootDirPath: "cache/link-summary",
              destinationSubDirPath: "link-summary",
              sites: [
                {
                  pattern: /^https:\/\/github\.com\/.*/,
                  generator: async ({
                    metadata: { image, url, title, description },
                    cacheRemoteFile,
                  }) => {
                    const filePath = await cacheRemoteFile(image, true)
                    return `
                      <div class="large-image-summary-card">
                        <a href="${url}">
                          <img
                            class="large-image-summary-card__image"
                            src="${filePath}"
                          />
                          <div class="large-image-summary-card__description">
                            <div class="large-image-summary-card__description__title"
                              >${title}</div
                            >
                            <div class="large-image-summary-card__description__summary"
                              >${description}</div
                            >
                            <div class="large-image-summary-card__description__url"
                              >${url}</div
                            >
                          </div>
                        </a>
                      </div>
                    `
                  },
                  rules: [
                    urlRule(),
                    titleRule(),
                    imageRule(),
                    descriptionRule(),
                  ],
                },
              ],
            },
          },
          // snip...
        ],
      },
    },
    // snip...
  ],
}
your-style-file.css
/* import css, e.g. from gatsby-browser.js */
.large-image-summary-card {
  line-height: 1.5;
}

.large-image-summary-card a {
  display: flex;
  color: inherit;
  text-decoration: none;
  flex-direction: column;
  border: 1px solid #e5e5e5;
  border-radius: 3px;
}

.large-image-summary-card__image {
  width: 100%;
  object-fit: cover;
  border-block-end: 1px solid #e5e5e5;
}

.large-image-summary-card__description {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 1.2rem;
}

.large-image-summary-card__description__title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  font-weight: 700;
  max-height: calc(2rem * 1.5);
  overflow: hidden;
}

.large-image-summary-card__description__summary {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  margin-top: 0.2rem;
  font-size: 0.8rem;
  max-height: calc(1.6rem * 1.5);
  overflow: hidden;
  color: #a3a3a3;
}

.large-image-summary-card__description__url {
  margin-top: 0.4rem;
  font-size: 0.8rem;
  color: #a3a3a3;
  overflow: hidden;
  text-overflow: ellipsis;
}

gatsby-remark-link-summary's People

Contributors

blyoa avatar dependabot[bot] avatar

Stargazers

 avatar

Watchers

 avatar

gatsby-remark-link-summary's Issues

PQR: Worker exited before finishing task

After I installed this plugin gatsby-remark-link-summary. I see it uses async/await internally: code ref

When I run Gatsby build, I see this error:

 AggregateError: 
  
  - deploy.ts:200 deployRemoteFile
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/deploy.ts:200:13
  
  - plugin.ts:131 
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/plugin.ts:131:17
  
  - gatsby-config.js:81 Object.generator
    /Users/gopala.akshintala/code-clones/my-github/overfullstack.github.io/gatsby-config.js:81:38
  
  - plugin.ts:193 
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/plugin.ts:193:29
  
  - async-visit.ts:29 visitRecursively
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/async-visit.ts:29:31
  
  - async-visit.ts:35 visitRecursively
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/async-visit.ts:35:5
  
  - async-visit.ts:35 visitRecursively
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/async-visit.ts:35:5
  
  - async-visit.ts:21 visit
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/async-visit.ts:21:3
  
  - plugin.ts:221 exports.default
    [overfullstack.github.io]/[gatsby-remark-link-summary]/src/plugin.ts:221:3
  
  - extend-node-type.js:245 parseString
    [overfullstack.github.io]/[gatsby-transformer-remark]/extend-node-type.js:245:11
  
  - extend-node-type.js:199 getAST
    [overfullstack.github.io]/[gatsby-transformer-remark]/extend-node-type.js:199:29
  
  - extend-node-type.js:371 getHTMLAst
    [overfullstack.github.io]/[gatsby-transformer-remark]/extend-node-type.js:371:21
  
  - extend-node-type.js:385 getHTML
    [overfullstack.github.io]/[gatsby-transformer-remark]/extend-node-type.js:385:21
  
  - async Promise.all
  
  - async Promise.all
  
  - graphql-runner.ts:255 GraphQLRunner.query
    [overfullstack.github.io]/[gatsby]/src/query/graphql-runner.ts:255:14
  


 ERROR #85928  GRAPHQL.QUERY_RUNNING

An error occurred during parallel query running.
Go here for troubleshooting tips: https://gatsby.dev/pqr-feedback



  Error: Worker exited before finishing task
  
  - index.js:205 ChildProcess.<anonymous>
    [overfullstack.github.io]/[gatsby-worker]/dist/index.js:205:41
  

not finished run queries in workers - 4.458s
not finished Running gatsby-plugin-sharp.IMAGE_PROCESSING jobs - 3.901s

I tried with GATSBY_CPU_COUNT: 1, but got the same error. Interestingly, the gatsby build intermittently passes

Repo commit to reproduce: overfullstack/overfullstack.github.io@8d647ab

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.