Files
lucide/docs/api/gh-icon/[...data].get.tsx
2026-11-06 13:05:36 +01:00

63 lines
2.0 KiB
TypeScript

import { defineHandler } from 'nitro/h3';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import React from 'react';
import SvgPreview from '~/.vitepress/lib/SvgPreview/index.tsx';
import iconNodes from '~/.vitepress/data/iconNodes';
import createLucideIcon from 'lucide-react/src/createLucideIcon';
import Backdrop from '~/.vitepress/lib/SvgPreview/Backdrop.tsx';
export default defineHandler((event) => {
const { params } = event.context;
const pathData = params.data.split('/');
const data = pathData.at(-1).slice(0, -4);
const [name] = pathData;
const src = Buffer.from(data, 'base64').toString('utf8').replaceAll('\n', '');
const width = parseInt((src.includes('<svg ') ? src.match(/width="(\d+)"/)?.[1] : null) ?? '24');
const height = parseInt(
(src.includes('<svg ') ? src.match(/height="(\d+)"/)?.[1] : null) ?? '24',
);
const children = [];
// Finds the longest matching icon to be use as the backdrop.
// For `square-dashed-bottom-code` it suggests `square-dashed-bottom-code`.
// For `square-dashed-bottom-i-dont-exist` it suggests `square-dashed-bottom`.
const backdropName = name
.split('-')
.map((_, idx, arr) => arr.slice(0, idx + 1).join('-'))
.reverse()
.find((groupName) => groupName in iconNodes);
if (!(name in iconNodes) && backdropName) {
const iconNode = iconNodes[backdropName];
const LucideIcon = createLucideIcon(backdropName, iconNode);
const svg = renderToStaticMarkup(<LucideIcon />);
const backdropString = svg.replaceAll('\n', '').replace(/<svg[^>]*>|<\/svg>/g, '');
children.push(
<Backdrop
backdropString={backdropString}
src={src.replace(/<svg[^>]*>|<\/svg>/g, '')}
color="#777"
/>,
);
}
event.res.headers.set('Content-Type', 'image/svg+xml');
event.res.headers.set('Cache-Control', 'public,max-age=31536000');
return renderToString(
<SvgPreview
src={src.replace(/<svg[^>]*>|<\/svg>/g, '')}
showGrid
height={height}
width={width}
>
{children}
</SvgPreview>,
);
});