diff --git a/src/components/modals/settings/sections/BackgroundSettings.jsx b/src/components/modals/settings/sections/BackgroundSettings.jsx index 67a37c7d..9a234c51 100644 --- a/src/components/modals/settings/sections/BackgroundSettings.jsx +++ b/src/components/modals/settings/sections/BackgroundSettings.jsx @@ -6,7 +6,8 @@ export default class BackgroundSettings extends React.PureComponent { super(...args); this.state = { blur: 0, - brightness: 100 + brightness: 100, + gradientSettings: '' }; } @@ -14,7 +15,7 @@ export default class BackgroundSettings extends React.PureComponent { switch (key) { case 'customBackgroundColour': localStorage.setItem('customBackgroundColour', ''); - document.getElementById('customBackgroundHex').textContent = 'Disabled'; + this.setState({ gradientSettings: '' }); break; case 'customBackground': document.getElementById('customBackground').value = ''; break; case 'blur': @@ -30,72 +31,159 @@ export default class BackgroundSettings extends React.PureComponent { toast(this.props.toastLanguage.reset); } - componentDidMount() { - document.getElementById('bg-input').onchange = (e) => { - const reader = new FileReader(); - const file = e.target.files[0]; + componentDidMount() { + document.getElementById('bg-input').onchange = (e) => { + const reader = new FileReader(); + const file = e.target.files[0]; - if (file.size > 2000000) return toast('File is over 2MB', '#ff0000', '#ffffff'); + if (file.size > 2000000) return toast('File is over 2MB', '#ff0000', '#ffffff'); - reader.addEventListener('load', (e) => { - localStorage.setItem('customBackground', e.target.result); - document.getElementById('customBackground').src = e.target.result; - document.getElementById('customBackground').value = e.target.result; - }); + reader.addEventListener('load', (e) => { + localStorage.setItem('customBackground', e.target.result); + document.getElementById('customBackground').src = e.target.result; + document.getElementById('customBackground').value = e.target.result; + }); - reader.readAsDataURL(file); - }; + reader.readAsDataURL(file); + }; - const hex = localStorage.getItem('customBackgroundColour'); - if (hex !== '') { - document.getElementById('customBackgroundColour').value = hex; - document.getElementById('customBackgroundHex').innerText = hex; - } else document.getElementById('customBackgroundHex').innerText = 'Disabled'; - - this.setState({ - blur: localStorage.getItem('blur'), - brightness: localStorage.getItem('brightness') - }) - - document.getElementById('customBackground').value = localStorage.getItem('customBackground'); - document.getElementById('backgroundAPI').value = localStorage.getItem('backgroundAPI'); + const hex = localStorage.getItem('customBackgroundColour'); + let gradientSettings = ''; + if (hex !== '') { + try { + gradientSettings = JSON.parse(hex); + } catch (e) { + //Disregard exception. + } } + this.setState({ + blur: localStorage.getItem('blur'), + brightness: localStorage.getItem('brightness'), + gradientSettings + }) + + document.getElementById('customBackground').value = localStorage.getItem('customBackground'); + document.getElementById('backgroundAPI').value = localStorage.getItem('backgroundAPI'); + } + + onGradientChange = (event, index) => { + const newValue = event.target.value; + const name = event.target.name; + this.setState((s) => { + const newState = { + gradientSettings: { + ...s.gradientSettings, + gradient: s.gradientSettings.gradient.map((g, i) => i === index ? { ...g, [name]: newValue } : g) + } + }; + return newState; + }); + } + + pickFirstColour = (event) => { + const value = event.target.value; + this.setState({ gradientSettings: { "angle": "180", "gradient": [{ "colour": value, "stop": 0 }], "type": "linear" } }); + } + + addColour = () => { + this.setState((s) => { + const [lastGradient, ...initGradients] = s.gradientSettings.gradient.reverse(); + const newState = { + gradientSettings: { + ...s.gradientSettings, + gradient: [...initGradients, lastGradient, { ...lastGradient, stop: 100 }].sort((a, b) => (a.stop > b.stop) ? 1 : -1) + } + }; + return newState; + }); + } + + removeColour = (index) => { + this.setState((s) => { + const newState = { + gradientSettings: { + ...s.gradientSettings, + gradient: s.gradientSettings.gradient.filter((g, i) => i !== index) + } + }; + return newState; + }); + } + + currentGradientSettings = () => { + if (typeof this.state.gradientSettings === 'object') { + const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b)); + return JSON.stringify({ + ...this.state.gradientSettings, + gradient: [...this.state.gradientSettings.gradient.map(g => { return { ...g, stop: clampNumber(+g.stop, 0, 100) } })].sort((a, b) => (a.stop > b.stop) ? 1 : -1) + }); + } + return "Disabled"; + } + render() { - return ( + let colourSettings; + if (typeof this.state.gradientSettings === 'object') { + const gradientInputs = this.state.gradientSettings.gradient.map((g, i) => { + const gradientHasMoreThanOneColour = this.state.gradientSettings.gradient.length > 1; + return ( +
+ {gradientHasMoreThanOneColour ? () : null} + this.onGradientChange(event, i)} value={g.colour}> + + {gradientHasMoreThanOneColour ? ( + – + this.onGradientChange(event, i)} /> + ) : null} +
); + }); + colourSettings = (
- - - - - - -
+ {gradientInputs} + + ); + } else { + colourSettings = ( +
this.pickFirstColour(event)} value="#000000"> + +
); + } + + return ( +
+ + + + + + +
); } } \ No newline at end of file diff --git a/src/components/widgets/Background.jsx b/src/components/widgets/Background.jsx index bb048b9c..cf4906eb 100644 --- a/src/components/widgets/Background.jsx +++ b/src/components/widgets/Background.jsx @@ -3,20 +3,29 @@ import * as Constants from '../../modules/constants'; export default class Background extends React.PureComponent { gradientStyleBuilder(gradientSettings) { - const {type, angle, gradient } = gradientSettings; - const stepStyles = gradient.map(g => ` ${g.colour} ${g.stop}%`).join(); - return `background: ${gradient[0].colour}; background: ${type}-gradient(${angle}deg,${stepStyles})`; + const { type, angle, gradient } = gradientSettings; + let style = `background: ${gradient[0].colour};`; + if (gradient.length > 1) { + //Note: Append the gradient for additional browser support. + const stepStyles = gradient.map(g => ` ${g.colour} ${g.stop}%`).join(); + style += ` background: ${type}-gradient(${angle}deg,${stepStyles})`; + } + return style; } setBackground(url, colour, credit) { // Sets the attributes of the background image - let gradientSettings; + let gradientSettings = ''; try { gradientSettings = JSON.parse(colour); } catch (e) { - //colour use to be simply a hex colour or a NULL value before it was a JSON object. This automatically upgrades the hex colour value to the new standard. (NULL would not trigger an exception) - gradientSettings = {"type": "linear", "angle": "0", "gradient": [{"colour": colour, "stop": 0}, {"colour": colour, "stop": 100}]}; + const hexColorRegex = /#[0-9a-fA-F]{6}/s; + if (hexColorRegex.exec(colour)) { + //colour use to be simply a hex colour or a NULL value before it was a JSON object. This automatically upgrades the hex colour value to the new standard. (NULL would not trigger an exception) + gradientSettings = { "type": "linear", "angle": "180", "gradient": [{ "colour": colour, "stop": 0 }] }; + localStorage.setItem('customBackgroundColour', JSON.stringify(gradientSettings)); + } } - const background = colour ? this.gradientStyleBuilder(gradientSettings) : `background-image: url(${url});`; + const background = typeof gradientSettings === 'object' && gradientSettings !== null ? this.gradientStyleBuilder(gradientSettings) : `background-image: url(${url});`; document.querySelector('#backgroundImage').setAttribute( 'style', diff --git a/src/modules/settingsFunctions.js b/src/modules/settingsFunctions.js index 0e5626db..19f104e2 100644 --- a/src/modules/settingsFunctions.js +++ b/src/modules/settingsFunctions.js @@ -40,12 +40,12 @@ export default class SettingsFunctions { static setSearchEngine(input) { const searchEngineInput = document.getElementById('searchEngineInput'); if (input === 'custom') { - searchEngineInput.enabled = 'true'; - searchEngineInput.style.display = 'block'; + searchEngineInput.enabled = 'true'; + searchEngineInput.style.display = 'block'; } else { - searchEngineInput.style.display = 'none'; - searchEngineInput.enabled = 'false'; - localStorage.setItem('searchEngine', input); + searchEngineInput.style.display = 'none'; + searchEngineInput.enabled = 'false'; + localStorage.setItem('searchEngine', input); } } @@ -54,15 +54,15 @@ export default class SettingsFunctions { localStorage.setItem('brightness', document.getElementById('brightnessRange').value); localStorage.setItem('greetingName', document.getElementById('greetingName').value); localStorage.setItem('customBackground', document.getElementById('customBackground').value); - if (document.getElementById('customBackgroundHex').textContent !== 'Disabled') { - localStorage.setItem('customBackgroundColour', document.getElementById('customBackgroundHex').textContent); + if (document.getElementById('customBackgroundHex').value !== 'Disabled') { + localStorage.setItem('customBackgroundColour', document.getElementById('customBackgroundHex').value); } if (document.getElementById('searchEngineInput').enabled === 'true') { - const input = document.getElementById('customSearchEngine').value; - if (input) { - localStorage.setItem('searchEngine', 'custom'); - localStorage.setItem('customSearchEngine', input); - } + const input = document.getElementById('customSearchEngine').value; + if (input) { + localStorage.setItem('searchEngine', 'custom'); + localStorage.setItem('customSearchEngine', input); + } } window.location.reload(); } diff --git a/src/scss/modules/_buttons.scss b/src/scss/modules/_buttons.scss index ec74781c..e17ac31c 100644 --- a/src/scss/modules/_buttons.scss +++ b/src/scss/modules/_buttons.scss @@ -59,6 +59,23 @@ } } +.add, +.remove { + @extend %settingsButton; + padding: 5px; + width: 25px; + background-color: map-get($button-colours, "other"); + border: 2px solid map-get($button-colours, "other"); + text-align: center; + vertical-align: sub; + + &:hover { + color: map-get($button-colours, "other"); + border: 2px solid map-get($button-colours, "other"); + background: none; + } +} + .export, .uploadbg, .import {