mirror of
https://github.com/sern-handler/website
synced 2026-06-27 02:02:23 +00:00
feat: migrate to starlight
This commit is contained in:
52
node_modules/astro-remote/lib/Markdown.astro
generated
vendored
Normal file
52
node_modules/astro-remote/lib/Markdown.astro
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
import type { SanitizeOptions } from 'ultrahtml/transformers/sanitize'
|
||||
import { createComponentProxy, markdown } from './utils';
|
||||
import type { MarkedExtension } from 'marked';
|
||||
|
||||
export interface Props {
|
||||
/** The markdown content to be rendered. If not provided, the content will be taken from the default slot.
|
||||
* @example
|
||||
*
|
||||
<Markdown
|
||||
content={MarkdownContent}
|
||||
/>
|
||||
*/
|
||||
content?: string;
|
||||
/** Allows the user to define custom SanitizeOptions to be used when rendering the markdown.
|
||||
* @example
|
||||
*
|
||||
<Markdown
|
||||
sanitize={{ allowComponents: true }}
|
||||
/>
|
||||
*/
|
||||
sanitize?: SanitizeOptions;
|
||||
/** Allows the user to pass in custom components to be used when rendering the markdown.
|
||||
* @example
|
||||
*
|
||||
<Markdown
|
||||
components={{ Heading, CodeBlock, CodeSpan, Note }}
|
||||
/>
|
||||
*/
|
||||
components?: Record<string, any>;
|
||||
/** Allows usage of Marked extensions to use when rendering the markdown.
|
||||
* @example
|
||||
*
|
||||
<Markdown
|
||||
marked={{extensions: [MarkedExtension1(), MarkedExtension2(), MarkedExtension3()]}}
|
||||
/>
|
||||
*/
|
||||
marked?: {
|
||||
extensions?: MarkedExtension[]
|
||||
}
|
||||
}
|
||||
|
||||
const input = Astro.props.content ?? await Astro.slots.render('default');
|
||||
if (!input) {
|
||||
throw new Error('Unable to render <Markdown> without a content prop or children')
|
||||
}
|
||||
// @ts-ignore
|
||||
const components = createComponentProxy($$result, Astro.props.components);
|
||||
const content = await markdown(input, { sanitize: Astro.props.sanitize, components }, Astro.props.marked?.extensions);
|
||||
---
|
||||
|
||||
<Fragment set:html={content} />
|
||||
41
node_modules/astro-remote/lib/Markup.astro
generated
vendored
Normal file
41
node_modules/astro-remote/lib/Markup.astro
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
import type { SanitizeOptions } from 'ultrahtml/transformers/sanitize'
|
||||
import { createComponentProxy, html } from './utils';
|
||||
|
||||
export interface Props {
|
||||
/** The HTML content to be rendered. If not provided, the content will be taken from the default slot.
|
||||
* @example
|
||||
*
|
||||
<Markup
|
||||
content={HTMLContent}
|
||||
/>
|
||||
*/
|
||||
content?: string;
|
||||
/** Allows the user to define custom SanitizeOptions to be used when rendering the HTML.
|
||||
* @example
|
||||
*
|
||||
<Markup
|
||||
sanitize={{ allowComponents: true }}
|
||||
/>
|
||||
*/
|
||||
sanitize?: SanitizeOptions;
|
||||
/** Allows the user to pass in custom components to be used when rendering the HTML.
|
||||
* @example
|
||||
*
|
||||
<Markup
|
||||
components={{ Heading, CodeBlock, CodeSpan, Note }}
|
||||
/>
|
||||
*/
|
||||
components?: Record<string, any>;
|
||||
}
|
||||
|
||||
const input = Astro.props.content ?? await Astro.slots.render('default');
|
||||
if (!input) {
|
||||
throw new Error('Unable to render <Markup> without a content prop or children')
|
||||
}
|
||||
// @ts-ignore
|
||||
const components = createComponentProxy($$result, Astro.props.components);
|
||||
const content = await html(input, { sanitize: Astro.props.sanitize, components });
|
||||
---
|
||||
|
||||
<Fragment set:html={content} />
|
||||
1
node_modules/astro-remote/lib/env.d.ts
generated
vendored
Normal file
1
node_modules/astro-remote/lib/env.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="astro/client" />
|
||||
131
node_modules/astro-remote/lib/utils.ts
generated
vendored
Normal file
131
node_modules/astro-remote/lib/utils.ts
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
/**@ts-expect-error */
|
||||
import { renderJSX } from "astro/runtime/server/jsx";
|
||||
import { jsx as h } from "astro/jsx-runtime";
|
||||
import { transform, __unsafeHTML } from "ultrahtml";
|
||||
import sanitize from "ultrahtml/transformers/sanitize";
|
||||
import swap from "ultrahtml/transformers/swap";
|
||||
|
||||
import { type MarkedExtension, marked } from "marked";
|
||||
import markedFootnote from "marked-footnote";
|
||||
import { markedSmartypants } from "marked-smartypants";
|
||||
|
||||
import * as entities from "entities";
|
||||
|
||||
export function createComponentProxy(
|
||||
result: any,
|
||||
_components: Record<string, any> = {},
|
||||
) {
|
||||
const components: Record<string, any> = {};
|
||||
for (const [key, value] of Object.entries(_components)) {
|
||||
if (typeof value === "string") {
|
||||
components[key] = value;
|
||||
} else {
|
||||
components[key] = async (
|
||||
props: Record<string, any>,
|
||||
children: { value: any },
|
||||
) => {
|
||||
if (key === "CodeBlock" || key === "CodeSpan") {
|
||||
props.code = entities.decode(JSON.parse(`"${props.code}"`));
|
||||
}
|
||||
const output = await renderJSX(
|
||||
result,
|
||||
h(value, { ...props, "set:html": children.value }),
|
||||
);
|
||||
return __unsafeHTML(output);
|
||||
};
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
function getIndent(ln: string): string {
|
||||
if (ln.trim() === ln) return "";
|
||||
return ln.slice(0, ln.length - ln.trim().length);
|
||||
}
|
||||
|
||||
export function dedent(str: string): string {
|
||||
const lns = str.replace(/^[\r\n]+/, "").split("\n");
|
||||
let indent = getIndent(lns[0]);
|
||||
if (indent.length === 0 && lns.length > 1) {
|
||||
indent = getIndent(lns[1]);
|
||||
}
|
||||
if (indent.length === 0) return lns.join("\n");
|
||||
return lns
|
||||
.map(ln => ln.startsWith(indent) ? ln.slice(indent.length) : ln)
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
export interface HTMLOptions {
|
||||
sanitize?: Record<string, any>;
|
||||
components?: Record<string, any>;
|
||||
}
|
||||
|
||||
export async function markdown(
|
||||
input: string,
|
||||
opts: HTMLOptions = {},
|
||||
markedExtenstion: MarkedExtension[] = [],
|
||||
): Promise<string> {
|
||||
const renderer: any = {};
|
||||
if (opts.components) {
|
||||
if ("Note" in opts.components) {
|
||||
renderer.blockquote = (text: string) => {
|
||||
const lines = text.split("\n");
|
||||
const ln = lines[0].replace("<p>", "");
|
||||
if (ln === "<strong>Note</strong>") {
|
||||
return `<Note type="note"><p>${lines.slice(1).join("\n")}</Note>`;
|
||||
}
|
||||
if (ln === "<strong>Warning</strong>") {
|
||||
return `<Note type="warning"><p>${lines.slice(1).join("\n")}</Note>`;
|
||||
}
|
||||
return `<blockquote>${text}</blockquote>`;
|
||||
};
|
||||
}
|
||||
if ("Heading" in opts.components) {
|
||||
renderer.heading = (
|
||||
children: string,
|
||||
level: number,
|
||||
raw: string,
|
||||
slugger: { slug: (arg0: string) => any },
|
||||
) => {
|
||||
//const slug = slugger.slug(raw);
|
||||
// href="#${slug}"
|
||||
return `<Heading as="h${level}" text="${raw}">${children}</Heading>`;
|
||||
};
|
||||
}
|
||||
if ("CodeBlock" in opts.components) {
|
||||
renderer.code = (code: string, meta = "") => {
|
||||
const info = meta.split(/\s+/g) ?? [];
|
||||
const lang = info[0] ?? "plaintext";
|
||||
const value = JSON.stringify(entities.encode(code));
|
||||
return `<CodeBlock lang=${JSON.stringify(lang)} code=${value} ${info
|
||||
.splice(1)
|
||||
.join(" ")} />`;
|
||||
};
|
||||
}
|
||||
if ("CodeSpan" in opts.components) {
|
||||
renderer.codespan = (code: string) => {
|
||||
const value = JSON.stringify(entities.encode(code));
|
||||
return `<CodeSpan code=${value}>${code}</CodeSpan>`;
|
||||
};
|
||||
}
|
||||
}
|
||||
marked.use(markedSmartypants(), markedFootnote(), ...markedExtenstion, {
|
||||
gfm: true,
|
||||
renderer,
|
||||
});
|
||||
const content = await marked.parse(dedent(input));
|
||||
return transform(content, [
|
||||
swap(opts.components),
|
||||
sanitize(opts.sanitize),
|
||||
]);
|
||||
}
|
||||
|
||||
export async function html(
|
||||
input: string,
|
||||
opts: HTMLOptions = {},
|
||||
): Promise<string> {
|
||||
return transform(dedent(input), [
|
||||
sanitize(opts.sanitize),
|
||||
swap(opts.components),
|
||||
]);
|
||||
}
|
||||
Reference in New Issue
Block a user