Refactor icon rendering and head element injection

This commit is contained in:
Corey Johnson 2025-07-07 15:52:03 -07:00
parent 49a8471628
commit df23b62962
2 changed files with 30 additions and 42 deletions

View File

@ -42,6 +42,12 @@ const renderHtml = async (req: Request, route: Bun.MatchedRoute) => {
// Remove any < characters from the loader data to prevent XSS attacks
const escapedLoaderData = JSON.stringify(loaderData).replace(/</g, "\\u003c")
const headLinks = component.head?.links?.map(
(link: any) => `<link rel="${link.rel}" href="${link.href}" ${link.attributes || ""}>`
)
const headScripts = component.head?.scripts?.map(
(script: any) => `<script src="${script.src}" ${script.type ? `type="${script.type}"` : ""}></script>`
)
return new Response(
`<!DOCTYPE html>
<html lang="en">
@ -50,20 +56,8 @@ const renderHtml = async (req: Request, route: Bun.MatchedRoute) => {
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="${routeName + ".css"}" />
<title>${component.head?.title ?? "Untitled"}</title>
${
component.head?.links
?.map((link: any) => `<link rel="${link.rel}" href="${link.href}" ${link.attributes || ""}>`)
.join("\n") || ""
}
${
component.head?.scripts
?.map(
(script: any) =>
`<script src="${script.src}" ${script.type ? `type="${script.type}"` : ""}></script>`
)
.join("\n") || ""
}
${headLinks?.join("\n") ?? ""}
${headScripts?.join("\n") ?? ""}
<script id="__LOADER_DATA__" type="application/json">${escapedLoaderData}</script>
</head>
<body>

View File

@ -24,25 +24,19 @@ export const Icon: FC<IconProps> = (props) => {
throw new Error(`Icon "${name}" not found in Lucide icons`)
}
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
width={size}
height={size}
class={className}
style={{
display: "block",
flexShrink: 0,
}}
dangerouslySetInnerHTML={{ __html: getIconContent(iconSvg) }}
/>
)
// Modify the SVG string to include our custom attributes
const modifiedSvg = iconSvg
.replace(/width="[^"]*"/, `width="${size}"`)
.replace(/height="[^"]*"/, `height="${size}"`)
.replace(/class="[^"]*"/, className ? `class="${className}"` : "")
.replace(
/<svg([^>]*)>/,
`<svg$1 style="display: block; flex-shrink: 0;"${
className && !iconSvg.includes("class=") ? ` class="${className}"` : ""
}>`
)
return <div dangerouslySetInnerHTML={{ __html: modifiedSvg }} />
}
export const IconLink: FC<IconLinkProps> = (props) => {
@ -82,23 +76,23 @@ export const Test = () => {
<h2 class="text-xl font-bold mb-4">Styling with CSS Classes</h2>
<div class="grid grid-cols-5 gap-6">
<div class="flex flex-col items-center space-y-2">
<Icon name="Star" size={8} />
<Icon name="Star" size={24} />
<p class="text-sm">Default</p>
</div>
<div class="flex flex-col items-center space-y-2">
<Icon name="Star" size={8} class="text-blue-500" />
<Icon name="Star" size={24} class="text-blue-500" />
<p class="text-sm">Blue Color</p>
</div>
<div class="flex flex-col items-center space-y-2">
<Icon name="Star" size={8} class="stroke-1" />
<Icon name="Star" size={24} class="stroke-1" />
<p class="text-sm">Thin Stroke</p>
</div>
<div class="flex flex-col items-center space-y-2">
<Icon name="Star" size={8} class="text-yellow-400 stroke-0 fill-current" />
<Icon name="Star" size={24} class="text-yellow-400 stroke-0 fill-current" />
<p class="text-sm">Filled</p>
</div>
<div class="flex flex-col items-center space-y-2">
<Icon name="Star" size={8} class="text-purple-500 hover:text-purple-700 transition-colors" />
<Icon name="Star" size={24} class="text-purple-500 hover:text-purple-700 transition-colors" />
<p class="text-sm">Hover Effect</p>
</div>
</div>
@ -109,19 +103,19 @@ export const Test = () => {
<h2 class="text-xl font-bold mb-4">Advanced Styling</h2>
<div class="grid grid-cols-4 gap-6">
<div class="flex flex-col items-center space-y-2">
<Icon name="Heart" size={10} class="text-red-500 stroke-0 fill-current" />
<Icon name="Heart" size={24} class="text-red-500 stroke-0 fill-current" />
<p class="text-sm">Filled Heart</p>
</div>
<div class="flex flex-col items-center space-y-2">
<Icon name="Shield" size={10} class="text-green-600 stroke-2" />
<Icon name="Shield" size={24} class="text-green-600 stroke-2" />
<p class="text-sm">Thick Stroke</p>
</div>
<div class="flex flex-col items-center space-y-2">
<Icon name="Sun" size={10} class="text-yellow-500 animate-spin" />
<Icon name="Sun" size={24} class="text-yellow-500 animate-spin" />
<p class="text-sm">Animated</p>
</div>
<div class="flex flex-col items-center space-y-2">
<Icon name="Zap" size={10} class="text-blue-400 drop-shadow-lg" />
<Icon name="Zap" size={24} class="text-blue-400 drop-shadow-lg" />
<p class="text-sm">Drop Shadow</p>
</div>
</div>