diff --git a/src/css/components/_settings.scss b/src/css/components/_settings.scss index 361671386..5faff2095 100644 --- a/src/css/components/_settings.scss +++ b/src/css/components/_settings.scss @@ -64,11 +64,12 @@ color: #767676; } -.setting-reset-row { +.setting-actions { padding: 12px 16px 16px; text-align: right; } +.setting-download, .setting-reset { text-transform: uppercase; color: #fff; diff --git a/src/index.html b/src/index.html index f7766fc7b..392aeb66a 100644 --- a/src/index.html +++ b/src/index.html @@ -152,7 +152,8 @@

Features

{% endfor %} -
+
+
diff --git a/src/js/page/ui/settings.js b/src/js/page/ui/settings.js index cac3d1a01..87dfe9435 100644 --- a/src/js/page/ui/settings.js +++ b/src/js/page/ui/settings.js @@ -1,4 +1,5 @@ import { createNanoEvents } from 'nanoevents'; +import { download } from '../../utils/download.js'; import { domReady } from '../utils.js'; import MaterialSlider from './material-slider.js'; import Ripple from './ripple.js'; @@ -18,12 +19,16 @@ export default class Settings { ]; const scroller = this.container.querySelector('.settings-scroller'); + const exportBtn = this.container.querySelector('.setting-export'); const resetBtn = this.container.querySelector('.setting-reset'); const ranges = this.container.querySelectorAll('input[type=range]'); this._resetRipple = new Ripple(); resetBtn.append(this._resetRipple.container); + this._exportRipple = new Ripple(); + exportBtn.append(this._exportRipple.container); + // map real range elements to Slider instances this._sliderMap = new WeakMap(); @@ -33,9 +38,10 @@ export default class Settings { } this.container.addEventListener('input', (event) => - this._onChange(event), + this._onChange(event) ); resetBtn.addEventListener('click', () => this._onReset()); + exportBtn.addEventListener('click', () => this._onExport()); // TODO: revisit this // Stop double-tap text selection. @@ -55,7 +61,7 @@ export default class Settings { if (event.target.type === 'range') { this._throttleTimeout = setTimeout( () => this.emitter.emit('change'), - 150, + 150 ); } else { this.emitter.emit('change'); @@ -83,6 +89,41 @@ export default class Settings { this.emitter.emit('change'); } + _onExport() { + this._exportRipple.animate(); + + const { fingerprint, multipass, pretty, ...settings } = this.getSettings(); + const floatPrecision = Number(settings.floatPrecision); + const plugins = []; + + for (const [name, active] of Object.entries(settings.plugins)) { + if (!active) continue; + + const plugin = { + name, + params: {}, + }; + + plugin.params.floatPrecision = + plugin.name === 'cleanupNumericValues' && floatPrecision === 0 + ? 1 + : floatPrecision; + + plugins.push(plugin); + } + + const file = 'module.exports = ' + JSON.stringify({ + multipass, + plugins, + js2svg: { + indent: ' ', + pretty, + }, + }, null, 2) + + download('svgo.config.js', file) + } + setSettings(settings) { for (const inputEl of this._globalInputs) { if (!(inputEl.name in settings)) continue; diff --git a/src/js/utils/download.js b/src/js/utils/download.js new file mode 100644 index 000000000..2bd609c54 --- /dev/null +++ b/src/js/utils/download.js @@ -0,0 +1,15 @@ +export function download(filename, text) { + const element = document.createElement('a'); + element.setAttribute( + 'href', + 'data:text/plain;charset=utf-8,' + encodeURIComponent(text) + ); + element.setAttribute('download', filename); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); +}