diff --git a/src/app/[name]/(Main)/components/CategoryScroll.tsx b/src/app/[name]/(Main)/components/CategoryScroll.tsx
index 548fb73..eb47ef8 100644
--- a/src/app/[name]/(Main)/components/CategoryScroll.tsx
+++ b/src/app/[name]/(Main)/components/CategoryScroll.tsx
@@ -1,5 +1,6 @@
'use client';
+import { usePathname } from "next/navigation";
import Image from "next/image";
import clsx from "clsx";
import HorizontalScrollView from "@/components/listview/HorizontalScrollView";
@@ -7,6 +8,74 @@ import CategoryItemRenderer from "@/components/listview/CategoryItemRenderer";
import CategorySmallItemRenderer from "@/components/listview/CategorySmallItemRenderer";
import { Category } from "@/app/[name]/(Main)/types/Types";
+const SVG_MASK_STYLE = {
+ maskSize: "contain",
+ maskRepeat: "no-repeat",
+ maskPosition: "center",
+ WebkitMaskSize: "contain",
+ WebkitMaskRepeat: "no-repeat",
+ WebkitMaskPosition: "center",
+} as const;
+
+function CategoryImage({
+ src,
+ size,
+ alt,
+ proxyBase,
+}: {
+ src: string;
+ size: number;
+ alt: string;
+ proxyBase: string | null;
+}) {
+ const isSvg = src.endsWith(".svg");
+
+ if (isSvg) {
+ const isSameOrigin =
+ src.startsWith("/") ||
+ (typeof window !== "undefined" &&
+ new URL(src, window.location.href).origin === window.location.origin);
+
+ const maskUrl = isSameOrigin
+ ? src
+ : proxyBase
+ ? `${proxyBase}/api/proxy-svg?url=${encodeURIComponent(src)}`
+ : null;
+
+ if (maskUrl) {
+ return (
+
+ );
+ }
+
+ return (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ );
+ }
+
+ return (
+
+ );
+}
+
type Variant = "large" | "small";
const variantConfig: Record<
@@ -41,6 +110,8 @@ const CategoryScroll = ({
variant = "large",
className,
}: Props) => {
+ const segment = usePathname()?.split("/").filter(Boolean)[0];
+ const proxyBase = segment != null ? `/${segment}` : null;
const { renderer: Renderer, imageSize } = variantConfig[variant];
const handleSelect = (categoryId: string) => () => onSelect(categoryId);
@@ -76,12 +147,11 @@ const CategoryScroll = ({
className={clsx(isSelected && "bg-container!")}
onClick={handleSelect(item.id)}
>
-
{item.title}
diff --git a/src/app/[name]/api/proxy-svg/route.ts b/src/app/[name]/api/proxy-svg/route.ts
new file mode 100644
index 0000000..f57e2cc
--- /dev/null
+++ b/src/app/[name]/api/proxy-svg/route.ts
@@ -0,0 +1,46 @@
+import { NextRequest, NextResponse } from "next/server";
+
+export const dynamic = "force-dynamic";
+export const revalidate = 0;
+
+const CACHE_MAX_AGE = "public, max-age=3600";
+
+export async function GET(request: NextRequest) {
+ const url = request.nextUrl.searchParams.get("url");
+ if (!url) {
+ return NextResponse.json({ error: "url is required" }, { status: 400 });
+ }
+ try {
+ const parsed = new URL(url);
+ if (!["http:", "https:"].includes(parsed.protocol)) {
+ return NextResponse.json({ error: "Invalid URL" }, { status: 400 });
+ }
+ const res = await fetch(url, {
+ headers: { Accept: "image/svg+xml, text/xml, text/plain" },
+ });
+ if (!res.ok) {
+ return NextResponse.json(
+ { error: "Failed to fetch SVG" },
+ { status: res.status }
+ );
+ }
+ const text = await res.text();
+ if (!text.trim().toLowerCase().includes("