javascriptfunctionbreakpointssimplify

Is there a way to simplify this code creating css variables with javascript for specific breakpoints on my webpage?


I am using this bit of javascript code to create a string with css variables in it. It helps me to specifically set a size for each breakpoint on a webpage.

This is my code:

const sizes = {
  xs: 0.9,
  md: 2,
  lg: 2.5,
  xl: 4
};

function getCssVar(size) {
  var varStr = "";

  const defaultBPs = ["xs", "sm", "md", "lg", "xl"];

  defaultBPs.forEach(bp => {
    const bpi = defaultBPs.indexOf(bp);
    var nextHigherIndex = defaultBPs.indexOf(Object.keys(size)[getNextHighestIndex(Object.keys(size).map(bp => (defaultBPs.indexOf(bp))), defaultBPs.indexOf(bp))]);

    if (getNextHighestIndex(Object.keys(size).map(bp => (defaultBPs.indexOf(bp))), defaultBPs.indexOf(bp)) === Object.keys(size).length) {
      nextHigherIndex = defaultBPs.length;
    }

    if (size[bp]) {
      defaultBPs.forEach(bp2 => {
        const bp2i = defaultBPs.indexOf(bp2);
        const generateVar = " --size-" + bp2 + ":" + size[bp] + ";";

        if (bp2i >= bpi && bp2i < nextHigherIndex) {
          varStr += generateVar;
        }
        
      })
    };

  });
  return varStr;
}

function getNextHighestIndex(arr, value) {
  var i = arr.length;
  while (arr[--i] > value);
  return ++i; 
}


console.log(getCssVar(sizes));

The Output is the following:

 --size-xs:0.9; --size-sm:0.9; --size-md:2; --size-lg:2.5; --size-xl:4;

This is technically the correct answer and this code already works but I am still wondering if there is any way to improve my code.

I want it to be a shorter and more compact but with the same output.

Any help will be appreciated. Thanks.


Solution

  • I don't know if I get you right, but consider this logic as an option... Check inline comments

    //
    // Main function
    const getCssVar = (s, last = 0) => {
      // Possible modes in proper sequence
      const modes = ["xs", "sm", "md", "lg", "xl", "xxl"];
      // Loop modes and check if value has been provided for current mode
      // If no value provided, put last (0 or any passed overrider)
      // And update last with new value
      const res = {};
      for(const m of modes) last = res[`--size-${m}`] = s[m] || last;
      // Transform res object to any needed string
      const str = Object.keys(res).map(key => `${[key, res[key]].join(':')};`).join('');
      // Return result
      return str;
    }
    
    //
    // Tests
    console.log("Test 1:", getCssVar({
      md: 2,
      lg: 2.5,
      xl: 4
    }, 1.33)); // here we override last (lower) value
    
    console.log("Test 2:", getCssVar({
      md: 2,
      xl: 4
    }));
    
    console.log("Test 3:", getCssVar({
      xs: 0.9,
      md: 2,
    }));