Files
lucide/docs/.vitepress/markdown/snackPlayer.ts
Copilot 75b55160aa chore(dev): upgrade ESLint to latest compatible stack (v10) (#4378)
* chore: upgrade eslint to v9 latest with compatible lint deps

Agent-Logs-Url: https://github.com/lucide-icons/lucide/sessions/f7c1f1b5-d213-4afa-91a8-b799a16397ec

* Fix eslint config

* Fix a lot of eslint errors

* Fix eslint

* Fix eslint errors

* Fix eslint errors

* Fix types

* Fix eslint warning

* Format code

* Add eslint 10

* Remove unused vars

* Update pnpm

* Update deps

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Eric Fennis <eric.fennis@gmail.com>
2026-08-18 13:09:22 +02:00

99 lines
2.9 KiB
TypeScript

/**
* SnackPlayer markdown-it plugin
*
* Converts fenced code blocks like:
*
* ```SnackPlayer name=My%20Example&description=Nice%20demo&ext=tsx
* // code here
* ```
*
* into:
*
* <div
* class="snack-player"
* data-snack-name="My Example"
* ...
* />
*/
import type MarkdownIt from 'markdown-it';
type SnackParams = Record<string, string>;
function parseParams(paramString = ''): SnackParams {
const params = Object.fromEntries(new URLSearchParams(paramString)) as SnackParams;
if (!params.platform) {
params.platform = 'web';
}
return params;
}
export default function snackPlayerPlugin(md: MarkdownIt) {
const escapeHtml = md.utils.escapeHtml;
const defaultFence =
md.renderer.rules.fence ||
((tokens, idx, options, env, self) => self.renderToken(tokens, idx, options));
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const info = (token.info || '').trim();
if (!info) {
return defaultFence(tokens, idx, options, env, self);
}
const [lang, ...rest] = info.split(/\s+/);
if (lang !== 'SnackPlayer') {
return defaultFence(tokens, idx, options, env, self);
}
const paramString = rest.join(' ');
const params = parseParams(paramString);
// Gather necessary params
const name = params.name ? decodeURIComponent(params.name) : 'Example';
const description = params.description
? decodeURIComponent(params.description)
: 'Example usage';
const ext = params.ext ? decodeURIComponent(params.ext) : 'tsx';
const filename = `App.${ext}`;
const files = encodeURIComponent(
JSON.stringify({
[filename]: {
type: 'CODE',
contents: token.content,
},
}),
);
const dependencies =
'react-native-safe-area-context' + (params.dependencies ? `,${params.dependencies}` : '');
const platform = params.platform ?? 'web';
const supportedPlatforms = params.supportedPlatforms ?? 'ios,android,web';
const preview = params.preview ?? 'true';
const loading = params.loading ?? 'lazy';
const deviceAppearance = params.deviceAppearance ?? 'dark';
// Build the HTML output (escaping where appropriate)
return (
`<SnackPlayer` +
` class="snack-player"` +
` data-snack-name="${escapeHtml(name)}"` +
` data-snack-description="${escapeHtml(description)}"` +
` data-snack-files="${files}"` +
` data-snack-dependencies="${escapeHtml(dependencies)}"` +
` data-snack-platform="${escapeHtml(platform)}"` +
` data-snack-supported-platforms="${escapeHtml(supportedPlatforms)}"` +
// ` data-snack-theme="${escapeHtml(params.theme ?? 'light')}"` +
` data-snack-preview="${escapeHtml(preview)}"` +
` data-snack-loading="${escapeHtml(loading)}"` +
` data-snack-device-appearance="${escapeHtml(deviceAppearance)}"` +
` data-snack-device-frame="false"` +
`></SnackPlayer>`
);
};
}