diff --git a/src/components/addressBar/index.ts b/src/components/addressBar/index.ts new file mode 100644 index 0000000..82c7534 --- /dev/null +++ b/src/components/addressBar/index.ts @@ -0,0 +1,20 @@ +import state, { SLIDER_MODES } from "../../state"; +import { oklabToOkhsl, oklabToOkhsv, sRgbToOklab } from "../../utils/color"; +import { isHex, getHexTokensFromString, getRgbaFromHex } from "../../utils/hex"; +import { updateSliderRangeInputs } from "../sliders/sliderRangeInputs"; + +export default function initAddressBar() { + var hash = window.location.hash.substring(1); + let hex = getHexTokensFromString(hash); + + if (isHex(hex)) { + let [r, g, b, alpha] = getRgbaFromHex(hex); + + const fn = + state.sliderMode === SLIDER_MODES.OKHSV ? oklabToOkhsv : oklabToOkhsl; + + const color = fn(...sRgbToOklab(r, g, b, alpha)); + const values = color.map((v, i: number) => v * state.currentSliders[i].max); + updateSliderRangeInputs(values); + } +} diff --git a/src/components/hexInput/index.ts b/src/components/hexInput/index.ts index 5abe271..d915ae7 100644 --- a/src/components/hexInput/index.ts +++ b/src/components/hexInput/index.ts @@ -5,6 +5,7 @@ import { oklabToOkhsv, sRgbToOklab } from "../../utils/color"; +import { isHex, getHexTokensFromString, getRgbaFromHex } from "../../utils/hex"; import { getOklab, updateSliderRangeInputs @@ -37,14 +38,10 @@ function handleFocus(e: Event) { function handleInput(e: Event) { const el = e.target; - let tokens = getHexTokens(el.value); + let hex = getHexTokensFromString(el.value); - if (isHex(tokens)) { - let [r, g, b, alpha] = tokens!.map((v: string) => - v.length === 1 ? parseInt(v + v, 16) : parseInt(v, 16) - ); - - alpha = alpha === undefined ? 1 : alpha / 255; + if (isHex(hex)) { + let [r, g, b, alpha] = getRgbaFromHex(hex); const fn = state.sliderMode === SLIDER_MODES.OKHSV ? oklabToOkhsv : oklabToOkhsl; @@ -72,16 +69,3 @@ function handleKeydown(e: KeyboardEvent) { } } } - -function getHexTokens(value: string) { - let tokens = value.match( - /^#*([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})$|^#*([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$|^#*([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})$|^#*([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i - ); - tokens ??= []; - tokens &&= tokens.slice(1).filter((v) => !!v); // remove complete match and null matches - return tokens; -} - -function isHex(tokens: string[]) { - return !tokens?.length ? false : true; -} diff --git a/src/components/sliders/sliderRangeInputs/index.ts b/src/components/sliders/sliderRangeInputs/index.ts index fc30d5c..7971e72 100644 --- a/src/components/sliders/sliderRangeInputs/index.ts +++ b/src/components/sliders/sliderRangeInputs/index.ts @@ -5,6 +5,7 @@ import { updateSliderTextInput } from "../sliderTextInputs"; import { okhsvToOklab, okhslToOklab } from "../../../utils/color"; import { updateHexInput } from "../../hexInput"; import { updateColors } from "../../../utils/dom"; +import debounce from "../.././../utils/debounce"; export const sliderRangeLabelEls = >( document.querySelectorAll(".sliderLabel") @@ -83,6 +84,10 @@ export function getValue(value: number, key: number) { : value; } +const updateAddressBar = debounce((hex: string) => { + window.location.hash = hex; +}, 300); + function handleSync(skipHexInput: boolean = false) { const oklab = getOklab(); const hex = oklabToHex(oklab); @@ -90,6 +95,7 @@ function handleSync(skipHexInput: boolean = false) { updateHexInput(hex); } updateDomColors(hex, oklab); + updateAddressBar(hex); } function handleAsync() {} diff --git a/src/main.ts b/src/main.ts index d8d6136..f9ff010 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,9 +7,11 @@ import initActionBar from "./components/actionBar"; import initSliders from "./components/sliders"; import initPWA from "./pwa"; import initGitHubButton from "./components/githubButton"; +import initAddressBar from "./components/addressBar"; initSliders(); initHexInput(); initActionBar(); +initAddressBar(); initPWA(); initGitHubButton(); diff --git a/src/utils/debounce.ts b/src/utils/debounce.ts new file mode 100644 index 0000000..7f68174 --- /dev/null +++ b/src/utils/debounce.ts @@ -0,0 +1,13 @@ +export default function debounce(fn: Function, delay = 300, immediate = false) { + let timeout: number | undefined; + return function (this: any, ...args: any) { + function delayed(this: any) { + timeout = undefined; + if (!immediate) fn.apply(this, args); + } + const callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(delayed, delay); + if (callNow) fn.apply(this, args); + }; +} diff --git a/src/utils/hex.ts b/src/utils/hex.ts new file mode 100644 index 0000000..430a734 --- /dev/null +++ b/src/utils/hex.ts @@ -0,0 +1,20 @@ +export function isHex(tokens: string[]) { + return !tokens?.length ? false : true; +} + +export function getHexTokensFromString(value: string) { + let tokens = value.match( + /^#*([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})$|^#*([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$|^#*([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})([a-f0-9]{1})$|^#*([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i + ); + tokens ??= []; + tokens &&= tokens.slice(1).filter((v) => !!v); // remove complete match and null matches + return tokens; +} + +export function getRgbaFromHex(tokens: string[]) { + let [r, g, b, alpha] = tokens!.map((v: string) => + v.length === 1 ? parseInt(v + v, 16) : parseInt(v, 16) + ); + alpha = alpha === undefined ? 1 : alpha / 255; + return [r, g, b, alpha]; +}