Code Monkey home page Code Monkey logo

astro-remote's Introduction

Astro Remote

NPM Version

Render remote HTML or Markdown content in Astro with full control over the output.

Powered by ultrahtml and marked.

Install

npm install astro-remote
pnpm install astro-remote
yarn install astro-remote

Rendering Remote Content

The most basic function of astro-remote is to convert a string of HTML or Markdown to HTML. Use the Markup and Markdown components depending on your input.

---
import { Markup, Markdown } from 'astro-remote';
const { html, markdown } = await fetch('http://my-site.com/api/v1/post').then(res => res.json());
---

<Markup content={html} />
<Markdown content={markdown} />

Sanitization

By default, all HTML content will be sanitized with sensible defaults (script blocks are dropped). This can be controlled using the SanitizeOptions available in ultrahtml. Set to false to disable sanitization.

---
import { Markup } from 'astro-remote';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---

<!-- Disallow `head` and `style` attributes, and standard formatting from host website -->
<Markup 
    content={content} 
    sanitize={{ 
        dropElements: ["head","style"], 
        blockElements: ["html", "body", "div"],
    }} 
/>

Customization

Both Markup and Markdown allow full control over the rendering of output. The components option allows you to replace a standard HTML element with a custom component.

---
import { Markdown, Markup } from 'astro-remote';
import Title from '../components/Title.astro';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---

<!-- Render <h1> as custom <Title> component -->
<Markup content={content} components={{ h1: Title }} />
<Markdown content={content} components={{ h1: Title }} />

In addition to built-in HTML Elements, Markdown also supports a few custom components for convenience.

<Heading />

The Heading component renders all h1 through h6 elements. It receives the following props:

  • as, the h1 through h6 tag
  • href, a pre-generated, slugified href
  • text, the text content of the children (for generating a custom slug)
---
import { Markdown } from 'astro-remote';
import Heading from '../components/Heading.astro';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---

<!-- Render all <h1> through <h6> using custom <Heading> component -->
<Markdown content={content} components={{ Heading }} />

A sample Heading component might look something like this.

---
const { as: Component, href } = Astro.props;
---

<Component><a href={href}><slot /></a></Component>

<CodeBlock />

The CodeBlock component allows you customize the rendering of code blocks. It receives the following props:

  • lang, the language specified after the three backticks (defaults to plaintext)
  • code, the raw code to be highlighted. Be sure to escape the output!
  • ...props, any other attributes passed to the three backticks. These should follow HTML attribute format (name="value")

A sample CodeBlock component might look something like this.

---
const { lang, code, ...props } = Astro.props;
const highlighted = await highlight(code, { lang });
---

<pre class={`language-${lang}`}><code set:html={highlighted} /></pre>

<CodeSpan />

The CodeSpan component allows you customize the rendering of inline code spans. It receives the following props:

  • code, the value of the code span

A sample CodeSpan component might look something like this.

---
const { code } = Astro.props;
---

<code set:text={code} />

<Note />

The Note component allows you customize the rendering of GitHub-style notes and warnings. It receives the following props:

  • type, either "note" or "warning"

To use a Note component in Markdown, use the following syntax:

> **Note**
> Some tip here!

> **Warning**
> Some warning here!

Custom Components in Markdown

If you'd like to allow custom components in Markdown, you can do so using a combination of the sanitize and components options. By default, sanitization removes components.

Given the following markdown source:

# Hello world!

<MyCustomComponent a="1" b="2" c="3">It works!</MyCustomComponent>
---
import { Markdown } from 'astro-remote';
import MyCustomComponent from '../components/MyCustomComponent.astro';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---

<Markdown content={content} sanitize={{ allowComponents: true }} components={{ MyCustomComponent }} />

Using Marked Extensions

If you'd like to extend the underlying Marked behavior, the marked prop accepts extensions.

---
import { Markdown } from 'astro-remote';
import markedAlert from 'marked-alert'

const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---

<Markdown content={content} marked={{ extensions: [ markedAlert() ] }} />

astro-remote's People

Contributors

adammatthiesen avatar github-actions[bot] avatar juliancataldo avatar natemoo-re avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

astro-remote's Issues

Some content disappear inside paragraph tags

Thanks @natemoo-re, that's an awesome plugin for SSR uses!

I'm actually evaluating it for this work-in-progress: https://github.com/JulianCataldo/content-maestro
It's a content edition framework, with advanced Astro integration in mind, for SSR live-content feeding.

astro-remote is promising for my uses cases, and I've successfully binded the two and injected custom components, however,

I've encountered this major issue:


Setup:

pnpx degit natemoo-re/astro-remote .
pnpm i
pnpm run dev

Edit ./packages/demo/src/pages/index.astro

      <Markdown
        content={`
      
      Double spaces here ->  
      Oh no! Everything disappear

      Works fine here.
      
      `}
        components={{}}
      />

result:

      <p><br></p><p>Works fine here.</p>

Add some bold:

      <Markdown
        content={`
      
      Double spaces here ->  
      Oh no! **Everything** (BOLDed) disappear

      Works fine here.
      
      `}
        components={{}}
      />

result:

<p><br>Oh no! <strong>Everything</strong></p><p>Works fine here.</p>

Might be a bug with the parser maybe? (ultra-html).

This occurs also with the <Markup /> component, which I was using in the first place, with pre-transformed markdown from content-maestro server.

Adding spaces at specific places removes first characters.

Having spaces and newlines or spaces at the end of the paragraph makes it so first characters are not rendered correctly. Given code like this:

---
import { Markdown } from "astro-remote";

// Working as expected
const c0 = `Most .`;

// 1 space
const c1 = `Most 
.`;

// 2 spaces
const c2 = `Most  
.`;

// Space at the end
const c3 = `Most . `;

const content = [c0, c1, c2, c3];
---
<div>
	{content.map((c) => <Markdown san>{c}</Markdown>)}
</div>

Result is
image

Reproduction

This is not issue with marked since it handles those use cases correctly

he.decode is not a function inside production ssr mode

When running built project I get error he.encode is not a function

Manually inserting console.log inside dist/server/entry.mjs file 'he' module functions are exported inside default namespace

[Module: null prototype] {
  default: {
    version: '1.2.0',
    encode: [Function: encode] { options: [Object] },
    decode: [Function: decode] { options: [Object] },
    escape: [Function: escape],
    unescape: [Function: decode] { options: [Object] }
  }
}

To fix this I tried adding 'he' to noExternal which fixes it during production, but breaks dev mode

export default defineConfig({
  vite: {
    ssr: {
      noExternal: ['he'],
    },
  },
})

Throws error when building.

I'm guessing the latest pull request may fix this. Getting this when building.

Error: Invalid second argument for `transform`! Expected `Transformer[]` but got `object`
--
15:26:55.883 | at B (file:///vercel/path0/node_modules/ultrahtml/dist/index.js:1:4646)
15:26:55.883 | at markdown (file:///vercel/path0/dist/chunks/prerender_x7JghXdG.mjs:3260:10)
15:26:55.883 | at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
15:26:55.883 | at async file:///vercel/path0/dist/chunks/prerender_x7JghXdG.mjs:3281:19

Support for ~~`Fragment`~~ and named slots

Hey there!

Actually, passing the Fragment component like this doesn't seems to work:

  <Markdown
    content={content}
    components={{
      // ...,
      Fragment,
      Tabs,
    }}
  />

In a MD:

<Fragment slot="tab-1">Tab 1</Fragment>

Fragment is skipped
Using a real elem. like div fixes this.
However named slots are not supported. The default one are working well.


EDIT:
Ok, I've done some test, and passing Fragment is effective, it's the named slots which are the culprit.

Any Change for Revival?

So I created a HTML only version (for Astro-GhostCMS) of this that I would love to merge, to help upgrade the package to current versions. But I haven't figured out the markdown side of things yet.

Are you still interested in this project? I do understand that you a busy person I would love to help keep a useful tool alive, as it dose extend on the functionality of your great utility ultrahtml! and still has a good usage today.

Props are passed to React TSX component but not Astro ones

Astro.props outputs nothing, while React components are receiving attributes properly.

E.g.

	<Markdown
		content={pkg.readme}
		components={{
			pre: Code,
		}}
	/>

React params:

{
  "children": {
    "key": null,
    "ref": null,
    "props": {
      "value": "<code class=\"language-sh\">pnpm astro add @astro-content/validator\n</code>"
    },
    "_owner": null,
    "_store": {}
  }
}

Other method that could be a "work-around" or a "nice-to-have" depending on the case:

	<Markdown
		content={pkg.readme}
		components={{
			pre: (attrs) => <Code code={'...'} />,
		}}
	/>

Yields:

Expected ">" but found "code"

No License File

Could you add a license file? I am hoping for something permissive open source but I can't use this at all without knowing some kind of license.

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.