UNPKG

blackmagic-js

Version:

A powerful dark mode framework with automatic color adjustment and contrast optimization

1 lines 4.81 kB
class BlackMagic{constructor(t={}){this.cookieName=t.cookieName||"darkmode",this.backgroundColor=t.backgroundColor||"#000",this.localStorageKey=t.localStorageKey||"darkmode",this.themeClass=t.themeClass||void 0,this.cookieDuration=t.cookieDuration||365,this.autoSwitch=void 0===t.autoSwitch||t.autoSwitch,this.factor=t.factor||.4,this.currentTheme=t.currentTheme||"light",this.initialize()}initialize(){if(this.autoSwitch){const t=this.getStoredTheme();t?(this.currentTheme=t,this.applyTheme(t)):(this.currentTheme="light",this.applyTheme("light"))}else{const t=this.getStoredTheme();this.currentTheme=t||"light"}}applyTheme(t){if(this.currentTheme=t,this.themeClass){const e=document.body;"dark"===t?e.classList.add(this.themeClass):e.classList.remove(this.themeClass)}else this.adjustColorsForTheme(t);this.saveTheme(t)}saveTheme(t){this.setCookie(this.cookieName,t,this.cookieDuration),this.setLocalStorage(this.localStorageKey,t)}getStoredTheme(){const t=this.getCookie(this.cookieName);return t||this.getLocalStorage(this.localStorageKey)}toggle(){const t="dark"===this.getCurrentTheme()?"light":"dark";this.applyTheme(t)}getCurrentTheme(){if(this.currentTheme)return this.currentTheme;if(this.themeClass)return document.body.classList.contains(this.themeClass)?"dark":"light";const t=document.body.style.backgroundColor;return t&&""!==t&&"rgb(255, 255, 255)"!==t?"dark":"light"}setCookie(t,e,o){if(0===o)document.cookie=`${t}=${e};path=/`;else{const r=new Date;r.setTime(r.getTime()+24*o*60*60*1e3),document.cookie=`${t}=${e};expires=${r.toUTCString()};path=/`}}getCookie(t){const e=`${t}=`,o=document.cookie.split(";");for(let t=0;t<o.length;t++){let r=o[t].trim();if(0===r.indexOf(e))return r.substring(e.length,r.length)}return null}setLocalStorage(t,e){try{localStorage.setItem(t,e)}catch(t){console.warn("localStorage not available:",t)}}getLocalStorage(t){try{return localStorage.getItem(t)}catch(t){return console.warn("localStorage not available:",t),null}}rgbToHsl(t,e,o){t/=255,e/=255,o/=255;let r,s,a=Math.max(t,e,o),i=Math.min(t,e,o),h=(a+i)/2;if(a===i)r=s=0;else{let n=a-i;switch(s=h>.5?n/(2-a-i):n/(a+i),a){case t:r=(e-o)/n+(e<o?6:0);break;case e:r=(o-t)/n+2;break;case o:r=(t-e)/n+4}r/=6}return[360*r,s,h]}adjustLightness(t,e,o,r){return[t,e,o=Math.max(0,Math.min(1,o+r))]}getColorFromElement(t){let e=window.getComputedStyle(t).color;if(e.startsWith("rgb")){let t=e.match(/\d+/g).map(Number);return[t[0]||0,t[1]||0,t[2]||0]}return e.startsWith("#")?this.hexToRgb(e):[0,0,0]}hexToRgb(t){return[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)]}getLuminance(t,e,o){return e/=255,o/=255,.2126*(t=(t/=255)<=.03928?t/12.92:Math.pow((t+.055)/1.055,2.4))+.7152*(e=e<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4))+.0722*(o=o<=.03928?o/12.92:Math.pow((o+.055)/1.055,2.4))}getContrastRatio(t,e){const[o,r,s]=t,[a,i,h]=e,n=this.getLuminance(o,r,s),l=this.getLuminance(a,i,h);return(Math.max(n,l)+.05)/(Math.min(n,l)+.05)}getBackgroundColor(t){let e=t;for(;e&&e!==document.body;){const t=window.getComputedStyle(e).backgroundColor;if(t&&"rgba(0, 0, 0, 0)"!==t&&"transparent"!==t&&t.startsWith("rgb")){let e=t.match(/\d+/g).map(Number);return[e[0]||255,e[1]||255,e[2]||255]}e=e.parentElement}const o=document.body.style.backgroundColor;if(o&&""!==o){if(o.startsWith("rgb")){let t=o.match(/\d+/g).map(Number);return[t[0]||255,t[1]||255,t[2]||255]}if(o.startsWith("#"))return this.hexToRgb(o)}return"dark"===this.currentTheme?this.hexToRgb(this.backgroundColor):[255,255,255]}getOptimalTextColor(t,e){const[o,r,s]=t,[a,i,h]=e;if(this.getContrastRatio(e,t)>=4.5)return e;if(this.getLuminance(o,r,s)<.5){let[e,o,r]=this.rgbToHsl(a,i,h);r=r<.5?.9:Math.max(.8,r);const s=this.hslToRgb(e,o,r);return this.getContrastRatio(s,t)<4.5?[255,255,255]:s}{let[e,o,r]=this.rgbToHsl(a,i,h);r=r>.5?.2:Math.min(.3,r);const s=this.hslToRgb(e,o,r);return this.getContrastRatio(s,t)<4.5?[0,0,0]:s}}hslToRgb(t,e,o){t/=360;const r=(1-Math.abs(2*o-1))*e,s=r*(1-Math.abs(6*t%2-1)),a=o-r/2;let i,h,n;return t<1/6?(i=r,h=s,n=0):t<2/6?(i=s,h=r,n=0):t<.5?(i=0,h=r,n=s):t<4/6?(i=0,h=s,n=r):t<5/6?(i=s,h=0,n=r):(i=r,h=0,n=s),i=Math.round(255*(i+a)),h=Math.round(255*(h+a)),n=Math.round(255*(n+a)),[i,h,n]}adjustColorsForTheme(t){const e=document.querySelectorAll("*");"dark"===t?(document.body.style.backgroundColor=this.backgroundColor,document.body.style.color="#e0e0e0"):(document.body.style.backgroundColor="",document.body.style.color=""),e.forEach((e=>{if("light"===t)return void e.style.removeProperty("color");const o=e.tagName.toLowerCase();if("script"===o||"style"===o||"meta"===o||"link"===o)return;let r=this.getColorFromElement(e),s=this.getBackgroundColor(e);if(!r||!s)return;let a=this.getOptimalTextColor(s,r),[i,h,n]=a,l=`rgb(${i}, ${h}, ${n})`;e.style.setProperty("color",l,"important")}))}}