mirror of
https://github.com/lucide-icons/lucide.git
synced 2026-11-12 13:38:32 +00:00
feat: added backdrop to gh-icon (#1097)
* feat: added backdrop to gh-icon * feat: added backdrop to gh-icon * feat: changed fill pattern * chore: pattern cleanup * feat: improved backdrop color
This commit is contained in:
@@ -32,7 +32,7 @@ jobs:
|
||||
tr '\n' ' ' | # remove line breaks
|
||||
sed -e 's/<svg[^>]*>/<svg>/g' | # remove attributes from svg element
|
||||
base64 -w 0 | # encode svg
|
||||
sed "s|.*|<img width=\"400\" title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/&.svg\"/> |"
|
||||
sed "s|.*|<img width=\"400\" title=\"$file\" alt=\"$file\" src=\"https://lucide.dev/api/gh-icon/$(basename ${file//\.svg/})/&.svg\"/> |"
|
||||
done | tr '\n' ' ' >> $GITHUB_OUTPUT
|
||||
echo >> $GITHUB_OUTPUT
|
||||
echo "$delimiter" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -173,53 +173,60 @@ const ControlPath = ({
|
||||
);
|
||||
};
|
||||
|
||||
const SvgPreview = React.forwardRef<SVGSVGElement, { src: string; showGrid?: boolean }>(
|
||||
({ src, showGrid = false }, ref) => {
|
||||
const paths = getPaths(src);
|
||||
const darkModeCss = `@media screen and (prefers-color-scheme: dark) {
|
||||
const SvgPreview = React.forwardRef<
|
||||
SVGSVGElement,
|
||||
{
|
||||
src: string | ReturnType<typeof getPaths>;
|
||||
showGrid?: boolean;
|
||||
} & React.SVGProps<SVGSVGElement>
|
||||
>(({ src, children, showGrid = false, ...props }, ref) => {
|
||||
const paths = typeof src === 'string' ? getPaths(src) : src;
|
||||
|
||||
const darkModeCss = `@media screen and (prefers-color-scheme: dark) {
|
||||
.svg-preview-grid-group,
|
||||
.svg-preview-shadow-mask-group,
|
||||
.svg-preview-shadow-group {
|
||||
stroke: #fff;
|
||||
}
|
||||
}`;
|
||||
return (
|
||||
<svg
|
||||
ref={ref}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<style>{darkModeCss}</style>
|
||||
{showGrid && <Grid strokeWidth={0.1} stroke="#777" strokeOpacity={0.3} radius={1} />}
|
||||
<Shadow paths={paths} strokeWidth={4} stroke="#777" radius={1} strokeOpacity={0.15} />
|
||||
<ColoredPath
|
||||
paths={paths}
|
||||
colors={[
|
||||
'#1982c4',
|
||||
'#4267AC',
|
||||
'#6a4c93',
|
||||
'#B55379',
|
||||
'#FF595E',
|
||||
'#FF7655',
|
||||
'#ff924c',
|
||||
'#FFAE43',
|
||||
'#ffca3a',
|
||||
'#C5CA30',
|
||||
'#8ac926',
|
||||
'#52A675',
|
||||
]}
|
||||
/>
|
||||
<ControlPath radius={1} paths={paths} pointSize={1} stroke="#fff" strokeWidth={0.125} />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
);
|
||||
return (
|
||||
<svg
|
||||
ref={ref}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width={24}
|
||||
height={24}
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={2}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
{...props}
|
||||
>
|
||||
<style>{darkModeCss}</style>
|
||||
{showGrid && <Grid strokeWidth={0.1} stroke="#777" strokeOpacity={0.3} radius={1} />}
|
||||
<Shadow paths={paths} strokeWidth={4} stroke="#777" radius={1} strokeOpacity={0.15} />
|
||||
<ColoredPath
|
||||
paths={paths}
|
||||
colors={[
|
||||
'#1982c4',
|
||||
'#4267AC',
|
||||
'#6a4c93',
|
||||
'#B55379',
|
||||
'#FF595E',
|
||||
'#FF7655',
|
||||
'#ff924c',
|
||||
'#FFAE43',
|
||||
'#ffca3a',
|
||||
'#C5CA30',
|
||||
'#8ac926',
|
||||
'#52A675',
|
||||
]}
|
||||
/>
|
||||
<ControlPath radius={1} paths={paths} pointSize={1} stroke="#fff" strokeWidth={0.125} />
|
||||
{children}
|
||||
</svg>
|
||||
);
|
||||
});
|
||||
|
||||
export default SvgPreview;
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import { getData } from 'src/lib/icons';
|
||||
import SvgPreview from '../../../components/SvgPreview';
|
||||
import { stringify } from 'svgson';
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
export default async function handler(req, res) {
|
||||
// ReactDOMServer needs to be imported dynamically
|
||||
// https://github.com/vercel/next.js/issues/43810
|
||||
const ReactDOMServer = (await import('react-dom/server')).default;
|
||||
|
||||
const url = req.url.split('/');
|
||||
const data = url.at(-1).slice(0, -4);
|
||||
const src = Buffer.from(data, 'base64')
|
||||
.toString('utf8')
|
||||
.replace(/<svg[^>]*>|<\/svg>/g, '');
|
||||
|
||||
let backdrop: ReactNode;
|
||||
try {
|
||||
if (url.at(-2) !== 'gh-icon') {
|
||||
const backdropString = stringify({
|
||||
type: 'element',
|
||||
name: 'svg',
|
||||
value: undefined,
|
||||
attributes: {},
|
||||
children: (await getData(url.at(-2))).iconNode.map(([name, attributes]) => ({
|
||||
type: 'element',
|
||||
name,
|
||||
attributes,
|
||||
children: undefined,
|
||||
value: undefined,
|
||||
})),
|
||||
}).replace(/<svg[^>]*>|<\/svg>/g, '');
|
||||
|
||||
backdrop = (
|
||||
<>
|
||||
<defs xmlns="http://www.w3.org/2000/svg">
|
||||
<pattern
|
||||
id="pattern"
|
||||
width=".1"
|
||||
height=".1"
|
||||
patternUnits="userSpaceOnUse"
|
||||
patternTransform="rotate(45 50 50)"
|
||||
>
|
||||
<line stroke="red" strokeWidth={0.1} y2={1} />
|
||||
<line stroke="red" strokeWidth={0.1} y2={1} />
|
||||
</pattern>
|
||||
</defs>
|
||||
<mask id="svg-preview-backdrop-mask-outline" maskUnits="userSpaceOnUse">
|
||||
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
|
||||
<g dangerouslySetInnerHTML={{ __html: src }} />
|
||||
</mask>
|
||||
<mask id="svg-preview-backdrop-mask-fill" maskUnits="userSpaceOnUse">
|
||||
<g stroke="#fff" dangerouslySetInnerHTML={{ __html: backdropString }} />
|
||||
<g dangerouslySetInnerHTML={{ __html: src }} />
|
||||
<g strokeWidth={1.75} dangerouslySetInnerHTML={{ __html: backdropString }} />
|
||||
</mask>
|
||||
<g
|
||||
strokeWidth={2.25}
|
||||
stroke="url(#pattern)"
|
||||
mask={'url(#svg-preview-backdrop-mask-outline)'}
|
||||
>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="url(#pattern)"
|
||||
opacity={0.5}
|
||||
stroke="none"
|
||||
/>
|
||||
<g dangerouslySetInnerHTML={{ __html: src }} />
|
||||
</g>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="url(#pattern)"
|
||||
stroke="none"
|
||||
mask={'url(#svg-preview-backdrop-mask-fill)'}
|
||||
/>
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
fill="red"
|
||||
opacity={0.5}
|
||||
stroke="none"
|
||||
mask={'url(#svg-preview-backdrop-mask-fill)'}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
backdrop = undefined;
|
||||
}
|
||||
|
||||
const svg = Buffer.from(
|
||||
ReactDOMServer.renderToString(
|
||||
<SvgPreview src={src} showGrid>
|
||||
{backdrop}
|
||||
</SvgPreview>
|
||||
)
|
||||
);
|
||||
|
||||
res.setHeader('Cache-Control', 'public,max-age=31536000');
|
||||
res.setHeader('Content-Type', 'image/svg+xml');
|
||||
res.status(200).end(svg);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import SvgPreview from '../../../components/SvgPreview';
|
||||
|
||||
export default async function handler(req, res) {
|
||||
// ReactDOMServer needs to be imported dynamically
|
||||
// https://github.com/vercel/next.js/issues/43810
|
||||
const ReactDOMServer = (await import('react-dom/server')).default;
|
||||
|
||||
const url = req.url.split('/').at(-1);
|
||||
const data = url.slice(0, -4);
|
||||
const src = Buffer.from(data, 'base64').toString('utf8');
|
||||
|
||||
const svg = Buffer.from(
|
||||
ReactDOMServer.renderToString(<SvgPreview src={src} showGrid />)
|
||||
);
|
||||
|
||||
res.setHeader('Cache-Control', 'public,max-age=31536000');
|
||||
res.setHeader('Content-Type', 'image/svg+xml');
|
||||
res.status(200).end(svg);
|
||||
}
|
||||
Reference in New Issue
Block a user