UnlyEd/next-right-now-admin

View on GitHub
src/utils/logo.ts

Summary

Maintainability
A
0 mins
Test Coverage
import map from 'lodash.map';
import { Logo } from '../types/data/Logo';

export const SIZE_XS = 'xs';
export const SIZE_SM = 'sm';
export const SIZE_MD = 'md';
export const SIZE_LG = 'lg';
export const SIZE_XL = 'xl';
export const SIZES = [
  SIZE_XS,
  SIZE_SM,
  SIZE_MD,
  SIZE_LG,
  SIZE_XL,
];

export const DEFAULT_SIZES_MULTIPLIERS: SizeMultiplier[] = [
  {
    size: SIZE_XS,
    multiplier: 0.5,
  },
  {
    size: SIZE_SM,
    multiplier: 0.75,
  },
  {
    size: SIZE_MD,
    multiplier: 1,
  },
];

export type Size = {
  width: number | string;
  height: number | string;
}

export type SizeMultiplier = {
  size: string;
  multiplier: number;
}

/**
 * Convert a number to pixels, left strings untouched
 *
 * @param value {string|number} Value to convert to pixels, will be converted to string
 * @example
 * toPixels(50) => '50px'
 * toPixels('50') => '50'
 * toPixels('50px') => '50px'
 *
 * @returns {string}
 */
export const toPixels = (value: number | string): string => {
  if (typeof value === 'number') {
    return `${value}px`;
  }

  return value;
};

/**
 * Generates an array of sizes containing as many sizes as there are DEFAULT_SIZES_MULTIPLIERS, based on a "medium" logo sizes.
 * Each generated size contains a logo data model.
 * Allows for customized image, width, height per size,
 *
 * @param baseWidth {number} Value to use as base for a logo of 'medium' size
 * @param baseHeight {number} Value to use as base for a logo of 'medium' size
 * @param sizesMultipliers
 * @returns {object}
 */
export const generateSizes = ({ baseWidth, baseHeight, sizesMultipliers = DEFAULT_SIZES_MULTIPLIERS }: { baseWidth: number; baseHeight: number; sizesMultipliers?: SizeMultiplier[] }): object => {
  const sizes = {};

  map(sizesMultipliers, (sizeMultiplier) => {
    sizes[sizeMultiplier.size] = {
      width: toPixels(baseWidth * sizeMultiplier.multiplier),
      height: toPixels(baseHeight * sizeMultiplier.multiplier),
    };
  });

  return sizes;
};

/**
 * Resolve the unknown width/height based on base width/height, using a cross-multiplication
 *
 * @param baseWidth
 * @param baseHeight
 * @param width
 * @param height
 * @returns {{width:}}
 */
export const resolveRatio = ({ baseWidth, baseHeight, width, height }): Size => {
  if (width) {
    // Need to resolve the height
    return {
      width,
      height: toPixels(parseFloat(width) * parseFloat(baseHeight) / parseFloat(baseWidth)),
    };
  } else {
    // Need to resolve the width
    return {
      width: toPixels(parseFloat(height) * parseFloat(baseWidth) / parseFloat(baseHeight)),
      height,
    };
  }
};

/**
 * Resolve the size to apply to a logo, based on whether its height or width was provided.
 * If both are provided, then do not changes them.
 * If none are provided, then use the logo default values.
 * If one of them is provided, then resolves the other value using a cross-multiplication.
 *
 * @param width
 * @param height
 * @param logo
 * @returns {{width: *, height: *}}
 */
export const resolveSize = ({ width, height, logo }: Size & { logo: Logo }): Size => {
  if (width && height) {
    // Both width and height provided, which means we force the logo's size
    return {
      width: width,
      height: height,
    };
  } else if (width) {
    // Only the width is provided, therefore only the width should be set
    return {
      width: width,
      height: resolveRatio({ baseHeight: logo.height, baseWidth: logo.width, width, height }).height,
    };
  } else if (height) {
    // Only the height is provided, therefore only the height should be set
    return {
      width: resolveRatio({ baseHeight: logo.height, baseWidth: logo.width, width, height }).width,
      height: height,
    };
  } else {
    // If no height nor width are provided, use the default logo values
    return {
      width: logo.width,
      height: logo.height,
    };
  }
};