diff --git a/package.json b/package.json index 7b8b8d1..61eb6b9 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,7 @@ "react-router-dom": "5.0.1", "react-scripts": "3.1.1", "redux": "4.0.4", - "simple-svg-icons": "2.0.2", - "simple-svg-tools": "1.1.12" + "svg-inline-react": "3.2.0" }, "scripts": { "start": "react-scripts start", diff --git a/src/App.js b/src/App.js index 83b533e..f18e95c 100644 --- a/src/App.js +++ b/src/App.js @@ -9,6 +9,8 @@ import NavBar from './components/NavBar/NavBar'; import ReduxDemo from './components/ReduxDemo/ReduxDemo'; import mainReducer from './store/mainReducer'; import SvgSettingOptions from './components/svgSetting/svgSettingOptions'; +import DisplayAllComponent from './components/displayAllComponent'; +import FinalSvgDisplay from './components/displaySvg/finalSvgDisplay'; import './App.scss'; class App extends Component { render() { @@ -23,6 +25,8 @@ class App extends Component { + + diff --git a/src/App.scss b/src/App.scss index b41d297..501d381 100644 --- a/src/App.scss +++ b/src/App.scss @@ -16,7 +16,7 @@ align-items: center; justify-content: center; font-size: calc(10px + 2vmin); - color: white; + color: #FFFFFF; } .App-link { diff --git a/src/components/NavBar/NavBar.js b/src/components/NavBar/NavBar.js index 9815f01..28dfccb 100644 --- a/src/components/NavBar/NavBar.js +++ b/src/components/NavBar/NavBar.js @@ -1,28 +1,28 @@ -import React, { Component } from 'react'; -import { Link } from 'react-router-dom'; +import React, { Component } from "react"; +import { Link } from "react-router-dom"; -import './NavBar.scss'; +import "./NavBar.scss"; export default class NavBar extends Component { - render() { - return ( -
- -
{'Home'}
- -
{' | '}
- -
{'Choose File'}
- -
{' | '}
- -
{'Display Svg'}
- -
{' | '}
- -
{'Redux Demo'}
- -
- ); - } + render() { + return ( +
+ +
{"Home"}
+ +
{" | "}
+ +
{"Choose File"}
+ +
{" | "}
+ +
{"Display Svg"}
+ +
{" | "}
+ +
{"Redux Demo"}
+ +
+ ); + } } diff --git a/src/components/NavBar/NavBar.scss b/src/components/NavBar/NavBar.scss index 0fe6412..c4d6013 100644 --- a/src/components/NavBar/NavBar.scss +++ b/src/components/NavBar/NavBar.scss @@ -1,6 +1,6 @@ .navbar{ display: flex; - height: 30px; + height: 105px; background-color: #bcda12; align-items: center; @@ -12,4 +12,8 @@ a:hover{ background-color: #abc514; } +} + +.navbar-divider{ + font-size: 59px; } \ No newline at end of file diff --git a/src/components/ReduxDemo/ReduxDemo.js b/src/components/ReduxDemo/ReduxDemo.js index 8e24800..5d965e6 100644 --- a/src/components/ReduxDemo/ReduxDemo.js +++ b/src/components/ReduxDemo/ReduxDemo.js @@ -50,4 +50,4 @@ const mapDispatchToProps = dispatch => { }; }; -export default connect(mapStateToProps, mapDispatchToProps)(ReduxDemo); \ No newline at end of file +export default connect(mapStateToProps, mapDispatchToProps)(ReduxDemo); diff --git a/src/components/checkBoxSelection/checkBoxSelection.js b/src/components/checkBoxSelection/checkBoxSelection.js index 745e0a7..97ace28 100644 --- a/src/components/checkBoxSelection/checkBoxSelection.js +++ b/src/components/checkBoxSelection/checkBoxSelection.js @@ -1,47 +1,103 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import './checkBoxSelection.scss'; +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import "./checkBoxSelection.scss"; +import { connect } from "react-redux"; +import { + ADD_VARIABLE, + UPDATE_VARIABLE, + DELETE_VARIABLE +} from "../../store/actionTypes"; + class CheckBoxSelection extends Component { - constructor(props) { - super(props); - this.state = { - isClicked: false - }; + constructor(props) { + super(props); + this.state = { + isClicked: this.props.isSelected + }; + } + + convertSvgToDataUrl = file => { + let reader = new FileReader(); + const svgSettings = [...this.props.svgSettingList]; + reader.onload = result => { + + svgSettings.push({ + name: file.name, + dataurl: result.target.result + }); + this.props.updateStore("svgSettingList",svgSettings) + + }; + if (file) { + reader.readAsDataURL(file); } + }; - componentWillMount() { - this.setState({ isClicked: this.props.isSelected }); + changeColourAndTick = () => { + + this.setState({ isClicked: !this.state.isClicked }); + let index = this.props.svgSettingList.findIndex( + setting => setting.name == this.props.file.name + ); + + if (index < 0) { + this.convertSvgToDataUrl(this.props.file); + } else { + this.props.svgSettingList.splice(index, 1); } + }; - handleDivClick= () => { - this.setState({ - isClicked: !this.state.isClicked - }); - } - - render() { - - return ( - -
- - -
- ); - } + render() { + return ( +
this.changeColourAndTick()} + > + + +
+ ); + } } CheckBoxSelection.propTypes = { - filename: PropTypes.string, - isSelected: PropTypes.bool + svgSettingList: PropTypes.array, + filename: PropTypes.string }; -export default CheckBoxSelection; + +const mapStateToProps = state => { + const svgSettingList = state.svgSettingList; + return { svgSettingList }; +}; + +const mapDispatchToProps = dispatch => { + return { + addToStore: (variableName, variableValue) => + dispatch({ + type: ADD_VARIABLE, + variableName: variableName, + variableValue: variableValue + }), + updateStore: (variableName, variableValue) => + dispatch({ + type: UPDATE_VARIABLE, + variableName: variableName, + variableValue: variableValue + }), + deleteFromStore: variableName => + dispatch({ type: DELETE_VARIABLE, variableName: variableName }) + }; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(CheckBoxSelection); diff --git a/src/components/checkBoxSelection/checkBoxSelection.scss b/src/components/checkBoxSelection/checkBoxSelection.scss index 1c94dc9..98dfb66 100644 --- a/src/components/checkBoxSelection/checkBoxSelection.scss +++ b/src/components/checkBoxSelection/checkBoxSelection.scss @@ -1,25 +1,16 @@ .checkbox-container-clicked { - background-color: yellow; - width: 80%; - height: 10%; + background-color: #b5cfe1; } .checkbox-container-unclicked { - background-color: white; - width: 80%; - height: 10%; - border: 1px solid black; + background-color: #FFFFFF; + border: 1px solid #000000; } -.checkbox-input, -.checkbox-label { - margin-top: 12%; - margin-left: 12%; -} + .checkbox-input-svg, .checkbox-label-svg { - margin-top: 2%; - margin-left: 2%; + padding-left: 3%; } .main { @@ -29,24 +20,50 @@ .file { display: flex; - margin-top: 20px; + padding: 2%; } .hide-file-list { - margin-top: 20px; display: none; } - .card-settings { - height: 600px; + height: 350px; overflow-y: scroll; + background-color:#b5cfe1 ; + width: 600px; +} + +.home-display { + display: flex; +} +.choose { + width: 50%; +} +.display { + width: 50%; +} + +.optimize-button{ + text-align: center; + display: inline-block; + justify-items: center; + width:100px; + height: 70px; + border-radius: 25px; background-color: #b5cfe1; - width: 350px; - padding-left: 20px; - box-shadow: 10px 10px 55px 0px black; + align-items: center; +} + +.download-button { + height: 70px; + border-radius: 35px; + background-color: #b6e1b5; + position: fixed; } +.optimise-button-div{ + display: flex; + justify-content: center; -.slider { - margin-top: 10px; - margin-bottom: 10px; } + + diff --git a/src/components/chooseFolder/chooseFolder.js b/src/components/chooseFolder/chooseFolder.js index 436026f..0956524 100644 --- a/src/components/chooseFolder/chooseFolder.js +++ b/src/components/chooseFolder/chooseFolder.js @@ -1,54 +1,60 @@ -import React, { Component } from 'react'; -import './../checkBoxSelection/checkBoxSelection.scss'; -import optimizeSvg from '../functions'; -import CheckBoxSelection from '../checkBoxSelection/checkBoxSelection'; +import React, { Component } from "react"; +import "./../checkBoxSelection/checkBoxSelection.scss"; +import { optimizeSvg } from "../functions"; +import CheckBoxSelection from "../checkBoxSelection/checkBoxSelection"; + class ChooseFolder extends Component { - constructor(props) { - super(props); - this.state = { - path: [], - displayMenu: false, - originalDataUrl:'', - optimizedDataUrl:'' - }; - } + constructor(props) { + super(props); + this.state = { + path: [], + displayMenu: false, + originalSvgDataUrl: "", + optimizedDataUrl: "" + }; + } onChangeHandler = event => { - this.setState({path:event.target.files}); - } + this.setState({ path: event.target.files}); + }; + + convertSvgToDataUrl = file => { + let reader = new FileReader(); + reader.onload = result => { + this.setState({ originalSvgDataUrl: result.target.result }); + }; + if (file) { + reader.readAsDataURL(file); + } + }; + + optimizeSvgDataUrl = async dataUrl => { + this.setState({ optimizedDataUrl: await optimizeSvg(dataUrl) }); + }; - convertSvgToDataUrl=(file)=>{ - let reader = new FileReader(); - reader.onload = (result)=>{ - this.setState({originalDataUrl:result.target.result}); - }; - if (file) { - reader.readAsDataURL(file); - } - } + render() { + const listOfFileNames = []; + for (let key of this.state.path) { + listOfFileNames.push( + + ); + } - optimizeSvgDataUrl= async (dataUrl) =>{ - this.setState({optimizedDataUrl:await optimizeSvg(dataUrl)}); - } + return ( +
+
+ +
- render() { - const listOfFileNames = []; - for(var key of this.state.path) { - listOfFileNames.push(); - } - - return ( -
-
- -
-
- {listOfFileNames} -
-
- ); - } +
{listOfFileNames}
+
+ ); + } } -export default ChooseFolder; \ No newline at end of file +export default ChooseFolder; diff --git a/src/components/displayAllComponent.js b/src/components/displayAllComponent.js new file mode 100644 index 0000000..df66c00 --- /dev/null +++ b/src/components/displayAllComponent.js @@ -0,0 +1,82 @@ +import React, { Component } from "react"; +import ChooseFolder from "./chooseFolder/chooseFolder"; +import { Redirect } from "react-router-dom"; +import SvgSettingOptions from "./svgSetting/svgSettingOptions"; +import "../components/checkBoxSelection/checkBoxSelection.scss"; +import { changeObj, optimizeSvg } from "../../src/components/functions"; +import { connect } from "react-redux"; +import PropTypes from "prop-types"; +import { UPDATE_VARIABLE} from "../../src/store/actionTypes"; + +class DisplayAllComponent extends Component { + constructor(props) { + super(props); + this.state = { + redirect: false + }; + } + getOptimizeSvg = async () => { + let originalAndOptimised = {}; + for (var option of this.props.svgOptions) { + changeObj(option, this.props.svgObject.plugins); + } + for (var setting of this.props.svgSettingList) { + let { displayOptimize=[] } = this.props; + let SvgPlugins = this.props.svgOptions.length > 0 ? this.props.svgObject.plugins : null; + originalAndOptimised = { + originalSvg: setting.dataurl, + name: setting.name, + optimisedSvg: await optimizeSvg( + setting.dataurl, + SvgPlugins + ) + }; + this.props.updateStore("displayOptimize",[...displayOptimize,originalAndOptimised]); + } + this.setState({ redirect: true }); + }; + + render() { + return ( +
+ {this.state.redirect ? : null} +
+ +
+
+ +
+ +
+
+
+ ); + } +} + +DisplayAllComponent.propTypes = { + addToStore: PropTypes.func, + updateStore: PropTypes.func, + svgSettingList: PropTypes.array, + svgOptions: PropTypes.array, + svgObject: PropTypes.object, + displayOptimize: PropTypes.array +}; + +const mapStateToProps = state => { + const svgSettingList = state.svgSettingList; + const svgOptions = state.svgOptions; + const svgObject = state.svgObject; + const displayOptimize = state.displayOptimize; + return { svgSettingList, svgOptions, svgObject, displayOptimize }; +}; + +const mapDispatchToProps = dispatch => { + return { + updateStore: (variableName, variableValue) => dispatch({ type: UPDATE_VARIABLE, variableName: variableName, variableValue: variableValue }) + }; +}; + +export default connect(mapStateToProps,mapDispatchToProps)(DisplayAllComponent); diff --git a/src/components/displaySvg/displaySvg.js b/src/components/displaySvg/displaySvg.js index 1db0ac8..d1fe8d0 100644 --- a/src/components/displaySvg/displaySvg.js +++ b/src/components/displaySvg/displaySvg.js @@ -1,48 +1,78 @@ -import React, { Component } from 'react'; -import base64 from 'base-64'; -import PropTypes from 'prop-types'; +import React, { Component } from "react"; +import base64 from "base-64"; +import "./finalSvgDisplay.scss"; +import PropTypes from "prop-types"; +import InlineSVG from "svg-inline-react"; class DisplaySvg extends Component { - constructor(props) { - super(props); - this.state = { - fileSize: 0 - }; - } - - componentWillMount = () => { - if (this.props.dataUrl) { - this.setState({ - fileSize: this.dataURLtoKilloBytes(this.props.dataUrl.split(',')[1]) - }); - } + constructor(props) { + super(props); + this.state = { + fileSizeNormal: 0, + fileSizeOptimised: 0, + isClicked: false }; + } - dataURLtoKilloBytes = dataURI => { - return base64.decode(dataURI).length / 1000; - }; + changeColourOnclickToMark = () => { + this.setState({ isClicked: !this.state.isClicked }); + }; - render() { - return ( -
+ componentWillMount = () => { + if (this.props.dataUrl) { + this.setState({ + fileSizeNormal: this.dataURLtoKilloBytes( + this.props.dataUrl.split(",")[1] + ), + fileSizeOptimised: this.props.finalStringElementWrappedWithLink.length / 1000 + }); + } + }; + + dataURLtoKilloBytes = dataURI => { + return base64.decode(dataURI).length / 1000; + }; + + render() { + return ( +
+ { (this.props.dataUrl && this.props.finalStringElementWrappedWithLink) ? +
+
    +
  • - svg to be displayed -
    { 'File Size : '+this.state.fileSize +' KB'}
    + svg to be displayed +
    + {"File Size : " + this.state.fileSizeNormal + " KB"} +
    -
- ); - } + +
  • +
    +
    + +
    +
    + {"File Size : " + this.state.fileSizeOptimised + " KB"} +
    +
    +
  • + +
    + : null} +
    + ); + } } DisplaySvg.propTypes = { - dataUrl: PropTypes.string, - width: PropTypes.string, - height: PropTypes.string + dataUrl: PropTypes.string, + width: PropTypes.string, + height: PropTypes.string }; export default DisplaySvg; diff --git a/src/components/displaySvg/finalSvgDisplay.js b/src/components/displaySvg/finalSvgDisplay.js new file mode 100644 index 0000000..04f47c0 --- /dev/null +++ b/src/components/displaySvg/finalSvgDisplay.js @@ -0,0 +1,158 @@ +import React, { Component } from "react"; +import PropTypes from "prop-types"; +import finalSvgDisplay from "./finalSvgDisplay.scss"; +import { connect } from "react-redux"; +import { SVG_TAG_NAMES } from "../../constants/constants"; +import { + ADD_VARIABLE, + UPDATE_VARIABLE, + DELETE_VARIABLE +} from "../../store/actionTypes"; +import { + wrapElements, + updateSvgElements, + changeSvgColourById +} from "../functions"; + +class FinalSvgDisplay extends Component { + constructor(props) { + super(props); + this.state = { + wrappedPathsElement: [], + pathArrayState: null, + storePathsIds: [], + clickedSvgState: [] + }; + } + + downloadOptimizedSvgs = () => { + let svgElementList = document.getElementsByTagName("svg"); + + //get svg source. + let serializer = new XMLSerializer(); + for (let svgDataIndex in svgElementList) { + //get svg source. + let source = serializer.serializeToString(svgElementList[svgDataIndex]); + source = source + .replace('', "") + .replace("", "") + .replace('onclick="changeSvgColourById(this.id);"', ""); + + //add name spaces. + if ( + !source.match(/^]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/) + ) { + source = source.replace( + /^]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)) { + source = source.replace( + /^ { + let array = []; + let pathArrayLocal = []; + let elementIds = []; + wrapElements(SVG_TAG_NAMES, array, pathArrayLocal, 7, elementIds); + let functionStr = + 'function changeSvgColourById(elemId,white){ let arrayOfClickedIds = [];if(!arrayOfClickedIds.includes(elemId) || arrayOfClickedIds.length == 0 ){ arrayOfClickedIds.push(elemId);document.getElementById(elemId).style.fill = "brown";}else{arrayOfClickedIds.push(elemId);document.getElementById(elemId).removeAttribute("style");document.getElementById(elemId).style.fill = prevColour;}}'; + const script = document.createElement("script"); + let textNodeToChangeAvgColour = document.createTextNode(functionStr); + script.setAttribute("class", "fucntionality-script"); + script.appendChild(textNodeToChangeAvgColour); + document.body.appendChild(script); + + this.setState({ + wrappedPathsElement: array, + pathArrayState: pathArrayLocal, + storePathsIds: elementIds + }); + }; + + render() { + const listOfFileNames = []; + updateSvgElements( + listOfFileNames, + this.props.displayOptimize, + this.state.wrappedPathsElement, + this.state.pathArrayState + ); + + return ( +
    + {listOfFileNames.length > 0 ? ( +
    +
    {listOfFileNames}
    +
    + +
    +
    + ) : ( +
    +
    loading svg .....
    +
    +
    + )} +
    + ); + } +} + +FinalSvgDisplay.propTypes = { + displayOptimize: PropTypes.array +}; + +const mapStateToProps = state => { + const displayOptimize = state.displayOptimize; + return { displayOptimize }; +}; + +const mapDispatchToProps = dispatch => { + return { + addToStore: (variableName, variableValue) => + dispatch({ + type: ADD_VARIABLE, + variableName: variableName, + variableValue: variableValue + }), + updateStore: (variableName, variableValue) => + dispatch({ + type: UPDATE_VARIABLE, + variableName: variableName, + variableValue: variableValue + }), + deleteFromStore: variableName => + dispatch({ type: DELETE_VARIABLE, variableName: variableName }) + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(FinalSvgDisplay); diff --git a/src/components/displaySvg/finalSvgDisplay.scss b/src/components/displaySvg/finalSvgDisplay.scss new file mode 100644 index 0000000..9e2ad91 --- /dev/null +++ b/src/components/displaySvg/finalSvgDisplay.scss @@ -0,0 +1,67 @@ +.display-page-div{ + padding: 171px; + width: 373px; +} + + + +ellipse,rect,path,text,linearGradient,polygon,circle{ &:hover{ + background-color: yellow; + fill: yellow; +} } + .inline-display-position{ + padding-top: 40px; + } + svg{ + max-height: 106px; + max-width: fit-content; + } + + .display-svgs-border-match { + max-height: 381px; + border: outset; + border-color: green; +} + + .display-original-optimised{ + overflow-y: scroll; + max-height: 571px; + border: outset; + border-color: green; + } + + .button-background{ + background-color: grey; + height: 171px; + } + .position-loader{ + padding-top: 11%; +} + + .loader { + border: 16px solid greenyellow; + border-radius: 111px; + border-top: 16px solid #bcda12; + width: 197px; + height: 199px; + animation: spin 4s linear infinite; + } + + /* Safari */ +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); } + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + li{ + display: table-cell; + padding: 10px; + vertical-align: top; + position:relative; + text-align: center; + } diff --git a/src/components/functions.js b/src/components/functions.js index 84ae424..2419e54 100644 --- a/src/components/functions.js +++ b/src/components/functions.js @@ -1,10 +1,185 @@ -import axios from 'axios'; -import {BASE_URL,OPTIMIZE_SVG} from '../constants/constants'; - -export default function optimizeSvg(dataUrl){ - return axios.post(`${BASE_URL}${OPTIMIZE_SVG}`, { dataUrl }) - .then(res => { - return res.data; - }) - .catch(err => console.log(err)); -} +import axios from "axios"; +import React from "react"; +import DisplaySvg from "../components/displaySvg/displaySvg"; +import finalSvgDisplay from "../components/displaySvg/finalSvgDisplay.scss"; +import { BASE_URL, OPTIMIZE_SVG } from "../constants/constants"; +import base64 from "base-64"; + +export const optimizeSvg = (dataUrl, svgo) => { + return axios + .post(`${BASE_URL}${OPTIMIZE_SVG}`, { dataUrl, svgo }) + .then(res => { + return res.data.urlData; + }) + .catch(err => console.log(err)); +}; + +export const changeObj = (value, svgoObjectPlugins) => { + let newSvgoObject = svgoObjectPlugins.map(option => { + if (option[value] !== null && option[value] !== undefined) { + option[value] = true; + } + }); + return newSvgoObject; +}; + +const generate_random_id = string_length => { + let random_string = ""; + let random_ascii; + let ascii_low = 65; + let ascii_high = 90; + for (let i = 0; i < string_length; i++) { + random_ascii = Math.floor( + Math.random() * (ascii_high - ascii_low) + ascii_low + ); + random_string += String.fromCharCode(random_ascii); + } + return `id_${random_string}`; +}; + +export const wrapElements = ( + SVG_TAG_NAMES, + array, + drawingComponetLocal, + idLengthToGenerate, + idOfElements +) => { + for (let svgTagNameIndex in SVG_TAG_NAMES) { + let drawingComponet = document.getElementsByTagName( + SVG_TAG_NAMES[svgTagNameIndex] + ); + for (let drawingComponetIndex of drawingComponet) { + let element = new XMLSerializer() + .serializeToString(drawingComponetIndex) + .toString() + .replace('xmlns="http://www.w3.org/2000/svg"', ""); + if (!element.includes("id=")) { + let idInserter = + "<" + + SVG_TAG_NAMES[svgTagNameIndex] + + ' id="id_' + + generate_random_id(idLengthToGenerate) + + '"'; + idOfElements.push(idInserter.substring(9)); + element = element.replace( + "<" + SVG_TAG_NAMES[svgTagNameIndex], + idInserter + ); + } + let elementWrapper = document.createElement("a"); + elementWrapper.setAttribute("class", "svg-elem-wrapper"); + elementWrapper.setAttribute("id", "id-1"); + drawingComponetLocal.push(drawingComponetIndex); + elementWrapper.appendChild( + new DOMParser().parseFromString(element, "text/html").body.firstChild + ); + elementWrapper.firstChild.setAttribute( + "onclick", + "changeSvgColourById(this.id)" + ); + + array.push(elementWrapper); + } + } +}; + +export const updateSvgElements = ( + listOfFileNames, + optimisedArray, + wrappedPathsElement, + drawingComponetState +) => { + for (let key in optimisedArray) { + let finalStringElementWrappedWithLink = base64.decode( + optimisedArray[key].optimisedSvg + ); + if (wrappedPathsElement.length > 0) { + for (let index = 0; index < wrappedPathsElement.length; index++) { + let stringToWithLinkToWrap = new XMLSerializer() + .serializeToString(wrappedPathsElement[index]) + .toString(); + + let StringToBeWrappedByLink = new XMLSerializer() + .serializeToString(drawingComponetState[index]) + .toString(); + StringToBeWrappedByLink = StringToBeWrappedByLink.replace( + 'xmlns="http://www.w3.org/2000/svg"', + "" + ); + if (StringToBeWrappedByLink.substring(0, 5) == " + + + ); + } +}; diff --git a/src/components/svgSetting/svgCardLayout.js b/src/components/svgSetting/svgCardLayout.js index c84c0a5..afd28a6 100644 --- a/src/components/svgSetting/svgCardLayout.js +++ b/src/components/svgSetting/svgCardLayout.js @@ -1,216 +1,231 @@ export const CardLayout = [ - { - - text: 'Show original', - type: 'checkbox' - }, - { - text: 'Compare gzipped', - type: 'checkbox' - }, - { - text: 'Prettify markup', - type: 'checkbox' - }, - { - text: 'Precision', - type: 'slider' - }, { text: 'Remove doctype', - type: 'checkbox' + type: 'checkbox', + value: 'removeDoctype' }, { text: 'Remove XML instructions', - type: 'checkbox' + type: 'checkbox', + value:'removeXMLProcInst' }, { text: 'Remove comments', - type: 'checkbox' + type: 'checkbox', + value:'removeComments' }, { text: 'Remove ', - type: 'checkbox' + type: 'checkbox', + value:'removeMetadata' }, { - text: 'Remove xmln', - type: 'checkbox' + text: 'Cleanup attributes', + type: 'checkbox', + value:'cleanupAttrs' }, { text: 'Remove edit data', - type: 'checkbox' + type: 'checkbox', + value:'removeEditorsNSData' }, { text: 'Cleanup attributes whitespace', - type: 'checkbox' + type: 'checkbox', + value:'cleanupAttrs' }, { - text: 'Inline style', - type: 'checkbox' - + text:'Cleanup numeric values', + type:'checkbox', + value:'cleanupNumericValues' + }, { - text:'Minify style', - type: 'checkbox' + text: 'Remove unused def', + type: 'checkbox', + value:'removeUselessDefs' }, { - text: 'Style to attribute', - type: 'checkbox' + text: 'Remove XML procInst', + type: 'checkbox', + value:'removeXMLProcInst' }, { - text: 'Remove raster images', - type: 'checkbox' + text: 'Remove useless stroke and fill', + type: 'checkbox', + value:'removeUselessStrokeAndFil' + }, { - text: 'Remove unused def', - type: 'checkbox' + text: 'Remove viewbox', + type: 'checkbox', + value:'removeViewBox' }, { - text: 'Round/rewrite numbers', - type: 'checkbox' + text: 'Remove hidden elements', + type: 'checkbox', + value:' removeHiddenElems' }, { - text: 'Round/rewrite number list', - type: 'checkbox' + text: 'Remove empty text', + type: 'checkbox', + value:'removeEmptyText' }, { - text: 'Minify colours', - type: 'checkbox' - - }, - { - text: 'Remove unknowns and defaults', - type: 'checkbox' + text: 'Remove raster images', + type: 'checkbox', + value:'removeRasterImages' }, { - text: 'Remove unknowns and defaults', - type: 'checkbox' + text: 'Move attrs to parent group', + type: 'checkbox', + value:'moveElemsAttrsToGroup' }, { - text: 'Remove unneeded group attrs', - type: 'checkbox' + text: 'Move group attrs to elements', + type: 'checkbox', + value:'moveGroupAttrsToElems' }, { - text: 'Remove useless stroke and fill', - type: 'checkbox' + text: 'Remove empty attrs', + type: 'checkbox', + value:'removeEmptyAttrs' }, { - text: 'Remove viewbox', - type: 'checkbox' + text: 'Remove empty containers', + type: 'checkbox', + value:' removeEmptyContainers' }, { - text: 'Remove/tidy enable-background', - type: 'checkbox' + text: 'Merge paths', + type: 'checkbox', + value:' mergePaths' }, { - text: 'Remove hidden elements', - type: 'checkbox' + text: 'Sort attrs', + type: 'checkbox', + value:'sortAttrs' }, { - text: 'Remove empty text', - type: 'checkbox' + text: 'Remove ', + type: 'checkbox', + value:'removeTitle' }, { - text: 'Shapes to(smaller) paths', - type: 'checkbox' + text: 'Remove <desc>', + type: 'checkbox', + value:'removeDesc' }, - { - text: 'Move attrs to parent group', - type: 'checkbox' - + { text:'Remove Dimensions', + type: 'checkbox', + value:'removeDimensions' }, - { - text: 'Move group attrs to elements', - type: 'checkbox' - + { + text:'Convert shape to path', + type: 'checkbox', + value:'convertShapeToPath' + + }, + { + text:'Sort attribute', + type:'checkbox', + value:'sortAttrs' }, { - text: 'Collapse useless group', - type: 'checkbox' - + text:'Remove dimensions', + type:'checkbox', + value:' removeDimensions' }, { - text: 'Round/rewrite paths', - type: 'checkbox' - + text:'Remove raster images', + type:'checkbox', + value:'removeRasterImages' }, { - text: 'Round/rewrite transformation', - type: 'checkbox' - + text:'Cleanup numeric value', + type:'checkbox', + value:'cleanupNumericValues' }, { - text: 'Remove empty attrs', - type: 'checkbox' - + text:'Cleanup IDs', + type:'checkbox', + value:'cleanupIDs' }, { - text: 'Remove empty containers', - type: 'checkbox' - + text:'Remove Unused NS', + type:'checkbox', + value:'removeUnusedNS' }, { - text: 'Merge paths', - type: 'checkbox' - + text:'Convert path data', + type:'checkbox', + value:'convertPathData' + }, { - text: 'Remove unused namesopace', - type: 'checkbox' - + text:'Convert colors', + type:'checkbox', + value:'convertColors' + }, { - text: 'Sort attrs', - type: 'checkbox' - + text:'Convert transform', + type:'checkbox', + value:'convertTransform' + }, { - text: 'Remove <title>', - type: 'checkbox' - + text:'Remove non inheritable group attribute', + type:'checkbox', + value:'removeNonInheritableGroupAttr' + }, { - text: 'Remove <desc>', - type: 'checkbox' - + text:'Cleanup enable background', + type:'checkbox', + value:'cleanupEnableBackground' + }, { - text: 'Prefer viewBox to width/height', - type: 'checkbox' - + text:'Convert style to attribute', + type:'checkbox', + value:'convertStyleToAttrs' + }, { - text: 'Remove style elements', - type: 'checkbox' - + text:'Remove noninheritable group attribute', + type:'checkbox', + value:'removeNonInheritableGroupAttrs' + }, { - text: 'Remove script elements', - type: 'checkbox' - + text:'Collapse groups', + type:'checkbox', + value:'collapseGroups' + } ]; \ No newline at end of file diff --git a/src/components/svgSetting/svgSetting.js b/src/components/svgSetting/svgSetting.js index a553f91..6d81ea9 100644 --- a/src/components/svgSetting/svgSetting.js +++ b/src/components/svgSetting/svgSetting.js @@ -1,34 +1,78 @@ -import React, { Component } from 'react'; -import '../checkBoxSelection/checkBoxSelection.scss'; -import PropTypes from 'prop-types'; +import React, { Component } from "react"; +import "../checkBoxSelection/checkBoxSelection.scss"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { Svgo } from "../svgSetting/svgoConfig"; +import { + ADD_VARIABLE, + UPDATE_VARIABLE, + DELETE_VARIABLE +} from "../../store/actionTypes"; + class SvgSetting extends Component { - constructor(props) { - super(props); - this.state = { - isClicked: this.props.isSelected - }; - } - - handleDivClick= () => { - this.setState({ - isClicked: !this.state.isClicked - }); - } - - render() { - return ( - <div OnClick ={this.handleDivClick}> - <input className='checkbox-input-svg' type='checkbox' checked={this.state.isClicked} - /> - <label className='checkbox-label-svg'> - {this.props.option} - </label> - </div> - ); - } + constructor(props) { + super(props); + this.state = { + isClicked: this.props.isSelected, + arr: [], + svgoObject: { ...Svgo } + }; + } + + handleSettingsClick = () => { + this.setState({ + isClicked: !this.state.isClicked + }); + + let indexOf = this.props.svgOptions.findIndex(this.props.value); + + let { svgOptions = [] } = this.props; + let updatedArr = + indexOf < 0 + ? [...svgOptions, this.props.value] + : [...svgOptions.slice(0, indexOf), ...svgOptions.slice(indexOf + 1)]; + this.props.updateStore("svgOptions", updatedArr); + }; + + render() { + return ( + <div onClick={() => this.handleSettingsClick()}> + <input type="checkbox" checked={this.state.isClicked} /> + <label className="checkbox-label-svg">{this.props.option}</label> + </div> + ); + } } + SvgSetting.propTypes = { - option: PropTypes.string, - isSelected: PropTypes.bool + svgOptions: PropTypes.array, + svgObject: PropTypes.object, + option: PropTypes.string, + isSelected: PropTypes.bool +}; + +const mapStateToProps = state => { + const svgOptions = state.svgOptions; + const svgObject = state.svgObject; + return { svgOptions, svgObject }; }; -export default SvgSetting; \ No newline at end of file +const mapDispatchToProps = dispatch => { + return { + addToStore: (variableName, variableValue) => + dispatch({ + type: ADD_VARIABLE, + variableName: variableName, + variableValue: variableValue + }), + updateStore: (variableName, variableValue) => + dispatch({ + type: UPDATE_VARIABLE, + variableName: variableName, + variableValue: variableValue + }), + deleteFromStore: variableName => + dispatch({ type: DELETE_VARIABLE, variableName: variableName }) + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(SvgSetting); diff --git a/src/components/svgSetting/svgSettingOptions.js b/src/components/svgSetting/svgSettingOptions.js index a5621b4..e318e81 100644 --- a/src/components/svgSetting/svgSettingOptions.js +++ b/src/components/svgSetting/svgSettingOptions.js @@ -1,35 +1,38 @@ -import React, { Component } from 'react'; -import './../checkBoxSelection/checkBoxSelection.scss'; -import {CardLayout} from './svgCardLayout'; -import SvgSetting from './svgSetting'; -import Slider from './slider'; +import React, { Component } from "react"; +import "./../checkBoxSelection/checkBoxSelection.scss"; +import { CardLayout } from "./svgCardLayout"; +import SvgSetting from "./svgSetting"; +import Slider from "./slider"; class SvgSettingOptions extends Component { - constructor(props) { - super(props); - this.state = { - settingOptionList : [] - }; - } + constructor(props) { + super(props); + this.state = { + settingOptionList: [] + }; + } - render() { - for(var key in CardLayout) { - if(CardLayout[key].type==='checkbox'){ - this.state.settingOptionList.push(<SvgSetting key={key} option={CardLayout[key].text} />); - }else if(CardLayout[key].type==='slider'){ - this.state.settingOptionList.push(<div className='slider'><Slider key={key} option={CardLayout[key].text} /></div>); - } - } - - return ( - <div className='card-settings' > - <div > - <label> {'SVG settings'} </label> - </div> - <div > - { this.state.settingOptionList} - </div> - </div> - ); - } -} + render() { + + return ( + <div className="card-settings"> + <div> + <label>{"SVG settings"}</label> + </div> + {CardLayout.map(function(option,key){ + if(option.type === "checkbox"){ + return (<SvgSetting + key={key} + value={option.value} + option={option.text} + />) + } else if (option.type === "slider"){ + return (<div className="slider"> + <Slider key={key} option={option.text} /> + </div>) + } + })} + </div> + ); + } +} export default SvgSettingOptions; diff --git a/src/components/svgSetting/svgoConfig.js b/src/components/svgSetting/svgoConfig.js new file mode 100644 index 0000000..f4a0dbd --- /dev/null +++ b/src/components/svgSetting/svgoConfig.js @@ -0,0 +1,72 @@ +export const Svgo = { + plugins: [{ + cleanupAttrs: false + }, { + removeDoctype: false + },{ + removeXMLProcInst: false + },{ + removeComments: false + },{ + removeMetadata: false + },{ + removeTitle: false + },{ + removeDesc: false + },{ + removeUselessDefs: false + },{ + removeEditorsNSData: false + },{ + removeEmptyAttrs: false + },{ + removeHiddenElems: false + },{ + removeEmptyText: false + },{ + removeEmptyContainers: false + },{ + removeViewBox: false + },{ + cleanupEnableBackground: false + },{ + convertStyleToAttrs: false + },{ + convertColors: false + },{ + convertPathData: false + },{ + convertTransform: false + },{ + removeUnknownsAndDefaults: false + },{ + removeNonInheritableGroupAttrs: false + },{ + removeUselessStrokeAndFill: false + },{ + removeUnusedNS: false + },{ + cleanupIDs: false + },{ + cleanupNumericValues: false + },{ + moveElemsAttrsToGroup: false + },{ + moveGroupAttrsToElems: false + },{ + collapseGroups: false + },{ + removeRasterImages: false + },{ + mergePaths: false + },{ + convertShapeToPath: false + },{ + sortAttrs: false + },{ + removeDimensions:false + },{ + removeAttrs: {attrs: '(stroke|fill)'} + } + ] +}; \ No newline at end of file diff --git a/src/constants/constants.js b/src/constants/constants.js index 402f3dc..d507282 100644 --- a/src/constants/constants.js +++ b/src/constants/constants.js @@ -1,2 +1,12 @@ export const BASE_URL = 'http://localhost:3500/'; -export const OPTIMIZE_SVG= 'optimizeSvg'; \ No newline at end of file +export const OPTIMIZE_SVG= 'optimizeSvg'; +export const OPTIMIZE_SVG_LIST= 'optimizesvgElementList'; +export const SVG_TAG_NAMES= [ + "rect", + "path", + "circle", + "polygon", + "ellipse", + "linearGradient", + "text" +] diff --git a/src/index.js b/src/index.js index 3f1f5f9..a28b3ec 100644 --- a/src/index.js +++ b/src/index.js @@ -1,11 +1,9 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; +import React from "react"; +import ReactDOM from "react-dom"; +import "./index.scss"; +import App from "./App"; +import * as serviceWorker from "./serviceWorker"; -import './index.scss'; -import App from './App'; -import * as serviceWorker from './serviceWorker'; - -ReactDOM.render(<App />, document.getElementById('root')); +ReactDOM.render(<App />, document.getElementById("root")); serviceWorker.unregister(); - diff --git a/src/serviceWorker.js b/src/serviceWorker.js index f8c7e50..5ef2083 100644 --- a/src/serviceWorker.js +++ b/src/serviceWorker.js @@ -11,9 +11,9 @@ // opt-in, read https://bit.ly/CRA-PWA const isLocalhost = Boolean( - window.location.hostname === 'localhost' || + window.location.hostname === "localhost" || // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || + window.location.hostname === "[::1]" || // 127.0.0.1/8 is considered localhost for IPv4. window.location.hostname.match( /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ @@ -21,7 +21,7 @@ const isLocalhost = Boolean( ); export function register(config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { // The URL constructor is available in all browsers that support SW. const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); if (publicUrl.origin !== window.location.origin) { @@ -31,7 +31,7 @@ export function register(config) { return; } - window.addEventListener('load', () => { + window.addEventListener("load", () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { @@ -42,8 +42,8 @@ export function register(config) { // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { console.log( - 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://bit.ly/CRA-PWA' + "This web app is being served cache-first by a service " + + "worker. To learn more, visit https://bit.ly/CRA-PWA" ); }); } else { @@ -64,14 +64,14 @@ function registerValidSW(swUrl, config) { return; } installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { + if (installingWorker.state === "installed") { if (navigator.serviceWorker.controller) { // At this point, the updated precached content has been fetched, // but the previous service worker will still serve the older // content until all client tabs are closed. console.log( - 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' + "New content is available and will be used when all " + + "tabs for this page are closed. See https://bit.ly/CRA-PWA." ); // Execute callback @@ -82,7 +82,7 @@ function registerValidSW(swUrl, config) { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); + console.log("Content is cached for offline use."); // Execute callback if (config && config.onSuccess) { @@ -94,7 +94,7 @@ function registerValidSW(swUrl, config) { }; }) .catch(error => { - console.error('Error during service worker registration:', error); + console.error("Error during service worker registration:", error); }); } @@ -103,10 +103,10 @@ function checkValidServiceWorker(swUrl, config) { fetch(swUrl) .then(response => { // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get('content-type'); + const contentType = response.headers.get("content-type"); if ( response.status === 404 || - (contentType != null && contentType.indexOf('javascript') === -1) + (contentType != null && contentType.indexOf("javascript") === -1) ) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then(registration => { @@ -121,13 +121,13 @@ function checkValidServiceWorker(swUrl, config) { }) .catch(() => { console.log( - 'No internet connection found. App is running in offline mode.' + "No internet connection found. App is running in offline mode." ); }); } export function unregister() { - if ('serviceWorker' in navigator) { + if ("serviceWorker" in navigator) { navigator.serviceWorker.ready.then(registration => { registration.unregister(); }); diff --git a/src/store/mainReducer.js b/src/store/mainReducer.js index be4bb60..a07510b 100644 --- a/src/store/mainReducer.js +++ b/src/store/mainReducer.js @@ -1,7 +1,12 @@ import { ADD_VARIABLE, UPDATE_VARIABLE, DELETE_VARIABLE } from './actionTypes'; +import {Svgo} from '../../src/components/svgSetting/svgoConfig' let initialState = { - fileNames: [] + fileNames: [], + svgSettingList:[], + svgOptions:[], + svgObject:{...Svgo}, + displayOptimize:[] }; export default (state=initialState, action) => {