Skip to content

Commit

Permalink
Use blob url instead of data url for svg, create specal classes for s…
Browse files Browse the repository at this point in the history
…troke
  • Loading branch information
garronej committed Nov 21, 2023
1 parent 1b14eeb commit 47f5b88
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 27 deletions.
28 changes: 24 additions & 4 deletions src/ThemedImage.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
import { ThemedSvg } from "./ThemedSvg";
import { ThemedSvg, useThemedSvgAsBlobUrl } from "./ThemedSvg";
import {
type ThemedAssetUrl,
useResolveThemedAssetUrl,
} from "./lib/ThemedAssetUrl";
import { getSafeUrl } from "./tools/getSafeUrl";

type Props = {
className?: string;
url: ThemedAssetUrl;
alt?: string;
};

function getIsSvg(url: string) {
return url.split("?")[0].endsWith(".svg");
}

export function ThemedImage(props: Props) {
const { className, alt = "" } = props;

const { resolveThemedAssetUrl } = useResolveThemedAssetUrl();

const url = resolveThemedAssetUrl(props.url);

return url.split("?")[0].endsWith(".svg") ? (
return getIsSvg(url) ? (
<ThemedSvg svgUrl={url} className={className} />
) : (
<img src={getSafeUrl(url)} alt={alt} className={className} />
<img src={url} alt={alt} className={className} />
);
}

export function useThemedImageUrl(
themedAssetUrl: ThemedAssetUrl | undefined,
): string | undefined {
const { resolveThemedAssetUrl } = useResolveThemedAssetUrl();

const url =
themedAssetUrl === undefined
? undefined
: resolveThemedAssetUrl(themedAssetUrl);

const svgDataUrl = useThemedSvgAsBlobUrl(
url === undefined ? undefined : getIsSvg(url) ? url : undefined,
);

return url === undefined ? undefined : getIsSvg(url) ? svgDataUrl : url;
}
60 changes: 39 additions & 21 deletions src/ThemedSvg.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ const useStyles = tss.withName({ ThemedSvg }).create(({ theme }) => ({
getClassesAndColors({
"palette": theme.colors.palette,
"useCases": theme.colors.useCases,
}).map(({ className, color }) => [
}).map(({ className, color, attributeName }) => [
["&.", "& ."].map(prefix => `${prefix}${className}`).join(", "),
{ "fill": color },
{ [attributeName]: color },
]),
),
},
Expand All @@ -72,7 +72,11 @@ const useStyles = tss.withName({ ThemedSvg }).create(({ theme }) => ({
function getClassesAndColors(params: {
palette: PaletteBase;
useCases: ColorUseCasesBase;
}): { className: string; color: string }[] {
}): {
className: string;
color: string;
attributeName: "fill" | "stroke";
}[] {
const { palette, useCases } = params;

const generatePaletteObject = (
Expand All @@ -82,15 +86,19 @@ function getClassesAndColors(params: {
const out: {
className: string;
color: string;
attributeName: "fill" | "stroke";
}[] = [];

for (const key in colors) {
const colorGroup = colors[key];
for (const colorKey in colorGroup) {
out.push({
"className": `onyxia-fill-${type}-${key}-${colorKey}`,
"color": colorGroup[colorKey],
});
for (const attributeName of ["fill", "stroke"] as const) {
for (const key in colors) {
const colorGroup = colors[key];
for (const colorKey in colorGroup) {
out.push({
"className": `onyxia-${attributeName}-${type}-${key}-${colorKey}`,
"color": colorGroup[colorKey],
attributeName,
});
}
}
}

Expand All @@ -103,12 +111,12 @@ function getClassesAndColors(params: {
];
}

export async function getThemedSvgAsDataUrl(params: {
export async function getThemedSvgAsBlobUrl(params: {
svgUrl: ThemedAssetUrl;
isDarkModeEnabled: boolean;
palette: PaletteBase;
useCases: ColorUseCasesBase;
}): Promise<`data:image/svg+xml,${string}`> {
}): Promise<string> {
const { svgUrl, isDarkModeEnabled, palette, useCases } = params;

const resolvedUrl = resolveThemedAssetUrl({
Expand All @@ -126,9 +134,9 @@ export async function getThemedSvgAsDataUrl(params: {
getClassesAndColors({
palette,
useCases,
}).forEach(({ className, color }) => {
}).forEach(({ className, color, attributeName }) => {
if (element.getAttribute("class")?.includes(className)) {
element.setAttribute("fill", color);
element.setAttribute(attributeName, color);
}
});

Expand All @@ -137,12 +145,18 @@ export async function getThemedSvgAsDataUrl(params: {
}
})(svgElement);

return `data:image/svg+xml,${encodeURIComponent(
new XMLSerializer().serializeToString(svgElement),
)}`;
const svg = new XMLSerializer().serializeToString(svgElement);
const blob = new Blob([svg], { "type": "image/svg+xml" });
const url = URL.createObjectURL(blob);

if (url.length >= 65536) {
console.warn("Encoded SVG might be too long for a data URL.");
}

return url;
}

export function useThemedSvgAsDataUrl(svgUrl: ThemedAssetUrl) {
export function useThemedSvgAsBlobUrl(svgUrl: ThemedAssetUrl | undefined) {
const {
theme: {
isDarkModeEnabled,
Expand All @@ -153,13 +167,17 @@ export function useThemedSvgAsDataUrl(svgUrl: ThemedAssetUrl) {
const [dataUrl, setDataUrl] = useState<string | undefined>(undefined);

useEffect(() => {
if (svgUrl === undefined) {
return;
}

let isActive = true;

(async () => {
let dataUrl: string;
let blobUrl: string;

try {
dataUrl = await getThemedSvgAsDataUrl({
blobUrl = await getThemedSvgAsBlobUrl({
svgUrl,
isDarkModeEnabled,
palette,
Expand All @@ -174,7 +192,7 @@ export function useThemedSvgAsDataUrl(svgUrl: ThemedAssetUrl) {
return;
}

setDataUrl(dataUrl);
setDataUrl(blobUrl);
})();

return () => {
Expand Down
7 changes: 5 additions & 2 deletions src/lib/ThemedAssetUrl.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useMemo } from "react";
import { useDarkMode } from "./darkMode";
import { getSafeUrl } from "../tools/getSafeUrl";

/**
* ThemedAssetUrl is a type that enable Onyxia administrators to provide a different asset url
Expand Down Expand Up @@ -30,10 +31,12 @@ export function resolveThemedAssetUrl(params: {
const { isDarkModeEnabled, themedAssetUrl } = params;

if (typeof themedAssetUrl === "string") {
return themedAssetUrl;
return getSafeUrl(themedAssetUrl);
}

return isDarkModeEnabled ? themedAssetUrl.dark : themedAssetUrl.light;
return getSafeUrl(
isDarkModeEnabled ? themedAssetUrl.dark : themedAssetUrl.light,
);
}

export function useResolveThemedAssetUrl() {
Expand Down

0 comments on commit 47f5b88

Please sign in to comment.