You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			139 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			TypeScript
		
	
import { useCallback, useEffect, useState } from 'react';
 | 
						|
import { createRoot } from 'react-dom/client';
 | 
						|
import useMount from 'react-use/lib/useMount';
 | 
						|
import { SessionIcon, SessionIconProps, SessionIconType } from '../components/icon';
 | 
						|
import { sleepFor } from '../session/utils/Promise';
 | 
						|
import { useIsDarkTheme } from '../state/selectors/theme';
 | 
						|
import { ThemeKeys, getThemeValue } from '../themes/globals';
 | 
						|
 | 
						|
const chooseIconColors = (
 | 
						|
  defaultColor: ThemeKeys,
 | 
						|
  darkColor?: ThemeKeys,
 | 
						|
  lightColor?: ThemeKeys,
 | 
						|
  isThemed?: boolean,
 | 
						|
  isDarkTheme?: boolean
 | 
						|
) => {
 | 
						|
  return getThemeValue(
 | 
						|
    isThemed && darkColor && lightColor ? (isDarkTheme ? darkColor : lightColor) : defaultColor
 | 
						|
  );
 | 
						|
};
 | 
						|
 | 
						|
export const convertIconToImageURL = async (
 | 
						|
  props: Pick<SessionIconProps, 'iconType' | 'iconSize'> & {
 | 
						|
    isThemed?: boolean;
 | 
						|
    isDarkTheme?: boolean;
 | 
						|
  }
 | 
						|
): Promise<{ dataUrl: string; bgColor: string; fgColor: string }> => {
 | 
						|
  const { iconType, iconSize, isThemed, isDarkTheme } = props;
 | 
						|
 | 
						|
  const fgColor = chooseIconColors(
 | 
						|
    '--black-color',
 | 
						|
    '--background-primary-color',
 | 
						|
    '--text-primary-color',
 | 
						|
    isThemed,
 | 
						|
    isDarkTheme
 | 
						|
  );
 | 
						|
 | 
						|
  const bgColor = chooseIconColors(
 | 
						|
    '--white-color',
 | 
						|
    '--text-primary-color',
 | 
						|
    '--background-primary-color',
 | 
						|
    isThemed,
 | 
						|
    isDarkTheme
 | 
						|
  );
 | 
						|
 | 
						|
  const root = document.querySelector('#root');
 | 
						|
  const divElement = document.createElement('div');
 | 
						|
  divElement.id = 'icon-to-image-url';
 | 
						|
  divElement.style.display = 'none';
 | 
						|
  root?.appendChild(divElement);
 | 
						|
 | 
						|
  const reactRoot = createRoot(divElement!);
 | 
						|
  reactRoot.render(
 | 
						|
    <SessionIcon
 | 
						|
      iconType={iconType}
 | 
						|
      iconSize={iconSize}
 | 
						|
      iconColor={fgColor}
 | 
						|
      backgroundColor={bgColor}
 | 
						|
    />
 | 
						|
  );
 | 
						|
  // wait for it to render
 | 
						|
  await sleepFor(200);
 | 
						|
 | 
						|
  const svg = root?.querySelector(`#icon-to-image-url svg`);
 | 
						|
  svg?.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
 | 
						|
  const svgString = svg?.outerHTML;
 | 
						|
  reactRoot?.unmount();
 | 
						|
  root?.removeChild(divElement);
 | 
						|
 | 
						|
  return {
 | 
						|
    bgColor,
 | 
						|
    fgColor,
 | 
						|
    dataUrl: svgString ? `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgString)}` : '',
 | 
						|
  };
 | 
						|
};
 | 
						|
 | 
						|
export const useIconToImageURL = ({
 | 
						|
  iconType,
 | 
						|
  iconSize,
 | 
						|
  isThemed = true,
 | 
						|
}: {
 | 
						|
  iconType: SessionIconType;
 | 
						|
  iconSize: number;
 | 
						|
  isThemed?: boolean;
 | 
						|
}) => {
 | 
						|
  const isDarkTheme = useIsDarkTheme();
 | 
						|
  const [dataURL, setDataURL] = useState('');
 | 
						|
  const [loading, setLoading] = useState(false);
 | 
						|
  const [mounted, setMounted] = useState(false);
 | 
						|
  const [inDarkTheme, setInDarkTheme] = useState(false);
 | 
						|
  const [backgroundColor, setBackgroundColor] = useState('');
 | 
						|
  const [iconColor, setIconColor] = useState('');
 | 
						|
 | 
						|
  const loadURL = useCallback(async () => {
 | 
						|
    setLoading(true);
 | 
						|
    setDataURL('');
 | 
						|
 | 
						|
    try {
 | 
						|
      const {
 | 
						|
        dataUrl: newURL,
 | 
						|
        bgColor,
 | 
						|
        fgColor,
 | 
						|
      } = await convertIconToImageURL({
 | 
						|
        iconType,
 | 
						|
        iconSize,
 | 
						|
        isThemed,
 | 
						|
        isDarkTheme,
 | 
						|
      });
 | 
						|
 | 
						|
      if (!newURL) {
 | 
						|
        throw new Error('[useIconToImageURL] Failed to convert icon to URL');
 | 
						|
      }
 | 
						|
 | 
						|
      setInDarkTheme(isDarkTheme);
 | 
						|
      setBackgroundColor(bgColor);
 | 
						|
      setIconColor(fgColor);
 | 
						|
      setDataURL(newURL);
 | 
						|
 | 
						|
      if (!mounted) {
 | 
						|
        setMounted(true);
 | 
						|
      }
 | 
						|
      setLoading(false);
 | 
						|
    } catch (error) {
 | 
						|
      window.log.error('[useIconToImageURL] Error fetching icon data url', error);
 | 
						|
    }
 | 
						|
  }, [iconSize, iconType, isDarkTheme, isThemed, mounted]);
 | 
						|
 | 
						|
  useMount(() => {
 | 
						|
    void loadURL();
 | 
						|
  });
 | 
						|
 | 
						|
  useEffect(() => {
 | 
						|
    if (!loading && mounted && isThemed && isDarkTheme !== inDarkTheme) {
 | 
						|
      void loadURL();
 | 
						|
    }
 | 
						|
  }, [inDarkTheme, isDarkTheme, isThemed, loadURL, loading, mounted]);
 | 
						|
 | 
						|
  return { dataURL, iconSize, iconColor, backgroundColor, loading };
 | 
						|
};
 |