style preset
This commit is contained in:
parent
f06f2c9b2a
commit
6fed952a22
|
@ -16,6 +16,7 @@
|
||||||
"react-github-btn": "^1.2.0",
|
"react-github-btn": "^1.2.0",
|
||||||
"react-indiana-drag-scroll": "^1.6.1",
|
"react-indiana-drag-scroll": "^1.6.1",
|
||||||
"react-lazy-load": "^3.0.13",
|
"react-lazy-load": "^3.0.13",
|
||||||
|
"react-modal": "^3.12.1",
|
||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
"react-scripts": "3.4.1",
|
"react-scripts": "3.4.1",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
|
|
|
@ -6,11 +6,11 @@ export const genQRInfo = text => ({
|
||||||
text
|
text
|
||||||
})
|
})
|
||||||
|
|
||||||
export const changeStyle = (rendererIndex, rendererType, value) => {
|
export const changeStyle = (rendererIndex, value) => {
|
||||||
handleStyle(value);
|
handleStyle(value);
|
||||||
return {
|
return {
|
||||||
type: actionTypes.CHANGE_STYLE,
|
type: actionTypes.CHANGE_STYLE,
|
||||||
rendererIndex, rendererType, value
|
rendererIndex, value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React, {useState} from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {isWeiXin} from "../../utils/navigatorUtils";
|
import {isWeiXin} from "../../utils/navigatorUtils";
|
||||||
|
import PresetModalViewer from "../../containers/preset/PresetModalViewer";
|
||||||
|
|
||||||
const WxMessage = () => {
|
const WxMessage = () => {
|
||||||
if (isWeiXin()) {
|
if (isWeiXin()) {
|
||||||
|
@ -28,8 +29,9 @@ const ImgBox = ({ imgData }) => {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const PartDownload = ({ value, downloadCount, onSvgDownload, onImgDownload }) => {
|
const PartDownload = ({ value, downloadCount, onSvgDownload, onImgDownload, savePreset }) => {
|
||||||
const [imgData, setImgData] = useState('');
|
const [imgData, setImgData] = useState('');
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Qr-titled">
|
<div className="Qr-titled">
|
||||||
|
@ -41,11 +43,15 @@ const PartDownload = ({ value, downloadCount, onSvgDownload, onImgDownload }) =>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="Qr-Centered">
|
<div className="Qr-Centered">
|
||||||
|
<PresetModalViewer visible={visible} onClose={() => setVisible(false)} />
|
||||||
<div className="btn-row">
|
<div className="btn-row">
|
||||||
<div className="div-btn img-dl-btn">
|
<div className="div-btn img-dl-btn">
|
||||||
<button className="dl-btn" onClick={() => {onImgDownload("jpg").then(res => setImgData(res));}}>JPG</button>
|
<button className="dl-btn" onClick={() => {onImgDownload("jpg").then(res => setImgData(res));}}>JPG</button>
|
||||||
<button className="dl-btn" onClick={() => {onImgDownload("png").then(res => setImgData(res));}}>PNG</button>
|
<button className="dl-btn" onClick={() => {onImgDownload("png").then(res => setImgData(res));}}>PNG</button>
|
||||||
<button className="dl-btn" onClick={onSvgDownload}>SVG</button>
|
<button className="dl-btn" onClick={onSvgDownload}>SVG</button>
|
||||||
|
|
||||||
|
<button className="dl-btn" onClick={() => setVisible(true)}>管理预设</button>
|
||||||
|
<button className="dl-btn" onClick={savePreset}>保存预设</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="wx-message">
|
<div id="wx-message">
|
||||||
|
|
|
@ -38,7 +38,7 @@ const ParamIcon = ({icon, onBlur, onKeyPress}) => (
|
||||||
<FrameworkParam paramName={"图标"}>
|
<FrameworkParam paramName={"图标"}>
|
||||||
<select
|
<select
|
||||||
className="Qr-select"
|
className="Qr-select"
|
||||||
defaultValue={icon.enabled}
|
value={icon.enabled}
|
||||||
onChange={(e) => onBlur({...icon, enabled: e.target.value})}>
|
onChange={(e) => onBlur({...icon, enabled: e.target.value})}>
|
||||||
<option value={0}>无</option>
|
<option value={0}>无</option>
|
||||||
<option value={1}>自定义</option>
|
<option value={1}>自定义</option>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
.ReactModal__Overlay {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 100ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ReactModal__Overlay--after-open{
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ReactModal__Overlay--before-close{
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-preset-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-preset-side {
|
||||||
|
width: 70%;
|
||||||
|
height: 100%;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Qr-preset-detail {
|
||||||
|
width: 40%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const PresetCard = ({ preset }) => (
|
||||||
|
<div className="Qr-Centered">
|
||||||
|
<div className="Qr-item-image">
|
||||||
|
<div className="Qr-item-image-inner">
|
||||||
|
<img id="dl-image-inner-jpg" src={preset.preview}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="Qr-item-detail">
|
||||||
|
{preset.name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
PresetCard.propTypes = {
|
||||||
|
preset: PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
styleName: PropTypes.string.isRequired,
|
||||||
|
preview: PropTypes.string.isRequired,
|
||||||
|
params: PropTypes.array.isRequired,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PresetCard;
|
|
@ -0,0 +1,49 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const ParamLabel = ({ params, label }) => (
|
||||||
|
params.map((param, index) => {
|
||||||
|
if (param.value.length > 30) return null;
|
||||||
|
return (
|
||||||
|
<table key={label + '_' + index} className="Qr-table">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>{param.name}</td>
|
||||||
|
<td>{param.value}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const PresetDetail = ({ preset }) => (
|
||||||
|
<div className="Qr-Centered">
|
||||||
|
<div id="dl-image">
|
||||||
|
<div id="dl-image-inner">
|
||||||
|
<img id="dl-image-inner-jpg" src={preset.preview}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<table className="Qr-table">
|
||||||
|
<tbody><tr>
|
||||||
|
<td>样式名</td>
|
||||||
|
<td>{preset.styleName}</td>
|
||||||
|
</tr></tbody>
|
||||||
|
</table>
|
||||||
|
<ParamLabel params={preset.params} label="preset_param"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
PresetDetail.propTypes = {
|
||||||
|
preset: PropTypes.shape({
|
||||||
|
name: PropTypes.string.isRequired,
|
||||||
|
styleName: PropTypes.string.isRequired,
|
||||||
|
preview: PropTypes.string.isRequired,
|
||||||
|
globalParams: PropTypes.array.isRequired,
|
||||||
|
params: PropTypes.array.isRequired,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PresetDetail;
|
|
@ -1,6 +1,80 @@
|
||||||
import React from "react";
|
import React, {useState} from "react";
|
||||||
|
import Modal from "react-modal";
|
||||||
|
import './Preset.css';
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import PresetCard from "./PresetCard";
|
||||||
|
import PresetDetail from "./PresetDetail";
|
||||||
|
import ScrollContainer from "react-indiana-drag-scroll";
|
||||||
|
import {getPresets, removePreset} from "../../utils/storageUtils";
|
||||||
|
|
||||||
const PresetModal({ visible, onClose, }) => {
|
function calClassName(selected) {
|
||||||
|
if (selected === true) return 'Qr-item Qr-item-selected';
|
||||||
|
return 'Qr-item';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customStyles = {
|
||||||
|
content: {
|
||||||
|
inset: '40px 60px 40px 60px',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PresetModal = ({ visible, onClose, loadPreset }) => {
|
||||||
|
const storedPresets = getPresets();
|
||||||
|
const [selected, setSelected] = useState(0);
|
||||||
|
const [presets, setPresets] = useState(storedPresets);
|
||||||
|
if (presets.length !== storedPresets.length) setPresets(storedPresets);
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
appElement={document.getElementById("root")}
|
||||||
|
closeTimeoutMS={100}
|
||||||
|
isOpen={visible}
|
||||||
|
onRequestClose={onClose}
|
||||||
|
style={customStyles}>
|
||||||
|
<div className="Qr-preset-container">
|
||||||
|
<ScrollContainer
|
||||||
|
className="Qr-div-table Qr-preset-side"
|
||||||
|
vertical={true}
|
||||||
|
horizontal={false}
|
||||||
|
hideScrollbars={false}>
|
||||||
|
{
|
||||||
|
presets.map((preset, index) => (
|
||||||
|
<div
|
||||||
|
key={'preset_' + index}
|
||||||
|
className={calClassName(selected === index)}
|
||||||
|
onClick={() => setSelected(index)}>
|
||||||
|
<PresetCard preset={preset}/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ScrollContainer>
|
||||||
|
<div className="Qr-preset-detail">
|
||||||
|
{presets[selected] ? <PresetDetail preset={presets[selected]}/> : null}
|
||||||
|
<div>
|
||||||
|
<button className="dl-btn" onClick={() => {
|
||||||
|
if (presets[selected]) {
|
||||||
|
loadPreset(presets[selected]);
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
}}>加载预设</button>
|
||||||
|
<button className="dl-btn" onClick={() => {
|
||||||
|
if (presets[selected]) {
|
||||||
|
removePreset(selected);
|
||||||
|
setPresets(getPresets())
|
||||||
|
}
|
||||||
|
}}>删除预设</button>
|
||||||
|
<button className="dl-btn" onClick={onClose}>取消</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
PresetModal.propTypes = {
|
||||||
|
visible: PropTypes.bool,
|
||||||
|
onClose: PropTypes.func.isRequired,
|
||||||
|
presetArray: PropTypes.array.isRequired,
|
||||||
|
loadPreset: PropTypes.func.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PresetModal;
|
|
@ -7,7 +7,6 @@ import {getExactValue, getIdNum} from "../../utils/util";
|
||||||
|
|
||||||
function listPoints({ qrcode, params, icon }) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
console.log(icon)
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
const typeTable = getTypeTable(qrcode);
|
const typeTable = getTypeTable(qrcode);
|
||||||
const pointList = new Array(nCount);
|
const pointList = new Array(nCount);
|
||||||
|
|
|
@ -36,7 +36,7 @@ let defaultDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
const randomIdDefs = getIdNum();
|
const randomIdDefs = getIdNum();
|
||||||
const randomIdClips = getIdNum();
|
const randomIdClips = getIdNum();
|
||||||
|
|
||||||
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={`translate(${iconXY}, ${iconXY}) scale(${iconSize / 100}, ${iconSize / 100})`} />);
|
pointList.push(<path key={id++} d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={`translate(${iconXY}, ${iconXY}) scale(${iconSize / 100}, ${iconSize / 100})`} />);
|
||||||
pointList.push(
|
pointList.push(
|
||||||
<g key={id++}>
|
<g key={id++}>
|
||||||
<defs>
|
<defs>
|
||||||
|
@ -117,7 +117,7 @@ let builtinDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
if (icon && iconMode) {
|
if (icon && iconMode) {
|
||||||
const randomIdDefs = getIdNum();
|
const randomIdDefs = getIdNum();
|
||||||
const randomIdClips = getIdNum();
|
const randomIdClips = getIdNum();
|
||||||
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={`translate(${iconXY}, ${iconXY}) scale(${iconSize / 100}, ${iconSize / 100})`} />);
|
pointList.push(<path key={id++} d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={`translate(${iconXY}, ${iconXY}) scale(${iconSize / 100}, ${iconSize / 100})`} />);
|
||||||
pointList.push(
|
pointList.push(
|
||||||
<g key={id++}>
|
<g key={id++}>
|
||||||
<defs>
|
<defs>
|
||||||
|
|
|
@ -4,6 +4,8 @@ import {saveImg, saveSvg} from "../../utils/downloader";
|
||||||
import {getDownloadCount, increaseDownloadData, recordDownloadDetail} from "../../api/TcbHandler";
|
import {getDownloadCount, increaseDownloadData, recordDownloadDetail} from "../../api/TcbHandler";
|
||||||
import {getParamDetailedValue, outerHtml} from "../../utils/util";
|
import {getParamDetailedValue, outerHtml} from "../../utils/util";
|
||||||
import {handleDownloadImg, handleDownloadSvg} from "../../utils/gaHelper";
|
import {handleDownloadImg, handleDownloadSvg} from "../../utils/gaHelper";
|
||||||
|
import {appendPreset} from "../../utils/storageUtils";
|
||||||
|
import {svgToBase64} from "../../utils/imageUtils";
|
||||||
|
|
||||||
function saveDB(state, type, updateDownloadData) {
|
function saveDB(state, type, updateDownloadData) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
|
@ -42,7 +44,7 @@ const mapStateToProps = (state, ownProps) => ({
|
||||||
downloadCount: state.downloadData[state.value],
|
downloadCount: state.downloadData[state.value],
|
||||||
onSvgDownload: () => {
|
onSvgDownload: () => {
|
||||||
saveSvg(state.value, outerHtml(state.selectedIndex));
|
saveSvg(state.value, outerHtml(state.selectedIndex));
|
||||||
saveDB(state, 'svg', ownProps.updateDownloadData);
|
saveDB(state, 'svg', ownProps.updateDownloadData).catch(console.error);
|
||||||
handleDownloadSvg(state.value);
|
handleDownloadSvg(state.value);
|
||||||
},
|
},
|
||||||
onImgDownload: (type) => {
|
onImgDownload: (type) => {
|
||||||
|
@ -54,6 +56,26 @@ const mapStateToProps = (state, ownProps) => ({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
savePreset: () => {
|
||||||
|
let preset = {
|
||||||
|
name: '测试预设',
|
||||||
|
selectedIndex: state.selectedIndex,
|
||||||
|
preview: svgToBase64(outerHtml(state.selectedIndex), 1500, 1500),
|
||||||
|
styleName: state.value,
|
||||||
|
params: state.paramInfo[state.selectedIndex].map((paramInfo, index) => {
|
||||||
|
return {
|
||||||
|
name: paramInfo.key,
|
||||||
|
value: state.paramValue[state.selectedIndex][index],
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
globalParams: new Array(3),
|
||||||
|
};
|
||||||
|
preset.globalParams[0] = {name: '容错率', value: state.correctLevel};
|
||||||
|
preset.globalParams[1] = {name: '图标', value: state.icon};
|
||||||
|
preset.globalParams[2] = {name: '文字', value: state.title};
|
||||||
|
appendPreset(preset);
|
||||||
|
alert('saved');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PresetModal from "../../components/preset/PresetModal";
|
||||||
|
import {getPresets} from "../../utils/storageUtils";
|
||||||
|
import {changeCorrectLevel, changeIcon, changeParam, changeStyle, changeTitle} from "../../actions";
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
visible: ownProps.visible,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||||
|
onClose: ownProps.onClose,
|
||||||
|
loadPreset: (preset) => {
|
||||||
|
dispatch(changeStyle(preset.selectedIndex, preset.styleName));
|
||||||
|
dispatch(changeCorrectLevel(preset.globalParams[0].value));
|
||||||
|
dispatch(changeIcon(preset.globalParams[1].value));
|
||||||
|
dispatch(changeTitle(preset.globalParams[2].value));
|
||||||
|
preset.params.forEach((param, index) => dispatch(changeParam(preset.selectedIndex, index, param.value)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(PresetModal);
|
|
@ -52,7 +52,7 @@ const mapStateToProps = state => ({
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onSelected: rendererIndex => {
|
onSelected: rendererIndex => {
|
||||||
dispatch(changeStyle(rendererIndex, styles[rendererIndex].renderer, styles[rendererIndex].value))
|
dispatch(changeStyle(rendererIndex, styles[rendererIndex].value))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,10 @@ import {encodeData} from "../utils/qrcodeHandler";
|
||||||
import {actionTypes} from "../constant/ActionTypes";
|
import {actionTypes} from "../constant/ActionTypes";
|
||||||
import {QRBTF_URL} from "../constant/References";
|
import {QRBTF_URL} from "../constant/References";
|
||||||
import {getExactValue} from "../utils/util";
|
import {getExactValue} from "../utils/util";
|
||||||
import {RendererRect} from "../components/renderer/RendererBase";
|
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
selectedIndex: 0,
|
selectedIndex: 0,
|
||||||
value: 'A1',
|
value: 'A1',
|
||||||
rendererType: RendererRect,
|
|
||||||
correctLevel: 0,
|
correctLevel: 0,
|
||||||
textUrl: QRBTF_URL,
|
textUrl: QRBTF_URL,
|
||||||
history: [],
|
history: [],
|
||||||
|
@ -32,7 +30,6 @@ export default function appReducer(state = initialState, action) {
|
||||||
case actionTypes.CHANGE_STYLE: {
|
case actionTypes.CHANGE_STYLE: {
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
value: action.value,
|
value: action.value,
|
||||||
rendererType: action.rendererType,
|
|
||||||
selectedIndex: action.rendererIndex,
|
selectedIndex: action.rendererIndex,
|
||||||
history: state.history.slice().concat(action.value)
|
history: state.history.slice().concat(action.value)
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,20 @@ export function isPicture(file) {
|
||||||
return fileTypes.includes(file.type);
|
return fileTypes.includes(file.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function svgToBase64(content, width, height) {
|
||||||
|
const wrap = document.createElement('div');
|
||||||
|
wrap.innerHTML = content;
|
||||||
|
|
||||||
|
const $svg = wrap.firstChild
|
||||||
|
const $clone = $svg.cloneNode(true);
|
||||||
|
|
||||||
|
$clone.setAttribute('width', width);
|
||||||
|
$clone.setAttribute('height', height);
|
||||||
|
|
||||||
|
const svgData = new XMLSerializer().serializeToString($clone);
|
||||||
|
return 'data:image/svg+xml;base64,' + btoa(svgData);
|
||||||
|
}
|
||||||
|
|
||||||
export function toBase64(file, aspectRatio) {
|
export function toBase64(file, aspectRatio) {
|
||||||
let canvas = document.createElement('canvas');
|
let canvas = document.createElement('canvas');
|
||||||
let ctx = canvas.getContext('2d');
|
let ctx = canvas.getContext('2d');
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
const STORAGE_KEYS = {
|
||||||
|
PRESETS: 'presets'
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getPresets() {
|
||||||
|
let presetArray = [];
|
||||||
|
const presetsValue = localStorage.getItem(STORAGE_KEYS.PRESETS);
|
||||||
|
if (presetsValue) {
|
||||||
|
presetArray = JSON.parse(presetsValue);
|
||||||
|
}
|
||||||
|
return presetArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function appendPreset(preset) {
|
||||||
|
const presets = getPresets();
|
||||||
|
presets.push(preset);
|
||||||
|
localStorage.setItem(STORAGE_KEYS.PRESETS, JSON.stringify(presets));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function removePreset(index) {
|
||||||
|
const presets = getPresets();
|
||||||
|
presets.splice(index, 1);
|
||||||
|
localStorage.setItem(STORAGE_KEYS.PRESETS, JSON.stringify(presets));
|
||||||
|
}
|
27
yarn.lock
27
yarn.lock
|
@ -4311,6 +4311,11 @@ execa@^1.0.0:
|
||||||
signal-exit "^3.0.0"
|
signal-exit "^3.0.0"
|
||||||
strip-eof "^1.0.0"
|
strip-eof "^1.0.0"
|
||||||
|
|
||||||
|
exenv@^1.2.0:
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.npm.taobao.org/exenv/download/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||||
|
integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
|
||||||
|
|
||||||
exit@^0.1.2:
|
exit@^0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.npm.taobao.org/exit/download/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
|
resolved "https://registry.npm.taobao.org/exit/download/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
|
||||||
|
@ -8774,6 +8779,21 @@ react-lazy-load@^3.0.13:
|
||||||
lodash.throttle "^4.0.0"
|
lodash.throttle "^4.0.0"
|
||||||
prop-types "^15.5.8"
|
prop-types "^15.5.8"
|
||||||
|
|
||||||
|
react-lifecycles-compat@^3.0.0:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.npm.taobao.org/react-lifecycles-compat/download/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||||
|
integrity sha1-TxonOv38jzSIqMUWv9p4+HI1I2I=
|
||||||
|
|
||||||
|
react-modal@^3.12.1:
|
||||||
|
version "3.12.1"
|
||||||
|
resolved "https://registry.npm.taobao.org/react-modal/download/react-modal-3.12.1.tgz?cache=0&sync_timestamp=1606096428365&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-modal%2Fdownload%2Freact-modal-3.12.1.tgz#38c33f70d81c33d02ff1ed115530443a3dc2afd3"
|
||||||
|
integrity sha1-OMM/cNgcM9Av8e0RVTBEOj3Cr9M=
|
||||||
|
dependencies:
|
||||||
|
exenv "^1.2.0"
|
||||||
|
prop-types "^15.5.10"
|
||||||
|
react-lifecycles-compat "^3.0.0"
|
||||||
|
warning "^4.0.3"
|
||||||
|
|
||||||
react-redux@^7.2.0:
|
react-redux@^7.2.0:
|
||||||
version "7.2.0"
|
version "7.2.0"
|
||||||
resolved "https://registry.npm.taobao.org/react-redux/download/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d"
|
resolved "https://registry.npm.taobao.org/react-redux/download/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d"
|
||||||
|
@ -10642,6 +10662,13 @@ walker@^1.0.7, walker@~1.0.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
makeerror "1.0.x"
|
makeerror "1.0.x"
|
||||||
|
|
||||||
|
warning@^4.0.3:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
|
||||||
|
integrity sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.0.0"
|
||||||
|
|
||||||
watchpack-chokidar2@^2.0.0:
|
watchpack-chokidar2@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.npm.taobao.org/watchpack-chokidar2/download/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
|
resolved "https://registry.npm.taobao.org/watchpack-chokidar2/download/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
|
||||||
|
|
Loading…
Reference in New Issue